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