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