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         // All events posted via this method are system-generated.
 517         // Placing the following call here reduces considerably the
 518         // number of places throughout the toolkit that would
 519         // otherwise have to be modified to precisely identify
 520         // system-generated events.
 521         setSystemGenerated(event);
 522         AppContext eventContext = targetToAppContext(event.getSource());
 523         if (eventContext != null && !eventContext.equals(appContext)) {
 524             log.fine("Event posted on wrong app context : " + event);
 525         }
 526         PostEventQueue postEventQueue =
 527             (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 528         if (postEventQueue != null) {
 529             postEventQueue.postEvent(event);
 530         }
 531     }
 532 
 533     /*
 534      * Post AWTEvent of high priority.
 535      */
 536     public static void postPriorityEvent(final AWTEvent e) {
 537         PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(), new Runnable() {
 538                 public void run() {
 539                     AWTAccessor.getAWTEventAccessor().setPosted(e);
 540                     ((Component)e.getSource()).dispatchEvent(e);
 541                 }
 542             }, PeerEvent.ULTIMATE_PRIORITY_EVENT);
 543         postEvent(targetToAppContext(e.getSource()), pe);
 544     }
 545 
 546     protected static final Lock flushLock = new ReentrantLock();
 547     private static boolean isFlushingPendingEvents = false;
 548 
 549     /*
 550      * Flush any pending events which haven't been posted to the AWT
 551      * EventQueue yet.
 552      */
 553     public static void flushPendingEvents()  {
 554         flushLock.lock();
 555         try {
 556             // Don't call flushPendingEvents() recursively
 557             if (!isFlushingPendingEvents) {
 558                 isFlushingPendingEvents = true;
 559                 AppContext appContext = AppContext.getAppContext();
 560                 PostEventQueue postEventQueue =
 561                     (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 562                 if (postEventQueue != null) {
 563                     postEventQueue.flush();
 564                 }
 565             }
 566         } finally {
 567             isFlushingPendingEvents = false;
 568             flushLock.unlock();
 569         }
 570     }
 571 
 572     public static boolean isPostEventQueueEmpty()  {
 573         AppContext appContext = AppContext.getAppContext();
 574         PostEventQueue postEventQueue =
 575             (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
 576         if (postEventQueue != null) {
 577             return postEventQueue.noEvents();
 578         } else {
 579             return true;
 580         }
 581     }
 582 
 583     /*
 584      * Execute a chunk of code on the Java event handler thread for the
 585      * given target.  Does not wait for the execution to occur before
 586      * returning to the caller.
 587      */
 588     public static void executeOnEventHandlerThread(Object target,
 589                                                    Runnable runnable) {
 590         executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT));
 591     }
 592 
 593     /*
 594      * Fixed 5064013: the InvocationEvent time should be equals
 595      * the time of the ActionEvent
 596      */
 597     @SuppressWarnings("serial")
 598     public static void executeOnEventHandlerThread(Object target,
 599                                                    Runnable runnable,
 600                                                    final long when) {
 601         executeOnEventHandlerThread(
 602             new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT) {
 603                 public long getWhen() {
 604                     return when;
 605                 }
 606             });
 607     }
 608 
 609     /*
 610      * Execute a chunk of code on the Java event handler thread for the
 611      * given target.  Does not wait for the execution to occur before
 612      * returning to the caller.
 613      */
 614     public static void executeOnEventHandlerThread(PeerEvent peerEvent) {
 615         postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
 616     }
 617 
 618     /*
 619      * Execute a chunk of code on the Java event handler thread. The
 620      * method takes into account provided AppContext and sets
 621      * <code>SunToolkit.getDefaultToolkit()</code> as a target of the
 622      * event. See 6451487 for detailes.
 623      * Does not wait for the execution to occur before returning to
 624      * the caller.
 625      */
 626      public static void invokeLaterOnAppContext(
 627         AppContext appContext, Runnable dispatcher)
 628      {
 629         postEvent(appContext,
 630             new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher,
 631                 PeerEvent.PRIORITY_EVENT));
 632      }
 633 
 634     /*
 635      * Execute a chunk of code on the Java event handler thread for the
 636      * given target.  Waits for the execution to occur before returning
 637      * to the caller.
 638      */
 639     public static void executeOnEDTAndWait(Object target, Runnable runnable)
 640         throws InterruptedException, InvocationTargetException
 641     {
 642         if (EventQueue.isDispatchThread()) {
 643             throw new Error("Cannot call executeOnEDTAndWait from any event dispatcher thread");
 644         }
 645 
 646         class AWTInvocationLock {}
 647         Object lock = new AWTInvocationLock();
 648 
 649         PeerEvent event = new PeerEvent(target, runnable, lock, true, PeerEvent.PRIORITY_EVENT);
 650 
 651         synchronized (lock) {
 652             executeOnEventHandlerThread(event);
 653             while(!event.isDispatched()) {
 654                 lock.wait();
 655             }
 656         }
 657 
 658         Throwable eventThrowable = event.getThrowable();
 659         if (eventThrowable != null) {
 660             throw new InvocationTargetException(eventThrowable);
 661         }
 662     }
 663 
 664     /*
 665      * Returns true if the calling thread is the event dispatch thread
 666      * contained within AppContext which associated with the given target.
 667      * Use this call to ensure that a given task is being executed
 668      * (or not being) on the event dispatch thread for the given target.
 669      */
 670     public static boolean isDispatchThreadForAppContext(Object target) {
 671         AppContext appContext = targetToAppContext(target);
 672         EventQueue eq = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
 673 
 674         AWTAccessor.EventQueueAccessor accessor = AWTAccessor.getEventQueueAccessor();
 675         return accessor.isDispatchThreadImpl(eq);
 676     }
 677 
 678     public Dimension getScreenSize() {
 679         return new Dimension(getScreenWidth(), getScreenHeight());
 680     }
 681     protected abstract int getScreenWidth();
 682     protected abstract int getScreenHeight();
 683 
 684     @SuppressWarnings("deprecation")
 685     public FontMetrics getFontMetrics(Font font) {
 686         return FontDesignMetrics.getMetrics(font);
 687     }
 688 
 689     @SuppressWarnings("deprecation")
 690     public String[] getFontList() {
 691         String[] hardwiredFontList = {
 692             Font.DIALOG, Font.SANS_SERIF, Font.SERIF, Font.MONOSPACED,
 693             Font.DIALOG_INPUT
 694 
 695             // -- Obsolete font names from 1.0.2.  It was decided that
 696             // -- getFontList should not return these old names:
 697             //    "Helvetica", "TimesRoman", "Courier", "ZapfDingbats"
 698         };
 699         return hardwiredFontList;
 700     }
 701 
 702     public PanelPeer createPanel(Panel target) {
 703         return (PanelPeer)createComponent(target);
 704     }
 705 
 706     public CanvasPeer createCanvas(Canvas target) {
 707         return (CanvasPeer)createComponent(target);
 708     }
 709 
 710     /**
 711      * Disables erasing of background on the canvas before painting if
 712      * this is supported by the current toolkit. It is recommended to
 713      * call this method early, before the Canvas becomes displayable,
 714      * because some Toolkit implementations do not support changing
 715      * this property once the Canvas becomes displayable.
 716      */
 717     public void disableBackgroundErase(Canvas canvas) {
 718         disableBackgroundEraseImpl(canvas);
 719     }
 720 
 721     /**
 722      * Disables the native erasing of the background on the given
 723      * component before painting if this is supported by the current
 724      * toolkit. This only has an effect for certain components such as
 725      * Canvas, Panel and Window. It is recommended to call this method
 726      * early, before the Component becomes displayable, because some
 727      * Toolkit implementations do not support changing this property
 728      * once the Component becomes displayable.
 729      */
 730     public void disableBackgroundErase(Component component) {
 731         disableBackgroundEraseImpl(component);
 732     }
 733 
 734     private void disableBackgroundEraseImpl(Component component) {
 735         AWTAccessor.getComponentAccessor().setBackgroundEraseDisabled(component, true);
 736     }
 737 
 738     /**
 739      * Returns the value of "sun.awt.noerasebackground" property. Default
 740      * value is {@code false}.
 741      */
 742     public static boolean getSunAwtNoerasebackground() {
 743         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.noerasebackground"));
 744     }
 745 
 746     /**
 747      * Returns the value of "sun.awt.erasebackgroundonresize" property. Default
 748      * value is {@code false}.
 749      */
 750     public static boolean getSunAwtErasebackgroundonresize() {
 751         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.erasebackgroundonresize"));
 752     }
 753 
 754 
 755     static final SoftCache imgCache = new SoftCache();
 756 
 757     static Image getImageFromHash(Toolkit tk, URL url) {
 758         SecurityManager sm = System.getSecurityManager();
 759         if (sm != null) {
 760             try {
 761                 java.security.Permission perm =
 762                     url.openConnection().getPermission();
 763                 if (perm != null) {
 764                     try {
 765                         sm.checkPermission(perm);
 766                     } catch (SecurityException se) {
 767                         // fallback to checkRead/checkConnect for pre 1.2
 768                         // security managers
 769                         if ((perm instanceof java.io.FilePermission) &&
 770                             perm.getActions().indexOf("read") != -1) {
 771                             sm.checkRead(perm.getName());
 772                         } else if ((perm instanceof
 773                             java.net.SocketPermission) &&
 774                             perm.getActions().indexOf("connect") != -1) {
 775                             sm.checkConnect(url.getHost(), url.getPort());
 776                         } else {
 777                             throw se;
 778                         }
 779                     }
 780                 }
 781             } catch (java.io.IOException ioe) {
 782                     sm.checkConnect(url.getHost(), url.getPort());
 783             }
 784         }
 785         synchronized (imgCache) {
 786             Image img = (Image)imgCache.get(url);
 787             if (img == null) {
 788                 try {
 789                     img = tk.createImage(new URLImageSource(url));
 790                     imgCache.put(url, img);
 791                 } catch (Exception e) {
 792                 }
 793             }
 794             return img;
 795         }
 796     }
 797 
 798     static Image getImageFromHash(Toolkit tk,
 799                                                String filename) {
 800         SecurityManager security = System.getSecurityManager();
 801         if (security != null) {
 802             security.checkRead(filename);
 803         }
 804         synchronized (imgCache) {
 805             Image img = (Image)imgCache.get(filename);
 806             if (img == null) {
 807                 try {
 808                     img = tk.createImage(new FileImageSource(filename));
 809                     imgCache.put(filename, img);
 810                 } catch (Exception e) {
 811                 }
 812             }
 813             return img;
 814         }
 815     }
 816 
 817     public Image getImage(String filename) {
 818         return getImageFromHash(this, filename);
 819     }
 820 
 821     public Image getImage(URL url) {
 822         return getImageFromHash(this, url);
 823     }
 824 
 825     public Image createImage(String filename) {
 826         SecurityManager security = System.getSecurityManager();
 827         if (security != null) {
 828             security.checkRead(filename);
 829         }
 830         return createImage(new FileImageSource(filename));
 831     }
 832 
 833     public Image createImage(URL url) {
 834         SecurityManager sm = System.getSecurityManager();
 835         if (sm != null) {
 836             try {
 837                 java.security.Permission perm =
 838                     url.openConnection().getPermission();
 839                 if (perm != null) {
 840                     try {
 841                         sm.checkPermission(perm);
 842                     } catch (SecurityException se) {
 843                         // fallback to checkRead/checkConnect for pre 1.2
 844                         // security managers
 845                         if ((perm instanceof java.io.FilePermission) &&
 846                             perm.getActions().indexOf("read") != -1) {
 847                             sm.checkRead(perm.getName());
 848                         } else if ((perm instanceof
 849                             java.net.SocketPermission) &&
 850                             perm.getActions().indexOf("connect") != -1) {
 851                             sm.checkConnect(url.getHost(), url.getPort());
 852                         } else {
 853                             throw se;
 854                         }
 855                     }
 856                 }
 857             } catch (java.io.IOException ioe) {
 858                     sm.checkConnect(url.getHost(), url.getPort());
 859             }
 860         }
 861         return createImage(new URLImageSource(url));
 862     }
 863 
 864     public Image createImage(byte[] data, int offset, int length) {
 865         return createImage(new ByteArrayImageSource(data, offset, length));
 866     }
 867 
 868     public Image createImage(ImageProducer producer) {
 869         return new ToolkitImage(producer);
 870     }
 871 
 872     public int checkImage(Image img, int w, int h, ImageObserver o) {
 873         if (!(img instanceof ToolkitImage)) {
 874             return ImageObserver.ALLBITS;
 875         }
 876 
 877         ToolkitImage tkimg = (ToolkitImage)img;
 878         int repbits;
 879         if (w == 0 || h == 0) {
 880             repbits = ImageObserver.ALLBITS;
 881         } else {
 882             repbits = tkimg.getImageRep().check(o);
 883         }
 884         return tkimg.check(o) | repbits;
 885     }
 886 
 887     public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
 888         if (w == 0 || h == 0) {
 889             return true;
 890         }
 891 
 892         // Must be a ToolkitImage
 893         if (!(img instanceof ToolkitImage)) {
 894             return true;
 895         }
 896 
 897         ToolkitImage tkimg = (ToolkitImage)img;
 898         if (tkimg.hasError()) {
 899             if (o != null) {
 900                 o.imageUpdate(img, ImageObserver.ERROR|ImageObserver.ABORT,
 901                               -1, -1, -1, -1);
 902             }
 903             return false;
 904         }
 905         ImageRepresentation ir = tkimg.getImageRep();
 906         return ir.prepare(o);
 907     }
 908 
 909     /**
 910      * Scans {@code imageList} for best-looking image of specified dimensions.
 911      * Image can be scaled and/or padded with transparency.
 912      */
 913     public static BufferedImage getScaledIconImage(java.util.List<Image> imageList, int width, int height) {
 914         if (width == 0 || height == 0) {
 915             return null;
 916         }
 917         Image bestImage = null;
 918         int bestWidth = 0;
 919         int bestHeight = 0;
 920         double bestSimilarity = 3; //Impossibly high value
 921         double bestScaleFactor = 0;
 922         for (Iterator<Image> i = imageList.iterator();i.hasNext();) {
 923             //Iterate imageList looking for best matching image.
 924             //'Similarity' measure is defined as good scale factor and small insets.
 925             //best possible similarity is 0 (no scale, no insets).
 926             //It's found while the experiments that good-looking result is achieved
 927             //with scale factors x1, x3/4, x2/3, xN, x1/N.
 928             Image im = i.next();
 929             if (im == null) {
 930                 if (log.isLoggable(PlatformLogger.FINER)) {
 931                     log.finer("SunToolkit.getScaledIconImage: " +
 932                               "Skipping the image passed into Java because it's null.");
 933                 }
 934                 continue;
 935             }
 936             if (im instanceof ToolkitImage) {
 937                 ImageRepresentation ir = ((ToolkitImage)im).getImageRep();
 938                 ir.reconstruct(ImageObserver.ALLBITS);
 939             }
 940             int iw;
 941             int ih;
 942             try {
 943                 iw = im.getWidth(null);
 944                 ih = im.getHeight(null);
 945             } catch (Exception e){
 946                 if (log.isLoggable(PlatformLogger.FINER)) {
 947                     log.finer("SunToolkit.getScaledIconImage: " +
 948                               "Perhaps the image passed into Java is broken. Skipping this icon.");
 949                 }
 950                 continue;
 951             }
 952             if (iw > 0 && ih > 0) {
 953                 //Calc scale factor
 954                 double scaleFactor = Math.min((double)width / (double)iw,
 955                                               (double)height / (double)ih);
 956                 //Calculate scaled image dimensions
 957                 //adjusting scale factor to nearest "good" value
 958                 int adjw = 0;
 959                 int adjh = 0;
 960                 double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad
 961                 if (scaleFactor >= 2) {
 962                     //Need to enlarge image more than twice
 963                     //Round down scale factor to multiply by integer value
 964                     scaleFactor = Math.floor(scaleFactor);
 965                     adjw = iw * (int)scaleFactor;
 966                     adjh = ih * (int)scaleFactor;
 967                     scaleMeasure = 1.0 - 0.5 / scaleFactor;
 968                 } else if (scaleFactor >= 1) {
 969                     //Don't scale
 970                     scaleFactor = 1.0;
 971                     adjw = iw;
 972                     adjh = ih;
 973                     scaleMeasure = 0;
 974                 } else if (scaleFactor >= 0.75) {
 975                     //Multiply by 3/4
 976                     scaleFactor = 0.75;
 977                     adjw = iw * 3 / 4;
 978                     adjh = ih * 3 / 4;
 979                     scaleMeasure = 0.3;
 980                 } else if (scaleFactor >= 0.6666) {
 981                     //Multiply by 2/3
 982                     scaleFactor = 0.6666;
 983                     adjw = iw * 2 / 3;
 984                     adjh = ih * 2 / 3;
 985                     scaleMeasure = 0.33;
 986                 } else {
 987                     //Multiply size by 1/scaleDivider
 988                     //where scaleDivider is minimum possible integer
 989                     //larger than 1/scaleFactor
 990                     double scaleDivider = Math.ceil(1.0 / scaleFactor);
 991                     scaleFactor = 1.0 / scaleDivider;
 992                     adjw = (int)Math.round((double)iw / scaleDivider);
 993                     adjh = (int)Math.round((double)ih / scaleDivider);
 994                     scaleMeasure = 1.0 - 1.0 / scaleDivider;
 995                 }
 996                 double similarity = ((double)width - (double)adjw) / (double)width +
 997                     ((double)height - (double)adjh) / (double)height + //Large padding is bad
 998                     scaleMeasure; //Large rescale is bad
 999                 if (similarity < bestSimilarity) {
1000                     bestSimilarity = similarity;
1001                     bestScaleFactor = scaleFactor;
1002                     bestImage = im;
1003                     bestWidth = adjw;
1004                     bestHeight = adjh;
1005                 }
1006                 if (similarity == 0) break;
1007             }
1008         }
1009         if (bestImage == null) {
1010             //No images were found, possibly all are broken
1011             return null;
1012         }
1013         BufferedImage bimage =
1014             new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
1015         Graphics2D g = bimage.createGraphics();
1016         g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
1017                            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
1018         try {
1019             int x = (width - bestWidth) / 2;
1020             int y = (height - bestHeight) / 2;
1021             if (log.isLoggable(PlatformLogger.FINER)) {
1022                 log.finer("WWindowPeer.getScaledIconData() result : " +
1023                         "w : " + width + " h : " + height +
1024                         " iW : " + bestImage.getWidth(null) + " iH : " + bestImage.getHeight(null) +
1025                         " sim : " + bestSimilarity + " sf : " + bestScaleFactor +
1026                         " adjW : " + bestWidth + " adjH : " + bestHeight +
1027                         " x : " + x + " y : " + y);
1028             }
1029             g.drawImage(bestImage, x, y, bestWidth, bestHeight, null);
1030         } finally {
1031             g.dispose();
1032         }
1033         return bimage;
1034     }
1035 
1036     public static DataBufferInt getScaledIconData(java.util.List<Image> imageList, int width, int height) {
1037         BufferedImage bimage = getScaledIconImage(imageList, width, height);
1038         if (bimage == null) {
1039              if (log.isLoggable(PlatformLogger.FINER)) {
1040                  log.finer("SunToolkit.getScaledIconData: " +
1041                            "Perhaps the image passed into Java is broken. Skipping this icon.");
1042              }
1043             return null;
1044         }
1045         Raster raster = bimage.getRaster();
1046         DataBuffer buffer = raster.getDataBuffer();
1047         return (DataBufferInt)buffer;
1048     }
1049 
1050     protected EventQueue getSystemEventQueueImpl() {
1051         return getSystemEventQueueImplPP();
1052     }
1053 
1054     // Package private implementation
1055     static EventQueue getSystemEventQueueImplPP() {
1056         return getSystemEventQueueImplPP(AppContext.getAppContext());
1057     }
1058 
1059     public static EventQueue getSystemEventQueueImplPP(AppContext appContext) {
1060         EventQueue theEventQueue =
1061             (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
1062         return theEventQueue;
1063     }
1064 
1065     /**
1066      * Give native peers the ability to query the native container
1067      * given a native component (eg the direct parent may be lightweight).
1068      */
1069     public static Container getNativeContainer(Component c) {
1070         return Toolkit.getNativeContainer(c);
1071     }
1072 
1073     /**
1074      * Gives native peers the ability to query the closest HW component.
1075      * If the given component is heavyweight, then it returns this. Otherwise,
1076      * it goes one level up in the hierarchy and tests next component.
1077      */
1078     public static Component getHeavyweightComponent(Component c) {
1079         while (c != null && AWTAccessor.getComponentAccessor().isLightweight(c)) {
1080             c = AWTAccessor.getComponentAccessor().getParent(c);
1081         }
1082         return c;
1083     }
1084 
1085     /**
1086      * Returns key modifiers used by Swing to set up a focus accelerator key stroke.
1087      */
1088     public int getFocusAcceleratorKeyMask() {
1089         return InputEvent.ALT_MASK;
1090     }
1091 
1092     /**
1093      * Tests whether specified key modifiers mask can be used to enter a printable
1094      * character. This is a default implementation of this method, which reflects
1095      * the way things work on Windows: here, pressing ctrl + alt allows user to enter
1096      * characters from the extended character set (like euro sign or math symbols)
1097      */
1098     public boolean isPrintableCharacterModifiersMask(int mods) {
1099         return ((mods & InputEvent.ALT_MASK) == (mods & InputEvent.CTRL_MASK));
1100     }
1101 
1102     /**
1103      * Returns whether popup is allowed to be shown above the task bar.
1104      * This is a default implementation of this method, which checks
1105      * corresponding security permission.
1106      */
1107     public boolean canPopupOverlapTaskBar() {
1108         boolean result = true;
1109         try {
1110             SecurityManager sm = System.getSecurityManager();
1111             if (sm != null) {
1112                 sm.checkPermission(
1113                         SecurityConstants.AWT.SET_WINDOW_ALWAYS_ON_TOP_PERMISSION);
1114             }
1115         } catch (SecurityException se) {
1116             // There is no permission to show popups over the task bar
1117             result = false;
1118         }
1119         return result;
1120     }
1121 
1122     /**
1123      * Returns a new input method window, with behavior as specified in
1124      * {@link java.awt.im.spi.InputMethodContext#createInputMethodWindow}.
1125      * If the inputContext is not null, the window should return it from its
1126      * getInputContext() method. The window needs to implement
1127      * sun.awt.im.InputMethodWindow.
1128      * <p>
1129      * SunToolkit subclasses can override this method to return better input
1130      * method windows.
1131      */
1132     public Window createInputMethodWindow(String title, InputContext context) {
1133         return new sun.awt.im.SimpleInputMethodWindow(title, context);
1134     }
1135 
1136     /**
1137      * Returns whether enableInputMethods should be set to true for peered
1138      * TextComponent instances on this platform. False by default.
1139      */
1140     public boolean enableInputMethodsForTextComponent() {
1141         return false;
1142     }
1143 
1144     private static Locale startupLocale = null;
1145 
1146     /**
1147      * Returns the locale in which the runtime was started.
1148      */
1149     public static Locale getStartupLocale() {
1150         if (startupLocale == null) {
1151             String language, region, country, variant;
1152             language = AccessController.doPrivileged(
1153                             new GetPropertyAction("user.language", "en"));
1154             // for compatibility, check for old user.region property
1155             region = AccessController.doPrivileged(
1156                             new GetPropertyAction("user.region"));
1157             if (region != null) {
1158                 // region can be of form country, country_variant, or _variant
1159                 int i = region.indexOf('_');
1160                 if (i >= 0) {
1161                     country = region.substring(0, i);
1162                     variant = region.substring(i + 1);
1163                 } else {
1164                     country = region;
1165                     variant = "";
1166                 }
1167             } else {
1168                 country = AccessController.doPrivileged(
1169                                 new GetPropertyAction("user.country", ""));
1170                 variant = AccessController.doPrivileged(
1171                                 new GetPropertyAction("user.variant", ""));
1172             }
1173             startupLocale = new Locale(language, country, variant);
1174         }
1175         return startupLocale;
1176     }
1177 
1178     /**
1179      * Returns the default keyboard locale of the underlying operating system
1180      */
1181     public Locale getDefaultKeyboardLocale() {
1182         return getStartupLocale();
1183     }
1184 
1185     private static String dataTransfererClassName = null;
1186 
1187     protected static void setDataTransfererClassName(String className) {
1188         dataTransfererClassName = className;
1189     }
1190 
1191     public static String getDataTransfererClassName() {
1192         if (dataTransfererClassName == null) {
1193             Toolkit.getDefaultToolkit(); // transferer set during toolkit init
1194         }
1195         return dataTransfererClassName;
1196     }
1197 
1198     // Support for window closing event notifications
1199     private transient WindowClosingListener windowClosingListener = null;
1200     /**
1201      * @see sun.awt.WindowClosingSupport#getWindowClosingListener
1202      */
1203     public WindowClosingListener getWindowClosingListener() {
1204         return windowClosingListener;
1205     }
1206     /**
1207      * @see sun.awt.WindowClosingSupport#setWindowClosingListener
1208      */
1209     public void setWindowClosingListener(WindowClosingListener wcl) {
1210         windowClosingListener = wcl;
1211     }
1212 
1213     /**
1214      * @see sun.awt.WindowClosingListener#windowClosingNotify
1215      */
1216     public RuntimeException windowClosingNotify(WindowEvent event) {
1217         if (windowClosingListener != null) {
1218             return windowClosingListener.windowClosingNotify(event);
1219         } else {
1220             return null;
1221         }
1222     }
1223     /**
1224      * @see sun.awt.WindowClosingListener#windowClosingDelivered
1225      */
1226     public RuntimeException windowClosingDelivered(WindowEvent event) {
1227         if (windowClosingListener != null) {
1228             return windowClosingListener.windowClosingDelivered(event);
1229         } else {
1230             return null;
1231         }
1232     }
1233 
1234     private static DefaultMouseInfoPeer mPeer = null;
1235 
1236     protected synchronized MouseInfoPeer getMouseInfoPeer() {
1237         if (mPeer == null) {
1238             mPeer = new DefaultMouseInfoPeer();
1239         }
1240         return mPeer;
1241     }
1242 
1243 
1244     /**
1245      * Returns whether default toolkit needs the support of the xembed
1246      * from embedding host(if any).
1247      * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1248      */
1249     public static boolean needsXEmbed() {
1250         String noxembed = AccessController.
1251             doPrivileged(new GetPropertyAction("sun.awt.noxembed", "false"));
1252         if ("true".equals(noxembed)) {
1253             return false;
1254         }
1255 
1256         Toolkit tk = Toolkit.getDefaultToolkit();
1257         if (tk instanceof SunToolkit) {
1258             // SunToolkit descendants should override this method to specify
1259             // concrete behavior
1260             return ((SunToolkit)tk).needsXEmbedImpl();
1261         } else {
1262             // Non-SunToolkit doubtly might support XEmbed
1263             return false;
1264         }
1265     }
1266 
1267     /**
1268      * Returns whether this toolkit needs the support of the xembed
1269      * from embedding host(if any).
1270      * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1271      */
1272     protected boolean needsXEmbedImpl() {
1273         return false;
1274     }
1275 
1276     private static Dialog.ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE = null;
1277 
1278     /**
1279      * Returns whether the XEmbed server feature is requested by
1280      * developer.  If true, Toolkit should return an
1281      * XEmbed-server-enabled CanvasPeer instead of the ordinary CanvasPeer.
1282      */
1283     protected final boolean isXEmbedServerRequested() {
1284         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembedserver"));
1285     }
1286 
1287     /**
1288      * Returns whether the modal exclusion API is supported by the current toolkit.
1289      * When it isn't supported, calling <code>setModalExcluded</code> has no
1290      * effect, and <code>isModalExcluded</code> returns false for all windows.
1291      *
1292      * @return true if modal exclusion is supported by the toolkit, false otherwise
1293      *
1294      * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1295      * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1296      *
1297      * @since 1.5
1298      */
1299     public static boolean isModalExcludedSupported()
1300     {
1301         Toolkit tk = Toolkit.getDefaultToolkit();
1302         return tk.isModalExclusionTypeSupported(DEFAULT_MODAL_EXCLUSION_TYPE);
1303     }
1304     /*
1305      * Default implementation for isModalExcludedSupportedImpl(), returns false.
1306      *
1307      * @see sun.awt.windows.WToolkit#isModalExcludeSupportedImpl
1308      * @see sun.awt.X11.XToolkit#isModalExcludeSupportedImpl
1309      *
1310      * @since 1.5
1311      */
1312     protected boolean isModalExcludedSupportedImpl()
1313     {
1314         return false;
1315     }
1316 
1317     /*
1318      * Sets this window to be excluded from being modally blocked. When the
1319      * toolkit supports modal exclusion and this method is called, input
1320      * events, focus transfer and z-order will continue to work for the
1321      * window, it's owned windows and child components, even in the
1322      * presence of a modal dialog.
1323      * For details on which <code>Window</code>s are normally blocked
1324      * by modal dialog, see {@link java.awt.Dialog}.
1325      * Invoking this method when the modal exclusion API is not supported by
1326      * the current toolkit has no effect.
1327      * @param window Window to be marked as not modally blocked
1328      * @see java.awt.Dialog
1329      * @see java.awt.Dialog#setModal(boolean)
1330      * @see sun.awt.SunToolkit#isModalExcludedSupported
1331      * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1332      */
1333     public static void setModalExcluded(Window window)
1334     {
1335         if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {
1336             DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;
1337         }
1338         window.setModalExclusionType(DEFAULT_MODAL_EXCLUSION_TYPE);
1339     }
1340 
1341     /*
1342      * Returns whether the specified window is blocked by modal dialogs.
1343      * If the modal exclusion API isn't supported by the current toolkit,
1344      * it returns false for all windows.
1345      *
1346      * @param window Window to test for modal exclusion
1347      *
1348      * @return true if the window is modal excluded, false otherwise. If
1349      * the modal exclusion isn't supported by the current Toolkit, false
1350      * is returned
1351      *
1352      * @see sun.awt.SunToolkit#isModalExcludedSupported
1353      * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1354      *
1355      * @since 1.5
1356      */
1357     public static boolean isModalExcluded(Window window)
1358     {
1359         if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {
1360             DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;
1361         }
1362         return window.getModalExclusionType().compareTo(DEFAULT_MODAL_EXCLUSION_TYPE) >= 0;
1363     }
1364 
1365     /**
1366      * Overridden in XToolkit and WToolkit
1367      */
1368     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
1369         return (modalityType == Dialog.ModalityType.MODELESS) ||
1370                (modalityType == Dialog.ModalityType.APPLICATION_MODAL);
1371     }
1372 
1373     /**
1374      * Overridden in XToolkit and WToolkit
1375      */
1376     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
1377         return (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE);
1378     }
1379 
1380     ///////////////////////////////////////////////////////////////////////////
1381     //
1382     // The following is used by the Java Plug-in to coordinate dialog modality
1383     // between containing applications (browsers, ActiveX containers etc) and
1384     // the AWT.
1385     //
1386     ///////////////////////////////////////////////////////////////////////////
1387 
1388     private ModalityListenerList modalityListeners = new ModalityListenerList();
1389 
1390     public void addModalityListener(ModalityListener listener) {
1391         modalityListeners.add(listener);
1392     }
1393 
1394     public void removeModalityListener(ModalityListener listener) {
1395         modalityListeners.remove(listener);
1396     }
1397 
1398     public void notifyModalityPushed(Dialog dialog) {
1399         notifyModalityChange(ModalityEvent.MODALITY_PUSHED, dialog);
1400     }
1401 
1402     public void notifyModalityPopped(Dialog dialog) {
1403         notifyModalityChange(ModalityEvent.MODALITY_POPPED, dialog);
1404     }
1405 
1406     final void notifyModalityChange(int id, Dialog source) {
1407         ModalityEvent ev = new ModalityEvent(source, modalityListeners, id);
1408         ev.dispatch();
1409     }
1410 
1411     static class ModalityListenerList implements ModalityListener {
1412 
1413         Vector<ModalityListener> listeners = new Vector<ModalityListener>();
1414 
1415         void add(ModalityListener listener) {
1416             listeners.addElement(listener);
1417         }
1418 
1419         void remove(ModalityListener listener) {
1420             listeners.removeElement(listener);
1421         }
1422 
1423         public void modalityPushed(ModalityEvent ev) {
1424             Iterator<ModalityListener> it = listeners.iterator();
1425             while (it.hasNext()) {
1426                 it.next().modalityPushed(ev);
1427             }
1428         }
1429 
1430         public void modalityPopped(ModalityEvent ev) {
1431             Iterator<ModalityListener> it = listeners.iterator();
1432             while (it.hasNext()) {
1433                 it.next().modalityPopped(ev);
1434             }
1435         }
1436     } // end of class ModalityListenerList
1437 
1438     ///////////////////////////////////////////////////////////////////////////
1439     // End Plug-in code
1440     ///////////////////////////////////////////////////////////////////////////
1441 
1442     public static boolean isLightweightOrUnknown(Component comp) {
1443         if (comp.isLightweight()
1444             || !(getDefaultToolkit() instanceof SunToolkit))
1445         {
1446             return true;
1447         }
1448         return !(comp instanceof Button
1449             || comp instanceof Canvas
1450             || comp instanceof Checkbox
1451             || comp instanceof Choice
1452             || comp instanceof Label
1453             || comp instanceof java.awt.List
1454             || comp instanceof Panel
1455             || comp instanceof Scrollbar
1456             || comp instanceof ScrollPane
1457             || comp instanceof TextArea
1458             || comp instanceof TextField
1459             || comp instanceof Window);
1460     }
1461 
1462     public static Method getMethod(final Class<?> clz, final String methodName, final Class[] params) {
1463         Method res = null;
1464         try {
1465             res = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
1466                     public Method run() throws Exception {
1467                         Method m = clz.getDeclaredMethod(methodName, params);
1468                         m.setAccessible(true);
1469                         return m;
1470                     }
1471                 });
1472         } catch (PrivilegedActionException ex) {
1473             ex.printStackTrace();
1474         }
1475         return res;
1476     }
1477 
1478     @SuppressWarnings("serial")
1479     public static class OperationTimedOut extends RuntimeException {
1480         public OperationTimedOut(String msg) {
1481             super(msg);
1482         }
1483         public OperationTimedOut() {
1484         }
1485     }
1486 
1487     @SuppressWarnings("serial")
1488     public static class InfiniteLoop extends RuntimeException {
1489     }
1490 
1491     @SuppressWarnings("serial")
1492     public static class IllegalThreadException extends RuntimeException {
1493         public IllegalThreadException(String msg) {
1494             super(msg);
1495         }
1496         public IllegalThreadException() {
1497         }
1498     }
1499 
1500     public static final int DEFAULT_WAIT_TIME = 10000;
1501     private static final int MAX_ITERS = 20;
1502     private static final int MIN_ITERS = 0;
1503     private static final int MINIMAL_EDELAY = 0;
1504 
1505     /**
1506      * Parameterless version of realsync which uses default timout (see DEFAUL_WAIT_TIME).
1507      */
1508     public void realSync() throws OperationTimedOut, InfiniteLoop {
1509         realSync(DEFAULT_WAIT_TIME);
1510     }
1511 
1512     /**
1513      * Forces toolkit to synchronize with the native windowing
1514      * sub-system, flushing all pending work and waiting for all the
1515      * events to be processed.  This method guarantees that after
1516      * return no additional Java events will be generated, unless
1517      * cause by user. Obviously, the method cannot be used on the
1518      * event dispatch thread (EDT). In case it nevertheless gets
1519      * invoked on this thread, the method throws the
1520      * IllegalThreadException runtime exception.
1521      *
1522      * <p> This method allows to write tests without explicit timeouts
1523      * or wait for some event.  Example:
1524      * <code>
1525      * Frame f = ...;
1526      * f.setVisible(true);
1527      * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1528      * </code>
1529      *
1530      * <p> After realSync, <code>f</code> will be completely visible
1531      * on the screen, its getLocationOnScreen will be returning the
1532      * right result and it will be the focus owner.
1533      *
1534      * <p> Another example:
1535      * <code>
1536      * b.requestFocus();
1537      * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1538      * </code>
1539      *
1540      * <p> After realSync, <code>b</code> will be focus owner.
1541      *
1542      * <p> Notice that realSync isn't guaranteed to work if recurring
1543      * actions occur, such as if during processing of some event
1544      * another request which may generate some events occurs.  By
1545      * default, sync tries to perform as much as {@value MAX_ITERS}
1546      * cycles of event processing, allowing for roughly {@value
1547      * MAX_ITERS} additional requests.
1548      *
1549      * <p> For example, requestFocus() generates native request, which
1550      * generates one or two Java focus events, which then generate a
1551      * serie of paint events, a serie of Java focus events, which then
1552      * generate a serie of paint events which then are processed -
1553      * three cycles, minimum.
1554      *
1555      * @param timeout the maximum time to wait in milliseconds, negative means "forever".
1556      */
1557     public void realSync(final long timeout) throws OperationTimedOut, InfiniteLoop
1558     {
1559         if (EventQueue.isDispatchThread()) {
1560             throw new IllegalThreadException("The SunToolkit.realSync() method cannot be used on the event dispatch thread (EDT).");
1561         }
1562         int bigLoop = 0;
1563         do {
1564             // Let's do sync first
1565             sync();
1566 
1567             // During the wait process, when we were processing incoming
1568             // events, we could have made some new request, which can
1569             // generate new events.  Example: MapNotify/XSetInputFocus.
1570             // Therefore, we dispatch them as long as there is something
1571             // to dispatch.
1572             int iters = 0;
1573             while (iters < MIN_ITERS) {
1574                 syncNativeQueue(timeout);
1575                 iters++;
1576             }
1577             while (syncNativeQueue(timeout) && iters < MAX_ITERS) {
1578                 iters++;
1579             }
1580             if (iters >= MAX_ITERS) {
1581                 throw new InfiniteLoop();
1582             }
1583 
1584             // native requests were dispatched by X/Window Manager or Windows
1585             // Moreover, we processed them all on Toolkit thread
1586             // Now wait while EDT processes them.
1587             //
1588             // During processing of some events (focus, for example),
1589             // some other events could have been generated.  So, after
1590             // waitForIdle, we may end up with full EventQueue
1591             iters = 0;
1592             while (iters < MIN_ITERS) {
1593                 waitForIdle(timeout);
1594                 iters++;
1595             }
1596             while (waitForIdle(timeout) && iters < MAX_ITERS) {
1597                 iters++;
1598             }
1599             if (iters >= MAX_ITERS) {
1600                 throw new InfiniteLoop();
1601             }
1602 
1603             bigLoop++;
1604             // Again, for Java events, it was simple to check for new Java
1605             // events by checking event queue, but what if Java events
1606             // resulted in native requests?  Therefor, check native events again.
1607         } while ((syncNativeQueue(timeout) || waitForIdle(timeout)) && bigLoop < MAX_ITERS);
1608     }
1609 
1610     /**
1611      * Platform toolkits need to implement this method to perform the
1612      * sync of the native queue.  The method should wait until native
1613      * requests are processed, all native events are processed and
1614      * corresponding Java events are generated.  Should return
1615      * <code>true</code> if some events were processed,
1616      * <code>false</code> otherwise.
1617      */
1618     protected abstract boolean syncNativeQueue(final long timeout);
1619 
1620     private boolean eventDispatched = false;
1621     private boolean queueEmpty = false;
1622     private final Object waitLock = "Wait Lock";
1623 
1624     static Method eqNoEvents;
1625 
1626     private boolean isEQEmpty() {
1627         EventQueue queue = getSystemEventQueueImpl();
1628         synchronized(SunToolkit.class) {
1629             if (eqNoEvents == null) {
1630                 eqNoEvents = getMethod(java.awt.EventQueue.class, "noEvents", null);
1631             }
1632         }
1633         try {
1634             return (Boolean)eqNoEvents.invoke(queue);
1635         } catch (Exception e) {
1636             e.printStackTrace();
1637             return false;
1638         }
1639     }
1640 
1641     /**
1642      * Waits for the Java event queue to empty.  Ensures that all
1643      * events are processed (including paint events), and that if
1644      * recursive events were generated, they are also processed.
1645      * Should return <code>true</code> if more processing is
1646      * necessary, <code>false</code> otherwise.
1647      */
1648     @SuppressWarnings("serial")
1649     protected final boolean waitForIdle(final long timeout) {
1650         flushPendingEvents();
1651         boolean queueWasEmpty = isEQEmpty();
1652         queueEmpty = false;
1653         eventDispatched = false;
1654         synchronized(waitLock) {
1655             postEvent(AppContext.getAppContext(),
1656                       new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
1657                           public void dispatch() {
1658                               // Here we block EDT.  It could have some
1659                               // events, it should have dispatched them by
1660                               // now.  So native requests could have been
1661                               // generated.  First, dispatch them.  Then,
1662                               // flush Java events again.
1663                               int iters = 0;
1664                               while (iters < MIN_ITERS) {
1665                                   syncNativeQueue(timeout);
1666                                   iters++;
1667                               }
1668                               while (syncNativeQueue(timeout) && iters < MAX_ITERS) {
1669                                   iters++;
1670                               }
1671                               flushPendingEvents();
1672 
1673                               synchronized(waitLock) {
1674                                   queueEmpty = isEQEmpty();
1675                                   eventDispatched = true;
1676                                   waitLock.notifyAll();
1677                               }
1678                           }
1679                       });
1680             try {
1681                 while (!eventDispatched) {
1682                     waitLock.wait();
1683                 }
1684             } catch (InterruptedException ie) {
1685                 return false;
1686             }
1687         }
1688 
1689         try {
1690             Thread.sleep(MINIMAL_EDELAY);
1691         } catch (InterruptedException ie) {
1692             throw new RuntimeException("Interrupted");
1693         }
1694 
1695         flushPendingEvents();
1696 
1697         // Lock to force write-cache flush for queueEmpty.
1698         synchronized (waitLock) {
1699             return !(queueEmpty && isEQEmpty() && queueWasEmpty);
1700         }
1701     }
1702 
1703     /**
1704      * Grabs the mouse input for the given window.  The window must be
1705      * visible.  The window or its children do not receive any
1706      * additional mouse events besides those targeted to them.  All
1707      * other events will be dispatched as before - to the respective
1708      * targets.  This Window will receive UngrabEvent when automatic
1709      * ungrab is about to happen.  The event can be listened to by
1710      * installing AWTEventListener with WINDOW_EVENT_MASK.  See
1711      * UngrabEvent class for the list of conditions when ungrab is
1712      * about to happen.
1713      * @see UngrabEvent
1714      */
1715     public abstract void grab(Window w);
1716 
1717     /**
1718      * Forces ungrab.  No event will be sent.
1719      */
1720     public abstract void ungrab(Window w);
1721 
1722 
1723     /**
1724      * Locates the splash screen library in a platform dependent way and closes
1725      * the splash screen. Should be invoked on first top-level frame display.
1726      * @see java.awt.SplashScreen
1727      * @since 1.6
1728      */
1729     public static native void closeSplashScreen();
1730 
1731     /* The following methods and variables are to support retrieving
1732      * desktop text anti-aliasing settings
1733      */
1734 
1735     /* Need an instance method because setDesktopProperty(..) is protected. */
1736     private void fireDesktopFontPropertyChanges() {
1737         setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,
1738                            SunToolkit.getDesktopFontHints());
1739     }
1740 
1741     private static boolean checkedSystemAAFontSettings;
1742     private static boolean useSystemAAFontSettings;
1743     private static boolean lastExtraCondition = true;
1744     private static RenderingHints desktopFontHints;
1745 
1746     /* Since Swing is the reason for this "extra condition" logic its
1747      * worth documenting it in some detail.
1748      * First, a goal is for Swing and applications to both retrieve and
1749      * use the same desktop property value so that there is complete
1750      * consistency between the settings used by JDK's Swing implementation
1751      * and 3rd party custom Swing components, custom L&Fs and any general
1752      * text rendering that wants to be consistent with these.
1753      * But by default on Solaris & Linux Swing will not use AA text over
1754      * remote X11 display (unless Xrender can be used which is TBD and may not
1755      * always be available anyway) as that is a noticeable performance hit.
1756      * So there needs to be a way to express that extra condition so that
1757      * it is seen by all clients of the desktop property API.
1758      * If this were the only condition it could be handled here as it would
1759      * be the same for any L&F and could reasonably be considered to be
1760      * a static behaviour of those systems.
1761      * But GTK currently has an additional test based on locale which is
1762      * not applied by Metal. So mixing GTK in a few locales with Metal
1763      * would mean the last one wins.
1764      * This could be stored per-app context which would work
1765      * for different applets, but wouldn't help for a single application
1766      * using GTK and some other L&F concurrently.
1767      * But it is expected this will be addressed within GTK and the font
1768      * system so is a temporary and somewhat unlikely harmless corner case.
1769      */
1770     public static void setAAFontSettingsCondition(boolean extraCondition) {
1771         if (extraCondition != lastExtraCondition) {
1772             lastExtraCondition = extraCondition;
1773             if (checkedSystemAAFontSettings) {
1774                 /* Someone already asked for this info, under a different
1775                  * condition.
1776                  * We'll force re-evaluation instead of replicating the
1777                  * logic, then notify any listeners of any change.
1778                  */
1779                 checkedSystemAAFontSettings = false;
1780                 Toolkit tk = Toolkit.getDefaultToolkit();
1781                 if (tk instanceof SunToolkit) {
1782                      ((SunToolkit)tk).fireDesktopFontPropertyChanges();
1783                 }
1784             }
1785         }
1786     }
1787 
1788     /* "false", "off", ""default" aren't explicitly tested, they
1789      * just fall through to produce a null return which all are equated to
1790      * "false".
1791      */
1792     private static RenderingHints getDesktopAAHintsByName(String hintname) {
1793         Object aaHint = null;
1794         hintname = hintname.toLowerCase(Locale.ENGLISH);
1795         if (hintname.equals("on")) {
1796             aaHint = VALUE_TEXT_ANTIALIAS_ON;
1797         } else if (hintname.equals("gasp")) {
1798             aaHint = VALUE_TEXT_ANTIALIAS_GASP;
1799         } else if (hintname.equals("lcd") || hintname.equals("lcd_hrgb")) {
1800             aaHint = VALUE_TEXT_ANTIALIAS_LCD_HRGB;
1801         } else if (hintname.equals("lcd_hbgr")) {
1802             aaHint = VALUE_TEXT_ANTIALIAS_LCD_HBGR;
1803         } else if (hintname.equals("lcd_vrgb")) {
1804             aaHint = VALUE_TEXT_ANTIALIAS_LCD_VRGB;
1805         } else if (hintname.equals("lcd_vbgr")) {
1806             aaHint = VALUE_TEXT_ANTIALIAS_LCD_VBGR;
1807         }
1808         if (aaHint != null) {
1809             RenderingHints map = new RenderingHints(null);
1810             map.put(KEY_TEXT_ANTIALIASING, aaHint);
1811             return map;
1812         } else {
1813             return null;
1814         }
1815     }
1816 
1817     /* This method determines whether to use the system font settings,
1818      * or ignore them if a L&F has specified they should be ignored, or
1819      * to override both of these with a system property specified value.
1820      * If the toolkit isn't a SunToolkit, (eg may be headless) then that
1821      * system property isn't applied as desktop properties are considered
1822      * to be inapplicable in that case. In that headless case although
1823      * this method will return "true" the toolkit will return a null map.
1824      */
1825     private static boolean useSystemAAFontSettings() {
1826         if (!checkedSystemAAFontSettings) {
1827             useSystemAAFontSettings = true; /* initially set this true */
1828             String systemAAFonts = null;
1829             Toolkit tk = Toolkit.getDefaultToolkit();
1830             if (tk instanceof SunToolkit) {
1831                 systemAAFonts =
1832                     AccessController.doPrivileged(
1833                          new GetPropertyAction("awt.useSystemAAFontSettings"));
1834             }
1835             if (systemAAFonts != null) {
1836                 useSystemAAFontSettings =
1837                     Boolean.valueOf(systemAAFonts).booleanValue();
1838                 /* If it is anything other than "true", then it may be
1839                  * a hint name , or it may be "off, "default", etc.
1840                  */
1841                 if (!useSystemAAFontSettings) {
1842                     desktopFontHints = getDesktopAAHintsByName(systemAAFonts);
1843                 }
1844             }
1845             /* If its still true, apply the extra condition */
1846             if (useSystemAAFontSettings) {
1847                  useSystemAAFontSettings = lastExtraCondition;
1848             }
1849             checkedSystemAAFontSettings = true;
1850         }
1851         return useSystemAAFontSettings;
1852     }
1853 
1854     /* A variable defined for the convenience of JDK code */
1855     public static final String DESKTOPFONTHINTS = "awt.font.desktophints";
1856 
1857     /* Overridden by subclasses to return platform/desktop specific values */
1858     protected RenderingHints getDesktopAAHints() {
1859         return null;
1860     }
1861 
1862     /* Subclass desktop property loading methods call this which
1863      * in turn calls the appropriate subclass implementation of
1864      * getDesktopAAHints() when system settings are being used.
1865      * Its public rather than protected because subclasses may delegate
1866      * to a helper class.
1867      */
1868     public static RenderingHints getDesktopFontHints() {
1869         if (useSystemAAFontSettings()) {
1870              Toolkit tk = Toolkit.getDefaultToolkit();
1871              if (tk instanceof SunToolkit) {
1872                  Object map = ((SunToolkit)tk).getDesktopAAHints();
1873                  return (RenderingHints)map;
1874              } else { /* Headless Toolkit */
1875                  return null;
1876              }
1877         } else if (desktopFontHints != null) {
1878             /* cloning not necessary as the return value is cloned later, but
1879              * its harmless.
1880              */
1881             return (RenderingHints)(desktopFontHints.clone());
1882         } else {
1883             return null;
1884         }
1885     }
1886 
1887 
1888     public abstract boolean isDesktopSupported();
1889 
1890     /*
1891      * consumeNextKeyTyped() method is not currently used,
1892      * however Swing could use it in the future.
1893      */
1894     private static Method consumeNextKeyTypedMethod = null;
1895     public static synchronized void consumeNextKeyTyped(KeyEvent keyEvent) {
1896         if (consumeNextKeyTypedMethod == null) {
1897             consumeNextKeyTypedMethod = getMethod(DefaultKeyboardFocusManager.class,
1898                                                   "consumeNextKeyTyped",
1899                                                   new Class<?>[] {KeyEvent.class});
1900         }
1901         try {
1902             consumeNextKeyTypedMethod.invoke(KeyboardFocusManager.getCurrentKeyboardFocusManager(),
1903                                              keyEvent);
1904         } catch (IllegalAccessException iae) {
1905             iae.printStackTrace();
1906         } catch (InvocationTargetException ite) {
1907             ite.printStackTrace();
1908         }
1909     }
1910 
1911     protected static void dumpPeers(final PlatformLogger aLog) {
1912         AWTAutoShutdown.getInstance().dumpPeers(aLog);
1913     }
1914 
1915     /**
1916      * Returns the <code>Window</code> ancestor of the component <code>comp</code>.
1917      * @return Window ancestor of the component or component by itself if it is Window;
1918      *         null, if component is not a part of window hierarchy
1919      */
1920     public static Window getContainingWindow(Component comp) {
1921         while (comp != null && !(comp instanceof Window)) {
1922             comp = comp.getParent();
1923         }
1924         return (Window)comp;
1925     }
1926 
1927     /**
1928      * Returns the value of the system property indicated by the specified key.
1929      */
1930     public static String getSystemProperty(final String key) {
1931         return AccessController.doPrivileged(new PrivilegedAction<String>() {
1932                 public String run() {
1933                     return System.getProperty(key);
1934                 }
1935             });
1936     }
1937 
1938     /**
1939      * Returns the boolean value of the system property indicated by the specified key.
1940      */
1941     protected static Boolean getBooleanSystemProperty(String key) {
1942         return AccessController.doPrivileged(new GetBooleanAction(key));
1943     }
1944 
1945     private static Boolean sunAwtDisableMixing = null;
1946 
1947     /**
1948      * Returns the value of "sun.awt.disableMixing" property. Default
1949      * value is {@code false}.
1950      */
1951     public synchronized static boolean getSunAwtDisableMixing() {
1952         if (sunAwtDisableMixing == null) {
1953             sunAwtDisableMixing = getBooleanSystemProperty("sun.awt.disableMixing");
1954         }
1955         return sunAwtDisableMixing.booleanValue();
1956     }
1957 
1958     /**
1959      * Returns true if the native GTK libraries are available.  The
1960      * default implementation returns false, but UNIXToolkit overrides this
1961      * method to provide a more specific answer.
1962      */
1963     public boolean isNativeGTKAvailable() {
1964         return false;
1965     }
1966 
1967     // Cosntant alpha
1968     public boolean isWindowOpacitySupported() {
1969         return false;
1970     }
1971 
1972     // Shaping
1973     public boolean isWindowShapingSupported() {
1974         return false;
1975     }
1976 
1977     // Per-pixel alpha
1978     public boolean isWindowTranslucencySupported() {
1979         return false;
1980     }
1981 
1982     public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
1983         return false;
1984     }
1985 
1986     /**
1987      * Returns true if swing backbuffer should be translucent.
1988      */
1989     public boolean isSwingBackbufferTranslucencySupported() {
1990         return false;
1991     }
1992 
1993     /**
1994      * Returns whether or not a containing top level window for the passed
1995      * component is
1996      * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}.
1997      *
1998      * @param c a Component which toplevel's to check
1999      * @return {@code true}  if the passed component is not null and has a
2000      * containing toplevel window which is opaque (so per-pixel translucency
2001      * is not enabled), {@code false} otherwise
2002      * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
2003      */
2004     public static boolean isContainingTopLevelOpaque(Component c) {
2005         Window w = getContainingWindow(c);
2006         return w != null && w.isOpaque();
2007     }
2008 
2009     /**
2010      * Returns whether or not a containing top level window for the passed
2011      * component is
2012      * {@link GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}.
2013      *
2014      * @param c a Component which toplevel's to check
2015      * @return {@code true} if the passed component is not null and has a
2016      * containing toplevel window which has opacity less than
2017      * 1.0f (which means that it is translucent), {@code false} otherwise
2018      * @see GraphicsDevice.WindowTranslucency#TRANSLUCENT
2019      */
2020     public static boolean isContainingTopLevelTranslucent(Component c) {
2021         Window w = getContainingWindow(c);
2022         return w != null && w.getOpacity() < 1.0f;
2023     }
2024 
2025     /**
2026      * Returns whether the native system requires using the peer.updateWindow()
2027      * method to update the contents of a non-opaque window, or if usual
2028      * painting procedures are sufficient. The default return value covers
2029      * the X11 systems. On MS Windows this method is overriden in WToolkit
2030      * to return true.
2031      */
2032     public boolean needUpdateWindow() {
2033         return false;
2034     }
2035 
2036     /**
2037      * Descendants of the SunToolkit should override and put their own logic here.
2038      */
2039     public int getNumberOfButtons(){
2040         return 3;
2041     }
2042 
2043     /**
2044      * Checks that the given object implements/extends the given
2045      * interface/class.
2046      *
2047      * Note that using the instanceof operator causes a class to be loaded.
2048      * Using this method doesn't load a class and it can be used instead of
2049      * the instanceof operator for performance reasons.
2050      *
2051      * @param obj Object to be checked
2052      * @param type The name of the interface/class. Must be
2053      * fully-qualified interface/class name.
2054      * @return true, if this object implements/extends the given
2055      *         interface/class, false, otherwise, or if obj or type is null
2056      */
2057     public static boolean isInstanceOf(Object obj, String type) {
2058         if (obj == null) return false;
2059         if (type == null) return false;
2060 
2061         return isInstanceOf(obj.getClass(), type);
2062     }
2063 
2064     private static boolean isInstanceOf(Class<?> cls, String type) {
2065         if (cls == null) return false;
2066 
2067         if (cls.getName().equals(type)) {
2068             return true;
2069         }
2070 
2071         for (Class<?> c : cls.getInterfaces()) {
2072             if (c.getName().equals(type)) {
2073                 return true;
2074             }
2075         }
2076         return isInstanceOf(cls.getSuperclass(), type);
2077     }
2078 
2079     ///////////////////////////////////////////////////////////////////////////
2080     //
2081     // The following methods help set and identify whether a particular
2082     // AWTEvent object was produced by the system or by user code. As of this
2083     // writing the only consumer is the Java Plug-In, although this information
2084     // could be useful to more clients and probably should be formalized in
2085     // the public API.
2086     //
2087     ///////////////////////////////////////////////////////////////////////////
2088 
2089     public static void setSystemGenerated(AWTEvent e) {
2090         AWTAccessor.getAWTEventAccessor().setSystemGenerated(e);
2091     }
2092 
2093     public static boolean isSystemGenerated(AWTEvent e) {
2094         return AWTAccessor.getAWTEventAccessor().isSystemGenerated(e);
2095     }
2096 
2097 } // class SunToolkit
2098 
2099 
2100 /*
2101  * PostEventQueue is a Thread that runs in the same AppContext as the
2102  * Java EventQueue.  It is a queue of AWTEvents to be posted to the
2103  * Java EventQueue.  The toolkit Thread (AWT-Windows/AWT-Motif) posts
2104  * events to this queue, which then calls EventQueue.postEvent().
2105  *
2106  * We do this because EventQueue.postEvent() may be overridden by client
2107  * code, and we mustn't ever call client code from the toolkit thread.
2108  */
2109 class PostEventQueue {
2110     private EventQueueItem queueHead = null;
2111     private EventQueueItem queueTail = null;
2112     private final EventQueue eventQueue;
2113 
2114     // For the case when queue is cleared but events are not posted
2115     private volatile boolean isFlushing = false;
2116 
2117     PostEventQueue(EventQueue eq) {
2118         eventQueue = eq;
2119     }
2120 
2121     public synchronized boolean noEvents() {
2122         return queueHead == null && !isFlushing;
2123     }
2124 
2125     /*
2126      * Continually post pending AWTEvents to the Java EventQueue. The method
2127      * is synchronized to ensure the flush is completed before a new event
2128      * can be posted to this queue.
2129      *
2130      * 7177040: The method couldn't be wholly synchronized because of calls
2131      * of EventQueue.postEvent() that uses pushPopLock, otherwise it could
2132      * potentially lead to deadlock
2133      */
2134     public void flush() {
2135         EventQueueItem tempQueue;
2136         synchronized (this) {
2137             tempQueue = queueHead;
2138             queueHead = queueTail = null;
2139             isFlushing = true;
2140         }
2141         try {
2142             while (tempQueue != null) {
2143                 eventQueue.postEvent(tempQueue.event);
2144                 tempQueue = tempQueue.next;
2145             }
2146         }
2147         finally {
2148             isFlushing = false;
2149         }
2150     }
2151 
2152     /*
2153      * Enqueue an AWTEvent to be posted to the Java EventQueue.
2154      */
2155     void postEvent(AWTEvent event) {
2156         EventQueueItem item = new EventQueueItem(event);
2157 
2158         synchronized (this) {
2159             if (queueHead == null) {
2160                 queueHead = queueTail = item;
2161             } else {
2162                 queueTail.next = item;
2163                 queueTail = item;
2164             }
2165         }
2166         SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance());
2167     }
2168 } // class PostEventQueue