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