1 /* 2 * Copyright (c) 2002-2010 LWJGL Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'LWJGL' nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.lwjgl.opengl; 33 34 /** 35 * This is the Display implementation interface. Display delegates 36 * to implementors of this interface. There is one DisplayImplementation 37 * for each supported platform. 38 * @author elias_naur 39 */ 40 41 import java.awt.Canvas; 42 import java.awt.event.FocusListener; 43 import java.awt.event.FocusEvent; 44 45 import java.io.BufferedReader; 46 import java.io.IOException; 47 import java.io.InputStreamReader; 48 import java.nio.ByteOrder; 49 import java.nio.ByteBuffer; 50 import java.nio.FloatBuffer; 51 import java.nio.IntBuffer; 52 import java.lang.reflect.InvocationTargetException; 53 54 import org.lwjgl.BufferUtils; 55 import org.lwjgl.LWJGLException; 56 import org.lwjgl.LWJGLUtil; 57 import org.lwjgl.MemoryUtil; 58 import org.lwjgl.opengl.XRandR.Screen; 59 import org.lwjgl.opengles.EGL; 60 61 import java.security.AccessController; 62 import java.security.PrivilegedAction; 63 import java.util.ArrayList; 64 import java.util.List; 65 66 final class LinuxDisplay implements DisplayImplementation { 67 /* X11 constants */ 68 public static final int CurrentTime = 0; 69 public static final int GrabSuccess = 0; 70 public static final int AutoRepeatModeOff = 0; 71 public static final int AutoRepeatModeOn = 1; 72 public static final int AutoRepeatModeDefault = 2; 73 public static final int None = 0; 74 75 private static final int KeyPressMask = 1 << 0; 76 private static final int KeyReleaseMask = 1 << 1; 77 private static final int ButtonPressMask = 1 << 2; 78 private static final int ButtonReleaseMask = 1 << 3; 79 80 private static final int NotifyAncestor = 0; 81 private static final int NotifyNonlinear = 3; 82 private static final int NotifyPointer = 5; 83 private static final int NotifyPointerRoot = 6; 84 private static final int NotifyDetailNone = 7; 85 86 private static final int SetModeInsert = 0; 87 private static final int SaveSetRoot = 1; 88 private static final int SaveSetUnmap = 1; 89 90 private static final int X_SetInputFocus = 42; 91 92 /** Window mode enum */ 93 private static final int FULLSCREEN_LEGACY = 1; 94 private static final int FULLSCREEN_NETWM = 2; 95 private static final int WINDOWED = 3; 96 97 /** Current window mode */ 98 private static int current_window_mode = WINDOWED; 99 100 /** Display mode switching API */ 101 private static final int XRANDR = 10; 102 private static final int XF86VIDMODE = 11; 103 private static final int NONE = 12; 104 105 /** Current X11 Display pointer */ 106 private static long display; 107 private static long current_window; 108 private static long saved_error_handler; 109 110 private static int display_connection_usage_count; 111 112 /** Event buffer */ 113 private final LinuxEvent event_buffer = new LinuxEvent(); 114 private final LinuxEvent tmp_event_buffer = new LinuxEvent(); 115 116 /** Current mode swithcing API */ 117 private int current_displaymode_extension = NONE; 118 119 /** Atom used for the pointer warp messages */ 120 private long delete_atom; 121 122 private PeerInfo peer_info; 123 124 /** Saved gamma used to restore display settings */ 125 private ByteBuffer saved_gamma; 126 private ByteBuffer current_gamma; 127 128 /** Saved mode to restore with */ 129 private DisplayMode saved_mode; 130 private DisplayMode current_mode; 131 132 133 private boolean keyboard_grabbed; 134 private boolean pointer_grabbed; 135 private boolean input_released; 136 private boolean grab; 137 private boolean focused; 138 private boolean minimized; 139 private boolean dirty; 140 private boolean close_requested; 141 private long current_cursor; 142 private long blank_cursor; 143 private boolean mouseInside = true; 144 private boolean resizable; 145 private boolean resized; 146 147 private int window_x; 148 private int window_y; 149 private int window_width; 150 private int window_height; 151 152 private Canvas parent; 153 private long parent_window; 154 private static boolean xembedded; 155 private long parent_proxy_focus_window; 156 private boolean parent_focused; 157 private boolean parent_focus_changed; 158 private long last_window_focus = 0; 159 160 private LinuxKeyboard keyboard; 161 private LinuxMouse mouse; 162 163 private String wm_class; 164 165 private final FocusListener focus_listener = new FocusListener() { 166 public void focusGained(FocusEvent e) { 167 synchronized (GlobalLock.lock) { 168 parent_focused = true; 169 parent_focus_changed = true; 170 } 171 } 172 public void focusLost(FocusEvent e) { 173 synchronized (GlobalLock.lock) { 174 parent_focused = false; 175 parent_focus_changed = true; 176 } 177 } 178 }; 179 getCurrentGammaRamp()180 private static ByteBuffer getCurrentGammaRamp() throws LWJGLException { 181 lockAWT(); 182 try { 183 incDisplay(); 184 try { 185 if (isXF86VidModeSupported()) 186 return nGetCurrentGammaRamp(getDisplay(), getDefaultScreen()); 187 else 188 return null; 189 } finally { 190 decDisplay(); 191 } 192 } finally { 193 unlockAWT(); 194 } 195 } nGetCurrentGammaRamp(long display, int screen)196 private static native ByteBuffer nGetCurrentGammaRamp(long display, int screen) throws LWJGLException; 197 getBestDisplayModeExtension()198 private static int getBestDisplayModeExtension() { 199 int result; 200 if (isXrandrSupported()) { 201 LWJGLUtil.log("Using Xrandr for display mode switching"); 202 result = XRANDR; 203 } else if (isXF86VidModeSupported()) { 204 LWJGLUtil.log("Using XF86VidMode for display mode switching"); 205 result = XF86VIDMODE; 206 } else { 207 LWJGLUtil.log("No display mode extensions available"); 208 result = NONE; 209 } 210 return result; 211 } 212 isXrandrSupported()213 private static boolean isXrandrSupported() { 214 if (Display.getPrivilegedBoolean("LWJGL_DISABLE_XRANDR")) 215 return false; 216 lockAWT(); 217 try { 218 incDisplay(); 219 try { 220 return nIsXrandrSupported(getDisplay()); 221 } finally { 222 decDisplay(); 223 } 224 } catch (LWJGLException e) { 225 LWJGLUtil.log("Got exception while querying Xrandr support: " + e); 226 return false; 227 } finally { 228 unlockAWT(); 229 } 230 } nIsXrandrSupported(long display)231 private static native boolean nIsXrandrSupported(long display) throws LWJGLException; 232 isXF86VidModeSupported()233 private static boolean isXF86VidModeSupported() { 234 lockAWT(); 235 try { 236 incDisplay(); 237 try { 238 return nIsXF86VidModeSupported(getDisplay()); 239 } finally { 240 decDisplay(); 241 } 242 } catch (LWJGLException e) { 243 LWJGLUtil.log("Got exception while querying XF86VM support: " + e); 244 return false; 245 } finally { 246 unlockAWT(); 247 } 248 } nIsXF86VidModeSupported(long display)249 private static native boolean nIsXF86VidModeSupported(long display) throws LWJGLException; 250 isNetWMFullscreenSupported()251 private static boolean isNetWMFullscreenSupported() throws LWJGLException { 252 if (Display.getPrivilegedBoolean("LWJGL_DISABLE_NETWM")) 253 return false; 254 lockAWT(); 255 try { 256 incDisplay(); 257 try { 258 return nIsNetWMFullscreenSupported(getDisplay(), getDefaultScreen()); 259 } finally { 260 decDisplay(); 261 } 262 } catch (LWJGLException e) { 263 LWJGLUtil.log("Got exception while querying NetWM support: " + e); 264 return false; 265 } finally { 266 unlockAWT(); 267 } 268 } nIsNetWMFullscreenSupported(long display, int screen)269 private static native boolean nIsNetWMFullscreenSupported(long display, int screen) throws LWJGLException; 270 271 /* Since Xlib is not guaranteed to be thread safe, we need a way to synchronize LWJGL 272 * Xlib calls with AWT Xlib calls. Fortunately, JAWT implements Lock()/Unlock() to 273 * do just that. 274 */ lockAWT()275 static void lockAWT() { 276 try { 277 nLockAWT(); 278 } catch (LWJGLException e) { 279 LWJGLUtil.log("Caught exception while locking AWT: " + e); 280 } 281 } nLockAWT()282 private static native void nLockAWT() throws LWJGLException; 283 unlockAWT()284 static void unlockAWT() { 285 try { 286 nUnlockAWT(); 287 } catch (LWJGLException e) { 288 LWJGLUtil.log("Caught exception while unlocking AWT: " + e); 289 } 290 } nUnlockAWT()291 private static native void nUnlockAWT() throws LWJGLException; 292 293 /** 294 * increment and decrement display usage. 295 */ incDisplay()296 static void incDisplay() throws LWJGLException { 297 if (display_connection_usage_count == 0) { 298 try { 299 // TODO: Can we know if we're on desktop or ES? 300 GLContext.loadOpenGLLibrary(); 301 org.lwjgl.opengles.GLContext.loadOpenGLLibrary(); 302 } catch (Throwable t) { 303 } 304 saved_error_handler = setErrorHandler(); 305 display = openDisplay(); 306 // synchronize(display, true); 307 } 308 display_connection_usage_count++; 309 } callErrorHandler(long handler, long display, long error_ptr)310 private static native int callErrorHandler(long handler, long display, long error_ptr); setErrorHandler()311 private static native long setErrorHandler(); resetErrorHandler(long handler)312 private static native long resetErrorHandler(long handler); synchronize(long display, boolean synchronize)313 private static native void synchronize(long display, boolean synchronize); 314 globalErrorHandler(long display, long event_ptr, long error_display, long serial, long error_code, long request_code, long minor_code)315 private static int globalErrorHandler(long display, long event_ptr, long error_display, long serial, long error_code, long request_code, long minor_code) throws LWJGLException { 316 if (xembedded && request_code == X_SetInputFocus) return 0; // ignore X error in xembeded mode to fix a browser issue when dragging or switching tabs 317 318 if (display == getDisplay()) { 319 String error_msg = getErrorText(display, error_code); 320 throw new LWJGLException("X Error - disp: 0x" + Long.toHexString(error_display) + " serial: " + serial + " error: " + error_msg + " request_code: " + request_code + " minor_code: " + minor_code); 321 } else if (saved_error_handler != 0) 322 return callErrorHandler(saved_error_handler, display, event_ptr); 323 return 0; 324 } getErrorText(long display, long error_code)325 private static native String getErrorText(long display, long error_code); 326 decDisplay()327 static void decDisplay() { 328 /* 329 * Some drivers (at least some versions of the radeon dri driver) 330 * don't like it when the display is closed and later re-opened, 331 * so we'll just let the singleton display connection leak. 332 */ 333 /* display_connection_usage_count--; 334 if (display_connection_usage_count < 0) 335 throw new InternalError("display_connection_usage_count < 0: " + display_connection_usage_count); 336 if (display_connection_usage_count == 0) { 337 closeDisplay(display); 338 resetErrorHandler(saved_error_handler); 339 display = 0; 340 GLContext.unloadOpenGLLibrary(); 341 }*/ 342 } 343 openDisplay()344 static native long openDisplay() throws LWJGLException; closeDisplay(long display)345 static native void closeDisplay(long display); 346 getWindowMode(boolean fullscreen)347 private int getWindowMode(boolean fullscreen) throws LWJGLException { 348 if (fullscreen) { 349 if (current_displaymode_extension == XRANDR && isNetWMFullscreenSupported()) { 350 LWJGLUtil.log("Using NetWM for fullscreen window"); 351 return FULLSCREEN_NETWM; 352 } else { 353 LWJGLUtil.log("Using legacy mode for fullscreen window"); 354 return FULLSCREEN_LEGACY; 355 } 356 } else 357 return WINDOWED; 358 } 359 getDisplay()360 static long getDisplay() { 361 if (display_connection_usage_count <= 0) 362 throw new InternalError("display_connection_usage_count = " + display_connection_usage_count); 363 return display; 364 } 365 getDefaultScreen()366 static int getDefaultScreen() { 367 return nGetDefaultScreen(getDisplay()); 368 } nGetDefaultScreen(long display)369 static native int nGetDefaultScreen(long display); 370 getWindow()371 static long getWindow() { 372 return current_window; 373 } 374 ungrabKeyboard()375 private void ungrabKeyboard() { 376 if (keyboard_grabbed) { 377 nUngrabKeyboard(getDisplay()); 378 keyboard_grabbed = false; 379 } 380 } nUngrabKeyboard(long display)381 static native int nUngrabKeyboard(long display); 382 grabKeyboard()383 private void grabKeyboard() { 384 if (!keyboard_grabbed) { 385 int res = nGrabKeyboard(getDisplay(), getWindow()); 386 if (res == GrabSuccess) 387 keyboard_grabbed = true; 388 } 389 } nGrabKeyboard(long display, long window)390 static native int nGrabKeyboard(long display, long window); 391 grabPointer()392 private void grabPointer() { 393 if (!pointer_grabbed) { 394 int result = nGrabPointer(getDisplay(), getWindow(), None); 395 if (result == GrabSuccess) { 396 pointer_grabbed = true; 397 // make sure we have a centered window 398 if (isLegacyFullscreen()) { 399 nSetViewPort(getDisplay(), getWindow(), getDefaultScreen()); 400 } 401 } 402 } 403 } nGrabPointer(long display, long window, long cursor)404 static native int nGrabPointer(long display, long window, long cursor); nSetViewPort(long display, long window, int screen)405 private static native void nSetViewPort(long display, long window, int screen); 406 ungrabPointer()407 private void ungrabPointer() { 408 if (pointer_grabbed) { 409 pointer_grabbed = false; 410 nUngrabPointer(getDisplay()); 411 } 412 } nUngrabPointer(long display)413 static native int nUngrabPointer(long display); 414 isFullscreen()415 private static boolean isFullscreen() { 416 return current_window_mode == FULLSCREEN_LEGACY || current_window_mode == FULLSCREEN_NETWM; 417 } 418 shouldGrab()419 private boolean shouldGrab() { 420 return !input_released && grab && mouse != null; 421 } 422 updatePointerGrab()423 private void updatePointerGrab() { 424 if (isFullscreen() || shouldGrab()) { 425 grabPointer(); 426 } else { 427 ungrabPointer(); 428 } 429 updateCursor(); 430 } 431 updateCursor()432 private void updateCursor() { 433 long cursor; 434 if (shouldGrab()) { 435 cursor = blank_cursor; 436 } else { 437 cursor = current_cursor; 438 } 439 nDefineCursor(getDisplay(), getWindow(), cursor); 440 } nDefineCursor(long display, long window, long cursor_handle)441 private static native void nDefineCursor(long display, long window, long cursor_handle); 442 isLegacyFullscreen()443 private static boolean isLegacyFullscreen() { 444 return current_window_mode == FULLSCREEN_LEGACY; 445 } 446 updateKeyboardGrab()447 private void updateKeyboardGrab() { 448 if (isLegacyFullscreen()) 449 grabKeyboard(); 450 else 451 ungrabKeyboard(); 452 } 453 createWindow(final DrawableLWJGL drawable, DisplayMode mode, Canvas parent, int x, int y)454 public void createWindow(final DrawableLWJGL drawable, DisplayMode mode, Canvas parent, int x, int y) throws LWJGLException { 455 lockAWT(); 456 try { 457 incDisplay(); 458 try { 459 if ( drawable instanceof DrawableGLES ) 460 peer_info = new LinuxDisplayPeerInfo(); 461 462 ByteBuffer handle = peer_info.lockAndGetHandle(); 463 try { 464 current_window_mode = getWindowMode(Display.isFullscreen()); 465 466 // Try to enable Lecagy FullScreen Support in Compiz, else 467 // we may have trouble with stuff overlapping our fullscreen window. 468 if ( current_window_mode != WINDOWED ) 469 Compiz.setLegacyFullscreenSupport(true); 470 471 // Setting _MOTIF_WM_HINTS in fullscreen mode is problematic for certain window 472 // managers. We do not set MWM_HINTS_DECORATIONS in fullscreen mode anymore, 473 // unless org.lwjgl.opengl.Window.undecorated_fs has been specified. 474 // See native/linux/org_lwjgl_opengl_Display.c, createWindow function. 475 boolean undecorated = Display.getPrivilegedBoolean("org.lwjgl.opengl.Window.undecorated") || (current_window_mode != WINDOWED && Display.getPrivilegedBoolean("org.lwjgl.opengl.Window.undecorated_fs")); 476 477 this.parent = parent; 478 parent_window = parent != null ? getHandle(parent) : getRootWindow(getDisplay(), getDefaultScreen()); 479 resizable = Display.isResizable(); 480 resized = false; 481 window_x = x; 482 window_y = y; 483 window_width = mode.getWidth(); 484 window_height = mode.getHeight(); 485 486 // overwrite arguments x and y - superclass always uses 0,0 for fullscreen windows 487 // use the coordinates of XRandRs primary screen instead 488 // this is required to let the fullscreen window appear on the primary screen 489 if (mode.isFullscreenCapable() && current_displaymode_extension == XRANDR) { 490 Screen primaryScreen = XRandR.DisplayModetoScreen(Display.getDisplayMode()); 491 x = primaryScreen.xPos; 492 y = primaryScreen.yPos; 493 } 494 495 current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y, undecorated, parent_window, resizable); 496 497 // Set the WM_CLASS hint which is needed by some WM's e.g. Gnome Shell 498 wm_class = Display.getPrivilegedString("LWJGL_WM_CLASS"); 499 if (wm_class == null) wm_class = Display.getTitle(); 500 setClassHint(Display.getTitle(), wm_class); 501 502 mapRaised(getDisplay(), current_window); 503 xembedded = parent != null && isAncestorXEmbedded(parent_window); 504 blank_cursor = createBlankCursor(); 505 current_cursor = None; 506 focused = false; 507 input_released = false; 508 pointer_grabbed = false; 509 keyboard_grabbed = false; 510 close_requested = false; 511 grab = false; 512 minimized = false; 513 dirty = true; 514 515 if ( drawable instanceof DrawableGLES ) 516 ((DrawableGLES)drawable).initialize(current_window, getDisplay(), EGL.EGL_WINDOW_BIT, (org.lwjgl.opengles.PixelFormat)drawable.getPixelFormat()); 517 518 if (parent != null) { 519 parent.addFocusListener(focus_listener); 520 parent_focused = parent.isFocusOwner(); 521 parent_focus_changed = true; 522 } 523 } finally { 524 peer_info.unlock(); 525 } 526 } catch (LWJGLException e) { 527 decDisplay(); 528 throw e; 529 } 530 } finally { 531 unlockAWT(); 532 } 533 } nCreateWindow(long display, int screen, ByteBuffer peer_info_handle, DisplayMode mode, int window_mode, int x, int y, boolean undecorated, long parent_handle, boolean resizable)534 private static native long nCreateWindow(long display, int screen, ByteBuffer peer_info_handle, DisplayMode mode, int window_mode, int x, int y, boolean undecorated, long parent_handle, boolean resizable) throws LWJGLException; getRootWindow(long display, int screen)535 private static native long getRootWindow(long display, int screen); hasProperty(long display, long window, long property)536 private static native boolean hasProperty(long display, long window, long property); getParentWindow(long display, long window)537 private static native long getParentWindow(long display, long window) throws LWJGLException; getChildCount(long display, long window)538 private static native int getChildCount(long display, long window) throws LWJGLException; mapRaised(long display, long window)539 private static native void mapRaised(long display, long window); reparentWindow(long display, long window, long parent, int x, int y)540 private static native void reparentWindow(long display, long window, long parent, int x, int y); nGetInputFocus(long display)541 private static native long nGetInputFocus(long display) throws LWJGLException; nSetInputFocus(long display, long window, long time)542 private static native void nSetInputFocus(long display, long window, long time); nSetWindowSize(long display, long window, int width, int height, boolean resizable)543 private static native void nSetWindowSize(long display, long window, int width, int height, boolean resizable); nGetX(long display, long window)544 private static native int nGetX(long display, long window); nGetY(long display, long window)545 private static native int nGetY(long display, long window); nGetWidth(long display, long window)546 private static native int nGetWidth(long display, long window); nGetHeight(long display, long window)547 private static native int nGetHeight(long display, long window); 548 isAncestorXEmbedded(long window)549 private static boolean isAncestorXEmbedded(long window) throws LWJGLException { 550 long xembed_atom = internAtom("_XEMBED_INFO", true); 551 if (xembed_atom != None) { 552 long w = window; 553 while (w != None) { 554 if (hasProperty(getDisplay(), w, xembed_atom)) 555 return true; 556 w = getParentWindow(getDisplay(), w); 557 } 558 } 559 return false; 560 } 561 getHandle(Canvas parent)562 private static long getHandle(Canvas parent) throws LWJGLException { 563 AWTCanvasImplementation awt_impl = AWTGLCanvas.createImplementation(); 564 LinuxPeerInfo parent_peer_info = (LinuxPeerInfo)awt_impl.createPeerInfo(parent, null, null); 565 ByteBuffer parent_peer_info_handle = parent_peer_info.lockAndGetHandle(); 566 try { 567 return parent_peer_info.getDrawable(); 568 } finally { 569 parent_peer_info.unlock(); 570 } 571 } 572 updateInputGrab()573 private void updateInputGrab() { 574 updatePointerGrab(); 575 updateKeyboardGrab(); 576 } 577 destroyWindow()578 public void destroyWindow() { 579 lockAWT(); 580 try { 581 if (parent != null) { 582 parent.removeFocusListener(focus_listener); 583 } 584 try { 585 setNativeCursor(null); 586 } catch (LWJGLException e) { 587 LWJGLUtil.log("Failed to reset cursor: " + e.getMessage()); 588 } 589 nDestroyCursor(getDisplay(), blank_cursor); 590 blank_cursor = None; 591 ungrabKeyboard(); 592 nDestroyWindow(getDisplay(), getWindow()); 593 decDisplay(); 594 595 if ( current_window_mode != WINDOWED ) 596 Compiz.setLegacyFullscreenSupport(false); 597 } finally { 598 unlockAWT(); 599 } 600 } nDestroyWindow(long display, long window)601 static native void nDestroyWindow(long display, long window); 602 switchDisplayMode(DisplayMode mode)603 public void switchDisplayMode(DisplayMode mode) throws LWJGLException { 604 lockAWT(); 605 try { 606 switchDisplayModeOnTmpDisplay(mode); 607 current_mode = mode; 608 } finally { 609 unlockAWT(); 610 } 611 } 612 switchDisplayModeOnTmpDisplay(DisplayMode mode)613 private void switchDisplayModeOnTmpDisplay(DisplayMode mode) throws LWJGLException { 614 if (current_displaymode_extension == XRANDR) { 615 // let Xrandr set the display mode 616 XRandR.setConfiguration(false, XRandR.DisplayModetoScreen(mode)); 617 } else { 618 incDisplay(); 619 try { 620 nSwitchDisplayMode(getDisplay(), getDefaultScreen(), current_displaymode_extension, mode); 621 } finally { 622 decDisplay(); 623 } 624 } 625 } nSwitchDisplayMode(long display, int screen, int extension, DisplayMode mode)626 private static native void nSwitchDisplayMode(long display, int screen, int extension, DisplayMode mode) throws LWJGLException; 627 internAtom(String atom_name, boolean only_if_exists)628 private static long internAtom(String atom_name, boolean only_if_exists) throws LWJGLException { 629 incDisplay(); 630 try { 631 return nInternAtom(getDisplay(), atom_name, only_if_exists); 632 } finally { 633 decDisplay(); 634 } 635 } nInternAtom(long display, String atom_name, boolean only_if_exists)636 static native long nInternAtom(long display, String atom_name, boolean only_if_exists); 637 resetDisplayMode()638 public void resetDisplayMode() { 639 lockAWT(); 640 try { 641 if( current_displaymode_extension == XRANDR ) 642 { 643 AccessController.doPrivileged(new PrivilegedAction<Object>() { 644 public Object run() { 645 XRandR.restoreConfiguration(); 646 return null; 647 } 648 }); 649 } 650 else 651 { 652 switchDisplayMode(saved_mode); 653 } 654 if (isXF86VidModeSupported()) 655 doSetGamma(saved_gamma); 656 657 Compiz.setLegacyFullscreenSupport(false); 658 } catch (LWJGLException e) { 659 LWJGLUtil.log("Caught exception while resetting mode: " + e); 660 } finally { 661 unlockAWT(); 662 } 663 } 664 getGammaRampLength()665 public int getGammaRampLength() { 666 if (!isXF86VidModeSupported()) 667 return 0; 668 lockAWT(); 669 try { 670 try { 671 incDisplay(); 672 try { 673 return nGetGammaRampLength(getDisplay(), getDefaultScreen()); 674 } catch (LWJGLException e) { 675 LWJGLUtil.log("Got exception while querying gamma length: " + e); 676 return 0; 677 } finally { 678 decDisplay(); 679 } 680 } catch (LWJGLException e) { 681 LWJGLUtil.log("Failed to get gamma ramp length: " + e); 682 return 0; 683 } 684 } finally { 685 unlockAWT(); 686 } 687 } nGetGammaRampLength(long display, int screen)688 private static native int nGetGammaRampLength(long display, int screen) throws LWJGLException; 689 setGammaRamp(FloatBuffer gammaRamp)690 public void setGammaRamp(FloatBuffer gammaRamp) throws LWJGLException { 691 if (!isXF86VidModeSupported()) 692 throw new LWJGLException("No gamma ramp support (Missing XF86VM extension)"); 693 doSetGamma(convertToNativeRamp(gammaRamp)); 694 } 695 doSetGamma(ByteBuffer native_gamma)696 private void doSetGamma(ByteBuffer native_gamma) throws LWJGLException { 697 lockAWT(); 698 try { 699 setGammaRampOnTmpDisplay(native_gamma); 700 current_gamma = native_gamma; 701 } finally { 702 unlockAWT(); 703 } 704 } 705 setGammaRampOnTmpDisplay(ByteBuffer native_gamma)706 private static void setGammaRampOnTmpDisplay(ByteBuffer native_gamma) throws LWJGLException { 707 incDisplay(); 708 try { 709 nSetGammaRamp(getDisplay(), getDefaultScreen(), native_gamma); 710 } finally { 711 decDisplay(); 712 } 713 } nSetGammaRamp(long display, int screen, ByteBuffer gammaRamp)714 private static native void nSetGammaRamp(long display, int screen, ByteBuffer gammaRamp) throws LWJGLException; 715 convertToNativeRamp(FloatBuffer ramp)716 private static ByteBuffer convertToNativeRamp(FloatBuffer ramp) throws LWJGLException { 717 return nConvertToNativeRamp(ramp, ramp.position(), ramp.remaining()); 718 } nConvertToNativeRamp(FloatBuffer ramp, int offset, int length)719 private static native ByteBuffer nConvertToNativeRamp(FloatBuffer ramp, int offset, int length) throws LWJGLException; 720 getAdapter()721 public String getAdapter() { 722 return null; 723 } 724 getVersion()725 public String getVersion() { 726 return null; 727 } 728 init()729 public DisplayMode init() throws LWJGLException { 730 lockAWT(); 731 try { 732 Compiz.init(); 733 734 delete_atom = internAtom("WM_DELETE_WINDOW", false); 735 current_displaymode_extension = getBestDisplayModeExtension(); 736 if (current_displaymode_extension == NONE) 737 throw new LWJGLException("No display mode extension is available"); 738 DisplayMode[] modes = getAvailableDisplayModes(); 739 if (modes == null || modes.length == 0) 740 throw new LWJGLException("No modes available"); 741 switch (current_displaymode_extension) { 742 case XRANDR: 743 saved_mode = AccessController.doPrivileged(new PrivilegedAction<DisplayMode>() { 744 public DisplayMode run() { 745 return XRandR.ScreentoDisplayMode(XRandR.getConfiguration()); 746 } 747 }); 748 break; 749 case XF86VIDMODE: 750 saved_mode = modes[0]; 751 break; 752 default: 753 throw new LWJGLException("Unknown display mode extension: " + current_displaymode_extension); 754 } 755 current_mode = saved_mode; 756 saved_gamma = getCurrentGammaRamp(); 757 current_gamma = saved_gamma; 758 return saved_mode; 759 } finally { 760 unlockAWT(); 761 } 762 } 763 getCurrentXRandrMode()764 private static DisplayMode getCurrentXRandrMode() throws LWJGLException { 765 lockAWT(); 766 try { 767 incDisplay(); 768 try { 769 return nGetCurrentXRandrMode(getDisplay(), getDefaultScreen()); 770 } finally { 771 decDisplay(); 772 } 773 } finally { 774 unlockAWT(); 775 } 776 } 777 778 /** Assumes extension == XRANDR */ nGetCurrentXRandrMode(long display, int screen)779 private static native DisplayMode nGetCurrentXRandrMode(long display, int screen) throws LWJGLException; 780 setTitle(String title)781 public void setTitle(String title) { 782 lockAWT(); 783 try { 784 final ByteBuffer titleText = MemoryUtil.encodeUTF8(title); 785 nSetTitle(getDisplay(), getWindow(), MemoryUtil.getAddress(titleText), titleText.remaining() - 1); 786 } finally { 787 unlockAWT(); 788 } 789 } nSetTitle(long display, long window, long title, int len)790 private static native void nSetTitle(long display, long window, long title, int len); 791 792 /** the WM_CLASS hint is needed by some WM's e.g. gnome shell */ setClassHint(String wm_name, String wm_class)793 private void setClassHint(String wm_name, String wm_class) { 794 lockAWT(); 795 try { 796 final ByteBuffer nameText = MemoryUtil.encodeUTF8(wm_name); 797 final ByteBuffer classText = MemoryUtil.encodeUTF8(wm_class); 798 799 nSetClassHint(getDisplay(), getWindow(), MemoryUtil.getAddress(nameText), MemoryUtil.getAddress(classText)); 800 } finally { 801 unlockAWT(); 802 } 803 } nSetClassHint(long display, long window, long wm_name, long wm_class)804 private static native void nSetClassHint(long display, long window, long wm_name, long wm_class); 805 isCloseRequested()806 public boolean isCloseRequested() { 807 boolean result = close_requested; 808 close_requested = false; 809 return result; 810 } 811 isVisible()812 public boolean isVisible() { 813 return !minimized; 814 } 815 isActive()816 public boolean isActive() { 817 return focused || isLegacyFullscreen(); 818 } 819 isDirty()820 public boolean isDirty() { 821 boolean result = dirty; 822 dirty = false; 823 return result; 824 } 825 createPeerInfo(PixelFormat pixel_format, ContextAttribs attribs)826 public PeerInfo createPeerInfo(PixelFormat pixel_format, ContextAttribs attribs) throws LWJGLException { 827 peer_info = new LinuxDisplayPeerInfo(pixel_format); 828 return peer_info; 829 } 830 relayEventToParent(LinuxEvent event_buffer, int event_mask)831 private void relayEventToParent(LinuxEvent event_buffer, int event_mask) { 832 tmp_event_buffer.copyFrom(event_buffer); 833 tmp_event_buffer.setWindow(parent_window); 834 tmp_event_buffer.sendEvent(getDisplay(), parent_window, true, event_mask); 835 } 836 relayEventToParent(LinuxEvent event_buffer)837 private void relayEventToParent(LinuxEvent event_buffer) { 838 if (parent == null) 839 return; 840 switch (event_buffer.getType()) { 841 case LinuxEvent.KeyPress: 842 relayEventToParent(event_buffer, KeyPressMask); 843 break; 844 case LinuxEvent.KeyRelease: 845 relayEventToParent(event_buffer, KeyPressMask); 846 break; 847 case LinuxEvent.ButtonPress: 848 if (xembedded || !focused) relayEventToParent(event_buffer, KeyPressMask); 849 break; 850 case LinuxEvent.ButtonRelease: 851 if (xembedded || !focused) relayEventToParent(event_buffer, KeyPressMask); 852 break; 853 default: 854 break; 855 } 856 } 857 processEvents()858 private void processEvents() { 859 while (LinuxEvent.getPending(getDisplay()) > 0) { 860 event_buffer.nextEvent(getDisplay()); 861 long event_window = event_buffer.getWindow(); 862 relayEventToParent(event_buffer); 863 if (event_window != getWindow() || event_buffer.filterEvent(event_window) || 864 (mouse != null && mouse.filterEvent(grab, shouldWarpPointer(), event_buffer)) || 865 (keyboard != null && keyboard.filterEvent(event_buffer))) 866 continue; 867 switch (event_buffer.getType()) { 868 case LinuxEvent.FocusIn: 869 setFocused(true, event_buffer.getFocusDetail()); 870 break; 871 case LinuxEvent.FocusOut: 872 setFocused(false, event_buffer.getFocusDetail()); 873 break; 874 case LinuxEvent.ClientMessage: 875 if ((event_buffer.getClientFormat() == 32) && (event_buffer.getClientData(0) == delete_atom)) 876 close_requested = true; 877 break; 878 case LinuxEvent.MapNotify: 879 dirty = true; 880 minimized = false; 881 break; 882 case LinuxEvent.UnmapNotify: 883 dirty = true; 884 minimized = true; 885 break; 886 case LinuxEvent.Expose: 887 dirty = true; 888 break; 889 case LinuxEvent.ConfigureNotify: 890 int x = nGetX(getDisplay(), getWindow()); 891 int y = nGetY(getDisplay(), getWindow()); 892 893 int width = nGetWidth(getDisplay(), getWindow()); 894 int height = nGetHeight(getDisplay(), getWindow()); 895 896 window_x = x; 897 window_y = y; 898 899 if (window_width != width || window_height != height) { 900 resized = true; 901 window_width = width; 902 window_height = height; 903 } 904 905 break; 906 case LinuxEvent.EnterNotify: 907 mouseInside = true; 908 break; 909 case LinuxEvent.LeaveNotify: 910 mouseInside = false; 911 break; 912 default: 913 break; 914 } 915 } 916 } 917 update()918 public void update() { 919 lockAWT(); 920 try { 921 processEvents(); 922 checkInput(); 923 } finally { 924 unlockAWT(); 925 } 926 } 927 reshape(int x, int y, int width, int height)928 public void reshape(int x, int y, int width, int height) { 929 lockAWT(); 930 try { 931 nReshape(getDisplay(), getWindow(), x, y, width, height); 932 } finally { 933 unlockAWT(); 934 } 935 } nReshape(long display, long window, int x, int y, int width, int height)936 private static native void nReshape(long display, long window, int x, int y, int width, int height); 937 getAvailableDisplayModes()938 public DisplayMode[] getAvailableDisplayModes() throws LWJGLException { 939 lockAWT(); 940 try { 941 incDisplay(); 942 if (current_displaymode_extension == XRANDR) { 943 // nGetAvailableDisplayModes cannot be trusted. Use it only for bitsPerPixel 944 DisplayMode[] nDisplayModes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension); 945 int bpp = 24; 946 if (nDisplayModes.length > 0) { 947 bpp = nDisplayModes[0].getBitsPerPixel(); 948 } 949 // get the resolutions and frequencys from XRandR 950 Screen[] resolutions = XRandR.getResolutions(XRandR.getScreenNames()[0]); 951 DisplayMode[] modes = new DisplayMode[resolutions.length]; 952 for (int i = 0; i < modes.length; i++) { 953 modes[i] = new DisplayMode(resolutions[i].width, resolutions[i].height, bpp, resolutions[i].freq); 954 } 955 return modes; 956 } else { 957 try { 958 DisplayMode[] modes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension); 959 return modes; 960 } finally { 961 decDisplay(); 962 } 963 } 964 } finally { 965 unlockAWT(); 966 } 967 } nGetAvailableDisplayModes(long display, int screen, int extension)968 private static native DisplayMode[] nGetAvailableDisplayModes(long display, int screen, int extension) throws LWJGLException; 969 970 /* Mouse */ hasWheel()971 public boolean hasWheel() { 972 return true; 973 } 974 getButtonCount()975 public int getButtonCount() { 976 return mouse.getButtonCount(); 977 } 978 createMouse()979 public void createMouse() throws LWJGLException { 980 lockAWT(); 981 try { 982 mouse = new LinuxMouse(getDisplay(), getWindow(), getWindow()); 983 } finally { 984 unlockAWT(); 985 } 986 } 987 destroyMouse()988 public void destroyMouse() { 989 mouse = null; 990 updateInputGrab(); 991 } 992 pollMouse(IntBuffer coord_buffer, ByteBuffer buttons)993 public void pollMouse(IntBuffer coord_buffer, ByteBuffer buttons) { 994 lockAWT(); 995 try { 996 mouse.poll(grab, coord_buffer, buttons); 997 } finally { 998 unlockAWT(); 999 } 1000 } 1001 readMouse(ByteBuffer buffer)1002 public void readMouse(ByteBuffer buffer) { 1003 lockAWT(); 1004 try { 1005 mouse.read(buffer); 1006 } finally { 1007 unlockAWT(); 1008 } 1009 } 1010 setCursorPosition(int x, int y)1011 public void setCursorPosition(int x, int y) { 1012 lockAWT(); 1013 try { 1014 mouse.setCursorPosition(x, y); 1015 } finally { 1016 unlockAWT(); 1017 } 1018 } 1019 checkInput()1020 private void checkInput() { 1021 if (parent == null) return; 1022 1023 if (xembedded) { 1024 long current_focus_window = 0; 1025 1026 if (last_window_focus != current_focus_window || parent_focused != focused) { 1027 if (isParentWindowActive(current_focus_window)) { 1028 if (parent_focused) { 1029 nSetInputFocus(getDisplay(), current_window, CurrentTime); 1030 last_window_focus = current_window; 1031 focused = true; 1032 } 1033 else { 1034 // return focus to the parent proxy focus window 1035 nSetInputFocus(getDisplay(), parent_proxy_focus_window, CurrentTime); 1036 last_window_focus = parent_proxy_focus_window; 1037 focused = false; 1038 } 1039 } 1040 else { 1041 last_window_focus = current_focus_window; 1042 focused = false; 1043 } 1044 } 1045 } 1046 else { 1047 if (parent_focus_changed && parent_focused) { 1048 setInputFocusUnsafe(getWindow()); 1049 parent_focus_changed = false; 1050 } 1051 } 1052 } 1053 setInputFocusUnsafe(long window)1054 private void setInputFocusUnsafe(long window) { 1055 try { 1056 nSetInputFocus(getDisplay(), window, CurrentTime); 1057 nSync(getDisplay(), false); 1058 } catch (LWJGLException e) { 1059 // Since we don't have any event timings for XSetInputFocus, a race condition might give a BadMatch, which we'll catch and ignore 1060 LWJGLUtil.log("Got exception while trying to focus: " + e); 1061 } 1062 } 1063 nSync(long display, boolean throw_away_events)1064 private static native void nSync(long display, boolean throw_away_events) throws LWJGLException; 1065 1066 /** 1067 * This method will check if the parent window is active when running 1068 * in xembed mode. Every xembed embedder window has a focus proxy 1069 * window that recieves all the input. This method will test whether 1070 * the provided window handle is the focus proxy, if so it will get its 1071 * parent window and then test whether this is an ancestor to our 1072 * current_window. If so then parent window is active. 1073 * 1074 * @param window - the window handle to test 1075 */ isParentWindowActive(long window)1076 private boolean isParentWindowActive(long window) { 1077 try { 1078 // parent window already active as window is current_window 1079 if (window == current_window) return true; 1080 1081 // xembed focus proxy will have no children 1082 if (getChildCount(getDisplay(), window) != 0) return false; 1083 1084 // get parent, will be xembed embedder window and ancestor of current_window 1085 long parent_window = getParentWindow(getDisplay(), window); 1086 1087 // parent must not be None 1088 if (parent_window == None) return false; 1089 1090 // scroll current_window's ancestors to find parent_window 1091 long w = current_window; 1092 1093 while (w != None) { 1094 w = getParentWindow(getDisplay(), w); 1095 if (w == parent_window) { 1096 parent_proxy_focus_window = window; // save focus proxy window 1097 return true; 1098 } 1099 } 1100 } catch (LWJGLException e) { 1101 LWJGLUtil.log("Failed to detect if parent window is active: " + e.getMessage()); 1102 return true; // on failure assume still active 1103 } 1104 1105 return false; // failed to find an active parent window 1106 } 1107 setFocused(boolean got_focus, int focus_detail)1108 private void setFocused(boolean got_focus, int focus_detail) { 1109 if (focused == got_focus || focus_detail == NotifyDetailNone || focus_detail == NotifyPointer || focus_detail == NotifyPointerRoot || xembedded) 1110 return; 1111 focused = got_focus; 1112 1113 if (focused) { 1114 acquireInput(); 1115 } 1116 else { 1117 releaseInput(); 1118 } 1119 } 1120 releaseInput()1121 private void releaseInput() { 1122 if (isLegacyFullscreen() || input_released) 1123 return; 1124 if ( keyboard != null ) 1125 keyboard.releaseAll(); 1126 input_released = true; 1127 updateInputGrab(); 1128 if (current_window_mode == FULLSCREEN_NETWM) { 1129 nIconifyWindow(getDisplay(), getWindow(), getDefaultScreen()); 1130 try { 1131 if( current_displaymode_extension == XRANDR ) 1132 { 1133 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1134 public Object run() { 1135 XRandR.restoreConfiguration(); 1136 return null; 1137 } 1138 }); 1139 } 1140 else 1141 { 1142 switchDisplayModeOnTmpDisplay(saved_mode); 1143 } 1144 setGammaRampOnTmpDisplay(saved_gamma); 1145 } catch (LWJGLException e) { 1146 LWJGLUtil.log("Failed to restore saved mode: " + e.getMessage()); 1147 } 1148 } 1149 } nIconifyWindow(long display, long window, int screen)1150 private static native void nIconifyWindow(long display, long window, int screen); 1151 acquireInput()1152 private void acquireInput() { 1153 if (isLegacyFullscreen() || !input_released) 1154 return; 1155 input_released = false; 1156 updateInputGrab(); 1157 if (current_window_mode == FULLSCREEN_NETWM) { 1158 try { 1159 switchDisplayModeOnTmpDisplay(current_mode); 1160 setGammaRampOnTmpDisplay(current_gamma); 1161 } catch (LWJGLException e) { 1162 LWJGLUtil.log("Failed to restore mode: " + e.getMessage()); 1163 } 1164 } 1165 } 1166 grabMouse(boolean new_grab)1167 public void grabMouse(boolean new_grab) { 1168 lockAWT(); 1169 try { 1170 if (new_grab != grab) { 1171 grab = new_grab; 1172 updateInputGrab(); 1173 mouse.changeGrabbed(grab, shouldWarpPointer()); 1174 } 1175 } finally { 1176 unlockAWT(); 1177 } 1178 } 1179 shouldWarpPointer()1180 private boolean shouldWarpPointer() { 1181 return pointer_grabbed && shouldGrab(); 1182 } 1183 getNativeCursorCapabilities()1184 public int getNativeCursorCapabilities() { 1185 lockAWT(); 1186 try { 1187 incDisplay(); 1188 try { 1189 return nGetNativeCursorCapabilities(getDisplay()); 1190 } finally { 1191 decDisplay(); 1192 } 1193 } catch (LWJGLException e) { 1194 throw new RuntimeException(e); 1195 } finally { 1196 unlockAWT(); 1197 } 1198 } nGetNativeCursorCapabilities(long display)1199 private static native int nGetNativeCursorCapabilities(long display) throws LWJGLException; 1200 setNativeCursor(Object handle)1201 public void setNativeCursor(Object handle) throws LWJGLException { 1202 current_cursor = getCursorHandle(handle); 1203 lockAWT(); 1204 try { 1205 updateCursor(); 1206 } finally { 1207 unlockAWT(); 1208 } 1209 } 1210 getMinCursorSize()1211 public int getMinCursorSize() { 1212 lockAWT(); 1213 try { 1214 incDisplay(); 1215 try { 1216 return nGetMinCursorSize(getDisplay(), getWindow()); 1217 } finally { 1218 decDisplay(); 1219 } 1220 } catch (LWJGLException e) { 1221 LWJGLUtil.log("Exception occurred in getMinCursorSize: " + e); 1222 return 0; 1223 } finally { 1224 unlockAWT(); 1225 } 1226 } nGetMinCursorSize(long display, long window)1227 private static native int nGetMinCursorSize(long display, long window); 1228 getMaxCursorSize()1229 public int getMaxCursorSize() { 1230 lockAWT(); 1231 try { 1232 incDisplay(); 1233 try { 1234 return nGetMaxCursorSize(getDisplay(), getWindow()); 1235 } finally { 1236 decDisplay(); 1237 } 1238 } catch (LWJGLException e) { 1239 LWJGLUtil.log("Exception occurred in getMaxCursorSize: " + e); 1240 return 0; 1241 } finally { 1242 unlockAWT(); 1243 } 1244 } nGetMaxCursorSize(long display, long window)1245 private static native int nGetMaxCursorSize(long display, long window); 1246 1247 /* Keyboard */ createKeyboard()1248 public void createKeyboard() throws LWJGLException { 1249 lockAWT(); 1250 try { 1251 keyboard = new LinuxKeyboard(getDisplay(), getWindow()); 1252 } finally { 1253 unlockAWT(); 1254 } 1255 } 1256 destroyKeyboard()1257 public void destroyKeyboard() { 1258 lockAWT(); 1259 try { 1260 keyboard.destroy(getDisplay()); 1261 keyboard = null; 1262 } finally { 1263 unlockAWT(); 1264 } 1265 } 1266 pollKeyboard(ByteBuffer keyDownBuffer)1267 public void pollKeyboard(ByteBuffer keyDownBuffer) { 1268 lockAWT(); 1269 try { 1270 keyboard.poll(keyDownBuffer); 1271 } finally { 1272 unlockAWT(); 1273 } 1274 } 1275 readKeyboard(ByteBuffer buffer)1276 public void readKeyboard(ByteBuffer buffer) { 1277 lockAWT(); 1278 try { 1279 keyboard.read(buffer); 1280 } finally { 1281 unlockAWT(); 1282 } 1283 } 1284 nCreateCursor(long display, int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, int images_offset, IntBuffer delays, int delays_offset)1285 private static native long nCreateCursor(long display, int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, int images_offset, IntBuffer delays, int delays_offset) throws LWJGLException; 1286 createBlankCursor()1287 private static long createBlankCursor() { 1288 return nCreateBlankCursor(getDisplay(), getWindow()); 1289 } nCreateBlankCursor(long display, long window)1290 static native long nCreateBlankCursor(long display, long window); 1291 createCursor(int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, IntBuffer delays)1292 public Object createCursor(int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, IntBuffer delays) throws LWJGLException { 1293 lockAWT(); 1294 try { 1295 incDisplay(); 1296 try { 1297 long cursor = nCreateCursor(getDisplay(), width, height, xHotspot, yHotspot, numImages, images, images.position(), delays, delays != null ? delays.position() : -1); 1298 return cursor; 1299 } catch (LWJGLException e) { 1300 decDisplay(); 1301 throw e; 1302 } 1303 } finally { 1304 unlockAWT(); 1305 } 1306 } 1307 getCursorHandle(Object cursor_handle)1308 private static long getCursorHandle(Object cursor_handle) { 1309 return cursor_handle != null ? (Long)cursor_handle : None; 1310 } 1311 destroyCursor(Object cursorHandle)1312 public void destroyCursor(Object cursorHandle) { 1313 lockAWT(); 1314 try { 1315 nDestroyCursor(getDisplay(), getCursorHandle(cursorHandle)); 1316 decDisplay(); 1317 } finally { 1318 unlockAWT(); 1319 } 1320 } nDestroyCursor(long display, long cursorHandle)1321 static native void nDestroyCursor(long display, long cursorHandle); 1322 getPbufferCapabilities()1323 public int getPbufferCapabilities() { 1324 lockAWT(); 1325 try { 1326 incDisplay(); 1327 try { 1328 return nGetPbufferCapabilities(getDisplay(), getDefaultScreen()); 1329 } finally { 1330 decDisplay(); 1331 } 1332 } catch (LWJGLException e) { 1333 LWJGLUtil.log("Exception occurred in getPbufferCapabilities: " + e); 1334 return 0; 1335 } finally { 1336 unlockAWT(); 1337 } 1338 } nGetPbufferCapabilities(long display, int screen)1339 private static native int nGetPbufferCapabilities(long display, int screen); 1340 isBufferLost(PeerInfo handle)1341 public boolean isBufferLost(PeerInfo handle) { 1342 return false; 1343 } 1344 createPbuffer(int width, int height, PixelFormat pixel_format, ContextAttribs attribs, IntBuffer pixelFormatCaps, IntBuffer pBufferAttribs)1345 public PeerInfo createPbuffer(int width, int height, PixelFormat pixel_format, ContextAttribs attribs, 1346 IntBuffer pixelFormatCaps, 1347 IntBuffer pBufferAttribs) throws LWJGLException { 1348 return new LinuxPbufferPeerInfo(width, height, pixel_format); 1349 } 1350 setPbufferAttrib(PeerInfo handle, int attrib, int value)1351 public void setPbufferAttrib(PeerInfo handle, int attrib, int value) { 1352 throw new UnsupportedOperationException(); 1353 } 1354 bindTexImageToPbuffer(PeerInfo handle, int buffer)1355 public void bindTexImageToPbuffer(PeerInfo handle, int buffer) { 1356 throw new UnsupportedOperationException(); 1357 } 1358 releaseTexImageFromPbuffer(PeerInfo handle, int buffer)1359 public void releaseTexImageFromPbuffer(PeerInfo handle, int buffer) { 1360 throw new UnsupportedOperationException(); 1361 } 1362 1363 /** 1364 * This method will convert icon bytebuffers into a single bytebuffer 1365 * as the icon format required by _NET_WM_ICON should be in a cardinal 1366 * 32 bit ARGB format i.e. all icons in a single buffer the data starting 1367 * with 32 bit width & height followed by the color data as 32bit ARGB. 1368 * 1369 * @param icons Array of icons in RGBA format 1370 */ convertIcons(ByteBuffer[] icons)1371 private static ByteBuffer convertIcons(ByteBuffer[] icons) { 1372 1373 int bufferSize = 0; 1374 1375 // calculate size of bytebuffer 1376 for ( ByteBuffer icon : icons ) { 1377 int size = icon.limit() / 4; 1378 int dimension = (int)Math.sqrt(size); 1379 if ( dimension > 0 ) { 1380 bufferSize += 2 * 4; // add 32 bit width & height, 4 bytes each 1381 bufferSize += dimension * dimension * 4; 1382 } 1383 } 1384 1385 if (bufferSize == 0) return null; 1386 1387 ByteBuffer icon_argb = BufferUtils.createByteBuffer(bufferSize);//icon.capacity()+(2*4)); 1388 icon_argb.order(ByteOrder.BIG_ENDIAN); 1389 1390 for ( ByteBuffer icon : icons ) { 1391 int size = icon.limit() / 4; 1392 int dimension = (int)Math.sqrt(size); 1393 1394 icon_argb.putInt(dimension); // width 1395 icon_argb.putInt(dimension); // height 1396 1397 for (int y = 0; y < dimension; y++) { 1398 for (int x = 0; x < dimension; x++) { 1399 1400 byte r = icon.get((x*4)+(y*dimension*4)); 1401 byte g = icon.get((x*4)+(y*dimension*4)+1); 1402 byte b = icon.get((x*4)+(y*dimension*4)+2); 1403 byte a = icon.get((x*4)+(y*dimension*4)+3); 1404 1405 icon_argb.put(a); 1406 icon_argb.put(r); 1407 icon_argb.put(g); 1408 icon_argb.put(b); 1409 } 1410 } 1411 } 1412 1413 return icon_argb; 1414 } 1415 1416 /** 1417 * Sets one or more icons for the Display. 1418 * <ul> 1419 * <li>On Windows you should supply at least one 16x16 icon and one 32x32.</li> 1420 * <li>Linux (and similar platforms) expect one 32x32 icon.</li> 1421 * <li>Mac OS X should be supplied one 128x128 icon</li> 1422 * </ul> 1423 * The implementation will use the supplied ByteBuffers with image data in RGBA and perform any conversions necessary for the specific platform. 1424 * 1425 * @param icons Array of icons in RGBA mode 1426 * @return number of icons used. 1427 */ setIcon(ByteBuffer[] icons)1428 public int setIcon(ByteBuffer[] icons) { 1429 lockAWT(); 1430 try { 1431 incDisplay(); 1432 try { 1433 // get icons as cardinal ARGB format 1434 ByteBuffer icons_data = convertIcons(icons); 1435 if (icons_data == null) return 0; 1436 nSetWindowIcon(getDisplay(), getWindow(), icons_data, icons_data.capacity());//, icon_mask, icon_mask.capacity(), dimension, dimension); 1437 return icons.length; 1438 } finally { 1439 decDisplay(); 1440 } 1441 } catch (LWJGLException e) { 1442 LWJGLUtil.log("Failed to set display icon: " + e); 1443 return 0; 1444 } finally { 1445 unlockAWT(); 1446 } 1447 } 1448 nSetWindowIcon(long display, long window, ByteBuffer icons_data, int icons_size)1449 private static native void nSetWindowIcon(long display, long window, ByteBuffer icons_data, int icons_size); 1450 getX()1451 public int getX() { 1452 return window_x; 1453 } 1454 getY()1455 public int getY() { 1456 return window_y; 1457 } 1458 getWidth()1459 public int getWidth() { 1460 return window_width; 1461 } 1462 getHeight()1463 public int getHeight() { 1464 return window_height; 1465 } 1466 isInsideWindow()1467 public boolean isInsideWindow() { 1468 return mouseInside; 1469 } 1470 setResizable(boolean resizable)1471 public void setResizable(boolean resizable) { 1472 if (this.resizable == resizable) { 1473 return; 1474 } 1475 1476 this.resizable = resizable; 1477 nSetWindowSize(getDisplay(), getWindow(), window_width, window_height, resizable); 1478 } 1479 wasResized()1480 public boolean wasResized() { 1481 if (resized) { 1482 resized = false; 1483 return true; 1484 } 1485 1486 return false; 1487 } 1488 getPixelScaleFactor()1489 public float getPixelScaleFactor() { 1490 return 1f; 1491 } 1492 1493 /** 1494 * Helper class for managing Compiz's workarounds. We need this to enable Legacy 1495 * Fullscreen Support in Compiz, else we'll have trouble with fullscreen windows 1496 * when Compiz effects are enabled. 1497 * 1498 * Implementation Note: This code is probably too much for an inner class, but 1499 * keeping it here until we're sure we cannot find a better solution. 1500 */ 1501 private static final class Compiz { 1502 1503 private static boolean applyFix; 1504 1505 private static Provider provider; 1506 Compiz()1507 private Compiz() { 1508 } 1509 init()1510 static void init() { 1511 if ( Display.getPrivilegedBoolean("org.lwjgl.opengl.Window.nocompiz_lfs") ) 1512 return; 1513 1514 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1515 public Object run() { 1516 try { 1517 // Check if Compiz is active 1518 if ( !isProcessActive("compiz") ) 1519 return null; 1520 1521 provider = null; 1522 1523 String providerName = null; 1524 1525 // Check if Dbus is available 1526 if ( isProcessActive("dbus-daemon") ) { 1527 providerName = "Dbus"; 1528 provider = new Provider() { 1529 1530 private static final String KEY = "/org/freedesktop/compiz/workarounds/allscreens/legacy_fullscreen"; 1531 1532 public boolean hasLegacyFullscreenSupport() throws LWJGLException { 1533 final List output = Compiz.run( 1534 "dbus-send", "--print-reply", "--type=method_call", "--dest=org.freedesktop.compiz", KEY, "org.freedesktop.compiz.get" 1535 ); 1536 1537 if ( output == null || output.size() < 2 ) 1538 throw new LWJGLException("Invalid Dbus reply."); 1539 1540 String line = (String)output.get(0); 1541 1542 if ( !line.startsWith("method return") ) 1543 throw new LWJGLException("Invalid Dbus reply."); 1544 1545 line = ((String)output.get(1)).trim(); // value 1546 if ( !line.startsWith("boolean") || line.length() < 12) 1547 throw new LWJGLException("Invalid Dbus reply."); 1548 1549 return "true".equalsIgnoreCase(line.substring("boolean".length() + 1)); 1550 } 1551 1552 public void setLegacyFullscreenSupport(final boolean state) throws LWJGLException { 1553 if ( Compiz.run( 1554 "dbus-send", "--type=method_call", "--dest=org.freedesktop.compiz", KEY, "org.freedesktop.compiz.set", "boolean:" + Boolean.toString(state) 1555 ) == null ) 1556 throw new LWJGLException("Failed to apply Compiz LFS workaround."); 1557 } 1558 }; 1559 } else { 1560 try { 1561 // Check if Gconf is available 1562 Runtime.getRuntime().exec("gconftool"); 1563 1564 providerName = "gconftool"; 1565 provider = new Provider() { 1566 1567 private static final String KEY = "/apps/compiz/plugins/workarounds/allscreens/options/legacy_fullscreen"; 1568 1569 public boolean hasLegacyFullscreenSupport() throws LWJGLException { 1570 final List output = Compiz.run(new String[] { 1571 "gconftool", "-g", KEY 1572 }); 1573 1574 if ( output == null || output.size() == 0 ) 1575 throw new LWJGLException("Invalid gconftool reply."); 1576 1577 return Boolean.parseBoolean(((String)output.get(0)).trim()); 1578 } 1579 1580 public void setLegacyFullscreenSupport(final boolean state) throws LWJGLException { 1581 if ( Compiz.run(new String[] { 1582 "gconftool", "-s", KEY, "-s", Boolean.toString(state), "-t", "bool" 1583 }) == null ) 1584 throw new LWJGLException("Failed to apply Compiz LFS workaround."); 1585 1586 if ( state ) { 1587 try { 1588 // gconftool will not apply the workaround immediately, sleep a bit 1589 // to make sure it will be ok when we create the window. 1590 Thread.sleep(200); // 100 is too low, 150 works, set to 200 to be safe. 1591 } catch (InterruptedException e) { 1592 e.printStackTrace(); 1593 } 1594 } 1595 } 1596 }; 1597 } catch (IOException e) { 1598 // Ignore 1599 } 1600 } 1601 1602 if ( provider != null && !provider.hasLegacyFullscreenSupport() ) { // No need to do anything if LFS is already enabled. 1603 applyFix = true; 1604 LWJGLUtil.log("Using " + providerName + " to apply Compiz LFS workaround."); 1605 } 1606 } catch (LWJGLException e) { 1607 // Ignore 1608 } finally { 1609 return null; 1610 } 1611 } 1612 }); 1613 } 1614 setLegacyFullscreenSupport(final boolean enabled)1615 static void setLegacyFullscreenSupport(final boolean enabled) { 1616 if ( !applyFix ) 1617 return; 1618 1619 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1620 public Object run() { 1621 try { 1622 provider.setLegacyFullscreenSupport(enabled); 1623 } catch (LWJGLException e) { 1624 LWJGLUtil.log("Failed to change Compiz Legacy Fullscreen Support. Reason: " + e.getMessage()); 1625 } 1626 return null; 1627 } 1628 }); 1629 } 1630 run(final String... command)1631 private static List<String> run(final String... command) throws LWJGLException { 1632 final List<String> output = new ArrayList<String>(); 1633 1634 try { 1635 final Process p = Runtime.getRuntime().exec(command); 1636 try { 1637 final int exitValue = p.waitFor(); 1638 if ( exitValue != 0 ) 1639 return null; 1640 } catch (InterruptedException e) { 1641 throw new LWJGLException("Process interrupted.", e); 1642 } 1643 1644 final BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); 1645 1646 String line; 1647 while ( (line = br.readLine()) != null ) 1648 output.add(line); 1649 1650 br.close(); 1651 } catch (final IOException e) { 1652 throw new LWJGLException("Process failed.", e); 1653 } 1654 1655 return output; 1656 } 1657 isProcessActive(final String processName)1658 private static boolean isProcessActive(final String processName) throws LWJGLException { 1659 final List<String> output = run(new String[] { "ps", "-C", processName }); 1660 if ( output == null ) 1661 return false; 1662 1663 for ( final String line : output ) { 1664 if ( line.contains(processName) ) 1665 return true; 1666 } 1667 1668 return false; 1669 } 1670 1671 private interface Provider { 1672 hasLegacyFullscreenSupport()1673 boolean hasLegacyFullscreenSupport() throws LWJGLException; 1674 setLegacyFullscreenSupport(boolean state)1675 void setLegacyFullscreenSupport(boolean state) throws LWJGLException; 1676 1677 } 1678 } 1679 1680 } 1681