--- old/src/macosx/classes/sun/lwawt/LWComponentPeer.java 2012-08-31 15:36:50.000000000 +0400 +++ new/src/macosx/classes/sun/lwawt/LWComponentPeer.java 2012-08-31 15:36:49.000000000 +0400 @@ -1248,12 +1248,9 @@ protected void handleJavaMouseEvent(MouseEvent e) { Component target = getTarget(); assert (e.getSource() == target); - + 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); } } --- old/src/macosx/classes/sun/lwawt/LWWindowPeer.java 2012-08-31 15:36:51.000000000 +0400 +++ new/src/macosx/classes/sun/lwawt/LWWindowPeer.java 2012-08-31 15:36:51.000000000 +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); --- old/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java 2012-08-31 15:36:52.000000000 +0400 +++ new/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java 2012-08-31 15:36:52.000000000 +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; --- old/src/share/classes/java/awt/Component.java 2012-08-31 15:36:54.000000000 +0400 +++ new/src/share/classes/java/awt/Component.java 2012-08-31 15:36:53.000000000 +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) { --- old/src/share/classes/java/awt/Container.java 2012-08-31 15:36:55.000000000 +0400 +++ new/src/share/classes/java/awt/Container.java 2012-08-31 15:36:55.000000000 +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(). --- old/src/share/classes/java/awt/DefaultKeyboardFocusManager.java 2012-08-31 15:36:57.000000000 +0400 +++ new/src/share/classes/java/awt/DefaultKeyboardFocusManager.java 2012-08-31 15:36:57.000000000 +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 realOppositeWindowWR = NULL_WINDOW_WR; private WeakReference realOppositeComponentWR = NULL_COMPONENT_WR; private int inSendMessage; - private LinkedList enqueuedKeyEvents = new LinkedList(), - typeAheadMarkers = new LinkedList(); + private LinkedList enqueuedKeyEvents = new LinkedList(); + private LinkedList typeAheadMarkers = new LinkedList(); 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 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 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 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 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 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 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 iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) { + KeyEvent ke = iter.next(); long time = ke.getWhen(); if (start < time && (end < 0 || time <= end)) { --- old/src/share/classes/java/awt/Dialog.java 2012-08-31 15:36:58.000000000 +0400 +++ new/src/share/classes/java/awt/Dialog.java 2012-08-31 15:36:58.000000000 +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); } --- old/src/share/classes/java/awt/EventQueue.java 2012-08-31 15:36:59.000000000 +0400 +++ new/src/share/classes/java/awt/EventQueue.java 2012-08-31 15:36:59.000000000 +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(); --- old/src/share/classes/java/awt/SequencedEvent.java 2012-08-31 15:37:01.000000000 +0400 +++ new/src/share/classes/java/awt/SequencedEvent.java 2012-08-31 15:37:01.000000000 +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. --- old/src/share/classes/sun/awt/AWTAccessor.java 2012-08-31 15:37:02.000000000 +0400 +++ new/src/share/classes/sun/awt/AWTAccessor.java 2012-08-31 15:37:02.000000000 +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; + } } --- old/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java 2012-08-31 15:37:03.000000000 +0400 +++ new/src/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java 2012-08-31 15:37:03.000000000 +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; } --- old/src/share/classes/sun/awt/SunToolkit.java 2012-08-31 15:37:05.000000000 +0400 +++ new/src/share/classes/sun/awt/SunToolkit.java 2012-08-31 15:37:05.000000000 +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 map = (WeakHashMap)ctx.get(DEACTIVATION_TIMES_MAP_KEY); + if (map == null) { + map = new WeakHashMap(); + ctx.put(DEACTIVATION_TIMES_MAP_KEY, map); + } + map.put(w, time); + } + + public synchronized long getWindowDeactivationTime(Window w) { + AppContext ctx = getAppContext(w); + WeakHashMap map = (WeakHashMap)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; --- old/src/solaris/classes/sun/awt/X11/XBaseWindow.java 2012-08-31 15:37:07.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XBaseWindow.java 2012-08-31 15:37:07.000000000 +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; --- old/src/solaris/classes/sun/awt/X11/XComponentPeer.java 2012-08-31 15:37:09.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XComponentPeer.java 2012-08-31 15:37:08.000000000 +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(); } --- old/src/windows/native/sun/windows/awt_Window.cpp 2012-08-31 15:37:10.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_Window.cpp 2012-08-31 15:37:10.000000000 +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, "", - "(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 2012-08-31 15:37:11.000000000 +0400 +++ new/src/share/classes/sun/awt/TimedWindowEvent.java 2012-08-31 15:37:11.000000000 +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; + } +} + --- /dev/null 2012-08-31 15:37:12.000000000 +0400 +++ new/test/java/awt/Focus/6981400/Test1.java 2012-08-31 15:37:12.000000000 +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 gainedList = new ArrayList(); + static List lostList = new ArrayList(); + + 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 2012-08-31 15:37:13.000000000 +0400 +++ new/test/java/awt/Focus/6981400/Test2.java 2012-08-31 15:37:13.000000000 +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 2012-08-31 15:37:15.000000000 +0400 +++ new/test/java/awt/Focus/6981400/Test3.java 2012-08-31 15:37:14.000000000 +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); + } + } +} + +