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