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