mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-16 08:05:19 -04:00
refactor: implement keyboard focus management
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
// Manages keyboard focus policy for popouts, modals, and Hyprland focus grabs
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function keyboardFocus(active, customFocus) {
|
||||||
|
if (PopoutManager.screenshotActive)
|
||||||
|
return WlrKeyboardFocus.None;
|
||||||
|
if (customFocus !== null && customFocus !== undefined)
|
||||||
|
return customFocus;
|
||||||
|
if (!active)
|
||||||
|
return WlrKeyboardFocus.None;
|
||||||
|
if (CompositorService.useHyprlandFocusGrab)
|
||||||
|
return WlrKeyboardFocus.OnDemand;
|
||||||
|
return WlrKeyboardFocus.Exclusive;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wantsGrab(active, customFocus) {
|
||||||
|
return CompositorService.useHyprlandFocusGrab && keyboardFocus(active, customFocus) === WlrKeyboardFocus.OnDemand;
|
||||||
|
}
|
||||||
|
|
||||||
|
property list<var> barWindows: []
|
||||||
|
|
||||||
|
function registerBarWindow(window) {
|
||||||
|
if (!window || barWindows.indexOf(window) !== -1)
|
||||||
|
return;
|
||||||
|
barWindows = barWindows.concat([window]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterBarWindow(window) {
|
||||||
|
const idx = barWindows.indexOf(window);
|
||||||
|
if (idx === -1)
|
||||||
|
return;
|
||||||
|
const next = barWindows.slice();
|
||||||
|
next.splice(idx, 1);
|
||||||
|
barWindows = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -11,11 +10,6 @@ DankModal {
|
|||||||
|
|
||||||
layerNamespace: "dms:bluetooth-pairing"
|
layerNamespace: "dms:bluetooth-pairing"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [root.contentWindow]
|
|
||||||
active: root.useHyprlandFocusGrab && root.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
property string deviceName: ""
|
property string deviceName: ""
|
||||||
property string deviceAddress: ""
|
property string deviceAddress: ""
|
||||||
property string requestType: ""
|
property string requestType: ""
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Clipboard
|
import qs.Modals.Clipboard
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
@@ -12,11 +11,6 @@ DankModal {
|
|||||||
|
|
||||||
layerNamespace: "dms:clipboard"
|
layerNamespace: "dms:clipboard"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [clipboardHistoryModal.contentWindow]
|
|
||||||
active: clipboardHistoryModal.useHyprlandFocusGrab && clipboardHistoryModal.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
if (shouldBeVisible) {
|
if (shouldBeVisible) {
|
||||||
hide();
|
hide();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell.Hyprland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
@@ -52,6 +53,22 @@ Item {
|
|||||||
focus: true
|
focus: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One focus grab for every modal; on Hyprland this is what delivers
|
||||||
|
// keyboard focus to the OnDemand surface, identically in both modes.
|
||||||
|
// The clickCatcher is whitelisted so an outside click is delivered to
|
||||||
|
// it (closing the modal) instead of being consumed clearing the grab.
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
windows: {
|
||||||
|
const list = [];
|
||||||
|
if (root.contentWindow)
|
||||||
|
list.push(root.contentWindow);
|
||||||
|
if (root.clickCatcher)
|
||||||
|
list.push(root.clickCatcher);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
active: KeyboardFocus.wantsGrab(root.shouldHaveFocus, root.customKeyboardFocus)
|
||||||
|
}
|
||||||
readonly property var contentWindow: impl.item ? impl.item.contentWindow : null
|
readonly property var contentWindow: impl.item ? impl.item.contentWindow : null
|
||||||
readonly property var clickCatcher: impl.item ? impl.item.clickCatcher : null
|
readonly property var clickCatcher: impl.item ? impl.item.clickCatcher : null
|
||||||
readonly property var effectiveScreen: impl.item ? impl.item.effectiveScreen : null
|
readonly property var effectiveScreen: impl.item ? impl.item.effectiveScreen : null
|
||||||
|
|||||||
@@ -509,15 +509,7 @@ Item {
|
|||||||
"error": true
|
"error": true
|
||||||
})
|
})
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldHaveFocus, customKeyboardFocus)
|
||||||
if (customKeyboardFocus !== null)
|
|
||||||
return customKeyboardFocus;
|
|
||||||
if (!shouldHaveFocus)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (root.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
|
|||||||
@@ -259,15 +259,7 @@ Item {
|
|||||||
"error": true
|
"error": true
|
||||||
})
|
})
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldHaveFocus, customKeyboardFocus)
|
||||||
if (customKeyboardFocus !== null)
|
|
||||||
return customKeyboardFocus;
|
|
||||||
if (!shouldHaveFocus)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (root.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
@@ -13,11 +12,6 @@ DankModal {
|
|||||||
|
|
||||||
layerNamespace: "dms:color-picker"
|
layerNamespace: "dms:color-picker"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [root.contentWindow]
|
|
||||||
active: root.useHyprlandFocusGrab && root.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
property string pickerTitle: I18n.tr("Choose Color")
|
property string pickerTitle: I18n.tr("Choose Color")
|
||||||
property color selectedColor: SessionData.recentColors.length > 0 ? SessionData.recentColors[0] : Theme.primary
|
property color selectedColor: SessionData.recentColors.length > 0 ? SessionData.recentColors[0] : Theme.primary
|
||||||
property var onColorSelectedCallback: null
|
property var onColorSelectedCallback: null
|
||||||
|
|||||||
@@ -441,8 +441,6 @@ Item {
|
|||||||
spotlightOpen = true;
|
spotlightOpen = true;
|
||||||
backgroundWindow.visible = true;
|
backgroundWindow.visible = true;
|
||||||
contentWindow.visible = true;
|
contentWindow.visible = true;
|
||||||
if (useHyprlandFocusGrab)
|
|
||||||
focusGrab.active = true;
|
|
||||||
|
|
||||||
// Load content and initialize (but no forceActiveFocus — that's deferred)
|
// Load content and initialize (but no forceActiveFocus — that's deferred)
|
||||||
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
||||||
@@ -485,7 +483,6 @@ Item {
|
|||||||
|
|
||||||
keyboardActive = false;
|
keyboardActive = false;
|
||||||
spotlightOpen = false;
|
spotlightOpen = false;
|
||||||
focusGrab.active = false;
|
|
||||||
ModalManager.closeModal(modalHandle);
|
ModalManager.closeModal(modalHandle);
|
||||||
closeCleanupTimer.start();
|
closeCleanupTimer.start();
|
||||||
}
|
}
|
||||||
@@ -541,7 +538,7 @@ Item {
|
|||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
id: focusGrab
|
id: focusGrab
|
||||||
windows: [contentWindow]
|
windows: [contentWindow]
|
||||||
active: false
|
active: root.useHyprlandFocusGrab && root.spotlightOpen
|
||||||
|
|
||||||
onCleared: {
|
onCleared: {
|
||||||
if (spotlightOpen) {
|
if (spotlightOpen) {
|
||||||
@@ -685,7 +682,7 @@ Item {
|
|||||||
WlrLayershell.namespace: "dms:spotlight"
|
WlrLayershell.namespace: "dms:spotlight"
|
||||||
WlrLayershell.layer: root.effectiveLauncherLayer
|
WlrLayershell.layer: root.effectiveLauncherLayer
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None)
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(keyboardActive, null)
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
|
|||||||
@@ -164,8 +164,6 @@ Item {
|
|||||||
openedFromOverview = false;
|
openedFromOverview = false;
|
||||||
keyboardActive = true;
|
keyboardActive = true;
|
||||||
ModalManager.openModal(modalHandle);
|
ModalManager.openModal(modalHandle);
|
||||||
if (useHyprlandFocusGrab)
|
|
||||||
focusGrab.active = true;
|
|
||||||
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +199,6 @@ Item {
|
|||||||
contentVisible = false;
|
contentVisible = false;
|
||||||
keyboardActive = false;
|
keyboardActive = false;
|
||||||
spotlightOpen = false;
|
spotlightOpen = false;
|
||||||
focusGrab.active = false;
|
|
||||||
ModalManager.closeModal(modalHandle);
|
ModalManager.closeModal(modalHandle);
|
||||||
closeCleanupTimer.start();
|
closeCleanupTimer.start();
|
||||||
}
|
}
|
||||||
@@ -231,7 +228,7 @@ Item {
|
|||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
id: focusGrab
|
id: focusGrab
|
||||||
windows: [launcherWindow]
|
windows: [launcherWindow]
|
||||||
active: false
|
active: root.useHyprlandFocusGrab && root.keyboardActive
|
||||||
onCleared: {
|
onCleared: {
|
||||||
if (spotlightOpen)
|
if (spotlightOpen)
|
||||||
hide();
|
hide();
|
||||||
@@ -337,7 +334,7 @@ Item {
|
|||||||
WlrLayershell.namespace: "dms:spotlight"
|
WlrLayershell.namespace: "dms:spotlight"
|
||||||
WlrLayershell.layer: root.effectiveLauncherLayer
|
WlrLayershell.layer: root.effectiveLauncherLayer
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None)
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(keyboardActive, null)
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
|
|||||||
@@ -172,8 +172,6 @@ Item {
|
|||||||
|
|
||||||
keyboardActive = true;
|
keyboardActive = true;
|
||||||
ModalManager.openModal(modalHandle);
|
ModalManager.openModal(modalHandle);
|
||||||
if (useHyprlandFocusGrab)
|
|
||||||
focusGrab.active = true;
|
|
||||||
|
|
||||||
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
_ensureContentLoadedAndInitialize(query || "", mode || "");
|
||||||
}
|
}
|
||||||
@@ -211,7 +209,6 @@ Item {
|
|||||||
|
|
||||||
keyboardActive = false;
|
keyboardActive = false;
|
||||||
spotlightOpen = false;
|
spotlightOpen = false;
|
||||||
focusGrab.active = false;
|
|
||||||
ModalManager.closeModal(modalHandle);
|
ModalManager.closeModal(modalHandle);
|
||||||
|
|
||||||
closeCleanupTimer.start();
|
closeCleanupTimer.start();
|
||||||
@@ -262,7 +259,7 @@ Item {
|
|||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
id: focusGrab
|
id: focusGrab
|
||||||
windows: [launcherWindow]
|
windows: [launcherWindow]
|
||||||
active: false
|
active: root.useHyprlandFocusGrab && root.keyboardActive
|
||||||
|
|
||||||
onCleared: {
|
onCleared: {
|
||||||
if (spotlightOpen) {
|
if (spotlightOpen) {
|
||||||
@@ -373,7 +370,7 @@ Item {
|
|||||||
WlrLayershell.namespace: "dms:spotlight"
|
WlrLayershell.namespace: "dms:spotlight"
|
||||||
WlrLayershell.layer: root.effectiveLauncherLayer
|
WlrLayershell.layer: root.effectiveLauncherLayer
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None)
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(keyboardActive, null)
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import QtQml
|
import QtQml
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -29,11 +28,6 @@ DankModal {
|
|||||||
KeybindsService.loadCheatsheet();
|
KeybindsService.loadCheatsheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [root.contentWindow]
|
|
||||||
active: root.useHyprlandFocusGrab && root.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollDown() {
|
function scrollDown() {
|
||||||
if (!root.activeFlickable)
|
if (!root.activeFlickable)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Common
|
import qs.Common
|
||||||
@@ -45,12 +44,6 @@ DankModal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
id: grab
|
|
||||||
windows: [muxModal.contentWindow]
|
|
||||||
active: CompositorService.isHyprland && muxModal.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
if (shouldBeVisible) {
|
if (shouldBeVisible) {
|
||||||
hide();
|
hide();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
@@ -11,11 +10,6 @@ DankModal {
|
|||||||
|
|
||||||
layerNamespace: "dms:notification-center-modal"
|
layerNamespace: "dms:notification-center-modal"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [notificationModal.contentWindow]
|
|
||||||
active: notificationModal.useHyprlandFocusGrab && notificationModal.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool notificationModalOpen: false
|
property bool notificationModalOpen: false
|
||||||
property var notificationListRef: null
|
property var notificationListRef: null
|
||||||
property var historyListRef: null
|
property var historyListRef: null
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -13,11 +12,6 @@ DankModal {
|
|||||||
layerNamespace: "dms:power-menu"
|
layerNamespace: "dms:power-menu"
|
||||||
keepPopoutsOpen: true
|
keepPopoutsOpen: true
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
windows: [root.contentWindow]
|
|
||||||
active: root.useHyprlandFocusGrab && root.shouldHaveFocus
|
|
||||||
}
|
|
||||||
|
|
||||||
property int selectedIndex: 0
|
property int selectedIndex: 0
|
||||||
property int selectedRow: 0
|
property int selectedRow: 0
|
||||||
property int selectedCol: 0
|
property int selectedCol: 0
|
||||||
|
|||||||
@@ -109,15 +109,7 @@ DankPopout {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
customKeyboardFocus: {
|
customKeyboardFocus: anyModalOpen ? WlrKeyboardFocus.None : null
|
||||||
if (!shouldBeVisible)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (anyModalOpen)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
onBackgroundClicked: close()
|
onBackgroundClicked: close()
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ PanelWindow {
|
|||||||
id: barWindow
|
id: barWindow
|
||||||
readonly property var log: Log.scoped("DankBarWindow")
|
readonly property var log: Log.scoped("DankBarWindow")
|
||||||
|
|
||||||
|
Component.onDestruction: KeyboardFocus.unregisterBarWindow(barWindow)
|
||||||
|
|
||||||
required property var rootWindow
|
required property var rootWindow
|
||||||
required property var barConfig
|
required property var barConfig
|
||||||
property var modelData: item
|
property var modelData: item
|
||||||
@@ -555,6 +557,7 @@ PanelWindow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
KeyboardFocus.registerBarWindow(barWindow);
|
||||||
updateGpuTempConfig();
|
updateGpuTempConfig();
|
||||||
_updateBackgroundAlpha();
|
_updateBackgroundAlpha();
|
||||||
_updateHasMaximizedToplevel();
|
_updateHasMaximizedToplevel();
|
||||||
@@ -956,8 +959,13 @@ PanelWindow {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const screenName = barWindow.screen?.name;
|
const screenName = barWindow.screen?.name;
|
||||||
if (screenName && PopoutManager.currentPopoutsByScreen[screenName])
|
if (!screenName)
|
||||||
|
return;
|
||||||
|
if (PopoutManager.currentPopoutsByScreen[screenName])
|
||||||
PopoutManager.closeAllPopouts();
|
PopoutManager.closeAllPopouts();
|
||||||
|
if (ModalManager.currentModalsByScreen[screenName])
|
||||||
|
ModalManager.closeAllModalsExcept(null);
|
||||||
|
TrayMenuManager.closeAllMenus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,15 +38,7 @@ DankPopout {
|
|||||||
|
|
||||||
backgroundInteractive: !anyModalOpen
|
backgroundInteractive: !anyModalOpen
|
||||||
|
|
||||||
customKeyboardFocus: {
|
customKeyboardFocus: anyModalOpen ? WlrKeyboardFocus.None : null
|
||||||
if (!shouldBeVisible)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (anyModalOpen)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SystemUpdateService
|
target: SystemUpdateService
|
||||||
|
|||||||
@@ -980,21 +980,13 @@ BasePill {
|
|||||||
screen: root.parentScreen
|
screen: root.parentScreen
|
||||||
WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top
|
WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(root.menuOpen, null)
|
||||||
if (PopoutManager.screenshotActive)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (!root.menuOpen)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
WlrLayershell.namespace: "dms:tray-overflow-menu"
|
WlrLayershell.namespace: "dms:tray-overflow-menu"
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
windows: [overflowMenu]
|
windows: [overflowMenu].concat(KeyboardFocus.barWindows)
|
||||||
active: CompositorService.useHyprlandFocusGrab && root.useOverflowPopup && root.menuOpen
|
active: root.useOverflowPopup && KeyboardFocus.wantsGrab(root.menuOpen, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -1051,32 +1043,21 @@ BasePill {
|
|||||||
"leftBar": 0,
|
"leftBar": 0,
|
||||||
"rightBar": 0
|
"rightBar": 0
|
||||||
})
|
})
|
||||||
readonly property real effectiveBarSize: root.barThickness + root.barSpacing
|
readonly property real maskX: _overflowDismissZone.x
|
||||||
|
readonly property real maskY: _overflowDismissZone.y
|
||||||
|
readonly property real maskWidth: _overflowDismissZone.width
|
||||||
|
readonly property real maskHeight: _overflowDismissZone.height
|
||||||
|
|
||||||
readonly property real maskX: {
|
DismissZone {
|
||||||
const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0;
|
id: _overflowDismissZone
|
||||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
|
barPosition: overflowMenu.barPosition
|
||||||
return Math.max(triggeringBarX, adjacentLeftBar);
|
barX: overflowMenu.barX
|
||||||
}
|
barY: overflowMenu.barY
|
||||||
|
barWidth: overflowMenu.barWidth
|
||||||
readonly property real maskY: {
|
barHeight: overflowMenu.barHeight
|
||||||
const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0;
|
screenWidth: overflowMenu.width
|
||||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
|
screenHeight: overflowMenu.height
|
||||||
return Math.max(triggeringBarY, adjacentTopBar);
|
adjacentBarInfo: overflowMenu.adjacentBarInfo
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskWidth: {
|
|
||||||
const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0;
|
|
||||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
|
|
||||||
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar);
|
|
||||||
return Math.max(100, width - maskX - rightExclusion);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskHeight: {
|
|
||||||
const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0;
|
|
||||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
|
|
||||||
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar);
|
|
||||||
return Math.max(100, height - maskY - bottomExclusion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
@@ -1444,20 +1425,12 @@ BasePill {
|
|||||||
screen: menuRoot.parentScreen
|
screen: menuRoot.parentScreen
|
||||||
WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top
|
WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(menuRoot.showMenu, null)
|
||||||
if (PopoutManager.screenshotActive)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (!menuRoot.showMenu)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
windows: [menuWindow]
|
windows: [menuWindow].concat(KeyboardFocus.barWindows)
|
||||||
active: CompositorService.useHyprlandFocusGrab && menuRoot.showMenu
|
active: KeyboardFocus.wantsGrab(menuRoot.showMenu, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
@@ -1496,32 +1469,21 @@ BasePill {
|
|||||||
"leftBar": 0,
|
"leftBar": 0,
|
||||||
"rightBar": 0
|
"rightBar": 0
|
||||||
})
|
})
|
||||||
readonly property real effectiveBarSize: root.barThickness + root.barSpacing
|
readonly property real maskX: _menuDismissZone.x
|
||||||
|
readonly property real maskY: _menuDismissZone.y
|
||||||
|
readonly property real maskWidth: _menuDismissZone.width
|
||||||
|
readonly property real maskHeight: _menuDismissZone.height
|
||||||
|
|
||||||
readonly property real maskX: {
|
DismissZone {
|
||||||
const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0;
|
id: _menuDismissZone
|
||||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
|
barPosition: menuWindow.barPosition
|
||||||
return Math.max(triggeringBarX, adjacentLeftBar);
|
barX: menuWindow.barX
|
||||||
}
|
barY: menuWindow.barY
|
||||||
|
barWidth: menuWindow.barWidth
|
||||||
readonly property real maskY: {
|
barHeight: menuWindow.barHeight
|
||||||
const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0;
|
screenWidth: menuWindow.width
|
||||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
|
screenHeight: menuWindow.height
|
||||||
return Math.max(triggeringBarY, adjacentTopBar);
|
adjacentBarInfo: menuWindow.adjacentBarInfo
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskWidth: {
|
|
||||||
const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0;
|
|
||||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
|
|
||||||
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar);
|
|
||||||
return Math.max(100, width - maskX - rightExclusion);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskHeight: {
|
|
||||||
const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0;
|
|
||||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
|
|
||||||
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar);
|
|
||||||
return Math.max(100, height - maskY - bottomExclusion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell.Hyprland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
@@ -50,6 +51,24 @@ Item {
|
|||||||
readonly property var contentLoader: impl.item ? impl.item.contentLoader : _fallbackContentLoader
|
readonly property var contentLoader: impl.item ? impl.item.contentLoader : _fallbackContentLoader
|
||||||
readonly property var overlayLoader: impl.item ? impl.item.overlayLoader : _fallbackOverlayLoader
|
readonly property var overlayLoader: impl.item ? impl.item.overlayLoader : _fallbackOverlayLoader
|
||||||
readonly property var backgroundWindow: impl.item ? impl.item.backgroundWindow : null
|
readonly property var backgroundWindow: impl.item ? impl.item.backgroundWindow : null
|
||||||
|
readonly property var contentWindow: impl.item ? impl.item.contentWindow : null
|
||||||
|
|
||||||
|
// On Hyprland the OnDemand content surface only receives keyboard focus
|
||||||
|
// through a grab; everywhere else Exclusive focus covers this. Both
|
||||||
|
// popout windows plus every bar are whitelisted so clicks on them are
|
||||||
|
// delivered normally (dismiss MouseAreas, widget-to-widget transfer)
|
||||||
|
// instead of being consumed clearing the grab.
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
windows: {
|
||||||
|
const list = [];
|
||||||
|
if (root.contentWindow)
|
||||||
|
list.push(root.contentWindow);
|
||||||
|
if (root.backgroundWindow && root.backgroundWindow !== root.contentWindow)
|
||||||
|
list.push(root.backgroundWindow);
|
||||||
|
return list.concat(KeyboardFocus.barWindows);
|
||||||
|
}
|
||||||
|
active: KeyboardFocus.wantsGrab(root.shouldBeVisible, root.customKeyboardFocus)
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: _fallbackContentLoader
|
id: _fallbackContentLoader
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Item {
|
|||||||
property Component overlayContent: null
|
property Component overlayContent: null
|
||||||
property alias overlayLoader: overlayLoader
|
property alias overlayLoader: overlayLoader
|
||||||
readonly property alias backgroundWindow: contentWindow
|
readonly property alias backgroundWindow: contentWindow
|
||||||
|
readonly property alias contentWindow: contentWindow
|
||||||
property real popupWidth: 400
|
property real popupWidth: 400
|
||||||
property real popupHeight: 300
|
property real popupHeight: 300
|
||||||
property real triggerX: 0
|
property real triggerX: 0
|
||||||
@@ -758,31 +759,21 @@ Item {
|
|||||||
}
|
}
|
||||||
})(), dpr)
|
})(), dpr)
|
||||||
|
|
||||||
readonly property real triggeringBarLeftExclusion: (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? Math.max(0, barX + barWidth) : 0
|
readonly property real maskX: _dismissZone.x
|
||||||
readonly property real triggeringBarTopExclusion: (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? Math.max(0, barY + barHeight) : 0
|
readonly property real maskY: _dismissZone.y
|
||||||
readonly property real triggeringBarRightExclusion: (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? Math.max(0, screenWidth - barX) : 0
|
readonly property real maskWidth: _dismissZone.width
|
||||||
readonly property real triggeringBarBottomExclusion: (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? Math.max(0, screenHeight - barY) : 0
|
readonly property real maskHeight: _dismissZone.height
|
||||||
|
|
||||||
readonly property real maskX: {
|
DismissZone {
|
||||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
|
id: _dismissZone
|
||||||
return Math.max(triggeringBarLeftExclusion, adjacentLeftBar);
|
barPosition: root.effectiveBarPosition
|
||||||
}
|
barX: root.barX
|
||||||
|
barY: root.barY
|
||||||
readonly property real maskY: {
|
barWidth: root.barWidth
|
||||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
|
barHeight: root.barHeight
|
||||||
return Math.max(triggeringBarTopExclusion, adjacentTopBar);
|
screenWidth: root.screenWidth
|
||||||
}
|
screenHeight: root.screenHeight
|
||||||
|
adjacentBarInfo: root.adjacentBarInfo
|
||||||
readonly property real maskWidth: {
|
|
||||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
|
|
||||||
const rightExclusion = Math.max(triggeringBarRightExclusion, adjacentRightBar);
|
|
||||||
return Math.max(100, screenWidth - maskX - rightExclusion);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskHeight: {
|
|
||||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
|
|
||||||
const bottomExclusion = Math.max(triggeringBarBottomExclusion, adjacentBottomBar);
|
|
||||||
return Math.max(100, screenHeight - maskY - bottomExclusion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
@@ -814,17 +805,7 @@ Item {
|
|||||||
WlrLayershell.namespace: root.layerNamespace
|
WlrLayershell.namespace: root.layerNamespace
|
||||||
WlrLayershell.layer: root.effectivePopoutLayer
|
WlrLayershell.layer: root.effectivePopoutLayer
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible, customKeyboardFocus)
|
||||||
if (PopoutManager.screenshotActive)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (customKeyboardFocus !== null)
|
|
||||||
return customKeyboardFocus;
|
|
||||||
if (!shouldBeVisible)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property bool _fullHeight: root.fullHeightSurface
|
readonly property bool _fullHeight: root.fullHeightSurface
|
||||||
anchors {
|
anchors {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ Item {
|
|||||||
property Component overlayContent: null
|
property Component overlayContent: null
|
||||||
property alias overlayLoader: overlayLoader
|
property alias overlayLoader: overlayLoader
|
||||||
readonly property alias backgroundWindow: backgroundWindow
|
readonly property alias backgroundWindow: backgroundWindow
|
||||||
|
readonly property alias contentWindow: contentWindow
|
||||||
property real popupWidth: 400
|
property real popupWidth: 400
|
||||||
property real popupHeight: 300
|
property real popupHeight: 300
|
||||||
property real triggerX: 0
|
property real triggerX: 0
|
||||||
@@ -494,31 +495,21 @@ Item {
|
|||||||
}
|
}
|
||||||
})(), dpr)
|
})(), dpr)
|
||||||
|
|
||||||
readonly property real triggeringBarLeftExclusion: (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? Math.max(0, barX + barWidth) : 0
|
readonly property real maskX: _dismissZone.x
|
||||||
readonly property real triggeringBarTopExclusion: (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? Math.max(0, barY + barHeight) : 0
|
readonly property real maskY: _dismissZone.y
|
||||||
readonly property real triggeringBarRightExclusion: (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? Math.max(0, screenWidth - barX) : 0
|
readonly property real maskWidth: _dismissZone.width
|
||||||
readonly property real triggeringBarBottomExclusion: (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? Math.max(0, screenHeight - barY) : 0
|
readonly property real maskHeight: _dismissZone.height
|
||||||
|
|
||||||
readonly property real maskX: {
|
DismissZone {
|
||||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
|
id: _dismissZone
|
||||||
return Math.max(triggeringBarLeftExclusion, adjacentLeftBar);
|
barPosition: root.effectiveBarPosition
|
||||||
}
|
barX: root.barX
|
||||||
|
barY: root.barY
|
||||||
readonly property real maskY: {
|
barWidth: root.barWidth
|
||||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
|
barHeight: root.barHeight
|
||||||
return Math.max(triggeringBarTopExclusion, adjacentTopBar);
|
screenWidth: root.screenWidth
|
||||||
}
|
screenHeight: root.screenHeight
|
||||||
|
adjacentBarInfo: root.adjacentBarInfo
|
||||||
readonly property real maskWidth: {
|
|
||||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
|
|
||||||
const rightExclusion = Math.max(triggeringBarRightExclusion, adjacentRightBar);
|
|
||||||
return Math.max(100, screenWidth - maskX - rightExclusion);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real maskHeight: {
|
|
||||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
|
|
||||||
const bottomExclusion = Math.max(triggeringBarBottomExclusion, adjacentBottomBar);
|
|
||||||
return Math.max(100, screenHeight - maskY - bottomExclusion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
@@ -612,17 +603,7 @@ Item {
|
|||||||
WlrLayershell.namespace: root.layerNamespace
|
WlrLayershell.namespace: root.layerNamespace
|
||||||
WlrLayershell.layer: root.effectivePopoutLayer
|
WlrLayershell.layer: root.effectivePopoutLayer
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible, customKeyboardFocus)
|
||||||
if (PopoutManager.screenshotActive)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (customKeyboardFocus !== null)
|
|
||||||
return customKeyboardFocus;
|
|
||||||
if (!shouldBeVisible)
|
|
||||||
return WlrKeyboardFocus.None;
|
|
||||||
if (CompositorService.useHyprlandFocusGrab)
|
|
||||||
return WlrKeyboardFocus.OnDemand;
|
|
||||||
return WlrKeyboardFocus.Exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
// Defines the screen area (excluding bars) that dismisses popouts
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int barPosition: 0
|
||||||
|
property real barX: 0
|
||||||
|
property real barY: 0
|
||||||
|
property real barWidth: 0
|
||||||
|
property real barHeight: 0
|
||||||
|
property real screenWidth: 0
|
||||||
|
property real screenHeight: 0
|
||||||
|
property var adjacentBarInfo: null
|
||||||
|
|
||||||
|
readonly property real _leftExclusion: (barPosition === SettingsData.Position.Left && barWidth > 0) ? Math.max(0, barX + barWidth) : 0
|
||||||
|
readonly property real _topExclusion: (barPosition === SettingsData.Position.Top && barHeight > 0) ? Math.max(0, barY + barHeight) : 0
|
||||||
|
readonly property real _rightExclusion: (barPosition === SettingsData.Position.Right && barWidth > 0) ? Math.max(0, screenWidth - barX) : 0
|
||||||
|
readonly property real _bottomExclusion: (barPosition === SettingsData.Position.Bottom && barHeight > 0) ? Math.max(0, screenHeight - barY) : 0
|
||||||
|
|
||||||
|
readonly property real x: Math.max(_leftExclusion, adjacentBarInfo?.leftBar ?? 0)
|
||||||
|
readonly property real y: Math.max(_topExclusion, adjacentBarInfo?.topBar ?? 0)
|
||||||
|
readonly property real width: Math.max(100, screenWidth - x - Math.max(_rightExclusion, adjacentBarInfo?.rightBar ?? 0))
|
||||||
|
readonly property real height: Math.max(100, screenHeight - y - Math.max(_bottomExclusion, adjacentBarInfo?.bottomBar ?? 0))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user