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