mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 19:44:41 +02:00
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
4 changed files with 213 additions and 86 deletions
|
@ -420,40 +420,36 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget
|
||||||
case SNFH_SUCCESS_PROCEED:
|
case SNFH_SUCCESS_PROCEED:
|
||||||
// Currently we just generate focus events like we deal with lightweight instead of calling
|
// Currently we just generate focus events like we deal with lightweight instead of calling
|
||||||
// XSetInputFocus on native window
|
// 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
|
* 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
|
* 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
|
* 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
|
* in requests list - and it breaks our requests sequence as first record on WGF should be the last
|
||||||
* owner which had focus before WLF. So, we should not add request record for such requests
|
* 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.
|
* but store this component in mostRecent - and return true as before for compatibility.
|
||||||
*/
|
*/
|
||||||
Window parentWindow = getContainingWindow(target);
|
Window parentWindow = getContainingWindow(target);
|
||||||
if (parentWindow != null) {
|
if (parentWindow == null) {
|
||||||
// and check that it is focused
|
return rejectFocusRequestHelper("WARNING: Parent window is null");
|
||||||
if (!parentWindow.isFocused()) {
|
}
|
||||||
XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
|
XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
|
||||||
|
if (wpeer == null) {
|
||||||
|
return rejectFocusRequestHelper("WARNING: Parent window's peer is null");
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Fix for 6314575.
|
* Passing null 'actualFocusedWindow' as we don't want to restore focus on it
|
||||||
* Shouldn't restore focus on 'actualFocusedWindow'
|
* when a component inside a Frame is requesting focus.
|
||||||
* when a component inside a Frame is requesting it.
|
* See 6314575 for details.
|
||||||
*/
|
*/
|
||||||
wpeer.setActualFocusedWindow(null);
|
boolean res = wpeer.requestWindowFocus(null);
|
||||||
|
|
||||||
boolean res = wpeer.requestWindowFocus();
|
|
||||||
if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Requested window focus: " + res);
|
if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Requested window focus: " + res);
|
||||||
// If parent window can be made focused and has been made focused(synchronously)
|
// If parent window can be made focused and has been made focused(synchronously)
|
||||||
// then we can proceed with children, otherwise we retreat.
|
// then we can proceed with children, otherwise we retreat.
|
||||||
if (!(res && parentWindow.isFocused())) {
|
if (!(res && parentWindow.isFocused())) {
|
||||||
focusLog.finer("Waiting for asynchronous processing of window focus request");
|
return rejectFocusRequestHelper("Waiting for asynchronous processing of the request");
|
||||||
KeyboardFocusManagerPeerImpl.removeLastFocusRequest(target);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (focusLog.isLoggable(Level.FINER)) focusLog.finer("WARNING: Parent window is null");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We simulate heavyweight behavior of Motif - component receives focus right
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean rejectFocusRequestHelper(String logMsg) {
|
||||||
|
if (focusLog.isLoggable(Level.FINER)) focusLog.finer(logMsg);
|
||||||
|
KeyboardFocusManagerPeerImpl.removeLastFocusRequest(target);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void handleJavaFocusEvent(AWTEvent e) {
|
void handleJavaFocusEvent(AWTEvent e) {
|
||||||
if (focusLog.isLoggable(Level.FINER)) focusLog.finer(e.toString());
|
if (focusLog.isLoggable(Level.FINER)) focusLog.finer(e.toString());
|
||||||
if (e.getID() == FocusEvent.FOCUS_GAINED) {
|
if (e.getID() == FocusEvent.FOCUS_GAINED) {
|
||||||
|
|
|
@ -1013,16 +1013,6 @@ abstract class XDecoratedPeer extends XWindowPeer {
|
||||||
|
|
||||||
private void handleWmTakeFocus(XClientMessageEvent cl) {
|
private void handleWmTakeFocus(XClientMessageEvent cl) {
|
||||||
focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}", new Object[]{this});
|
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);
|
requestWindowFocus(cl.get_data(1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,53 +1114,51 @@ abstract class XDecoratedPeer extends XWindowPeer {
|
||||||
focusLog.fine("Request for decorated window focus");
|
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 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.
|
// 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 focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
|
||||||
Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
|
Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
|
||||||
|
|
||||||
focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}",
|
focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}",
|
||||||
new Object[]{ Boolean.valueOf(win == activeWindow),
|
new Object[]{ Boolean.valueOf(target == activeWindow),
|
||||||
Boolean.valueOf(win == focusedWindow)});
|
Boolean.valueOf(target == focusedWindow)});
|
||||||
|
|
||||||
XWindowPeer toFocus = this;
|
XWindowPeer toFocus = this;
|
||||||
while (toFocus.nextTransientFor != null) {
|
while (toFocus.nextTransientFor != null) {
|
||||||
toFocus = toFocus.nextTransientFor;
|
toFocus = toFocus.nextTransientFor;
|
||||||
}
|
}
|
||||||
|
if (toFocus == null || !toFocus.focusAllowedFor()) {
|
||||||
if (this == toFocus) {
|
// This might change when WM will have property to determine focus policy.
|
||||||
if (focusAllowedFor()) {
|
// Right now, because policy is unknown we can't be sure we succedded
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (this == toFocus) {
|
||||||
|
if (isWMStateNetHidden()) {
|
||||||
|
focusLog.fine("The window is unmapped, so rejecting the request");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else if (toFocus.focusAllowedFor()) {
|
if (target == activeWindow && target != focusedWindow) {
|
||||||
focusLog.fine("Requesting focus to " + toFocus);
|
// 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) {
|
if (timeProvided) {
|
||||||
toFocus.requestXFocus(time);
|
toFocus.requestXFocus(time);
|
||||||
} else {
|
} else {
|
||||||
toFocus.requestXFocus();
|
toFocus.requestXFocus();
|
||||||
}
|
}
|
||||||
return false;
|
return (this == toFocus);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XWindowPeer actualFocusedWindow = null;
|
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() {
|
static XWindowPeer getNativeFocusedWindowPeer() {
|
||||||
XBaseWindow baseWindow = XToolkit.windowToXWindow(xGetInputFocus());
|
XBaseWindow baseWindow = XToolkit.windowToXWindow(xGetInputFocus());
|
||||||
|
@ -591,6 +591,14 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||||
((XFocusProxyWindow)baseWindow).getOwner() : null;
|
((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() {
|
boolean isFocusableWindow() {
|
||||||
if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread())
|
if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread())
|
||||||
{
|
{
|
||||||
|
@ -1252,7 +1260,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isWMStateNetHidden() {
|
protected boolean isWMStateNetHidden() {
|
||||||
XNETProtocol protocol = XWM.getWM().getNETProtocol();
|
XNETProtocol protocol = XWM.getWM().getNETProtocol();
|
||||||
return (protocol != null && protocol.isWMStateNetHidden(this));
|
return (protocol != null && protocol.isWMStateNetHidden(this));
|
||||||
}
|
}
|
||||||
|
@ -1740,6 +1748,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean requestWindowFocus(XWindowPeer actualFocusedWindow) {
|
||||||
|
setActualFocusedWindow(actualFocusedWindow);
|
||||||
|
return requestWindowFocus();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean requestWindowFocus() {
|
public boolean requestWindowFocus() {
|
||||||
return requestWindowFocus(0, false);
|
return requestWindowFocus(0, false);
|
||||||
}
|
}
|
||||||
|
@ -1748,26 +1761,26 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||||
focusLog.fine("Request for window focus");
|
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 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.
|
// If this is Window and its owner Frame is active we can be sure request succedded.
|
||||||
Window win = (Window) target;
|
Window ownerWindow = XWindowPeer.getDecoratedOwner((Window)target);
|
||||||
Window owner = XWindowPeer.getDecoratedOwner(win);
|
Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
|
||||||
|
Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
|
||||||
|
|
||||||
final Window activeWindow =
|
if (isWMStateNetHidden()) {
|
||||||
XWindowPeer.getDecoratedOwner(XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow());
|
focusLog.fine("The window is unmapped, so rejecting the request");
|
||||||
if (activeWindow == owner) {
|
return false;
|
||||||
|
}
|
||||||
|
if (activeWindow == ownerWindow) {
|
||||||
focusLog.fine("Parent window is active - generating focus for this window");
|
focusLog.fine("Parent window is active - generating focus for this window");
|
||||||
handleWindowFocusInSync(-1);
|
handleWindowFocusInSync(-1);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
focusLog.fine("Parent window is not active");
|
|
||||||
}
|
}
|
||||||
ComponentPeer peer = ComponentAccessor.getPeer(owner);
|
focusLog.fine("Parent window is not active");
|
||||||
if (peer instanceof XDecoratedPeer) {
|
|
||||||
XDecoratedPeer wpeer = (XDecoratedPeer) peer;
|
XDecoratedPeer wpeer = (XDecoratedPeer)ComponentAccessor.getPeer(ownerWindow);
|
||||||
if (wpeer.requestWindowFocus(this, time, timeProvided)) {
|
if (wpeer != null && wpeer.requestWindowFocus(this, time, timeProvided)) {
|
||||||
focusLog.fine("Parent window accepted focus request - generating focus for this window");
|
focusLog.fine("Parent window accepted focus request - generating focus for this window");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
focusLog.fine("Denied - parent window is not active and didn't accept focus request");
|
focusLog.fine("Denied - parent window is not active and didn't accept focus request");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue