Back to index

nux  3.0.0
GraphicsDisplayX11.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "GLResource.h"
00024 #include "GpuDevice.h"
00025 #include "GLDeviceObjects.h"
00026 #include "GLResourceManager.h"
00027 
00028 #include "GLTextureResourceManager.h"
00029 #include "GLVertexResourceManager.h"
00030 #include "GraphicsEngine.h"
00031 #include "GLWindowManager.h"
00032 #include "Events.h"
00033 
00034 #include "GraphicsDisplay.h"
00035 
00036 #include <X11/extensions/shape.h>
00037 
00038 namespace nux
00039 {
00040   int GraphicsDisplay::double_click_time_delay = 400; // milliseconds
00041 
00042   GraphicsDisplay::GraphicsDisplay()
00043     : m_X11Display(NULL)
00044     , m_X11Screen(0)
00045     , m_ParentWindow(0)
00046     , m_GLCtx(0)
00047 #ifndef NUX_OPENGLES_20    
00048     , glx_window_(0)
00049 #endif
00050     , m_NumVideoModes(0)
00051     , m_BorderPixel(0)
00052     , _x11_major(0)
00053     , _x11_minor(0)
00054     , _glx_major(0)
00055     , _glx_minor(0)
00056     , _has_glx_13(false)
00057     , m_X11RepeatKey(true)
00058     , m_ViewportSize(Size(0,0))
00059     , m_WindowSize(Size(0,0))
00060     , m_WindowPosition(Point(0,0)) 
00061     , m_Fullscreen(false)
00062     , m_ScreenBitDepth(32)
00063     , m_GfxInterfaceCreated(false)
00064     , m_BestMode(-1)
00065     , m_CreatedFromForeignWindow(false)
00066     , last_click_time_(0)
00067     , double_click_counter_(0)
00068     , m_num_device_modes(0)
00069     , m_pEvent(NULL)
00070     , _last_dnd_position(Point(0, 0)) //DND
00071     , m_PauseGraphicsRendering(false)
00072     , m_FrameTime(0) 
00073     , m_DeviceFactory(0)
00074     , m_GraphicsContext(0)
00075     , m_Style(WINDOWSTYLE_NORMAL)
00076     , _drag_display(NULL)
00077     , _drag_drop_timestamp(0)
00078     , _dnd_source_data(NULL)
00079     , _dnd_source_window(0)
00080     , _global_pointer_grab_data(0)
00081     , _global_pointer_grab_active(false)
00082     , _global_pointer_grab_callback(0)
00083     , _global_keyboard_grab_data(0)
00084     , _global_keyboard_grab_active(false)
00085     , _global_keyboard_grab_callback(0)
00086     , _dnd_is_drag_source(false)
00087     , _dnd_source_target_accepts_drop(false)
00088     , _dnd_source_grab_active(false)
00089     , _dnd_source_drop_sent(false)
00090   {
00091     inlSetThreadLocalStorage(_TLS_GraphicsDisplay, this);
00092 
00093     m_X11LastEvent.type = -1;
00094 
00095     m_pEvent = new Event();
00096 
00097     _dnd_source_funcs.get_drag_image = 0;
00098     _dnd_source_funcs.get_drag_types = 0;
00099     _dnd_source_funcs.get_data_for_type = 0;
00100     _dnd_source_funcs.drag_finished = 0;
00101   }
00102 
00103   GraphicsDisplay::~GraphicsDisplay()
00104   {
00105     NUX_SAFE_DELETE( m_GraphicsContext );
00106     NUX_SAFE_DELETE( m_DeviceFactory );
00107 
00108     if (m_CreatedFromForeignWindow == false)
00109     {
00110       DestroyOpenGLWindow();
00111     }
00112     
00113     NUX_SAFE_DELETE( m_pEvent );
00114     inlSetThreadLocalStorage(_TLS_GraphicsDisplay, 0);
00115   }
00116 
00117   NString GraphicsDisplay::FindResourceLocation(const char *ResourceFileName, bool ErrorOnFail)
00118   {
00119     NString path = m_ResourcePathLocation.GetFile(ResourceFileName);
00120 
00121     if (path == "" && ErrorOnFail)
00122     {
00123       nuxCriticalMsg("[GraphicsDisplay::FindResourceLocation] Failed to locate resource file: %s.", ResourceFileName);
00124       return NString("");
00125     }
00126 
00127     return path;
00128   }
00129 
00130   NString GraphicsDisplay::FindUITextureLocation(const char *ResourceFileName, bool ErrorOnFail)
00131   {
00132     FilePath searchpath;
00133     searchpath.AddSearchPath(m_UITextureSearchPath);
00134     NString path = searchpath.GetFile(ResourceFileName);
00135 
00136     if ((path == "") && ErrorOnFail)
00137     {
00138       nuxCriticalMsg("[GraphicsDisplay::FindResourceLocation] Failed to locate ui texture file: %s.", ResourceFileName);
00139       return NString("");
00140     }
00141 
00142     return path;
00143   }
00144 
00145   NString GraphicsDisplay::FindShaderLocation(const char *ResourceFileName, bool ErrorOnFail)
00146   {
00147     FilePath searchpath;
00148     searchpath.AddSearchPath(m_ShaderSearchPath);
00149     NString path = searchpath.GetFile(ResourceFileName);
00150 
00151     if ((path == "") && ErrorOnFail)
00152     {
00153       nuxCriticalMsg("[GraphicsDisplay::FindResourceLocation] Failed to locate shader file: %s.", ResourceFileName);
00154       return NString("");
00155     }
00156 
00157     return path;
00158   }
00159 
00160   NString GraphicsDisplay::FindFontLocation(const char *ResourceFileName, bool ErrorOnFail)
00161   {
00162     FilePath searchpath;
00163     searchpath.AddSearchPath(m_FontSearchPath);
00164     NString path = searchpath.GetFile(ResourceFileName);
00165 
00166     if ((path == "") && ErrorOnFail)
00167     {
00168       nuxCriticalMsg("[GraphicsDisplay::FindResourceLocation] Failed to locate font file file: %s.", ResourceFileName);
00169       return NString("");
00170     }
00171 
00172     return path;
00173   }
00174 
00175 
00176 
00177   bool GraphicsDisplay::IsGfxInterfaceCreated()
00178   {
00179     return m_GfxInterfaceCreated;
00180   }
00181 
00182   static Bool WaitForNotify( Display *dpy, XEvent *event, XPointer arg )
00183   {
00184     return(event->type == MapNotify) && (event->xmap.window == (Window) arg);
00185   }
00186 
00187 // TODO: change windowWidth, windowHeight, to window_size;
00188   static NCriticalSection CreateOpenGLWindow_CriticalSection;
00189   bool GraphicsDisplay::CreateOpenGLWindow(const char *WindowTitle,
00190                                          unsigned int WindowWidth,
00191                                          unsigned int WindowHeight,
00192                                          WindowStyle Style,
00193                                          const GraphicsDisplay *Parent,
00194                                          bool FullscreenFlag,
00195                                          bool create_rendering_data)
00196   {
00197     int xinerama_event, xinerama_error;
00198     int xinerama_major, xinerama_minor;
00199     NScopeLock Scope(&CreateOpenGLWindow_CriticalSection);
00200 
00201     m_GfxInterfaceCreated = false;
00202 
00203     // FIXME : put at the end
00204     Size new_size(WindowWidth, WindowHeight);
00205     m_ViewportSize = new_size;
00206     m_WindowSize = new_size;
00207     // end of fixme
00208 
00209     m_Fullscreen = FullscreenFlag;  // Set The Global Fullscreen Flag
00210     m_BestMode = -1;                // assume -1 if the mode is not fullscreen
00211 
00212     // Open The display.
00213     m_X11Display = XOpenDisplay(0);
00214 
00215     if (m_X11Display == 0)
00216     {
00217       nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] XOpenDisplay has failed. The window cannot be created.");
00218       return false;
00219     }
00220 
00221     m_X11Screen = DefaultScreen(m_X11Display);
00222     XF86VidModeQueryVersion(m_X11Display, &_x11_major, &_x11_minor);
00223     XineramaQueryVersion(m_X11Display, &xinerama_major, &xinerama_minor);
00224     XineramaQueryExtension(m_X11Display, &xinerama_event, &xinerama_error);
00225 
00226     XF86VidModeGetAllModeLines(m_X11Display, m_X11Screen, &m_NumVideoModes, &m_X11VideoModes);
00227     m_X11OriginalVideoMode = *m_X11VideoModes[0];
00228 
00229     if (m_Fullscreen)               // Attempt Fullscreen Mode?
00230     {
00231       // check if resolution is supported
00232       bool mode_supported = false;
00233 
00234       for (int num_modes = 0 ; num_modes < m_NumVideoModes; num_modes++)
00235       {
00236         if ((m_X11VideoModes[num_modes]->hdisplay == m_ViewportSize.width )
00237           && (m_X11VideoModes[num_modes]->vdisplay == m_ViewportSize.height ))
00238         {
00239           mode_supported = true;
00240           m_BestMode = num_modes;
00241           break;
00242         }
00243       }
00244 
00245       if (mode_supported == false)
00246       {
00247         m_Fullscreen = false;
00248       }
00249     }
00250 
00251 #ifndef NUX_OPENGLES_20
00252     // Check support for GLX
00253     int dummy0, dummy1;
00254     if (!glXQueryExtension(m_X11Display, &dummy0, &dummy1))
00255     {
00256       nuxCriticalMsg("[GraphicsDisplay::CreateOpenGLWindow] GLX is not supported.");
00257       return false;
00258     }
00259 
00260     // Check GLX version
00261     glXQueryVersion(m_X11Display, &_glx_major, &_glx_minor);
00262 
00263     // FBConfigs support added in GLX version 1.3
00264     if (((_glx_major == 1) && (_glx_minor < 3)) || (_glx_major < 1))
00265     {
00266       _has_glx_13 = false;
00267     }
00268     else
00269     {
00270       _has_glx_13 = true;
00271     }
00272 
00273     _has_glx_13 = false; // force old way. this is temporary...
00274  
00275     if (_has_glx_13 == false)
00276     {
00277       // Find an OpenGL capable visual.
00278       static int g_DoubleBufferVisual[] =
00279       {
00280         GLX_RGBA,
00281         GLX_DOUBLEBUFFER,
00282         GLX_RED_SIZE,       8,
00283         GLX_GREEN_SIZE,     8,
00284         GLX_BLUE_SIZE,      8,
00285         GLX_ALPHA_SIZE,     8,
00286         GLX_DEPTH_SIZE,     24,
00287         GLX_STENCIL_SIZE,   8,
00288         None
00289       };
00290 
00291       m_X11VisualInfo = glXChooseVisual(m_X11Display, m_X11Screen, g_DoubleBufferVisual);
00292 
00293       if (m_X11VisualInfo == NULL)
00294       {
00295         nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot get appropriate visual.");
00296         return false;
00297       }
00298 
00299       // Create OpenGL Context.
00300       m_GLCtx = glXCreateContext(m_X11Display, m_X11VisualInfo, 0, GL_TRUE);
00301 
00302       m_X11Colormap = XCreateColormap(m_X11Display,
00303                                        RootWindow(m_X11Display, m_X11VisualInfo->screen),
00304                                        m_X11VisualInfo->visual,
00305                                        AllocNone);
00306     }
00307     else
00308     {
00309         int DoubleBufferAttributes[] =
00310         {
00311           //GLX_X_RENDERABLE, True,
00312           GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
00313           GLX_RENDER_TYPE,   GLX_RGBA_BIT,
00314           GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
00315           GLX_DOUBLEBUFFER,  True,
00316           GLX_RED_SIZE,      8,     /* the maximum number of bits per component    */
00317           GLX_GREEN_SIZE,    8, 
00318           GLX_BLUE_SIZE,     8,
00319           GLX_ALPHA_SIZE,    8,
00320           GLX_DEPTH_SIZE,    24,
00321           GLX_STENCIL_SIZE,  8,
00322           None
00323         };
00324 
00325         GLXFBConfig *fbconfigs = NULL;
00326         int         fbcount;
00327 
00328         #define GET_PROC(proc_type, proc_name, check)       \
00329         do                                                  \
00330         {                                                   \
00331           proc_name = (proc_type) glXGetProcAddress((const GLubyte *) #proc_name); \
00332         } while (0)
00333 
00334         /* initialize GLX 1.3 function pointers */
00335         GET_PROC(PFNGLXGETFBCONFIGSPROC,              glXGetFBConfigs, false);
00336         GET_PROC(PFNGLXGETFBCONFIGATTRIBPROC,         glXGetFBConfigAttrib, false);
00337         GET_PROC(PFNGLXGETVISUALFROMFBCONFIGPROC,     glXGetVisualFromFBConfig, false);
00338         GET_PROC(PFNGLXCREATEWINDOWPROC,              glXCreateWindow, false);
00339         GET_PROC(PFNGLXDESTROYWINDOWPROC,             glXDestroyWindow, false);
00340         GET_PROC(PFNGLXCREATEPIXMAPPROC,              glXCreatePixmap, false);
00341         GET_PROC(PFNGLXDESTROYPIXMAPPROC,             glXDestroyPixmap, false);
00342         GET_PROC(PFNGLXCREATEPBUFFERPROC,             glXCreatePbuffer, false);
00343         GET_PROC(PFNGLXDESTROYPBUFFERPROC,            glXDestroyPbuffer, false);
00344         GET_PROC(PFNGLXCREATENEWCONTEXTPROC,          glXCreateNewContext, false);
00345         GET_PROC(PFNGLXMAKECONTEXTCURRENTPROC,        glXMakeContextCurrent, false);
00346         GET_PROC(PFNGLXCHOOSEFBCONFIGPROC,            glXChooseFBConfig, false);
00347         
00348         /* GLX_SGIX_pbuffer */
00349         GET_PROC(PFNGLXCREATEGLXPBUFFERSGIXPROC,      glXCreateGLXPbufferSGIX, false);
00350         GET_PROC(PFNGLXDESTROYGLXPBUFFERSGIXPROC,     glXDestroyGLXPbufferSGIX, false);
00351         #undef GET_PROC
00352 
00353 
00354         // Request a double buffer configuration
00355         fbconfigs = glXChooseFBConfig(m_X11Display, DefaultScreen(m_X11Display), DoubleBufferAttributes, &fbcount);
00356 
00357         if (fbconfigs == NULL)
00358         {
00359           nuxCriticalMsg("[GraphicsDisplay::CreateOpenGLWindow] glXChooseFBConfig cannot get a supported configuration.");
00360           return false;
00361         }
00362 
00363         // Select best multi-sample config.
00364         if ((_glx_major >= 1) && (_glx_minor >= 4))
00365         {
00366           int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
00367           for (int i = 0; i < fbcount; i++)
00368           {
00369             XVisualInfo *vi = glXGetVisualFromFBConfig(m_X11Display, fbconfigs[i]);
00370             if (vi)
00371             {
00372               int sample_buf, samples;
00373               glXGetFBConfigAttrib(m_X11Display, fbconfigs[i], GLX_SAMPLE_BUFFERS, &sample_buf);
00374               glXGetFBConfigAttrib(m_X11Display, fbconfigs[i], GLX_SAMPLES       , &samples);
00375 
00376               //nuxDebugMsg("Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d SAMPLES = %d\n", i, vi->visualid, sample_buf, samples);
00377 
00378               if (((best_fbc < 0) || sample_buf) && (samples > best_num_samp))
00379               {
00380                 best_fbc = i;
00381                 best_num_samp = samples; 
00382               }
00383 
00384               if ((worst_fbc < 0) || (!sample_buf) || (samples < worst_num_samp))
00385               {
00386                 worst_fbc = i;
00387                 worst_num_samp = samples;
00388               }
00389             }
00390             XFree(vi);
00391           }
00392 
00393           nuxAssertMsg(best_fbc >= 0, "[GraphicsDisplay::CreateOpenGLWindow] Invalid frame buffer config.");
00394 
00395           _fb_config = fbconfigs[best_fbc];
00396         }
00397         else
00398         {
00399           // Choose the first one
00400           _fb_config = fbconfigs[0];
00401         }
00402 
00403         XFree(fbconfigs);
00404 
00405         m_X11VisualInfo = glXGetVisualFromFBConfig(m_X11Display, _fb_config);
00406 
00407         m_X11Colormap = XCreateColormap(m_X11Display, RootWindow(m_X11Display, m_X11VisualInfo->screen),
00408           m_X11VisualInfo->visual,
00409           AllocNone);
00410     }
00411 #else
00412     EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)m_X11Display);
00413     if (dpy == EGL_NO_DISPLAY)
00414     {
00415       nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot get EGL display.");
00416       return false;
00417     }
00418     EGLint            major, minor;
00419     if (!eglInitialize(dpy, &major, &minor))
00420     {
00421       nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot initialize EGL.");
00422       return false;
00423     }
00424 
00425     eglBindAPI(EGL_OPENGL_ES_API);
00426 
00427     const EGLint config_attribs[] =
00428     {
00429       EGL_SURFACE_TYPE,         EGL_WINDOW_BIT,
00430       EGL_RED_SIZE,             1,
00431       EGL_GREEN_SIZE,           1,
00432       EGL_BLUE_SIZE,            1,
00433       EGL_ALPHA_SIZE,           1,
00434       EGL_DEPTH_SIZE,           1,
00435       EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES2_BIT,
00436       EGL_CONFIG_CAVEAT,        EGL_NONE,
00437       EGL_NONE,
00438     };
00439     EGLConfig         configs[1024];
00440     EGLint            count;
00441     if (!eglChooseConfig(dpy, config_attribs, configs, 1024, &count))
00442     {
00443       nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot get EGL config.");
00444       return false;
00445     }
00446 
00447     EGLConfig config = configs[0];
00448     EGLint visualid = 0;
00449     if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &visualid))
00450     {
00451       nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot get native visual ID from EGL config.");
00452       return false;
00453     }
00454 
00455     XVisualInfo       visual_info = {0};
00456     visual_info.visualid = visualid;
00457     m_X11VisualInfo = XGetVisualInfo(m_X11Display, VisualIDMask, &visual_info, &count);
00458     if (!m_X11VisualInfo)
00459     {
00460       nuxCriticalMsg("[GraphicsDisplay::CreateOpenGLWindow] Cannot get appropriate visual.");
00461       return false;
00462     }
00463 
00464     m_X11Colormap = XCreateColormap(m_X11Display,
00465                                      RootWindow(m_X11Display, m_X11VisualInfo->screen),
00466                                      m_X11VisualInfo->visual,
00467                                      AllocNone);
00468 #endif
00469 
00470     m_X11Attr.background_pixmap = 0;
00471     m_X11Attr.border_pixel      = 0;
00472     m_X11Attr.colormap          = m_X11Colormap;
00473     m_X11Attr.override_redirect = m_Fullscreen;
00474     m_X11Attr.event_mask =
00475       // Mouse
00476       /*Button1MotionMask |
00477       Button2MotionMask |
00478       Button3MotionMask |
00479       Button4MotionMask |
00480       Button5MotionMask |
00481       ButtonMotionMask |*/
00482       ButtonPressMask |
00483       ButtonReleaseMask |
00484       // Mouse motion
00485       //-OwnerGrabButtonMask |
00486       //PointerMotionHintMask |
00487       PointerMotionMask |
00488       // Keyboard
00489       //--KeymapStateMask |
00490       KeyPressMask    |
00491       KeyReleaseMask  |
00492       // Window enter/exit
00493       LeaveWindowMask |
00494       EnterWindowMask |
00495       // Exposure Focus
00496       ExposureMask |
00497       FocusChangeMask |
00498       // Structure notify
00499       //--ResizeRedirectMask |
00500       StructureNotifyMask;// |
00501     //--SubstructureNotifyMask |
00502     //--SubstructureRedirectMask |
00503     // Visibility
00504     //--VisibilityChangeMask |
00505     // Property
00506     //--PropertyChangeMask |
00507     // Colormap
00508     //--ColormapChangeMask |
00509     // No event
00510     //--NoEventMask;
00511 
00512 
00513     if (m_Fullscreen)
00514     {
00515       XF86VidModeSwitchToMode(m_X11Display, m_X11Screen, m_X11VideoModes[m_BestMode]);
00516       XF86VidModeSetViewPort(m_X11Display, m_X11Screen, 0, 0);
00517       //Width = m_X11VideoModes[m_BestMode]->hdisplay;
00518       //Height = m_X11VideoModes[m_BestMode]->vdisplay;
00519       XFree(m_X11VideoModes);
00520 
00521       /* create a fullscreen window */
00522 
00523       m_X11Window = XCreateWindow(m_X11Display,
00524                                    RootWindow(m_X11Display, m_X11VisualInfo->screen),
00525                                    0, 0,                           // X, Y
00526                                    m_WindowSize.width, m_WindowSize.height,
00527                                    0,                              // Border
00528                                    m_X11VisualInfo->depth,         // Depth
00529                                    InputOutput,                    // Class
00530                                    m_X11VisualInfo->visual,        // Visual
00531                                    CWBorderPixel |
00532                                    CWColormap |
00533                                    CWEventMask |
00534                                    CWOverrideRedirect,
00535                                    &m_X11Attr);
00536 
00537       XWarpPointer(m_X11Display, None, m_X11Window, 0, 0, 0, 0, 0, 0);
00538       //XMapRaised(m_X11Display, m_X11Window);
00539       XGrabKeyboard(m_X11Display, m_X11Window, True,
00540                      GrabModeAsync,
00541                      GrabModeAsync,
00542                      CurrentTime);
00543       XGrabPointer(m_X11Display, m_X11Window, True,
00544                     ButtonPressMask,
00545                     GrabModeAsync, GrabModeAsync, m_X11Window, None, CurrentTime);
00546     }
00547     else
00548     {
00549       m_X11Window = XCreateWindow(m_X11Display,
00550                                    RootWindow(m_X11Display, m_X11VisualInfo->screen),
00551                                    0, 0,
00552                                    m_WindowSize.width, m_WindowSize.height,
00553                                    0,
00554                                    m_X11VisualInfo->depth,
00555                                    InputOutput,
00556                                    m_X11VisualInfo->visual,
00557                                    CWBorderPixel |
00558                                    CWColormap |
00559                                    CWEventMask |
00560                                    CWOverrideRedirect,
00561                                    &m_X11Attr);
00562 
00563       /* only set window title and handle wm_delete_events if in windowed mode */
00564       m_WMDeleteWindow = XInternAtom(m_X11Display, "WM_DELETE_WINDOW", True);
00565       XSetWMProtocols(m_X11Display, m_X11Window, &m_WMDeleteWindow, 1);
00566 
00567       XSetStandardProperties(m_X11Display, m_X11Window, WindowTitle, WindowTitle, None, NULL, 0, NULL);
00568       //XMapRaised(m_X11Display, m_X11Window);
00569     }
00570 
00571 #ifndef NUX_OPENGLES_20
00572     if (_has_glx_13)
00573     {
00574       XFree(m_X11VisualInfo);
00575       m_X11VisualInfo = 0;
00576 
00577       /* Create a GLX context for OpenGL rendering */
00578       m_GLCtx = glXCreateNewContext(m_X11Display, _fb_config, GLX_RGBA_TYPE, NULL, True);
00579 
00580       if (m_GLCtx == 0)
00581       {
00582         nuxDebugMsg("[GraphicsDisplay::CreateOpenGLWindow] m_GLCtx is null");
00583       }
00584 
00585       /* Create a GLX window to associate the frame buffer configuration
00586       ** with the created X window */
00587       glx_window_ = glXCreateWindow(m_X11Display, _fb_config, m_X11Window, NULL);
00588 
00589       // Map the window to the screen, and wait for it to appear */
00590       XMapWindow(m_X11Display, m_X11Window);
00591       XEvent event;
00592       XIfEvent(m_X11Display, &event, WaitForNotify, (XPointer) m_X11Window);
00593 
00594       /* Bind the GLX context to the Window */
00595       glXMakeContextCurrent(m_X11Display, glx_window_, glx_window_, m_GLCtx);
00596     }
00597 #else
00598     m_GLSurface = eglCreateWindowSurface(dpy, config, (EGLNativeWindowType)m_X11Window, 0);
00599     if (!m_GLSurface)
00600     {
00601       nuxCriticalMsg("[GraphicsDisplay::CreateOpenGLWindow] Failed to create surface.");
00602       return false;
00603     }
00604 
00605     const EGLint context_attribs[] =
00606     {
00607       EGL_CONTEXT_CLIENT_VERSION, 2,
00608       EGL_NONE
00609     };
00610     m_GLCtx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs);
00611     if (m_GLCtx == EGL_NO_CONTEXT)
00612     {
00613       nuxCriticalMsg("[GraphicsDisplay::CreateOpenGLWindow] Failed to create EGL context.");
00614       return false;
00615     }
00616 #endif
00617 
00618     MakeGLContextCurrent();
00619 
00620     m_GfxInterfaceCreated = true;
00621 
00622     m_DeviceFactory = new GpuDevice(m_ViewportSize.width, m_ViewportSize.height, BITFMT_R8G8B8A8,
00623         m_X11Display,
00624         m_X11Window,
00625         _has_glx_13,
00626         _fb_config,
00627         m_GLCtx,
00628         1, 0, false);
00629 
00630     m_GraphicsContext = new GraphicsEngine(*this);
00631 
00632     //EnableVSyncSwapControl();
00633     //DisableVSyncSwapControl();
00634         
00635     glClearColor(0.0, 0.0, 0.0, 0.0);
00636     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
00637     SwapBuffer();
00638     
00639        
00640     InitGlobalGrabWindow();
00641 
00642     return TRUE;
00643   }
00644 
00645 #ifdef NUX_OPENGLES_20
00646   bool GraphicsDisplay::CreateFromOpenGLWindow(Display *X11Display, Window X11Window, EGLContext OpenGLContext)
00647 #else
00648   bool GraphicsDisplay::CreateFromOpenGLWindow(Display *X11Display, Window X11Window, GLXContext OpenGLContext)
00649 #endif
00650   {
00651     // Do not make the opengl context current
00652     // Do not swap the framebuffer
00653     // Do not clear the depth or color buffer
00654     // Do not enable/disbale VSync
00655 
00656     m_X11Display = X11Display;
00657     m_X11Window = X11Window;
00658     m_GLCtx = OpenGLContext;
00659 
00660     m_X11Screen = DefaultScreen(m_X11Display);
00661 
00662     Window root_return;
00663     int x_return, y_return;
00664     unsigned int width_return, height_return;
00665     unsigned int border_width_return;
00666     unsigned int depth_return;
00667 
00668     XGetGeometry(X11Display, X11Window, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return);
00669     m_WindowSize = Size(width_return, height_return);
00670     m_WindowPosition = Point(x_return, y_return);
00671 
00672     m_ViewportSize = Size(width_return, height_return);
00673 
00674     m_GfxInterfaceCreated = true;
00675 
00676     // m_DeviceFactory = new GpuDevice(m_ViewportSize.GetWidth(), m_ViewportSize.GetHeight(), BITFMT_R8G8B8A8);
00677     m_DeviceFactory = new GpuDevice(m_ViewportSize.width, m_ViewportSize.height, BITFMT_R8G8B8A8,
00678         m_X11Display,
00679         m_X11Window,
00680         false,
00681         _fb_config,
00682         m_GLCtx,
00683         1, 0, false);
00684     m_GraphicsContext = new GraphicsEngine(*this);
00685 
00686     InitGlobalGrabWindow();
00687 
00688     m_CreatedFromForeignWindow = true;
00689 
00690     return true;
00691   }
00692 
00693   GraphicsEngine* GraphicsDisplay::GetGraphicsEngine() const
00694   {
00695     return m_GraphicsContext;
00696   }
00697 
00698   GpuDevice* GraphicsDisplay::GetGpuDevice() const
00699   {
00700     return m_DeviceFactory;
00701   }
00702 
00703   int GraphicsDisplay::GetGlXMajor() const
00704   {
00705     return _glx_major;
00706   }
00707 
00708   int GraphicsDisplay::GetGlXMinor() const
00709   {
00710     return _glx_minor;
00711   }
00712 
00713   bool GraphicsDisplay::HasFrameBufferSupport()
00714   {
00715     return m_DeviceFactory->GetGpuInfo().Support_EXT_Framebuffer_Object();
00716   }
00717 
00718 // TODO(thumper): Size const& GraphicsDisplay::GetWindowSize();
00719   void GraphicsDisplay::GetWindowSize(int &w, int &h)
00720   {
00721     w = m_WindowSize.width;
00722     h = m_WindowSize.height;
00723   }
00724 
00725   void GraphicsDisplay::GetDesktopSize(int &w, int &h)
00726   {
00727     Window root;
00728     int x, y;
00729     unsigned int width, height, depth, border_width;
00730     bool ret = XGetGeometry(m_X11Display, RootWindow(m_X11Display, m_X11Screen),
00731                              &root,
00732                              &x, &y,
00733                              &width, &height, &border_width, &depth);
00734 
00735     if (ret == false)
00736     {
00737       nuxAssert("[GetDesktopSize] Failed to get the desktop size");
00738       w = 0;
00739       h = 0;
00740     }
00741   }
00742 
00743   void GraphicsDisplay::SetWindowSize(int width, int height)
00744   {
00745     nuxDebugMsg("[GraphicsDisplay::SetWindowSize] Setting window size to %dx%d", width, height);
00746     // Resize window client area
00747     XResizeWindow(m_X11Display, m_X11Window, width, height);
00748     XFlush(m_X11Display);
00749   }
00750 
00751   void GraphicsDisplay::SetWindowPosition(int x, int y)
00752   {
00753     nuxDebugMsg("[GraphicsDisplay::SetWindowPosition] Setting window position to %dx%d", x, y);
00754     // Resize window client area
00755     XMoveWindow(m_X11Display, m_X11Window, x, y);
00756     XFlush(m_X11Display);
00757   }
00758 
00759   int GraphicsDisplay::GetWindowWidth()
00760   {
00761     return m_WindowSize.width;
00762   }
00763 
00764   int GraphicsDisplay::GetWindowHeight()
00765   {
00766     return m_WindowSize.height;
00767   }
00768 
00769   void GraphicsDisplay::SetViewPort(int x, int y, int width, int height)
00770   {
00771     if (IsGfxInterfaceCreated())
00772     {
00773       //do not rely on m_ViewportSize: glViewport can be called directly
00774       m_ViewportSize = Size(width, height);
00775       m_GraphicsContext->SetViewport(x, y, width, height);
00776       m_GraphicsContext->SetScissor(0, 0, width, height);
00777     }
00778   }
00779 
00780   void GraphicsDisplay::ResetWindowSize()
00781   {
00782     Window root_return;
00783     int x_return, y_return;
00784     unsigned int width_return, height_return;
00785     unsigned int border_width_return;
00786     unsigned int depth_return;
00787 
00788     XGetGeometry(m_X11Display,
00789       m_X11Window,
00790       &root_return,
00791       &x_return,
00792       &y_return,
00793       &width_return,
00794       &height_return,
00795       &border_width_return,
00796       &depth_return);
00797 
00798     m_WindowSize = Size(width_return, height_return);
00799     m_WindowPosition = Point(x_return, y_return);
00800   }
00801 
00802   Point GraphicsDisplay::GetMouseScreenCoord()
00803   {
00804     Window root_return;
00805     Window child_return;
00806     int root_x_return;
00807     int root_y_return;
00808     int win_x_return;
00809     int win_y_return;
00810     unsigned int mask_return;
00811 
00812 
00813     XQueryPointer(m_X11Display,
00814                    RootWindow(m_X11Display, m_X11Screen),
00815                    &root_return,
00816                    &child_return,
00817                    &root_x_return,
00818                    &root_y_return,
00819                    &win_x_return,
00820                    &win_y_return,
00821                    &mask_return);
00822     XFlush(m_X11Display);
00823 
00824     return Point(root_x_return, root_y_return);
00825   }
00826 
00827   Point GraphicsDisplay::GetMouseWindowCoord()
00828   {
00829     Window root_return;
00830     Window child_return;
00831     int root_x_return;
00832     int root_y_return;
00833     int win_x_return;
00834     int win_y_return;
00835     unsigned int mask_return;
00836 
00837     XQueryPointer(m_X11Display,
00838                    RootWindow(m_X11Display, m_X11Screen),
00839                    &root_return,
00840                    &child_return,
00841                    &root_x_return,
00842                    &root_y_return,
00843                    &win_x_return,
00844                    &win_y_return,
00845                    &mask_return);
00846     XFlush(m_X11Display);
00847 
00848     return Point(win_x_return, win_y_return);
00849   }
00850 
00851   Point GraphicsDisplay::GetWindowCoord()
00852   {
00853     XWindowAttributes attrib;
00854     int status = XGetWindowAttributes(m_X11Display, m_X11Window, &attrib);
00855 
00856     if (status == 0)
00857     {
00858       nuxAssert("[GraphicsDisplay::GetWindowCoord] Failed to get the window attributes.");
00859       return Point(0, 0);
00860     }
00861 
00862     return Point(attrib.x, attrib.y);
00863   }
00864 
00865   Rect GraphicsDisplay::GetWindowGeometry()
00866   {
00867     return Rect(m_WindowPosition.x, m_WindowPosition.y, m_WindowSize.width, m_WindowSize.height);
00868   }
00869 
00870   Rect GraphicsDisplay::GetNCWindowGeometry()
00871   {
00872     return Rect(m_WindowPosition.x, m_WindowPosition.y, m_WindowSize.width, m_WindowSize.height);
00873   }
00874 
00875   void GraphicsDisplay::MakeGLContextCurrent()
00876   {
00877 #ifndef NUX_OPENGLES_20
00878     if (_has_glx_13)
00879     {
00880       nuxDebugMsg("Has glx 1.3");
00881       if (!glXMakeContextCurrent(m_X11Display, glx_window_, glx_window_, m_GLCtx))
00882       {
00883         nuxDebugMsg("Destroy");
00884         DestroyOpenGLWindow();
00885       }
00886     }
00887     else if (!glXMakeCurrent(m_X11Display, m_X11Window, m_GLCtx))
00888     {
00889       DestroyOpenGLWindow();
00890     }
00891 #else
00892     EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)m_X11Display);
00893 
00894     if (!eglMakeCurrent(dpy, m_GLSurface, m_GLSurface, m_GLCtx))
00895     {
00896       DestroyOpenGLWindow();
00897     }
00898 #endif
00899   }
00900 
00901   void GraphicsDisplay::SwapBuffer(bool glswap)
00902   {
00903     // There are a lot of mouse motion events coming from X11. The system processes one event at a time and sleeps
00904     // if necessary to cap the frame rate to 60 frames per seconds. But while the thread sleeping, there are accumulated
00905     // motion events waiting to be processed. This creates an increasing backlog of motion events. It translate into a slow
00906     // motion of elements that moves in response to the mouse.
00907     // Solution: if the the current event is a motion event, changes are, it is followed many more motion events.
00908     // In this case, don't sleep the thread... Swap the framebuffer to see the result of the current single motion event.
00909     // It maybe worth investigating how to properly balance event processing and drawing in order to keep the
00910     // frame rate and the responsiveness at acceptable levels.
00911     // As a consequence, when the mouse is moving, the frame rate goes beyond 60fps.
00912 
00913     /*bool bsleep = true;
00914     if (XPending(m_X11Display) > 0)
00915     {
00916         XEvent xevent;
00917         XPeekEvent(m_X11Display, &xevent);
00918         if (xevent.type == MotionNotify)
00919         {
00920             //nuxDebugMsg("[GraphicsDisplay::SwapBuffer]: MotionNotify event.");
00921             bsleep = false;
00922         }
00923     }*/
00924 
00925     if (IsPauseThreadGraphicsRendering())
00926       return;
00927 
00928     if (glswap)
00929     {
00930 #ifndef NUX_OPENGLES_20
00931       if (_has_glx_13)
00932         glXSwapBuffers(m_X11Display, glx_window_);
00933       else
00934         glXSwapBuffers(m_X11Display, m_X11Window);
00935 #else
00936       eglSwapBuffers(eglGetDisplay((EGLNativeDisplayType)m_X11Display), m_GLSurface);
00937 #endif
00938     }
00939 
00940     m_FrameTime = m_Timer.PassedMilliseconds();
00941   }
00942 
00943   void GraphicsDisplay::DestroyOpenGLWindow()
00944   {
00945     if (m_GfxInterfaceCreated == true)
00946     {
00947       if (m_GLCtx == 0)
00948       {
00949         nuxDebugMsg("[GraphicsDisplay::DestroyOpenGLWindow] m_GLCtx is null");
00950       }
00951 
00952       if (m_GLCtx)
00953       {
00954 #ifndef NUX_OPENGLES_20
00955 
00956         // Release the current context
00957         if (_has_glx_13)
00958         {
00959           if (!glXMakeContextCurrent(m_X11Display, None, None, NULL))
00960           {
00961             nuxAssert("[GraphicsDisplay::DestroyOpenGLWindow] glXMakeContextCurrent failed.");
00962           }
00963         }
00964         else
00965         {
00966           if (!glXMakeCurrent(m_X11Display, None, NULL))
00967           {
00968             nuxAssert("[GraphicsDisplay::DestroyOpenGLWindow] glXMakeCurrent failed.");
00969           }
00970         }
00971 
00972         glXDestroyContext(m_X11Display, m_GLCtx);
00973 
00974         if (_has_glx_13)
00975         {
00976           glXDestroyWindow(m_X11Display, glx_window_);
00977         }
00978 #else
00979         EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)m_X11Display);
00980 
00981         if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
00982         {
00983           nuxAssert("[GraphicsDisplay::DestroyOpenGLWindow] eglMakeCurrent failed.");
00984         }
00985 
00986         eglDestroyContext(dpy, m_GLCtx);
00987         eglDestroySurface(dpy, m_GLSurface);
00988         eglTerminate(dpy);
00989         eglReleaseThread();
00990 #endif
00991         m_GLCtx = NULL;
00992       }
00993 
00994       /* switch back to original desktop resolution if we were in fs */
00995       if (m_Fullscreen)
00996       {
00997         XF86VidModeSwitchToMode(m_X11Display, m_X11Screen, &m_X11OriginalVideoMode);
00998         XF86VidModeSetViewPort(m_X11Display, m_X11Screen, 0, 0);
00999       }
01000 
01001       XDestroyWindow(m_X11Display, m_X11Window);
01002       XFreeColormap(m_X11Display, m_X11Colormap);
01003       XCloseDisplay(m_X11Display);
01004     }
01005 
01006     m_GfxInterfaceCreated = false;
01007   }
01008 
01009   int GraphicsDisplay::MouseMove(XEvent xevent, Event *m_pEvent)
01010   {
01011     // Erase mouse event and mouse doubleclick events. Keep the mouse states.
01012     unsigned int _mouse_state = m_pEvent->mouse_state & 0x0F000000;
01013 
01014     m_pEvent->type = NUX_MOUSE_MOVE;
01015 
01016     if (xevent.type == MotionNotify)
01017     {
01018       _mouse_state |= (xevent.xmotion.state & Button1Mask) ? NUX_STATE_BUTTON1_DOWN : 0;
01019       _mouse_state |= (xevent.xmotion.state & Button2Mask) ? NUX_STATE_BUTTON2_DOWN : 0;
01020       _mouse_state |= (xevent.xmotion.state & Button3Mask) ? NUX_STATE_BUTTON3_DOWN : 0;
01021     }
01022     else if (xevent.type == LeaveNotify || xevent.type == EnterNotify)
01023     {
01024       _mouse_state |= (xevent.xcrossing.state & Button1Mask) ? NUX_STATE_BUTTON1_DOWN : 0;
01025       _mouse_state |= (xevent.xcrossing.state & Button2Mask) ? NUX_STATE_BUTTON2_DOWN : 0;
01026       _mouse_state |= (xevent.xcrossing.state & Button3Mask) ? NUX_STATE_BUTTON3_DOWN : 0;
01027     }
01028     m_pEvent->mouse_state = _mouse_state;
01029 
01030     return 0;
01031   }
01032 
01033   int GraphicsDisplay::MousePress(XEvent xevent, Event *m_pEvent)
01034   {
01035     // Erase mouse event and mouse double-click events. Keep the mouse states.
01036     ulong _mouse_state = m_pEvent->mouse_state & 0x0F000000;
01037 
01038     bool double_click = false;
01039     Time current_time = xevent.xbutton.time;
01040     if ((double_click_counter_ == 1) && ((int)current_time - (int)last_click_time_ < double_click_time_delay))
01041     {
01042       double_click = true;
01043       double_click_counter_ = 0;
01044     }
01045     else
01046     {
01047       double_click_counter_ = 1;
01048     }
01049 
01050     // State of the button before the event
01051     _mouse_state |= (xevent.xbutton.state & Button1Mask) ? NUX_STATE_BUTTON1_DOWN : 0;
01052     _mouse_state |= (xevent.xbutton.state & Button2Mask) ? NUX_STATE_BUTTON2_DOWN : 0;
01053     _mouse_state |= (xevent.xbutton.state & Button3Mask) ? NUX_STATE_BUTTON3_DOWN : 0;
01054 
01055     if (xevent.xbutton.type == ButtonPress)
01056     {
01057       if (xevent.xbutton.button == Button1)
01058       {
01059         if (double_click)
01060           m_pEvent->type = NUX_MOUSE_DOUBLECLICK;
01061         else
01062           m_pEvent->type = NUX_MOUSE_PRESSED;
01063 
01064         _mouse_state |= NUX_EVENT_BUTTON1_DOWN;
01065         _mouse_state |= NUX_STATE_BUTTON1_DOWN;
01066       }
01067 
01068       if (xevent.xbutton.button == Button2)
01069       {
01070         if (double_click)
01071           m_pEvent->type = NUX_MOUSE_DOUBLECLICK;
01072         else
01073           m_pEvent->type = NUX_MOUSE_PRESSED;
01074 
01075         _mouse_state |= NUX_EVENT_BUTTON2_DOWN;
01076         _mouse_state |= NUX_STATE_BUTTON2_DOWN;
01077       }
01078 
01079       if (xevent.xbutton.button == Button3)
01080       {
01081         if (double_click)
01082           m_pEvent->type = NUX_MOUSE_DOUBLECLICK;
01083         else
01084           m_pEvent->type = NUX_MOUSE_PRESSED;
01085 
01086         _mouse_state |= NUX_EVENT_BUTTON3_DOWN;
01087         _mouse_state |= NUX_STATE_BUTTON3_DOWN;
01088       }
01089 
01090       if (xevent.xbutton.button == Button4)
01091       {
01092         _mouse_state |= NUX_EVENT_MOUSEWHEEL;
01093         m_pEvent->type = NUX_MOUSE_WHEEL;
01094         m_pEvent->wheel_delta = NUX_MOUSEWHEEL_DELTA;
01095         return 1;
01096       }
01097 
01098       if (xevent.xbutton.button == Button5)
01099       {
01100         _mouse_state |= NUX_EVENT_MOUSEWHEEL;
01101         m_pEvent->type = NUX_MOUSE_WHEEL;
01102         m_pEvent->wheel_delta = -NUX_MOUSEWHEEL_DELTA;
01103         return 1;
01104       }
01105 
01106       if (xevent.xbutton.button == 6)
01107       {
01108         _mouse_state |= NUX_EVENT_MOUSEWHEEL;
01109         m_pEvent->type = NUX_MOUSE_WHEEL;
01110         m_pEvent->wheel_delta = NUX_MOUSEWHEEL_DELTA;
01111         return 1;
01112       }
01113 
01114       if (xevent.xbutton.button == 7)
01115       {
01116         _mouse_state |= NUX_EVENT_MOUSEWHEEL;
01117         m_pEvent->type = NUX_MOUSE_WHEEL;
01118         m_pEvent->wheel_delta = -NUX_MOUSEWHEEL_DELTA;
01119         return 1;
01120       }
01121     }
01122 
01123     m_pEvent->mouse_state = _mouse_state;
01124 
01125     return 0;
01126   }
01127 
01128   int GraphicsDisplay::MouseRelease(XEvent xevent, Event *m_pEvent)
01129   {
01130     // Erase mouse event and mouse double-click events. Keep the mouse states.
01131     ulong _mouse_state = m_pEvent->mouse_state & 0x0F000000;
01132 
01133     // State of the button before the event
01134     _mouse_state |= (xevent.xbutton.state & Button1Mask) ? NUX_STATE_BUTTON1_DOWN : 0;
01135     _mouse_state |= (xevent.xbutton.state & Button2Mask) ? NUX_STATE_BUTTON2_DOWN : 0;
01136     _mouse_state |= (xevent.xbutton.state & Button3Mask) ? NUX_STATE_BUTTON3_DOWN : 0;
01137 
01138     if (xevent.xbutton.type == ButtonRelease)
01139     {
01140       if (xevent.xbutton.button == Button1)
01141       {
01142         m_pEvent->type = NUX_MOUSE_RELEASED;
01143         _mouse_state |= NUX_EVENT_BUTTON1_UP;
01144         _mouse_state &= ~NUX_STATE_BUTTON1_DOWN;
01145       }
01146 
01147       if (xevent.xbutton.button == Button2)
01148       {
01149         m_pEvent->type = NUX_MOUSE_RELEASED;
01150         _mouse_state |= NUX_EVENT_BUTTON2_UP;
01151         _mouse_state &= ~NUX_STATE_BUTTON2_DOWN;
01152       }
01153 
01154       if (xevent.xbutton.button == Button3)
01155       {
01156         m_pEvent->type = NUX_MOUSE_RELEASED;
01157         _mouse_state |= NUX_EVENT_BUTTON3_UP;
01158         _mouse_state &= ~NUX_STATE_BUTTON3_DOWN;
01159       }
01160     }
01161 
01162     m_pEvent->mouse_state = _mouse_state;
01163     last_click_time_ = xevent.xbutton.time;
01164 
01165     return 0;
01166   }
01167 
01168   unsigned int GetModifierKeyState(unsigned int modifier_key_state)
01169   {
01170     unsigned int state = 0;
01171 
01172     // For CapsLock, we don't want to know if the key is pressed Down or Up.
01173     // We really want to know the state of the the CapsLock: on(keyboard light is on) or off?
01174     if (modifier_key_state & LockMask)
01175     {
01176       state |= KEY_MODIFIER_CAPS_LOCK;
01177     }
01178 
01179     if (modifier_key_state & ControlMask)
01180     {
01181       state |= KEY_MODIFIER_CTRL;
01182     }
01183 
01184     if (modifier_key_state & ShiftMask)
01185     {
01186       state |= KEY_MODIFIER_SHIFT;
01187     }
01188 
01189     if (modifier_key_state & Mod1Mask)
01190     {
01191       state |= KEY_MODIFIER_ALT;
01192     }
01193 
01194     if (modifier_key_state & Mod2Mask)
01195     {
01196       state |= KEY_MODIFIER_NUMLOCK;
01197     }
01198 
01199     // todo(jaytaoko): find out which key enable mod3mask
01200     // if (modifier_key_state & Mod3Mask)
01201     // {
01202 
01203     // }
01204 
01205     if (modifier_key_state & Mod4Mask)
01206     {
01207       state |= KEY_MODIFIER_SUPER;
01208     }
01209 
01210     // todo(jaytaoko): find out which key enable mod5mask
01211     // if (modifier_key_state & Mod5Mask)
01212     // {
01213 
01214     // }
01215 
01216     return state;
01217   }
01218 
01219   void GraphicsDisplay::GetSystemEvent(Event *evt)
01220   {
01221     m_pEvent->Reset();
01222     // Erase mouse event and mouse doubleclick states. Keep the mouse states.
01223     m_pEvent->mouse_state &= 0x0F000000;
01224     bool bProcessEvent = true;
01225 
01226     // Process event matching this window
01227     XEvent xevent;
01228 
01229     if (XPending(m_X11Display))
01230     {
01231       XNextEvent(m_X11Display, &xevent);
01232 
01233       if (!_event_filters.empty())
01234       {
01235         for (auto filter : _event_filters)
01236         {
01237           bool result = filter.filter(xevent, filter.data);
01238           if (result)
01239           {
01240             memcpy(evt, m_pEvent, sizeof(Event));
01241             return;
01242           }
01243         }
01244       }
01245       // Detect auto repeat keys. X11 sends a combination of KeyRelease/KeyPress(at the same time) when a key auto repeats.
01246       // Here, we make sure we process only the keyRelease when the key is effectively released.
01247       if ((xevent.type == KeyPress) || (xevent.type == KeyRelease))
01248       {
01249         if (xevent.xkey.keycode < 256)
01250         {
01251           // Detect if a key is repeated
01252           char Keys[32];
01253           // The XQueryKeymap function returns a bit vector for the logical state of the keyboard, where each bit set
01254           // to 1 indicates that the corresponding key is currently pressed down. The vector is represented as 32 bytes.
01255           // Byte N(from 0) contains the bits for keys 8N to 8N + 7 with the least significant bit in the byte representing
01256           // key 8N.
01257           // Note that the logical state of a device(as seen by client applications) may lag the physical state if device
01258           // event processing is frozen.
01259 
01260           XQueryKeymap(m_X11Display, Keys);
01261 
01262           if (Keys[xevent.xkey.keycode >> 3] & (1 << (xevent.xkey.keycode % 8)))
01263           {
01264             // KeyRelease event + KeyDown = discard repeated event
01265             if (xevent.type == KeyRelease)
01266             {
01267               m_X11LastEvent = xevent;
01268               bProcessEvent = false;
01269             }
01270 
01271             // KeyPress event + key repeat disabled + matching KeyRelease event = discard repeated event
01272             if ((xevent.type == KeyPress) && (!m_X11RepeatKey) &&
01273                  (m_X11LastEvent.xkey.keycode == xevent.xkey.keycode) &&
01274                  (m_X11LastEvent.xkey.time == xevent.xkey.time))
01275             {
01276               bProcessEvent = false;;
01277             }
01278           }
01279         }
01280       }
01281 
01282       if (xevent.type == MotionNotify)
01283       {
01284         while (XCheckTypedEvent(m_X11Display, MotionNotify, &xevent));
01285       }
01286 
01287       if (bProcessEvent)
01288         ProcessXEvent(xevent, false);
01289 
01290       memcpy(evt, m_pEvent, sizeof(Event));
01291 
01292     }
01293     else
01294     {
01295       memcpy(evt, m_pEvent, sizeof(Event));
01296     }
01297   }
01298   
01299 #if defined(NUX_OS_LINUX)
01300   void GraphicsDisplay::InjectXEvent(Event *evt, XEvent xevent)
01301   {
01302     m_pEvent->Reset();
01303     // Erase mouse event and mouse doubleclick states. Keep the mouse states.
01304     m_pEvent->mouse_state &= 0x0F000000;
01305     
01306     // We could do some checks here to make sure the xevent is really what it pretends to be.
01307     ProcessXEvent(xevent, false);
01308     memcpy(evt, m_pEvent, sizeof(Event));
01309   }
01310 
01311   void GraphicsDisplay::AddEventFilter(EventFilterArg arg)
01312   {
01313     _event_filters.push_back(arg);
01314   }
01315 
01316   void GraphicsDisplay::RemoveEventFilter(void *owner)
01317   {
01318     std::list<EventFilterArg>::iterator it;
01319     for (it = _event_filters.begin(); it != _event_filters.end(); ++it)
01320     {
01321       if ((*it).data == owner)
01322       {
01323         _event_filters.erase(it);
01324         break;
01325       }
01326     }
01327   }
01328 #endif
01329 
01330   void GraphicsDisplay::ProcessForeignX11Event(XEvent *xevent, Event *nux_event)
01331   {
01332     m_pEvent->Reset();
01333     // Erase mouse event and mouse doubleclick states. Keep the mouse states.
01334     m_pEvent->mouse_state &= 0x0F000000;
01335     bool bProcessEvent = true;
01336 
01337     // Process event matching this window
01338     if (true /*(NUX_REINTERPRET_CAST(XAnyEvent*, xevent))->window == m_X11Window*/)
01339     {
01340       // Detect auto repeat keys. X11 sends a combination of KeyRelease/KeyPress(at the same time) when a key auto repeats.
01341       // Here, we make sure we process only the keyRelease when the key is effectively released.
01342       if ((xevent->type == KeyPress) || (xevent->type == KeyRelease))
01343       {
01344         if (xevent->xkey.keycode < 256)
01345         {
01346           // Detect if a key is repeated
01347           char Keys[32];
01348           // The XQueryKeymap function returns a bit vector for the logical state of the keyboard, where each bit set
01349           // to 1 indicates that the corresponding key is currently pressed down. The vector is represented as 32 bytes.
01350           // Byte N(from 0) contains the bits for keys 8N to 8N + 7 with the least significant bit in the byte representing
01351           // key 8N.
01352           // Note that the logical state of a device(as seen by client applications) may lag the physical state if device
01353           // event processing is frozen.
01354 
01355           XQueryKeymap(xevent->xany.display, Keys);
01356 
01357           if (Keys[xevent->xkey.keycode >> 3] & (1 << (xevent->xkey.keycode % 8)))
01358           {
01359             // KeyRelease event + KeyDown = discard repeated event
01360             if (xevent->type == KeyRelease)
01361             {
01362               m_X11LastEvent = *xevent;
01363               bProcessEvent = false;
01364             }
01365 
01366             // KeyPress event + key repeat disabled + matching KeyRelease event = discard repeated event
01367             if ((xevent->type == KeyPress) && (!m_X11RepeatKey) &&
01368                  (m_X11LastEvent.xkey.keycode == xevent->xkey.keycode) &&
01369                  (m_X11LastEvent.xkey.time == xevent->xkey.time))
01370             {
01371               bProcessEvent = false;;
01372             }
01373           }
01374         }
01375       }
01376 
01377       if (xevent->type == MotionNotify)
01378       {
01379         while (XCheckTypedEvent(m_X11Display, MotionNotify, xevent));
01380       }
01381 
01382       if (bProcessEvent)
01383         ProcessXEvent(*xevent, true);
01384 
01385       memcpy(nux_event, m_pEvent, sizeof(Event));
01386     }
01387     else
01388     {
01389       memcpy(nux_event, m_pEvent, sizeof(Event));
01390     }
01391   }
01392 
01393   Event &GraphicsDisplay::GetCurrentEvent()
01394   {
01395     return *m_pEvent;
01396   }
01397 
01398   bool GraphicsDisplay::HasXPendingEvent() const
01399   {
01400     return XPending(m_X11Display) ? true : false;
01401   }
01402   
01403   void GraphicsDisplay::RecalcXYPosition(int x_root, int y_root, int &x_recalc, int &y_recalc)
01404   {
01405     int main_window_x = m_WindowPosition.x;
01406     int main_window_y = m_WindowPosition.y;
01407   
01408     x_recalc = x_root - main_window_x;
01409     y_recalc = y_root - main_window_y;
01410   }
01411 
01412   void GraphicsDisplay::RecalcXYPosition(Window TheMainWindow, XEvent xevent, int &x_recalc, int &y_recalc)
01413   {
01414     x_recalc = y_recalc = 0;
01415     int main_window_x = m_WindowPosition.x;
01416     int main_window_y = m_WindowPosition.y;
01417     bool same = (TheMainWindow == xevent.xany.window);
01418     
01419     switch(xevent.type)
01420     {
01421       case ButtonPress:
01422       case ButtonRelease:
01423       {
01424         if (same)
01425         {
01426           x_recalc = xevent.xbutton.x;
01427           y_recalc = xevent.xbutton.y;
01428         }
01429         else
01430         {
01431           x_recalc = xevent.xbutton.x_root - main_window_x;
01432           y_recalc = xevent.xbutton.y_root - main_window_y;
01433         }
01434         break;
01435       }
01436 
01437       case MotionNotify:
01438       {
01439         if (same)
01440         {
01441           x_recalc = xevent.xmotion.x;
01442           y_recalc = xevent.xmotion.y;
01443         }
01444         else
01445         {
01446           x_recalc = xevent.xmotion.x_root - main_window_x;
01447           y_recalc = xevent.xmotion.y_root - main_window_y;
01448         }
01449         break;
01450       }
01451 
01452       case LeaveNotify:
01453       case EnterNotify:
01454       {
01455         if (same)
01456         {
01457           x_recalc = xevent.xcrossing.x;
01458           y_recalc = xevent.xcrossing.y;
01459         }
01460         else
01461         {
01462           x_recalc = xevent.xcrossing.x_root - main_window_x;
01463           y_recalc = xevent.xcrossing.y_root - main_window_y;
01464         }
01465         break;
01466       }
01467     }
01468   }
01469 
01470   void GraphicsDisplay::ProcessXEvent(XEvent xevent, bool foreign)
01471   {
01472     int x_recalc = 0;
01473     int y_recalc = 0;
01474 
01475     RecalcXYPosition(m_X11Window, xevent, x_recalc, y_recalc);
01476     
01477     bool local_from_server = !foreign;
01478     foreign = foreign || xevent.xany.window != m_X11Window;
01479 
01480     m_pEvent->type = NUX_NO_EVENT;
01481     m_pEvent->x11_window = xevent.xany.window;
01482 
01483     switch(xevent.type)
01484     {
01485       case DestroyNotify:
01486       {
01487         if (foreign)
01488           break;
01489           
01490         m_pEvent->type = NUX_DESTROY_WINDOW;
01491         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: DestroyNotify event.");
01492         break;
01493       }
01494 
01495       case Expose:
01496       {
01497         if (foreign)
01498           break;
01499         
01500         m_pEvent->type = NUX_WINDOW_DIRTY;
01501         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: Expose event.");
01502         break;
01503       }
01504 
01505 
01506       case ConfigureNotify:
01507       {
01508         if (foreign)
01509           break;
01510         
01511         m_pEvent->type = NUX_SIZE_CONFIGURATION;
01512         m_pEvent->width =  xevent.xconfigure.width;
01513         m_pEvent->height = xevent.xconfigure.height;
01514         m_WindowSize = Size(xevent.xconfigure.width, xevent.xconfigure.height);
01515 
01516         int x, y;
01517         Window child_return;
01518 
01519         XTranslateCoordinates(m_X11Display, m_X11Window, RootWindow(m_X11Display, 0), 0, 0, &x, &y, &child_return);
01520         m_WindowPosition = Point(x, y);
01521 
01522         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: ConfigureNotify event. %d %d", x, y);
01523         break;
01524       }
01525 
01526       case FocusIn:
01527       {
01528         if (!local_from_server)
01529           break;
01530           
01531         m_pEvent->type = NUX_WINDOW_ENTER_FOCUS;
01532         m_pEvent->mouse_state = 0;
01533 
01534         m_pEvent->dx = 0;
01535         m_pEvent->dy = 0;
01536         m_pEvent->virtual_code = 0;
01537         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusIn event.");
01538         break;
01539       }
01540 
01541       case FocusOut:
01542       {
01543         if (!local_from_server)
01544           break;
01545           
01546         m_pEvent->type = NUX_WINDOW_EXIT_FOCUS;
01547         m_pEvent->mouse_state = 0;
01548 
01549         m_pEvent->dx = 0;
01550         m_pEvent->dy = 0;
01551         m_pEvent->virtual_code = 0;
01552         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusOut event.");
01553         break;
01554       }
01555 
01556       case KeyPress:
01557       {
01558         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: KeyPress event.");
01559         KeyCode keycode = xevent.xkey.keycode;
01560         KeySym keysym = NoSymbol;
01561         keysym = XKeycodeToKeysym(xevent.xany.display, keycode, 0);
01562 
01563         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01564         m_pEvent->key_repeat_count = 0;
01565         m_pEvent->x11_keysym = keysym;
01566         m_pEvent->x11_keycode = xevent.xkey.keycode;
01567         m_pEvent->type = NUX_KEYDOWN;
01568         m_pEvent->x11_timestamp = xevent.xkey.time;
01569         m_pEvent->x11_key_state = xevent.xkey.state;
01570 
01571         char buffer[NUX_EVENT_TEXT_BUFFER_SIZE];
01572         Memset(m_pEvent->text, 0, NUX_EVENT_TEXT_BUFFER_SIZE);
01573 
01574         bool skip = false;
01575         if ((keysym == NUX_VK_BACKSPACE) ||
01576             (keysym == NUX_VK_DELETE) ||
01577             (keysym == NUX_VK_ESCAPE))
01578         {
01579           //temporary fix for TextEntry widget: filter some keys
01580          skip = true; 
01581         }
01582         
01583         int num_char_stored = XLookupString(&xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL);
01584         if (num_char_stored && (!skip))
01585         {
01586           Memcpy(m_pEvent->text, buffer, num_char_stored);
01587         }
01588 
01589         break;
01590       }
01591 
01592       case KeyRelease:
01593       {
01594         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: KeyRelease event.");
01595         KeyCode keycode = xevent.xkey.keycode;
01596         KeySym keysym = NoSymbol;
01597         keysym = XKeycodeToKeysym(xevent.xany.display, keycode, 0);
01598 
01599         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01600         m_pEvent->key_repeat_count = 0;
01601         m_pEvent->x11_keysym = keysym;
01602         m_pEvent->x11_keycode = xevent.xkey.keycode;
01603         m_pEvent->type = NUX_KEYUP;
01604         m_pEvent->x11_timestamp = xevent.xkey.time;
01605         m_pEvent->x11_key_state = xevent.xkey.state;
01606         break;
01607       }
01608 
01609       case ButtonPress:
01610       {
01611         if (_dnd_is_drag_source)
01612         {
01613           HandleDndDragSourceEvent(xevent);
01614           break;
01615         }
01616         
01617         m_pEvent->x = x_recalc;
01618         m_pEvent->y = y_recalc;
01619         m_pEvent->x_root = 0;
01620         m_pEvent->y_root = 0;
01621         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01622         MousePress(xevent, m_pEvent);
01623         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: ButtonPress event.");
01624         break;
01625       }
01626 
01627       case ButtonRelease:
01628       {
01629         if (_dnd_is_drag_source)
01630         {
01631           HandleDndDragSourceEvent(xevent);
01632           // fall through on purpose
01633         }
01634       
01635         m_pEvent->x = x_recalc;
01636         m_pEvent->y = y_recalc;
01637         m_pEvent->x_root = 0;
01638         m_pEvent->y_root = 0;
01639         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01640         MouseRelease(xevent, m_pEvent);
01641         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: ButtonRelease event.");
01642         break;
01643       }
01644 
01645       case MotionNotify:
01646       {
01647         if (_dnd_is_drag_source)
01648         {
01649           HandleDndDragSourceEvent(xevent);
01650           break;
01651         }
01652       
01653         m_pEvent->x = x_recalc;
01654         m_pEvent->y = y_recalc;
01655         m_pEvent->x_root = 0;
01656         m_pEvent->y_root = 0;
01657         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01658         MouseMove(xevent, m_pEvent);
01659         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: MotionNotify event.");
01660         break;
01661       }
01662 
01663       // Note: there is no WM_MOUSEENTER. WM_MOUSEENTER is equivalent to WM_MOUSEMOVE after a WM_MOUSELEAVE.
01664       case LeaveNotify:
01665       {
01666         if (xevent.xcrossing.mode != NotifyNormal || !local_from_server)
01667           break;
01668           
01669         m_pEvent->x = -1;
01670         m_pEvent->y = -1;
01671         m_pEvent->x_root = 0;
01672         m_pEvent->y_root = 0;
01673         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01674         m_pEvent->type = NUX_WINDOW_MOUSELEAVE;
01675         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: LeaveNotify event.");
01676         break;
01677       }
01678 
01679       case EnterNotify:
01680       {
01681         if (xevent.xcrossing.mode != NotifyNormal || !local_from_server)
01682           break;
01683           
01684         m_pEvent->x = x_recalc;
01685         m_pEvent->y = y_recalc;
01686         m_pEvent->x_root = 0;
01687         m_pEvent->y_root = 0;
01688         m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
01689         MouseMove(xevent, m_pEvent);
01690         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: EnterNotify event.");
01691         break;
01692       }
01693       
01694       case SelectionRequest:
01695       {
01696         if (xevent.xselectionrequest.selection == XInternAtom(xevent.xany.display, "XdndSelection", false))
01697            HandleDndSelectionRequest(xevent);
01698         break;
01699       }
01700       
01701       case MapNotify:
01702       {
01703         if (xevent.xmap.window == _dnd_source_window)
01704         {
01705           DrawDndSourceWindow();
01706         } 
01707         else
01708         {
01709           //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: MapNotify event.");
01710           m_pEvent->type = NUX_WINDOW_MAP;
01711         }
01712         
01713         break;
01714       }
01715 
01716       case UnmapNotify:
01717       {
01718         //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: UnmapNotify event.");
01719         m_pEvent->type = NUX_WINDOW_UNMAP;
01720         break;
01721       }
01722 
01723       case ClientMessage:
01724       {
01725         //if(foreign)
01726         //  break;
01727 
01728         if ((xevent.xclient.format == 32) && ((xevent.xclient.data.l[0]) == static_cast<long> (m_WMDeleteWindow)))
01729         {
01730           m_pEvent->type = NUX_TERMINATE_APP;
01731           //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: ClientMessage event: Close Application.");
01732         }
01733         
01734         if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndPosition", false))
01735         {
01736           HandleXDndPosition(xevent, m_pEvent);
01737         }
01738         else if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndEnter", false))
01739         {
01740           HandleXDndEnter(xevent);
01741           m_pEvent->type = NUX_DND_ENTER_WINDOW;
01742         }
01743         else if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndStatus", false))
01744         {
01745           HandleXDndStatus(xevent);
01746           m_pEvent->type = NUX_NO_EVENT;
01747         }
01748         else if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndLeave", false))
01749         {
01750           HandleXDndLeave(xevent);
01751           m_pEvent->type = NUX_DND_LEAVE_WINDOW;
01752         }
01753         else if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndDrop", false))
01754         {
01755           HandleXDndDrop(xevent, m_pEvent);
01756         }
01757         else if (xevent.xclient.message_type == XInternAtom(xevent.xany.display, "XdndFinished", false))
01758         {
01759           HandleXDndFinished(xevent);
01760           m_pEvent->type = NUX_NO_EVENT;
01761         }
01762         
01763         break;
01764       }
01765     }
01766   }
01767   
01768   void GraphicsDisplay::HandleDndSelectionRequest(XEvent xevent)
01769   {
01770     XEvent result;
01771     
01772     if (!_dnd_source_funcs.get_data_for_type)
01773       return;
01774 
01775     result.xselection.type = SelectionNotify;
01776     result.xselection.display = xevent.xany.display;
01777     result.xselection.requestor = xevent.xselectionrequest.requestor;
01778     result.xselection.selection = xevent.xselectionrequest.selection;
01779     result.xselection.target = xevent.xselectionrequest.target;
01780     result.xselection.property = xevent.xselectionrequest.property;
01781     result.xselection.time = xevent.xselectionrequest.time;
01782 
01783     int format, size;
01784     char *type = XGetAtomName(xevent.xany.display, xevent.xselectionrequest.target);
01785     const unsigned char *data = (const unsigned char *) (*(_dnd_source_funcs.get_data_for_type)) (type, &size, &format, _dnd_source_data);
01786     
01787     XFree(type);
01788     
01789     XChangeProperty(xevent.xany.display,  
01790                      xevent.xselectionrequest.requestor, 
01791                      xevent.xselectionrequest.property,
01792                      xevent.xselectionrequest.target, 
01793                      format, 
01794                      PropModeReplace, 
01795                      data,
01796                      size);
01797     XSendEvent(xevent.xany.display, xevent.xselectionrequest.requestor, False, 0, &result);
01798   }
01799   
01800   gboolean
01801   GraphicsDisplay::OnDragEndTimeout(gpointer data)
01802   {
01803     static_cast<GraphicsDisplay*> (data)->EndDndDrag(DNDACTION_NONE);
01804     
01805     return false;
01806   }
01807   
01808   void GraphicsDisplay::HandleDndDragSourceEvent(XEvent xevent)
01809   {
01810     if (_dnd_source_drop_sent)
01811       return;
01812 
01813     switch(xevent.type)
01814     {
01815       case ButtonPress:
01816         break;
01817 
01818       case ButtonRelease:
01819       
01820         if (!_dnd_source_target_window || !_dnd_source_target_accepts_drop)
01821         {
01822           SetDndSourceTargetWindow(None);
01823           EndDndDrag(DNDACTION_NONE);
01824         }
01825         else
01826         {
01827           SendDndSourceDrop(_dnd_source_target_window, xevent.xbutton.time);
01828           _dnd_source_drop_sent = true;
01829 
01830           UngrabPointer(this);
01831           _dnd_source_grab_active = false;
01832 
01833           g_timeout_add(1000, &GraphicsDisplay::OnDragEndTimeout, this);
01834         }
01835         break;
01836 
01837       case MotionNotify:
01838         Window target = GetDndTargetWindowForPos(xevent.xmotion.x_root, xevent.xmotion.y_root);
01839         
01840         if (_dnd_source_window)
01841         {
01842           Window rw;
01843           int x, y;
01844           unsigned int w, h, b, d;
01845           XGetGeometry(GetX11Display(), _dnd_source_window, &rw, &x, &y, &w, &h, &b, &d);
01846           XMoveWindow(GetX11Display(), _dnd_source_window, xevent.xmotion.x_root - (w / 2), xevent.xmotion.y_root - (h / 2));
01847         }
01848         
01849         if (target != _dnd_source_target_window)
01850           SetDndSourceTargetWindow(target);
01851         
01852         if (_dnd_source_target_window)
01853           SendDndSourcePosition(_dnd_source_target_window, xevent.xmotion.x_root, xevent.xmotion.y_root, xevent.xmotion.time);
01854         
01855         break;
01856     }
01857   }
01858   
01859   void GraphicsDisplay::SendDndSourceDrop(Window target, Time time)
01860   {
01861     XClientMessageEvent drop_message;
01862     drop_message.window = target;
01863     drop_message.format = 32;
01864     drop_message.type = ClientMessage;
01865 
01866     drop_message.message_type = XInternAtom(GetX11Display(), "XdndDrop", false);
01867     drop_message.data.l[0] = _dnd_source_window;
01868     drop_message.data.l[1] = 0;
01869     drop_message.data.l[2] = time;
01870     
01871     XSendEvent(GetX11Display(), target, False, NoEventMask, (XEvent *) &drop_message);
01872   }
01873   
01874   void GraphicsDisplay::SendDndSourcePosition(Window target, int x, int y, Time time)
01875   {
01876     XClientMessageEvent position_message;
01877     position_message.window = target;
01878     position_message.format = 32;
01879     position_message.type = ClientMessage;
01880 
01881     position_message.message_type = XInternAtom(GetX11Display(), "XdndPosition", false);
01882     position_message.data.l[0] = _dnd_source_window;
01883     position_message.data.l[1] = 0;
01884     position_message.data.l[2] = (x << 16) + y;
01885     position_message.data.l[3] = time;
01886     position_message.data.l[4] = XInternAtom(GetX11Display(), "XdndActionCopy", false); //fixme
01887     
01888     XSendEvent(GetX11Display(), target, False, NoEventMask, (XEvent *) &position_message);
01889   }
01890   
01891   void GraphicsDisplay::SendDndSourceEnter(Window target)
01892   {
01893     XClientMessageEvent enter_message;
01894     enter_message.window = target;
01895     enter_message.format = 32;
01896     enter_message.type = ClientMessage;
01897 
01898     enter_message.message_type = XInternAtom(GetX11Display(), "XdndEnter", false);
01899     enter_message.data.l[0] = _dnd_source_window;
01900     enter_message.data.l[1] = (((unsigned long) xdnd_version) << 24) + 1; // mark that we have set the atom list
01901     enter_message.data.l[2] = None; // fixme, these should contain the first 3 atoms
01902     enter_message.data.l[3] = None;
01903     enter_message.data.l[4] = None;
01904     
01905     XSendEvent(GetX11Display(), target, False, NoEventMask, (XEvent *) &enter_message);
01906   }
01907   
01908   void GraphicsDisplay::SendDndSourceLeave(Window target)
01909   {
01910     XClientMessageEvent leave_message;
01911     leave_message.window = target;
01912     leave_message.format = 32;
01913     leave_message.type = ClientMessage;
01914 
01915     leave_message.message_type = XInternAtom(GetX11Display(), "XdndLeave", false);
01916     leave_message.data.l[0] = _dnd_source_window;
01917     leave_message.data.l[1] = 0; // flags
01918     
01919     XSendEvent(GetX11Display(), target, False, NoEventMask, (XEvent *) &leave_message);
01920   }
01921   
01922   void GraphicsDisplay::SetDndSourceTargetWindow(Window target)
01923   {
01924     if (target == _dnd_source_target_window || !_dnd_source_grab_active)
01925       return;
01926     
01927     if (_dnd_source_target_window)
01928       SendDndSourceLeave(_dnd_source_target_window);
01929     
01930     if (target)
01931       SendDndSourceEnter(target);
01932     
01933     _dnd_source_target_accepts_drop = false;
01934     _dnd_source_target_window = target;
01935   }
01936   
01937   // This function hilariously inefficient
01938   Window GraphicsDisplay::GetDndTargetWindowForPos(int pos_x, int pos_y)
01939   {
01940     Window result = 0;
01941     
01942     Window root_window = DefaultRootWindow(GetX11Display());
01943     
01944     int cur_x, cur_y;
01945     XTranslateCoordinates(GetX11Display(), root_window, root_window, pos_x, pos_y, &cur_x, &cur_y, &result);
01946     
01947     if (!result)
01948       return result;
01949       
01950     Window src = root_window;
01951     while (true)
01952     {
01953       // translate into result space
01954       Window child;
01955       int new_x, new_y;
01956       XTranslateCoordinates(GetX11Display(), src, result, cur_x, cur_y, &new_x, &new_y, &child);
01957       
01958       cur_x = new_x;
01959       cur_y = new_y;
01960     
01961       // Check if our current window is XdndAware
01962       Atom type = 0;
01963       int format;
01964       unsigned long n, a;
01965       unsigned char *data = 0;
01966       if (XGetWindowProperty(GetX11Display(), result, XInternAtom(GetX11Display(), "XdndAware", false), 0, 1, False,
01967                              XA_ATOM, &type, &format, &n, &a, &data) == Success) 
01968       {
01969         long dnd_version = 0;
01970         if (data)
01971         {
01972           dnd_version = ((Atom *)data)[0];
01973 
01974           if (dnd_version < 5)
01975             result = 0; // dont have v5? go away until I implement this :)
01976 
01977           XFree(data);
01978           break; // result is the winner
01979         }
01980       }
01981       
01982       // Find child window if any and ignore translation
01983       XTranslateCoordinates(GetX11Display(), result, result, cur_x, cur_y, &new_x, &new_y, &child);
01984       
01985       // there is no child window, stop
01986       if (!child)
01987       {
01988         result = 0;
01989         break;
01990       }
01991       
01992       src = result;
01993       result = child;
01994     }
01995     
01996     return result;
01997   }
01998   
01999   void GraphicsDisplay::EndDndDrag(DndAction action)
02000   {
02001     Display *display = GetX11Display();
02002     
02003     if (_dnd_source_funcs.drag_finished)
02004       (*(_dnd_source_funcs.drag_finished)) (action, _dnd_source_data);
02005     _dnd_is_drag_source = false;
02006     
02007     if (_dnd_source_window)
02008       XDestroyWindow(display, _dnd_source_window);
02009     _dnd_source_window = 0;
02010     
02011     GrabDndSelection(display, None, CurrentTime);
02012     UngrabPointer(this);
02013     _dnd_source_grab_active = false;
02014     
02015     _dnd_source_funcs.get_drag_image = 0;
02016     _dnd_source_funcs.get_drag_types = 0;
02017     _dnd_source_funcs.get_data_for_type = 0;
02018     _dnd_source_funcs.drag_finished = 0;
02019     
02020     _dnd_source_data = 0;
02021   }
02022   
02023   void GraphicsDisplay::DrawDndSourceWindow()
02024   {
02025     if (!_dnd_source_funcs.get_drag_image || !_dnd_source_data || !_dnd_source_window)
02026       return;
02027     
02028     Display *display = GetX11Display();
02029     NBitmapData *data = (*(_dnd_source_funcs.get_drag_image)) (_dnd_source_data);
02030     XImage *image;
02031     
02032     image = XGetImage(display, _dnd_source_window, 0, 0, data->GetWidth(), data->GetHeight(), AllPlanes, ZPixmap);
02033     GC gc = XCreateGC(display, _dnd_source_window, 0, NULL);
02034     
02035     BitmapFormat format = data->GetFormat();
02036     
02037     /* draw some shit */
02038     if (data->IsTextureData())
02039     {
02040       ImageSurface surface = data->GetSurface(0);
02041       
02042       int x, y;
02043       for (y = 0; y < data->GetHeight(); y++)
02044       {
02045         for (x = 0; x < data->GetWidth(); x++)
02046         {
02047           long pixel = (long) surface.Read(x, y);
02048          long a;
02049          
02050          if (format  == BITFMT_R8G8B8)
02051            a = 255;
02052          else
02053            a = ((pixel >> 24) & 0xff);
02054           long r = (((pixel >> 16) & 0xff) * a) / 255;
02055           long g = (((pixel >> 8)  & 0xff) * a) / 255;
02056           long b = (((pixel >> 0)  & 0xff) * a) / 255;
02057           
02058           long result_pixel = (a << 24) | (b << 16) | (g << 8) | (r << 0);
02059           
02060           XPutPixel(image, x, y, result_pixel);
02061         }
02062       }
02063     }
02064     
02065     /* upload */
02066     XPutImage(display, _dnd_source_window, gc, image, 0, 0, 0, 0, data->GetWidth(), data->GetHeight());
02067     
02068     XDestroyImage(image);
02069   }
02070   
02071   void GraphicsDisplay::StartDndDrag(const DndSourceFuncs &funcs, void *user_data)
02072   {
02073     Display *display = GetX11Display();
02074     
02075     if (!display || !GrabPointer(NULL, this, true))
02076     {
02077       if (funcs.drag_finished)
02078         (*(funcs.drag_finished)) (DNDACTION_NONE, user_data);
02079       return;
02080     }
02081   
02082     _dnd_source_funcs = funcs;
02083     _dnd_source_data = user_data;
02084     _dnd_source_grab_active = true;
02085     _dnd_source_drop_sent = false;
02086     
02087     int width = 100, height = 100;
02088     if (_dnd_source_funcs.get_drag_image)
02089     {
02090       NBitmapData *data = (*(_dnd_source_funcs.get_drag_image)) (_dnd_source_data);
02091       width = data->GetWidth();
02092       height = data->GetHeight();
02093       
02094       delete data;
02095     }
02096     
02097     Window root = DefaultRootWindow(display);
02098     XVisualInfo vinfo;
02099     if (!XMatchVisualInfo(display, XDefaultScreen(display), 32, TrueColor, &vinfo))
02100     {
02101       printf("Could not match visual info\n");
02102       EndDndDrag(DNDACTION_NONE);
02103       return;
02104     }
02105     
02106     XSetWindowAttributes attribs;
02107     attribs.override_redirect = true;
02108     attribs.background_pixel = 0;
02109     attribs.border_pixel = 0;
02110     attribs.colormap = XCreateColormap(display, root, vinfo.visual, AllocNone);
02111     
02112     unsigned long attrib_mask = CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap;
02113     // make a window which will serve two purposes:
02114     // First this window will be used to display feedback to the user
02115     // Second this window will grab and own the XdndSelection Selection
02116     _dnd_source_window = XCreateWindow(display, 
02117                                         root, 
02118                                         -1000, -1000, 
02119                                         width, height, 
02120                                         0,
02121                                         vinfo.depth,
02122                                         InputOutput,
02123                                         vinfo.visual, 
02124                                         attrib_mask,
02125                                         &attribs);
02126                                         
02127     XSelectInput(display, _dnd_source_window, StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask);
02128     XMapRaised(display, _dnd_source_window);
02129     
02130     Atom atom_type[1];
02131     atom_type[0] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DND", false);
02132     XChangeProperty(display, _dnd_source_window, XInternAtom(display, "_NET_WM_WINDOW_TYPE", false), 
02133                      XA_ATOM, 32, PropModeReplace, (unsigned char*) atom_type, 1);
02134 
02135     Atom data[32];
02136     int     i = 0;
02137     data[i++] = XInternAtom(display, "_NET_WM_STATE_STICKY", false);
02138     data[i++] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", false);
02139     data[i++] = XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", false);
02140     data[i++] = XInternAtom(display, "_NET_WM_STATE_ABOVE", false);
02141 
02142     XChangeProperty(display, _dnd_source_window, XInternAtom(display, "_NET_WM_STATE", 0),
02143                  XA_ATOM, 32, PropModeReplace,
02144                  (unsigned char *) data, i);
02145 
02146     Region region = XCreateRegion();
02147     if (region)
02148     {
02149       XShapeCombineRegion(display, _dnd_source_window, ShapeInput, 0, 0, region, ShapeSet);
02150       XDestroyRegion(region);
02151     }
02152     
02153     XFlush(display);
02154     
02155     _dnd_is_drag_source = true;
02156     _dnd_source_target_window = 0;
02157     
02158     
02159     std::list<const char *> types = _dnd_source_funcs.get_drag_types(_dnd_source_data);
02160     std::list<const char *>::iterator it;
02161     
02162     Atom type_atoms[types.size()];
02163     
02164     i = 0;
02165     for (it = types.begin(); it != types.end(); it++)
02166     {
02167       type_atoms[i] = XInternAtom(display, *it, false);
02168       i++;
02169     }
02170     
02171     XChangeProperty(display, _dnd_source_window, XInternAtom(display, "XdndTypeList", false),
02172                     XA_ATOM, 32, PropModeReplace, (unsigned char *)type_atoms, i);
02173     
02174     GrabDndSelection(display, _dnd_source_window, CurrentTime);
02175   }
02176   
02177   bool GraphicsDisplay::GrabDndSelection(Display *display, Window window, Time time)
02178   {
02179     XSetSelectionOwner(GetX11Display(), XInternAtom(display, "XdndSelection", false), window, time);
02180     Window owner = XGetSelectionOwner(display, XInternAtom(display, "XdndSelection", false));
02181     return owner == window;
02182   }
02183   
02184   void GraphicsDisplay::SendDndStatus(bool accept, DndAction action, Rect region)
02185   {
02186     if (!_drag_window || !_drag_display || !_drag_source)
02187       return;
02188   
02189     Atom a;
02190     switch(action)
02191     {
02192       case DNDACTION_MOVE:
02193         a = XInternAtom(_drag_display, "XdndActionMove", false);
02194         break;
02195       case DNDACTION_COPY:
02196         a = XInternAtom(_drag_display, "XdndActionCopy", false);
02197         break;
02198       case DNDACTION_PRIVATE:
02199         a = XInternAtom(_drag_display, "XdndActionPrivate", false);
02200         break;
02201       case DNDACTION_LINK:
02202         a = XInternAtom(_drag_display, "XdndActionLink", false);
02203         break;
02204       case DNDACTION_ASK:
02205         a = XInternAtom(_drag_display, "XdndActionAsk", false);
02206         break;
02207       default:
02208         a = None;
02209         break;
02210     }
02211     SendXDndStatus(_drag_display, _drag_window, _drag_source, accept, a, region);
02212   }
02213   
02214   void GraphicsDisplay::SendDndFinished(bool accepted, DndAction performed_action)
02215   {
02216     if (!_drag_window || !_drag_display || !_drag_source)
02217       return;
02218     
02219     Atom a;
02220     switch(performed_action)
02221     {
02222       case DNDACTION_MOVE:
02223         a = XInternAtom(_drag_display, "XdndActionMove", false);
02224         break;
02225       case DNDACTION_COPY:
02226         a = XInternAtom(_drag_display, "XdndActionCopy", false);
02227         break;
02228       case DNDACTION_PRIVATE:
02229         a = XInternAtom(_drag_display, "XdndActionPrivate", false);
02230         break;
02231       case DNDACTION_LINK:
02232         a = XInternAtom(_drag_display, "XdndActionLink", false);
02233         break;
02234       case DNDACTION_ASK:
02235         a = XInternAtom(_drag_display, "XdndActionAsk", false);
02236         break;
02237       default:
02238         a = None;
02239         break;
02240     }
02241     SendXDndFinished(_drag_display, _drag_window, _drag_source, accepted, a);
02242   }
02243   
02244   std::list<char *> GraphicsDisplay::GetDndMimeTypes()
02245   {
02246     std::list<char *> result;
02247     
02248     if (!_drag_display)
02249       return result;
02250     
02251     Atom a;
02252     int i;
02253     for (i = 0; i <= _xdnd_max_type; i++)
02254     {
02255       a = _xdnd_types[i];
02256       
02257       if (!a)
02258         break;
02259       
02260       char *name = XGetAtomName(_drag_display, a);
02261       result.push_back(g_strdup(name));
02262       XFree(name);
02263     }
02264     return result;
02265   }
02266   
02267   char * GraphicsDisplay::GetDndData(char *property)
02268   {
02269     if (_dnd_is_drag_source)
02270     {
02271       int size, format;
02272       return g_strdup((*(_dnd_source_funcs.get_data_for_type)) (property, &size, &format, _dnd_source_data));
02273     }
02274     else
02275     {
02276       Atom a = XInternAtom(_drag_display, property, false);
02277       return GetXDndData(_drag_display, _drag_window, a, _drag_drop_timestamp);
02278     }
02279   }
02280   
02281   void GraphicsDisplay::SendXDndStatus(Display *display, Window source, Window target, bool accept, Atom action, Rect box)
02282   {
02283     XClientMessageEvent response;
02284     response.window = target;
02285     response.format = 32;
02286     response.type = ClientMessage;
02287 
02288     response.message_type = XInternAtom(display, "XdndStatus", false);
02289     response.data.l[0] = source;
02290     response.data.l[1] = 0; // flags
02291     response.data.l[2] = (box.x << 16) | box.y; // x, y
02292     response.data.l[3] = (box.width << 16) | box.height; // w, h
02293     
02294     if (accept)
02295     {
02296       response.data.l[4] = action;
02297       response.data.l[1] |= 1 << 0;
02298     }
02299     else
02300     {
02301       response.data.l[4] = None;
02302     }
02303     
02304     XSendEvent(display, target, False, NoEventMask, (XEvent *) &response);
02305   }
02306   
02307   void GraphicsDisplay::HandleXDndPosition(XEvent event, Event* nux_event)
02308   {
02309     const unsigned long *l = (const unsigned long *)event.xclient.data.l;
02310   
02311     int x = (l[2] & 0xffff0000) >> 16;
02312     int y = l[2] & 0x0000ffff;
02313     
02314     int x_recalc = 0;
02315     int y_recalc = 0;
02316 
02317     RecalcXYPosition(x, y, x_recalc, y_recalc);
02318 
02319     nux_event->type = NUX_DND_MOVE;
02320     nux_event->x = x_recalc;
02321     nux_event->y = y_recalc;
02322 
02323     // Store the last DND position;
02324     _last_dnd_position = Point(x_recalc, y_recalc);
02325   }
02326   
02327   void GraphicsDisplay::HandleXDndEnter(XEvent event)
02328   {
02329     const long *l = event.xclient.data.l;
02330     int version = (int)(((unsigned long)(l[1])) >> 24);
02331     
02332     if (version > xdnd_version)
02333       return;
02334     
02335     _drag_source = l[0];
02336     _drag_window = event.xany.window;
02337     _drag_display = event.xany.display;
02338     
02339     int j = 0;
02340     if (l[1] & 1) 
02341     {
02342       unsigned char *retval = 0;
02343       unsigned long n, a;
02344       int f;
02345       Atom type = None;
02346 
02347       XGetWindowProperty(_drag_display, _drag_source, XInternAtom(_drag_display, "XdndTypeList", false), 0,
02348                          _xdnd_max_type, False, XA_ATOM, &type, &f, &n, &a, &retval);
02349 
02350       if (retval) 
02351       {
02352         Atom *data = (Atom *)retval;
02353         for (; j < _xdnd_max_type && j < (int)n; j++)
02354           _xdnd_types[j] = data[j];
02355         
02356         XFree((uchar*)data);
02357       }
02358     } 
02359     else 
02360     {
02361       // xdnd supports up to 3 types without using XdndTypelist
02362       int i;
02363       for (i = 2; i < 5; i++) 
02364         _xdnd_types[j++] = l[i];
02365     }
02366     
02367     _xdnd_types[j] = 0;
02368   }
02369   
02370   void GraphicsDisplay::HandleXDndStatus(XEvent event)
02371   {
02372     const unsigned long *l = (const unsigned long *)event.xclient.data.l;
02373     
02374     // should protect against stray messages
02375     if (l[1] & 1)
02376       _dnd_source_target_accepts_drop = true;
02377     else
02378       _dnd_source_target_accepts_drop = false;
02379   }
02380   
02381   void GraphicsDisplay::HandleXDndLeave(XEvent event)
02382   {
02383     // reset the key things
02384     _xdnd_types[0] = 0;
02385     _drag_source = 0;
02386     _drag_window = 0;
02387     _drag_drop_timestamp = 0;
02388   }
02389   
02390   bool GraphicsDisplay::GetXDndSelectionEvent(Display *display, Window target, Atom property, long time, XEvent *result, int attempts)
02391   {
02392     // request the selection
02393     XConvertSelection(display,
02394                        XInternAtom(display, "XdndSelection", false),
02395                        property,
02396                        XInternAtom(display, "XdndSelection", false),
02397                        target,
02398                        time);
02399     XFlush(display);
02400     
02401     int i;
02402     for (i = 0; i < attempts; i++)
02403     {
02404       if (XCheckTypedWindowEvent(display, target, SelectionNotify, result))
02405       {
02406         return true;
02407       }
02408       
02409       XFlush(display);
02410       
02411       struct timeval usleep_tv;
02412       usleep_tv.tv_sec = 0;
02413       usleep_tv.tv_usec = 50000;
02414       select(0, 0, 0, 0, &usleep_tv);
02415     }
02416     
02417     return false;
02418   }
02419   
02420   void GraphicsDisplay::SendXDndFinished(Display *display, Window source, Window target, bool result, Atom action)
02421   {
02422     XClientMessageEvent response;
02423     response.window = target;
02424     response.format = 32;
02425     response.type = ClientMessage;
02426 
02427     response.message_type = XInternAtom(display, "XdndFinished", false);
02428     response.data.l[0] = source;
02429     response.data.l[1] = result ? 1 : 0; // flags
02430     response.data.l[2] = action; // action
02431     
02432     XSendEvent(display, target, False, NoEventMask, (XEvent *) &response);
02433   }
02434   
02435   char * GraphicsDisplay::GetXDndData(Display *display, Window requestor, Atom property, long time)
02436   {
02437     char *result = 0;
02438     XEvent xevent;
02439     if (GetXDndSelectionEvent(display, requestor, property, time, &xevent, 50))
02440     {
02441       unsigned char *buffer = NULL;
02442       Atom type;
02443 
02444       unsigned long  bytes_left; // bytes_after
02445       unsigned long  length;     // nitems
02446       int   format;
02447       
02448       if (XGetWindowProperty(display, 
02449                              requestor, 
02450                              XInternAtom(display, "XdndSelection", false), 
02451                              0, 
02452                              10000,
02453                              False,
02454                              AnyPropertyType, 
02455                              &type, 
02456                              &format, 
02457                              &length, 
02458                              &bytes_left, 
02459                              &buffer) == Success)
02460       {
02461         result = g_strdup((char *) buffer);
02462         XFree(buffer);
02463       }
02464     }
02465     
02466     return result;
02467   }
02468   
02469   void GraphicsDisplay::HandleXDndDrop(XEvent event, Event *nux_event)
02470   {
02471     const long *l = event.xclient.data.l;
02472     _drag_drop_timestamp = l[2];
02473     
02474     nux_event->type = NUX_DND_DROP;
02475 
02476     // The drop does not provide(x, y) coordinates of the location of the drop. Use the last DND position.
02477     nux_event->x = _last_dnd_position.x;
02478     nux_event->y = _last_dnd_position.y;
02479   }
02480   
02481   void GraphicsDisplay::HandleXDndFinished(XEvent event)
02482   {
02483     const unsigned long *l = (const unsigned long *)event.xclient.data.l;
02484     
02485     if (l[0] != _dnd_source_target_window)
02486       return;
02487     
02488     bool accepted = l[1] & 1;
02489     DndAction result = DNDACTION_NONE;
02490 
02491     if (accepted)
02492     {
02493       if (l[2] == XInternAtom(GetX11Display(), "XdndActionCopy", false))
02494         result = DNDACTION_COPY;
02495       else if (l[2] == XInternAtom(GetX11Display(), "XdndActionAsk", false))
02496         result = DNDACTION_ASK;
02497       else if (l[2] == XInternAtom(GetX11Display(), "XdndActionLink", false))
02498         result = DNDACTION_LINK;
02499       else if (l[2] == XInternAtom(GetX11Display(), "XdndActionMove", false))
02500         result = DNDACTION_MOVE;
02501       else if (l[2] == XInternAtom(GetX11Display(), "XdndActionPrivate", false))
02502         result = DNDACTION_PRIVATE;  
02503     }
02504     
02505     EndDndDrag(result);
02506   }
02507   
02508   void GraphicsDisplay::InitGlobalGrabWindow()
02509   {
02510     Display *display = GetX11Display();
02511 
02512     XSetWindowAttributes attribs;
02513     attribs.override_redirect = True;
02514     _global_grab_window = XCreateWindow(display,
02515                                          DefaultRootWindow(display),
02516                                          -100, -100,                     // X, Y
02517                                          1, 1,                           // Width, Height
02518                                          0,                              // Border
02519                                          0,                              // Depth
02520                                          InputOnly,                      // Class
02521                                          CopyFromParent,                 // Visual
02522                                          CWOverrideRedirect,
02523                                          &attribs);
02524     
02525     XSelectInput(display, _global_grab_window, StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask);
02526     XMapRaised(display, _global_grab_window);
02527     
02528     Atom atom_type[1];
02529     atom_type[0] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_UTILITY", false);
02530     XChangeProperty(display, _global_grab_window, XInternAtom(display, "_NET_WM_WINDOW_TYPE", false), 
02531                      XA_ATOM, 32, PropModeReplace, (unsigned char*) atom_type, 1);
02532 
02533     Atom data[32];
02534     int     i = 0;
02535     data[i++] = XInternAtom(display, "_NET_WM_STATE_STICKY", false);
02536     data[i++] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", false);
02537     data[i++] = XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", false);
02538     data[i++] = XInternAtom(display, "_NET_WM_STATE_ABOVE", false);
02539 
02540     XChangeProperty(display, _global_grab_window, XInternAtom(display, "_NET_WM_STATE", 0),
02541                  XA_ATOM, 32, PropModeReplace,
02542                  (unsigned char *) data, i);
02543   }
02544 
02545   bool GraphicsDisplay::GrabPointer(GrabReleaseCallback callback, void *data, bool replace_existing)
02546   {
02547     if (_global_pointer_grab_active)
02548     {
02549       if (!replace_existing || _dnd_source_grab_active) // prevent grabbing over DND grabs
02550         return false;
02551       
02552       if (_global_pointer_grab_callback)
02553         (*_global_pointer_grab_callback) (true, _global_pointer_grab_data);
02554     }
02555     
02556     if (!_global_pointer_grab_active)
02557     {
02558       int result = XGrabPointer(GetX11Display(), 
02559                                 _global_grab_window, 
02560                                 True, 
02561                                    ButtonPressMask | 
02562                                    ButtonReleaseMask | 
02563                                    PointerMotionMask | 
02564                                    ButtonMotionMask , 
02565                                 GrabModeAsync,
02566                                 GrabModeAsync, 
02567                                 None,
02568                                 None, 
02569                                 CurrentTime);
02570                                       
02571       if (result == GrabSuccess)
02572         _global_pointer_grab_active = true;
02573     }
02574     
02575     if (_global_pointer_grab_active)
02576     {
02577       _global_pointer_grab_callback = callback;
02578       _global_pointer_grab_data = data;
02579     }
02580     
02581     return _global_pointer_grab_active;
02582   }
02583   
02584   bool GraphicsDisplay::UngrabPointer(void *data)
02585   {
02586     if (data != _global_pointer_grab_data || !_global_pointer_grab_active)
02587       return false;
02588     
02589     _global_pointer_grab_active = false;
02590     XUngrabPointer(GetX11Display(), CurrentTime);
02591     
02592     if (_global_pointer_grab_callback)
02593       (*_global_pointer_grab_callback) (false, data);
02594     
02595     _global_pointer_grab_data = false;
02596     _global_pointer_grab_callback = 0;
02597     
02598     return true;
02599   }
02600   
02601   bool GraphicsDisplay::PointerIsGrabbed()
02602   {
02603     return _global_pointer_grab_active;  
02604   }
02605 
02606   bool GraphicsDisplay::GrabKeyboard(GrabReleaseCallback callback, void *data, bool replace_existing)
02607   {
02608     if (_global_keyboard_grab_active)
02609     {
02610       if (!replace_existing)
02611         return false; // fail case
02612       
02613       if (_global_keyboard_grab_callback)
02614         (*_global_keyboard_grab_callback) (true, _global_keyboard_grab_data);
02615     }
02616     
02617     if (!_global_keyboard_grab_active)
02618     {
02619       int result = XGrabKeyboard(GetX11Display(), 
02620                                 _global_grab_window, 
02621                                 True, 
02622                                 GrabModeAsync,
02623                                 GrabModeAsync, 
02624                                 CurrentTime);
02625                                       
02626       if (result == GrabSuccess)
02627         _global_keyboard_grab_active = true;
02628     }
02629     
02630     if (_global_keyboard_grab_active)
02631     {
02632       _global_keyboard_grab_callback = callback;
02633       _global_keyboard_grab_data = data;
02634     }
02635     
02636     return _global_keyboard_grab_active;
02637   }
02638   
02639   bool GraphicsDisplay::UngrabKeyboard(void *data)
02640   {
02641     if (data != _global_keyboard_grab_data || !_global_keyboard_grab_active)
02642       return false;
02643     
02644     _global_keyboard_grab_active = false;
02645     XUngrabKeyboard(GetX11Display(), CurrentTime);
02646     
02647     if (_global_keyboard_grab_callback)
02648       (*_global_keyboard_grab_callback) (false, data);
02649     
02650     _global_keyboard_grab_data = false;
02651     _global_keyboard_grab_callback = 0;
02652     
02653     return true;
02654   }
02655   
02656   bool GraphicsDisplay::KeyboardIsGrabbed()
02657   {
02658     return _global_keyboard_grab_active;  
02659   }
02660 
02661   void GraphicsDisplay::ShowWindow()
02662   {
02663     XMapRaised(m_X11Display, m_X11Window);
02664   }
02665 
02666   void GraphicsDisplay::HideWindow()
02667   {
02668     XUnmapWindow(m_X11Display, m_X11Window);
02669   }
02670 
02671   bool GraphicsDisplay::IsWindowVisible()
02672   {
02673     XWindowAttributes window_attributes_return;
02674     XGetWindowAttributes(m_X11Display, m_X11Window, &window_attributes_return);
02675 
02676     if (window_attributes_return.map_state == IsViewable)
02677     {
02678       return true;
02679     }
02680     return false;
02681   }
02682 
02683   void GraphicsDisplay::EnterMaximizeWindow()
02684   {
02685 
02686   }
02687 
02688   void GraphicsDisplay::ExitMaximizeWindow()
02689   {
02690 
02691   }
02692 
02693   void GraphicsDisplay::SetWindowTitle(const char *Title)
02694   {
02695     XStoreName(m_X11Display, m_X11Window, TCHAR_TO_ANSI(Title));
02696   }
02697 
02698   bool GraphicsDisplay::HasVSyncSwapControl() const
02699   {
02700     return GetGpuDevice()->GetGpuInfo().Support_EXT_Swap_Control();
02701   }
02702 
02703   void GraphicsDisplay::EnableVSyncSwapControl()
02704   {
02705 #ifndef NUX_OPENGLES_20
02706     if (GetGpuDevice()->GetGpuInfo().Support_EXT_Swap_Control())
02707     {
02708       GLXDrawable drawable = glXGetCurrentDrawable();
02709       glXSwapIntervalEXT(m_X11Display, drawable, 1);
02710     }
02711 #endif
02712   }
02713 
02714   void GraphicsDisplay::DisableVSyncSwapControl()
02715   {
02716 #ifndef NUX_OPENGLES_20
02717     if (GetGpuDevice()->GetGpuInfo().Support_EXT_Swap_Control())
02718     {
02719       GLXDrawable drawable = glXGetCurrentDrawable();
02720       if (drawable != None)
02721       {
02722         glXSwapIntervalEXT(m_X11Display, drawable, 0);
02723       }
02724     }
02725 #endif
02726   }
02727 
02728   float GraphicsDisplay::GetFrameTime() const
02729   {
02730     return m_FrameTime;
02731   }
02732 
02733   void GraphicsDisplay::ResetFrameTime()
02734   {
02735     m_Timer.Reset();
02736   }
02737 
02738   void GraphicsDisplay::PauseThreadGraphicsRendering()
02739   {
02740     m_PauseGraphicsRendering = true;
02741     MakeGLContextCurrent();
02742   }
02743 
02744   bool GraphicsDisplay::IsPauseThreadGraphicsRendering() const
02745   {
02746     return m_PauseGraphicsRendering;
02747   }
02748 
02749 }