Path: blob/master/src/java.desktop/share/classes/sun/awt/SunToolkit.java
41152 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt;2627import java.awt.AWTEvent;28import java.awt.AWTException;29import java.awt.Button;30import java.awt.Canvas;31import java.awt.Checkbox;32import java.awt.Choice;33import java.awt.Component;34import java.awt.Container;35import java.awt.DefaultKeyboardFocusManager;36import java.awt.Dialog;37import java.awt.Dimension;38import java.awt.EventQueue;39import java.awt.FocusTraversalPolicy;40import java.awt.Font;41import java.awt.FontMetrics;42import java.awt.Graphics2D;43import java.awt.GraphicsConfiguration;44import java.awt.GraphicsDevice;45import java.awt.GraphicsEnvironment;46import java.awt.HeadlessException;47import java.awt.Image;48import java.awt.KeyboardFocusManager;49import java.awt.Label;50import java.awt.MenuComponent;51import java.awt.Panel;52import java.awt.RenderingHints;53import java.awt.ScrollPane;54import java.awt.Scrollbar;55import java.awt.SystemTray;56import java.awt.TextArea;57import java.awt.TextField;58import java.awt.Toolkit;59import java.awt.TrayIcon;60import java.awt.Window;61import java.awt.event.InputEvent;62import java.awt.event.KeyEvent;63import java.awt.event.WindowEvent;64import java.awt.image.BufferedImage;65import java.awt.image.ColorModel;66import java.awt.image.DataBuffer;67import java.awt.image.DataBufferInt;68import java.awt.image.ImageObserver;69import java.awt.image.ImageProducer;70import java.awt.image.MultiResolutionImage;71import java.awt.image.Raster;72import java.awt.peer.FramePeer;73import java.awt.peer.KeyboardFocusManagerPeer;74import java.awt.peer.SystemTrayPeer;75import java.awt.peer.TrayIconPeer;76import java.io.File;77import java.io.IOException;78import java.io.InputStream;79import java.lang.reflect.InvocationTargetException;80import java.net.URL;81import java.security.AccessController;82import java.util.ArrayList;83import java.util.Collections;84import java.util.Iterator;85import java.util.Locale;86import java.util.Map;87import java.util.Vector;88import java.util.WeakHashMap;89import java.util.concurrent.TimeUnit;90import java.util.concurrent.atomic.AtomicBoolean;91import java.util.concurrent.locks.Condition;92import java.util.concurrent.locks.ReentrantLock;9394import sun.awt.im.InputContext;95import sun.awt.image.ByteArrayImageSource;96import sun.awt.image.FileImageSource;97import sun.awt.image.ImageRepresentation;98import sun.awt.image.MultiResolutionToolkitImage;99import sun.awt.image.ToolkitImage;100import sun.awt.image.URLImageSource;101import sun.font.FontDesignMetrics;102import sun.net.util.URLUtil;103import sun.security.action.GetBooleanAction;104import sun.security.action.GetPropertyAction;105import sun.util.logging.PlatformLogger;106107import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;108import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_GASP;109import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR;110import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB;111import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR;112import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB;113import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON;114115public abstract class SunToolkit extends Toolkit116implements ComponentFactory, InputMethodSupport, KeyboardFocusManagerPeerProvider {117118// 8014718: logging has been removed from SunToolkit119120/* Load debug settings for native code */121static {122initStatic();123}124125@SuppressWarnings("removal")126private static void initStatic() {127if (AccessController.doPrivileged(new GetBooleanAction("sun.awt.nativedebug"))) {128DebugSettings.init();129}130touchKeyboardAutoShowIsEnabled = Boolean.valueOf(131GetPropertyAction.privilegedGetProperty(132"awt.touchKeyboardAutoShowIsEnabled", "true"));133};134135/**136* Special mask for the UngrabEvent events, in addition to the137* public masks defined in AWTEvent. Should be used as the mask138* value for Toolkit.addAWTEventListener.139*/140public static final int GRAB_EVENT_MASK = 0x80000000;141142/* The key to put()/get() the PostEventQueue into/from the AppContext.143*/144private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";145146/**147* Number of buttons.148* By default it's taken from the system. If system value does not149* fit into int type range, use our own MAX_BUTTONS_SUPPORT value.150*/151protected static int numberOfButtons = 0;152153154/* XFree standard mention 24 buttons as maximum:155* http://www.xfree86.org/current/mouse.4.html156* We workaround systems supporting more than 24 buttons.157* Otherwise, we have to use long type values as masks158* which leads to API change.159* InputEvent.BUTTON_DOWN_MASK may contain only 21 masks due to160* the 4-bytes limit for the int type. (CR 6799099)161* One more bit is reserved for FIRST_HIGH_BIT.162*/163public static final int MAX_BUTTONS_SUPPORTED = 20;164165/**166* Creates and initializes EventQueue instance for the specified167* AppContext.168* Note that event queue must be created from createNewAppContext()169* only in order to ensure that EventQueue constructor obtains170* the correct AppContext.171* @param appContext AppContext to associate with the event queue172*/173private static void initEQ(AppContext appContext) {174EventQueue eventQueue = new EventQueue();175appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);176177PostEventQueue postEventQueue = new PostEventQueue(eventQueue);178appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);179}180181public SunToolkit() {182}183184public boolean useBufferPerWindow() {185return false;186}187188public abstract FramePeer createLightweightFrame(LightweightFrame target)189throws HeadlessException;190191public abstract TrayIconPeer createTrayIcon(TrayIcon target)192throws HeadlessException, AWTException;193194public abstract SystemTrayPeer createSystemTray(SystemTray target);195196public abstract boolean isTraySupported();197198@Override199public abstract KeyboardFocusManagerPeer getKeyboardFocusManagerPeer()200throws HeadlessException;201202/**203* The AWT lock is typically only used on Unix platforms to synchronize204* access to Xlib, OpenGL, etc. However, these methods are implemented205* in SunToolkit so that they can be called from shared code (e.g.206* from the OGL pipeline) or from the X11 pipeline regardless of whether207* XToolkit or MToolkit is currently in use. There are native macros208* (such as AWT_LOCK) defined in awt.h, so if the implementation of these209* methods is changed, make sure it is compatible with the native macros.210*211* Note: The following methods (awtLock(), awtUnlock(), etc) should be212* used in place of:213* synchronized (getAWTLock()) {214* ...215* }216*217* By factoring these methods out specially, we are able to change the218* implementation of these methods (e.g. use more advanced locking219* mechanisms) without impacting calling code.220*221* Sample usage:222* private void doStuffWithXlib() {223* assert !SunToolkit.isAWTLockHeldByCurrentThread();224* SunToolkit.awtLock();225* try {226* ...227* XlibWrapper.XDoStuff();228* } finally {229* SunToolkit.awtUnlock();230* }231* }232*/233234private static final ReentrantLock AWT_LOCK = new ReentrantLock();235private static final Condition AWT_LOCK_COND = AWT_LOCK.newCondition();236237public static final void awtLock() {238AWT_LOCK.lock();239}240241public static final boolean awtTryLock() {242return AWT_LOCK.tryLock();243}244245public static final void awtUnlock() {246AWT_LOCK.unlock();247}248249public static final void awtLockWait()250throws InterruptedException251{252AWT_LOCK_COND.await();253}254255public static final void awtLockWait(long timeout)256throws InterruptedException257{258AWT_LOCK_COND.await(timeout, TimeUnit.MILLISECONDS);259}260261public static final void awtLockNotify() {262AWT_LOCK_COND.signal();263}264265public static final void awtLockNotifyAll() {266AWT_LOCK_COND.signalAll();267}268269public static final boolean isAWTLockHeldByCurrentThread() {270return AWT_LOCK.isHeldByCurrentThread();271}272273/*274* Create a new AppContext, along with its EventQueue, for a275* new ThreadGroup. Browser code, for example, would use this276* method to create an AppContext & EventQueue for an Applet.277*/278public static AppContext createNewAppContext() {279ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();280return createNewAppContext(threadGroup);281}282283static final AppContext createNewAppContext(ThreadGroup threadGroup) {284// Create appContext before initialization of EventQueue, so all285// the calls to AppContext.getAppContext() from EventQueue ctor286// return correct values287AppContext appContext = new AppContext(threadGroup);288initEQ(appContext);289290return appContext;291}292293static void wakeupEventQueue(EventQueue q, boolean isShutdown){294AWTAccessor.getEventQueueAccessor().wakeup(q, isShutdown);295}296297/*298* Fetch the peer associated with the given target (as specified299* in the peer creation method). This can be used to determine300* things like what the parent peer is. If the target is null301* or the target can't be found (either because the a peer was302* never created for it or the peer was disposed), a null will303* be returned.304*/305protected static Object targetToPeer(Object target) {306if (target != null && !GraphicsEnvironment.isHeadless()) {307return AWTAutoShutdown.getInstance().getPeer(target);308}309return null;310}311312protected static void targetCreatedPeer(Object target, Object peer) {313if (target != null && peer != null &&314!GraphicsEnvironment.isHeadless())315{316AWTAutoShutdown.getInstance().registerPeer(target, peer);317}318}319320protected static void targetDisposedPeer(Object target, Object peer) {321if (target != null && peer != null &&322!GraphicsEnvironment.isHeadless())323{324AWTAutoShutdown.getInstance().unregisterPeer(target, peer);325}326}327328// Maps from non-Component/MenuComponent to AppContext.329// WeakHashMap<Component,AppContext>330private static final Map<Object, AppContext> appContextMap =331Collections.synchronizedMap(new WeakIdentityHashMap<Object, AppContext>());332333/**334* Sets the appContext field of target. If target is not a Component or335* MenuComponent, this returns false.336*/337private static boolean setAppContext(Object target,338AppContext context) {339if (target instanceof Component) {340AWTAccessor.getComponentAccessor().341setAppContext((Component)target, context);342} else if (target instanceof MenuComponent) {343AWTAccessor.getMenuComponentAccessor().344setAppContext((MenuComponent)target, context);345} else {346return false;347}348return true;349}350351/**352* Returns the appContext field for target. If target is not a353* Component or MenuComponent this returns null.354*/355private static AppContext getAppContext(Object target) {356if (target instanceof Component) {357return AWTAccessor.getComponentAccessor().358getAppContext((Component)target);359} else if (target instanceof MenuComponent) {360return AWTAccessor.getMenuComponentAccessor().361getAppContext((MenuComponent)target);362} else {363return null;364}365}366367/*368* Fetch the AppContext associated with the given target.369* This can be used to determine things like which EventQueue370* to use for posting events to a Component. If the target is371* null or the target can't be found, a null with be returned.372*/373public static AppContext targetToAppContext(Object target) {374if (target == null) {375return null;376}377AppContext context = getAppContext(target);378if (context == null) {379// target is not a Component/MenuComponent, try the380// appContextMap.381context = appContextMap.get(target);382}383return context;384}385386/**387* Sets the synchronous status of focus requests on lightweight388* components in the specified window to the specified value.389* If the boolean parameter is {@code true} then the focus390* requests on lightweight components will be performed391* synchronously, if it is {@code false}, then asynchronously.392* By default, all windows have their lightweight request status393* set to asynchronous.394* <p>395* The application can only set the status of lightweight focus396* requests to synchronous for any of its windows if it doesn't397* perform focus transfers between different heavyweight containers.398* In this case the observable focus behaviour is the same as with399* asynchronous status.400* <p>401* If the application performs focus transfer between different402* heavyweight containers and sets the lightweight focus request403* status to synchronous for any of its windows, then further focus404* behaviour is unspecified.405* <p>406* @param changed the window for which the lightweight focus request407* status should be set408* @param status the value of lightweight focus request status409*/410411public static void setLWRequestStatus(Window changed,boolean status){412AWTAccessor.getWindowAccessor().setLWRequestStatus(changed, status);413};414415public static void checkAndSetPolicy(Container cont) {416FocusTraversalPolicy defaultPolicy = KeyboardFocusManager.417getCurrentKeyboardFocusManager().418getDefaultFocusTraversalPolicy();419420cont.setFocusTraversalPolicy(defaultPolicy);421}422423/*424* Insert a mapping from target to AppContext, for later retrieval425* via targetToAppContext() above.426*/427public static void insertTargetMapping(Object target, AppContext appContext) {428if (!setAppContext(target, appContext)) {429// Target is not a Component/MenuComponent, use the private Map430// instead.431appContextMap.put(target, appContext);432}433}434435/*436* Post an AWTEvent to the Java EventQueue, using the PostEventQueue437* to avoid possibly calling client code (EventQueueSubclass.postEvent())438* on the toolkit (AWT-Windows/AWT-Motif) thread. This function should439* not be called under another lock since it locks the EventQueue.440* See bugids 4632918, 4526597.441*/442public static void postEvent(AppContext appContext, AWTEvent event) {443if (event == null) {444throw new NullPointerException();445}446447AWTAccessor.SequencedEventAccessor sea = AWTAccessor.getSequencedEventAccessor();448if (sea != null && sea.isSequencedEvent(event)) {449AWTEvent nested = sea.getNested(event);450if (nested.getID() == WindowEvent.WINDOW_LOST_FOCUS &&451nested instanceof TimedWindowEvent)452{453TimedWindowEvent twe = (TimedWindowEvent)nested;454((SunToolkit)Toolkit.getDefaultToolkit()).455setWindowDeactivationTime((Window)twe.getSource(), twe.getWhen());456}457}458459// All events posted via this method are system-generated.460// Placing the following call here reduces considerably the461// number of places throughout the toolkit that would462// otherwise have to be modified to precisely identify463// system-generated events.464setSystemGenerated(event);465AppContext eventContext = targetToAppContext(event.getSource());466if (eventContext != null && !eventContext.equals(appContext)) {467throw new RuntimeException("Event posted on wrong app context : " + event);468}469PostEventQueue postEventQueue =470(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);471if (postEventQueue != null) {472postEventQueue.postEvent(event);473}474}475476/*477* Post AWTEvent of high priority.478*/479public static void postPriorityEvent(final AWTEvent e) {480PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(), new Runnable() {481@Override482public void run() {483AWTAccessor.getAWTEventAccessor().setPosted(e);484((Component)e.getSource()).dispatchEvent(e);485}486}, PeerEvent.ULTIMATE_PRIORITY_EVENT);487postEvent(targetToAppContext(e.getSource()), pe);488}489490/*491* Flush any pending events which haven't been posted to the AWT492* EventQueue yet.493*/494public static void flushPendingEvents() {495AppContext appContext = AppContext.getAppContext();496flushPendingEvents(appContext);497}498499/*500* Flush the PostEventQueue for the right AppContext.501* The default flushPendingEvents only flushes the thread-local context,502* which is not always correct, c.f. 3746956503*/504public static void flushPendingEvents(AppContext appContext) {505PostEventQueue postEventQueue =506(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);507if (postEventQueue != null) {508postEventQueue.flush();509}510}511512/*513* Execute a chunk of code on the Java event handler thread for the514* given target. Does not wait for the execution to occur before515* returning to the caller.516*/517public static void executeOnEventHandlerThread(Object target,518Runnable runnable) {519executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT));520}521522/*523* Fixed 5064013: the InvocationEvent time should be equals524* the time of the ActionEvent525*/526@SuppressWarnings("serial")527public static void executeOnEventHandlerThread(Object target,528Runnable runnable,529final long when) {530executeOnEventHandlerThread(531new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT) {532@Override533public long getWhen() {534return when;535}536});537}538539/*540* Execute a chunk of code on the Java event handler thread for the541* given target. Does not wait for the execution to occur before542* returning to the caller.543*/544public static void executeOnEventHandlerThread(PeerEvent peerEvent) {545postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);546}547548/*549* Execute a chunk of code on the Java event handler thread. The550* method takes into account provided AppContext and sets551* {@code SunToolkit.getDefaultToolkit()} as a target of the552* event. See 6451487 for detailes.553* Does not wait for the execution to occur before returning to554* the caller.555*/556public static void invokeLaterOnAppContext(557AppContext appContext, Runnable dispatcher)558{559postEvent(appContext,560new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher,561PeerEvent.PRIORITY_EVENT));562}563564/*565* Execute a chunk of code on the Java event handler thread for the566* given target. Waits for the execution to occur before returning567* to the caller.568*/569public static void executeOnEDTAndWait(Object target, Runnable runnable)570throws InterruptedException, InvocationTargetException571{572if (EventQueue.isDispatchThread()) {573throw new Error("Cannot call executeOnEDTAndWait from any event dispatcher thread");574}575576class AWTInvocationLock {}577Object lock = new AWTInvocationLock();578579PeerEvent event = new PeerEvent(target, runnable, lock, true, PeerEvent.PRIORITY_EVENT);580581synchronized (lock) {582executeOnEventHandlerThread(event);583while(!event.isDispatched()) {584lock.wait();585}586}587588Throwable eventThrowable = event.getThrowable();589if (eventThrowable != null) {590throw new InvocationTargetException(eventThrowable);591}592}593594/*595* Returns true if the calling thread is the event dispatch thread596* contained within AppContext which associated with the given target.597* Use this call to ensure that a given task is being executed598* (or not being) on the event dispatch thread for the given target.599*/600public static boolean isDispatchThreadForAppContext(Object target) {601AppContext appContext = targetToAppContext(target);602EventQueue eq = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);603604AWTAccessor.EventQueueAccessor accessor = AWTAccessor.getEventQueueAccessor();605return accessor.isDispatchThreadImpl(eq);606}607608@Override609public Dimension getScreenSize() {610return GraphicsEnvironment.getLocalGraphicsEnvironment()611.getDefaultScreenDevice().getDefaultConfiguration()612.getBounds().getSize();613}614615@Override616public ColorModel getColorModel() throws HeadlessException {617return GraphicsEnvironment.getLocalGraphicsEnvironment()618.getDefaultScreenDevice().getDefaultConfiguration()619.getColorModel();620}621622@Override623@SuppressWarnings("deprecation")624public FontMetrics getFontMetrics(Font font) {625return FontDesignMetrics.getMetrics(font);626}627628@Override629@SuppressWarnings("deprecation")630public String[] getFontList() {631String[] hardwiredFontList = {632Font.DIALOG, Font.SANS_SERIF, Font.SERIF, Font.MONOSPACED,633Font.DIALOG_INPUT634635// -- Obsolete font names from 1.0.2. It was decided that636// -- getFontList should not return these old names:637// "Helvetica", "TimesRoman", "Courier", "ZapfDingbats"638};639return hardwiredFontList;640}641642/**643* Disables erasing of background on the canvas before painting if644* this is supported by the current toolkit. It is recommended to645* call this method early, before the Canvas becomes displayable,646* because some Toolkit implementations do not support changing647* this property once the Canvas becomes displayable.648*/649public void disableBackgroundErase(Canvas canvas) {650disableBackgroundEraseImpl(canvas);651}652653/**654* Disables the native erasing of the background on the given655* component before painting if this is supported by the current656* toolkit. This only has an effect for certain components such as657* Canvas, Panel and Window. It is recommended to call this method658* early, before the Component becomes displayable, because some659* Toolkit implementations do not support changing this property660* once the Component becomes displayable.661*/662public void disableBackgroundErase(Component component) {663disableBackgroundEraseImpl(component);664}665666private void disableBackgroundEraseImpl(Component component) {667AWTAccessor.getComponentAccessor().setBackgroundEraseDisabled(component, true);668}669670/**671* Returns the value of "sun.awt.noerasebackground" property. Default672* value is {@code false}.673*/674@SuppressWarnings("removal")675public static boolean getSunAwtNoerasebackground() {676return AccessController.doPrivileged(new GetBooleanAction("sun.awt.noerasebackground"));677}678679/**680* Returns the value of "sun.awt.erasebackgroundonresize" property. Default681* value is {@code false}.682*/683@SuppressWarnings("removal")684public static boolean getSunAwtErasebackgroundonresize() {685return AccessController.doPrivileged(new GetBooleanAction("sun.awt.erasebackgroundonresize"));686}687688689@SuppressWarnings("deprecation")690static final SoftCache fileImgCache = new SoftCache();691692@SuppressWarnings("deprecation")693static final SoftCache urlImgCache = new SoftCache();694695static Image getImageFromHash(Toolkit tk, URL url) {696checkPermissions(url);697synchronized (urlImgCache) {698String key = url.toString();699Image img = (Image)urlImgCache.get(key);700if (img == null) {701try {702img = tk.createImage(new URLImageSource(url));703urlImgCache.put(key, img);704} catch (Exception e) {705}706}707return img;708}709}710711static Image getImageFromHash(Toolkit tk,712String filename) {713checkPermissions(filename);714synchronized (fileImgCache) {715Image img = (Image)fileImgCache.get(filename);716if (img == null) {717try {718img = tk.createImage(new FileImageSource(filename));719fileImgCache.put(filename, img);720} catch (Exception e) {721}722}723return img;724}725}726727@Override728public Image getImage(String filename) {729return getImageFromHash(this, filename);730}731732@Override733public Image getImage(URL url) {734return getImageFromHash(this, url);735}736737protected Image getImageWithResolutionVariant(String fileName,738String resolutionVariantName) {739synchronized (fileImgCache) {740Image image = getImageFromHash(this, fileName);741if (image instanceof MultiResolutionImage) {742return image;743}744Image resolutionVariant = getImageFromHash(this, resolutionVariantName);745image = createImageWithResolutionVariant(image, resolutionVariant);746fileImgCache.put(fileName, image);747return image;748}749}750751protected Image getImageWithResolutionVariant(URL url,752URL resolutionVariantURL) {753synchronized (urlImgCache) {754Image image = getImageFromHash(this, url);755if (image instanceof MultiResolutionImage) {756return image;757}758Image resolutionVariant = getImageFromHash(this, resolutionVariantURL);759image = createImageWithResolutionVariant(image, resolutionVariant);760String key = url.toString();761urlImgCache.put(key, image);762return image;763}764}765766767@Override768public Image createImage(String filename) {769checkPermissions(filename);770return createImage(new FileImageSource(filename));771}772773@Override774public Image createImage(URL url) {775checkPermissions(url);776return createImage(new URLImageSource(url));777}778779@Override780public Image createImage(byte[] data, int offset, int length) {781return createImage(new ByteArrayImageSource(data, offset, length));782}783784@Override785public Image createImage(ImageProducer producer) {786return new ToolkitImage(producer);787}788789public static Image createImageWithResolutionVariant(Image image,790Image resolutionVariant) {791return new MultiResolutionToolkitImage(image, resolutionVariant);792}793794@Override795public int checkImage(Image img, int w, int h, ImageObserver o) {796if (!(img instanceof ToolkitImage)) {797return ImageObserver.ALLBITS;798}799800ToolkitImage tkimg = (ToolkitImage)img;801int repbits;802if (w == 0 || h == 0) {803repbits = ImageObserver.ALLBITS;804} else {805repbits = tkimg.getImageRep().check(o);806}807return (tkimg.check(o) | repbits) & checkResolutionVariant(img, w, h, o);808}809810@Override811public boolean prepareImage(Image img, int w, int h, ImageObserver o) {812if (w == 0 || h == 0) {813return true;814}815816// Must be a ToolkitImage817if (!(img instanceof ToolkitImage)) {818return true;819}820821ToolkitImage tkimg = (ToolkitImage)img;822if (tkimg.hasError()) {823if (o != null) {824o.imageUpdate(img, ImageObserver.ERROR|ImageObserver.ABORT,825-1, -1, -1, -1);826}827return false;828}829ImageRepresentation ir = tkimg.getImageRep();830return ir.prepare(o) & prepareResolutionVariant(img, w, h, o);831}832833private int checkResolutionVariant(Image img, int w, int h, ImageObserver o) {834ToolkitImage rvImage = getResolutionVariant(img);835int rvw = getRVSize(w);836int rvh = getRVSize(h);837// Ignore the resolution variant in case of error838return (rvImage == null || rvImage.hasError()) ? 0xFFFF :839checkImage(rvImage, rvw, rvh, MultiResolutionToolkitImage.840getResolutionVariantObserver(841img, o, w, h, rvw, rvh, true));842}843844private boolean prepareResolutionVariant(Image img, int w, int h,845ImageObserver o) {846847ToolkitImage rvImage = getResolutionVariant(img);848int rvw = getRVSize(w);849int rvh = getRVSize(h);850// Ignore the resolution variant in case of error851return rvImage == null || rvImage.hasError() || prepareImage(852rvImage, rvw, rvh,853MultiResolutionToolkitImage.getResolutionVariantObserver(854img, o, w, h, rvw, rvh, true));855}856857private static int getRVSize(int size){858return size == -1 ? -1 : 2 * size;859}860861private static ToolkitImage getResolutionVariant(Image image) {862if (image instanceof MultiResolutionToolkitImage) {863Image resolutionVariant = ((MultiResolutionToolkitImage) image).864getResolutionVariant();865if (resolutionVariant instanceof ToolkitImage) {866return (ToolkitImage) resolutionVariant;867}868}869return null;870}871872protected static boolean imageCached(String fileName) {873return fileImgCache.containsKey(fileName);874}875876protected static boolean imageCached(URL url) {877String key = url.toString();878return urlImgCache.containsKey(key);879}880881protected static boolean imageExists(String filename) {882if (filename != null) {883checkPermissions(filename);884return new File(filename).exists();885}886return false;887}888889@SuppressWarnings("try")890protected static boolean imageExists(URL url) {891if (url != null) {892checkPermissions(url);893try (InputStream is = url.openStream()) {894return true;895}catch(IOException e){896return false;897}898}899return false;900}901902private static void checkPermissions(String filename) {903@SuppressWarnings("removal")904SecurityManager security = System.getSecurityManager();905if (security != null) {906security.checkRead(filename);907}908}909910private static void checkPermissions(URL url) {911@SuppressWarnings("removal")912SecurityManager sm = System.getSecurityManager();913if (sm != null) {914try {915java.security.Permission perm =916URLUtil.getConnectPermission(url);917if (perm != null) {918sm.checkPermission(perm);919}920} catch (java.io.IOException ioe) {921sm.checkConnect(url.getHost(), url.getPort());922}923}924}925926/**927* Scans {@code imageList} for best-looking image of specified dimensions.928* Image can be scaled and/or padded with transparency.929*/930public static BufferedImage getScaledIconImage(java.util.List<Image> imageList, int width, int height) {931if (width == 0 || height == 0) {932return null;933}934java.util.List<Image> multiResAndnormalImages = new ArrayList<>(imageList.size());935for (Image image : imageList) {936if ((image instanceof MultiResolutionImage)) {937Image im = ((MultiResolutionImage) image).getResolutionVariant(width, height);938multiResAndnormalImages.add(im);939} else {940multiResAndnormalImages.add(image);941}942}943Image bestImage = null;944int bestWidth = 0;945int bestHeight = 0;946double bestSimilarity = 3; //Impossibly high value947double bestScaleFactor = 0;948for (Iterator<Image> i = multiResAndnormalImages.iterator();i.hasNext();) {949//Iterate imageList looking for best matching image.950//'Similarity' measure is defined as good scale factor and small insets.951//best possible similarity is 0 (no scale, no insets).952//It's found while the experiments that good-looking result is achieved953//with scale factors x1, x3/4, x2/3, xN, x1/N.954Image im = i.next();955if (im == null) {956continue;957}958if (im instanceof ToolkitImage) {959ImageRepresentation ir = ((ToolkitImage)im).getImageRep();960ir.reconstruct(ImageObserver.ALLBITS);961}962int iw;963int ih;964try {965iw = im.getWidth(null);966ih = im.getHeight(null);967} catch (Exception e){968continue;969}970if (iw > 0 && ih > 0) {971//Calc scale factor972double scaleFactor = Math.min((double)width / (double)iw,973(double)height / (double)ih);974//Calculate scaled image dimensions975//adjusting scale factor to nearest "good" value976int adjw = 0;977int adjh = 0;978double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad979if (scaleFactor >= 2) {980//Need to enlarge image more than twice981//Round down scale factor to multiply by integer value982scaleFactor = Math.floor(scaleFactor);983adjw = iw * (int)scaleFactor;984adjh = ih * (int)scaleFactor;985scaleMeasure = 1.0 - 0.5 / scaleFactor;986} else if (scaleFactor >= 1) {987//Don't scale988scaleFactor = 1.0;989adjw = iw;990adjh = ih;991scaleMeasure = 0;992} else if (scaleFactor >= 0.75) {993//Multiply by 3/4994scaleFactor = 0.75;995adjw = iw * 3 / 4;996adjh = ih * 3 / 4;997scaleMeasure = 0.3;998} else if (scaleFactor >= 0.6666) {999//Multiply by 2/31000scaleFactor = 0.6666;1001adjw = iw * 2 / 3;1002adjh = ih * 2 / 3;1003scaleMeasure = 0.33;1004} else {1005//Multiply size by 1/scaleDivider1006//where scaleDivider is minimum possible integer1007//larger than 1/scaleFactor1008double scaleDivider = Math.ceil(1.0 / scaleFactor);1009scaleFactor = 1.0 / scaleDivider;1010adjw = (int)Math.round((double)iw / scaleDivider);1011adjh = (int)Math.round((double)ih / scaleDivider);1012scaleMeasure = 1.0 - 1.0 / scaleDivider;1013}1014double similarity = ((double)width - (double)adjw) / (double)width +1015((double)height - (double)adjh) / (double)height + //Large padding is bad1016scaleMeasure; //Large rescale is bad1017if (similarity < bestSimilarity) {1018bestSimilarity = similarity;1019bestScaleFactor = scaleFactor;1020bestImage = im;1021bestWidth = adjw;1022bestHeight = adjh;1023}1024if (similarity == 0) break;1025}1026}1027if (bestImage == null) {1028//No images were found, possibly all are broken1029return null;1030}1031BufferedImage bimage =1032new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);1033Graphics2D g = bimage.createGraphics();1034g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,1035RenderingHints.VALUE_INTERPOLATION_BILINEAR);1036try {1037int x = (width - bestWidth) / 2;1038int y = (height - bestHeight) / 2;1039g.drawImage(bestImage, x, y, bestWidth, bestHeight, null);1040} finally {1041g.dispose();1042}1043return bimage;1044}10451046public static DataBufferInt getScaledIconData(java.util.List<Image> imageList, int width, int height) {1047BufferedImage bimage = getScaledIconImage(imageList, width, height);1048if (bimage == null) {1049return null;1050}1051Raster raster = bimage.getRaster();1052DataBuffer buffer = raster.getDataBuffer();1053return (DataBufferInt)buffer;1054}10551056@Override1057protected EventQueue getSystemEventQueueImpl() {1058return getSystemEventQueueImplPP();1059}10601061// Package private implementation1062static EventQueue getSystemEventQueueImplPP() {1063return getSystemEventQueueImplPP(AppContext.getAppContext());1064}10651066public static EventQueue getSystemEventQueueImplPP(AppContext appContext) {1067EventQueue theEventQueue =1068(EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);1069return theEventQueue;1070}10711072/**1073* Give native peers the ability to query the native container1074* given a native component (eg the direct parent may be lightweight).1075*/1076public static Container getNativeContainer(Component c) {1077return Toolkit.getNativeContainer(c);1078}10791080/**1081* Gives native peers the ability to query the closest HW component.1082* If the given component is heavyweight, then it returns this. Otherwise,1083* it goes one level up in the hierarchy and tests next component.1084*/1085public static Component getHeavyweightComponent(Component c) {1086while (c != null && AWTAccessor.getComponentAccessor().isLightweight(c)) {1087c = AWTAccessor.getComponentAccessor().getParent(c);1088}1089return c;1090}10911092/**1093* Returns key modifiers used by Swing to set up a focus accelerator key stroke.1094*/1095@SuppressWarnings("deprecation")1096public int getFocusAcceleratorKeyMask() {1097return InputEvent.ALT_MASK;1098}10991100/**1101* Tests whether specified key modifiers mask can be used to enter a printable1102* character. This is a default implementation of this method, which reflects1103* the way things work on Windows: here, pressing ctrl + alt allows user to enter1104* characters from the extended character set (like euro sign or math symbols)1105*/1106@SuppressWarnings("deprecation")1107public boolean isPrintableCharacterModifiersMask(int mods) {1108return ((mods & InputEvent.ALT_MASK) == (mods & InputEvent.CTRL_MASK));1109}11101111/**1112* Returns whether popup is allowed to be shown above the task bar.1113* This is a default implementation of this method, which checks1114* corresponding security permission.1115*/1116public boolean canPopupOverlapTaskBar() {1117boolean result = true;1118try {1119@SuppressWarnings("removal")1120SecurityManager sm = System.getSecurityManager();1121if (sm != null) {1122sm.checkPermission(AWTPermissions.SET_WINDOW_ALWAYS_ON_TOP_PERMISSION);1123}1124} catch (SecurityException se) {1125// There is no permission to show popups over the task bar1126result = false;1127}1128return result;1129}11301131/**1132* Returns a new input method window, with behavior as specified in1133* {@link java.awt.im.spi.InputMethodContext#createInputMethodWindow}.1134* If the inputContext is not null, the window should return it from its1135* getInputContext() method. The window needs to implement1136* sun.awt.im.InputMethodWindow.1137* <p>1138* SunToolkit subclasses can override this method to return better input1139* method windows.1140*/1141@Override1142public Window createInputMethodWindow(String title, InputContext context) {1143return new sun.awt.im.SimpleInputMethodWindow(title, context);1144}11451146/**1147* Returns whether enableInputMethods should be set to true for peered1148* TextComponent instances on this platform. False by default.1149*/1150@Override1151public boolean enableInputMethodsForTextComponent() {1152return false;1153}11541155private static Locale startupLocale = null;11561157/**1158* Returns the locale in which the runtime was started.1159*/1160@SuppressWarnings("removal")1161public static Locale getStartupLocale() {1162if (startupLocale == null) {1163String language, region, country, variant;1164language = AccessController.doPrivileged(1165new GetPropertyAction("user.language", "en"));1166// for compatibility, check for old user.region property1167region = AccessController.doPrivileged(1168new GetPropertyAction("user.region"));1169if (region != null) {1170// region can be of form country, country_variant, or _variant1171int i = region.indexOf('_');1172if (i >= 0) {1173country = region.substring(0, i);1174variant = region.substring(i + 1);1175} else {1176country = region;1177variant = "";1178}1179} else {1180country = AccessController.doPrivileged(1181new GetPropertyAction("user.country", ""));1182variant = AccessController.doPrivileged(1183new GetPropertyAction("user.variant", ""));1184}1185startupLocale = new Locale(language, country, variant);1186}1187return startupLocale;1188}11891190/**1191* Returns the default keyboard locale of the underlying operating system1192*/1193@Override1194public Locale getDefaultKeyboardLocale() {1195return getStartupLocale();1196}11971198/**1199* Returns whether default toolkit needs the support of the xembed1200* from embedding host(if any).1201* @return {@code true}, if XEmbed is needed, {@code false} otherwise1202*/1203public static boolean needsXEmbed() {1204@SuppressWarnings("removal")1205String noxembed = AccessController.1206doPrivileged(new GetPropertyAction("sun.awt.noxembed", "false"));1207if ("true".equals(noxembed)) {1208return false;1209}12101211Toolkit tk = Toolkit.getDefaultToolkit();1212if (tk instanceof SunToolkit) {1213// SunToolkit descendants should override this method to specify1214// concrete behavior1215return ((SunToolkit)tk).needsXEmbedImpl();1216} else {1217// Non-SunToolkit doubtly might support XEmbed1218return false;1219}1220}12211222/**1223* Returns whether this toolkit needs the support of the xembed1224* from embedding host(if any).1225* @return {@code true}, if XEmbed is needed, {@code false} otherwise1226*/1227protected boolean needsXEmbedImpl() {1228return false;1229}12301231private static Dialog.ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE = null;12321233/**1234* Returns whether the XEmbed server feature is requested by1235* developer. If true, Toolkit should return an1236* XEmbed-server-enabled CanvasPeer instead of the ordinary CanvasPeer.1237*/1238@SuppressWarnings("removal")1239protected final boolean isXEmbedServerRequested() {1240return AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembedserver"));1241}12421243/**1244* Returns whether the modal exclusion API is supported by the current toolkit.1245* When it isn't supported, calling {@code setModalExcluded} has no1246* effect, and {@code isModalExcluded} returns false for all windows.1247*1248* @return true if modal exclusion is supported by the toolkit, false otherwise1249*1250* @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)1251* @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)1252*1253* @since 1.51254*/1255public static boolean isModalExcludedSupported()1256{1257Toolkit tk = Toolkit.getDefaultToolkit();1258return tk.isModalExclusionTypeSupported(DEFAULT_MODAL_EXCLUSION_TYPE);1259}1260/*1261* Default implementation for isModalExcludedSupportedImpl(), returns false.1262*1263* @see sun.awt.windows.WToolkit#isModalExcludeSupportedImpl1264* @see sun.awt.X11.XToolkit#isModalExcludeSupportedImpl1265*1266* @since 1.51267*/1268protected boolean isModalExcludedSupportedImpl()1269{1270return false;1271}12721273/*1274* Sets this window to be excluded from being modally blocked. When the1275* toolkit supports modal exclusion and this method is called, input1276* events, focus transfer and z-order will continue to work for the1277* window, it's owned windows and child components, even in the1278* presence of a modal dialog.1279* For details on which {@code Window}s are normally blocked1280* by modal dialog, see {@link java.awt.Dialog}.1281* Invoking this method when the modal exclusion API is not supported by1282* the current toolkit has no effect.1283* @param window Window to be marked as not modally blocked1284* @see java.awt.Dialog1285* @see java.awt.Dialog#setModal(boolean)1286* @see sun.awt.SunToolkit#isModalExcludedSupported1287* @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)1288*/1289public static void setModalExcluded(Window window)1290{1291if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {1292DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;1293}1294window.setModalExclusionType(DEFAULT_MODAL_EXCLUSION_TYPE);1295}12961297/*1298* Returns whether the specified window is blocked by modal dialogs.1299* If the modal exclusion API isn't supported by the current toolkit,1300* it returns false for all windows.1301*1302* @param window Window to test for modal exclusion1303*1304* @return true if the window is modal excluded, false otherwise. If1305* the modal exclusion isn't supported by the current Toolkit, false1306* is returned1307*1308* @see sun.awt.SunToolkit#isModalExcludedSupported1309* @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)1310*1311* @since 1.51312*/1313public static boolean isModalExcluded(Window window)1314{1315if (DEFAULT_MODAL_EXCLUSION_TYPE == null) {1316DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE;1317}1318return window.getModalExclusionType().compareTo(DEFAULT_MODAL_EXCLUSION_TYPE) >= 0;1319}13201321/**1322* Overridden in XToolkit and WToolkit1323*/1324@Override1325public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {1326return (modalityType == Dialog.ModalityType.MODELESS) ||1327(modalityType == Dialog.ModalityType.APPLICATION_MODAL);1328}13291330/**1331* Overridden in XToolkit and WToolkit1332*/1333@Override1334public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {1335return (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE);1336}13371338///////////////////////////////////////////////////////////////////////////1339//1340// The following is used by the Java Plug-in to coordinate dialog modality1341// between containing applications (browsers, ActiveX containers etc) and1342// the AWT.1343//1344///////////////////////////////////////////////////////////////////////////13451346private ModalityListenerList modalityListeners = new ModalityListenerList();13471348public void addModalityListener(ModalityListener listener) {1349modalityListeners.add(listener);1350}13511352public void removeModalityListener(ModalityListener listener) {1353modalityListeners.remove(listener);1354}13551356public void notifyModalityPushed(Dialog dialog) {1357notifyModalityChange(ModalityEvent.MODALITY_PUSHED, dialog);1358}13591360public void notifyModalityPopped(Dialog dialog) {1361notifyModalityChange(ModalityEvent.MODALITY_POPPED, dialog);1362}13631364final void notifyModalityChange(int id, Dialog source) {1365ModalityEvent ev = new ModalityEvent(source, modalityListeners, id);1366ev.dispatch();1367}13681369static class ModalityListenerList implements ModalityListener {13701371Vector<ModalityListener> listeners = new Vector<ModalityListener>();13721373void add(ModalityListener listener) {1374listeners.addElement(listener);1375}13761377void remove(ModalityListener listener) {1378listeners.removeElement(listener);1379}13801381@Override1382public void modalityPushed(ModalityEvent ev) {1383for (ModalityListener listener : listeners) {1384listener.modalityPushed(ev);1385}1386}13871388@Override1389public void modalityPopped(ModalityEvent ev) {1390for (ModalityListener listener : listeners) {1391listener.modalityPopped(ev);1392}1393}1394} // end of class ModalityListenerList13951396///////////////////////////////////////////////////////////////////////////1397// End Plug-in code1398///////////////////////////////////////////////////////////////////////////13991400public static boolean isLightweightOrUnknown(Component comp) {1401if (comp.isLightweight()1402|| !(getDefaultToolkit() instanceof SunToolkit))1403{1404return true;1405}1406return !(comp instanceof Button1407|| comp instanceof Canvas1408|| comp instanceof Checkbox1409|| comp instanceof Choice1410|| comp instanceof Label1411|| comp instanceof java.awt.List1412|| comp instanceof Panel1413|| comp instanceof Scrollbar1414|| comp instanceof ScrollPane1415|| comp instanceof TextArea1416|| comp instanceof TextField1417|| comp instanceof Window);1418}14191420@SuppressWarnings("serial")1421public static class IllegalThreadException extends RuntimeException {1422public IllegalThreadException(String msg) {1423super(msg);1424}1425public IllegalThreadException() {1426}1427}14281429public static final int DEFAULT_WAIT_TIME = 10000;1430private static final int MAX_ITERS = 100;1431private static final int MIN_ITERS = 1;1432private static final int MINIMAL_DELAY = 5;14331434/**1435* Parameterless version of realsync which uses default timout (see DEFAUL_WAIT_TIME).1436*/1437public void realSync() {1438realSync(DEFAULT_WAIT_TIME);1439}14401441/**1442* Forces toolkit to synchronize with the native windowing1443* sub-system, flushing all pending work and waiting for all the1444* events to be processed. This method guarantees that after1445* return no additional Java events will be generated, unless1446* cause by user. Obviously, the method cannot be used on the1447* event dispatch thread (EDT). In case it nevertheless gets1448* invoked on this thread, the method throws the1449* IllegalThreadException runtime exception.1450*1451* <p> This method allows to write tests without explicit timeouts1452* or wait for some event. Example:1453* <pre>{@code1454* Frame f = ...;1455* f.setVisible(true);1456* ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();1457* }</pre>1458*1459* <p> After realSync, {@code f} will be completely visible1460* on the screen, its getLocationOnScreen will be returning the1461* right result and it will be the focus owner.1462*1463* <p> Another example:1464* <pre>{@code1465* b.requestFocus();1466* ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();1467* }</pre>1468*1469* <p> After realSync, {@code b} will be focus owner.1470*1471* <p> Notice that realSync isn't guaranteed to work if recurring1472* actions occur, such as if during processing of some event1473* another request which may generate some events occurs. By1474* default, sync tries to perform as much as {@value #MAX_ITERS}1475* cycles of event processing, allowing for roughly {@value1476* #MAX_ITERS} additional requests.1477*1478* <p> For example, requestFocus() generates native request, which1479* generates one or two Java focus events, which then generate a1480* serie of paint events, a serie of Java focus events, which then1481* generate a serie of paint events which then are processed -1482* three cycles, minimum.1483*1484* @param timeout the maximum time to wait in milliseconds, negative means "forever".1485*/1486public void realSync(final long timeout) {1487if (EventQueue.isDispatchThread()) {1488throw new IllegalThreadException("The SunToolkit.realSync() method cannot be used on the event dispatch thread (EDT).");1489}1490try {1491// We should wait unconditionally for the first event on EDT1492EventQueue.invokeAndWait(() -> {/*dummy implementation*/});1493} catch (InterruptedException | InvocationTargetException ignored) {1494}1495int bigLoop = 0;1496long end = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + timeout;1497do {1498if (timeout(end) < 0) {1499return;1500}1501// Let's do sync first1502sync();15031504// During the wait process, when we were processing incoming1505// events, we could have made some new request, which can1506// generate new events. Example: MapNotify/XSetInputFocus.1507// Therefore, we dispatch them as long as there is something1508// to dispatch.1509int iters = 0;1510while (iters < MIN_ITERS) {1511syncNativeQueue(timeout(end));1512iters++;1513}1514while (syncNativeQueue(timeout(end)) && iters < MAX_ITERS) {1515iters++;1516}15171518// native requests were dispatched by X/Window Manager or Windows1519// Moreover, we processed them all on Toolkit thread1520// Now wait while EDT processes them.1521//1522// During processing of some events (focus, for example),1523// some other events could have been generated. So, after1524// waitForIdle, we may end up with full EventQueue1525iters = 0;1526while (iters < MIN_ITERS) {1527waitForIdle(timeout(end));1528iters++;1529}1530while (waitForIdle(end) && iters < MAX_ITERS) {1531iters++;1532}15331534bigLoop++;1535// Again, for Java events, it was simple to check for new Java1536// events by checking event queue, but what if Java events1537// resulted in native requests? Therefor, check native events again.1538} while ((syncNativeQueue(timeout(end)) || waitForIdle(end))1539&& bigLoop < MAX_ITERS);1540}15411542protected long timeout(long end){1543return end - TimeUnit.NANOSECONDS.toMillis(System.nanoTime());1544}15451546/**1547* Platform toolkits need to implement this method to perform the1548* sync of the native queue. The method should wait until native1549* requests are processed, all native events are processed and1550* corresponding Java events are generated. Should return1551* {@code true} if some events were processed,1552* {@code false} otherwise.1553*/1554protected abstract boolean syncNativeQueue(long timeout);15551556private final Object waitLock = new Object();15571558private boolean isEQEmpty() {1559EventQueue queue = getSystemEventQueueImpl();1560return AWTAccessor.getEventQueueAccessor().noEvents(queue);1561}15621563/**1564* Waits for the Java event queue to empty. Ensures that all1565* events are processed (including paint events), and that if1566* recursive events were generated, they are also processed.1567* Should return {@code true} if more processing is1568* necessary, {@code false} otherwise.1569*/1570@SuppressWarnings("serial")1571private final boolean waitForIdle(final long end) {1572if (timeout(end) <= 0) {1573return false;1574}1575flushPendingEvents();1576final boolean queueWasEmpty;1577final AtomicBoolean queueEmpty = new AtomicBoolean();1578final AtomicBoolean eventDispatched = new AtomicBoolean();1579synchronized (waitLock) {1580queueWasEmpty = isEQEmpty();1581postEvent(AppContext.getAppContext(),1582new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {1583@Override1584public void dispatch() {1585// Here we block EDT. It could have some1586// events, it should have dispatched them by1587// now. So native requests could have been1588// generated. First, dispatch them. Then,1589// flush Java events again.1590int iters = 0;1591while (iters < MIN_ITERS) {1592syncNativeQueue(timeout(end));1593iters++;1594}1595while (syncNativeQueue(timeout(end)) && iters < MAX_ITERS) {1596iters++;1597}1598flushPendingEvents();15991600synchronized(waitLock) {1601queueEmpty.set(isEQEmpty());1602eventDispatched.set(true);1603waitLock.notifyAll();1604}1605}1606});1607try {1608while (!eventDispatched.get() && timeout(end) > 0) {1609waitLock.wait(timeout(end));1610}1611} catch (InterruptedException ie) {1612return false;1613}1614}16151616try {1617Thread.sleep(MINIMAL_DELAY);1618} catch (InterruptedException ie) {1619throw new RuntimeException("Interrupted");1620}16211622flushPendingEvents();16231624// Lock to force write-cache flush for queueEmpty.1625synchronized (waitLock) {1626return !(queueEmpty.get() && isEQEmpty() && queueWasEmpty);1627}1628}16291630/**1631* Grabs the mouse input for the given window. The window must be1632* visible. The window or its children do not receive any1633* additional mouse events besides those targeted to them. All1634* other events will be dispatched as before - to the respective1635* targets. This Window will receive UngrabEvent when automatic1636* ungrab is about to happen. The event can be listened to by1637* installing AWTEventListener with WINDOW_EVENT_MASK. See1638* UngrabEvent class for the list of conditions when ungrab is1639* about to happen.1640* @see UngrabEvent1641*/1642public abstract void grab(Window w);16431644/**1645* Forces ungrab. No event will be sent.1646*/1647public abstract void ungrab(Window w);16481649public void showOrHideTouchKeyboard(Component comp, AWTEvent e) {}16501651private static boolean touchKeyboardAutoShowIsEnabled;16521653public static boolean isTouchKeyboardAutoShowEnabled() {1654return touchKeyboardAutoShowIsEnabled;1655}16561657/**1658* Locates the splash screen library in a platform dependent way and closes1659* the splash screen. Should be invoked on first top-level frame display.1660* @see java.awt.SplashScreen1661* @since 1.61662*/1663public static native void closeSplashScreen();16641665/* The following methods and variables are to support retrieving1666* desktop text anti-aliasing settings1667*/16681669/* Need an instance method because setDesktopProperty(..) is protected. */1670private void fireDesktopFontPropertyChanges() {1671setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,1672SunToolkit.getDesktopFontHints());1673}16741675private static boolean checkedSystemAAFontSettings;1676private static boolean useSystemAAFontSettings;1677private static boolean lastExtraCondition = true;1678private static RenderingHints desktopFontHints;16791680/* Since Swing is the reason for this "extra condition" logic its1681* worth documenting it in some detail.1682* First, a goal is for Swing and applications to both retrieve and1683* use the same desktop property value so that there is complete1684* consistency between the settings used by JDK's Swing implementation1685* and 3rd party custom Swing components, custom L&Fs and any general1686* text rendering that wants to be consistent with these.1687* But by default on Solaris & Linux Swing will not use AA text over1688* remote X11 display (unless Xrender can be used which is TBD and may not1689* always be available anyway) as that is a noticeable performance hit.1690* So there needs to be a way to express that extra condition so that1691* it is seen by all clients of the desktop property API.1692* If this were the only condition it could be handled here as it would1693* be the same for any L&F and could reasonably be considered to be1694* a static behaviour of those systems.1695* But GTK currently has an additional test based on locale which is1696* not applied by Metal. So mixing GTK in a few locales with Metal1697* would mean the last one wins.1698* This could be stored per-app context which would work1699* for different applets, but wouldn't help for a single application1700* using GTK and some other L&F concurrently.1701* But it is expected this will be addressed within GTK and the font1702* system so is a temporary and somewhat unlikely harmless corner case.1703*/1704public static void setAAFontSettingsCondition(boolean extraCondition) {1705if (extraCondition != lastExtraCondition) {1706lastExtraCondition = extraCondition;1707if (checkedSystemAAFontSettings) {1708/* Someone already asked for this info, under a different1709* condition.1710* We'll force re-evaluation instead of replicating the1711* logic, then notify any listeners of any change.1712*/1713checkedSystemAAFontSettings = false;1714Toolkit tk = Toolkit.getDefaultToolkit();1715if (tk instanceof SunToolkit) {1716((SunToolkit)tk).fireDesktopFontPropertyChanges();1717}1718}1719}1720}17211722/* "false", "off", ""default" aren't explicitly tested, they1723* just fall through to produce a null return which all are equated to1724* "false".1725*/1726private static RenderingHints getDesktopAAHintsByName(String hintname) {1727Object aaHint = null;1728hintname = hintname.toLowerCase(Locale.ENGLISH);1729if (hintname.equals("on")) {1730aaHint = VALUE_TEXT_ANTIALIAS_ON;1731} else if (hintname.equals("gasp")) {1732aaHint = VALUE_TEXT_ANTIALIAS_GASP;1733} else if (hintname.equals("lcd") || hintname.equals("lcd_hrgb")) {1734aaHint = VALUE_TEXT_ANTIALIAS_LCD_HRGB;1735} else if (hintname.equals("lcd_hbgr")) {1736aaHint = VALUE_TEXT_ANTIALIAS_LCD_HBGR;1737} else if (hintname.equals("lcd_vrgb")) {1738aaHint = VALUE_TEXT_ANTIALIAS_LCD_VRGB;1739} else if (hintname.equals("lcd_vbgr")) {1740aaHint = VALUE_TEXT_ANTIALIAS_LCD_VBGR;1741}1742if (aaHint != null) {1743RenderingHints map = new RenderingHints(null);1744map.put(KEY_TEXT_ANTIALIASING, aaHint);1745return map;1746} else {1747return null;1748}1749}17501751/* This method determines whether to use the system font settings,1752* or ignore them if a L&F has specified they should be ignored, or1753* to override both of these with a system property specified value.1754* If the toolkit isn't a SunToolkit, (eg may be headless) then that1755* system property isn't applied as desktop properties are considered1756* to be inapplicable in that case. In that headless case although1757* this method will return "true" the toolkit will return a null map.1758*/1759@SuppressWarnings("removal")1760private static boolean useSystemAAFontSettings() {1761if (!checkedSystemAAFontSettings) {1762useSystemAAFontSettings = true; /* initially set this true */1763String systemAAFonts = null;1764Toolkit tk = Toolkit.getDefaultToolkit();1765if (tk instanceof SunToolkit) {1766systemAAFonts =1767AccessController.doPrivileged(1768new GetPropertyAction("awt.useSystemAAFontSettings"));1769}1770if (systemAAFonts != null) {1771useSystemAAFontSettings =1772Boolean.valueOf(systemAAFonts).booleanValue();1773/* If it is anything other than "true", then it may be1774* a hint name , or it may be "off, "default", etc.1775*/1776if (!useSystemAAFontSettings) {1777desktopFontHints = getDesktopAAHintsByName(systemAAFonts);1778}1779}1780/* If its still true, apply the extra condition */1781if (useSystemAAFontSettings) {1782useSystemAAFontSettings = lastExtraCondition;1783}1784checkedSystemAAFontSettings = true;1785}1786return useSystemAAFontSettings;1787}17881789/* A variable defined for the convenience of JDK code */1790public static final String DESKTOPFONTHINTS = "awt.font.desktophints";17911792/* Overridden by subclasses to return platform/desktop specific values */1793protected RenderingHints getDesktopAAHints() {1794return null;1795}17961797/* Subclass desktop property loading methods call this which1798* in turn calls the appropriate subclass implementation of1799* getDesktopAAHints() when system settings are being used.1800* Its public rather than protected because subclasses may delegate1801* to a helper class.1802*/1803public static RenderingHints getDesktopFontHints() {1804if (useSystemAAFontSettings()) {1805Toolkit tk = Toolkit.getDefaultToolkit();1806if (tk instanceof SunToolkit) {1807Object map = ((SunToolkit)tk).getDesktopAAHints();1808return (RenderingHints)map;1809} else { /* Headless Toolkit */1810return null;1811}1812} else if (desktopFontHints != null) {1813/* cloning not necessary as the return value is cloned later, but1814* its harmless.1815*/1816return (RenderingHints)(desktopFontHints.clone());1817} else {1818return null;1819}1820}182118221823public abstract boolean isDesktopSupported();1824public abstract boolean isTaskbarSupported();18251826/*1827* consumeNextKeyTyped() method is not currently used,1828* however Swing could use it in the future.1829*/1830public static synchronized void consumeNextKeyTyped(KeyEvent keyEvent) {1831try {1832AWTAccessor.getDefaultKeyboardFocusManagerAccessor().consumeNextKeyTyped(1833(DefaultKeyboardFocusManager)KeyboardFocusManager.1834getCurrentKeyboardFocusManager(),1835keyEvent);1836} catch (ClassCastException cce) {1837cce.printStackTrace();1838}1839}18401841protected static void dumpPeers(final PlatformLogger aLog) {1842AWTAutoShutdown.getInstance().dumpPeers(aLog);1843}18441845/**1846* Returns the {@code Window} ancestor of the component {@code comp}.1847* @return Window ancestor of the component or component by itself if it is Window;1848* null, if component is not a part of window hierarchy1849*/1850public static Window getContainingWindow(Component comp) {1851while (comp != null && !(comp instanceof Window)) {1852comp = comp.getParent();1853}1854return (Window)comp;1855}18561857private static Boolean sunAwtDisableMixing = null;18581859/**1860* Returns the value of "sun.awt.disableMixing" property. Default1861* value is {@code false}.1862*/1863@SuppressWarnings("removal")1864public static synchronized boolean getSunAwtDisableMixing() {1865if (sunAwtDisableMixing == null) {1866sunAwtDisableMixing = AccessController.doPrivileged(1867new GetBooleanAction("sun.awt.disableMixing"));1868}1869return sunAwtDisableMixing.booleanValue();1870}18711872public String getDesktop() {1873return null;1874}18751876/**1877* Returns true if the native GTK libraries are available. The1878* default implementation returns false, but UNIXToolkit overrides this1879* method to provide a more specific answer.1880*/1881public boolean isNativeGTKAvailable() {1882return false;1883}18841885private static final Object DEACTIVATION_TIMES_MAP_KEY = new Object();18861887public synchronized void setWindowDeactivationTime(Window w, long time) {1888AppContext ctx = getAppContext(w);1889if (ctx == null) {1890return;1891}1892@SuppressWarnings("unchecked")1893WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);1894if (map == null) {1895map = new WeakHashMap<Window, Long>();1896ctx.put(DEACTIVATION_TIMES_MAP_KEY, map);1897}1898map.put(w, time);1899}19001901public synchronized long getWindowDeactivationTime(Window w) {1902AppContext ctx = getAppContext(w);1903if (ctx == null) {1904return -1;1905}1906@SuppressWarnings("unchecked")1907WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);1908if (map == null) {1909return -1;1910}1911Long time = map.get(w);1912return time == null ? -1 : time;1913}19141915public void updateScreenMenuBarUI() {1916}19171918// Cosntant alpha1919public boolean isWindowOpacitySupported() {1920return false;1921}19221923// Shaping1924public boolean isWindowShapingSupported() {1925return false;1926}19271928// Per-pixel alpha1929public boolean isWindowTranslucencySupported() {1930return false;1931}19321933public boolean isTranslucencyCapable(GraphicsConfiguration gc) {1934return false;1935}19361937/**1938* Returns true if swing backbuffer should be translucent.1939*/1940public boolean isSwingBackbufferTranslucencySupported() {1941return false;1942}19431944/**1945* Returns whether or not a containing top level window for the passed1946* component is1947* {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}.1948*1949* @param c a Component which toplevel's to check1950* @return {@code true} if the passed component is not null and has a1951* containing toplevel window which is opaque (so per-pixel translucency1952* is not enabled), {@code false} otherwise1953* @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT1954*/1955public static boolean isContainingTopLevelOpaque(Component c) {1956Window w = getContainingWindow(c);1957return w != null && w.isOpaque();1958}19591960/**1961* Returns whether or not a containing top level window for the passed1962* component is1963* {@link GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}.1964*1965* @param c a Component which toplevel's to check1966* @return {@code true} if the passed component is not null and has a1967* containing toplevel window which has opacity less than1968* 1.0f (which means that it is translucent), {@code false} otherwise1969* @see GraphicsDevice.WindowTranslucency#TRANSLUCENT1970*/1971public static boolean isContainingTopLevelTranslucent(Component c) {1972Window w = getContainingWindow(c);1973return w != null && w.getOpacity() < 1.0f;1974}19751976/**1977* Returns whether the native system requires using the peer.updateWindow()1978* method to update the contents of a non-opaque window, or if usual1979* painting procedures are sufficient. The default return value covers1980* the X11 systems. On MS Windows this method is overriden in WToolkit1981* to return true.1982*/1983public boolean needUpdateWindow() {1984return false;1985}19861987/**1988* Descendants of the SunToolkit should override and put their own logic here.1989*/1990public int getNumberOfButtons(){1991return 3;1992}19931994/**1995* Checks that the given object implements/extends the given1996* interface/class.1997*1998* Note that using the instanceof operator causes a class to be loaded.1999* Using this method doesn't load a class and it can be used instead of2000* the instanceof operator for performance reasons.2001*2002* @param obj Object to be checked2003* @param type The name of the interface/class. Must be2004* fully-qualified interface/class name.2005* @return true, if this object implements/extends the given2006* interface/class, false, otherwise, or if obj or type is null2007*/2008public static boolean isInstanceOf(Object obj, String type) {2009if (obj == null) return false;2010if (type == null) return false;20112012return isInstanceOf(obj.getClass(), type);2013}20142015private static boolean isInstanceOf(Class<?> cls, String type) {2016if (cls == null) return false;20172018if (cls.getName().equals(type)) {2019return true;2020}20212022for (Class<?> c : cls.getInterfaces()) {2023if (c.getName().equals(type)) {2024return true;2025}2026}2027return isInstanceOf(cls.getSuperclass(), type);2028}20292030protected static LightweightFrame getLightweightFrame(Component c) {2031for (; c != null; c = c.getParent()) {2032if (c instanceof LightweightFrame) {2033return (LightweightFrame)c;2034}2035if (c instanceof Window) {2036// Don't traverse owner windows2037return null;2038}2039}2040return null;2041}20422043///////////////////////////////////////////////////////////////////////////2044//2045// The following methods help set and identify whether a particular2046// AWTEvent object was produced by the system or by user code. As of this2047// writing the only consumer is the Java Plug-In, although this information2048// could be useful to more clients and probably should be formalized in2049// the public API.2050//2051///////////////////////////////////////////////////////////////////////////20522053public static void setSystemGenerated(AWTEvent e) {2054AWTAccessor.getAWTEventAccessor().setSystemGenerated(e);2055}20562057public static boolean isSystemGenerated(AWTEvent e) {2058return AWTAccessor.getAWTEventAccessor().isSystemGenerated(e);2059}20602061} // class SunToolkit206220632064/*2065* PostEventQueue is a Thread that runs in the same AppContext as the2066* Java EventQueue. It is a queue of AWTEvents to be posted to the2067* Java EventQueue. The toolkit Thread (AWT-Windows/AWT-Motif) posts2068* events to this queue, which then calls EventQueue.postEvent().2069*2070* We do this because EventQueue.postEvent() may be overridden by client2071* code, and we mustn't ever call client code from the toolkit thread.2072*/2073class PostEventQueue {2074private EventQueueItem queueHead = null;2075private EventQueueItem queueTail = null;2076private final EventQueue eventQueue;20772078private Thread flushThread = null;20792080PostEventQueue(EventQueue eq) {2081eventQueue = eq;2082}20832084/*2085* Continually post pending AWTEvents to the Java EventQueue. The method2086* is synchronized to ensure the flush is completed before a new event2087* can be posted to this queue.2088*2089* 7177040: The method couldn't be wholly synchronized because of calls2090* of EventQueue.postEvent() that uses pushPopLock, otherwise it could2091* potentially lead to deadlock2092*/2093public void flush() {20942095Thread newThread = Thread.currentThread();20962097try {2098EventQueueItem tempQueue;2099synchronized (this) {2100// Avoid method recursion2101if (newThread == flushThread) {2102return;2103}2104// Wait for other threads' flushing2105while (flushThread != null) {2106wait();2107}2108// Skip everything if queue is empty2109if (queueHead == null) {2110return;2111}2112// Remember flushing thread2113flushThread = newThread;21142115tempQueue = queueHead;2116queueHead = queueTail = null;2117}2118try {2119while (tempQueue != null) {2120eventQueue.postEvent(tempQueue.event);2121tempQueue = tempQueue.next;2122}2123}2124finally {2125// Only the flushing thread can get here2126synchronized (this) {2127// Forget flushing thread, inform other pending threads2128flushThread = null;2129notifyAll();2130}2131}2132}2133catch (InterruptedException e) {2134// Couldn't allow exception go up, so at least recover the flag2135newThread.interrupt();2136}2137}21382139/*2140* Enqueue an AWTEvent to be posted to the Java EventQueue.2141*/2142void postEvent(AWTEvent event) {2143EventQueueItem item = new EventQueueItem(event);21442145synchronized (this) {2146if (queueHead == null) {2147queueHead = queueTail = item;2148} else {2149queueTail.next = item;2150queueTail = item;2151}2152}2153SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance());2154}2155} // class PostEventQueue215621572158