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