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