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

Revision 13130, 73.0 kB (checked in by robert, 15 hours ago)

Added in source shaders

  • 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
14/* Note, elements of GraphicsWindowX11 have used Prodcer/RenderSurface_X11.cpp as both
15 * a guide to use of X11/GLX and copying directly in the case of setBorder().
16 * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004  Don Burns.
17 */
18
19// TODO:
20// implement http://www.opengl.org/registry/specs/OML/glx_swap_method.txt
21
22#include <osgViewer/api/X11/GraphicsWindowX11>
23#include <osgViewer/api/X11/PixelBufferX11>
24
25#include <osg/DeleteHandler>
26
27#include <X11/Xlib.h>
28#include <X11/Xutil.h>
29
30#include <X11/Xmd.h>
31#include <X11/keysym.h>
32#include <X11/cursorfont.h>
33
34#include <X11/Xmd.h>        /* For CARD16 */
35
36#ifdef OSGVIEWER_USE_XRANDR
37#include <X11/extensions/Xrandr.h>
38#endif
39
40#include <unistd.h>
41
42using namespace osgViewer;
43
44#ifdef OSG_USE_EGL
45bool checkEGLError(const char* str)
46{
47    EGLint err = eglGetError();
48    if (err != EGL_SUCCESS)
49    {
50        OSG_WARN<<"Warning: "<<str<<" EGL error "<<std::hex<<err<<std::dec<<std::endl;
51        return true;
52    }
53    else
54    {
55        // OSG_WARN<<"EGL reports no errors: "<<str<<std::endl;
56        return false;
57    }
58}
59#endif
60
61class X11KeyboardMap
62{
63    public:
64
65        X11KeyboardMap()
66        {
67#if 0
68            _extendKeymap[8               ] = osgGA::GUIEventAdapter::KEY_BackSpace;
69            _extendKeymap[127             ] = osgGA::GUIEventAdapter::KEY_Delete;
70            _extendKeymap[27              ] = osgGA::GUIEventAdapter::KEY_Escape;
71            // _extendKeymap[13              ] = osgGA::GUIEventAdapter::KEY_Enter;
72#endif
73            _extendedKeymap[XK_Escape       ] = osgGA::GUIEventAdapter::KEY_Escape;
74            _extendedKeymap[XK_F1           ] = osgGA::GUIEventAdapter::KEY_F1;
75            _extendedKeymap[XK_F2           ] = osgGA::GUIEventAdapter::KEY_F2;
76            _extendedKeymap[XK_F3           ] = osgGA::GUIEventAdapter::KEY_F3;
77            _extendedKeymap[XK_F4           ] = osgGA::GUIEventAdapter::KEY_F4;
78            _extendedKeymap[XK_F5           ] = osgGA::GUIEventAdapter::KEY_F5;
79            _extendedKeymap[XK_F6           ] = osgGA::GUIEventAdapter::KEY_F6;
80            _extendedKeymap[XK_F7           ] = osgGA::GUIEventAdapter::KEY_F7;
81            _extendedKeymap[XK_F8           ] = osgGA::GUIEventAdapter::KEY_F8;
82            _extendedKeymap[XK_F9           ] = osgGA::GUIEventAdapter::KEY_F9;
83            _extendedKeymap[XK_F10          ] = osgGA::GUIEventAdapter::KEY_F10;
84            _extendedKeymap[XK_F11          ] = osgGA::GUIEventAdapter::KEY_F11;
85            _extendedKeymap[XK_F12          ] = osgGA::GUIEventAdapter::KEY_F12;
86            _extendedKeymap[XK_quoteleft    ] = '`';
87            _extendedKeymap[XK_minus        ] = '-';
88            _extendedKeymap[XK_equal        ] = '=';
89            _extendedKeymap[XK_BackSpace    ] = osgGA::GUIEventAdapter::KEY_BackSpace;
90            _extendedKeymap[XK_Tab          ] = osgGA::GUIEventAdapter::KEY_Tab;
91            _extendedKeymap[XK_bracketleft  ] = '[';
92            _extendedKeymap[XK_bracketright ] = ']';
93            _extendedKeymap[XK_backslash    ] = '\\';
94            _extendedKeymap[XK_Caps_Lock    ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
95            _extendedKeymap[XK_semicolon    ] = ';';
96            _extendedKeymap[XK_apostrophe   ] = '\'';
97            _extendedKeymap[XK_Return       ] = osgGA::GUIEventAdapter::KEY_Return;
98            _extendedKeymap[XK_comma        ] = ',';
99            _extendedKeymap[XK_period       ] = '.';
100            _extendedKeymap[XK_slash        ] = '/';
101            _extendedKeymap[XK_space        ] = ' ';
102            _extendedKeymap[XK_Shift_L      ] = osgGA::GUIEventAdapter::KEY_Shift_L;
103            _extendedKeymap[XK_Shift_R      ] = osgGA::GUIEventAdapter::KEY_Shift_R;
104            _extendedKeymap[XK_Control_L    ] = osgGA::GUIEventAdapter::KEY_Control_L;
105            _extendedKeymap[XK_Control_R    ] = osgGA::GUIEventAdapter::KEY_Control_R;
106            _extendedKeymap[XK_Meta_L       ] = osgGA::GUIEventAdapter::KEY_Meta_L;
107            _extendedKeymap[XK_Meta_R       ] = osgGA::GUIEventAdapter::KEY_Meta_R;
108            _extendedKeymap[XK_Alt_L        ] = osgGA::GUIEventAdapter::KEY_Alt_L;
109            _extendedKeymap[XK_Alt_R        ] = osgGA::GUIEventAdapter::KEY_Alt_R;
110            _extendedKeymap[XK_Super_L      ] = osgGA::GUIEventAdapter::KEY_Super_L;
111            _extendedKeymap[XK_Super_R      ] = osgGA::GUIEventAdapter::KEY_Super_R;
112            _extendedKeymap[XK_Hyper_L      ] = osgGA::GUIEventAdapter::KEY_Hyper_L;
113            _extendedKeymap[XK_Hyper_R      ] = osgGA::GUIEventAdapter::KEY_Hyper_R;
114            _extendedKeymap[XK_Menu         ] = osgGA::GUIEventAdapter::KEY_Menu;
115            _extendedKeymap[XK_Print        ] = osgGA::GUIEventAdapter::KEY_Print;
116            _extendedKeymap[XK_Scroll_Lock  ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
117            _extendedKeymap[XK_Pause        ] = osgGA::GUIEventAdapter::KEY_Pause;
118            _extendedKeymap[XK_Home         ] = osgGA::GUIEventAdapter::KEY_Home;
119            _extendedKeymap[XK_Page_Up      ] = osgGA::GUIEventAdapter::KEY_Page_Up;
120            _extendedKeymap[XK_End          ] = osgGA::GUIEventAdapter::KEY_End;
121            _extendedKeymap[XK_Page_Down    ] = osgGA::GUIEventAdapter::KEY_Page_Down;
122            _extendedKeymap[XK_Delete       ] = osgGA::GUIEventAdapter::KEY_Delete;
123            _extendedKeymap[XK_Insert       ] = osgGA::GUIEventAdapter::KEY_Insert;
124            _extendedKeymap[XK_Left         ] = osgGA::GUIEventAdapter::KEY_Left;
125            _extendedKeymap[XK_Up           ] = osgGA::GUIEventAdapter::KEY_Up;
126            _extendedKeymap[XK_Right        ] = osgGA::GUIEventAdapter::KEY_Right;
127            _extendedKeymap[XK_Down         ] = osgGA::GUIEventAdapter::KEY_Down;
128            _extendedKeymap[XK_Num_Lock     ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
129            _extendedKeymap[XK_KP_Divide    ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
130            _extendedKeymap[XK_KP_Multiply  ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
131            _extendedKeymap[XK_KP_Subtract  ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
132            _extendedKeymap[XK_KP_Add       ] = osgGA::GUIEventAdapter::KEY_KP_Add;
133            _extendedKeymap[XK_KP_Home      ] = osgGA::GUIEventAdapter::KEY_KP_Home;
134            _extendedKeymap[XK_KP_Up        ] = osgGA::GUIEventAdapter::KEY_KP_Up;
135            _extendedKeymap[XK_KP_Page_Up   ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
136            _extendedKeymap[XK_KP_Left      ] = osgGA::GUIEventAdapter::KEY_KP_Left;
137            _extendedKeymap[XK_KP_Begin     ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
138            _extendedKeymap[XK_KP_Right     ] = osgGA::GUIEventAdapter::KEY_KP_Right;
139            _extendedKeymap[XK_KP_End       ] = osgGA::GUIEventAdapter::KEY_KP_End;
140            _extendedKeymap[XK_KP_Down      ] = osgGA::GUIEventAdapter::KEY_KP_Down;
141            _extendedKeymap[XK_KP_Page_Down ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
142            _extendedKeymap[XK_KP_Insert    ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
143            _extendedKeymap[XK_KP_Delete    ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
144            _extendedKeymap[XK_KP_Enter     ] = osgGA::GUIEventAdapter::KEY_KP_Enter;
145
146            _standardKeymap[XK_1            ] = '1';
147            _standardKeymap[XK_2            ] = '2';
148            _standardKeymap[XK_3            ] = '3';
149            _standardKeymap[XK_4            ] = '4';
150            _standardKeymap[XK_5            ] = '5';
151            _standardKeymap[XK_6            ] = '6';
152            _standardKeymap[XK_7            ] = '7';
153            _standardKeymap[XK_8            ] = '8';
154            _standardKeymap[XK_9            ] = '9';
155            _standardKeymap[XK_0            ] = '0';
156            _standardKeymap[XK_A            ] = 'A';
157            _standardKeymap[XK_B            ] = 'B';
158            _standardKeymap[XK_C            ] = 'C';
159            _standardKeymap[XK_D            ] = 'D';
160            _standardKeymap[XK_E            ] = 'E';
161            _standardKeymap[XK_F            ] = 'F';
162            _standardKeymap[XK_G            ] = 'G';
163            _standardKeymap[XK_H            ] = 'H';
164            _standardKeymap[XK_I            ] = 'I';
165            _standardKeymap[XK_J            ] = 'J';
166            _standardKeymap[XK_K            ] = 'K';
167            _standardKeymap[XK_L            ] = 'L';
168            _standardKeymap[XK_M            ] = 'M';
169            _standardKeymap[XK_N            ] = 'N';
170            _standardKeymap[XK_O            ] = 'O';
171            _standardKeymap[XK_P            ] = 'P';
172            _standardKeymap[XK_Q            ] = 'Q';
173            _standardKeymap[XK_R            ] = 'R';
174            _standardKeymap[XK_S            ] = 'S';
175            _standardKeymap[XK_T            ] = 'T';
176            _standardKeymap[XK_U            ] = 'U';
177            _standardKeymap[XK_V            ] = 'V';
178            _standardKeymap[XK_W            ] = 'W';
179            _standardKeymap[XK_X            ] = 'X';
180            _standardKeymap[XK_Y            ] = 'Y';
181            _standardKeymap[XK_Z            ] = 'Z';
182            _standardKeymap[XK_a            ] = 'a';
183            _standardKeymap[XK_b            ] = 'b';
184            _standardKeymap[XK_c            ] = 'c';
185            _standardKeymap[XK_d            ] = 'd';
186            _standardKeymap[XK_e            ] = 'e';
187            _standardKeymap[XK_f            ] = 'f';
188            _standardKeymap[XK_g            ] = 'g';
189            _standardKeymap[XK_h            ] = 'h';
190            _standardKeymap[XK_i            ] = 'i';
191            _standardKeymap[XK_j            ] = 'j';
192            _standardKeymap[XK_k            ] = 'k';
193            _standardKeymap[XK_l            ] = 'l';
194            _standardKeymap[XK_m            ] = 'm';
195            _standardKeymap[XK_n            ] = 'n';
196            _standardKeymap[XK_o            ] = 'o';
197            _standardKeymap[XK_p            ] = 'p';
198            _standardKeymap[XK_q            ] = 'q';
199            _standardKeymap[XK_r            ] = 'r';
200            _standardKeymap[XK_s            ] = 's';
201            _standardKeymap[XK_t            ] = 't';
202            _standardKeymap[XK_u            ] = 'u';
203            _standardKeymap[XK_v            ] = 'v';
204            _standardKeymap[XK_w            ] = 'w';
205            _standardKeymap[XK_x            ] = 'x';
206            _standardKeymap[XK_y            ] = 'y';
207            _standardKeymap[XK_z            ] = 'z';
208        }
209
210        ~X11KeyboardMap() {}
211
212        int remapKey(int key)
213        {
214            KeyMap::iterator itr = _extendedKeymap.find(key);
215            if (itr != _extendedKeymap.end()) return itr->second;
216
217            itr = _standardKeymap.find(key);
218            if (itr != _standardKeymap.end()) return itr->second;
219
220            return key;
221        }
222
223        bool remapExtendedKey(int& key)
224        {
225            KeyMap::iterator itr = _extendedKeymap.find(key);
226            if (itr != _extendedKeymap.end())
227            {
228                key = itr->second;
229                return true;
230            }
231            else return false;
232        }
233
234    protected:
235
236        typedef std::map<int, int> KeyMap;
237        KeyMap _extendedKeymap;
238        KeyMap _standardKeymap;
239};
240
241static bool remapExtendedX11Key(int& key)
242{
243    static X11KeyboardMap s_x11KeyboardMap;
244    return s_x11KeyboardMap.remapExtendedKey(key);
245}
246
247// Functions to handle key maps of type char[32] as contained in
248// an XKeymapEvent or returned by XQueryKeymap().
249static inline bool keyMapGetKey(const char* map, unsigned int key)
250{
251    return (map[(key & 0xff) / 8] & (1 << (key & 7))) != 0;
252}
253
254static inline void keyMapSetKey(char* map, unsigned int key)
255{
256    map[(key & 0xff) / 8] |= (1 << (key & 7));
257}
258
259static inline void keyMapClearKey(char* map, unsigned int key)
260{
261    map[(key & 0xff) / 8] &= ~(1 << (key & 7));
262}
263
264GraphicsWindowX11::~GraphicsWindowX11()
265{
266    close(true);
267}
268
269Display* GraphicsWindowX11::getDisplayToUse() const
270{
271    if (_threadOfLastMakeCurrent==0)
272    {
273        return _display;
274    }
275
276    if (OpenThreads::Thread::CurrentThread()==_threadOfLastMakeCurrent)
277    {
278        return _display;
279    }
280    else
281    {
282        return _eventDisplay;
283    }
284}
285
286bool GraphicsWindowX11::createVisualInfo()
287{
288    if (_visualInfo)
289    {
290    #ifdef OSG_USE_EGL
291        delete _visualInfo;
292    #else
293        XFree(_visualInfo);
294    #endif
295        _visualInfo = 0;
296    }
297
298    if( _window != 0 )
299    {
300        XWindowAttributes watt;
301        XGetWindowAttributes( _display, _window, &watt );
302        XVisualInfo temp;
303        temp.visualid = XVisualIDFromVisual(watt.visual);
304        int n;
305        _visualInfo = XGetVisualInfo( _display, VisualIDMask, &temp, &n );
306    }
307    else
308    {
309    #ifdef OSG_USE_EGL
310
311        _visualInfo = new XVisualInfo;
312        int depth = DefaultDepth( _display, _traits->screenNum );
313        if (XMatchVisualInfo( _display, _traits->screenNum, depth, TrueColor, _visualInfo )==0)
314        {
315            OSG_NOTICE<<"GraphicsWindowX11::createVisualInfo() failed."<<std::endl;
316            return false;
317        }
318
319    #else
320
321        typedef std::vector<int> Attributes;
322        Attributes attributes;
323
324        attributes.push_back(GLX_USE_GL);
325
326        attributes.push_back(GLX_RGBA);
327
328        if (_traits->doubleBuffer) attributes.push_back(GLX_DOUBLEBUFFER);
329
330        if (_traits->quadBufferStereo) attributes.push_back(GLX_STEREO);
331
332        attributes.push_back(GLX_RED_SIZE); attributes.push_back(_traits->red);
333        attributes.push_back(GLX_GREEN_SIZE); attributes.push_back(_traits->green);
334        attributes.push_back(GLX_BLUE_SIZE); attributes.push_back(_traits->blue);
335        attributes.push_back(GLX_DEPTH_SIZE); attributes.push_back(_traits->depth);
336
337        if (_traits->alpha) { attributes.push_back(GLX_ALPHA_SIZE); attributes.push_back(_traits->alpha); }
338
339        if (_traits->stencil) { attributes.push_back(GLX_STENCIL_SIZE); attributes.push_back(_traits->stencil); }
340
341        #if defined(GLX_SAMPLE_BUFFERS) && defined (GLX_SAMPLES)
342
343            if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); }
344            if (_traits->samples) { attributes.push_back(GLX_SAMPLES); attributes.push_back(_traits->samples); }
345
346        #endif
347        // TODO
348        //  GLX_AUX_BUFFERS
349        //  GLX_ACCUM_RED_SIZE
350        //  GLX_ACCUM_GREEN_SIZE
351
352        attributes.push_back(None);
353
354        _visualInfo = glXChooseVisual( _display, _traits->screenNum, &(attributes.front()) );
355    #endif
356    }
357
358    return _visualInfo != 0;
359}
360
361bool GraphicsWindowX11::checkAndSendEventFullScreenIfNeeded(Display* display, int x, int y, int width, int height, bool windowDecoration)
362{
363    osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface();
364    if (wsi == NULL)
365    {
366        OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl;
367        return false;
368    }
369
370    unsigned int    screenWidth;
371    unsigned int    screenHeight;
372
373    wsi->getScreenResolution(*_traits, screenWidth, screenHeight);
374    bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !windowDecoration;
375
376    if (isFullScreen) {
377        resized(x, y, width, height);
378        getEventQueue()->windowResize(x, y, width, height, getEventQueue()->getTime());
379    }
380
381    Atom netWMStateAtom = XInternAtom(display, "_NET_WM_STATE", True);
382    Atom netWMStateFullscreenAtom = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", True);
383
384    if (netWMStateAtom != None && netWMStateFullscreenAtom != None)
385    {
386        XEvent xev;
387        xev.xclient.type = ClientMessage;
388        xev.xclient.serial = 0;
389        xev.xclient.send_event = True;
390        xev.xclient.window = _window;
391        xev.xclient.message_type = netWMStateAtom;
392        xev.xclient.format = 32;
393        xev.xclient.data.l[0] = isFullScreen ? 1 : 0;
394        xev.xclient.data.l[1] = netWMStateFullscreenAtom;
395        xev.xclient.data.l[2] = 0;
396
397        XSendEvent(display, RootWindow(display, DefaultScreen(display)),
398                    False,  SubstructureRedirectMask | SubstructureNotifyMask, &xev);
399        return true;
400    }
401    return false;
402}
403
404#define MWM_HINTS_FUNCTIONS   (1L << 0)
405#define MWM_HINTS_DECORATIONS (1L << 1)
406#define MWM_HINTS_INPUT_MODE  (1L << 2)
407#define MWM_HINTS_STATUS      (1L << 3)
408
409#define MWM_DECOR_ALL         (1L<<0)
410#define MWM_DECOR_BORDER      (1L<<1)
411#define MWM_DECOR_RESIZEH     (1L<<2)
412#define MWM_DECOR_TITLE       (1L<<3)
413#define MWM_DECOR_MENU        (1L<<4)
414#define MWM_DECOR_MINIMIZE    (1L<<5)
415#define MWM_DECOR_MAXIMIZE    (1L<<6)
416
417#define MWM_FUNC_ALL          (1L<<0)
418#define MWM_FUNC_RESIZE       (1L<<1)
419#define MWM_FUNC_MOVE         (1L<<2)
420#define MWM_FUNC_MINIMIZE     (1L<<3)
421#define MWM_FUNC_MAXIMIZE     (1L<<4)
422#define MWM_FUNC_CLOSE        (1L<<5)
423
424bool GraphicsWindowX11::setWindowDecorationImplementation(bool flag)
425{
426    Display* display = getDisplayToUse();
427
428    XMapWindow(display, _window );
429
430    checkAndSendEventFullScreenIfNeeded(display, _traits->x, _traits->y, _traits->width, _traits->height, flag);
431    struct
432    {
433        unsigned long flags;
434        unsigned long functions;
435        unsigned long decorations;
436        long          inputMode;
437        unsigned long status;
438    } wmHints;
439
440    Atom atom;
441    bool result = false;
442    if( (atom = XInternAtom( display, "_MOTIF_WM_HINTS", 0 )) != None )
443    {
444
445        if (flag)
446        {
447            wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
448            wmHints.functions = MWM_FUNC_ALL;
449            wmHints.decorations = MWM_DECOR_ALL;
450            wmHints.inputMode = 0;
451            wmHints.status = 0;
452
453            // if traits says not resize we want to set the functions to exlude MWM_FUNC_RESIZE,
454            // but this bitmask needs to be set if the MWM_FUNC_ALL bit is already set in order to toggle it off.
455            if (_traits.valid() && !_traits->supportsResize) wmHints.functions = wmHints.functions | MWM_FUNC_RESIZE;
456
457        }
458        else
459        {
460            wmHints.flags = MWM_HINTS_DECORATIONS;
461            wmHints.functions = 0;
462            wmHints.decorations = 0;
463            wmHints.inputMode = 0;
464            wmHints.status = 0;
465        }
466
467        XChangeProperty( display, _window, atom, atom, 32, PropModeReplace, (unsigned char *)&wmHints,  5 );
468        result = true;
469    }
470    else
471    {
472        OSG_NOTICE<<"Error: GraphicsWindowX11::setWindowDecorationImplementation(" << flag << ") - couldn't change decorations." << std::endl;
473        result = false;
474    }
475
476    XFlush(display);
477    XSync(display,0);
478    // add usleep here to give window manager a chance to handle the request, if
479    // we don't add this sleep then any X11 calls right afterwards can produce
480    // X11 errors.
481    usleep(100000);
482    return result;
483}
484
485bool GraphicsWindowX11::setWindowRectangleImplementation(int x, int y, int width, int height)
486{
487    if (!_initialized) return false;
488
489    Display* display = getDisplayToUse();
490
491    checkAndSendEventFullScreenIfNeeded(display, x, y, width, height, _traits->windowDecoration);
492
493    XMoveResizeWindow(display, _window, x, y, width, height);
494
495    XFlush(display);
496    XSync(display, 0);
497
498    // add usleep here to give window manager a chance to handle the request, if
499    // we don't add this sleep then any X11 calls right afterwards can produce
500    // X11 errors.
501    usleep(100000);
502
503
504    return true;
505}
506
507void GraphicsWindowX11::setWindowName(const std::string& name)
508{
509    if( _window == 0) return;
510
511    //    char *slist[] = { name.c_str(), 0L };
512    //    XTextProperty xtp;
513
514    //    XStringListToTextProperty( slist, 1, &xtp );
515
516    Display* display = getDisplayToUse();
517    if( !display ) return;
518
519    //    XSetWMName( display, _window, &xtp );
520    XStoreName( display, _window, name.c_str() );
521    XSetIconName( display, _window, name.c_str() );
522
523    XFlush(display);
524    XSync(display,0);
525
526    _traits->windowName = name;
527}
528
529void GraphicsWindowX11::setCursor(MouseCursor mouseCursor)
530{
531    Cursor newCursor = getOrCreateCursor(mouseCursor);
532    if (newCursor == _currentCursor) return;
533
534    _currentCursor = newCursor;
535    if (!_window) return;
536    Display* display = getDisplayToUse();
537    if (!display) return;
538    XDefineCursor( display, _window, _currentCursor );
539    XFlush(display);
540    XSync(display, 0);
541
542    _traits->useCursor = (_currentCursor != getOrCreateCursor(NoCursor));
543}
544
545Cursor GraphicsWindowX11::getOrCreateCursor(MouseCursor mouseCursor)
546{
547    std::map<MouseCursor,Cursor>::iterator i = _mouseCursorMap.find(mouseCursor);
548    if (i != _mouseCursorMap.end()) return i->second;
549
550    Display* display = getDisplayToUse();
551    if (!display) return None;
552
553    switch (mouseCursor) {
554    case NoCursor:
555    {
556        // create an empty mouse cursor, note that it is safe to destroy the Pixmap just past cursor creation
557        // since the resource in the x server is reference counted.
558        char buff[2] = {0,0};
559        XColor ncol = {0,0,0,0,DoRed|DoGreen|DoBlue,0};
560        Pixmap pixmap = XCreateBitmapFromData( display, _parent, buff, 1, 1);
561        _mouseCursorMap[mouseCursor] = XCreatePixmapCursor( display, pixmap, pixmap, &ncol, &ncol, 0, 0 );
562        XFreePixmap(display, pixmap);
563        // Important to have the pixmap and the buffer still available when the request is sent to the server ...
564        XFlush(display);
565        XSync(display, 0);
566        break;
567    }
568    case RightArrowCursor:
569        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_ptr );
570        break;
571    case LeftArrowCursor:
572        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_arrow );
573        break;
574    case InfoCursor:
575        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 );
576        break;
577    case DestroyCursor:
578        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_pirate );
579        break;
580    case HelpCursor:
581        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_question_arrow );
582        break;
583    case CycleCursor:
584        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_exchange );
585        break;
586    case SprayCursor:
587        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_spraycan );
588        break;
589    case WaitCursor:
590        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_watch );
591        break;
592    case TextCursor:
593        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_xterm );
594        break;
595    case CrosshairCursor:
596        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_crosshair );
597        break;
598    case UpDownCursor:
599        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_v_double_arrow );
600        break;
601    case LeftRightCursor:
602        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_h_double_arrow );
603        break;
604    case TopSideCursor:
605        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_side );
606        break;
607    case BottomSideCursor:
608        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_side );
609        break;
610    case LeftSideCursor:
611        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_side );
612        break;
613    case RightSideCursor:
614        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_right_side );
615        break;
616    case TopLeftCorner:
617        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_corner );
618        break;
619    case TopRightCorner:
620        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_right_corner );
621        break;
622    case BottomRightCorner:
623        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_right_corner );
624        break;
625    case BottomLeftCorner:
626        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_left_corner );
627        break;
628    case HandCursor:
629        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 );
630        break;
631
632    case InheritCursor:
633    default:
634        _mouseCursorMap[mouseCursor] = None;
635        break;
636    };
637    return _mouseCursorMap[mouseCursor];
638}
639
640void GraphicsWindowX11::init()
641{
642    if (_initialized) return;
643
644    if (!_traits)
645    {
646        _valid = false;
647        return;
648    }
649
650    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
651
652    WindowData* inheritedWindowData = dynamic_cast<WindowData*>(_traits->inheritedWindowData.get());
653    Window windowHandle = inheritedWindowData ? inheritedWindowData->_window : 0;
654
655    _ownsWindow = windowHandle == 0;
656
657    _display = XOpenDisplay(_traits->displayName().c_str());
658
659    if (!_display)
660    {
661        OSG_NOTICE<<"Error: Unable to open display \"" << XDisplayName(_traits->displayName().c_str()) << "\"."<<std::endl;
662        _valid = false;
663        return;
664    }
665
666    #ifdef OSG_USE_EGL
667
668        _eglDisplay = eglGetDisplay((EGLNativeDisplayType)_display);
669
670        EGLint eglMajorVersion, eglMinorVersion;
671        if (!eglInitialize(_eglDisplay, &eglMajorVersion, &eglMinorVersion))
672        {
673            OSG_NOTICE<<"GraphicsWindowX11::init() - eglInitialize() failed."<<std::endl;
674
675            XCloseDisplay( _display );
676            _display = 0;
677            _valid = false;
678            return;
679        }
680
681        OSG_NOTICE<<"GraphicsWindowX11::init() - eglInitialize() succeded eglMajorVersion="<<eglMajorVersion<<" iMinorVersion="<<eglMinorVersion<<std::endl;
682
683   #else
684        // Query for GLX extension
685        int errorBase, eventBase;
686        if( glXQueryExtension( _display, &errorBase, &eventBase)  == False )
687        {
688            OSG_NOTICE<<"Error: " << XDisplayName(_traits->displayName().c_str()) <<" has no GLX extension." << std::endl;
689
690            XCloseDisplay( _display );
691            _display = 0;
692            _valid = false;
693            return;
694        }
695    #endif
696
697    // OSG_NOTICE<<"GLX extension, errorBase="<<errorBase<<" eventBase="<<eventBase<<std::endl;
698
699    if (!createVisualInfo())
700    {
701        _traits->red /= 2;
702        _traits->green /= 2;
703        _traits->blue /= 2;
704        _traits->alpha /= 2;
705        _traits->depth /= 2;
706
707        OSG_INFO<<"Relaxing traits"<<std::endl;
708
709        if (!createVisualInfo())
710        {
711            OSG_NOTICE<<"Error: Not able to create requested visual." << std::endl;
712            XCloseDisplay( _display );
713            _display = 0;
714            _valid = false;
715            return;
716        }
717    }
718
719    // get any shared GLX contexts
720    GraphicsHandleX11* graphicsHandleX11 = dynamic_cast<GraphicsHandleX11*>(_traits->sharedContext.get());
721    Context sharedContext = graphicsHandleX11 ? graphicsHandleX11->getContext() : 0;
722
723    #ifdef OSG_USE_EGL
724
725        _valid = _ownsWindow ? createWindow() : setWindow(windowHandle);
726
727        if (!_valid)
728        {
729            XCloseDisplay( _display );
730            _display = 0;
731            return;
732        }
733
734        OSG_NOTICE<<"GraphicsWindowX11::init() - window created ="<<_valid<<std::endl;
735
736        eglBindAPI(EGL_OPENGL_ES_API);
737
738        EGLConfig eglConfig = 0;
739
740        #if defined(OSG_GLES2_AVAILABLE)
741            #define OSG_EGL_OPENGL_TARGET_BIT EGL_OPENGL_ES2_BIT
742        #else
743            #define OSG_EGL_OPENGL_TARGET_BIT EGL_OPENGL_ES_BIT
744        #endif
745
746        typedef std::vector<EGLint> Attributes;
747        Attributes attributes;
748
749        attributes.push_back(EGL_RED_SIZE); attributes.push_back(_traits->red);
750        attributes.push_back(EGL_GREEN_SIZE); attributes.push_back(_traits->green);
751        attributes.push_back(EGL_BLUE_SIZE); attributes.push_back(_traits->blue);
752        attributes.push_back(EGL_DEPTH_SIZE); attributes.push_back(_traits->depth);
753
754        if (_traits->alpha) { attributes.push_back(EGL_ALPHA_SIZE); attributes.push_back(_traits->alpha); }
755        if (_traits->stencil) { attributes.push_back(EGL_STENCIL_SIZE); attributes.push_back(_traits->stencil); }
756
757        if (_traits->sampleBuffers) { attributes.push_back(EGL_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); }
758        if (_traits->samples) { attributes.push_back(EGL_SAMPLES); attributes.push_back(_traits->samples); }
759
760        attributes.push_back(EGL_RENDERABLE_TYPE); attributes.push_back(OSG_EGL_OPENGL_TARGET_BIT);
761
762        attributes.push_back(EGL_NONE);
763        attributes.push_back(EGL_NONE);
764
765        int numConfigs;
766        if (!eglChooseConfig(_eglDisplay, &(attributes.front()), &eglConfig, 1, &numConfigs) || (numConfigs != 1))
767        {
768            OSG_NOTICE<<"GraphicsWindowX11::init() - eglChooseConfig() failed."<<std::endl;
769            XCloseDisplay( _display );
770            _valid = false;
771            _display = 0;
772            return;
773        }
774
775
776        _eglSurface = eglCreateWindowSurface(_eglDisplay, eglConfig, (EGLNativeWindowType)_window, NULL);
777        if (_eglSurface == EGL_NO_SURFACE)
778        {
779            OSG_NOTICE<<"GraphicsWindowX11::init() - eglCreateWindowSurface(..) failed."<<std::endl;
780            XCloseDisplay( _display );
781            _valid = false;
782            _display = 0;
783            return;
784        }
785
786        #if defined(OSG_GLES1_AVAILABLE)
787            EGLint* contextAttribs = 0;
788        #else
789            EGLint contextAttribs[] = {
790                 EGL_CONTEXT_CLIENT_VERSION,
791                2,
792                EGL_NONE
793            };
794        #endif
795
796        _context = eglCreateContext(_eglDisplay, eglConfig, sharedContext, contextAttribs);
797        if (_context == EGL_NO_CONTEXT)
798        {
799            OSG_NOTICE<<"GraphicsWindowX11::init() - eglCreateContext(..) failed."<<std::endl;
800            XCloseDisplay( _display );
801            _valid = false;
802            _display = 0;
803            return;
804        }
805
806        _initialized = true;
807
808        checkEGLError("after eglCreateContext()");
809
810    #else
811
812        _context = glXCreateContext( _display, _visualInfo, sharedContext, True );
813
814        if (!_context)
815        {
816            OSG_NOTICE<<"Error: Unable to create OpenGL graphics context."<<std::endl;
817            XCloseDisplay( _display );
818            _display = 0;
819            _valid = false;
820            return;
821        }
822
823        _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
824        _valid = _initialized;
825
826    #endif
827
828    if (_valid == false)
829    {
830        if (_display)
831        {
832            XCloseDisplay( _display );
833            _display = 0;
834        }
835
836        if (_eventDisplay)
837        {
838            XCloseDisplay( _eventDisplay );
839            _eventDisplay = 0;
840        }
841    }
842
843
844
845}
846
847bool GraphicsWindowX11::createWindow()
848{
849    unsigned int screen = _traits->screenNum;
850
851    _eventDisplay = XOpenDisplay(_traits->displayName().c_str());
852
853    _parent = RootWindow( _display, screen );
854
855    XWindowAttributes watt;
856    XGetWindowAttributes( _display, _parent, &watt );
857    // unsigned int parentWindowHeight = watt.height;
858
859    XSetWindowAttributes swatt;
860    swatt.colormap = XCreateColormap( _display, _parent, _visualInfo->visual, AllocNone);
861    //swatt.colormap = DefaultColormap( _dpy, 10 );
862    swatt.background_pixel = 0;
863    swatt.border_pixel = 0;
864    swatt.event_mask =  0;
865    unsigned long mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap;
866
867    if (_traits->overrideRedirect)
868    {
869        swatt.override_redirect = true;
870        mask |= CWOverrideRedirect;
871
872        OSG_INFO<<"Setting override redirect"<<std::endl;
873    }
874
875
876    osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface();
877    if (wsi == NULL) {
878    OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl;
879    return false;
880    }
881
882    int x = _traits->x;
883    int y = _traits->y;
884    int width = _traits->width;
885    int height = _traits->height;
886
887
888    unsigned int screenWidth;
889    unsigned int screenHeight;
890    wsi->getScreenResolution(*_traits, screenWidth, screenHeight);
891
892    bool doFullSceenWorkAround = false;
893    bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !_traits->windowDecoration;
894    if (isFullScreen && !_traits->overrideRedirect)
895    {
896        // follows is hack to get around problems with toggling off full screen with modern X11 window
897        // managers that try to be too clever when toggling off full screen and ignore the window size
898        // calls made by the OSG when the initial window size is full screen.
899
900        Atom netWMStateAtom = XInternAtom(_display, "_NET_WM_STATE", True);
901        Atom netWMStateFullscreenAtom = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", True);
902
903        // we have a modern X11 server so assume we need the do the full screen hack.
904        if (netWMStateAtom != None && netWMStateFullscreenAtom != None)
905        {
906            // artifically reduce the initial window size so that the windowing
907            // system has a size to go back to when toggling off full screen,
908            // we don't have to worry about the window being initially smaller as the
909            // setWindowDecoration(..) implementation with enable full screen for us
910            x = width/4;
911            y = height/4;
912            width /= 2;
913            height /= 2;
914
915            doFullSceenWorkAround = true;
916        }
917    }
918
919    _window = XCreateWindow( _display, _parent,
920                             x,
921                             y,
922                             width, height, 0,
923                             _visualInfo->depth, InputOutput,
924                             _visualInfo->visual, mask, &swatt );
925
926    if (!_window)
927    {
928        OSG_NOTICE<<"Error: Unable to create Window."<<std::endl;
929        _context = 0;
930        return false;
931    }
932
933
934    // Give window a class so that user preferences can be saved in the resource database.
935    XClassHint clH;
936    clH.res_name = (char *)"OSG";
937    clH.res_class = (char *)"osgViewer";
938    XSetClassHint( _display, _window, &clH);
939
940    // This positions the window at _windowX, _windowY
941    XSizeHints sh;
942    sh.flags = 0;
943    sh.flags |= USSize;
944    sh.flags &= 0x7;
945    sh.flags |= USPosition;
946    sh.flags &= 0xB;
947    sh.x = _traits->x;
948    sh.y = _traits->y;
949    sh.width  = _traits->width;
950    sh.height = _traits->height;
951    XSetStandardProperties( _display, _window, _traits->windowName.c_str(), _traits->windowName.c_str(), None, 0, 0, &sh);
952
953    setWindowDecoration(_traits->windowDecoration);
954
955
956    useCursor(_traits->useCursor);
957
958    _deleteWindow = XInternAtom (_display, "WM_DELETE_WINDOW", False);
959    XSetWMProtocols(_display, _window, &_deleteWindow, 1);
960
961
962    XFlush( _display );
963    XSync( _display, 0 );
964
965    // now update the window dimensions to account for any size changes made by the window manager,
966    XGetWindowAttributes( _display, _window, &watt );
967
968    if (_traits->x != watt.x || _traits->y != watt.y
969        ||_traits->width != watt.width || _traits->height != watt.height)
970    {
971
972        if (doFullSceenWorkAround)
973        {
974            OSG_INFO<<"Full Screen failed, resizing manually"<<std::endl;
975            XMoveResizeWindow(_display, _window, _traits->x, _traits->y, _traits->width, _traits->height);
976
977            XFlush(_display);
978            XSync(_display, 0);
979
980            XGetWindowAttributes( _display, _window, &watt );
981        }
982
983        resized( watt.x, watt.y, watt.width, watt.height );
984    }
985
986    //OSG_NOTICE<<"After sync apply.x = "<<watt.x<<" watt.y="<<watt.y<<" width="<<watt.width<<" height="<<watt.height<<std::endl;
987
988
989    XSelectInput( _eventDisplay, _window, ExposureMask | StructureNotifyMask |
990                                     KeyPressMask | KeyReleaseMask |
991                                     PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
992                                     KeymapStateMask | FocusChangeMask | EnterWindowMask );
993
994    XFlush( _eventDisplay );
995    XSync( _eventDisplay, 0 );
996    rescanModifierMapping();
997
998    return true;
999}
1000
1001bool GraphicsWindowX11::setWindow(Window window)
1002{
1003    if (_initialized)
1004    {
1005        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Window already created; it cannot be changed";
1006        return false;
1007    }
1008
1009    if (window==0)
1010    {
1011        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Invalid window handle passed ";
1012        return false;
1013    }
1014
1015    _window = window;
1016    if (_window==0)
1017    {
1018        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Unable to retrieve native window handle";
1019        return false;
1020    }
1021
1022    XWindowAttributes watt;
1023    XGetWindowAttributes( _display, _window, &watt );
1024    _traits->x = watt.x;
1025    _traits->y = watt.y;
1026    _traits->width = watt.width;
1027    _traits->height = watt.height;
1028
1029    _parent = DefaultRootWindow( _display );
1030
1031    //_traits->supportsResize = false;
1032    _traits->windowDecoration = false;
1033
1034    if (_traits->windowName.size()) setWindowName(_traits->windowName);
1035
1036    _eventDisplay = XOpenDisplay(_traits->displayName().c_str());
1037
1038    XFlush( _eventDisplay );
1039    XSync( _eventDisplay, 0 );
1040
1041    return true;
1042}
1043
1044bool GraphicsWindowX11::realizeImplementation()
1045{
1046    if (_realized)
1047    {
1048        OSG_NOTICE<<"GraphicsWindowX11::realizeImplementation() Already realized"<<std::endl;
1049        return true;
1050    }
1051
1052    if (!_initialized) init();
1053
1054    if (!_initialized) return false;
1055
1056    XMapWindow( _display, _window );
1057
1058//    Window temp = _window;
1059//    XSetWMColormapWindows( _display, _window, &temp, 1);
1060
1061    _realized = true;
1062
1063    return true;
1064}
1065
1066bool GraphicsWindowX11::makeCurrentImplementation()
1067{
1068    if (!_realized)
1069    {
1070        OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
1071        return false;
1072    }
1073
1074    #ifdef OSG_USE_EGL
1075        bool result = eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _context)==EGL_TRUE;
1076        checkEGLError("after eglMakeCurrent()");
1077        return result;
1078    #else
1079        return glXMakeCurrent( _display, _window, _context )==True;
1080    #endif
1081}
1082
1083bool GraphicsWindowX11::releaseContextImplementation()
1084{
1085    if (!_realized)
1086    {
1087        OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do release context."<<std::endl;
1088        return false;
1089    }
1090
1091    #ifdef OSG_USE_EGL
1092        bool result = eglMakeCurrent( _eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )==EGL_TRUE;
1093        checkEGLError("after eglMakeCurrent() release");
1094        return result;
1095    #else
1096        return glXMakeCurrent( _display, None, NULL )==True;
1097    #endif
1098}
1099
1100
1101void GraphicsWindowX11::closeImplementation()
1102{
1103    // OSG_NOTICE<<"Closing GraphicsWindowX11"<<std::endl;
1104
1105    if (_eventDisplay)
1106    {
1107        XCloseDisplay( _eventDisplay );
1108        _eventDisplay = 0;
1109    }
1110
1111    if (_display)
1112    {
1113        if (_context)
1114        {
1115        #ifdef OSG_USE_EGL
1116            eglDestroyContext( _eglDisplay, _context );
1117        #else
1118            glXDestroyContext( _display, _context );
1119        #endif
1120        }
1121
1122        if (_window && _ownsWindow)
1123        {
1124            XDestroyWindow(_display, _window);
1125        }
1126
1127        XFlush( _display );
1128        XSync( _display,0 );
1129    }
1130
1131    _window = 0;
1132    _parent = 0;
1133    _context = 0;
1134
1135    if (_visualInfo)
1136    {
1137        #ifdef OSG_USE_EGL
1138            delete _visualInfo;
1139        #else
1140            XFree(_visualInfo);
1141        #endif
1142        _visualInfo = 0;
1143    }
1144
1145
1146    if (_display)
1147    {
1148        XCloseDisplay( _display );
1149        _display = 0;
1150    }
1151
1152    _initialized = false;
1153    _realized = false;
1154    _valid = false;
1155}
1156
1157void GraphicsWindowX11::swapBuffersImplementation()
1158{
1159    if (!_realized) return;
1160
1161    // OSG_NOTICE<<"swapBuffersImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
1162
1163    #ifdef OSG_USE_EGL
1164        eglSwapBuffers( _eglDisplay, _eglSurface );
1165        checkEGLError("after eglSwapBuffers()");
1166    #else
1167#if 0
1168        if (_traits.valid() && _traits->vsync) {
1169
1170            unsigned int counter;
1171            glXGetVideoSyncSGI(&counter);
1172            glXWaitVideoSyncSGI(1, 0, &counter);
1173        }
1174#endif
1175        glXSwapBuffers( _display, _window );
1176    #endif
1177
1178
1179    while( XPending(_display) )
1180    {
1181        XEvent ev;
1182        XNextEvent( _display, &ev );
1183
1184        switch( ev.type )
1185        {
1186            case ClientMessage:
1187            {
1188                if (static_cast<Atom>(ev.xclient.data.l[0]) == _deleteWindow)
1189                {
1190                    OSG_INFO<<"DeleteWindow event received"<<std::endl;
1191                    getEventQueue()->closeWindow();
1192                }
1193            }
1194        }
1195    }
1196}
1197
1198void GraphicsWindowX11::checkEvents()
1199{
1200    if (!_realized) return;
1201
1202    Display* display = _eventDisplay;
1203
1204    double baseTime = _timeOfLastCheckEvents;
1205    double eventTime = baseTime;
1206    double resizeTime = eventTime;
1207    _timeOfLastCheckEvents = getEventQueue()->getTime();
1208    if (baseTime>_timeOfLastCheckEvents) baseTime = _timeOfLastCheckEvents;
1209
1210
1211    // OSG_NOTICE<<"GraphicsWindowX11::checkEvents() : getEventQueue()->getCurrentEventState()->getGraphicsContext()="<<getEventQueue()->getCurrentEventState()->getGraphicsContext()<<std::endl;
1212
1213    int windowX = _traits->x;
1214    int windowY = _traits->y;
1215    int windowWidth = _traits->width;
1216    int windowHeight = _traits->height;
1217
1218    Time firstEventTime = 0;
1219
1220    // OSG_NOTICE<<"Check events"<<std::endl;
1221    while( XPending(display) )
1222    {
1223        XEvent ev;
1224        XNextEvent( display, &ev );
1225
1226        switch( ev.type )
1227        {
1228            case ClientMessage:
1229            {
1230                OSG_NOTICE<<"ClientMessage event received"<<std::endl;
1231                if (static_cast<Atom>(ev.xclient.data.l[0]) == _deleteWindow)
1232                {
1233                    OSG_NOTICE<<"DeleteWindow event received"<<std::endl;
1234                    // FIXME only do if _ownsWindow ?
1235                    getEventQueue()->closeWindow(eventTime);
1236                }
1237                break;
1238            }
1239            case Expose :
1240                OSG_INFO<<"Expose x="<<ev.xexpose.x<<" y="<<ev.xexpose.y<<" width="<<ev.xexpose.width<<", height="<<ev.xexpose.height<<std::endl;
1241                requestRedraw();
1242                break;
1243
1244            case GravityNotify :
1245                OSG_INFO<<"GravityNotify event received"<<std::endl;
1246                break;
1247
1248            case ReparentNotify:
1249                OSG_INFO<<"ReparentNotify event received"<<std::endl;
1250                break;
1251
1252            case DestroyNotify :
1253                OSG_NOTICE<<"DestroyNotify event received"<<std::endl;
1254                _realized =  false;
1255                _valid = false;
1256                break;
1257
1258            case ConfigureNotify :
1259            {
1260                OSG_INFO<<"ConfigureNotify x="<<ev.xconfigure.x<<" y="<<ev.xconfigure.y<<" width="<<ev.xconfigure.width<<", height="<<ev.xconfigure.height<<std::endl;
1261
1262                if (windowX != ev.xconfigure.x ||
1263                    windowY != ev.xconfigure.y ||
1264                    windowWidth != ev.xconfigure.width ||
1265                    windowHeight != ev.xconfigure.height)
1266                {
1267                    resizeTime = eventTime;
1268
1269                    windowX = ev.xconfigure.x;
1270                    windowY = ev.xconfigure.y;
1271                    windowWidth = ev.xconfigure.width;
1272                    windowHeight = ev.xconfigure.height;
1273                }
1274
1275                break;
1276            }
1277
1278            case MapNotify :
1279            {
1280                OSG_INFO<<"MapNotify"<<std::endl;
1281                XWindowAttributes watt;
1282                do
1283                    XGetWindowAttributes(display, _window, &watt );
1284                while( watt.map_state != IsViewable );
1285
1286                OSG_INFO<<"MapNotify x="<<watt.x<<" y="<<watt.y<<" width="<<watt.width<<", height="<<watt.height<<std::endl;
1287
1288                if (windowWidth != watt.width || windowHeight != watt.height)
1289                {
1290                    resizeTime = eventTime;
1291
1292                    windowWidth = watt.width;
1293                    windowHeight = watt.height;
1294                }
1295
1296                break;
1297            }
1298
1299            case FocusIn :
1300                OSG_INFO<<"FocusIn event received"<<std::endl;
1301                flushKeyEvents();
1302                break;
1303
1304            case UnmapNotify :
1305            case FocusOut :
1306            {
1307                OSG_INFO<<"FocusOut/UnmapNotify event received"<<std::endl;
1308                if (ev.type == FocusOut && ev.xfocus.mode != NotifyNormal) break;
1309
1310                char modMap[32];
1311                getModifierMap(modMap);
1312
1313                // release normal (non-modifier) keys
1314                for (unsigned int key = 8; key < 256; key++)
1315                {
1316                    bool isModifier = keyMapGetKey(modMap, key);
1317                    if (!isModifier) forceKey(key, eventTime, false);
1318                }
1319
1320                // release modifier keys
1321                for (unsigned int key = 8; key < 256; key++)
1322                {
1323                    bool isModifier = keyMapGetKey(modMap, key);
1324                    if (isModifier) forceKey(key, eventTime, false);
1325                }
1326                break;
1327            }
1328
1329            case EnterNotify :
1330                OSG_INFO<<"EnterNotify event received"<<std::endl;
1331                _modifierState = ev.xcrossing.state;
1332                syncLocks();
1333                break;
1334
1335            case KeymapNotify :
1336            {
1337                OSG_INFO<<"KeymapNotify event received"<<std::endl;
1338
1339                // KeymapNotify is guaranteed to directly follow either a FocusIn or
1340                // an EnterNotify event. We are only interested in the FocusIn case.
1341                if (_lastEventType != FocusIn) break;
1342
1343                char modMap[32];
1344                getModifierMap(modMap);
1345                syncLocks();
1346
1347                char keyMap[32];
1348                XQueryKeymap(_eventDisplay, keyMap);
1349
1350                // release normal (non-modifier) keys
1351                for (unsigned int key = 8; key < 256; key++)
1352                {
1353                    bool isModifier = keyMapGetKey(modMap, key);
1354                    if (isModifier) continue;
1355                    bool isPressed = keyMapGetKey(keyMap, key);
1356                    if (!isPressed) forceKey(key, eventTime, false);
1357                }
1358
1359                // press/release modifier keys
1360                for (unsigned int key = 8; key < 256; key++)
1361                {
1362                    bool isModifier = keyMapGetKey(modMap, key);
1363                    if (!isModifier) continue;
1364                    bool isPressed = keyMapGetKey(keyMap, key);
1365                    forceKey(key, eventTime, isPressed);
1366                }
1367
1368                // press normal keys
1369                for (unsigned int key = 8; key < 256; key++)
1370                {
1371                    bool isModifier = keyMapGetKey(modMap, key);
1372                    if (isModifier) continue;
1373                    bool isPressed = keyMapGetKey(keyMap, key);
1374                    if (isPressed) forceKey(key, eventTime, true);
1375                }
1376                break;
1377            }
1378
1379            case MappingNotify :
1380                OSG_INFO<<"MappingNotify event received"<<std::endl;
1381                if (ev.xmapping.request == MappingModifier) rescanModifierMapping();
1382                break;
1383
1384            case MotionNotify :
1385            {
1386                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1387                Time relativeTime = ev.xmotion.time - firstEventTime;
1388                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1389
1390                int  wx, wy;
1391                Window win = 0L;
1392                if( ev.xmotion.same_screen )
1393                {
1394                    wx = ev.xmotion.x;
1395                    wy = ev.xmotion.y;
1396                }
1397                else
1398                {
1399                    // the mouse in on another screen so need to compute the
1400                    // coordinates of the mouse position relative to an absolute position
1401                    // then take away the position of the original window/screen to get
1402                    // the coordinates relative to the original position.
1403                    Window root;
1404                    int rx, ry;
1405                    unsigned int buttons;
1406
1407                    int screenOrigin_x = 0;
1408                    int screenOrigin_y = 0;
1409                    int i;
1410                    for(i= 0; i < ScreenCount(display); i++ )
1411                    {
1412                        if( XQueryPointer( display, RootWindow(display, i),
1413                              &root, &win, &rx, &ry, &wx, &wy, &buttons) )
1414                        {
1415                            break;
1416                        }
1417
1418                        screenOrigin_x += DisplayWidth(display, i);
1419                    }
1420
1421                    for(i= 0; i < static_cast<int>(_traits->screenNum); i++ )
1422                    {
1423                        screenOrigin_x -= DisplayWidth(display, i);
1424                    }
1425
1426                    int dest_x_return, dest_y_return;
1427                    Window child_return;
1428                    XTranslateCoordinates(display, _window, _parent, 0, 0, &dest_x_return, &dest_y_return, &child_return);
1429
1430                    wx += (screenOrigin_x - dest_x_return);
1431                    wy += (screenOrigin_y - dest_y_return);
1432                }
1433
1434
1435                float mx = wx;
1436                float my = wy;
1437                transformMouseXY(mx, my);
1438                getEventQueue()->mouseMotion(mx, my, eventTime);
1439
1440                // OSG_NOTICE<<"MotionNotify wx="<<wx<<" wy="<<wy<<" mx="<<mx<<" my="<<my<<std::endl;
1441
1442                break;
1443            }
1444
1445            case ButtonPress :
1446            {
1447                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1448                Time relativeTime = ev.xmotion.time - firstEventTime;
1449                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1450
1451                if( ev.xbutton.button == Button4 )
1452                {
1453                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP, eventTime);
1454                }
1455                else if( ev.xbutton.button == Button5)
1456                {
1457                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN, eventTime);
1458                }
1459                else
1460                {
1461                    float mx = ev.xbutton.x;
1462                    float my = ev.xmotion.y;
1463                    transformMouseXY(mx, my);
1464                    getEventQueue()->mouseButtonPress(mx, my, ev.xbutton.button, eventTime);
1465                }
1466                break;
1467            }
1468
1469            case ButtonRelease :
1470            {
1471                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1472                Time relativeTime = ev.xmotion.time - firstEventTime;
1473                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1474
1475                if( ev.xbutton.button == Button4 )
1476                {
1477                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP, eventTime);
1478                }
1479                else if( ev.xbutton.button == Button5)
1480                {
1481                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN, eventTime);
1482                }
1483                else
1484                {
1485                    float mx = ev.xbutton.x;
1486                    float my = ev.xmotion.y;
1487                    transformMouseXY(mx, my);
1488                    getEventQueue()->mouseButtonRelease(mx, my, ev.xbutton.button, eventTime);
1489                }
1490                break;
1491            }
1492
1493            case KeyPress:
1494            {
1495                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1496                Time relativeTime = ev.xmotion.time - firstEventTime;
1497                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1498
1499                _modifierState = ev.xkey.state;
1500                keyMapSetKey(_keyMap, ev.xkey.keycode);
1501                int keySymbol = 0;
1502                int unmodifiedKeySymbol = 0;
1503                adaptKey(ev.xkey, keySymbol, unmodifiedKeySymbol);
1504
1505                getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
1506                break;
1507            }
1508
1509            case KeyRelease:
1510            {
1511                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1512                Time relativeTime = ev.xmotion.time - firstEventTime;
1513                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1514#if 1
1515                // Check for following KeyPress events and see if
1516                // the pair are the result of auto-repeat. If so, drop
1517                // this one on the floor, to be consistent with
1518                // Windows and Mac ports. The idea comes from libSDL sources.
1519                XEvent nextev;
1520                if (XPending(display))
1521                {
1522                    XPeekEvent(display, &nextev);
1523                    if ((nextev.type == KeyPress)
1524                        && (nextev.xkey.keycode == ev.xkey.keycode)
1525                        && (nextev.xmotion.time - ev.xmotion.time < 2))
1526                    {
1527                        break;
1528                    }
1529                }
1530#endif
1531                _modifierState = ev.xkey.state;
1532                keyMapClearKey(_keyMap, ev.xkey.keycode);
1533                int keySymbol = 0;
1534                int unmodifiedKeySymbol = 0;
1535                adaptKey(ev.xkey, keySymbol, unmodifiedKeySymbol);
1536
1537                getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
1538                break;
1539            }
1540
1541            default:
1542                OSG_NOTICE<<"Other event "<<ev.type<<std::endl;
1543                break;
1544
1545        }
1546        _lastEventType = ev.type;
1547    }
1548
1549    // send window resize event if window position or size was changed
1550    if (windowX != _traits->x ||
1551        windowY != _traits->y ||
1552        windowWidth != _traits->width ||
1553        windowHeight != _traits->height)
1554    {
1555        resized(windowX, windowY, windowWidth, windowHeight);
1556        getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
1557
1558        // request window repaint if window size was changed
1559        if (windowWidth != _traits->width ||
1560            windowHeight != _traits->height)
1561        {
1562            requestRedraw();
1563        }
1564    }
1565}
1566
1567void GraphicsWindowX11::grabFocus()
1568{
1569    Display* display = getDisplayToUse();
1570
1571    XSetInputFocus( display, _window, RevertToNone, CurrentTime );
1572    XFlush(display);
1573    XSync(display,0);
1574}
1575
1576void GraphicsWindowX11::grabFocusIfPointerInWindow()
1577{
1578    Window win, root;
1579    int wx, wy, rx, ry;
1580    unsigned int buttons;
1581
1582    Display* display = getDisplayToUse();
1583
1584    if( XQueryPointer( display, _window,
1585          &root, &win, &rx, &ry, &wx, &wy, &buttons))
1586    {
1587#if 0
1588        if (wx>=0 && wx<_traits->width &&
1589            wy>=0 && wy<_traits->height)
1590        {
1591            grabFocus();
1592        }
1593#else
1594        grabFocus();
1595#endif
1596    }
1597}
1598
1599void GraphicsWindowX11::transformMouseXY(float& x, float& y)
1600{
1601    if (getEventQueue()->getUseFixedMouseInputRange())
1602    {
1603        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1604        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1605        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1606    }
1607}
1608
1609void GraphicsWindowX11::adaptKey(XKeyEvent& keyevent, int& keySymbol, int& unmodifiedKeySymbol)
1610{
1611    unsigned char buffer_return[32];
1612    int bytes_buffer = 32;
1613    KeySym keysym_return;
1614
1615    int numChars = XLookupString(&keyevent, reinterpret_cast<char*>(buffer_return), bytes_buffer, &keysym_return, NULL);
1616    keySymbol = keysym_return;
1617    if (!remapExtendedX11Key(keySymbol) && (numChars==1))
1618    {
1619        keySymbol = buffer_return[0];
1620    }
1621
1622    unmodifiedKeySymbol = XKeycodeToKeysym(keyevent.display, keyevent.keycode, 0);
1623}
1624
1625// Function to inject artificial key presses/releases.
1626void GraphicsWindowX11::forceKey(int key, double time, bool state)
1627{
1628    if (!(state ^ keyMapGetKey(_keyMap, key))) return; // already pressed/released
1629
1630    XKeyEvent event;
1631    event.serial = 0;
1632    event.send_event = True;
1633    event.display = _eventDisplay;
1634    event.window = _window;
1635    event.subwindow = 0;
1636    event.time = 0;
1637    event.x = 0;
1638    event.y = 0;
1639    event.x_root = 0;
1640    event.y_root = 0;
1641    event.state = getModifierMask() | (_modifierState & (LockMask | _numLockMask));
1642    event.keycode = key;
1643    event.same_screen = True;
1644
1645    int keySymbol = 0;
1646    int unmodifiedKeySymbol = 0;
1647    if (state)
1648    {
1649        event.type = KeyPress;
1650        adaptKey(event, keySymbol, unmodifiedKeySymbol);
1651        getEventQueue()->keyPress(keySymbol, time, unmodifiedKeySymbol);
1652        keyMapSetKey(_keyMap, key);
1653    }
1654    else
1655    {
1656        event.type = KeyRelease;
1657        adaptKey(event, keySymbol, unmodifiedKeySymbol);
1658        getEventQueue()->keyRelease(keySymbol, time, unmodifiedKeySymbol);
1659        keyMapClearKey(_keyMap, key);
1660    }
1661}
1662
1663void GraphicsWindowX11::syncLocks()
1664{
1665    unsigned int mask = getEventQueue()->getCurrentEventState()->getModKeyMask();
1666
1667    if (_modifierState & LockMask)
1668        mask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
1669    else
1670        mask &= ~osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
1671
1672    if (_modifierState & _numLockMask)
1673        mask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
1674    else
1675        mask &= ~osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
1676
1677    getEventQueue()->getCurrentEventState()->setModKeyMask(mask);
1678}
1679
1680void GraphicsWindowX11::rescanModifierMapping()
1681{
1682    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1683    KeyCode *m = mkm->modifiermap;
1684    KeyCode numlock = XKeysymToKeycode(_eventDisplay, XK_Num_Lock);
1685    _numLockMask = 0;
1686    for (int i = 0; i < mkm->max_keypermod * 8; i++, m++)
1687    {
1688        if (*m == numlock)
1689        {
1690            _numLockMask = 1 << (i / mkm->max_keypermod);
1691            break;
1692        }
1693    }
1694    XFree(mkm->modifiermap);
1695    XFree(mkm);
1696}
1697
1698void GraphicsWindowX11::flushKeyEvents()
1699{
1700    XEvent e;
1701    while (XCheckMaskEvent(_eventDisplay, KeyPressMask|KeyReleaseMask, &e))
1702        continue;
1703}
1704
1705// Returns char[32] keymap with bits for every modifier key set.
1706void GraphicsWindowX11::getModifierMap(char* keymap) const
1707{
1708    memset(keymap, 0, 32);
1709    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1710    KeyCode *m = mkm->modifiermap;
1711    for (int i = 0; i < mkm->max_keypermod * 8; i++, m++)
1712    {
1713        if (*m) keyMapSetKey(keymap, *m);
1714    }
1715    XFree(mkm->modifiermap);
1716    XFree(mkm);
1717}
1718
1719int GraphicsWindowX11::getModifierMask() const
1720{
1721    int mask = 0;
1722    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1723    for (int i = 0; i < mkm->max_keypermod * 8; i++)
1724    {
1725        unsigned int key = mkm->modifiermap[i];
1726        if (key && keyMapGetKey(_keyMap, key))
1727        {
1728            mask |= 1 << (i / mkm->max_keypermod);
1729        }
1730    }
1731    XFree(mkm->modifiermap);
1732    XFree(mkm);
1733    return mask;
1734}
1735
1736void GraphicsWindowX11::requestWarpPointer(float x,float y)
1737{
1738    if (!_realized)
1739    {
1740        OSG_INFO<<"GraphicsWindowX11::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
1741        return;
1742    }
1743
1744    Display* display = _eventDisplay; // getDisplayToUse();
1745
1746    XWarpPointer( display,
1747                  None,
1748                  _window,
1749                  0, 0, 0, 0,
1750                  static_cast<int>(x), static_cast<int>(y) );
1751
1752    XFlush(display);
1753    XSync(display, 0);
1754
1755    getEventQueue()->mouseWarped(x,y);
1756}
1757
1758extern "C"
1759{
1760
1761typedef int (*X11ErrorHandler)(Display*, XErrorEvent*);
1762
1763int X11ErrorHandling(Display* display, XErrorEvent* event)
1764{
1765    OSG_NOTICE<<"Got an X11ErrorHandling call display="<<display<<" event="<<event<<std::endl;
1766
1767    char buffer[256];
1768    XGetErrorText( display, event->error_code, buffer, 256);
1769
1770    OSG_NOTICE << buffer << std::endl;
1771    OSG_NOTICE << "Major opcode: " << (int)event->request_code << std::endl;
1772    OSG_NOTICE << "Minor opcode: " << (int)event->minor_code << std::endl;
1773    OSG_NOTICE << "Error code: " << (int)event->error_code << std::endl;
1774    OSG_NOTICE << "Request serial: " << event->serial << std::endl;
1775    OSG_NOTICE << "Current serial: " << NextRequest( display ) - 1 << std::endl;
1776
1777    switch( event->error_code )
1778    {
1779        case BadValue:
1780            OSG_NOTICE << "  Value: " << event->resourceid << std::endl;
1781            break;
1782
1783        case BadAtom:
1784            OSG_NOTICE << "  AtomID: " << event->resourceid << std::endl;
1785            break;
1786
1787        default:
1788            OSG_NOTICE << "  ResourceID: " << event->resourceid << std::endl;
1789            break;
1790    }
1791    return 0;
1792}
1793
1794}
1795
1796class X11WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface
1797{
1798#ifdef OSGVIEWER_USE_XRANDR
1799    // TODO: Investigate whether or not Robert thinks we should store/restore the original
1800    // resolution in the destructor; I'm not sure the other ones do this, and it may be the
1801    // responsibility of the user.
1802    bool _setScreen(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height, unsigned int colorDepth, double rate) {
1803        if (colorDepth>0)
1804            OSG_NOTICE << "X11WindowingSystemInterface::_setScreen() is not fully implemented (missing depth)."<<std::endl;
1805
1806        Display* display = XOpenDisplay(si.displayName().c_str());
1807
1808        if(display)
1809        {
1810            XRRScreenConfiguration* sc = XRRGetScreenInfo(display, RootWindow(display, si.screenNum));
1811
1812            if(!sc)
1813            {
1814                OSG_NOTICE << "Unable to create XRRScreenConfiguration on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1815                return false;
1816            }
1817
1818            int      numScreens = 0;
1819            int      numRates   = 0;
1820            Rotation currentRot = 0;
1821            bool     okay       = false;
1822
1823            XRRConfigRotations(sc, &currentRot);
1824
1825            // If the width or height are zero, use our defaults.
1826            if(!width || !height)
1827            {
1828                getScreenResolution(si, width, height);
1829            }
1830
1831            // If this somehow fails, okay will still be false, no iteration will take place below,
1832            // and the sc pointer will still be freed later on.
1833            XRRScreenSize* ss = XRRConfigSizes(sc, &numScreens);
1834
1835            for(int i = 0; i < numScreens; i++)
1836            {
1837                if(ss[i].width == static_cast<int>(width) && ss[i].height == static_cast<int>(height))
1838                {
1839                    short* rates     = XRRConfigRates(sc, i, &numRates);
1840                    bool   rateFound = false;
1841
1842                    // Search for our rate in the list of acceptable rates given to us by Xrandr.
1843                    // If it's not found, rateFound will still be false and the call will never
1844                    // be made to XRRSetScreenConfigAndRate since the rate will be invalid.
1845                    for(int r = 0; r < numRates; r++)
1846                    {
1847                        if(rates[r] == static_cast<short>(rate))
1848                        {
1849                            rateFound = true;
1850                            break;
1851                        }
1852                    }
1853
1854                    if(rate > 0.0f && !rateFound)
1855                    {
1856                        OSG_NOTICE << "Unable to find valid refresh rate " << rate << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1857                    }
1858                    else if(XRRSetScreenConfigAndRate(display, sc, DefaultRootWindow(display), i, currentRot, static_cast<short>(rate), CurrentTime) != RRSetConfigSuccess)
1859                    {
1860                        OSG_NOTICE << "Unable to set resolution to " << width << "x" << height << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1861                    }
1862                    else
1863                    {
1864                        okay = true;
1865                        break;
1866                    }
1867                }
1868            }
1869
1870            XRRFreeScreenConfigInfo(sc);
1871
1872            return okay;
1873        }
1874        else
1875        {
1876            OSG_NOTICE << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1877            return false;
1878        }
1879    }
1880#endif
1881
1882protected:
1883    bool _errorHandlerSet;
1884
1885
1886public:
1887    X11WindowingSystemInterface()
1888    {
1889        OSG_INFO<<"X11WindowingSystemInterface()"<<std::endl;
1890
1891
1892        // Install an X11 error handler, if the application has not already done so.
1893
1894        // Set default handler, and get pointer to current handler.
1895        X11ErrorHandler currentHandler = XSetErrorHandler(NULL);
1896
1897        // Set our handler, and get pointer to default handler.
1898        X11ErrorHandler defHandler = XSetErrorHandler(X11ErrorHandling);
1899
1900        if ( currentHandler == defHandler )
1901        {
1902            // No application error handler, use ours.
1903            // OSG_INFO<<"Set osgViewer X11 error handler"<<std::endl;
1904            _errorHandlerSet = 1;
1905        }
1906        else
1907        {
1908            // Application error handler exists, leave it set.
1909            // OSG_INFO<<"Existing application X11 error handler set"<<std::endl;
1910            _errorHandlerSet = 0;
1911            XSetErrorHandler(currentHandler);
1912        }
1913
1914#if 0
1915        if (XInitThreads() == 0)
1916        {
1917            OSG_NOTICE << "Error: XInitThreads() failed. Aborting." << std::endl;
1918            exit(1);
1919        }
1920        else
1921        {
1922            OSG_INFO << "X11WindowingSystemInterface, xInitThreads() multi-threaded X support initialized.\n";
1923        }
1924#endif
1925
1926    }
1927
1928
1929
1930    ~X11WindowingSystemInterface()
1931    {
1932        if (osg::Referenced::getDeleteHandler())
1933        {
1934            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
1935            osg::Referenced::getDeleteHandler()->flushAll();
1936        }
1937
1938        //OSG_NOTICE<<"~X11WindowingSystemInterface()"<<std::endl;
1939
1940        // Unset our X11 error handler, providing the application has not replaced it.
1941
1942        if ( _errorHandlerSet )
1943        {
1944            X11ErrorHandler currentHandler = XSetErrorHandler(NULL);
1945            if ( currentHandler == X11ErrorHandling )
1946            {
1947                // OSG_INFO<<"osgViewer X11 error handler removed"<<std::endl;
1948            }
1949            else
1950            {
1951                // Not our error handler, leave it set.
1952                // OSG_INFO<<"Application X11 error handler left"<<std::endl;
1953                XSetErrorHandler(currentHandler);
1954            }
1955        }
1956    }
1957
1958    virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si)
1959    {
1960        Display* display = XOpenDisplay(si.displayName().c_str());
1961        if(display)
1962        {
1963            unsigned int numScreens = ScreenCount(display);
1964            XCloseDisplay(display);
1965
1966            return numScreens;
1967        }
1968        else
1969        {
1970            OSG_NOTICE << "A Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\""<<std::endl;
1971            return 0;
1972        }
1973    }
1974
1975    bool supportsRandr(Display* display) const
1976    {
1977#ifdef OSGVIEWER_USE_XRANDR
1978        int event_basep;
1979        int error_basep;
1980        bool supports_randr = XRRQueryExtension( display, &event_basep, &error_basep );
1981        if( supports_randr )
1982        {
1983            int major, minor;
1984            XRRQueryVersion( display, &major, &minor );
1985            return ( major > 1 || ( major == 1 && minor >= 2 ) );
1986        }
1987#endif
1988        return false;
1989    }
1990
1991    virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
1992    {
1993        Display* display = XOpenDisplay(si.displayName().c_str());
1994        if(display)
1995        {
1996            resolution.width = DisplayWidth(display, si.screenNum);
1997            resolution.height = DisplayHeight(display, si.screenNum);
1998            resolution.colorDepth = DefaultDepth(display, si.screenNum);
1999
2000            resolution.refreshRate = 0;            // Missing call. Need a X11 expert.
2001
2002
2003#ifdef OSGVIEWER_USE_XRANDR
2004           if (supportsRandr(display))
2005           {
2006
2007               XRRScreenConfiguration* screenConfig = XRRGetScreenInfo ( display, RootWindow(display, si.screenNum) );
2008
2009               resolution.refreshRate = XRRConfigCurrentRate ( screenConfig );
2010
2011               XRRFreeScreenConfigInfo( screenConfig );
2012           }
2013#endif
2014
2015
2016            XCloseDisplay(display);
2017        }
2018        else
2019        {
2020            OSG_NOTICE << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
2021            resolution.width = 0;
2022            resolution.height = 0;
2023            resolution.colorDepth = 0;
2024            resolution.refreshRate = 0;
2025        }
2026    }
2027
2028    virtual bool setScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
2029    {
2030#ifdef OSGVIEWER_USE_XRANDR
2031        _setScreen(si, resolution.width, resolution.height, resolution.colorDepth, resolution.refreshRate);
2032#else
2033        OSG_NOTICE << "You must build osgViewer with Xrandr 1.2 or higher for setScreenSettings support!" << std::endl;
2034#endif
2035        return false;
2036    }
2037
2038    virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList)
2039    {
2040        resolutionList.clear();
2041
2042        Display* display = XOpenDisplay(si.displayName().c_str());
2043        if(display)
2044        {
2045#ifdef OSGVIEWER_USE_XRANDR
2046            int defaultDepth = DefaultDepth(display, si.screenNum);
2047
2048            if (supportsRandr(display))
2049            {
2050                int nsizes = 0;
2051                XRRScreenSize * screenSizes = XRRSizes(display, si.screenNum, &nsizes);
2052                if (screenSizes && nsizes>0)
2053                {
2054                    for(int i=0; i<nsizes; ++i)
2055                    {
2056                        OSG_INFO<<"Screen size "<<screenSizes[i].width<<" "<<screenSizes[i].height<<" "<<screenSizes[i].mwidth<<" "<<screenSizes[i].mheight<<std::endl;
2057
2058                        int nrates;
2059                        short * rates = XRRRates (display, si.screenNum, i, &nrates);
2060                        if (rates && nrates>0)
2061                        {
2062                            for(int j=0; j<nrates; ++j)
2063                            {
2064                                OSG_INFO<<"   rates "<<rates[j]<<std::endl;
2065
2066                                resolutionList.push_back(osg::GraphicsContext::ScreenSettings(
2067                                    screenSizes[i].width,
2068                                    screenSizes[i].height,
2069                                    double(rates[j]),
2070                                    defaultDepth));
2071                            }
2072                        }
2073                        else
2074                        {
2075                            resolutionList.push_back(osg::GraphicsContext::ScreenSettings(
2076                                screenSizes[i].width,
2077                                screenSizes[i].height,
2078                                0.0,
2079                                defaultDepth));
2080                        }
2081
2082                    }
2083                }
2084            }
2085#endif
2086            XCloseDisplay(display);
2087        }
2088
2089        if (resolutionList.empty())
2090        {
2091            OSG_NOTICE << "X11WindowingSystemInterface::enumerateScreenSettings() not supported." << std::endl;
2092        }
2093    }
2094
2095    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
2096    {
2097        if (traits->pbuffer)
2098        {
2099#if 1
2100            osg::ref_ptr<osgViewer::PixelBufferX11> pbuffer = new PixelBufferX11(traits);
2101            if (pbuffer->valid()) return pbuffer.release();
2102            else return 0;
2103#else
2104            osg::ref_ptr<osgViewer::GraphicsWindowX11> window = new GraphicsWindowX11(traits);
2105            if (window->valid()) return window.release();
2106            else return 0;
2107#endif
2108        }
2109        else
2110        {
2111            osg::ref_ptr<osgViewer::GraphicsWindowX11> window = new GraphicsWindowX11(traits);
2112            if (window->valid()) return window.release();
2113            else return 0;
2114        }
2115    }
2116
2117};
2118
2119struct RegisterWindowingSystemInterfaceProxy
2120{
2121    RegisterWindowingSystemInterfaceProxy()
2122    {
2123        OSG_INFO<<"RegisterWindowingSystemInterfaceProxy()"<<std::endl;
2124        osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface);
2125    }
2126
2127    ~RegisterWindowingSystemInterfaceProxy()
2128    {
2129        OSG_INFO<<"~RegisterWindowingSystemInterfaceProxy()"<<std::endl;
2130
2131        if (osg::Referenced::getDeleteHandler())
2132        {
2133            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2134            osg::Referenced::getDeleteHandler()->flushAll();
2135        }
2136
2137        osg::GraphicsContext::setWindowingSystemInterface(0);
2138
2139    }
2140};
2141
2142RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2143
2144// declare C entry point for static compilation.
2145extern "C" void graphicswindow_X11(void)
2146{
2147    osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface);
2148}
2149
2150
2151void GraphicsWindowX11::raiseWindow()
2152{
2153    Display* display = getDisplayToUse();
2154    XWindowAttributes winAttrib;
2155
2156    Window root_return, parent_return, *children;
2157    unsigned int nchildren, i=0;
2158    XTextProperty windowName;
2159    bool xraise = false;
2160
2161
2162    XQueryTree(display, _parent, &root_return, &parent_return, &children, &nchildren);
2163    while (!xraise &&  i<nchildren)
2164    {
2165    XGetWMName(display,children[i++],&windowName);
2166        if ((windowName.nitems != 0) && (strcmp(_traits->windowName.c_str(),(const char *)windowName.value) == 0)) xraise = true;
2167    }
2168    if (xraise) XRaiseWindow(display,_window);
2169    else
2170    {
2171    XGetWindowAttributes(display, _window, &winAttrib);
2172    XReparentWindow(display, _window, _parent, winAttrib.x, winAttrib.y);
2173    }
2174    XFree(children);
2175
2176    XFlush(display);
2177    XSync(display,0);
2178}
Note: See TracBrowser for help on using the browser.