1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt;
  27 
  28 import java.awt.*;
  29 import static java.awt.RenderingHints.*;
  30 import java.awt.dnd.*;
  31 import java.awt.dnd.peer.DragSourceContextPeer;
  32 import java.awt.peer.*;
  33 import java.awt.event.WindowEvent;
  34 import java.awt.event.KeyEvent;
  35 import java.awt.image.*;
  36 import java.awt.TrayIcon;
  37 import java.awt.SystemTray;
  38 import java.net.URL;
  39 import java.util.*;
  40 import java.util.concurrent.TimeUnit;
  41 import java.util.concurrent.locks.Condition;
  42 import java.util.concurrent.locks.Lock;
  43 import java.util.concurrent.locks.ReentrantLock;
  44 import sun.util.logging.PlatformLogger;
  45 import sun.misc.SoftCache;
  46 import sun.font.FontDesignMetrics;
  47 import sun.awt.im.InputContext;
  48 import sun.awt.image.*;
  49 import sun.security.action.GetPropertyAction;
  50 import sun.security.action.GetBooleanAction;
  51 import java.lang.reflect.Field;
  52 import java.lang.reflect.Method;
  53 import java.lang.reflect.Constructor;
  54 import java.lang.reflect.InvocationTargetException;
  55 import java.security.AccessController;
  56 import java.security.PrivilegedAction;
  57 import java.security.PrivilegedActionException;
  58 import java.security.PrivilegedExceptionAction;
  59 
  60 public abstract class SunToolkit extends Toolkit
  61     implements WindowClosingSupport, WindowClosingListener,
  62     ComponentFactory, InputMethodSupport, KeyboardFocusManagerPeerProvider {
  63 
  64     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.SunToolkit");
  65 
  66     /* Load debug settings for native code */
  67     static {
  68         if (AccessController.doPrivileged(new GetBooleanAction("sun.awt.nativedebug"))) {
  69             DebugSettings.init();
  70         }
  71     };
  72 
  73     /**
  74      * Special mask for the UngrabEvent events, in addition to the
  75      * public masks defined in AWTEvent.  Should be used as the mask
  76      * value for Toolkit.addAWTEventListener.
  77      */
  78     public static final int GRAB_EVENT_MASK = 0x80000000;
  79 
  80     private static Method  wakeupMethod;
  81     /* The key to put()/get() the PostEventQueue into/from the AppContext.
  82      */
  83     private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";
  84 
  85     /**
  86      * Number of buttons.
  87      * By default it's taken from the system. If system value does not
  88      * fit into int type range, use our own MAX_BUTTONS_SUPPORT value.
  89      */
  90     protected static int numberOfButtons = 0;
  91 
  92 
  93     /* XFree standard mention 24 buttons as maximum:
  94      * http://www.xfree86.org/current/mouse.4.html
  95      * We workaround systems supporting more than 24 buttons.
  96      * Otherwise, we have to use long type values as masks
  97      * which leads to API change.
  98      * InputEvent.BUTTON_DOWN_MASK may contain only 21 masks due to
  99      * the 4-bytes limit for the int type. (CR 6799099)
 100      * One more bit is reserved for FIRST_HIGH_BIT.
 101      */
 102     public final static int MAX_BUTTONS_SUPPORTED = 20;
 103 
 104     public SunToolkit() {
 105         Runnable initEQ = new Runnable() {
 106             public void run () {
 107                 EventQueue eventQueue;
 108 
 109                 String eqName = System.getProperty("AWT.EventQueueClass",
 110                                                    "java.awt.EventQueue");
 111 
 112                 try {
 113                     eventQueue = (EventQueue)Class.forName(eqName).newInstance();
 114                 } catch (Exception e) {
 115                     e.printStackTrace();
 116                     System.err.println("Failed loading " + eqName + ": " + e);
 117                     eventQueue = new EventQueue();
 118                 }
 119                 AppContext appContext = AppContext.getAppContext();
 120                 appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
 121 
 122                 PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
 123                 appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
 124             }
 125         };
 126 
 127         initEQ.run();
 128     }
 129 
 130     public boolean useBufferPerWindow() {
 131         return false;
 132     }
 133 
 134     public abstract WindowPeer createWindow(Window target)
 135         throws HeadlessException;
 136 
 137     public abstract FramePeer createFrame(Frame target)
 138         throws HeadlessException;
 139 
 140     public abstract DialogPeer createDialog(Dialog target)
 141         throws HeadlessException;
 142 
 143     public abstract ButtonPeer createButton(Button target)
 144         throws HeadlessException;
 145 
 146     public abstract TextFieldPeer createTextField(TextField target)
 147         throws HeadlessException;
 148 
 149     public abstract ChoicePeer createChoice(Choice target)
 150         throws HeadlessException;
 151 
 152     public abstract LabelPeer createLabel(Label target)
 153         throws HeadlessException;
 154 
 155     public abstract ListPeer createList(java.awt.List target)
 156         throws HeadlessException;
 157 
 158     public abstract CheckboxPeer createCheckbox(Checkbox target)
 159         throws HeadlessException;
 160 
 161     public abstract ScrollbarPeer createScrollbar(Scrollbar target)
 162         throws HeadlessException;
 163 
 164     public abstract ScrollPanePeer createScrollPane(ScrollPane target)
 165         throws HeadlessException;
 166 
 167     public abstract TextAreaPeer createTextArea(TextArea target)
 168         throws HeadlessException;
 169 
 170     public abstract FileDialogPeer createFileDialog(FileDialog target)
 171         throws HeadlessException;
 172 
 173     public abstract MenuBarPeer createMenuBar(MenuBar target)
 174         throws HeadlessException;
 175 
 176     public abstract MenuPeer createMenu(Menu target)
 177         throws HeadlessException;
 178 
 179     public abstract PopupMenuPeer createPopupMenu(PopupMenu target)
 180         throws HeadlessException;
 181 
 182     public abstract MenuItemPeer createMenuItem(MenuItem target)
 183         throws HeadlessException;
 184 
 185     public abstract CheckboxMenuItemPeer createCheckboxMenuItem(
 186         CheckboxMenuItem target)
 187         throws HeadlessException;
 188 
 189     public abstract DragSourceContextPeer createDragSourceContextPeer(
 190         DragGestureEvent dge)
 191         throws InvalidDnDOperationException;
 192 
 193     public abstract TrayIconPeer createTrayIcon(TrayIcon target)
 194         throws HeadlessException, AWTException;
 195 
 196     public abstract SystemTrayPeer createSystemTray(SystemTray target);
 197 
 198     public abstract boolean isTraySupported();
 199 
 200     public abstract FontPeer getFontPeer(String name, int style);
 201 
 202     public abstract RobotPeer createRobot(Robot target, GraphicsDevice screen)
 203         throws AWTException;
 204 
 205     public abstract KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager)
 206         throws HeadlessException;
 207 
 208     /**
 209      * The AWT lock is typically only used on Unix platforms to synchronize
 210      * access to Xlib, OpenGL, etc.  However, these methods are implemented
 211      * in SunToolkit so that they can be called from shared code (e.g.
 212      * from the OGL pipeline) or from the X11 pipeline regardless of whether
 213      * XToolkit or MToolkit is currently in use.  There are native macros
 214      * (such as AWT_LOCK) defined in awt.h, so if the implementation of these
 215      * methods is changed, make sure it is compatible with the native macros.
 216      *
 217      * Note: The following methods (awtLock(), awtUnlock(), etc) should be
 218      * used in place of:
 219      *     synchronized (getAWTLock()) {
 220      *         ...
 221      *     }
 222      *
 223      * By factoring these methods out specially, we are able to change the
 224      * implementation of these methods (e.g. use more advanced locking
 225      * mechanisms) without impacting calling code.
 226      *
 227      * Sample usage:
 228      *     private void doStuffWithXlib() {
 229      *         assert !SunToolkit.isAWTLockHeldByCurrentThread();
 230      *         SunToolkit.awtLock();
 231      *         try {
 232      *             ...
 233      *             XlibWrapper.XDoStuff();
 234      *         } finally {
 235      *             SunToolkit.awtUnlock();
 236      *         }
 237      *     }
 238      */
 239 
 240     private static final ReentrantLock AWT_LOCK = new ReentrantLock();
 241     private static final Condition AWT_LOCK_COND = AWT_LOCK.newCondition();
 242 
 243     public static final void awtLock() {
 244         AWT_LOCK.lock();
 245     }
 246 
 247     public static final boolean awtTryLock() {
 248         return AWT_LOCK.tryLock();
 249     }
 250 
 251     public static final void awtUnlock() {
 252         AWT_LOCK.unlock();
 253     }
 254 
 255     public static final void awtLockWait()
 256         throws InterruptedException
 257     {
 258         AWT_LOCK_COND.await();
 259     }
 260 
 261     public static final void awtLockWait(long timeout)
 262         throws InterruptedException
 263     {
 264         AWT_LOCK_COND.await(timeout, TimeUnit.MILLISECONDS);
 265     }
 266 
 267     public static final void awtLockNotify() {
 268         AWT_LOCK_COND.signal();
 269     }
 270 
 271     public static final void awtLockNotifyAll() {
 272         AWT_LOCK_COND.signalAll();
 273     }
 274 
 275     public static final boolean isAWTLockHeldByCurrentThread() {
 276         return AWT_LOCK.isHeldByCurrentThread();
 277     }
 278 
 279     /*
 280      * Create a new AppContext, along with its EventQueue, for a
 281      * new ThreadGroup.  Browser code, for example, would use this
 282      * method to create an AppContext & EventQueue for an Applet.
 283      */
 284     public static AppContext createNewAppContext() {
 285         ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
 286         // Create appContext before initialization of EventQueue, so all
 287         // the calls to AppContext.getAppContext() from EventQueue ctor
 288         // return correct values
 289         AppContext appContext = new AppContext(threadGroup);
 290 
 291         EventQueue eventQueue;
 292         String eqName = System.getProperty("AWT.EventQueueClass",
 293                                            "java.awt.EventQueue");
 294         try {
 295             eventQueue = (EventQueue)Class.forName(eqName).newInstance();
 296         } catch (Exception e) {
 297             System.err.println("Failed loading " + eqName + ": " + e);
 298             eventQueue = new EventQueue();
 299         }
 300         appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
 301 
 302         PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
 303         appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
 304 
 305         return appContext;
 306     }
 307 
 308     public static Field getField(final Class klass, final String fieldName) {
 309         return AccessController.doPrivileged(new PrivilegedAction<Field>() {
 310             public Field run() {
 311                 try {
 312                     Field field = klass.getDeclaredField(fieldName);
 313                     assert (field != null);
 314                     field.setAccessible(true);
 315                     return field;
 316                 } catch (SecurityException e) {
 317                     assert false;
 318                 } catch (NoSuchFieldException e) {
 319                     assert false;
 320                 }
 321                 return null;
 322             }//run
 323         });
 324     }
 325 
 326     static void wakeupEventQueue(EventQueue q, boolean isShutdown){
 327         if (wakeupMethod == null){
 328             wakeupMethod = (Method)AccessController.doPrivileged(new PrivilegedAction(){
 329                     public Object run(){
 330                         try {
 331                             Method method  = EventQueue.class.getDeclaredMethod("wakeup",new Class [] {Boolean.TYPE} );
 332                             if (method != null) {
 333                                 method.setAccessible(true);
 334                             }
 335                             return method;
 336                         } catch (NoSuchMethodException e) {
 337                             assert false;
 338                         } catch (SecurityException e) {
 339                             assert false;
 340                         }
 341                         return null;
 342                     }//run
 343                 });
 344         }
 345         try{
 346             if (wakeupMethod != null){
 347                 wakeupMethod.invoke(q, new Object[]{Boolean.valueOf(isShutdown)});
 348             }
 349         } catch (InvocationTargetException e){
 350             assert false;
 351         } catch (IllegalAccessException e) {
 352             assert false;
 353         }
 354     }
 355 
 356     /*
 357      * Fetch the peer associated with the given target (as specified
 358      * in the peer creation method).  This can be used to determine
 359      * things like what the parent peer is.  If the target is null
 360      * or the target can't be found (either because the a peer was
 361      * never created for it or the peer was disposed), a null will
 362      * be returned.
 363      */
 364     protected static Object targetToPeer(Object target) {
 365         if (target != null && !GraphicsEnvironment.isHeadless()) {
 366             return AWTAutoShutdown.getInstance().getPeer(target);
 367         }
 368         return null;
 369     }
 370 
 371     protected static void targetCreatedPeer(Object target, Object peer) {
 372         if (target != null && peer != null &&
 373             !GraphicsEnvironment.isHeadless())
 374         {
 375             AWTAutoShutdown.getInstance().registerPeer(target, peer);
 376         }
 377     }
 378 
 379     protected static void targetDisposedPeer(Object target, Object peer) {
 380         if (target != null && peer != null &&
 381             !GraphicsEnvironment.isHeadless())
 382         {
 383             AWTAutoShutdown.getInstance().unregisterPeer(target, peer);
 384         }
 385     }
 386 
 387     // Maps from non-Component/MenuComponent to AppContext.
 388     // WeakHashMap<Component,AppContext>
 389     private static final Map appContextMap =
 390         Collections.synchronizedMap(new WeakHashMap());
 391 
 392     /**
 393      * Sets the appContext field of target. If target is not a Component or
 394      * MenuComponent, this returns false.
 395      */
 396     private static boolean setAppContext(Object target,
 397                                          AppContext context) {
 398         if (target instanceof Component) {
 399             AWTAccessor.getComponentAccessor().
 400                 setAppContext((Component)target, context);
 401         } else if (target instanceof MenuComponent) {
 402             AWTAccessor.getMenuComponentAccessor().
 403                 setAppContext((MenuComponent)target, context);
 404         } else {
 405             return false;
 406         }
 407         return true;
 408     }
 409 
 410     /**
 411      * Returns the appContext field for target. If target is not a
 412      * Component or MenuComponent this returns null.
 413      */
 414     private static AppContext getAppContext(Object target) {
 415         if (target instanceof Component) {
 416             return AWTAccessor.getComponentAccessor().
 417                        getAppContext((Component)target);
 418         } else if (target instanceof MenuComponent) {
 419             return AWTAccessor.getMenuComponentAccessor().
 420                        getAppContext((MenuComponent)target);
 421         } else {
 422             return null;
 423         }
 424     }
 425 
 426     /*
 427      * Fetch the AppContext associated with the given target.
 428      * This can be used to determine things like which EventQueue
 429      * to use for posting events to a Component.  If the target is
 430      * null or the target can't be found, a null with be returned.
 431      */
 432     public static AppContext targetToAppContext(Object target) {
 433         if (target == null || GraphicsEnvironment.isHeadless()) {
 434             return null;
 435         }
 436         AppContext context = getAppContext(target);
 437         if (context == null) {
 438             // target is not a Component/MenuComponent, try the
 439             // appContextMap.
 440             context = (AppContext)appContextMap.get(target);
 441         }
 442         return context;
 443     }
 444 
 445      /**
 446       * Sets the synchronous status of focus requests on lightweight
 447       * components in the specified window to the specified value.
 448       * If the boolean parameter is <code>true</code> then the focus
 449       * requests on lightweight components will be performed
 450       * synchronously, if it is <code>false</code>, then asynchronously.
 451       * By default, all windows have their lightweight request status
 452       * set to asynchronous.
 453       * <p>
 454       * The application can only set the status of lightweight focus
 455       * requests to synchronous for any of its windows if it doesn't
 456       * perform focus transfers between different heavyweight containers.
 457       * In this case the observable focus behaviour is the same as with
 458       * asynchronous status.
 459       * <p>
 460       * If the application performs focus transfer between different
 461       * heavyweight containers and sets the lightweight focus request
 462       * status to synchronous for any of its windows, then further focus
 463       * behaviour is unspecified.
 464       * <p>
 465       * @param    w window for which the lightweight focus request status
 466       *             should be set
 467       * @param    status the value of lightweight focus request status
 468       */
 469 
 470     public static void setLWRequestStatus(Window changed,boolean status){
 471         AWTAccessor.getWindowAccessor().setLWRequestStatus(changed, status);
 472     };
 473 
 474     public static void checkAndSetPolicy(Container cont, boolean isSwingCont)
 475     {
 476         FocusTraversalPolicy defaultPolicy = KeyboardFocusManager
 477             .getCurrentKeyboardFocusManager().getDefaultFocusTraversalPolicy();
 478 
 479         String toolkitName = Toolkit.getDefaultToolkit().getClass().getName();
 480         // if this is not XAWT then use default policy
 481         // because Swing change it
 482         if (!"sun.awt.X11.XToolkit".equals(toolkitName)) {
 483             cont.setFocusTraversalPolicy(defaultPolicy);
 484             return;
 485         }
 486 
 487         String policyName = defaultPolicy.getClass().getName();
 488 
 489         if (DefaultFocusTraversalPolicy.class != defaultPolicy.getClass()) {
 490             // Policy was changed
 491             // Check if it is awt policy or swing policy
 492             // If it is Swing policy we shouldn't use it in AWT frames
 493             // If it is AWT policy  we shouldn't use it in Swing frames
 494             // Otherwise we should use this policy
 495             if (policyName.startsWith("java.awt.")) {
 496                 // AWT
 497                 if (isSwingCont) {
 498                     // Can't use AWT policy in Swing windows - should use Swing's one.
 499                     defaultPolicy = createLayoutPolicy();
 500                 } else {
 501                     // New awt policy.
 502                 }
 503             } else if (policyName.startsWith("javax.swing.")) {
 504                 if (isSwingCont) {
 505                     // New Swing's policy
 506                 } else {
 507                     defaultPolicy = new DefaultFocusTraversalPolicy();
 508                 }
 509             }
 510         } else {
 511             // Policy is default, use different default policy for swing
 512             if (isSwingCont) {
 513                 defaultPolicy = createLayoutPolicy();
 514             }
 515         }
 516         cont.setFocusTraversalPolicy(defaultPolicy);
 517     }
 518 
 519     private static FocusTraversalPolicy createLayoutPolicy() {
 520         FocusTraversalPolicy policy = null;
 521         try {
 522             Class layoutPolicyClass =
 523                 Class.forName("javax.swing.LayoutFocusTraversalPolicy");
 524             policy = (FocusTraversalPolicy) layoutPolicyClass.newInstance();
 525         }
 526         catch (ClassNotFoundException e) {
 527             assert false;
 528         }
 529         catch (InstantiationException e) {
 530             assert false;
 531         }
 532         catch (IllegalAccessException e) {
 533             assert false;
 534         }
 535 
 536         return policy;
 537     }
 538 
 539     /*
 540      * Insert a mapping from target to AppContext, for later retrieval
 541      * via targetToAppContext() above.
 542      */
 543     public static void insertTargetMapping(Object target, AppContext appContext) {
 544         if (!GraphicsEnvironment.isHeadless()) {
 545             if (!setAppContext(target, appContext)) {
 546                 // Target is not a Component/MenuComponent, use the private Map
 547                 // instead.
 548                 appContextMap.put(target, appContext);
 549             }
 550         }
 551     }
 552 
 553     /*
 554      * Post an AWTEvent to the Java EventQueue, using the PostEventQueue
 555      * to avoid possibly calling client code (EventQueueSubclass.postEvent())
 556      * on the toolkit (AWT-Windows/AWT-Motif) thread.  This function should
 557      * not be called under another lock since it locks the EventQueue.
 558      * See bugids 4632918, 4526597.
 559      */
 560     public static void postEvent(AppContext appContext, AWTEvent event) {
 561         if (event == null) {
 562             throw new NullPointerException();
 563         }
 564         // All events posted via this method are system-generated.
 565         // Placing the following call here reduces considerably the
 566         // number of places throughout the toolkit that would
 567         // otherwise have to be modified to precisely identify
 568         // system-generated events.
 569         setSystemGenerated(event);
 570         AppContext eventContext = targetToAppContext(event.getSource());
 571         if (eventContext != null && !eventContext.equals(appContext)) {
 572             log.fine("Event posted on wrong app context : " + event);
 573         }
 574         PostEventQueue postEventQueue =
 575             (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 576         if (postEventQueue != null) {
 577             postEventQueue.postEvent(event);
 578         }
 579     }
 580 
 581     /*
 582      * Post AWTEvent of high priority.
 583      */
 584     public static void postPriorityEvent(final AWTEvent e) {
 585         PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(), new Runnable() {
 586                 public void run() {
 587                     AWTAccessor.getAWTEventAccessor().setPosted(e);
 588                     ((Component)e.getSource()).dispatchEvent(e);
 589                 }
 590             }, PeerEvent.ULTIMATE_PRIORITY_EVENT);
 591         postEvent(targetToAppContext(e.getSource()), pe);
 592     }
 593 
 594     private static final Lock flushLock = new ReentrantLock();
 595     private static boolean isFlushingPendingEvents = false;
 596 
 597     /*
 598      * Flush any pending events which haven't been posted to the AWT
 599      * EventQueue yet.
 600      */
 601     public static void flushPendingEvents()  {
 602         flushLock.lock();
 603         try {
 604             // Don't call flushPendingEvents() recursively
 605             if (!isFlushingPendingEvents) {
 606                 isFlushingPendingEvents = true;
 607                 AppContext appContext = AppContext.getAppContext();
 608                 PostEventQueue postEventQueue =
 609                     (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 610                 if (postEventQueue != null) {
 611                     postEventQueue.flush();
 612                 }
 613             }
 614         } finally {
 615             isFlushingPendingEvents = false;
 616             flushLock.unlock();
 617         }
 618     }
 619 
 620     public static boolean isPostEventQueueEmpty()  {
 621         AppContext appContext = AppContext.getAppContext();
 622         PostEventQueue postEventQueue =
 623             (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 624         if (postEventQueue != null) {
 625             return postEventQueue.noEvents();
 626         } else {
 627             return true;
 628         }
 629     }
 630 
 631     /*
 632      * Execute a chunk of code on the Java event handler thread for the
 633      * given target.  Does not wait for the execution to occur before
 634      * returning to the caller.
 635      */
 636     public static void executeOnEventHandlerThread(Object target,
 637                                                    Runnable runnable) {
 638         executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT));
 639     }
 640 
 641     /*
 642      * Fixed 5064013: the InvocationEvent time should be equals
 643      * the time of the ActionEvent
 644      */
 645     public static void executeOnEventHandlerThread(Object target,
 646                                                    Runnable runnable,
 647                                                    final long when) {
 648         executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT){
 649                 public long getWhen(){
 650                     return when;
 651                 }
 652             });
 653     }
 654 
 655     /*
 656      * Execute a chunk of code on the Java event handler thread for the
 657      * given target.  Does not wait for the execution to occur before
 658      * returning to the caller.
 659      */
 660     public static void executeOnEventHandlerThread(PeerEvent peerEvent) {
 661         postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
 662     }
 663 
 664     /*
 665      * Execute a chunk of code on the Java event handler thread. The
 666      * method takes into account provided AppContext and sets
 667      * <code>SunToolkit.getDefaultToolkit()</code> as a target of the
 668      * event. See 6451487 for detailes.
 669      * Does not wait for the execution to occur before returning to
 670      * the caller.
 671      */
 672      public static void invokeLaterOnAppContext(
 673         AppContext appContext, Runnable dispatcher)
 674      {
 675         postEvent(appContext,
 676             new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher,
 677                 PeerEvent.PRIORITY_EVENT));
 678      }
 679 
 680     /*
 681      * Execute a chunk of code on the Java event handler thread for the
 682      * given target.  Waits for the execution to occur before returning
 683      * to the caller.
 684      */
 685     public static void executeOnEDTAndWait(Object target, Runnable runnable)
 686         throws InterruptedException, InvocationTargetException
 687     {
 688         if (EventQueue.isDispatchThread()) {
 689             throw new Error("Cannot call executeOnEDTAndWait from any event dispatcher thread");
 690         }
 691 
 692         class AWTInvocationLock {}
 693         Object lock = new AWTInvocationLock();
 694 
 695         PeerEvent event = new PeerEvent(target, runnable, lock, true, PeerEvent.PRIORITY_EVENT);
 696 
 697         synchronized (lock) {
 698             executeOnEventHandlerThread(event);
 699             while(!event.isDispatched()) {
 700                 lock.wait();
 701             }
 702         }
 703 
 704         Throwable eventThrowable = event.getThrowable();
 705         if (eventThrowable != null) {
 706             throw new InvocationTargetException(eventThrowable);
 707         }
 708     }
 709 
 710     /*
 711      * Returns true if the calling thread is the event dispatch thread
 712      * contained within AppContext which associated with the given target.
 713      * Use this call to ensure that a given task is being executed
 714      * (or not being) on the event dispatch thread for the given target.
 715      */
 716     public static boolean isDispatchThreadForAppContext(Object target) {
 717         AppContext appContext = targetToAppContext(target);
 718         EventQueue eq = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
 719 
 720         AWTAccessor.EventQueueAccessor accessor = AWTAccessor.getEventQueueAccessor();
 721         return accessor.isDispatchThreadImpl(eq);
 722     }
 723 
 724     public Dimension getScreenSize() {
 725         return new Dimension(getScreenWidth(), getScreenHeight());
 726     }
 727     protected abstract int getScreenWidth();
 728     protected abstract int getScreenHeight();
 729 
 730     public FontMetrics getFontMetrics(Font font) {
 731         return FontDesignMetrics.getMetrics(font);
 732     }
 733 
 734     public String[] getFontList() {
 735         String[] hardwiredFontList = {
 736             Font.DIALOG, Font.SANS_SERIF, Font.SERIF, Font.MONOSPACED,
 737             Font.DIALOG_INPUT
 738 
 739             // -- Obsolete font names from 1.0.2.  It was decided that
 740             // -- getFontList should not return these old names:
 741             //    "Helvetica", "TimesRoman", "Courier", "ZapfDingbats"
 742         };
 743         return hardwiredFontList;
 744     }
 745 
 746     public PanelPeer createPanel(Panel target) {
 747         return (PanelPeer)createComponent(target);
 748     }
 749 
 750     public CanvasPeer createCanvas(Canvas target) {
 751         return (CanvasPeer)createComponent(target);
 752     }
 753 
 754     /**
 755      * Disables erasing of background on the canvas before painting if
 756      * this is supported by the current toolkit. It is recommended to
 757      * call this method early, before the Canvas becomes displayable,
 758      * because some Toolkit implementations do not support changing
 759      * this property once the Canvas becomes displayable.
 760      */
 761     public void disableBackgroundErase(Canvas canvas) {
 762         disableBackgroundEraseImpl(canvas);
 763     }
 764 
 765     /**
 766      * Disables the native erasing of the background on the given
 767      * component before painting if this is supported by the current
 768      * toolkit. This only has an effect for certain components such as
 769      * Canvas, Panel and Window. It is recommended to call this method
 770      * early, before the Component becomes displayable, because some
 771      * Toolkit implementations do not support changing this property
 772      * once the Component becomes displayable.
 773      */
 774     public void disableBackgroundErase(Component component) {
 775         disableBackgroundEraseImpl(component);
 776     }
 777 
 778     private void disableBackgroundEraseImpl(Component component) {
 779         AWTAccessor.getComponentAccessor().setBackgroundEraseDisabled(component, true);
 780     }
 781 
 782     /**
 783      * Returns the value of "sun.awt.noerasebackground" property. Default
 784      * value is {@code false}.
 785      */
 786     public static boolean getSunAwtNoerasebackground() {
 787         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.noerasebackground"));
 788     }
 789 
 790     /**
 791      * Returns the value of "sun.awt.erasebackgroundonresize" property. Default
 792      * value is {@code false}.
 793      */
 794     public static boolean getSunAwtErasebackgroundonresize() {
 795         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.erasebackgroundonresize"));
 796     }
 797 
 798 
 799     static final SoftCache imgCache = new SoftCache();
 800 
 801     static Image getImageFromHash(Toolkit tk, URL url) {
 802         SecurityManager sm = System.getSecurityManager();
 803         if (sm != null) {
 804             try {
 805                 java.security.Permission perm =
 806                     url.openConnection().getPermission();
 807                 if (perm != null) {
 808                     try {
 809                         sm.checkPermission(perm);
 810                     } catch (SecurityException se) {
 811                         // fallback to checkRead/checkConnect for pre 1.2
 812                         // security managers
 813                         if ((perm instanceof java.io.FilePermission) &&
 814                             perm.getActions().indexOf("read") != -1) {
 815                             sm.checkRead(perm.getName());
 816                         } else if ((perm instanceof
 817                             java.net.SocketPermission) &&
 818                             perm.getActions().indexOf("connect") != -1) {
 819                             sm.checkConnect(url.getHost(), url.getPort());
 820                         } else {
 821                             throw se;
 822                         }
 823                     }
 824                 }
 825             } catch (java.io.IOException ioe) {
 826                     sm.checkConnect(url.getHost(), url.getPort());
 827             }
 828         }
 829         synchronized (imgCache) {
 830             Image img = (Image)imgCache.get(url);
 831             if (img == null) {
 832                 try {
 833                     img = tk.createImage(new URLImageSource(url));
 834                     imgCache.put(url, img);
 835                 } catch (Exception e) {
 836                 }
 837             }
 838             return img;
 839         }
 840     }
 841 
 842     static Image getImageFromHash(Toolkit tk,
 843                                                String filename) {
 844         SecurityManager security = System.getSecurityManager();
 845         if (security != null) {
 846             security.checkRead(filename);
 847         }
 848         synchronized (imgCache) {
 849             Image img = (Image)imgCache.get(filename);
 850             if (img == null) {
 851                 try {
 852                     img = tk.createImage(new FileImageSource(filename));
 853                     imgCache.put(filename, img);
 854                 } catch (Exception e) {
 855                 }
 856             }
 857             return img;
 858         }
 859     }
 860 
 861     public Image getImage(String filename) {
 862         return getImageFromHash(this, filename);
 863     }
 864 
 865     public Image getImage(URL url) {
 866         return getImageFromHash(this, url);
 867     }
 868 
 869     public Image createImage(String filename) {
 870         SecurityManager security = System.getSecurityManager();
 871         if (security != null) {
 872             security.checkRead(filename);
 873         }
 874         return createImage(new FileImageSource(filename));
 875     }
 876 
 877     public Image createImage(URL url) {
 878         SecurityManager sm = System.getSecurityManager();
 879         if (sm != null) {
 880             try {
 881                 java.security.Permission perm =
 882                     url.openConnection().getPermission();
 883                 if (perm != null) {
 884                     try {
 885                         sm.checkPermission(perm);
 886                     } catch (SecurityException se) {
 887                         // fallback to checkRead/checkConnect for pre 1.2
 888                         // security managers
 889                         if ((perm instanceof java.io.FilePermission) &&
 890                             perm.getActions().indexOf("read") != -1) {
 891                             sm.checkRead(perm.getName());
 892                         } else if ((perm instanceof
 893                             java.net.SocketPermission) &&
 894                             perm.getActions().indexOf("connect") != -1) {
 895                             sm.checkConnect(url.getHost(), url.getPort());
 896                         } else {
 897                             throw se;
 898                         }
 899                     }
 900                 }
 901             } catch (java.io.IOException ioe) {
 902                     sm.checkConnect(url.getHost(), url.getPort());
 903             }
 904         }
 905         return createImage(new URLImageSource(url));
 906     }
 907 
 908     public Image createImage(byte[] data, int offset, int length) {
 909         return createImage(new ByteArrayImageSource(data, offset, length));
 910     }
 911 
 912     public Image createImage(ImageProducer producer) {
 913         return new ToolkitImage(producer);
 914     }
 915 
 916     public int checkImage(Image img, int w, int h, ImageObserver o) {
 917         if (!(img instanceof ToolkitImage)) {
 918             return ImageObserver.ALLBITS;
 919         }
 920 
 921         ToolkitImage tkimg = (ToolkitImage)img;
 922         int repbits;
 923         if (w == 0 || h == 0) {
 924             repbits = ImageObserver.ALLBITS;
 925         } else {
 926             repbits = tkimg.getImageRep().check(o);
 927         }
 928         return tkimg.check(o) | repbits;
 929     }
 930 
 931     public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
 932         if (w == 0 || h == 0) {
 933             return true;
 934         }
 935 
 936         // Must be a ToolkitImage
 937         if (!(img instanceof ToolkitImage)) {
 938             return true;
 939         }
 940 
 941         ToolkitImage tkimg = (ToolkitImage)img;
 942         if (tkimg.hasError()) {
 943             if (o != null) {
 944                 o.imageUpdate(img, ImageObserver.ERROR|ImageObserver.ABORT,
 945                               -1, -1, -1, -1);
 946             }
 947             return false;
 948         }
 949         ImageRepresentation ir = tkimg.getImageRep();
 950         return ir.prepare(o);
 951     }
 952 
 953     /**
 954      * Scans {@code imageList} for best-looking image of specified dimensions.
 955      * Image can be scaled and/or padded with transparency.
 956      */
 957     public static BufferedImage getScaledIconImage(java.util.List<Image> imageList, int width, int height) {
 958         if (width == 0 || height == 0) {
 959             return null;
 960         }
 961         Image bestImage = null;
 962         int bestWidth = 0;
 963         int bestHeight = 0;
 964         double bestSimilarity = 3; //Impossibly high value
 965         double bestScaleFactor = 0;
 966         for (Iterator<Image> i = imageList.iterator();i.hasNext();) {
 967             //Iterate imageList looking for best matching image.
 968             //'Similarity' measure is defined as good scale factor and small insets.
 969             //best possible similarity is 0 (no scale, no insets).
 970             //It's found while the experiments that good-looking result is achieved
 971             //with scale factors x1, x3/4, x2/3, xN, x1/N.
 972             Image im = i.next();
 973             if (im == null) {
 974                 if (log.isLoggable(PlatformLogger.FINER)) {
 975                     log.finer("SunToolkit.getScaledIconImage: " +
 976                               "Skipping the image passed into Java because it's null.");
 977                 }
 978                 continue;
 979             }
 980             if (im instanceof ToolkitImage) {
 981                 ImageRepresentation ir = ((ToolkitImage)im).getImageRep();
 982                 ir.reconstruct(ImageObserver.ALLBITS);
 983             }
 984             int iw;
 985             int ih;
 986             try {
 987                 iw = im.getWidth(null);
 988                 ih = im.getHeight(null);
 989             } catch (Exception e){
 990                 if (log.isLoggable(PlatformLogger.FINER)) {
 991                     log.finer("SunToolkit.getScaledIconImage: " +
 992                               "Perhaps the image passed into Java is broken. Skipping this icon.");
 993                 }
 994                 continue;
 995             }
 996             if (iw > 0 && ih > 0) {
 997                 //Calc scale factor
 998                 double scaleFactor = Math.min((double)width / (double)iw,
 999                                               (double)height / (double)ih);
1000                 //Calculate scaled image dimensions
1001                 //adjusting scale factor to nearest "good" value
1002                 int adjw = 0;
1003                 int adjh = 0;
1004                 double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad
1005                 if (scaleFactor >= 2) {
1006                     //Need to enlarge image more than twice
1007                     //Round down scale factor to multiply by integer value
1008                     scaleFactor = Math.floor(scaleFactor);
1009                     adjw = iw * (int)scaleFactor;
1010                     adjh = ih * (int)scaleFactor;
1011                     scaleMeasure = 1.0 - 0.5 / scaleFactor;
1012                 } else if (scaleFactor >= 1) {
1013                     //Don't scale
1014                     scaleFactor = 1.0;
1015                     adjw = iw;
1016                     adjh = ih;
1017                     scaleMeasure = 0;
1018                 } else if (scaleFactor >= 0.75) {
1019                     //Multiply by 3/4
1020                     scaleFactor = 0.75;
1021                     adjw = iw * 3 / 4;
1022                     adjh = ih * 3 / 4;
1023                     scaleMeasure = 0.3;
1024                 } else if (scaleFactor >= 0.6666) {
1025                     //Multiply by 2/3
1026                     scaleFactor = 0.6666;
1027                     adjw = iw * 2 / 3;
1028                     adjh = ih * 2 / 3;
1029                     scaleMeasure = 0.33;
1030                 } else {
1031                     //Multiply size by 1/scaleDivider
1032                     //where scaleDivider is minimum possible integer
1033                     //larger than 1/scaleFactor
1034                     double scaleDivider = Math.ceil(1.0 / scaleFactor);
1035                     scaleFactor = 1.0 / scaleDivider;
1036                     adjw = (int)Math.round((double)iw / scaleDivider);
1037                     adjh = (int)Math.round((double)ih / scaleDivider);
1038                     scaleMeasure = 1.0 - 1.0 / scaleDivider;
1039                 }
1040                 double similarity = ((double)width - (double)adjw) / (double)width +
1041                     ((double)height - (double)adjh) / (double)height + //Large padding is bad
1042                     scaleMeasure; //Large rescale is bad
1043                 if (similarity < bestSimilarity) {
1044                     bestSimilarity = similarity;
1045                     bestScaleFactor = scaleFactor;
1046                     bestImage = im;
1047                     bestWidth = adjw;
1048                     bestHeight = adjh;
1049                 }
1050                 if (similarity == 0) break;
1051             }
1052         }
1053         if (bestImage == null) {
1054             //No images were found, possibly all are broken
1055             return null;
1056         }
1057         BufferedImage bimage =
1058             new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
1059         Graphics2D g = bimage.createGraphics();
1060         g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
1061                            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
1062         try {
1063             int x = (width - bestWidth) / 2;
1064             int y = (height - bestHeight) / 2;
1065             if (log.isLoggable(PlatformLogger.FINER)) {
1066                 log.finer("WWindowPeer.getScaledIconData() result : " +
1067                         "w : " + width + " h : " + height +
1068                         " iW : " + bestImage.getWidth(null) + " iH : " + bestImage.getHeight(null) +
1069                         " sim : " + bestSimilarity + " sf : " + bestScaleFactor +
1070                         " adjW : " + bestWidth + " adjH : " + bestHeight +
1071                         " x : " + x + " y : " + y);
1072             }
1073             g.drawImage(bestImage, x, y, bestWidth, bestHeight, null);
1074         } finally {
1075             g.dispose();
1076         }
1077         return bimage;
1078     }
1079 
1080     public static DataBufferInt getScaledIconData(java.util.List<Image> imageList, int width, int height) {
1081         BufferedImage bimage = getScaledIconImage(imageList, width, height);
1082         if (bimage == null) {
1083              if (log.isLoggable(PlatformLogger.FINER)) {
1084                  log.finer("SunToolkit.getScaledIconData: " +
1085                            "Perhaps the image passed into Java is broken. Skipping this icon.");
1086              }
1087             return null;
1088         }
1089         Raster raster = bimage.getRaster();
1090         DataBuffer buffer = raster.getDataBuffer();
1091         return (DataBufferInt)buffer;
1092     }
1093 
1094     protected EventQueue getSystemEventQueueImpl() {
1095         return getSystemEventQueueImplPP();
1096     }
1097 
1098     // Package private implementation
1099     static EventQueue getSystemEventQueueImplPP() {
1100         return getSystemEventQueueImplPP(AppContext.getAppContext());
1101     }
1102 
1103     public static EventQueue getSystemEventQueueImplPP(AppContext appContext) {
1104         EventQueue theEventQueue =
1105             (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
1106         return theEventQueue;
1107     }
1108 
1109     /**
1110      * Give native peers the ability to query the native container
1111      * given a native component (eg the direct parent may be lightweight).
1112      */
1113     public static Container getNativeContainer(Component c) {
1114         return Toolkit.getNativeContainer(c);
1115     }
1116 
1117     /**
1118      * Gives native peers the ability to query the closest HW component.
1119      * If the given component is heavyweight, then it returns this. Otherwise,
1120      * it goes one level up in the hierarchy and tests next component.
1121      */
1122     public static Component getHeavyweightComponent(Component c) {
1123         while (c != null && AWTAccessor.getComponentAccessor().isLightweight(c)) {
1124             c = AWTAccessor.getComponentAccessor().getParent(c);
1125         }
1126         return c;
1127     }
1128 
1129     /**
1130      * Returns a new input method window, with behavior as specified in
1131      * {@link java.awt.im.spi.InputMethodContext#createInputMethodWindow}.
1132      * If the inputContext is not null, the window should return it from its
1133      * getInputContext() method. The window needs to implement
1134      * sun.awt.im.InputMethodWindow.
1135      * <p>
1136      * SunToolkit subclasses can override this method to return better input
1137      * method windows.
1138      */
1139     public Window createInputMethodWindow(String title, InputContext context) {
1140         return new sun.awt.im.SimpleInputMethodWindow(title, context);
1141     }
1142 
1143     /**
1144      * Returns whether enableInputMethods should be set to true for peered
1145      * TextComponent instances on this platform. False by default.
1146      */
1147     public boolean enableInputMethodsForTextComponent() {
1148         return false;
1149     }
1150 
1151     private static Locale startupLocale = null;
1152 
1153     /**
1154      * Returns the locale in which the runtime was started.
1155      */
1156     public static Locale getStartupLocale() {
1157         if (startupLocale == null) {
1158             String language, region, country, variant;
1159             language = (String) AccessController.doPrivileged(
1160                             new GetPropertyAction("user.language", "en"));
1161             // for compatibility, check for old user.region property
1162             region = (String) AccessController.doPrivileged(
1163                             new GetPropertyAction("user.region"));
1164             if (region != null) {
1165                 // region can be of form country, country_variant, or _variant
1166                 int i = region.indexOf('_');
1167                 if (i >= 0) {
1168                     country = region.substring(0, i);
1169                     variant = region.substring(i + 1);
1170                 } else {
1171                     country = region;
1172                     variant = "";
1173                 }
1174             } else {
1175                 country = (String) AccessController.doPrivileged(
1176                                 new GetPropertyAction("user.country", ""));
1177                 variant = (String) AccessController.doPrivileged(
1178                                 new GetPropertyAction("user.variant", ""));
1179             }
1180             startupLocale = new Locale(language, country, variant);
1181         }
1182         return startupLocale;
1183     }
1184 
1185     /**
1186      * Returns the default keyboard locale of the underlying operating system
1187      */
1188     public Locale getDefaultKeyboardLocale() {
1189         return getStartupLocale();
1190     }
1191 
1192     private static String dataTransfererClassName = null;
1193 
1194     protected static void setDataTransfererClassName(String className) {
1195         dataTransfererClassName = className;
1196     }
1197 
1198     public static String getDataTransfererClassName() {
1199         if (dataTransfererClassName == null) {
1200             Toolkit.getDefaultToolkit(); // transferer set during toolkit init
1201         }
1202         return dataTransfererClassName;
1203     }
1204 
1205     // Support for window closing event notifications
1206     private transient WindowClosingListener windowClosingListener = null;
1207     /**
1208      * @see sun.awt.WindowClosingSupport#getWindowClosingListener
1209      */
1210     public WindowClosingListener getWindowClosingListener() {
1211         return windowClosingListener;
1212     }
1213     /**
1214      * @see sun.awt.WindowClosingSupport#setWindowClosingListener
1215      */
1216     public void setWindowClosingListener(WindowClosingListener wcl) {
1217         windowClosingListener = wcl;
1218     }
1219 
1220     /**
1221      * @see sun.awt.WindowClosingListener#windowClosingNotify
1222      */
1223     public RuntimeException windowClosingNotify(WindowEvent event) {
1224         if (windowClosingListener != null) {
1225             return windowClosingListener.windowClosingNotify(event);
1226         } else {
1227             return null;
1228         }
1229     }
1230     /**
1231      * @see sun.awt.WindowClosingListener#windowClosingDelivered
1232      */
1233     public RuntimeException windowClosingDelivered(WindowEvent event) {
1234         if (windowClosingListener != null) {
1235             return windowClosingListener.windowClosingDelivered(event);
1236         } else {
1237             return null;
1238         }
1239     }
1240 
1241     private static DefaultMouseInfoPeer mPeer = null;
1242 
1243     protected synchronized MouseInfoPeer getMouseInfoPeer() {
1244         if (mPeer == null) {
1245             mPeer = new DefaultMouseInfoPeer();
1246         }
1247         return mPeer;
1248     }
1249 
1250 
1251     /**
1252      * Returns whether default toolkit needs the support of the xembed
1253      * from embedding host(if any).
1254      * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1255      */
1256     public static boolean needsXEmbed() {
1257         String noxembed = (String) AccessController.
1258             doPrivileged(new GetPropertyAction("sun.awt.noxembed", "false"));
1259         if ("true".equals(noxembed)) {
1260             return false;
1261         }
1262 
1263         Toolkit tk = Toolkit.getDefaultToolkit();
1264         if (tk instanceof SunToolkit) {
1265             // SunToolkit descendants should override this method to specify
1266             // concrete behavior
1267             return ((SunToolkit)tk).needsXEmbedImpl();
1268         } else {
1269             // Non-SunToolkit doubtly might support XEmbed
1270             return false;
1271         }
1272     }
1273 
1274     /**
1275      * Returns whether this toolkit needs the support of the xembed
1276      * from embedding host(if any).
1277      * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1278      */
1279     protected boolean needsXEmbedImpl() {
1280         return false;
1281     }
1282 
1283     private static Dialog.ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE = null;
1284 
1285     /**
1286      * Returns whether the XEmbed server feature is requested by
1287      * developer.  If true, Toolkit should return an
1288      * XEmbed-server-enabled CanvasPeer instead of the ordinary CanvasPeer.
1289      */
1290     protected final boolean isXEmbedServerRequested() {
1291         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembedserver"));
1292     }
1293 
1294     /**
1295      * Returns whether the modal exclusion API is supported by the current toolkit.
1296      * When it isn't supported, calling <code>setModalExcluded</code> has no
1297      * effect, and <code>isModalExcluded</code> returns false for all windows.
1298      *
1299      * @return true if modal exclusion is supported by the toolkit, false otherwise
1300      *
1301      * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1302      * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1303      *
1304      * @since 1.5
1305      */
1306     public static boolean isModalExcludedSupported()
1307     {
1308         Toolkit tk = Toolkit.getDefaultToolkit();
1309         return tk.isModalExclusionTypeSupported(DEFAULT_MODAL_EXCLUSION_TYPE);
1310     }
1311     /*
1312      * Default implementation for isModalExcludedSupportedImpl(), returns false.
1313      *
1314      * @see sun.awt.windows.WToolkit#isModalExcludeSupportedImpl
1315      * @see sun.awt.X11.XToolkit#isModalExcludeSupportedImpl
1316      *
1317      * @since 1.5
1318      */
1319     protected boolean isModalExcludedSupportedImpl()
1320     {
1321         return false;
1322     }
1323 
1324     /*
1325      * Sets this window to be excluded from being modally blocked. When the
1326      * toolkit supports modal exclusion and this method is called, input
1327      * events, focus transfer and z-order will continue to work for the
1328      * window, it's owned windows and child components, even in the
1329      * presence of a modal dialog.
1330      * For details on which <code>Window</code>s are normally blocked
1331      * by modal dialog, see {@link java.awt.Dialog}.
1332      * Invoking this method when the modal exclusion API is not supported by
1333      * the current toolkit has no effect.
1334      * @param window Window to be marked as not modally blocked
1335      * @see java.awt.Dialog
1336      * @see java.awt.Dialog#setModal(boolean)
1337      * @see sun.awt.SunToolkit#isModalExcludedSupported
1338      * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1339      */
1340     public static void setModalExcluded(Window window)
1341     {
1342         if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {
1343             DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;
1344         }
1345         window.setModalExclusionType(DEFAULT_MODAL_EXCLUSION_TYPE);
1346     }
1347 
1348     /*
1349      * Returns whether the specified window is blocked by modal dialogs.
1350      * If the modal exclusion API isn't supported by the current toolkit,
1351      * it returns false for all windows.
1352      *
1353      * @param window Window to test for modal exclusion
1354      *
1355      * @return true if the window is modal excluded, false otherwise. If
1356      * the modal exclusion isn't supported by the current Toolkit, false
1357      * is returned
1358      *
1359      * @see sun.awt.SunToolkit#isModalExcludedSupported
1360      * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1361      *
1362      * @since 1.5
1363      */
1364     public static boolean isModalExcluded(Window window)
1365     {
1366         if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {
1367             DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;
1368         }
1369         return window.getModalExclusionType().compareTo(DEFAULT_MODAL_EXCLUSION_TYPE) >= 0;
1370     }
1371 
1372     /**
1373      * Overridden in XToolkit and WToolkit
1374      */
1375     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
1376         return (modalityType == Dialog.ModalityType.MODELESS) ||
1377                (modalityType == Dialog.ModalityType.APPLICATION_MODAL);
1378     }
1379 
1380     /**
1381      * Overridden in XToolkit and WToolkit
1382      */
1383     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
1384         return (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE);
1385     }
1386 
1387     ///////////////////////////////////////////////////////////////////////////
1388     //
1389     // The following is used by the Java Plug-in to coordinate dialog modality
1390     // between containing applications (browsers, ActiveX containers etc) and
1391     // the AWT.
1392     //
1393     ///////////////////////////////////////////////////////////////////////////
1394 
1395     private ModalityListenerList modalityListeners = new ModalityListenerList();
1396 
1397     public void addModalityListener(ModalityListener listener) {
1398         modalityListeners.add(listener);
1399     }
1400 
1401     public void removeModalityListener(ModalityListener listener) {
1402         modalityListeners.remove(listener);
1403     }
1404 
1405     public void notifyModalityPushed(Dialog dialog) {
1406         notifyModalityChange(ModalityEvent.MODALITY_PUSHED, dialog);
1407     }
1408 
1409     public void notifyModalityPopped(Dialog dialog) {
1410         notifyModalityChange(ModalityEvent.MODALITY_POPPED, dialog);
1411     }
1412 
1413     final void notifyModalityChange(int id, Dialog source) {
1414         ModalityEvent ev = new ModalityEvent(source, modalityListeners, id);
1415         ev.dispatch();
1416     }
1417 
1418     static class ModalityListenerList implements ModalityListener {
1419 
1420         Vector<ModalityListener> listeners = new Vector<ModalityListener>();
1421 
1422         void add(ModalityListener listener) {
1423             listeners.addElement(listener);
1424         }
1425 
1426         void remove(ModalityListener listener) {
1427             listeners.removeElement(listener);
1428         }
1429 
1430         public void modalityPushed(ModalityEvent ev) {
1431             Iterator<ModalityListener> it = listeners.iterator();
1432             while (it.hasNext()) {
1433                 it.next().modalityPushed(ev);
1434             }
1435         }
1436 
1437         public void modalityPopped(ModalityEvent ev) {
1438             Iterator<ModalityListener> it = listeners.iterator();
1439             while (it.hasNext()) {
1440                 it.next().modalityPopped(ev);
1441             }
1442         }
1443     } // end of class ModalityListenerList
1444 
1445     ///////////////////////////////////////////////////////////////////////////
1446     // End Plug-in code
1447     ///////////////////////////////////////////////////////////////////////////
1448 
1449     public static boolean isLightweightOrUnknown(Component comp) {
1450         if (comp.isLightweight()
1451             || !(getDefaultToolkit() instanceof SunToolkit))
1452         {
1453             return true;
1454         }
1455         return !(comp instanceof Button
1456             || comp instanceof Canvas
1457             || comp instanceof Checkbox
1458             || comp instanceof Choice
1459             || comp instanceof Label
1460             || comp instanceof java.awt.List
1461             || comp instanceof Panel
1462             || comp instanceof Scrollbar
1463             || comp instanceof ScrollPane
1464             || comp instanceof TextArea
1465             || comp instanceof TextField
1466             || comp instanceof Window);
1467     }
1468 
1469     public static Method getMethod(final Class clz, final String methodName, final Class[] params) {
1470         Method res = null;
1471         try {
1472             res = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
1473                     public Method run() throws Exception {
1474                         Method m = clz.getDeclaredMethod(methodName, params);
1475                         m.setAccessible(true);
1476                         return m;
1477                     }
1478                 });
1479         } catch (PrivilegedActionException ex) {
1480             ex.printStackTrace();
1481         }
1482         return res;
1483     }
1484 
1485     public static class OperationTimedOut extends RuntimeException {
1486         public OperationTimedOut(String msg) {
1487             super(msg);
1488         }
1489         public OperationTimedOut() {
1490         }
1491     }
1492     public static class InfiniteLoop extends RuntimeException {
1493     }
1494 
1495     public static class IllegalThreadException extends RuntimeException {
1496         public IllegalThreadException(String msg) {
1497             super(msg);
1498         }
1499         public IllegalThreadException() {
1500         }
1501     }
1502 
1503     public static final int DEFAULT_WAIT_TIME = 10000;
1504     private static final int MAX_ITERS = 20;
1505     private static final int MIN_ITERS = 0;
1506     private static final int MINIMAL_EDELAY = 0;
1507 
1508     /**
1509      * Parameterless version of realsync which uses default timout (see DEFAUL_WAIT_TIME).
1510      */
1511     public void realSync() throws OperationTimedOut, InfiniteLoop {
1512         realSync(DEFAULT_WAIT_TIME);
1513     }
1514 
1515     /**
1516      * Forces toolkit to synchronize with the native windowing
1517      * sub-system, flushing all pending work and waiting for all the
1518      * events to be processed.  This method guarantees that after
1519      * return no additional Java events will be generated, unless
1520      * cause by user. Obviously, the method cannot be used on the
1521      * event dispatch thread (EDT). In case it nevertheless gets
1522      * invoked on this thread, the method throws the
1523      * IllegalThreadException runtime exception.
1524      *
1525      * <p> This method allows to write tests without explicit timeouts
1526      * or wait for some event.  Example:
1527      * <code>
1528      * Frame f = ...;
1529      * f.setVisible(true);
1530      * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1531      * </code>
1532      *
1533      * <p> After realSync, <code>f</code> will be completely visible
1534      * on the screen, its getLocationOnScreen will be returning the
1535      * right result and it will be the focus owner.
1536      *
1537      * <p> Another example:
1538      * <code>
1539      * b.requestFocus();
1540      * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1541      * </code>
1542      *
1543      * <p> After realSync, <code>b</code> will be focus owner.
1544      *
1545      * <p> Notice that realSync isn't guaranteed to work if recurring
1546      * actions occur, such as if during processing of some event
1547      * another request which may generate some events occurs.  By
1548      * default, sync tries to perform as much as {@value MAX_ITERS}
1549      * cycles of event processing, allowing for roughly {@value
1550      * MAX_ITERS} additional requests.
1551      *
1552      * <p> For example, requestFocus() generates native request, which
1553      * generates one or two Java focus events, which then generate a
1554      * serie of paint events, a serie of Java focus events, which then
1555      * generate a serie of paint events which then are processed -
1556      * three cycles, minimum.
1557      *
1558      * @param timeout the maximum time to wait in milliseconds, negative means "forever".
1559      */
1560     public void realSync(final long timeout) throws OperationTimedOut, InfiniteLoop
1561     {
1562         if (EventQueue.isDispatchThread()) {
1563             throw new IllegalThreadException("The SunToolkit.realSync() method cannot be used on the event dispatch thread (EDT).");
1564         }
1565         int bigLoop = 0;
1566         do {
1567             // Let's do sync first
1568             sync();
1569 
1570             // During the wait process, when we were processing incoming
1571             // events, we could have made some new request, which can
1572             // generate new events.  Example: MapNotify/XSetInputFocus.
1573             // Therefore, we dispatch them as long as there is something
1574             // to dispatch.
1575             int iters = 0;
1576             while (iters < MIN_ITERS) {
1577                 syncNativeQueue(timeout);
1578                 iters++;
1579             }
1580             while (syncNativeQueue(timeout) && iters < MAX_ITERS) {
1581                 iters++;
1582             }
1583             if (iters >= MAX_ITERS) {
1584                 throw new InfiniteLoop();
1585             }
1586 
1587             // native requests were dispatched by X/Window Manager or Windows
1588             // Moreover, we processed them all on Toolkit thread
1589             // Now wait while EDT processes them.
1590             //
1591             // During processing of some events (focus, for example),
1592             // some other events could have been generated.  So, after
1593             // waitForIdle, we may end up with full EventQueue
1594             iters = 0;
1595             while (iters < MIN_ITERS) {
1596                 waitForIdle(timeout);
1597                 iters++;
1598             }
1599             while (waitForIdle(timeout) && iters < MAX_ITERS) {
1600                 iters++;
1601             }
1602             if (iters >= MAX_ITERS) {
1603                 throw new InfiniteLoop();
1604             }
1605 
1606             bigLoop++;
1607             // Again, for Java events, it was simple to check for new Java
1608             // events by checking event queue, but what if Java events
1609             // resulted in native requests?  Therefor, check native events again.
1610         } while ((syncNativeQueue(timeout) || waitForIdle(timeout)) && bigLoop < MAX_ITERS);
1611     }
1612 
1613     /**
1614      * Platform toolkits need to implement this method to perform the
1615      * sync of the native queue.  The method should wait until native
1616      * requests are processed, all native events are processed and
1617      * corresponding Java events are generated.  Should return
1618      * <code>true</code> if some events were processed,
1619      * <code>false</code> otherwise.
1620      */
1621     protected abstract boolean syncNativeQueue(final long timeout);
1622 
1623     private boolean eventDispatched = false;
1624     private boolean queueEmpty = false;
1625     private final Object waitLock = "Wait Lock";
1626 
1627     static Method eqNoEvents;
1628 
1629     private boolean isEQEmpty() {
1630         EventQueue queue = getSystemEventQueueImpl();
1631         synchronized(SunToolkit.class) {
1632             if (eqNoEvents == null) {
1633                 eqNoEvents = getMethod(java.awt.EventQueue.class, "noEvents", null);
1634             }
1635         }
1636         try {
1637             return (Boolean)eqNoEvents.invoke(queue);
1638         } catch (Exception e) {
1639             e.printStackTrace();
1640             return false;
1641         }
1642     }
1643 
1644     /**
1645      * Waits for the Java event queue to empty.  Ensures that all
1646      * events are processed (including paint events), and that if
1647      * recursive events were generated, they are also processed.
1648      * Should return <code>true</code> if more processing is
1649      * necessary, <code>false</code> otherwise.
1650      */
1651     protected final boolean waitForIdle(final long timeout) {
1652         flushPendingEvents();
1653         boolean queueWasEmpty = isEQEmpty();
1654         queueEmpty = false;
1655         eventDispatched = false;
1656         synchronized(waitLock) {
1657             postEvent(AppContext.getAppContext(),
1658                       new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
1659                           public void dispatch() {
1660                               // Here we block EDT.  It could have some
1661                               // events, it should have dispatched them by
1662                               // now.  So native requests could have been
1663                               // generated.  First, dispatch them.  Then,
1664                               // flush Java events again.
1665                               int iters = 0;
1666                               while (iters < MIN_ITERS) {
1667                                   syncNativeQueue(timeout);
1668                                   iters++;
1669                               }
1670                               while (syncNativeQueue(timeout) && iters < MAX_ITERS) {
1671                                   iters++;
1672                               }
1673                               flushPendingEvents();
1674 
1675                               synchronized(waitLock) {
1676                                   queueEmpty = isEQEmpty();
1677                                   eventDispatched = true;
1678                                   waitLock.notifyAll();
1679                               }
1680                           }
1681                       });
1682             try {
1683                 while (!eventDispatched) {
1684                     waitLock.wait();
1685                 }
1686             } catch (InterruptedException ie) {
1687                 return false;
1688             }
1689         }
1690 
1691         try {
1692             Thread.sleep(MINIMAL_EDELAY);
1693         } catch (InterruptedException ie) {
1694             throw new RuntimeException("Interrupted");
1695         }
1696 
1697         flushPendingEvents();
1698 
1699         // Lock to force write-cache flush for queueEmpty.
1700         synchronized (waitLock) {
1701             return !(queueEmpty && isEQEmpty() && queueWasEmpty);
1702         }
1703     }
1704 
1705     /**
1706      * Grabs the mouse input for the given window.  The window must be
1707      * visible.  The window or its children do not receive any
1708      * additional mouse events besides those targeted to them.  All
1709      * other events will be dispatched as before - to the respective
1710      * targets.  This Window will receive UngrabEvent when automatic
1711      * ungrab is about to happen.  The event can be listened to by
1712      * installing AWTEventListener with WINDOW_EVENT_MASK.  See
1713      * UngrabEvent class for the list of conditions when ungrab is
1714      * about to happen.
1715      * @see UngrabEvent
1716      */
1717     public abstract void grab(Window w);
1718 
1719     /**
1720      * Forces ungrab.  No event will be sent.
1721      */
1722     public abstract void ungrab(Window w);
1723 
1724 
1725     /**
1726      * Locates the splash screen library in a platform dependent way and closes
1727      * the splash screen. Should be invoked on first top-level frame display.
1728      * @see java.awt.SplashScreen
1729      * @since 1.6
1730      */
1731     public static native void closeSplashScreen();
1732 
1733     /* The following methods and variables are to support retrieving
1734      * desktop text anti-aliasing settings
1735      */
1736 
1737     /* Need an instance method because setDesktopProperty(..) is protected. */
1738     private void fireDesktopFontPropertyChanges() {
1739         setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,
1740                            SunToolkit.getDesktopFontHints());
1741     }
1742 
1743     private static boolean checkedSystemAAFontSettings;
1744     private static boolean useSystemAAFontSettings;
1745     private static boolean lastExtraCondition = true;
1746     private static RenderingHints desktopFontHints;
1747 
1748     /* Since Swing is the reason for this "extra condition" logic its
1749      * worth documenting it in some detail.
1750      * First, a goal is for Swing and applications to both retrieve and
1751      * use the same desktop property value so that there is complete
1752      * consistency between the settings used by JDK's Swing implementation
1753      * and 3rd party custom Swing components, custom L&Fs and any general
1754      * text rendering that wants to be consistent with these.
1755      * But by default on Solaris & Linux Swing will not use AA text over
1756      * remote X11 display (unless Xrender can be used which is TBD and may not
1757      * always be available anyway) as that is a noticeable performance hit.
1758      * So there needs to be a way to express that extra condition so that
1759      * it is seen by all clients of the desktop property API.
1760      * If this were the only condition it could be handled here as it would
1761      * be the same for any L&F and could reasonably be considered to be
1762      * a static behaviour of those systems.
1763      * But GTK currently has an additional test based on locale which is
1764      * not applied by Metal. So mixing GTK in a few locales with Metal
1765      * would mean the last one wins.
1766      * This could be stored per-app context which would work
1767      * for different applets, but wouldn't help for a single application
1768      * using GTK and some other L&F concurrently.
1769      * But it is expected this will be addressed within GTK and the font
1770      * system so is a temporary and somewhat unlikely harmless corner case.
1771      */
1772     public static void setAAFontSettingsCondition(boolean extraCondition) {
1773         if (extraCondition != lastExtraCondition) {
1774             lastExtraCondition = extraCondition;
1775             if (checkedSystemAAFontSettings) {
1776                 /* Someone already asked for this info, under a different
1777                  * condition.
1778                  * We'll force re-evaluation instead of replicating the
1779                  * logic, then notify any listeners of any change.
1780                  */
1781                 checkedSystemAAFontSettings = false;
1782                 Toolkit tk = Toolkit.getDefaultToolkit();
1783                 if (tk instanceof SunToolkit) {
1784                      ((SunToolkit)tk).fireDesktopFontPropertyChanges();
1785                 }
1786             }
1787         }
1788     }
1789 
1790     /* "false", "off", ""default" aren't explicitly tested, they
1791      * just fall through to produce a null return which all are equated to
1792      * "false".
1793      */
1794     private static RenderingHints getDesktopAAHintsByName(String hintname) {
1795         Object aaHint = null;
1796         hintname = hintname.toLowerCase(Locale.ENGLISH);
1797         if (hintname.equals("on")) {
1798             aaHint = VALUE_TEXT_ANTIALIAS_ON;
1799         } else if (hintname.equals("gasp")) {
1800             aaHint = VALUE_TEXT_ANTIALIAS_GASP;
1801         } else if (hintname.equals("lcd") || hintname.equals("lcd_hrgb")) {
1802             aaHint = VALUE_TEXT_ANTIALIAS_LCD_HRGB;
1803         } else if (hintname.equals("lcd_hbgr")) {
1804             aaHint = VALUE_TEXT_ANTIALIAS_LCD_HBGR;
1805         } else if (hintname.equals("lcd_vrgb")) {
1806             aaHint = VALUE_TEXT_ANTIALIAS_LCD_VRGB;
1807         } else if (hintname.equals("lcd_vbgr")) {
1808             aaHint = VALUE_TEXT_ANTIALIAS_LCD_VBGR;
1809         }
1810         if (aaHint != null) {
1811             RenderingHints map = new RenderingHints(null);
1812             map.put(KEY_TEXT_ANTIALIASING, aaHint);
1813             return map;
1814         } else {
1815             return null;
1816         }
1817     }
1818 
1819     /* This method determines whether to use the system font settings,
1820      * or ignore them if a L&F has specified they should be ignored, or
1821      * to override both of these with a system property specified value.
1822      * If the toolkit isn't a SunToolkit, (eg may be headless) then that
1823      * system property isn't applied as desktop properties are considered
1824      * to be inapplicable in that case. In that headless case although
1825      * this method will return "true" the toolkit will return a null map.
1826      */
1827     private static boolean useSystemAAFontSettings() {
1828         if (!checkedSystemAAFontSettings) {
1829             useSystemAAFontSettings = true; /* initially set this true */
1830             String systemAAFonts = null;
1831             Toolkit tk = Toolkit.getDefaultToolkit();
1832             if (tk instanceof SunToolkit) {
1833                 systemAAFonts =
1834                     (String)AccessController.doPrivileged(
1835                          new GetPropertyAction("awt.useSystemAAFontSettings"));
1836             }
1837             if (systemAAFonts != null) {
1838                 useSystemAAFontSettings =
1839                     Boolean.valueOf(systemAAFonts).booleanValue();
1840                 /* If it is anything other than "true", then it may be
1841                  * a hint name , or it may be "off, "default", etc.
1842                  */
1843                 if (!useSystemAAFontSettings) {
1844                     desktopFontHints = getDesktopAAHintsByName(systemAAFonts);
1845                 }
1846             }
1847             /* If its still true, apply the extra condition */
1848             if (useSystemAAFontSettings) {
1849                  useSystemAAFontSettings = lastExtraCondition;
1850             }
1851             checkedSystemAAFontSettings = true;
1852         }
1853         return useSystemAAFontSettings;
1854     }
1855 
1856     /* A variable defined for the convenience of JDK code */
1857     public static final String DESKTOPFONTHINTS = "awt.font.desktophints";
1858 
1859     /* Overridden by subclasses to return platform/desktop specific values */
1860     protected RenderingHints getDesktopAAHints() {
1861         return null;
1862     }
1863 
1864     /* Subclass desktop property loading methods call this which
1865      * in turn calls the appropriate subclass implementation of
1866      * getDesktopAAHints() when system settings are being used.
1867      * Its public rather than protected because subclasses may delegate
1868      * to a helper class.
1869      */
1870     public static RenderingHints getDesktopFontHints() {
1871         if (useSystemAAFontSettings()) {
1872              Toolkit tk = Toolkit.getDefaultToolkit();
1873              if (tk instanceof SunToolkit) {
1874                  Object map = ((SunToolkit)tk).getDesktopAAHints();
1875                  return (RenderingHints)map;
1876              } else { /* Headless Toolkit */
1877                  return null;
1878              }
1879         } else if (desktopFontHints != null) {
1880             /* cloning not necessary as the return value is cloned later, but
1881              * its harmless.
1882              */
1883             return (RenderingHints)(desktopFontHints.clone());
1884         } else {
1885             return null;
1886         }
1887     }
1888 
1889 
1890     public abstract boolean isDesktopSupported();
1891 
1892     /*
1893      * consumeNextKeyTyped() method is not currently used,
1894      * however Swing could use it in the future.
1895      */
1896     private static Method consumeNextKeyTypedMethod = null;
1897     public static synchronized void consumeNextKeyTyped(KeyEvent keyEvent) {
1898         if (consumeNextKeyTypedMethod == null) {
1899             consumeNextKeyTypedMethod = getMethod(DefaultKeyboardFocusManager.class,
1900                                                   "consumeNextKeyTyped",
1901                                                   new Class[] {KeyEvent.class});
1902         }
1903         try {
1904             consumeNextKeyTypedMethod.invoke(KeyboardFocusManager.getCurrentKeyboardFocusManager(),
1905                                              keyEvent);
1906         } catch (IllegalAccessException iae) {
1907             iae.printStackTrace();
1908         } catch (InvocationTargetException ite) {
1909             ite.printStackTrace();
1910         }
1911     }
1912 
1913     protected static void dumpPeers(final PlatformLogger aLog) {
1914         AWTAutoShutdown.getInstance().dumpPeers(aLog);
1915     }
1916 
1917     /**
1918      * Returns the <code>Window</code> ancestor of the component <code>comp</code>.
1919      * @return Window ancestor of the component or component by itself if it is Window;
1920      *         null, if component is not a part of window hierarchy
1921      */
1922     public static Window getContainingWindow(Component comp) {
1923         while (comp != null && !(comp instanceof Window)) {
1924             comp = comp.getParent();
1925         }
1926         return (Window)comp;
1927     }
1928 
1929     /**
1930      * Returns the value of the system property indicated by the specified key.
1931      */
1932     public static String getSystemProperty(final String key) {
1933         return (String)AccessController.doPrivileged(new PrivilegedAction() {
1934                 public Object run() {
1935                     return System.getProperty(key);
1936                 }
1937             });
1938     }
1939 
1940     /**
1941      * Returns the boolean value of the system property indicated by the specified key.
1942      */
1943     protected static Boolean getBooleanSystemProperty(String key) {
1944         return Boolean.valueOf(AccessController.
1945                    doPrivileged(new GetBooleanAction(key)));
1946     }
1947 
1948     private static Boolean sunAwtDisableMixing = null;
1949 
1950     /**
1951      * Returns the value of "sun.awt.disableMixing" property. Default
1952      * value is {@code false}.
1953      */
1954     public synchronized static boolean getSunAwtDisableMixing() {
1955         if (sunAwtDisableMixing == null) {
1956             sunAwtDisableMixing = getBooleanSystemProperty("sun.awt.disableMixing");
1957         }
1958         return sunAwtDisableMixing.booleanValue();
1959     }
1960 
1961     /**
1962      * Returns true if the native GTK libraries are available.  The
1963      * default implementation returns false, but UNIXToolkit overrides this
1964      * method to provide a more specific answer.
1965      */
1966     public boolean isNativeGTKAvailable() {
1967         return false;
1968     }
1969 
1970     // Cosntant alpha
1971     public boolean isWindowOpacitySupported() {
1972         return false;
1973     }
1974 
1975     // Shaping
1976     public boolean isWindowShapingSupported() {
1977         return false;
1978     }
1979 
1980     // Per-pixel alpha
1981     public boolean isWindowTranslucencySupported() {
1982         return false;
1983     }
1984 
1985     public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
1986         return false;
1987     }
1988 
1989     /**
1990      * Returns whether or not a containing top level window for the passed
1991      * component is
1992      * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}.
1993      *
1994      * @param c a Component which toplevel's to check
1995      * @return {@code true}  if the passed component is not null and has a
1996      * containing toplevel window which is opaque (so per-pixel translucency
1997      * is not enabled), {@code false} otherwise
1998      * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
1999      */
2000     public static boolean isContainingTopLevelOpaque(Component c) {
2001         Window w = getContainingWindow(c);
2002         return w != null && w.isOpaque();
2003     }
2004 
2005     /**
2006      * Returns whether or not a containing top level window for the passed
2007      * component is
2008      * {@link GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}.
2009      *
2010      * @param c a Component which toplevel's to check
2011      * @return {@code true} if the passed component is not null and has a
2012      * containing toplevel window which has opacity less than
2013      * 1.0f (which means that it is translucent), {@code false} otherwise
2014      * @see GraphicsDevice.WindowTranslucency#TRANSLUCENT
2015      */
2016     public static boolean isContainingTopLevelTranslucent(Component c) {
2017         Window w = getContainingWindow(c);
2018         return w != null && ((Window)w).getOpacity() < 1.0f;
2019     }
2020 
2021     /**
2022      * Returns whether the native system requires using the peer.updateWindow()
2023      * method to update the contents of a non-opaque window, or if usual
2024      * painting procedures are sufficient. The default return value covers
2025      * the X11 systems. On MS Windows this method is overriden in WToolkit
2026      * to return true.
2027      */
2028     public boolean needUpdateWindow() {
2029         return false;
2030     }
2031 
2032     /**
2033      * Descendants of the SunToolkit should override and put their own logic here.
2034      */
2035     public int getNumberOfButtons(){
2036         return 3;
2037     }
2038 
2039     /**
2040      * Checks that the given object implements/extends the given
2041      * interface/class.
2042      *
2043      * Note that using the instanceof operator causes a class to be loaded.
2044      * Using this method doesn't load a class and it can be used instead of
2045      * the instanceof operator for performance reasons.
2046      *
2047      * @param obj Object to be checked
2048      * @param type The name of the interface/class. Must be
2049      * fully-qualified interface/class name.
2050      * @return true, if this object implements/extends the given
2051      *         interface/class, false, otherwise, or if obj or type is null
2052      */
2053     public static boolean isInstanceOf(Object obj, String type) {
2054         if (obj == null) return false;
2055         if (type == null) return false;
2056 
2057         return isInstanceOf(obj.getClass(), type);
2058     }
2059 
2060     private static boolean isInstanceOf(Class cls, String type) {
2061         if (cls == null) return false;
2062 
2063         if (cls.getName().equals(type)) {
2064             return true;
2065         }
2066 
2067         for (Class c : cls.getInterfaces()) {
2068             if (c.getName().equals(type)) {
2069                 return true;
2070             }
2071         }
2072         return isInstanceOf(cls.getSuperclass(), type);
2073     }
2074 
2075     ///////////////////////////////////////////////////////////////////////////
2076     //
2077     // The following methods help set and identify whether a particular
2078     // AWTEvent object was produced by the system or by user code. As of this
2079     // writing the only consumer is the Java Plug-In, although this information
2080     // could be useful to more clients and probably should be formalized in
2081     // the public API.
2082     //
2083     ///////////////////////////////////////////////////////////////////////////
2084 
2085     public static void setSystemGenerated(AWTEvent e) {
2086         AWTAccessor.getAWTEventAccessor().setSystemGenerated(e);
2087     }
2088 
2089     public static boolean isSystemGenerated(AWTEvent e) {
2090         return AWTAccessor.getAWTEventAccessor().isSystemGenerated(e);
2091     }
2092 
2093 } // class SunToolkit
2094 
2095 
2096 /*
2097  * PostEventQueue is a Thread that runs in the same AppContext as the
2098  * Java EventQueue.  It is a queue of AWTEvents to be posted to the
2099  * Java EventQueue.  The toolkit Thread (AWT-Windows/AWT-Motif) posts
2100  * events to this queue, which then calls EventQueue.postEvent().
2101  *
2102  * We do this because EventQueue.postEvent() may be overridden by client
2103  * code, and we mustn't ever call client code from the toolkit thread.
2104  */
2105 class PostEventQueue {
2106     private EventQueueItem queueHead = null;
2107     private EventQueueItem queueTail = null;
2108     private final EventQueue eventQueue;
2109 
2110     PostEventQueue(EventQueue eq) {
2111         eventQueue = eq;
2112     }
2113 
2114     public synchronized boolean noEvents() {
2115         return queueHead == null;
2116     }
2117 
2118     /*
2119      * Continually post pending AWTEvents to the Java EventQueue. The method
2120      * is synchronized to ensure the flush is completed before a new event
2121      * can be posted to this queue.
2122      */
2123     public synchronized void flush() {
2124         EventQueueItem tempQueue = queueHead;
2125         queueHead = queueTail = null;
2126         while (tempQueue != null) {
2127             eventQueue.postEvent(tempQueue.event);
2128             tempQueue = tempQueue.next;
2129         }
2130     }
2131 
2132     /*
2133      * Enqueue an AWTEvent to be posted to the Java EventQueue.
2134      */
2135     void postEvent(AWTEvent event) {
2136         EventQueueItem item = new EventQueueItem(event);
2137 
2138         synchronized (this) {
2139             if (queueHead == null) {
2140                 queueHead = queueTail = item;
2141             } else {
2142                 queueTail.next = item;
2143                 queueTail = item;
2144             }
2145         }
2146         SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance());
2147     }
2148 } // class PostEventQueue