Merge
This commit is contained in:
commit
8baf254d15
@ -61,85 +61,43 @@ import sun.awt.EventQueueDelegate;
|
||||
* @since 1.1
|
||||
*/
|
||||
class EventDispatchThread extends Thread {
|
||||
|
||||
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
|
||||
|
||||
private EventQueue theQueue;
|
||||
private boolean doDispatch = true;
|
||||
private boolean threadDeathCaught = false;
|
||||
|
||||
private static final int ANY_EVENT = -1;
|
||||
|
||||
private Vector<EventFilter> eventFilters = new Vector<EventFilter>();
|
||||
// used in handleException
|
||||
private int modalFiltersCount = 0;
|
||||
|
||||
EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
|
||||
super(group, name);
|
||||
theQueue = queue;
|
||||
}
|
||||
|
||||
void stopDispatchingImpl(boolean wait) {
|
||||
// Note: We stop dispatching via a flag rather than using
|
||||
// Thread.interrupt() because we can't guarantee that the wait()
|
||||
// we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
|
||||
|
||||
StopDispatchEvent stopEvent = new StopDispatchEvent();
|
||||
|
||||
// wait for the dispatcher to complete
|
||||
if (Thread.currentThread() != this) {
|
||||
|
||||
// fix 4122683, 4128923
|
||||
// Post an empty event to ensure getNextEvent is unblocked
|
||||
//
|
||||
// We have to use postEventPrivate instead of postEvent because
|
||||
// EventQueue.pop calls EventDispatchThread.stopDispatching.
|
||||
// Calling SunToolkit.flushPendingEvents in this case could
|
||||
// lead to deadlock.
|
||||
theQueue.postEventPrivate(stopEvent);
|
||||
|
||||
if (wait) {
|
||||
try {
|
||||
join();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stopEvent.dispatch();
|
||||
}
|
||||
|
||||
theQueue.detachDispatchThread(this, false);
|
||||
setEventQueue(queue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called on EDT only, that's why no synchronization
|
||||
*/
|
||||
public void stopDispatching() {
|
||||
stopDispatchingImpl(true);
|
||||
}
|
||||
|
||||
public void stopDispatchingLater() {
|
||||
stopDispatchingImpl(false);
|
||||
}
|
||||
|
||||
class StopDispatchEvent extends AWTEvent implements ActiveEvent {
|
||||
/*
|
||||
* serialVersionUID
|
||||
*/
|
||||
static final long serialVersionUID = -3692158172100730735L;
|
||||
|
||||
public StopDispatchEvent() {
|
||||
super(EventDispatchThread.this,0);
|
||||
}
|
||||
|
||||
public void dispatch() {
|
||||
doDispatch = false;
|
||||
}
|
||||
doDispatch = false;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
pumpEvents(new Conditional() {
|
||||
public boolean evaluate() {
|
||||
return true;
|
||||
while (true) {
|
||||
try {
|
||||
pumpEvents(new Conditional() {
|
||||
public boolean evaluate() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
EventQueue eq = getEventQueue();
|
||||
if (eq.detachDispatchThread(this) || threadDeathCaught) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
theQueue.detachDispatchThread(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +148,6 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
}
|
||||
eventFilters.add(k, filter);
|
||||
modalFiltersCount++;
|
||||
} else {
|
||||
eventFilters.add(filter);
|
||||
}
|
||||
@ -200,28 +157,25 @@ class EventDispatchThread extends Thread {
|
||||
|
||||
void removeEventFilter(EventFilter filter) {
|
||||
synchronized (eventFilters) {
|
||||
if (eventFilters.contains(filter)) {
|
||||
if (filter instanceof ModalEventFilter) {
|
||||
modalFiltersCount--;
|
||||
}
|
||||
eventFilters.remove(filter);
|
||||
}
|
||||
eventFilters.remove(filter);
|
||||
}
|
||||
}
|
||||
|
||||
boolean pumpOneEventForFilters(int id) {
|
||||
AWTEvent event = null;
|
||||
boolean eventOK = false;
|
||||
try {
|
||||
AWTEvent event;
|
||||
boolean eventOK;
|
||||
EventQueueDelegate.Delegate delegate =
|
||||
EventQueueDelegate.getDelegate();
|
||||
EventQueue eq = null;
|
||||
EventQueueDelegate.Delegate delegate = null;
|
||||
do {
|
||||
// EventQueue may change during the dispatching
|
||||
eq = getEventQueue();
|
||||
delegate = EventQueueDelegate.getDelegate();
|
||||
|
||||
if (delegate != null && id == ANY_EVENT) {
|
||||
event = delegate.getNextEvent(theQueue);
|
||||
event = delegate.getNextEvent(eq);
|
||||
} else {
|
||||
event = (id == ANY_EVENT)
|
||||
? theQueue.getNextEvent()
|
||||
: theQueue.getNextEvent(id);
|
||||
event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
|
||||
}
|
||||
|
||||
eventOK = true;
|
||||
@ -252,13 +206,15 @@ class EventDispatchThread extends Thread {
|
||||
if (delegate != null) {
|
||||
handle = delegate.beforeDispatch(event);
|
||||
}
|
||||
theQueue.dispatchEvent(event);
|
||||
eq.dispatchEvent(event);
|
||||
if (delegate != null) {
|
||||
delegate.afterDispatch(event, handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (ThreadDeath death) {
|
||||
threadDeathCaught = true;
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -267,12 +223,10 @@ class EventDispatchThread extends Thread {
|
||||
// Threads in the AppContext
|
||||
|
||||
}
|
||||
// Can get and throw only unchecked exceptions
|
||||
catch (RuntimeException e) {
|
||||
processException(e);
|
||||
} catch (Error e) {
|
||||
catch (Throwable e) {
|
||||
processException(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -281,14 +235,14 @@ class EventDispatchThread extends Thread {
|
||||
eventLog.fine("Processing exception: " + e);
|
||||
}
|
||||
getUncaughtExceptionHandler().uncaughtException(this, e);
|
||||
// don't rethrow the exception to avoid EDT recreation
|
||||
}
|
||||
|
||||
boolean isDispatching(EventQueue eq) {
|
||||
return theQueue.equals(eq);
|
||||
public synchronized EventQueue getEventQueue() {
|
||||
return theQueue;
|
||||
}
|
||||
public synchronized void setEventQueue(EventQueue eq) {
|
||||
theQueue = eq;
|
||||
}
|
||||
|
||||
EventQueue getEventQueue() { return theQueue; }
|
||||
|
||||
private static class HierarchyEventFilter implements EventFilter {
|
||||
private Component modalComponent;
|
||||
|
@ -138,6 +138,15 @@ public class EventQueue {
|
||||
private final Lock pushPopLock;
|
||||
private final Condition pushPopCond;
|
||||
|
||||
/*
|
||||
* Dummy runnable to wake up EDT from getNextEvent() after
|
||||
push/pop is performed
|
||||
*/
|
||||
private final static Runnable dummyRunnable = new Runnable() {
|
||||
public void run() {
|
||||
}
|
||||
};
|
||||
|
||||
private EventDispatchThread dispatchThread;
|
||||
|
||||
private final ThreadGroup threadGroup =
|
||||
@ -219,22 +228,22 @@ public class EventQueue {
|
||||
* @param theEvent an instance of <code>java.awt.AWTEvent</code>,
|
||||
* or a subclass of it
|
||||
*/
|
||||
final void postEventPrivate(AWTEvent theEvent) {
|
||||
private final void postEventPrivate(AWTEvent theEvent) {
|
||||
theEvent.isPosted = true;
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
if (dispatchThread == null && nextQueue == null) {
|
||||
if (nextQueue != null) {
|
||||
// Forward the event to the top of EventQueue stack
|
||||
nextQueue.postEventPrivate(theEvent);
|
||||
return;
|
||||
}
|
||||
if (dispatchThread == null) {
|
||||
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
|
||||
return;
|
||||
} else {
|
||||
initDispatchThread();
|
||||
}
|
||||
}
|
||||
if (nextQueue != null) {
|
||||
// Forward event to top of EventQueue stack.
|
||||
nextQueue.postEventPrivate(theEvent);
|
||||
return;
|
||||
}
|
||||
postEvent(theEvent, getPriority(theEvent));
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
@ -242,29 +251,20 @@ public class EventQueue {
|
||||
}
|
||||
|
||||
private static int getPriority(AWTEvent theEvent) {
|
||||
if (theEvent instanceof PeerEvent &&
|
||||
(((PeerEvent)theEvent).getFlags() &
|
||||
PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0)
|
||||
{
|
||||
return ULTIMATE_PRIORITY;
|
||||
if (theEvent instanceof PeerEvent) {
|
||||
PeerEvent peerEvent = (PeerEvent)theEvent;
|
||||
if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
|
||||
return ULTIMATE_PRIORITY;
|
||||
}
|
||||
if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
|
||||
return HIGH_PRIORITY;
|
||||
}
|
||||
if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
|
||||
return LOW_PRIORITY;
|
||||
}
|
||||
}
|
||||
|
||||
if (theEvent instanceof PeerEvent &&
|
||||
(((PeerEvent)theEvent).getFlags() &
|
||||
PeerEvent.PRIORITY_EVENT) != 0)
|
||||
{
|
||||
return HIGH_PRIORITY;
|
||||
}
|
||||
|
||||
if (theEvent instanceof PeerEvent &&
|
||||
(((PeerEvent)theEvent).getFlags() &
|
||||
PeerEvent.LOW_PRIORITY_EVENT) != 0)
|
||||
{
|
||||
return LOW_PRIORITY;
|
||||
}
|
||||
|
||||
int id = theEvent.getID();
|
||||
if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
|
||||
if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
|
||||
return LOW_PRIORITY;
|
||||
}
|
||||
return NORM_PRIORITY;
|
||||
@ -501,16 +501,9 @@ public class EventQueue {
|
||||
SunToolkit.flushPendingEvents();
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
|
||||
if (queues[i].head != null) {
|
||||
EventQueueItem entry = queues[i].head;
|
||||
queues[i].head = entry.next;
|
||||
if (entry.next == null) {
|
||||
queues[i].tail = null;
|
||||
}
|
||||
uncacheEQItem(entry);
|
||||
return entry.event;
|
||||
}
|
||||
AWTEvent event = getNextEventPrivate();
|
||||
if (event != null) {
|
||||
return event;
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
|
||||
pushPopCond.await();
|
||||
@ -520,6 +513,24 @@ public class EventQueue {
|
||||
} while(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called under the lock. Doesn't call flushPendingEvents()
|
||||
*/
|
||||
AWTEvent getNextEventPrivate() throws InterruptedException {
|
||||
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
|
||||
if (queues[i].head != null) {
|
||||
EventQueueItem entry = queues[i].head;
|
||||
queues[i].head = entry.next;
|
||||
if (entry.next == null) {
|
||||
queues[i].tail = null;
|
||||
}
|
||||
uncacheEQItem(entry);
|
||||
return entry.event;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
AWTEvent getNextEvent(int id) throws InterruptedException {
|
||||
do {
|
||||
/*
|
||||
@ -659,7 +670,9 @@ public class EventQueue {
|
||||
dispatchThread.stopDispatching();
|
||||
}
|
||||
} else {
|
||||
System.err.println("unable to dispatch event: " + event);
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("Unable to dispatch event: " + event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -761,15 +774,23 @@ public class EventQueue {
|
||||
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventQueue toPush = this;
|
||||
while (toPush.nextQueue != null) {
|
||||
toPush = toPush.nextQueue;
|
||||
EventQueue topQueue = this;
|
||||
while (topQueue.nextQueue != null) {
|
||||
topQueue = topQueue.nextQueue;
|
||||
}
|
||||
|
||||
if ((topQueue.dispatchThread != null) &&
|
||||
(topQueue.dispatchThread.getEventQueue() == this))
|
||||
{
|
||||
newEventQueue.dispatchThread = topQueue.dispatchThread;
|
||||
topQueue.dispatchThread.setEventQueue(newEventQueue);
|
||||
}
|
||||
|
||||
// Transfer all events forward to new EventQueue.
|
||||
while (toPush.peekEvent() != null) {
|
||||
while (topQueue.peekEvent() != null) {
|
||||
try {
|
||||
newEventQueue.postEventPrivate(toPush.getNextEvent());
|
||||
// Use getNextEventPrivate() as it doesn't call flushPendingEvents()
|
||||
newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
|
||||
} catch (InterruptedException ie) {
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("Interrupted push", ie);
|
||||
@ -777,28 +798,21 @@ public class EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
newEventQueue.previousQueue = toPush;
|
||||
// Wake up EDT waiting in getNextEvent(), so it can
|
||||
// pick up a new EventQueue. Post the waking event before
|
||||
// topQueue.nextQueue is assigned, otherwise the event would
|
||||
// go newEventQueue
|
||||
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
|
||||
|
||||
/*
|
||||
* Stop the event dispatch thread associated with the currently
|
||||
* active event queue, so that after the new queue is pushed
|
||||
* on the top this event dispatch thread won't prevent AWT from
|
||||
* being automatically shut down.
|
||||
* Use stopDispatchingLater() to avoid deadlock: stopDispatching()
|
||||
* waits for the dispatch thread to exit, which in turn waits
|
||||
* for the lock in EQ.detachDispatchThread(), which is hold by
|
||||
* this method.
|
||||
*/
|
||||
if (toPush.dispatchThread != null) {
|
||||
toPush.dispatchThread.stopDispatchingLater();
|
||||
}
|
||||
|
||||
toPush.nextQueue = newEventQueue;
|
||||
newEventQueue.previousQueue = topQueue;
|
||||
topQueue.nextQueue = newEventQueue;
|
||||
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) {
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
|
||||
}
|
||||
|
||||
pushPopCond.signalAll();
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
@ -822,44 +836,51 @@ public class EventQueue {
|
||||
eventLog.fine("EventQueue.pop(" + this + ")");
|
||||
}
|
||||
|
||||
EventDispatchThread dt = null;
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventQueue toPop = this;
|
||||
while (toPop.nextQueue != null) {
|
||||
toPop = toPop.nextQueue;
|
||||
EventQueue topQueue = this;
|
||||
while (topQueue.nextQueue != null) {
|
||||
topQueue = topQueue.nextQueue;
|
||||
}
|
||||
EventQueue prev = toPop.previousQueue;
|
||||
if (prev == null) {
|
||||
EventQueue prevQueue = topQueue.previousQueue;
|
||||
if (prevQueue == null) {
|
||||
throw new EmptyStackException();
|
||||
}
|
||||
toPop.previousQueue = null;
|
||||
|
||||
topQueue.previousQueue = null;
|
||||
prevQueue.nextQueue = null;
|
||||
|
||||
// Transfer all events back to previous EventQueue.
|
||||
prev.nextQueue = null;
|
||||
while (toPop.peekEvent() != null) {
|
||||
while (topQueue.peekEvent() != null) {
|
||||
try {
|
||||
prev.postEventPrivate(toPop.getNextEvent());
|
||||
prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
|
||||
} catch (InterruptedException ie) {
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("Interrupted pop", ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, prev);
|
||||
|
||||
if ((topQueue.dispatchThread != null) &&
|
||||
(topQueue.dispatchThread.getEventQueue() == this))
|
||||
{
|
||||
prevQueue.dispatchThread = topQueue.dispatchThread;
|
||||
topQueue.dispatchThread.setEventQueue(prevQueue);
|
||||
}
|
||||
|
||||
dt = toPop.dispatchThread;
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
|
||||
}
|
||||
|
||||
// Wake up EDT waiting in getNextEvent(), so it can
|
||||
// pick up a new EventQueue
|
||||
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
|
||||
|
||||
pushPopCond.signalAll();
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
|
||||
if (dt != null) {
|
||||
dt.stopDispatching(); // Must be done outside synchronized
|
||||
// block to avoid possible deadlock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -907,9 +928,9 @@ public class EventQueue {
|
||||
try {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
|
||||
dispatchThread = (EventDispatchThread)
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
dispatchThread = AccessController.doPrivileged(
|
||||
new PrivilegedAction<EventDispatchThread>() {
|
||||
public EventDispatchThread run() {
|
||||
EventDispatchThread t =
|
||||
new EventDispatchThread(threadGroup,
|
||||
name,
|
||||
@ -919,7 +940,8 @@ public class EventQueue {
|
||||
t.setDaemon(false);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
|
||||
dispatchThread.start();
|
||||
}
|
||||
@ -928,7 +950,7 @@ public class EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
final void detachDispatchThread(EventDispatchThread edt, boolean restart) {
|
||||
final boolean detachDispatchThread(EventDispatchThread edt) {
|
||||
/*
|
||||
* This synchronized block is to secure that the event dispatch
|
||||
* thread won't die in the middle of posting a new event to the
|
||||
@ -939,26 +961,21 @@ public class EventQueue {
|
||||
*/
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventDispatchThread oldDispatchThread = dispatchThread;
|
||||
if (dispatchThread == edt) {
|
||||
dispatchThread = null;
|
||||
}
|
||||
if (restart) {
|
||||
if (edt == dispatchThread) {
|
||||
/*
|
||||
* Event dispatch thread dies in case of an uncaught exception.
|
||||
* A new event dispatch thread for this queue will be started
|
||||
* only if a new event is posted to it. In case if no more
|
||||
* events are posted after this thread died all events that
|
||||
* currently are in the queue will never be dispatched.
|
||||
* Don't detach the thread if any events are pending. Not
|
||||
* sure if it's a possible scenario, though.
|
||||
*
|
||||
* Fix for 4648733. Check both the associated java event
|
||||
* queue and the PostEventQueue.
|
||||
*/
|
||||
if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
|
||||
initDispatchThread();
|
||||
return false;
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread);
|
||||
dispatchThread = null;
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(edt);
|
||||
return true;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import sun.misc.SoftCache;
|
||||
@ -592,7 +593,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
}
|
||||
PostEventQueue postEventQueue =
|
||||
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
|
||||
if(postEventQueue != null) {
|
||||
if (postEventQueue != null) {
|
||||
postEventQueue.postEvent(event);
|
||||
}
|
||||
}
|
||||
@ -610,16 +611,29 @@ public abstract class SunToolkit extends Toolkit
|
||||
postEvent(targetToAppContext(e.getSource()), pe);
|
||||
}
|
||||
|
||||
private static final Lock flushLock = new ReentrantLock();
|
||||
private static boolean isFlushingPendingEvents = false;
|
||||
|
||||
/*
|
||||
* Flush any pending events which haven't been posted to the AWT
|
||||
* EventQueue yet.
|
||||
*/
|
||||
public static void flushPendingEvents() {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
PostEventQueue postEventQueue =
|
||||
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
|
||||
if(postEventQueue != null) {
|
||||
postEventQueue.flush();
|
||||
flushLock.lock();
|
||||
try {
|
||||
// Don't call flushPendingEvents() recursively
|
||||
if (!isFlushingPendingEvents) {
|
||||
isFlushingPendingEvents = true;
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
PostEventQueue postEventQueue =
|
||||
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
|
||||
if (postEventQueue != null) {
|
||||
postEventQueue.flush();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isFlushingPendingEvents = false;
|
||||
flushLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1930,6 +1944,25 @@ public abstract class SunToolkit extends Toolkit
|
||||
return (Window)comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the system property indicated by the specified key.
|
||||
*/
|
||||
public static String getSystemProperty(final String key) {
|
||||
return (String)AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
return System.getProperty(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean value of the system property indicated by the specified key.
|
||||
*/
|
||||
protected static Boolean getBooleanSystemProperty(String key) {
|
||||
return Boolean.valueOf(AccessController.
|
||||
doPrivileged(new GetBooleanAction(key)));
|
||||
}
|
||||
|
||||
private static Boolean sunAwtDisableMixing = null;
|
||||
|
||||
/**
|
||||
@ -1938,9 +1971,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
*/
|
||||
public synchronized static boolean getSunAwtDisableMixing() {
|
||||
if (sunAwtDisableMixing == null) {
|
||||
sunAwtDisableMixing = Boolean.valueOf(
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.awt.disableMixing")));
|
||||
sunAwtDisableMixing = getBooleanSystemProperty("sun.awt.disableMixing");
|
||||
}
|
||||
return sunAwtDisableMixing.booleanValue();
|
||||
}
|
||||
@ -2079,12 +2110,14 @@ class PostEventQueue {
|
||||
eventQueue = eq;
|
||||
}
|
||||
|
||||
public boolean noEvents() {
|
||||
public synchronized boolean noEvents() {
|
||||
return queueHead == null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Continually post pending AWTEvents to the Java EventQueue.
|
||||
* Continually post pending AWTEvents to the Java EventQueue. The method
|
||||
* is synchronized to ensure the flush is completed before a new event
|
||||
* can be posted to this queue.
|
||||
*/
|
||||
public synchronized void flush() {
|
||||
EventQueueItem tempQueue = queueHead;
|
||||
|
@ -1053,10 +1053,28 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
return peer;
|
||||
}
|
||||
|
||||
private static Boolean sunAwtDisableGtkFileDialogs = null;
|
||||
|
||||
/**
|
||||
* Returns the value of "sun.awt.disableGtkFileDialogs" property. Default
|
||||
* value is {@code false}.
|
||||
*/
|
||||
public synchronized static boolean getSunAwtDisableGtkFileDialogs() {
|
||||
if (sunAwtDisableGtkFileDialogs == null) {
|
||||
sunAwtDisableGtkFileDialogs =
|
||||
getBooleanSystemProperty("sun.awt.disableGtkFileDialogs");
|
||||
}
|
||||
return sunAwtDisableGtkFileDialogs.booleanValue();
|
||||
}
|
||||
|
||||
public FileDialogPeer createFileDialog(FileDialog target) {
|
||||
FileDialogPeer peer = null;
|
||||
// The current GtkFileChooser is available from GTK+ 2.4
|
||||
FileDialogPeer peer = checkGtkVersion(2, 4, 0) ? new GtkFileDialogPeer(
|
||||
target) : new XFileDialogPeer(target);
|
||||
if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(2, 4, 0)) {
|
||||
peer = new GtkFileDialogPeer(target);
|
||||
} else {
|
||||
peer = new XFileDialogPeer(target);
|
||||
}
|
||||
targetCreatedPeer(target, peer);
|
||||
return peer;
|
||||
}
|
||||
@ -1201,14 +1219,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
static String getSystemProperty(final String name) {
|
||||
return (String)AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
return System.getProperty(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public PrintJob getPrintJob(final Frame frame, final String doctitle,
|
||||
final Properties props) {
|
||||
|
||||
|
@ -778,8 +778,8 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
x, y,
|
||||
xbe.get_x_root(),
|
||||
xbe.get_y_root(),
|
||||
clickCount,false,MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
3,button==4 ? -1 : 1);
|
||||
1,false,MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
3,button==4 ? -1*clickCount : 1*clickCount);
|
||||
postEventToEventQueue(mwe);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,29 @@ static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gp
|
||||
filename);
|
||||
}
|
||||
|
||||
static void quit(gboolean isSignalHandler)
|
||||
{
|
||||
if (dialog != NULL)
|
||||
{
|
||||
// Callbacks from GTK signals are made within the GTK lock
|
||||
// So, within a signal handler there is no need to call
|
||||
// gdk_threads_enter() / fp_gdk_threads_leave()
|
||||
if (!isSignalHandler) {
|
||||
fp_gdk_threads_enter();
|
||||
}
|
||||
|
||||
fp_gtk_widget_hide (dialog);
|
||||
fp_gtk_widget_destroy (dialog);
|
||||
|
||||
fp_gtk_main_quit ();
|
||||
dialog = NULL;
|
||||
|
||||
if (!isSignalHandler) {
|
||||
fp_gdk_threads_leave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_X11_GtkFileDialogPeer
|
||||
* Method: quit
|
||||
@ -50,18 +73,7 @@ static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gp
|
||||
JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
|
||||
(JNIEnv * env, jobject jpeer)
|
||||
{
|
||||
if (dialog != NULL)
|
||||
{
|
||||
fp_gdk_threads_enter();
|
||||
|
||||
fp_gtk_widget_hide (dialog);
|
||||
fp_gtk_widget_destroy (dialog);
|
||||
|
||||
fp_gtk_main_quit ();
|
||||
dialog = NULL;
|
||||
|
||||
fp_gdk_threads_leave();
|
||||
}
|
||||
quit(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,7 +159,7 @@ static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj)
|
||||
jfilenames);
|
||||
fp_g_free(current_folder);
|
||||
|
||||
Java_sun_awt_X11_GtkFileDialogPeer_quit(NULL, NULL);
|
||||
quit(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code 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 code 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 in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 6304473 6727884
|
||||
|
@ -34,35 +34,40 @@
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.lang.Math;
|
||||
|
||||
import sun.awt.SunToolkit;
|
||||
|
||||
import test.java.awt.regtesthelpers.Util;
|
||||
|
||||
public class LoopRobustness {
|
||||
static int clicks = 0;
|
||||
|
||||
final static long TIMEOUT = 5000;
|
||||
final static Object LOCK = new Object();
|
||||
static volatile boolean notifyOccur = false;
|
||||
|
||||
public static void main(String [] args) {
|
||||
public static int clicks = 0;
|
||||
public static volatile boolean notifyOccured = false;
|
||||
public static volatile boolean otherExceptionsCaught = false;
|
||||
|
||||
public static void main(String [] args) throws Exception {
|
||||
ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
|
||||
|
||||
long at;
|
||||
//wait for a TIMEOUT giving a chance to a new Thread above to accomplish its stuff.
|
||||
synchronized (LoopRobustness.LOCK){
|
||||
synchronized (LoopRobustness.LOCK) {
|
||||
new Thread(new TestThreadGroup(mainThreadGroup, "TestGroup"), new Impl()).start();
|
||||
at = System.currentTimeMillis();
|
||||
try {
|
||||
while(!notifyOccur && System.currentTimeMillis() - at < TIMEOUT) {
|
||||
while (!notifyOccured && (System.currentTimeMillis() - at < TIMEOUT)) {
|
||||
LoopRobustness.LOCK.wait(1000);
|
||||
}
|
||||
} catch(InterruptedException e){
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Test interrupted.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if( !notifyOccur){
|
||||
if (!notifyOccured) {
|
||||
//notify doesn't occur after a reasonable time.
|
||||
throw new RuntimeException("Test failed. Second Thread didn't notify MainThread.");
|
||||
throw new RuntimeException("Test FAILED: second thread hasn't notified MainThread");
|
||||
}
|
||||
|
||||
//now wait for two clicks
|
||||
@ -75,7 +80,10 @@ public class LoopRobustness {
|
||||
}
|
||||
}
|
||||
if (clicks != 2) {
|
||||
throw new RuntimeException("robot should press button twice");
|
||||
throw new RuntimeException("Test FAILED: robot should press button twice");
|
||||
}
|
||||
if (otherExceptionsCaught) {
|
||||
throw new RuntimeException("Test FAILED: unexpected exceptions caught");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,18 +91,11 @@ public class LoopRobustness {
|
||||
class Impl implements Runnable{
|
||||
static Robot robot;
|
||||
public void run() {
|
||||
SunToolkit.createNewAppContext();
|
||||
|
||||
Button b = new Button("Press me to test the AWT-Event Queue thread");
|
||||
Frame lr = new Frame("ROBUST FRAME");
|
||||
/* Must load Toolkit on this thread only, rather then on Main.
|
||||
If load on Main (on the parent ThreadGroup of current ThreadGroup) then
|
||||
EDT will be created on Main thread and supplied with it's own exceptionHandler,
|
||||
which just throws an Exception and terminates current thread.
|
||||
The test implies that EDT is created on the child ThreadGroup (testThreadGroup)
|
||||
which is supplied with its own uncaughtException().
|
||||
*/
|
||||
Toolkit.getDefaultToolkit();
|
||||
lr.setBounds(100, 100, 300, 100);
|
||||
|
||||
b.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LoopRobustness.clicks++;
|
||||
@ -107,40 +108,46 @@ class Impl implements Runnable{
|
||||
|
||||
try {
|
||||
robot = new Robot();
|
||||
} catch(AWTException e){
|
||||
} catch (AWTException e) {
|
||||
throw new RuntimeException("Test interrupted.", e);
|
||||
}
|
||||
Util.waitForIdle(robot);
|
||||
|
||||
synchronized (LoopRobustness.LOCK){
|
||||
LoopRobustness.LOCK.notify();
|
||||
LoopRobustness.notifyOccur = true;
|
||||
LoopRobustness.notifyOccured = true;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while(i < 2){
|
||||
while (i < 2) {
|
||||
robot.mouseMove(b.getLocationOnScreen().x + b.getWidth()/2,
|
||||
b.getLocationOnScreen().y + b.getHeight()/2 );
|
||||
b.getLocationOnScreen().y + b.getHeight()/2);
|
||||
Util.waitForIdle(robot);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
// robot.delay(10);
|
||||
Util.waitForIdle(robot);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
Util.waitForIdle(robot);
|
||||
i++;
|
||||
robot.delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestThreadGroup extends ThreadGroup {
|
||||
TestThreadGroup(ThreadGroup threadGroup, String name){
|
||||
TestThreadGroup(ThreadGroup threadGroup, String name) {
|
||||
super(threadGroup, name);
|
||||
}
|
||||
|
||||
public void uncaughtException(Thread exitedThread, Throwable e) {
|
||||
e.printStackTrace();
|
||||
if ((e instanceof ExceptionInInitializerError) || (e instanceof
|
||||
NoClassDefFoundError)){
|
||||
throw new RuntimeException("Test failed: other Exceptions were thrown ", e);
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
System.out.println("Exception caught: " + e);
|
||||
e.printStackTrace(System.out);
|
||||
System.out.flush();
|
||||
if ((e instanceof ExceptionInInitializerError) ||
|
||||
(e instanceof NoClassDefFoundError))
|
||||
{
|
||||
// These two are expected
|
||||
return;
|
||||
}
|
||||
LoopRobustness.otherExceptionsCaught = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code 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 code 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 in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 6424157
|
||||
@author Artem Ananiev: area=eventqueue
|
||||
@run main PreserveDispatchThread
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
public class PreserveDispatchThread {
|
||||
|
||||
private static volatile Frame f;
|
||||
private static volatile Dialog d;
|
||||
|
||||
private static volatile boolean isEDT = true;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
f = new Frame("F");
|
||||
f.setSize(320, 340);
|
||||
f.setLocationRelativeTo(null);
|
||||
f.setVisible(true);
|
||||
|
||||
try {
|
||||
test1();
|
||||
if (!isEDT) {
|
||||
throw new RuntimeException("Test FAILED (test1): event dispatch thread is changed");
|
||||
}
|
||||
|
||||
test2();
|
||||
if (!isEDT) {
|
||||
throw new RuntimeException("Test FAILED (test2): event dispatch thread is changed");
|
||||
}
|
||||
|
||||
test3();
|
||||
if (!isEDT) {
|
||||
throw new RuntimeException("Test FAILED (test3): event dispatch thread is changed");
|
||||
}
|
||||
} finally {
|
||||
if (d != null) {
|
||||
d.dispose();
|
||||
}
|
||||
f.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that push/pop doesn't change the dispatch thread if
|
||||
* called on EDT.
|
||||
*/
|
||||
private static void test1() throws Exception {
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TestEventQueue teq = new TestEventQueue();
|
||||
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
try {
|
||||
seq.push(teq);
|
||||
d = new TestDialog();
|
||||
d.setVisible(true);
|
||||
checkEDT();
|
||||
} finally {
|
||||
teq.pop();
|
||||
}
|
||||
checkEDT();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that push/pop doesn't change the dispatch thread if
|
||||
* called on the main thread.
|
||||
*/
|
||||
private static void test2() throws Exception {
|
||||
TestEventQueue teq = new TestEventQueue();
|
||||
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
try {
|
||||
seq.push(teq);
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
checkEDT();
|
||||
d = new TestDialog();
|
||||
d.setVisible(true);
|
||||
checkEDT();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
teq.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object test3Lock = new Object();
|
||||
private static boolean test3Sync = false;
|
||||
|
||||
/*
|
||||
* A complex test: several nested invokeLater() are called and
|
||||
* in every runnable a check for EDT is performed. At the ent
|
||||
* of the test we wait for all the runnables to be processed
|
||||
* and the dialog is disposed; otherwise the last EDT check can
|
||||
* be later than this method returns and the whole test is passed.
|
||||
*/
|
||||
private static void test3() throws Exception {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
d = new Dialog(f, true);
|
||||
d.setSize(240, 180);
|
||||
d.setLocationRelativeTo(f);
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
d.setVisible(true);
|
||||
checkEDT();
|
||||
}
|
||||
});
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TestEventQueue teq = new TestEventQueue();
|
||||
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
try {
|
||||
seq.push(teq);
|
||||
checkEDT();
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
d.dispose();
|
||||
checkEDT();
|
||||
synchronized (test3Lock) {
|
||||
test3Sync = true;
|
||||
test3Lock.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
teq.pop();
|
||||
}
|
||||
checkEDT();
|
||||
}
|
||||
});
|
||||
checkEDT();
|
||||
}
|
||||
});
|
||||
synchronized (test3Lock) {
|
||||
while (!test3Sync) {
|
||||
try {
|
||||
test3Lock.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure all the nested invokeLater/invokeAndWait are processed
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void checkEDT() {
|
||||
isEDT = isEDT && EventQueue.isDispatchThread();
|
||||
}
|
||||
|
||||
private static class TestEventQueue extends EventQueue {
|
||||
public TestEventQueue() {
|
||||
super();
|
||||
}
|
||||
public void pop() {
|
||||
super.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestDialog extends Dialog {
|
||||
private volatile boolean dialogShown = false;
|
||||
private volatile boolean paintCalled = false;
|
||||
public TestDialog() {
|
||||
super(f, true);
|
||||
setSize(240, 180);
|
||||
setLocationRelativeTo(f);
|
||||
addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
if (paintCalled) {
|
||||
dispose();
|
||||
}
|
||||
dialogShown = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
if (dialogShown) {
|
||||
dispose();
|
||||
}
|
||||
paintCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -43,6 +43,7 @@ public class PushPopTest {
|
||||
Runnable dummy = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy is here.");
|
||||
System.err.flush();
|
||||
}
|
||||
};
|
||||
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
@ -58,10 +59,11 @@ public class PushPopTest {
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy from SunToolkit");
|
||||
System.err.flush();
|
||||
}
|
||||
};
|
||||
InvocationEvent ie = new InvocationEvent(eq2, runnable, null, false);
|
||||
System.err.println(ie);
|
||||
// System.err.println(ie);
|
||||
SunToolkit.postEvent(SunToolkit.targetToAppContext(frame), ie);
|
||||
eq1.pop();
|
||||
frame.dispose();
|
||||
@ -70,14 +72,14 @@ public class PushPopTest {
|
||||
|
||||
class MyEventQueue1 extends EventQueue {
|
||||
|
||||
public void pop() throws EmptyStackException {
|
||||
public void pop() {
|
||||
super.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class MyEventQueue2 extends EventQueue {
|
||||
|
||||
protected void pop() throws EmptyStackException {
|
||||
protected void pop() {
|
||||
System.err.println("pop2()");
|
||||
Thread.dumpStack();
|
||||
try {
|
||||
@ -85,7 +87,8 @@ class MyEventQueue2 extends EventQueue {
|
||||
public void run() {
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy from here");
|
||||
System.err.println("Dummy from pop");
|
||||
System.err.flush();
|
||||
}
|
||||
};
|
||||
InvocationEvent ie = new InvocationEvent(MyEventQueue2.this, runnable, null, false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user