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

Revision 13429, 104.1 kB (checked in by robert, 3 days ago)

Moved widgets from VolumeEditorWidget? to TransferFunctionWidget?, and widget utilities into WidgetUtils?.

  • 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    // make sure the event queue has the correct window rectangle size and input range
1189    getEventQueue()->syncWindowRectangleWithGraphcisContext();
1190
1191    // 2008/10/03
1192    // Few days ago NVidia released WHQL certified drivers ver 178.13.
1193    // These drivers (as well as former beta ver 177.92) were free from the bug described below.
1194    // So it looks like its high time to make the workaround inactive by default.
1195    // If you happen to still use earlier drivers and have problems consider changing to new ones or
1196    // activate OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND macro def through CMake advanced vars.
1197#ifdef OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND
1198
1199    // 2008/05/12
1200    // Workaround for Bugs in NVidia drivers for windows XP / multithreaded / dualview / multicore CPU
1201    // affects GeForce 6x00, 7x00, 8x00 boards (others were not tested) driver versions 174.xx - 175.xx
1202    // pre 174.xx had other issues so reverting is not an option (statitistics, fbo)
1203    // drivers release 175.16 is the latest currently available
1204    //
1205    // When using OpenGL in threaded app ( main thread sets up context / renderer thread draws using it )
1206    // first wglMakeCurrent seems to not work right and screw OpenGL context driver data:
1207    // 1: succesive drawing shows a number of artifacts in TriangleStrips and TriangleFans
1208    // 2: weird behaviour of FramBufferObjects (glGenFramebuffer generates already generated ids ...)
1209    // Looks like repeating wglMakeCurrent call fixes all these issues
1210    // wglMakeCurrent call can impact performance so I try to minimize number of
1211    // wglMakeCurrent calls by checking current HDC and GL context
1212    // and repeat wglMakeCurrent only when they change for current thread
1213
1214    _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = true;
1215#endif
1216
1217    const char* str = getenv("OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND");
1218    if (str)
1219    {
1220        _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = (strcmp(str, "on")==0 || strcmp(str, "ON")==0 || strcmp(str, "On")==0 );
1221    }
1222}
1223
1224bool GraphicsWindowWin32::createWindow()
1225{
1226    unsigned int extendedStyle;
1227    unsigned int windowStyle;
1228
1229    if (!determineWindowPositionAndStyle(_traits->screenNum,
1230                                         _traits->x,
1231                                         _traits->y,
1232                                         _traits->width,
1233                                         _traits->height,
1234                                         _traits->windowDecoration,
1235                                         _windowOriginXToRealize,
1236                                         _windowOriginYToRealize,
1237                                         _windowWidthToRealize,
1238                                         _windowHeightToRealize,
1239                                         windowStyle,
1240                                         extendedStyle))
1241    {
1242        reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
1243        return false;
1244    }
1245
1246    _hwnd = ::CreateWindowEx(extendedStyle,
1247                             _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() :
1248                                                  Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(),
1249                             _traits->windowName.c_str(),
1250                             windowStyle,
1251                             _windowOriginXToRealize,
1252                             _windowOriginYToRealize,
1253                             _windowWidthToRealize,
1254                             _windowHeightToRealize,
1255                             NULL,
1256                             NULL,
1257                             ::GetModuleHandle(NULL),
1258                             NULL);
1259    if (_hwnd==0)
1260    {
1261        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError());
1262        return false;
1263    }
1264
1265    _hdc = ::GetDC(_hwnd);
1266    if (_hdc==0)
1267    {
1268        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1269        destroyWindow();
1270        _hwnd = 0;
1271        return false;
1272    }
1273
1274    //
1275    // Set the pixel format according to traits specified
1276    //
1277
1278    if (!setPixelFormat())
1279    {
1280        ::ReleaseDC(_hwnd, _hdc);
1281        _hdc  = 0;
1282        destroyWindow();
1283        return false;
1284    }
1285
1286    //
1287    // Create the OpenGL rendering context associated with this window
1288    //
1289
1290    _hglrc = createContextImplementation();
1291    if (_hglrc==0)
1292    {
1293        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1294        ::ReleaseDC(_hwnd, _hdc);
1295        _hdc  = 0;
1296        destroyWindow();
1297        return false;
1298    }
1299
1300    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1301
1302    if (registerTouchWindowFunc)
1303        (*registerTouchWindowFunc)( _hwnd, 0);
1304    return true;
1305}
1306
1307bool GraphicsWindowWin32::setWindow( HWND handle )
1308{
1309    if (_initialized)
1310    {
1311        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError());
1312        return false;
1313    }
1314
1315    if (handle==0)
1316    {
1317        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError());
1318        return false;
1319    }
1320
1321    _hwnd = handle;
1322    if (_hwnd==0)
1323    {
1324        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError());
1325        return false;
1326    }
1327
1328    _hdc = ::GetDC(_hwnd);
1329    if (_hdc==0)
1330    {
1331        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1332        _hwnd = 0;
1333        return false;
1334    }
1335
1336    //
1337    // Check if we must set the pixel format of the inherited window
1338    //
1339
1340    if (!setPixelFormat())
1341    {
1342        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError());
1343        ::ReleaseDC(_hwnd, _hdc);
1344        _hdc  = 0;
1345        _hwnd = 0;
1346        return false;
1347    }
1348
1349    _hglrc = createContextImplementation();
1350    if (_hglrc==0)
1351    {
1352        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1353        ::ReleaseDC(_hwnd, _hdc);
1354        _hdc  = 0;
1355        _hwnd = 0;
1356        return false;
1357    }
1358
1359    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1360
1361    if (!windowData || windowData->_installEventHandler)
1362    {
1363        if (!registerWindowProcedure())
1364        {
1365            ::wglDeleteContext(_hglrc);
1366            _hglrc = 0;
1367            ::ReleaseDC(_hwnd, _hdc);
1368            _hdc  = 0;
1369            _hwnd = 0;
1370            return false;
1371        }
1372    }
1373
1374    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1375
1376    _initialized = true;
1377    _valid       = true;
1378
1379    return true;
1380}
1381
1382void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
1383{
1384    if (_destroying) return;
1385    _destroying = true;
1386
1387    if (_graphicsThread && _graphicsThread->isRunning())
1388    {
1389        // find all the viewers that might own use this graphics context
1390        osg::GraphicsContext::Cameras cameras = getCameras();
1391        for(osg::GraphicsContext::Cameras::iterator it=cameras.begin(); it!=cameras.end(); ++it)
1392        {
1393            osgViewer::View* view = dynamic_cast<osgViewer::View*>((*it)->getView());
1394            osgViewer::ViewerBase* viewerBase = view ? view->getViewerBase() : 0;
1395            if (viewerBase && viewerBase->areThreadsRunning())
1396            {
1397                viewerBase->stopThreading();
1398            }
1399        }
1400    }
1401
1402    if (_hdc)
1403    {
1404        releaseContext();
1405
1406        if (_hglrc)
1407        {
1408            ::wglDeleteContext(_hglrc);
1409            _hglrc = 0;
1410        }
1411
1412        ::ReleaseDC(_hwnd, _hdc);
1413        _hdc = 0;
1414    }
1415
1416    (void)unregisterWindowProcedure();
1417
1418    if (_hwnd)
1419    {
1420        Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1421        if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd);
1422        _hwnd = 0;
1423    }
1424
1425    _initialized = false;
1426    _realized    = false;
1427    _valid       = false;
1428    _destroying  = false;
1429}
1430
1431void GraphicsWindowWin32::registerWindow()
1432{
1433  Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1434}
1435
1436void GraphicsWindowWin32::unregisterWindow()
1437{
1438  Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1439}
1440
1441bool GraphicsWindowWin32::registerWindowProcedure()
1442{
1443    ::SetLastError(0);
1444    _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc));
1445    unsigned int error = ::GetLastError();
1446
1447    if (_windowProcedure==0 && error)
1448    {
1449        reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error);
1450        return false;
1451    }
1452
1453    return true;
1454}
1455
1456bool GraphicsWindowWin32::unregisterWindowProcedure()
1457{
1458    if (_windowProcedure==0 || _hwnd==0) return true;
1459
1460    ::SetLastError(0);
1461    WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure));
1462    unsigned int error = ::GetLastError();
1463
1464    if (wndProc==0 && error)
1465    {
1466        reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error);
1467        return false;
1468    }
1469
1470    _windowProcedure = 0;
1471
1472    return true;
1473}
1474
1475bool GraphicsWindowWin32::determineWindowPositionAndStyle( unsigned int  screenNum,
1476                                                           int           clientAreaX,
1477                                                           int           clientAreaY,
1478                                                           unsigned int  clientAreaWidth,
1479                                                           unsigned int  clientAreaHeight,
1480                                                           bool          decorated,
1481                                                           int&          x,
1482                                                           int&          y,
1483                                                           unsigned int& w,
1484                                                           unsigned int& h,
1485                                                           unsigned int& style,
1486                                                           unsigned int& extendedStyle )
1487{
1488    if (_traits==0) return false;
1489
1490    //
1491    // Query the screen position and size
1492    //
1493
1494    osg::GraphicsContext::ScreenIdentifier screenId(screenNum);
1495    Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface();
1496
1497    windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
1498    if (_screenWidth==0 || _screenHeight==0) return false;
1499
1500    x = clientAreaX + _screenOriginX;
1501    y = clientAreaY + _screenOriginY;
1502    w = clientAreaWidth;
1503    h = clientAreaHeight;
1504
1505    style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1506
1507    extendedStyle = 0;
1508
1509    if (decorated)
1510    {
1511        style |= WS_CAPTION     |
1512                 WS_SYSMENU     |
1513                 WS_MINIMIZEBOX |
1514                 WS_MAXIMIZEBOX;
1515
1516        if (_traits->supportsResize) style |= WS_SIZEBOX;
1517
1518        extendedStyle = WS_EX_APPWINDOW           |
1519                        WS_EX_OVERLAPPEDWINDOW |
1520                        WS_EX_ACCEPTFILES      |
1521                        WS_EX_LTRREADING;
1522
1523        RECT corners;
1524
1525        corners.left   = x;
1526        corners.top    = y;
1527        corners.right  = x + w - 1;
1528        corners.bottom = y + h - 1;
1529
1530        //
1531        // Determine the location of the window corners in order to have
1532        // a client area of the requested size
1533        //
1534
1535        if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
1536        {
1537            reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError());
1538            return false;
1539        }
1540
1541        x = corners.left;
1542        y = corners.top;
1543        w = corners.right  - corners.left + 1;
1544        h = corners.bottom - corners.top  + 1;
1545    }
1546
1547    return true;
1548}
1549
1550static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits,
1551                                              WGLIntegerAttributes&               attributes,
1552                                              bool                                allowSwapExchangeARB )
1553{
1554    attributes.begin();
1555
1556    attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
1557    attributes.enable(WGL_SUPPORT_OPENGL_ARB);
1558
1559    attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
1560    attributes.set(WGL_PIXEL_TYPE_ARB,   WGL_TYPE_RGBA_ARB);
1561
1562    attributes.set(WGL_COLOR_BITS_ARB,   traits.red + traits.green + traits.blue);
1563    attributes.set(WGL_RED_BITS_ARB,     traits.red);
1564    attributes.set(WGL_GREEN_BITS_ARB,   traits.green);
1565    attributes.set(WGL_BLUE_BITS_ARB,    traits.blue);
1566    attributes.set(WGL_DEPTH_BITS_ARB,   traits.depth);
1567
1568    if (traits.doubleBuffer)
1569    {
1570        attributes.enable(WGL_DOUBLE_BUFFER_ARB);
1571
1572        switch ( traits.swapMethod )
1573        {
1574            case osg::DisplaySettings::SWAP_COPY:
1575                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB);
1576                break;
1577            case osg::DisplaySettings::SWAP_EXCHANGE:
1578                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1579                break;
1580            case osg::DisplaySettings::SWAP_UNDEFINED:
1581                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_UNDEFINED_ARB);
1582                break;
1583            case osg::DisplaySettings::SWAP_DEFAULT:
1584                // Wojtek Lewandowski 2010-09-28:
1585                // Keep backward compatibility if no method is selected via traits
1586                // and let wglSwapExchangeARB flag select swap method.
1587                // However, I would rather remove this flag because its
1588                // now redundant to Traits::swapMethod and it looks like
1589                // WGL_SWAP_EXCHANGE_ARB is the GL default when no WGL_SWAP attrib is given.
1590                // To be precise: At least on Windows 7 and Nvidia it seems to be a default.
1591                if ( allowSwapExchangeARB )
1592                    attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1593                break;
1594        }
1595    }
1596
1597    if (traits.alpha)         attributes.set(WGL_ALPHA_BITS_ARB,     traits.alpha);
1598    if (traits.stencil)       attributes.set(WGL_STENCIL_BITS_ARB,   traits.stencil);
1599    if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers);
1600    if (traits.samples)       attributes.set(WGL_SAMPLES_ARB,        traits.samples);
1601
1602    if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB);
1603
1604    attributes.end();
1605}
1606
1607static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits)
1608{
1609    //
1610    // Access the entry point for the wglChoosePixelFormatARB function
1611    //
1612
1613    WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
1614    if (wglChoosePixelFormatARB==0)
1615    {
1616        // = openGLContext.getTraits()
1617        reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError());
1618        PIXELFORMATDESCRIPTOR pixelFormat = {
1619            sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
1620            1,                     // version number
1621            PFD_DRAW_TO_WINDOW |   // support window
1622            PFD_SUPPORT_OPENGL |   // support OpenGL
1623            (_traits->doubleBuffer ? PFD_DOUBLEBUFFER : NULL) |      // double buffered ?
1624            (_traits->swapMethod ==  osg::DisplaySettings::SWAP_COPY ? PFD_SWAP_COPY : NULL) |
1625            (_traits->swapMethod ==  osg::DisplaySettings::SWAP_EXCHANGE ? PFD_SWAP_EXCHANGE : NULL),
1626            PFD_TYPE_RGBA,         // RGBA type
1627            _traits->red + _traits->green + _traits->blue,                // color depth
1628            _traits->red ,0, _traits->green ,0, _traits->blue, 0,          // shift bits ignored
1629            _traits->alpha,          // alpha buffer ?
1630            0,                     // shift bit ignored
1631            0,                     // no accumulation buffer
1632            0, 0, 0, 0,            // accum bits ignored
1633            _traits->depth,          // 32 or 16 bit z-buffer ?
1634            _traits->stencil,        // stencil buffer ?
1635            0,                     // no auxiliary buffer
1636            PFD_MAIN_PLANE,        // main layer
1637            0,                     // reserved
1638            0, 0, 0                // layer masks ignored
1639        };
1640        int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
1641        if (pixelFormatIndex == 0)
1642        {
1643            reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError());
1644            return -1;
1645        }
1646
1647        ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat);
1648        if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0)  && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0))
1649        {
1650            OSG_WARN << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl;
1651        }
1652        return pixelFormatIndex;
1653    }
1654
1655    int pixelFormatIndex = 0;
1656    unsigned int numMatchingPixelFormats = 0;
1657
1658    if (!wglChoosePixelFormatARB(hdc,
1659                                 formatSpecifications.get(),
1660                                 NULL,
1661                                 1,
1662                                 &pixelFormatIndex,
1663                                 &numMatchingPixelFormats))
1664    {
1665        reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError());
1666        return -1;
1667    }
1668
1669    return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex;
1670}
1671
1672bool GraphicsWindowWin32::setPixelFormat()
1673{
1674    Win32WindowingSystem::OpenGLContext openGLContext;
1675    if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false;
1676
1677    //
1678    // Build the specifications of the requested pixel format
1679    //
1680
1681    WGLIntegerAttributes formatSpecs;
1682    ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);
1683
1684    //
1685    // Choose the closest matching pixel format from the specified traits
1686    //
1687
1688    int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1689
1690    if (pixelFormatIndex<0)
1691    {
1692            unsigned int bpp;
1693            Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp);
1694            if (bpp < 32) {
1695                OSG_INFO    << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, "
1696                                        << bpp
1697                                        << " bits per pixel on screen #"
1698                                        << _traits->screenNum
1699                                        << std::endl;
1700
1701                _traits->red = bpp / 4; //integer devide, determine minimum number of bits we will accept
1702                _traits->green = bpp / 4;
1703                _traits->blue = bpp / 4;
1704                ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB
1705                pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1706            }
1707    }
1708    if (pixelFormatIndex<0)
1709    {
1710        ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false);
1711        pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1712        if (pixelFormatIndex<0)
1713        {
1714            reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0);
1715            return false;
1716        }
1717
1718        OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #"
1719                               << _traits->screenNum
1720                               << std::endl;
1721    }
1722
1723    //
1724    // Set the pixel format found
1725    //
1726
1727    PIXELFORMATDESCRIPTOR pfd;
1728    ::memset(&pfd, 0, sizeof(pfd));
1729    pfd.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
1730    pfd.nVersion = 1;
1731
1732    if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
1733    {
1734        reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError());
1735        return false;
1736    }
1737
1738    return true;
1739}
1740
1741HGLRC GraphicsWindowWin32::createContextImplementation()
1742{
1743    HGLRC context( NULL );
1744
1745    if( OSG_GL3_FEATURES )
1746    {
1747        OSG_NOTIFY( osg::INFO ) << "GL3: Attempting to create OpenGL3 context." << std::endl;
1748        OSG_NOTIFY( osg::INFO ) << "GL3: version: " << _traits->glContextVersion << std::endl;
1749        OSG_NOTIFY( osg::INFO ) << "GL3: context flags: " << _traits->glContextFlags << std::endl;
1750        OSG_NOTIFY( osg::INFO ) << "GL3: profile: " << _traits->glContextProfileMask << std::endl;
1751
1752        Win32WindowingSystem::OpenGLContext openGLContext;
1753        if( !Win32WindowingSystem::getInterface()->getSampleOpenGLContext( openGLContext, _hdc, _screenOriginX, _screenOriginY ) )
1754        {
1755            reportErrorForScreen( "GL3: Can't create sample context.",
1756                _traits->screenNum, ::GetLastError() );
1757        }
1758        else
1759        {
1760            PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
1761                ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress( "wglCreateContextAttribsARB" );
1762            if( wglCreateContextAttribsARB==0 )
1763            {
1764                reportErrorForScreen( "GL3: wglCreateContextAttribsARB not available.",
1765                    _traits->screenNum, ::GetLastError() );
1766            }
1767            else
1768            {
1769                unsigned int idx( 0 );
1770                int attribs[ 16 ];
1771
1772                unsigned int major = 1, minor = 0;
1773                if( !_traits->getContextVersion(major, minor) || major<3 )
1774                {
1775                    OSG_NOTIFY( osg::WARN ) << "GL3: Non-GL3 version number: " << _traits->glContextVersion << std::endl;
1776                }
1777
1778                attribs[ idx++ ] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1779                attribs[ idx++ ] = major;
1780                attribs[ idx++ ] = WGL_CONTEXT_MINOR_VERSION_ARB;
1781                attribs[ idx++ ] = minor;
1782                if( _traits->glContextFlags != 0 )
1783                {
1784                    attribs[ idx++ ] = WGL_CONTEXT_FLAGS_ARB;
1785                    attribs[ idx++ ] = _traits->glContextFlags;
1786                }
1787                if( _traits->glContextProfileMask != 0 )
1788                {
1789                    attribs[ idx++ ] = WGL_CONTEXT_PROFILE_MASK_ARB;
1790                    attribs[ idx++ ] = _traits->glContextProfileMask;
1791                }
1792                attribs[ idx++ ] = 0;
1793
1794                context = wglCreateContextAttribsARB( _hdc, 0, attribs );
1795                if( context == NULL )
1796                {
1797                    reportErrorForScreen( "GL3: wglCreateContextAttribsARB returned NULL.",
1798                        _traits->screenNum, ::GetLastError() );
1799                }
1800                else
1801                {
1802                    OSG_NOTIFY( osg::INFO ) << "GL3: context created successfully." << std::endl;
1803                }
1804            }
1805        }
1806    }
1807
1808    // TBD insert GL ES 2 suppurt, if required for Win32.
1809
1810    // If platform context creation fails for any reason,
1811    // we'll create a standard context. This means you could
1812    // build OSG for GL3, have the context creation fail
1813    // (because you have the wrong driver), and end up with
1814    // a GL3 context. Something else will likely fail down
1815    // the line, as the GL3-built OSG will assume GL3 features
1816    // are present.
1817    //
1818    // This is also the typical path for GL 1/2 context creation.
1819    if( context == NULL )
1820        context = ::wglCreateContext(_hdc);
1821
1822    return( context );
1823}
1824
1825bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated )
1826{
1827    unsigned int windowStyle;
1828    unsigned int extendedStyle;
1829
1830    //
1831    // Determine position and size of window with/without decorations to retain the size specified in traits
1832    //
1833
1834    int x, y;
1835    unsigned int w, h;
1836
1837    if (!determineWindowPositionAndStyle(_traits->screenNum,
1838                                 _traits->x,
1839                     _traits->y,
1840                     _traits->width,
1841                     _traits->height,
1842                     decorated,
1843                     x,
1844                     y,
1845                     w,
1846                     h,
1847                     windowStyle,
1848                     extendedStyle))
1849    {
1850        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0);
1851        return false;
1852    }
1853
1854    //
1855    // Change the window style
1856    //
1857
1858    ::SetLastError(0);
1859    unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
1860    unsigned int error  = ::GetLastError();
1861    if (result==0 && error)
1862    {
1863        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error);
1864        return false;
1865    }
1866
1867    //
1868    // Change the window extended style
1869    //
1870
1871    ::SetLastError(0);
1872    result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
1873    error  = ::GetLastError();
1874    if (result==0 && error)
1875    {
1876        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error);
1877        return false;
1878    }
1879
1880    //
1881    // Change the window position and size and realize the style changes
1882    //
1883
1884    if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
1885    {
1886        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
1887        return false;
1888    }
1889
1890    //
1891    // Force a repaint of the desktop
1892    //
1893
1894    ::InvalidateRect(NULL, NULL, TRUE);
1895
1896    return true;
1897}
1898
1899bool GraphicsWindowWin32::realizeImplementation()
1900{
1901    if (_realized) return true;
1902
1903    if (!_initialized)
1904    {
1905        init();
1906        if (!_initialized) return false;
1907    }
1908
1909    if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled))
1910    {
1911        // make context current so we can test capabilities and set up context sharing
1912        struct RestoreContext
1913        {
1914            RestoreContext()
1915            {
1916                _hdc = wglGetCurrentDC();
1917                _hglrc = wglGetCurrentContext();
1918            }
1919            ~RestoreContext()
1920            {
1921                wglMakeCurrent(_hdc,_hglrc);
1922            }
1923        protected:
1924            HDC      _hdc;
1925            HGLRC    _hglrc;
1926        } restoreContext;
1927
1928        _realized = true;
1929        bool result = makeCurrent();
1930        _realized = false;
1931
1932        if (!result)
1933        {
1934            return false;
1935        }
1936
1937        // set up sharing of contexts if required
1938        GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast<GraphicsHandleWin32*>(_traits->sharedContext.get());
1939        if (graphicsHandleWin32)
1940        {
1941            if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext()))
1942            {
1943                reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
1944                return false;
1945            }
1946        }
1947
1948        // if vysnc should be on then enable it.
1949        if (_traits->vsync)
1950        {
1951            setSyncToVBlank(_traits->vsync);
1952        }
1953
1954        // If the swap group is active then enable it.
1955        if (_traits->swapGroupEnabled)
1956        {
1957            setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier);
1958        }
1959    }
1960
1961    if (_ownsWindow)
1962    {
1963        //
1964        // Bring the window on top of other ones (including the taskbar if it covers it completely)
1965        //
1966        // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
1967        // Z-order must be used in the code below instead of HWND_TOP.
1968        // @todo: This should be controlled through a flag in the traits (topMostWindow)
1969        //
1970
1971        if (!::SetWindowPos(_hwnd,
1972                            HWND_TOP,
1973                            _windowOriginXToRealize,
1974                            _windowOriginYToRealize,
1975                            _windowWidthToRealize,
1976                            _windowHeightToRealize,
1977                            SWP_SHOWWINDOW))
1978        {
1979            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
1980            return false;
1981        }
1982
1983        if (!::UpdateWindow(_hwnd))
1984        {
1985            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
1986            return false;
1987        }
1988    }
1989
1990    _realized = true;
1991
1992    // make sure the event queue has the correct window rectangle size and input range
1993    getEventQueue()->syncWindowRectangleWithGraphcisContext();
1994
1995    return true;
1996}
1997
1998bool GraphicsWindowWin32::makeCurrentImplementation()
1999{
2000    if (!_realized)
2001    {
2002        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0);
2003        return false;
2004    }
2005
2006    if( _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues )
2007    {
2008        if( ::wglGetCurrentDC() != _hdc ||
2009            ::wglGetCurrentContext() != _hglrc )
2010        {
2011            if (!::wglMakeCurrent(_hdc, _hglrc))
2012            {
2013                reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2014                return false;
2015            }
2016        }
2017    }
2018
2019    if (!::wglMakeCurrent(_hdc, _hglrc))
2020    {
2021        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2022        return false;
2023    }
2024
2025    return true;
2026}
2027
2028bool GraphicsWindowWin32::releaseContextImplementation()
2029{
2030    if (!::wglMakeCurrent(_hdc, NULL))
2031    {
2032        reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2033        return false;
2034    }
2035
2036    return true;
2037}
2038
2039void GraphicsWindowWin32::closeImplementation()
2040{
2041    destroyWindow();
2042
2043    _initialized = false;
2044    _valid       = false;
2045    _realized    = false;
2046}
2047
2048void GraphicsWindowWin32::swapBuffersImplementation()
2049{
2050    if (!_realized) return;
2051    if (!::SwapBuffers(_hdc) && ::GetLastError() != 0)
2052    {
2053        reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError());
2054    }
2055}
2056
2057bool GraphicsWindowWin32::checkEvents()
2058{
2059    if (!_realized) return false;
2060
2061    MSG msg;
2062    while (::PeekMessage(&msg, _hwnd, 0, 0, PM_REMOVE))
2063    {
2064        ::TranslateMessage(&msg);
2065        ::DispatchMessage(&msg);
2066    }
2067
2068    if (_closeWindow)
2069    {
2070        _closeWindow = false;
2071        close();
2072    }
2073
2074    if (_destroyWindow)
2075    {
2076        _destroyWindow = false;
2077        destroyWindow(false);
2078    }
2079           
2080    return !(getEventQueue()->empty());
2081}
2082
2083void GraphicsWindowWin32::grabFocus()
2084{
2085    if (!::SetForegroundWindow(_hwnd))
2086    {
2087        OSG_WARN << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
2088    }
2089}
2090
2091void GraphicsWindowWin32::grabFocusIfPointerInWindow()
2092{
2093    POINT mousePos;
2094    if (!::GetCursorPos(&mousePos))
2095    {
2096        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError());
2097        return;
2098    }
2099
2100    RECT windowRect;
2101    if (!::GetWindowRect(_hwnd, &windowRect))
2102    {
2103        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError());
2104        return;
2105    }
2106
2107    if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
2108        mousePos.y>=windowRect.top  && mousePos.y<=windowRect.bottom)
2109    {
2110        grabFocus();
2111    }
2112}
2113
2114void GraphicsWindowWin32::requestWarpPointer( float x, float y )
2115{
2116    if (!_realized)
2117    {
2118        OSG_INFO<<"GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
2119        return;
2120    }
2121
2122#if 0
2123    RECT windowRect;
2124    if (!::GetWindowRect(_hwnd, &windowRect))
2125    {
2126        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to get window rectangle", _traits->screenNum, ::GetLastError());
2127        return;
2128    }
2129
2130    if (!::SetCursorPos(windowRect.left + x, windowRect.top + y))
2131    {
2132        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2133        return;
2134    }
2135#else
2136    // MIKEC: NEW CODE
2137    POINT pt;
2138    pt.x = (LONG)x;
2139    pt.y = (LONG)y;
2140
2141    // convert point in client area coordinates to screen coordinates
2142    if (!::ClientToScreen(_hwnd, &pt))
2143    {
2144        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError());
2145    }
2146    if (!::SetCursorPos(pt.x, pt.y))
2147    {
2148        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2149        return;
2150    }
2151#endif
2152
2153    getEventQueue()->mouseWarped(x,y);
2154}
2155
2156bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height)
2157{
2158    unsigned int windowStyle;
2159    unsigned int extendedStyle;
2160
2161    //
2162    // Determine position and size of window with/without decorations to retain the size specified in traits
2163    //
2164
2165    int wx, wy;
2166    unsigned int ww, wh;
2167
2168    if (!determineWindowPositionAndStyle(_traits->screenNum,
2169                                         x,
2170                                         y,
2171                                         width,
2172                                         height,
2173                                         _traits->windowDecoration,
2174                                         wx,
2175                                         wy,
2176                                         ww,
2177                                         wh,
2178                                         windowStyle,
2179                                         extendedStyle))
2180    {
2181        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to determine the window position and style", _traits->screenNum, 0);
2182        return false;
2183    }
2184
2185    if (!::SetWindowPos(_hwnd, HWND_TOP, wx, wy, ww, wh, SWP_SHOWWINDOW | SWP_FRAMECHANGED))
2186    {
2187        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
2188        return false;
2189    }
2190    return true;
2191}
2192
2193void GraphicsWindowWin32::setWindowName( const std::string & name )
2194{
2195    _traits->windowName = name;
2196    SetWindowText(_hwnd, name.c_str());
2197}
2198
2199void GraphicsWindowWin32::useCursor( bool cursorOn )
2200{
2201    if (_traits.valid())
2202        _traits->useCursor = cursorOn;
2203
2204    // note, we are using setCursorImpl to set the cursor, so we can use
2205    // _appMouseCursor to cache the current mouse-cursor
2206    setCursorImpl(cursorOn ? _appMouseCursor : NoCursor);
2207}
2208
2209void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor )
2210{
2211    _appMouseCursor = mouseCursor;
2212    setCursorImpl(mouseCursor);
2213}
2214
2215void GraphicsWindowWin32::setCursorImpl( MouseCursor mouseCursor )
2216{
2217    if (_mouseCursor != mouseCursor)
2218    {
2219        _mouseCursor = mouseCursor;
2220        HCURSOR newCursor = getOrCreateCursor( mouseCursor);
2221        if (newCursor == _currentCursor) return;
2222
2223        _currentCursor = newCursor;
2224        _traits->useCursor = (_currentCursor != NULL) && (_mouseCursor != NoCursor);
2225
2226        if (_mouseCursor != InheritCursor)
2227            ::SetCursor(_currentCursor);
2228    }
2229}
2230
2231HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor)
2232{
2233    std::map<MouseCursor,HCURSOR>::iterator i = _mouseCursorMap.find(mouseCursor);
2234    if (i != _mouseCursorMap.end()) return i->second;
2235
2236    switch (mouseCursor) {
2237    case NoCursor:
2238        _mouseCursorMap[mouseCursor] = NULL;
2239    break;
2240    case RightArrowCursor:
2241        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2242        break;
2243    case LeftArrowCursor:
2244        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2245        break;
2246    case InfoCursor:
2247        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL);
2248        break;
2249    case DestroyCursor:
2250        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2251        break;
2252    case HelpCursor:
2253        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP );
2254        break;
2255    case CycleCursor:
2256        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2257        break;
2258    case SprayCursor:
2259        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL );
2260        break;
2261    case WaitCursor:
2262        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT);
2263        break;
2264    case TextCursor:
2265        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM );
2266        break;
2267    case CrosshairCursor:
2268        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS );
2269        break;
2270    case UpDownCursor:
2271        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS );
2272        break;
2273    case LeftRightCursor:
2274        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2275        break;
2276    case TopSideCursor:
2277        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2278        break;
2279    case BottomSideCursor:
2280        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2281        break;
2282    case LeftSideCursor:
2283        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE);
2284        break;
2285    case RightSideCursor:
2286        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2287        break;
2288    case TopLeftCorner:
2289        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2290        break;
2291    case TopRightCorner:
2292        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2293        break;
2294    case BottomRightCorner:
2295        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2296        break;
2297    case BottomLeftCorner:
2298        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2299        break;
2300    case HandCursor:
2301        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HAND );
2302        break;
2303    default:
2304        break;
2305    }
2306
2307    return _mouseCursorMap[mouseCursor];
2308}
2309
2310void GraphicsWindowWin32::setSwapGroup(bool on, GLuint group, GLuint barrier)
2311{
2312    if (_traits.valid())
2313    {
2314        _traits->swapGroupEnabled = on;
2315        _traits->swapGroup        = group;
2316        _traits->swapBarrier      = barrier;
2317    }
2318
2319    typedef BOOL (GL_APIENTRY *PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
2320    PFNWGLJOINSWAPGROUPNVPROC wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)wglGetProcAddress( "wglJoinSwapGroupNV" );
2321
2322    typedef BOOL (GL_APIENTRY *PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
2323    PFNWGLBINDSWAPBARRIERNVPROC wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)wglGetProcAddress( "wglBindSwapBarrierNV" );
2324
2325    if ((!wglJoinSwapGroupNV) || (!wglBindSwapBarrierNV))
2326    {
2327        OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV(bool, GLuint, GLuint) not supported" << std::endl;
2328        return;
2329    }
2330
2331    int swapGroup = (on ? group : 0);
2332    BOOL resultJoin = wglJoinSwapGroupNV(_hdc, swapGroup);
2333    OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV (" << swapGroup << ") returned " << resultJoin << std::endl;
2334
2335    int swapBarrier = (on ? barrier : 0);
2336    BOOL resultBind = wglBindSwapBarrierNV(swapGroup, swapBarrier);
2337    OSG_INFO << "GraphicsWindowWin32::wglBindSwapBarrierNV (" << swapGroup << ", " << swapBarrier << ") returned " << resultBind << std::endl;
2338}
2339
2340void GraphicsWindowWin32::setSyncToVBlank( bool on )
2341{
2342    if (_traits.valid())
2343    {
2344        _traits->vsync = on;
2345    }
2346
2347//#if 0
2348    // we ought to properly check if the extension is listed as supported rather than just
2349    // if the function pointer resolves through wglGetProcAddress, but in practice everything
2350    // supports this extension
2351    typedef BOOL (GL_APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
2352    PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
2353
2354    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
2355    if( wglSwapIntervalEXT )
2356    {
2357        int swapInterval = (on ? 1 : 0);
2358        wglSwapIntervalEXT(swapInterval);
2359        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl;
2360    }
2361    else
2362    {
2363        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl;
2364    }
2365//#else
2366//    OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl;
2367//#endif
2368}
2369
2370void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask, int& unmodifiedKeySymbol)
2371{
2372    modifierMask = 0;
2373
2374    bool rightSide = (lParam & 0x01000000)!=0;
2375    int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0));
2376
2377    BYTE keyState[256];
2378
2379    if (virtualKey==0 || !::GetKeyboardState(keyState))
2380    {
2381        keySymbol = 0;
2382        return;
2383    }
2384
2385    switch (virtualKey)
2386    {
2387        //////////////////
2388        case VK_LSHIFT   :
2389        //////////////////
2390
2391        modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
2392            break;
2393
2394        //////////////////
2395        case VK_RSHIFT   :
2396        //////////////////
2397
2398        modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT;
2399            break;
2400
2401        //////////////////
2402        case VK_CONTROL  :
2403        case VK_LCONTROL :
2404        //////////////////
2405
2406            virtualKey    = rightSide ? VK_RCONTROL : VK_LCONTROL;
2407            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
2408            break;
2409
2410        //////////////////
2411        case VK_MENU     :
2412        case VK_LMENU    :
2413        //////////////////
2414
2415            virtualKey    = rightSide ? VK_RMENU : VK_LMENU;
2416            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
2417            break;
2418
2419        //////////////////
2420        default          :
2421        //////////////////
2422
2423            virtualKey = wParam;
2424            break;
2425    }
2426
2427    if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
2428    if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
2429
2430    keySymbol = remapWin32Key(virtualKey);
2431
2432    if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
2433    {
2434        keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
2435    }
2436
2437    unmodifiedKeySymbol = keySymbol;
2438
2439    if ((keySymbol & 0xff00)==0)
2440    {
2441        char asciiKey[2];
2442        int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
2443        if (numChars>0) keySymbol = asciiKey[0];
2444    }
2445}
2446
2447void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
2448{
2449    if (getEventQueue()->getUseFixedMouseInputRange())
2450    {
2451        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
2452
2453        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
2454        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
2455    }
2456}
2457
2458LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2459{
2460    //!@todo adapt windows event time to osgGA event queue time for better resolution
2461    double eventTime  = getEventQueue()->getTime();
2462    double resizeTime = eventTime;
2463    _timeOfLastCheckEvents = eventTime;
2464
2465    switch(uMsg)
2466    {
2467        // Wojtek Lewandowski 2010-09-28:
2468        // All web docs on Windows Aero and OpenGL compatibiltiy
2469        // suggest WM_ERASEBKGND should be handled with non NULL value return.
2470        // This sugesstion may be irrelevant for our window class
2471        // as default brush pattern is not set so erase flag is forwarded to WM_PAINT
2472        // and gets ignored when WM_PAINT is handled.
2473        // But it will certainly be safer and not make things worse
2474        // if we handle this message to be sure everything is done as suggested.
2475        case WM_ERASEBKGND :
2476            return TRUE;
2477            break;
2478
2479        /////////////////
2480        case WM_PAINT   :
2481        /////////////////
2482
2483            if (_ownsWindow)
2484            {
2485                PAINTSTRUCT paint;
2486                ::BeginPaint(hwnd, &paint);
2487                ::EndPaint(hwnd, &paint);
2488                requestRedraw();
2489            }
2490            break;
2491
2492        ///////////////////
2493        case WM_MOUSEMOVE :
2494        ///////////////////
2495
2496            {
2497                float mx = GET_X_LPARAM(lParam);
2498                float my = GET_Y_LPARAM(lParam);
2499                transformMouseXY(mx, my);
2500                getEventQueue()->mouseMotion(mx, my, eventTime);
2501            }
2502            break;
2503
2504        /////////////////////
2505        case WM_LBUTTONDOWN :
2506        case WM_MBUTTONDOWN :
2507        case WM_RBUTTONDOWN :
2508        /////////////////////
2509
2510            {
2511                ::SetCapture(hwnd);
2512
2513                int button;
2514
2515                if (uMsg==WM_LBUTTONDOWN)      button = 1;
2516                else if (uMsg==WM_MBUTTONDOWN) button = 2;
2517                else button = 3;
2518
2519                _capturedMouseButtons.insert(button);
2520
2521                float mx = GET_X_LPARAM(lParam);
2522                float my = GET_Y_LPARAM(lParam);
2523                transformMouseXY(mx, my);
2524                getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
2525            }
2526            break;
2527
2528        /////////////////////
2529        case WM_LBUTTONUP   :
2530        case WM_MBUTTONUP   :
2531        case WM_RBUTTONUP   :
2532        /////////////////////
2533
2534            {
2535                int button;
2536
2537                if (uMsg==WM_LBUTTONUP)      button = 1;
2538                else if (uMsg==WM_MBUTTONUP) button = 2;
2539                else button = 3;
2540
2541                _capturedMouseButtons.erase(button);
2542
2543                if(_capturedMouseButtons.empty())
2544                  ::ReleaseCapture();
2545
2546                float mx = GET_X_LPARAM(lParam);
2547                float my = GET_Y_LPARAM(lParam);
2548                transformMouseXY(mx, my);
2549                getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
2550            }
2551            break;
2552
2553        ///////////////////////
2554        case WM_LBUTTONDBLCLK :
2555        case WM_MBUTTONDBLCLK :
2556        case WM_RBUTTONDBLCLK :
2557        ///////////////////////
2558
2559            {
2560                ::SetCapture(hwnd);
2561
2562                int button;
2563
2564                if (uMsg==WM_LBUTTONDBLCLK)            button = 1;
2565                else if (uMsg==WM_MBUTTONDBLCLK)    button = 2;
2566                else button = 3;
2567
2568                _capturedMouseButtons.insert(button);
2569
2570                float mx = GET_X_LPARAM(lParam);
2571                float my = GET_Y_LPARAM(lParam);
2572                transformMouseXY(mx, my);
2573                getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime);
2574            }
2575            break;
2576
2577        ////////////////////
2578        case WM_MOUSEWHEEL :
2579        ////////////////////
2580
2581            getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
2582                                                                            osgGA::GUIEventAdapter::SCROLL_UP,
2583                                         eventTime);
2584            break;
2585
2586        /////////////////
2587        case WM_MOVE    :
2588        case WM_SIZE    :
2589        /////////////////
2590
2591            {
2592                POINT origin;
2593                origin.x = 0;
2594                origin.y = 0;
2595
2596                ::ClientToScreen(hwnd, &origin);
2597
2598                int windowX = origin.x - _screenOriginX;
2599                int windowY = origin.y - _screenOriginY;
2600                resizeTime  = eventTime;
2601
2602                RECT clientRect;
2603                ::GetClientRect(hwnd, &clientRect);
2604
2605                int windowWidth = (clientRect.right == 0) ? 1 : clientRect.right ;
2606                int windowHeight = (clientRect.bottom == 0) ? 1 : clientRect.bottom;;
2607
2608                // send resize event if window position or size was changed
2609                if (windowX!=_traits->x || windowY!=_traits->y || windowWidth!=_traits->width || windowHeight!=_traits->height)
2610                {
2611                    resized(windowX, windowY, windowWidth, windowHeight);
2612                    getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
2613
2614                    // request redraw if window size was changed
2615                    if (windowWidth!=_traits->width || windowHeight!=_traits->height)
2616                        requestRedraw();
2617                }
2618            }
2619            break;
2620
2621        ////////////////////
2622        case WM_KEYDOWN    :
2623        case WM_SYSKEYDOWN :
2624        ////////////////////
2625
2626            {
2627                int keySymbol = 0;
2628                int unmodifiedKeySymbol = 0;
2629                unsigned int modifierMask = 0;
2630                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2631                _keyMap[std::make_pair(keySymbol,unmodifiedKeySymbol)] = true;
2632                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2633                getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
2634            }
2635            break;
2636
2637        //////////////////
2638        case WM_KEYUP    :
2639        case WM_SYSKEYUP :
2640        //////////////////
2641
2642            {
2643                int keySymbol = 0;
2644                int unmodifiedKeySymbol = 0;
2645                unsigned int modifierMask = 0;
2646                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2647                _keyMap[std::make_pair(keySymbol, unmodifiedKeySymbol)] = false;
2648                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2649                getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
2650            }
2651            break;
2652
2653        ///////////////////
2654        case WM_SETCURSOR :
2655        ///////////////////
2656            //The cursor is only modified in response to the WM_SETCURSOR message if the mouse cursor isn't set to
2657            //InheritCursor.  InheritCursor lets the user manage the cursor externally.
2658            if (_mouseCursor != InheritCursor)
2659            {
2660                if (_traits->useCursor)
2661                    ::SetCursor( _currentCursor);
2662                else
2663                    ::SetCursor(NULL);
2664                return TRUE;
2665            }
2666            break;
2667
2668        ///////////////////
2669        case WM_SETFOCUS :
2670        ///////////////////
2671            // Check keys and send a message if the key is pressed when the
2672            // focus comes back to the window.
2673            // I don't really like this hard-coded loop, but the key codes
2674            // (VK_* constants) seem to go from 0x08 to 0xFE so it should be
2675            // ok. See winuser.h for the key codes.
2676            for (unsigned int i = 0x08; i < 0xFF; i++)
2677            {
2678                // Wojciech Lewandowski: 2011/09/12
2679                // Skip CONTROL | MENU | SHIFT tests because we are polling exact left or right keys
2680                // above return press for both right and left so we may end up with incosistent
2681                // modifier mask if we report left control & right control while only right was pressed
2682                LONG rightSideCode = 0;
2683                switch( i )
2684                {
2685                    case VK_CONTROL:
2686                    case VK_SHIFT:
2687                    case VK_MENU:
2688                        continue;
2689
2690                    case VK_RCONTROL:
2691                    case VK_RSHIFT:
2692                    case VK_RMENU:
2693                        rightSideCode = 0x01000000;
2694                }
2695                if ((::GetAsyncKeyState(i) & 0x8000) != 0)
2696                {
2697                    // Compute lParam because subsequent adaptKey will rely on correct lParam
2698                    UINT scanCode = ::MapVirtualKeyEx( i, 0, ::GetKeyboardLayout(0));
2699                    // Set Extended Key bit + Scan Code + 30 bit to indicate key was set before sending message
2700                    // See Windows SDK help on WM_KEYDOWN for explanation
2701                    LONG lParam = rightSideCode | ( ( scanCode & 0xFF ) << 16 ) | (1 << 30);
2702                    ::SendMessage(hwnd, WM_KEYDOWN, i, lParam );
2703                }
2704            }
2705            break;
2706
2707        ///////////////////
2708        case WM_KILLFOCUS :
2709        ///////////////////
2710
2711            // Release all keys that were pressed when the window lost focus.
2712            for (std::map<std::pair<int, int>, bool>::iterator key = _keyMap.begin();
2713                 key != _keyMap.end(); ++key)
2714            {
2715                if (key->second)
2716                {
2717                    getEventQueue()->keyRelease(key->first.first, key->first.second);
2718                    key->second = false;
2719                }
2720            }
2721
2722            _capturedMouseButtons.clear();
2723
2724            break;
2725
2726        ///////////////////
2727        case WM_NCHITTEST :
2728        ///////////////////
2729            {
2730                LONG_PTR result = _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2731                                                        ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2732
2733                switch(result)
2734                {
2735                case HTLEFT:
2736                case HTRIGHT:
2737                    setCursorImpl(LeftRightCursor);
2738                    break;
2739                case HTTOP:
2740                case HTBOTTOM:
2741                    setCursorImpl(UpDownCursor);
2742                    break;
2743                case HTTOPLEFT:
2744                    setCursorImpl(TopLeftCorner);
2745                    break;
2746                case HTTOPRIGHT:
2747                    setCursorImpl(TopRightCorner);
2748                    break;
2749                case HTBOTTOMLEFT:
2750                    setCursorImpl(BottomLeftCorner);
2751                    break;
2752                case HTBOTTOMRIGHT:
2753                case HTGROWBOX:
2754                    setCursorImpl(BottomRightCorner);
2755                    break;
2756                case HTSYSMENU:
2757                case HTCAPTION:
2758                case HTMAXBUTTON:
2759                case HTMINBUTTON:
2760                case HTCLOSE:
2761                case HTHELP:
2762                   setCursorImpl(LeftArrowCursor);
2763                   break;
2764
2765                default:
2766                    if (_traits->useCursor && _appMouseCursor != InheritCursor)
2767                        setCursorImpl(_appMouseCursor);
2768                    break;
2769                }
2770                return result;
2771            }
2772            break;
2773
2774        /////////////////
2775        case WM_CLOSE   :
2776        /////////////////
2777
2778            getEventQueue()->closeWindow(eventTime);
2779            break;
2780
2781        /////////////////
2782        case WM_DESTROY :
2783        /////////////////
2784
2785            _destroyWindow = true;
2786            if (_ownsWindow)
2787            {
2788                ::PostQuitMessage(0);
2789            }
2790            break;
2791
2792        //////////////
2793        case WM_QUIT :
2794        //////////////
2795
2796            _closeWindow = true;
2797            return wParam;
2798
2799        //////////////
2800        case WM_TOUCH:
2801        /////////////
2802            {
2803                unsigned int numInputs = (unsigned int) wParam;
2804                TOUCHINPUT* ti = new TOUCHINPUT[numInputs];
2805                osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
2806                if(getTouchInputInfoFunc && (*getTouchInputInfoFunc)((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT)))
2807                {
2808                    // For each contact, dispatch the message to the appropriate message handler.
2809                    for(unsigned int i=0; i< numInputs; ++i)
2810                    {
2811                        if(ti[i].dwFlags & TOUCHEVENTF_DOWN)
2812                        {
2813                            if (!osg_event) {
2814                                osg_event = getEventQueue()->touchBegan( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100 , ti[i].y/100);
2815                            } else {
2816                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100, ti[i].y/100);
2817                            }
2818                        }
2819                        else if(ti[i].dwFlags & TOUCHEVENTF_MOVE)
2820                        {
2821                            if (!osg_event) {
2822                                osg_event = getEventQueue()->touchMoved(  ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x/ 100, ti[i].y/ 100);
2823                            } else {
2824                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x / 100, ti[i].y/100);
2825                            }
2826                        }
2827                        else if(ti[i].dwFlags & TOUCHEVENTF_UP)
2828                        {
2829                            // No double tap detection with RAW TOUCH Events, sorry.
2830                            if (!osg_event) {
2831                                osg_event = getEventQueue()->touchEnded( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x/ 100, ti[i].y/ 100, 1);
2832                            } else {
2833                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x / 100, ti[i].y/100);
2834                            }
2835                        }
2836                    }
2837                }
2838                if (closeTouchInputHandleFunc)
2839                    (*closeTouchInputHandleFunc)((HTOUCHINPUT)lParam);
2840                delete [] ti;
2841            }
2842            break;
2843
2844        /////////////////
2845        default         :
2846        /////////////////
2847
2848            if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
2849            break;
2850    }
2851
2852    if (_ownsWindow) return 0;
2853
2854    return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2855                                 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2856}
2857
2858
2859//////////////////////////////////////////////////////////////////////////////
2860//  Class responsible for registering the Win32 Windowing System interface
2861//////////////////////////////////////////////////////////////////////////////
2862
2863struct RegisterWindowingSystemInterfaceProxy
2864{
2865    RegisterWindowingSystemInterfaceProxy()
2866    {
2867        osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
2868    }
2869
2870    ~RegisterWindowingSystemInterfaceProxy()
2871    {
2872        if (osg::Referenced::getDeleteHandler())
2873        {
2874            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2875            osg::Referenced::getDeleteHandler()->flushAll();
2876        }
2877
2878        osg::GraphicsContext::setWindowingSystemInterface(0);
2879    }
2880};
2881
2882static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2883
2884} // namespace OsgViewer
2885
2886
2887// declare C entry point for static compilation.
2888extern "C" void OSGVIEWER_EXPORT graphicswindow_Win32(void)
2889{
2890    osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
2891}
2892
2893
2894void GraphicsWindowWin32::raiseWindow()
2895{
2896
2897    SetWindowPos(_hwnd, HWND_TOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2898    SetWindowPos(_hwnd, HWND_NOTOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2899
2900}
Note: See TracBrowser for help on using the browser.