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