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