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