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