nux-1.16.0
|
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