diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 47d52044..616a3fd5 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -1179,6 +1179,12 @@ Singleton { saveSettings(); } + function getLauncherRestoreMode() { + if (!SettingsData.rememberLastMode) + return "all"; + return launcherLastMode || "all"; + } + function setLauncherLastFileSearchType(type) { launcherLastFileSearchType = type; saveSettings(); diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 6177d2f6..145de077 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -435,6 +435,7 @@ Singleton { property int appLauncherGridColumns: 4 property bool spotlightCloseNiriOverview: true property bool rememberLastQuery: false + property bool rememberLastMode: true property var spotlightSectionViewModes: ({}) onSpotlightSectionViewModesChanged: saveSettings() property var appDrawerSectionViewModes: ({}) diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index b8e74c29..b4bdd49c 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -203,6 +203,7 @@ var SPEC = { appLauncherGridColumns: { def: 4 }, spotlightCloseNiriOverview: { def: true }, rememberLastQuery: { def: false }, + rememberLastMode: { def: true }, spotlightSectionViewModes: { def: {} }, appDrawerSectionViewModes: { def: {} }, niriOverviewOverlayEnabled: { def: true }, diff --git a/quickshell/Modals/DankLauncherV2/Controller.qml b/quickshell/Modals/DankLauncherV2/Controller.qml index d47d86d4..681b29a0 100644 --- a/quickshell/Modals/DankLauncherV2/Controller.qml +++ b/quickshell/Modals/DankLauncherV2/Controller.qml @@ -39,7 +39,7 @@ Item { signal itemExecuted signal searchCompleted - signal modeChanged(string mode) + signal modeChanged(string mode, bool userInitiated) signal queryChanged(string query) signal viewModeChanged(string sectionId, string mode) signal searchQueryRequested(string query) @@ -440,7 +440,7 @@ Item { } } - function setMode(mode, isAutoSwitch, fileTypeOverride) { + function setMode(mode, isAutoSwitch, fileTypeOverride, notPersist) { if (searchMode === mode) { if (mode === "files" && fileTypeOverride !== undefined && fileSearchType !== fileTypeOverride) { fileSearchType = fileTypeOverride; @@ -458,7 +458,7 @@ Item { if (mode === "files") { fileSearchType = fileTypeOverride !== undefined ? fileTypeOverride : (SessionData.launcherLastFileSearchType || "all"); } - modeChanged(mode); + modeChanged(mode, !isAutoSwitch && notPersist !== true); performSearch(); var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0; if (mode === "files" || filesInAll) { @@ -471,7 +471,7 @@ Item { return; autoSwitchedToFiles = false; searchMode = previousSearchMode; - modeChanged(previousSearchMode); + modeChanged(previousSearchMode, false); performSearch(); } @@ -1897,7 +1897,7 @@ Item { if (browseTrigger && browseTrigger.length > 0) { searchQueryRequested(browseTrigger); } else { - setMode("plugins"); + setMode("plugins", false, undefined, true); pluginFilter = browsePluginId; performSearch(); } diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml index 3a5e3d29..d130fb8a 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml @@ -396,7 +396,7 @@ Item { spotlightContent.searchField.text = query; } if (spotlightContent.controller) { - var targetMode = mode || SessionData.launcherLastMode || "all"; + var targetMode = mode || SessionData.getLauncherRestoreMode(); spotlightContent.controller.searchMode = targetMode; spotlightContent.controller.activePluginId = ""; spotlightContent.controller.activePluginName = ""; @@ -539,8 +539,8 @@ Item { Connections { target: spotlightContent?.controller ?? null - function onModeChanged(mode) { - if (spotlightContent.controller.autoSwitchedToFiles) + function onModeChanged(mode, userInitiated) { + if (!userInitiated || !SettingsData.rememberLastMode) return; SessionData.setLauncherLastMode(mode); } @@ -928,8 +928,12 @@ Item { } } + Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event) + Keys.onEscapePressed: event => { - root.hide(); + root.spotlightContent?.activeContextMenu?.handleKey(event); + if (!event.accepted) + root.hide(); event.accepted = true; } } diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml index 16b2bdcb..f17e3cba 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml @@ -145,7 +145,7 @@ Item { spotlightContent.closeTransientUi?.(); const targetQuery = query || (SettingsData.rememberLastQuery ? (SessionData.launcherLastQuery || "") : ""); - const targetMode = mode || SessionData.launcherLastMode || "all"; + const targetMode = mode || SessionData.getLauncherRestoreMode(); if (spotlightContent.searchField) { spotlightContent.searchField.text = targetQuery; @@ -489,8 +489,12 @@ Item { } } + Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event) + Keys.onEscapePressed: event => { - root.hide(); + root.spotlightContent?.activeContextMenu?.handleKey(event); + if (!event.accepted) + root.hide(); event.accepted = true; } } diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml index a4e832a8..4d9222a2 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml @@ -148,7 +148,7 @@ Item { spotlightContent.searchField.text = targetQuery; } if (spotlightContent.controller) { - var targetMode = mode || SessionData.launcherLastMode || "all"; + var targetMode = mode || SessionData.getLauncherRestoreMode(); spotlightContent.controller.searchMode = targetMode; spotlightContent.controller.activePluginId = ""; spotlightContent.controller.activePluginName = ""; @@ -260,8 +260,8 @@ Item { Connections { target: spotlightContent?.controller ?? null - function onModeChanged(mode) { - if (spotlightContent.controller.autoSwitchedToFiles) + function onModeChanged(mode, userInitiated) { + if (!userInitiated || !SettingsData.rememberLastMode || (mode !== "all" && mode !== "apps")) return; SessionData.setLauncherLastMode(mode); } @@ -536,8 +536,12 @@ Item { } } + Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event) + Keys.onEscapePressed: event => { - root.hide(); + root.spotlightContent?.activeContextMenu?.handleKey(event); + if (!event.accepted) + root.hide(); event.accepted = true; } } diff --git a/quickshell/Modals/DankLauncherV2/LauncherContent.qml b/quickshell/Modals/DankLauncherV2/LauncherContent.qml index 025b9f2f..890f4fef 100644 --- a/quickshell/Modals/DankLauncherV2/LauncherContent.qml +++ b/quickshell/Modals/DankLauncherV2/LauncherContent.qml @@ -17,6 +17,7 @@ FocusScope { property alias controller: controller property alias resultsList: resultsList property alias actionPanel: actionPanel + readonly property alias activeContextMenu: contextMenu property bool editMode: false property var editingApp: null diff --git a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml index 330b36f0..0056ac6c 100644 --- a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml +++ b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml @@ -340,6 +340,31 @@ Item { return count; } + function handleKey(event) { + if (!openState) + return; + switch (event.key) { + case Qt.Key_Down: + selectNext(); + event.accepted = true; + return; + case Qt.Key_Up: + selectPrevious(); + event.accepted = true; + return; + case Qt.Key_Return: + case Qt.Key_Enter: + activateSelected(); + event.accepted = true; + return; + case Qt.Key_Left: + case Qt.Key_Escape: + hide(); + event.accepted = true; + return; + } + } + function selectNext() { if (visibleItemCount > 0) { keyboardNavigation = true; diff --git a/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml b/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml index af6656b3..add822aa 100644 --- a/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml +++ b/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml @@ -12,6 +12,7 @@ FocusScope { property var parentModal: null property alias searchField: searchInput property alias controller: searchController + readonly property alias activeContextMenu: contextMenu readonly property bool _hasQuery: searchInput.text.length > 0 readonly property real _searchBarH: 56 @@ -239,8 +240,8 @@ FocusScope { Connections { target: searchController - function onModeChanged(mode) { - if (searchController.autoSwitchedToFiles) + function onModeChanged(mode, userInitiated) { + if (!userInitiated || !SettingsData.rememberLastMode) return; SessionData.setLauncherLastMode(mode); } diff --git a/quickshell/Modules/Settings/LauncherTab.qml b/quickshell/Modules/Settings/LauncherTab.qml index a00dc4b8..0447e7df 100644 --- a/quickshell/Modules/Settings/LauncherTab.qml +++ b/quickshell/Modules/Settings/LauncherTab.qml @@ -1121,6 +1121,15 @@ Item { onToggled: checked => SessionData.setSearchAppActions(checked) } + SettingsToggleRow { + settingKey: "rememberLastMode" + tags: ["launcher", "remember", "last", "mode", "tab"] + text: I18n.tr("Remember Last Mode") + description: I18n.tr("Restore the last selected mode (tab) when the launcher is opened") + checked: SettingsData.rememberLastMode + onToggled: checked => SettingsData.set("rememberLastMode", checked) + } + SettingsToggleRow { settingKey: "rememberLastQuery" tags: ["launcher", "remember", "last", "search", "query"] diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml index 89155b40..b3e4070d 100644 --- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml @@ -338,45 +338,61 @@ Scope { border.width: 1 } - LauncherContent { - id: launcherContent + FocusScope { anchors.fill: parent - anchors.margins: 0 + focus: true - property var fakeParentModal: QtObject { - property bool spotlightOpen: spotlightContainer.visible - property bool isClosing: niriOverviewScope.isClosing - function hide() { - if (niriOverviewScope.searchActive) { - niriOverviewScope.hideSpotlight(); - return; + Keys.onPressed: event => launcherContent.activeContextMenu?.handleKey(event) + + Keys.onEscapePressed: event => { + launcherContent.activeContextMenu?.handleKey(event); + if (!event.accepted) + launcherContent.parentModal?.hide(); + event.accepted = true; + } + + LauncherContent { + id: launcherContent + anchors.fill: parent + anchors.margins: 0 + + property var fakeParentModal: QtObject { + property bool spotlightOpen: spotlightContainer.visible + property bool isClosing: niriOverviewScope.isClosing + property real alignedX: spotlightContainer.x + property real alignedY: spotlightContainer.y + function hide() { + if (niriOverviewScope.searchActive) { + niriOverviewScope.hideSpotlight(); + return; + } + NiriService.toggleOverview(); } - NiriService.toggleOverview(); } - } - Connections { - target: launcherContent.searchField - function onTextChanged() { - if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive) - return; - niriOverviewScope.hideSpotlight(); + Connections { + target: launcherContent.searchField + function onTextChanged() { + if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive) + return; + niriOverviewScope.hideSpotlight(); + } } - } - Component.onCompleted: { - parentModal = fakeParentModal; - } - - Connections { - target: launcherContent.controller - function onItemExecuted() { - niriOverviewScope.releaseKeyboard = true; + Component.onCompleted: { + parentModal = fakeParentModal; } - function onModeChanged(mode) { - if (launcherContent.controller.autoSwitchedToFiles) - return; - SessionData.setNiriOverviewLastMode(mode); + + Connections { + target: launcherContent.controller + function onItemExecuted() { + niriOverviewScope.releaseKeyboard = true; + } + function onModeChanged(mode) { + if (launcherContent.controller.autoSwitchedToFiles) + return; + SessionData.setNiriOverviewLastMode(mode); + } } } }