--- a/jdk/src/share/classes/java/awt/Dialog.java Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/share/classes/java/awt/Dialog.java Thu Sep 16 11:16:02 2010 -0700
@@ -277,10 +277,8 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
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;
}
--- a/jdk/src/share/classes/java/awt/EventDispatchThread.java Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java Thu Sep 16 11:16:02 2010 -0700
@@ -113,8 +113,7 @@
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 @@
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 @@
}
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 @@
}
void removeEventFilter(EventFilter filter) {
+ eventLog.finest("removing the event filter: " + filter);
synchronized (eventFilters) {
eventFilters.remove(filter);
}
--- a/jdk/src/share/classes/java/awt/EventQueue.java Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/share/classes/java/awt/EventQueue.java Thu Sep 16 11:16:02 2010 -0700
@@ -884,6 +884,41 @@
}
/**
+ * 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
* dispatch thread. Use this method to ensure that a particular
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/SecondaryLoop.java Thu Sep 16 11:16:02 2010 -0700
@@ -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();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/WaitDispatchSupport.java Thu Sep 16 11:16:02 2010 -0700
@@ -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));
+ }
+}
--- a/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp Thu Sep 16 11:16:02 2010 -0700
@@ -794,6 +794,11 @@
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);
--- a/jdk/src/windows/native/sun/windows/awt_TextComponent.h Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_TextComponent.h Thu Sep 16 11:16:02 2010 -0700
@@ -113,8 +113,6 @@
// 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:
--- a/jdk/src/windows/native/sun/windows/awt_TextField.cpp Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_TextField.cpp Thu Sep 16 11:16:02 2010 -0700
@@ -41,7 +41,9 @@
* AwtTextField methods
*/
-AwtTextField::AwtTextField() {
+AwtTextField::AwtTextField()
+ : m_initialRescrollFlag( true )
+{
}
/* Create a new AwtTextField object and window. */
@@ -116,10 +118,6 @@
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 @@
* 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 @@
SetStartSelectionPos(lCurPos);
SetEndSelectionPos(lCurPos);
}
+ CHARRANGE cr;
cr.cpMin = GetStartSelectionPos();
cr.cpMax = GetEndSelectionPos();
EditSetSel(cr);
@@ -310,6 +307,47 @@
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
*/
--- a/jdk/src/windows/native/sun/windows/awt_TextField.h Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_TextField.h Thu Sep 16 11:16:02 2010 -0700
@@ -55,9 +55,14 @@
static void _SetEchoChar(void *param);
protected:
+ LONG EditGetCharFromPos(POINT& pt);
+ virtual void Reshape(int x, int y, int w, int h);
+
+private:
void EditSetSel(CHARRANGE &cr);
- void EditGetSel(CHARRANGE &cr);
- LONG EditGetCharFromPos(POINT& pt);
+ void initialRescroll();
+
+ bool m_initialRescrollFlag;
};
#endif /* AWT_TEXTFIELD_H */
--- a/jdk/src/windows/native/sun/windows/awt_Window.h Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_Window.h Thu Sep 16 11:16:02 2010 -0700
@@ -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 @@
// 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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/EventQueue/SecondaryLoopTest/SecondaryLoopTest.java Thu Sep 16 11:16:02 2010 -0700
@@ -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);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Menu/NullMenuLabelTest/NullMenuLabelTest.java Thu Sep 16 11:16:02 2010 -0700
@@ -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
--- a/jdk/test/java/awt/TextField/ScrollSelectionTest/ScrollSelectionTest.java Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/test/java/awt/TextField/ScrollSelectionTest/ScrollSelectionTest.java Thu Sep 16 11:16:02 2010 -0700
@@ -53,13 +53,14 @@
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()
--- a/jdk/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java Thu Sep 16 11:15:07 2010 -0700
+++ b/jdk/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java Thu Sep 16 11:16:02 2010 -0700
@@ -114,6 +114,7 @@
checkEvents(frameAdapter, 1, 1);
checkEvents(buttonAdapter, 0, 0);
w.setVisible(false);
+ Util.waitForIdle(r);
}
public static void main(String []s)