0001: /*
0002: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.awt;
0027:
0028: import java.awt.*;
0029: import static java.awt.RenderingHints.*;
0030: import java.awt.dnd.*;
0031: import java.awt.dnd.peer.DragSourceContextPeer;
0032: import java.awt.peer.*;
0033: import java.awt.event.WindowEvent;
0034: import java.awt.event.KeyEvent;
0035: import java.awt.im.spi.InputMethodDescriptor;
0036: import java.awt.image.*;
0037: import java.awt.geom.AffineTransform;
0038: import java.awt.TrayIcon;
0039: import java.awt.SystemTray;
0040: import java.io.*;
0041: import java.net.URL;
0042: import java.net.JarURLConnection;
0043: import java.util.*;
0044: import java.util.concurrent.TimeUnit;
0045: import java.util.concurrent.locks.Condition;
0046: import java.util.concurrent.locks.ReentrantLock;
0047: import java.util.logging.Level;
0048: import java.util.logging.Logger;
0049: import sun.misc.SoftCache;
0050: import sun.font.FontDesignMetrics;
0051: import sun.awt.im.InputContext;
0052: import sun.awt.im.SimpleInputMethodWindow;
0053: import sun.awt.image.*;
0054: import sun.security.action.GetPropertyAction;
0055: import sun.security.action.GetBooleanAction;
0056: import java.lang.reflect.Field;
0057: import java.lang.reflect.Method;
0058: import java.lang.reflect.Constructor;
0059: import java.lang.reflect.InvocationTargetException;
0060: import java.security.AccessController;
0061: import java.security.PrivilegedAction;
0062: import java.security.PrivilegedActionException;
0063: import java.security.PrivilegedExceptionAction;
0064:
0065: public abstract class SunToolkit extends Toolkit implements
0066: WindowClosingSupport, WindowClosingListener, ComponentFactory,
0067: InputMethodSupport {
0068:
0069: private static final Logger log = Logger
0070: .getLogger("sun.awt.SunToolkit");
0071:
0072: /* Force the debug helper classes to initialize */
0073: {
0074: DebugHelper.init();
0075: }
0076:
0077: /**
0078: * Special mask for the UngrabEvent events, in addition to the
0079: * public masks defined in AWTEvent. Should be used as the mask
0080: * value for Toolkit.addAWTEventListener.
0081: */
0082: public static final int GRAB_EVENT_MASK = 0x80000000;
0083:
0084: private static Field syncLWRequestsField;
0085: private static Method wakeupMethod;
0086: private static Field componentKeyField;
0087: private static Field menuComponentKeyField;
0088: private static Field trayIconKeyField;
0089: private static Field componentAppContextField;
0090: private static Field menuComponentAppContextField;
0091: private static Field isPostedField;
0092: /* The key to put()/get() the PostEventQueue into/from the AppContext.
0093: */
0094: private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";
0095:
0096: public SunToolkit() {
0097: /* If awt.threadgroup is set to class name the instance of
0098: * this class is created (should be subclass of ThreadGroup)
0099: * and EventDispatchThread is created inside of it
0100: *
0101: * If loaded class overrides uncaughtException instance
0102: * handles all uncaught exception on EventDispatchThread
0103: */
0104: ThreadGroup threadGroup = null;
0105: String tgName = System.getProperty("awt.threadgroup", "");
0106:
0107: if (tgName.length() != 0) {
0108: try {
0109: Constructor ctor = Class.forName(tgName)
0110: .getConstructor(new Class[] { String.class });
0111: threadGroup = (ThreadGroup) ctor
0112: .newInstance(new Object[] { "AWT-ThreadGroup" });
0113: } catch (Exception e) {
0114: System.err.println("Failed loading " + tgName + ": "
0115: + e);
0116: }
0117: }
0118:
0119: Runnable initEQ = new Runnable() {
0120: public void run() {
0121: EventQueue eventQueue;
0122:
0123: String eqName = System.getProperty(
0124: "AWT.EventQueueClass", "java.awt.EventQueue");
0125:
0126: try {
0127: eventQueue = (EventQueue) Class.forName(eqName)
0128: .newInstance();
0129: } catch (Exception e) {
0130: e.printStackTrace();
0131: System.err.println("Failed loading " + eqName
0132: + ": " + e);
0133: eventQueue = new EventQueue();
0134: }
0135: AppContext appContext = AppContext.getAppContext();
0136: appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
0137:
0138: PostEventQueue postEventQueue = new PostEventQueue(
0139: eventQueue);
0140: appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
0141: }
0142: };
0143:
0144: if (threadGroup != null) {
0145: Thread eqInitThread = new Thread(threadGroup, initEQ,
0146: "EventQueue-Init");
0147: eqInitThread.start();
0148: try {
0149: eqInitThread.join();
0150: } catch (InterruptedException e) {
0151: e.printStackTrace();
0152: }
0153: } else {
0154: initEQ.run();
0155: }
0156: }
0157:
0158: public boolean useBufferPerWindow() {
0159: return false;
0160: }
0161:
0162: public abstract WindowPeer createWindow(Window target)
0163: throws HeadlessException;
0164:
0165: public abstract FramePeer createFrame(Frame target)
0166: throws HeadlessException;
0167:
0168: public abstract DialogPeer createDialog(Dialog target)
0169: throws HeadlessException;
0170:
0171: public abstract ButtonPeer createButton(Button target)
0172: throws HeadlessException;
0173:
0174: public abstract TextFieldPeer createTextField(TextField target)
0175: throws HeadlessException;
0176:
0177: public abstract ChoicePeer createChoice(Choice target)
0178: throws HeadlessException;
0179:
0180: public abstract LabelPeer createLabel(Label target)
0181: throws HeadlessException;
0182:
0183: public abstract ListPeer createList(java.awt.List target)
0184: throws HeadlessException;
0185:
0186: public abstract CheckboxPeer createCheckbox(Checkbox target)
0187: throws HeadlessException;
0188:
0189: public abstract ScrollbarPeer createScrollbar(Scrollbar target)
0190: throws HeadlessException;
0191:
0192: public abstract ScrollPanePeer createScrollPane(ScrollPane target)
0193: throws HeadlessException;
0194:
0195: public abstract TextAreaPeer createTextArea(TextArea target)
0196: throws HeadlessException;
0197:
0198: public abstract FileDialogPeer createFileDialog(FileDialog target)
0199: throws HeadlessException;
0200:
0201: public abstract MenuBarPeer createMenuBar(MenuBar target)
0202: throws HeadlessException;
0203:
0204: public abstract MenuPeer createMenu(Menu target)
0205: throws HeadlessException;
0206:
0207: public abstract PopupMenuPeer createPopupMenu(PopupMenu target)
0208: throws HeadlessException;
0209:
0210: public abstract MenuItemPeer createMenuItem(MenuItem target)
0211: throws HeadlessException;
0212:
0213: public abstract CheckboxMenuItemPeer createCheckboxMenuItem(
0214: CheckboxMenuItem target) throws HeadlessException;
0215:
0216: public abstract DragSourceContextPeer createDragSourceContextPeer(
0217: DragGestureEvent dge) throws InvalidDnDOperationException;
0218:
0219: public abstract TrayIconPeer createTrayIcon(TrayIcon target)
0220: throws HeadlessException, AWTException;
0221:
0222: public abstract SystemTrayPeer createSystemTray(SystemTray target);
0223:
0224: public abstract boolean isTraySupported();
0225:
0226: public abstract FontPeer getFontPeer(String name, int style);
0227:
0228: public abstract RobotPeer createRobot(Robot target,
0229: GraphicsDevice screen) throws AWTException;
0230:
0231: public KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(
0232: KeyboardFocusManager manager) throws HeadlessException {
0233: KeyboardFocusManagerPeerImpl peer = new KeyboardFocusManagerPeerImpl(
0234: manager);
0235: return peer;
0236: }
0237:
0238: /**
0239: * The AWT lock is typically only used on Unix platforms to synchronize
0240: * access to Xlib, OpenGL, etc. However, these methods are implemented
0241: * in SunToolkit so that they can be called from shared code (e.g.
0242: * from the OGL pipeline) or from the X11 pipeline regardless of whether
0243: * XToolkit or MToolkit is currently in use. There are native macros
0244: * (such as AWT_LOCK) defined in awt.h, so if the implementation of these
0245: * methods is changed, make sure it is compatible with the native macros.
0246: *
0247: * Note: The following methods (awtLock(), awtUnlock(), etc) should be
0248: * used in place of:
0249: * synchronized (getAWTLock()) {
0250: * ...
0251: * }
0252: *
0253: * By factoring these methods out specially, we are able to change the
0254: * implementation of these methods (e.g. use more advanced locking
0255: * mechanisms) without impacting calling code.
0256: *
0257: * Sample usage:
0258: * private void doStuffWithXlib() {
0259: * assert !SunToolkit.isAWTLockHeldByCurrentThread();
0260: * SunToolkit.awtLock();
0261: * try {
0262: * ...
0263: * XlibWrapper.XDoStuff();
0264: * } finally {
0265: * SunToolkit.awtUnlock();
0266: * }
0267: * }
0268: */
0269:
0270: private static final ReentrantLock AWT_LOCK = new ReentrantLock();
0271: private static final Condition AWT_LOCK_COND = AWT_LOCK
0272: .newCondition();
0273:
0274: public static final void awtLock() {
0275: AWT_LOCK.lock();
0276: }
0277:
0278: public static final boolean awtTryLock() {
0279: return AWT_LOCK.tryLock();
0280: }
0281:
0282: public static final void awtUnlock() {
0283: AWT_LOCK.unlock();
0284: }
0285:
0286: public static final void awtLockWait() throws InterruptedException {
0287: AWT_LOCK_COND.await();
0288: }
0289:
0290: public static final void awtLockWait(long timeout)
0291: throws InterruptedException {
0292: AWT_LOCK_COND.await(timeout, TimeUnit.MILLISECONDS);
0293: }
0294:
0295: public static final void awtLockNotify() {
0296: AWT_LOCK_COND.signal();
0297: }
0298:
0299: public static final void awtLockNotifyAll() {
0300: AWT_LOCK_COND.signalAll();
0301: }
0302:
0303: public static final boolean isAWTLockHeldByCurrentThread() {
0304: return AWT_LOCK.isHeldByCurrentThread();
0305: }
0306:
0307: /*
0308: * Create a new AppContext, along with its EventQueue, for a
0309: * new ThreadGroup. Browser code, for example, would use this
0310: * method to create an AppContext & EventQueue for an Applet.
0311: */
0312: public static AppContext createNewAppContext() {
0313: ThreadGroup threadGroup = Thread.currentThread()
0314: .getThreadGroup();
0315: EventQueue eventQueue;
0316: String eqName = System.getProperty("AWT.EventQueueClass",
0317: "java.awt.EventQueue");
0318: try {
0319: eventQueue = (EventQueue) Class.forName(eqName)
0320: .newInstance();
0321: } catch (Exception e) {
0322: System.err.println("Failed loading " + eqName + ": " + e);
0323: eventQueue = new EventQueue();
0324: }
0325: AppContext appContext = new AppContext(threadGroup);
0326: appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
0327:
0328: PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
0329: appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
0330:
0331: return appContext;
0332: }
0333:
0334: public static Field getField(final Class klass,
0335: final String fieldName) {
0336: return AccessController
0337: .doPrivileged(new PrivilegedAction<Field>() {
0338: public Field run() {
0339: try {
0340: Field field = klass
0341: .getDeclaredField(fieldName);
0342: assert (field != null);
0343: field.setAccessible(true);
0344: return field;
0345: } catch (SecurityException e) {
0346: assert false;
0347: } catch (NoSuchFieldException e) {
0348: assert false;
0349: }
0350: return null;
0351: }//run
0352: });
0353: }
0354:
0355: static void wakeupEventQueue(EventQueue q, boolean isShutdown) {
0356: if (wakeupMethod == null) {
0357: wakeupMethod = (Method) AccessController
0358: .doPrivileged(new PrivilegedAction() {
0359: public Object run() {
0360: try {
0361: Method method = EventQueue.class
0362: .getDeclaredMethod(
0363: "wakeup",
0364: new Class[] { Boolean.TYPE });
0365: if (method != null) {
0366: method.setAccessible(true);
0367: }
0368: return method;
0369: } catch (NoSuchMethodException e) {
0370: assert false;
0371: } catch (SecurityException e) {
0372: assert false;
0373: }
0374: return null;
0375: }//run
0376: });
0377: }
0378: try {
0379: if (wakeupMethod != null) {
0380: wakeupMethod.invoke(q, new Object[] { Boolean
0381: .valueOf(isShutdown) });
0382: }
0383: } catch (InvocationTargetException e) {
0384: assert false;
0385: } catch (IllegalAccessException e) {
0386: assert false;
0387: }
0388: }
0389:
0390: /*
0391: * Fetch the peer associated with the given target (as specified
0392: * in the peer creation method). This can be used to determine
0393: * things like what the parent peer is. If the target is null
0394: * or the target can't be found (either because the a peer was
0395: * never created for it or the peer was disposed), a null will
0396: * be returned.
0397: */
0398: protected static Object targetToPeer(Object target) {
0399: if (target != null && !GraphicsEnvironment.isHeadless()) {
0400: return AWTAutoShutdown.getInstance().getPeer(target);
0401: }
0402: return null;
0403: }
0404:
0405: protected static void targetCreatedPeer(Object target, Object peer) {
0406: if (target != null && peer != null
0407: && !GraphicsEnvironment.isHeadless()) {
0408: AWTAutoShutdown.getInstance().registerPeer(target, peer);
0409: }
0410: }
0411:
0412: protected static void targetDisposedPeer(Object target, Object peer) {
0413: if (target != null && peer != null
0414: && !GraphicsEnvironment.isHeadless()) {
0415: AWTAutoShutdown.getInstance().unregisterPeer(target, peer);
0416: }
0417: }
0418:
0419: // Maps from non-Component/MenuComponent to AppContext.
0420: // WeakHashMap<Component,AppContext>
0421: private static final Map appContextMap = Collections
0422: .synchronizedMap(new WeakHashMap());
0423:
0424: /**
0425: * Sets the appContext field of target. If target is not a Component or
0426: * MenuComponent, this returns false.
0427: */
0428: private static boolean setAppContext(Object target,
0429: AppContext context) {
0430: if (!(target instanceof Component)
0431: && !(target instanceof MenuComponent)) {
0432: return false;
0433: }
0434: try {
0435: if (target instanceof Component) {
0436: if (componentAppContextField == null) {
0437: componentAppContextField = getField(
0438: Component.class, "appContext");
0439: }
0440: componentAppContextField.set(target, context);
0441: } else if (target instanceof MenuComponent) {
0442: if (menuComponentAppContextField == null) {
0443: menuComponentAppContextField = getField(
0444: MenuComponent.class, "appContext");
0445: }
0446: menuComponentAppContextField.set(target, context);
0447: }
0448: } catch (IllegalAccessException e) {
0449: assert false;
0450: }
0451:
0452: return true;
0453: }
0454:
0455: /**
0456: * Returns the appContext field for target. If target is not a
0457: * Component or MenuComponent this returns null.
0458: */
0459: private static AppContext getAppContext(Object target) {
0460: AppContext retObj = null;
0461: try {
0462: if (target instanceof Component) {
0463: if (componentAppContextField == null) {
0464: componentAppContextField = getField(
0465: Component.class, "appContext");
0466: }
0467: retObj = (AppContext) componentAppContextField
0468: .get(target);
0469: } else if (target instanceof MenuComponent) {
0470: if (menuComponentAppContextField == null) {
0471: menuComponentAppContextField = getField(
0472: MenuComponent.class, "appContext");
0473: }
0474: retObj = (AppContext) menuComponentAppContextField
0475: .get(target);
0476: }
0477: } catch (IllegalAccessException e) {
0478: assert false;
0479: }
0480: return retObj;
0481: }
0482:
0483: /*
0484: * Fetch the AppContext associated with the given target.
0485: * This can be used to determine things like which EventQueue
0486: * to use for posting events to a Component. If the target is
0487: * null or the target can't be found, a null with be returned.
0488: */
0489: public static AppContext targetToAppContext(Object target) {
0490: if (target == null || GraphicsEnvironment.isHeadless()) {
0491: return null;
0492: }
0493: AppContext context = getAppContext(target);
0494: if (context == null) {
0495: // target is not a Component/MenuComponent, try the
0496: // appContextMap.
0497: context = (AppContext) appContextMap.get(target);
0498: }
0499: return context;
0500: }
0501:
0502: /**
0503: * Sets the synchronous status of focus requests on lightweight
0504: * components in the specified window to the specified value.
0505: * If the boolean parameter is <code>true</code> then the focus
0506: * requests on lightweight components will be performed
0507: * synchronously, if it is <code>false</code>, then asynchronously.
0508: * By default, all windows have their lightweight request status
0509: * set to asynchronous.
0510: * <p>
0511: * The application can only set the status of lightweight focus
0512: * requests to synchronous for any of its windows if it doesn't
0513: * perform focus transfers between different heavyweight containers.
0514: * In this case the observable focus behaviour is the same as with
0515: * asynchronous status.
0516: * <p>
0517: * If the application performs focus transfer between different
0518: * heavyweight containers and sets the lightweight focus request
0519: * status to synchronous for any of its windows, then further focus
0520: * behaviour is unspecified.
0521: * <p>
0522: * @param w window for which the lightweight focus request status
0523: * should be set
0524: * @param status the value of lightweight focus request status
0525: */
0526:
0527: public static void setLWRequestStatus(Window changed, boolean status) {
0528: if (syncLWRequestsField == null) {
0529: syncLWRequestsField = getField(Window.class,
0530: "syncLWRequests");
0531: }
0532: try {
0533: if (syncLWRequestsField != null) {
0534: syncLWRequestsField.setBoolean(changed, status);
0535: }
0536: } catch (IllegalAccessException e) {
0537: assert false;
0538: }
0539: };
0540:
0541: public static void checkAndSetPolicy(Container cont,
0542: boolean isSwingCont) {
0543: FocusTraversalPolicy defaultPolicy = KeyboardFocusManager
0544: .getCurrentKeyboardFocusManager()
0545: .getDefaultFocusTraversalPolicy();
0546:
0547: String toolkitName = Toolkit.getDefaultToolkit().getClass()
0548: .getName();
0549: // if this is not XAWT then use default policy
0550: // because Swing change it
0551: if (!"sun.awt.X11.XToolkit".equals(toolkitName)) {
0552: cont.setFocusTraversalPolicy(defaultPolicy);
0553: return;
0554: }
0555:
0556: String policyName = defaultPolicy.getClass().getName();
0557:
0558: if (DefaultFocusTraversalPolicy.class != defaultPolicy
0559: .getClass()) {
0560: // Policy was changed
0561: // Check if it is awt policy or swing policy
0562: // If it is Swing policy we shouldn't use it in AWT frames
0563: // If it is AWT policy we shouldn't use it in Swing frames
0564: // Otherwise we should use this policy
0565: if (policyName.startsWith("java.awt.")) {
0566: // AWT
0567: if (isSwingCont) {
0568: // Can't use AWT policy in Swing windows - should use Swing's one.
0569: defaultPolicy = createLayoutPolicy();
0570: } else {
0571: // New awt policy.
0572: }
0573: } else if (policyName.startsWith("javax.swing.")) {
0574: if (isSwingCont) {
0575: // New Swing's policy
0576: } else {
0577: defaultPolicy = new DefaultFocusTraversalPolicy();
0578: }
0579: }
0580: } else {
0581: // Policy is default, use different default policy for swing
0582: if (isSwingCont) {
0583: defaultPolicy = createLayoutPolicy();
0584: }
0585: }
0586: cont.setFocusTraversalPolicy(defaultPolicy);
0587: }
0588:
0589: private static FocusTraversalPolicy createLayoutPolicy() {
0590: FocusTraversalPolicy policy = null;
0591: try {
0592: Class layoutPolicyClass = Class
0593: .forName("javax.swing.LayoutFocusTraversalPolicy");
0594: policy = (FocusTraversalPolicy) layoutPolicyClass
0595: .newInstance();
0596: } catch (ClassNotFoundException e) {
0597: assert false;
0598: } catch (InstantiationException e) {
0599: assert false;
0600: } catch (IllegalAccessException e) {
0601: assert false;
0602: }
0603:
0604: return policy;
0605: }
0606:
0607: /*
0608: * Insert a mapping from target to AppContext, for later retrieval
0609: * via targetToAppContext() above.
0610: */
0611: public static void insertTargetMapping(Object target,
0612: AppContext appContext) {
0613: if (!GraphicsEnvironment.isHeadless()) {
0614: if (!setAppContext(target, appContext)) {
0615: // Target is not a Component/MenuComponent, use the private Map
0616: // instead.
0617: appContextMap.put(target, appContext);
0618: }
0619: }
0620: }
0621:
0622: /*
0623: * Post an AWTEvent to the Java EventQueue, using the PostEventQueue
0624: * to avoid possibly calling client code (EventQueueSubclass.postEvent())
0625: * on the toolkit (AWT-Windows/AWT-Motif) thread. This function should
0626: * not be called under another lock since it locks the EventQueue.
0627: * See bugids 4632918, 4526597.
0628: */
0629: public static void postEvent(AppContext appContext, AWTEvent event) {
0630: if (event == null) {
0631: throw new NullPointerException();
0632: }
0633: AppContext eventContext = targetToAppContext(event.getSource());
0634: if (eventContext != null && !eventContext.equals(appContext)) {
0635: log.fine("Event posted on wrong app context : " + event);
0636: }
0637: PostEventQueue postEventQueue = (PostEventQueue) appContext
0638: .get(POST_EVENT_QUEUE_KEY);
0639: if (postEventQueue != null) {
0640: postEventQueue.postEvent(event);
0641: }
0642: }
0643:
0644: /*
0645: * Post AWTEvent of high priority.
0646: */
0647: public static void postPriorityEvent(final AWTEvent e) {
0648: if (isPostedField == null) {
0649: isPostedField = getField(AWTEvent.class, "isPosted");
0650: }
0651: PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(),
0652: new Runnable() {
0653: public void run() {
0654: try {
0655: isPostedField.setBoolean(e, true);
0656: } catch (IllegalArgumentException e) {
0657: assert (false);
0658: } catch (IllegalAccessException e) {
0659: assert (false);
0660: }
0661: ((Component) e.getSource()).dispatchEvent(e);
0662: }
0663: }, PeerEvent.ULTIMATE_PRIORITY_EVENT);
0664: postEvent(targetToAppContext(e.getSource()), pe);
0665: }
0666:
0667: /*
0668: * Flush any pending events which haven't been posted to the AWT
0669: * EventQueue yet.
0670: */
0671: public static void flushPendingEvents() {
0672: AppContext appContext = AppContext.getAppContext();
0673: PostEventQueue postEventQueue = (PostEventQueue) appContext
0674: .get(POST_EVENT_QUEUE_KEY);
0675: if (postEventQueue != null) {
0676: postEventQueue.flush();
0677: }
0678: }
0679:
0680: public static boolean isPostEventQueueEmpty() {
0681: AppContext appContext = AppContext.getAppContext();
0682: PostEventQueue postEventQueue = (PostEventQueue) appContext
0683: .get(POST_EVENT_QUEUE_KEY);
0684: if (postEventQueue != null) {
0685: return postEventQueue.noEvents();
0686: } else {
0687: return true;
0688: }
0689: }
0690:
0691: /*
0692: * Execute a chunk of code on the Java event handler thread for the
0693: * given target. Does not wait for the execution to occur before
0694: * returning to the caller.
0695: */
0696: public static void executeOnEventHandlerThread(Object target,
0697: Runnable runnable) {
0698: executeOnEventHandlerThread(new PeerEvent(target, runnable,
0699: PeerEvent.PRIORITY_EVENT));
0700: }
0701:
0702: /*
0703: * Fixed 5064013: the InvocationEvent time should be equals
0704: * the time of the ActionEvent
0705: */
0706: public static void executeOnEventHandlerThread(Object target,
0707: Runnable runnable, final long when) {
0708: executeOnEventHandlerThread(new PeerEvent(target, runnable,
0709: PeerEvent.PRIORITY_EVENT) {
0710: public long getWhen() {
0711: return when;
0712: }
0713: });
0714: }
0715:
0716: /*
0717: * Execute a chunk of code on the Java event handler thread for the
0718: * given target. Does not wait for the execution to occur before
0719: * returning to the caller.
0720: */
0721: public static void executeOnEventHandlerThread(PeerEvent peerEvent) {
0722: postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
0723: }
0724:
0725: /*
0726: * Execute a chunk of code on the Java event handler thread. The
0727: * method takes into account provided AppContext and sets
0728: * <code>SunToolkit.getDefaultToolkit()</code> as a target of the
0729: * event. See 6451487 for detailes.
0730: * Does not wait for the execution to occur before returning to
0731: * the caller.
0732: */
0733: public static void invokeLaterOnAppContext(AppContext appContext,
0734: Runnable dispatcher) {
0735: postEvent(appContext, new PeerEvent(
0736: Toolkit.getDefaultToolkit(), dispatcher,
0737: PeerEvent.PRIORITY_EVENT));
0738: }
0739:
0740: /*
0741: * Execute a chunk of code on the Java event handler thread for the
0742: * given target. Waits for the execution to occur before returning
0743: * to the caller.
0744: */
0745: public static void executeOnEDTAndWait(Object target,
0746: Runnable runnable) throws InterruptedException,
0747: InvocationTargetException {
0748: if (EventQueue.isDispatchThread()) {
0749: throw new Error(
0750: "Cannot call executeOnEDTAndWait from any event dispatcher thread");
0751: }
0752:
0753: class AWTInvocationLock {
0754: }
0755: Object lock = new AWTInvocationLock();
0756:
0757: PeerEvent event = new PeerEvent(target, runnable, lock, true,
0758: PeerEvent.PRIORITY_EVENT);
0759:
0760: synchronized (lock) {
0761: executeOnEventHandlerThread(event);
0762: lock.wait();
0763: }
0764:
0765: Throwable eventThrowable = event.getThrowable();
0766: if (eventThrowable != null) {
0767: throw new InvocationTargetException(eventThrowable);
0768: }
0769: }
0770:
0771: /*
0772: * Returns next queue for the given EventQueue which has private access
0773: */
0774: private static EventQueue getNextQueue(final Object o) {
0775: EventQueue result = null;
0776: try {
0777: Field nextQueueField = getField(EventQueue.class,
0778: "nextQueue");
0779: result = (EventQueue) nextQueueField.get(o);
0780: } catch (IllegalAccessException e) {
0781: assert false;
0782: }
0783: return result;
0784: }
0785:
0786: /*
0787: * Returns dispatch thread for the given EventQueue which has private access
0788: */
0789: private static Thread getDispatchThread(final Object o) {
0790: Thread result = null;
0791: try {
0792: Field dispatchThreadField = getField(EventQueue.class,
0793: "dispatchThread");
0794: result = (Thread) dispatchThreadField.get(o);
0795: } catch (IllegalAccessException e) {
0796: assert false;
0797: }
0798: return result;
0799: }
0800:
0801: /*
0802: * Returns true if the calling thread is the event dispatch thread
0803: * contained within AppContext which associated with the given target.
0804: * Use this call to ensure that a given task is being executed
0805: * (or not being) on the event dispatch thread for the given target.
0806: */
0807: public static boolean isDispatchThreadForAppContext(Object target) {
0808: AppContext appContext = targetToAppContext(target);
0809: EventQueue eq = (EventQueue) appContext
0810: .get(AppContext.EVENT_QUEUE_KEY);
0811:
0812: EventQueue next = getNextQueue(eq);
0813: while (next != null) {
0814: eq = next;
0815: next = getNextQueue(eq);
0816: }
0817:
0818: return (Thread.currentThread() == getDispatchThread(eq));
0819: }
0820:
0821: public Dimension getScreenSize() {
0822: return new Dimension(getScreenWidth(), getScreenHeight());
0823: }
0824:
0825: protected abstract int getScreenWidth();
0826:
0827: protected abstract int getScreenHeight();
0828:
0829: public FontMetrics getFontMetrics(Font font) {
0830: return FontDesignMetrics.getMetrics(font);
0831: }
0832:
0833: public String[] getFontList() {
0834: String[] hardwiredFontList = { Font.DIALOG, Font.SANS_SERIF,
0835: Font.SERIF, Font.MONOSPACED, Font.DIALOG_INPUT
0836:
0837: // -- Obsolete font names from 1.0.2. It was decided that
0838: // -- getFontList should not return these old names:
0839: // "Helvetica", "TimesRoman", "Courier", "ZapfDingbats"
0840: };
0841: return hardwiredFontList;
0842: }
0843:
0844: public PanelPeer createPanel(Panel target) {
0845: return (PanelPeer) createComponent(target);
0846: }
0847:
0848: public CanvasPeer createCanvas(Canvas target) {
0849: return (CanvasPeer) createComponent(target);
0850: }
0851:
0852: /**
0853: * Disables erasing of background on the canvas before painting
0854: * if this is supported by the current toolkit.
0855: *
0856: * @throws IllegalStateException if the canvas is not displayable
0857: * @see java.awt.Component#isDisplayable
0858: */
0859: public void disableBackgroundErase(Canvas canvas) {
0860: if (!canvas.isDisplayable()) {
0861: throw new IllegalStateException(
0862: "Canvas must have a valid peer");
0863: }
0864: }
0865:
0866: /**
0867: * Returns the value of "sun.awt.noerasebackground" property. Default
0868: * value is {@code false}.
0869: */
0870: public static boolean getSunAwtNoerasebackground() {
0871: return AccessController.doPrivileged(new GetBooleanAction(
0872: "sun.awt.noerasebackground"));
0873: }
0874:
0875: /**
0876: * Returns the value of "sun.awt.erasebackgroundonresize" property. Default
0877: * value is {@code false}.
0878: */
0879: public static boolean getSunAwtErasebackgroundonresize() {
0880: return AccessController.doPrivileged(new GetBooleanAction(
0881: "sun.awt.erasebackgroundonresize"));
0882: }
0883:
0884: static SoftCache imgCache = new SoftCache();
0885:
0886: static synchronized Image getImageFromHash(Toolkit tk, URL url) {
0887: SecurityManager sm = System.getSecurityManager();
0888: if (sm != null) {
0889: try {
0890: java.security.Permission perm = url.openConnection()
0891: .getPermission();
0892: if (perm != null) {
0893: try {
0894: sm.checkPermission(perm);
0895: } catch (SecurityException se) {
0896: // fallback to checkRead/checkConnect for pre 1.2
0897: // security managers
0898: if ((perm instanceof java.io.FilePermission)
0899: && perm.getActions().indexOf("read") != -1) {
0900: sm.checkRead(perm.getName());
0901: } else if ((perm instanceof java.net.SocketPermission)
0902: && perm.getActions().indexOf("connect") != -1) {
0903: sm.checkConnect(url.getHost(), url
0904: .getPort());
0905: } else {
0906: throw se;
0907: }
0908: }
0909: }
0910: } catch (java.io.IOException ioe) {
0911: sm.checkConnect(url.getHost(), url.getPort());
0912: }
0913: }
0914: Image img = (Image) imgCache.get(url);
0915: if (img == null) {
0916: try {
0917: img = tk.createImage(new URLImageSource(url));
0918: imgCache.put(url, img);
0919: } catch (Exception e) {
0920: }
0921: }
0922: return img;
0923: }
0924:
0925: static synchronized Image getImageFromHash(Toolkit tk,
0926: String filename) {
0927: SecurityManager security = System.getSecurityManager();
0928: if (security != null) {
0929: security.checkRead(filename);
0930: }
0931: Image img = (Image) imgCache.get(filename);
0932: if (img == null) {
0933: try {
0934: img = tk.createImage(new FileImageSource(filename));
0935: imgCache.put(filename, img);
0936: } catch (Exception e) {
0937: }
0938: }
0939: return img;
0940: }
0941:
0942: public Image getImage(String filename) {
0943: return getImageFromHash(this , filename);
0944: }
0945:
0946: public Image getImage(URL url) {
0947: return getImageFromHash(this , url);
0948: }
0949:
0950: public Image createImage(String filename) {
0951: SecurityManager security = System.getSecurityManager();
0952: if (security != null) {
0953: security.checkRead(filename);
0954: }
0955: return createImage(new FileImageSource(filename));
0956: }
0957:
0958: public Image createImage(URL url) {
0959: SecurityManager sm = System.getSecurityManager();
0960: if (sm != null) {
0961: try {
0962: java.security.Permission perm = url.openConnection()
0963: .getPermission();
0964: if (perm != null) {
0965: try {
0966: sm.checkPermission(perm);
0967: } catch (SecurityException se) {
0968: // fallback to checkRead/checkConnect for pre 1.2
0969: // security managers
0970: if ((perm instanceof java.io.FilePermission)
0971: && perm.getActions().indexOf("read") != -1) {
0972: sm.checkRead(perm.getName());
0973: } else if ((perm instanceof java.net.SocketPermission)
0974: && perm.getActions().indexOf("connect") != -1) {
0975: sm.checkConnect(url.getHost(), url
0976: .getPort());
0977: } else {
0978: throw se;
0979: }
0980: }
0981: }
0982: } catch (java.io.IOException ioe) {
0983: sm.checkConnect(url.getHost(), url.getPort());
0984: }
0985: }
0986: return createImage(new URLImageSource(url));
0987: }
0988:
0989: public Image createImage(byte[] data, int offset, int length) {
0990: return createImage(new ByteArrayImageSource(data, offset,
0991: length));
0992: }
0993:
0994: public Image createImage(ImageProducer producer) {
0995: return new ToolkitImage(producer);
0996: }
0997:
0998: public int checkImage(Image img, int w, int h, ImageObserver o) {
0999: if (!(img instanceof ToolkitImage)) {
1000: return ImageObserver.ALLBITS;
1001: }
1002:
1003: ToolkitImage tkimg = (ToolkitImage) img;
1004: int repbits;
1005: if (w == 0 || h == 0) {
1006: repbits = ImageObserver.ALLBITS;
1007: } else {
1008: repbits = tkimg.getImageRep().check(o);
1009: }
1010: return tkimg.check(o) | repbits;
1011: }
1012:
1013: public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
1014: if (w == 0 || h == 0) {
1015: return true;
1016: }
1017:
1018: // Must be a ToolkitImage
1019: if (!(img instanceof ToolkitImage)) {
1020: return true;
1021: }
1022:
1023: ToolkitImage tkimg = (ToolkitImage) img;
1024: if (tkimg.hasError()) {
1025: if (o != null) {
1026: o.imageUpdate(img, ImageObserver.ERROR
1027: | ImageObserver.ABORT, -1, -1, -1, -1);
1028: }
1029: return false;
1030: }
1031: ImageRepresentation ir = tkimg.getImageRep();
1032: return ir.prepare(o);
1033: }
1034:
1035: /**
1036: * Scans {@code imageList} for best-looking image of specified dimensions.
1037: * Image can be scaled and/or padded with transparency.
1038: */
1039: public static BufferedImage getScaledIconImage(
1040: java.util.List<Image> imageList, int width, int height) {
1041: if (width == 0 || height == 0) {
1042: return null;
1043: }
1044: Image bestImage = null;
1045: int bestWidth = 0;
1046: int bestHeight = 0;
1047: double bestSimilarity = 3; //Impossibly high value
1048: double bestScaleFactor = 0;
1049: for (Iterator<Image> i = imageList.iterator(); i.hasNext();) {
1050: //Iterate imageList looking for best matching image.
1051: //'Similarity' measure is defined as good scale factor and small insets.
1052: //best possible similarity is 0 (no scale, no insets).
1053: //It's found while the experiments that good-looking result is achieved
1054: //with scale factors x1, x3/4, x2/3, xN, x1/N.
1055: Image im = i.next();
1056: if (im == null) {
1057: if (log.isLoggable(Level.FINEST)) {
1058: log
1059: .finest("SunToolkit.getScaledIconImage: Skipping the image passed into Java because it's null.");
1060: }
1061: continue;
1062: }
1063: if (im instanceof ToolkitImage) {
1064: ImageRepresentation ir = ((ToolkitImage) im)
1065: .getImageRep();
1066: ir.reconstruct(ImageObserver.ALLBITS);
1067: }
1068: int iw;
1069: int ih;
1070: try {
1071: iw = im.getWidth(null);
1072: ih = im.getHeight(null);
1073: } catch (Exception e) {
1074: if (log.isLoggable(Level.FINEST)) {
1075: log
1076: .finest("SunToolkit.getScaledIconImage: Perhaps the image passed into Java is broken. Skipping this icon.");
1077: }
1078: continue;
1079: }
1080: if (iw > 0 && ih > 0) {
1081: //Calc scale factor
1082: double scaleFactor = Math.min((double) width
1083: / (double) iw, (double) height / (double) ih);
1084: //Calculate scaled image dimensions
1085: //adjusting scale factor to nearest "good" value
1086: int adjw = 0;
1087: int adjh = 0;
1088: double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad
1089: if (scaleFactor >= 2) {
1090: //Need to enlarge image more than twice
1091: //Round down scale factor to multiply by integer value
1092: scaleFactor = Math.floor(scaleFactor);
1093: adjw = iw * (int) scaleFactor;
1094: adjh = ih * (int) scaleFactor;
1095: scaleMeasure = 1.0 - 0.5 / scaleFactor;
1096: } else if (scaleFactor >= 1) {
1097: //Don't scale
1098: scaleFactor = 1.0;
1099: adjw = iw;
1100: adjh = ih;
1101: scaleMeasure = 0;
1102: } else if (scaleFactor >= 0.75) {
1103: //Multiply by 3/4
1104: scaleFactor = 0.75;
1105: adjw = iw * 3 / 4;
1106: adjh = ih * 3 / 4;
1107: scaleMeasure = 0.3;
1108: } else if (scaleFactor >= 0.6666) {
1109: //Multiply by 2/3
1110: scaleFactor = 0.6666;
1111: adjw = iw * 2 / 3;
1112: adjh = ih * 2 / 3;
1113: scaleMeasure = 0.33;
1114: } else {
1115: //Multiply size by 1/scaleDivider
1116: //where scaleDivider is minimum possible integer
1117: //larger than 1/scaleFactor
1118: double scaleDivider = Math.ceil(1.0 / scaleFactor);
1119: scaleFactor = 1.0 / scaleDivider;
1120: adjw = (int) Math.round((double) iw / scaleDivider);
1121: adjh = (int) Math.round((double) ih / scaleDivider);
1122: scaleMeasure = 1.0 - 1.0 / scaleDivider;
1123: }
1124: double similarity = ((double) width - (double) adjw)
1125: / (double) width
1126: + ((double) height - (double) adjh)
1127: / (double) height + //Large padding is bad
1128: scaleMeasure; //Large rescale is bad
1129: if (similarity < bestSimilarity) {
1130: bestSimilarity = similarity;
1131: bestScaleFactor = scaleFactor;
1132: bestImage = im;
1133: bestWidth = adjw;
1134: bestHeight = adjh;
1135: }
1136: if (similarity == 0)
1137: break;
1138: }
1139: }
1140: if (bestImage == null) {
1141: //No images were found, possibly all are broken
1142: return null;
1143: }
1144: BufferedImage bimage = new BufferedImage(width, height,
1145: BufferedImage.TYPE_INT_ARGB);
1146: Graphics2D g = bimage.createGraphics();
1147: g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
1148: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
1149: try {
1150: int x = (width - bestWidth) / 2;
1151: int y = (height - bestHeight) / 2;
1152: if (log.isLoggable(Level.FINER)) {
1153: log.finer("WWindowPeer.getScaledIconData() result : "
1154: + "w : " + width + " h : " + height + " iW : "
1155: + bestImage.getWidth(null) + " iH : "
1156: + bestImage.getHeight(null) + " sim : "
1157: + bestSimilarity + " sf : " + bestScaleFactor
1158: + " adjW : " + bestWidth + " adjH : "
1159: + bestHeight + " x : " + x + " y : " + y);
1160: }
1161: g.drawImage(bestImage, x, y, bestWidth, bestHeight, null);
1162: } finally {
1163: g.dispose();
1164: }
1165: return bimage;
1166: }
1167:
1168: public static DataBufferInt getScaledIconData(
1169: java.util.List<Image> imageList, int width, int height) {
1170: BufferedImage bimage = getScaledIconImage(imageList, width,
1171: height);
1172: if (bimage == null) {
1173: if (log.isLoggable(Level.FINEST)) {
1174: log
1175: .finest("SunToolkit.getScaledIconData: Perhaps the image passed into Java is broken. Skipping this icon.");
1176: }
1177: return null;
1178: }
1179: Raster raster = bimage.getRaster();
1180: DataBuffer buffer = raster.getDataBuffer();
1181: return (DataBufferInt) buffer;
1182: }
1183:
1184: protected EventQueue getSystemEventQueueImpl() {
1185: return getSystemEventQueueImplPP();
1186: }
1187:
1188: // Package private implementation
1189: static EventQueue getSystemEventQueueImplPP() {
1190: return getSystemEventQueueImplPP(AppContext.getAppContext());
1191: }
1192:
1193: public static EventQueue getSystemEventQueueImplPP(
1194: AppContext appContext) {
1195: EventQueue theEventQueue = (EventQueue) appContext
1196: .get(AppContext.EVENT_QUEUE_KEY);
1197: return theEventQueue;
1198: }
1199:
1200: /**
1201: * Give native peers the ability to query the native container
1202: * given a native component (eg the direct parent may be lightweight).
1203: */
1204: public static Container getNativeContainer(Component c) {
1205: return Toolkit.getNativeContainer(c);
1206: }
1207:
1208: /**
1209: * Returns a new input method window, with behavior as specified in
1210: * {@link java.awt.im.spi.InputMethodContext#createInputMethodWindow}.
1211: * If the inputContext is not null, the window should return it from its
1212: * getInputContext() method. The window needs to implement
1213: * sun.awt.im.InputMethodWindow.
1214: * <p>
1215: * SunToolkit subclasses can override this method to return better input
1216: * method windows.
1217: */
1218: public Window createInputMethodWindow(String title,
1219: InputContext context) {
1220: return new sun.awt.im.SimpleInputMethodWindow(title, context);
1221: }
1222:
1223: /**
1224: * Returns whether enableInputMethods should be set to true for peered
1225: * TextComponent instances on this platform. False by default.
1226: */
1227: public boolean enableInputMethodsForTextComponent() {
1228: return false;
1229: }
1230:
1231: private static Locale startupLocale = null;
1232:
1233: /**
1234: * Returns the locale in which the runtime was started.
1235: */
1236: public static Locale getStartupLocale() {
1237: if (startupLocale == null) {
1238: String language, region, country, variant;
1239: language = (String) AccessController
1240: .doPrivileged(new GetPropertyAction(
1241: "user.language", "en"));
1242: // for compatibility, check for old user.region property
1243: region = (String) AccessController
1244: .doPrivileged(new GetPropertyAction("user.region"));
1245: if (region != null) {
1246: // region can be of form country, country_variant, or _variant
1247: int i = region.indexOf('_');
1248: if (i >= 0) {
1249: country = region.substring(0, i);
1250: variant = region.substring(i + 1);
1251: } else {
1252: country = region;
1253: variant = "";
1254: }
1255: } else {
1256: country = (String) AccessController
1257: .doPrivileged(new GetPropertyAction(
1258: "user.country", ""));
1259: variant = (String) AccessController
1260: .doPrivileged(new GetPropertyAction(
1261: "user.variant", ""));
1262: }
1263: startupLocale = new Locale(language, country, variant);
1264: }
1265: return startupLocale;
1266: }
1267:
1268: /**
1269: * Returns the default keyboard locale of the underlying operating system
1270: */
1271: public Locale getDefaultKeyboardLocale() {
1272: return getStartupLocale();
1273: }
1274:
1275: private static String dataTransfererClassName = null;
1276:
1277: protected static void setDataTransfererClassName(String className) {
1278: dataTransfererClassName = className;
1279: }
1280:
1281: public static String getDataTransfererClassName() {
1282: if (dataTransfererClassName == null) {
1283: Toolkit.getDefaultToolkit(); // transferer set during toolkit init
1284: }
1285: return dataTransfererClassName;
1286: }
1287:
1288: // Support for window closing event notifications
1289: private transient WindowClosingListener windowClosingListener = null;
1290:
1291: /**
1292: * @see sun.awt.WindowClosingSupport#getWindowClosingListener
1293: */
1294: public WindowClosingListener getWindowClosingListener() {
1295: return windowClosingListener;
1296: }
1297:
1298: /**
1299: * @see sun.awt.WindowClosingSupport#setWindowClosingListener
1300: */
1301: public void setWindowClosingListener(WindowClosingListener wcl) {
1302: windowClosingListener = wcl;
1303: }
1304:
1305: /**
1306: * @see sun.awt.WindowClosingListener#windowClosingNotify
1307: */
1308: public RuntimeException windowClosingNotify(WindowEvent event) {
1309: if (windowClosingListener != null) {
1310: return windowClosingListener.windowClosingNotify(event);
1311: } else {
1312: return null;
1313: }
1314: }
1315:
1316: /**
1317: * @see sun.awt.WindowClosingListener#windowClosingDelivered
1318: */
1319: public RuntimeException windowClosingDelivered(WindowEvent event) {
1320: if (windowClosingListener != null) {
1321: return windowClosingListener.windowClosingDelivered(event);
1322: } else {
1323: return null;
1324: }
1325: }
1326:
1327: private static DefaultMouseInfoPeer mPeer = null;
1328:
1329: protected synchronized MouseInfoPeer getMouseInfoPeer() {
1330: if (mPeer == null) {
1331: mPeer = new DefaultMouseInfoPeer();
1332: }
1333: return mPeer;
1334: }
1335:
1336: /**
1337: * Returns whether default toolkit needs the support of the xembed
1338: * from embedding host(if any).
1339: * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1340: */
1341: public static boolean needsXEmbed() {
1342: String noxembed = (String) AccessController
1343: .doPrivileged(new GetPropertyAction("sun.awt.noxembed",
1344: "false"));
1345: if ("true".equals(noxembed)) {
1346: return false;
1347: }
1348:
1349: Toolkit tk = Toolkit.getDefaultToolkit();
1350: if (tk instanceof SunToolkit) {
1351: // SunToolkit descendants should override this method to specify
1352: // concrete behavior
1353: return ((SunToolkit) tk).needsXEmbedImpl();
1354: } else {
1355: // Non-SunToolkit doubtly might support XEmbed
1356: return false;
1357: }
1358: }
1359:
1360: /**
1361: * Returns whether this toolkit needs the support of the xembed
1362: * from embedding host(if any).
1363: * @return <code>true</code>, if XEmbed is needed, <code>false</code> otherwise
1364: */
1365: protected boolean needsXEmbedImpl() {
1366: return false;
1367: }
1368:
1369: private static Dialog.ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE;
1370:
1371: static {
1372: DEFAULT_MODAL_EXCLUSION_TYPE = (Dialog.ModalExclusionType) AccessController
1373: .doPrivileged(new PrivilegedAction() {
1374: public Object run() {
1375: Dialog.ModalExclusionType defaultType = Dialog.ModalExclusionType.NO_EXCLUDE;
1376: try {
1377: java.lang.reflect.Field f = Dialog.class
1378: .getDeclaredField("DEFAULT_MODAL_EXCLUSION_TYPE");
1379: f.setAccessible(true);
1380: defaultType = (Dialog.ModalExclusionType) f
1381: .get(null);
1382: } catch (Exception e) {
1383: }
1384: return defaultType;
1385: }
1386: });
1387: }
1388:
1389: /**
1390: * Returns whether the XEmbed server feature is requested by
1391: * developer. If true, Toolkit should return an
1392: * XEmbed-server-enabled CanvasPeer instead of the ordinary CanvasPeer.
1393: */
1394: protected final boolean isXEmbedServerRequested() {
1395: return AccessController.doPrivileged(new GetBooleanAction(
1396: "sun.awt.xembedserver"));
1397: }
1398:
1399: /**
1400: * Returns whether the modal exclusion API is supported by the current toolkit.
1401: * When it isn't supported, calling <code>setModalExcluded</code> has no
1402: * effect, and <code>isModalExcluded</code> returns false for all windows.
1403: *
1404: * @return true if modal exclusion is supported by the toolkit, false otherwise
1405: *
1406: * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1407: * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1408: *
1409: * @since 1.5
1410: */
1411: public static boolean isModalExcludedSupported() {
1412: Toolkit tk = Toolkit.getDefaultToolkit();
1413: return tk
1414: .isModalExclusionTypeSupported(DEFAULT_MODAL_EXCLUSION_TYPE);
1415: }
1416:
1417: /*
1418: * Default implementation for isModalExcludedSupportedImpl(), returns false.
1419: *
1420: * @see sun.awt.windows.WToolkit#isModalExcludeSupportedImpl
1421: * @see sun.awt.X11.XToolkit#isModalExcludeSupportedImpl
1422: *
1423: * @since 1.5
1424: */
1425: protected boolean isModalExcludedSupportedImpl() {
1426: return false;
1427: }
1428:
1429: /*
1430: * Sets this window to be excluded from being modally blocked. When the
1431: * toolkit supports modal exclusion and this method is called, input
1432: * events, focus transfer and z-order will continue to work for the
1433: * window, it's owned windows and child components, even in the
1434: * presence of a modal dialog.
1435: * For details on which <code>Window</code>s are normally blocked
1436: * by modal dialog, see {@link java.awt.Dialog}.
1437: * Invoking this method when the modal exclusion API is not supported by
1438: * the current toolkit has no effect.
1439: * @param window Window to be marked as not modally blocked
1440: * @see java.awt.Dialog
1441: * @see java.awt.Dialog#setModal(boolean)
1442: * @see sun.awt.SunToolkit#isModalExcludedSupported
1443: * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window)
1444: */
1445: public static void setModalExcluded(Window window) {
1446: window.setModalExclusionType(DEFAULT_MODAL_EXCLUSION_TYPE);
1447: }
1448:
1449: /*
1450: * Returns whether the specified window is blocked by modal dialogs.
1451: * If the modal exclusion API isn't supported by the current toolkit,
1452: * it returns false for all windows.
1453: *
1454: * @param window Window to test for modal exclusion
1455: *
1456: * @return true if the window is modal excluded, false otherwise. If
1457: * the modal exclusion isn't supported by the current Toolkit, false
1458: * is returned
1459: *
1460: * @see sun.awt.SunToolkit#isModalExcludedSupported
1461: * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window)
1462: *
1463: * @since 1.5
1464: */
1465: public static boolean isModalExcluded(Window window) {
1466: return window.getModalExclusionType().compareTo(
1467: DEFAULT_MODAL_EXCLUSION_TYPE) >= 0;
1468: }
1469:
1470: /**
1471: * Overridden in XToolkit and WToolkit
1472: */
1473: public boolean isModalityTypeSupported(
1474: Dialog.ModalityType modalityType) {
1475: return (modalityType == Dialog.ModalityType.MODELESS)
1476: || (modalityType == Dialog.ModalityType.APPLICATION_MODAL);
1477: }
1478:
1479: /**
1480: * Overridden in XToolkit and WToolkit
1481: */
1482: public boolean isModalExclusionTypeSupported(
1483: Dialog.ModalExclusionType exclusionType) {
1484: return (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE);
1485: }
1486:
1487: ///////////////////////////////////////////////////////////////////////////
1488: //
1489: // The following is used by the Java Plug-in to coordinate dialog modality
1490: // between containing applications (browsers, ActiveX containers etc) and
1491: // the AWT.
1492: //
1493: ///////////////////////////////////////////////////////////////////////////
1494:
1495: private ModalityListenerList modalityListeners = new ModalityListenerList();
1496:
1497: public void addModalityListener(ModalityListener listener) {
1498: modalityListeners.add(listener);
1499: }
1500:
1501: public void removeModalityListener(ModalityListener listener) {
1502: modalityListeners.remove(listener);
1503: }
1504:
1505: public void notifyModalityPushed(Dialog dialog) {
1506: notifyModalityChange(ModalityEvent.MODALITY_PUSHED, dialog);
1507: }
1508:
1509: public void notifyModalityPopped(Dialog dialog) {
1510: notifyModalityChange(ModalityEvent.MODALITY_POPPED, dialog);
1511: }
1512:
1513: final void notifyModalityChange(int id, Dialog source) {
1514: ModalityEvent ev = new ModalityEvent(source, modalityListeners,
1515: id);
1516: ev.dispatch();
1517: }
1518:
1519: static class ModalityListenerList implements ModalityListener {
1520:
1521: Vector<ModalityListener> listeners = new Vector<ModalityListener>();
1522:
1523: void add(ModalityListener listener) {
1524: listeners.addElement(listener);
1525: }
1526:
1527: void remove(ModalityListener listener) {
1528: listeners.removeElement(listener);
1529: }
1530:
1531: public void modalityPushed(ModalityEvent ev) {
1532: Iterator<ModalityListener> it = listeners.iterator();
1533: while (it.hasNext()) {
1534: it.next().modalityPushed(ev);
1535: }
1536: }
1537:
1538: public void modalityPopped(ModalityEvent ev) {
1539: Iterator<ModalityListener> it = listeners.iterator();
1540: while (it.hasNext()) {
1541: it.next().modalityPopped(ev);
1542: }
1543: }
1544: } // end of class ModalityListenerList
1545:
1546: ///////////////////////////////////////////////////////////////////////////
1547: // End Plug-in code
1548: ///////////////////////////////////////////////////////////////////////////
1549:
1550: public static boolean isLightweightOrUnknown(Component comp) {
1551: if (comp.isLightweight()
1552: || !(getDefaultToolkit() instanceof SunToolkit)) {
1553: return true;
1554: }
1555: return !(comp instanceof Button || comp instanceof Canvas
1556: || comp instanceof Checkbox || comp instanceof Choice
1557: || comp instanceof Label
1558: || comp instanceof java.awt.List
1559: || comp instanceof Panel || comp instanceof Scrollbar
1560: || comp instanceof ScrollPane
1561: || comp instanceof TextArea
1562: || comp instanceof TextField || comp instanceof Window);
1563: }
1564:
1565: public static Method getMethod(final Class clz,
1566: final String methodName, final Class[] params) {
1567: Method res = null;
1568: try {
1569: res = AccessController
1570: .doPrivileged(new PrivilegedExceptionAction<Method>() {
1571: public Method run() throws Exception {
1572: Method m = clz.getDeclaredMethod(
1573: methodName, params);
1574: m.setAccessible(true);
1575: return m;
1576: }
1577: });
1578: } catch (PrivilegedActionException ex) {
1579: ex.printStackTrace();
1580: }
1581: return res;
1582: }
1583:
1584: public static class OperationTimedOut extends RuntimeException {
1585: public OperationTimedOut(String msg) {
1586: super (msg);
1587: }
1588:
1589: public OperationTimedOut() {
1590: }
1591: }
1592:
1593: public static class InfiniteLoop extends RuntimeException {
1594: }
1595:
1596: public static class IllegalThreadException extends RuntimeException {
1597: public IllegalThreadException(String msg) {
1598: super (msg);
1599: }
1600:
1601: public IllegalThreadException() {
1602: }
1603: }
1604:
1605: public static final int DEFAULT_WAIT_TIME = 10000;
1606: private static final int MAX_ITERS = 20;
1607: private static final int MIN_ITERS = 0;
1608: private static final int MINIMAL_EDELAY = 0;
1609:
1610: /**
1611: * Parameterless version of realsync which uses default timout (see DEFAUL_WAIT_TIME).
1612: */
1613: public void realSync() throws OperationTimedOut, InfiniteLoop {
1614: realSync(DEFAULT_WAIT_TIME);
1615: }
1616:
1617: /**
1618: * Forces toolkit to synchronize with the native windowing
1619: * sub-system, flushing all pending work and waiting for all the
1620: * events to be processed. This method guarantees that after
1621: * return no additional Java events will be generated, unless
1622: * cause by user. Obviously, the method cannot be used on the
1623: * event dispatch thread (EDT). In case it nevertheless gets
1624: * invoked on this thread, the method throws the
1625: * IllegalThreadException runtime exception.
1626: *
1627: * <p> This method allows to write tests without explicit timeouts
1628: * or wait for some event. Example:
1629: * <code>
1630: * Frame f = ...;
1631: * f.setVisible(true);
1632: * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1633: * </code>
1634: *
1635: * <p> After realSync, <code>f</code> will be completely visible
1636: * on the screen, its getLocationOnScreen will be returning the
1637: * right result and it will be the focus owner.
1638: *
1639: * <p> Another example:
1640: * <code>
1641: * b.requestFocus();
1642: * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
1643: * </code>
1644: *
1645: * <p> After realSync, <code>b</code> will be focus owner.
1646: *
1647: * <p> Notice that realSync isn't guaranteed to work if recurring
1648: * actions occur, such as if during processing of some event
1649: * another request which may generate some events occurs. By
1650: * default, sync tries to perform as much as {@value MAX_ITERS}
1651: * cycles of event processing, allowing for roughly {@value
1652: * MAX_ITERS} additional requests.
1653: *
1654: * <p> For example, requestFocus() generates native request, which
1655: * generates one or two Java focus events, which then generate a
1656: * serie of paint events, a serie of Java focus events, which then
1657: * generate a serie of paint events which then are processed -
1658: * three cycles, minimum.
1659: *
1660: * @param timeout the maximum time to wait in milliseconds, negative means "forever".
1661: */
1662: public void realSync(final long timeout) throws OperationTimedOut,
1663: InfiniteLoop {
1664: if (EventQueue.isDispatchThread()) {
1665: throw new IllegalThreadException(
1666: "The SunToolkit.realSync() method cannot be used on the event dispatch thread (EDT).");
1667: }
1668: int bigLoop = 0;
1669: do {
1670: // Let's do sync first
1671: sync();
1672:
1673: // During the wait process, when we were processing incoming
1674: // events, we could have made some new request, which can
1675: // generate new events. Example: MapNotify/XSetInputFocus.
1676: // Therefore, we dispatch them as long as there is something
1677: // to dispatch.
1678: int iters = 0;
1679: while (iters < MIN_ITERS) {
1680: syncNativeQueue(timeout);
1681: iters++;
1682: }
1683: while (syncNativeQueue(timeout) && iters < MAX_ITERS) {
1684: iters++;
1685: }
1686: if (iters >= MAX_ITERS) {
1687: throw new InfiniteLoop();
1688: }
1689:
1690: // native requests were dispatched by X/Window Manager or Windows
1691: // Moreover, we processed them all on Toolkit thread
1692: // Now wait while EDT processes them.
1693: //
1694: // During processing of some events (focus, for example),
1695: // some other events could have been generated. So, after
1696: // waitForIdle, we may end up with full EventQueue
1697: iters = 0;
1698: while (iters < MIN_ITERS) {
1699: waitForIdle(timeout);
1700: iters++;
1701: }
1702: while (waitForIdle(timeout) && iters < MAX_ITERS) {
1703: iters++;
1704: }
1705: if (iters >= MAX_ITERS) {
1706: throw new InfiniteLoop();
1707: }
1708:
1709: bigLoop++;
1710: // Again, for Java events, it was simple to check for new Java
1711: // events by checking event queue, but what if Java events
1712: // resulted in native requests? Therefor, check native events again.
1713: } while ((syncNativeQueue(timeout) || waitForIdle(timeout))
1714: && bigLoop < MAX_ITERS);
1715: }
1716:
1717: /**
1718: * Platform toolkits need to implement this method to perform the
1719: * sync of the native queue. The method should wait until native
1720: * requests are processed, all native events are processed and
1721: * corresponding Java events are generated. Should return
1722: * <code>true</code> if some events were processed,
1723: * <code>false</code> otherwise.
1724: */
1725: protected abstract boolean syncNativeQueue(final long timeout);
1726:
1727: private boolean eventDispatched = false;
1728: private boolean queueEmpty = false;
1729: private final Object waitLock = "Wait Lock";
1730:
1731: static Method eqNoEvents;
1732:
1733: private boolean isEQEmpty() {
1734: EventQueue queue = getSystemEventQueueImpl();
1735: synchronized (SunToolkit.class) {
1736: if (eqNoEvents == null) {
1737: eqNoEvents = getMethod(java.awt.EventQueue.class,
1738: "noEvents", null);
1739: }
1740: }
1741: try {
1742: return (Boolean) eqNoEvents.invoke(queue);
1743: } catch (Exception e) {
1744: e.printStackTrace();
1745: return false;
1746: }
1747: }
1748:
1749: /**
1750: * Waits for the Java event queue to empty. Ensures that all
1751: * events are processed (including paint events), and that if
1752: * recursive events were generated, they are also processed.
1753: * Should return <code>true</code> if more processing is
1754: * necessary, <code>false</code> otherwise.
1755: */
1756: protected final boolean waitForIdle(final long timeout) {
1757: flushPendingEvents();
1758: boolean queueWasEmpty = isEQEmpty();
1759: queueEmpty = false;
1760: eventDispatched = false;
1761: synchronized (waitLock) {
1762: postEvent(AppContext.getAppContext(), new PeerEvent(
1763: getSystemEventQueueImpl(), null,
1764: PeerEvent.LOW_PRIORITY_EVENT) {
1765: public void dispatch() {
1766: // Here we block EDT. It could have some
1767: // events, it should have dispatched them by
1768: // now. So native requests could have been
1769: // generated. First, dispatch them. Then,
1770: // flush Java events again.
1771: int iters = 0;
1772: while (iters < MIN_ITERS) {
1773: syncNativeQueue(timeout);
1774: iters++;
1775: }
1776: while (syncNativeQueue(timeout)
1777: && iters < MAX_ITERS) {
1778: iters++;
1779: }
1780: flushPendingEvents();
1781:
1782: synchronized (waitLock) {
1783: queueEmpty = isEQEmpty();
1784: eventDispatched = true;
1785: waitLock.notifyAll();
1786: }
1787: }
1788: });
1789: try {
1790: while (!eventDispatched) {
1791: waitLock.wait();
1792: }
1793: } catch (InterruptedException ie) {
1794: return false;
1795: }
1796: }
1797:
1798: try {
1799: Thread.sleep(MINIMAL_EDELAY);
1800: } catch (InterruptedException ie) {
1801: throw new RuntimeException("Interrupted");
1802: }
1803:
1804: flushPendingEvents();
1805:
1806: // Lock to force write-cache flush for queueEmpty.
1807: synchronized (waitLock) {
1808: return !(queueEmpty && isEQEmpty() && queueWasEmpty);
1809: }
1810: }
1811:
1812: /**
1813: * Grabs the mouse input for the given window. The window must be
1814: * visible. The window or its children do not receive any
1815: * additional mouse events besides those targeted to them. All
1816: * other events will be dispatched as before - to the respective
1817: * targets. This Window will receive UngrabEvent when automatic
1818: * ungrab is about to happen. The event can be listened to by
1819: * installing AWTEventListener with WINDOW_EVENT_MASK. See
1820: * UngrabEvent class for the list of conditions when ungrab is
1821: * about to happen.
1822: * @see UngrabEvent
1823: */
1824: public abstract void grab(Window w);
1825:
1826: /**
1827: * Forces ungrab. No event will be sent.
1828: */
1829: public abstract void ungrab(Window w);
1830:
1831: /**
1832: * Locates the splash screen library in a platform dependent way and closes
1833: * the splash screen. Should be invoked on first top-level frame display.
1834: * @see java.awt.SplashScreen
1835: * @since 1.6
1836: */
1837: public static native void closeSplashScreen();
1838:
1839: /* The following methods and variables are to support retrieving
1840: * desktop text anti-aliasing settings
1841: */
1842:
1843: /* Need an instance method because setDesktopProperty(..) is protected. */
1844: private void fireDesktopFontPropertyChanges() {
1845: setDesktopProperty(SunToolkit.DESKTOPFONTHINTS, SunToolkit
1846: .getDesktopFontHints());
1847: }
1848:
1849: private static boolean checkedSystemAAFontSettings;
1850: private static boolean useSystemAAFontSettings;
1851: private static boolean lastExtraCondition = true;
1852: private static RenderingHints desktopFontHints;
1853:
1854: /* Since Swing is the reason for this "extra condition" logic its
1855: * worth documenting it in some detail.
1856: * First, a goal is for Swing and applications to both retrieve and
1857: * use the same desktop property value so that there is complete
1858: * consistency between the settings used by JDK's Swing implementation
1859: * and 3rd party custom Swing components, custom L&Fs and any general
1860: * text rendering that wants to be consistent with these.
1861: * But by default on Solaris & Linux Swing will not use AA text over
1862: * remote X11 display (unless Xrender can be used which is TBD and may not
1863: * always be available anyway) as that is a noticeable performance hit.
1864: * So there needs to be a way to express that extra condition so that
1865: * it is seen by all clients of the desktop property API.
1866: * If this were the only condition it could be handled here as it would
1867: * be the same for any L&F and could reasonably be considered to be
1868: * a static behaviour of those systems.
1869: * But GTK currently has an additional test based on locale which is
1870: * not applied by Metal. So mixing GTK in a few locales with Metal
1871: * would mean the last one wins.
1872: * This could be stored per-app context which would work
1873: * for different applets, but wouldn't help for a single application
1874: * using GTK and some other L&F concurrently.
1875: * But it is expected this will be addressed within GTK and the font
1876: * system so is a temporary and somewhat unlikely harmless corner case.
1877: */
1878: public static void setAAFontSettingsCondition(boolean extraCondition) {
1879: if (extraCondition != lastExtraCondition) {
1880: lastExtraCondition = extraCondition;
1881: if (checkedSystemAAFontSettings) {
1882: /* Someone already asked for this info, under a different
1883: * condition.
1884: * We'll force re-evaluation instead of replicating the
1885: * logic, then notify any listeners of any change.
1886: */
1887: checkedSystemAAFontSettings = false;
1888: Toolkit tk = Toolkit.getDefaultToolkit();
1889: if (tk instanceof SunToolkit) {
1890: ((SunToolkit) tk).fireDesktopFontPropertyChanges();
1891: }
1892: }
1893: }
1894: }
1895:
1896: /* "false", "off", ""default" aren't explicitly tested, they
1897: * just fall through to produce a null return which all are equated to
1898: * "false".
1899: */
1900: private static RenderingHints getDesktopAAHintsByName(
1901: String hintname) {
1902: Object aaHint = null;
1903: hintname = hintname.toLowerCase(Locale.ENGLISH);
1904: if (hintname.equals("on")) {
1905: aaHint = VALUE_TEXT_ANTIALIAS_ON;
1906: } else if (hintname.equals("gasp")) {
1907: aaHint = VALUE_TEXT_ANTIALIAS_GASP;
1908: } else if (hintname.equals("lcd")
1909: || hintname.equals("lcd_hrgb")) {
1910: aaHint = VALUE_TEXT_ANTIALIAS_LCD_HRGB;
1911: } else if (hintname.equals("lcd_hbgr")) {
1912: aaHint = VALUE_TEXT_ANTIALIAS_LCD_HBGR;
1913: } else if (hintname.equals("lcd_vrgb")) {
1914: aaHint = VALUE_TEXT_ANTIALIAS_LCD_VRGB;
1915: } else if (hintname.equals("lcd_vbgr")) {
1916: aaHint = VALUE_TEXT_ANTIALIAS_LCD_VBGR;
1917: }
1918: if (aaHint != null) {
1919: RenderingHints map = new RenderingHints(null);
1920: map.put(KEY_TEXT_ANTIALIASING, aaHint);
1921: return map;
1922: } else {
1923: return null;
1924: }
1925: }
1926:
1927: /* This method determines whether to use the system font settings,
1928: * or ignore them if a L&F has specified they should be ignored, or
1929: * to override both of these with a system property specified value.
1930: * If the toolkit isn't a SunToolkit, (eg may be headless) then that
1931: * system property isn't applied as desktop properties are considered
1932: * to be inapplicable in that case. In that headless case although
1933: * this method will return "true" the toolkit will return a null map.
1934: */
1935: private static boolean useSystemAAFontSettings() {
1936: if (!checkedSystemAAFontSettings) {
1937: useSystemAAFontSettings = true; /* initially set this true */
1938: String systemAAFonts = null;
1939: Toolkit tk = Toolkit.getDefaultToolkit();
1940: if (tk instanceof SunToolkit) {
1941: systemAAFonts = (String) AccessController
1942: .doPrivileged(new GetPropertyAction(
1943: "awt.useSystemAAFontSettings"));
1944: }
1945: if (systemAAFonts != null) {
1946: useSystemAAFontSettings = Boolean
1947: .valueOf(systemAAFonts).booleanValue();
1948: /* If it is anything other than "true", then it may be
1949: * a hint name , or it may be "off, "default", etc.
1950: */
1951: if (!useSystemAAFontSettings) {
1952: desktopFontHints = getDesktopAAHintsByName(systemAAFonts);
1953: }
1954: }
1955: /* If its still true, apply the extra condition */
1956: if (useSystemAAFontSettings) {
1957: useSystemAAFontSettings = lastExtraCondition;
1958: }
1959: checkedSystemAAFontSettings = true;
1960: }
1961: return useSystemAAFontSettings;
1962: }
1963:
1964: /* A variable defined for the convenience of JDK code */
1965: public static final String DESKTOPFONTHINTS = "awt.font.desktophints";
1966:
1967: /* Overridden by subclasses to return platform/desktop specific values */
1968: protected RenderingHints getDesktopAAHints() {
1969: return null;
1970: }
1971:
1972: /* Subclass desktop property loading methods call this which
1973: * in turn calls the appropriate subclass implementation of
1974: * getDesktopAAHints() when system settings are being used.
1975: * Its public rather than protected because subclasses may delegate
1976: * to a helper class.
1977: */
1978: public static RenderingHints getDesktopFontHints() {
1979: if (useSystemAAFontSettings()) {
1980: Toolkit tk = Toolkit.getDefaultToolkit();
1981: if (tk instanceof SunToolkit) {
1982: Object map = ((SunToolkit) tk).getDesktopAAHints();
1983: return (RenderingHints) map;
1984: } else { /* Headless Toolkit */
1985: return null;
1986: }
1987: } else if (desktopFontHints != null) {
1988: /* cloning not necessary as the return value is cloned later, but
1989: * its harmless.
1990: */
1991: return (RenderingHints) (desktopFontHints.clone());
1992: } else {
1993: return null;
1994: }
1995: }
1996:
1997: public abstract boolean isDesktopSupported();
1998:
1999: /*
2000: * consumeNextKeyTyped() method is not currently used,
2001: * however Swing could use it in the future.
2002: */
2003: private static Method consumeNextKeyTypedMethod = null;
2004:
2005: public static synchronized void consumeNextKeyTyped(
2006: KeyEvent keyEvent) {
2007: if (consumeNextKeyTypedMethod == null) {
2008: consumeNextKeyTypedMethod = getMethod(
2009: DefaultKeyboardFocusManager.class,
2010: "consumeNextKeyTyped",
2011: new Class[] { KeyEvent.class });
2012: }
2013: try {
2014: consumeNextKeyTypedMethod.invoke(KeyboardFocusManager
2015: .getCurrentKeyboardFocusManager(), keyEvent);
2016: } catch (IllegalAccessException iae) {
2017: iae.printStackTrace();
2018: } catch (InvocationTargetException ite) {
2019: ite.printStackTrace();
2020: }
2021: }
2022:
2023: protected static void dumpPeers(final Logger aLog) {
2024: AWTAutoShutdown.getInstance().dumpPeers(aLog);
2025: }
2026:
2027: /**
2028: * Returns true if the native GTK libraries are available. The
2029: * default implementation returns false, but UNIXToolkit overrides this
2030: * method to provide a more specific answer.
2031: */
2032: public boolean isNativeGTKAvailable() {
2033: return false;
2034: }
2035: } // class SunToolkit
2036:
2037: /*
2038: * PostEventQueue is a Thread that runs in the same AppContext as the
2039: * Java EventQueue. It is a queue of AWTEvents to be posted to the
2040: * Java EventQueue. The toolkit Thread (AWT-Windows/AWT-Motif) posts
2041: * events to this queue, which then calls EventQueue.postEvent().
2042: *
2043: * We do this because EventQueue.postEvent() may be overridden by client
2044: * code, and we mustn't ever call client code from the toolkit thread.
2045: */
2046: class PostEventQueue {
2047: private EventQueueItem queueHead = null;
2048: private EventQueueItem queueTail = null;
2049: private final EventQueue eventQueue;
2050:
2051: PostEventQueue(EventQueue eq) {
2052: eventQueue = eq;
2053: }
2054:
2055: public boolean noEvents() {
2056: return queueHead == null;
2057: }
2058:
2059: /*
2060: * Continually post pending AWTEvents to the Java EventQueue.
2061: */
2062: public void flush() {
2063: if (queueHead != null) {
2064: EventQueueItem tempQueue;
2065: /*
2066: * We have to execute the loop inside the synchronized block
2067: * to ensure that the flush is completed before a new event
2068: * can be posted to this queue.
2069: */
2070: synchronized (this ) {
2071: tempQueue = queueHead;
2072: queueHead = queueTail = null;
2073: /*
2074: * If this PostEventQueue is flushed in parallel on two
2075: * different threads tempQueue will be null for one of them.
2076: */
2077: while (tempQueue != null) {
2078: eventQueue.postEvent(tempQueue.event);
2079: tempQueue = tempQueue.next;
2080: }
2081: }
2082: }
2083: }
2084:
2085: /*
2086: * Enqueue an AWTEvent to be posted to the Java EventQueue.
2087: */
2088: void postEvent(AWTEvent event) {
2089: EventQueueItem item = new EventQueueItem(event);
2090:
2091: synchronized (this ) {
2092: if (queueHead == null) {
2093: queueHead = queueTail = item;
2094: } else {
2095: queueTail.next = item;
2096: queueTail = item;
2097: }
2098: }
2099: SunToolkit.wakeupEventQueue(eventQueue,
2100: event.getSource() == AWTAutoShutdown.getInstance());
2101: }
2102: } // class PostEventQueue
2103:
2104: class EventQueueItem {
2105: AWTEvent event;
2106: EventQueueItem next;
2107:
2108: EventQueueItem(AWTEvent evt) {
2109: event = evt;
2110: }
2111: } // class EventQueueItem
|