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