6522725: Component in a minimized Frame has focus and receives key events
Summary: XAWT: a window natively focused may request focus in it only synthetically
Reviewed-by: son
--- a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Tue Apr 08 13:32:30 2008 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Wed Apr 09 09:37:07 2008 +0400
@@ -420,40 +420,36 @@
case SNFH_SUCCESS_PROCEED:
// Currently we just generate focus events like we deal with lightweight instead of calling
// XSetInputFocus on native window
- if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Proceeding with request to " + lightweightChild + " in " + target);
+ if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Proceeding with request to " +
+ lightweightChild + " in " + target);
/**
* The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight
* checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet
* been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record
- * in requests list - and it breaks our requests sequence as first record on WGF should be the last focus
- * owner which had focus before WLF. So, we should not add request record for such requests
+ * in requests list - and it breaks our requests sequence as first record on WGF should be the last
+ * focus owner which had focus before WLF. So, we should not add request record for such requests
* but store this component in mostRecent - and return true as before for compatibility.
*/
Window parentWindow = getContainingWindow(target);
- if (parentWindow != null) {
- // and check that it is focused
- if (!parentWindow.isFocused()) {
- XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
- /*
- * Fix for 6314575.
- * Shouldn't restore focus on 'actualFocusedWindow'
- * when a component inside a Frame is requesting it.
- */
- wpeer.setActualFocusedWindow(null);
+ if (parentWindow == null) {
+ return rejectFocusRequestHelper("WARNING: Parent window is null");
+ }
+ XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
+ if (wpeer == null) {
+ return rejectFocusRequestHelper("WARNING: Parent window's peer is null");
+ }
+ /*
+ * Passing null 'actualFocusedWindow' as we don't want to restore focus on it
+ * when a component inside a Frame is requesting focus.
+ * See 6314575 for details.
+ */
+ boolean res = wpeer.requestWindowFocus(null);
- boolean res = wpeer.requestWindowFocus();
- if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Requested window focus: " + res);
- // If parent window can be made focused and has been made focused(synchronously)
- // then we can proceed with children, otherwise we retreat.
- if (!(res && parentWindow.isFocused())) {
- focusLog.finer("Waiting for asynchronous processing of window focus request");
- KeyboardFocusManagerPeerImpl.removeLastFocusRequest(target);
- return false;
- }
- }
- } else {
- if (focusLog.isLoggable(Level.FINER)) focusLog.finer("WARNING: Parent window is null");
- return false;
+ if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Requested window focus: " + res);
+ // If parent window can be made focused and has been made focused(synchronously)
+ // then we can proceed with children, otherwise we retreat.
+ if (!(res && parentWindow.isFocused())) {
+ return rejectFocusRequestHelper("Waiting for asynchronous processing of the request");
}
// NOTE: We simulate heavyweight behavior of Motif - component receives focus right
@@ -469,6 +465,12 @@
return false;
}
+ private boolean rejectFocusRequestHelper(String logMsg) {
+ if (focusLog.isLoggable(Level.FINER)) focusLog.finer(logMsg);
+ KeyboardFocusManagerPeerImpl.removeLastFocusRequest(target);
+ return false;
+ }
+
void handleJavaFocusEvent(AWTEvent e) {
if (focusLog.isLoggable(Level.FINER)) focusLog.finer(e.toString());
if (e.getID() == FocusEvent.FOCUS_GAINED) {
--- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Tue Apr 08 13:32:30 2008 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Wed Apr 09 09:37:07 2008 +0400
@@ -1013,16 +1013,6 @@
private void handleWmTakeFocus(XClientMessageEvent cl) {
focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}", new Object[]{this});
- // A workaround to Metacity issue (see 6613426).
- // The first check is to skip redundant WM_TAKE_FOCUS on click
- // in a focused frame. The second check is to allow requesting focus
- // on click in a frame when its owned window is currently focused.
- if (this == getNativeFocusedWindowPeer() &&
- target == XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow())
- {
- focusLog.fine("The window is already focused, skipping.");
- return;
- }
requestWindowFocus(cl.get_data(1), true);
}
@@ -1124,53 +1114,51 @@
focusLog.fine("Request for decorated window focus");
// If this is Frame or Dialog we can't assure focus request success - but we still can try
// If this is Window and its owner Frame is active we can be sure request succedded.
- Window win = (Window)target;
Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}",
- new Object[]{ Boolean.valueOf(win == activeWindow),
- Boolean.valueOf(win == focusedWindow)});
+ new Object[]{ Boolean.valueOf(target == activeWindow),
+ Boolean.valueOf(target == focusedWindow)});
XWindowPeer toFocus = this;
while (toFocus.nextTransientFor != null) {
toFocus = toFocus.nextTransientFor;
}
-
- if (this == toFocus) {
- if (focusAllowedFor()) {
- if (win == activeWindow && win != focusedWindow) {
- // Happens when focus is on window child
- focusLog.fine("Focus is on child window - transfering it back");
- handleWindowFocusInSync(-1);
- } else {
- focusLog.fine("Requesting focus to this window");
- if (timeProvided) {
- requestXFocus(time);
- } else {
- requestXFocus();
- }
- }
- return true;
- } else {
- return false;
- }
- }
- else if (toFocus.focusAllowedFor()) {
- focusLog.fine("Requesting focus to " + toFocus);
- if (timeProvided) {
- toFocus.requestXFocus(time);
- } else {
- toFocus.requestXFocus();
- }
- return false;
- }
- else
- {
+ if (toFocus == null || !toFocus.focusAllowedFor()) {
// This might change when WM will have property to determine focus policy.
// Right now, because policy is unknown we can't be sure we succedded
return false;
}
+ if (this == toFocus) {
+ if (isWMStateNetHidden()) {
+ focusLog.fine("The window is unmapped, so rejecting the request");
+ return false;
+ }
+ if (target == activeWindow && target != focusedWindow) {
+ // Happens when an owned window is currently focused
+ focusLog.fine("Focus is on child window - transfering it back to the owner");
+ handleWindowFocusInSync(-1);
+ return true;
+ }
+ Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow();
+ focusLog.finest("Real native focused window: " + realNativeFocusedWindow +
+ "\nKFM's focused window: " + focusedWindow);
+
+ // See 6522725, 6613426.
+ if (target == realNativeFocusedWindow) {
+ focusLog.fine("The window is already natively focused.");
+ return true;
+ }
+ }
+ focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus));
+
+ if (timeProvided) {
+ toFocus.requestXFocus(time);
+ } else {
+ toFocus.requestXFocus();
+ }
+ return (this == toFocus);
}
XWindowPeer actualFocusedWindow = null;
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Tue Apr 08 13:32:30 2008 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Wed Apr 09 09:37:07 2008 +0400
@@ -582,7 +582,7 @@
}
/*
- * Converts native focused X window id into Java peer.
+ * Retrives real native focused window and converts it into Java peer.
*/
static XWindowPeer getNativeFocusedWindowPeer() {
XBaseWindow baseWindow = XToolkit.windowToXWindow(xGetInputFocus());
@@ -591,6 +591,14 @@
((XFocusProxyWindow)baseWindow).getOwner() : null;
}
+ /*
+ * Retrives real native focused window and converts it into Java window.
+ */
+ static Window getNativeFocusedWindow() {
+ XWindowPeer peer = getNativeFocusedWindowPeer();
+ return peer != null ? (Window)peer.target : null;
+ }
+
boolean isFocusableWindow() {
if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread())
{
@@ -1252,7 +1260,7 @@
return res;
}
- private boolean isWMStateNetHidden() {
+ protected boolean isWMStateNetHidden() {
XNETProtocol protocol = XWM.getWM().getNETProtocol();
return (protocol != null && protocol.isWMStateNetHidden(this));
}
@@ -1740,6 +1748,11 @@
return window;
}
+ public boolean requestWindowFocus(XWindowPeer actualFocusedWindow) {
+ setActualFocusedWindow(actualFocusedWindow);
+ return requestWindowFocus();
+ }
+
public boolean requestWindowFocus() {
return requestWindowFocus(0, false);
}
@@ -1748,25 +1761,25 @@
focusLog.fine("Request for window focus");
// If this is Frame or Dialog we can't assure focus request success - but we still can try
// If this is Window and its owner Frame is active we can be sure request succedded.
- Window win = (Window) target;
- Window owner = XWindowPeer.getDecoratedOwner(win);
+ Window ownerWindow = XWindowPeer.getDecoratedOwner((Window)target);
+ Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
+ Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
- final Window activeWindow =
- XWindowPeer.getDecoratedOwner(XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow());
- if (activeWindow == owner) {
+ if (isWMStateNetHidden()) {
+ focusLog.fine("The window is unmapped, so rejecting the request");
+ return false;
+ }
+ if (activeWindow == ownerWindow) {
focusLog.fine("Parent window is active - generating focus for this window");
handleWindowFocusInSync(-1);
return true;
- } else {
- focusLog.fine("Parent window is not active");
}
- ComponentPeer peer = ComponentAccessor.getPeer(owner);
- if (peer instanceof XDecoratedPeer) {
- XDecoratedPeer wpeer = (XDecoratedPeer) peer;
- if (wpeer.requestWindowFocus(this, time, timeProvided)) {
- focusLog.fine("Parent window accepted focus request - generating focus for this window");
- return true;
- }
+ focusLog.fine("Parent window is not active");
+
+ XDecoratedPeer wpeer = (XDecoratedPeer)ComponentAccessor.getPeer(ownerWindow);
+ if (wpeer != null && wpeer.requestWindowFocus(this, time, timeProvided)) {
+ focusLog.fine("Parent window accepted focus request - generating focus for this window");
+ return true;
}
focusLog.fine("Denied - parent window is not active and didn't accept focus request");
return false;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java Wed Apr 09 09:37:07 2008 +0400
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ @test
+ @bug 6522725
+ @summary Tests for proper request-focus-back on FOCUS_LOST.
+ @author Anton Tarasov: area=awt-focus
+ @library ../../regtesthelpers
+ @build Util
+ @run main IconifiedFrameFocusChangeTest
+*/
+
+import java.awt.*;
+import java.applet.Applet;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class IconifiedFrameFocusChangeTest extends Applet {
+ Frame testFrame = new Frame("Test Frame");
+ Frame otherFrame = new Frame("Other Frame");
+ Button testButton = new Button("test button");
+ Button otherButton = new Button("other button");
+ Robot robot;
+
+ public static void main(String[] args) {
+ IconifiedFrameFocusChangeTest app = new IconifiedFrameFocusChangeTest();
+ app.init();
+ app.start();
+ }
+
+ public void init() {
+ robot = Util.createRobot();
+
+ testFrame.add(testButton);
+ testFrame.pack();
+ otherFrame.add(otherButton);
+ otherFrame.pack();
+ otherFrame.setLocation(200, 0);
+
+ testButton.addFocusListener(new FocusAdapter() {
+ public void focusLost(FocusEvent e) {
+ testButton.requestFocus();
+ }
+ });
+ }
+
+ public void start() {
+ otherFrame.setVisible(true);
+ Util.waitForIdle(robot);
+ testFrame.setVisible(true);
+ Util.waitForIdle(robot);
+
+ if (!testButton.hasFocus()) {
+ throw new TestErrorException("wrong initial focus");
+ }
+
+ /*
+ * Iconify the Frame. Test that focus switches properly.
+ */
+ Runnable action = new Runnable() {
+ public void run() {
+ testFrame.setExtendedState(Frame.ICONIFIED);
+ }
+ };
+ if (!Util.trackFocusGained(otherButton, action, 2000, true)) {
+ throw new TestFailedException("iconifying focused window didn't trigger focus change");
+ }
+
+ /*
+ * Test that key events go into the focus owner.
+ */
+ action = new Runnable() {
+ public void run() {
+ robot.keyPress(KeyEvent.VK_SPACE);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_SPACE);
+ }
+ };
+ if (!Util.trackActionPerformed(otherButton, action, 2000, true)) {
+ throw new TestFailedException("Java focus owner doesn't match to the native one");
+ }
+
+ System.out.println("Test passed.");
+ }
+}
+
+/**
+ * Thrown when the behavior being verified is found wrong.
+ */
+class TestFailedException extends RuntimeException {
+ TestFailedException(String msg) {
+ super("Test failed: " + msg);
+ }
+}
+
+/**
+ * Thrown when an error not related to the behavior being verified is encountered.
+ */
+class TestErrorException extends RuntimeException {
+ TestErrorException(String msg) {
+ super("Unexpected error: " + msg);
+ }
+}