/*
* @(#)SunToolkit.java 1.34 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package sun.awt;
import java.awt.*;
import java.awt.im.InputMethodHighlight;
import java.io.*;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import sun.awt.image.ByteArrayImageSource;
import sun.awt.image.FileImageSource;
import sun.awt.image.URLImageSource;
import sun.awt.im.InputMethod;
import sun.misc.SoftCache;
public abstract class SunToolkit extends Toolkit {
// the system EventQueue
// no longer static - EventQueue accessed through AppContext now
//protected static EventQueue theEventQueue;
/* The key to put()/get() the PostEventQueue into/from the AppContext.
*/
private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";
public SunToolkit() {
EventQueue theEventQueue;
String eqName = Toolkit.getProperty("AWT.EventQueueClass",
"java.awt.EventQueue");
try {
theEventQueue = (EventQueue) Class.forName(eqName).newInstance();
} catch (Exception e) {
System.err.println("Failed loading " + eqName + ": " + e);
theEventQueue = new EventQueue();
}
AppContext appContext = AppContext.getAppContext();
appContext.put(AppContext.EVENT_QUEUE_KEY, theEventQueue);
PostEventQueue postEventQueue = new PostEventQueue(theEventQueue);
appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
}
/*
* Create a new AppContext, along with its EventQueue, for a
* new ThreadGroup. Browser code, for example, would use this
* method to create an AppContext & EventQueue for an Applet.
*/
public static AppContext createNewAppContext() {
return createNewAppContext(Thread.currentThread().getThreadGroup());
}
/*
* Create a new AppContext with a given ThreadGroup
* Note that this method is directly called from AppContext itself only
*/
static AppContext createNewAppContext(ThreadGroup threadGroup) {
EventQueue eventQueue;
String eqName = Toolkit.getProperty("AWT.EventQueueClass",
"java.awt.EventQueue");
try {
eventQueue = (EventQueue) Class.forName(eqName).newInstance();
} catch (Exception e) {
System.err.println("Failed loading " + eqName + ": " + e);
eventQueue = new EventQueue();
}
AppContext appContext = new AppContext(threadGroup);
appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue);
PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
return appContext;
}
// mapping of Components to AppContexts, WeakHashMap<Component,AppContext>
private static final Map appContextMap =
Collections.synchronizedMap(new IdentityWeakHashMap());
/*
* Fetch the AppContext associated with the given target.
* This can be used to determine things like which EventQueue
* to use for posting events to a Component. If the target is
* null or the target can't be found, a null with be returned.
*/
public static AppContext targetToAppContext(Object target) {
if (target != null && !GraphicsEnvironment.isHeadless()) {
return (AppContext) appContextMap.get(target);
}
return null;
}
/*
* Insert a mapping from target to AppContext, for later retrieval
* via targetToAppContext() above.
*/
public static void insertTargetMapping(Object target, AppContext appContext) {
if (!GraphicsEnvironment.isHeadless()) {
appContextMap.put(target, appContext);
}
}
protected EventQueue getSystemEventQueueImpl() {
// EventQueue now accessed through AppContext now
//return theEventQueue;
AppContext appContext = AppContext.getAppContext();
EventQueue theEventQueue =
(EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY);
return theEventQueue;
}
/*
* Post an AWTEvent to the Java EventQueue, using the PostEventQueue
* to avoid possibly calling client code (EventQueueSubclass.postEvent())
* on the toolkit (AWT-Windows/AWT-Motif) thread.
*/
public static void postEvent(AppContext appContext, AWTEvent event) {
PostEventQueue postEventQueue =
(PostEventQueue) appContext.get(POST_EVENT_QUEUE_KEY);
// 6235492, check for null just like in jdk
if (postEventQueue != null) {
postEventQueue.postEvent(event);
}
}
public Dimension getScreenSize() {
return new Dimension(getScreenWidth(), getScreenHeight());
}
/*
* Gets the default encoding used on the current platform
* to transfer text (character) data.
*/
public abstract String getDefaultCharacterEncoding();
protected abstract int getScreenWidth();
protected abstract int getScreenHeight();
static SoftCache imgCache = new SoftCache();
static synchronized Image getImageFromHash(Toolkit tk, URL url) {
// security check is done inside of getImageFromHash(tk, url.getFile());
if (url.getProtocol().equals("file")) {
return getImageFromHash(tk, url.getFile());
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
java.security.Permission perm =
url.openConnection().getPermission();
if (perm != null) {
try {
sm.checkPermission(perm);
} catch (SecurityException se) {
// fallback to checkRead/checkConnect for pre 1.2
// security managers
if ((perm instanceof java.io.FilePermission) &&
perm.getActions().indexOf("read") != -1) {
sm.checkRead(perm.getName());
} else if ((perm instanceof
java.net.SocketPermission) &&
perm.getActions().indexOf("connect") != -1) {
sm.checkConnect(url.getHost(), url.getPort());
} else {
throw se;
}
}
}
} catch (java.io.IOException ioe) {
sm.checkConnect(url.getHost(), url.getPort());
}
}
Image img = (Image)imgCache.get(url);
if (img == null) {
try {
img = tk.createImage(new URLImageSource(url));
imgCache.put(url, img);
} catch (Exception e) {
}
}
return img;
}
static synchronized Image getImageFromHash(Toolkit tk,
String filename) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(filename);
}
Image img = (Image)imgCache.get(filename);
if (img == null) {
try {
img = tk.createImage(new FileImageSource(filename));
imgCache.put(filename, img);
} catch (Exception e) {
}
}
return img;
}
public Image getImage(String filename) {
return getImageFromHash(this, filename);
}
public Image getImage(URL url) {
return getImageFromHash(this, url);
}
public Image createImage(String filename) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(filename);
}
return createImage(new FileImageSource(filename));
}
public Image createImage(URL url) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
java.security.Permission perm =
url.openConnection().getPermission();
if (perm != null) {
try {
sm.checkPermission(perm);
} catch (SecurityException se) {
// fallback to checkRead/checkConnect for pre 1.2
// security managers
if ((perm instanceof java.io.FilePermission) &&
perm.getActions().indexOf("read") != -1) {
sm.checkRead(perm.getName());
} else if ((perm instanceof
java.net.SocketPermission) &&
perm.getActions().indexOf("connect") != -1) {
sm.checkConnect(url.getHost(), url.getPort());
} else {
throw se;
}
}
}
} catch (java.io.IOException ioe) {
sm.checkConnect(url.getHost(), url.getPort());
}
}
return createImage(new URLImageSource(url));
}
public Image createImage(byte[] data, int offset, int length) {
return createImage(new ByteArrayImageSource(data, offset, length));
}
/**
* Returns whether enableInputMethods should be set to true for peered
* TextComponent instances on this platform. False by default.
*/
public boolean enableInputMethodsForTextComponent() {
return false;
}
/**
* Show the specified window in a multi-vm environment
*/
public void activate(Window window) {
return;
}
/**
* Hide the specified window in a multi-vm environment
*/
public void deactivate(Window window) {
return;
}
}
/*
* PostEventQueue is a Thread that runs in the same AppContext as the
* Java EventQueue. It is a queue of AWTEvents to be posted to the
* Java EventQueue. The toolkit Thread (AWT-Windows/AWT-Motif) posts
* events to this queue, which then calls EventQueue.postEvent().
*
* We do this because EventQueue.postEvent() may be overridden by client
* code, and we mustn't ever call client code from the toolkit thread.
*/
class PostEventQueue extends Thread {
static private int threadNum = 0;
private EventQueueItem queueHead = null;
private EventQueueItem queueTail = null;
private boolean keepGoing = true;
private final EventQueue eventQueue;
PostEventQueue(EventQueue eq) {
super("SunToolkit.PostEventQueue-" + threadNum);
synchronized (PostEventQueue.class) {
threadNum++;
}
eventQueue = eq;
start();
}
/*
* Continually post pending AWTEvents to the Java EventQueue.
*/
public void run() {
while (keepGoing && !isInterrupted()) {
try {
EventQueueItem item;
synchronized(this) {
while (keepGoing && (queueHead == null)) {
notifyAll();
wait();
}
if (!keepGoing)
break;
item = queueHead;
}
eventQueue.postEvent(item.event);
synchronized(this) {
queueHead = queueHead.next;
if (queueHead == null)
queueTail = null;
}
} catch (InterruptedException e) {
keepGoing = false; // Exit gracefully when interrupted
synchronized(this) {
notifyAll();
}
}
}
}
/*
* Enqueue an AWTEvent to be posted to the Java EventQueue.
*/
synchronized void postEvent(AWTEvent event) {
EventQueueItem item = new EventQueueItem(event);
if (queueHead == null) {
queueHead = queueTail = item;
notifyAll();
} else {
queueTail.next = item;
queueTail = item;
}
}
/*
* Wait for all pending events to be processed before returning.
* If other events are posted before the queue empties, those
* will also be processed before this method returns.
*/
void flush() {
if (Thread.currentThread() == this) {
return; // Won't wait for itself
}
synchronized (this) {
if (queueHead != null) {
try {
wait();
} catch (InterruptedException e) {}
}
}
}
/*
* Notifies this PostEventQueue to stop running.
*/
synchronized void quitRunning() {
keepGoing = false;
notifyAll();
}
} // class PostEventQueue
class EventQueueItem {
AWTEvent event;
EventQueueItem next;
EventQueueItem(AWTEvent evt) {
event = evt;
}
} // class EventQueueItem