diff --git a/Modules/MainScreen/MainScreen.qml b/Modules/MainScreen/MainScreen.qml index 8b8fe9e49..8cd6ef194 100644 --- a/Modules/MainScreen/MainScreen.qml +++ b/Modules/MainScreen/MainScreen.qml @@ -50,11 +50,17 @@ PanelWindow { return WlrKeyboardFocus.None; } // Panel open on THIS screen: use panel's preferred focus mode - // Exception: Hyprland's Exclusive captures all input globally, preventing - // click-to-close from working on other monitors, so always use OnDemand - if (root.isPanelOpen && !CompositorService.isHyprland) { + if (root.isPanelOpen) { + // Hyprland's Exclusive captures ALL input globally (including pointer), + // preventing click-to-close from working on other monitors. + // Workaround: briefly use Exclusive when panel opens (for text input focus), + // then switch to OnDemand (for click-to-close on other screens). + if (CompositorService.isHyprland) { + return PanelService.isInitializingKeyboard ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.OnDemand; + } return PanelService.openedPanel.exclusiveKeyboard ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.OnDemand; } + // Panel open on ANOTHER screen: OnDemand allows receiving pointer events for click-to-close return WlrKeyboardFocus.OnDemand; } diff --git a/Services/UI/PanelService.qml b/Services/UI/PanelService.qml index d6938af61..e255d8ead 100644 --- a/Services/UI/PanelService.qml +++ b/Services/UI/PanelService.qml @@ -1,5 +1,6 @@ pragma Singleton +import QtQuick import Quickshell import qs.Commons @@ -14,6 +15,9 @@ Singleton { property var openedPanel: null property var closingPanel: null property bool closedImmediately: false + // Brief window after panel opens where Exclusive keyboard is allowed on Hyprland + // This allows text inputs to receive focus, then switches to OnDemand for click-to-close + property bool isInitializingKeyboard: false signal willOpen signal didClose @@ -87,6 +91,16 @@ Singleton { return name in registeredPanels; } + // Timer to switch from Exclusive to OnDemand keyboard focus on Hyprland + Timer { + id: keyboardInitTimer + interval: 100 + repeat: false + onTriggered: { + root.isInitializingKeyboard = false; + } + } + // Helper to keep only one panel open at any time function willOpenPanel(panel) { if (openedPanel && openedPanel !== panel) { @@ -100,6 +114,12 @@ Singleton { openedPanel = panel; assignToSlot(0, panel); + // Start keyboard initialization period (for Hyprland workaround) + if (panel.exclusiveKeyboard) { + isInitializingKeyboard = true; + keyboardInitTimer.restart(); + } + // emit signal willOpen(); } @@ -115,6 +135,10 @@ Singleton { assignToSlot(1, null); } + // Reset keyboard init state + isInitializingKeyboard = false; + keyboardInitTimer.stop(); + // emit signal didClose(); }