001: /*
002: * @(#)SunToolkit.java 1.34 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.awt;
029:
030: import java.awt.*;
031: import java.awt.im.InputMethodHighlight;
032: import java.io.*;
033: import java.net.URL;
034: import java.util.Collections;
035: import java.util.Map;
036: import sun.awt.image.ByteArrayImageSource;
037: import sun.awt.image.FileImageSource;
038: import sun.awt.image.URLImageSource;
039: import sun.awt.im.InputMethod;
040: import sun.misc.SoftCache;
041:
042: public abstract class SunToolkit extends Toolkit {
043: // the system EventQueue
044: // no longer static - EventQueue accessed through AppContext now
045: //protected static EventQueue theEventQueue;
046:
047: /* The key to put()/get() the PostEventQueue into/from the AppContext.
048: */
049: private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";
050:
051: public SunToolkit() {
052: EventQueue theEventQueue;
053: String eqName = Toolkit.getProperty("AWT.EventQueueClass",
054: "java.awt.EventQueue");
055: try {
056: theEventQueue = (EventQueue) Class.forName(eqName)
057: .newInstance();
058: } catch (Exception e) {
059: System.err.println("Failed loading " + eqName + ": " + e);
060: theEventQueue = new EventQueue();
061: }
062: AppContext appContext = AppContext.getAppContext();
063: appContext.put(AppContext.EVENT_QUEUE_KEY, theEventQueue);
064: PostEventQueue postEventQueue = new PostEventQueue(
065: theEventQueue);
066: appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
067: }
068:
069: /*
070: * Create a new AppContext, along with its EventQueue, for a
071: * new ThreadGroup. Browser code, for example, would use this
072: * method to create an AppContext & EventQueue for an Applet.
073: */
074: public static AppContext createNewAppContext() {
075: return createNewAppContext(Thread.currentThread()
076: .getThreadGroup());
077: }
078:
079: /*
080: * Create a new AppContext with a given ThreadGroup
081: * Note that this method is directly called from AppContext itself only
082: */
083: static AppContext createNewAppContext(ThreadGroup threadGroup) {
084: EventQueue eventQueue;
085: String eqName = Toolkit.getProperty("AWT.EventQueueClass",
086: "java.awt.EventQueue");
087: try {
088: eventQueue = (EventQueue) Class.forName(eqName)
089: .newInstance();
090: } catch (Exception e) {
091: System.err.println("Failed loading " + eqName + ": " + e);
092: eventQueue = new EventQueue();
093: }
094: AppContext appContext = new AppContext(threadGroup);
095: appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
096: PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
097: appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
098: return appContext;
099: }
100:
101: // mapping of Components to AppContexts, WeakHashMap<Component,AppContext>
102: private static final Map appContextMap = Collections
103: .synchronizedMap(new IdentityWeakHashMap());
104:
105: /*
106: * Fetch the AppContext associated with the given target.
107: * This can be used to determine things like which EventQueue
108: * to use for posting events to a Component. If the target is
109: * null or the target can't be found, a null with be returned.
110: */
111: public static AppContext targetToAppContext(Object target) {
112: if (target != null && !GraphicsEnvironment.isHeadless()) {
113: return (AppContext) appContextMap.get(target);
114: }
115: return null;
116: }
117:
118: /*
119: * Insert a mapping from target to AppContext, for later retrieval
120: * via targetToAppContext() above.
121: */
122: public static void insertTargetMapping(Object target,
123: AppContext appContext) {
124: if (!GraphicsEnvironment.isHeadless()) {
125: appContextMap.put(target, appContext);
126: }
127: }
128:
129: protected EventQueue getSystemEventQueueImpl() {
130: // EventQueue now accessed through AppContext now
131: //return theEventQueue;
132: AppContext appContext = AppContext.getAppContext();
133: EventQueue theEventQueue = (EventQueue) appContext
134: .get(AppContext.EVENT_QUEUE_KEY);
135: return theEventQueue;
136: }
137:
138: /*
139: * Post an AWTEvent to the Java EventQueue, using the PostEventQueue
140: * to avoid possibly calling client code (EventQueueSubclass.postEvent())
141: * on the toolkit (AWT-Windows/AWT-Motif) thread.
142: */
143: public static void postEvent(AppContext appContext, AWTEvent event) {
144: PostEventQueue postEventQueue = (PostEventQueue) appContext
145: .get(POST_EVENT_QUEUE_KEY);
146: // 6235492, check for null just like in jdk
147: if (postEventQueue != null) {
148: postEventQueue.postEvent(event);
149: }
150: }
151:
152: public Dimension getScreenSize() {
153: return new Dimension(getScreenWidth(), getScreenHeight());
154: }
155:
156: /*
157: * Gets the default encoding used on the current platform
158: * to transfer text (character) data.
159: */
160: public abstract String getDefaultCharacterEncoding();
161:
162: protected abstract int getScreenWidth();
163:
164: protected abstract int getScreenHeight();
165:
166: static SoftCache imgCache = new SoftCache();
167:
168: static synchronized Image getImageFromHash(Toolkit tk, URL url) {
169: SecurityManager sm = System.getSecurityManager();
170: if (sm != null) {
171: try {
172: java.security.Permission perm = url.openConnection()
173: .getPermission();
174: if (perm != null) {
175: try {
176: sm.checkPermission(perm);
177: } catch (SecurityException se) {
178: // fallback to checkRead/checkConnect for pre 1.2
179: // security managers
180: if ((perm instanceof java.io.FilePermission)
181: && perm.getActions().indexOf("read") != -1) {
182: sm.checkRead(perm.getName());
183: } else if ((perm instanceof java.net.SocketPermission)
184: && perm.getActions().indexOf("connect") != -1) {
185: sm.checkConnect(url.getHost(), url
186: .getPort());
187: } else {
188: throw se;
189: }
190: }
191: }
192: } catch (java.io.IOException ioe) {
193: sm.checkConnect(url.getHost(), url.getPort());
194: }
195: }
196: Image img = (Image) imgCache.get(url);
197: if (img == null) {
198: try {
199: img = tk.createImage(new URLImageSource(url));
200: imgCache.put(url, img);
201: } catch (Exception e) {
202: }
203: }
204: return img;
205: }
206:
207: static synchronized Image getImageFromHash(Toolkit tk,
208: String filename) {
209: SecurityManager security = System.getSecurityManager();
210: if (security != null) {
211: security.checkRead(filename);
212: }
213: Image img = (Image) imgCache.get(filename);
214: if (img == null) {
215: try {
216: img = tk.createImage(new FileImageSource(filename));
217: imgCache.put(filename, img);
218: } catch (Exception e) {
219: }
220: }
221: return img;
222: }
223:
224: public Image getImage(String filename) {
225: return getImageFromHash(this , filename);
226: }
227:
228: public Image getImage(URL url) {
229: return getImageFromHash(this , url);
230: }
231:
232: public Image createImage(String filename) {
233: SecurityManager security = System.getSecurityManager();
234: if (security != null) {
235: security.checkRead(filename);
236: }
237: return createImage(new FileImageSource(filename));
238: }
239:
240: public Image createImage(URL url) {
241: SecurityManager sm = System.getSecurityManager();
242: if (sm != null) {
243: try {
244: java.security.Permission perm = url.openConnection()
245: .getPermission();
246: if (perm != null) {
247: try {
248: sm.checkPermission(perm);
249: } catch (SecurityException se) {
250: // fallback to checkRead/checkConnect for pre 1.2
251: // security managers
252: if ((perm instanceof java.io.FilePermission)
253: && perm.getActions().indexOf("read") != -1) {
254: sm.checkRead(perm.getName());
255: } else if ((perm instanceof java.net.SocketPermission)
256: && perm.getActions().indexOf("connect") != -1) {
257: sm.checkConnect(url.getHost(), url
258: .getPort());
259: } else {
260: throw se;
261: }
262: }
263: }
264: } catch (java.io.IOException ioe) {
265: sm.checkConnect(url.getHost(), url.getPort());
266: }
267: }
268: return createImage(new URLImageSource(url));
269: }
270:
271: public Image createImage(byte[] data, int offset, int length) {
272: return createImage(new ByteArrayImageSource(data, offset,
273: length));
274: }
275:
276: /**
277: * Returns whether enableInputMethods should be set to true for peered
278: * TextComponent instances on this platform. False by default.
279: */
280: public boolean enableInputMethodsForTextComponent() {
281: return false;
282: }
283:
284: /**
285: * Show the specified window in a multi-vm environment
286: */
287: public void activate(Window window) {
288: return;
289: }
290:
291: /**
292: * Hide the specified window in a multi-vm environment
293: */
294: public void deactivate(Window window) {
295: return;
296: }
297: }
298:
299: /*
300: * PostEventQueue is a Thread that runs in the same AppContext as the
301: * Java EventQueue. It is a queue of AWTEvents to be posted to the
302: * Java EventQueue. The toolkit Thread (AWT-Windows/AWT-Motif) posts
303: * events to this queue, which then calls EventQueue.postEvent().
304: *
305: * We do this because EventQueue.postEvent() may be overridden by client
306: * code, and we mustn't ever call client code from the toolkit thread.
307: */
308: class PostEventQueue extends Thread {
309: static private int threadNum = 0;
310: private EventQueueItem queueHead = null;
311: private EventQueueItem queueTail = null;
312: private boolean keepGoing = true;
313: private final EventQueue eventQueue;
314:
315: PostEventQueue(EventQueue eq) {
316: super ("SunToolkit.PostEventQueue-" + threadNum);
317: synchronized (PostEventQueue.class) {
318: threadNum++;
319: }
320: eventQueue = eq;
321: start();
322: }
323:
324: /*
325: * Continually post pending AWTEvents to the Java EventQueue.
326: */
327: public void run() {
328: while (keepGoing && !isInterrupted()) {
329: try {
330: EventQueueItem item;
331: synchronized (this ) {
332: while (keepGoing && (queueHead == null)) {
333: notifyAll();
334: wait();
335: }
336: if (!keepGoing)
337: break;
338: item = queueHead;
339: }
340: eventQueue.postEvent(item.event);
341: synchronized (this ) {
342: queueHead = queueHead.next;
343: if (queueHead == null)
344: queueTail = null;
345: }
346: } catch (InterruptedException e) {
347: keepGoing = false; // Exit gracefully when interrupted
348: synchronized (this ) {
349: notifyAll();
350: }
351: }
352: }
353: }
354:
355: /*
356: * Enqueue an AWTEvent to be posted to the Java EventQueue.
357: */
358: synchronized void postEvent(AWTEvent event) {
359: EventQueueItem item = new EventQueueItem(event);
360: if (queueHead == null) {
361: queueHead = queueTail = item;
362: notifyAll();
363: } else {
364: queueTail.next = item;
365: queueTail = item;
366: }
367: }
368:
369: /*
370: * Wait for all pending events to be processed before returning.
371: * If other events are posted before the queue empties, those
372: * will also be processed before this method returns.
373: */
374: void flush() {
375: if (Thread.currentThread() == this ) {
376: return; // Won't wait for itself
377: }
378: synchronized (this ) {
379: if (queueHead != null) {
380: try {
381: wait();
382: } catch (InterruptedException e) {
383: }
384: }
385: }
386: }
387:
388: /*
389: * Notifies this PostEventQueue to stop running.
390: */
391: synchronized void quitRunning() {
392: keepGoing = false;
393: notifyAll();
394: }
395: } // class PostEventQueue
396:
397: class EventQueueItem {
398: AWTEvent event;
399: EventQueueItem next;
400:
401: EventQueueItem(AWTEvent evt) {
402: event = evt;
403: }
404: } // class EventQueueItem
|