root/OpenSceneGraph/trunk/src/osgViewer/GraphicsWindowWin32.cpp @ 13130

Revision 13130, 103.4 kB (checked in by robert, 3 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12 *
13 * This file is Copyright (C) 2007 - André Garneau (andre@pixdev.com) and licensed under OSGPL.
14 *
15 * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference.
16 * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004  Don Burns.
17 */
18
19#include <osgViewer/api/Win32/GraphicsWindowWin32>
20#include <osgViewer/api/Win32/PixelBufferWin32>
21#include <osgViewer/View>
22
23#include <osg/GL>
24#include <osg/DeleteHandler>
25#include <osg/ApplicationUsage>
26
27#include <vector>
28#include <map>
29#include <sstream>
30#include <windowsx.h>
31
32#if(WINVER < 0x0601)
33// Provide Declarations for Multitouch
34
35#define WM_TOUCH                        0x0240
36
37/*
38 * Touch Input defines and functions
39 */
40
41/*
42 * Touch input handle
43 */
44DECLARE_HANDLE(HTOUCHINPUT);
45
46typedef struct tagTOUCHINPUT {
47    LONG x;
48    LONG y;
49    HANDLE hSource;
50    DWORD dwID;
51    DWORD dwFlags;
52    DWORD dwMask;
53    DWORD dwTime;
54    ULONG_PTR dwExtraInfo;
55    DWORD cxContact;
56    DWORD cyContact;
57} TOUCHINPUT, *PTOUCHINPUT;
58typedef TOUCHINPUT const * PCTOUCHINPUT;
59
60
61/*
62 * Conversion of touch input coordinates to pixels
63 */
64#define TOUCH_COORD_TO_PIXEL(l)         ((l) / 100)
65
66/*
67 * Touch input flag values (TOUCHINPUT.dwFlags)
68 */
69#define TOUCHEVENTF_MOVE            0x0001
70#define TOUCHEVENTF_DOWN            0x0002
71#define TOUCHEVENTF_UP              0x0004
72#define TOUCHEVENTF_INRANGE         0x0008
73#define TOUCHEVENTF_PRIMARY         0x0010
74#define TOUCHEVENTF_NOCOALESCE      0x0020
75#define TOUCHEVENTF_PEN             0x0040
76#define TOUCHEVENTF_PALM            0x0080
77
78#endif
79
80typedef
81BOOL
82(WINAPI GetTouchInputInfoFunc)(
83    HTOUCHINPUT hTouchInput,               // input event handle; from touch message lParam
84    UINT cInputs,                          // number of elements in the array
85    PTOUCHINPUT pInputs,  // array of touch inputs
86    int cbSize);                           // sizeof(TOUCHINPUT)
87
88typedef
89BOOL
90(WINAPI CloseTouchInputHandleFunc(
91    HTOUCHINPUT hTouchInput));                   // input event handle; from touch message lParam
92
93typedef
94BOOL
95(WINAPI RegisterTouchWindowFunc(
96    HWND hwnd,
97    ULONG ulFlags));
98
99// Declared static in order to get Header File clean
100static RegisterTouchWindowFunc *registerTouchWindowFunc = NULL;
101static CloseTouchInputHandleFunc *closeTouchInputHandleFunc = NULL;
102static GetTouchInputInfoFunc *getTouchInputInfoFunc = NULL;
103
104using namespace osgViewer;
105
106namespace osgViewer
107{
108
109static osg::ApplicationUsageProxy GraphicsWindowWin32_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND on/off","Enable/disable duplicate makeCurrentContext call used as workaround for WinXP/NVidia/MultiView/MulitThread isues (pre 178.13 drivers).");
110
111//
112// Defines from the WGL_ARB_pixel_format specification document
113// See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
114//
115
116#define WGL_NUMBER_PIXEL_FORMATS_ARB            0x2000
117#define WGL_DRAW_TO_WINDOW_ARB                  0x2001
118#define WGL_DRAW_TO_BITMAP_ARB                  0x2002
119#define WGL_ACCELERATION_ARB                    0x2003
120#define WGL_NEED_PALETTE_ARB                    0x2004
121#define WGL_NEED_SYSTEM_PALETTE_ARB             0x2005
122#define WGL_SWAP_LAYER_BUFFERS_ARB              0x2006
123#define WGL_SWAP_METHOD_ARB                     0x2007
124#define WGL_NUMBER_OVERLAYS_ARB                 0x2008
125#define WGL_NUMBER_UNDERLAYS_ARB                0x2009
126#define WGL_TRANSPARENT_ARB                     0x200A
127#define WGL_TRANSPARENT_RED_VALUE_ARB           0x2037
128#define WGL_TRANSPARENT_GREEN_VALUE_ARB         0x2038
129#define WGL_TRANSPARENT_BLUE_VALUE_ARB          0x2039
130#define WGL_TRANSPARENT_ALPHA_VALUE_ARB         0x203A
131#define WGL_TRANSPARENT_INDEX_VALUE_ARB         0x203B
132#define WGL_SHARE_DEPTH_ARB                     0x200C
133#define WGL_SHARE_STENCIL_ARB                   0x200D
134#define WGL_SHARE_ACCUM_ARB                     0x200E
135#define WGL_SUPPORT_GDI_ARB                     0x200F
136#define WGL_SUPPORT_OPENGL_ARB                  0x2010
137#define WGL_DOUBLE_BUFFER_ARB                   0x2011
138#define WGL_STEREO_ARB                          0x2012
139#define WGL_PIXEL_TYPE_ARB                      0x2013
140#define WGL_COLOR_BITS_ARB                      0x2014
141#define WGL_RED_BITS_ARB                        0x2015
142#define WGL_RED_SHIFT_ARB                       0x2016
143#define WGL_GREEN_BITS_ARB                      0x2017
144#define WGL_GREEN_SHIFT_ARB                     0x2018
145#define WGL_BLUE_BITS_ARB                       0x2019
146#define WGL_BLUE_SHIFT_ARB                      0x201A
147#define WGL_ALPHA_BITS_ARB                      0x201B
148#define WGL_ALPHA_SHIFT_ARB                     0x201C
149#define WGL_ACCUM_BITS_ARB                      0x201D
150#define WGL_ACCUM_RED_BITS_ARB                  0x201E
151#define WGL_ACCUM_GREEN_BITS_ARB                0x201F
152#define WGL_ACCUM_BLUE_BITS_ARB                 0x2020
153#define WGL_ACCUM_ALPHA_BITS_ARB                0x2021
154#define WGL_DEPTH_BITS_ARB                      0x2022
155#define WGL_STENCIL_BITS_ARB                    0x2023
156#define WGL_AUX_BUFFERS_ARB                     0x2024
157#define WGL_NO_ACCELERATION_ARB                 0x2025
158#define WGL_GENERIC_ACCELERATION_ARB            0x2026
159#define WGL_FULL_ACCELERATION_ARB               0x2027
160#define WGL_SWAP_EXCHANGE_ARB                   0x2028
161#define WGL_SWAP_COPY_ARB                       0x2029
162#define WGL_SWAP_UNDEFINED_ARB                  0x202A
163#define WGL_TYPE_RGBA_ARB                       0x202B
164#define WGL_TYPE_COLORINDEX_ARB                 0x202C
165#define WGL_SAMPLE_BUFFERS_ARB                  0x2041
166#define WGL_SAMPLES_ARB                         0x2042
167
168#ifndef WGL_ARB_create_context
169#define WGL_CONTEXT_DEBUG_BIT_ARB      0x00000001
170#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
171#define WGL_CONTEXT_MAJOR_VERSION_ARB  0x2091
172#define WGL_CONTEXT_MINOR_VERSION_ARB  0x2092
173#define WGL_CONTEXT_LAYER_PLANE_ARB    0x2093
174#define WGL_CONTEXT_FLAGS_ARB          0x2094
175#define WGL_CONTEXT_PROFILE_MASK_ARB   0x9126
176#define ERROR_INVALID_VERSION_ARB      0x2095
177#endif
178
179#ifndef WGL_ARB_create_context
180#define WGL_ARB_create_context 1
181#ifdef WGL_WGLEXT_PROTOTYPES
182extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
183#endif /* WGL_WGLEXT_PROTOTYPES */
184typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
185#endif
186
187//
188// Entry points used from the WGL extensions
189//
190//    BOOL wglChoosePixelFormatARB(HDC hdc,
191//                                 const int *piAttribIList,
192//                                 const FLOAT *pfAttribFList,
193//                                 UINT nMaxFormats,
194//                                 int *piFormats,
195//                                 UINT *nNumFormats);
196//
197
198typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * );
199
200//
201// Utility class to specify the visual attributes for wglChoosePixelFormatARB() function
202//
203
204template <typename T> class WGLAttributes
205{
206  public:
207
208      WGLAttributes()  {}
209      ~WGLAttributes() {}
210
211      void begin()                              { m_parameters.clear(); }
212      void set( const T& id, const T& value )   { add(id); add(value); }
213      void enable( const T& id )                { add(id); add(true); }
214      void disable( const T& id )               { add(id); add(false); }
215      void end()                                { add(0); }
216
217      const T* get() const                      { return &m_parameters.front(); }
218
219  protected:
220
221      void add( const T& t )                    { m_parameters.push_back(t); }
222
223      std::vector<T>    m_parameters;        // parameters added
224
225  private:
226
227      // No implementation for these
228      WGLAttributes( const WGLAttributes& );
229      WGLAttributes& operator=( const WGLAttributes& );
230};
231
232typedef WGLAttributes<int>     WGLIntegerAttributes;
233typedef WGLAttributes<float> WGLFloatAttributes;
234
235//
236// Class responsible for interfacing with the Win32 Window Manager
237// The behavior of this class is specific to OSG needs and is not a
238// generic Windowing interface.
239//
240// NOTE: This class is intended to be used by a single-thread.
241//         Multi-threading is not enabled for performance reasons.
242//         The creation/deletion of graphics windows should be done
243//         by a single controller thread. That thread should then
244//         call the checkEvents() method of all created windows periodically.
245//         This is the case with OSG as a "main" thread does all
246//         setup, update & event processing. Rendering is done (optionally) by other threads.
247//
248// !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the
249//        creation and event message processing for all windows it manages. This
250//        is to relieve the "main" thread from having to do this synchronously
251//        during frame generation. The "main" thread would only have to process
252//          each osgGA-type window event queue.
253//
254
255class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
256{
257  public:
258
259    // A class representing an OpenGL rendering context
260    class OpenGLContext
261    {
262      public:
263
264        OpenGLContext()
265        : _previousHdc(0),
266          _previousHglrc(0),
267          _hwnd(0),
268          _hdc(0),
269          _hglrc(0),
270          _restorePreviousOnExit(false)
271        {}
272
273        OpenGLContext( HWND hwnd, HDC hdc, HGLRC hglrc )
274        : _previousHdc(0),
275          _previousHglrc(0),
276          _hwnd(hwnd),
277          _hdc(hdc),
278          _hglrc(hglrc),
279          _restorePreviousOnExit(false)
280        {}
281
282        ~OpenGLContext();
283
284        void set( HWND hwnd, HDC hdc, HGLRC hglrc )
285        {
286            _hwnd  = hwnd;
287            _hdc   = hdc;
288            _hglrc = hglrc;
289        }
290
291        HDC deviceContext() { return _hdc; }
292
293        bool makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit );
294
295      protected:
296
297        //
298        // Data members
299        //
300
301        HDC   _previousHdc;                // previously HDC to restore rendering context on
302        HGLRC _previousHglrc;           // previously current rendering context
303        HWND  _hwnd;                    // handle to OpenGL window
304        HDC   _hdc;                     // handle to device context
305        HGLRC _hglrc;                   // handle to OpenGL rendering context
306        bool  _restorePreviousOnExit;   // restore original context on exit
307
308        private:
309
310        // no implementation for these
311        OpenGLContext( const OpenGLContext& );
312        OpenGLContext& operator=( const OpenGLContext& );
313    };
314
315    static std::string osgGraphicsWindowWithCursorClass;    //!< Name of Win32 window class (with cursor) used by OSG graphics window instances
316    static std::string osgGraphicsWindowWithoutCursorClass; //!< Name of Win32 window class (without cursor) used by OSG graphics window instances
317
318    Win32WindowingSystem();
319    ~Win32WindowingSystem();
320
321    // Access the Win32 windowing system through this singleton class.
322    static Win32WindowingSystem* getInterface()
323    {
324        static Win32WindowingSystem* win32Interface = new Win32WindowingSystem;
325        return win32Interface;
326    }
327
328    // Return the number of screens present in the system
329    virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si );
330
331    // Return the resolution of specified screen
332    // (0,0) is returned if screen is unknown
333    virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution );
334
335    // Return the bits per pixel of specified screen
336    // (0) is returned if screen is unknown
337    virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel );
338
339    // Set the resolution for given screen
340    virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution );
341
342    // Enumerates available resolutions
343    virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution);
344
345    // Return the screen position and width/height.
346    // all zeros returned if screen is unknown
347    virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height );
348
349    // Create a graphics context with given traits
350    virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits );
351
352    // Register a newly created native window along with its application counterpart
353    // This is required to maintain a link between Windows messages and the application window object
354    // at event processing time
355    virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window );
356
357    // Unregister a window
358    // This is called as part of a window being torn down
359    virtual void unregisterWindow( HWND hwnd );
360
361    // Get the application window object associated with a native window
362    virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd );
363
364    // Return a valid sample OpenGL Device Context and current rendering context that can be used with wglXYZ extensions
365    virtual bool getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY );
366
367  protected:
368
369    // Display devices present in the system
370    typedef std::vector<DISPLAY_DEVICE> DisplayDevices;
371
372    // Map Win32 window handles to GraphicsWindowWin32 instance
373    typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* >  WindowHandleEntry;
374    typedef std::map<  HWND, osgViewer::GraphicsWindowWin32* >  WindowHandles;
375
376    // Enumerate all display devices and return in passed container
377    void enumerateDisplayDevices( DisplayDevices& displayDevices ) const;
378
379    // Get the screen device current mode information
380    bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
381
382    // Change the screen settings (resolution, refresh rate, etc.)
383    bool changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
384
385    // Register the window classes used by OSG graphics window instances
386    void registerWindowClasses();
387
388    // Unregister the window classes used by OSG graphics window instances
389    void unregisterWindowClasses();
390
391    // Data members
392    WindowHandles       _activeWindows;                //!< handles to active windows
393    bool                _windowClassesRegistered;      //!< true after window classes have been registered
394
395 private:
396
397     // No implementation for these
398     Win32WindowingSystem( const Win32WindowingSystem& );
399     Win32WindowingSystem& operator=( const Win32WindowingSystem& );
400};
401
402///////////////////////////////////////////////////////////////////////////////
403//                             Error reporting
404//////////////////////////////////////////////////////////////////////////////
405
406static void reportError( const std::string& msg )
407{
408    OSG_WARN << "Error: " << msg.c_str() << std::endl;
409}
410
411static void reportError( const std::string& msg, unsigned int errorCode )
412{
413    //
414    // Some APIs are documented as returning the error in ::GetLastError but apparently do not
415    // Skip "Reason" field if the errorCode is still success
416    //
417
418    if (errorCode==0)
419    {
420        reportError(msg);
421        return;
422    }
423
424    OSG_WARN << "Windows Error #"   << errorCode << ": " << msg.c_str();
425
426    LPVOID lpMsgBuf;
427
428    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
429                      NULL,
430                      errorCode,
431                      0, // Default language
432                      (LPTSTR) &lpMsgBuf,
433                      0,
434                      NULL)!=0)
435    {
436        OSG_WARN << ". Reason: " << LPTSTR(lpMsgBuf) << std::endl;
437        ::LocalFree(lpMsgBuf);
438    }
439    else
440    {
441        OSG_WARN << std::endl;
442    }
443}
444
445static void reportErrorForScreen( const std::string& msg, const osg::GraphicsContext::ScreenIdentifier& si, unsigned int errorCode )
446{
447    std::ostringstream str;
448
449    str << "[Screen #" << si.screenNum << "] " << msg;
450    reportError(str.str(), errorCode);
451}
452
453//////////////////////////////////////////////////////////////////////////////
454//                       Keyboard key mapping for Win32
455//////////////////////////////////////////////////////////////////////////////
456
457class Win32KeyboardMap
458{
459    public:
460
461        Win32KeyboardMap()
462        {
463            _keymap[VK_ESCAPE       ] = osgGA::GUIEventAdapter::KEY_Escape;
464            _keymap[VK_F1           ] = osgGA::GUIEventAdapter::KEY_F1;
465            _keymap[VK_F2           ] = osgGA::GUIEventAdapter::KEY_F2;
466            _keymap[VK_F3           ] = osgGA::GUIEventAdapter::KEY_F3;
467            _keymap[VK_F4           ] = osgGA::GUIEventAdapter::KEY_F4;
468            _keymap[VK_F5           ] = osgGA::GUIEventAdapter::KEY_F5;
469            _keymap[VK_F6           ] = osgGA::GUIEventAdapter::KEY_F6;
470            _keymap[VK_F7           ] = osgGA::GUIEventAdapter::KEY_F7;
471            _keymap[VK_F8           ] = osgGA::GUIEventAdapter::KEY_F8;
472            _keymap[VK_F9           ] = osgGA::GUIEventAdapter::KEY_F9;
473            _keymap[VK_F10          ] = osgGA::GUIEventAdapter::KEY_F10;
474            _keymap[VK_F11          ] = osgGA::GUIEventAdapter::KEY_F11;
475            _keymap[VK_F12          ] = osgGA::GUIEventAdapter::KEY_F12;
476            _keymap[0xc0            ] = osgGA::GUIEventAdapter::KEY_Backquote;
477            _keymap['0'             ] = osgGA::GUIEventAdapter::KEY_0;
478            _keymap['1'             ] = osgGA::GUIEventAdapter::KEY_1;
479            _keymap['2'             ] = osgGA::GUIEventAdapter::KEY_2;
480            _keymap['3'             ] = osgGA::GUIEventAdapter::KEY_3;
481            _keymap['4'             ] = osgGA::GUIEventAdapter::KEY_4;
482            _keymap['5'             ] = osgGA::GUIEventAdapter::KEY_5;
483            _keymap['6'             ] = osgGA::GUIEventAdapter::KEY_6;
484            _keymap['7'             ] = osgGA::GUIEventAdapter::KEY_7;
485            _keymap['8'             ] = osgGA::GUIEventAdapter::KEY_8;
486            _keymap['9'             ] = osgGA::GUIEventAdapter::KEY_9;
487            _keymap[0xbd            ] = osgGA::GUIEventAdapter::KEY_Minus;
488            _keymap[0xbb            ] = osgGA::GUIEventAdapter::KEY_Equals;
489            _keymap[VK_BACK         ] = osgGA::GUIEventAdapter::KEY_BackSpace;
490            _keymap[VK_TAB          ] = osgGA::GUIEventAdapter::KEY_Tab;
491            _keymap['A'             ] = osgGA::GUIEventAdapter::KEY_A;
492            _keymap['B'             ] = osgGA::GUIEventAdapter::KEY_B;
493            _keymap['C'             ] = osgGA::GUIEventAdapter::KEY_C;
494            _keymap['D'             ] = osgGA::GUIEventAdapter::KEY_D;
495            _keymap['E'             ] = osgGA::GUIEventAdapter::KEY_E;
496            _keymap['F'             ] = osgGA::GUIEventAdapter::KEY_F;
497            _keymap['G'             ] = osgGA::GUIEventAdapter::KEY_G;
498            _keymap['H'             ] = osgGA::GUIEventAdapter::KEY_H;
499            _keymap['I'             ] = osgGA::GUIEventAdapter::KEY_I;
500            _keymap['J'             ] = osgGA::GUIEventAdapter::KEY_J;
501            _keymap['K'             ] = osgGA::GUIEventAdapter::KEY_K;
502            _keymap['L'             ] = osgGA::GUIEventAdapter::KEY_L;
503            _keymap['M'             ] = osgGA::GUIEventAdapter::KEY_M;
504            _keymap['N'             ] = osgGA::GUIEventAdapter::KEY_N;
505            _keymap['O'             ] = osgGA::GUIEventAdapter::KEY_O;
506            _keymap['P'             ] = osgGA::GUIEventAdapter::KEY_P;
507            _keymap['Q'             ] = osgGA::GUIEventAdapter::KEY_Q;
508            _keymap['R'             ] = osgGA::GUIEventAdapter::KEY_R;
509            _keymap['S'             ] = osgGA::GUIEventAdapter::KEY_S;
510            _keymap['T'             ] = osgGA::GUIEventAdapter::KEY_T;
511            _keymap['U'             ] = osgGA::GUIEventAdapter::KEY_U;
512            _keymap['V'             ] = osgGA::GUIEventAdapter::KEY_V;
513            _keymap['W'             ] = osgGA::GUIEventAdapter::KEY_W;
514            _keymap['X'             ] = osgGA::GUIEventAdapter::KEY_X;
515            _keymap['Y'             ] = osgGA::GUIEventAdapter::KEY_Y;
516            _keymap['Z'             ] = osgGA::GUIEventAdapter::KEY_Z;
517            _keymap[0xdb            ] = osgGA::GUIEventAdapter::KEY_Leftbracket;
518            _keymap[0xdd            ] = osgGA::GUIEventAdapter::KEY_Rightbracket;
519            _keymap[0xdc            ] = osgGA::GUIEventAdapter::KEY_Backslash;
520            _keymap[VK_CAPITAL      ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
521            _keymap[0xba            ] = osgGA::GUIEventAdapter::KEY_Semicolon;
522            _keymap[0xde            ] = osgGA::GUIEventAdapter::KEY_Quote;
523            _keymap[VK_RETURN       ] = osgGA::GUIEventAdapter::KEY_Return;
524            _keymap[VK_LSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_L;
525            _keymap[0xbc            ] = osgGA::GUIEventAdapter::KEY_Comma;
526            _keymap[0xbe            ] = osgGA::GUIEventAdapter::KEY_Period;
527            _keymap[0xbf            ] = osgGA::GUIEventAdapter::KEY_Slash;
528            _keymap[VK_RSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_R;
529            _keymap[VK_LCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_L;
530            _keymap[VK_LWIN         ] = osgGA::GUIEventAdapter::KEY_Super_L;
531            _keymap[VK_SPACE        ] = osgGA::GUIEventAdapter::KEY_Space;
532            _keymap[VK_LMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_L;
533            _keymap[VK_RMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_R;
534            _keymap[VK_RWIN         ] = osgGA::GUIEventAdapter::KEY_Super_R;
535            _keymap[VK_APPS         ] = osgGA::GUIEventAdapter::KEY_Menu;
536            _keymap[VK_RCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_R;
537            _keymap[VK_SNAPSHOT     ] = osgGA::GUIEventAdapter::KEY_Print;
538            _keymap[VK_SCROLL       ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
539            _keymap[VK_PAUSE        ] = osgGA::GUIEventAdapter::KEY_Pause;
540            _keymap[VK_HOME         ] = osgGA::GUIEventAdapter::KEY_Home;
541            _keymap[VK_PRIOR        ] = osgGA::GUIEventAdapter::KEY_Page_Up;
542            _keymap[VK_END          ] = osgGA::GUIEventAdapter::KEY_End;
543            _keymap[VK_NEXT         ] = osgGA::GUIEventAdapter::KEY_Page_Down;
544            _keymap[VK_DELETE       ] = osgGA::GUIEventAdapter::KEY_Delete;
545            _keymap[VK_INSERT       ] = osgGA::GUIEventAdapter::KEY_Insert;
546            _keymap[VK_LEFT         ] = osgGA::GUIEventAdapter::KEY_Left;
547            _keymap[VK_UP           ] = osgGA::GUIEventAdapter::KEY_Up;
548            _keymap[VK_RIGHT        ] = osgGA::GUIEventAdapter::KEY_Right;
549            _keymap[VK_DOWN         ] = osgGA::GUIEventAdapter::KEY_Down;
550            _keymap[VK_NUMLOCK      ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
551            _keymap[VK_DIVIDE       ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
552            _keymap[VK_MULTIPLY     ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
553            _keymap[VK_SUBTRACT     ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
554            _keymap[VK_ADD          ] = osgGA::GUIEventAdapter::KEY_KP_Add;
555            _keymap[VK_NUMPAD7      ] = osgGA::GUIEventAdapter::KEY_KP_Home;
556            _keymap[VK_NUMPAD8      ] = osgGA::GUIEventAdapter::KEY_KP_Up;
557            _keymap[VK_NUMPAD9      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
558            _keymap[VK_NUMPAD4      ] = osgGA::GUIEventAdapter::KEY_KP_Left;
559            _keymap[VK_NUMPAD5      ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
560            _keymap[VK_NUMPAD6      ] = osgGA::GUIEventAdapter::KEY_KP_Right;
561            _keymap[VK_NUMPAD1      ] = osgGA::GUIEventAdapter::KEY_KP_End;
562            _keymap[VK_NUMPAD2      ] = osgGA::GUIEventAdapter::KEY_KP_Down;
563            _keymap[VK_NUMPAD3      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
564            _keymap[VK_NUMPAD0      ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
565            _keymap[VK_DECIMAL      ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
566            _keymap[VK_CLEAR        ] = osgGA::GUIEventAdapter::KEY_Clear;
567        }
568
569        ~Win32KeyboardMap() {}
570
571        int remapKey(int key)
572        {
573            KeyMap::const_iterator map = _keymap.find(key);
574            return map==_keymap.end() ? key : map->second;
575        }
576
577    protected:
578
579        typedef std::map<int, int> KeyMap;
580        KeyMap _keymap;
581};
582
583static Win32KeyboardMap s_win32KeyboardMap;
584static int remapWin32Key(int key)
585{
586    return s_win32KeyboardMap.remapKey(key);
587}
588
589//////////////////////////////////////////////////////////////////////////////
590//         Window procedure for all GraphicsWindowWin32 instances
591//           Dispatches the call to the actual instance
592//////////////////////////////////////////////////////////////////////////////
593
594static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
595{
596    osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
597    return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
598                    ::DefWindowProc(hwnd, uMsg, wParam, lParam);
599}
600
601//////////////////////////////////////////////////////////////////////////////
602//              Win32WindowingSystem::OpenGLContext implementation
603//////////////////////////////////////////////////////////////////////////////
604
605Win32WindowingSystem::OpenGLContext::~OpenGLContext()
606{
607    if (_restorePreviousOnExit && _previousHglrc!=_hglrc && !::wglMakeCurrent(_previousHdc, _previousHglrc))
608    {
609        reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError());
610    }
611
612    _previousHdc   = 0;
613    _previousHglrc = 0;
614
615    if (_hglrc)
616    {
617        ::wglMakeCurrent(_hdc, NULL);
618        ::wglDeleteContext(_hglrc);
619        _hglrc = 0;
620    }
621
622    if (_hdc)
623    {
624        ::ReleaseDC(_hwnd, _hdc);
625        _hdc = 0;
626    }
627
628    if (_hwnd)
629    {
630        ::DestroyWindow(_hwnd);
631        _hwnd = 0;
632    }
633}
634
635bool Win32WindowingSystem::OpenGLContext::makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit )
636{
637    if (_hdc==0 || _hglrc==0) return false;
638
639    _previousHglrc = restorePreviousOnExit ? ::wglGetCurrentContext() : 0;
640    _previousHdc   = restoreOnHdc;
641
642    if (_hglrc==_previousHglrc) return true;
643
644    if (!::wglMakeCurrent(_hdc, _hglrc))
645    {
646        reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError());
647        return false;
648    }
649
650    _restorePreviousOnExit = restorePreviousOnExit;
651
652    return true;
653}
654
655//////////////////////////////////////////////////////////////////////////////
656//              Win32WindowingSystem implementation
657//////////////////////////////////////////////////////////////////////////////
658
659std::string Win32WindowingSystem::osgGraphicsWindowWithCursorClass;
660std::string Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass;
661
662Win32WindowingSystem::Win32WindowingSystem()
663: _windowClassesRegistered(false)
664{
665  // Detect presence of runtime support for multitouch
666    HMODULE hModule = LoadLibrary("user32");
667    if (hModule)
668    {
669        registerTouchWindowFunc = (RegisterTouchWindowFunc *) GetProcAddress( hModule, "RegisterTouchWindow");
670        closeTouchInputHandleFunc = (CloseTouchInputHandleFunc *) GetProcAddress( hModule, "CloseTouchInputHandle");
671        getTouchInputInfoFunc = (GetTouchInputInfoFunc *)  GetProcAddress( hModule, "GetTouchInputInfo");
672
673        if (!(registerTouchWindowFunc && closeTouchInputHandleFunc && getTouchInputInfoFunc))
674        {
675            registerTouchWindowFunc = NULL;
676            closeTouchInputHandleFunc = NULL;
677            getTouchInputInfoFunc = NULL;
678            FreeLibrary( hModule);
679        }
680    }
681}
682
683Win32WindowingSystem::~Win32WindowingSystem()
684{
685    if (osg::Referenced::getDeleteHandler())
686    {
687        osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
688        osg::Referenced::getDeleteHandler()->flushAll();
689    }
690
691    unregisterWindowClasses();
692}
693
694void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const
695{
696    for (unsigned int deviceNum=0;; ++deviceNum)
697    {
698        DISPLAY_DEVICE displayDevice;
699        displayDevice.cb = sizeof(displayDevice);
700
701        if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break;
702
703        // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
704        if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
705
706        // Only return display devices that are attached to the desktop
707        if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
708
709        displayDevices.push_back(displayDevice);
710    }
711}
712
713void Win32WindowingSystem::registerWindowClasses()
714{
715    if (_windowClassesRegistered) return;
716
717    //
718    // Register the window classes used by OSG GraphicsWindowWin32 instances
719    //
720
721    std::ostringstream str;
722    str << "OSG Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]";
723
724    osgGraphicsWindowWithCursorClass    = str.str() + "{ with cursor }";
725    osgGraphicsWindowWithoutCursorClass = str.str() + "{ without cursor }";
726
727    WNDCLASSEX wc;
728
729    HINSTANCE hinst = ::GetModuleHandle(NULL);
730
731    //
732    // First class: class for OSG Graphics Window with a cursor enabled
733    //
734
735    wc.cbSize        = sizeof(wc);
736    wc.style         = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
737    wc.lpfnWndProc   = WindowProc;
738    wc.cbClsExtra    = 0;
739    wc.cbWndExtra    = 0;
740    wc.hInstance     = hinst;
741    wc.hIcon         = ::LoadIcon(hinst, "OSG_ICON");
742    wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
743    wc.hbrBackground = NULL;
744    wc.lpszMenuName  = 0;
745    wc.lpszClassName = osgGraphicsWindowWithCursorClass.c_str();
746    wc.hIconSm       = NULL;
747
748    if (::RegisterClassEx(&wc)==0)
749    {
750        unsigned int lastError = ::GetLastError();
751        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
752        {
753            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register first window class", lastError);
754            return;
755        }
756    }
757
758    //
759    // Second class: class for OSG Graphics Window without a cursor
760    //
761
762    wc.hCursor       = NULL;
763    wc.lpszClassName = osgGraphicsWindowWithoutCursorClass.c_str();
764
765    if (::RegisterClassEx(&wc)==0)
766    {
767        unsigned int lastError = ::GetLastError();
768        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
769        {
770            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register second window class", lastError);
771            return;
772        }
773    }
774
775    _windowClassesRegistered = true;
776}
777
778void Win32WindowingSystem::unregisterWindowClasses()
779{
780    if (_windowClassesRegistered)
781    {
782        ::UnregisterClass(osgGraphicsWindowWithCursorClass.c_str(),    ::GetModuleHandle(NULL));
783        ::UnregisterClass(osgGraphicsWindowWithoutCursorClass.c_str(), ::GetModuleHandle(NULL));
784        _windowClassesRegistered = false;
785    }
786}
787
788bool Win32WindowingSystem::getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY )
789{
790    context.set(0, 0, 0);
791
792    registerWindowClasses();
793
794    HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
795                                 osgGraphicsWindowWithoutCursorClass.c_str(),
796                                 NULL,
797                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
798                                 windowOriginX,
799                                 windowOriginY,
800                                 1,
801                                 1,
802                                 NULL,
803                                 NULL,
804                                 ::GetModuleHandle(NULL),
805                                 NULL);
806    if (hwnd==0)
807    {
808        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError());
809        return false;
810    }
811
812    //
813    // Set the pixel format of the window
814    //
815
816    PIXELFORMATDESCRIPTOR pixelFormat =
817    {
818        sizeof(PIXELFORMATDESCRIPTOR),
819        1,
820        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
821        PFD_TYPE_RGBA,
822        24,
823        0, 0, 0, 0, 0, 0, 0, 0,
824        0, 0, 0, 0, 0,
825        24,
826        0,
827        0,
828        PFD_MAIN_PLANE,
829        0,
830        0, 0, 0
831    };
832
833    HDC hdc = ::GetDC(hwnd);
834    if (hdc==0)
835    {
836        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError());
837        ::DestroyWindow(hwnd);
838        return false;
839    }
840
841    int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
842    if (pixelFormatIndex==0)
843    {
844        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError());
845        ::ReleaseDC(hwnd, hdc);
846        ::DestroyWindow(hwnd);
847        return false;
848    }
849
850    if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat))
851    {
852        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError());
853        ::ReleaseDC(hwnd, hdc);
854        ::DestroyWindow(hwnd);
855        return false;
856    }
857
858    HGLRC hglrc = ::wglCreateContext(hdc);
859    if (hglrc==0)
860    {
861        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError());
862        ::ReleaseDC(hwnd, hdc);
863        ::DestroyWindow(hwnd);
864        return false;
865    }
866
867    context.set(hwnd, hdc, hglrc);
868
869    if (!context.makeCurrent(windowHDC, true)) return false;
870
871    return true;
872}
873
874unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
875{
876    return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0;
877}
878
879bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
880{
881    if (si.displayNum>0)
882    {
883        OSG_WARN << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
884        return false;
885    }
886
887    DisplayDevices displayDevices;
888    enumerateDisplayDevices(displayDevices);
889
890    if (si.screenNum>=static_cast<int>(displayDevices.size()))
891    {
892        OSG_WARN << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
893        return false;
894    }
895
896    displayDevice = displayDevices[si.screenNum];
897
898    deviceMode.dmSize        = sizeof(deviceMode);
899    deviceMode.dmDriverExtra = 0;
900
901    if (!::EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
902    {
903        std::ostringstream str;
904        str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum;
905        reportError(str.str(), ::GetLastError());
906        return false;
907    }
908
909    return true;
910}
911
912void Win32WindowingSystem::getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
913{
914    DISPLAY_DEVICE displayDevice;
915    DEVMODE        deviceMode;
916
917    if (!getScreenInformation(si, displayDevice, deviceMode))
918        deviceMode.dmFields = 0;        // Set the fields to 0 so that it says 'nothing'.
919
920    // Get resolution
921    if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0) {
922        resolution.width  = deviceMode.dmPelsWidth;
923        resolution.height = deviceMode.dmPelsHeight;
924    } else {
925        resolution.width  = 0;
926        resolution.height = 0;
927    }
928
929    // Get refersh rate
930    if ((deviceMode.dmFields & DM_DISPLAYFREQUENCY) != 0) {
931        resolution.refreshRate = deviceMode.dmDisplayFrequency;
932        if (resolution.refreshRate == 0 || resolution.refreshRate == 1) {
933            // Windows specific: 0 and 1 represent the hhardware's default refresh rate.
934            // If someone knows how to get this refresh rate (in Hz)...
935            OSG_NOTICE << "Win32WindowingSystem::getScreenSettings() is not fully implemented (cannot retreive the hardware's default refresh rate)."<<std::endl;
936            resolution.refreshRate = 0;
937        }
938    } else
939        resolution.refreshRate = 0;
940
941    // Get bits per pixel for color buffer
942    if ((deviceMode.dmFields & DM_BITSPERPEL) != 0)
943        resolution.colorDepth = deviceMode.dmBitsPerPel;
944    else
945        resolution.colorDepth = 0;
946}
947
948void Win32WindowingSystem::getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel )
949{
950    DISPLAY_DEVICE displayDevice;
951    DEVMODE        deviceMode;
952
953    if (getScreenInformation(si, displayDevice, deviceMode))
954    {
955        dmBitsPerPel = deviceMode.dmBitsPerPel;
956    }
957    else
958    {
959        dmBitsPerPel  = 0;
960    }
961}
962
963bool Win32WindowingSystem::changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
964{
965    //
966    // Start by testing if the change would be successful (without applying it)
967    //
968
969    unsigned int result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, CDS_TEST, NULL);
970    if (result==DISP_CHANGE_SUCCESSFUL)
971    {
972        result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, 0, NULL);
973        if (result==DISP_CHANGE_SUCCESSFUL) return true;
974    }
975
976    std::string msg = "Win32WindowingSystem::changeScreenSettings() - Unable to change the screen settings.";
977
978    switch( result )
979    {
980        case DISP_CHANGE_BADMODE     : msg += " The specified graphics mode is not supported."; break;
981        case DISP_CHANGE_FAILED      : msg += " The display driver failed the specified graphics mode."; break;
982        case DISP_CHANGE_RESTART     : msg += " The computer must be restarted for the graphics mode to work."; break;
983        default : break;
984    }
985
986    reportErrorForScreen(msg, si, result);
987    return false;
988}
989
990bool Win32WindowingSystem::setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
991{
992    DISPLAY_DEVICE displayDevice;
993    DEVMODE        deviceMode;
994
995    if (!getScreenInformation(si, displayDevice, deviceMode)) return false;
996
997    deviceMode.dmFields = 0;
998    // Set resolution
999    if (resolution.width>0 && resolution.height>0) {
1000        deviceMode.dmFields    |= DM_PELSWIDTH | DM_PELSHEIGHT;
1001        deviceMode.dmPelsWidth  = static_cast<DWORD>(resolution.width);
1002        deviceMode.dmPelsHeight = static_cast<DWORD>(resolution.height);
1003    }
1004    // Set refersh rate
1005    if (resolution.refreshRate>0) {
1006        deviceMode.dmFields           |= DM_DISPLAYFREQUENCY;
1007        deviceMode.dmDisplayFrequency  = static_cast<DWORD>(resolution.refreshRate);
1008    }
1009    // Set bits per pixel for color buffer
1010    if (resolution.colorDepth>0) {
1011        deviceMode.dmFields     |= DM_BITSPERPEL;
1012        deviceMode.dmBitsPerPel  = static_cast<DWORD>(resolution.colorDepth);
1013    }
1014
1015    return changeScreenSettings(si, displayDevice, deviceMode);
1016}
1017
1018void Win32WindowingSystem::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) {
1019    resolutionList.clear();
1020
1021    if (si.displayNum>0)
1022    {
1023        OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
1024        return;
1025    }
1026
1027    DisplayDevices displayDevices;
1028    enumerateDisplayDevices(displayDevices);
1029
1030    if (si.screenNum>=static_cast<int>(displayDevices.size()))
1031    {
1032        OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
1033        return;
1034    }
1035
1036    DISPLAY_DEVICE displayDevice = displayDevices[si.screenNum];
1037
1038    // Do the enumeration
1039    DEVMODE deviceMode;
1040    static const unsigned int MAX_RESOLUTIONS = 4046;        // Upper limit to avoid infinite (= very long) loop.
1041    for (unsigned int i=0; i<MAX_RESOLUTIONS; ++i)
1042    {
1043        if (!::EnumDisplaySettings(displayDevice.DeviceName, i, &deviceMode))
1044            break;
1045        deviceMode.dmSize        = sizeof(deviceMode);
1046        deviceMode.dmDriverExtra = 0;
1047        resolutionList.push_back(osg::GraphicsContext::ScreenSettings(deviceMode.dmPelsWidth, deviceMode.dmPelsHeight, deviceMode.dmDisplayFrequency, deviceMode.dmBitsPerPel));
1048    }
1049}
1050
1051void Win32WindowingSystem::getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height )
1052{
1053    DISPLAY_DEVICE displayDevice;
1054    DEVMODE        deviceMode;
1055
1056    if (getScreenInformation(si, displayDevice, deviceMode))
1057    {
1058        originX = deviceMode.dmPosition.x;
1059        originY = deviceMode.dmPosition.y;
1060        width   = deviceMode.dmPelsWidth;
1061        height  = deviceMode.dmPelsHeight;
1062    }
1063    else
1064    {
1065        originX = 0;
1066        originY = 0;
1067        width   = 0;
1068        height  = 0;
1069    }
1070}
1071
1072osg::GraphicsContext* Win32WindowingSystem::createGraphicsContext( osg::GraphicsContext::Traits* traits )
1073{
1074    if (traits->pbuffer)
1075    {
1076        osg::ref_ptr<osgViewer::PixelBufferWin32> pbuffer = new PixelBufferWin32(traits);
1077        if (pbuffer->valid()) return pbuffer.release();
1078        else return 0;
1079    }
1080    else
1081    {
1082        registerWindowClasses();
1083
1084        osg::ref_ptr<osgViewer::GraphicsWindowWin32> window = new GraphicsWindowWin32(traits);
1085        if (window->valid()) return window.release();
1086        else return 0;
1087    }
1088}
1089
1090void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window )
1091{
1092    if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window));
1093}
1094
1095//
1096// Unregister a window
1097// This is called as part of a window being torn down
1098//
1099
1100void Win32WindowingSystem::unregisterWindow( HWND hwnd )
1101{
1102    if (hwnd) _activeWindows.erase(hwnd);
1103}
1104
1105//
1106// Get the application window object associated with a native window
1107//
1108
1109osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd )
1110{
1111    WindowHandles::const_iterator entry = _activeWindows.find(hwnd);
1112    return entry==_activeWindows.end() ? 0 : entry->second;
1113}
1114
1115//////////////////////////////////////////////////////////////////////////////
1116//                    GraphicsWindowWin32 implementation
1117//////////////////////////////////////////////////////////////////////////////
1118
1119GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits )
1120: _currentCursor(0),
1121  _windowProcedure(0),
1122  _timeOfLastCheckEvents(-1.0),
1123  _screenOriginX(0),
1124  _screenOriginY(0),
1125  _screenWidth(0),
1126  _screenHeight(0),
1127  _windowOriginXToRealize(0),
1128  _windowOriginYToRealize(0),
1129  _windowWidthToRealize(0),
1130  _windowHeightToRealize(0),
1131  _initialized(false),
1132  _valid(false),
1133  _realized(false),
1134  _ownsWindow(true),
1135  _closeWindow(false),
1136  _destroyWindow(false),
1137  _destroying(false),
1138  _mouseCursor(InheritCursor),
1139  _appMouseCursor(LeftArrowCursor),
1140  _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues( false )
1141{
1142    _traits = traits;
1143    if (_traits->useCursor) setCursor(LeftArrowCursor);
1144    else setCursor(NoCursor);
1145
1146    init();
1147
1148    if (valid())
1149    {
1150        setState( new osg::State );
1151        getState()->setGraphicsContext(this);
1152
1153        if (_traits.valid() && _traits->sharedContext.valid())
1154        {
1155            getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
1156            incrementContextIDUsageCount( getState()->getContextID() );
1157        }
1158        else
1159        {
1160            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
1161        }
1162    }
1163}
1164
1165GraphicsWindowWin32::~GraphicsWindowWin32()
1166{
1167    close();
1168    destroyWindow();
1169}
1170
1171void GraphicsWindowWin32::init()
1172{
1173    if (_initialized) return;
1174
1175    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
1176
1177    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1178    HWND windowHandle = windowData ? windowData->_hwnd : 0;
1179
1180    _ownsWindow    = windowHandle==0;
1181    _closeWindow   = false;
1182    _destroyWindow = false;
1183    _destroying    = false;
1184
1185    _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
1186    _valid       = _initialized;
1187
1188    // 2008/10/03
1189    // Few days ago NVidia released WHQL certified drivers ver 178.13.
1190    // These drivers (as well as former beta ver 177.92) were free from the bug described below.
1191    // So it looks like its high time to make the workaround inactive by default.
1192    // If you happen to still use earlier drivers and have problems consider changing to new ones or
1193    // activate OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND macro def through CMake advanced vars.
1194#ifdef OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND
1195
1196    // 2008/05/12
1197    // Workaround for Bugs in NVidia drivers for windows XP / multithreaded / dualview / multicore CPU
1198    // affects GeForce 6x00, 7x00, 8x00 boards (others were not tested) driver versions 174.xx - 175.xx
1199    // pre 174.xx had other issues so reverting is not an option (statitistics, fbo)
1200    // drivers release 175.16 is the latest currently available
1201    //
1202    // When using OpenGL in threaded app ( main thread sets up context / renderer thread draws using it )
1203    // first wglMakeCurrent seems to not work right and screw OpenGL context driver data:
1204    // 1: succesive drawing shows a number of artifacts in TriangleStrips and TriangleFans
1205    // 2: weird behaviour of FramBufferObjects (glGenFramebuffer generates already generated ids ...)
1206    // Looks like repeating wglMakeCurrent call fixes all these issues
1207    // wglMakeCurrent call can impact performance so I try to minimize number of
1208    // wglMakeCurrent calls by checking current HDC and GL context
1209    // and repeat wglMakeCurrent only when they change for current thread
1210
1211    _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = true;
1212#endif
1213
1214    const char* str = getenv("OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND");
1215    if (str)
1216    {
1217        _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = (strcmp(str, "on")==0 || strcmp(str, "ON")==0 || strcmp(str, "On")==0 );
1218    }
1219}
1220
1221bool GraphicsWindowWin32::createWindow()
1222{
1223    unsigned int extendedStyle;
1224    unsigned int windowStyle;
1225
1226    if (!determineWindowPositionAndStyle(_traits->screenNum,
1227                                         _traits->x,
1228                                         _traits->y,
1229                                         _traits->width,
1230                                         _traits->height,
1231                                         _traits->windowDecoration,
1232                                         _windowOriginXToRealize,
1233                                         _windowOriginYToRealize,
1234                                         _windowWidthToRealize,
1235                                         _windowHeightToRealize,
1236                                         windowStyle,
1237                                         extendedStyle))
1238    {
1239        reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
1240        return false;
1241    }
1242
1243    _hwnd = ::CreateWindowEx(extendedStyle,
1244                             _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() :
1245                                                  Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(),
1246                             _traits->windowName.c_str(),
1247                             windowStyle,
1248                             _windowOriginXToRealize,
1249                             _windowOriginYToRealize,
1250                             _windowWidthToRealize,
1251                             _windowHeightToRealize,
1252                             NULL,
1253                             NULL,
1254                             ::GetModuleHandle(NULL),
1255                             NULL);
1256    if (_hwnd==0)
1257    {
1258        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError());
1259        return false;
1260    }
1261
1262    _hdc = ::GetDC(_hwnd);
1263    if (_hdc==0)
1264    {
1265        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1266        destroyWindow();
1267        _hwnd = 0;
1268        return false;
1269    }
1270
1271    //
1272    // Set the pixel format according to traits specified
1273    //
1274
1275    if (!setPixelFormat())
1276    {
1277        ::ReleaseDC(_hwnd, _hdc);
1278        _hdc  = 0;
1279        destroyWindow();
1280        return false;
1281    }
1282
1283    //
1284    // Create the OpenGL rendering context associated with this window
1285    //
1286
1287    _hglrc = createContextImplementation();
1288    if (_hglrc==0)
1289    {
1290        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1291        ::ReleaseDC(_hwnd, _hdc);
1292        _hdc  = 0;
1293        destroyWindow();
1294        return false;
1295    }
1296
1297    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1298
1299    if (registerTouchWindowFunc)
1300        (*registerTouchWindowFunc)( _hwnd, 0);
1301    return true;
1302}
1303
1304bool GraphicsWindowWin32::setWindow( HWND handle )
1305{
1306    if (_initialized)
1307    {
1308        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError());
1309        return false;
1310    }
1311
1312    if (handle==0)
1313    {
1314        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError());
1315        return false;
1316    }
1317
1318    _hwnd = handle;
1319    if (_hwnd==0)
1320    {
1321        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError());
1322        return false;
1323    }
1324
1325    _hdc = ::GetDC(_hwnd);
1326    if (_hdc==0)
1327    {
1328        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1329        _hwnd = 0;
1330        return false;
1331    }
1332
1333    //
1334    // Check if we must set the pixel format of the inherited window
1335    //
1336
1337    if (!setPixelFormat())
1338    {
1339        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError());
1340        ::ReleaseDC(_hwnd, _hdc);
1341        _hdc  = 0;
1342        _hwnd = 0;
1343        return false;
1344    }
1345
1346    _hglrc = createContextImplementation();
1347    if (_hglrc==0)
1348    {
1349        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1350        ::ReleaseDC(_hwnd, _hdc);
1351        _hdc  = 0;
1352        _hwnd = 0;
1353        return false;
1354    }
1355
1356    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1357
1358    if (!windowData || windowData->_installEventHandler)
1359    {
1360        if (!registerWindowProcedure())
1361        {
1362            ::wglDeleteContext(_hglrc);
1363            _hglrc = 0;
1364            ::ReleaseDC(_hwnd, _hdc);
1365            _hdc  = 0;
1366            _hwnd = 0;
1367            return false;
1368        }
1369    }
1370
1371    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1372
1373    _initialized = true;
1374    _valid       = true;
1375
1376    return true;
1377}
1378
1379void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
1380{
1381    if (_destroying) return;
1382    _destroying = true;
1383
1384    if (_graphicsThread && _graphicsThread->isRunning())
1385    {
1386        // find all the viewers that might own use this graphics context
1387        osg::GraphicsContext::Cameras cameras = getCameras();
1388        for(osg::GraphicsContext::Cameras::iterator it=cameras.begin(); it!=cameras.end(); ++it)
1389        {
1390            osgViewer::View* view = dynamic_cast<osgViewer::View*>((*it)->getView());
1391            osgViewer::ViewerBase* viewerBase = view ? view->getViewerBase() : 0;
1392            if (viewerBase && viewerBase->areThreadsRunning())
1393            {
1394                viewerBase->stopThreading();
1395            }
1396        }
1397    }
1398
1399    if (_hdc)
1400    {
1401        releaseContext();
1402
1403        if (_hglrc)
1404        {
1405            ::wglDeleteContext(_hglrc);
1406            _hglrc = 0;
1407        }
1408
1409        ::ReleaseDC(_hwnd, _hdc);
1410        _hdc = 0;
1411    }
1412
1413    (void)unregisterWindowProcedure();
1414
1415    if (_hwnd)
1416    {
1417        Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1418        if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd);
1419        _hwnd = 0;
1420    }
1421
1422    _initialized = false;
1423    _realized    = false;
1424    _valid       = false;
1425    _destroying  = false;
1426}
1427
1428void GraphicsWindowWin32::registerWindow()
1429{
1430  Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1431}
1432
1433void GraphicsWindowWin32::unregisterWindow()
1434{
1435  Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1436}
1437
1438bool GraphicsWindowWin32::registerWindowProcedure()
1439{
1440    ::SetLastError(0);
1441    _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc));
1442    unsigned int error = ::GetLastError();
1443
1444    if (_windowProcedure==0 && error)
1445    {
1446        reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error);
1447        return false;
1448    }
1449
1450    return true;
1451}
1452
1453bool GraphicsWindowWin32::unregisterWindowProcedure()
1454{
1455    if (_windowProcedure==0 || _hwnd==0) return true;
1456
1457    ::SetLastError(0);
1458    WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure));
1459    unsigned int error = ::GetLastError();
1460
1461    if (wndProc==0 && error)
1462    {
1463        reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error);
1464        return false;
1465    }
1466
1467    _windowProcedure = 0;
1468
1469    return true;
1470}
1471
1472bool GraphicsWindowWin32::determineWindowPositionAndStyle( unsigned int  screenNum,
1473                                                           int           clientAreaX,
1474                                                           int           clientAreaY,
1475                                                           unsigned int  clientAreaWidth,
1476                                                           unsigned int  clientAreaHeight,
1477                                                           bool          decorated,
1478                                                           int&          x,
1479                                                           int&          y,
1480                                                           unsigned int& w,
1481                                                           unsigned int& h,
1482                                                           unsigned int& style,
1483                                                           unsigned int& extendedStyle )
1484{
1485    if (_traits==0) return false;
1486
1487    //
1488    // Query the screen position and size
1489    //
1490
1491    osg::GraphicsContext::ScreenIdentifier screenId(screenNum);
1492    Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface();
1493
1494    windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
1495    if (_screenWidth==0 || _screenHeight==0) return false;
1496
1497    x = clientAreaX + _screenOriginX;
1498    y = clientAreaY + _screenOriginY;
1499    w = clientAreaWidth;
1500    h = clientAreaHeight;
1501
1502    style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1503
1504    extendedStyle = 0;
1505
1506    if (decorated)
1507    {
1508        style |= WS_CAPTION     |
1509                 WS_SYSMENU     |
1510                 WS_MINIMIZEBOX |
1511                 WS_MAXIMIZEBOX;
1512
1513        if (_traits->supportsResize) style |= WS_SIZEBOX;
1514
1515        extendedStyle = WS_EX_APPWINDOW           |
1516                        WS_EX_OVERLAPPEDWINDOW |
1517                        WS_EX_ACCEPTFILES      |
1518                        WS_EX_LTRREADING;
1519
1520        RECT corners;
1521
1522        corners.left   = x;
1523        corners.top    = y;
1524        corners.right  = x + w - 1;
1525        corners.bottom = y + h - 1;
1526
1527        //
1528        // Determine the location of the window corners in order to have
1529        // a client area of the requested size
1530        //
1531
1532        if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
1533        {
1534            reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError());
1535            return false;
1536        }
1537
1538        x = corners.left;
1539        y = corners.top;
1540        w = corners.right  - corners.left + 1;
1541        h = corners.bottom - corners.top  + 1;
1542    }
1543
1544    return true;
1545}
1546
1547static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits,
1548                                              WGLIntegerAttributes&               attributes,
1549                                              bool                                allowSwapExchangeARB )
1550{
1551    attributes.begin();
1552
1553    attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
1554    attributes.enable(WGL_SUPPORT_OPENGL_ARB);
1555
1556    attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
1557    attributes.set(WGL_PIXEL_TYPE_ARB,   WGL_TYPE_RGBA_ARB);
1558
1559    attributes.set(WGL_COLOR_BITS_ARB,   traits.red + traits.green + traits.blue);
1560    attributes.set(WGL_RED_BITS_ARB,     traits.red);
1561    attributes.set(WGL_GREEN_BITS_ARB,   traits.green);
1562    attributes.set(WGL_BLUE_BITS_ARB,    traits.blue);
1563    attributes.set(WGL_DEPTH_BITS_ARB,   traits.depth);
1564
1565    if (traits.doubleBuffer)
1566    {
1567        attributes.enable(WGL_DOUBLE_BUFFER_ARB);
1568
1569        switch ( traits.swapMethod )
1570        {
1571            case osg::DisplaySettings::SWAP_COPY:
1572                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB);
1573                break;
1574            case osg::DisplaySettings::SWAP_EXCHANGE:
1575                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1576                break;
1577            case osg::DisplaySettings::SWAP_UNDEFINED:
1578                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_UNDEFINED_ARB);
1579                break;
1580            case osg::DisplaySettings::SWAP_DEFAULT:
1581                // Wojtek Lewandowski 2010-09-28:
1582                // Keep backward compatibility if no method is selected via traits
1583                // and let wglSwapExchangeARB flag select swap method.
1584                // However, I would rather remove this flag because its
1585                // now redundant to Traits::swapMethod and it looks like
1586                // WGL_SWAP_EXCHANGE_ARB is the GL default when no WGL_SWAP attrib is given.
1587                // To be precise: At least on Windows 7 and Nvidia it seems to be a default.
1588                if ( allowSwapExchangeARB )
1589                    attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1590                break;
1591        }
1592    }
1593
1594    if (traits.alpha)         attributes.set(WGL_ALPHA_BITS_ARB,     traits.alpha);
1595    if (traits.stencil)       attributes.set(WGL_STENCIL_BITS_ARB,   traits.stencil);
1596    if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers);
1597    if (traits.samples)       attributes.set(WGL_SAMPLES_ARB,        traits.samples);
1598
1599    if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB);
1600
1601    attributes.end();
1602}
1603
1604static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits)
1605{
1606    //
1607    // Access the entry point for the wglChoosePixelFormatARB function
1608    //
1609
1610    WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
1611    if (wglChoosePixelFormatARB==0)
1612    {
1613        // = openGLContext.getTraits()
1614        reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError());
1615        PIXELFORMATDESCRIPTOR pixelFormat = {
1616            sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
1617            1,                     // version number
1618            PFD_DRAW_TO_WINDOW |   // support window
1619            PFD_SUPPORT_OPENGL |   // support OpenGL
1620            (_traits->doubleBuffer ? PFD_DOUBLEBUFFER : NULL) |      // double buffered ?
1621            (_traits->swapMethod ==  osg::DisplaySettings::SWAP_COPY ? PFD_SWAP_COPY : NULL) |
1622            (_traits->swapMethod ==  osg::DisplaySettings::SWAP_EXCHANGE ? PFD_SWAP_EXCHANGE : NULL),
1623            PFD_TYPE_RGBA,         // RGBA type
1624            _traits->red + _traits->green + _traits->blue,                // color depth
1625            _traits->red ,0, _traits->green ,0, _traits->blue, 0,          // shift bits ignored
1626            _traits->alpha,          // alpha buffer ?
1627            0,                     // shift bit ignored
1628            0,                     // no accumulation buffer
1629            0, 0, 0, 0,            // accum bits ignored
1630            _traits->depth,          // 32 or 16 bit z-buffer ?
1631            _traits->stencil,        // stencil buffer ?
1632            0,                     // no auxiliary buffer
1633            PFD_MAIN_PLANE,        // main layer
1634            0,                     // reserved
1635            0, 0, 0                // layer masks ignored
1636        };
1637        int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
1638        if (pixelFormatIndex == 0)
1639        {
1640            reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError());
1641            return -1;
1642        }
1643
1644        ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat);
1645        if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0)  && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0))
1646        {
1647            OSG_WARN << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl;
1648        }
1649        return pixelFormatIndex;
1650    }
1651
1652    int pixelFormatIndex = 0;
1653    unsigned int numMatchingPixelFormats = 0;
1654
1655    if (!wglChoosePixelFormatARB(hdc,
1656                                 formatSpecifications.get(),
1657                                 NULL,
1658                                 1,
1659                                 &pixelFormatIndex,
1660                                 &numMatchingPixelFormats))
1661    {
1662        reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError());
1663        return -1;
1664    }
1665
1666    return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex;
1667}
1668
1669bool GraphicsWindowWin32::setPixelFormat()
1670{
1671    Win32WindowingSystem::OpenGLContext openGLContext;
1672    if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false;
1673
1674    //
1675    // Build the specifications of the requested pixel format
1676    //
1677
1678    WGLIntegerAttributes formatSpecs;
1679    ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);
1680
1681    //
1682    // Choose the closest matching pixel format from the specified traits
1683    //
1684
1685    int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1686
1687    if (pixelFormatIndex<0)
1688    {
1689            unsigned int bpp;
1690            Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp);
1691            if (bpp < 32) {
1692                OSG_INFO    << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, "
1693                                        << bpp
1694                                        << " bits per pixel on screen #"
1695                                        << _traits->screenNum
1696                                        << std::endl;
1697
1698                _traits->red = bpp / 4; //integer devide, determine minimum number of bits we will accept
1699                _traits->green = bpp / 4;
1700                _traits->blue = bpp / 4;
1701                ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB
1702                pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1703            }
1704    }
1705    if (pixelFormatIndex<0)
1706    {
1707        ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false);
1708        pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1709        if (pixelFormatIndex<0)
1710        {
1711            reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0);
1712            return false;
1713        }
1714
1715        OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #"
1716                               << _traits->screenNum
1717                               << std::endl;
1718    }
1719
1720    //
1721    // Set the pixel format found
1722    //
1723
1724    PIXELFORMATDESCRIPTOR pfd;
1725    ::memset(&pfd, 0, sizeof(pfd));
1726    pfd.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
1727    pfd.nVersion = 1;
1728
1729    if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
1730    {
1731        reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError());
1732        return false;
1733    }
1734
1735    return true;
1736}
1737
1738HGLRC GraphicsWindowWin32::createContextImplementation()
1739{
1740    HGLRC context( NULL );
1741
1742    if( OSG_GL3_FEATURES )
1743    {
1744        OSG_NOTIFY( osg::INFO ) << "GL3: Attempting to create OpenGL3 context." << std::endl;
1745        OSG_NOTIFY( osg::INFO ) << "GL3: version: " << _traits->glContextVersion << std::endl;
1746        OSG_NOTIFY( osg::INFO ) << "GL3: context flags: " << _traits->glContextFlags << std::endl;
1747        OSG_NOTIFY( osg::INFO ) << "GL3: profile: " << _traits->glContextProfileMask << std::endl;
1748
1749        Win32WindowingSystem::OpenGLContext openGLContext;
1750        if( !Win32WindowingSystem::getInterface()->getSampleOpenGLContext( openGLContext, _hdc, _screenOriginX, _screenOriginY ) )
1751        {
1752            reportErrorForScreen( "GL3: Can't create sample context.",
1753                _traits->screenNum, ::GetLastError() );
1754        }
1755        else
1756        {
1757            PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
1758                ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress( "wglCreateContextAttribsARB" );
1759            if( wglCreateContextAttribsARB==0 )
1760            {
1761                reportErrorForScreen( "GL3: wglCreateContextAttribsARB not available.",
1762                    _traits->screenNum, ::GetLastError() );
1763            }
1764            else
1765            {
1766                unsigned int idx( 0 );
1767                int attribs[ 16 ];
1768
1769                unsigned int major = 1, minor = 0;
1770                if( !_traits->getContextVersion(major, minor) || major<3 )
1771                {
1772                    OSG_NOTIFY( osg::WARN ) << "GL3: Non-GL3 version number: " << _traits->glContextVersion << std::endl;
1773                }
1774
1775                attribs[ idx++ ] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1776                attribs[ idx++ ] = major;
1777                attribs[ idx++ ] = WGL_CONTEXT_MINOR_VERSION_ARB;
1778                attribs[ idx++ ] = minor;
1779                if( _traits->glContextFlags != 0 )
1780                {
1781                    attribs[ idx++ ] = WGL_CONTEXT_FLAGS_ARB;
1782                    attribs[ idx++ ] = _traits->glContextFlags;
1783                }
1784                if( _traits->glContextProfileMask != 0 )
1785                {
1786                    attribs[ idx++ ] = WGL_CONTEXT_PROFILE_MASK_ARB;
1787                    attribs[ idx++ ] = _traits->glContextProfileMask;
1788                }
1789                attribs[ idx++ ] = 0;
1790
1791                context = wglCreateContextAttribsARB( _hdc, 0, attribs );
1792                if( context == NULL )
1793                {
1794                    reportErrorForScreen( "GL3: wglCreateContextAttribsARB returned NULL.",
1795                        _traits->screenNum, ::GetLastError() );
1796                }
1797                else
1798                {
1799                    OSG_NOTIFY( osg::INFO ) << "GL3: context created successfully." << std::endl;
1800                }
1801            }
1802        }
1803    }
1804
1805    // TBD insert GL ES 2 suppurt, if required for Win32.
1806
1807    // If platform context creation fails for any reason,
1808    // we'll create a standard context. This means you could
1809    // build OSG for GL3, have the context creation fail
1810    // (because you have the wrong driver), and end up with
1811    // a GL3 context. Something else will likely fail down
1812    // the line, as the GL3-built OSG will assume GL3 features
1813    // are present.
1814    //
1815    // This is also the typical path for GL 1/2 context creation.
1816    if( context == NULL )
1817        context = ::wglCreateContext(_hdc);
1818
1819    return( context );
1820}
1821
1822bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated )
1823{
1824    unsigned int windowStyle;
1825    unsigned int extendedStyle;
1826
1827    //
1828    // Determine position and size of window with/without decorations to retain the size specified in traits
1829    //
1830
1831    int x, y;
1832    unsigned int w, h;
1833
1834    if (!determineWindowPositionAndStyle(_traits->screenNum,
1835                                 _traits->x,
1836                     _traits->y,
1837                     _traits->width,
1838                     _traits->height,
1839                     decorated,
1840                     x,
1841                     y,
1842                     w,
1843                     h,
1844                     windowStyle,
1845                     extendedStyle))
1846    {
1847        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0);
1848        return false;
1849    }
1850
1851    //
1852    // Change the window style
1853    //
1854
1855    ::SetLastError(0);
1856    unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
1857    unsigned int error  = ::GetLastError();
1858    if (result==0 && error)
1859    {
1860        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error);
1861        return false;
1862    }
1863
1864    //
1865    // Change the window extended style
1866    //
1867
1868    ::SetLastError(0);
1869    result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
1870    error  = ::GetLastError();
1871    if (result==0 && error)
1872    {
1873        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error);
1874        return false;
1875    }
1876
1877    //
1878    // Change the window position and size and realize the style changes
1879    //
1880
1881    if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
1882    {
1883        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
1884        return false;
1885    }
1886
1887    //
1888    // Force a repaint of the desktop
1889    //
1890
1891    ::InvalidateRect(NULL, NULL, TRUE);
1892
1893    return true;
1894}
1895
1896bool GraphicsWindowWin32::realizeImplementation()
1897{
1898    if (_realized) return true;
1899
1900    if (!_initialized)
1901    {
1902        init();
1903        if (!_initialized) return false;
1904    }
1905
1906    if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled))
1907    {
1908        // make context current so we can test capabilities and set up context sharing
1909        struct RestoreContext
1910        {
1911            RestoreContext()
1912            {
1913                _hdc = wglGetCurrentDC();
1914                _hglrc = wglGetCurrentContext();
1915            }
1916            ~RestoreContext()
1917            {
1918                wglMakeCurrent(_hdc,_hglrc);
1919            }
1920        protected:
1921            HDC      _hdc;
1922            HGLRC    _hglrc;
1923        } restoreContext;
1924
1925        _realized = true;
1926        bool result = makeCurrent();
1927        _realized = false;
1928
1929        if (!result)
1930        {
1931            return false;
1932        }
1933
1934        // set up sharing of contexts if required
1935        GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast<GraphicsHandleWin32*>(_traits->sharedContext.get());
1936        if (graphicsHandleWin32)
1937        {
1938            if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext()))
1939            {
1940                reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
1941                return false;
1942            }
1943        }
1944
1945        // if vysnc should be on then enable it.
1946        if (_traits->vsync)
1947        {
1948            setSyncToVBlank(_traits->vsync);
1949        }
1950
1951        // If the swap group is active then enable it.
1952        if (_traits->swapGroupEnabled)
1953        {
1954            setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier);
1955        }
1956    }
1957
1958    if (_ownsWindow)
1959    {
1960        //
1961        // Bring the window on top of other ones (including the taskbar if it covers it completely)
1962        //
1963        // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
1964        // Z-order must be used in the code below instead of HWND_TOP.
1965        // @todo: This should be controlled through a flag in the traits (topMostWindow)
1966        //
1967
1968        if (!::SetWindowPos(_hwnd,
1969                            HWND_TOP,
1970                            _windowOriginXToRealize,
1971                            _windowOriginYToRealize,
1972                            _windowWidthToRealize,
1973                            _windowHeightToRealize,
1974                            SWP_SHOWWINDOW))
1975        {
1976            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
1977            return false;
1978        }
1979
1980        if (!::UpdateWindow(_hwnd))
1981        {
1982            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
1983            return false;
1984        }
1985    }
1986
1987    _realized = true;
1988
1989    return true;
1990}
1991
1992bool GraphicsWindowWin32::makeCurrentImplementation()
1993{
1994    if (!_realized)
1995    {
1996        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0);
1997        return false;
1998    }
1999
2000    if( _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues )
2001    {
2002        if( ::wglGetCurrentDC() != _hdc ||
2003            ::wglGetCurrentContext() != _hglrc )
2004        {
2005            if (!::wglMakeCurrent(_hdc, _hglrc))
2006            {
2007                reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2008                return false;
2009            }
2010        }
2011    }
2012
2013    if (!::wglMakeCurrent(_hdc, _hglrc))
2014    {
2015        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2016        return false;
2017    }
2018
2019    return true;
2020}
2021
2022bool GraphicsWindowWin32::releaseContextImplementation()
2023{
2024    if (!::wglMakeCurrent(_hdc, NULL))
2025    {
2026        reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2027        return false;
2028    }
2029
2030    return true;
2031}
2032
2033void GraphicsWindowWin32::closeImplementation()
2034{
2035    destroyWindow();
2036
2037    _initialized = false;
2038    _valid       = false;
2039    _realized    = false;
2040}
2041
2042void GraphicsWindowWin32::swapBuffersImplementation()
2043{
2044    if (!_realized) return;
2045    if (!::SwapBuffers(_hdc) && ::GetLastError() != 0)
2046    {
2047        reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError());
2048    }
2049}
2050
2051void GraphicsWindowWin32::checkEvents()
2052{
2053    if (!_realized) return;
2054
2055    MSG msg;
2056    while (::PeekMessage(&msg, _hwnd, 0, 0, PM_REMOVE))
2057    {
2058        ::TranslateMessage(&msg);
2059        ::DispatchMessage(&msg);
2060    }
2061
2062    if (_closeWindow)
2063    {
2064        _closeWindow = false;
2065        close();
2066    }
2067
2068    if (_destroyWindow)
2069    {
2070        _destroyWindow = false;
2071        destroyWindow(false);
2072    }
2073}
2074
2075void GraphicsWindowWin32::grabFocus()
2076{
2077    if (!::SetForegroundWindow(_hwnd))
2078    {
2079        OSG_WARN << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
2080    }
2081}
2082
2083void GraphicsWindowWin32::grabFocusIfPointerInWindow()
2084{
2085    POINT mousePos;
2086    if (!::GetCursorPos(&mousePos))
2087    {
2088        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError());
2089        return;
2090    }
2091
2092    RECT windowRect;
2093    if (!::GetWindowRect(_hwnd, &windowRect))
2094    {
2095        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError());
2096        return;
2097    }
2098
2099    if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
2100        mousePos.y>=windowRect.top  && mousePos.y<=windowRect.bottom)
2101    {
2102        grabFocus();
2103    }
2104}
2105
2106void GraphicsWindowWin32::requestWarpPointer( float x, float y )
2107{
2108    if (!_realized)
2109    {
2110        OSG_INFO<<"GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
2111        return;
2112    }
2113
2114#if 0
2115    RECT windowRect;
2116    if (!::GetWindowRect(_hwnd, &windowRect))
2117    {
2118        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to get window rectangle", _traits->screenNum, ::GetLastError());
2119        return;
2120    }
2121
2122    if (!::SetCursorPos(windowRect.left + x, windowRect.top + y))
2123    {
2124        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2125        return;
2126    }
2127#else
2128    // MIKEC: NEW CODE
2129    POINT pt;
2130    pt.x = (LONG)x;
2131    pt.y = (LONG)y;
2132
2133    // convert point in client area coordinates to screen coordinates
2134    if (!::ClientToScreen(_hwnd, &pt))
2135    {
2136        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError());
2137    }
2138    if (!::SetCursorPos(pt.x, pt.y))
2139    {
2140        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2141        return;
2142    }
2143#endif
2144
2145    getEventQueue()->mouseWarped(x,y);
2146}
2147
2148bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height)
2149{
2150    unsigned int windowStyle;
2151    unsigned int extendedStyle;
2152
2153    //
2154    // Determine position and size of window with/without decorations to retain the size specified in traits
2155    //
2156
2157    int wx, wy;
2158    unsigned int ww, wh;
2159
2160    if (!determineWindowPositionAndStyle(_traits->screenNum,
2161                                         x,
2162                                         y,
2163                                         width,
2164                                         height,
2165                                         _traits->windowDecoration,
2166                                         wx,
2167                                         wy,
2168                                         ww,
2169                                         wh,
2170                                         windowStyle,
2171                                         extendedStyle))
2172    {
2173        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to determine the window position and style", _traits->screenNum, 0);
2174        return false;
2175    }
2176
2177    if (!::SetWindowPos(_hwnd, HWND_TOP, wx, wy, ww, wh, SWP_SHOWWINDOW | SWP_FRAMECHANGED))
2178    {
2179        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
2180        return false;
2181    }
2182    return true;
2183}
2184
2185void GraphicsWindowWin32::setWindowName( const std::string & name )
2186{
2187    _traits->windowName = name;
2188    SetWindowText(_hwnd, name.c_str());
2189}
2190
2191void GraphicsWindowWin32::useCursor( bool cursorOn )
2192{
2193    if (_traits.valid())
2194        _traits->useCursor = cursorOn;
2195
2196    // note, we are using setCursorImpl to set the cursor, so we can use
2197    // _appMouseCursor to cache the current mouse-cursor
2198    setCursorImpl(cursorOn ? _appMouseCursor : NoCursor);
2199}
2200
2201void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor )
2202{
2203    _appMouseCursor = mouseCursor;
2204    setCursorImpl(mouseCursor);
2205}
2206
2207void GraphicsWindowWin32::setCursorImpl( MouseCursor mouseCursor )
2208{
2209    if (_mouseCursor != mouseCursor)
2210    {
2211        _mouseCursor = mouseCursor;
2212        HCURSOR newCursor = getOrCreateCursor( mouseCursor);
2213        if (newCursor == _currentCursor) return;
2214
2215        _currentCursor = newCursor;
2216        _traits->useCursor = (_currentCursor != NULL) && (_mouseCursor != NoCursor);
2217
2218        if (_mouseCursor != InheritCursor)
2219            ::SetCursor(_currentCursor);
2220    }
2221}
2222
2223HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor)
2224{
2225    std::map<MouseCursor,HCURSOR>::iterator i = _mouseCursorMap.find(mouseCursor);
2226    if (i != _mouseCursorMap.end()) return i->second;
2227
2228    switch (mouseCursor) {
2229    case NoCursor:
2230        _mouseCursorMap[mouseCursor] = NULL;
2231    break;
2232    case RightArrowCursor:
2233        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2234        break;
2235    case LeftArrowCursor:
2236        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2237        break;
2238    case InfoCursor:
2239        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL);
2240        break;
2241    case DestroyCursor:
2242        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2243        break;
2244    case HelpCursor:
2245        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP );
2246        break;
2247    case CycleCursor:
2248        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2249        break;
2250    case SprayCursor:
2251        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL );
2252        break;
2253    case WaitCursor:
2254        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT);
2255        break;
2256    case TextCursor:
2257        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM );
2258        break;
2259    case CrosshairCursor:
2260        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS );
2261        break;
2262    case UpDownCursor:
2263        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS );
2264        break;
2265    case LeftRightCursor:
2266        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2267        break;
2268    case TopSideCursor:
2269        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2270        break;
2271    case BottomSideCursor:
2272        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2273        break;
2274    case LeftSideCursor:
2275        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE);
2276        break;
2277    case RightSideCursor:
2278        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2279        break;
2280    case TopLeftCorner:
2281        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2282        break;
2283    case TopRightCorner:
2284        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2285        break;
2286    case BottomRightCorner:
2287        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2288        break;
2289    case BottomLeftCorner:
2290        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2291        break;
2292    case HandCursor:
2293        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HAND );
2294        break;
2295    default:
2296        break;
2297    }
2298
2299    return _mouseCursorMap[mouseCursor];
2300}
2301
2302void GraphicsWindowWin32::setSwapGroup(bool on, GLuint group, GLuint barrier)
2303{
2304    if (_traits.valid())
2305    {
2306        _traits->swapGroupEnabled = on;
2307        _traits->swapGroup        = group;
2308        _traits->swapBarrier      = barrier;
2309    }
2310
2311    typedef BOOL (GL_APIENTRY *PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
2312    PFNWGLJOINSWAPGROUPNVPROC wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)wglGetProcAddress( "wglJoinSwapGroupNV" );
2313
2314    typedef BOOL (GL_APIENTRY *PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
2315    PFNWGLBINDSWAPBARRIERNVPROC wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)wglGetProcAddress( "wglBindSwapBarrierNV" );
2316
2317    if ((!wglJoinSwapGroupNV) || (!wglBindSwapBarrierNV))
2318    {
2319        OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV(bool, GLuint, GLuint) not supported" << std::endl;
2320        return;
2321    }
2322
2323    int swapGroup = (on ? group : 0);
2324    BOOL resultJoin = wglJoinSwapGroupNV(_hdc, swapGroup);
2325    OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV (" << swapGroup << ") returned " << resultJoin << std::endl;
2326
2327    int swapBarrier = (on ? barrier : 0);
2328    BOOL resultBind = wglBindSwapBarrierNV(swapGroup, swapBarrier);
2329    OSG_INFO << "GraphicsWindowWin32::wglBindSwapBarrierNV (" << swapGroup << ", " << swapBarrier << ") returned " << resultBind << std::endl;
2330}
2331
2332void GraphicsWindowWin32::setSyncToVBlank( bool on )
2333{
2334    if (_traits.valid())
2335    {
2336        _traits->vsync = on;
2337    }
2338
2339//#if 0
2340    // we ought to properly check if the extension is listed as supported rather than just
2341    // if the function pointer resolves through wglGetProcAddress, but in practice everything
2342    // supports this extension
2343    typedef BOOL (GL_APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
2344    PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
2345
2346    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
2347    if( wglSwapIntervalEXT )
2348    {
2349        int swapInterval = (on ? 1 : 0);
2350        wglSwapIntervalEXT(swapInterval);
2351        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl;
2352    }
2353    else
2354    {
2355        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl;
2356    }
2357//#else
2358//    OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl;
2359//#endif
2360}
2361
2362void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask, int& unmodifiedKeySymbol)
2363{
2364    modifierMask = 0;
2365
2366    bool rightSide = (lParam & 0x01000000)!=0;
2367    int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0));
2368
2369    BYTE keyState[256];
2370
2371    if (virtualKey==0 || !::GetKeyboardState(keyState))
2372    {
2373        keySymbol = 0;
2374        return;
2375    }
2376
2377    switch (virtualKey)
2378    {
2379        //////////////////
2380        case VK_LSHIFT   :
2381        //////////////////
2382
2383        modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
2384            break;
2385
2386        //////////////////
2387        case VK_RSHIFT   :
2388        //////////////////
2389
2390        modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT;
2391            break;
2392
2393        //////////////////
2394        case VK_CONTROL  :
2395        case VK_LCONTROL :
2396        //////////////////
2397
2398            virtualKey    = rightSide ? VK_RCONTROL : VK_LCONTROL;
2399            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
2400            break;
2401
2402        //////////////////
2403        case VK_MENU     :
2404        case VK_LMENU    :
2405        //////////////////
2406
2407            virtualKey    = rightSide ? VK_RMENU : VK_LMENU;
2408            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
2409            break;
2410
2411        //////////////////
2412        default          :
2413        //////////////////
2414
2415            virtualKey = wParam;
2416            break;
2417    }
2418
2419    if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
2420    if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
2421
2422    keySymbol = remapWin32Key(virtualKey);
2423
2424    if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
2425    {
2426        keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
2427    }
2428
2429    unmodifiedKeySymbol = keySymbol;
2430
2431    if ((keySymbol & 0xff00)==0)
2432    {
2433        char asciiKey[2];
2434        int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
2435        if (numChars>0) keySymbol = asciiKey[0];
2436    }
2437}
2438
2439void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
2440{
2441    if (getEventQueue()->getUseFixedMouseInputRange())
2442    {
2443        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
2444
2445        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
2446        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
2447    }
2448}
2449
2450LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2451{
2452    //!@todo adapt windows event time to osgGA event queue time for better resolution
2453    double eventTime  = getEventQueue()->getTime();
2454    double resizeTime = eventTime;
2455    _timeOfLastCheckEvents = eventTime;
2456
2457    switch(uMsg)
2458    {
2459        // Wojtek Lewandowski 2010-09-28:
2460        // All web docs on Windows Aero and OpenGL compatibiltiy
2461        // suggest WM_ERASEBKGND should be handled with non NULL value return.
2462        // This sugesstion may be irrelevant for our window class
2463        // as default brush pattern is not set so erase flag is forwarded to WM_PAINT
2464        // and gets ignored when WM_PAINT is handled.
2465        // But it will certainly be safer and not make things worse
2466        // if we handle this message to be sure everything is done as suggested.
2467        case WM_ERASEBKGND :
2468            return TRUE;
2469            break;
2470
2471        /////////////////
2472        case WM_PAINT   :
2473        /////////////////
2474
2475            if (_ownsWindow)
2476            {
2477                PAINTSTRUCT paint;
2478                ::BeginPaint(hwnd, &paint);
2479                ::EndPaint(hwnd, &paint);
2480                requestRedraw();
2481            }
2482            break;
2483
2484        ///////////////////
2485        case WM_MOUSEMOVE :
2486        ///////////////////
2487
2488            {
2489                float mx = GET_X_LPARAM(lParam);
2490                float my = GET_Y_LPARAM(lParam);
2491                transformMouseXY(mx, my);
2492                getEventQueue()->mouseMotion(mx, my, eventTime);
2493            }
2494            break;
2495
2496        /////////////////////
2497        case WM_LBUTTONDOWN :
2498        case WM_MBUTTONDOWN :
2499        case WM_RBUTTONDOWN :
2500        /////////////////////
2501
2502            {
2503                ::SetCapture(hwnd);
2504
2505                int button;
2506
2507                if (uMsg==WM_LBUTTONDOWN)      button = 1;
2508                else if (uMsg==WM_MBUTTONDOWN) button = 2;
2509                else button = 3;
2510
2511                float mx = GET_X_LPARAM(lParam);
2512                float my = GET_Y_LPARAM(lParam);
2513                transformMouseXY(mx, my);
2514                getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
2515            }
2516            break;
2517
2518        /////////////////////
2519        case WM_LBUTTONUP   :
2520        case WM_MBUTTONUP   :
2521        case WM_RBUTTONUP   :
2522        /////////////////////
2523
2524            {
2525                ::ReleaseCapture();
2526
2527                int button;
2528
2529                if (uMsg==WM_LBUTTONUP)      button = 1;
2530                else if (uMsg==WM_MBUTTONUP) button = 2;
2531                else button = 3;
2532
2533                float mx = GET_X_LPARAM(lParam);
2534                float my = GET_Y_LPARAM(lParam);
2535                transformMouseXY(mx, my);
2536                getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
2537            }
2538            break;
2539
2540        ///////////////////////
2541        case WM_LBUTTONDBLCLK :
2542        case WM_MBUTTONDBLCLK :
2543        case WM_RBUTTONDBLCLK :
2544        ///////////////////////
2545
2546            {
2547                ::SetCapture(hwnd);
2548
2549                int button;
2550
2551                if (uMsg==WM_LBUTTONDBLCLK)            button = 1;
2552                else if (uMsg==WM_MBUTTONDBLCLK)    button = 2;
2553                else button = 3;
2554
2555                float mx = GET_X_LPARAM(lParam);
2556                float my = GET_Y_LPARAM(lParam);
2557                transformMouseXY(mx, my);
2558                getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime);
2559            }
2560            break;
2561
2562        ////////////////////
2563        case WM_MOUSEWHEEL :
2564        ////////////////////
2565
2566            getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
2567                                                                            osgGA::GUIEventAdapter::SCROLL_UP,
2568                                         eventTime);
2569            break;
2570
2571        /////////////////
2572        case WM_MOVE    :
2573        case WM_SIZE    :
2574        /////////////////
2575
2576            {
2577                POINT origin;
2578                origin.x = 0;
2579                origin.y = 0;
2580
2581                ::ClientToScreen(hwnd, &origin);
2582
2583                int windowX = origin.x - _screenOriginX;
2584                int windowY = origin.y - _screenOriginY;
2585                resizeTime  = eventTime;
2586
2587                RECT clientRect;
2588                ::GetClientRect(hwnd, &clientRect);
2589
2590                int windowWidth = (clientRect.right == 0) ? 1 : clientRect.right ;
2591                int windowHeight = (clientRect.bottom == 0) ? 1 : clientRect.bottom;;
2592
2593                // send resize event if window position or size was changed
2594                if (windowX!=_traits->x || windowY!=_traits->y || windowWidth!=_traits->width || windowHeight!=_traits->height)
2595                {
2596                    resized(windowX, windowY, windowWidth, windowHeight);
2597                    getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
2598
2599                    // request redraw if window size was changed
2600                    if (windowWidth!=_traits->width || windowHeight!=_traits->height)
2601                        requestRedraw();
2602                }
2603            }
2604            break;
2605
2606        ////////////////////
2607        case WM_KEYDOWN    :
2608        case WM_SYSKEYDOWN :
2609        ////////////////////
2610
2611            {
2612                int keySymbol = 0;
2613                int unmodifiedKeySymbol = 0;
2614                unsigned int modifierMask = 0;
2615                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2616                _keyMap[std::make_pair(keySymbol,unmodifiedKeySymbol)] = true;
2617                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2618                getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
2619            }
2620            break;
2621
2622        //////////////////
2623        case WM_KEYUP    :
2624        case WM_SYSKEYUP :
2625        //////////////////
2626
2627            {
2628                int keySymbol = 0;
2629                int unmodifiedKeySymbol = 0;
2630                unsigned int modifierMask = 0;
2631                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2632                _keyMap[std::make_pair(keySymbol, unmodifiedKeySymbol)] = false;
2633                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2634                getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
2635            }
2636            break;
2637
2638        ///////////////////
2639        case WM_SETCURSOR :
2640        ///////////////////
2641            //The cursor is only modified in response to the WM_SETCURSOR message if the mouse cursor isn't set to
2642            //InheritCursor.  InheritCursor lets the user manage the cursor externally.
2643            if (_mouseCursor != InheritCursor)
2644            {
2645                if (_traits->useCursor)
2646                    ::SetCursor( _currentCursor);
2647                else
2648                    ::SetCursor(NULL);
2649                return TRUE;
2650            }
2651            break;
2652
2653        ///////////////////
2654        case WM_SETFOCUS :
2655        ///////////////////
2656            // Check keys and send a message if the key is pressed when the
2657            // focus comes back to the window.
2658            // I don't really like this hard-coded loop, but the key codes
2659            // (VK_* constants) seem to go from 0x08 to 0xFE so it should be
2660            // ok. See winuser.h for the key codes.
2661            for (unsigned int i = 0x08; i < 0xFF; i++)
2662            {
2663                // Wojciech Lewandowski: 2011/09/12
2664                // Skip CONTROL | MENU | SHIFT tests because we are polling exact left or right keys
2665                // above return press for both right and left so we may end up with incosistent
2666                // modifier mask if we report left control & right control while only right was pressed
2667                LONG rightSideCode = 0;
2668                switch( i )
2669                {
2670                    case VK_CONTROL:
2671                    case VK_SHIFT:
2672                    case VK_MENU:
2673                        continue;
2674
2675                    case VK_RCONTROL:
2676                    case VK_RSHIFT:
2677                    case VK_RMENU:
2678                        rightSideCode = 0x01000000;
2679                }
2680                if ((::GetAsyncKeyState(i) & 0x8000) != 0)
2681                {
2682                    // Compute lParam because subsequent adaptKey will rely on correct lParam
2683                    UINT scanCode = ::MapVirtualKeyEx( i, 0, ::GetKeyboardLayout(0));
2684                    // Set Extended Key bit + Scan Code + 30 bit to indicate key was set before sending message
2685                    // See Windows SDK help on WM_KEYDOWN for explanation
2686                    LONG lParam = rightSideCode | ( ( scanCode & 0xFF ) << 16 ) | (1 << 30);
2687                    ::SendMessage(hwnd, WM_KEYDOWN, i, lParam );
2688                }
2689            }
2690            break;
2691
2692        ///////////////////
2693        case WM_KILLFOCUS :
2694        ///////////////////
2695
2696            // Release all keys that were pressed when the window lost focus.
2697            for (std::map<std::pair<int, int>, bool>::iterator key = _keyMap.begin();
2698                 key != _keyMap.end(); ++key)
2699            {
2700                if (key->second)
2701                {
2702                    getEventQueue()->keyRelease(key->first.first, key->first.second);
2703                    key->second = false;
2704                }
2705            }
2706            break;
2707
2708        ///////////////////
2709        case WM_NCHITTEST :
2710        ///////////////////
2711            {
2712                LONG_PTR result = _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2713                                                        ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2714
2715                switch(result)
2716                {
2717                case HTLEFT:
2718                case HTRIGHT:
2719                    setCursorImpl(LeftRightCursor);
2720                    break;
2721                case HTTOP:
2722                case HTBOTTOM:
2723                    setCursorImpl(UpDownCursor);
2724                    break;
2725                case HTTOPLEFT:
2726                    setCursorImpl(TopLeftCorner);
2727                    break;
2728                case HTTOPRIGHT:
2729                    setCursorImpl(TopRightCorner);
2730                    break;
2731                case HTBOTTOMLEFT:
2732                    setCursorImpl(BottomLeftCorner);
2733                    break;
2734                case HTBOTTOMRIGHT:
2735                case HTGROWBOX:
2736                    setCursorImpl(BottomRightCorner);
2737                    break;
2738                case HTSYSMENU:
2739                case HTCAPTION:
2740                case HTMAXBUTTON:
2741                case HTMINBUTTON:
2742                case HTCLOSE:
2743                case HTHELP:
2744                   setCursorImpl(LeftArrowCursor);
2745                   break;
2746
2747                default:
2748                    if (_traits->useCursor && _appMouseCursor != InheritCursor)
2749                        setCursorImpl(_appMouseCursor);
2750                    break;
2751                }
2752                return result;
2753            }
2754            break;
2755
2756        /////////////////
2757        case WM_CLOSE   :
2758        /////////////////
2759
2760            getEventQueue()->closeWindow(eventTime);
2761            break;
2762
2763        /////////////////
2764        case WM_DESTROY :
2765        /////////////////
2766
2767            _destroyWindow = true;
2768            if (_ownsWindow)
2769            {
2770                ::PostQuitMessage(0);
2771            }
2772            break;
2773
2774        //////////////
2775        case WM_QUIT :
2776        //////////////
2777
2778            _closeWindow = true;
2779            return wParam;
2780
2781        //////////////
2782        case WM_TOUCH:
2783        /////////////
2784            {
2785                unsigned int numInputs = (unsigned int) wParam;
2786                TOUCHINPUT* ti = new TOUCHINPUT[numInputs];
2787                osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
2788                if(getTouchInputInfoFunc && (*getTouchInputInfoFunc)((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT)))
2789                {
2790                    // For each contact, dispatch the message to the appropriate message handler.
2791                    for(unsigned int i=0; i< numInputs; ++i)
2792                    {
2793                        if(ti[i].dwFlags & TOUCHEVENTF_DOWN)
2794                        {
2795                            if (!osg_event) {
2796                                osg_event = getEventQueue()->touchBegan( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100 , ti[i].y/100);
2797                            } else {
2798                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100, ti[i].y/100);
2799                            }
2800                        }
2801                        else if(ti[i].dwFlags & TOUCHEVENTF_MOVE)
2802                        {
2803                            if (!osg_event) {
2804                                osg_event = getEventQueue()->touchMoved(  ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x/ 100, ti[i].y/ 100);
2805                            } else {
2806                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x / 100, ti[i].y/100);
2807                            }
2808                        }
2809                        else if(ti[i].dwFlags & TOUCHEVENTF_UP)
2810                        {
2811                            // No double tap detection with RAW TOUCH Events, sorry.
2812                            if (!osg_event) {
2813                                osg_event = getEventQueue()->touchEnded( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x/ 100, ti[i].y/ 100, 1);
2814                            } else {
2815                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x / 100, ti[i].y/100);
2816                            }
2817                        }
2818                    }
2819                }
2820                if (closeTouchInputHandleFunc)
2821                    (*closeTouchInputHandleFunc)((HTOUCHINPUT)lParam);
2822                delete [] ti;
2823            }
2824            break;
2825
2826        /////////////////
2827        default         :
2828        /////////////////
2829
2830            if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
2831            break;
2832    }
2833
2834    if (_ownsWindow) return 0;
2835
2836    return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2837                                 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2838}
2839
2840
2841//////////////////////////////////////////////////////////////////////////////
2842//  Class responsible for registering the Win32 Windowing System interface
2843//////////////////////////////////////////////////////////////////////////////
2844
2845struct RegisterWindowingSystemInterfaceProxy
2846{
2847    RegisterWindowingSystemInterfaceProxy()
2848    {
2849        osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
2850    }
2851
2852    ~RegisterWindowingSystemInterfaceProxy()
2853    {
2854        if (osg::Referenced::getDeleteHandler())
2855        {
2856            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2857            osg::Referenced::getDeleteHandler()->flushAll();
2858        }
2859
2860        osg::GraphicsContext::setWindowingSystemInterface(0);
2861    }
2862};
2863
2864static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2865
2866} // namespace OsgViewer
2867
2868
2869// declare C entry point for static compilation.
2870extern "C" void OSGVIEWER_EXPORT graphicswindow_Win32(void)
2871{
2872    osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
2873}
2874
2875
2876void GraphicsWindowWin32::raiseWindow()
2877{
2878
2879    SetWindowPos(_hwnd, HWND_TOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2880    SetWindowPos(_hwnd, HWND_NOTOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2881
2882}
Note: See TracBrowser for help on using the browser.