6981400: Tabbing between textfield do not work properly when ALT+TAB
7157015: [macosx] Situation when KeyEventDispatcher doesn't work on AWT but does on Swing.
7121442: Regression : Reopen CR 6458497 still reproducible using JDK 7.
Reviewed-by: art, leonidr
--- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Fri Aug 31 16:31:29 2012 +0400
@@ -1251,9 +1251,6 @@
if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) {
LWKeyboardFocusManagerPeer.requestFocusFor(target, CausedFocusEvent.Cause.MOUSE_EVENT);
- } else {
- // Anyway request focus to the toplevel.
- getWindowPeerOrSelf().requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);
}
}
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Aug 31 16:31:29 2012 +0400
@@ -798,6 +798,14 @@
mouseClickButtons |= eventButtonMask;
}
+ // The window should be focused on mouse click. If it gets activated by the native platform,
+ // this request will be no op. It will take effect when:
+ // 1. A simple not focused window is clicked.
+ // 2. An active but not focused owner frame/dialog is clicked.
+ // The mouse event then will trigger a focus request "in window" to the component, so the window
+ // should gain focus before.
+ requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);
+
mouseDownTarget[targetIdx] = targetPeer;
} else if (id == MouseEvent.MOUSE_DRAGGED) {
// Cocoa dragged event has the information about which mouse
@@ -914,20 +922,16 @@
public void dispatchKeyEvent(int id, long when, int modifiers,
int keyCode, char keyChar, int keyLocation)
{
- KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
+ LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
Component focusOwner = kfmPeer.getCurrentFocusOwner();
- // Null focus owner may receive key event when
- // application hides the focused window upon ESC press
- // (AWT transfers/clears the focus owner) and pending ESC release
- // may come to already hidden window. This check eliminates NPE.
- if (focusOwner != null) {
- KeyEvent event =
- new KeyEvent(focusOwner, id, when, modifiers,
- keyCode, keyChar, keyLocation);
- LWComponentPeer peer = (LWComponentPeer)focusOwner.getPeer();
- peer.postEvent(event);
+ if (focusOwner == null) {
+ focusOwner = kfmPeer.getCurrentFocusedWindow();
+ if (focusOwner == null) {
+ focusOwner = this.getTarget();
+ }
}
+ postEvent(new KeyEvent(focusOwner, id, when, modifiers, keyCode, keyChar, keyLocation));
}
@@ -1260,7 +1264,7 @@
kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);
int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;
- WindowEvent windowEvent = new WindowEvent(getTarget(), eventID, oppositeWindow);
+ WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, oppositeWindow, System.currentTimeMillis());
// TODO: wrap in SequencedEvent
postEvent(windowEvent);
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java Fri Aug 31 16:31:29 2012 +0400
@@ -30,6 +30,8 @@
import java.awt.Event;
import java.awt.KeyEventPostProcessor;
import java.awt.Window;
+import java.awt.Toolkit;
+import sun.awt.SunToolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
@@ -125,7 +127,19 @@
}
JMenu menu = mbar != null ? mbar.getMenu(0) : null;
- if (menu != null) {
+ // It might happen that the altRelease event is processed
+ // with a reasonable delay since it has been generated.
+ // Here we check the last deactivation time of the containing
+ // window. If this time appears to be greater than the altRelease
+ // event time the event is skipped to avoid unexpected menu
+ // activation. See 7121442.
+ boolean skip = false;
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ if (tk instanceof SunToolkit) {
+ skip = ev.getWhen() <= ((SunToolkit)tk).getWindowDeactivationTime(winAncestor);
+ }
+
+ if (menu != null && !skip) {
MenuElement[] path = new MenuElement[2];
path[0] = mbar;
path[1] = menu;
--- a/jdk/src/share/classes/java/awt/Component.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Component.java Fri Aug 31 16:31:29 2012 +0400
@@ -4710,7 +4710,10 @@
/*
* 0. Set timestamp and modifiers of current event.
*/
- EventQueue.setCurrentEventAndMostRecentTime(e);
+ if (!(e instanceof KeyEvent)) {
+ // Timestamp of a key event is set later in DKFM.preDispatchKeyEvent(KeyEvent).
+ EventQueue.setCurrentEventAndMostRecentTime(e);
+ }
/*
* 1. Pre-dispatchers. Do any necessary retargeting/reordering here
@@ -7606,13 +7609,33 @@
boolean focusedWindowChangeAllowed,
CausedFocusEvent.Cause cause)
{
+ // 1) Check if the event being dispatched is a system-generated mouse event.
+ AWTEvent currentEvent = EventQueue.getCurrentEvent();
+ if (currentEvent instanceof MouseEvent &&
+ SunToolkit.isSystemGenerated(currentEvent))
+ {
+ // 2) Sanity check: if the mouse event component source belongs to the same containing window.
+ Component source = ((MouseEvent)currentEvent).getComponent();
+ if (source == null || source.getContainingWindow() == getContainingWindow()) {
+ focusLog.finest("requesting focus by mouse event \"in window\"");
+
+ // If both the conditions are fulfilled the focus request should be strictly
+ // bounded by the toplevel window. It's assumed that the mouse event activates
+ // the window (if it wasn't active) and this makes it possible for a focus
+ // request with a strong in-window requirement to change focus in the bounds
+ // of the toplevel. If, by any means, due to asynchronous nature of the event
+ // dispatching mechanism, the window happens to be natively inactive by the time
+ // this focus request is eventually handled, it should not re-activate the
+ // toplevel. Otherwise the result may not meet user expectations. See 6981400.
+ focusedWindowChangeAllowed = false;
+ }
+ }
if (!isRequestFocusAccepted(temporary, focusedWindowChangeAllowed, cause)) {
if (focusLog.isLoggable(PlatformLogger.FINEST)) {
focusLog.finest("requestFocus is not accepted");
}
return false;
}
-
// Update most-recent map
KeyboardFocusManager.setMostRecentFocusOwner(this);
@@ -7645,7 +7668,15 @@
}
// Focus this Component
- long time = EventQueue.getMostRecentEventTime();
+ long time = 0;
+ if (EventQueue.isDispatchThread()) {
+ time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
+ } else {
+ // A focus request made from outside EDT should not be associated with any event
+ // and so its time stamp is simply set to the current time.
+ time = System.currentTimeMillis();
+ }
+
boolean success = peer.requestFocus
(this, temporary, focusedWindowChangeAllowed, time, cause);
if (!success) {
--- a/jdk/src/share/classes/java/awt/Container.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Container.java Fri Aug 31 16:31:29 2012 +0400
@@ -2863,7 +2863,7 @@
// keep the KeyEvents from being dispatched
// until the focus has been transfered
- long time = Toolkit.getEventQueue().getMostRecentEventTime();
+ long time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame)(this)).getMostRecentFocusOwner() : null;
if (predictedFocusOwner != null) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().
--- a/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Fri Aug 31 16:31:29 2012 +0400
@@ -40,6 +40,7 @@
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.awt.CausedFocusEvent;
+import sun.awt.TimedWindowEvent;
/**
* The default KeyboardFocusManager for AWT applications. Focus traversal is
@@ -71,8 +72,8 @@
private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
private int inSendMessage;
- private LinkedList enqueuedKeyEvents = new LinkedList(),
- typeAheadMarkers = new LinkedList();
+ private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
+ private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
private boolean consumeNextKeyTyped;
private static class TypeAheadMarker {
@@ -259,6 +260,31 @@
return se.dispatched;
}
+ /*
+ * Checks if the focus window event follows key events waiting in the type-ahead
+ * queue (if any). This may happen when a user types ahead in the window, the client
+ * listeners hang EDT for a while, and the user switches b/w toplevels. In that
+ * case the focus window events may be dispatched before the type-ahead events
+ * get handled. This may lead to wrong focus behavior and in order to avoid it,
+ * the focus window events are reposted to the end of the event queue. See 6981400.
+ */
+ private boolean repostIfFollowsKeyEvents(WindowEvent e) {
+ if (!(e instanceof TimedWindowEvent)) {
+ return false;
+ }
+ TimedWindowEvent we = (TimedWindowEvent)e;
+ long time = we.getWhen();
+ synchronized (this) {
+ for (KeyEvent ke: enqueuedKeyEvents) {
+ if (time >= ke.getWhen()) {
+ SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* This method is called by the AWT event dispatcher requesting that the
* current KeyboardFocusManager dispatch the specified event on its behalf.
@@ -277,6 +303,10 @@
if (focusLog.isLoggable(PlatformLogger.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) focusLog.fine("" + e);
switch (e.getID()) {
case WindowEvent.WINDOW_GAINED_FOCUS: {
+ if (repostIfFollowsKeyEvents((WindowEvent)e)) {
+ break;
+ }
+
WindowEvent we = (WindowEvent)e;
Window oldFocusedWindow = getGlobalFocusedWindow();
Window newFocusedWindow = we.getWindow();
@@ -636,6 +666,10 @@
}
case WindowEvent.WINDOW_LOST_FOCUS: {
+ if (repostIfFollowsKeyEvents((WindowEvent)e)) {
+ break;
+ }
+
WindowEvent we = (WindowEvent)e;
Window currentFocusedWindow = getGlobalFocusedWindow();
Window losingFocusWindow = we.getWindow();
@@ -815,10 +849,9 @@
ke = null;
synchronized (this) {
if (enqueuedKeyEvents.size() != 0) {
- ke = (KeyEvent)enqueuedKeyEvents.getFirst();
+ ke = enqueuedKeyEvents.getFirst();
if (typeAheadMarkers.size() != 0) {
- TypeAheadMarker marker = (TypeAheadMarker)
- typeAheadMarkers.getFirst();
+ TypeAheadMarker marker = typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
@@ -847,9 +880,9 @@
focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
synchronized (this) {
if (typeAheadMarkers.size() != 0) {
- Iterator iter = typeAheadMarkers.iterator();
+ Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
while (iter.hasNext()) {
- TypeAheadMarker marker = (TypeAheadMarker)iter.next();
+ TypeAheadMarker marker = iter.next();
focusLog.finest(" {0}", marker);
}
}
@@ -871,8 +904,7 @@
KeyEvent ke = (KeyEvent)e;
synchronized (this) {
if (e.isPosted && typeAheadMarkers.size() != 0) {
- TypeAheadMarker marker = (TypeAheadMarker)
- typeAheadMarkers.getFirst();
+ TypeAheadMarker marker = typeAheadMarkers.getFirst();
// Fixed 5064013: may appears that the events have the same time
// if (ke.getWhen() >= marker.after) {
// The fix is rolled out.
@@ -905,12 +937,10 @@
synchronized (this) {
boolean found = false;
if (hasMarker(target)) {
- for (Iterator iter = typeAheadMarkers.iterator();
+ for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
iter.hasNext(); )
{
- if (((TypeAheadMarker)iter.next()).untilFocused ==
- target)
- {
+ if (iter.next().untilFocused == target) {
found = true;
} else if (found) {
break;
@@ -945,8 +975,8 @@
* @since 1.5
*/
private boolean hasMarker(Component comp) {
- for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
- if (((TypeAheadMarker)iter.next()).untilFocused == comp) {
+ for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
+ if (iter.next().untilFocused == comp) {
return true;
}
}
@@ -972,11 +1002,10 @@
return true;
}
- // Explicitly set the current event and most recent timestamp here in
- // addition to the call in Component.dispatchEventImpl. Because
- // KeyEvents can be delivered in response to a FOCUS_GAINED event, the
- // current timestamp may be incorrect. We need to set it here so that
- // KeyEventDispatchers will use the correct time.
+ // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
+ // - A key event is anyway passed to this method which starts its actual dispatching.
+ // - If a key event is put to the type ahead queue, its time stamp should not be registered
+ // until its dispatching actually starts (by this method).
EventQueue.setCurrentEventAndMostRecentTime(ke);
/**
@@ -1164,10 +1193,10 @@
int insertionIndex = 0,
i = typeAheadMarkers.size();
- ListIterator iter = typeAheadMarkers.listIterator(i);
+ ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i);
for (; i > 0; i--) {
- TypeAheadMarker marker = (TypeAheadMarker)iter.previous();
+ TypeAheadMarker marker = iter.previous();
if (marker.after <= after) {
insertionIndex = i;
break;
@@ -1203,12 +1232,12 @@
after, untilFocused);
TypeAheadMarker marker;
- ListIterator iter = typeAheadMarkers.listIterator
+ ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
- marker = (TypeAheadMarker)iter.next();
+ marker = iter.next();
if (marker.untilFocused == untilFocused)
{
iter.remove();
@@ -1217,7 +1246,7 @@
}
} else {
while (iter.hasPrevious()) {
- marker = (TypeAheadMarker)iter.previous();
+ marker = iter.previous();
if (marker.untilFocused == untilFocused &&
marker.after == after)
{
@@ -1245,8 +1274,8 @@
long start = -1;
- for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
- TypeAheadMarker marker = (TypeAheadMarker)iter.next();
+ for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
+ TypeAheadMarker marker = iter.next();
Component toTest = marker.untilFocused;
boolean match = (toTest == comp);
while (!match && toTest != null && !(toTest instanceof Window)) {
@@ -1277,8 +1306,8 @@
return;
}
- for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
- KeyEvent ke = (KeyEvent)iter.next();
+ for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
+ KeyEvent ke = iter.next();
long time = ke.getWhen();
if (start < time && (end < 0 || time <= end)) {
--- a/jdk/src/share/classes/java/awt/Dialog.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/Dialog.java Fri Aug 31 16:31:29 2012 +0400
@@ -924,7 +924,7 @@
isEnabled() && !isModalBlocked()) {
// keep the KeyEvents from being dispatched
// until the focus has been transfered
- time.set(Toolkit.getEventQueue().getMostRecentEventTimeEx());
+ time.set(Toolkit.getEventQueue().getMostRecentKeyEventTime());
KeyboardFocusManager.getCurrentKeyboardFocusManager().
enqueueKeyEvents(time.get(), toFocus);
}
--- a/jdk/src/share/classes/java/awt/EventQueue.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/EventQueue.java Fri Aug 31 16:31:29 2012 +0400
@@ -163,6 +163,11 @@
*/
private long mostRecentEventTime = System.currentTimeMillis();
+ /*
+ * The time stamp of the last KeyEvent .
+ */
+ private long mostRecentKeyEventTime = System.currentTimeMillis();
+
/**
* The modifiers field of the current event, if the current event is an
* InputEvent or ActionEvent.
@@ -1132,6 +1137,15 @@
}
}
+ synchronized long getMostRecentKeyEventTime() {
+ pushPopLock.lock();
+ try {
+ return mostRecentKeyEventTime;
+ } finally {
+ pushPopLock.unlock();
+ }
+ }
+
static void setCurrentEventAndMostRecentTime(AWTEvent e) {
Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
}
@@ -1156,6 +1170,9 @@
if (e instanceof InputEvent) {
InputEvent ie = (InputEvent)e;
mostRecentEventTime2 = ie.getWhen();
+ if (e instanceof KeyEvent) {
+ mostRecentKeyEventTime = ie.getWhen();
+ }
} else if (e instanceof InputMethodEvent) {
InputMethodEvent ime = (InputMethodEvent)e;
mostRecentEventTime2 = ime.getWhen();
--- a/jdk/src/share/classes/java/awt/SequencedEvent.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/java/awt/SequencedEvent.java Fri Aug 31 16:31:29 2012 +0400
@@ -26,6 +26,7 @@
package java.awt;
import java.util.LinkedList;
+import sun.awt.AWTAccessor;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
@@ -54,6 +55,17 @@
private AppContext appContext;
private boolean disposed;
+ static {
+ AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {
+ public AWTEvent getNested(AWTEvent sequencedEvent) {
+ return ((SequencedEvent)sequencedEvent).nested;
+ }
+ public boolean isSequencedEvent(AWTEvent event) {
+ return event instanceof SequencedEvent;
+ }
+ });
+ }
+
/**
* Constructs a new SequencedEvent which will dispatch the specified
* nested event.
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java Fri Aug 31 16:31:29 2012 +0400
@@ -487,6 +487,21 @@
}
/*
+ * An accessor for the SequencedEventAccessor class
+ */
+ public interface SequencedEventAccessor {
+ /*
+ * Returns the nested event.
+ */
+ AWTEvent getNested(AWTEvent sequencedEvent);
+
+ /*
+ * Returns true if the event is an instances of SequencedEvent.
+ */
+ boolean isSequencedEvent(AWTEvent event);
+ }
+
+ /*
* Accessor instances are initialized in the static initializers of
* corresponding AWT classes by using setters defined below.
*/
@@ -502,6 +517,7 @@
private static PopupMenuAccessor popupMenuAccessor;
private static FileDialogAccessor fileDialogAccessor;
private static ScrollPaneAdjustableAccessor scrollPaneAdjustableAccessor;
+ private static SequencedEventAccessor sequencedEventAccessor;
/*
* Set an accessor object for the java.awt.Component class.
@@ -709,4 +725,21 @@
}
return scrollPaneAdjustableAccessor;
}
+
+ /*
+ * Set an accessor object for the java.awt.SequencedEvent class.
+ */
+ public static void setSequencedEventAccessor(SequencedEventAccessor sea) {
+ sequencedEventAccessor = sea;
+ }
+
+ /*
+ * Get the accessor object for the java.awt.SequencedEvent class.
+ */
+ public static SequencedEventAccessor getSequencedEventAccessor() {
+ // The class is not public. So we can't ensure it's initialized.
+ // Null returned value means it's not initialized
+ // (so not a single instance of the event has been created).
+ return sequencedEventAccessor;
+ }
}
--- a/jdk/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Fri Aug 31 16:31:29 2012 +0400
@@ -128,7 +128,7 @@
if (focusLog.isLoggable(PlatformLogger.FINER))
focusLog.finer("Posting focus event: " + fl);
- SunToolkit.postPriorityEvent(fl);
+ SunToolkit.postEvent(SunToolkit.targetToAppContext(currentOwner), fl);
}
FocusEvent fg = new CausedFocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED,
@@ -136,7 +136,7 @@
if (focusLog.isLoggable(PlatformLogger.FINER))
focusLog.finer("Posting focus event: " + fg);
- SunToolkit.postPriorityEvent(fg);
+ SunToolkit.postEvent(SunToolkit.targetToAppContext(lightweightChild), fg);
return true;
}
--- a/jdk/src/share/classes/sun/awt/SunToolkit.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Fri Aug 31 16:31:29 2012 +0400
@@ -513,6 +513,19 @@
if (event == null) {
throw new NullPointerException();
}
+
+ AWTAccessor.SequencedEventAccessor sea = AWTAccessor.getSequencedEventAccessor();
+ if (sea != null && sea.isSequencedEvent(event)) {
+ AWTEvent nested = sea.getNested(event);
+ if (nested.getID() == WindowEvent.WINDOW_LOST_FOCUS &&
+ nested instanceof TimedWindowEvent)
+ {
+ TimedWindowEvent twe = (TimedWindowEvent)nested;
+ ((SunToolkit)Toolkit.getDefaultToolkit()).
+ setWindowDeactivationTime((Window)twe.getSource(), twe.getWhen());
+ }
+ }
+
// All events posted via this method are system-generated.
// Placing the following call here reduces considerably the
// number of places throughout the toolkit that would
@@ -1964,6 +1977,28 @@
return false;
}
+ private static final Object DEACTIVATION_TIMES_MAP_KEY = new Object();
+
+ public synchronized void setWindowDeactivationTime(Window w, long time) {
+ AppContext ctx = getAppContext(w);
+ WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);
+ if (map == null) {
+ map = new WeakHashMap<Window, Long>();
+ ctx.put(DEACTIVATION_TIMES_MAP_KEY, map);
+ }
+ map.put(w, time);
+ }
+
+ public synchronized long getWindowDeactivationTime(Window w) {
+ AppContext ctx = getAppContext(w);
+ WeakHashMap<Window, Long> map = (WeakHashMap<Window, Long>)ctx.get(DEACTIVATION_TIMES_MAP_KEY);
+ if (map == null) {
+ return -1;
+ }
+ Long time = map.get(w);
+ return time == null ? -1 : time;
+ }
+
// Cosntant alpha
public boolean isWindowOpacitySupported() {
return false;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/awt/TimedWindowEvent.java Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 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 sun.awt;
+
+import java.awt.event.WindowEvent;
+import java.awt.Window;
+
+public class TimedWindowEvent extends WindowEvent {
+
+ private long time;
+
+ public long getWhen() {
+ return time;
+ }
+
+ public TimedWindowEvent(Window source, int id, Window opposite, long time) {
+ super(source, id, opposite);
+ this.time = time;
+ }
+
+ public TimedWindowEvent(Window source, int id, Window opposite,
+ int oldState, int newState, long time)
+ {
+ super(source, id, opposite, oldState, newState);
+ this.time = time;
+ }
+}
+
--- a/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java Fri Aug 31 16:31:29 2012 +0400
@@ -1001,6 +1001,13 @@
switch (xev.get_type()) {
case XConstants.ButtonPress:
if (buttonState == 0) {
+ XWindowPeer parent = getToplevelXWindow();
+ // See 6385277, 6981400.
+ if (parent != null && parent.isFocusableWindow()) {
+ // A click in a client area drops the actual focused window retaining.
+ parent.setActualFocusedWindow(null);
+ parent.requestWindowFocus(xbe.get_time(), true);
+ }
XAwtState.setAutoGrabWindow(this);
}
break;
--- a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Fri Aug 31 16:31:29 2012 +0400
@@ -588,33 +588,6 @@
}
- public void handleButtonPressRelease(XEvent xev) {
- /*
- * Fix for 6385277.
- * We request focus on simple Window by click in order
- * to make it behave like Frame/Dialog in this case and also to unify
- * the behaviour with what we have on MS Windows.
- * handleJavaMouseEvent() would be more suitable place to do this
- * but we want Swing to have this functionality also.
- */
- if (xev.get_type() == XConstants.ButtonPress) {
- final XWindowPeer parentXWindow = getParentTopLevel();
- Window parentWindow = (Window)parentXWindow.getTarget();
- if (parentXWindow.isFocusableWindow() && parentXWindow.isSimpleWindow() &&
- XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() != parentWindow)
- {
- postEvent(new InvocationEvent(parentWindow, new Runnable() {
- public void run() {
- // Request focus on the EDT of 'parentWindow' because
- // XDecoratedPeer.requestWindowFocus() calls client code.
- parentXWindow.requestXFocus();
- }
- }));
- }
- }
- super.handleButtonPressRelease(xev);
- }
-
public Dimension getMinimumSize() {
return target.getSize();
}
--- a/jdk/src/windows/native/sun/windows/awt_Window.cpp Fri Aug 31 14:49:23 2012 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp Fri Aug 31 16:31:29 2012 +0400
@@ -1477,7 +1477,7 @@
if (wClassEvent == NULL) {
if (env->PushLocalFrame(1) < 0)
return;
- wClassEvent = env->FindClass("java/awt/event/WindowEvent");
+ wClassEvent = env->FindClass("sun/awt/TimedWindowEvent");
if (wClassEvent != NULL) {
wClassEvent = (jclass)env->NewGlobalRef(wClassEvent);
}
@@ -1491,7 +1491,7 @@
if (wEventInitMID == NULL) {
wEventInitMID =
env->GetMethodID(wClassEvent, "<init>",
- "(Ljava/awt/Window;ILjava/awt/Window;II)V");
+ "(Ljava/awt/Window;ILjava/awt/Window;IIJ)V");
DASSERT(wEventInitMID);
if (wEventInitMID == NULL) {
return;
@@ -1532,7 +1532,7 @@
}
}
jobject event = env->NewObject(wClassEvent, wEventInitMID, target, id,
- jOpposite, oldState, newState);
+ jOpposite, oldState, newState, TimeHelper::getMessageTimeUTC());
DASSERT(!safe_ExceptionOccurred(env));
DASSERT(event != NULL);
if (jOpposite != NULL) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test1.java Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * @test
+ * @bug 6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author anton.tarasov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main Test1
+ */
+
+// This test shows a frame with four focusable components: b0, b1, b2, b3.
+// Then it presses Tab three times. EDT is freezed for a while on the first FOCUS_LOST event.
+// Meantime, the test clicks in a component of another frame and then clicks in the title
+// of the original frame. When EDT awakes and all the queued events get processed,
+// the other frame should ones gain focus and then pass it to the original frame.
+// The b3 component of the orinial frame should finally become a focus owner.
+// The FOCUS_LOST/FOCUS_GAINED events order in the original frame is tracked and should be:
+// b0 -> b1 -> b2 -> b3.
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test1 {
+ static JFrame f0 = new JFrame("base_frame") { public String getName() {return "base_frame";} };
+ static JButton f0b0 = new JB("b0");
+ static JButton f0b1 = new JB("b1");
+ static JButton f0b2 = new JB("b2");
+ static JButton f0b3 = new JB("b3");
+
+ static JFrame f1 = new JFrame("swing_frame") { public String getName() {return "swing_frame";} };
+ static JButton f1b0 = new JButton("button");
+
+ static Frame f2 = new Frame("awt_frame") { public String getName() {return "awt_frame";} };
+ static Button f2b0 = new Button("button");
+
+ static Robot robot;
+
+ static List<Component> gainedList = new ArrayList<Component>();
+ static List<Component> lostList = new ArrayList<Component>();
+
+ static Component[] refGainedList = new Component[] {f0b1, f0b2, f0b3, f0b3};
+ static Component[] refLostList = new Component[] {f0b0, f0b1, f0b2, f0b3};
+
+ static boolean tracking;
+
+ public static void main(String[] args) {
+ Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+ public void eventDispatched(AWTEvent e) {
+ System.out.println(e);
+ }
+ }, FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK);
+
+ try {
+ robot = new Robot();
+ } catch (AWTException ex) {
+ throw new RuntimeException("Error: can't create Robot");
+ }
+
+ f0.add(f0b0);
+ f0.add(f0b1);
+ f0.add(f0b2);
+ f0.add(f0b3);
+ f0.setLayout(new FlowLayout());
+ f0.setBounds(0, 100, 400, 200);
+
+ f1.add(f1b0);
+ f1.setBounds(0, 400, 400, 200);
+
+ f2.add(f2b0);
+ f2.setBounds(0, 400, 400, 200);
+
+ f0b0.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ try {
+ Thread.sleep(1000);
+ } catch (Exception ex) {}
+ }
+ });
+
+ //
+ // Case 1. Test against swing JFrame.
+ //
+
+ f1.setVisible(true);
+ f0.setVisible(true);
+
+ Util.waitForIdle(robot);
+
+ if (!f0b0.isFocusOwner()) {
+ Util.clickOnComp(f0b0, robot);
+ Util.waitForIdle(robot);
+ if (!f0b0.isFocusOwner()) {
+ throw new RuntimeException("Error: can't focus the component " + f0b0);
+ }
+ }
+
+ System.out.println("\nTest case 1: swing frame\n");
+ test(f1b0);
+
+ //
+ // Case 2. Test against awt Frame.
+ //
+
+ tracking = false;
+ gainedList.clear();
+ lostList.clear();
+
+ f1.dispose();
+ f2.setAutoRequestFocus(false);
+ f2.setVisible(true);
+ Util.waitForIdle(robot);
+
+ Util.clickOnComp(f0b0, robot);
+ Util.waitForIdle(robot);
+ if (!f0b0.isFocusOwner()) {
+ throw new RuntimeException("Error: can't focus the component " + f0b0);
+ }
+
+ System.out.println("\nTest case 2: awt frame\n");
+ test(f2b0);
+
+ System.out.println("\nTest passed.");
+ }
+
+ public static void test(Component compToClick) {
+ tracking = true;
+
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.delay(50);
+
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.delay(50);
+
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+
+ robot.delay(50);
+ Util.clickOnComp(compToClick, robot);
+
+ robot.delay(50);
+ Util.clickOnTitle(f0, robot);
+
+ Util.waitForIdle(robot);
+
+ if (!f0b3.isFocusOwner()) {
+ throw new RuntimeException("Test failed: f0b3 is not a focus owner");
+ }
+
+ if (!"sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
+
+ if (!Arrays.asList(refGainedList).equals(gainedList)) {
+ System.out.println("gained list: " + gainedList);
+ throw new RuntimeException("Test failed: wrong FOCUS_GAINED events order");
+ }
+ if (!Arrays.asList(refLostList).equals(lostList)) {
+ System.out.println("lost list: " + lostList);
+ throw new RuntimeException("Test failed: wrong FOCUS_LOST events order");
+ }
+ }
+ }
+}
+
+class JB extends JButton {
+ String name;
+
+ public JB(String name) {
+ super(name);
+ this.name = name;
+
+ addFocusListener(new FocusListener() {
+ public void focusGained(FocusEvent e) {
+ if (Test1.tracking)
+ Test1.gainedList.add(e.getComponent());
+ }
+
+ public void focusLost(FocusEvent e) {
+ if (Test1.tracking)
+ Test1.lostList.add(e.getComponent());
+ }
+ });
+ }
+
+ public String toString() {
+ return "[" + name + "]";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test2.java Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * @test
+ * @bug 6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author anton.tarasov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main Test2
+ */
+
+// A focus request made after a char is typed ahead shouldn't affect the char's target component.
+
+import java.awt.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test2 {
+ static Frame f = new Frame("frame");
+ static TextArea t0 = new TextArea(1, 10) { public String toString() { return "[TA-0]";} };
+ static TextArea t1 = new TextArea(1, 10) { public String toString() { return "[TA-1]";} };
+ static TextArea t2 = new TextArea(1, 10) { public String toString() { return "[TA-2]";} };
+
+ static volatile boolean passed = true;
+
+ static Robot robot;
+
+ public static void main(String[] args) {
+ Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+ public void eventDispatched(AWTEvent e) {
+ System.out.println(e);
+ if (e.getID() == KeyEvent.KEY_TYPED) {
+ if (e.getSource() != t1) {
+ passed = false;
+ throw new RuntimeException("Test failed: the key event has wrong source: " + e);
+ }
+ }
+ }
+ }, FocusEvent.FOCUS_EVENT_MASK | KeyEvent.KEY_EVENT_MASK);
+
+ try {
+ robot = new Robot();
+ } catch (AWTException ex) {
+ throw new RuntimeException("Error: can't create Robot");
+ }
+
+ f.add(t0);
+ f.add(t1);
+ f.add(t2);
+
+ f.setLayout(new FlowLayout());
+ f.pack();
+
+ t0.addFocusListener(new FocusAdapter() {
+ public void focusLost(FocusEvent e) {
+ try {
+ Thread.sleep(3000);
+ } catch (Exception ex) {}
+ }
+ });
+
+ // The request shouldn't affect the key event delivery.
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ } catch (Exception ex) {}
+ System.out.println("requesting focus to " + t2);
+ t2.requestFocus();
+ }
+ }).start();
+
+
+ f.setVisible(true);
+ Util.waitForIdle(robot);
+
+ test();
+
+ if (passed) System.out.println("\nTest passed.");
+ }
+
+ static void test() {
+ Util.clickOnComp(t1, robot);
+
+ // The key event should be eventually delivered to t1.
+ robot.delay(50);
+ robot.keyPress(KeyEvent.VK_A);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_A);
+
+ Util.waitForIdle(robot);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/6981400/Test3.java Fri Aug 31 16:31:29 2012 +0400
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * @test
+ * @bug 6981400
+ * @summary Tabbing between textfiled do not work properly when ALT+TAB
+ * @author anton.tarasov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main Test3
+ */
+
+// A menu item in a frame should not be auto-selected when switching by Alt+TAB back and forth.
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Test3 {
+ static JFrame f = new JFrame("Frame");
+ static JMenuBar bar = new JMenuBar();
+ static JMenu menu = new JMenu("File");
+ static JMenuItem item = new JMenuItem("Save");
+
+ static JButton b0 = new JButton("b0");
+ static JButton b1 = new JButton("b1");
+
+ static Robot robot;
+
+ public static void main(String[] args) {
+ Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
+ public void eventDispatched(AWTEvent e) {
+ System.err.println(e);
+ }
+ }, KeyEvent.KEY_EVENT_MASK);
+
+ try {
+ robot = new Robot();
+ } catch (AWTException ex) {
+ throw new RuntimeException("Error: can't create Robot");
+ }
+
+ try {
+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ } catch (Exception e) {}
+
+ b0.addFocusListener(new FocusAdapter() {
+ public void focusLost(FocusEvent f) {
+ try {
+ Thread.sleep(2000);
+ } catch (Exception e) {}
+ }
+ });
+
+ menu.add(item);
+ bar.add(menu);
+ f.setJMenuBar(bar);
+
+ f.add(b0);
+ f.add(b1);
+
+ f.setLayout(new FlowLayout());
+ f.setSize(400, 100);
+ f.setVisible(true);
+ Util.waitForIdle(robot);
+
+ if (!b0.hasFocus()) {
+ Util.clickOnComp(b0, robot);
+ Util.waitForIdle(robot);
+ if (!b0.hasFocus()) {
+ throw new RuntimeException("Error: can't focus " + b0);
+ }
+ }
+
+ test();
+
+ System.out.println("Test passed.");
+ }
+
+ public static void test() {
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.delay(50);
+
+ robot.keyPress(KeyEvent.VK_ALT);
+ robot.delay(50);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_ALT);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+
+ robot.delay(500);
+
+ robot.keyPress(KeyEvent.VK_ALT);
+ robot.delay(50);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_ALT);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_TAB);
+
+ // Control shot.
+ Util.clickOnTitle(f, robot);
+ Util.waitForIdle(robot);
+
+ if (menu.isSelected()) {
+ throw new RuntimeException("Test failed: the menu gets selected");
+ }
+ if (!b1.hasFocus()) {
+ throw new RuntimeException("Test failed: the button is not a focus owner " + b1);
+ }
+ }
+}
+
+