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