Merge
authorlana
Thu, 16 Sep 2010 11:16:02 -0700
changeset 6488 404882083757
parent 6483 8f9f87a564f6 (current diff)
parent 6487 d6ad2c68a522 (diff)
child 6514 4a6fbb0da68a
Merge
--- 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)