From d281245b4b7840575d16ef033d0a2e84e618afbc Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Tue, 16 Sep 2025 13:02:47 +0400 Subject: [PATCH] IJPL-207199 Popups are shown on top of other windows In Wayland, focus transfer between windows is not "atomic": indeterminate amount of time can pass between focus lost and gain, and the corresponding even would have null for the 'opposite window' property. When a popup is shown, the keyboard focus remains on the parent window. So if a popup is shown as a top-level window, make sure it is NOT canceled on window deactivation. The existing cancellation logic remains valid for regular popups, however. GitOrigin-RevId: fd55354e5b3930736c4b7f3442d91d9f96506bd1 --- .../SearchEverywhereManagerImpl.java | 1 + .../src/com/intellij/ide/IdePopupManager.java | 13 ------------- .../src/com/intellij/ide/actions/Switcher.kt | 2 +- .../platform/recentFiles/frontend/Switcher.kt | 2 +- .../frontend/src/SeFrontendService.kt | 1 + 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index 5d943bb4a2b3..afe46c18f293 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -106,6 +106,7 @@ public final class SearchEverywhereManagerImpl implements SearchEverywhereManage .setProject(myProject) .setModalContext(false) .setNormalWindowLevel(StartupUiUtil.isWaylandToolkit()) + .setCancelOnWindowDeactivation(!StartupUiUtil.isWaylandToolkit()) .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false) diff --git a/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java b/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java index 8b7ddf832cbf..6f6d32be3c5f 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java +++ b/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java @@ -45,19 +45,6 @@ public final class IdePopupManager implements IdeEventQueue.EventDispatcher { 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(); diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.kt b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.kt index 022fd1cd316e..1477f36dd2e6 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.kt +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.kt @@ -359,7 +359,7 @@ object Switcher : BaseSwitcherAction(null) { .setModalContext(false) .setFocusable(true) .setRequestFocus(true) - .setCancelOnWindowDeactivation(true) + .setCancelOnWindowDeactivation(!pinned || !StartupUiUtil.isWaylandToolkit()) .setCancelOnOtherWindowOpen(true) .setMovable(pinned) .setDimensionServiceKey(if (pinned) project else null, if (pinned) "SwitcherDM" else null, false) diff --git a/platform/recentFiles/frontend/src/com/intellij/platform/recentFiles/frontend/Switcher.kt b/platform/recentFiles/frontend/src/com/intellij/platform/recentFiles/frontend/Switcher.kt index c6cb9b10e452..124e11c20c0b 100644 --- a/platform/recentFiles/frontend/src/com/intellij/platform/recentFiles/frontend/Switcher.kt +++ b/platform/recentFiles/frontend/src/com/intellij/platform/recentFiles/frontend/Switcher.kt @@ -394,7 +394,7 @@ object Switcher : BaseSwitcherAction(null), ActionRemoteBehaviorSpecification.Fr .setModalContext(false) .setFocusable(true) .setRequestFocus(true) - .setCancelOnWindowDeactivation(true) + .setCancelOnWindowDeactivation(!pinned || !StartupUiUtil.isWaylandToolkit()) .setCancelOnOtherWindowOpen(true) .setMovable(pinned) .setDimensionServiceKey(if (pinned) project else null, if (pinned) "SwitcherDM" else null, false) diff --git a/platform/searchEverywhere/frontend/src/SeFrontendService.kt b/platform/searchEverywhere/frontend/src/SeFrontendService.kt index 941e06cbeb85..7d425bcaa398 100644 --- a/platform/searchEverywhere/frontend/src/SeFrontendService.kt +++ b/platform/searchEverywhere/frontend/src/SeFrontendService.kt @@ -214,6 +214,7 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou .setProject(project) .setModalContext(false) .setNormalWindowLevel(StartupUiUtil.isWaylandToolkit()) + .setCancelOnWindowDeactivation(!StartupUiUtil.isWaylandToolkit()) .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false)