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