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 // The current GtkFileChooser is available from GTK+ 2.4 1045 FileDialogPeer peer = checkGtkVersion(2, 4, 0) ? new GtkFileDialogPeer( 1046 target) : new XFileDialogPeer(target); 1047 targetCreatedPeer(target, peer); 1048 return peer; 1049 } 1050 1051 public MenuBarPeer createMenuBar(MenuBar target) { 1052 XMenuBarPeer peer = new XMenuBarPeer(target); 1053 targetCreatedPeer(target, peer); 1054 return peer; 1055 } 1056 1057 public MenuPeer createMenu(Menu target) { 1058 XMenuPeer peer = new XMenuPeer(target); 1059 //vb157120: looks like we don't need to map menu items 1060 //in new menus implementation 1061 //targetCreatedPeer(target, peer); 1062 return peer; 1063 } 1064 1065 public PopupMenuPeer createPopupMenu(PopupMenu target) { 1066 XPopupMenuPeer peer = new XPopupMenuPeer(target); 1067 targetCreatedPeer(target, peer); 1068 return peer; 1069 } 1070 1071 public synchronized MouseInfoPeer getMouseInfoPeer() { 1072 if (xPeer == null) { 1073 xPeer = new XMouseInfoPeer(); 1074 } 1075 return xPeer; 1076 } 1077 1078 public XEmbeddedFramePeer createEmbeddedFrame(XEmbeddedFrame target) 1079 { 1080 XEmbeddedFramePeer peer = new XEmbeddedFramePeer(target); 1081 targetCreatedPeer(target, peer); 1082 return peer; 1083 } 1084 1085 XEmbedChildProxyPeer createEmbedProxy(XEmbedChildProxy target) { 1086 XEmbedChildProxyPeer peer = new XEmbedChildProxyPeer(target); 1087 targetCreatedPeer(target, peer); 1088 return peer; 1089 } 1090 1091 public KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager) throws HeadlessException { 1092 XKeyboardFocusManagerPeer peer = new XKeyboardFocusManagerPeer(manager); 1093 return peer; 1094 } 1095 1096 /** 1097 * Returns a new custom cursor. 1098 */ 1099 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) 1100 throws IndexOutOfBoundsException { 1101 return new XCustomCursor(cursor, hotSpot, name); 1102 } 1103 1104 public TrayIconPeer createTrayIcon(TrayIcon target) 1105 throws HeadlessException, AWTException 1106 { 1107 TrayIconPeer peer = new XTrayIconPeer(target); 1108 targetCreatedPeer(target, peer); 1109 return peer; 1110 } 1111 1112 public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException { 1113 SystemTrayPeer peer = new XSystemTrayPeer(target); 1114 return peer; 1115 } 1116 1117 public boolean isTraySupported() { 1118 XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance(); 1119 if (peer != null) { 1120 return peer.isAvailable(); 1121 } 1122 return false; 1123 } 1124 1125 /** 1126 * Returns the supported cursor size 1127 */ 1128 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) { 1129 return XCustomCursor.getBestCursorSize( 1130 java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight)); 1131 } 1132 1133 1134 public int getMaximumCursorColors() { 1135 return 2; // Black and white. 1136 } 1137 1138 public Map mapInputMethodHighlight(InputMethodHighlight highlight) { 1139 return XInputMethod.mapInputMethodHighlight(highlight); 1140 } 1141 @Override 1142 public boolean getLockingKeyState(int key) { 1143 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK || 1144 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) { 1145 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState"); 1146 } 1147 awtLock(); 1148 try { 1149 return getModifierState( key ); 1150 } finally { 1151 awtUnlock(); 1152 } 1153 } 1154 1155 public Clipboard getSystemClipboard() { 1156 SecurityManager security = System.getSecurityManager(); 1157 if (security != null) { 1158 security.checkSystemClipboardAccess(); 1159 } 1160 synchronized (this) { 1161 if (clipboard == null) { 1162 clipboard = new XClipboard("System", "CLIPBOARD"); 1163 } 1164 } 1165 return clipboard; 1166 } 1167 1168 public Clipboard getSystemSelection() { 1169 SecurityManager security = System.getSecurityManager(); 1170 if (security != null) { 1171 security.checkSystemClipboardAccess(); 1172 } 1173 synchronized (this) { 1174 if (selection == null) { 1175 selection = new XClipboard("Selection", "PRIMARY"); 1176 } 1177 } 1178 return selection; 1179 } 1180 1181 public void beep() { 1182 awtLock(); 1183 try { 1184 XlibWrapper.XBell(getDisplay(), 0); 1185 XlibWrapper.XFlush(getDisplay()); 1186 } finally { 1187 awtUnlock(); 1188 } 1189 } 1190 1191 static String getSystemProperty(final String name) { 1192 return (String)AccessController.doPrivileged(new PrivilegedAction() { 1193 public Object run() { 1194 return System.getProperty(name); 1195 } 1196 }); 1197 } 1198 1199 public PrintJob getPrintJob(final Frame frame, final String doctitle, 1200 final Properties props) { 1201 1202 if (GraphicsEnvironment.isHeadless()) { 1203 throw new IllegalArgumentException(); 1204 } 1205 1206 PrintJob2D printJob = new PrintJob2D(frame, doctitle, props); 1207 1208 if (printJob.printDialog() == false) { 1209 printJob = null; 1210 } 1211 return printJob; 1212 } 1213 1214 public PrintJob getPrintJob(final Frame frame, final String doctitle, 1215 final JobAttributes jobAttributes, 1216 final PageAttributes pageAttributes) { 1217 1218 1219 if (GraphicsEnvironment.isHeadless()) { 1220 throw new IllegalArgumentException(); 1221 } 1222 1223 PrintJob2D printJob = new PrintJob2D(frame, doctitle, 1224 jobAttributes, pageAttributes); 1225 1226 if (printJob.printDialog() == false) { 1227 printJob = null; 1228 } 1229 1230 return printJob; 1231 } 1232 1233 static void XSync() { 1234 awtLock(); 1235 try { 1236 XlibWrapper.XSync(getDisplay(),0); 1237 } finally { 1238 awtUnlock(); 1239 } 1240 } 1241 1242 public int getScreenResolution() { 1243 long display = getDisplay(); 1244 awtLock(); 1245 try { 1246 return (int) ((XlibWrapper.DisplayWidth(display, 1247 XlibWrapper.DefaultScreen(display)) * 25.4) / 1248 XlibWrapper.DisplayWidthMM(display, 1249 XlibWrapper.DefaultScreen(display))); 1250 } finally { 1251 awtUnlock(); 1252 } 1253 } 1254 1255 static native long getDefaultXColormap(); 1256 static native long getDefaultScreenData(); 1257 1258 static ColorModel screenmodel; 1259 1260 static ColorModel getStaticColorModel() { 1261 if (screenmodel == null) { 1262 screenmodel = config.getColorModel (); 1263 } 1264 return screenmodel; 1265 } 1266 1267 public ColorModel getColorModel() { 1268 return getStaticColorModel(); 1269 } 1270 1271 /** 1272 * Returns a new input method adapter descriptor for native input methods. 1273 */ 1274 public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException { 1275 return new XInputMethodDescriptor(); 1276 } 1277 1278 static int getMultiClickTime() { 1279 if (awt_multiclick_time == 0) { 1280 initializeMultiClickTime(); 1281 } 1282 return awt_multiclick_time; 1283 } 1284 static void initializeMultiClickTime() { 1285 awtLock(); 1286 try { 1287 try { 1288 String multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), "*", "multiClickTime"); 1289 if (multiclick_time_query != null) { 1290 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query); 1291 } else { 1292 multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), 1293 "OpenWindows", "MultiClickTimeout"); 1294 if (multiclick_time_query != null) { 1295 /* Note: OpenWindows.MultiClickTimeout is in tenths of 1296 a second, so we need to multiply by 100 to convert to 1297 milliseconds */ 1298 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query) * 100; 1299 } else { 1300 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME; 1301 } 1302 } 1303 } catch (NumberFormatException nf) { 1304 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME; 1305 } catch (NullPointerException npe) { 1306 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME; 1307 } 1308 } finally { 1309 awtUnlock(); 1310 } 1311 if (awt_multiclick_time == 0) { 1312 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME; 1313 } 1314 } 1315 1316 public boolean isFrameStateSupported(int state) 1317 throws HeadlessException 1318 { 1319 if (state == Frame.NORMAL || state == Frame.ICONIFIED) { 1320 return true; 1321 } else { 1322 return XWM.getWM().supportsExtendedState(state); 1323 } 1324 } 1325 1326 static void dumpPeers() { 1327 if (log.isLoggable(PlatformLogger.FINE)) { 1328 log.fine("Mapped windows:"); 1329 Iterator iter = winMap.entrySet().iterator(); 1330 while (iter.hasNext()) { 1331 Map.Entry entry = (Map.Entry)iter.next(); 1332 log.fine(entry.getKey() + "->" + entry.getValue()); 1333 if (entry.getValue() instanceof XComponentPeer) { 1334 Component target = (Component)((XComponentPeer)entry.getValue()).getTarget(); 1335 log.fine("\ttarget: " + target); 1336 } 1337 } 1338 1339 SunToolkit.dumpPeers(log); 1340 1341 log.fine("Mapped special peers:"); 1342 iter = specialPeerMap.entrySet().iterator(); 1343 while (iter.hasNext()) { 1344 Map.Entry entry = (Map.Entry)iter.next(); 1345 log.fine(entry.getKey() + "->" + entry.getValue()); 1346 } 1347 1348 log.fine("Mapped dispatchers:"); 1349 iter = winToDispatcher.entrySet().iterator(); 1350 while (iter.hasNext()) { 1351 Map.Entry entry = (Map.Entry)iter.next(); 1352 log.fine(entry.getKey() + "->" + entry.getValue()); 1353 } 1354 } 1355 } 1356 1357 /* Protected with awt_lock. */ 1358 private static boolean initialized; 1359 private static boolean timeStampUpdated; 1360 private static long timeStamp; 1361 1362 private static final XEventDispatcher timeFetcher = 1363 new XEventDispatcher() { 1364 public void dispatchEvent(XEvent ev) { 1365 switch (ev.get_type()) { 1366 case XConstants.PropertyNotify: 1367 XPropertyEvent xpe = ev.get_xproperty(); 1368 1369 awtLock(); 1370 try { 1371 timeStamp = xpe.get_time(); 1372 timeStampUpdated = true; 1373 awtLockNotifyAll(); 1374 } finally { 1375 awtUnlock(); 1376 } 1377 1378 break; 1379 } 1380 } 1381 }; 1382 1383 private static XAtom _XA_JAVA_TIME_PROPERTY_ATOM; 1384 1385 static long getCurrentServerTime() { 1386 awtLock(); 1387 try { 1388 try { 1389 if (!initialized) { 1390 XToolkit.addEventDispatcher(XBaseWindow.getXAWTRootWindow().getWindow(), 1391 timeFetcher); 1392 _XA_JAVA_TIME_PROPERTY_ATOM = XAtom.get("_SUNW_JAVA_AWT_TIME"); 1393 initialized = true; 1394 } 1395 timeStampUpdated = false; 1396 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), 1397 XBaseWindow.getXAWTRootWindow().getWindow(), 1398 _XA_JAVA_TIME_PROPERTY_ATOM.getAtom(), XAtom.XA_ATOM, 32, 1399 XConstants.PropModeAppend, 1400 0, 0); 1401 XlibWrapper.XFlush(XToolkit.getDisplay()); 1402 1403 if (isToolkitThread()) { 1404 XEvent event = new XEvent(); 1405 try { 1406 XlibWrapper.XWindowEvent(XToolkit.getDisplay(), 1407 XBaseWindow.getXAWTRootWindow().getWindow(), 1408 XConstants.PropertyChangeMask, 1409 event.pData); 1410 timeFetcher.dispatchEvent(event); 1411 } 1412 finally { 1413 event.dispose(); 1414 } 1415 } 1416 else { 1417 while (!timeStampUpdated) { 1418 awtLockWait(); 1419 } 1420 } 1421 } catch (InterruptedException ie) { 1422 // Note: the returned timeStamp can be incorrect in this case. 1423 if (log.isLoggable(PlatformLogger.FINE)) log.fine("Catched exception, timeStamp may not be correct (ie = " + ie + ")"); 1424 } 1425 } finally { 1426 awtUnlock(); 1427 } 1428 return timeStamp; 1429 } 1430 protected void initializeDesktopProperties() { 1431 desktopProperties.put("DnD.Autoscroll.initialDelay", 1432 Integer.valueOf(50)); 1433 desktopProperties.put("DnD.Autoscroll.interval", 1434 Integer.valueOf(50)); 1435 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", 1436 Integer.valueOf(5)); 1437 desktopProperties.put("Shell.shellFolderManager", 1438 "sun.awt.shell.ShellFolderManager"); 1439 // Don't want to call getMultiClickTime() if we are headless 1440 if (!GraphicsEnvironment.isHeadless()) { 1441 desktopProperties.put("awt.multiClickInterval", 1442 Integer.valueOf(getMultiClickTime())); 1443 desktopProperties.put("awt.mouse.numButtons", 1444 Integer.valueOf(getNumberOfButtons())); 1445 } 1446 } 1447 1448 /** 1449 * This method runs through the XPointer and XExtendedPointer array. 1450 * XExtendedPointer has priority because on some systems XPointer 1451 * (which is assigned to the virtual pointer) reports the maximum 1452 * capabilities of the mouse pointer (i.e. 32 physical buttons). 1453 */ 1454 private native int getNumberOfButtonsImpl(); 1455 1456 @Override 1457 public int getNumberOfButtons(){ 1458 awtLock(); 1459 try { 1460 if (numberOfButtons == 0) { 1461 numberOfButtons = getNumberOfButtonsImpl(); 1462 } 1463 return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons; 1464 } finally { 1465 awtUnlock(); 1466 } 1467 } 1468 1469 private final static String prefix = "DnD.Cursor."; 1470 private final static String postfix = ".32x32"; 1471 private static final String dndPrefix = "DnD."; 1472 1473 protected Object lazilyLoadDesktopProperty(String name) { 1474 if (name.startsWith(prefix)) { 1475 String cursorName = name.substring(prefix.length(), name.length()) + postfix; 1476 1477 try { 1478 return Cursor.getSystemCustomCursor(cursorName); 1479 } catch (AWTException awte) { 1480 throw new RuntimeException("cannot load system cursor: " + cursorName, awte); 1481 } 1482 } 1483 1484 if (name.equals("awt.dynamicLayoutSupported")) { 1485 return Boolean.valueOf(isDynamicLayoutSupported()); 1486 } 1487 1488 if (initXSettingsIfNeeded(name)) { 1489 return desktopProperties.get(name); 1490 } 1491 1492 return super.lazilyLoadDesktopProperty(name); 1493 } 1494 1495 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) { 1496 initXSettingsIfNeeded(name); 1497 super.addPropertyChangeListener(name, pcl); 1498 } 1499 1500 /** 1501 * Initializes XAWTXSettings if a property for a given property name is provided by 1502 * XSettings and they are not initialized yet. 1503 * 1504 * @return true if the method has initialized XAWTXSettings. 1505 */ 1506 private boolean initXSettingsIfNeeded(final String propName) { 1507 if (!loadedXSettings && 1508 (propName.startsWith("gnome.") || 1509 propName.equals(SunToolkit.DESKTOPFONTHINTS) || 1510 propName.startsWith(dndPrefix))) 1511 { 1512 loadedXSettings = true; 1513 if (!GraphicsEnvironment.isHeadless()) { 1514 loadXSettings(); 1515 /* If no desktop font hint could be retrieved, check for 1516 * KDE running KWin and retrieve settings from fontconfig. 1517 * If that isn't found let SunToolkit will see if there's a 1518 * system property set by a user. 1519 */ 1520 if (desktopProperties.get(SunToolkit.DESKTOPFONTHINTS) == null) { 1521 if (XWM.isKDE2()) { 1522 Object hint = fcManager.getFontConfigAAHint(); 1523 if (hint != null) { 1524 /* set the fontconfig/KDE property so that 1525 * getDesktopHints() below will see it 1526 * and set the public property. 1527 */ 1528 desktopProperties.put(UNIXToolkit.FONTCONFIGAAHINT, 1529 hint); 1530 } 1531 } 1532 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, 1533 SunToolkit.getDesktopFontHints()); 1534 } 1535 1536 return true; 1537 } 1538 } 1539 return false; 1540 } 1541 1542 private void loadXSettings() { 1543 xs = new XAWTXSettings(); 1544 } 1545 1546 /** 1547 * Callback from the native side indicating some, or all, of the 1548 * desktop properties have changed and need to be reloaded. 1549 * <code>data</code> is the byte array directly from the x server and 1550 * may be in little endian format. 1551 * <p> 1552 * NB: This could be called from any thread if triggered by 1553 * <code>loadXSettings</code>. It is called from the System EDT 1554 * if triggered by an XSETTINGS change. 1555 */ 1556 void parseXSettings(int screen_XXX_ignored,Map updatedSettings) { 1557 1558 if (updatedSettings == null || updatedSettings.isEmpty()) { 1559 return; 1560 } 1561 1562 Iterator i = updatedSettings.entrySet().iterator(); 1563 while (i.hasNext()) { 1564 Map.Entry e = (Map.Entry)i.next(); 1565 String name = (String)e.getKey(); 1566 1567 name = "gnome." + name; 1568 setDesktopProperty(name, e.getValue()); 1569 log.fine("name = " + name + " value = " + e.getValue()); 1570 1571 // XXX: we probably want to do something smarter. In 1572 // particular, "Net" properties are of interest to the 1573 // "core" AWT itself. E.g. 1574 // 1575 // Net/DndDragThreshold -> ??? 1576 // Net/DoubleClickTime -> awt.multiClickInterval 1577 } 1578 1579 setDesktopProperty(SunToolkit.DESKTOPFONTHINTS, 1580 SunToolkit.getDesktopFontHints()); 1581 1582 Integer dragThreshold = null; 1583 synchronized (this) { 1584 dragThreshold = (Integer)desktopProperties.get("gnome.Net/DndDragThreshold"); 1585 } 1586 if (dragThreshold != null) { 1587 setDesktopProperty("DnD.gestureMotionThreshold", dragThreshold); 1588 } 1589 1590 } 1591 1592 1593 1594 static int altMask; 1595 static int metaMask; 1596 static int numLockMask; 1597 static int modeSwitchMask; 1598 static int modLockIsShiftLock; 1599 1600 /* Like XKeysymToKeycode, but ensures that keysym is the primary 1601 * symbol on the keycode returned. Returns zero otherwise. 1602 */ 1603 static int keysymToPrimaryKeycode(long sym) { 1604 awtLock(); 1605 try { 1606 int code = XlibWrapper.XKeysymToKeycode(getDisplay(), sym); 1607 if (code == 0) { 1608 return 0; 1609 } 1610 long primary = XlibWrapper.XKeycodeToKeysym(getDisplay(), code, 0); 1611 if (sym != primary) { 1612 return 0; 1613 } 1614 return code; 1615 } finally { 1616 awtUnlock(); 1617 } 1618 } 1619 static boolean getModifierState( int jkc ) { 1620 int iKeyMask = 0; 1621 long ks = XKeysym.javaKeycode2Keysym( jkc ); 1622 int kc = XlibWrapper.XKeysymToKeycode(getDisplay(), ks); 1623 if (kc == 0) { 1624 return false; 1625 } 1626 awtLock(); 1627 try { 1628 XModifierKeymap modmap = new XModifierKeymap( 1629 XlibWrapper.XGetModifierMapping(getDisplay())); 1630 1631 int nkeys = modmap.get_max_keypermod(); 1632 1633 long map_ptr = modmap.get_modifiermap(); 1634 for( int k = 0; k < 8; k++ ) { 1635 for (int i = 0; i < nkeys; ++i) { 1636 int keycode = Native.getUByte(map_ptr, k * nkeys + i); 1637 if (keycode == 0) { 1638 continue; // ignore zero keycode 1639 } 1640 if (kc == keycode) { 1641 iKeyMask = 1 << k; 1642 break; 1643 } 1644 } 1645 if( iKeyMask != 0 ) { 1646 break; 1647 } 1648 } 1649 XlibWrapper.XFreeModifiermap(modmap.pData); 1650 if (iKeyMask == 0 ) { 1651 return false; 1652 } 1653 // Now we know to which modifier is assigned the keycode 1654 // correspondent to the keysym correspondent to the java 1655 // keycode. We are going to check a state of this modifier. 1656 // If a modifier is a weird one, we cannot help it. 1657 long window = 0; 1658 try{ 1659 // get any application window 1660 window = ((Long)(winMap.firstKey())).longValue(); 1661 }catch(NoSuchElementException nex) { 1662 // get root window 1663 window = getDefaultRootWindow(); 1664 } 1665 boolean res = XlibWrapper.XQueryPointer(getDisplay(), window, 1666 XlibWrapper.larg1, //root 1667 XlibWrapper.larg2, //child 1668 XlibWrapper.larg3, //root_x 1669 XlibWrapper.larg4, //root_y 1670 XlibWrapper.larg5, //child_x 1671 XlibWrapper.larg6, //child_y 1672 XlibWrapper.larg7);//mask 1673 int mask = Native.getInt(XlibWrapper.larg7); 1674 return ((mask & iKeyMask) != 0); 1675 } finally { 1676 awtUnlock(); 1677 } 1678 } 1679 1680 /* Assign meaning - alt, meta, etc. - to X modifiers mod1 ... mod5. 1681 * Only consider primary symbols on keycodes attached to modifiers. 1682 */ 1683 static void setupModifierMap() { 1684 final int metaL = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_L); 1685 final int metaR = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_R); 1686 final int altL = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_L); 1687 final int altR = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_R); 1688 final int numLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Num_Lock); 1689 final int modeSwitch = keysymToPrimaryKeycode(XKeySymConstants.XK_Mode_switch); 1690 final int shiftLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Shift_Lock); 1691 final int capsLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Caps_Lock); 1692 1693 final int modmask[] = { XConstants.ShiftMask, XConstants.LockMask, XConstants.ControlMask, XConstants.Mod1Mask, 1694 XConstants.Mod2Mask, XConstants.Mod3Mask, XConstants.Mod4Mask, XConstants.Mod5Mask }; 1695 1696 log.fine("In setupModifierMap"); 1697 awtLock(); 1698 try { 1699 XModifierKeymap modmap = new XModifierKeymap( 1700 XlibWrapper.XGetModifierMapping(getDisplay())); 1701 1702 int nkeys = modmap.get_max_keypermod(); 1703 1704 long map_ptr = modmap.get_modifiermap(); 1705 1706 for (int modn = XConstants.Mod1MapIndex; 1707 modn <= XConstants.Mod5MapIndex; 1708 ++modn) 1709 { 1710 for (int i = 0; i < nkeys; ++i) { 1711 /* for each keycode attached to this modifier */ 1712 int keycode = Native.getUByte(map_ptr, modn * nkeys + i); 1713 1714 if (keycode == 0) { 1715 break; 1716 } 1717 if (metaMask == 0 && 1718 (keycode == metaL || keycode == metaR)) 1719 { 1720 metaMask = modmask[modn]; 1721 break; 1722 } 1723 if (altMask == 0 && (keycode == altL || keycode == altR)) { 1724 altMask = modmask[modn]; 1725 break; 1726 } 1727 if (numLockMask == 0 && keycode == numLock) { 1728 numLockMask = modmask[modn]; 1729 break; 1730 } 1731 if (modeSwitchMask == 0 && keycode == modeSwitch) { 1732 modeSwitchMask = modmask[modn]; 1733 break; 1734 } 1735 continue; 1736 } 1737 } 1738 modLockIsShiftLock = 0; 1739 for (int j = 0; j < nkeys; ++j) { 1740 int keycode = Native.getUByte(map_ptr, XConstants.LockMapIndex * nkeys + j); 1741 if (keycode == 0) { 1742 break; 1743 } 1744 if (keycode == shiftLock) { 1745 modLockIsShiftLock = 1; 1746 break; 1747 } 1748 if (keycode == capsLock) { 1749 break; 1750 } 1751 } 1752 XlibWrapper.XFreeModifiermap(modmap.pData); 1753 } finally { 1754 awtUnlock(); 1755 } 1756 if (log.isLoggable(PlatformLogger.FINE)) { 1757 log.fine("metaMask = " + metaMask); 1758 log.fine("altMask = " + altMask); 1759 log.fine("numLockMask = " + numLockMask); 1760 log.fine("modeSwitchMask = " + modeSwitchMask); 1761 log.fine("modLockIsShiftLock = " + modLockIsShiftLock); 1762 } 1763 } 1764 1765 1766 private static SortedMap timeoutTasks; 1767 1768 /** 1769 * Removed the task from the list of waiting-to-be called tasks. 1770 * If the task has been scheduled several times removes only first one. 1771 */ 1772 static void remove(Runnable task) { 1773 if (task == null) { 1774 throw new NullPointerException("task is null"); 1775 } 1776 awtLock(); 1777 try { 1778 if (timeoutTaskLog.isLoggable(PlatformLogger.FINER)) { 1779 timeoutTaskLog.finer("Removing task " + task); 1780 } 1781 if (timeoutTasks == null) { 1782 if (timeoutTaskLog.isLoggable(PlatformLogger.FINER)) { 1783 timeoutTaskLog.finer("Task is not scheduled"); 1784 } 1785 return; 1786 } 1787 Collection values = timeoutTasks.values(); 1788 Iterator iter = values.iterator(); 1789 while (iter.hasNext()) { 1790 java.util.List list = (java.util.List)iter.next(); 1791 boolean removed = false; 1792 if (list.contains(task)) { 1793 list.remove(task); 1794 if (list.isEmpty()) { 1795 iter.remove(); 1796 } 1797 break; 1798 } 1799 } 1800 } finally { 1801 awtUnlock(); 1802 } 1803 } 1804 1805 static native void wakeup_poll(); 1806 1807 /** 1808 * Registers a Runnable which <code>run()</code> method will be called 1809 * once on the toolkit thread when a specified interval of time elapses. 1810 * 1811 * @param task a Runnable which <code>run</code> method will be called 1812 * on the toolkit thread when <code>interval</code> milliseconds 1813 * elapse 1814 * @param interval an interal in milliseconds 1815 * 1816 * @throws NullPointerException if <code>task</code> is <code>null</code> 1817 * @throws IllegalArgumentException if <code>interval</code> is not positive 1818 */ 1819 static void schedule(Runnable task, long interval) { 1820 if (task == null) { 1821 throw new NullPointerException("task is null"); 1822 } 1823 if (interval <= 0) { 1824 throw new IllegalArgumentException("interval " + interval + " is not positive"); 1825 } 1826 1827 awtLock(); 1828 try { 1829 if (timeoutTaskLog.isLoggable(PlatformLogger.FINER)) { 1830 timeoutTaskLog.finer("XToolkit.schedule(): current time={0}" + 1831 "; interval={1}" + 1832 "; task being added={2}" + "; tasks before addition={3}", 1833 Long.valueOf(System.currentTimeMillis()), Long.valueOf(interval), task, timeoutTasks); 1834 } 1835 1836 if (timeoutTasks == null) { 1837 timeoutTasks = new TreeMap(); 1838 } 1839 1840 Long time = Long.valueOf(System.currentTimeMillis() + interval); 1841 java.util.List tasks = (java.util.List)timeoutTasks.get(time); 1842 if (tasks == null) { 1843 tasks = new ArrayList(1); 1844 timeoutTasks.put(time, tasks); 1845 } 1846 tasks.add(task); 1847 1848 1849 if (timeoutTasks.get(timeoutTasks.firstKey()) == tasks && tasks.size() == 1) { 1850 // Added task became first task - poll won't know 1851 // about it so we need to wake it up 1852 wakeup_poll(); 1853 } 1854 } finally { 1855 awtUnlock(); 1856 } 1857 } 1858 1859 private long getNextTaskTime() { 1860 awtLock(); 1861 try { 1862 if (timeoutTasks == null || timeoutTasks.isEmpty()) { 1863 return -1L; 1864 } 1865 return (Long)timeoutTasks.firstKey(); 1866 } finally { 1867 awtUnlock(); 1868 } 1869 } 1870 1871 /** 1872 * Executes mature timeout tasks registered with schedule(). 1873 * Called from run() under awtLock. 1874 */ 1875 private static void callTimeoutTasks() { 1876 if (timeoutTaskLog.isLoggable(PlatformLogger.FINER)) { 1877 timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" + 1878 "; tasks={1}", Long.valueOf(System.currentTimeMillis()), timeoutTasks); 1879 } 1880 1881 if (timeoutTasks == null || timeoutTasks.isEmpty()) { 1882 return; 1883 } 1884 1885 Long currentTime = Long.valueOf(System.currentTimeMillis()); 1886 Long time = (Long)timeoutTasks.firstKey(); 1887 1888 while (time.compareTo(currentTime) <= 0) { 1889 java.util.List tasks = (java.util.List)timeoutTasks.remove(time); 1890 1891 for (Iterator iter = tasks.iterator(); iter.hasNext();) { 1892 Runnable task = (Runnable)iter.next(); 1893 1894 if (timeoutTaskLog.isLoggable(PlatformLogger.FINER)) { 1895 timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" + 1896 "; about to run task={1}", Long.valueOf(currentTime), task); 1897 } 1898 1899 try { 1900 task.run(); 1901 } catch (ThreadDeath td) { 1902 throw td; 1903 } catch (Throwable thr) { 1904 processException(thr); 1905 } 1906 } 1907 1908 if (timeoutTasks.isEmpty()) { 1909 break; 1910 } 1911 time = (Long)timeoutTasks.firstKey(); 1912 } 1913 } 1914 1915 static long getAwtDefaultFg() { 1916 return awt_defaultFg; 1917 } 1918 1919 static boolean isLeftMouseButton(MouseEvent me) { 1920 switch (me.getID()) { 1921 case MouseEvent.MOUSE_PRESSED: 1922 case MouseEvent.MOUSE_RELEASED: 1923 return (me.getButton() == MouseEvent.BUTTON1); 1924 case MouseEvent.MOUSE_ENTERED: 1925 case MouseEvent.MOUSE_EXITED: 1926 case MouseEvent.MOUSE_CLICKED: 1927 case MouseEvent.MOUSE_DRAGGED: 1928 return ((me.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0); 1929 } 1930 return false; 1931 } 1932 1933 static boolean isRightMouseButton(MouseEvent me) { 1934 int numButtons = ((Integer)getDefaultToolkit().getDesktopProperty("awt.mouse.numButtons")).intValue(); 1935 switch (me.getID()) { 1936 case MouseEvent.MOUSE_PRESSED: 1937 case MouseEvent.MOUSE_RELEASED: 1938 return ((numButtons == 2 && me.getButton() == MouseEvent.BUTTON2) || 1939 (numButtons > 2 && me.getButton() == MouseEvent.BUTTON3)); 1940 case MouseEvent.MOUSE_ENTERED: 1941 case MouseEvent.MOUSE_EXITED: 1942 case MouseEvent.MOUSE_CLICKED: 1943 case MouseEvent.MOUSE_DRAGGED: 1944 return ((numButtons == 2 && (me.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) || 1945 (numButtons > 2 && (me.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0)); 1946 } 1947 return false; 1948 } 1949 1950 static long reset_time_utc; 1951 static final long WRAP_TIME_MILLIS = Integer.MAX_VALUE; 1952 1953 /* 1954 * This function converts between the X server time (number of milliseconds 1955 * since the last server reset) and the UTC time for the 'when' field of an 1956 * InputEvent (or another event type with a timestamp). 1957 */ 1958 static long nowMillisUTC_offset(long server_offset) { 1959 // ported from awt_util.c 1960 /* 1961 * Because Time is of type 'unsigned long', it is possible that Time will 1962 * never wrap when using 64-bit Xlib. However, if a 64-bit client 1963 * connects to a 32-bit server, I suspect the values will still wrap. So 1964 * we should not attempt to remove the wrap checking even if _LP64 is 1965 * true. 1966 */ 1967 1968 long current_time_utc = System.currentTimeMillis(); 1969 if (log.isLoggable(PlatformLogger.FINER)) { 1970 log.finer("reset_time=" + reset_time_utc + ", current_time=" + current_time_utc 1971 + ", server_offset=" + server_offset + ", wrap_time=" + WRAP_TIME_MILLIS); 1972 } 1973 1974 if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) { 1975 reset_time_utc = System.currentTimeMillis() - getCurrentServerTime(); 1976 } 1977 1978 if (log.isLoggable(PlatformLogger.FINER)) { 1979 log.finer("result = " + (reset_time_utc + server_offset)); 1980 } 1981 return reset_time_utc + server_offset; 1982 } 1983 1984 /** 1985 * @see sun.awt.SunToolkit#needsXEmbedImpl 1986 */ 1987 protected boolean needsXEmbedImpl() { 1988 // XToolkit implements supports for XEmbed-client protocol and 1989 // requires the supports from the embedding host for it to work. 1990 return true; 1991 } 1992 1993 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { 1994 return (modalityType == null) || 1995 (modalityType == Dialog.ModalityType.MODELESS) || 1996 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) || 1997 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) || 1998 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL); 1999 } 2000 2001 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { 2002 return (exclusionType == null) || 2003 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) || 2004 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) || 2005 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); 2006 } 2007 2008 static EventQueue getEventQueue(Object target) { 2009 AppContext appContext = targetToAppContext(target); 2010 if (appContext != null) { 2011 return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); 2012 } 2013 return null; 2014 } 2015 2016 static void removeSourceEvents(EventQueue queue, Object source, boolean removeAllEvents) { 2017 try { 2018 m_removeSourceEvents.invoke(queue, source, removeAllEvents); 2019 } 2020 catch (IllegalAccessException e) 2021 { 2022 e.printStackTrace(); 2023 } 2024 catch (InvocationTargetException e) { 2025 e.printStackTrace(); 2026 } 2027 } 2028 2029 public boolean isAlwaysOnTopSupported() { 2030 for (XLayerProtocol proto : XWM.getWM().getProtocols(XLayerProtocol.class)) { 2031 if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) { 2032 return true; 2033 } 2034 } 2035 return false; 2036 } 2037 2038 public boolean useBufferPerWindow() { 2039 return XToolkit.getBackingStoreType() == XConstants.NotUseful; 2040 } 2041 2042 /** 2043 * Returns one of XConstants: NotUseful, WhenMapped or Always. 2044 * If backing store is not available on at least one screen, or 2045 * java2d uses DGA(which conflicts with backing store) on at least one screen, 2046 * or the string system property "sun.awt.backingStore" is neither "Always" 2047 * nor "WhenMapped", then the method returns XConstants.NotUseful. 2048 * Otherwise, if the system property "sun.awt.backingStore" is "WhenMapped", 2049 * then the method returns XConstants.WhenMapped. 2050 * Otherwise (i.e., if the system property "sun.awt.backingStore" is "Always"), 2051 * the method returns XConstants.Always. 2052 */ 2053 static int getBackingStoreType() { 2054 return backingStoreType; 2055 } 2056 2057 private static void setBackingStoreType() { 2058 String prop = (String)AccessController.doPrivileged( 2059 new sun.security.action.GetPropertyAction("sun.awt.backingStore")); 2060 2061 if (prop == null) { 2062 backingStoreType = XConstants.NotUseful; 2063 if (backingStoreLog.isLoggable(PlatformLogger.CONFIG)) { 2064 backingStoreLog.config("The system property sun.awt.backingStore is not set" + 2065 ", by default backingStore=NotUseful"); 2066 } 2067 return; 2068 } 2069 2070 if (backingStoreLog.isLoggable(PlatformLogger.CONFIG)) { 2071 backingStoreLog.config("The system property sun.awt.backingStore is " + prop); 2072 } 2073 prop = prop.toLowerCase(); 2074 if (prop.equals("always")) { 2075 backingStoreType = XConstants.Always; 2076 } else if (prop.equals("whenmapped")) { 2077 backingStoreType = XConstants.WhenMapped; 2078 } else { 2079 backingStoreType = XConstants.NotUseful; 2080 } 2081 2082 if (backingStoreLog.isLoggable(PlatformLogger.CONFIG)) { 2083 backingStoreLog.config("backingStore(as provided by the system property)=" + 2084 ( backingStoreType == XConstants.NotUseful ? "NotUseful" 2085 : backingStoreType == XConstants.WhenMapped ? 2086 "WhenMapped" : "Always") ); 2087 } 2088 2089 if (sun.java2d.x11.X11SurfaceData.isDgaAvailable()) { 2090 backingStoreType = XConstants.NotUseful; 2091 2092 if (backingStoreLog.isLoggable(PlatformLogger.CONFIG)) { 2093 backingStoreLog.config("DGA is available, backingStore=NotUseful"); 2094 } 2095 2096 return; 2097 } 2098 2099 awtLock(); 2100 try { 2101 int screenCount = XlibWrapper.ScreenCount(getDisplay()); 2102 for (int i = 0; i < screenCount; i++) { 2103 if (XlibWrapper.DoesBackingStore(XlibWrapper.ScreenOfDisplay(getDisplay(), i)) 2104 == XConstants.NotUseful) { 2105 backingStoreType = XConstants.NotUseful; 2106 2107 if (backingStoreLog.isLoggable(PlatformLogger.CONFIG)) { 2108 backingStoreLog.config("Backing store is not available on the screen " + 2109 i + ", backingStore=NotUseful"); 2110 } 2111 2112 return; 2113 } 2114 } 2115 } finally { 2116 awtUnlock(); 2117 } 2118 } 2119 2120 /** 2121 * One of XConstants: NotUseful, WhenMapped or Always. 2122 */ 2123 private static int backingStoreType; 2124 2125 static final int XSUN_KP_BEHAVIOR = 1; 2126 static final int XORG_KP_BEHAVIOR = 2; 2127 static final int IS_SUN_KEYBOARD = 1; 2128 static final int IS_NONSUN_KEYBOARD = 2; 2129 static final int IS_KANA_KEYBOARD = 1; 2130 static final int IS_NONKANA_KEYBOARD = 2; 2131 2132 2133 static int awt_IsXsunKPBehavior = 0; 2134 static boolean awt_UseXKB = false; 2135 static boolean awt_UseXKB_Calls = false; 2136 static int awt_XKBBaseEventCode = 0; 2137 static int awt_XKBEffectiveGroup = 0; // so far, I don't use it leaving all calculations 2138 // to XkbTranslateKeyCode 2139 static long awt_XKBDescPtr = 0; 2140 2141 /** 2142 * Check for Xsun convention regarding numpad keys. 2143 * Xsun and some other servers (i.e. derived from Xsun) 2144 * under certain conditions process numpad keys unlike Xorg. 2145 */ 2146 static boolean isXsunKPBehavior() { 2147 awtLock(); 2148 try { 2149 if( awt_IsXsunKPBehavior == 0 ) { 2150 if( XlibWrapper.IsXsunKPBehavior(getDisplay()) ) { 2151 awt_IsXsunKPBehavior = XSUN_KP_BEHAVIOR; 2152 }else{ 2153 awt_IsXsunKPBehavior = XORG_KP_BEHAVIOR; 2154 } 2155 } 2156 return awt_IsXsunKPBehavior == XSUN_KP_BEHAVIOR ? true : false; 2157 } finally { 2158 awtUnlock(); 2159 } 2160 } 2161 2162 static int sunOrNotKeyboard = 0; 2163 static int kanaOrNotKeyboard = 0; 2164 static void resetKeyboardSniffer() { 2165 sunOrNotKeyboard = 0; 2166 kanaOrNotKeyboard = 0; 2167 } 2168 static boolean isSunKeyboard() { 2169 if( sunOrNotKeyboard == 0 ) { 2170 if( XlibWrapper.IsSunKeyboard( getDisplay() )) { 2171 sunOrNotKeyboard = IS_SUN_KEYBOARD; 2172 }else{ 2173 sunOrNotKeyboard = IS_NONSUN_KEYBOARD; 2174 } 2175 } 2176 return (sunOrNotKeyboard == IS_SUN_KEYBOARD); 2177 } 2178 static boolean isKanaKeyboard() { 2179 if( kanaOrNotKeyboard == 0 ) { 2180 if( XlibWrapper.IsKanaKeyboard( getDisplay() )) { 2181 kanaOrNotKeyboard = IS_KANA_KEYBOARD; 2182 }else{ 2183 kanaOrNotKeyboard = IS_NONKANA_KEYBOARD; 2184 } 2185 } 2186 return (kanaOrNotKeyboard == IS_KANA_KEYBOARD); 2187 } 2188 static boolean isXKBenabled() { 2189 awtLock(); 2190 try { 2191 return awt_UseXKB; 2192 } finally { 2193 awtUnlock(); 2194 } 2195 } 2196 2197 /** 2198 Query XKEYBOARD extension. 2199 If possible, initialize xkb library. 2200 */ 2201 static boolean tryXKB() { 2202 awtLock(); 2203 try { 2204 String name = "XKEYBOARD"; 2205 // First, if there is extension at all. 2206 awt_UseXKB = XlibWrapper.XQueryExtension( getDisplay(), name, XlibWrapper.larg1, XlibWrapper.larg2, XlibWrapper.larg3); 2207 if( awt_UseXKB ) { 2208 // There is a keyboard extension. Check if a client library is compatible. 2209 // If not, don't use xkb calls. 2210 // In this case we still may be Xkb-capable application. 2211 awt_UseXKB_Calls = XlibWrapper.XkbLibraryVersion( XlibWrapper.larg1, XlibWrapper.larg2); 2212 if( awt_UseXKB_Calls ) { 2213 awt_UseXKB_Calls = XlibWrapper.XkbQueryExtension( getDisplay(), XlibWrapper.larg1, XlibWrapper.larg2, 2214 XlibWrapper.larg3, XlibWrapper.larg4, XlibWrapper.larg5); 2215 if( awt_UseXKB_Calls ) { 2216 awt_XKBBaseEventCode = Native.getInt(XlibWrapper.larg2); 2217 XlibWrapper.XkbSelectEvents (getDisplay(), 2218 XConstants.XkbUseCoreKbd, 2219 XConstants.XkbNewKeyboardNotifyMask | 2220 XConstants.XkbMapNotifyMask ,//| 2221 //XConstants.XkbStateNotifyMask, 2222 XConstants.XkbNewKeyboardNotifyMask | 2223 XConstants.XkbMapNotifyMask );//| 2224 //XConstants.XkbStateNotifyMask); 2225 2226 XlibWrapper.XkbSelectEventDetails(getDisplay(), XConstants.XkbUseCoreKbd, 2227 XConstants.XkbStateNotify, 2228 XConstants.XkbGroupStateMask, 2229 XConstants.XkbGroupStateMask); 2230 //XXX ? XkbGroupLockMask last, XkbAllStateComponentsMask before last? 2231 awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(), 2232 XConstants.XkbKeyTypesMask | 2233 XConstants.XkbKeySymsMask | 2234 XConstants.XkbModifierMapMask | 2235 XConstants.XkbVirtualModsMask, 2236 XConstants.XkbUseCoreKbd); 2237 } 2238 } 2239 } 2240 return awt_UseXKB; 2241 } finally { 2242 awtUnlock(); 2243 } 2244 } 2245 static boolean canUseXKBCalls() { 2246 awtLock(); 2247 try { 2248 return awt_UseXKB_Calls; 2249 } finally { 2250 awtUnlock(); 2251 } 2252 } 2253 static int getXKBEffectiveGroup() { 2254 awtLock(); 2255 try { 2256 return awt_XKBEffectiveGroup; 2257 } finally { 2258 awtUnlock(); 2259 } 2260 } 2261 static int getXKBBaseEventCode() { 2262 awtLock(); 2263 try { 2264 return awt_XKBBaseEventCode; 2265 } finally { 2266 awtUnlock(); 2267 } 2268 } 2269 static long getXKBKbdDesc() { 2270 awtLock(); 2271 try { 2272 return awt_XKBDescPtr; 2273 } finally { 2274 awtUnlock(); 2275 } 2276 } 2277 void freeXKB() { 2278 awtLock(); 2279 try { 2280 if (awt_UseXKB_Calls && awt_XKBDescPtr != 0) { 2281 XlibWrapper.XkbFreeKeyboard(awt_XKBDescPtr, 0xFF, true); 2282 awt_XKBDescPtr = 0; 2283 } 2284 } finally { 2285 awtUnlock(); 2286 } 2287 } 2288 private void processXkbChanges(XEvent ev) { 2289 // mapping change --> refresh kbd map 2290 // state change --> get a new effective group; do I really need it 2291 // or that should be left for XkbTranslateKeyCode? 2292 XkbEvent xke = new XkbEvent( ev.getPData() ); 2293 int xkb_type = xke.get_any().get_xkb_type(); 2294 switch( xkb_type ) { 2295 case XConstants.XkbNewKeyboardNotify : 2296 if( awt_XKBDescPtr != 0 ) { 2297 freeXKB(); 2298 } 2299 awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(), 2300 XConstants.XkbKeyTypesMask | 2301 XConstants.XkbKeySymsMask | 2302 XConstants.XkbModifierMapMask | 2303 XConstants.XkbVirtualModsMask, 2304 XConstants.XkbUseCoreKbd); 2305 //System.out.println("XkbNewKeyboard:"+(xke.get_new_kbd())); 2306 break; 2307 case XConstants.XkbMapNotify : 2308 //TODO: provide a simple unit test. 2309 XlibWrapper.XkbGetUpdatedMap(getDisplay(), 2310 XConstants.XkbKeyTypesMask | 2311 XConstants.XkbKeySymsMask | 2312 XConstants.XkbModifierMapMask | 2313 XConstants.XkbVirtualModsMask, 2314 awt_XKBDescPtr); 2315 //System.out.println("XkbMap:"+(xke.get_map())); 2316 break; 2317 case XConstants.XkbStateNotify : 2318 // May use it later e.g. to obtain an effective group etc. 2319 //System.out.println("XkbState:"+(xke.get_state())); 2320 break; 2321 default: 2322 //System.out.println("XkbEvent of xkb_type "+xkb_type); 2323 break; 2324 } 2325 } 2326 2327 private static long eventNumber; 2328 public static long getEventNumber() { 2329 awtLock(); 2330 try { 2331 return eventNumber; 2332 } finally { 2333 awtUnlock(); 2334 } 2335 } 2336 2337 private static XEventDispatcher oops_waiter; 2338 private static boolean oops_updated; 2339 private static boolean oops_failed; 2340 private XAtom oops; 2341 private static final long WORKAROUND_SLEEP = 100; 2342 2343 /** 2344 * @inheritDoc 2345 */ 2346 protected boolean syncNativeQueue(final long timeout) { 2347 XBaseWindow win = XBaseWindow.getXAWTRootWindow(); 2348 2349 if (oops_waiter == null) { 2350 oops_waiter = new XEventDispatcher() { 2351 public void dispatchEvent(XEvent e) { 2352 if (e.get_type() == XConstants.SelectionNotify) { 2353 XSelectionEvent pe = e.get_xselection(); 2354 if (pe.get_property() == oops.getAtom()) { 2355 oops_updated = true; 2356 awtLockNotifyAll(); 2357 } else if (pe.get_selection() == XAtom.get("WM_S0").getAtom() && 2358 pe.get_target() == XAtom.get("VERSION").getAtom() && 2359 pe.get_property() == 0 && 2360 XlibWrapper.XGetSelectionOwner(getDisplay(), XAtom.get("WM_S0").getAtom()) == 0) 2361 { 2362 // WM forgot to acquire selection or there is no WM 2363 oops_failed = true; 2364 awtLockNotifyAll(); 2365 } 2366 2367 } 2368 } 2369 }; 2370 } 2371 2372 if (oops == null) { 2373 oops = XAtom.get("OOPS"); 2374 } 2375 2376 awtLock(); 2377 try { 2378 addEventDispatcher(win.getWindow(), oops_waiter); 2379 2380 oops_updated = false; 2381 oops_failed = false; 2382 // Wait for selection notify for oops on win 2383 long event_number = getEventNumber(); 2384 XAtom atom = XAtom.get("WM_S0"); 2385 eventLog.finer("WM_S0 selection owner {0}", XlibWrapper.XGetSelectionOwner(getDisplay(), atom.getAtom())); 2386 XlibWrapper.XConvertSelection(getDisplay(), atom.getAtom(), 2387 XAtom.get("VERSION").getAtom(), oops.getAtom(), 2388 win.getWindow(), XConstants.CurrentTime); 2389 XSync(); 2390 2391 2392 eventLog.finer("Requested OOPS"); 2393 2394 long start = System.currentTimeMillis(); 2395 while (!oops_updated && !oops_failed) { 2396 try { 2397 awtLockWait(timeout); 2398 } catch (InterruptedException e) { 2399 throw new RuntimeException(e); 2400 } 2401 // This "while" is a protection from spurious 2402 // wake-ups. However, we shouldn't wait for too long 2403 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) { 2404 throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start)); 2405 } 2406 } 2407 if (oops_failed && getEventNumber() - event_number == 1) { 2408 // If selection update failed we can simply wait some time 2409 // hoping some events will arrive 2410 awtUnlock(); 2411 eventLog.finest("Emergency sleep"); 2412 try { 2413 Thread.sleep(WORKAROUND_SLEEP); 2414 } catch (InterruptedException ie) { 2415 throw new RuntimeException(ie); 2416 } finally { 2417 awtLock(); 2418 } 2419 } 2420 return getEventNumber() - event_number > 2; 2421 } finally { 2422 removeEventDispatcher(win.getWindow(), oops_waiter); 2423 eventLog.finer("Exiting syncNativeQueue"); 2424 awtUnlock(); 2425 } 2426 } 2427 public void grab(Window w) { 2428 if (w.getPeer() != null) { 2429 ((XWindowPeer)w.getPeer()).setGrab(true); 2430 } 2431 } 2432 2433 public void ungrab(Window w) { 2434 if (w.getPeer() != null) { 2435 ((XWindowPeer)w.getPeer()).setGrab(false); 2436 } 2437 } 2438 /** 2439 * Returns if the java.awt.Desktop class is supported on the current 2440 * desktop. 2441 * <p> 2442 * The methods of java.awt.Desktop class are supported on the Gnome desktop. 2443 * Check if the running desktop is Gnome by checking the window manager. 2444 */ 2445 public boolean isDesktopSupported(){ 2446 return XDesktopPeer.isDesktopSupported(); 2447 } 2448 2449 public DesktopPeer createDesktopPeer(Desktop target){ 2450 return new XDesktopPeer(); 2451 } 2452 2453 public boolean areExtraMouseButtonsEnabled() throws HeadlessException { 2454 return areExtraMouseButtonsEnabled; 2455 } 2456 2457 @Override 2458 public boolean isWindowOpacitySupported() { 2459 XNETProtocol net_protocol = XWM.getWM().getNETProtocol(); 2460 2461 if (net_protocol == null) { 2462 return false; 2463 } 2464 2465 return net_protocol.doOpacityProtocol(); 2466 } 2467 2468 @Override 2469 public boolean isWindowShapingSupported() { 2470 return XlibUtil.isShapingSupported(); 2471 } 2472 2473 @Override 2474 public boolean isWindowTranslucencySupported() { 2475 //NOTE: it may not be supported. The actual check is being performed 2476 // at com.sun.awt.AWTUtilities(). In X11 we need to check 2477 // whether there's any translucency-capable GC available. 2478 return true; 2479 } 2480 2481 @Override 2482 public boolean isTranslucencyCapable(GraphicsConfiguration gc) { 2483 if (!(gc instanceof X11GraphicsConfig)) { 2484 return false; 2485 } 2486 return ((X11GraphicsConfig)gc).isTranslucencyCapable(); 2487 } 2488 2489 /** 2490 * Returns the value of "sun.awt.disablegrab" property. Default 2491 * value is {@code false}. 2492 */ 2493 public static boolean getSunAwtDisableGrab() { 2494 return AccessController.doPrivileged(new GetBooleanAction("sun.awt.disablegrab")); 2495 } 2496 }