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