IDEA-339714 Wayland: some popup-like windows disappear immediately

GitOrigin-RevId: bec8c2d404cd8615c73eb311335d3c3d1d5c5f91
This commit is contained in:
Maxim Kartashev
2023-12-11 10:23:23 +00:00
committed by intellij-monorepo-bot
parent 43f454ee2d
commit b1814d0a22
2 changed files with 58 additions and 33 deletions
@@ -10,6 +10,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.ui.jcef.JBCefBrowserBase;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.StartupUiUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -46,6 +47,20 @@ public final class IdePopupManager implements IdeEventQueue.EventDispatcher {
LOG.warn("Skipped " + e);
return false;
}
if (StartupUiUtil.isWaylandToolkit()) {
// Reasons for skipping 'focus lost'-like events on Wayland:
// - When a new popup window appears, the main frame looses focus, but the "opposite window"
// for that event is null (because Wayland); this can be solved by waiting a bit
// (several hundreds ms) for
// KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow()
// to become non-null.
// - When a (popup) window is dragged, it also looses focus (because Wayland); this one is
// not solvable because there's no guarantee that the focus will get back, nor is there
// a notification that the drag is actually happening.
return false;
}
if (!isPopupActive()) return false;
Window sourceWindow = ((WindowEvent)e).getWindow();
@@ -57,36 +72,9 @@ public final class IdePopupManager implements IdeEventQueue.EventDispatcher {
return false;
}
Window focused = ((WindowEvent)e).getOppositeWindow();
if (focused == null) {
focused = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (focused == null) {
// Check if any browser is in focus (java focus can be in the process of transfer).
JBCefBrowserBase browser = JBCefBrowserBase.getFocusedBrowser();
if (browser != null && browser.getComponent() != null) {
focused = SwingUtilities.getWindowAncestor(browser.getComponent());
}
}
}
Component ultimateParentForFocusedComponent = UIUtil.findUltimateParent(focused);
Component ultimateParentForEventWindow = UIUtil.findUltimateParent(sourceWindow);
boolean shouldCloseAllPopup = false;
if (ultimateParentForEventWindow == null || ultimateParentForFocusedComponent == null) {
shouldCloseAllPopup = true;
}
if (!shouldCloseAllPopup && ultimateParentForEventWindow instanceof IdeFrame ultimateParentWindowForEvent) {
if (ultimateParentWindowForEvent.isInFullScreen()
&& !ultimateParentForFocusedComponent.equals(ultimateParentForEventWindow)) {
shouldCloseAllPopup = true;
}
}
if (shouldCloseAllPopup) {
closeAllPopups();
}
Window focusedWindow = ((WindowEvent)e).getOppositeWindow();
maybeCloseAllPopups(focusedWindow, sourceWindow);
return false;
}
else if (e instanceof KeyEvent keyEvent) {
// the following is copied from IdeKeyEventDispatcher
@@ -116,6 +104,38 @@ public final class IdePopupManager implements IdeEventQueue.EventDispatcher {
return false;
}
private void maybeCloseAllPopups(Window focused, Window sourceWindow) {
if (focused == null) {
focused = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (focused == null) {
// Check if any browser is in focus (java focus can be in the process of transfer).
JBCefBrowserBase browser = JBCefBrowserBase.getFocusedBrowser();
if (browser != null && browser.getComponent() != null) {
focused = SwingUtilities.getWindowAncestor(browser.getComponent());
}
}
}
Component ultimateParentForFocusedComponent = UIUtil.findUltimateParent(focused);
Component ultimateParentForEventWindow = UIUtil.findUltimateParent(sourceWindow);
boolean shouldCloseAllPopup = false;
if (ultimateParentForEventWindow == null || ultimateParentForFocusedComponent == null) {
shouldCloseAllPopup = true;
}
if (!shouldCloseAllPopup && ultimateParentForEventWindow instanceof IdeFrame ultimateParentWindowForEvent) {
if (ultimateParentWindowForEvent.isInFullScreen()
&& !ultimateParentForFocusedComponent.equals(ultimateParentForEventWindow)) {
shouldCloseAllPopup = true;
}
}
if (shouldCloseAllPopup) {
closeAllPopups();
}
}
public void push(IdePopupEventDispatcher dispatcher) {
myDispatchStack.remove(dispatcher);
myDispatchStack.add(dispatcher);
@@ -2,6 +2,7 @@
package com.intellij.ui;
import com.intellij.util.ui.StartupUiUtil;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.JBR;
import org.intellij.lang.annotations.JdkConstants;
@@ -210,8 +211,12 @@ abstract class WindowMouseListener extends MouseAdapter implements MouseInputLis
protected void notifyResized() {}
private static boolean jbrMoveSupported(Component component) {
// The JBR team states that isWindowMoveSupported works only for Frame/Dialog
return (component instanceof Frame || component instanceof Dialog)
&& JBR.isWindowMoveSupported();
if (StartupUiUtil.isWaylandToolkit()) {
return (component instanceof Window window) && window.getType() != Window.Type.POPUP;
} else {
// The JBR team states that isWindowMoveSupported works only for Frame/Dialog
return (component instanceof Frame || component instanceof Dialog)
&& JBR.isWindowMoveSupported();
}
}
}