mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-19 18:07:49 +00:00
Merge
This commit is contained in:
commit
734c8fdcc0
@ -277,10 +277,8 @@ public class Dialog extends Window {
|
||||
*/
|
||||
String title;
|
||||
|
||||
private transient volatile boolean keepBlockingEDT = false;
|
||||
private transient volatile boolean keepBlockingCT = false;
|
||||
|
||||
private transient ModalEventFilter modalFilter;
|
||||
private transient volatile SecondaryLoop secondaryLoop;
|
||||
|
||||
/*
|
||||
* Indicates that this dialog is being hidden. This flag is set to true at
|
||||
@ -1005,12 +1003,6 @@ public class Dialog extends Window {
|
||||
super.setVisible(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the app context on which event dispatch thread the dialog
|
||||
* is being shown. Initialized in show(), used in hideAndDisposeHandler()
|
||||
*/
|
||||
transient private AppContext showAppContext;
|
||||
|
||||
/**
|
||||
* Makes the {@code Dialog} visible. If the dialog and/or its owner
|
||||
* are not yet displayable, both are made displayable. The
|
||||
@ -1037,39 +1029,18 @@ public class Dialog extends Window {
|
||||
if (!isModal()) {
|
||||
conditionalShow(null, null);
|
||||
} else {
|
||||
// Set this variable before calling conditionalShow(). That
|
||||
// way, if the Dialog is hidden right after being shown, we
|
||||
// won't mistakenly block this thread.
|
||||
keepBlockingEDT = true;
|
||||
keepBlockingCT = true;
|
||||
|
||||
// Store the app context on which this dialog is being shown.
|
||||
// Event dispatch thread of this app context will be sleeping until
|
||||
// we wake it by any event from hideAndDisposeHandler().
|
||||
showAppContext = AppContext.getAppContext();
|
||||
AppContext showAppContext = AppContext.getAppContext();
|
||||
|
||||
AtomicLong time = new AtomicLong();
|
||||
Component predictedFocusOwner = null;
|
||||
try {
|
||||
predictedFocusOwner = getMostRecentFocusOwner();
|
||||
if (conditionalShow(predictedFocusOwner, time)) {
|
||||
// We have two mechanisms for blocking: 1. If we're on the
|
||||
// EventDispatchThread, start a new event pump. 2. If we're
|
||||
// on any other thread, call wait() on the treelock.
|
||||
|
||||
modalFilter = ModalEventFilter.createFilterForDialog(this);
|
||||
|
||||
final Runnable pumpEventsForFilter = new Runnable() {
|
||||
public void run() {
|
||||
EventDispatchThread dispatchThread =
|
||||
(EventDispatchThread)Thread.currentThread();
|
||||
dispatchThread.pumpEventsForFilter(new Conditional() {
|
||||
public boolean evaluate() {
|
||||
synchronized (getTreeLock()) {
|
||||
return keepBlockingEDT && windowClosingException == null;
|
||||
}
|
||||
}
|
||||
}, modalFilter);
|
||||
Conditional cond = new Conditional() {
|
||||
@Override
|
||||
public boolean evaluate() {
|
||||
return windowClosingException == null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1096,44 +1067,10 @@ public class Dialog extends Window {
|
||||
|
||||
modalityPushed();
|
||||
try {
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
/*
|
||||
* dispose SequencedEvent we are dispatching on current
|
||||
* AppContext, to prevent us from hang.
|
||||
*
|
||||
*/
|
||||
// BugId 4531693 (son@sparc.spb.su)
|
||||
SequencedEvent currentSequencedEvent = KeyboardFocusManager.
|
||||
getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
|
||||
if (currentSequencedEvent != null) {
|
||||
currentSequencedEvent.dispose();
|
||||
}
|
||||
|
||||
/*
|
||||
* Event processing is done inside doPrivileged block so that
|
||||
* it wouldn't matter even if user code is on the stack
|
||||
* Fix for BugId 6300270
|
||||
*/
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
pumpEventsForFilter.run();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
synchronized (getTreeLock()) {
|
||||
Toolkit.getEventQueue().postEvent(new PeerEvent(this,
|
||||
pumpEventsForFilter,
|
||||
PeerEvent.PRIORITY_EVENT));
|
||||
while (keepBlockingCT && windowClosingException == null) {
|
||||
try {
|
||||
getTreeLock().wait();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
secondaryLoop = eventQueue.createSecondaryLoop(cond, modalFilter, 5000);
|
||||
if (!secondaryLoop.enter()) {
|
||||
secondaryLoop = null;
|
||||
}
|
||||
} finally {
|
||||
modalityPopped();
|
||||
@ -1194,18 +1131,11 @@ public class Dialog extends Window {
|
||||
windowClosingException = null;
|
||||
}
|
||||
}
|
||||
final class WakingRunnable implements Runnable {
|
||||
public void run() {
|
||||
synchronized (getTreeLock()) {
|
||||
keepBlockingCT = false;
|
||||
getTreeLock().notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideAndDisposePreHandler() {
|
||||
isInHide = true;
|
||||
synchronized (getTreeLock()) {
|
||||
if (keepBlockingEDT) {
|
||||
if (secondaryLoop != null) {
|
||||
modalHide();
|
||||
// dialog can be shown and then disposed before its
|
||||
// modal filter is created
|
||||
@ -1217,20 +1147,9 @@ public class Dialog extends Window {
|
||||
}
|
||||
}
|
||||
private void hideAndDisposeHandler() {
|
||||
synchronized (getTreeLock()) {
|
||||
if (keepBlockingEDT) {
|
||||
keepBlockingEDT = false;
|
||||
PeerEvent wakingEvent = new PeerEvent(getToolkit(), new WakingRunnable(), PeerEvent.PRIORITY_EVENT);
|
||||
AppContext curAppContext = AppContext.getAppContext();
|
||||
if (showAppContext != curAppContext) {
|
||||
// Wake up event dispatch thread on which the dialog was
|
||||
// initially shown
|
||||
SunToolkit.postEvent(showAppContext, wakingEvent);
|
||||
showAppContext = null;
|
||||
} else {
|
||||
Toolkit.getEventQueue().postEvent(wakingEvent);
|
||||
}
|
||||
}
|
||||
if (secondaryLoop != null) {
|
||||
secondaryLoop.exit();
|
||||
secondaryLoop = null;
|
||||
}
|
||||
isInHide = false;
|
||||
}
|
||||
|
||||
@ -113,8 +113,7 @@ class EventDispatchThread extends Thread {
|
||||
pumpEventsForHierarchy(id, cond, null);
|
||||
}
|
||||
|
||||
void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent)
|
||||
{
|
||||
void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
|
||||
pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
|
||||
}
|
||||
|
||||
@ -124,6 +123,7 @@ class EventDispatchThread extends Thread {
|
||||
|
||||
void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
|
||||
addEventFilter(filter);
|
||||
doDispatch = true;
|
||||
while (doDispatch && cond.evaluate()) {
|
||||
if (isInterrupted() || !pumpOneEventForFilters(id)) {
|
||||
doDispatch = false;
|
||||
@ -133,6 +133,7 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
|
||||
void addEventFilter(EventFilter filter) {
|
||||
eventLog.finest("adding the event filter: " + filter);
|
||||
synchronized (eventFilters) {
|
||||
if (!eventFilters.contains(filter)) {
|
||||
if (filter instanceof ModalEventFilter) {
|
||||
@ -156,6 +157,7 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
|
||||
void removeEventFilter(EventFilter filter) {
|
||||
eventLog.finest("removing the event filter: " + filter);
|
||||
synchronized (eventFilters) {
|
||||
eventFilters.remove(filter);
|
||||
}
|
||||
|
||||
@ -883,6 +883,41 @@ public class EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code secondary loop} associated with this
|
||||
* event queue. Use the {@link SecondaryLoop#enter} and
|
||||
* {@link SecondaryLoop#exit} methods to start and stop the
|
||||
* event loop and dispatch the events from this queue.
|
||||
*
|
||||
* @return secondaryLoop A new secondary loop object, which can
|
||||
* be used to launch a new nested event
|
||||
* loop and dispatch events from this queue
|
||||
*
|
||||
* @see SecondaryLoop#enter
|
||||
* @see SecondaryLoop#exit
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public SecondaryLoop createSecondaryLoop() {
|
||||
return createSecondaryLoop(null, null, 0);
|
||||
}
|
||||
|
||||
SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
if (nextQueue != null) {
|
||||
// Forward the request to the top of EventQueue stack
|
||||
return nextQueue.createSecondaryLoop(cond, filter, interval);
|
||||
}
|
||||
if (dispatchThread == null) {
|
||||
initDispatchThread();
|
||||
}
|
||||
return new WaitDispatchSupport(dispatchThread, cond, filter, interval);
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the calling thread is
|
||||
* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
|
||||
|
||||
147
jdk/src/share/classes/java/awt/SecondaryLoop.java
Normal file
147
jdk/src/share/classes/java/awt/SecondaryLoop.java
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.awt;
|
||||
|
||||
/**
|
||||
* A helper interface to run the nested event loop.
|
||||
* <p>
|
||||
* Objects that implement this interface are created with the
|
||||
* {@link EventQueue#createSecondaryLoop} method. The interface
|
||||
* provides two methods, {@link enter} and {@link exit},
|
||||
* which can be used to start and stop the event loop.
|
||||
* <p>
|
||||
* When the {@link enter} method is called, the current
|
||||
* thread is blocked until the loop is terminated by the
|
||||
* {@link exit} method. Also, a new event loop is started
|
||||
* on the event dispatch thread, which may or may not be
|
||||
* the current thread. The loop can be terminated on any
|
||||
* thread by calling its {@link exit} method. After the
|
||||
* loop is terminated, the {@code SecondaryLoop} object can
|
||||
* be reused to run a new nested event loop.
|
||||
* <p>
|
||||
* A typical use case of applying this interface is AWT
|
||||
* and Swing modal dialogs. When a modal dialog is shown on
|
||||
* the event dispatch thread, it enters a new secondary loop.
|
||||
* Later, when the dialog is hidden or disposed, it exits
|
||||
* the loop, and the thread continues its execution.
|
||||
* <p>
|
||||
* The following example illustrates a simple use case of
|
||||
* secondary loops:
|
||||
*
|
||||
* <pre>
|
||||
* SecondaryLoop loop;
|
||||
*
|
||||
* JButton jButton = new JButton("Button");
|
||||
* jButton.addActionListener(new ActionListener() {
|
||||
* {@code @Override}
|
||||
* public void actionPerformed(ActionEvent e) {
|
||||
* Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
* EventQueue eq = tk.getSystemEventQueue();
|
||||
* loop = eq.createSecondaryLoop();
|
||||
*
|
||||
* // Spawn a new thread to do the work
|
||||
* Thread worker = new WorkerThread();
|
||||
* worker.start();
|
||||
*
|
||||
* // Enter the loop to block the current event
|
||||
* // handler, but leave UI responsive
|
||||
* if (!loop.enter()) {
|
||||
* // Report an error
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* class WorkerThread extends Thread {
|
||||
* {@code @Override}
|
||||
* public void run() {
|
||||
* // Perform calculations
|
||||
* doSomethingUseful();
|
||||
*
|
||||
* // Exit the loop
|
||||
* loop.exit();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see Dialog#show
|
||||
* @see EventQueue#createSecondaryLoop
|
||||
* @see Toolkit#getSystemEventQueue
|
||||
*
|
||||
* @author Anton Tarasov, Artem Ananiev
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface SecondaryLoop {
|
||||
|
||||
/**
|
||||
* Blocks the execution of the current thread and enters a new
|
||||
* secondary event loop on the event dispatch thread.
|
||||
* <p>
|
||||
* This method can be called by any thread including the event
|
||||
* dispatch thread. This thread will be blocked until the {@link
|
||||
* exit} method is called or the loop is terminated. A new
|
||||
* secondary loop will be created on the event dispatch thread
|
||||
* for dispatching events in either case.
|
||||
* <p>
|
||||
* This method can only start one new event loop at a time per
|
||||
* object. If a secondary event loop has already been started
|
||||
* by this object and is currently still running, this method
|
||||
* returns {@code false} to indicate that it was not successful
|
||||
* in starting a new event loop. Otherwise, this method blocks
|
||||
* the calling thread and later returns {@code true} when the
|
||||
* new event loop is terminated. At such time, this object can
|
||||
* again be used to start another new event loop.
|
||||
*
|
||||
* @return {@code true} after termination of the secondary loop,
|
||||
* if the secondary loop was started by this call,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public boolean enter();
|
||||
|
||||
/**
|
||||
* Unblocks the execution of the thread blocked by the {@link
|
||||
* enter} method and exits the secondary loop.
|
||||
* <p>
|
||||
* This method resumes the thread that called the {@link enter}
|
||||
* method and exits the secondary loop that was created when
|
||||
* the {@link enter} method was invoked.
|
||||
* <p>
|
||||
* Note that if any other secondary loop is started while this
|
||||
* loop is running, the blocked thread will not resume execution
|
||||
* until the nested loop is terminated.
|
||||
* <p>
|
||||
* If this secondary loop has not been started with the {@link
|
||||
* enter} method, or this secondary loop has already finished
|
||||
* with the {@link exit} method, this method returns {@code
|
||||
* false}, otherwise {@code true} is returned.
|
||||
*
|
||||
* @return {@code true} if this loop was previously started and
|
||||
* has not yet been finished with the {@link exit} method,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public boolean exit();
|
||||
|
||||
}
|
||||
302
jdk/src/share/classes/java/awt/WaitDispatchSupport.java
Normal file
302
jdk/src/share/classes/java/awt/WaitDispatchSupport.java
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.awt;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.AccessController;
|
||||
|
||||
import sun.awt.PeerEvent;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
/**
|
||||
* This utility class is used to suspend execution on a thread
|
||||
* while still allowing {@code EventDispatchThread} to dispatch events.
|
||||
* The API methods of the class are thread-safe.
|
||||
*
|
||||
* @author Anton Tarasov, Artem Ananiev
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
class WaitDispatchSupport implements SecondaryLoop {
|
||||
|
||||
private final static PlatformLogger log =
|
||||
PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
|
||||
|
||||
private EventDispatchThread dispatchThread;
|
||||
private EventFilter filter;
|
||||
|
||||
private volatile Conditional extCondition;
|
||||
private volatile Conditional condition;
|
||||
|
||||
private long interval;
|
||||
// Use a shared daemon timer to serve all the WaitDispatchSupports
|
||||
private static Timer timer;
|
||||
// When this WDS expires, we cancel the timer task leaving the
|
||||
// shared timer up and running
|
||||
private TimerTask timerTask;
|
||||
|
||||
private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
|
||||
private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
|
||||
|
||||
private static synchronized void initializeTimer() {
|
||||
if (timer == null) {
|
||||
timer = new Timer("AWT-WaitDispatchSupport-Timer", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code WaitDispatchSupport} instance to
|
||||
* serve the given event dispatch thread.
|
||||
*
|
||||
* @param dispatchThread An event dispatch thread that
|
||||
* should not stop dispatching events while waiting
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public WaitDispatchSupport(EventDispatchThread dispatchThread) {
|
||||
this(dispatchThread, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code WaitDispatchSupport} instance to
|
||||
* serve the given event dispatch thread.
|
||||
*
|
||||
* @param dispatchThread An event dispatch thread that
|
||||
* should not stop dispatching events while waiting
|
||||
* @param extCondition A conditional object used to determine
|
||||
* if the loop should be terminated
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public WaitDispatchSupport(EventDispatchThread dispatchThread,
|
||||
Conditional extCond)
|
||||
{
|
||||
if (dispatchThread == null) {
|
||||
throw new IllegalArgumentException("The dispatchThread can not be null");
|
||||
}
|
||||
|
||||
this.dispatchThread = dispatchThread;
|
||||
this.extCondition = extCond;
|
||||
this.condition = new Conditional() {
|
||||
@Override
|
||||
public boolean evaluate() {
|
||||
if (log.isLoggable(PlatformLogger.FINEST)) {
|
||||
log.finest("evaluate(): blockingEDT=" + keepBlockingEDT.get() +
|
||||
", blockingCT=" + keepBlockingCT.get());
|
||||
}
|
||||
boolean extEvaluate =
|
||||
(extCondition != null) ? extCondition.evaluate() : true;
|
||||
if (!keepBlockingEDT.get() || !extEvaluate) {
|
||||
if (timerTask != null) {
|
||||
timerTask.cancel();
|
||||
timerTask = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code WaitDispatchSupport} instance to
|
||||
* serve the given event dispatch thread.
|
||||
* <p>
|
||||
* The {@link EventFilter} is set on the {@code dispatchThread}
|
||||
* while waiting. The filter is removed on completion of the
|
||||
* waiting process.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @param dispatchThread An event dispatch thread that
|
||||
* should not stop dispatching events while waiting
|
||||
* @param filter {@code EventFilter} to be set
|
||||
* @param interval A time interval to wait for. Note that
|
||||
* when the waiting process takes place on EDT
|
||||
* there is no guarantee to stop it in the given time
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public WaitDispatchSupport(EventDispatchThread dispatchThread,
|
||||
Conditional extCondition,
|
||||
EventFilter filter, long interval)
|
||||
{
|
||||
this(dispatchThread, extCondition);
|
||||
this.filter = filter;
|
||||
if (interval < 0) {
|
||||
throw new IllegalArgumentException("The interval value must be >= 0");
|
||||
}
|
||||
this.interval = interval;
|
||||
if (interval != 0) {
|
||||
initializeTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean enter() {
|
||||
log.fine("enter(): blockingEDT=" + keepBlockingEDT.get() +
|
||||
", blockingCT=" + keepBlockingCT.get());
|
||||
|
||||
if (!keepBlockingEDT.compareAndSet(false, true)) {
|
||||
log.fine("The secondary loop is already running, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
final Runnable run = new Runnable() {
|
||||
public void run() {
|
||||
log.fine("Starting a new event pump");
|
||||
if (filter == null) {
|
||||
dispatchThread.pumpEvents(condition);
|
||||
} else {
|
||||
dispatchThread.pumpEventsForFilter(condition, filter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We have two mechanisms for blocking: if we're on the
|
||||
// dispatch thread, start a new event pump; if we're
|
||||
// on any other thread, call wait() on the treelock
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
if (currentThread == dispatchThread) {
|
||||
log.finest("On dispatch thread: " + dispatchThread);
|
||||
if (interval != 0) {
|
||||
log.finest("scheduling the timer for " + interval + " ms");
|
||||
timer.schedule(timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (keepBlockingEDT.compareAndSet(true, false)) {
|
||||
wakeupEDT();
|
||||
}
|
||||
}
|
||||
}, interval);
|
||||
}
|
||||
// Dispose SequencedEvent we are dispatching on the the current
|
||||
// AppContext, to prevent us from hang - see 4531693 for details
|
||||
SequencedEvent currentSE = KeyboardFocusManager.
|
||||
getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
|
||||
if (currentSE != null) {
|
||||
log.fine("Dispose current SequencedEvent: " + currentSE);
|
||||
currentSE.dispose();
|
||||
}
|
||||
// In case the exit() method is called before starting
|
||||
// new event pump it will post the waking event to EDT.
|
||||
// The event will be handled after the the new event pump
|
||||
// starts. Thus, the enter() method will not hang.
|
||||
//
|
||||
// Event pump should be privileged. See 6300270.
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
run.run();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.finest("On non-dispatch thread: " + currentThread);
|
||||
synchronized (getTreeLock()) {
|
||||
if (filter != null) {
|
||||
dispatchThread.addEventFilter(filter);
|
||||
}
|
||||
try {
|
||||
EventQueue eq = dispatchThread.getEventQueue();
|
||||
eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
|
||||
keepBlockingCT.set(true);
|
||||
if (interval > 0) {
|
||||
long currTime = System.currentTimeMillis();
|
||||
while (keepBlockingCT.get() &&
|
||||
((extCondition != null) ? extCondition.evaluate() : true) &&
|
||||
(currTime + interval > System.currentTimeMillis()))
|
||||
{
|
||||
getTreeLock().wait(interval);
|
||||
}
|
||||
} else {
|
||||
while (keepBlockingCT.get() &&
|
||||
((extCondition != null) ? extCondition.evaluate() : true))
|
||||
{
|
||||
getTreeLock().wait();
|
||||
}
|
||||
}
|
||||
log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
|
||||
} catch (InterruptedException e) {
|
||||
log.fine("Exception caught while waiting: " + e);
|
||||
} finally {
|
||||
if (filter != null) {
|
||||
dispatchThread.removeEventFilter(filter);
|
||||
}
|
||||
}
|
||||
// If the waiting process has been stopped because of the
|
||||
// time interval passed or an exception occurred, the state
|
||||
// should be changed
|
||||
keepBlockingEDT.set(false);
|
||||
keepBlockingCT.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public boolean exit() {
|
||||
log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
|
||||
", blockingCT=" + keepBlockingCT.get());
|
||||
if (keepBlockingEDT.compareAndSet(true, false)) {
|
||||
wakeupEDT();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private final static Object getTreeLock() {
|
||||
return Component.LOCK;
|
||||
}
|
||||
|
||||
private final Runnable wakingRunnable = new Runnable() {
|
||||
public void run() {
|
||||
log.fine("Wake up EDT");
|
||||
synchronized (getTreeLock()) {
|
||||
keepBlockingCT.set(false);
|
||||
getTreeLock().notifyAll();
|
||||
}
|
||||
log.fine("Wake up EDT done");
|
||||
}
|
||||
};
|
||||
|
||||
private void wakeupEDT() {
|
||||
log.finest("wakeupEDT(): EDT == " + dispatchThread);
|
||||
EventQueue eq = dispatchThread.getEventQueue();
|
||||
eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT));
|
||||
}
|
||||
}
|
||||
@ -794,6 +794,11 @@ BOOL AwtMenuItem::IsSeparator() {
|
||||
jobject jitem = GetTarget(env);
|
||||
jstring label =
|
||||
(jstring)(env)->GetObjectField(jitem, AwtMenuItem::labelID);
|
||||
if (label == NULL) {
|
||||
env->DeleteLocalRef(label);
|
||||
env->DeleteLocalRef(jitem);
|
||||
return FALSE; //separator must has '-' as label.
|
||||
}
|
||||
LPCWSTR labelW = JNU_GetStringPlatformChars(env, label, NULL);
|
||||
BOOL isSeparator = (labelW && (wcscmp(labelW, L"-") == 0));
|
||||
JNU_ReleaseStringPlatformChars(env, label, labelW);
|
||||
|
||||
@ -113,8 +113,6 @@ public:
|
||||
// Used to prevent untrusted code from synthesizing a WM_PASTE message
|
||||
// by posting a <CTRL>-V KeyEvent
|
||||
BOOL m_synthetic;
|
||||
virtual void EditSetSel(CHARRANGE &cr) = 0;
|
||||
virtual void EditGetSel(CHARRANGE &cr) = 0;
|
||||
virtual LONG EditGetCharFromPos(POINT& pt) = 0;
|
||||
|
||||
private:
|
||||
|
||||
@ -41,7 +41,9 @@ struct SetEchoCharStruct {
|
||||
* AwtTextField methods
|
||||
*/
|
||||
|
||||
AwtTextField::AwtTextField() {
|
||||
AwtTextField::AwtTextField()
|
||||
: m_initialRescrollFlag( true )
|
||||
{
|
||||
}
|
||||
|
||||
/* Create a new AwtTextField object and window. */
|
||||
@ -116,10 +118,6 @@ void AwtTextField::EditSetSel(CHARRANGE &cr) {
|
||||
SendMessage(EM_SETSEL, cr.cpMin, cr.cpMax);
|
||||
}
|
||||
|
||||
void AwtTextField::EditGetSel(CHARRANGE &cr) {
|
||||
SendMessage(EM_SETSEL, reinterpret_cast<WPARAM>(&cr.cpMin), reinterpret_cast<LPARAM>(&cr.cpMax));
|
||||
}
|
||||
|
||||
LONG AwtTextField::EditGetCharFromPos(POINT& pt) {
|
||||
return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)));
|
||||
}
|
||||
@ -153,11 +151,9 @@ AwtTextField::HandleEvent(MSG *msg, BOOL synthetic)
|
||||
* The workaround also allows us to implement synthetic focus mechanism.
|
||||
*/
|
||||
if (IsFocusingMouseMessage(msg)) {
|
||||
CHARRANGE cr;
|
||||
|
||||
LONG lCurPos = EditGetCharFromPos(msg->pt);
|
||||
|
||||
EditGetSel(cr);
|
||||
/*
|
||||
* NOTE: Plain EDIT control always clears selection on mouse
|
||||
* button press. We are clearing the current selection only if
|
||||
@ -174,6 +170,7 @@ AwtTextField::HandleEvent(MSG *msg, BOOL synthetic)
|
||||
SetStartSelectionPos(lCurPos);
|
||||
SetEndSelectionPos(lCurPos);
|
||||
}
|
||||
CHARRANGE cr;
|
||||
cr.cpMin = GetStartSelectionPos();
|
||||
cr.cpMax = GetEndSelectionPos();
|
||||
EditSetSel(cr);
|
||||
@ -310,6 +307,47 @@ ret:
|
||||
delete secs;
|
||||
}
|
||||
|
||||
void AwtTextField::Reshape(int x, int y, int w, int h)
|
||||
{
|
||||
AwtTextComponent::Reshape( x, y, w, h );
|
||||
|
||||
// Another option would be to call this
|
||||
// after WM_SIZE notification is handled
|
||||
initialRescroll();
|
||||
}
|
||||
|
||||
|
||||
// Windows' Edit control features:
|
||||
// (i) if text selection is set while control's width or height is 0,
|
||||
// text is scrolled oddly.
|
||||
// (ii) if control's size is changed, text seems never be automatically
|
||||
// rescrolled.
|
||||
//
|
||||
// This method is designed for the following scenario: AWT spawns Edit
|
||||
// control with 0x0 dimensions, then sets text selection, then resizes the
|
||||
// control (couple of times). This might cause text appear undesirably scrolled.
|
||||
// So we reset/set selection again to rescroll text. (see also CR 6480547)
|
||||
void AwtTextField::initialRescroll()
|
||||
{
|
||||
if( ! m_initialRescrollFlag ) {
|
||||
return;
|
||||
}
|
||||
|
||||
::RECT r;
|
||||
BOOL ok = ::GetClientRect( GetHWnd(), &r );
|
||||
if( ! ok || r.right==0 || r.bottom==0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialRescrollFlag = false;
|
||||
|
||||
DWORD start, end;
|
||||
SendMessage( EM_GETSEL, (WPARAM)&start, (LPARAM)&end );
|
||||
SendMessage( EM_SETSEL, (WPARAM)0, (LPARAM)0 );
|
||||
SendMessage( EM_SETSEL, (WPARAM)start, (LPARAM)end );
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* WTextFieldPeer native methods
|
||||
*/
|
||||
|
||||
@ -55,9 +55,14 @@ public:
|
||||
static void _SetEchoChar(void *param);
|
||||
|
||||
protected:
|
||||
void EditSetSel(CHARRANGE &cr);
|
||||
void EditGetSel(CHARRANGE &cr);
|
||||
LONG EditGetCharFromPos(POINT& pt);
|
||||
virtual void Reshape(int x, int y, int w, int h);
|
||||
|
||||
private:
|
||||
void EditSetSel(CHARRANGE &cr);
|
||||
void initialRescroll();
|
||||
|
||||
bool m_initialRescrollFlag;
|
||||
};
|
||||
|
||||
#endif /* AWT_TEXTFIELD_H */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -193,12 +193,17 @@ public:
|
||||
|
||||
// Execute on Toolkit only.
|
||||
INLINE static LRESULT SynthesizeWmActivate(BOOL doActivate, HWND targetHWnd, HWND oppositeHWnd) {
|
||||
if (::IsWindowVisible(targetHWnd)) {
|
||||
return ::SendMessage(targetHWnd, WM_ACTIVATE,
|
||||
MAKEWPARAM(doActivate ? WA_ACTIVE : WA_INACTIVE, FALSE),
|
||||
(LPARAM) oppositeHWnd);
|
||||
if (doActivate &&
|
||||
(!::IsWindowVisible(targetHWnd) || ::IsIconic(::GetAncestor(targetHWnd, GA_ROOT))))
|
||||
{
|
||||
// The activation is rejected if either:
|
||||
// - The toplevel is not visible
|
||||
// - The toplevel (or its embedder) is minimised
|
||||
return 1;
|
||||
}
|
||||
return 1; // if not processed
|
||||
return ::SendMessage(targetHWnd, WM_ACTIVATE,
|
||||
MAKEWPARAM(doActivate ? WA_ACTIVE : WA_INACTIVE, FALSE),
|
||||
(LPARAM) oppositeHWnd);
|
||||
}
|
||||
|
||||
void moveToDefaultLocation(); /* moves Window to X,Y specified by Window Manger */
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 6949936
|
||||
@author Artem Ananiev: area=eventqueue
|
||||
@run main/timeout=30 SecondaryLoopTest
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Unit test for java.awt.SecondaryLoop implementation
|
||||
*/
|
||||
public class SecondaryLoopTest {
|
||||
|
||||
private static volatile boolean loopStarted;
|
||||
private static volatile boolean doubleEntered;
|
||||
private static volatile boolean loopActive;
|
||||
private static volatile boolean eventDispatched;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
test(true, true);
|
||||
test(true, false);
|
||||
test(false, true);
|
||||
test(false, false);
|
||||
}
|
||||
|
||||
private static void test(final boolean enterEDT, final boolean exitEDT) throws Exception {
|
||||
System.out.println("Running test(" + enterEDT + ", " + exitEDT + ")");
|
||||
System.err.flush();
|
||||
loopStarted = true;
|
||||
Runnable enterRun = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
EventQueue eq = tk.getSystemEventQueue();
|
||||
final SecondaryLoop loop = eq.createSecondaryLoop();
|
||||
doubleEntered = false;
|
||||
eventDispatched = false;
|
||||
Runnable eventRun = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Let the loop enter
|
||||
sleep(1000);
|
||||
if (loop.enter()) {
|
||||
doubleEntered = true;
|
||||
}
|
||||
eventDispatched = true;
|
||||
}
|
||||
};
|
||||
EventQueue.invokeLater(eventRun);
|
||||
Runnable exitRun = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Let the loop enter and eventRun finish
|
||||
sleep(2000);
|
||||
if (doubleEntered) {
|
||||
// Hopefully, we get here if the loop is entered twice
|
||||
loop.exit();
|
||||
}
|
||||
loop.exit();
|
||||
}
|
||||
};
|
||||
if (exitEDT) {
|
||||
EventQueue.invokeLater(exitRun);
|
||||
} else {
|
||||
new Thread(exitRun).start();
|
||||
}
|
||||
if (!loop.enter()) {
|
||||
loopStarted = false;
|
||||
}
|
||||
loopActive = eventDispatched;
|
||||
}
|
||||
};
|
||||
if (enterEDT) {
|
||||
EventQueue.invokeAndWait(enterRun);
|
||||
} else {
|
||||
enterRun.run();
|
||||
}
|
||||
// Print all the flags before we fail with exception
|
||||
System.out.println(" loopStarted = " + loopStarted);
|
||||
System.out.println(" doubleEntered = " + doubleEntered);
|
||||
System.out.println(" loopActive = " + loopActive);
|
||||
System.out.flush();
|
||||
if (!loopStarted) {
|
||||
throw new RuntimeException("Test FAILED: the secondary loop is not started");
|
||||
}
|
||||
if (doubleEntered) {
|
||||
throw new RuntimeException("Test FAILED: the secondary loop is started twice");
|
||||
}
|
||||
if (!loopActive) {
|
||||
throw new RuntimeException("Test FAILED: the secondary loop exited immediately");
|
||||
}
|
||||
}
|
||||
|
||||
private static void sleep(long t) {
|
||||
try {
|
||||
Thread.sleep(t);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/* @test 1.5 98/07/23
|
||||
@bug 4064202 4253466
|
||||
@summary Test for Win32 NPE when MenuItem with null label added.
|
||||
@author fred.ecks
|
||||
@run main/othervm NullMenuLabelTest
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class NullMenuLabelTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Frame frame = new Frame("Test Frame");
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
MenuBar menuBar = new MenuBar();
|
||||
frame.setMenuBar(menuBar);
|
||||
Menu menu = new Menu(null);
|
||||
menuBar.add(menu);
|
||||
menu.add(new MenuItem(null));
|
||||
// If we got this far, the test succeeded
|
||||
frame.setVisible(false);
|
||||
frame.dispose();
|
||||
}
|
||||
|
||||
} // class NullMenuLabelTest
|
||||
@ -53,13 +53,14 @@ public class ScrollSelectionTest extends Applet
|
||||
frame.add(tf);
|
||||
tf.select(0, 20);
|
||||
|
||||
String[] instructions =
|
||||
{
|
||||
String[] instructions = {
|
||||
"INSTRUCTIONS:",
|
||||
"This is a test for a win32 specific problem",
|
||||
"If you see all the letters from 'a' to 'z' and",
|
||||
"letters from 'a' to 't' are selected then test passes"
|
||||
};
|
||||
"If you see all the letters from 'a' to 'z' and",
|
||||
"letters from 'a' to 't' are selected then test passes.",
|
||||
"You may have to activate the frame to see the selection"
|
||||
+ " highlighted (e.g. by clicking on frame's title)."
|
||||
};
|
||||
Sysout.createDialogWithInstructions( instructions );
|
||||
|
||||
}// init()
|
||||
|
||||
@ -114,6 +114,7 @@ public class SpuriousExitEnter_3 {
|
||||
checkEvents(frameAdapter, 1, 1);
|
||||
checkEvents(buttonAdapter, 0, 0);
|
||||
w.setVisible(false);
|
||||
Util.waitForIdle(r);
|
||||
}
|
||||
|
||||
public static void main(String []s)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user