1 /* 2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 package sun.awt.X11; 26 27 import java.awt.*; 28 import java.awt.event.*; 29 import java.awt.peer.*; 30 import java.beans.PropertyChangeListener; 31 import sun.awt.*; 32 import java.util.*; 33 import java.awt.dnd.DragSource; 34 import java.awt.dnd.DragGestureListener; 35 import java.awt.dnd.DragGestureEvent; 36 import java.awt.dnd.DragGestureRecognizer; 37 import java.awt.dnd.MouseDragGestureRecognizer; 38 import java.awt.dnd.InvalidDnDOperationException; 39 import java.awt.dnd.peer.DragSourceContextPeer; 40 import java.awt.image.*; 41 import java.security.*; 42 import java.awt.im.InputMethodHighlight; 43 import java.awt.im.spi.InputMethodDescriptor; 44 import java.awt.datatransfer.Clipboard; 45 import javax.swing.LookAndFeel; 46 import javax.swing.UIDefaults; 47 import java.util.logging.*; 48 import sun.font.FontManager; 49 import sun.misc.PerformanceLogger; 50 import sun.print.PrintJob2D; 51 import java.lang.reflect.*; 52 53 public class XToolkit extends UNIXToolkit implements Runnable, XConstants { 54 private static Logger log = Logger.getLogger("sun.awt.X11.XToolkit"); 55 private static Logger eventLog = Logger.getLogger("sun.awt.X11.event.XToolkit"); 56 private static final Logger timeoutTaskLog = Logger.getLogger("sun.awt.X11.timeoutTask.XToolkit"); 57 private static Logger keyEventLog = Logger.getLogger("sun.awt.X11.kye.XToolkit"); 58 private static final Logger backingStoreLog = Logger.getLogger("sun.awt.X11.backingStore.XToolkit"); 59 60 static final boolean PRIMARY_LOOP = false; 61 static final boolean SECONDARY_LOOP = true; 62 63 private static String awtAppClassName = null; 64 65 // the system clipboard - CLIPBOARD selection 66 XClipboard clipboard; 67 // the system selection - PRIMARY selection 68 XClipboard selection; 69 70 // Dynamic Layout Resize client code setting 71 protected static boolean dynamicLayoutSetting = false; 72 73 /** 74 * True when the x settings have been loaded. 75 */ 76 private boolean loadedXSettings; 77 78 /** 79 * XSETTINGS for the default screen. 80 * <p> 81 */ 82 private XSettings xs; 83 84 static int arrowCursor; 85 static TreeMap winMap = new TreeMap(); 86 static HashMap specialPeerMap = new HashMap(); 87 static HashMap winToDispatcher = new HashMap(); 88 private static long _display; 89 static UIDefaults uidefaults; 90 static X11GraphicsEnvironment localEnv; 91 static X11GraphicsDevice device; 92 static final X11GraphicsConfig config; 93 static int awt_multiclick_time; 94 static boolean securityWarningEnabled; 95 96 private static int screenWidth = -1, screenHeight = -1; // Dimensions of default screen 97 static long awt_defaultFg; // Pixel 98 private static XMouseInfoPeer xPeer; 99 private static Method m_removeSourceEvents; 100 101 static { 102 initSecurityWarning(); 103 if (GraphicsEnvironment.isHeadless()) { 104 config = null; 105 } else { 106 localEnv = (X11GraphicsEnvironment) GraphicsEnvironment 107 .getLocalGraphicsEnvironment(); 108 device = (X11GraphicsDevice) localEnv.getDefaultScreenDevice(); 109 config = (X11GraphicsConfig) (device.getDefaultConfiguration()); 110 if (device != null) { 111 _display = device.getDisplay(); 112 } 113 setupModifierMap(); 114 initIDs(); 115 setBackingStoreType(); 116 } 117 m_removeSourceEvents = SunToolkit.getMethod(EventQueue.class, "removeSourceEvents", new Class[] {Object.class, Boolean.TYPE}) ; 118 } 119 120 // Error handler stuff 121 static XErrorEvent saved_error; 122 static long saved_error_handler; 123 static XErrorHandler curErrorHandler; 124 // Should be called under LOCK, before releasing LOCK RESTORE_XERROR_HANDLER should be called 125 static void WITH_XERROR_HANDLER(XErrorHandler handler) { 126 saved_error = null; 127 curErrorHandler = handler; 128 XSync(); 129 saved_error_handler = XlibWrapper.SetToolkitErrorHandler(); 130 } 131 static void XERROR_SAVE(XErrorEvent event) { 132 saved_error = event; 133 } 134 // Should be called under LOCK 135 static void RESTORE_XERROR_HANDLER() { 136 XSync(); 137 XlibWrapper.XSetErrorHandler(saved_error_handler); 138 curErrorHandler = null; 139 } 140 // Should be called under LOCK 141 static int SAVED_ERROR_HANDLER(long display, XErrorEvent error) { 142 return XlibWrapper.CallErrorHandler(saved_error_handler, display, error.pData); 143 } 144 interface XErrorHandler { 145 int handleError(long display, XErrorEvent err); 146 } 147 static int GlobalErrorHandler(long display, long event_ptr) { 148 XErrorEvent event = new XErrorEvent(event_ptr); 149 try { 150 if (curErrorHandler != null) { 151 return curErrorHandler.handleError(display, event); 152 } else { 153 return SAVED_ERROR_HANDLER(display, event); 154 } 155 } finally { 156 } 157 } 158 159 /* 160 * Instead of validating window id, we simply call XGetWindowProperty, 161 * but temporary install this function as the error handler to ignore 162 * BadWindow error. 163 */ 164 static XErrorHandler IgnoreBadWindowHandler = new XErrorHandler() { 165 public int handleError(long display, XErrorEvent err) { 166 XERROR_SAVE(err); 167 if (err.get_error_code() == BadWindow) { 168 return 0; 169 } else { 170 return SAVED_ERROR_HANDLER(display, err); 171 } 172 } 173 }; 174 175 176 private native static void initIDs(); 177 native static void waitForEvents(long nextTaskTime); 178 static Thread toolkitThread; 179 static boolean isToolkitThread() { 180 return Thread.currentThread() == toolkitThread; 181 } 182 183 static void initSecurityWarning() { 184 // Enable warning only for internal builds 185 String runtime = getSystemProperty("java.runtime.version"); 186 securityWarningEnabled = (runtime != null && runtime.contains("internal")); 187 } 188 189 static boolean isSecurityWarningEnabled() { 190 return securityWarningEnabled; 191 } 192 193 static native void awt_output_flush(); 194 195 static final void awtFUnlock() { 196 awtUnlock(); 197 awt_output_flush(); 198 } 199 200 201 public native void nativeLoadSystemColors(int[] systemColors); 202 203 static UIDefaults getUIDefaults() { 204 if (uidefaults == null) { 205 initUIDefaults(); 206 } 207 return uidefaults; 208 } 209 210 public void loadSystemColors(int[] systemColors) { 211 nativeLoadSystemColors(systemColors); 212 MotifColorUtilities.loadSystemColors(systemColors); 213 } 214 215 216 217 static void initUIDefaults() { 218 try { 219 // Load Defaults from MotifLookAndFeel 220 221 // This dummy load is necessary to get SystemColor initialized. !!!!!! 222 Color c = SystemColor.text; 223 224 LookAndFeel lnf = new XAWTLookAndFeel(); 225 uidefaults = lnf.getDefaults(); 226 } 227 catch (Exception e) 228 { 229 e.printStackTrace(); 230 } 231 } 232 233 static Object displayLock = new Object(); 234 235 public static long getDisplay() { 236 return _display; 237 } 238 239 public static long getDefaultRootWindow() { 240 awtLock(); 241 try { 242 long res = XlibWrapper.RootWindow(XToolkit.getDisplay(), 243 XlibWrapper.DefaultScreen(XToolkit.getDisplay())); 244 245 if (res == 0) { 246 throw new IllegalStateException("Root window must not be null"); 247 } 248 return res; 249 } finally { 250 awtUnlock(); 251 } 252 } 253 254 void init() { 255 awtLock(); 256 try { 257 XlibWrapper.XSupportsLocale(); 258 if (XlibWrapper.XSetLocaleModifiers("") == null) { 259 log.finer("X locale modifiers are not supported, using default"); 260 } 261 262 AwtScreenData defaultScreen = new AwtScreenData(XToolkit.getDefaultScreenData()); 263 awt_defaultFg = defaultScreen.get_blackpixel(); 264 265 arrowCursor = XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(), 266 XCursorFontConstants.XC_arrow); 267 } finally { 268 awtUnlock(); 269 } 270 271 if (log.isLoggable(Level.FINE)) { 272 Runtime.getRuntime().addShutdownHook(new Thread() { 273 public void run() { 274 dumpPeers(); 275 } 276 }); 277 } 278 } 279 280 static String getCorrectXIDString(String val) { 281 if (val != null) { 282 return val.replace('.', '-'); 283 } else { 284 return val; 285 } 286 } 287 288 static native String getEnv(String key); 289 290 291 static String getAWTAppClassName() { 292 return awtAppClassName; 293 } 294 295 static final String DATA_TRANSFERER_CLASS_NAME = "sun.awt.X11.XDataTransferer"; 296 297 public XToolkit() { 298 super(); 299 if (PerformanceLogger.loggingEnabled()) { 300 PerformanceLogger.setTime("XToolkit construction"); 301 } 302 303 if (!GraphicsEnvironment.isHeadless()) { 304 String mainClassName = null; 305 306 StackTraceElement trace[] = (new Throwable()).getStackTrace(); 307 int bottom = trace.length - 1; 308 if (bottom >= 0) { 309 mainClassName = trace[bottom].getClassName(); 310 } 311 if (mainClassName == null || mainClassName.equals("")) { 312 mainClassName = "AWT"; 313 } 314 awtAppClassName = getCorrectXIDString(mainClassName); 315 316 init(); 317 XWM.init(); 318 SunToolkit.setDataTransfererClassName(DATA_TRANSFERER_CLASS_NAME); 319 toolkitThread = new Thread(this, "AWT-XAWT"); 320 toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); 321 toolkitThread.setDaemon(true); 322 ThreadGroup mainTG = (ThreadGroup)AccessController.doPrivileged( 323 new PrivilegedAction() { 324 public Object run() { 325 ThreadGroup currentTG = 326 Thread.currentThread().getThreadGroup(); 327 ThreadGroup parentTG = currentTG.getParent(); 328 while (parentTG != null) { 329 currentTG = parentTG; 330 parentTG = currentTG.getParent(); 331 } 332 return currentTG; 333 } 334 }); 335 toolkitThread.start(); 336 } 337 } 338 339 public ButtonPeer createButton(Button target) { 340 ButtonPeer peer = new XButtonPeer(target); 341 targetCreatedPeer(target, peer); 342 return peer; 343 } 344 345 public FramePeer createFrame(Frame target) { 346 FramePeer peer = new XFramePeer(target); 347 targetCreatedPeer(target, peer); 348 return peer; 349 } 350 351 static void addToWinMap(long window, XBaseWindow xwin) 352 { 353 synchronized(winMap) { 354 winMap.put(Long.valueOf(window),xwin); 355 } 356 } 357 358 static void removeFromWinMap(long window, XBaseWindow xwin) { 359 synchronized(winMap) { 360 winMap.remove(Long.valueOf(window)); 361 } 362 } 363 static XBaseWindow windowToXWindow(long window) { 364 synchronized(winMap) { 365 return (XBaseWindow) winMap.get(Long.valueOf(window)); 366 } 367 } 368 369 static void addEventDispatcher(long window, XEventDispatcher dispatcher) { 370 synchronized(winToDispatcher) { 371 Long key = Long.valueOf(window); 372 Collection dispatchers = (Collection)winToDispatcher.get(key); 373 if (dispatchers == null) { 374 dispatchers = new Vector(); 375 winToDispatcher.put(key, dispatchers); 376 } 377 dispatchers.add(dispatcher); 378 } 379 } 380 static void removeEventDispatcher(long window, XEventDispatcher dispatcher) { 381 synchronized(winToDispatcher) { 382 Long key = Long.valueOf(window); 383 Collection dispatchers = (Collection)winToDispatcher.get(key); 384 if (dispatchers != null) { 385 dispatchers.remove(dispatcher); 386 } 387 } 388 } 389 390 private Point lastCursorPos; 391 392 /** 393 * Returns whether there is last remembered cursor position. The 394 * position is remembered from X mouse events on our peers. The 395 * position is stored in <code>p</code>. 396 * @return true, if there is remembered last cursor position, 397 * false otherwise 398 */ 399 boolean getLastCursorPos(Point p) { 400 awtLock(); 401 try { 402 if (lastCursorPos == null) { 403 return false; 404 } 405 p.setLocation(lastCursorPos); 406 return true; 407 } finally { 408 awtUnlock(); 409 } 410 } 411 412 private void processGlobalMotionEvent(XEvent e) { 413 // Only our windows guaranteely generate MotionNotify, so we 414 // should track enter/leave, to catch the moment when to 415 // switch to XQueryPointer 416 if (e.get_type() == MotionNotify) { 417 XMotionEvent ev = e.get_xmotion(); 418 awtLock(); 419 try { 420 if (lastCursorPos == null) { 421 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); 422 } else { 423 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); 424 } 425 } finally { 426 awtUnlock(); 427 } 428 } else if (e.get_type() == LeaveNotify) { 429 // Leave from our window 430 awtLock(); 431 try { 432 lastCursorPos = null; 433 } finally { 434 awtUnlock(); 435 } 436 } else if (e.get_type() == EnterNotify) { 437 // Entrance into our window 438 XCrossingEvent ev = e.get_xcrossing(); 439 awtLock(); 440 try { 441 if (lastCursorPos == null) { 442 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); 443 } else { 444 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); 445 } 446 } finally { 447 awtUnlock(); 448 } 449 } 450 } 451 452 public interface XEventListener { 453 public void eventProcessed(XEvent e); 454 } 455 456 private Collection<XEventListener> listeners = new LinkedList<XEventListener>(); 457 458 public void addXEventListener(XEventListener listener) { 459 synchronized (listeners) { 460 listeners.add(listener); 461 } 462 } 463 464 private void notifyListeners(XEvent xev) { 465 synchronized (listeners) { 466 if (listeners.size() == 0) return; 467 468 XEvent copy = xev.clone(); 469 try { 470 for (XEventListener listener : listeners) { 471 listener.eventProcessed(copy); 472 } 473 } finally { 474 copy.dispose(); 475 } 476 } 477 } 478 479 private void dispatchEvent(XEvent ev) { 480 final XAnyEvent xany = ev.get_xany(); 481 482 if (windowToXWindow(xany.get_window()) != null && 483 (ev.get_type() == MotionNotify || ev.get_type() == EnterNotify || ev.get_type() == LeaveNotify)) 484 { 485 processGlobalMotionEvent(ev); 486 } 487 488 XBaseWindow.dispatchToWindow(ev); 489 490 Collection dispatchers = null; 491 synchronized(winToDispatcher) { 492 Long key = Long.valueOf(xany.get_window()); 493 dispatchers = (Collection)winToDispatcher.get(key); 494 if (dispatchers != null) { // Clone it to avoid synchronization during dispatching 495 dispatchers = new Vector(dispatchers); 496 } 497 } 498 if (dispatchers != null) { 499 Iterator iter = dispatchers.iterator(); 500 while (iter.hasNext()) { 501 XEventDispatcher disp = (XEventDispatcher)iter.next(); 502 disp.dispatchEvent(ev); 503 } 504 } 505 notifyListeners(ev); 506 } 507 508 static void processException(Throwable thr) { 509 if (log.isLoggable(Level.WARNING)) { 510 log.log(Level.WARNING, "Exception on Toolkit thread", thr); 511 } 512 } 513 514 static native void awt_toolkit_init(); 515 516 public void run() { 517 awt_toolkit_init(); 518 run(PRIMARY_LOOP); 519 } 520 521 public void run(boolean loop) 522 { 523 XEvent ev = new XEvent(); 524 while(true) { 525 awtLock(); 526 try { 527 if (loop == SECONDARY_LOOP) { 528 // In the secondary loop we may have already aquired awt_lock 529 // several times, so waitForEvents() might be unable to release 530 // the awt_lock and this causes lock up. 531 // For now, we just avoid waitForEvents in the secondary loop. 532 if (!XlibWrapper.XNextSecondaryLoopEvent(getDisplay(),ev.pData)) { 533 break; 534 } 535 } else { 536 callTimeoutTasks(); 537 // If no events are queued, waitForEvents() causes calls to 538 // awtUnlock(), awtJNI_ThreadYield, poll, awtLock(), 539 // so it spends most of its time in poll, without holding the lock. 540 while ((XlibWrapper.XEventsQueued(getDisplay(), XlibWrapper.QueuedAfterReading) == 0) && 541 (XlibWrapper.XEventsQueued(getDisplay(), XlibWrapper.QueuedAfterFlush) == 0)) { 542 callTimeoutTasks(); 543 waitForEvents(getNextTaskTime()); 544 } 545 XlibWrapper.XNextEvent(getDisplay(),ev.pData); 546 } 547 548 if (ev.get_type() != NoExpose) { 549 eventNumber++; 550 } 551 552 if (XDropTargetEventProcessor.processEvent(ev) || 553 XDragSourceContextPeer.processEvent(ev)) { 554 continue; 555 } 556 557 if (eventLog.isLoggable(Level.FINER)) { 558 eventLog.log(Level.FINER, "{0}", ev); 559 } 560 561 // Check if input method consumes the event 562 long w = 0; 563 if (windowToXWindow(ev.get_xany().get_window()) != null) { 564 Component owner = 565 XKeyboardFocusManagerPeer.getCurrentNativeFocusOwner(); 566 if (owner != null) { 567 XWindow ownerWindow = (XWindow) ComponentAccessor.getPeer(owner); 568 if (ownerWindow != null) { 569 w = ownerWindow.getContentWindow(); 570 } 571 } 572 } 573 if( keyEventLog.isLoggable(Level.FINE) && (ev.get_type() == KeyPress || ev.get_type() == KeyRelease) ) { 574 keyEventLog.fine("before XFilterEvent:"+ev); 575 } 576 if (XlibWrapper.XFilterEvent(ev.getPData(), w)) { 577 continue; 578 } 579 if( keyEventLog.isLoggable(Level.FINE) && (ev.get_type() == KeyPress || ev.get_type() == KeyRelease) ) { 580 keyEventLog.fine("after XFilterEvent:"+ev); // IS THIS CORRECT? 581 } 582 583 dispatchEvent(ev); 584 } catch (ThreadDeath td) { 585 XBaseWindow.ungrabInput(); 586 return; 587 } catch (Throwable thr) { 588 XBaseWindow.ungrabInput(); 589 processException(thr); 590 } finally { 591 awtUnlock(); 592 } 593 } 594 } 595 596 static int getDefaultScreenWidth() { 597 if (screenWidth == -1) { 598 long display = getDisplay(); 599 awtLock(); 600 try { 601 screenWidth = (int) XlibWrapper.DisplayWidth(display, XlibWrapper.DefaultScreen(display)); 602 } finally { 603 awtUnlock(); 604 } 605 } 606 return screenWidth; 607 } 608 609 static int getDefaultScreenHeight() { 610 if (screenHeight == -1) { 611 long display = getDisplay(); 612 awtLock(); 613 try { 614 screenHeight = (int) XlibWrapper.DisplayHeight(display, XlibWrapper.DefaultScreen(display)); 615 } finally { 616 awtUnlock(); 617 } 618 } 619 return screenHeight; 620 } 621 622 protected int getScreenWidth() { 623 return getDefaultScreenWidth(); 624 } 625 626 protected int getScreenHeight() { 627 return getDefaultScreenHeight(); 628 } 629 630 private static Rectangle getWorkArea(long root) 631 { 632 XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA"); 633 634 long native_ptr = Native.allocateLongArray(4); 635 try 636 { 637 boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root, 638 XAtom.XA_CARDINAL, native_ptr, 4); 639 if (workareaPresent) 640 { 641 int rootX = (int)Native.getLong(native_ptr, 0); 642 int rootY = (int)Native.getLong(native_ptr, 1); 643 int rootWidth = (int)Native.getLong(native_ptr, 2); 644 int rootHeight = (int)Native.getLong(native_ptr, 3); 645 646 return new Rectangle(rootX, rootY, rootWidth, rootHeight); 647 } 648 } 649 finally 650 { 651 XlibWrapper.unsafe.freeMemory(native_ptr); 652 } 653 654 return null; 655 } 656 657 /* 658 * If we're running in non-Xinerama environment and the current 659 * window manager supports _NET protocol then the screen insets 660 * are calculated using _NET_WM_WORKAREA property of the root 661 * window. 662 * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is 663 * not set, we try to calculate the insets ourselves using 664 * getScreenInsetsManually method. 665 */ 666 public Insets getScreenInsets(GraphicsConfiguration gc) 667 { 668 XNETProtocol netProto = XWM.getWM().getNETProtocol(); 669 if ((netProto == null) || !netProto.active()) 670 { 671 return super.getScreenInsets(gc); 672 } 673 674 XToolkit.awtLock(); 675 try 676 { 677 X11GraphicsConfig x11gc = (X11GraphicsConfig)gc; 678 X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice(); 679 long root = XlibUtil.getRootWindow(x11gd.getScreen()); 680 Rectangle rootBounds = XlibUtil.getWindowGeometry(root); 681 682 X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment) 683 GraphicsEnvironment.getLocalGraphicsEnvironment(); 684 if (!x11ge.runningXinerama()) 685 { 686 Rectangle workArea = XToolkit.getWorkArea(root); 687 if (workArea != null) 688 { 689 return new Insets(workArea.y, 690 workArea.x, 691 rootBounds.height - workArea.height - workArea.y, 692 rootBounds.width - workArea.width - workArea.x); 693 } 694 } 695 696 return getScreenInsetsManually(root, rootBounds, gc.getBounds()); 697 } 698 finally 699 { 700 XToolkit.awtUnlock(); 701 } 702 } 703 704 /* 705 * Manual calculation of screen insets: get all the windows with 706 * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these 707 * hints' values to screen insets. 708 * 709 * This method should be called under XToolkit.awtLock() 710 */ 711 private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds) 712 { 713 /* 714 * During the manual calculation of screen insets we iterate 715 * all the X windows hierarchy starting from root window. This 716 * constant is the max level inspected in this hierarchy. 717 * 3 is a heuristic value: I suppose any the toolbar-like 718 * window is a child of either root or desktop window. 719 */ 720 final int MAX_NESTED_LEVEL = 3; 721 722 XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT"); 723 XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL"); 724 725 Insets insets = new Insets(0, 0, 0, 0); 726 727 java.util.List search = new LinkedList(); 728 search.add(root); 729 search.add(0); 730 while (!search.isEmpty()) 731 { 732 long window = (Long)search.remove(0); 733 int windowLevel = (Integer)search.remove(0); 734 735 /* 736 * Note that most of the modern window managers unmap 737 * application window if it is iconified. Thus, any 738 * _NET_WM_STRUT[_PARTIAL] hints for iconified windows 739 * are not included to the screen insets. 740 */ 741 if (XlibUtil.getWindowMapState(window) == XlibWrapper.IsUnmapped) 742 { 743 continue; 744 } 745 746 long native_ptr = Native.allocateLongArray(4); 747 try 748 { 749 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present 750 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec) 751 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4); 752 if (!strutPresent) 753 { 754 strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4); 755 } 756 if (strutPresent) 757 { 758 // second, verify that window is located on the proper screen 759 Rectangle windowBounds = XlibUtil.getWindowGeometry(window); 760 if (windowLevel > 1) 761 { 762 windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds); 763 } 764 // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect 765 // if the struts area intersects with screenBounds, however some window 766 // managers don't set this hint correctly, so we just get intersection with windowBounds 767 if (windowBounds.intersects(screenBounds)) 768 { 769 insets.left = Math.max((int)Native.getLong(native_ptr, 0), insets.left); 770 insets.right = Math.max((int)Native.getLong(native_ptr, 1), insets.right); 771 insets.top = Math.max((int)Native.getLong(native_ptr, 2), insets.top); 772 insets.bottom = Math.max((int)Native.getLong(native_ptr, 3), insets.bottom); 773 } 774 } 775 } 776 finally 777 { 778 XlibWrapper.unsafe.freeMemory(native_ptr); 779 } 780 781 if (windowLevel < MAX_NESTED_LEVEL) 782 { 783 Set<Long> children = XlibUtil.getChildWindows(window); 784 for (long child : children) 785 { 786 search.add(child); 787 search.add(windowLevel + 1); 788 } 789 } 790 } 791 792 return insets; 793 } 794 795 /* 796 * The current implementation of disabling background erasing for 797 * canvases is that we don't set any native background color 798 * (with XSetWindowBackground) for the canvas window. However, 799 * this color is set in the peer constructor - see 800 * XWindow.postInit() for details. That's why this method from 801 * SunToolkit is not overridden in XToolkit: it's too late to 802 * disable background erasing :( 803 */ 804 /* 805 @Override 806 public void disableBackgroundErase(Canvas canvas) { 807 XCanvasPeer peer = (XCanvasPeer)canvas.getPeer(); 808 if (peer == null) { 809 throw new IllegalStateException("Canvas must have a valid peer"); 810 } 811 peer.disableBackgroundErase(); 812 } 813 */ 814 815 // Need this for XMenuItemPeer. 816 protected static final Object targetToPeer(Object target) { 817 Object p=null; 818 if (target != null && !GraphicsEnvironment.isHeadless()) { 819 p = specialPeerMap.get(target); 820 } 821 if (p != null) return p; 822 else 823 return SunToolkit.targetToPeer(target); 824 } 825 826 // Need this for XMenuItemPeer. 827 protected static final void targetDisposedPeer(Object target, Object peer) { 828 SunToolkit.targetDisposedPeer(target, peer); 829 } 830 831 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 832 return new XRobotPeer(screen.getDefaultConfiguration()); 833 } 834 835 836 /* 837 * On X, support for dynamic layout on resizing is governed by the 838 * window manager. If the window manager supports it, it happens 839 * automatically. The setter method for this property is 840 * irrelevant on X. 841 */ 842 public void setDynamicLayout(boolean b) { 843 dynamicLayoutSetting = b; 844 } 845 846 protected boolean isDynamicLayoutSet() { 847 return dynamicLayoutSetting; 848 } 849 850 /* Called from isDynamicLayoutActive() and from 851 * lazilyLoadDynamicLayoutSupportedProperty() 852 */ 853 protected boolean isDynamicLayoutSupported() { 854 return XWM.getWM().supportsDynamicLayout(); 855 } 856 857 public boolean isDynamicLayoutActive() { 858 return isDynamicLayoutSupported(); 859 } 860 861 862 public FontPeer getFontPeer(String name, int style){ 863 return new XFontPeer(name, style); 864 } 865 866 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { 867 return XDragSourceContextPeer.createDragSourceContextPeer(dge); 868 } 869 870 public <T extends DragGestureRecognizer> T 871 createDragGestureRecognizer(Class<T> recognizerClass, 872 DragSource ds, 873 Component c, 874 int srcActions, 875 DragGestureListener dgl) 876 { 877 if (MouseDragGestureRecognizer.class.equals(recognizerClass)) 878 return (T)new XMouseDragGestureRecognizer(ds, c, srcActions, dgl); 879 else 880 return null; 881 } 882 883 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 884 XCheckboxMenuItemPeer peer = new XCheckboxMenuItemPeer(target); 885 //vb157120: looks like we don't need to map menu items 886 //in new menus implementation 887 //targetCreatedPeer(target, peer); 888 return peer; 889 } 890 891 public MenuItemPeer createMenuItem(MenuItem target) { 892 XMenuItemPeer peer = new XMenuItemPeer(target); 893 //vb157120: looks like we don't need to map menu items 894 //in new menus implementation 895 //targetCreatedPeer(target, peer); 896 return peer; 897 } 898 899 public TextFieldPeer createTextField(TextField target) { 900 TextFieldPeer peer = new XTextFieldPeer(target); 901 targetCreatedPeer(target, peer); 902 return peer; 903 } 904 905 public LabelPeer createLabel(Label target) { 906 LabelPeer peer = new XLabelPeer(target); 907 targetCreatedPeer(target, peer); 908 return peer; 909 } 910 911 public ListPeer createList(java.awt.List target) { 912 ListPeer peer = new XListPeer(target); 913 targetCreatedPeer(target, peer); 914 return peer; 915 } 916 917 public CheckboxPeer createCheckbox(Checkbox target) { 918 CheckboxPeer peer = new XCheckboxPeer(target); 919 targetCreatedPeer(target, peer); 920 return peer; 921 } 922 923 public ScrollbarPeer createScrollbar(Scrollbar target) { 924 XScrollbarPeer peer = new XScrollbarPeer(target); 925 targetCreatedPeer(target, peer); 926 return peer; 927 } 928 929 public ScrollPanePeer createScrollPane(ScrollPane target) { 930 XScrollPanePeer peer = new XScrollPanePeer(target); 931 targetCreatedPeer(target, peer); 932 return peer; 933 } 934 935 public TextAreaPeer createTextArea(TextArea target) { 936 TextAreaPeer peer = new XTextAreaPeer(target); 937 targetCreatedPeer(target, peer); 938 return peer; 939 } 940 941 public ChoicePeer createChoice(Choice target) { 942 XChoicePeer peer = new XChoicePeer(target); 943 targetCreatedPeer(target, peer); 944 return peer; 945 } 946 947 public CanvasPeer createCanvas(Canvas target) { 948 XCanvasPeer peer = (isXEmbedServerRequested() ? new XEmbedCanvasPeer(target) : new XCanvasPeer(target)); 949 targetCreatedPeer(target, peer); 950 return peer; 951 } 952 953 public PanelPeer createPanel(Panel target) { 954 PanelPeer peer = new XPanelPeer(target); 955 targetCreatedPeer(target, peer); 956 return peer; 957 } 958 959 public WindowPeer createWindow(Window target) { 960 WindowPeer peer = new XWindowPeer(target); 961 targetCreatedPeer(target, peer); 962 return peer; 963 } 964 965 public DialogPeer createDialog(Dialog target) { 966 DialogPeer peer = new XDialogPeer(target); 967 targetCreatedPeer(target, peer); 968 return peer; 969 } 970 971 public FileDialogPeer createFileDialog(FileDialog target) { 972 FileDialogPeer peer = new XFileDialogPeer(target); 973 targetCreatedPeer(target, peer); 974 return peer; 975 } 976 977 public MenuBarPeer createMenuBar(MenuBar target) { 978 XMenuBarPeer peer = new XMenuBarPeer(target); 979 targetCreatedPeer(target, peer); 980 return peer; 981 } 982 983 public MenuPeer createMenu(Menu target) { 984 XMenuPeer peer = new XMenuPeer(target); 985 //vb157120: looks like we don't need to map menu items 986 //in new menus implementation 987 //targetCreatedPeer(target, peer); 988 return peer; 989 } 990 991 public PopupMenuPeer createPopupMenu(PopupMenu target) { 992 XPopupMenuPeer peer = new XPopupMenuPeer(target); 993 targetCreatedPeer(target, peer); 994 return peer; 995 } 996 997 public synchronized MouseInfoPeer getMouseInfoPeer() { 998 if (xPeer == null) { 999 xPeer = new XMouseInfoPeer(); 1000 } 1001 return xPeer; 1002 } 1003 1004 public XEmbeddedFramePeer createEmbeddedFrame(XEmbeddedFrame target) 1005 { 1006 XEmbeddedFramePeer peer = new XEmbeddedFramePeer(target); 1007 targetCreatedPeer(target, peer); 1008 return peer; 1009 } 1010 1011 XEmbedChildProxyPeer createEmbedProxy(XEmbedChildProxy target) { 1012 XEmbedChildProxyPeer peer = new XEmbedChildProxyPeer(target); 1013 targetCreatedPeer(target, peer); 1014 return peer; 1015 } 1016 1017 public KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager) throws HeadlessException { 1018 XKeyboardFocusManagerPeer peer = new XKeyboardFocusManagerPeer(manager); 1019 return peer; 1020 } 1021 1022 /** 1023 * Returns a new custom cursor. 1024 */ 1025 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) 1026 throws IndexOutOfBoundsException { 1027 return new XCustomCursor(cursor, hotSpot, name); 1028 } 1029 1030 public TrayIconPeer createTrayIcon(TrayIcon target) 1031 throws HeadlessException, AWTException 1032 { 1033 TrayIconPeer peer = new XTrayIconPeer(target); 1034 targetCreatedPeer(target, peer); 1035 return peer; 1036 } 1037 1038 public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException { 1039 SystemTrayPeer peer = new XSystemTrayPeer(target); 1040 return peer; 1041 } 1042 1043 public boolean isTraySupported() { 1044 int wm = XWM.getWMID(); 1045 if (wm == XWM.METACITY_WM || wm == XWM.KDE2_WM) 1046 { 1047 return true; 1048 } 1049 return false; 1050 } 1051 1052 /** 1053 * Returns the supported cursor size 1054 */ 1055 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) { 1056 return XCustomCursor.getBestCursorSize( 1057 java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight)); 1058 } 1059 1060 1061 public int getMaximumCursorColors() { 1062 return 2; // Black and white. 1063 } 1064 1065 public Map mapInputMethodHighlight(InputMethodHighlight highlight) { 1066 return XInputMethod.mapInputMethodHighlight(highlight); 1067 } 1068 1069 public Clipboard getSystemClipboard() { 1070 SecurityManager security = System.getSecurityManager(); 1071 if (security != null) { 1072 security.checkSystemClipboardAccess(); 1073 } 1074 synchronized (this) { 1075 if (clipboard == null) { 1076 clipboard = new XClipboard("System", "CLIPBOARD"); 1077 } 1078 } 1079 return clipboard; 1080 } 1081 1082 public Clipboard getSystemSelection() { 1083 SecurityManager security = System.getSecurityManager(); 1084 if (security != null) { 1085 security.checkSystemClipboardAccess(); 1086 } 1087 synchronized (this) { 1088 if (selection == null) { 1089 selection = new XClipboard("Selection", "PRIMARY"); 1090 } 1091 } 1092 return selection; 1093 } 1094 1095 public void beep() { 1096 awtLock(); 1097 try { 1098 XlibWrapper.XBell(getDisplay(), 0); 1099 XlibWrapper.XFlush(getDisplay()); 1100 } finally { 1101 awtUnlock(); 1102 } 1103 } 1104 1105 static String getSystemProperty(final String name) { 1106 return (String)AccessController.doPrivileged(new PrivilegedAction() { 1107 public Object run() { 1108 return System.getProperty(name); 1109 } 1110 }); 1111 } 1112 1113 public PrintJob getPrintJob(final Frame frame, final String doctitle, 1114 final Properties props) { 1115 1116 if (GraphicsEnvironment.isHeadless()) { 1117 throw new IllegalArgumentException(); 1118 } 1119 1120 PrintJob2D printJob = new PrintJob2D(frame, doctitle, props); 1121 1122 if (printJob.printDialog() == false) { 1123 printJob = null; 1124 } 1125 return printJob; 1126 } 1127 1128 public PrintJob getPrintJob(final Frame frame, final String doctitle, 1129 final JobAttributes jobAttributes, 1130 final PageAttributes pageAttributes) { 1131 1132 1133 if (GraphicsEnvironment.isHeadless()) { 1134 throw new IllegalArgumentException(); 1135 } 1136 1137 PrintJob2D printJob = new PrintJob2D(frame, doctitle, 1138 jobAttributes, pageAttributes); 1139 1140 if (printJob.printDialog() == false) { 1141 printJob = null; 1142 } 1143 1144 return printJob; 1145 } 1146 1147 static void XSync() { 1148 awtLock(); 1149 try { 1150 XlibWrapper.XSync(getDisplay(),0); 1151 } finally { 1152 awtUnlock(); 1153 } 1154 } 1155 1156 public int getScreenResolution() { 1157 long display = getDisplay(); 1158 awtLock(); 1159 try { 1160 return (int) ((XlibWrapper.DisplayWidth(display, 1161 XlibWrapper.DefaultScreen(display)) * 25.4) / 1162 XlibWrapper.DisplayWidthMM(display, 1163 XlibWrapper.DefaultScreen(display))); 1164 } finally { 1165 awtUnlock(); 1166 } 1167 } 1168 1169 static native long getDefaultXColormap(); 1170 static native long getDefaultScreenData(); 1171 1172 static ColorModel screenmodel; 1173 1174 static ColorModel getStaticColorModel() { 1175 if (screenmodel == null) { 1176 screenmodel = config.getColorModel (); 1177 } 1178 return screenmodel; 1179 } 1180 1181 public ColorModel getColorModel() { 1182 return getStaticColorModel(); 1183 } 1184 1185 /** 1186 * Returns a new input method adapter descriptor for native input methods. 1187 */ 1188 public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException { 1189 return new XInputMethodDescriptor(); 1190 } 1191 1192 static int getMultiClickTime() { 1193 if (awt_multiclick_time == 0) { 1194 initializeMultiClickTime(); 1195 } 1196 return awt_multiclick_time; 1197 } 1198 static void initializeMultiClickTime() { 1199 awtLock(); 1200 try { 1201 try { 1202 String multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), "*", "multiClickTime"); 1203 if (multiclick_time_query != null) { 1204 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query); 1205 // awt_multiclick_time = XtGetMultiClickTime(awt_display); 1206 } else { 1207 multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), 1208 "OpenWindows", "MultiClickTimeout"); 1209 if (multiclick_time_query != null) { 1210 /* Note: OpenWindows.MultiClickTimeout is in tenths of 1211 a second, so we need to multiply by 100 to convert to 1212 milliseconds */ 1213 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query) * 100; 1214 } else { 1215 awt_multiclick_time = 200; 1216 // awt_multiclick_time = XtGetMultiClickTime(awt_display); 1217 } 1218 } 1219 } catch (NumberFormatException nf) { 1220 awt_multiclick_time = 200; 1221 } catch (NullPointerException npe) { 1222 awt_multiclick_time = 200; 1223 } 1224 } finally { 1225 awtUnlock(); 1226 } 1227 if (awt_multiclick_time == 0) { 1228 awt_multiclick_time = 200; 1229 } 1230 } 1231 1232 public boolean isFrameStateSupported(int state) 1233 throws HeadlessException 1234 { 1235 if (state == Frame.NORMAL || state == Frame.ICONIFIED) { 1236 return true; 1237 } else { 1238 return XWM.getWM().supportsExtendedState(state); 1239 } 1240 } 1241 1242 static void dumpPeers() { 1243 if (log.isLoggable(Level.FINE)) { 1244 log.fine("Mapped windows:"); 1245 Iterator iter = winMap.entrySet().iterator(); 1246 while (iter.hasNext()) { 1247 Map.Entry entry = (Map.Entry)iter.next(); 1248 log.fine(entry.getKey() + "->" + entry.getValue()); 1249 if (entry.getValue() instanceof XComponentPeer) { 1250 Component target = (Component)((XComponentPeer)entry.getValue()).getTarget(); 1251 log.fine("\ttarget: " + target); 1252 } 1253 } 1254 1255 SunToolkit.dumpPeers(log); 1256 1257 log.fine("Mapped special peers:"); 1258 iter = specialPeerMap.entrySet().iterator(); 1259 while (iter.hasNext()) { 1260 Map.Entry entry = (Map.Entry)iter.next(); 1261 log.fine(entry.getKey() + "->" + entry.getValue()); 1262 } 1263 1264 log.fine("Mapped dispatchers:"); 1265 iter = winToDispatcher.entrySet().iterator(); 1266 while (iter.hasNext()) { 1267 Map.Entry entry = (Map.Entry)iter.next(); 1268 log.fine(entry.getKey() + "->" + entry.getValue()); 1269 } 1270 } 1271 } 1272 1273 /* Protected with awt_lock. */ 1274 private static boolean initialized; 1275 private static boolean timeStampUpdated; 1276 private static long timeStamp; 1277 1278 private static final XEventDispatcher timeFetcher = 1279 new XEventDispatcher() { 1280 public void dispatchEvent(XEvent ev) { 1281 switch (ev.get_type()) { 1282 case PropertyNotify: 1283 XPropertyEvent xpe = ev.get_xproperty(); 1284 1285 awtLock(); 1286 try { 1287 timeStamp = xpe.get_time(); 1288 timeStampUpdated = true; 1289 awtLockNotifyAll(); 1290 } finally { 1291 awtUnlock(); 1292 } 1293 1294 break; 1295 } 1296 } 1297 }; 1298 1299 private static XAtom _XA_JAVA_TIME_PROPERTY_ATOM; 1300 1301 static long getCurrentServerTime() { 1302 awtLock(); 1303 try { 1304 try { 1305 if (!initialized) { 1306 XToolkit.addEventDispatcher(XBaseWindow.getXAWTRootWindow().getWindow(), 1307 timeFetcher); 1308 _XA_JAVA_TIME_PROPERTY_ATOM = XAtom.get("_SUNW_JAVA_AWT_TIME"); 1309 initialized = true; 1310 } 1311 timeStampUpdated = false; 1312 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), 1313 XBaseWindow.getXAWTRootWindow().getWindow(), 1314 _XA_JAVA_TIME_PROPERTY_ATOM.getAtom(), XAtom.XA_ATOM, 32, 1315 PropModeAppend, 1316 0, 0); 1317 XlibWrapper.XFlush(XToolkit.getDisplay()); 1318 1319 if (isToolkitThread()) { 1320 XEvent event = new XEvent(); 1321 try { 1322 XlibWrapper.XWindowEvent(XToolkit.getDisplay(), 1323 XBaseWindow.getXAWTRootWindow().getWindow(), 1324 XConstants.PropertyChangeMask, 1325 event.pData); 1326 timeFetcher.dispatchEvent(event); 1327 } 1328 finally { 1329 event.dispose(); 1330 } 1331 } 1332 else { 1333 while (!timeStampUpdated) { 1334 awtLockWait(); 1335 } 1336 } 1337 } catch (InterruptedException ie) { 1338 // Note: the returned timeStamp can be incorrect in this case. 1339 if (log.isLoggable(Level.FINE)) log.fine("Catched exception, timeStamp may not be correct (ie = " + ie + ")"); 1340 } 1341 } finally { 1342 awtUnlock(); 1343 } 1344 return timeStamp; 1345 } 1346 protected void initializeDesktopProperties() { 1347 desktopProperties.put("DnD.Autoscroll.initialDelay", Integer.valueOf(50)); 1348 desktopProperties.put("DnD.Autoscroll.interval", Integer.valueOf(50)); 1349 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", Integer.valueOf(5)); 1350 // Don't want to call getMultiClickTime() if we are headless 1351 if (!GraphicsEnvironment.isHeadless()) { 1352 desktopProperties.put("awt.multiClickInterval", 1353 Integer.valueOf(getMultiClickTime())); 1354 desktopProperties.put("awt.mouse.numButtons", 1355 Integer.valueOf(getNumMouseButtons())); 1356 } 1357 } 1358 1359 private int getNumMouseButtons() { 1360 awtLock(); 1361 try { 1362 return XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), 0, 0); 1363 } finally { 1364 awtUnlock(); 1365 } 1366 } 1367 1368 private final static String prefix = "DnD.Cursor."; 1369 private final static String postfix = ".32x32"; 1370 private static final String dndPrefix = "DnD."; 1371 1372 protected Object lazilyLoadDesktopProperty(String name) { 1373 if (name.startsWith(prefix)) { 1374 String cursorName = name.substring(prefix.length(), name.length()) + postfix; 1375 1376 try { 1377 return Cursor.getSystemCustomCursor(cursorName); 1378 } catch (AWTException awte) { 1379 throw new RuntimeException("cannot load system cursor: " + cursorName, awte); 1380 } 1381 } 1382 1383 if (name.equals("awt.dynamicLayoutSupported")) { 1384 return Boolean.valueOf(isDynamicLayoutSupported()); 1385 } 1386 1387 if (initXSettingsIfNeeded(name)) { 1388 return desktopProperties.get(name); 1389 } 1390 1391 return super.lazilyLoadDesktopProperty(name); 1392 } 1393 1394 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) { 1395 initXSettingsIfNeeded(name); 1396 super.addPropertyChangeListener(name, pcl); 1397 } 1398 1399 /** 1400 * Initializes XAWTXSettings if a property for a given property name is provided by 1401 * XSettings and they are not initialized yet. 1402 * 1403 * @return true if the method has initialized XAWTXSettings. 1404 */ 1405 private boolean initXSettingsIfNeeded(final String propName) { 1406 if (!loadedXSettings && 1407 (propName.startsWith("gnome.") || 1408 propName.equals(SunToolkit.DESKTOPFONTHINTS) || 1409 propName.startsWith(dndPrefix))) 1410 { 1411 loadedXSettings = true; 1412 if (!GraphicsEnvironment.isHeadless()) { 1413 loadXSettings(); 1414 /* If no desktop font hint could be retrieved, check for 1415 * KDE running KWin and retrieve settings from fontconfig. 1416 * If that isn't found let SunToolkit will see if there's a 1417 * system property set by a user. 1418 */ 1419 if (desktopProperties.get(SunToolkit.DESKTOPFONTHINTS) == null) { 1420 if (XWM.isKDE2()) { 1421 Object hint = FontManager.getFontConfigAAHint(); 1422 if (hint != null) { 1423 /* set the fontconfig/KDE property so that 1424 * getDesktopHints() below will see it 1425 * and set the public property. 1426 */ 1427 desktopProperties.put(UNIXToolkit.FONTCONFIGAAHINT, 1428 hint); 1429 } 1430 } 1431 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, 1432 SunToolkit.getDesktopFontHints()); 1433 } 1434 1435 return true; 1436 } 1437 } 1438 return false; 1439 } 1440 1441 private void loadXSettings() { 1442 xs = new XAWTXSettings(); 1443 } 1444 1445 /** 1446 * Callback from the native side indicating some, or all, of the 1447 * desktop properties have changed and need to be reloaded. 1448 * <code>data</code> is the byte array directly from the x server and 1449 * may be in little endian format. 1450 * <p> 1451 * NB: This could be called from any thread if triggered by 1452 * <code>loadXSettings</code>. It is called from the System EDT 1453 * if triggered by an XSETTINGS change. 1454 */ 1455 void parseXSettings(int screen_XXX_ignored,Map updatedSettings) { 1456 1457 if (updatedSettings == null || updatedSettings.isEmpty()) { 1458 return; 1459 } 1460 1461 Iterator i = updatedSettings.entrySet().iterator(); 1462 while (i.hasNext()) { 1463 Map.Entry e = (Map.Entry)i.next(); 1464 String name = (String)e.getKey(); 1465 1466 name = "gnome." + name; 1467 setDesktopProperty(name, e.getValue()); 1468 log.fine("name = " + name + " value = " + e.getValue()); 1469 1470 // XXX: we probably want to do something smarter. In 1471 // particular, "Net" properties are of interest to the 1472 // "core" AWT itself. E.g. 1473 // 1474 // Net/DndDragThreshold -> ??? 1475 // Net/DoubleClickTime -> awt.multiClickInterval 1476 } 1477 1478 setDesktopProperty(SunToolkit.DESKTOPFONTHINTS, 1479 SunToolkit.getDesktopFontHints()); 1480 1481 Integer dragThreshold = null; 1482 synchronized (this) { 1483 dragThreshold = (Integer)desktopProperties.get("gnome.Net/DndDragThreshold"); 1484 } 1485 if (dragThreshold != null) { 1486 setDesktopProperty("DnD.gestureMotionThreshold", dragThreshold); 1487 } 1488 1489 } 1490 1491 1492 1493 static int altMask; 1494 static int metaMask; 1495 static int numLockMask; 1496 static int modeSwitchMask; 1497 static int modLockIsShiftLock; 1498 1499 /* Like XKeysymToKeycode, but ensures that keysym is the primary 1500 * symbol on the keycode returned. Returns zero otherwise. 1501 */ 1502 static int keysymToPrimaryKeycode(long sym) { 1503 awtLock(); 1504 try { 1505 int code = XlibWrapper.XKeysymToKeycode(getDisplay(), sym); 1506 if (code == 0) { 1507 return 0; 1508 } 1509 long primary = XlibWrapper.XKeycodeToKeysym(getDisplay(), code, 0); 1510 if (sym != primary) { 1511 return 0; 1512 } 1513 return code; 1514 } finally { 1515 awtUnlock(); 1516 } 1517 } 1518 1519 /* Assign meaning - alt, meta, etc. - to X modifiers mod1 ... mod5. 1520 * Only consider primary symbols on keycodes attached to modifiers. 1521 */ 1522 static void setupModifierMap() { 1523 final int metaL = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_L); 1524 final int metaR = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_R); 1525 final int altL = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_L); 1526 final int altR = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_R); 1527 final int numLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Num_Lock); 1528 final int modeSwitch = keysymToPrimaryKeycode(XKeySymConstants.XK_Mode_switch); 1529 final int shiftLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Shift_Lock); 1530 final int capsLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Caps_Lock); 1531 1532 final int modmask[] = { ShiftMask, LockMask, ControlMask, Mod1Mask, 1533 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; 1534 1535 log.fine("In setupModifierMap"); 1536 awtLock(); 1537 try { 1538 XModifierKeymap modmap = new XModifierKeymap( 1539 XlibWrapper.XGetModifierMapping(getDisplay())); 1540 1541 int nkeys = modmap.get_max_keypermod(); 1542 1543 long map_ptr = modmap.get_modifiermap(); 1544 1545 for (int modn = XConstants.Mod1MapIndex; 1546 modn <= XConstants.Mod5MapIndex; 1547 ++modn) 1548 { 1549 for (int i = 0; i < nkeys; ++i) { 1550 /* for each keycode attached to this modifier */ 1551 int keycode = Native.getUByte(map_ptr, modn * nkeys + i); 1552 1553 if (keycode == 0) { 1554 break; 1555 } 1556 if (metaMask == 0 && 1557 (keycode == metaL || keycode == metaR)) 1558 { 1559 metaMask = modmask[modn]; 1560 break; 1561 } 1562 if (altMask == 0 && (keycode == altL || keycode == altR)) { 1563 altMask = modmask[modn]; 1564 break; 1565 } 1566 if (numLockMask == 0 && keycode == numLock) { 1567 numLockMask = modmask[modn]; 1568 break; 1569 } 1570 if (modeSwitchMask == 0 && keycode == modeSwitch) { 1571 modeSwitchMask = modmask[modn]; 1572 break; 1573 } 1574 continue; 1575 } 1576 } 1577 modLockIsShiftLock = 0; 1578 for (int j = 0; j < nkeys; ++j) { 1579 int keycode = Native.getUByte(map_ptr, XConstants.LockMapIndex * nkeys + j); 1580 if (keycode == 0) { 1581 break; 1582 } 1583 if (keycode == shiftLock) { 1584 modLockIsShiftLock = 1; 1585 break; 1586 } 1587 if (keycode == capsLock) { 1588 break; 1589 } 1590 } 1591 XlibWrapper.XFreeModifiermap(modmap.pData); 1592 } finally { 1593 awtUnlock(); 1594 } 1595 if (log.isLoggable(Level.FINE)) { 1596 log.fine("metaMask = " + metaMask); 1597 log.fine("altMask = " + altMask); 1598 log.fine("numLockMask = " + numLockMask); 1599 log.fine("modeSwitchMask = " + modeSwitchMask); 1600 log.fine("modLockIsShiftLock = " + modLockIsShiftLock); 1601 } 1602 } 1603 1604 1605 private static SortedMap timeoutTasks; 1606 1607 /** 1608 * Removed the task from the list of waiting-to-be called tasks. 1609 * If the task has been scheduled several times removes only first one. 1610 */ 1611 static void remove(Runnable task) { 1612 if (task == null) { 1613 throw new NullPointerException("task is null"); 1614 } 1615 awtLock(); 1616 try { 1617 if (timeoutTaskLog.isLoggable(Level.FINER)) { 1618 timeoutTaskLog.finer("Removing task " + task); 1619 } 1620 if (timeoutTasks == null) { 1621 if (timeoutTaskLog.isLoggable(Level.FINER)) { 1622 timeoutTaskLog.finer("Task is not scheduled"); 1623 } 1624 return; 1625 } 1626 Collection values = timeoutTasks.values(); 1627 Iterator iter = values.iterator(); 1628 while (iter.hasNext()) { 1629 java.util.List list = (java.util.List)iter.next(); 1630 boolean removed = false; 1631 if (list.contains(task)) { 1632 list.remove(task); 1633 if (list.isEmpty()) { 1634 iter.remove(); 1635 } 1636 break; 1637 } 1638 } 1639 } finally { 1640 awtUnlock(); 1641 } 1642 } 1643 1644 static native void wakeup_poll(); 1645 1646 /** 1647 * Registers a Runnable which <code>run()</code> method will be called 1648 * once on the toolkit thread when a specified interval of time elapses. 1649 * 1650 * @param task a Runnable which <code>run</code> method will be called 1651 * on the toolkit thread when <code>interval</code> milliseconds 1652 * elapse 1653 * @param interval an interal in milliseconds 1654 * 1655 * @throws NullPointerException if <code>task</code> is <code>null</code> 1656 * @throws IllegalArgumentException if <code>interval</code> is not positive 1657 */ 1658 static void schedule(Runnable task, long interval) { 1659 if (task == null) { 1660 throw new NullPointerException("task is null"); 1661 } 1662 if (interval <= 0) { 1663 throw new IllegalArgumentException("interval " + interval + " is not positive"); 1664 } 1665 1666 awtLock(); 1667 try { 1668 if (timeoutTaskLog.isLoggable(Level.FINER)) { 1669 timeoutTaskLog.log(Level.FINER, "XToolkit.schedule(): current time={0}" + 1670 "; interval={1}" + 1671 "; task being added={2}" + "; tasks before addition={3}", new Object[] { 1672 Long.valueOf(System.currentTimeMillis()), Long.valueOf(interval), task, timeoutTasks}); 1673 } 1674 1675 if (timeoutTasks == null) { 1676 timeoutTasks = new TreeMap(); 1677 } 1678 1679 Long time = Long.valueOf(System.currentTimeMillis() + interval); 1680 java.util.List tasks = (java.util.List)timeoutTasks.get(time); 1681 if (tasks == null) { 1682 tasks = new ArrayList(1); 1683 timeoutTasks.put(time, tasks); 1684 } 1685 tasks.add(task); 1686 1687 1688 if (timeoutTasks.get(timeoutTasks.firstKey()) == tasks && tasks.size() == 1) { 1689 // Added task became first task - poll won't know 1690 // about it so we need to wake it up 1691 wakeup_poll(); 1692 } 1693 } finally { 1694 awtUnlock(); 1695 } 1696 } 1697 1698 private long getNextTaskTime() { 1699 awtLock(); 1700 try { 1701 if (timeoutTasks == null || timeoutTasks.isEmpty()) { 1702 return -1L; 1703 } 1704 return (Long)timeoutTasks.firstKey(); 1705 } finally { 1706 awtUnlock(); 1707 } 1708 } 1709 1710 /** 1711 * Executes mature timeout tasks registered with schedule(). 1712 * Called from run() under awtLock. 1713 */ 1714 private static void callTimeoutTasks() { 1715 if (timeoutTaskLog.isLoggable(Level.FINER)) { 1716 timeoutTaskLog.log(Level.FINER, "XToolkit.callTimeoutTasks(): current time={0}" + 1717 "; tasks={1}", new Object[] {Long.valueOf(System.currentTimeMillis()), timeoutTasks}); 1718 } 1719 1720 if (timeoutTasks == null || timeoutTasks.isEmpty()) { 1721 return; 1722 } 1723 1724 Long currentTime = Long.valueOf(System.currentTimeMillis()); 1725 Long time = (Long)timeoutTasks.firstKey(); 1726 1727 while (time.compareTo(currentTime) <= 0) { 1728 java.util.List tasks = (java.util.List)timeoutTasks.remove(time); 1729 1730 for (Iterator iter = tasks.iterator(); iter.hasNext();) { 1731 Runnable task = (Runnable)iter.next(); 1732 1733 if (timeoutTaskLog.isLoggable(Level.FINER)) { 1734 timeoutTaskLog.log(Level.FINER, "XToolkit.callTimeoutTasks(): current time={0}" + 1735 "; about to run task={1}", new Object[] {Long.valueOf(currentTime), task}); 1736 } 1737 1738 try { 1739 task.run(); 1740 } catch (ThreadDeath td) { 1741 throw td; 1742 } catch (Throwable thr) { 1743 processException(thr); 1744 } 1745 } 1746 1747 if (timeoutTasks.isEmpty()) { 1748 break; 1749 } 1750 time = (Long)timeoutTasks.firstKey(); 1751 } 1752 } 1753 1754 static long getAwtDefaultFg() { 1755 return awt_defaultFg; 1756 } 1757 1758 static boolean isLeftMouseButton(MouseEvent me) { 1759 switch (me.getID()) { 1760 case MouseEvent.MOUSE_PRESSED: 1761 case MouseEvent.MOUSE_RELEASED: 1762 return (me.getButton() == MouseEvent.BUTTON1); 1763 case MouseEvent.MOUSE_ENTERED: 1764 case MouseEvent.MOUSE_EXITED: 1765 case MouseEvent.MOUSE_CLICKED: 1766 case MouseEvent.MOUSE_DRAGGED: 1767 return ((me.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0); 1768 } 1769 return false; 1770 } 1771 1772 static boolean isRightMouseButton(MouseEvent me) { 1773 int numButtons = ((Integer)getDefaultToolkit().getDesktopProperty("awt.mouse.numButtons")).intValue(); 1774 switch (me.getID()) { 1775 case MouseEvent.MOUSE_PRESSED: 1776 case MouseEvent.MOUSE_RELEASED: 1777 return ((numButtons == 2 && me.getButton() == MouseEvent.BUTTON2) || 1778 (numButtons > 2 && me.getButton() == MouseEvent.BUTTON3)); 1779 case MouseEvent.MOUSE_ENTERED: 1780 case MouseEvent.MOUSE_EXITED: 1781 case MouseEvent.MOUSE_CLICKED: 1782 case MouseEvent.MOUSE_DRAGGED: 1783 return ((numButtons == 2 && (me.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) || 1784 (numButtons > 2 && (me.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0)); 1785 } 1786 return false; 1787 } 1788 1789 static long reset_time_utc; 1790 static final long WRAP_TIME_MILLIS = Integer.MAX_VALUE; 1791 1792 /* 1793 * This function converts between the X server time (number of milliseconds 1794 * since the last server reset) and the UTC time for the 'when' field of an 1795 * InputEvent (or another event type with a timestamp). 1796 */ 1797 static long nowMillisUTC_offset(long server_offset) { 1798 // ported from awt_util.c 1799 /* 1800 * Because Time is of type 'unsigned long', it is possible that Time will 1801 * never wrap when using 64-bit Xlib. However, if a 64-bit client 1802 * connects to a 32-bit server, I suspect the values will still wrap. So 1803 * we should not attempt to remove the wrap checking even if _LP64 is 1804 * true. 1805 */ 1806 1807 long current_time_utc = System.currentTimeMillis(); 1808 if (log.isLoggable(Level.FINER)) { 1809 log.finer("reset_time=" + reset_time_utc + ", current_time=" + current_time_utc 1810 + ", server_offset=" + server_offset + ", wrap_time=" + WRAP_TIME_MILLIS); 1811 } 1812 1813 if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) { 1814 reset_time_utc = System.currentTimeMillis() - getCurrentServerTime(); 1815 } 1816 1817 if (log.isLoggable(Level.FINER)) { 1818 log.finer("result = " + (reset_time_utc + server_offset)); 1819 } 1820 return reset_time_utc + server_offset; 1821 } 1822 1823 /** 1824 * @see sun.awt.SunToolkit#needsXEmbedImpl 1825 */ 1826 protected boolean needsXEmbedImpl() { 1827 // XToolkit implements supports for XEmbed-client protocol and 1828 // requires the supports from the embedding host for it to work. 1829 return true; 1830 } 1831 1832 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { 1833 return (modalityType == null) || 1834 (modalityType == Dialog.ModalityType.MODELESS) || 1835 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) || 1836 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) || 1837 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL); 1838 } 1839 1840 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { 1841 return (exclusionType == null) || 1842 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) || 1843 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) || 1844 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); 1845 } 1846 1847 static EventQueue getEventQueue(Object target) { 1848 AppContext appContext = targetToAppContext(target); 1849 if (appContext != null) { 1850 return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); 1851 } 1852 return null; 1853 } 1854 1855 static void removeSourceEvents(EventQueue queue, Object source, boolean removeAllEvents) { 1856 try { 1857 m_removeSourceEvents.invoke(queue, source, removeAllEvents); 1858 } 1859 catch (IllegalAccessException e) 1860 { 1861 e.printStackTrace(); 1862 } 1863 catch (InvocationTargetException e) { 1864 e.printStackTrace(); 1865 } 1866 } 1867 1868 public boolean isAlwaysOnTopSupported() { 1869 Iterator iter = XWM.getWM().getProtocols(XLayerProtocol.class).iterator(); 1870 while (iter.hasNext()) { 1871 XLayerProtocol proto = (XLayerProtocol)iter.next(); 1872 if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) { 1873 return true; 1874 } 1875 } 1876 return false; 1877 } 1878 1879 public boolean useBufferPerWindow() { 1880 return XToolkit.getBackingStoreType() == XConstants.NotUseful; 1881 } 1882 1883 /** 1884 * Returns one of XConstants: NotUseful, WhenMapped or Always. 1885 * If backing store is not available on at least one screen, or 1886 * java2d uses DGA(which conflicts with backing store) on at least one screen, 1887 * or the string system property "sun.awt.backingStore" is neither "Always" 1888 * nor "WhenMapped", then the method returns XConstants.NotUseful. 1889 * Otherwise, if the system property "sun.awt.backingStore" is "WhenMapped", 1890 * then the method returns XConstants.WhenMapped. 1891 * Otherwise (i.e., if the system property "sun.awt.backingStore" is "Always"), 1892 * the method returns XConstants.Always. 1893 */ 1894 static int getBackingStoreType() { 1895 return backingStoreType; 1896 } 1897 1898 private static void setBackingStoreType() { 1899 String prop = (String)AccessController.doPrivileged( 1900 new sun.security.action.GetPropertyAction("sun.awt.backingStore")); 1901 1902 if (prop == null) { 1903 backingStoreType = XConstants.NotUseful; 1904 if (backingStoreLog.isLoggable(Level.CONFIG)) { 1905 backingStoreLog.config("The system property sun.awt.backingStore is not set" + 1906 ", by default backingStore=NotUseful"); 1907 } 1908 return; 1909 } 1910 1911 if (backingStoreLog.isLoggable(Level.CONFIG)) { 1912 backingStoreLog.config("The system property sun.awt.backingStore is " + prop); 1913 } 1914 prop = prop.toLowerCase(); 1915 if (prop.equals("always")) { 1916 backingStoreType = XConstants.Always; 1917 } else if (prop.equals("whenmapped")) { 1918 backingStoreType = XConstants.WhenMapped; 1919 } else { 1920 backingStoreType = XConstants.NotUseful; 1921 } 1922 1923 if (backingStoreLog.isLoggable(Level.CONFIG)) { 1924 backingStoreLog.config("backingStore(as provided by the system property)=" + 1925 ( backingStoreType == XConstants.NotUseful ? "NotUseful" 1926 : backingStoreType == XConstants.WhenMapped ? 1927 "WhenMapped" : "Always") ); 1928 } 1929 1930 if (sun.java2d.x11.X11SurfaceData.isDgaAvailable()) { 1931 backingStoreType = XConstants.NotUseful; 1932 1933 if (backingStoreLog.isLoggable(Level.CONFIG)) { 1934 backingStoreLog.config("DGA is available, backingStore=NotUseful"); 1935 } 1936 1937 return; 1938 } 1939 1940 awtLock(); 1941 try { 1942 int screenCount = XlibWrapper.ScreenCount(getDisplay()); 1943 for (int i = 0; i < screenCount; i++) { 1944 if (XlibWrapper.DoesBackingStore(XlibWrapper.ScreenOfDisplay(getDisplay(), i)) 1945 == XConstants.NotUseful) { 1946 backingStoreType = XConstants.NotUseful; 1947 1948 if (backingStoreLog.isLoggable(Level.CONFIG)) { 1949 backingStoreLog.config("Backing store is not available on the screen " + 1950 i + ", backingStore=NotUseful"); 1951 } 1952 1953 return; 1954 } 1955 } 1956 } finally { 1957 awtUnlock(); 1958 } 1959 } 1960 1961 /** 1962 * One of XConstants: NotUseful, WhenMapped or Always. 1963 */ 1964 private static int backingStoreType; 1965 1966 static boolean awt_ServerInquired = false; 1967 static boolean awt_IsXsunServer = false; 1968 static boolean awt_XKBInquired = false; 1969 static boolean awt_UseXKB = false; 1970 /** 1971 Try to understand if it is Xsun server. 1972 By now (2005) Sun is vendor of Xsun and Xorg servers; we only return true if Xsun is running. 1973 */ 1974 static boolean isXsunServer() { 1975 awtLock(); 1976 try { 1977 if( awt_ServerInquired ) { 1978 return awt_IsXsunServer; 1979 } 1980 if( ! XlibWrapper.ServerVendor(getDisplay()).startsWith("Sun Microsystems") ) { 1981 awt_ServerInquired = true; 1982 awt_IsXsunServer = false; 1983 return false; 1984 } 1985 // Now, it's Sun. It still may be Xorg though, eg on Solaris 10, x86. 1986 // Today (2005), VendorRelease of Xorg is a Big Number unlike Xsun. 1987 if( XlibWrapper.VendorRelease(getDisplay()) > 10000 ) { 1988 awt_ServerInquired = true; 1989 awt_IsXsunServer = false; 1990 return false; 1991 } 1992 awt_ServerInquired = true; 1993 awt_IsXsunServer = true; 1994 return true; 1995 } finally { 1996 awtUnlock(); 1997 } 1998 } 1999 /** 2000 Query XKEYBOARD extension. 2001 */ 2002 static boolean isXKBenabled() { 2003 awtLock(); 2004 try { 2005 if( awt_XKBInquired ) { 2006 return awt_UseXKB; 2007 } 2008 awt_XKBInquired = true; 2009 String name = "XKEYBOARD"; 2010 awt_UseXKB = XlibWrapper.XQueryExtension( getDisplay(), name, XlibWrapper.larg1, XlibWrapper.larg2, XlibWrapper.larg3); 2011 return awt_UseXKB; 2012 } finally { 2013 awtUnlock(); 2014 } 2015 } 2016 2017 private static long eventNumber; 2018 public static long getEventNumber() { 2019 awtLock(); 2020 try { 2021 return eventNumber; 2022 } finally { 2023 awtUnlock(); 2024 } 2025 } 2026 2027 private static XEventDispatcher oops_waiter; 2028 private static boolean oops_updated; 2029 private static boolean oops_failed; 2030 private XAtom oops; 2031 private static final long WORKAROUND_SLEEP = 100; 2032 2033 /** 2034 * @inheritDoc 2035 */ 2036 protected boolean syncNativeQueue(final long timeout) { 2037 XBaseWindow win = XBaseWindow.getXAWTRootWindow(); 2038 2039 if (oops_waiter == null) { 2040 oops_waiter = new XEventDispatcher() { 2041 public void dispatchEvent(XEvent e) { 2042 if (e.get_type() == SelectionNotify) { 2043 XSelectionEvent pe = e.get_xselection(); 2044 if (pe.get_property() == oops.getAtom()) { 2045 oops_updated = true; 2046 awtLockNotifyAll(); 2047 } else if (pe.get_selection() == XAtom.get("WM_S0").getAtom() && 2048 pe.get_target() == XAtom.get("VERSION").getAtom() && 2049 pe.get_property() == 0 && 2050 XlibWrapper.XGetSelectionOwner(getDisplay(), XAtom.get("WM_S0").getAtom()) == 0) 2051 { 2052 // WM forgot to acquire selection or there is no WM 2053 oops_failed = true; 2054 awtLockNotifyAll(); 2055 } 2056 2057 } 2058 } 2059 }; 2060 } 2061 2062 if (oops == null) { 2063 oops = XAtom.get("OOPS"); 2064 } 2065 2066 awtLock(); 2067 try { 2068 addEventDispatcher(win.getWindow(), oops_waiter); 2069 2070 oops_updated = false; 2071 oops_failed = false; 2072 // Wait for selection notify for oops on win 2073 long event_number = getEventNumber(); 2074 XAtom atom = XAtom.get("WM_S0"); 2075 eventLog.log(Level.FINER, "WM_S0 selection owner {0}", new Object[] {XlibWrapper.XGetSelectionOwner(getDisplay(), atom.getAtom())}); 2076 XlibWrapper.XConvertSelection(getDisplay(), atom.getAtom(), 2077 XAtom.get("VERSION").getAtom(), oops.getAtom(), 2078 win.getWindow(), XlibWrapper.CurrentTime); 2079 XSync(); 2080 2081 2082 eventLog.finer("Requested OOPS"); 2083 2084 long start = System.currentTimeMillis(); 2085 while (!oops_updated && !oops_failed) { 2086 try { 2087 awtLockWait(timeout); 2088 } catch (InterruptedException e) { 2089 throw new RuntimeException(e); 2090 } 2091 // This "while" is a protection from spurious 2092 // wake-ups. However, we shouldn't wait for too long 2093 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) { 2094 throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start)); 2095 } 2096 } 2097 if (oops_failed && getEventNumber() - event_number == 1) { 2098 // If selection update failed we can simply wait some time 2099 // hoping some events will arrive 2100 awtUnlock(); 2101 eventLog.log(Level.FINEST, "Emergency sleep"); 2102 try { 2103 Thread.sleep(WORKAROUND_SLEEP); 2104 } catch (InterruptedException ie) { 2105 throw new RuntimeException(ie); 2106 } finally { 2107 awtLock(); 2108 } 2109 } 2110 return getEventNumber() - event_number > 2; 2111 } finally { 2112 removeEventDispatcher(win.getWindow(), oops_waiter); 2113 eventLog.log(Level.FINER, "Exiting syncNativeQueue"); 2114 awtUnlock(); 2115 } 2116 } 2117 public void grab(Window w) { 2118 if (w.getPeer() != null) { 2119 ((XWindowPeer)w.getPeer()).setGrab(true); 2120 } 2121 } 2122 2123 public void ungrab(Window w) { 2124 if (w.getPeer() != null) { 2125 ((XWindowPeer)w.getPeer()).setGrab(false); 2126 } 2127 } 2128 /** 2129 * Returns if the java.awt.Desktop class is supported on the current 2130 * desktop. 2131 * <p> 2132 * The methods of java.awt.Desktop class are supported on the Gnome desktop. 2133 * Check if the running desktop is Gnome by checking the window manager. 2134 */ 2135 public boolean isDesktopSupported(){ 2136 return XDesktopPeer.isDesktopSupported(); 2137 } 2138 2139 public DesktopPeer createDesktopPeer(Desktop target){ 2140 return new XDesktopPeer(); 2141 } 2142 2143 public static native void setNoisyXErrorHandler(); 2144 }