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