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