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