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