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