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