Fix #32046: GHOST_DropTargetWin32 memory leak, patch by Matt D.
[blender.git] / intern / ghost / intern / GHOST_WindowWin32.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file ghost/intern/GHOST_WindowWin32.cpp
29  *  \ingroup GHOST
30  */
31
32
33 /**
34  * Copyright (C) 2001 NaN Technologies B.V.
35  * @author      Maarten Gribnau
36  * @date        May 10, 2001
37  */
38
39 #include <string.h>
40 #include "GHOST_WindowWin32.h"
41 #include "GHOST_SystemWin32.h"
42 #include "GHOST_DropTargetWin32.h"
43 #include "utfconv.h"
44 #include "utf_winfunc.h"
45
46 // Need glew for some defines
47 #include <GL/glew.h>
48 #include <GL/wglew.h>
49 #include <math.h>
50
51 // MSVC6 still doesn't define M_PI
52 #ifndef M_PI
53 #define M_PI 3.1415926536
54 #endif
55
56 // Some more multisample defines
57 #define WGL_SAMPLE_BUFFERS_ARB  0x2041
58 #define WGL_SAMPLES_ARB         0x2042
59
60 // win64 doesn't define GWL_USERDATA
61 #ifdef WIN32
62 #ifndef GWL_USERDATA
63 #define GWL_USERDATA GWLP_USERDATA
64 #define GWL_WNDPROC GWLP_WNDPROC
65 #endif
66 #endif
67
68 wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
69 const int GHOST_WindowWin32::s_maxTitleLength = 128;
70 HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL;
71 HDC GHOST_WindowWin32::s_firstHDC = NULL;
72
73 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd);
74 static int EnumPixelFormats(HDC hdc);
75
76 /*
77  * Color and depth bit values are not to be trusted.
78  * For instance, on TNT2:
79  * When the screen color depth is set to 16 bit, we get 5 color bits
80  * and 16 depth bits.
81  * When the screen color depth is set to 32 bit, we get 8 color bits
82  * and 24 depth bits.
83  * Just to be safe, we request high waulity settings.
84  */
85 static PIXELFORMATDESCRIPTOR sPreferredFormat = {
86         sizeof(PIXELFORMATDESCRIPTOR),  /* size */
87         1,                              /* version */
88         PFD_SUPPORT_OPENGL |
89         PFD_DRAW_TO_WINDOW |
90         PFD_SWAP_COPY |                 /* support swap copy */
91         PFD_DOUBLEBUFFER,               /* support double-buffering */
92         PFD_TYPE_RGBA,                  /* color type */
93         32,                             /* prefered color depth */
94         0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
95         0,                              /* no alpha buffer */
96         0,                              /* alpha bits (ignored) */
97         0,                              /* no accumulation buffer */
98         0, 0, 0, 0,                     /* accum bits (ignored) */
99         32,                             /* depth buffer */
100         0,                              /* no stencil buffer */
101         0,                              /* no auxiliary buffers */
102         PFD_MAIN_PLANE,                 /* main layer */
103         0,                              /* reserved */
104         0, 0, 0                         /* no layer, visible, damage masks */
105 };
106
107 /* Intel videocards don't work fine with multiple contexts and
108  * have to share the same context for all windows.
109  * But if we just share context for all windows it could work incorrect
110  * with multiple videocards configuration. Suppose, that Intel videocards
111  * can't be in multiple-devices configuration. */
112 static int is_crappy_intel_card(void)
113 {
114         int crappy = 0;
115         const char *vendor = (const char *)glGetString(GL_VENDOR);
116
117         if (strstr(vendor, "Intel"))
118                 crappy = 1;
119
120         return crappy;
121 }
122
123 GHOST_WindowWin32::GHOST_WindowWin32(
124     GHOST_SystemWin32 *system,
125     const STR_String& title,
126     GHOST_TInt32 left,
127     GHOST_TInt32 top,
128     GHOST_TUns32 width,
129     GHOST_TUns32 height,
130     GHOST_TWindowState state,
131     GHOST_TDrawingContextType type,
132     const bool stereoVisual,
133     const GHOST_TUns16 numOfAASamples,
134     GHOST_TEmbedderWindowID parentwindowhwnd,
135     GHOST_TSuccess msEnabled,
136     int msPixelFormat)
137         :
138         GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone,
139                      stereoVisual, numOfAASamples),
140         m_system(system),
141         m_hDC(0),
142         m_hGlRc(0),
143         m_hasMouseCaptured(false),
144         m_hasGrabMouse(false),
145         m_nPressedButtons(0),
146         m_customCursor(0),
147         m_wintab(NULL),
148         m_tabletData(NULL),
149         m_tablet(0),
150         m_maxPressure(0),
151         m_multisample(numOfAASamples),
152         m_parentWindowHwnd(parentwindowhwnd),
153         m_multisampleEnabled(msEnabled),
154         m_msPixelFormat(msPixelFormat),
155         //For recreation
156         m_title(title),
157         m_left(left),
158         m_top(top),
159         m_width(width),
160         m_height(height),
161         m_normal_state(GHOST_kWindowStateNormal),
162         m_stereo(stereoVisual),
163         m_nextWindow(NULL)
164 {
165         OSVERSIONINFOEX versionInfo;
166         bool hasMinVersionForTaskbar = false;
167         
168         ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
169         
170         versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
171         
172         if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
173                 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
174                 if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
175                         if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || versionInfo.dwMajorVersion >= 7) {
176                                 hasMinVersionForTaskbar = true;
177                         }
178                 }
179         }
180         else {
181                 if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || versionInfo.dwMajorVersion >= 7) {
182                         hasMinVersionForTaskbar = true;
183                 }
184         }
185
186         if (state != GHOST_kWindowStateFullScreen) {
187                 RECT rect;
188                 MONITORINFO monitor;
189                 GHOST_TUns32 tw, th; 
190
191                 width += GetSystemMetrics(SM_CXSIZEFRAME) * 2;
192                 height += GetSystemMetrics(SM_CYSIZEFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);
193
194                 rect.left = left;
195                 rect.right = left + width;
196                 rect.top = top;
197                 rect.bottom = top + height;
198
199                 monitor.cbSize = sizeof(monitor);
200                 monitor.dwFlags = 0;
201
202                 // take taskbar into account
203                 GetMonitorInfo(MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST), &monitor);
204
205                 th = monitor.rcWork.bottom - monitor.rcWork.top;
206                 tw = monitor.rcWork.right - monitor.rcWork.left;
207
208                 if (tw < width)
209                 {
210                         width = tw;
211                         left = monitor.rcWork.left;
212                 }
213                 else if (monitor.rcWork.right < left + (int)width)
214                         left = monitor.rcWork.right - width;
215                 else if (left < monitor.rcWork.left)
216                         left = monitor.rcWork.left;
217
218                 if (th < height)
219                 {
220                         height = th;
221                         top = monitor.rcWork.top;
222                 }
223                 else if (monitor.rcWork.bottom < top + (int)height)
224                         top = monitor.rcWork.bottom - height;
225                 else if (top < monitor.rcWork.top)
226                         top = monitor.rcWork.top;
227
228                 int wintype = WS_OVERLAPPEDWINDOW;
229                 if (m_parentWindowHwnd != 0)
230                 {
231                         wintype = WS_CHILD;
232                         GetWindowRect((HWND)m_parentWindowHwnd, &rect);
233                         left = 0;
234                         top = 0;
235                         width = rect.right - rect.left;
236                         height = rect.bottom - rect.top;
237                 }
238                 
239                 wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
240                 m_hWnd = ::CreateWindowW(
241                     s_windowClassName,          // pointer to registered class name
242                     title_16,                   // pointer to window name
243                     wintype,                    // window style
244                     left,                       // horizontal position of window
245                     top,                        // vertical position of window
246                     width,                      // window width
247                     height,                     // window height
248                     (HWND) m_parentWindowHwnd,  // handle to parent or owner window
249                     0,                          // handle to menu or child-window identifier
250                     ::GetModuleHandle(0),       // handle to application instance
251                     0);                         // pointer to window-creation data
252                 free(title_16);
253         }
254         else {
255                 wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
256                 m_hWnd = ::CreateWindowW(
257                     s_windowClassName,          // pointer to registered class name
258                     title_16,                   // pointer to window name
259                     WS_POPUP | WS_MAXIMIZE,     // window style
260                     left,                       // horizontal position of window
261                     top,                        // vertical position of window
262                     width,                      // window width
263                     height,                     // window height
264                     HWND_DESKTOP,               // handle to parent or owner window
265                     0,                          // handle to menu or child-window identifier
266                     ::GetModuleHandle(0),       // handle to application instance
267                     0);                         // pointer to window-creation data
268                 free(title_16);
269         }
270         if (m_hWnd) {
271                 // Register this window as a droptarget. Requires m_hWnd to be valid.
272                 // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
273                 m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
274                 if (m_dropTarget) {
275                         ::RegisterDragDrop(m_hWnd, m_dropTarget);
276                 }
277
278                 // Store a pointer to this class in the window structure
279                 ::SetWindowLongPtr(m_hWnd, GWL_USERDATA, (LONG_PTR) this);
280
281                 // Store the device context
282                 m_hDC = ::GetDC(m_hWnd);
283
284                 if (!s_firstHDC) {
285                         s_firstHDC = m_hDC;
286                 }
287
288                 // Show the window
289                 int nCmdShow;
290                 switch (state) {
291                         case GHOST_kWindowStateMaximized:
292                                 nCmdShow = SW_SHOWMAXIMIZED;
293                                 break;
294                         case GHOST_kWindowStateMinimized:
295                                 nCmdShow = SW_SHOWMINIMIZED;
296                                 break;
297                         case GHOST_kWindowStateNormal:
298                         default:
299                                 nCmdShow = SW_SHOWNORMAL;
300                                 break;
301                 }
302                 GHOST_TSuccess success;
303                 success = setDrawingContextType(type);
304
305                 if (success)
306                 {
307                         ::ShowWindow(m_hWnd, nCmdShow);
308                         // Force an initial paint of the window
309                         ::UpdateWindow(m_hWnd);
310                 }
311                 else {
312                         //invalidate the window
313                         m_hWnd = 0;
314                 }
315         }
316
317         if (parentwindowhwnd != 0) {
318                 RAWINPUTDEVICE device = {0};
319                 device.usUsagePage  = 0x01; /* usUsagePage & usUsage for keyboard*/
320                 device.usUsage      = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
321                 device.dwFlags |= RIDEV_INPUTSINK; // makes WM_INPUT is visible for ghost when has parent window
322                 device.hwndTarget = m_hWnd;
323                 RegisterRawInputDevices(&device, 1, sizeof(device));
324         }
325
326         m_wintab = ::LoadLibrary("Wintab32.dll");
327         if (m_wintab) {
328                 GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
329                 GHOST_WIN32_WTOpen fpWTOpen = (GHOST_WIN32_WTOpen) ::GetProcAddress(m_wintab, "WTOpenA");
330
331                 // let's see if we can initialize tablet here
332                 /* check if WinTab available. */
333                 if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
334                         // Now init the tablet
335                         LOGCONTEXT lc;
336                         AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
337
338                         // Open a Wintab context
339
340                         // Get default context information
341                         fpWTInfo(WTI_DEFCONTEXT, 0, &lc);
342
343                         // Open the context
344                         lc.lcPktData = PACKETDATA;
345                         lc.lcPktMode = PACKETMODE;
346                         lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
347
348                         /* Set the entire tablet as active */
349                         fpWTInfo(WTI_DEVICES, DVC_X, &TabletX);
350                         fpWTInfo(WTI_DEVICES, DVC_Y, &TabletY);
351
352                         /* get the max pressure, to divide into a float */
353                         BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
354                         if (pressureSupport)
355                                 m_maxPressure = Pressure.axMax;
356                         else
357                                 m_maxPressure = 0;
358
359                         /* get the max tilt axes, to divide into floats */
360                         BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
361                         if (tiltSupport) {
362                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
363                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
364                                         /* all this assumes the minimum is 0 */
365                                         m_maxAzimuth = Orientation[0].axMax;
366                                         m_maxAltitude = Orientation[1].axMax;
367                                 }
368                                 else {  /* no so dont do tilt stuff */
369                                         m_maxAzimuth = m_maxAltitude = 0;
370                                 }
371                         }
372
373                         if (fpWTOpen) {
374                                 m_tablet = fpWTOpen(m_hWnd, &lc, TRUE);
375                                 if (m_tablet) {
376                                         m_tabletData = new GHOST_TabletData();
377                                         m_tabletData->Active = GHOST_kTabletModeNone;
378                                 }
379                         }
380                 }
381         }
382
383         if (hasMinVersionForTaskbar)
384                 CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar);
385         else
386                 m_Bar = NULL;
387 }
388
389
390 GHOST_WindowWin32::~GHOST_WindowWin32()
391 {
392         if (m_Bar)
393         {
394                 m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
395                 m_Bar->Release();
396         };
397
398         if (m_wintab) {
399                 GHOST_WIN32_WTClose fpWTClose = (GHOST_WIN32_WTClose) ::GetProcAddress(m_wintab, "WTClose");
400                 if (fpWTClose) {
401                         if (m_tablet)
402                                 fpWTClose(m_tablet);
403                         if (m_tabletData)
404                                 delete m_tabletData;
405                         m_tabletData = NULL;
406                 }
407         }
408         if (m_customCursor) {
409                 DestroyCursor(m_customCursor);
410                 m_customCursor = NULL;
411         }
412
413         ::wglMakeCurrent(NULL, NULL);
414         m_multisampleEnabled = GHOST_kFailure;
415         m_multisample = 0;
416         setDrawingContextType(GHOST_kDrawingContextTypeNone);
417         if (m_hDC && m_hDC != s_firstHDC) {
418                 ::ReleaseDC(m_hWnd, m_hDC);
419                 m_hDC = 0;
420         }
421         if (m_hWnd) {
422                 if (m_dropTarget) {
423                         // Disable DragDrop
424                         RevokeDragDrop(m_hWnd);
425                         // Release our reference of the DropTarget and it will delete itself eventually.
426                         m_dropTarget->Release();
427                 }
428
429                 ::DestroyWindow(m_hWnd);
430                 m_hWnd = 0;
431         }
432 }
433
434 GHOST_Window *GHOST_WindowWin32::getNextWindow()
435 {
436         return m_nextWindow;
437 }
438
439 bool GHOST_WindowWin32::getValid() const
440 {
441         return m_hWnd != 0;
442 }
443
444 HWND GHOST_WindowWin32::getHWND() const
445 {
446         return m_hWnd;
447 }
448
449 void GHOST_WindowWin32::setTitle(const STR_String& title)
450 {
451         wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
452         ::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
453         free(title_16);
454 }
455
456
457 void GHOST_WindowWin32::getTitle(STR_String& title) const
458 {
459         char buf[s_maxTitleLength]; /*CHANGE + never used yet*/
460         ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
461         STR_String temp(buf);
462         title = buf;
463 }
464
465
466 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
467 {
468         RECT rect;
469         ::GetWindowRect(m_hWnd, &rect);
470         bounds.m_b = rect.bottom;
471         bounds.m_l = rect.left;
472         bounds.m_r = rect.right;
473         bounds.m_t = rect.top;
474 }
475
476
477 void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
478 {
479         RECT rect;
480         GHOST_TWindowState state = this->getState();
481         LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
482         int sm_cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
483         ::GetWindowRect(m_hWnd, &rect);
484
485         if ((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) {
486                 if (state == GHOST_kWindowStateMaximized) {
487                         // in maximized state we don't have borders on the window
488                         bounds.m_b = rect.bottom - GetSystemMetrics(SM_CYCAPTION) - sm_cysizeframe * 2;
489                         bounds.m_l = rect.left + sm_cysizeframe;
490                         bounds.m_r = rect.right - sm_cysizeframe;
491                         bounds.m_t = rect.top;
492                 }
493                 else if (state == GHOST_kWindowStateEmbedded) {
494                         bounds.m_b = rect.bottom;
495                         bounds.m_l = rect.left;
496                         bounds.m_r = rect.right;
497                         bounds.m_t = rect.top;
498                 }
499                 else {
500                         bounds.m_b = rect.bottom - GetSystemMetrics(SM_CYCAPTION) - sm_cysizeframe * 2;
501                         bounds.m_l = rect.left;
502                         bounds.m_r = rect.right - sm_cysizeframe * 2;
503                         bounds.m_t = rect.top;
504                 }
505         }
506         else {
507                 bounds.m_b = rect.bottom;
508                 bounds.m_l = rect.left;
509                 bounds.m_r = rect.right;
510                 bounds.m_t = rect.top;
511         }
512 }
513
514
515 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
516 {
517         GHOST_TSuccess success;
518         GHOST_Rect cBnds, wBnds;
519         getClientBounds(cBnds);
520         if (cBnds.getWidth() != (GHOST_TInt32)width) {
521                 getWindowBounds(wBnds);
522                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
523                 int cy = wBnds.getHeight();
524                 success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
525                           GHOST_kSuccess : GHOST_kFailure;
526         }
527         else {
528                 success = GHOST_kSuccess;
529         }
530         return success;
531 }
532
533
534 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
535 {
536         GHOST_TSuccess success;
537         GHOST_Rect cBnds, wBnds;
538         getClientBounds(cBnds);
539         if (cBnds.getHeight() != (GHOST_TInt32)height) {
540                 getWindowBounds(wBnds);
541                 int cx = wBnds.getWidth();
542                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
543                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
544                           GHOST_kSuccess : GHOST_kFailure;
545         }
546         else {
547                 success = GHOST_kSuccess;
548         }
549         return success;
550 }
551
552
553 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
554 {
555         GHOST_TSuccess success;
556         GHOST_Rect cBnds, wBnds;
557         getClientBounds(cBnds);
558         if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) {
559                 getWindowBounds(wBnds);
560                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
561                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
562                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
563                           GHOST_kSuccess : GHOST_kFailure;
564         }
565         else {
566                 success = GHOST_kSuccess;
567         }
568         return success;
569 }
570
571
572 GHOST_TWindowState GHOST_WindowWin32::getState() const
573 {
574         GHOST_TWindowState state;
575
576         // XXX 27.04.2011
577         // we need to find a way to combine parented windows + resizing if we simply set the
578         // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
579         // It's also strange that in Windows is the only platform we need to make this separation.
580         if (m_parentWindowHwnd != 0) {
581                 state = GHOST_kWindowStateEmbedded;
582                 return state;
583         }
584         if (::IsIconic(m_hWnd)) {
585                 state = GHOST_kWindowStateMinimized;
586         }
587         else if (::IsZoomed(m_hWnd)) {
588                 LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
589                 if ((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE))
590                         state = GHOST_kWindowStateMaximized;
591                 else
592                         state = GHOST_kWindowStateFullScreen;
593         }
594         else {
595                 state = GHOST_kWindowStateNormal;
596         }
597         return state;
598 }
599
600
601 void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
602 {
603         POINT point = { inX, inY };
604         ::ScreenToClient(m_hWnd, &point);
605         outX = point.x;
606         outY = point.y;
607 }
608
609
610 void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
611 {
612         POINT point = { inX, inY };
613         ::ClientToScreen(m_hWnd, &point);
614         outX = point.x;
615         outY = point.y;
616 }
617
618
619 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
620 {
621         GHOST_TWindowState curstate = getState();
622         WINDOWPLACEMENT wp;
623         wp.length = sizeof(WINDOWPLACEMENT);
624         ::GetWindowPlacement(m_hWnd, &wp);
625
626         if (state == GHOST_kWindowStateNormal)
627                 state = m_normal_state;
628         switch (state) {
629                 case GHOST_kWindowStateMinimized:
630                         wp.showCmd = SW_SHOWMINIMIZED;
631                         break;
632                 case GHOST_kWindowStateMaximized:
633                         wp.showCmd = SW_SHOWMAXIMIZED;
634                         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
635                         break;
636                 case GHOST_kWindowStateFullScreen:
637                         if (curstate != state && curstate != GHOST_kWindowStateMinimized)
638                                 m_normal_state = curstate;
639                         wp.showCmd = SW_SHOWMAXIMIZED;
640                         wp.ptMaxPosition.x = 0;
641                         wp.ptMaxPosition.y = 0;
642                         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
643                         break;
644                 case GHOST_kWindowStateEmbedded:
645                         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
646                         break;
647                 case GHOST_kWindowStateNormal:
648                 default:
649                         wp.showCmd = SW_SHOWNORMAL;
650                         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
651                         break;
652         }
653         SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); /*Clears window cache for SetWindowLongPtr */
654         return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
655 }
656
657
658 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
659 {
660         HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
661         return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
662 }
663
664
665 GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
666 {
667         HDC hDC = m_hDC;
668
669         if (is_crappy_intel_card())
670                 hDC = ::wglGetCurrentDC();
671
672         return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
673 }
674
675
676 GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
677 {
678         GHOST_TSuccess success;
679         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
680                 if (m_hDC && m_hGlRc) {
681                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
682                 }
683                 else {
684                         success = GHOST_kFailure;
685                 }
686         }
687         else {
688                 success = GHOST_kSuccess;
689         }
690         return success;
691 }
692
693
694 GHOST_TSuccess GHOST_WindowWin32::invalidate()
695 {
696         GHOST_TSuccess success;
697         if (m_hWnd) {
698                 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
699         }
700         else {
701                 success = GHOST_kFailure;
702         }
703         return success;
704 }
705
706 GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd)
707 {
708         int pixelFormat;
709         bool success = FALSE;
710         UINT numFormats;
711         HDC hDC = GetDC(getHWND());
712         float fAttributes[] = {0, 0};
713         UINT nMaxFormats = 1;
714
715         // The attributes to look for
716         int iAttributes[] = {
717                 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
718                 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
719                 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
720                 WGL_COLOR_BITS_ARB, pfd.cColorBits,
721                 WGL_DEPTH_BITS_ARB, pfd.cDepthBits,
722                 WGL_STENCIL_BITS_ARB, pfd.cStencilBits,
723                 WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
724                 WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
725                 WGL_SAMPLES_ARB, m_multisample,
726                 0, 0
727         };
728
729         // Get the function
730         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");  
731
732         if (!wglChoosePixelFormatARB)
733         {
734                 m_multisampleEnabled = GHOST_kFailure;
735                 return GHOST_kFailure;
736         }
737
738         // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it.
739         while (iAttributes[17] > 0) {
740                 // See if the format is valid
741                 success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats);
742                 GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats);
743
744                 if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) {
745                         GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]);
746                         m_multisampleEnabled = GHOST_kSuccess;
747                         m_msPixelFormat = pixelFormat;
748                 }
749                 iAttributes[17] -= 1;
750                 success = GHOST_kFailure;
751         }
752         if (m_multisampleEnabled == GHOST_kSuccess) {
753                 return GHOST_kSuccess;
754         }
755         GHOST_PRINT("no available pixel format\n");
756         return GHOST_kFailure;
757 }
758
759 GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
760 {
761         GHOST_TSuccess success;
762         switch (type) {
763                 case GHOST_kDrawingContextTypeOpenGL:
764                 {
765                         // If this window has multisample enabled, use the supplied format
766                         if (m_multisampleEnabled)
767                         {
768                                 if (SetPixelFormat(m_hDC, m_msPixelFormat, &sPreferredFormat) == FALSE)
769                                 {
770                                         success = GHOST_kFailure;
771                                         break;
772                                 }
773
774                                 // Create the context
775                                 m_hGlRc = ::wglCreateContext(m_hDC);
776                                 if (m_hGlRc) {
777                                         if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
778                                                 if (s_firsthGLRc) {
779                                                         if (is_crappy_intel_card()) {
780                                                                 if (::wglMakeCurrent(NULL, NULL) == TRUE) {
781                                                                         ::wglDeleteContext(m_hGlRc);
782                                                                         m_hGlRc = s_firsthGLRc;
783                                                                 }
784                                                                 else {
785                                                                         ::wglDeleteContext(m_hGlRc);
786                                                                         m_hGlRc = NULL;
787                                                                 }
788                                                         }
789                                                         else {
790                                                                 ::wglCopyContext(s_firsthGLRc, m_hGlRc, GL_ALL_ATTRIB_BITS);
791                                                                 ::wglShareLists(s_firsthGLRc, m_hGlRc);
792                                                         }
793                                                 }
794                                                 else {
795                                                         s_firsthGLRc = m_hGlRc;
796                                                 }
797
798                                                 if (m_hGlRc) {
799                                                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
800                                                 }
801                                                 else {
802                                                         success = GHOST_kFailure;
803                                                 }
804                                         }
805                                         else {
806                                                 success = GHOST_kFailure;
807                                         }
808                                 }
809                                 else {
810                                         success = GHOST_kFailure;
811                                 }
812
813                                 if (success == GHOST_kFailure) {
814                                         printf("Failed to get a context....\n");
815                                 }
816                         }
817                         else {
818                                 if (m_stereoVisual)
819                                         sPreferredFormat.dwFlags |= PFD_STEREO;
820
821                                 // Attempt to match device context pixel format to the preferred format
822                                 int iPixelFormat = EnumPixelFormats(m_hDC);
823                                 if (iPixelFormat == 0) {
824                                         success = GHOST_kFailure;
825                                         break;
826                                 }
827                                 if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
828                                         success = GHOST_kFailure;
829                                         break;
830                                 }
831                                 // For debugging only: retrieve the pixel format chosen
832                                 PIXELFORMATDESCRIPTOR preferredFormat;
833                                 ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
834
835                                 // Create the context
836                                 m_hGlRc = ::wglCreateContext(m_hDC);
837                                 if (m_hGlRc) {
838                                         if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
839                                                 if (s_firsthGLRc) {
840                                                         if (is_crappy_intel_card()) {
841                                                                 if (::wglMakeCurrent(NULL, NULL) == TRUE) {
842                                                                         ::wglDeleteContext(m_hGlRc);
843                                                                         m_hGlRc = s_firsthGLRc;
844                                                                 }
845                                                                 else {
846                                                                         ::wglDeleteContext(m_hGlRc);
847                                                                         m_hGlRc = NULL;
848                                                                 }
849                                                         }
850                                                         else {
851                                                                 ::wglShareLists(s_firsthGLRc, m_hGlRc);
852                                                         }
853                                                 }
854                                                 else {
855                                                         s_firsthGLRc = m_hGlRc;
856                                                 }
857
858                                                 if (m_hGlRc) {
859                                                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
860                                                 }
861                                                 else {
862                                                         success = GHOST_kFailure;
863                                                 }
864                                         }
865                                         else {
866                                                 success = GHOST_kFailure;
867                                         }
868                                 }
869                                 else {
870                                         success = GHOST_kFailure;
871                                 }
872                                         
873                                 if (success == GHOST_kFailure) {
874                                         printf("Failed to get a context....\n");
875                                 }
876
877                                 // Attempt to enable multisample
878                                 if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled)
879                                 {
880                                         success = initMultisample(preferredFormat);
881
882                                         if (success)
883                                         {
884
885                                                 // Make sure we don't screw up the context
886                                                 if (m_hGlRc == s_firsthGLRc)
887                                                         s_firsthGLRc = NULL;
888                                                 m_drawingContextType = GHOST_kDrawingContextTypeOpenGL;
889                                                 removeDrawingContext();
890
891                                                 // Create a new window
892                                                 GHOST_TWindowState new_state = getState();
893
894                                                 m_nextWindow = new GHOST_WindowWin32((GHOST_SystemWin32 *)GHOST_ISystem::getSystem(),
895                                                                                      m_title,
896                                                                                      m_left,
897                                                                                      m_top,
898                                                                                      m_width,
899                                                                                      m_height,
900                                                                                      new_state,
901                                                                                      type,
902                                                                                      m_stereo,
903                                                                                      m_multisample,
904                                                                                      m_parentWindowHwnd,
905                                                                                      m_multisampleEnabled,
906                                                                                      m_msPixelFormat);
907
908                                                 // Return failure so we can trash this window.
909                                                 success = GHOST_kFailure;
910                                                 break;
911                                         }
912                                         else {
913                                                 m_multisampleEnabled = GHOST_kSuccess;
914                                                 printf("Multisample failed to initialized\n");
915                                                 success = GHOST_kSuccess;
916                                         }
917                                 }
918                         }
919
920                 }
921                 break;
922
923                 case GHOST_kDrawingContextTypeNone:
924                         success = GHOST_kSuccess;
925                         break;
926
927                 default:
928                         success = GHOST_kFailure;
929         }
930         return success;
931 }
932
933 GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
934 {
935         GHOST_TSuccess success;
936         switch (m_drawingContextType) {
937                 case GHOST_kDrawingContextTypeOpenGL:
938                         // we shouldn't remove the drawing context if it's the first OpenGL context
939                         // If we do, we get corrupted drawing. See #19997
940                         if (m_hGlRc && m_hGlRc != s_firsthGLRc) {
941                                 success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
942                                 m_hGlRc = 0;
943                         }
944                         else {
945                                 success = GHOST_kFailure;
946                         }
947                         break;
948                 case GHOST_kDrawingContextTypeNone:
949                         success = GHOST_kSuccess;
950                         break;
951                 default:
952                         success = GHOST_kFailure;
953         }
954         return success;
955 }
956
957 void GHOST_WindowWin32::lostMouseCapture()
958 {
959         if (m_hasMouseCaptured)
960         {   m_hasGrabMouse = false;
961                 m_nPressedButtons = 0;
962                 m_hasMouseCaptured = false; };
963 }
964
965 void GHOST_WindowWin32::registerMouseClickEvent(int press)
966 {
967
968         switch (press)
969         {
970                 case 0: m_nPressedButtons++;    break;
971                 case 1: if (m_nPressedButtons) m_nPressedButtons--; break;
972                 case 2: m_hasGrabMouse = true;    break;
973                 case 3: m_hasGrabMouse = false;   break;
974         }
975
976         if (!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured)
977         {
978                 ::ReleaseCapture();
979                 m_hasMouseCaptured = false;
980         }
981         else if ((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured)
982         {
983                 ::SetCapture(m_hWnd);
984                 m_hasMouseCaptured = true;
985
986         }
987 }
988
989
990 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
991 {
992         if (!visible) {
993                 while (::ShowCursor(FALSE) >= 0) ;
994         }
995         else {
996                 while (::ShowCursor(TRUE) < 0) ;
997         }
998
999         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
1000                 ::SetCursor(m_customCursor);
1001         }
1002         else {
1003                 // Convert GHOST cursor to Windows OEM cursor
1004                 bool success = true;
1005                 LPCSTR id;
1006                 switch (cursor) {
1007                         case GHOST_kStandardCursorDefault:              id = IDC_ARROW;     break;
1008                         case GHOST_kStandardCursorRightArrow:           id = IDC_ARROW;     break;
1009                         case GHOST_kStandardCursorLeftArrow:            id = IDC_ARROW;     break;
1010                         case GHOST_kStandardCursorInfo:                 id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
1011                         case GHOST_kStandardCursorDestroy:              id = IDC_NO;        break;  // Slashed circle
1012                         case GHOST_kStandardCursorHelp:                 id = IDC_HELP;      break;  // Arrow and question mark
1013                         case GHOST_kStandardCursorCycle:                id = IDC_NO;        break;  // Slashed circle
1014                         case GHOST_kStandardCursorSpray:                id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
1015                         case GHOST_kStandardCursorWait:                 id = IDC_WAIT;      break;  // Hourglass
1016                         case GHOST_kStandardCursorText:                 id = IDC_IBEAM;     break;  // I-beam
1017                         case GHOST_kStandardCursorCrosshair:            id = IDC_CROSS;     break;  // Crosshair
1018                         case GHOST_kStandardCursorUpDown:               id = IDC_SIZENS;    break;  // Double-pointed arrow pointing north and south
1019                         case GHOST_kStandardCursorLeftRight:            id = IDC_SIZEWE;    break;  // Double-pointed arrow pointing west and east
1020                         case GHOST_kStandardCursorTopSide:              id = IDC_UPARROW;   break;  // Vertical arrow
1021                         case GHOST_kStandardCursorBottomSide:           id = IDC_SIZENS;    break;
1022                         case GHOST_kStandardCursorLeftSide:             id = IDC_SIZEWE;    break;
1023                         case GHOST_kStandardCursorTopLeftCorner:        id = IDC_SIZENWSE;  break;
1024                         case GHOST_kStandardCursorTopRightCorner:       id = IDC_SIZENESW;  break;
1025                         case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;  break;
1026                         case GHOST_kStandardCursorBottomLeftCorner:     id = IDC_SIZENESW;  break;
1027                         case GHOST_kStandardCursorPencil:               id = IDC_ARROW;     break;
1028                         case GHOST_kStandardCursorCopy:                 id = IDC_ARROW;     break;
1029                         default:
1030                                 success = false;
1031                 }
1032
1033                 if (success) {
1034                         ::SetCursor(::LoadCursor(0, id));
1035                 }
1036         }
1037 }
1038
1039 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
1040 {
1041         if (::GetForegroundWindow() == m_hWnd) {
1042                 loadCursor(visible, getCursorShape());
1043         }
1044
1045         return GHOST_kSuccess;
1046 }
1047
1048 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
1049 {
1050         if (mode != GHOST_kGrabDisable) {
1051                 if (mode != GHOST_kGrabNormal) {
1052                         m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
1053                         setCursorGrabAccum(0, 0);
1054
1055                         if (mode == GHOST_kGrabHide)
1056                                 setWindowCursorVisibility(false);
1057                 }
1058                 registerMouseClickEvent(2);
1059         }
1060         else {
1061                 if (m_cursorGrab == GHOST_kGrabHide) {
1062                         m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
1063                         setWindowCursorVisibility(true);
1064                 }
1065                 if (m_cursorGrab != GHOST_kGrabNormal) {
1066                         /* use to generate a mouse move event, otherwise the last event
1067                          * blender gets can be outside the screen causing menus not to show
1068                          * properly unless the user moves the mouse */
1069                         GHOST_TInt32 pos[2];
1070                         m_system->getCursorPosition(pos[0], pos[1]);
1071                         m_system->setCursorPosition(pos[0], pos[1]);
1072                 }
1073
1074                 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
1075                 setCursorGrabAccum(0, 0);
1076                 m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
1077                 registerMouseClickEvent(3);
1078         }
1079         
1080         return GHOST_kSuccess;
1081 }
1082
1083 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
1084 {
1085         if (m_customCursor) {
1086                 DestroyCursor(m_customCursor);
1087                 m_customCursor = NULL;
1088         }
1089
1090         if (::GetForegroundWindow() == m_hWnd) {
1091                 loadCursor(getCursorVisibility(), cursorShape);
1092         }
1093
1094         return GHOST_kSuccess;
1095 }
1096
1097 void GHOST_WindowWin32::processWin32TabletInitEvent()
1098 {
1099         if (m_wintab) {
1100                 GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
1101
1102                 // let's see if we can initialize tablet here
1103                 /* check if WinTab available. */
1104                 if (fpWTInfo) {
1105                         AXIS Pressure, Orientation[3]; /* The maximum tablet size */
1106
1107                         BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
1108                         if (pressureSupport)
1109                                 m_maxPressure = Pressure.axMax;
1110                         else
1111                                 m_maxPressure = 0;
1112
1113                         BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
1114                         if (tiltSupport) {
1115                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
1116                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
1117                                         m_maxAzimuth = Orientation[0].axMax;
1118                                         m_maxAltitude = Orientation[1].axMax;
1119                                 }
1120                                 else {  /* no so dont do tilt stuff */
1121                                         m_maxAzimuth = m_maxAltitude = 0;
1122                                 }
1123                         }
1124
1125                         m_tabletData->Active = GHOST_kTabletModeNone;
1126                 }
1127         }
1128 }
1129
1130 void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
1131 {
1132         PACKET pkt;
1133         if (m_wintab) {
1134                 GHOST_WIN32_WTPacket fpWTPacket = (GHOST_WIN32_WTPacket) ::GetProcAddress(m_wintab, "WTPacket");
1135                 if (fpWTPacket) {
1136                         if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
1137                                 if (m_tabletData) {
1138                                         switch (pkt.pkCursor) {
1139                                                 case 0: /* first device */
1140                                                 case 3: /* second device */
1141                                                         m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */
1142                                                         break;
1143                                                 case 1:
1144                                                 case 4:
1145                                                         m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */
1146                                                         break;
1147                                                 case 2:
1148                                                 case 5:
1149                                                         m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */
1150                                                         break;
1151                                         }
1152                                         if (m_maxPressure > 0) {
1153                                                 m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
1154                                         }
1155                                         else {
1156                                                 m_tabletData->Pressure = 1.0f;
1157                                         }
1158
1159                                         if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
1160                                                 ORIENTATION ort = pkt.pkOrientation;
1161                                                 float vecLen;
1162                                                 float altRad, azmRad;   /* in radians */
1163
1164                                                 /*
1165                                                  * from the wintab spec:
1166                                                  * orAzimuth    Specifies the clockwise rotation of the
1167                                                  * cursor about the z axis through a full circular range.
1168                                                  *
1169                                                  * orAltitude   Specifies the angle with the x-y plane
1170                                                  * through a signed, semicircular range.  Positive values
1171                                                  * specify an angle upward toward the positive z axis;
1172                                                  * negative values specify an angle downward toward the negative z axis.
1173                                                  *
1174                                                  * wintab.h defines .orAltitude as a UINT but documents .orAltitude
1175                                                  * as positive for upward angles and negative for downward angles.
1176                                                  * WACOM uses negative altitude values to show that the pen is inverted;
1177                                                  * therefore we cast .orAltitude as an (int) and then use the absolute value.
1178                                                  */
1179
1180                                                 /* convert raw fixed point data to radians */
1181                                                 altRad = (float)((fabs((float)ort.orAltitude) / (float)m_maxAltitude) * M_PI / 2.0);
1182                                                 azmRad = (float)(((float)ort.orAzimuth / (float)m_maxAzimuth) * M_PI * 2.0);
1183
1184                                                 /* find length of the stylus' projected vector on the XY plane */
1185                                                 vecLen = cos(altRad);
1186
1187                                                 /* from there calculate X and Y components based on azimuth */
1188                                                 m_tabletData->Xtilt = sin(azmRad) * vecLen;
1189                                                 m_tabletData->Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
1190
1191                                         }
1192                                         else {
1193                                                 m_tabletData->Xtilt = 0.0f;
1194                                                 m_tabletData->Ytilt = 0.0f;
1195                                         }
1196                                 }
1197                         }
1198                 }
1199         }
1200 }
1201
1202 /** Reverse the bits in a GHOST_TUns8 */
1203 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
1204 {
1205         ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1206         ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1207         ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1208         return ch;
1209 }
1210
1211 /** Reverse the bits in a GHOST_TUns16 */
1212 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
1213 {
1214         shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1215         shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1216         shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1217         shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1218         return shrt;
1219 }
1220 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
1221                                                              GHOST_TUns8 mask[16][2],
1222                                                              int hotX, int hotY)
1223 {
1224         return setWindowCustomCursorShape((GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask,
1225                                           16, 16, hotX, hotY, 0, 1);
1226 }
1227
1228 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
1229                                                              GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY,
1230                                                              int fg_color, int bg_color)
1231 {
1232         GHOST_TUns32 andData[32];
1233         GHOST_TUns32 xorData[32];
1234         GHOST_TUns32 fullBitRow, fullMaskRow;
1235         int x, y, cols;
1236
1237         cols = sizeX / 8; /* Num of whole bytes per row (width of bm/mask) */
1238         if (sizeX % 8) cols++;
1239
1240         if (m_customCursor) {
1241                 DestroyCursor(m_customCursor);
1242                 m_customCursor = NULL;
1243         }
1244
1245         memset(&andData, 0xFF, sizeof(andData));
1246         memset(&xorData, 0, sizeof(xorData));
1247
1248         for (y = 0; y < sizeY; y++) {
1249                 fullBitRow = 0;
1250                 fullMaskRow = 0;
1251                 for (x = cols - 1; x >= 0; x--) {
1252                         fullBitRow <<= 8;
1253                         fullMaskRow <<= 8;
1254                         fullBitRow  |= uns8ReverseBits(bitmap[cols * y + x]);
1255                         fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1256                 }
1257                 xorData[y] = fullBitRow & fullMaskRow;
1258                 andData[y] = ~fullMaskRow;
1259         }
1260
1261         m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1262         if (!m_customCursor) {
1263                 return GHOST_kFailure;
1264         }
1265
1266         if (::GetForegroundWindow() == m_hWnd) {
1267                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
1268         }
1269
1270         return GHOST_kSuccess;
1271 }
1272
1273
1274 GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
1275 {       
1276         /*SetProgressValue sets state to TBPF_NORMAL automaticly*/
1277         if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000))
1278                 return GHOST_kSuccess;
1279
1280         return GHOST_kFailure;
1281 }
1282
1283 GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
1284 {
1285         if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS))
1286                 return GHOST_kSuccess;
1287
1288         return GHOST_kFailure;
1289 }
1290
1291 /* Ron Fosner's code for weighting pixel formats and forcing software.
1292  * See http://www.opengl.org/resources/faq/technical/weight.cpp */
1293
1294 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd)
1295 {
1296         int weight = 0;
1297
1298         /* assume desktop color depth is 32 bits per pixel */
1299
1300         /* cull unusable pixel formats */
1301         /* if no formats can be found, can we determine why it was rejected? */
1302         if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
1303             !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
1304             !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
1305             (pfd.cDepthBits <= 8) ||
1306             !(pfd.iPixelType == PFD_TYPE_RGBA))
1307         {
1308                 return 0;
1309         }
1310
1311         weight = 1;  /* it's usable */
1312
1313         /* the bigger the depth buffer the better */
1314         /* give no weight to a 16-bit depth buffer, because those are crap */
1315         weight += pfd.cDepthBits - 16;
1316
1317         weight += pfd.cColorBits - 8;
1318
1319         /* want swap copy capability -- it matters a lot */
1320         if (pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
1321
1322         /* but if it's a generic (not accelerated) view, it's really bad */
1323         if (pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
1324
1325         return weight;
1326 }
1327
1328 /* A modification of Ron Fosner's replacement for ChoosePixelFormat */
1329 /* returns 0 on error, else returns the pixel format number to be used */
1330 static int EnumPixelFormats(HDC hdc)
1331 {
1332         int iPixelFormat;
1333         int i, n, w, weight = 0;
1334         PIXELFORMATDESCRIPTOR pfd;
1335
1336         /* we need a device context to do anything */
1337         if (!hdc) return 0;
1338
1339         iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
1340
1341         /* obtain detailed information about
1342          * the device context's first pixel format */
1343         n = 1 + ::DescribePixelFormat(hdc, iPixelFormat,
1344                                       sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1345
1346         /* choose a pixel format using the useless Windows function in case
1347          * we come up empty handed */
1348         iPixelFormat = ::ChoosePixelFormat(hdc, &sPreferredFormat);
1349
1350         if (!iPixelFormat) return 0;  /* couldn't find one to use */
1351
1352         for (i = 1; i <= n; i++) { /* not the idiom, but it's right */
1353                 ::DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1354                 w = WeightPixelFormat(pfd);
1355                 // be strict on stereo
1356                 if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO)) {
1357                         if (w > weight) {
1358                                 weight = w;
1359                                 iPixelFormat = i;
1360                         }
1361                 }
1362         }
1363         if (weight == 0) {
1364                 // we could find the correct stereo setting, just find any suitable format
1365                 for (i = 1; i <= n; i++) { /* not the idiom, but it's right */
1366                         ::DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1367                         w = WeightPixelFormat(pfd);
1368                         if (w > weight) {
1369                                 weight = w;
1370                                 iPixelFormat = i;
1371                         }
1372                 }
1373         }
1374         return iPixelFormat;
1375 }
1376
1377