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

Revision 12125, 69.6 kB (checked in by robert, 4 years ago)

From Alexander Sinditskiy, "reason of this changes described in http://forum.openscenegraph.org/viewtopic.php?t=7596

and another problem is:
example osgkeyboard is not work (keys not highlight) if user have 2 keyboard layout native and english and current user layout is native

I try to explain my changes

we need something that is identify key without modifier keys and layout -> this is UnmodifedKey?

I think osg must have its own UnmodifiedKeys? table. Code must be run same on different platforms. This can de guaranteed by UnmodifiedKeys? table.

Mikhail Izmestev helped me. He implemented VirtualKey? changes in GraphicsWindowX11"

  • 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// Fix toggling of fullscreen to window mode as it does enable window decoration with recent linux window managers
22
23#include <osgViewer/api/X11/GraphicsWindowX11>
24#include <osgViewer/api/X11/PixelBufferX11>
25
26#include <osg/DeleteHandler>
27
28#include <X11/Xlib.h>
29#include <X11/Xutil.h>
30
31#include <X11/Xmd.h>
32#include <X11/keysym.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->sampleBuffers) { 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        //  GLX_SAMPLE_BUFFERS
353        //  GLX_SAMPLES
354       
355        attributes.push_back(None);
356       
357        _visualInfo = glXChooseVisual( _display, _traits->screenNum, &(attributes.front()) );
358    #endif
359    }
360
361    return _visualInfo != 0;
362}
363#define MWM_HINTS_FUNCTIONS   (1L << 0)
364#define MWM_HINTS_DECORATIONS (1L << 1)
365#define MWM_HINTS_INPUT_MODE  (1L << 2)
366#define MWM_HINTS_STATUS      (1L << 3)
367
368#define MWM_DECOR_ALL         (1L<<0)
369#define MWM_DECOR_BORDER      (1L<<1)
370#define MWM_DECOR_RESIZEH     (1L<<2)
371#define MWM_DECOR_TITLE       (1L<<3)
372#define MWM_DECOR_MENU        (1L<<4)
373#define MWM_DECOR_MINIMIZE    (1L<<5)
374#define MWM_DECOR_MAXIMIZE    (1L<<6)
375
376#define MWM_FUNC_ALL          (1L<<0)
377#define MWM_FUNC_RESIZE       (1L<<1)
378#define MWM_FUNC_MOVE         (1L<<2)
379#define MWM_FUNC_MINIMIZE     (1L<<3)
380#define MWM_FUNC_MAXIMIZE     (1L<<4)
381#define MWM_FUNC_CLOSE        (1L<<5)
382
383
384bool GraphicsWindowX11::checkAndSendEventFullScreenIfNeeded(Display* display, int x, int y, int width, int height, bool windowDecoration)
385{
386  osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface();
387  if (wsi == NULL) {
388    OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl;
389    return false;
390  }
391
392  unsigned int    screenWidth;
393  unsigned int    screenHeight;
394
395  wsi->getScreenResolution(*_traits, screenWidth, screenHeight);
396  bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !windowDecoration;
397
398  Atom netWMStateAtom = XInternAtom(display, "_NET_WM_STATE", True);
399  Atom netWMStateFullscreenAtom = XInternAtom(display,
400                                              "_NET_WM_STATE_FULLSCREEN", True);
401
402  if (netWMStateAtom != None && netWMStateFullscreenAtom != None) {
403    XEvent xev;
404    xev.xclient.type = ClientMessage;
405    xev.xclient.serial = 0;
406    xev.xclient.send_event = True;
407    xev.xclient.window = _window;
408    xev.xclient.message_type = netWMStateAtom;
409    xev.xclient.format = 32;
410    xev.xclient.data.l[0] = isFullScreen ? 1 : 0;
411    xev.xclient.data.l[1] = netWMStateFullscreenAtom;
412    xev.xclient.data.l[2] = 0;
413
414    XSendEvent(display, RootWindow(display, DefaultScreen(display)),
415               False,  SubstructureRedirectMask | SubstructureNotifyMask, &xev);
416    return true;
417  }
418  return false;
419}
420
421bool GraphicsWindowX11::setWindowDecorationImplementation(bool flag)
422{
423    Display* display = getDisplayToUse();
424
425    XMapWindow(display, _window );
426
427    checkAndSendEventFullScreenIfNeeded(display, _traits->x, _traits->y, _traits->width, _traits->height, flag);
428    struct
429    {
430        unsigned long flags;
431        unsigned long functions;
432        unsigned long decorations;
433        long          inputMode;
434        unsigned long status;
435    } wmHints;
436
437    Atom atom;
438    bool result = false;
439    if( (atom = XInternAtom( display, "_MOTIF_WM_HINTS", 0 )) != None )
440    {
441       
442        wmHints.flags = 0;
443        wmHints.functions = MWM_FUNC_ALL;
444        wmHints.decorations = MWM_DECOR_ALL;
445        wmHints.inputMode = 0;
446        wmHints.status = 0;       
447       
448        if (!flag)
449        {
450            wmHints.flags = MWM_HINTS_DECORATIONS;
451            wmHints.decorations = 0;
452        }
453        else
454        {
455            wmHints.flags |= MWM_HINTS_FUNCTIONS;
456            if (_traits.valid() && !_traits->supportsResize) wmHints.functions |= MWM_FUNC_RESIZE;
457        }
458        XChangeProperty( display, _window, atom, atom, 32, PropModeReplace, (unsigned char *)&wmHints,  5 );
459        result = true;
460    }
461    else
462    {
463        OSG_NOTICE<<"Error: GraphicsWindowX11::setBorder(" << flag << ") - couldn't change decorations." << std::endl;
464        result = false;
465    }
466
467    XFlush(display);
468    XSync(display,0);
469    // add usleep here to give window manager a chance to handle the request, if
470    // we don't add this sleep then any X11 calls right afterwards can produce
471    // X11 errors.
472    usleep(100000);
473    return result;
474}
475
476bool GraphicsWindowX11::setWindowRectangleImplementation(int x, int y, int width, int height)
477{
478    if (!_initialized) return false;
479   
480    Display* display = getDisplayToUse();
481   
482    XMoveResizeWindow(display, _window, x, y, width, height);
483   
484    XFlush(display);
485    XSync(display, 0);
486
487    checkAndSendEventFullScreenIfNeeded(display, x, y, width, height, _traits->windowDecoration);
488
489    // add usleep here to give window manager a chance to handle the request, if
490    // we don't add this sleep then any X11 calls right afterwards can produce
491    // X11 errors.
492    usleep(100000);
493
494   
495    return true;
496}
497
498void GraphicsWindowX11::setWindowName(const std::string& name)
499{
500    if( _window == 0) return;
501
502    //    char *slist[] = { name.c_str(), 0L };
503    //    XTextProperty xtp;
504
505    //    XStringListToTextProperty( slist, 1, &xtp );
506
507    Display* display = getDisplayToUse();
508    if( !display ) return;
509
510    //    XSetWMName( display, _window, &xtp );
511    XStoreName( display, _window, name.c_str() );
512    XSetIconName( display, _window, name.c_str() );
513
514    XFlush(display);
515    XSync(display,0);
516
517    _traits->windowName = name;
518}
519
520void GraphicsWindowX11::setCursor(MouseCursor mouseCursor)
521{
522    Cursor newCursor = getOrCreateCursor(mouseCursor);
523    if (newCursor == _currentCursor) return;
524
525    _currentCursor = newCursor;
526    if (!_window) return;
527    Display* display = getDisplayToUse();
528    if (!display) return;
529    XDefineCursor( display, _window, _currentCursor );
530    XFlush(display);
531    XSync(display, 0);
532
533    _traits->useCursor = (_currentCursor != getOrCreateCursor(NoCursor));
534}
535
536Cursor GraphicsWindowX11::getOrCreateCursor(MouseCursor mouseCursor)
537{
538    std::map<MouseCursor,Cursor>::iterator i = _mouseCursorMap.find(mouseCursor);
539    if (i != _mouseCursorMap.end()) return i->second;
540
541    Display* display = getDisplayToUse();
542    if (!display) return None;
543
544    switch (mouseCursor) {
545    case NoCursor:
546    {
547        // create an empty mouse cursor, note that it is safe to destroy the Pixmap just past cursor creation
548        // since the resource in the x server is reference counted.
549        char buff[2] = {0,0};
550        XColor ncol = {0,0,0,0,DoRed|DoGreen|DoBlue,0};
551        Pixmap pixmap = XCreateBitmapFromData( display, _parent, buff, 1, 1);
552        _mouseCursorMap[mouseCursor] = XCreatePixmapCursor( display, pixmap, pixmap, &ncol, &ncol, 0, 0 );
553        XFreePixmap(display, pixmap);
554        // Important to have the pixmap and the buffer still available when the request is sent to the server ...
555        XFlush(display);
556        XSync(display, 0);
557        break;
558    }
559    case RightArrowCursor:
560        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_ptr );
561        break;
562    case LeftArrowCursor:
563        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_arrow );
564        break;
565    case InfoCursor:
566        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 );
567        break;
568    case DestroyCursor:
569        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_pirate );
570        break;
571    case HelpCursor:
572        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_question_arrow );
573        break;
574    case CycleCursor:
575        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_exchange );
576        break;
577    case SprayCursor:
578        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_spraycan );
579        break;
580    case WaitCursor:
581        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_watch );
582        break;
583    case TextCursor:
584        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_xterm );
585        break;
586    case CrosshairCursor:
587        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_crosshair );
588        break;
589    case UpDownCursor:
590        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_v_double_arrow );
591        break;
592    case LeftRightCursor:
593        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_h_double_arrow );
594        break;
595    case TopSideCursor:
596        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_side );
597        break;
598    case BottomSideCursor:
599        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_side );
600        break;
601    case LeftSideCursor:
602        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_side );
603        break;
604    case RightSideCursor:
605        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_right_side );
606        break;
607    case TopLeftCorner:
608        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_corner );
609        break;
610    case TopRightCorner:
611        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_right_corner );
612        break;
613    case BottomRightCorner:
614        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_right_corner );
615        break;
616    case BottomLeftCorner:
617        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_left_corner );
618        break;
619    case HandCursor:
620        _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 );
621        break;
622
623    case InheritCursor:
624    default:
625        _mouseCursorMap[mouseCursor] = None;
626        break;
627    };
628    return _mouseCursorMap[mouseCursor];
629}
630
631void GraphicsWindowX11::init()
632{
633    if (_initialized) return;
634
635    if (!_traits)
636    {
637        _valid = false;
638        return;
639    }
640
641    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
642
643    WindowData* inheritedWindowData = dynamic_cast<WindowData*>(_traits->inheritedWindowData.get());
644    Window windowHandle = inheritedWindowData ? inheritedWindowData->_window : 0;
645
646    _ownsWindow = windowHandle == 0;
647
648    _display = XOpenDisplay(_traits->displayName().c_str());
649
650    if (!_display)
651    {
652        OSG_NOTICE<<"Error: Unable to open display \"" << XDisplayName(_traits->displayName().c_str()) << "\"."<<std::endl;
653        _valid = false;
654        return;
655    }
656
657    #ifdef OSG_USE_EGL
658
659        _eglDisplay = eglGetDisplay((EGLNativeDisplayType)_display);
660
661        EGLint eglMajorVersion, eglMinorVersion;
662        if (!eglInitialize(_eglDisplay, &eglMajorVersion, &eglMinorVersion))
663        {
664            OSG_NOTICE<<"GraphicsWindowX11::init() - eglInitialize() failed."<<std::endl;
665
666            XCloseDisplay( _display );
667            _display = 0;
668            _valid = false;
669            return;
670        }
671
672        OSG_NOTICE<<"GraphicsWindowX11::init() - eglInitialize() succeded eglMajorVersion="<<eglMajorVersion<<" iMinorVersion="<<eglMinorVersion<<std::endl;
673
674   #else
675        // Query for GLX extension
676        int errorBase, eventBase;
677        if( glXQueryExtension( _display, &errorBase, &eventBase)  == False )
678        {
679            OSG_NOTICE<<"Error: " << XDisplayName(_traits->displayName().c_str()) <<" has no GLX extension." << std::endl;
680
681            XCloseDisplay( _display );
682            _display = 0;
683            _valid = false;
684            return;
685        }
686    #endif
687   
688    // OSG_NOTICE<<"GLX extension, errorBase="<<errorBase<<" eventBase="<<eventBase<<std::endl;
689
690    if (!createVisualInfo())
691    {
692        _traits->red /= 2;
693        _traits->green /= 2;
694        _traits->blue /= 2;
695        _traits->alpha /= 2;
696        _traits->depth /= 2;
697       
698        OSG_INFO<<"Relaxing traits"<<std::endl;
699
700        if (!createVisualInfo())
701        {
702            OSG_NOTICE<<"Error: Not able to create requested visual." << std::endl;
703            XCloseDisplay( _display );
704            _display = 0;
705            _valid = false;
706            return;
707        }   
708    }
709
710    // get any shared GLX contexts
711    GraphicsHandleX11* graphicsHandleX11 = dynamic_cast<GraphicsHandleX11*>(_traits->sharedContext);
712    Context sharedContext = graphicsHandleX11 ? graphicsHandleX11->getContext() : 0;
713
714    #ifdef OSG_USE_EGL
715
716        _valid = _ownsWindow ? createWindow() : setWindow(windowHandle);
717
718        if (!_valid)
719        {
720            XCloseDisplay( _display );
721            _display = 0;
722            return;
723        }
724       
725        OSG_NOTICE<<"GraphicsWindowX11::init() - window created ="<<_valid<<std::endl;
726
727        EGLConfig eglConfig = 0;
728       
729        #if defined(OSG_GLES2_AVAILABLE)
730            #define OSG_EGL_OPENGL_TARGET_BIT EGL_OPENGL_ES2_BIT
731        #else
732            #define OSG_EGL_OPENGL_TARGET_BIT EGL_OPENGL_ES_BIT
733        #endif
734       
735        EGLint configAttribs[] = {
736                EGL_SAMPLE_BUFFERS, 0,
737                EGL_SAMPLES, 0,
738                EGL_RED_SIZE, 1,
739                EGL_GREEN_SIZE, 1,
740                EGL_BLUE_SIZE, 1,
741                EGL_DEPTH_SIZE, 1,
742                EGL_RENDERABLE_TYPE, OSG_EGL_OPENGL_TARGET_BIT,
743                EGL_NONE
744        };
745
746        int numConfigs;
747        if (!eglChooseConfig(_eglDisplay, configAttribs, &eglConfig, 1, &numConfigs) || (numConfigs != 1))
748        {
749            OSG_NOTICE<<"GraphicsWindowX11::init() - eglChooseConfig() failed."<<std::endl;
750            XCloseDisplay( _display );
751            _valid = false;
752            _display = 0;
753            return;
754        }
755
756        eglBindAPI(EGL_OPENGL_ES_API);
757
758        _eglSurface = eglCreateWindowSurface(_eglDisplay, eglConfig, (EGLNativeWindowType)_window, NULL);
759        if (_eglSurface == EGL_NO_SURFACE)
760        {
761            OSG_NOTICE<<"GraphicsWindowX11::init() - eglCreateWindowSurface(..) failed."<<std::endl;
762            XCloseDisplay( _display );
763            _valid = false;
764            _display = 0;
765            return;
766        }
767
768        #if defined(OSG_GLES1_AVAILABLE)
769            EGLint* contextAttribs = 0;
770        #else
771            EGLint contextAttribs[] = {
772                 EGL_CONTEXT_CLIENT_VERSION,
773                2,
774                EGL_NONE
775            };
776        #endif
777
778        _context = eglCreateContext(_eglDisplay, eglConfig, sharedContext, contextAttribs);
779        if (_context == EGL_NO_CONTEXT)
780        {
781            OSG_NOTICE<<"GraphicsWindowX11::init() - eglCreateContext(..) failed."<<std::endl;
782            XCloseDisplay( _display );
783            _valid = false;
784            _display = 0;
785            return;
786        }
787
788        _initialized = true;
789           
790        checkEGLError("after eglCreateContext()");
791
792    #else
793       
794        _context = glXCreateContext( _display, _visualInfo, sharedContext, True );
795   
796        if (!_context)
797        {
798            OSG_NOTICE<<"Error: Unable to create OpenGL graphics context."<<std::endl;
799            XCloseDisplay( _display );
800            _display = 0;
801            _valid = false;
802            return;
803        }
804
805        _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
806        _valid = _initialized;
807
808    #endif
809   
810    if (_valid == false)
811    {
812        XCloseDisplay( _display );
813        _display = 0;
814    }
815
816
817
818}
819
820bool GraphicsWindowX11::createWindow()
821{
822    unsigned int screen = _traits->screenNum;
823
824    _eventDisplay = XOpenDisplay(_traits->displayName().c_str());
825
826    _parent = RootWindow( _display, screen );
827
828    XWindowAttributes watt;
829    XGetWindowAttributes( _display, _parent, &watt );
830    // unsigned int parentWindowHeight = watt.height;
831
832    XSetWindowAttributes swatt;
833    swatt.colormap = XCreateColormap( _display, _parent, _visualInfo->visual, AllocNone);
834    //swatt.colormap = DefaultColormap( _dpy, 10 );
835    swatt.background_pixel = 0;
836    swatt.border_pixel = 0;
837    swatt.event_mask =  0;
838    unsigned long mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap;
839
840    if (_traits->overrideRedirect)
841    {
842        swatt.override_redirect = true;
843        mask |= CWOverrideRedirect;
844       
845        OSG_INFO<<"Setting override redirect"<<std::endl;
846    }
847
848    _window = XCreateWindow( _display, _parent,
849                             _traits->x,
850                             _traits->y,
851                             _traits->width, _traits->height, 0,
852                             _visualInfo->depth, InputOutput,
853                             _visualInfo->visual, mask, &swatt );                         
854
855    if (!_window)
856    {
857        OSG_NOTICE<<"Error: Unable to create Window."<<std::endl;
858        _context = 0;
859        return false;
860    }
861
862
863    // Give window a class so that user preferences can be saved in the resource database.
864    XClassHint clH;
865    clH.res_name = (char *)"OSG";
866    clH.res_class = (char *)"osgViewer";
867    XSetClassHint( _display, _window, &clH);
868
869    // This positions the window at _windowX, _windowY
870    XSizeHints sh;
871    sh.flags = 0;
872    sh.flags |= USSize;
873    sh.flags &= 0x7;
874    sh.flags |= USPosition;
875    sh.flags &= 0xB;
876    sh.x = _traits->x;
877    sh.y = _traits->y;
878    sh.width  = _traits->width;
879    sh.height = _traits->height;
880    XSetStandardProperties( _display, _window, _traits->windowName.c_str(), _traits->windowName.c_str(), None, 0, 0, &sh);
881
882    setWindowDecoration(_traits->windowDecoration);
883
884    useCursor(_traits->useCursor);
885
886    _deleteWindow = XInternAtom (_display, "WM_DELETE_WINDOW", False);
887    XSetWMProtocols(_display, _window, &_deleteWindow, 1);
888
889
890    XFlush( _display );
891    XSync( _display, 0 );
892
893    // now update the window dimensions to account for any size changes made by the window manager,
894    XGetWindowAttributes( _display, _window, &watt );
895   
896    if (_traits->x != watt.x || _traits->y != watt.y
897        ||_traits->width != watt.width || _traits->height != watt.height)
898    {
899        resized( watt.x, watt.y, watt.width, watt.height );
900    }
901       
902    //OSG_NOTICE<<"After sync apply.x = "<<watt.x<<" watt.y="<<watt.y<<" width="<<watt.width<<" height="<<watt.height<<std::endl;
903
904
905    XSelectInput( _eventDisplay, _window, ExposureMask | StructureNotifyMask |
906                                     KeyPressMask | KeyReleaseMask |
907                                     PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
908                                     KeymapStateMask | FocusChangeMask | EnterWindowMask );
909
910    XFlush( _eventDisplay );
911    XSync( _eventDisplay, 0 );
912    rescanModifierMapping();
913
914    return true;
915}
916
917bool GraphicsWindowX11::setWindow(Window window)
918{
919    if (_initialized)
920    {
921        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Window already created; it cannot be changed";
922        return false;
923    }
924   
925    if (window==0)
926    {
927        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Invalid window handle passed ";
928        return false;
929    }
930   
931    _window = window;
932    if (_window==0)
933    {
934        OSG_NOTICE << "GraphicsWindowX11::setWindow() - Unable to retrieve native window handle";
935        return false;
936    }
937
938    XWindowAttributes watt;
939    XGetWindowAttributes( _display, _window, &watt );
940    _traits->x = watt.x;
941    _traits->y = watt.y;
942    _traits->width = watt.width;
943    _traits->height = watt.height;
944
945    _parent = DefaultRootWindow( _display );
946
947    //_traits->supportsResize = false;
948    _traits->windowDecoration = false;
949
950    if (_traits->windowName.size()) setWindowName(_traits->windowName);
951
952    _eventDisplay = XOpenDisplay(_traits->displayName().c_str());
953
954    XFlush( _eventDisplay );
955    XSync( _eventDisplay, 0 );
956
957    return true;
958}
959
960bool GraphicsWindowX11::realizeImplementation()
961{
962    if (_realized)
963    {
964        OSG_NOTICE<<"GraphicsWindowX11::realizeImplementation() Already realized"<<std::endl;
965        return true;
966    }
967
968    if (!_initialized) init();
969   
970    if (!_initialized) return false;
971   
972    XMapWindow( _display, _window );
973   
974//    Window temp = _window;
975//    XSetWMColormapWindows( _display, _window, &temp, 1);
976   
977    _realized = true;
978
979    return true;
980}
981
982bool GraphicsWindowX11::makeCurrentImplementation()
983{
984    if (!_realized)
985    {
986        OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
987        return false;
988    }
989
990    #ifdef OSG_USE_EGL
991        bool result = eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _context)==EGL_TRUE;
992        checkEGLError("after eglMakeCurrent()");
993        return result;
994    #else
995        return glXMakeCurrent( _display, _window, _context )==True;
996    #endif
997}
998
999bool GraphicsWindowX11::releaseContextImplementation()
1000{
1001    if (!_realized)
1002    {
1003        OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do release context."<<std::endl;
1004        return false;
1005    }
1006
1007    #ifdef OSG_USE_EGL
1008        bool result = eglMakeCurrent( _eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )==EGL_TRUE;
1009        checkEGLError("after eglMakeCurrent() release");
1010        return result;
1011    #else
1012        return glXMakeCurrent( _display, None, NULL )==True;
1013    #endif
1014}
1015
1016
1017void GraphicsWindowX11::closeImplementation()
1018{
1019    // OSG_NOTICE<<"Closing GraphicsWindowX11"<<std::endl;
1020
1021    if (_eventDisplay)
1022    {
1023        XCloseDisplay( _eventDisplay );
1024        _eventDisplay = 0;
1025    }
1026
1027    if (_display)
1028    {
1029        if (_context)
1030        {
1031        #ifdef OSG_USE_EGL
1032            eglDestroyContext( _eglDisplay, _context );
1033        #else
1034            glXDestroyContext( _display, _context );
1035        #endif
1036        }
1037   
1038        if (_window && _ownsWindow)
1039        {
1040            XDestroyWindow(_display, _window);
1041        }
1042
1043        XFlush( _display );
1044        XSync( _display,0 );
1045    }
1046   
1047    _window = 0;
1048    _parent = 0;
1049    _context = 0;
1050
1051    if (_visualInfo)
1052    {
1053        #ifdef OSG_USE_EGL
1054            delete _visualInfo;
1055        #else       
1056            XFree(_visualInfo);
1057        #endif
1058        _visualInfo = 0;
1059    }
1060
1061
1062    if (_display)
1063    {
1064        XCloseDisplay( _display );
1065        _display = 0;
1066    }
1067
1068    _initialized = false;
1069    _realized = false;
1070    _valid = false;
1071}
1072
1073void GraphicsWindowX11::swapBuffersImplementation()
1074{
1075    if (!_realized) return;
1076
1077    // OSG_NOTICE<<"swapBuffersImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
1078
1079    #ifdef OSG_USE_EGL
1080        eglSwapBuffers( _eglDisplay, _eglSurface );
1081        checkEGLError("after eglSwapBuffers()");
1082    #else
1083#if 0
1084        if (_traits.valid() && _traits->vsync) {
1085
1086            unsigned int counter;
1087            glXGetVideoSyncSGI(&counter);
1088            glXWaitVideoSyncSGI(1, 0, &counter);
1089        }
1090#endif
1091        glXSwapBuffers( _display, _window );
1092    #endif
1093
1094
1095    while( XPending(_display) )
1096    {
1097        XEvent ev;
1098        XNextEvent( _display, &ev );
1099
1100        switch( ev.type )
1101        {
1102            case ClientMessage:
1103            {
1104                if (static_cast<Atom>(ev.xclient.data.l[0]) == _deleteWindow)
1105                {
1106                    OSG_INFO<<"DeleteWindow event received"<<std::endl;
1107                    getEventQueue()->closeWindow();
1108                }
1109            }
1110        }
1111    }
1112}
1113
1114void GraphicsWindowX11::checkEvents()
1115{
1116    if (!_realized) return;
1117
1118    Display* display = _eventDisplay;
1119
1120    double baseTime = _timeOfLastCheckEvents;
1121    double eventTime = baseTime;
1122    double resizeTime = eventTime;
1123    _timeOfLastCheckEvents = getEventQueue()->getTime();
1124   
1125    // OSG_NOTICE<<"GraphicsWindowX11::checkEvents() : getEventQueue()->getCurrentEventState()->getGraphicsContext()="<<getEventQueue()->getCurrentEventState()->getGraphicsContext()<<std::endl;
1126
1127    int windowX = _traits->x;
1128    int windowY = _traits->y;
1129    int windowWidth = _traits->width;
1130    int windowHeight = _traits->height;
1131
1132    bool destroyWindowRequested = false;
1133   
1134    Time firstEventTime = 0;
1135     
1136    // OSG_NOTICE<<"Check events"<<std::endl;
1137    while( XPending(display) )
1138    {
1139        XEvent ev;
1140        XNextEvent( display, &ev );
1141
1142        switch( ev.type )
1143        {
1144            case ClientMessage:
1145            {
1146                OSG_NOTICE<<"ClientMessage event received"<<std::endl;
1147                if (static_cast<Atom>(ev.xclient.data.l[0]) == _deleteWindow)
1148                {
1149                    OSG_NOTICE<<"DeleteWindow event received"<<std::endl;
1150                    // FIXME only do if _ownsWindow ?
1151                    destroyWindowRequested = true;
1152                    getEventQueue()->closeWindow(eventTime);
1153                }
1154            }
1155            case Expose :
1156                OSG_INFO<<"Expose x="<<ev.xexpose.x<<" y="<<ev.xexpose.y<<" width="<<ev.xexpose.width<<", height="<<ev.xexpose.height<<std::endl;
1157                break;
1158
1159            case GravityNotify :
1160                OSG_INFO<<"GravityNotify event received"<<std::endl;
1161                break;
1162
1163            case ReparentNotify:
1164                OSG_INFO<<"ReparentNotify event received"<<std::endl;
1165                break;
1166
1167            case DestroyNotify :
1168                OSG_NOTICE<<"DestroyNotify event received"<<std::endl;
1169                _realized =  false;
1170                _valid = false;
1171                break;
1172               
1173            case ConfigureNotify :
1174            {
1175                OSG_INFO<<"ConfigureNotify x="<<ev.xconfigure.x<<" y="<<ev.xconfigure.y<<" width="<<ev.xconfigure.width<<", height="<<ev.xconfigure.height<<std::endl;
1176
1177                if (windowX != ev.xconfigure.x ||
1178                    windowX != ev.xconfigure.y ||
1179                    windowWidth != ev.xconfigure.width ||
1180                    windowHeight != ev.xconfigure.height)
1181                {
1182                    resizeTime = eventTime;
1183
1184                    windowX = ev.xconfigure.x;
1185                    windowY = ev.xconfigure.y;
1186                    windowWidth = ev.xconfigure.width;
1187                    windowHeight = ev.xconfigure.height;
1188                }
1189
1190                break;
1191            }
1192           
1193            case MapNotify :
1194            {
1195                OSG_INFO<<"MapNotify"<<std::endl;
1196                XWindowAttributes watt;
1197                do
1198                    XGetWindowAttributes(display, _window, &watt );
1199                while( watt.map_state != IsViewable );
1200               
1201                OSG_INFO<<"MapNotify x="<<watt.x<<" y="<<watt.y<<" width="<<watt.width<<", height="<<watt.height<<std::endl;
1202
1203                if (windowWidth != watt.width || windowHeight != watt.height)
1204                {
1205                    resizeTime = eventTime;
1206
1207                    windowWidth = watt.width;
1208                    windowHeight = watt.height;
1209                }
1210
1211                break;
1212            }
1213
1214            case FocusIn :
1215                OSG_INFO<<"FocusIn event received"<<std::endl;
1216                flushKeyEvents();
1217                break;
1218
1219            case UnmapNotify :
1220            case FocusOut :
1221            {
1222                OSG_INFO<<"FocusOut/UnmapNotify event received"<<std::endl;
1223                if (ev.type == FocusOut && ev.xfocus.mode != NotifyNormal) break;
1224
1225                char modMap[32];
1226                getModifierMap(modMap);
1227
1228                // release normal (non-modifier) keys
1229                for (unsigned int key = 8; key < 256; key++)
1230                {
1231                    bool isModifier = keyMapGetKey(modMap, key);
1232                    if (!isModifier) forceKey(key, eventTime, false);
1233                }
1234
1235                // release modifier keys
1236                for (unsigned int key = 8; key < 256; key++)
1237                {
1238                    bool isModifier = keyMapGetKey(modMap, key);
1239                    if (isModifier) forceKey(key, eventTime, false);
1240                }
1241                break;
1242            }
1243
1244            case EnterNotify :
1245                OSG_INFO<<"EnterNotify event received"<<std::endl;
1246                _modifierState = ev.xcrossing.state;
1247                syncLocks();
1248                break;
1249
1250            case KeymapNotify :
1251            {
1252                OSG_INFO<<"KeymapNotify event received"<<std::endl;
1253
1254                // KeymapNotify is guaranteed to directly follow either a FocusIn or
1255                // an EnterNotify event. We are only interested in the FocusIn case.
1256                if (_lastEventType != FocusIn) break;
1257
1258                char modMap[32];
1259                getModifierMap(modMap);
1260                syncLocks();
1261
1262                char keyMap[32];
1263                XQueryKeymap(_eventDisplay, keyMap);
1264
1265                // release normal (non-modifier) keys
1266                for (unsigned int key = 8; key < 256; key++)
1267                {
1268                    bool isModifier = keyMapGetKey(modMap, key);
1269                    if (isModifier) continue;
1270                    bool isPressed = keyMapGetKey(keyMap, key);
1271                    if (!isPressed) forceKey(key, eventTime, false);
1272                }
1273
1274                // press/release modifier keys
1275                for (unsigned int key = 8; key < 256; key++)
1276                {
1277                    bool isModifier = keyMapGetKey(modMap, key);
1278                    if (!isModifier) continue;
1279                    bool isPressed = keyMapGetKey(keyMap, key);
1280                    forceKey(key, eventTime, isPressed);
1281                }
1282
1283                // press normal keys
1284                for (unsigned int key = 8; key < 256; key++)
1285                {
1286                    bool isModifier = keyMapGetKey(modMap, key);
1287                    if (isModifier) continue;
1288                    bool isPressed = keyMapGetKey(keyMap, key);
1289                    if (isPressed) forceKey(key, eventTime, true);
1290                }
1291                break;
1292            }
1293
1294            case MappingNotify :
1295                OSG_INFO<<"MappingNotify event received"<<std::endl;
1296                if (ev.xmapping.request == MappingModifier) rescanModifierMapping();
1297                break;
1298
1299            case MotionNotify :
1300            {
1301                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1302                Time relativeTime = ev.xmotion.time - firstEventTime;
1303                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1304           
1305                int  wx, wy;
1306                Window win = 0L;
1307                if( ev.xmotion.same_screen )
1308                {
1309                    wx = ev.xmotion.x;
1310                    wy = ev.xmotion.y;
1311                }
1312                else
1313                {
1314                    // the mouse in on another screen so need to compute the
1315                    // coordinates of the mouse position relative to an absolute position
1316                    // then take away the position of the original window/screen to get
1317                    // the coordinates relative to the original position.
1318                    Window root;
1319                    int rx, ry;
1320                    unsigned int buttons;
1321
1322                    int screenOrigin_x = 0;
1323                    int screenOrigin_y = 0;
1324                    int i;
1325                    for(i= 0; i < ScreenCount(display); i++ )
1326                    {
1327                        if( XQueryPointer( display, RootWindow(display, i),
1328                              &root, &win, &rx, &ry, &wx, &wy, &buttons) )
1329                        {
1330                            break;
1331                        }
1332
1333                        screenOrigin_x += DisplayWidth(display, i);
1334                    }
1335
1336                    for(i= 0; i < static_cast<int>(_traits->screenNum); i++ )
1337                    {
1338                        screenOrigin_x -= DisplayWidth(display, i);
1339                    }
1340
1341                    int dest_x_return, dest_y_return;
1342                    Window child_return;
1343                    XTranslateCoordinates(display, _window, _parent, 0, 0, &dest_x_return, &dest_y_return, &child_return);
1344
1345                    wx += (screenOrigin_x - dest_x_return);
1346                    wy += (screenOrigin_y - dest_y_return);
1347                }
1348               
1349
1350                float mx = wx;
1351                float my = wy;
1352                transformMouseXY(mx, my);
1353                getEventQueue()->mouseMotion(mx, my, eventTime);
1354
1355                // OSG_NOTICE<<"MotionNotify wx="<<wx<<" wy="<<wy<<" mx="<<mx<<" my="<<my<<std::endl;
1356
1357                break;
1358            }
1359           
1360            case ButtonPress :
1361            {
1362                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1363                Time relativeTime = ev.xmotion.time - firstEventTime;
1364                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1365
1366                if( ev.xbutton.button == Button4 )
1367                {
1368                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP, eventTime);
1369                }
1370                else if( ev.xbutton.button == Button5)
1371                {
1372                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN, eventTime);
1373                }
1374                else
1375                {
1376                    float mx = ev.xbutton.x;
1377                    float my = ev.xmotion.y;
1378                    transformMouseXY(mx, my);
1379                    getEventQueue()->mouseButtonPress(mx, my, ev.xbutton.button, eventTime);
1380                }
1381                break;
1382            }
1383           
1384            case ButtonRelease :
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                if( ev.xbutton.button == Button4 )
1391                {
1392                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP, eventTime);
1393                }
1394                else if( ev.xbutton.button == Button5)
1395                {
1396                    getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN, eventTime);
1397                }
1398                else
1399                {
1400                    float mx = ev.xbutton.x;
1401                    float my = ev.xmotion.y;
1402                    transformMouseXY(mx, my);
1403                    getEventQueue()->mouseButtonRelease(mx, my, ev.xbutton.button, eventTime);
1404                }
1405                break;
1406            }
1407           
1408            case KeyPress:
1409            {
1410                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1411                Time relativeTime = ev.xmotion.time - firstEventTime;
1412                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1413
1414                _modifierState = ev.xkey.state;
1415                keyMapSetKey(_keyMap, ev.xkey.keycode);
1416                int keySymbol = 0;
1417                int unmodifiedKeySymbol = 0;
1418                adaptKey(ev.xkey, keySymbol, unmodifiedKeySymbol);
1419
1420                getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
1421                break;
1422            }
1423           
1424            case KeyRelease:
1425            {
1426                if (firstEventTime==0) firstEventTime = ev.xmotion.time;
1427                Time relativeTime = ev.xmotion.time - firstEventTime;
1428                eventTime = baseTime + static_cast<double>(relativeTime)*0.001;
1429#if 1               
1430                // Check for following KeyPress events and see if
1431                // the pair are the result of auto-repeat. If so, drop
1432                // this one on the floor, to be consistent with
1433                // Windows and Mac ports. The idea comes from libSDL sources.
1434                XEvent nextev;
1435                if (XPending(display))
1436                {
1437                    XPeekEvent(display, &nextev);
1438                    if ((nextev.type == KeyPress)
1439                        && (nextev.xkey.keycode == ev.xkey.keycode)
1440                        && (nextev.xmotion.time - ev.xmotion.time < 2))
1441                    {
1442                        break;
1443                    }
1444                }
1445#endif
1446                _modifierState = ev.xkey.state;
1447                keyMapClearKey(_keyMap, ev.xkey.keycode);
1448                int keySymbol = 0;
1449                int unmodifiedKeySymbol = 0;
1450                adaptKey(ev.xkey, keySymbol, unmodifiedKeySymbol);
1451               
1452                getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
1453                break;
1454            }
1455           
1456            default:
1457                OSG_NOTICE<<"Other event "<<ev.type<<std::endl;
1458                break;
1459               
1460        }
1461        _lastEventType = ev.type;
1462    }
1463
1464    if (windowX != _traits->x ||
1465        windowY != _traits->y ||
1466        windowWidth != _traits->width ||
1467        windowHeight != _traits->height)
1468    {
1469        resized(windowX, windowY, windowWidth, windowHeight);
1470        getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
1471    }
1472   
1473#if 0
1474    if (destroyWindowRequested)
1475    {
1476        close();
1477    }
1478#endif
1479}
1480
1481void GraphicsWindowX11::grabFocus()
1482{
1483    Display* display = getDisplayToUse();
1484
1485    XSetInputFocus( display, _window, RevertToNone, CurrentTime );
1486    XFlush(display);
1487    XSync(display,0);
1488}
1489
1490void GraphicsWindowX11::grabFocusIfPointerInWindow()
1491{
1492    Window win, root;
1493    int wx, wy, rx, ry;
1494    unsigned int buttons;
1495
1496    Display* display = getDisplayToUse();
1497
1498    if( XQueryPointer( display, _window,
1499          &root, &win, &rx, &ry, &wx, &wy, &buttons))
1500    {
1501#if 0
1502        if (wx>=0 && wx<_traits->width &&
1503            wy>=0 && wy<_traits->height)
1504        {
1505            grabFocus();
1506        }
1507#else       
1508        grabFocus();
1509#endif
1510    }
1511}
1512
1513void GraphicsWindowX11::transformMouseXY(float& x, float& y)
1514{
1515    if (getEventQueue()->getUseFixedMouseInputRange())
1516    {
1517        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1518        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1519        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1520    }
1521}
1522
1523void GraphicsWindowX11::adaptKey(XKeyEvent& keyevent, int& keySymbol, int& unmodifiedKeySymbol)
1524{
1525    unsigned char buffer_return[32];
1526    int bytes_buffer = 32;
1527    KeySym keysym_return;
1528
1529    int numChars = XLookupString(&keyevent, reinterpret_cast<char*>(buffer_return), bytes_buffer, &keysym_return, NULL);
1530    keySymbol = keysym_return;
1531    if (!remapExtendedX11Key(keySymbol) && (numChars==1))
1532    {
1533        keySymbol = buffer_return[0];
1534    }
1535
1536    unmodifiedKeySymbol = XKeycodeToKeysym(keyevent.display, keyevent.keycode, 0);
1537}
1538
1539// Function to inject artificial key presses/releases.
1540void GraphicsWindowX11::forceKey(int key, double time, bool state)
1541{
1542    if (!(state ^ keyMapGetKey(_keyMap, key))) return; // already pressed/released
1543
1544    XKeyEvent event;
1545    event.serial = 0;
1546    event.send_event = True;
1547    event.display = _eventDisplay;
1548    event.window = _window;
1549    event.subwindow = 0;
1550    event.time = 0;
1551    event.x = 0;
1552    event.y = 0;
1553    event.x_root = 0;
1554    event.y_root = 0;
1555    event.state = getModifierMask() | (_modifierState & (LockMask | _numLockMask));
1556    event.keycode = key;
1557    event.same_screen = True;
1558
1559    int keySymbol = 0;
1560    int unmodifiedKeySymbol = 0;
1561    if (state)
1562    {
1563        event.type = KeyPress;
1564        adaptKey(event, keySymbol, unmodifiedKeySymbol);
1565        getEventQueue()->keyPress(keySymbol, time, unmodifiedKeySymbol);
1566        keyMapSetKey(_keyMap, key);
1567    }
1568    else
1569    {
1570        event.type = KeyRelease;
1571        adaptKey(event, keySymbol, unmodifiedKeySymbol);
1572        getEventQueue()->keyRelease(keySymbol, time, unmodifiedKeySymbol);
1573        keyMapClearKey(_keyMap, key);
1574    }
1575}
1576
1577void GraphicsWindowX11::syncLocks()
1578{
1579    unsigned int mask = getEventQueue()->getCurrentEventState()->getModKeyMask();
1580
1581    if (_modifierState & LockMask)
1582        mask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
1583    else
1584        mask &= ~osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
1585
1586    if (_modifierState & _numLockMask)
1587        mask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
1588    else
1589        mask &= ~osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
1590
1591    getEventQueue()->getCurrentEventState()->setModKeyMask(mask);
1592}
1593
1594void GraphicsWindowX11::rescanModifierMapping()
1595{
1596    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1597    KeyCode *m = mkm->modifiermap;
1598    KeyCode numlock = XKeysymToKeycode(_eventDisplay, XK_Num_Lock);
1599    _numLockMask = 0;
1600    for (int i = 0; i < mkm->max_keypermod * 8; i++, m++)
1601    {
1602        if (*m == numlock)
1603        {
1604            _numLockMask = 1 << (i / mkm->max_keypermod);
1605            break;
1606        }
1607    }
1608    XFree(mkm->modifiermap);
1609    XFree(mkm);
1610}
1611
1612void GraphicsWindowX11::flushKeyEvents()
1613{
1614    XEvent e;
1615    while (XCheckMaskEvent(_eventDisplay, KeyPressMask|KeyReleaseMask, &e))
1616        continue;
1617}
1618
1619// Returns char[32] keymap with bits for every modifier key set.
1620void GraphicsWindowX11::getModifierMap(char* keymap) const
1621{
1622    memset(keymap, 0, 32);
1623    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1624    KeyCode *m = mkm->modifiermap;
1625    for (int i = 0; i < mkm->max_keypermod * 8; i++, m++)
1626    {
1627        if (*m) keyMapSetKey(keymap, *m);
1628    }
1629    XFree(mkm->modifiermap);
1630    XFree(mkm);
1631}
1632
1633int GraphicsWindowX11::getModifierMask() const
1634{
1635    int mask = 0;
1636    XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay);
1637    for (int i = 0; i < mkm->max_keypermod * 8; i++)
1638    {
1639        unsigned int key = mkm->modifiermap[i];
1640        if (key && keyMapGetKey(_keyMap, key))
1641        {
1642            mask |= 1 << (i / mkm->max_keypermod);
1643        }
1644    }
1645    XFree(mkm->modifiermap);
1646    XFree(mkm);
1647    return mask;
1648}
1649
1650void GraphicsWindowX11::requestWarpPointer(float x,float y)
1651{
1652    if (!_realized)
1653    {
1654        OSG_INFO<<"GraphicsWindowX11::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
1655        return;
1656    }
1657
1658    Display* display = _eventDisplay; // getDisplayToUse();
1659
1660    XWarpPointer( display,
1661                  None,
1662                  _window,
1663                  0, 0, 0, 0,
1664                  static_cast<int>(x), static_cast<int>(y) );
1665
1666    XFlush(display);
1667    XSync(display, 0);
1668   
1669    getEventQueue()->mouseWarped(x,y);
1670}
1671
1672extern "C" 
1673{
1674
1675typedef int (*X11ErrorHandler)(Display*, XErrorEvent*);
1676
1677int X11ErrorHandling(Display* display, XErrorEvent* event)
1678{
1679    OSG_NOTICE<<"Got an X11ErrorHandling call display="<<display<<" event="<<event<<std::endl;
1680
1681    char buffer[256];
1682    XGetErrorText( display, event->error_code, buffer, 256);
1683
1684    OSG_NOTICE << buffer << std::endl;
1685    OSG_NOTICE << "Major opcode: " << (int)event->request_code << std::endl;
1686    OSG_NOTICE << "Minor opcode: " << (int)event->minor_code << std::endl;
1687    OSG_NOTICE << "Error code: " << (int)event->error_code << std::endl;
1688    OSG_NOTICE << "Request serial: " << event->serial << std::endl;
1689    OSG_NOTICE << "Current serial: " << NextRequest( display ) - 1 << std::endl;
1690
1691    switch( event->error_code )
1692    {
1693        case BadValue:
1694            OSG_NOTICE << "  Value: " << event->resourceid << std::endl;
1695            break;
1696
1697        case BadAtom:
1698            OSG_NOTICE << "  AtomID: " << event->resourceid << std::endl;
1699            break;
1700
1701        default:
1702            OSG_NOTICE << "  ResourceID: " << event->resourceid << std::endl;
1703            break;
1704    }
1705    return 0;
1706}
1707
1708}
1709
1710class X11WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface
1711{
1712#ifdef OSGVIEWER_USE_XRANDR
1713    // TODO: Investigate whether or not Robert thinks we should store/restore the original
1714    // resolution in the destructor; I'm not sure the other ones do this, and it may be the
1715    // responsibility of the user.
1716    bool _setScreen(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height, unsigned int colorDepth, double rate) {
1717        if (colorDepth>0)
1718            OSG_NOTICE << "X11WindowingSystemInterface::_setScreen() is not fully implemented (missing depth)."<<std::endl;
1719
1720        Display* display = XOpenDisplay(si.displayName().c_str());
1721       
1722        if(display)
1723        {
1724            XRRScreenConfiguration* sc = XRRGetScreenInfo(display, RootWindow(display, si.screenNum));
1725
1726            if(!sc)
1727            {
1728                OSG_NOTICE << "Unable to create XRRScreenConfiguration on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1729                return false;
1730            }
1731
1732            int      numScreens = 0;
1733            int      numRates   = 0;
1734            Rotation currentRot = 0;
1735            bool     okay       = false;
1736
1737            XRRConfigRotations(sc, &currentRot);
1738           
1739            // If the width or height are zero, use our defaults.
1740            if(!width || !height)
1741            {
1742                getScreenResolution(si, width, height);
1743            }
1744
1745            // If this somehow fails, okay will still be false, no iteration will take place below,
1746            // and the sc pointer will still be freed later on.
1747            XRRScreenSize* ss = XRRConfigSizes(sc, &numScreens);
1748
1749            for(int i = 0; i < numScreens; i++)
1750            {
1751                if(ss[i].width == static_cast<int>(width) && ss[i].height == static_cast<int>(height))
1752                {
1753                    short* rates     = XRRConfigRates(sc, i, &numRates);
1754                    bool   rateFound = false;
1755                   
1756                    // Search for our rate in the list of acceptable rates given to us by Xrandr.
1757                    // If it's not found, rateFound will still be false and the call will never
1758                    // be made to XRRSetScreenConfigAndRate since the rate will be invalid.
1759                    for(int r = 0; r < numRates; r++)
1760                    {
1761                        if(rates[r] == static_cast<short>(rate))
1762                        {
1763                            rateFound = true;
1764                            break;
1765                        }
1766                    }
1767
1768                    if(rate > 0.0f && !rateFound)
1769                    {
1770                        OSG_NOTICE << "Unable to find valid refresh rate " << rate << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1771                    }
1772                    else if(XRRSetScreenConfigAndRate(display, sc, DefaultRootWindow(display), i, currentRot, static_cast<short>(rate), CurrentTime) != RRSetConfigSuccess)
1773                    {
1774                        OSG_NOTICE << "Unable to set resolution to " << width << "x" << height << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1775                    }
1776                    else
1777                    {
1778                        okay = true;
1779                        break;
1780                    }
1781                }
1782            }
1783   
1784            XRRFreeScreenConfigInfo(sc);
1785   
1786            return okay;
1787        }
1788        else
1789        {
1790            OSG_NOTICE << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1791            return false;
1792        }
1793    }
1794#endif
1795
1796protected:
1797    bool _errorHandlerSet;
1798   
1799
1800public:
1801    X11WindowingSystemInterface()
1802    {
1803        OSG_INFO<<"X11WindowingSystemInterface()"<<std::endl;
1804
1805
1806        // Install an X11 error handler, if the application has not already done so.
1807       
1808        // Set default handler, and get pointer to current handler.
1809        X11ErrorHandler currentHandler = XSetErrorHandler(NULL);
1810       
1811        // Set our handler, and get pointer to default handler.
1812        X11ErrorHandler defHandler = XSetErrorHandler(X11ErrorHandling);
1813
1814        if ( currentHandler == defHandler )
1815        {
1816            // No application error handler, use ours.
1817            // OSG_INFO<<"Set osgViewer X11 error handler"<<std::endl;
1818            _errorHandlerSet = 1;
1819        }
1820        else
1821        {
1822            // Application error handler exists, leave it set.
1823            // OSG_INFO<<"Existing application X11 error handler set"<<std::endl;
1824            _errorHandlerSet = 0;
1825            XSetErrorHandler(currentHandler);
1826        }
1827   
1828#if 0
1829        if (XInitThreads() == 0)
1830        {
1831            OSG_NOTICE << "Error: XInitThreads() failed. Aborting." << std::endl;
1832            exit(1);
1833        }
1834        else
1835        {
1836            OSG_INFO << "X11WindowingSystemInterface, xInitThreads() multi-threaded X support initialized.\n";
1837        }
1838#endif       
1839
1840    }
1841
1842
1843
1844    ~X11WindowingSystemInterface()
1845    {
1846        if (osg::Referenced::getDeleteHandler())
1847        {
1848            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
1849            osg::Referenced::getDeleteHandler()->flushAll();
1850        }
1851
1852        //OSG_NOTICE<<"~X11WindowingSystemInterface()"<<std::endl;
1853
1854        // Unset our X11 error handler, providing the application has not replaced it.
1855
1856        if ( _errorHandlerSet )
1857        {
1858            X11ErrorHandler currentHandler = XSetErrorHandler(NULL);
1859            if ( currentHandler == X11ErrorHandling )
1860            {
1861                // OSG_INFO<<"osgViewer X11 error handler removed"<<std::endl;
1862            }
1863            else
1864            {
1865                // Not our error handler, leave it set.
1866                // OSG_INFO<<"Application X11 error handler left"<<std::endl;
1867                XSetErrorHandler(currentHandler);
1868            }
1869        }
1870    }
1871
1872    virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si)
1873    {
1874        Display* display = XOpenDisplay(si.displayName().c_str());
1875        if(display)
1876        {
1877            unsigned int numScreens = ScreenCount(display);
1878            XCloseDisplay(display);
1879
1880            return numScreens;
1881        }
1882        else
1883        {
1884            OSG_NOTICE << "A Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\""<<std::endl;
1885            return 0;
1886        }
1887    }
1888
1889    bool supportsRandr(Display* display) const
1890    {
1891#ifdef OSGVIEWER_USE_XRANDR
1892        int event_basep;
1893        int error_basep;
1894        bool supports_randr = XRRQueryExtension( display, &event_basep, &error_basep );
1895        if( supports_randr )
1896        {
1897            int major, minor;
1898            XRRQueryVersion( display, &major, &minor );
1899            return ( major > 1 || ( major == 1 && minor >= 2 ) );
1900        }
1901#endif
1902        return false;
1903    }
1904
1905    virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
1906    {
1907        Display* display = XOpenDisplay(si.displayName().c_str());
1908        if(display)
1909        {
1910            resolution.width = DisplayWidth(display, si.screenNum);
1911            resolution.height = DisplayHeight(display, si.screenNum);
1912            resolution.colorDepth = DefaultDepth(display, si.screenNum);
1913            resolution.refreshRate = 0;            // Missing call. Need a X11 expert.
1914           
1915            XCloseDisplay(display);
1916        }
1917        else
1918        {
1919            OSG_NOTICE << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<<std::endl;
1920            resolution.width = 0;
1921            resolution.height = 0;
1922            resolution.colorDepth = 0;
1923            resolution.refreshRate = 0;
1924        }
1925    }
1926
1927    virtual bool setScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
1928    {
1929#ifdef OSGVIEWER_USE_XRANDR
1930        _setScreen(si, resolution.width, resolution.height, resolution.colorDepth, resolution.refreshRate);
1931#else
1932        OSG_NOTICE << "You must build osgViewer with Xrandr 1.2 or higher for setScreenSettings support!" << std::endl;
1933#endif
1934        return false;
1935    }
1936
1937    virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList)
1938    {
1939        resolutionList.clear();
1940
1941        Display* display = XOpenDisplay(si.displayName().c_str());
1942        if(display)
1943        {
1944#ifdef OSGVIEWER_USE_XRANDR
1945            int defaultDepth = DefaultDepth(display, si.screenNum);
1946
1947            if (supportsRandr(display))
1948            {
1949                int nsizes = 0;
1950                XRRScreenSize * screenSizes = XRRSizes(display, si.screenNum, &nsizes);
1951                if (screenSizes && nsizes>0)
1952                {
1953                    for(int i=0; i<nsizes; ++i)
1954                    {
1955                        OSG_INFO<<"Screen size "<<screenSizes[i].width<<" "<<screenSizes[i].height<<" "<<screenSizes[i].mwidth<<" "<<screenSizes[i].mheight<<std::endl;
1956
1957                        int nrates;
1958                        short * rates = XRRRates (display, si.screenNum, i, &nrates);
1959                        if (rates && nrates>0)
1960                        {
1961                            for(int j=0; j<nrates; ++j)
1962                            {
1963                                OSG_INFO<<"   rates "<<rates[j]<<std::endl;
1964                               
1965                                resolutionList.push_back(osg::GraphicsContext::ScreenSettings(
1966                                    screenSizes[i].width,
1967                                    screenSizes[i].height,
1968                                    double(rates[j]),
1969                                    defaultDepth));
1970                            }
1971                        }
1972                        else
1973                        {
1974                            resolutionList.push_back(osg::GraphicsContext::ScreenSettings(
1975                                screenSizes[i].width,
1976                                screenSizes[i].height,
1977                                0.0,
1978                                defaultDepth));
1979                        }
1980
1981                    }
1982                }
1983            }
1984#endif           
1985            XCloseDisplay(display);
1986        }
1987
1988        if (resolutionList.empty())
1989        {
1990            OSG_NOTICE << "X11WindowingSystemInterface::enumerateScreenSettings() not supported." << std::endl;
1991        }
1992    }
1993
1994    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1995    {
1996        if (traits->pbuffer)
1997        {
1998#if 1
1999            osg::ref_ptr<osgViewer::PixelBufferX11> pbuffer = new PixelBufferX11(traits);
2000            if (pbuffer->valid()) return pbuffer.release();
2001            else return 0;
2002#else
2003            osg::ref_ptr<osgViewer::GraphicsWindowX11> window = new GraphicsWindowX11(traits);
2004            if (window->valid()) return window.release();
2005            else return 0;
2006#endif
2007        }
2008        else
2009        {
2010            osg::ref_ptr<osgViewer::GraphicsWindowX11> window = new GraphicsWindowX11(traits);
2011            if (window->valid()) return window.release();
2012            else return 0;
2013        }
2014    }
2015
2016};
2017
2018struct RegisterWindowingSystemInterfaceProxy
2019{
2020    RegisterWindowingSystemInterfaceProxy()
2021    {
2022        OSG_INFO<<"RegisterWindowingSystemInterfaceProxy()"<<std::endl;
2023        osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface);
2024    }
2025
2026    ~RegisterWindowingSystemInterfaceProxy()
2027    {
2028        OSG_INFO<<"~RegisterWindowingSystemInterfaceProxy()"<<std::endl;
2029
2030        if (osg::Referenced::getDeleteHandler())
2031        {
2032            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2033            osg::Referenced::getDeleteHandler()->flushAll();
2034        }
2035
2036        osg::GraphicsContext::setWindowingSystemInterface(0);
2037
2038    }
2039};
2040
2041RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2042
2043// declare C entry point for static compilation.
2044extern "C" void graphicswindow_X11(void)
2045{
2046    osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface);
2047}
2048
2049
2050void GraphicsWindowX11::raiseWindow()
2051{
2052    Display* display = getDisplayToUse();
2053    XWindowAttributes winAttrib;
2054
2055    Window root_return, parent_return, *children;
2056    unsigned int nchildren, i=0;
2057    XTextProperty windowName;
2058    bool xraise = false;
2059   
2060
2061    XQueryTree(display, _parent, &root_return, &parent_return, &children, &nchildren);
2062    while (!xraise &&  i<nchildren)
2063    {
2064    XGetWMName(display,children[i++],&windowName);
2065        if ((windowName.nitems != 0) && (strcmp(_traits->windowName.c_str(),(const char *)windowName.value) == 0)) xraise = true;
2066    }
2067    if (xraise) XRaiseWindow(display,_window);
2068    else 
2069    {
2070    XGetWindowAttributes(display, _window, &winAttrib);
2071    XReparentWindow(display, _window, _parent, winAttrib.x, winAttrib.y);
2072    }
2073    XFree(children);
2074
2075    XFlush(display);
2076    XSync(display,0);
2077}
Note: See TracBrowser for help on using the browser.