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