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

Revision 7074, 74.3 kB (checked in by robert, 7 years ago)

Added include/osg/GLObjects + .cpp which provide osg::flush*DeletedGLObjects() methods.

Added and cleaned up DeleteHandler? calls in osgViewer to help avoid crashes on exit.

Changed DatabasePager? across to dynamically checcking osg::getCompileContext(..)

Updated wrappers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12 *
13 * This file is Copyright (C) 2007 - André Garneau (andre@pixdev.com) and licensed under OSGPL.
14 *
15 * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference.
16 * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004  Don Burns.
17 */
18
19#include <osgViewer/api/Win32/GraphicsWindowWin32>
20#include <osgViewer/api/Win32/PixelBufferWin32>
21#include <vector>
22#include <map>
23#include <sstream>
24#include <windowsx.h>
25
26using namespace osgViewer;
27
28namespace osgViewer
29{
30
31//
32// Defines from the WGL_ARB_pixel_format specification document
33// See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
34//
35
36#define WGL_NUMBER_PIXEL_FORMATS_ARB            0x2000
37#define WGL_DRAW_TO_WINDOW_ARB                  0x2001
38#define WGL_DRAW_TO_BITMAP_ARB                  0x2002
39#define WGL_ACCELERATION_ARB                    0x2003
40#define WGL_NEED_PALETTE_ARB                    0x2004
41#define WGL_NEED_SYSTEM_PALETTE_ARB             0x2005
42#define WGL_SWAP_LAYER_BUFFERS_ARB              0x2006
43#define WGL_SWAP_METHOD_ARB                     0x2007
44#define WGL_NUMBER_OVERLAYS_ARB                 0x2008
45#define WGL_NUMBER_UNDERLAYS_ARB                0x2009
46#define WGL_TRANSPARENT_ARB                     0x200A
47#define WGL_TRANSPARENT_RED_VALUE_ARB           0x2037
48#define WGL_TRANSPARENT_GREEN_VALUE_ARB         0x2038
49#define WGL_TRANSPARENT_BLUE_VALUE_ARB          0x2039
50#define WGL_TRANSPARENT_ALPHA_VALUE_ARB         0x203A
51#define WGL_TRANSPARENT_INDEX_VALUE_ARB         0x203B
52#define WGL_SHARE_DEPTH_ARB                     0x200C
53#define WGL_SHARE_STENCIL_ARB                   0x200D
54#define WGL_SHARE_ACCUM_ARB                     0x200E
55#define WGL_SUPPORT_GDI_ARB                     0x200F
56#define WGL_SUPPORT_OPENGL_ARB                  0x2010
57#define WGL_DOUBLE_BUFFER_ARB                   0x2011
58#define WGL_STEREO_ARB                          0x2012
59#define WGL_PIXEL_TYPE_ARB                      0x2013
60#define WGL_COLOR_BITS_ARB                      0x2014
61#define WGL_RED_BITS_ARB                        0x2015
62#define WGL_RED_SHIFT_ARB                       0x2016
63#define WGL_GREEN_BITS_ARB                      0x2017
64#define WGL_GREEN_SHIFT_ARB                     0x2018
65#define WGL_BLUE_BITS_ARB                       0x2019
66#define WGL_BLUE_SHIFT_ARB                      0x201A
67#define WGL_ALPHA_BITS_ARB                      0x201B
68#define WGL_ALPHA_SHIFT_ARB                     0x201C
69#define WGL_ACCUM_BITS_ARB                      0x201D
70#define WGL_ACCUM_RED_BITS_ARB                  0x201E
71#define WGL_ACCUM_GREEN_BITS_ARB                0x201F
72#define WGL_ACCUM_BLUE_BITS_ARB                 0x2020
73#define WGL_ACCUM_ALPHA_BITS_ARB                0x2021
74#define WGL_DEPTH_BITS_ARB                      0x2022
75#define WGL_STENCIL_BITS_ARB                    0x2023
76#define WGL_AUX_BUFFERS_ARB                     0x2024
77#define WGL_NO_ACCELERATION_ARB                 0x2025
78#define WGL_GENERIC_ACCELERATION_ARB            0x2026
79#define WGL_FULL_ACCELERATION_ARB               0x2027
80#define WGL_SWAP_EXCHANGE_ARB                   0x2028
81#define WGL_SWAP_COPY_ARB                       0x2029
82#define WGL_SWAP_UNDEFINED_ARB                  0x202A
83#define WGL_TYPE_RGBA_ARB                       0x202B
84#define WGL_TYPE_COLORINDEX_ARB                 0x202C
85#define WGL_SAMPLE_BUFFERS_ARB                  0x2041
86#define WGL_SAMPLES_ARB                         0x2042
87
88//
89// Entry points used from the WGL extensions
90//
91//    BOOL wglChoosePixelFormatARB(HDC hdc,
92//                                 const int *piAttribIList,
93//                                 const FLOAT *pfAttribFList,
94//                                 UINT nMaxFormats,
95//                                 int *piFormats,
96//                                 UINT *nNumFormats);
97//
98
99typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * );
100
101//
102// Utility class to specify the visual attributes for wglChoosePixelFormatARB() function
103//
104
105template <typename T> class WGLAttributes
106{
107  public:
108
109      WGLAttributes()  {}
110      ~WGLAttributes() {}
111
112      void begin()                              { m_parameters.clear(); }
113      void set( const T& id, const T& value )   { add(id); add(value); }
114      void enable( const T& id )                { add(id); add(true); }
115      void disable( const T& id )               { add(id); add(false); }
116      void end()                                { add(0); }
117
118      const T* get() const                      { return &m_parameters.front(); }
119
120  protected:
121
122      void add( const T& t )                    { m_parameters.push_back(t); }
123
124      std::vector<T>    m_parameters;        // parameters added
125
126  private:
127
128      // No implementation for these
129      WGLAttributes( const WGLAttributes& );
130      WGLAttributes& operator=( const WGLAttributes& );
131};
132
133typedef WGLAttributes<int>     WGLIntegerAttributes;
134typedef WGLAttributes<float> WGLFloatAttributes;
135
136//
137// Class responsible for interfacing with the Win32 Window Manager
138// The behavior of this class is specific to OSG needs and is not a
139// generic Windowing interface.
140//
141// NOTE: This class is intended to be used by a single-thread.
142//         Multi-threading is not enabled for performance reasons.
143//         The creation/deletion of graphics windows should be done
144//         by a single controller thread. That thread should then
145//         call the checkEvents() method of all created windows periodically.
146//         This is the case with OSG as a "main" thread does all
147//         setup, update & event processing. Rendering is done (optionally) by other threads.
148//
149// !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the
150//        creation and event message processing for all windows it manages. This
151//        is to relieve the "main" thread from having to do this synchronously
152//        during frame generation. The "main" thread would only have to process
153//          each osgGA-type window event queue.
154//
155
156class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
157{
158  public:
159
160    // A class representing an OpenGL rendering context
161    class OpenGLContext
162    {
163      public:
164
165        OpenGLContext()
166        : _previousHdc(0),
167          _previousHglrc(0),
168          _hwnd(0),
169          _hdc(0),
170          _hglrc(0),
171          _restorePreviousOnExit(false)
172        {}
173
174        OpenGLContext( HWND hwnd, HDC hdc, HGLRC hglrc )
175        : _previousHdc(0),
176          _previousHglrc(0),
177          _hwnd(hwnd),
178          _hdc(hdc),
179          _hglrc(hglrc),
180          _restorePreviousOnExit(false)
181        {}
182
183        ~OpenGLContext();
184
185        void set( HWND hwnd, HDC hdc, HGLRC hglrc )
186        {
187            _hwnd  = hwnd;
188            _hdc   = hdc;
189            _hglrc = hglrc;
190        }
191
192        HDC deviceContext() { return _hdc; }
193
194        bool makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit );
195
196      protected:
197
198        //
199        // Data members
200        //
201
202        HDC   _previousHdc;                // previously HDC to restore rendering context on
203        HGLRC _previousHglrc;           // previously current rendering context
204        HWND  _hwnd;                    // handle to OpenGL window
205        HDC   _hdc;                     // handle to device context
206        HGLRC _hglrc;                   // handle to OpenGL rendering context
207        bool  _restorePreviousOnExit;   // restore original context on exit
208
209        private:
210
211        // no implementation for these
212        OpenGLContext( const OpenGLContext& );
213        OpenGLContext& operator=( const OpenGLContext& );
214    };
215
216    static std::string osgGraphicsWindowWithCursorClass;    //!< Name of Win32 window class (with cursor) used by OSG graphics window instances
217    static std::string osgGraphicsWindowWithoutCursorClass; //!< Name of Win32 window class (without cursor) used by OSG graphics window instances
218
219    Win32WindowingSystem();
220    ~Win32WindowingSystem();
221
222    // Access the Win32 windowing system through this singleton class.
223    static Win32WindowingSystem* getInterface()
224    {
225        static Win32WindowingSystem* win32Interface = new Win32WindowingSystem;
226        return win32Interface;
227    }
228
229    // Return the number of screens present in the system
230    virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si );
231
232    // Return the resolution of specified screen
233    // (0,0) is returned if screen is unknown
234    virtual void getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height );
235
236    // Return the bits per pixel of specified screen
237    // (0) is returned if screen is unknown
238    virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel );
239
240    // Set the resolution for given screen
241    virtual bool setScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height );
242
243    // Set the refresh rate for given screen
244    virtual bool setScreenRefreshRate( const osg::GraphicsContext::ScreenIdentifier& si, double refreshRate );
245
246    // Return the screen position and width/height.
247    // all zeros returned if screen is unknown
248    virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height );
249
250    // Create a graphics context with given traits
251    virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits );
252
253    // Register a newly created native window along with its application counterpart
254    // This is required to maintain a link between Windows messages and the application window object
255    // at event processing time
256    virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window );
257
258    // Unregister a window
259    // This is called as part of a window being torn down
260    virtual void unregisterWindow( HWND hwnd );
261
262    // Get the application window object associated with a native window
263    virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd );
264
265    // Return a valid sample OpenGL Device Context and current rendering context that can be used with wglXYZ extensions
266    virtual bool getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY );
267
268  protected:
269
270    // Display devices present in the system
271    typedef std::vector<DISPLAY_DEVICE> DisplayDevices;
272
273    // Map Win32 window handles to GraphicsWindowWin32 instance
274    typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* >  WindowHandleEntry;
275    typedef std::map<  HWND, osgViewer::GraphicsWindowWin32* >  WindowHandles;
276
277    // Enumerate all display devices and return in passed container
278    void enumerateDisplayDevices( DisplayDevices& displayDevices ) const;
279
280    // Get the screen device current mode information
281    bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
282
283    // Change the screen settings (resolution, refresh rate, etc.)
284    bool changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
285
286    // Register the window classes used by OSG graphics window instances
287    void registerWindowClasses();
288
289    // Unregister the window classes used by OSG graphics window instances
290    void unregisterWindowClasses();
291
292    // Data members
293    WindowHandles       _activeWindows;                //!< handles to active windows
294    bool                _windowClassesRegistered;      //!< true after window classes have been registered
295
296 private:
297
298     // No implementation for these
299     Win32WindowingSystem( const Win32WindowingSystem& );
300     Win32WindowingSystem& operator=( const Win32WindowingSystem& );
301};
302
303///////////////////////////////////////////////////////////////////////////////
304//                             Error reporting
305//////////////////////////////////////////////////////////////////////////////
306
307static void reportError( const std::string& msg )
308{
309    osg::notify(osg::WARN) << "Error: " << msg.c_str() << std::endl;
310}
311
312static void reportError( const std::string& msg, unsigned int errorCode )
313{
314    //
315    // Some APIs are documented as returning the error in ::GetLastError but apparently do not
316    // Skip "Reason" field if the errorCode is still success
317    //
318
319    if (errorCode==0)
320    {
321        reportError(msg);
322        return;
323    }
324
325    osg::notify(osg::WARN) << "Windows Error #"   << errorCode << ": " << msg.c_str();
326
327    LPVOID lpMsgBuf;
328
329    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
330                      NULL,
331                      errorCode,
332                      0, // Default language
333                      (LPTSTR) &lpMsgBuf,
334                      0,
335                      NULL)!=0)
336    {
337        osg::notify(osg::WARN) << ". Reason: " << LPTSTR(lpMsgBuf) << std::endl;
338        ::LocalFree(lpMsgBuf);
339    }
340    else
341    {
342        osg::notify(osg::WARN) << std::endl;
343    }
344}
345
346static void reportErrorForScreen( const std::string& msg, const osg::GraphicsContext::ScreenIdentifier& si, unsigned int errorCode )
347{
348    std::ostringstream str;
349
350    str << "[Screen #" << si.screenNum << "] " << msg;
351    reportError(str.str(), errorCode);
352}
353
354//////////////////////////////////////////////////////////////////////////////
355//                       Keyboard key mapping for Win32
356//////////////////////////////////////////////////////////////////////////////
357
358class Win32KeyboardMap
359{
360    public:
361
362        Win32KeyboardMap()
363        {
364            _keymap[VK_ESCAPE       ] = osgGA::GUIEventAdapter::KEY_Escape;
365            _keymap[VK_F1           ] = osgGA::GUIEventAdapter::KEY_F1;
366            _keymap[VK_F2           ] = osgGA::GUIEventAdapter::KEY_F2;
367            _keymap[VK_F3           ] = osgGA::GUIEventAdapter::KEY_F3;
368            _keymap[VK_F4           ] = osgGA::GUIEventAdapter::KEY_F4;
369            _keymap[VK_F5           ] = osgGA::GUIEventAdapter::KEY_F5;
370            _keymap[VK_F6           ] = osgGA::GUIEventAdapter::KEY_F6;
371            _keymap[VK_F7           ] = osgGA::GUIEventAdapter::KEY_F7;
372            _keymap[VK_F8           ] = osgGA::GUIEventAdapter::KEY_F8;
373            _keymap[VK_F9           ] = osgGA::GUIEventAdapter::KEY_F9;
374            _keymap[VK_F10          ] = osgGA::GUIEventAdapter::KEY_F10;
375            _keymap[VK_F11          ] = osgGA::GUIEventAdapter::KEY_F11;
376            _keymap[VK_F12          ] = osgGA::GUIEventAdapter::KEY_F12;
377            _keymap[0xc0            ] = '`';
378            _keymap['0'             ] = '0';
379            _keymap['1'             ] = '1';
380            _keymap['2'             ] = '2';
381            _keymap['3'             ] = '3';
382            _keymap['4'             ] = '4';
383            _keymap['5'             ] = '5';
384            _keymap['6'             ] = '6';
385            _keymap['7'             ] = '7';
386            _keymap['8'             ] = '8';
387            _keymap['9'             ] = '9';
388            _keymap[0xbd            ] = '-';
389            _keymap[0xbb            ] = '=';
390            _keymap[VK_BACK         ] = osgGA::GUIEventAdapter::KEY_BackSpace;
391            _keymap[VK_TAB          ] = osgGA::GUIEventAdapter::KEY_Tab;
392            _keymap['A'             ] = 'A';
393            _keymap['B'             ] = 'B';
394            _keymap['C'             ] = 'C';
395            _keymap['D'             ] = 'D';
396            _keymap['E'             ] = 'E';
397            _keymap['F'             ] = 'F';
398            _keymap['G'             ] = 'G';
399            _keymap['H'             ] = 'H';
400            _keymap['I'             ] = 'I';
401            _keymap['J'             ] = 'J';
402            _keymap['K'             ] = 'K';
403            _keymap['L'             ] = 'L';
404            _keymap['M'             ] = 'M';
405            _keymap['N'             ] = 'N';
406            _keymap['O'             ] = 'O';
407            _keymap['P'             ] = 'P';
408            _keymap['Q'             ] = 'Q';
409            _keymap['R'             ] = 'R';
410            _keymap['S'             ] = 'S';
411            _keymap['T'             ] = 'T';
412            _keymap['U'             ] = 'U';
413            _keymap['V'             ] = 'V';
414            _keymap['W'             ] = 'W';
415            _keymap['X'             ] = 'X';
416            _keymap['Y'             ] = 'Y';
417            _keymap['Z'             ] = 'Z';
418            _keymap[0xdb            ] = '[';
419            _keymap[0xdd            ] = ']';
420            _keymap[0xdc            ] = '\\';
421            _keymap[VK_CAPITAL      ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
422            _keymap[0xba            ] = ';';
423            _keymap[0xde            ] = '\'';
424            _keymap[VK_RETURN       ] = osgGA::GUIEventAdapter::KEY_Return;
425            _keymap[VK_LSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_L;
426            _keymap[0xbc            ] = ',';
427            _keymap[0xbe            ] = '.';
428            _keymap[0xbf            ] = '/';
429            _keymap[VK_RSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_R;
430            _keymap[VK_LCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_L;
431            _keymap[VK_LWIN         ] = osgGA::GUIEventAdapter::KEY_Super_L;
432            _keymap[VK_SPACE        ] = ' ';
433            _keymap[VK_LMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_L;
434            _keymap[VK_RMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_R;
435            _keymap[VK_RWIN         ] = osgGA::GUIEventAdapter::KEY_Super_R;
436            _keymap[VK_APPS         ] = osgGA::GUIEventAdapter::KEY_Menu;
437            _keymap[VK_RCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_R;
438            _keymap[VK_SNAPSHOT     ] = osgGA::GUIEventAdapter::KEY_Print;
439            _keymap[VK_SCROLL       ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
440            _keymap[VK_PAUSE        ] = osgGA::GUIEventAdapter::KEY_Pause;
441            _keymap[VK_HOME         ] = osgGA::GUIEventAdapter::KEY_Home;
442            _keymap[VK_PRIOR        ] = osgGA::GUIEventAdapter::KEY_Page_Up;
443            _keymap[VK_END          ] = osgGA::GUIEventAdapter::KEY_End;
444            _keymap[VK_NEXT         ] = osgGA::GUIEventAdapter::KEY_Page_Down;
445            _keymap[VK_DELETE       ] = osgGA::GUIEventAdapter::KEY_Delete;
446            _keymap[VK_INSERT       ] = osgGA::GUIEventAdapter::KEY_Insert;
447            _keymap[VK_LEFT         ] = osgGA::GUIEventAdapter::KEY_Left;
448            _keymap[VK_UP           ] = osgGA::GUIEventAdapter::KEY_Up;
449            _keymap[VK_RIGHT        ] = osgGA::GUIEventAdapter::KEY_Right;
450            _keymap[VK_DOWN         ] = osgGA::GUIEventAdapter::KEY_Down;
451            _keymap[VK_NUMLOCK      ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
452            _keymap[VK_DIVIDE       ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
453            _keymap[VK_MULTIPLY     ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
454            _keymap[VK_SUBTRACT     ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
455            _keymap[VK_ADD          ] = osgGA::GUIEventAdapter::KEY_KP_Add;
456            _keymap[VK_NUMPAD7      ] = osgGA::GUIEventAdapter::KEY_KP_Home;
457            _keymap[VK_NUMPAD8      ] = osgGA::GUIEventAdapter::KEY_KP_Up;
458            _keymap[VK_NUMPAD9      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
459            _keymap[VK_NUMPAD4      ] = osgGA::GUIEventAdapter::KEY_KP_Left;
460            _keymap[VK_NUMPAD5      ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
461            _keymap[VK_NUMPAD6      ] = osgGA::GUIEventAdapter::KEY_KP_Right;
462            _keymap[VK_NUMPAD1      ] = osgGA::GUIEventAdapter::KEY_KP_End;
463            _keymap[VK_NUMPAD2      ] = osgGA::GUIEventAdapter::KEY_KP_Down;
464            _keymap[VK_NUMPAD3      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
465            _keymap[VK_NUMPAD0      ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
466            _keymap[VK_DECIMAL      ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
467            _keymap[VK_CLEAR        ] = osgGA::GUIEventAdapter::KEY_Clear;
468        }
469
470        ~Win32KeyboardMap() {}
471
472        int remapKey(int key)
473        {
474            KeyMap::const_iterator map = _keymap.find(key);
475            return map==_keymap.end() ? key : map->second;
476        }
477     
478    protected:
479
480        typedef std::map<int, int> KeyMap;
481        KeyMap _keymap;
482};
483
484static Win32KeyboardMap s_win32KeyboardMap;
485static int remapWin32Key(int key)
486{
487    return s_win32KeyboardMap.remapKey(key);
488}
489
490//////////////////////////////////////////////////////////////////////////////
491//         Window procedure for all GraphicsWindowWin32 instances
492//           Dispatches the call to the actual instance
493//////////////////////////////////////////////////////////////////////////////
494
495static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
496{
497    osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
498    return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
499                    ::DefWindowProc(hwnd, uMsg, wParam, lParam);
500}
501
502//////////////////////////////////////////////////////////////////////////////
503//              Win32WindowingSystem::OpenGLContext implementation
504//////////////////////////////////////////////////////////////////////////////
505
506Win32WindowingSystem::OpenGLContext::~OpenGLContext()
507{
508    if (_restorePreviousOnExit && _previousHglrc!=_hglrc && !::wglMakeCurrent(_previousHdc, _previousHglrc))
509    {
510        reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError());
511    }
512
513    _previousHdc   = 0;
514    _previousHglrc = 0;
515
516    if (_hglrc)
517    {
518        ::wglMakeCurrent(_hdc, NULL);
519        ::wglDeleteContext(_hglrc);
520        _hglrc = 0;
521    }
522
523    if (_hdc)
524    {
525        ::ReleaseDC(_hwnd, _hdc);
526        _hdc = 0;
527    }
528
529    if (_hwnd)
530    {
531        ::DestroyWindow(_hwnd);
532        _hwnd = 0;
533    }
534}
535
536bool Win32WindowingSystem::OpenGLContext::makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit )
537{
538    if (_hdc==0 || _hglrc==0) return false;
539
540    _previousHglrc = restorePreviousOnExit ? ::wglGetCurrentContext() : 0;
541    _previousHdc   = restoreOnHdc;
542
543    if (_hglrc==_previousHglrc) return true;
544
545    if (!::wglMakeCurrent(_hdc, _hglrc))
546    {
547        reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError());
548        return false;
549    }
550
551    _restorePreviousOnExit = restorePreviousOnExit;
552
553    return true;
554}
555
556//////////////////////////////////////////////////////////////////////////////
557//              Win32WindowingSystem implementation
558//////////////////////////////////////////////////////////////////////////////
559
560std::string Win32WindowingSystem::osgGraphicsWindowWithCursorClass;
561std::string Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass;
562
563Win32WindowingSystem::Win32WindowingSystem()
564: _windowClassesRegistered(false)
565{
566}
567
568Win32WindowingSystem::~Win32WindowingSystem()
569{
570    if (osg::Referenced::getDeleteHandler())
571    {
572        osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
573        osg::Referenced::getDeleteHandler()->flushAll();
574    }
575   
576    unregisterWindowClasses();
577}
578
579void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const
580{
581    for (unsigned int deviceNum=0;; ++deviceNum)
582    {
583        DISPLAY_DEVICE displayDevice;
584        displayDevice.cb = sizeof(displayDevice);
585
586        if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break;
587
588        // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
589        if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
590
591        // Only return display devices that are attached to the desktop
592        if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
593
594        displayDevices.push_back(displayDevice);
595    }
596}
597
598void Win32WindowingSystem::registerWindowClasses()
599{
600    if (_windowClassesRegistered) return;
601
602    //
603    // Register the window classes used by OSG GraphicsWindowWin32 instances
604    //
605
606    std::ostringstream str;
607    str << "OSG Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]";
608
609    osgGraphicsWindowWithCursorClass    = str.str() + "{ with cursor }";
610    osgGraphicsWindowWithoutCursorClass = str.str() + "{ without cursor }";
611
612    WNDCLASSEX wc;
613
614    HINSTANCE hinst = ::GetModuleHandle(NULL);
615
616    //
617    // First class: class for OSG Graphics Window with a cursor enabled
618    //
619
620    wc.cbSize        = sizeof(wc);
621    wc.style         = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
622    wc.lpfnWndProc   = WindowProc;
623    wc.cbClsExtra    = 0;
624    wc.cbWndExtra    = 0;
625    wc.hInstance     = hinst;
626    wc.hIcon         = ::LoadIcon(hinst, "OSG_ICON");
627    wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
628    wc.hbrBackground = NULL;
629    wc.lpszMenuName  = 0;
630    wc.lpszClassName = osgGraphicsWindowWithCursorClass.c_str();
631    wc.hIconSm       = NULL;
632
633    if (::RegisterClassEx(&wc)==0)
634    {
635        unsigned int lastError = ::GetLastError();
636        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
637        {
638            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register first window class", lastError);
639            return;
640        }
641    }
642
643    //
644    // Second class: class for OSG Graphics Window without a cursor
645    //
646
647    wc.hCursor       = NULL;
648    wc.lpszClassName = osgGraphicsWindowWithoutCursorClass.c_str();
649
650    if (::RegisterClassEx(&wc)==0)
651    {
652        unsigned int lastError = ::GetLastError();
653        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
654        {
655            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register second window class", lastError);
656            return;
657        }
658    }
659
660    _windowClassesRegistered = true;
661}
662
663void Win32WindowingSystem::unregisterWindowClasses()
664{
665    if (_windowClassesRegistered)
666    {
667        ::UnregisterClass(osgGraphicsWindowWithCursorClass.c_str(),    ::GetModuleHandle(NULL));
668        ::UnregisterClass(osgGraphicsWindowWithoutCursorClass.c_str(), ::GetModuleHandle(NULL));
669        _windowClassesRegistered = false;
670    }
671}
672
673bool Win32WindowingSystem::getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY )
674{
675    context.set(0, 0, 0);
676
677    registerWindowClasses();
678
679    HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
680                                 osgGraphicsWindowWithoutCursorClass.c_str(),
681                                 NULL,
682                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
683                                 windowOriginX,
684                                 windowOriginY,
685                                 1,
686                                 1,
687                                 NULL,
688                                 NULL,
689                                 ::GetModuleHandle(NULL),
690                                 NULL);
691    if (hwnd==0)
692    {
693        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError());
694        return false;
695    }
696
697    //
698    // Set the pixel format of the window
699    //
700
701    PIXELFORMATDESCRIPTOR pixelFormat =
702    {
703        sizeof(PIXELFORMATDESCRIPTOR),
704        1,
705        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
706        PFD_TYPE_RGBA,
707        24,
708        0, 0, 0, 0, 0, 0, 0, 0,
709        0, 0, 0, 0, 0,
710        24,
711        0,
712        0,
713        PFD_MAIN_PLANE,
714        0,
715        0, 0, 0
716    };
717
718    HDC hdc = ::GetDC(hwnd);
719    if (hdc==0)
720    {
721        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError());
722        ::DestroyWindow(hwnd);
723        return false;
724    }
725
726    int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
727    if (pixelFormatIndex==0)
728    {
729        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError());
730        ::ReleaseDC(hwnd, hdc);
731        ::DestroyWindow(hwnd);
732        return false;
733    }
734
735    if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat))
736    {
737        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError());
738        ::ReleaseDC(hwnd, hdc);
739        ::DestroyWindow(hwnd);
740        return false;
741    }
742
743    HGLRC hglrc = ::wglCreateContext(hdc);
744    if (hglrc==0)
745    {
746        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError());
747        ::ReleaseDC(hwnd, hdc);
748        ::DestroyWindow(hwnd);
749        return false;
750    }
751
752    context.set(hwnd, hdc, hglrc);
753
754    if (!context.makeCurrent(windowHDC, true)) return false;
755
756    return true;
757}
758
759unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
760{
761    return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0;
762}
763
764bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
765{
766    if (si.displayNum>0)
767    {
768        osg::notify(osg::WARN) << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
769        return false;
770    }
771
772    DisplayDevices displayDevices;
773    enumerateDisplayDevices(displayDevices);
774
775    if (si.screenNum>=displayDevices.size())
776    {
777        osg::notify(osg::WARN) << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
778        return false;
779    }
780
781    displayDevice = displayDevices[si.screenNum];
782
783    deviceMode.dmSize        = sizeof(deviceMode);
784    deviceMode.dmDriverExtra = 0;
785
786    if (!::EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
787    {
788        std::ostringstream str;
789        str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum;
790        reportError(str.str(), ::GetLastError());
791        return false;
792    }
793
794    return true;
795}
796
797void Win32WindowingSystem::getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height )
798{
799    DISPLAY_DEVICE displayDevice;
800    DEVMODE        deviceMode;
801
802    if (getScreenInformation(si, displayDevice, deviceMode))
803    {
804        width  = deviceMode.dmPelsWidth;
805        height = deviceMode.dmPelsHeight;
806    }
807    else
808    {
809        width  = 0;
810        height = 0;
811    }
812}
813
814void Win32WindowingSystem::getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel )
815{
816    DISPLAY_DEVICE displayDevice;
817    DEVMODE        deviceMode;
818
819    if (getScreenInformation(si, displayDevice, deviceMode))
820    {
821        dmBitsPerPel = deviceMode.dmBitsPerPel;
822    }
823    else
824    {
825        dmBitsPerPel  = 0;
826    }
827}
828
829bool Win32WindowingSystem::changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
830{
831    //
832    // Start by testing if the change would be successful (without applying it)
833    //
834
835    unsigned int result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, CDS_TEST, NULL);
836    if (result==DISP_CHANGE_SUCCESSFUL)
837    {
838        result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, 0, NULL);
839        if (result==DISP_CHANGE_SUCCESSFUL) return true;
840    }
841
842    std::string msg = "Win32WindowingSystem::changeScreenSettings() - Unable to change the screen settings.";
843
844    switch( result )
845    {
846        case DISP_CHANGE_BADMODE     : msg += " The specified graphics mode is not supported."; break;
847        case DISP_CHANGE_FAILED      : msg += " The display driver failed the specified graphics mode."; break;
848        case DISP_CHANGE_RESTART     : msg += " The computer must be restarted for the graphics mode to work."; break;
849        default : break;
850    }
851
852    reportErrorForScreen(msg, si, result);
853    return false;
854}
855
856bool Win32WindowingSystem::setScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height )
857{
858    DISPLAY_DEVICE displayDevice;
859    DEVMODE        deviceMode;
860
861    if (!getScreenInformation(si, displayDevice, deviceMode)) return false;
862
863    deviceMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;
864    deviceMode.dmPelsWidth  = width;
865    deviceMode.dmPelsHeight = height;
866   
867    return changeScreenSettings(si, displayDevice, deviceMode);
868}
869
870bool Win32WindowingSystem::setScreenRefreshRate( const osg::GraphicsContext::ScreenIdentifier& si, double refreshRate )
871{
872    DISPLAY_DEVICE displayDevice;
873    DEVMODE        deviceMode;
874
875    unsigned int width, height;
876    getScreenResolution(si, width, height);
877
878    if (!getScreenInformation(si, displayDevice, deviceMode)) return false;
879
880    deviceMode.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
881    deviceMode.dmPelsWidth        = width;
882    deviceMode.dmPelsHeight       = height;
883    deviceMode.dmDisplayFrequency = refreshRate;
884   
885    return changeScreenSettings(si, displayDevice, deviceMode);
886}
887
888void Win32WindowingSystem::getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height )
889{
890    DISPLAY_DEVICE displayDevice;
891    DEVMODE        deviceMode;
892
893    if (getScreenInformation(si, displayDevice, deviceMode))
894    {
895        originX = deviceMode.dmPosition.x;
896        originY = deviceMode.dmPosition.y;
897        width   = deviceMode.dmPelsWidth;
898        height  = deviceMode.dmPelsHeight;
899    }
900    else
901    {
902        originX = 0;
903        originY = 0;
904        width   = 0;
905        height  = 0;
906    }
907}
908
909osg::GraphicsContext* Win32WindowingSystem::createGraphicsContext( osg::GraphicsContext::Traits* traits )
910{
911    if (traits->pbuffer)
912    {
913        osg::ref_ptr<osgViewer::PixelBufferWin32> pbuffer = new PixelBufferWin32(traits);
914        if (pbuffer->valid()) return pbuffer.release();
915        else return 0;
916    }
917    else
918    {
919        registerWindowClasses();
920
921        osg::ref_ptr<osgViewer::GraphicsWindowWin32> window = new GraphicsWindowWin32(traits);
922        if (window->valid()) return window.release();
923        else return 0;
924    }
925}
926
927void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window )
928{
929    if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window));
930}
931
932//
933// Unregister a window
934// This is called as part of a window being torn down
935//
936
937void Win32WindowingSystem::unregisterWindow( HWND hwnd )
938{
939    if (hwnd) _activeWindows.erase(hwnd);
940}
941
942//
943// Get the application window object associated with a native window
944//
945
946osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd )
947{
948    WindowHandles::const_iterator entry = _activeWindows.find(hwnd);
949    return entry==_activeWindows.end() ? 0 : entry->second;
950}
951
952//////////////////////////////////////////////////////////////////////////////
953//                    GraphicsWindowWin32 implementation
954//////////////////////////////////////////////////////////////////////////////
955
956GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits )
957: _hwnd(0),
958  _hdc(0),
959  _hglrc(0),
960  _windowProcedure(0),
961  _timeOfLastCheckEvents(-1.0),
962  _screenOriginX(0),
963  _screenOriginY(0),
964  _screenWidth(0),
965  _screenHeight(0),
966  _windowOriginXToRealize(0),
967  _windowOriginYToRealize(0),
968  _windowWidthToRealize(0),
969  _windowHeightToRealize(0),
970  _initialized(false),
971  _valid(false),
972  _realized(false),
973  _ownsWindow(true),
974  _closeWindow(false),
975  _destroyWindow(false),
976  _destroying(false)
977{
978    _traits = traits;
979    if (_traits->useCursor) setCursor(LeftArrowCursor);
980
981    init();
982   
983    if (valid())
984    {
985        setState( new osg::State );
986        getState()->setGraphicsContext(this);
987
988        if (_traits.valid() && _traits->sharedContext)
989        {
990            getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
991            incrementContextIDUsageCount( getState()->getContextID() );   
992        }
993        else
994        {
995            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
996        }
997    }
998}
999
1000GraphicsWindowWin32::~GraphicsWindowWin32()
1001{
1002    close();
1003    destroyWindow();
1004}
1005
1006void GraphicsWindowWin32::init()
1007{
1008    if (_initialized) return;
1009
1010    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1011    HWND windowHandle = windowData ? windowData->_hwnd : 0;
1012
1013    _ownsWindow    = windowHandle==0;
1014    _closeWindow   = false;
1015    _destroyWindow = false;
1016    _destroying    = false;
1017
1018    _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
1019    _valid       = _initialized;
1020}
1021
1022bool GraphicsWindowWin32::createWindow()
1023{
1024    unsigned int extendedStyle;
1025    unsigned int windowStyle;
1026
1027    if (!determineWindowPositionAndStyle(_traits->windowDecoration,
1028                                         _windowOriginXToRealize,
1029                                         _windowOriginYToRealize,
1030                                         _windowWidthToRealize,
1031                                         _windowHeightToRealize,
1032                                         windowStyle,
1033                                         extendedStyle))
1034    {
1035        reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
1036        return false;
1037    }
1038
1039    _hwnd = ::CreateWindowEx(extendedStyle,
1040                             _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() :
1041                                                  Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(),
1042                             _traits->windowName.c_str(),
1043                             windowStyle,
1044                             _windowOriginXToRealize,
1045                             _windowOriginYToRealize,
1046                             _windowWidthToRealize,
1047                             _windowHeightToRealize,
1048                             NULL,
1049                             NULL,
1050                             ::GetModuleHandle(NULL),
1051                             NULL);
1052    if (_hwnd==0)
1053    {
1054        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError());
1055        return false;
1056    }
1057
1058    _hdc = ::GetDC(_hwnd);
1059    if (_hdc==0)
1060    {
1061        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1062        destroyWindow();
1063        _hwnd = 0;
1064        return false;
1065    }
1066
1067    //
1068    // Set the pixel format according to traits specified
1069    //
1070
1071    if (!setPixelFormat())
1072    {
1073        ::ReleaseDC(_hwnd, _hdc);
1074        _hdc  = 0;
1075        destroyWindow();
1076        return false;
1077    }
1078
1079    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1080    return true;
1081}
1082
1083bool GraphicsWindowWin32::setWindow( HWND handle )
1084{
1085    if (_initialized)
1086    {
1087        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError());
1088        return false;
1089    }
1090
1091    if (handle==0)
1092    {
1093        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError());
1094        return false;
1095    }
1096
1097    _hwnd = handle;
1098    if (_hwnd==0)
1099    {
1100        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError());
1101        return false;
1102    }
1103
1104    _hdc = ::GetDC(_hwnd);
1105    if (_hdc==0)
1106    {
1107        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1108        _hwnd = 0;
1109        return false;
1110    }
1111
1112    //
1113    // Check if we must set the pixel format of the inherited window
1114    //
1115
1116    if (_traits.valid() && _traits->setInheritedWindowPixelFormat)
1117    {
1118        if (!setPixelFormat())
1119        {
1120            reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError());
1121            _hdc  = 0;
1122            _hwnd = 0;
1123            return false;
1124        }
1125    }
1126    else
1127    {
1128        //
1129        // Create the OpenGL rendering context associated with this window
1130        //
1131
1132        _hglrc = ::wglCreateContext(_hdc);
1133        if (_hglrc==0)
1134        {
1135            reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1136            ::ReleaseDC(_hwnd, _hdc);
1137            _hdc  = 0;
1138            _hwnd = 0;
1139            return false;
1140        }
1141    }
1142
1143    if (!registerWindowProcedure())
1144    {
1145        ::wglDeleteContext(_hglrc);
1146        _hglrc = 0;
1147        ::ReleaseDC(_hwnd, _hdc);
1148        _hdc  = 0;
1149        _hwnd = 0;
1150        return false;
1151    }
1152
1153    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1154
1155    _initialized = true;
1156    _valid       = true;
1157
1158    return true;
1159}
1160
1161void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
1162{
1163    if (_destroying) return;
1164    _destroying = true;
1165
1166    if (_hdc)
1167    {
1168        releaseContext();
1169
1170        if (_hglrc)
1171        {
1172            ::wglDeleteContext(_hglrc);
1173            _hglrc = 0;
1174        }
1175
1176        ::ReleaseDC(_hwnd, _hdc);
1177        _hdc = 0;
1178    }
1179
1180    (void)unregisterWindowProcedure();
1181
1182    if (_hwnd)
1183    {
1184        Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1185        if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd);
1186        _hwnd = 0;
1187    }
1188
1189    _initialized = false;
1190    _realized    = false;
1191    _valid       = false;
1192    _destroying  = false;
1193}
1194
1195bool GraphicsWindowWin32::registerWindowProcedure()
1196{
1197    ::SetLastError(0);
1198    _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc));
1199    unsigned int error = ::GetLastError();
1200
1201    if (_windowProcedure==0 && error)
1202    {
1203        reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error);
1204        return false;
1205    }
1206
1207    return true;
1208}
1209
1210bool GraphicsWindowWin32::unregisterWindowProcedure()
1211{
1212    if (_windowProcedure==0 || _hwnd==0) return true;
1213
1214    ::SetLastError(0);
1215    WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure));
1216    unsigned int error = ::GetLastError();
1217
1218    if (wndProc==0 && error)
1219    {
1220        reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error);
1221        return false;
1222    }
1223
1224    _windowProcedure = 0;
1225
1226    return true;
1227}
1228
1229bool GraphicsWindowWin32::determineWindowPositionAndStyle( bool decorated, int& x, int& y, unsigned int& w, unsigned int& h, unsigned int& style, unsigned int& extendedStyle )
1230{
1231    if (_traits==0) return false;
1232
1233    //
1234    // Query the screen position and size
1235    //
1236
1237    osg::GraphicsContext::ScreenIdentifier screenId(_traits->screenNum);
1238    Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface();
1239
1240    windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
1241    if (_screenWidth==0 || _screenHeight==0) return false;
1242
1243    x = _traits->x + _screenOriginX;
1244    y = _traits->y + _screenOriginY;
1245    w = _traits->width;
1246    h = _traits->height;
1247
1248    style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1249
1250    extendedStyle = 0;
1251
1252    if (decorated)
1253    {
1254        style |= WS_CAPTION     |
1255                 WS_SYSMENU     |
1256                 WS_MINIMIZEBOX |
1257                 WS_MAXIMIZEBOX;
1258
1259        if (_traits->supportsResize) style |= WS_SIZEBOX;
1260
1261        extendedStyle = WS_EX_APPWINDOW           |
1262                        WS_EX_OVERLAPPEDWINDOW |
1263                        WS_EX_ACCEPTFILES      |
1264                        WS_EX_LTRREADING;
1265
1266        RECT corners;
1267
1268        corners.left   = x;
1269        corners.top    = y;
1270        corners.right  = x + w - 1;
1271        corners.bottom = y + h - 1;
1272
1273        //
1274        // Determine the location of the window corners in order to have
1275        // a client area of the requested size
1276        //
1277
1278        if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
1279        {
1280            reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError());
1281            return false;
1282        }
1283
1284        x = corners.left;
1285        y = corners.top;
1286        w = corners.right  - corners.left + 1;
1287        h = corners.bottom - corners.top  + 1;
1288    }
1289
1290    return true;
1291}
1292
1293static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits,
1294                                              WGLIntegerAttributes&               attributes,
1295                                              bool                                allowSwapExchangeARB )
1296{
1297    attributes.begin();
1298
1299    attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
1300    attributes.enable(WGL_SUPPORT_OPENGL_ARB);
1301
1302    attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
1303    attributes.set(WGL_PIXEL_TYPE_ARB,   WGL_TYPE_RGBA_ARB);
1304
1305    attributes.set(WGL_COLOR_BITS_ARB,   traits.red + traits.green + traits.blue);
1306    attributes.set(WGL_RED_BITS_ARB,     traits.red);
1307    attributes.set(WGL_GREEN_BITS_ARB,   traits.green);
1308    attributes.set(WGL_BLUE_BITS_ARB,    traits.blue);
1309    attributes.set(WGL_DEPTH_BITS_ARB,   traits.depth);
1310
1311    if (traits.doubleBuffer)
1312    {
1313        attributes.enable(WGL_DOUBLE_BUFFER_ARB);
1314        if (allowSwapExchangeARB) attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1315    }
1316
1317    if (traits.alpha)         attributes.set(WGL_ALPHA_BITS_ARB,     traits.alpha);
1318    if (traits.stencil)       attributes.set(WGL_STENCIL_BITS_ARB,   traits.stencil);
1319    if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers);
1320    if (traits.samples)       attributes.set(WGL_SAMPLES_ARB,        traits.samples);
1321
1322    if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB);
1323
1324    attributes.end();
1325}
1326
1327static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits)
1328{
1329    //
1330    // Access the entry point for the wglChoosePixelFormatARB function
1331    //
1332
1333    WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
1334    if (wglChoosePixelFormatARB==0)
1335    {
1336        // = openGLContext.getTraits()
1337        reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError());
1338        PIXELFORMATDESCRIPTOR pixelFormat = {
1339            sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
1340            1,                     // version number
1341            PFD_DRAW_TO_WINDOW |   // support window
1342            PFD_SUPPORT_OPENGL |   // support OpenGL
1343            (_traits->doubleBuffer ? PFD_DOUBLEBUFFER : NULL),      // double buffered ?
1344            PFD_TYPE_RGBA,         // RGBA type
1345            _traits->red + _traits->green + _traits->blue,                // color depth
1346            _traits->red ,0, _traits->green ,0, _traits->blue, 0,          // shift bits ignored
1347            _traits->alpha,          // alpha buffer ?
1348            0,                     // shift bit ignored
1349            0,                     // no accumulation buffer
1350            0, 0, 0, 0,            // accum bits ignored
1351            _traits->depth,          // 32 or 16 bit z-buffer ?
1352            _traits->stencil,        // stencil buffer ?
1353            0,                     // no auxiliary buffer
1354            PFD_MAIN_PLANE,        // main layer
1355            0,                     // reserved
1356            0, 0, 0                // layer masks ignored
1357        };
1358        int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
1359        if (pixelFormatIndex == 0)
1360        {
1361            reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError());
1362            return -1;
1363        }
1364
1365        ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat);
1366        if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0)  && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0))
1367        {
1368            osg::notify(osg::WARN) << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl;
1369        }
1370        return pixelFormatIndex;
1371    }
1372
1373    int pixelFormatIndex = 0;
1374    unsigned int numMatchingPixelFormats = 0;
1375
1376    if (!wglChoosePixelFormatARB(hdc,
1377                                 formatSpecifications.get(),
1378                                 NULL,
1379                                 1,
1380                                 &pixelFormatIndex,
1381                                 &numMatchingPixelFormats))
1382    {
1383        reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError());
1384        return -1;
1385    }
1386
1387    return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex;
1388}
1389
1390bool GraphicsWindowWin32::setPixelFormat()
1391{
1392    Win32WindowingSystem::OpenGLContext openGLContext;
1393    if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false;
1394
1395    //
1396    // Build the specifications of the requested pixel format
1397    //
1398
1399    WGLIntegerAttributes formatSpecs;
1400    ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);
1401
1402    //
1403    // Choose the closest matching pixel format from the specified traits
1404    //
1405
1406    int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1407
1408    if (pixelFormatIndex<0)
1409    {
1410            unsigned int bpp;
1411            Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp);
1412            if (bpp < 32) {
1413                osg::notify(osg::INFO)    << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, "
1414                                        << bpp
1415                                        << " bits per pixel on screen #"
1416                                        << _traits->screenNum
1417                                        << std::endl;
1418
1419                _traits->red = bpp / 4; //integer devide, determine minimum number of bits we will accept
1420                _traits->green = bpp / 4;
1421                _traits->blue = bpp / 4;
1422                ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB
1423                pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1424            }
1425    }
1426    if (pixelFormatIndex<0)
1427    {
1428        ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false);
1429        pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1430        if (pixelFormatIndex<0)
1431        {
1432            reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0);
1433            return false;
1434        }
1435
1436        osg::notify(osg::INFO) << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #"
1437                               << _traits->screenNum
1438                               << std::endl;
1439    }
1440
1441    //
1442    // Set the pixel format found
1443    //
1444
1445    PIXELFORMATDESCRIPTOR pfd;
1446    ::memset(&pfd, 0, sizeof(pfd));
1447    pfd.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
1448    pfd.nVersion = 1;
1449
1450    if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
1451    {
1452        reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError());
1453        return false;
1454    }
1455
1456    //
1457    // Create the OpenGL rendering context associated with this window
1458    //
1459
1460    _hglrc = ::wglCreateContext(_hdc);
1461    if (_hglrc==0)
1462    {
1463        reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1464        return false;
1465    }
1466
1467    return true;
1468}
1469
1470bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated )
1471{
1472    unsigned int windowStyle;
1473    unsigned int extendedStyle;
1474
1475    //
1476    // Determine position and size of window with/without decorations to retain the size specified in traits
1477    //
1478
1479    int x, y;
1480    unsigned int w, h;
1481
1482    if (!determineWindowPositionAndStyle(decorated, x, y, w, h, windowStyle, extendedStyle))
1483    {
1484        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0);
1485        return false;
1486    }
1487
1488    //
1489    // Change the window style
1490    //
1491
1492    ::SetLastError(0);
1493    unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
1494    unsigned int error  = ::GetLastError();
1495    if (result==0 && error)
1496    {
1497        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error);
1498        return false;
1499    }
1500
1501    //
1502    // Change the window extended style
1503    //
1504
1505    ::SetLastError(0);
1506    result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
1507    error  = ::GetLastError();
1508    if (result==0 && error)
1509    {
1510        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error);
1511        return false;
1512    }
1513
1514    //
1515    // Change the window position and size and realize the style changes
1516    //
1517
1518    if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
1519    {
1520        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
1521        return false;
1522    }
1523
1524    //
1525    // Repaint the desktop to cleanup decorations removed
1526    //
1527
1528    if (!decorated)
1529    {
1530        ::InvalidateRect(NULL, NULL, TRUE);
1531    }
1532   
1533    return true;
1534}
1535
1536bool GraphicsWindowWin32::realizeImplementation()
1537{
1538    if (_realized) return true;
1539
1540    if (!_initialized)
1541    {
1542        init();
1543        if (!_initialized) return false;
1544    }
1545    {
1546       
1547        if (_traits.valid() && _traits->sharedContext)
1548        {
1549            GraphicsWindowWin32* sharedContextWin32 = dynamic_cast<GraphicsWindowWin32*>(_traits->sharedContext);
1550            if (sharedContextWin32)
1551            {
1552                struct RestoreContext
1553                {
1554                    RestoreContext()
1555                    {
1556                        _hdc = wglGetCurrentDC();
1557                        _hglrc = wglGetCurrentContext();
1558                    }
1559                    ~RestoreContext()
1560                    {
1561                        if (_hdc)
1562                        {
1563                            wglMakeCurrent(_hdc,_hglrc);
1564                        }
1565                    }
1566                protected:
1567                    HDC        _hdc;
1568                    HGLRC    _hglrc;
1569                } restoreContext;
1570               
1571                _realized = true;
1572                bool result = makeCurrent();
1573                _realized = false;
1574
1575                if (!result)
1576                {
1577                    return false;       
1578                }
1579                if (!wglShareLists(sharedContextWin32->getWGLContext(), getWGLContext()))
1580                {
1581                    reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
1582                    return false;
1583                }
1584            }
1585        }
1586    }
1587
1588    if (_ownsWindow)
1589    {
1590        //
1591        // Bring the window on top of other ones (including the taskbar if it covers it completely)
1592        //
1593        // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
1594        // Z-order must be used in the code below instead of HWND_TOP.
1595        // @todo: This should be controlled through a flag in the traits (topMostWindow)
1596        //
1597
1598        if (!::SetWindowPos(_hwnd,
1599                            HWND_TOP,
1600                            _windowOriginXToRealize,
1601                            _windowOriginYToRealize,
1602                            _windowWidthToRealize,
1603                            _windowHeightToRealize,
1604                            SWP_SHOWWINDOW))
1605        {
1606            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
1607            return false;
1608        }
1609 
1610        if (!::UpdateWindow(_hwnd))
1611        {
1612            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
1613            return false;
1614        }
1615    }
1616
1617    _realized = true;
1618
1619    return true;
1620}
1621
1622bool GraphicsWindowWin32::makeCurrentImplementation()
1623{
1624    if (!_realized)
1625    {
1626        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0);
1627        return false;
1628    }
1629
1630    if (!::wglMakeCurrent(_hdc, _hglrc))
1631    {
1632        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
1633        return false;
1634    }
1635
1636    return true;
1637}
1638
1639bool GraphicsWindowWin32::releaseContextImplementation()
1640{
1641    if (!::wglMakeCurrent(_hdc, NULL))
1642    {
1643        reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError());
1644        return false;
1645    }
1646
1647    return true;
1648}
1649
1650void GraphicsWindowWin32::closeImplementation()
1651{
1652    destroyWindow();
1653
1654    _initialized = false;
1655    _valid       = false;
1656    _realized    = false;
1657}
1658
1659void GraphicsWindowWin32::swapBuffersImplementation()
1660{
1661    if (!_realized) return;
1662    if (!::SwapBuffers(_hdc))
1663    {
1664        reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError());
1665    }
1666}
1667
1668void GraphicsWindowWin32::checkEvents()
1669{
1670    if (!_realized) return;
1671
1672    MSG msg;
1673    while (::PeekMessage(&msg, _hwnd, NULL, NULL, PM_REMOVE))
1674    {
1675        ::TranslateMessage(&msg);
1676        ::DispatchMessage(&msg);
1677    }
1678
1679    if (_closeWindow)
1680    {
1681        _closeWindow = false;
1682        close();
1683    }
1684
1685    if (_destroyWindow)
1686    {
1687        _destroyWindow = false;
1688        destroyWindow(false);
1689    }
1690}
1691
1692void GraphicsWindowWin32::grabFocus()
1693{
1694    if (!::SetForegroundWindow(_hwnd))
1695    {
1696        osg::notify(osg::WARN) << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
1697    }
1698}
1699
1700void GraphicsWindowWin32::grabFocusIfPointerInWindow()
1701{
1702    POINT mousePos;
1703    if (!::GetCursorPos(&mousePos))
1704    {
1705        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError());
1706        return;
1707    }
1708
1709    RECT windowRect;
1710    if (!::GetWindowRect(_hwnd, &windowRect))
1711    {
1712        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError());
1713        return;
1714    }
1715
1716    if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
1717        mousePos.y>=windowRect.top  && mousePos.y<=windowRect.bottom)
1718    {
1719        grabFocus();
1720    }
1721}
1722
1723void GraphicsWindowWin32::requestWarpPointer( float x, float y )
1724{
1725    if (!_realized)
1726    {
1727        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer", _traits->screenNum, 0);
1728        return;
1729    }
1730
1731#if 0
1732    RECT windowRect;
1733    if (!::GetWindowRect(_hwnd, &windowRect))
1734    {
1735        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to get window rectangle", _traits->screenNum, ::GetLastError());
1736        return;
1737    }
1738
1739    if (!::SetCursorPos(windowRect.left + x, windowRect.top + y))
1740    {
1741        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
1742        return;
1743    }
1744#else
1745    // MIKEC: NEW CODE
1746    POINT pt;
1747    pt.x=x;
1748    pt.y=y;
1749    // convert point in client area coordinates to screen coordinates
1750    if (!::ClientToScreen(_hwnd,&pt))
1751    {
1752        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError());
1753    }
1754    if (!::SetCursorPos(pt.x,pt.y))
1755    {
1756        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
1757        return;
1758    }
1759#endif
1760   
1761    getEventQueue()->mouseWarped(x,y);
1762}
1763
1764bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height)
1765{
1766    if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, width, height, SWP_SHOWWINDOW | SWP_FRAMECHANGED))
1767    {
1768        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangle() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
1769        return false;
1770    }
1771    return true;
1772}
1773
1774void GraphicsWindowWin32::useCursor( bool cursorOn )
1775{
1776    _traits->useCursor = cursorOn;
1777}
1778
1779void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor )
1780{
1781    HCURSOR newCursor = getOrCreateCursor( mouseCursor);
1782    if (newCursor == _currentCursor) return;
1783
1784    _currentCursor = newCursor;
1785    _traits->useCursor = (_currentCursor != NULL);
1786}
1787
1788HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor)
1789{
1790    std::map<MouseCursor,HCURSOR>::iterator i = _mouseCursorMap.find(mouseCursor);
1791    if (i != _mouseCursorMap.end()) return i->second;
1792
1793    switch (mouseCursor) {
1794    case NoCursor:
1795        _mouseCursorMap[mouseCursor] = NULL;
1796    break;
1797    case RightArrowCursor:
1798    _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
1799        break;
1800    case LeftArrowCursor:
1801        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
1802        break;
1803    case InfoCursor:
1804        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL);
1805        break;
1806    case DestroyCursor:
1807        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
1808        break;
1809    case HelpCursor:
1810        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP );
1811        break;
1812    case CycleCursor:
1813        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
1814        break;
1815    case SprayCursor:
1816        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL );
1817        break;
1818    case WaitCursor:
1819        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT);
1820        break;
1821    case TextCursor:
1822        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM );
1823        break;
1824    case CrosshairCursor:
1825        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS );
1826        break;
1827    case UpDownCursor:
1828        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS );
1829        break;
1830    case LeftRightCursor:
1831        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
1832        break;
1833    case TopSideCursor:
1834        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
1835        break;
1836    case BottomSideCursor:
1837        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
1838        break;
1839    case LeftSideCursor:
1840        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE);
1841        break;
1842    case RightSideCursor:
1843        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
1844        break;
1845    case TopLeftCorner:
1846        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
1847        break;
1848    case TopRightCorner:
1849        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
1850        break;
1851    case BottomRightCorner:
1852        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
1853        break;
1854    case BottomLeftCorner:
1855        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
1856        break;
1857    }
1858   
1859    return _mouseCursorMap[mouseCursor];
1860}
1861
1862void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask )
1863{
1864    modifierMask = 0;
1865
1866    bool rightSide = (lParam & 0x01000000)!=0;
1867    int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0));
1868
1869    BYTE keyState[256];
1870
1871    if (virtualKey==0 || !::GetKeyboardState(keyState))
1872    {
1873        keySymbol = 0;
1874        return;
1875    }
1876
1877    switch (virtualKey)
1878    {
1879        //////////////////
1880        case VK_LSHIFT   :
1881        //////////////////
1882
1883        modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
1884            break;
1885
1886        //////////////////
1887        case VK_RSHIFT   :
1888        //////////////////
1889
1890        modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT;
1891            break;
1892
1893        //////////////////
1894        case VK_CONTROL  :
1895        case VK_LCONTROL :
1896        //////////////////
1897
1898            virtualKey    = rightSide ? VK_RCONTROL : VK_LCONTROL;
1899            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
1900            break;
1901
1902        //////////////////
1903        case VK_MENU     :
1904        case VK_LMENU    :
1905        //////////////////
1906
1907            virtualKey    = rightSide ? VK_RMENU : VK_LMENU;
1908            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
1909            break;
1910
1911        //////////////////
1912        default          :
1913        //////////////////
1914
1915            virtualKey = wParam;
1916            break;
1917    }
1918
1919    if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
1920    if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
1921
1922    keySymbol = remapWin32Key(virtualKey);
1923
1924    if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
1925    {
1926        keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
1927    }
1928    else if ((keySymbol & 0xff00)==0)
1929    {
1930        char asciiKey[2];
1931        int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
1932        if (numChars>0) keySymbol = asciiKey[0];
1933    }
1934}
1935
1936void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
1937{
1938    if (getEventQueue()->getUseFixedMouseInputRange())
1939    {
1940        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1941
1942        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1943        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1944    }
1945}
1946
1947LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1948{
1949    //!@todo adapt windows event time to osgGA event queue time for better resolution
1950
1951    double baseTime   = _timeOfLastCheckEvents;
1952    double eventTime  = _timeOfLastCheckEvents;
1953    double resizeTime = eventTime;
1954
1955    _timeOfLastCheckEvents = getEventQueue()->getTime();
1956
1957    switch(uMsg)
1958    {
1959        /////////////////
1960        case WM_PAINT   :
1961        /////////////////
1962
1963            if (_ownsWindow)
1964            {
1965                PAINTSTRUCT paint;
1966                ::BeginPaint(hwnd, &paint);
1967                ::EndPaint(hwnd, &paint);
1968            }
1969            break;
1970
1971        ///////////////////
1972        case WM_MOUSEMOVE :
1973        ///////////////////
1974
1975            {
1976                float mx = GET_X_LPARAM(lParam);
1977                float my = GET_Y_LPARAM(lParam);
1978                transformMouseXY(mx, my);
1979                getEventQueue()->mouseMotion(mx, my, eventTime);
1980            }
1981            break;
1982
1983        /////////////////////
1984        case WM_LBUTTONDOWN :
1985        case WM_MBUTTONDOWN :
1986        case WM_RBUTTONDOWN :
1987        /////////////////////
1988
1989            {
1990                ::SetCapture(hwnd);
1991
1992                int button;
1993
1994                if (uMsg==WM_LBUTTONDOWN)      button = 1;
1995                else if (uMsg==WM_MBUTTONDOWN) button = 2;
1996                else button = 3;
1997
1998                float mx = GET_X_LPARAM(lParam);
1999                float my = GET_Y_LPARAM(lParam);
2000                transformMouseXY(mx, my);
2001                getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
2002            }
2003            break;
2004
2005        /////////////////////
2006        case WM_LBUTTONUP   :
2007        case WM_MBUTTONUP   :
2008        case WM_RBUTTONUP   :
2009        /////////////////////
2010           
2011            {
2012                ::ReleaseCapture();
2013
2014                int button;
2015
2016                if (uMsg==WM_LBUTTONUP)      button = 1;
2017                else if (uMsg==WM_MBUTTONUP) button = 2;
2018                else button = 3;
2019
2020                float mx = GET_X_LPARAM(lParam);
2021                float my = GET_Y_LPARAM(lParam);
2022                transformMouseXY(mx, my);
2023                getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
2024            }
2025            break;
2026
2027        ///////////////////////
2028        case WM_LBUTTONDBLCLK :
2029        case WM_MBUTTONDBLCLK :
2030        case WM_RBUTTONDBLCLK :
2031        ///////////////////////
2032
2033            {
2034                ::SetCapture(hwnd);
2035
2036                int button;
2037
2038                if (uMsg==WM_LBUTTONDBLCLK)            button = 1;
2039                else if (uMsg==WM_MBUTTONDBLCLK)    button = 2;
2040                else button = 3;
2041
2042                float mx = GET_X_LPARAM(lParam);
2043                float my = GET_Y_LPARAM(lParam);
2044                transformMouseXY(mx, my);
2045                getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime);
2046            }
2047            break;
2048
2049        ////////////////////
2050        case WM_MOUSEWHEEL :
2051        ////////////////////
2052
2053            getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
2054                                                                            osgGA::GUIEventAdapter::SCROLL_UP,
2055                                         eventTime);
2056            break;
2057
2058        /////////////////
2059        case WM_MOVE    :
2060        case WM_SIZE    :
2061        /////////////////
2062
2063            {
2064                POINT origin;
2065                origin.x = 0;
2066                origin.y = 0;
2067
2068                ::ClientToScreen(hwnd, &origin);
2069
2070                int windowX = origin.x - _screenOriginX;
2071                int windowY = origin.y - _screenOriginY;
2072                resizeTime  = eventTime;
2073
2074                RECT clientRect;
2075                ::GetClientRect(hwnd, &clientRect);
2076
2077                int windowWidth;
2078                int windowHeight;
2079
2080                if (clientRect.bottom==0 && clientRect.right==0)
2081                {
2082                    //
2083                    // Window has been minimized; keep window width & height to a minimum of 1 pixel
2084                    //
2085
2086                    windowWidth  = 1;
2087                    windowHeight = 1;
2088                }
2089                else
2090                {
2091                    windowWidth  = clientRect.right;
2092                    windowHeight = clientRect.bottom;
2093                }
2094
2095                if (windowX!=_traits->x || windowY!=_traits->y || windowWidth!=_traits->width || windowHeight!=_traits->height)
2096                {
2097                    resized(windowX, windowY, windowWidth, windowHeight);
2098                    getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
2099                }
2100            }
2101            break;
2102
2103        ////////////////////
2104        case WM_KEYDOWN    :
2105        case WM_SYSKEYDOWN :
2106        ////////////////////
2107
2108            {
2109                int keySymbol = 0;
2110                unsigned int modifierMask = 0;
2111                adaptKey(wParam, lParam, keySymbol, modifierMask);
2112                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2113                getEventQueue()->keyPress(keySymbol, eventTime);
2114            }
2115            break;
2116
2117        //////////////////
2118        case WM_KEYUP    :
2119        case WM_SYSKEYUP :
2120        //////////////////
2121
2122            {
2123                int keySymbol = 0;
2124                unsigned int modifierMask = 0;
2125                adaptKey(wParam, lParam, keySymbol, modifierMask);
2126                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2127                getEventQueue()->keyRelease(keySymbol, eventTime);
2128            }
2129            break;
2130
2131        ///////////////////
2132        case WM_SETCURSOR :
2133        ///////////////////
2134            if (_traits->useCursor)
2135                ::SetCursor( _currentCursor);
2136            else
2137                ::SetCursor(NULL);
2138            return TRUE;
2139
2140        /////////////////
2141        case WM_CLOSE   :
2142        /////////////////
2143
2144            getEventQueue()->closeWindow(eventTime);
2145            break;
2146
2147        /////////////////
2148        case WM_DESTROY :
2149        /////////////////
2150
2151            _destroyWindow = true;
2152            if (_ownsWindow)
2153            {
2154                ::PostQuitMessage(0);
2155            }
2156            break;
2157
2158        //////////////
2159        case WM_QUIT :
2160        //////////////
2161
2162            _closeWindow = true;
2163            return wParam;
2164
2165        /////////////////
2166        default         :
2167        /////////////////
2168
2169            if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
2170            break;
2171    }
2172
2173    if (_ownsWindow) return 0;
2174
2175    return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2176                                 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2177}
2178
2179
2180//////////////////////////////////////////////////////////////////////////////
2181//  Class responsible for registering the Win32 Windowing System interface
2182//////////////////////////////////////////////////////////////////////////////
2183
2184struct RegisterWindowingSystemInterfaceProxy
2185{
2186    RegisterWindowingSystemInterfaceProxy()
2187    {
2188        osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
2189    }
2190
2191    ~RegisterWindowingSystemInterfaceProxy()
2192    {
2193        if (osg::Referenced::getDeleteHandler())
2194        {
2195            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2196            osg::Referenced::getDeleteHandler()->flushAll();
2197        }
2198
2199        osg::GraphicsContext::setWindowingSystemInterface(0);
2200    }
2201};
2202
2203static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2204
2205}; // namespace OsgViewer
2206
2207
2208// declare C entry point for static compilation.
2209extern "C" void graphicswindow_Win32(void)
2210{
2211    osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
2212}
Note: See TracBrowser for help on using the browser.