6522725: Component in a minimized Frame has focus and receives key events
XAWT: a window natively focused may request focus in it only synthetically Reviewed-by: son
This commit is contained in:
parent
06e3882354
commit
e1d1e39f49
jdk
src/solaris/classes/sun/awt/X11
test/java/awt/Focus/IconifiedFrameFocusChangeTest
@ -420,40 +420,36 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget
|
||||
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 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget
|
||||
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) {
|
||||
|
@ -1013,16 +1013,6 @@ abstract class XDecoratedPeer extends XWindowPeer {
|
||||
|
||||
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 @@ abstract class XDecoratedPeer extends XWindowPeer {
|
||||
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;
|
||||
|
@ -582,7 +582,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
((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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean isWMStateNetHidden() {
|
||||
protected boolean isWMStateNetHidden() {
|
||||
XNETProtocol protocol = XWM.getWM().getNETProtocol();
|
||||
return (protocol != null && protocol.isWMStateNetHidden(this));
|
||||
}
|
||||
@ -1740,6 +1748,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
return window;
|
||||
}
|
||||
|
||||
public boolean requestWindowFocus(XWindowPeer actualFocusedWindow) {
|
||||
setActualFocusedWindow(actualFocusedWindow);
|
||||
return requestWindowFocus();
|
||||
}
|
||||
|
||||
public boolean requestWindowFocus() {
|
||||
return requestWindowFocus(0, false);
|
||||
}
|
||||
@ -1748,25 +1761,25 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
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;
|
||||
|
124
jdk/test/java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java
Normal file
124
jdk/test/java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user