ClangFormat: apply to source, most of intern
[blender.git] / intern / ghost / intern / GHOST_WindowWin32.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup GHOST
22  */
23
24 #define _USE_MATH_DEFINES
25
26 #include "GHOST_WindowWin32.h"
27 #include "GHOST_SystemWin32.h"
28 #include "GHOST_DropTargetWin32.h"
29 #include "GHOST_ContextNone.h"
30 #include "utfconv.h"
31 #include "utf_winfunc.h"
32
33 #if defined(WITH_GL_EGL)
34 #  include "GHOST_ContextEGL.h"
35 #else
36 #  include "GHOST_ContextWGL.h"
37 #endif
38 #ifdef WIN32_COMPOSITING
39 #  include <Dwmapi.h>
40 #endif
41
42 #include <windowsx.h>
43 #include <math.h>
44 #include <string.h>
45 #include <assert.h>
46
47 #ifndef GET_POINTERID_WPARAM
48 #  define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam))
49 #endif  // GET_POINTERID_WPARAM
50
51 const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
52 const int GHOST_WindowWin32::s_maxTitleLength = 128;
53
54 /* force NVidia Optimus to used dedicated graphics */
55 extern "C" {
56 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
57 }
58
59 GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
60                                      const STR_String &title,
61                                      GHOST_TInt32 left,
62                                      GHOST_TInt32 top,
63                                      GHOST_TUns32 width,
64                                      GHOST_TUns32 height,
65                                      GHOST_TWindowState state,
66                                      GHOST_TDrawingContextType type,
67                                      bool wantStereoVisual,
68                                      bool alphaBackground,
69                                      GHOST_TUns16 wantNumOfAASamples,
70                                      GHOST_TEmbedderWindowID parentwindowhwnd,
71                                      bool is_debug)
72     : GHOST_Window(width, height, state, wantStereoVisual, false, wantNumOfAASamples),
73       m_inLiveResize(false),
74       m_system(system),
75       m_hDC(0),
76       m_hasMouseCaptured(false),
77       m_hasGrabMouse(false),
78       m_nPressedButtons(0),
79       m_customCursor(0),
80       m_wantAlphaBackground(alphaBackground),
81       m_normal_state(GHOST_kWindowStateNormal),
82       m_user32(NULL),
83       m_fpGetPointerInfo(NULL),
84       m_fpGetPointerPenInfo(NULL),
85       m_fpGetPointerTouchInfo(NULL),
86       m_parentWindowHwnd(parentwindowhwnd),
87       m_debug_context(is_debug)
88 {
89   // Initialize tablet variables
90   memset(&m_wintab, 0, sizeof(m_wintab));
91   memset(&m_tabletData, 0, sizeof(m_tabletData));
92   m_tabletData.Active = GHOST_kTabletModeNone;
93
94   // Create window
95   if (state != GHOST_kWindowStateFullScreen) {
96     RECT rect;
97     MONITORINFO monitor;
98     GHOST_TUns32 tw, th;
99
100 #ifndef _MSC_VER
101     int cxsizeframe = GetSystemMetrics(SM_CXSIZEFRAME);
102     int cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
103 #else
104     // MSVC 2012+ returns bogus values from GetSystemMetrics, bug in Windows
105     // http://connect.microsoft.com/VisualStudio/feedback/details/753224/regression-getsystemmetrics-delivers-different-values
106     RECT cxrect = {0, 0, 0, 0};
107     AdjustWindowRectEx(
108         &cxrect, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0);
109
110     int cxsizeframe = abs(cxrect.bottom);
111     int cysizeframe = abs(cxrect.left);
112 #endif
113
114     width += cxsizeframe * 2;
115     height += cysizeframe * 2 + GetSystemMetrics(SM_CYCAPTION);
116
117     rect.left = left;
118     rect.right = left + width;
119     rect.top = top;
120     rect.bottom = top + height;
121
122     monitor.cbSize = sizeof(monitor);
123     monitor.dwFlags = 0;
124
125     // take taskbar into account
126     GetMonitorInfo(MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST), &monitor);
127
128     th = monitor.rcWork.bottom - monitor.rcWork.top;
129     tw = monitor.rcWork.right - monitor.rcWork.left;
130
131     if (tw < width) {
132       width = tw;
133       left = monitor.rcWork.left;
134     }
135     else if (monitor.rcWork.right < left + (int)width)
136       left = monitor.rcWork.right - width;
137     else if (left < monitor.rcWork.left)
138       left = monitor.rcWork.left;
139
140     if (th < height) {
141       height = th;
142       top = monitor.rcWork.top;
143     }
144     else if (monitor.rcWork.bottom < top + (int)height)
145       top = monitor.rcWork.bottom - height;
146     else if (top < monitor.rcWork.top)
147       top = monitor.rcWork.top;
148
149     int wintype = WS_OVERLAPPEDWINDOW;
150     if (m_parentWindowHwnd != 0) {
151       wintype = WS_CHILD;
152       GetWindowRect((HWND)m_parentWindowHwnd, &rect);
153       left = 0;
154       top = 0;
155       width = rect.right - rect.left;
156       height = rect.bottom - rect.top;
157     }
158
159     wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
160     m_hWnd = ::CreateWindowW(s_windowClassName,         // pointer to registered class name
161                              title_16,                  // pointer to window name
162                              wintype,                   // window style
163                              left,                      // horizontal position of window
164                              top,                       // vertical position of window
165                              width,                     // window width
166                              height,                    // window height
167                              (HWND)m_parentWindowHwnd,  // handle to parent or owner window
168                              0,                     // handle to menu or child-window identifier
169                              ::GetModuleHandle(0),  // handle to application instance
170                              0);                    // pointer to window-creation data
171     free(title_16);
172   }
173   else {
174     wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
175     m_hWnd = ::CreateWindowW(s_windowClassName,     // pointer to registered class name
176                              title_16,              // pointer to window name
177                              WS_MAXIMIZE,           // window style
178                              left,                  // horizontal position of window
179                              top,                   // vertical position of window
180                              width,                 // window width
181                              height,                // window height
182                              HWND_DESKTOP,          // handle to parent or owner window
183                              0,                     // handle to menu or child-window identifier
184                              ::GetModuleHandle(0),  // handle to application instance
185                              0);                    // pointer to window-creation data
186     free(title_16);
187   }
188
189   m_user32 = ::LoadLibrary("user32.dll");
190
191   if (m_hWnd) {
192     if (m_user32) {
193       // Touch enabled screens with pen support by default have gestures
194       // enabled, which results in a delay between the pointer down event
195       // and the first move when using the stylus. RegisterTouchWindow
196       // disables the new gesture architecture enabling the events to be
197       // sent immediately to the application rather than being absorbed by
198       // the gesture API.
199       GHOST_WIN32_RegisterTouchWindow pRegisterTouchWindow = (GHOST_WIN32_RegisterTouchWindow)
200           GetProcAddress(m_user32, "RegisterTouchWindow");
201       if (pRegisterTouchWindow) {
202         pRegisterTouchWindow(m_hWnd, 0);
203       }
204     }
205
206     // Register this window as a droptarget. Requires m_hWnd to be valid.
207     // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
208     m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
209     if (m_dropTarget) {
210       ::RegisterDragDrop(m_hWnd, m_dropTarget);
211     }
212
213     // Store a pointer to this class in the window structure
214     ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
215
216     if (!m_system->m_windowFocus) {
217       // Lower to bottom and don't activate if we don't want focus
218       ::SetWindowPos(m_hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
219     }
220
221     // Store the device context
222     m_hDC = ::GetDC(m_hWnd);
223
224     GHOST_TSuccess success = setDrawingContextType(type);
225
226     if (success) {
227       // Show the window
228       int nCmdShow;
229       switch (state) {
230         case GHOST_kWindowStateMaximized:
231           nCmdShow = SW_SHOWMAXIMIZED;
232           break;
233         case GHOST_kWindowStateMinimized:
234           nCmdShow = (m_system->m_windowFocus) ? SW_SHOWMINIMIZED : SW_SHOWMINNOACTIVE;
235           break;
236         case GHOST_kWindowStateNormal:
237         default:
238           nCmdShow = (m_system->m_windowFocus) ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
239           break;
240       }
241
242       ::ShowWindow(m_hWnd, nCmdShow);
243 #ifdef WIN32_COMPOSITING
244       if (alphaBackground && parentwindowhwnd == 0) {
245
246         HRESULT hr = S_OK;
247
248         // Create and populate the Blur Behind structure
249         DWM_BLURBEHIND bb = {0};
250
251         // Enable Blur Behind and apply to the entire client area
252         bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
253         bb.fEnable = true;
254         bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
255
256         // Apply Blur Behind
257         hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
258         DeleteObject(bb.hRgnBlur);
259       }
260 #endif
261       // Force an initial paint of the window
262       ::UpdateWindow(m_hWnd);
263     }
264     else {
265       //invalidate the window
266       ::DestroyWindow(m_hWnd);
267       m_hWnd = NULL;
268     }
269   }
270
271   if (parentwindowhwnd != 0) {
272     RAWINPUTDEVICE device = {0};
273     device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/
274     device.usUsage = 0x06;     /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
275     device.dwFlags |=
276         RIDEV_INPUTSINK;  // makes WM_INPUT is visible for ghost when has parent window
277     device.hwndTarget = m_hWnd;
278     RegisterRawInputDevices(&device, 1, sizeof(device));
279   }
280
281   // Initialize Windows Ink
282   if (m_user32) {
283     m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo)::GetProcAddress(m_user32, "GetPointerInfo");
284     m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo)::GetProcAddress(m_user32,
285                                                                             "GetPointerPenInfo");
286     m_fpGetPointerTouchInfo = (GHOST_WIN32_GetPointerTouchInfo)::GetProcAddress(
287         m_user32, "GetPointerTouchInfo");
288   }
289
290   // Initialize Wintab
291   m_wintab.handle = ::LoadLibrary("Wintab32.dll");
292   if (m_wintab.handle) {
293     // Get API functions
294     m_wintab.info = (GHOST_WIN32_WTInfo)::GetProcAddress(m_wintab.handle, "WTInfoA");
295     m_wintab.open = (GHOST_WIN32_WTOpen)::GetProcAddress(m_wintab.handle, "WTOpenA");
296     m_wintab.close = (GHOST_WIN32_WTClose)::GetProcAddress(m_wintab.handle, "WTClose");
297     m_wintab.packet = (GHOST_WIN32_WTPacket)::GetProcAddress(m_wintab.handle, "WTPacket");
298     m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable");
299     m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap");
300
301     // Let's see if we can initialize tablet here.
302     // Check if WinTab available by getting system context info.
303     LOGCONTEXT lc = {0};
304     lc.lcOptions |= CXO_SYSTEM;
305     if (m_wintab.open && m_wintab.info && m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) {
306       // Now init the tablet
307       /* The maximum tablet size, pressure and orientation (tilt) */
308       AXIS TabletX, TabletY, Pressure, Orientation[3];
309
310       // Open a Wintab context
311
312       // Open the context
313       lc.lcPktData = PACKETDATA;
314       lc.lcPktMode = PACKETMODE;
315       lc.lcOptions |= CXO_MESSAGES;
316       lc.lcMoveMask = PACKETDATA;
317
318       /* Set the entire tablet as active */
319       m_wintab.info(WTI_DEVICES, DVC_X, &TabletX);
320       m_wintab.info(WTI_DEVICES, DVC_Y, &TabletY);
321
322       /* get the max pressure, to divide into a float */
323       BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
324       if (pressureSupport)
325         m_wintab.maxPressure = Pressure.axMax;
326       else
327         m_wintab.maxPressure = 0;
328
329       /* get the max tilt axes, to divide into floats */
330       BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
331       if (tiltSupport) {
332         /* does the tablet support azimuth ([0]) and altitude ([1]) */
333         if (Orientation[0].axResolution && Orientation[1].axResolution) {
334           /* all this assumes the minimum is 0 */
335           m_wintab.maxAzimuth = Orientation[0].axMax;
336           m_wintab.maxAltitude = Orientation[1].axMax;
337         }
338         else { /* no so dont do tilt stuff */
339           m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
340         }
341       }
342
343       // The Wintab spec says we must open the context disabled if we are using cursor masks.
344       m_wintab.tablet = m_wintab.open(m_hWnd, &lc, FALSE);
345       if (m_wintab.enable && m_wintab.tablet) {
346         m_wintab.enable(m_wintab.tablet, TRUE);
347       }
348     }
349   }
350   CoCreateInstance(
351       CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
352 }
353
354 GHOST_WindowWin32::~GHOST_WindowWin32()
355 {
356   if (m_Bar) {
357     m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
358     m_Bar->Release();
359     m_Bar = NULL;
360   }
361
362   if (m_wintab.handle) {
363     if (m_wintab.close && m_wintab.tablet) {
364       m_wintab.close(m_wintab.tablet);
365     }
366
367     FreeLibrary(m_wintab.handle);
368     memset(&m_wintab, 0, sizeof(m_wintab));
369   }
370
371   if (m_user32) {
372     FreeLibrary(m_user32);
373     m_user32 = NULL;
374     m_fpGetPointerInfo = NULL;
375     m_fpGetPointerPenInfo = NULL;
376     m_fpGetPointerTouchInfo = NULL;
377   }
378
379   if (m_customCursor) {
380     DestroyCursor(m_customCursor);
381     m_customCursor = NULL;
382   }
383
384   if (m_hWnd != NULL && m_hDC != NULL && releaseNativeHandles()) {
385     ::ReleaseDC(m_hWnd, m_hDC);
386     m_hDC = NULL;
387   }
388
389   if (m_hWnd) {
390     if (m_dropTarget) {
391       // Disable DragDrop
392       RevokeDragDrop(m_hWnd);
393       // Release our reference of the DropTarget and it will delete itself eventually.
394       m_dropTarget->Release();
395       m_dropTarget = NULL;
396     }
397     ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, NULL);
398     ::DestroyWindow(m_hWnd);
399     m_hWnd = 0;
400   }
401 }
402
403 bool GHOST_WindowWin32::getValid() const
404 {
405   return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0;
406 }
407
408 HWND GHOST_WindowWin32::getHWND() const
409 {
410   return m_hWnd;
411 }
412
413 void GHOST_WindowWin32::setTitle(const STR_String &title)
414 {
415   wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
416   ::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
417   free(title_16);
418 }
419
420 void GHOST_WindowWin32::getTitle(STR_String &title) const
421 {
422   char buf[s_maxTitleLength]; /*CHANGE + never used yet*/
423   ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
424   STR_String temp(buf);
425   title = buf;
426 }
427
428 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect &bounds) const
429 {
430   RECT rect;
431   ::GetWindowRect(m_hWnd, &rect);
432   bounds.m_b = rect.bottom;
433   bounds.m_l = rect.left;
434   bounds.m_r = rect.right;
435   bounds.m_t = rect.top;
436 }
437
438 void GHOST_WindowWin32::getClientBounds(GHOST_Rect &bounds) const
439 {
440   RECT rect;
441   POINT coord;
442   if (!IsIconic(m_hWnd)) {
443     ::GetClientRect(m_hWnd, &rect);
444
445     coord.x = rect.left;
446     coord.y = rect.top;
447     ::ClientToScreen(m_hWnd, &coord);
448
449     bounds.m_l = coord.x;
450     bounds.m_t = coord.y;
451
452     coord.x = rect.right;
453     coord.y = rect.bottom;
454     ::ClientToScreen(m_hWnd, &coord);
455
456     bounds.m_r = coord.x;
457     bounds.m_b = coord.y;
458   }
459   else {
460     bounds.m_b = 0;
461     bounds.m_l = 0;
462     bounds.m_r = 0;
463     bounds.m_t = 0;
464   }
465 }
466
467 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
468 {
469   GHOST_TSuccess success;
470   GHOST_Rect cBnds, wBnds;
471   getClientBounds(cBnds);
472   if (cBnds.getWidth() != (GHOST_TInt32)width) {
473     getWindowBounds(wBnds);
474     int cx = wBnds.getWidth() + width - cBnds.getWidth();
475     int cy = wBnds.getHeight();
476     success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
477                   GHOST_kSuccess :
478                   GHOST_kFailure;
479   }
480   else {
481     success = GHOST_kSuccess;
482   }
483   return success;
484 }
485
486 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
487 {
488   GHOST_TSuccess success;
489   GHOST_Rect cBnds, wBnds;
490   getClientBounds(cBnds);
491   if (cBnds.getHeight() != (GHOST_TInt32)height) {
492     getWindowBounds(wBnds);
493     int cx = wBnds.getWidth();
494     int cy = wBnds.getHeight() + height - cBnds.getHeight();
495     success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
496                   GHOST_kSuccess :
497                   GHOST_kFailure;
498   }
499   else {
500     success = GHOST_kSuccess;
501   }
502   return success;
503 }
504
505 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
506 {
507   GHOST_TSuccess success;
508   GHOST_Rect cBnds, wBnds;
509   getClientBounds(cBnds);
510   if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) {
511     getWindowBounds(wBnds);
512     int cx = wBnds.getWidth() + width - cBnds.getWidth();
513     int cy = wBnds.getHeight() + height - cBnds.getHeight();
514     success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
515                   GHOST_kSuccess :
516                   GHOST_kFailure;
517   }
518   else {
519     success = GHOST_kSuccess;
520   }
521   return success;
522 }
523
524 GHOST_TWindowState GHOST_WindowWin32::getState() const
525 {
526   GHOST_TWindowState state;
527
528   // XXX 27.04.2011
529   // we need to find a way to combine parented windows + resizing if we simply set the
530   // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
531   // It's also strange that in Windows is the only platform we need to make this separation.
532   if (m_parentWindowHwnd != 0) {
533     state = GHOST_kWindowStateEmbedded;
534     return state;
535   }
536
537   if (::IsIconic(m_hWnd)) {
538     state = GHOST_kWindowStateMinimized;
539   }
540   else if (::IsZoomed(m_hWnd)) {
541     LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
542     if ((result & (WS_DLGFRAME | WS_MAXIMIZE)) == (WS_DLGFRAME | WS_MAXIMIZE))
543       state = GHOST_kWindowStateMaximized;
544     else
545       state = GHOST_kWindowStateFullScreen;
546   }
547   else {
548     state = GHOST_kWindowStateNormal;
549   }
550   return state;
551 }
552
553 void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX,
554                                        GHOST_TInt32 inY,
555                                        GHOST_TInt32 &outX,
556                                        GHOST_TInt32 &outY) const
557 {
558   POINT point = {inX, inY};
559   ::ScreenToClient(m_hWnd, &point);
560   outX = point.x;
561   outY = point.y;
562 }
563
564 void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX,
565                                        GHOST_TInt32 inY,
566                                        GHOST_TInt32 &outX,
567                                        GHOST_TInt32 &outY) const
568 {
569   POINT point = {inX, inY};
570   ::ClientToScreen(m_hWnd, &point);
571   outX = point.x;
572   outY = point.y;
573 }
574
575 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
576 {
577   GHOST_TWindowState curstate = getState();
578   WINDOWPLACEMENT wp;
579   wp.length = sizeof(WINDOWPLACEMENT);
580   ::GetWindowPlacement(m_hWnd, &wp);
581
582   if (state == GHOST_kWindowStateNormal)
583     state = m_normal_state;
584
585   switch (state) {
586     case GHOST_kWindowStateMinimized:
587       wp.showCmd = SW_SHOWMINIMIZED;
588       break;
589     case GHOST_kWindowStateMaximized:
590       wp.showCmd = SW_SHOWMAXIMIZED;
591       ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
592       break;
593     case GHOST_kWindowStateFullScreen:
594       if (curstate != state && curstate != GHOST_kWindowStateMinimized)
595         m_normal_state = curstate;
596       wp.showCmd = SW_SHOWMAXIMIZED;
597       wp.ptMaxPosition.x = 0;
598       wp.ptMaxPosition.y = 0;
599       ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_MAXIMIZE);
600       break;
601     case GHOST_kWindowStateEmbedded:
602       ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
603       break;
604     case GHOST_kWindowStateNormal:
605     default:
606       wp.showCmd = SW_SHOWNORMAL;
607       ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
608       break;
609   }
610   /* Clears window cache for SetWindowLongPtr */
611   ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
612
613   return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
614 }
615
616 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
617 {
618   HWND hWndInsertAfter, hWndToRaise;
619
620   if (order == GHOST_kWindowOrderBottom) {
621     hWndInsertAfter = HWND_BOTTOM;
622     hWndToRaise = ::GetWindow(m_hWnd, GW_HWNDNEXT); /* the window to raise */
623   }
624   else {
625     hWndInsertAfter = HWND_TOP;
626     hWndToRaise = NULL;
627   }
628
629   if (::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
630     return GHOST_kFailure;
631   }
632
633   if (hWndToRaise &&
634       ::SetWindowPos(hWndToRaise, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
635     return GHOST_kFailure;
636   }
637   return GHOST_kSuccess;
638 }
639
640 GHOST_TSuccess GHOST_WindowWin32::invalidate()
641 {
642   GHOST_TSuccess success;
643   if (m_hWnd) {
644     success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
645   }
646   else {
647     success = GHOST_kFailure;
648   }
649   return success;
650 }
651
652 GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type)
653 {
654   if (type == GHOST_kDrawingContextTypeOpenGL) {
655     GHOST_Context *context;
656
657 #if defined(WITH_GL_PROFILE_CORE)
658     /* - AMD and Intel give us exactly this version
659      * - NVIDIA gives at least this version <-- desired behavior
660      * So we ask for 4.5, 4.4 ... 3.3 in descending order to get the best version on the user's system. */
661     for (int minor = 5; minor >= 0; --minor) {
662       context = new GHOST_ContextWGL(m_wantStereoVisual,
663                                      m_wantAlphaBackground,
664                                      m_wantNumOfAASamples,
665                                      m_hWnd,
666                                      m_hDC,
667                                      WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
668                                      4,
669                                      minor,
670                                      (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
671                                      GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
672
673       if (context->initializeDrawingContext()) {
674         return context;
675       }
676       else {
677         delete context;
678       }
679     }
680     context = new GHOST_ContextWGL(m_wantStereoVisual,
681                                    m_wantAlphaBackground,
682                                    m_wantNumOfAASamples,
683                                    m_hWnd,
684                                    m_hDC,
685                                    WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
686                                    3,
687                                    3,
688                                    (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
689                                    GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
690
691     if (context->initializeDrawingContext()) {
692       return context;
693     }
694     else {
695       MessageBox(m_hWnd,
696                  "A graphics card and driver with support for OpenGL 3.3 or higher is required.\n"
697                  "Installing the latest driver for your graphics card may resolve the issue.\n\n"
698                  "The program will now close.",
699                  "Blender - Unsupported Graphics Card or Driver",
700                  MB_OK | MB_ICONERROR);
701       delete context;
702       exit(0);
703     }
704
705 #elif defined(WITH_GL_PROFILE_COMPAT)
706     // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile)
707     // 2.1 ignores the profile bit & is incompatible with core profile
708     context = new GHOST_ContextWGL(m_wantStereoVisual,
709                                    m_wantAlphaBackground,
710                                    m_wantNumOfAASamples,
711                                    m_hWnd,
712                                    m_hDC,
713                                    0,  // no profile bit
714                                    2,
715                                    1,
716                                    (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
717                                    GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
718
719     if (context->initializeDrawingContext()) {
720       return context;
721     }
722     else {
723       delete context;
724     }
725 #else
726 #  error  // must specify either core or compat at build time
727 #endif
728   }
729
730   return NULL;
731 }
732
733 void GHOST_WindowWin32::lostMouseCapture()
734 {
735   if (m_hasMouseCaptured) {
736     m_hasGrabMouse = false;
737     m_nPressedButtons = 0;
738     m_hasMouseCaptured = false;
739   }
740 }
741
742 void GHOST_WindowWin32::registerMouseClickEvent(int press)
743 {
744
745   switch (press) {
746     case 0:
747       m_nPressedButtons++;
748       break;
749     case 1:
750       if (m_nPressedButtons)
751         m_nPressedButtons--;
752       break;
753     case 2:
754       m_hasGrabMouse = true;
755       break;
756     case 3:
757       m_hasGrabMouse = false;
758       break;
759   }
760
761   if (!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured) {
762     ::ReleaseCapture();
763     m_hasMouseCaptured = false;
764   }
765   else if ((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured) {
766     ::SetCapture(m_hWnd);
767     m_hasMouseCaptured = true;
768   }
769 }
770
771 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
772 {
773   if (!visible) {
774     while (::ShowCursor(FALSE) >= 0)
775       ;
776   }
777   else {
778     while (::ShowCursor(TRUE) < 0)
779       ;
780   }
781
782   if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
783     ::SetCursor(m_customCursor);
784   }
785   else {
786     // Convert GHOST cursor to Windows OEM cursor
787     bool success = true;
788     LPCSTR id;
789     switch (cursor) {
790       case GHOST_kStandardCursorDefault:
791         id = IDC_ARROW;
792         break;
793       case GHOST_kStandardCursorRightArrow:
794         id = IDC_ARROW;
795         break;
796       case GHOST_kStandardCursorLeftArrow:
797         id = IDC_ARROW;
798         break;
799       case GHOST_kStandardCursorInfo:
800         id = IDC_SIZEALL;
801         break;  // Four-pointed arrow pointing north, south, east, and west
802       case GHOST_kStandardCursorDestroy:
803         id = IDC_NO;
804         break;  // Slashed circle
805       case GHOST_kStandardCursorHelp:
806         id = IDC_HELP;
807         break;  // Arrow and question mark
808       case GHOST_kStandardCursorCycle:
809         id = IDC_NO;
810         break;  // Slashed circle
811       case GHOST_kStandardCursorSpray:
812         id = IDC_SIZEALL;
813         break;  // Four-pointed arrow pointing north, south, east, and west
814       case GHOST_kStandardCursorWait:
815         id = IDC_WAIT;
816         break;  // Hourglass
817       case GHOST_kStandardCursorText:
818         id = IDC_IBEAM;
819         break;  // I-beam
820       case GHOST_kStandardCursorCrosshair:
821         id = IDC_CROSS;
822         break;  // Crosshair
823       case GHOST_kStandardCursorUpDown:
824         id = IDC_SIZENS;
825         break;  // Double-pointed arrow pointing north and south
826       case GHOST_kStandardCursorLeftRight:
827         id = IDC_SIZEWE;
828         break;  // Double-pointed arrow pointing west and east
829       case GHOST_kStandardCursorTopSide:
830         id = IDC_UPARROW;
831         break;  // Vertical arrow
832       case GHOST_kStandardCursorBottomSide:
833         id = IDC_SIZENS;
834         break;
835       case GHOST_kStandardCursorLeftSide:
836         id = IDC_SIZEWE;
837         break;
838       case GHOST_kStandardCursorTopLeftCorner:
839         id = IDC_SIZENWSE;
840         break;
841       case GHOST_kStandardCursorTopRightCorner:
842         id = IDC_SIZENESW;
843         break;
844       case GHOST_kStandardCursorBottomRightCorner:
845         id = IDC_SIZENWSE;
846         break;
847       case GHOST_kStandardCursorBottomLeftCorner:
848         id = IDC_SIZENESW;
849         break;
850       case GHOST_kStandardCursorPencil:
851         id = IDC_ARROW;
852         break;
853       case GHOST_kStandardCursorCopy:
854         id = IDC_ARROW;
855         break;
856       default:
857         success = false;
858     }
859
860     if (success) {
861       ::SetCursor(::LoadCursor(0, id));
862     }
863   }
864 }
865
866 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
867 {
868   if (::GetForegroundWindow() == m_hWnd) {
869     loadCursor(visible, getCursorShape());
870   }
871
872   return GHOST_kSuccess;
873 }
874
875 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
876 {
877   if (mode != GHOST_kGrabDisable) {
878     if (mode != GHOST_kGrabNormal) {
879       m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
880       setCursorGrabAccum(0, 0);
881
882       if (mode == GHOST_kGrabHide)
883         setWindowCursorVisibility(false);
884     }
885     registerMouseClickEvent(2);
886   }
887   else {
888     if (m_cursorGrab == GHOST_kGrabHide) {
889       m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
890       setWindowCursorVisibility(true);
891     }
892     if (m_cursorGrab != GHOST_kGrabNormal) {
893       /* use to generate a mouse move event, otherwise the last event
894        * blender gets can be outside the screen causing menus not to show
895        * properly unless the user moves the mouse */
896       GHOST_TInt32 pos[2];
897       m_system->getCursorPosition(pos[0], pos[1]);
898       m_system->setCursorPosition(pos[0], pos[1]);
899     }
900
901     /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
902     setCursorGrabAccum(0, 0);
903     m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
904     registerMouseClickEvent(3);
905   }
906
907   return GHOST_kSuccess;
908 }
909
910 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
911 {
912   if (m_customCursor) {
913     DestroyCursor(m_customCursor);
914     m_customCursor = NULL;
915   }
916
917   if (::GetForegroundWindow() == m_hWnd) {
918     loadCursor(getCursorVisibility(), cursorShape);
919   }
920
921   return GHOST_kSuccess;
922 }
923
924 GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo,
925                                                  WPARAM wParam,
926                                                  LPARAM lParam)
927 {
928   ZeroMemory(pointerInfo, sizeof(GHOST_PointerInfoWin32));
929
930   // Obtain the basic information from the event
931   pointerInfo->pointerId = GET_POINTERID_WPARAM(wParam);
932   pointerInfo->isInContact = IS_POINTER_INCONTACT_WPARAM(wParam);
933   pointerInfo->isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
934
935   // Obtain more accurate and predicted information from the Pointer API
936   POINTER_INFO pointerApiInfo;
937   if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) {
938     return GHOST_kFailure;
939   }
940
941   pointerInfo->hasButtonMask = GHOST_kSuccess;
942   switch (pointerApiInfo.ButtonChangeType) {
943     case POINTER_CHANGE_FIRSTBUTTON_DOWN:
944     case POINTER_CHANGE_FIRSTBUTTON_UP:
945       pointerInfo->buttonMask = GHOST_kButtonMaskLeft;
946       break;
947     case POINTER_CHANGE_SECONDBUTTON_DOWN:
948     case POINTER_CHANGE_SECONDBUTTON_UP:
949       pointerInfo->buttonMask = GHOST_kButtonMaskRight;
950       break;
951     case POINTER_CHANGE_THIRDBUTTON_DOWN:
952     case POINTER_CHANGE_THIRDBUTTON_UP:
953       pointerInfo->buttonMask = GHOST_kButtonMaskMiddle;
954       break;
955     case POINTER_CHANGE_FOURTHBUTTON_DOWN:
956     case POINTER_CHANGE_FOURTHBUTTON_UP:
957       pointerInfo->buttonMask = GHOST_kButtonMaskButton4;
958       break;
959     case POINTER_CHANGE_FIFTHBUTTON_DOWN:
960     case POINTER_CHANGE_FIFTHBUTTON_UP:
961       pointerInfo->buttonMask = GHOST_kButtonMaskButton5;
962       break;
963     default:
964       pointerInfo->hasButtonMask = GHOST_kFailure;
965       break;
966   }
967
968   pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation;
969   pointerInfo->tabletData.Active = GHOST_kTabletModeNone;
970   pointerInfo->tabletData.Pressure = 1.0f;
971   pointerInfo->tabletData.Xtilt = 0.0f;
972   pointerInfo->tabletData.Ytilt = 0.0f;
973
974   if (pointerApiInfo.pointerType != PT_PEN) {
975     return GHOST_kFailure;
976   }
977
978   POINTER_PEN_INFO pointerPenInfo;
979   if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) {
980     pointerInfo->tabletData.Active = GHOST_kTabletModeStylus;
981
982     if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) {
983       pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f;
984     }
985
986     if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) {
987       pointerInfo->tabletData.Active = GHOST_kTabletModeEraser;
988     }
989
990     if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) {
991       pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f);
992     }
993
994     if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) {
995       pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f);
996     }
997   }
998
999   return GHOST_kSuccess;
1000 }
1001
1002 void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
1003 {
1004   if (pTabletData) {
1005     m_tabletData = *pTabletData;
1006   }
1007   else {
1008     m_tabletData.Active = GHOST_kTabletModeNone;
1009     m_tabletData.Pressure = 1.0f;
1010     m_tabletData.Xtilt = 0.0f;
1011     m_tabletData.Ytilt = 0.0f;
1012   }
1013 }
1014
1015 void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state)
1016 {
1017   if (!useTabletAPI(GHOST_kTabletWintab)) {
1018     return;
1019   }
1020
1021   if (m_wintab.enable && m_wintab.tablet) {
1022     m_wintab.enable(m_wintab.tablet, state);
1023
1024     if (m_wintab.overlap && state) {
1025       m_wintab.overlap(m_wintab.tablet, TRUE);
1026     }
1027   }
1028 }
1029
1030 bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const
1031 {
1032   if (m_system->getTabletAPI() == api) {
1033     return true;
1034   }
1035   else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
1036     if (m_wintab.tablet)
1037       return api == GHOST_kTabletWintab;
1038     else
1039       return api == GHOST_kTabletNative;
1040   }
1041   else {
1042     return false;
1043   }
1044 }
1045
1046 void GHOST_WindowWin32::processWin32TabletInitEvent()
1047 {
1048   if (!useTabletAPI(GHOST_kTabletWintab)) {
1049     return;
1050   }
1051
1052   // Let's see if we can initialize tablet here
1053   if (m_wintab.info && m_wintab.tablet) {
1054     AXIS Pressure, Orientation[3]; /* The maximum tablet size */
1055
1056     BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
1057     if (pressureSupport)
1058       m_wintab.maxPressure = Pressure.axMax;
1059     else
1060       m_wintab.maxPressure = 0;
1061
1062     BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
1063     if (tiltSupport) {
1064       /* does the tablet support azimuth ([0]) and altitude ([1]) */
1065       if (Orientation[0].axResolution && Orientation[1].axResolution) {
1066         m_wintab.maxAzimuth = Orientation[0].axMax;
1067         m_wintab.maxAltitude = Orientation[1].axMax;
1068       }
1069       else { /* no so dont do tilt stuff */
1070         m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
1071       }
1072     }
1073
1074     m_tabletData.Active = GHOST_kTabletModeNone;
1075   }
1076
1077   m_tabletData.Active = GHOST_kTabletModeNone;
1078 }
1079
1080 void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
1081 {
1082   if (!useTabletAPI(GHOST_kTabletWintab)) {
1083     return;
1084   }
1085
1086   if (m_wintab.packet && m_wintab.tablet) {
1087     PACKET pkt;
1088     if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) {
1089       switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
1090         case 0:
1091           m_tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
1092           break;
1093         case 1:
1094           m_tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
1095           break;
1096         case 2:
1097           m_tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
1098           break;
1099       }
1100
1101       if (m_wintab.maxPressure > 0) {
1102         m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
1103       }
1104       else {
1105         m_tabletData.Pressure = 1.0f;
1106       }
1107
1108       if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
1109         ORIENTATION ort = pkt.pkOrientation;
1110         float vecLen;
1111         float altRad, azmRad; /* in radians */
1112
1113         /*
1114          * from the wintab spec:
1115          * orAzimuth    Specifies the clockwise rotation of the
1116          * cursor about the z axis through a full circular range.
1117          *
1118          * orAltitude   Specifies the angle with the x-y plane
1119          * through a signed, semicircular range.  Positive values
1120          * specify an angle upward toward the positive z axis;
1121          * negative values specify an angle downward toward the negative z axis.
1122          *
1123          * wintab.h defines .orAltitude as a UINT but documents .orAltitude
1124          * as positive for upward angles and negative for downward angles.
1125          * WACOM uses negative altitude values to show that the pen is inverted;
1126          * therefore we cast .orAltitude as an (int) and then use the absolute value.
1127          */
1128
1129         /* convert raw fixed point data to radians */
1130         altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0);
1131         azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0);
1132
1133         /* find length of the stylus' projected vector on the XY plane */
1134         vecLen = cos(altRad);
1135
1136         /* from there calculate X and Y components based on azimuth */
1137         m_tabletData.Xtilt = sin(azmRad) * vecLen;
1138         m_tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
1139       }
1140       else {
1141         m_tabletData.Xtilt = 0.0f;
1142         m_tabletData.Ytilt = 0.0f;
1143       }
1144     }
1145   }
1146 }
1147
1148 void GHOST_WindowWin32::bringTabletContextToFront()
1149 {
1150   if (!useTabletAPI(GHOST_kTabletWintab)) {
1151     return;
1152   }
1153
1154   if (m_wintab.overlap && m_wintab.tablet) {
1155     m_wintab.overlap(m_wintab.tablet, TRUE);
1156   }
1157 }
1158
1159 GHOST_TUns16 GHOST_WindowWin32::getDPIHint()
1160 {
1161   if (m_user32) {
1162     GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow)::GetProcAddress(
1163         m_user32, "GetDpiForWindow");
1164
1165     if (fpGetDpiForWindow) {
1166       return fpGetDpiForWindow(this->m_hWnd);
1167     }
1168   }
1169
1170   return USER_DEFAULT_SCREEN_DPI;
1171 }
1172
1173 /** Reverse the bits in a GHOST_TUns8 */
1174 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
1175 {
1176   ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1177   ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1178   ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1179   return ch;
1180 }
1181
1182 #if 0 /* UNUSED */
1183 /** Reverse the bits in a GHOST_TUns16 */
1184 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
1185 {
1186   shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1187   shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1188   shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1189   shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1190   return shrt;
1191 }
1192 #endif
1193 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
1194                                                              GHOST_TUns8 mask[16][2],
1195                                                              int hotX,
1196                                                              int hotY)
1197 {
1198   return setWindowCustomCursorShape(
1199       (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotX, hotY, 0, 1);
1200 }
1201
1202 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
1203                                                              GHOST_TUns8 *mask,
1204                                                              int sizeX,
1205                                                              int sizeY,
1206                                                              int hotX,
1207                                                              int hotY,
1208                                                              int fg_color,
1209                                                              int bg_color)
1210 {
1211   GHOST_TUns32 andData[32];
1212   GHOST_TUns32 xorData[32];
1213   GHOST_TUns32 fullBitRow, fullMaskRow;
1214   int x, y, cols;
1215
1216   cols = sizeX / 8; /* Num of whole bytes per row (width of bm/mask) */
1217   if (sizeX % 8)
1218     cols++;
1219
1220   if (m_customCursor) {
1221     DestroyCursor(m_customCursor);
1222     m_customCursor = NULL;
1223   }
1224
1225   memset(&andData, 0xFF, sizeof(andData));
1226   memset(&xorData, 0, sizeof(xorData));
1227
1228   for (y = 0; y < sizeY; y++) {
1229     fullBitRow = 0;
1230     fullMaskRow = 0;
1231     for (x = cols - 1; x >= 0; x--) {
1232       fullBitRow <<= 8;
1233       fullMaskRow <<= 8;
1234       fullBitRow |= uns8ReverseBits(bitmap[cols * y + x]);
1235       fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1236     }
1237     xorData[y] = fullBitRow & fullMaskRow;
1238     andData[y] = ~fullMaskRow;
1239   }
1240
1241   m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1242   if (!m_customCursor) {
1243     return GHOST_kFailure;
1244   }
1245
1246   if (::GetForegroundWindow() == m_hWnd) {
1247     loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
1248   }
1249
1250   return GHOST_kSuccess;
1251 }
1252
1253 GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
1254 {
1255   /*SetProgressValue sets state to TBPF_NORMAL automaticly*/
1256   if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000))
1257     return GHOST_kSuccess;
1258
1259   return GHOST_kFailure;
1260 }
1261
1262 GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
1263 {
1264   if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS))
1265     return GHOST_kSuccess;
1266
1267   return GHOST_kFailure;
1268 }
1269
1270 #ifdef WITH_INPUT_IME
1271 void GHOST_WindowWin32::beginIME(
1272     GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 w, GHOST_TInt32 h, int completed)
1273 {
1274   m_imeInput.BeginIME(m_hWnd, GHOST_Rect(x, y - h, x, y), (bool)completed);
1275 }
1276
1277 void GHOST_WindowWin32::endIME()
1278 {
1279   m_imeInput.EndIME(m_hWnd);
1280 }
1281 #endif /* WITH_INPUT_IME */