a89b2608bb45c1136ab323dc79037d584d532a69
[blender-staging.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         m_wintab = ::LoadLibrary("Wintab32.dll");
311         if (m_wintab) {
312                 GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
313                 GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
314
315                 // let's see if we can initialize tablet here
316                 /* check if WinTab available. */
317                 if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
318                         // Now init the tablet
319                         LOGCONTEXT lc;
320                         AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
321
322                         // Open a Wintab context
323
324                         // Get default context information
325                         fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
326
327                         // Open the context
328                         lc.lcPktData = PACKETDATA;
329                         lc.lcPktMode = PACKETMODE;
330                         lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
331
332                         /* Set the entire tablet as active */
333                         fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
334                         fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
335
336                         /* get the max pressure, to divide into a float */
337                         BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
338                         if (pressureSupport)
339                                 m_maxPressure = Pressure.axMax;
340                         else
341                                 m_maxPressure = 0;
342
343                         /* get the max tilt axes, to divide into floats */
344                         BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
345                         if (tiltSupport) {
346                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
347                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
348                                         /* all this assumes the minimum is 0 */
349                                         m_maxAzimuth = Orientation[0].axMax;
350                                         m_maxAltitude = Orientation[1].axMax;
351                                 }
352                                 else {  /* no so dont do tilt stuff */
353                                         m_maxAzimuth = m_maxAltitude = 0;
354                                 }
355                         }
356
357                         if (fpWTOpen) {
358                                 m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
359                                 if (m_tablet) {
360                                         m_tabletData = new GHOST_TabletData();
361                                         m_tabletData->Active = GHOST_kTabletModeNone;
362                                 }
363                         }
364                 }
365         }
366
367         if(hasMinVersionForTaskbar)
368                 CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList ,(LPVOID*)&m_Bar);
369         else
370                 m_Bar=NULL;
371 }
372
373
374 GHOST_WindowWin32::~GHOST_WindowWin32()
375 {
376         if(m_Bar)
377         {
378                 m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
379                 m_Bar->Release();
380         };
381
382         if (m_wintab) {
383                 GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
384                 if (fpWTClose) {
385                         if (m_tablet)
386                                 fpWTClose(m_tablet);
387                         if (m_tabletData)
388                                 delete m_tabletData;
389                                 m_tabletData = NULL;
390                 }
391         }
392         if (m_customCursor) {
393                 DestroyCursor(m_customCursor);
394                 m_customCursor = NULL;
395         }
396
397         ::wglMakeCurrent(NULL, NULL);
398         m_multisampleEnabled = GHOST_kFailure;
399         m_multisample = 0;
400         setDrawingContextType(GHOST_kDrawingContextTypeNone);
401         if (m_hDC && m_hDC != s_firstHDC) {
402                 ::ReleaseDC(m_hWnd, m_hDC);
403                 m_hDC = 0;
404         }
405         if (m_hWnd) {
406                 m_dropTarget->Release(); // frees itself.
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         ::SetWindowText(m_hWnd, title);
430 }
431
432
433 void GHOST_WindowWin32::getTitle(STR_String& title) const
434 {
435         char buf[s_maxTitleLength];
436         ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
437         STR_String temp (buf);
438         title = buf;
439 }
440
441
442 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
443 {
444         RECT rect;
445         ::GetWindowRect(m_hWnd, &rect);
446         bounds.m_b = rect.bottom;
447         bounds.m_l = rect.left;
448         bounds.m_r = rect.right;
449         bounds.m_t = rect.top;
450 }
451
452
453 void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
454 {
455         RECT rect;
456         GHOST_TWindowState state= this->getState();
457         LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
458         int sm_cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
459         ::GetWindowRect(m_hWnd, &rect);
460
461         if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) {
462                 if(state==GHOST_kWindowStateMaximized) {
463                         // in maximized state we don't have borders on the window
464                         bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)- sm_cysizeframe*2;
465                         bounds.m_l = rect.left + sm_cysizeframe;
466                         bounds.m_r = rect.right - sm_cysizeframe;
467                         bounds.m_t = rect.top;
468                 } else if (state == GHOST_kWindowStateEmbedded) {
469                         bounds.m_b = rect.bottom;
470                         bounds.m_l = rect.left;
471                         bounds.m_r = rect.right;
472                         bounds.m_t = rect.top;
473                 } else {
474                         bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)-sm_cysizeframe*2;
475                         bounds.m_l = rect.left;
476                         bounds.m_r = rect.right-sm_cysizeframe*2;
477                         bounds.m_t = rect.top;
478                 }
479         } else {
480                 bounds.m_b = rect.bottom;
481                 bounds.m_l = rect.left;
482                 bounds.m_r = rect.right;
483                 bounds.m_t = rect.top;
484         }
485 }
486
487
488 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
489 {
490         GHOST_TSuccess success;
491         GHOST_Rect cBnds, wBnds;
492         getClientBounds(cBnds);
493         if (cBnds.getWidth() != (GHOST_TInt32)width) {
494                 getWindowBounds(wBnds);
495                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
496                 int cy = wBnds.getHeight();
497                 success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
498                         GHOST_kSuccess : GHOST_kFailure;
499         }
500         else {
501                 success = GHOST_kSuccess;
502         }
503         return success;
504 }
505
506
507 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
508 {
509         GHOST_TSuccess success;
510         GHOST_Rect cBnds, wBnds;
511         getClientBounds(cBnds);
512         if (cBnds.getHeight() != (GHOST_TInt32)height) {
513                 getWindowBounds(wBnds);
514                 int cx = wBnds.getWidth();
515                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
516                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
517                         GHOST_kSuccess : GHOST_kFailure;
518         }
519         else {
520                 success = GHOST_kSuccess;
521         }
522         return success;
523 }
524
525
526 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
527 {
528         GHOST_TSuccess success;
529         GHOST_Rect cBnds, wBnds;
530         getClientBounds(cBnds);
531         if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) {
532                 getWindowBounds(wBnds);
533                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
534                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
535                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
536                         GHOST_kSuccess : GHOST_kFailure;
537         }
538         else {
539                 success = GHOST_kSuccess;
540         }
541         return success;
542 }
543
544
545 GHOST_TWindowState GHOST_WindowWin32::getState() const
546 {
547         GHOST_TWindowState state;
548
549         // XXX 27.04.2011
550         // we need to find a way to combine parented windows + resizing if we simply set the
551         // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
552         // It's also strange that in Windows is the only platform we need to make this separation.
553         if (m_parentWindowHwnd != 0) {
554                 state = GHOST_kWindowStateEmbedded;
555                 return state;
556         }
557         if (::IsIconic(m_hWnd)) {
558                 state = GHOST_kWindowStateMinimized;
559         }
560         else if (::IsZoomed(m_hWnd)) {
561                 LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
562                 if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE))
563                         state = GHOST_kWindowStateMaximized;
564                 else
565                         state = GHOST_kWindowStateFullScreen;
566         }
567         else {
568                 state = GHOST_kWindowStateNormal;
569         }
570         return state;
571 }
572
573
574 void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
575 {
576         POINT point = { inX, inY };
577         ::ScreenToClient(m_hWnd, &point);
578         outX = point.x;
579         outY = point.y;
580 }
581
582
583 void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
584 {
585         POINT point = { inX, inY };
586         ::ClientToScreen(m_hWnd, &point);
587         outX = point.x;
588         outY = point.y;
589 }
590
591
592 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
593 {
594         GHOST_TWindowState curstate = getState();
595         WINDOWPLACEMENT wp;
596         wp.length = sizeof(WINDOWPLACEMENT);
597         ::GetWindowPlacement(m_hWnd, &wp);
598
599         if (state == GHOST_kWindowStateNormal)
600                 state = m_normal_state;
601         switch (state) {
602         case GHOST_kWindowStateMinimized:
603                 wp.showCmd = SW_SHOWMINIMIZED;
604                 break;
605         case GHOST_kWindowStateMaximized:
606                 ShowWindow(m_hWnd, SW_HIDE);
607                 wp.showCmd = SW_SHOWMAXIMIZED;
608                 SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
609                 break;
610         case GHOST_kWindowStateFullScreen:
611                 if (curstate != state && curstate != GHOST_kWindowStateMinimized)
612                         m_normal_state = curstate;
613                 wp.showCmd = SW_SHOWMAXIMIZED;
614                 wp.ptMaxPosition.x = 0;
615                 wp.ptMaxPosition.y = 0;
616                 SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
617                 break;
618         case GHOST_kWindowStateEmbedded:
619                 SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
620                 break;
621         case GHOST_kWindowStateNormal:
622         default:
623                 ShowWindow(m_hWnd, SW_HIDE);
624                 wp.showCmd = SW_SHOWNORMAL;
625                 SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
626                 break;
627         }
628         return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
629 }
630
631
632 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
633 {
634         HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
635         return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
636 }
637
638
639 GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
640 {
641         HDC hDC = m_hDC;
642
643         if (is_crappy_intel_card())
644                 hDC = ::wglGetCurrentDC();
645
646         return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
647 }
648
649
650 GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
651 {
652         GHOST_TSuccess success;
653         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
654                 if (m_hDC && m_hGlRc) {
655                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
656                 }
657                 else {
658                         success = GHOST_kFailure;
659                 }
660         }
661         else {
662                 success = GHOST_kSuccess;
663         }
664         return success;
665 }
666
667
668 GHOST_TSuccess GHOST_WindowWin32::invalidate()
669 {
670         GHOST_TSuccess success;
671         if (m_hWnd) {
672                 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
673         }
674         else {
675                 success = GHOST_kFailure;
676         }
677         return success;
678 }
679
680 GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd)
681 {
682         int pixelFormat;
683         bool success = FALSE;
684         UINT numFormats;
685         HDC hDC = GetDC(getHWND());
686         float fAttributes[] = {0, 0};
687         UINT nMaxFormats = 1;
688
689         // The attributes to look for
690         int iAttributes[] = {
691                 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
692                 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
693                 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
694                 WGL_COLOR_BITS_ARB, pfd.cColorBits,
695                 WGL_DEPTH_BITS_ARB, pfd.cDepthBits,
696                 WGL_STENCIL_BITS_ARB, pfd.cStencilBits,
697                 WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
698                 WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
699                 WGL_SAMPLES_ARB, m_multisample,
700                 0, 0
701         };
702
703         // Get the function
704         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");  
705
706         if (!wglChoosePixelFormatARB)
707         {
708                 m_multisampleEnabled = GHOST_kFailure;
709                 return GHOST_kFailure;
710         }
711
712         // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it.
713         while (iAttributes[17] > 0) {
714                 // See if the format is valid
715                 success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats);
716                 GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats);
717
718                 if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) {
719                         GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]);
720                         m_multisampleEnabled = GHOST_kSuccess;
721                         m_msPixelFormat = pixelFormat;
722                 }
723                 iAttributes[17] -= 1;
724                 success = GHOST_kFailure;
725         }
726         if (m_multisampleEnabled == GHOST_kSuccess)     {
727                 return GHOST_kSuccess;
728         }
729         GHOST_PRINT("no available pixel format\n");
730         return GHOST_kFailure;
731 }
732
733 GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
734 {
735         GHOST_TSuccess success;
736         switch (type) {
737         case GHOST_kDrawingContextTypeOpenGL:
738                 {
739                 // If this window has multisample enabled, use the supplied format
740                 if (m_multisampleEnabled)
741                 {
742                         if (SetPixelFormat(m_hDC, m_msPixelFormat, &sPreferredFormat)==FALSE)
743                         {
744                                 success = GHOST_kFailure;
745                                 break;
746                         }
747
748                         // Create the context
749                         m_hGlRc = ::wglCreateContext(m_hDC);
750                         if (m_hGlRc) {
751                                 if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
752                                         if (s_firsthGLRc) {
753                                                 if (is_crappy_intel_card()) {
754                                                         if (::wglMakeCurrent(NULL, NULL) == TRUE) {
755                                                                 ::wglDeleteContext(m_hGlRc);
756                                                                 m_hGlRc = s_firsthGLRc;
757                                                         }
758                                                         else {
759                                                                 ::wglDeleteContext(m_hGlRc);
760                                                                 m_hGlRc = NULL;
761                                                         }
762                                                 }
763                                                 else {
764                                                         ::wglCopyContext(s_firsthGLRc, m_hGlRc, GL_ALL_ATTRIB_BITS);
765                                                         ::wglShareLists(s_firsthGLRc, m_hGlRc);
766                                                 }
767                                         }
768                                         else {
769                                                 s_firsthGLRc = m_hGlRc;
770                                         }
771
772                                         if (m_hGlRc) {
773                                                 success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
774                                         }
775                                         else {
776                                                 success = GHOST_kFailure;
777                                         }
778                                 }
779                                 else {
780                                         success = GHOST_kFailure;
781                                 }
782                         }
783                         else {
784                                 success = GHOST_kFailure;
785                         }
786
787                         if (success == GHOST_kFailure) {
788                                 printf("Failed to get a context....\n");
789                         }
790                 }
791                 else
792                 {
793                         if(m_stereoVisual)
794                                 sPreferredFormat.dwFlags |= PFD_STEREO;
795
796                         // Attempt to match device context pixel format to the preferred format
797                         int iPixelFormat = EnumPixelFormats(m_hDC);
798                         if (iPixelFormat == 0) {
799                                 success = GHOST_kFailure;
800                                 break;
801                         }
802                         if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
803                                 success = GHOST_kFailure;
804                                 break;
805                         }
806                         // For debugging only: retrieve the pixel format chosen
807                         PIXELFORMATDESCRIPTOR preferredFormat;
808                         ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
809
810                         // Create the context
811                         m_hGlRc = ::wglCreateContext(m_hDC);
812                         if (m_hGlRc) {
813                                 if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
814                                         if (s_firsthGLRc) {
815                                                 if (is_crappy_intel_card()) {
816                                                         if (::wglMakeCurrent(NULL, NULL) == TRUE) {
817                                                                 ::wglDeleteContext(m_hGlRc);
818                                                                 m_hGlRc = s_firsthGLRc;
819                                                         }
820                                                         else {
821                                                                 ::wglDeleteContext(m_hGlRc);
822                                                                 m_hGlRc = NULL;
823                                                         }
824                                                 }
825                                                 else {
826                                                         ::wglShareLists(s_firsthGLRc, m_hGlRc);
827                                                 }
828                                         }
829                                         else {
830                                                 s_firsthGLRc = m_hGlRc;
831                                         }
832
833                                         if (m_hGlRc) {
834                                                 success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
835                                         }
836                                         else {
837                                                 success = GHOST_kFailure;
838                                         }
839                                 }
840                                 else {
841                                         success = GHOST_kFailure;
842                                 }
843                         }
844                         else {
845                                 success = GHOST_kFailure;
846                         }
847
848                         if (success == GHOST_kFailure) {
849                                 printf("Failed to get a context....\n");
850                         }
851                                         
852                         // Attempt to enable multisample
853                         if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled)
854                         {
855                                 success = initMultisample(preferredFormat);
856
857                                 if (success)
858                                 {
859
860                                         // Make sure we don't screw up the context
861                                         m_drawingContextType = GHOST_kDrawingContextTypeOpenGL;
862                                         removeDrawingContext();
863
864                                         // Create a new window
865                                         GHOST_TWindowState new_state = getState();
866
867                                         m_nextWindow = new GHOST_WindowWin32((GHOST_SystemWin32*)GHOST_ISystem::getSystem(),
868                                                                                                         m_title,
869                                                                                                         m_left,
870                                                                                                         m_top,
871                                                                                                         m_width,
872                                                                                                         m_height,
873                                                                                                         new_state,
874                                                                                                         type,
875                                                                                                         m_stereo,
876                                                                                                         m_multisample,
877                                                                                                         m_parentWindowHwnd,
878                                                                                                         m_multisampleEnabled,
879                                                                                                         m_msPixelFormat);
880
881                                         // Return failure so we can trash this window.
882                                         success = GHOST_kFailure;
883                                         break;
884                                 } else {
885                                         m_multisampleEnabled = GHOST_kSuccess;
886                                         printf("Multisample failed to initialized\n");
887                                         success = GHOST_kSuccess;
888                                 }
889                         }
890                 }
891
892                 }
893                 break;
894
895         case GHOST_kDrawingContextTypeNone:
896                 success = GHOST_kSuccess;
897                 break;
898
899         default:
900                 success = GHOST_kFailure;
901         }
902         return success;
903 }
904
905 GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
906 {
907         GHOST_TSuccess success;
908         switch (m_drawingContextType) {
909         case GHOST_kDrawingContextTypeOpenGL:
910                 // we shouldn't remove the drawing context if it's the first OpenGL context
911                 // If we do, we get corrupted drawing. See #19997
912                 if (m_hGlRc && m_hGlRc!=s_firsthGLRc) {
913                         success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
914                         m_hGlRc = 0;
915                 }
916                 else {
917                         success = GHOST_kFailure;
918                 }
919                 break;
920         case GHOST_kDrawingContextTypeNone:
921                 success = GHOST_kSuccess;
922                 break;
923         default:
924                 success = GHOST_kFailure;
925         }
926         return success;
927 }
928
929 void GHOST_WindowWin32::lostMouseCapture()
930 {
931         if(m_hasMouseCaptured)
932                 {       m_hasGrabMouse = false;
933                         m_nPressedButtons = 0;
934                         m_hasMouseCaptured = false;
935                 };
936 }
937
938 void GHOST_WindowWin32::registerMouseClickEvent(int press)
939 {
940
941         switch(press)
942         {
943                 case 0: m_nPressedButtons++;    break;
944                 case 1: if(m_nPressedButtons)   m_nPressedButtons--; break;
945                 case 2: m_hasGrabMouse=true;    break;
946                 case 3: m_hasGrabMouse=false;   break;
947         }
948
949         if(!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured)
950         {
951                         ::ReleaseCapture();
952                         m_hasMouseCaptured = false;
953         }
954         else if((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured)
955         {
956                         ::SetCapture(m_hWnd);
957                         m_hasMouseCaptured = true;
958
959         }
960 }
961
962
963 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
964 {
965         if (!visible) {
966                 while (::ShowCursor(FALSE) >= 0);
967         }
968         else {
969                 while (::ShowCursor(TRUE) < 0);
970         }
971
972         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
973                 ::SetCursor( m_customCursor );
974         } else {
975                 // Convert GHOST cursor to Windows OEM cursor
976                 bool success = true;
977                 LPCSTR id;
978                 switch (cursor) {
979                         case GHOST_kStandardCursorDefault:              id = IDC_ARROW;         break;
980                         case GHOST_kStandardCursorRightArrow:           id = IDC_ARROW;         break;
981                         case GHOST_kStandardCursorLeftArrow:            id = IDC_ARROW;         break;
982                         case GHOST_kStandardCursorInfo:                 id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
983                         case GHOST_kStandardCursorDestroy:              id = IDC_NO;            break;  // Slashed circle
984                         case GHOST_kStandardCursorHelp:                 id = IDC_HELP;          break;  // Arrow and question mark
985                         case GHOST_kStandardCursorCycle:                id = IDC_NO;            break;  // Slashed circle
986                         case GHOST_kStandardCursorSpray:                id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
987                         case GHOST_kStandardCursorWait:                 id = IDC_WAIT;          break;  // Hourglass
988                         case GHOST_kStandardCursorText:                 id = IDC_IBEAM;         break;  // I-beam
989                         case GHOST_kStandardCursorCrosshair:            id = IDC_CROSS;         break;  // Crosshair
990                         case GHOST_kStandardCursorUpDown:               id = IDC_SIZENS;        break;  // Double-pointed arrow pointing north and south
991                         case GHOST_kStandardCursorLeftRight:            id = IDC_SIZEWE;        break;  // Double-pointed arrow pointing west and east
992                         case GHOST_kStandardCursorTopSide:              id = IDC_UPARROW;       break;  // Vertical arrow
993                         case GHOST_kStandardCursorBottomSide:           id = IDC_SIZENS;        break;
994                         case GHOST_kStandardCursorLeftSide:             id = IDC_SIZEWE;        break;
995                         case GHOST_kStandardCursorTopLeftCorner:        id = IDC_SIZENWSE;      break;
996                         case GHOST_kStandardCursorTopRightCorner:       id = IDC_SIZENESW;      break;
997                         case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;      break;
998                         case GHOST_kStandardCursorBottomLeftCorner:     id = IDC_SIZENESW;      break;
999                         case GHOST_kStandardCursorPencil:               id = IDC_ARROW;         break;
1000                         case GHOST_kStandardCursorCopy:                 id = IDC_ARROW;         break;
1001                         default:
1002                         success = false;
1003                 }
1004
1005                 if (success) {
1006                         ::SetCursor(::LoadCursor(0, id));
1007                 }
1008         }
1009 }
1010
1011 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
1012 {
1013         if (::GetForegroundWindow() == m_hWnd) {
1014                 loadCursor(visible, getCursorShape());
1015         }
1016
1017         return GHOST_kSuccess;
1018 }
1019
1020 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
1021 {
1022         if(mode != GHOST_kGrabDisable) {
1023                 if(mode != GHOST_kGrabNormal) {
1024                         m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
1025                         setCursorGrabAccum(0, 0);
1026
1027                         if(mode == GHOST_kGrabHide)
1028                                 setWindowCursorVisibility(false);
1029                 }
1030                 registerMouseClickEvent(2);
1031         }
1032         else {
1033                 if (m_cursorGrab==GHOST_kGrabHide) {
1034                         m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
1035                         setWindowCursorVisibility(true);
1036                 }
1037                 if(m_cursorGrab != GHOST_kGrabNormal) {
1038                         /* use to generate a mouse move event, otherwise the last event
1039                          * blender gets can be outside the screen causing menus not to show
1040                          * properly unless the user moves the mouse */
1041                          GHOST_TInt32 pos[2];
1042                          m_system->getCursorPosition(pos[0], pos[1]);
1043                          m_system->setCursorPosition(pos[0], pos[1]);
1044                 }
1045
1046                 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
1047                 setCursorGrabAccum(0, 0);
1048                 m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */
1049                 registerMouseClickEvent(3);
1050         }
1051         
1052         return GHOST_kSuccess;
1053 }
1054
1055 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
1056 {
1057         if (m_customCursor) {
1058                 DestroyCursor(m_customCursor);
1059                 m_customCursor = NULL;
1060         }
1061
1062         if (::GetForegroundWindow() == m_hWnd) {
1063                 loadCursor(getCursorVisibility(), cursorShape);
1064         }
1065
1066         return GHOST_kSuccess;
1067 }
1068
1069 void GHOST_WindowWin32::processWin32TabletInitEvent()
1070 {
1071         if (m_wintab) {
1072                 GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
1073
1074                 // let's see if we can initialize tablet here
1075                 /* check if WinTab available. */
1076                 if (fpWTInfo) {
1077                         AXIS Pressure, Orientation[3]; /* The maximum tablet size */
1078
1079                         BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
1080                         if (pressureSupport)
1081                                 m_maxPressure = Pressure.axMax;
1082                         else
1083                                 m_maxPressure = 0;
1084
1085                         BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
1086                         if (tiltSupport) {
1087                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
1088                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
1089                                         m_maxAzimuth = Orientation[0].axMax;
1090                                         m_maxAltitude = Orientation[1].axMax;
1091                                 }
1092                                 else {  /* no so dont do tilt stuff */
1093                                         m_maxAzimuth = m_maxAltitude = 0;
1094                                 }
1095                         }
1096
1097                         m_tabletData->Active = GHOST_kTabletModeNone;
1098                 }
1099         }
1100 }
1101
1102 void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
1103 {
1104         PACKET pkt;
1105         if (m_wintab) {
1106                 GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
1107                 if (fpWTPacket) {
1108                         if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
1109                                 if (m_tabletData) {
1110                                         switch (pkt.pkCursor) {
1111                                                 case 0: /* first device */
1112                                                 case 3: /* second device */
1113                                                         m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */
1114                                                         break;
1115                                                 case 1:
1116                                                 case 4:
1117                                                         m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */
1118                                                         break;
1119                                                 case 2:
1120                                                 case 5:
1121                                                         m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */
1122                                                         break;
1123                                         }
1124                                         if (m_maxPressure > 0) {
1125                                                 m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
1126                                         } else {
1127                                                 m_tabletData->Pressure = 1.0f;
1128                                         }
1129
1130                                         if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
1131                                                 ORIENTATION ort = pkt.pkOrientation;
1132                                                 float vecLen;
1133                                                 float altRad, azmRad;   /* in radians */
1134
1135                                                 /*
1136                                                 from the wintab spec:
1137                                                 orAzimuth       Specifies the clockwise rotation of the
1138                                                 cursor about the z axis through a full circular range.
1139
1140                                                 orAltitude      Specifies the angle with the x-y plane
1141                                                 through a signed, semicircular range.  Positive values
1142                                                 specify an angle upward toward the positive z axis;
1143                                                 negative values specify an angle downward toward the negative z axis.
1144
1145                                                 wintab.h defines .orAltitude as a UINT but documents .orAltitude
1146                                                 as positive for upward angles and negative for downward angles.
1147                                                 WACOM uses negative altitude values to show that the pen is inverted;
1148                                                 therefore we cast .orAltitude as an (int) and then use the absolute value.
1149                                                 */
1150
1151                                                 /* convert raw fixed point data to radians */
1152                                                 altRad = (float)((fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0);
1153                                                 azmRad = (float)(((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0);
1154
1155                                                 /* find length of the stylus' projected vector on the XY plane */
1156                                                 vecLen = cos(altRad);
1157
1158                                                 /* from there calculate X and Y components based on azimuth */
1159                                                 m_tabletData->Xtilt = sin(azmRad) * vecLen;
1160                                                 m_tabletData->Ytilt = (float)(sin(M_PI/2.0 - azmRad) * vecLen);
1161
1162                                         } else {
1163                                                 m_tabletData->Xtilt = 0.0f;
1164                                                 m_tabletData->Ytilt = 0.0f;
1165                                         }
1166                                 }
1167                         }
1168                 }
1169         }
1170 }
1171
1172 /** Reverse the bits in a GHOST_TUns8 */
1173 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
1174 {
1175         ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
1176         ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
1177         ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
1178         return ch;
1179 }
1180
1181 /** Reverse the bits in a GHOST_TUns16 */
1182 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
1183 {
1184         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
1185         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
1186         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
1187         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
1188         return shrt;
1189 }
1190 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
1191                                         GHOST_TUns8 mask[16][2], int hotX, int hotY)
1192 {
1193         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask,
1194                                                                         16, 16, hotX, hotY, 0, 1);
1195 }
1196
1197 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
1198                                         GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY,
1199                                         int fg_color, int bg_color)
1200 {
1201         GHOST_TUns32 andData[32];
1202         GHOST_TUns32 xorData[32];
1203         GHOST_TUns32 fullBitRow, fullMaskRow;
1204         int x, y, cols;
1205
1206         cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
1207         if (sizeX%8) cols++;
1208
1209         if (m_customCursor) {
1210                 DestroyCursor(m_customCursor);
1211                 m_customCursor = NULL;
1212         }
1213
1214         memset(&andData, 0xFF, sizeof(andData));
1215         memset(&xorData, 0, sizeof(xorData));
1216
1217         for (y=0; y<sizeY; y++) {
1218                 fullBitRow=0;
1219                 fullMaskRow=0;
1220                 for (x=cols-1; x>=0; x--){
1221                         fullBitRow<<=8;
1222                         fullMaskRow<<=8;
1223                         fullBitRow  |= uns8ReverseBits(bitmap[cols*y + x]);
1224                         fullMaskRow |= uns8ReverseBits(  mask[cols*y + x]);
1225                 }
1226                 xorData[y]= fullBitRow & fullMaskRow;
1227                 andData[y]= ~fullMaskRow;
1228         }
1229
1230         m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1231         if (!m_customCursor) {
1232                 return GHOST_kFailure;
1233         }
1234
1235         if (::GetForegroundWindow() == m_hWnd) {
1236                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
1237         }
1238
1239         return GHOST_kSuccess;
1240 }
1241
1242
1243 GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
1244 {       
1245         /*SetProgressValue sets state to TBPF_NORMAL automaticly*/
1246         if(m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd,10000*progress,10000))
1247                 return GHOST_kSuccess;
1248
1249         return GHOST_kFailure;
1250 }
1251
1252 GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
1253 {
1254         if(m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd,TBPF_NOPROGRESS))
1255                 return GHOST_kSuccess;
1256
1257         return GHOST_kFailure;
1258 }
1259
1260 /*  Ron Fosner's code for weighting pixel formats and forcing software.
1261         See http://www.opengl.org/resources/faq/technical/weight.cpp */
1262
1263 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
1264         int weight = 0;
1265
1266         /* assume desktop color depth is 32 bits per pixel */
1267
1268         /* cull unusable pixel formats */
1269         /* if no formats can be found, can we determine why it was rejected? */
1270         if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
1271                 !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
1272                 !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
1273                 ( pfd.cDepthBits <= 8 ) ||
1274                 !(pfd.iPixelType == PFD_TYPE_RGBA))
1275                 return 0;
1276
1277         weight = 1;  /* it's usable */
1278
1279         /* the bigger the depth buffer the better */
1280         /* give no weight to a 16-bit depth buffer, because those are crap */
1281         weight += pfd.cDepthBits - 16;
1282
1283         weight += pfd.cColorBits - 8;
1284
1285         /* want swap copy capability -- it matters a lot */
1286         if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
1287
1288         /* but if it's a generic (not accelerated) view, it's really bad */
1289         if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
1290
1291         return weight;
1292 }
1293
1294 /* A modification of Ron Fosner's replacement for ChoosePixelFormat */
1295 /* returns 0 on error, else returns the pixel format number to be used */
1296 static int EnumPixelFormats(HDC hdc) {
1297         int iPixelFormat;
1298         int i, n, w, weight = 0;
1299         PIXELFORMATDESCRIPTOR pfd;
1300
1301         /* we need a device context to do anything */
1302         if(!hdc) return 0;
1303
1304         iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
1305
1306         /* obtain detailed information about
1307         the device context's first pixel format */
1308         n = 1+::DescribePixelFormat(hdc, iPixelFormat,
1309                 sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1310
1311         /* choose a pixel format using the useless Windows function in case
1312                 we come up empty handed */
1313         iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat );
1314
1315         if(!iPixelFormat) return 0; /* couldn't find one to use */
1316
1317         for(i=1; i<=n; i++) { /* not the idiom, but it's right */
1318                 ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
1319                 w = WeightPixelFormat(pfd);
1320                 // be strict on stereo
1321                 if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO))   {
1322                         if(w > weight) {
1323                                 weight = w;
1324                                 iPixelFormat = i;
1325                         }
1326                 }
1327         }
1328         if (weight == 0) {
1329                 // we could find the correct stereo setting, just find any suitable format
1330                 for(i=1; i<=n; i++) { /* not the idiom, but it's right */
1331                         ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
1332                         w = WeightPixelFormat(pfd);
1333                         if(w > weight) {
1334                                 weight = w;
1335                                 iPixelFormat = i;
1336                         }
1337                 }
1338         }
1339         return iPixelFormat;
1340 }
1341
1342