JBR-6145 [Wayland toolkit] Popup windows aren't focusable

A partial solution. Cases not still covered:
* Alt+tab from the app and back should keep popup focused if it was focused initially
* Mouse clicks between popup and owner should transfer focus as expected

(cherry picked from commit 903231dc50)
This commit is contained in:
Dmitry Batrak
2023-09-29 20:14:01 +03:00
committed by jbrbot
parent d73441d7fc
commit 6b16ae264e
3 changed files with 74 additions and 17 deletions

View File

@@ -206,20 +206,17 @@ public class WLComponentPeer implements ComponentPeer {
public boolean requestFocus(Component lightweightChild, boolean temporary,
boolean focusedWindowChangeAllowed, long time,
FocusEvent.Cause cause) {
final Component currentlyFocused = WLKeyboardFocusManagerPeer.getInstance().getCurrentFocusOwner();
if (currentlyFocused == null)
final Window currentlyFocusedWindow = WLKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
if (currentlyFocusedWindow == null)
return false;
WLComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(currentlyFocused);
if (peer == null)
return false;
if (this == peer) {
Window targetDecoratedWindow = getNativelyFocusableOwnerOrSelf(target);
if (currentlyFocusedWindow == targetDecoratedWindow) {
WLKeyboardFocusManagerPeer.deliverFocus(lightweightChild,
target,
null,
true,
cause,
WLKeyboardFocusManagerPeer.getInstance().getCurrentFocusOwner());
null);
} else {
return false;
}
@@ -286,9 +283,12 @@ public class WLComponentPeer implements ComponentPeer {
* Returns true if our target should be treated as a popup in Wayland's sense,
* i.e. it has to have a parent to position relative to.
*/
private boolean targetIsWlPopup() {
return target instanceof Window window
&& window.getType() == Window.Type.POPUP
protected boolean targetIsWlPopup() {
return target instanceof Window window && isWlPopup(window);
}
static boolean isWlPopup(Window window) {
return window.getType() == Window.Type.POPUP
&& AWTAccessor.getWindowAccessor().getPopupParent(window) != null;
}
@@ -1173,4 +1173,23 @@ public class WLComponentPeer implements ComponentPeer {
WLToolkit.awtLock();
}
}
private static void startMovingWindowTogetherWithMouse(Window window, int mouseButton)
{
final AWTAccessor.ComponentAccessor acc = AWTAccessor.getComponentAccessor();
ComponentPeer peer = acc.getPeer(window);
if (peer instanceof WLComponentPeer wlComponentPeer) {
wlComponentPeer.startDrag();
} else {
throw new IllegalArgumentException("AWT window must have WLComponentPeer as its peer");
}
}
static Window getNativelyFocusableOwnerOrSelf(Component component) {
Window result = component instanceof Window window ? window : SwingUtilities.getWindowAncestor(component);
while (result != null && isWlPopup(result)) {
result = result.getOwner();
}
return result;
}
}

View File

@@ -35,7 +35,8 @@ public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
@Override
public void setCurrentFocusOwner(Component comp) {
if (comp != null && comp != currentFocusedWindow) {
if (comp != null && (!(comp instanceof Window window) ||
WLComponentPeer.getNativelyFocusableOwnerOrSelf(window) != currentFocusedWindow)) {
// In Wayland, only Window can be focused, not any widget in it.
focusLog.severe("Unexpected focus owner set in a Window: " + comp);
}

View File

@@ -26,11 +26,13 @@ package sun.awt.wl;
import sun.awt.AWTAccessor;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.peer.ComponentPeer;
import java.awt.peer.WindowPeer;
public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
private static Font defaultFont;
private Dialog blocker;
static synchronized Font getDefaultFont() {
if (null == defaultFont) {
@@ -55,14 +57,29 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
@Override
protected void wlSetVisible(boolean v) {
if (v && targetIsWlPopup() && shouldBeFocusedOnShowing()) {
requestWindowFocus();
}
super.wlSetVisible(v);
final AWTAccessor.ComponentAccessor acc = AWTAccessor.getComponentAccessor();
for (Component c : ((Window)target).getComponents()) {
for (Component c : getWindow().getComponents()) {
ComponentPeer cPeer = acc.getPeer(c);
if (cPeer instanceof WLComponentPeer) {
((WLComponentPeer) cPeer).wlSetVisible(v);
}
}
if (!v && targetIsWlPopup() && getWindow().isFocused()) {
Window targetOwner = getWindow().getOwner();
while (targetOwner != null && (targetOwner.getOwner() != null && !targetOwner.isFocusableWindow())) {
targetOwner = targetOwner.getOwner();
}
if (targetOwner != null) {
WLWindowPeer wndpeer = AWTAccessor.getComponentAccessor().getPeer(targetOwner);
if (wndpeer != null) {
wndpeer.requestWindowFocus();
}
}
}
}
@Override
@@ -109,7 +126,7 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
@Override
public void setModalBlocked(Dialog blocker, boolean blocked) {
this.blocker = blocked ? blocker : null;
}
@Override
@@ -148,8 +165,28 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
@Override
public GraphicsConfiguration getAppropriateGraphicsConfiguration(
GraphicsConfiguration gc)
{
GraphicsConfiguration gc) {
return gc;
}
private Window getWindow() {
return (Window) target;
}
private boolean shouldBeFocusedOnShowing() {
Window window = getWindow();
return window.isFocusableWindow() &&
window.isAutoRequestFocus() &&
blocker == null;
}
// supporting only 'synthetic' focus transfers for now (when natively focused window stays the same)
private void requestWindowFocus() {
Window window = getWindow();
Window nativeFocusTarget = getNativelyFocusableOwnerOrSelf(window);
if (nativeFocusTarget != null &&
WLKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == nativeFocusTarget) {
WLToolkit.postEvent(new WindowEvent(window, WindowEvent.WINDOW_GAINED_FOCUS));
}
}
}