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

Revision 13429, 73.2 kB (checked in by robert, 4 days ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

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