Apply patch [#20145] Ghost Win32 roundup patch: Minimum Window Size, Continuous Grab...
[blender.git] / intern / ghost / intern / GHOST_SystemWin32.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /**
30
31  * $Id$
32  * Copyright (C) 2001 NaN Technologies B.V.
33  * @author      Maarten Gribnau
34  * @date        May 7, 2001
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include "GHOST_SystemWin32.h"
42 #include "GHOST_EventDragnDrop.h"
43
44 // win64 doesn't define GWL_USERDATA
45 #ifdef WIN32
46 #ifndef GWL_USERDATA
47 #define GWL_USERDATA GWLP_USERDATA
48 #define GWL_WNDPROC GWLP_WNDPROC
49 #endif
50 #endif
51
52 /*
53  * According to the docs the mouse wheel message is supported from windows 98 
54  * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the 
55  * wheel detent value are undefined.
56  */
57 #ifndef WM_MOUSEWHEEL
58 #define WM_MOUSEWHEEL 0x020A
59 #endif // WM_MOUSEWHEEL
60 #ifndef WHEEL_DELTA
61 #define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */
62 #endif // WHEEL_DELTA
63
64 /* 
65  * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
66  * MSDN: Declared in Winuser.h, include Windows.h 
67  * This does not seem to work with MinGW so we define our own here.
68  */
69 #ifndef XBUTTON1
70 #define XBUTTON1 0x0001
71 #endif // XBUTTON1
72 #ifndef XBUTTON2
73 #define XBUTTON2 0x0002
74 #endif // XBUTTON2
75 #ifndef WM_XBUTTONUP
76 #define WM_XBUTTONUP 524
77 #endif // WM_XBUTTONUP
78 #ifndef WM_XBUTTONDOWN
79 #define WM_XBUTTONDOWN 523
80 #endif // WM_XBUTTONDOWN
81
82 #include "GHOST_Debug.h"
83 #include "GHOST_DisplayManagerWin32.h"
84 #include "GHOST_EventButton.h"
85 #include "GHOST_EventCursor.h"
86 #include "GHOST_EventKey.h"
87 #include "GHOST_EventWheel.h"
88 #include "GHOST_EventNDOF.h"
89 #include "GHOST_TimerTask.h"
90 #include "GHOST_TimerManager.h"
91 #include "GHOST_WindowManager.h"
92 #include "GHOST_WindowWin32.h"
93 #include "GHOST_NDOFManager.h"
94
95 // Key code values not found in winuser.h
96 #ifndef VK_MINUS
97 #define VK_MINUS 0xBD
98 #endif // VK_MINUS
99 #ifndef VK_SEMICOLON
100 #define VK_SEMICOLON 0xBA
101 #endif // VK_SEMICOLON
102 #ifndef VK_PERIOD
103 #define VK_PERIOD 0xBE
104 #endif // VK_PERIOD
105 #ifndef VK_COMMA
106 #define VK_COMMA 0xBC
107 #endif // VK_COMMA
108 #ifndef VK_QUOTE
109 #define VK_QUOTE 0xDE
110 #endif // VK_QUOTE
111 #ifndef VK_BACK_QUOTE
112 #define VK_BACK_QUOTE 0xC0
113 #endif // VK_BACK_QUOTE
114 #ifndef VK_SLASH
115 #define VK_SLASH 0xBF
116 #endif // VK_SLASH
117 #ifndef VK_BACK_SLASH
118 #define VK_BACK_SLASH 0xDC
119 #endif // VK_BACK_SLASH
120 #ifndef VK_EQUALS
121 #define VK_EQUALS 0xBB
122 #endif // VK_EQUALS
123 #ifndef VK_OPEN_BRACKET
124 #define VK_OPEN_BRACKET 0xDB
125 #endif // VK_OPEN_BRACKET
126 #ifndef VK_CLOSE_BRACKET
127 #define VK_CLOSE_BRACKET 0xDD
128 #endif // VK_CLOSE_BRACKET
129 #ifndef VK_GR_LESS
130 #define VK_GR_LESS 0xE2
131 #endif // VK_GR_LESS
132
133
134 GHOST_SystemWin32::GHOST_SystemWin32()
135 : m_hasPerformanceCounter(false), m_freq(0), m_start(0),
136   m_separateLeftRight(false),
137   m_separateLeftRightInitialized(false)
138 {
139         m_displayManager = new GHOST_DisplayManagerWin32 ();
140         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
141         m_displayManager->initialize();
142         
143         // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
144         OleInitialize(0);
145 }
146
147 GHOST_SystemWin32::~GHOST_SystemWin32()
148 {
149         // Shutdown COM
150         OleUninitialize();
151 }
152
153
154 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
155 {
156         // Hardware does not support high resolution timers. We will use GetTickCount instead then.
157         if (!m_hasPerformanceCounter) {
158                 return ::GetTickCount();
159         }
160
161         // Retrieve current count
162         __int64 count = 0;
163         ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
164
165         // Calculate the time passed since system initialization.
166         __int64 delta = 1000*(count-m_start);
167
168         GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
169         return t; 
170 }
171
172
173 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
174 {
175         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
176         GHOST_TUns8 numDisplays;
177         m_displayManager->getNumDisplays(numDisplays);
178         return numDisplays;
179 }
180
181
182 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
183 {
184         width = ::GetSystemMetrics(SM_CXSCREEN);
185         height= ::GetSystemMetrics(SM_CYSCREEN);
186 }
187
188
189 GHOST_IWindow* GHOST_SystemWin32::createWindow(
190         const STR_String& title, 
191         GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
192         GHOST_TWindowState state, GHOST_TDrawingContextType type,
193         bool stereoVisual, const GHOST_TEmbedderWindowID parentWindow )
194 {
195         GHOST_Window* window = 0;
196         window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual);
197         if (window) {
198                 if (window->getValid()) {
199                         // Store the pointer to the window
200 //                      if (state != GHOST_kWindowStateFullScreen) {
201                                 m_windowManager->addWindow(window);
202 //                      }
203                 }
204                 else {
205                         delete window;
206                         window = 0;
207                 }
208         }
209         return window;
210 }
211
212
213 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
214 {
215         MSG msg;
216         bool anyProcessed = false;
217
218         do {
219                 GHOST_TimerManager* timerMgr = getTimerManager();
220
221                 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
222 #if 1
223                         ::Sleep(1);
224 #else
225                         GHOST_TUns64 next = timerMgr->nextFireTime();
226                         GHOST_TInt64 maxSleep = next - getMilliSeconds();
227                         
228                         if (next == GHOST_kFireTimeNever) {
229                                 ::WaitMessage();
230                         } else if(maxSleep >= 0.0) {
231                                 ::SetTimer(NULL, 0, maxSleep, NULL);
232                                 ::WaitMessage();
233                                 ::KillTimer(NULL, 0);
234                         }
235 #endif
236                 }
237
238                 if (timerMgr->fireTimers(getMilliSeconds())) {
239                         anyProcessed = true;
240                 }
241
242                 // Process all the events waiting for us
243                 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
244                         ::TranslateMessage(&msg);
245                         ::DispatchMessage(&msg);
246                         anyProcessed = true;
247                 }
248         } while (waitForEvent && !anyProcessed);
249
250         return anyProcessed;
251 }
252
253
254 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
255 {
256         POINT point;
257         if(::GetCursorPos(&point)){
258                 x = point.x;
259                 y = point.y;
260                 return GHOST_kSuccess;
261         }
262         return GHOST_kFailure;
263 }
264
265
266 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
267 {
268         return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
269 }
270
271
272 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
273 {
274         /*
275         GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
276         Terminal Server and Windows 2000.
277         But on WinME it always returns zero. These two functions are simply
278         skipped by Millenium Edition!
279
280         Official explanation from Microsoft:
281         Intentionally disabled.
282         It didn't work all that well on some newer hardware, and worked less 
283         well with the passage of time, so it was fully disabled in ME.
284         */
285         if (m_separateLeftRight && m_separateLeftRightInitialized) {
286                 bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
287                 keys.set(GHOST_kModifierKeyLeftShift, down);
288                 down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
289                 keys.set(GHOST_kModifierKeyRightShift, down);
290                 down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
291                 keys.set(GHOST_kModifierKeyLeftAlt, down);
292                 down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
293                 keys.set(GHOST_kModifierKeyRightAlt, down);
294                 down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
295                 keys.set(GHOST_kModifierKeyLeftControl, down);
296                 down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
297                 keys.set(GHOST_kModifierKeyRightControl, down);
298         }
299         else {
300                 bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
301                 keys.set(GHOST_kModifierKeyLeftShift, down);
302                 keys.set(GHOST_kModifierKeyRightShift, down);
303                 down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
304                 keys.set(GHOST_kModifierKeyLeftAlt, down);
305                 keys.set(GHOST_kModifierKeyRightAlt, down);
306                 down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
307                 keys.set(GHOST_kModifierKeyLeftControl, down);
308                 keys.set(GHOST_kModifierKeyRightControl, down);
309         }
310         return GHOST_kSuccess;
311 }
312
313
314 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
315 {
316         /* Check for swapped buttons (left-handed mouse buttons)
317          * GetAsyncKeyState() will give back the state of the physical mouse buttons.
318          */
319         bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
320
321         bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
322         buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
323
324         down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
325         buttons.set(GHOST_kButtonMaskMiddle, down);
326
327         down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
328         buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
329         return GHOST_kSuccess;
330 }
331
332
333 GHOST_TSuccess GHOST_SystemWin32::init()
334 {
335         GHOST_TSuccess success = GHOST_System::init();
336
337         /* Disable scaling on high DPI displays on Vista */
338         HMODULE user32 = ::LoadLibraryA("user32.dll");
339         typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
340         LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
341                 (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
342         if (SetProcessDPIAware)
343                 SetProcessDPIAware();
344         FreeLibrary(user32);
345
346         // Determine whether this system has a high frequency performance counter. */
347         m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
348         if (m_hasPerformanceCounter) {
349                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
350                 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
351         }
352         else {
353                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
354         }
355
356         if (success) {
357                 WNDCLASS wc;
358                 wc.style= CS_HREDRAW | CS_VREDRAW;
359                 wc.lpfnWndProc= s_wndProc;
360                 wc.cbClsExtra= 0;
361                 wc.cbWndExtra= 0;
362                 wc.hInstance= ::GetModuleHandle(0);
363                 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
364                 
365                 if (!wc.hIcon) {
366                         ::LoadIcon(NULL, IDI_APPLICATION);
367                 }
368                 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
369                 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
370                 wc.lpszMenuName = 0;
371                 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
372     
373                 // Use RegisterClassEx for setting small icon
374                 if (::RegisterClass(&wc) == 0) {
375                         success = GHOST_kFailure;
376                 }
377         }
378         return success;
379 }
380
381
382 GHOST_TSuccess GHOST_SystemWin32::exit()
383 {
384         return GHOST_System::exit();
385 }
386
387
388 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
389 {
390         GHOST_TKey key;
391         bool isExtended = (lParam&(1<<24))?true:false;
392
393         if ((wParam >= '0') && (wParam <= '9')) {
394                 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
395                 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
396         }
397         else if ((wParam >= 'A') && (wParam <= 'Z')) {
398                 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
399                 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
400         }
401         else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
402                 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
403         }
404         else {
405                 switch (wParam) {
406                 case VK_RETURN:
407                         key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
408                         break;
409
410                 case VK_BACK:     key = GHOST_kKeyBackSpace;            break;
411                 case VK_TAB:      key = GHOST_kKeyTab;                          break;
412                 case VK_ESCAPE:   key = GHOST_kKeyEsc;                          break;
413                 case VK_SPACE:    key = GHOST_kKeySpace;                        break;
414                 case VK_PRIOR:    key = GHOST_kKeyUpPage;                       break;
415                 case VK_NEXT:     key = GHOST_kKeyDownPage;                     break;
416                 case VK_END:      key = GHOST_kKeyEnd;                          break;
417                 case VK_HOME:     key = GHOST_kKeyHome;                         break;
418                 case VK_INSERT:   key = GHOST_kKeyInsert;                       break;
419                 case VK_DELETE:   key = GHOST_kKeyDelete;                       break;
420                 case VK_LEFT:     key = GHOST_kKeyLeftArrow;            break;
421                 case VK_RIGHT:    key = GHOST_kKeyRightArrow;           break;
422                 case VK_UP:       key = GHOST_kKeyUpArrow;                      break;
423                 case VK_DOWN:     key = GHOST_kKeyDownArrow;            break;
424                 case VK_NUMPAD0:  key = GHOST_kKeyNumpad0;                      break;
425                 case VK_NUMPAD1:  key = GHOST_kKeyNumpad1;                      break;
426                 case VK_NUMPAD2:  key = GHOST_kKeyNumpad2;                      break;
427                 case VK_NUMPAD3:  key = GHOST_kKeyNumpad3;                      break;
428                 case VK_NUMPAD4:  key = GHOST_kKeyNumpad4;                      break;
429                 case VK_NUMPAD5:  key = GHOST_kKeyNumpad5;                      break;
430                 case VK_NUMPAD6:  key = GHOST_kKeyNumpad6;                      break;
431                 case VK_NUMPAD7:  key = GHOST_kKeyNumpad7;                      break;
432                 case VK_NUMPAD8:  key = GHOST_kKeyNumpad8;                      break;
433                 case VK_NUMPAD9:  key = GHOST_kKeyNumpad9;                      break;
434                 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen;          break;
435                 case VK_PAUSE:    key = GHOST_kKeyPause;                        break;
436                 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk;        break;
437                 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus;          break;
438                 case VK_DECIMAL:  key = GHOST_kKeyNumpadPeriod;         break;
439                 case VK_DIVIDE:   key = GHOST_kKeyNumpadSlash;          break;
440                 case VK_ADD:      key = GHOST_kKeyNumpadPlus;           break;
441
442                 case VK_SEMICOLON:              key = GHOST_kKeySemicolon;              break;
443                 case VK_EQUALS:                 key = GHOST_kKeyEqual;                  break;
444                 case VK_COMMA:                  key = GHOST_kKeyComma;                  break;
445                 case VK_MINUS:                  key = GHOST_kKeyMinus;                  break;
446                 case VK_PERIOD:                 key = GHOST_kKeyPeriod;                 break;
447                 case VK_SLASH:                  key = GHOST_kKeySlash;                  break;
448                 case VK_BACK_QUOTE:             key = GHOST_kKeyAccentGrave;    break;
449                 case VK_OPEN_BRACKET:   key = GHOST_kKeyLeftBracket;    break;
450                 case VK_BACK_SLASH:             key = GHOST_kKeyBackslash;              break;
451                 case VK_CLOSE_BRACKET:  key = GHOST_kKeyRightBracket;   break;
452                 case VK_QUOTE:                  key = GHOST_kKeyQuote;                  break;
453                 case VK_GR_LESS:                key = GHOST_kKeyGrLess;                 break;
454
455                 // Process these keys separately because we need to distinguish right from left modifier keys
456                 case VK_SHIFT:
457                 case VK_CONTROL:
458                 case VK_MENU:
459
460                 // Ignore these keys
461                 case VK_NUMLOCK:
462                 case VK_SCROLL:
463                 case VK_CAPITAL:
464                 default:
465                         key = GHOST_kKeyUnknown;
466                         break;
467                 }
468         }
469         return key;
470 }
471
472
473 void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
474 {
475         GHOST_ModifierKeys oldModifiers, newModifiers;
476         // Retrieve old state of the modifier keys
477         ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
478         // Retrieve current state of the modifier keys
479         ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
480
481         // Compare the old and the new
482         if (!newModifiers.equals(oldModifiers)) {
483                 // Create events for the masks that changed
484                 for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
485                         if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
486                                 // Convert the mask to a key code
487                                 GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
488                                 bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
489                                 GHOST_EventKey* event;
490                                 if (key != GHOST_kKeyUnknown) {
491                                         // Create an event
492                                         event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
493                                         pushEvent(event);
494                                 }
495                         }
496                 }
497         }
498
499         // Store new modifier keys state
500         ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
501 }
502
503
504 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
505 {
506         return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
507 }
508
509
510 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
511 {
512         GHOST_TInt32 x_screen, y_screen;
513         GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
514         GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
515         
516         system->getCursorPosition(x_screen, y_screen);
517
518         if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
519         {
520                 GHOST_TInt32 x_new= x_screen;
521                 GHOST_TInt32 y_new= y_screen;
522                 GHOST_TInt32 x_accum, y_accum;
523                 GHOST_Rect bounds;
524
525                 /* fallback to window bounds */
526                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
527                         window->getClientBounds(bounds);
528                 }
529
530                 /* could also clamp to screen bounds
531                  * wrap with a window outside the view will fail atm  */
532
533                 bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
534
535                 window->getCursorGrabAccum(x_accum, y_accum);
536                 if(x_new != x_screen|| y_new != y_screen) {
537                         /* when wrapping we don't need to add an event because the
538                          * setCursorPosition call will cause a new event after */
539                         system->setCursorPosition(x_new, y_new); /* wrap */
540                         window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
541                 }else{
542                         return new GHOST_EventCursor(system->getMilliSeconds(),
543                                                                                  GHOST_kEventCursorMove,
544                                                                                  window,
545                                                                                  x_screen + x_accum,
546                                                                                  y_screen + y_accum
547                         );
548                 }
549
550         }
551         else {
552                 return new GHOST_EventCursor(system->getMilliSeconds(),
553                                                                          GHOST_kEventCursorMove,
554                                                                          window,
555                                                                          x_screen,
556                                                                          y_screen
557                 );
558         }
559         return NULL;
560 }
561
562
563 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
564 {
565         // short fwKeys = LOWORD(wParam);                       // key flags
566         int zDelta = (short) HIWORD(wParam);    // wheel rotation
567         
568         // zDelta /= WHEEL_DELTA;
569         // temporary fix below: microsoft now has added more precision, making the above division not work
570         if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;   
571         
572         // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
573         // short yPos = (short) HIWORD(lParam); // vertical position of pointer
574         return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
575 }
576
577
578 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
579 {
580         GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
581         GHOST_EventKey* event;
582         if (key != GHOST_kKeyUnknown) {
583                 MSG keyMsg;
584                 char ascii = '\0';
585
586                         /* Eat any character related messages */
587                 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
588                         ascii = (char) keyMsg.wParam;
589                 }
590
591                 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
592         }
593         else {
594                 event = 0;
595         }
596         return event;
597 }
598
599
600 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
601 {
602         return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
603 }
604
605 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
606                                                                                                         GHOST_TDragnDropTypes draggedObjectType,
607                                                                                                         GHOST_IWindow* window,
608                                                                                                         int mouseX, int mouseY,
609                                                                                                         void* data)
610 {
611         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
612         return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
613                                                                                                           eventType,
614                                                                                                           draggedObjectType,
615                                                                                                           window,mouseX,mouseY,data)
616                         );
617 }
618
619 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
620 {
621         minmax->ptMinTrackSize.x=320;
622         minmax->ptMinTrackSize.y=240;
623 }
624
625
626 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
627 {
628         GHOST_Event* event = 0;
629         LRESULT lResult = 0;
630         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
631         GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
632
633         if (hwnd) {
634                 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
635                 if (window) {
636                         switch (msg) {
637                                 ////////////////////////////////////////////////////////////////////////
638                                 // Keyboard events, processed
639                                 ////////////////////////////////////////////////////////////////////////
640                                 case WM_KEYDOWN:
641                                         /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a 
642                                          * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
643                                          * key is not pressed. 
644                                          */
645                                 case WM_SYSKEYDOWN:
646                                         /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when 
647                                          * the user presses the F10 key (which activates the menu bar) or holds down the 
648                                          * alt key and then presses another key. It also occurs when no window currently 
649                                          * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the 
650                                          * active window. The window that receives the message can distinguish between these 
651                                          * two contexts by checking the context code in the lKeyData parameter. 
652                                          */
653                                         switch (wParam) {
654                                                 case VK_SHIFT:
655                                                 case VK_CONTROL:
656                                                 case VK_MENU:
657                                                         if (!system->m_separateLeftRightInitialized) {
658                                                                 // Check whether this system supports seperate left and right keys
659                                                                 switch (wParam) {
660                                                                         case VK_SHIFT:
661                                                                                 system->m_separateLeftRight = 
662                                                                                         (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
663                                                                                         (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
664                                                                                         true : false;
665                                                                                 break;
666                                                                         case VK_CONTROL:
667                                                                                 system->m_separateLeftRight = 
668                                                                                         (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
669                                                                                         (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
670                                                                                         true : false;
671                                                                                 break;
672                                                                         case VK_MENU:
673                                                                                 system->m_separateLeftRight = 
674                                                                                         (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
675                                                                                         (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
676                                                                                         true : false;
677                                                                                 break;
678                                                                 }
679                                                                 system->m_separateLeftRightInitialized = true;
680                                                         }
681                                                         system->processModifierKeys(window);
682                                                         // Bypass call to DefWindowProc
683                                                         return 0;
684                                                 default:
685                                                         event = processKeyEvent(window, true, wParam, lParam);
686                                                         if (!event) {
687                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
688                                                                 GHOST_PRINT(msg)
689                                                                 GHOST_PRINT(" key ignored\n")
690                                                         }
691                                                         break;
692                                                 }
693                                         break;
694
695                                 case WM_KEYUP:
696                                 case WM_SYSKEYUP:
697                                         switch (wParam) {
698                                                 case VK_SHIFT:
699                                                 case VK_CONTROL:
700                                                 case VK_MENU:
701                                                         system->processModifierKeys(window);
702                                                         // Bypass call to DefWindowProc
703                                                         return 0;
704                                                 default:
705                                                         event = processKeyEvent(window, false, wParam, lParam);
706                                                         if (!event) {
707                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
708                                                                 GHOST_PRINT(msg)
709                                                                 GHOST_PRINT(" key ignored\n")
710                                                         }
711                                                         break;
712                                         }
713                                         break;
714
715                                 ////////////////////////////////////////////////////////////////////////
716                                 // Keyboard events, ignored
717                                 ////////////////////////////////////////////////////////////////////////
718                                 case WM_CHAR:
719                                         /* The WM_CHAR message is posted to the window with the keyboard focus when 
720                                          * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
721                                          * contains the character code of the key that was pressed. 
722                                          */
723                                 case WM_DEADCHAR:
724                                         /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
725                                          * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
726                                          * specifies a character code generated by a dead key. A dead key is a key that 
727                                          * generates a character, such as the umlaut (double-dot), that is combined with 
728                                          * another character to form a composite character. For example, the umlaut-O 
729                                          * character (Ù) is generated by typing the dead key for the umlaut character, and 
730                                          * then typing the O key.
731                                          */
732                                 case WM_SYSDEADCHAR:
733                                         /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
734                                          * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
735                                          * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
736                                          * a dead key that is pressed while holding down the alt key. 
737                                          */
738                                         break;
739                                 ////////////////////////////////////////////////////////////////////////
740                                 // Tablet events, processed
741                                 ////////////////////////////////////////////////////////////////////////
742                                 case WT_PACKET:
743                                         ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
744                                         break;
745                                 case WT_CSRCHANGE:
746                                 case WT_PROXIMITY:
747                                         ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
748                                         break;
749                                 ////////////////////////////////////////////////////////////////////////
750                                 // Mouse events, processed
751                                 ////////////////////////////////////////////////////////////////////////
752                                 case WM_LBUTTONDOWN:
753                                         window->registerMouseClickEvent(true);
754                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
755                                         break;
756                                 case WM_MBUTTONDOWN:
757                                         window->registerMouseClickEvent(true);
758                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
759                                         break;
760                                 case WM_RBUTTONDOWN:
761                                         window->registerMouseClickEvent(true);
762                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
763                                         break;
764                                 case WM_XBUTTONDOWN:
765                                         window->registerMouseClickEvent(true);
766                                         if ((short) HIWORD(wParam) == XBUTTON1){
767                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
768                                         }else if((short) HIWORD(wParam) == XBUTTON2){
769                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
770                                         }
771                                         break;
772                                 case WM_LBUTTONUP:
773                                         window->registerMouseClickEvent(false);
774                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
775                                         break;
776                                 case WM_MBUTTONUP:
777                                         window->registerMouseClickEvent(false);
778                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
779                                         break;
780                                 case WM_RBUTTONUP:
781                                         window->registerMouseClickEvent(false);
782                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
783                                         break;
784                                 case WM_XBUTTONUP:
785                                         window->registerMouseClickEvent(false);
786                                         if ((short) HIWORD(wParam) == XBUTTON1){
787                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
788                                         }else if((short) HIWORD(wParam) == XBUTTON2){
789                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
790                                         }
791                                         break;
792                                 case WM_MOUSEMOVE:
793                                         event = processCursorEvent(GHOST_kEventCursorMove, window);
794                                         break;
795                                 case WM_MOUSEWHEEL:
796                                         /* The WM_MOUSEWHEEL message is sent to the focus window 
797                                          * when the mouse wheel is rotated. The DefWindowProc 
798                                          * function propagates the message to the window's parent.
799                                          * There should be no internal forwarding of the message, 
800                                          * since DefWindowProc propagates it up the parent chain 
801                                          * until it finds a window that processes it.
802                                          */
803                                         event = processWheelEvent(window, wParam, lParam);
804                                         break;
805                                 case WM_SETCURSOR:
806                                         /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
807                                          * to move within a window and mouse input is not captured.
808                                          * This means we have to set the cursor shape every time the mouse moves!
809                                          * The DefWindowProc function uses this message to set the cursor to an 
810                                          * arrow if it is not in the client area.
811                                          */
812                                         if (LOWORD(lParam) == HTCLIENT) {
813                                                 // Load the current cursor
814                                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
815                                                 // Bypass call to DefWindowProc
816                                                 return 0;
817                                         } 
818                                         else {
819                                                 // Outside of client area show standard cursor
820                                                 window->loadCursor(true, GHOST_kStandardCursorDefault);
821                                         }
822                                         break;
823
824                                 ////////////////////////////////////////////////////////////////////////
825                                 // Mouse events, ignored
826                                 ////////////////////////////////////////////////////////////////////////
827                                 case WM_NCMOUSEMOVE:
828                                         /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
829                                          * within the nonclient area of the window. This message is posted to the window 
830                                          * that contains the cursor. If a window has captured the mouse, this message is not posted.
831                                          */
832                                 case WM_NCHITTEST:
833                                         /* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
834                                          * when a mouse button is pressed or released. If the mouse is not captured, 
835                                          * the message is sent to the window beneath the cursor. Otherwise, the message 
836                                          * is sent to the window that has captured the mouse. 
837                                          */
838                                         break;
839
840                                 ////////////////////////////////////////////////////////////////////////
841                                 // Window events, processed
842                                 ////////////////////////////////////////////////////////////////////////
843                                 case WM_CLOSE:
844                                         /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
845                                         event = processWindowEvent(GHOST_kEventWindowClose, window);
846                                         break;
847                                 case WM_ACTIVATE:
848                                         /* The WM_ACTIVATE message is sent to both the window being activated and the window being 
849                                          * deactivated. If the windows use the same input queue, the message is sent synchronously, 
850                                          * first to the window procedure of the top-level window being deactivated, then to the window
851                                          * procedure of the top-level window being activated. If the windows use different input queues,
852                                          * the message is sent asynchronously, so the window is activated immediately. 
853                                          */
854                                         event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
855                                         /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
856                                         will not be dispatched to OUR active window if we minimize one of OUR windows. */
857                                         lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
858                                         break;
859                                 case WM_PAINT:
860                                         /* An application sends the WM_PAINT message when the system or another application 
861                                          * makes a request to paint a portion of an application's window. The message is sent
862                                          * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
863                                          * function when the application obtains a WM_PAINT message by using the GetMessage or 
864                                          * PeekMessage function. 
865                                          */
866                                         event = processWindowEvent(GHOST_kEventWindowUpdate, window);
867                                         ::ValidateRect(hwnd, NULL);
868                                         break;
869                                 case WM_GETMINMAXINFO:
870                                         /* The WM_GETMINMAXINFO message is sent to a window when the size or 
871                                          * position of the window is about to change. An application can use 
872                                          * this message to override the window's default maximized size and 
873                                          * position, or its default minimum or maximum tracking size. 
874                                          */
875                                         processMinMaxInfo((MINMAXINFO *) lParam);
876                                         /* Let DefWindowProc handle it. */
877                                         break;
878                                 case WM_SIZE:
879                                         /* The WM_SIZE message is sent to a window after its size has changed.
880                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
881                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
882                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
883                                          * message without calling DefWindowProc.
884                                          */
885                                         event = processWindowEvent(GHOST_kEventWindowSize, window);
886                                         break;
887                                 case WM_CAPTURECHANGED:
888                                         window->lostMouseCapture();
889                                         break;
890                                 case WM_MOVING:
891                                         /* The WM_MOVING message is sent to a window that the user is moving. By processing 
892                                          * this message, an application can monitor the size and position of the drag rectangle
893                                          * and, if needed, change its size or position.
894                                          */
895                                 case WM_MOVE:
896                                         /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
897                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
898                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
899                                          * message without calling DefWindowProc. 
900                                          */
901                                         event = processWindowEvent(GHOST_kEventWindowMove, window);
902                                         break;
903                                 ////////////////////////////////////////////////////////////////////////
904                                 // Window events, ignored
905                                 ////////////////////////////////////////////////////////////////////////
906                                 case WM_WINDOWPOSCHANGED:
907                                         /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
908                                          * in the Z order has changed as a result of a call to the SetWindowPos function or 
909                                          * another window-management function.
910                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
911                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
912                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
913                                          * message without calling DefWindowProc.
914                                          */
915                                 case WM_ERASEBKGND:
916                                         /* An application sends the WM_ERASEBKGND message when the window background must be 
917                                          * erased (for example, when a window is resized). The message is sent to prepare an 
918                                          * invalidated portion of a window for painting. 
919                                          */
920                                 case WM_NCPAINT:
921                                         /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
922                                 case WM_NCACTIVATE:
923                                         /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
924                                          * to indicate an active or inactive state. 
925                                          */
926                                 case WM_DESTROY:
927                                         /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
928                                          * procedure of the window being destroyed after the window is removed from the screen. 
929                                          * This message is sent first to the window being destroyed and then to the child windows 
930                                          * (if any) as they are destroyed. During the processing of the message, it can be assumed 
931                                          * that all child windows still exist. 
932                                          */
933                                 case WM_NCDESTROY:
934                                         /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
935                                          * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
936                                          * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
937                                          */
938                                 case WM_KILLFOCUS:
939                                         /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
940                                 case WM_SHOWWINDOW:
941                                         /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
942                                 case WM_WINDOWPOSCHANGING:
943                                         /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
944                                          * the Z order is about to change as a result of a call to the SetWindowPos function or 
945                                          * another window-management function. 
946                                          */
947                                 case WM_SETFOCUS:
948                                         /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
949                                 case WM_ENTERSIZEMOVE:
950                                         /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
951                                          * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
952                                          * clicks the window's title bar or sizing border, or when the window passes the 
953                                          * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
954                                          * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
955                                          * DefWindowProc returns. 
956                                          */
957                                         break;
958                                         
959                                 ////////////////////////////////////////////////////////////////////////
960                                 // Other events
961                                 ////////////////////////////////////////////////////////////////////////
962                                 case WM_GETTEXT:
963                                         /* An application sends a WM_GETTEXT message to copy the text that 
964                                          * corresponds to a window into a buffer provided by the caller. 
965                                          */
966                                 case WM_ACTIVATEAPP:
967                                         /* The WM_ACTIVATEAPP message is sent when a window belonging to a 
968                                          * different application than the active window is about to be activated.
969                                          * The message is sent to the application whose window is being activated
970                                          * and to the application whose window is being deactivated. 
971                                          */
972                                 case WM_TIMER:
973                                         /* The WIN32 docs say:
974                                          * The WM_TIMER message is posted to the installing thread's message queue
975                                          * when a timer expires. You can process the message by providing a WM_TIMER
976                                          * case in the window procedure. Otherwise, the default window procedure will
977                                          * call the TimerProc callback function specified in the call to the SetTimer
978                                          * function used to install the timer. 
979                                          *
980                                          * In GHOST, we let DefWindowProc call the timer callback.
981                                          */
982                                         break;
983                                 case WM_BLND_NDOF_AXIS:
984                                         {
985                                                 GHOST_TEventNDOFData ndofdata;
986                                                 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
987                                                 system->m_eventManager->
988                                                         pushEvent(new GHOST_EventNDOF(
989                                                                 system->getMilliSeconds(), 
990                                                                 GHOST_kEventNDOFMotion, 
991                                                                 window, ndofdata));
992                                         }
993                                         break;
994                                 case WM_BLND_NDOF_BTN:
995                                         {
996                                                 GHOST_TEventNDOFData ndofdata;
997                                                 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
998                                                 system->m_eventManager->
999                                                         pushEvent(new GHOST_EventNDOF(
1000                                                                 system->getMilliSeconds(), 
1001                                                                 GHOST_kEventNDOFButton, 
1002                                                                 window, ndofdata));
1003                                         }
1004                                         break;
1005                         }
1006                 }
1007                 else {
1008                         // Event found for a window before the pointer to the class has been set.
1009                         GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
1010                         /* These are events we typically miss at this point:
1011                            WM_GETMINMAXINFO     0x24
1012                            WM_NCCREATE                  0x81
1013                            WM_NCCALCSIZE                0x83
1014                            WM_CREATE                    0x01
1015                            We let DefWindowProc do the work.
1016                         */
1017                 }
1018         }
1019         else {
1020                 // Events without valid hwnd
1021                 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
1022         }
1023
1024         if (event) {
1025                 system->pushEvent(event);
1026         }
1027         else {
1028                 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
1029         }
1030         return lResult;
1031 }
1032
1033 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const 
1034 {
1035         char *buffer;
1036         char *temp_buff;
1037         
1038         if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
1039                 HANDLE hData = GetClipboardData( CF_TEXT );
1040                 if (hData == NULL) {
1041                         CloseClipboard();
1042                         return NULL;
1043                 }
1044                 buffer = (char*)GlobalLock( hData );
1045                 
1046                 temp_buff = (char*) malloc(strlen(buffer)+1);
1047                 strcpy(temp_buff, buffer);
1048                 
1049                 GlobalUnlock( hData );
1050                 CloseClipboard();
1051                 
1052                 temp_buff[strlen(buffer)] = '\0';
1053                 if (buffer) {
1054                         return (GHOST_TUns8*)temp_buff;
1055                 } else {
1056                         return NULL;
1057                 }
1058         } else {
1059                 return NULL;
1060         }
1061 }
1062
1063 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1064 {
1065         if(selection) {return;} // for copying the selection, used on X11
1066
1067         if (OpenClipboard(NULL)) {
1068                 HLOCAL clipbuffer;
1069                 char *data;
1070                 
1071                 if (buffer) {
1072                         EmptyClipboard();
1073                         
1074                         clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1)));
1075                         data = (char*)GlobalLock(clipbuffer);
1076
1077                         strcpy(data, (char*)buffer);
1078                         data[strlen(buffer)] = '\0';
1079                         LocalUnlock(clipbuffer);
1080                         SetClipboardData(CF_TEXT,clipbuffer);
1081                 }
1082                 CloseClipboard();
1083         } else {
1084                 return;
1085         }
1086 }
1087