diff --git a/quickshell/Modals/Spotlight/SpotlightContent.qml b/quickshell/Modals/Spotlight/SpotlightContent.qml index 111ae438..a3b60e8e 100644 --- a/quickshell/Modals/Spotlight/SpotlightContent.qml +++ b/quickshell/Modals/Spotlight/SpotlightContent.qml @@ -1,5 +1,4 @@ import QtQuick -import QtQuick.Controls import qs.Common import qs.Modals.Spotlight import qs.Modules.AppDrawer @@ -17,33 +16,33 @@ Item { function resetScroll() { if (searchMode === "apps") { - resultsView.resetScroll() + resultsView.resetScroll(); } else { - fileSearchResults.resetScroll() + fileSearchResults.resetScroll(); } } function updateSearchMode() { if (searchField.text.startsWith("/")) { if (searchMode !== "files") { - searchMode = "files" + searchMode = "files"; } - const query = searchField.text.substring(1) - fileSearchController.searchQuery = query + const query = searchField.text.substring(1); + fileSearchController.searchQuery = query; } else { if (searchMode !== "apps") { - searchMode = "apps" - fileSearchController.reset() - appLauncher.searchQuery = searchField.text + searchMode = "apps"; + fileSearchController.reset(); + appLauncher.searchQuery = searchField.text; } } } onSearchModeChanged: { if (searchMode === "files") { - appLauncher.keyboardNavigationActive = false + appLauncher.keyboardNavigationActive = false; } else { - fileSearchController.keyboardNavigationActive = false + fileSearchController.keyboardNavigationActive = false; } } @@ -51,104 +50,104 @@ Item { focus: true clip: false Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - if (parentModal) - parentModal.hide() + if (event.key === Qt.Key_Escape) { + if (parentModal) + parentModal.hide(); - event.accepted = true - } else if (event.key === Qt.Key_Down) { - if (searchMode === "apps") { - appLauncher.selectNext() - } else { - fileSearchController.selectNext() - } - event.accepted = true - } else if (event.key === Qt.Key_Up) { - if (searchMode === "apps") { - appLauncher.selectPrevious() - } else { - fileSearchController.selectPrevious() - } - event.accepted = true - } else if (event.key === Qt.Key_Right && searchMode === "apps" && appLauncher.viewMode === "grid") { - appLauncher.selectNextInRow() - event.accepted = true - } else if (event.key === Qt.Key_Left && searchMode === "apps" && appLauncher.viewMode === "grid") { - appLauncher.selectPreviousInRow() - event.accepted = true - } else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) { - if (searchMode === "apps") { - appLauncher.selectNext() - } else { - fileSearchController.selectNext() - } - event.accepted = true - } else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) { - if (searchMode === "apps") { - appLauncher.selectPrevious() - } else { - fileSearchController.selectPrevious() - } - event.accepted = true - } else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") { - appLauncher.selectNextInRow() - event.accepted = true - } else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") { - appLauncher.selectPreviousInRow() - event.accepted = true - } else if (event.key === Qt.Key_Tab) { - if (searchMode === "apps") { - if (appLauncher.viewMode === "grid") { - appLauncher.selectNextInRow() - } else { - appLauncher.selectNext() - } - } else { - fileSearchController.selectNext() - } - event.accepted = true - } else if (event.key === Qt.Key_Backtab) { - if (searchMode === "apps") { - if (appLauncher.viewMode === "grid") { - appLauncher.selectPreviousInRow() - } else { - appLauncher.selectPrevious() - } - } else { - fileSearchController.selectPrevious() - } - event.accepted = true - } else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) { - if (searchMode === "apps") { - if (appLauncher.viewMode === "grid") { - appLauncher.selectNextInRow() - } else { - appLauncher.selectNext() - } - } else { - fileSearchController.selectNext() - } - event.accepted = true - } else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) { - if (searchMode === "apps") { - if (appLauncher.viewMode === "grid") { - appLauncher.selectPreviousInRow() - } else { - appLauncher.selectPrevious() - } - } else { - fileSearchController.selectPrevious() - } - event.accepted = true - } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (searchMode === "apps") { - appLauncher.launchSelected() - } else if (searchMode === "files") { - fileSearchController.openSelected() - } - event.accepted = true - } - } + event.accepted = true; + } else if (event.key === Qt.Key_Down) { + if (searchMode === "apps") { + appLauncher.selectNext(); + } else { + fileSearchController.selectNext(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Up) { + if (searchMode === "apps") { + appLauncher.selectPrevious(); + } else { + fileSearchController.selectPrevious(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Right && searchMode === "apps" && appLauncher.viewMode === "grid") { + appLauncher.selectNextInRow(); + event.accepted = true; + } else if (event.key === Qt.Key_Left && searchMode === "apps" && appLauncher.viewMode === "grid") { + appLauncher.selectPreviousInRow(); + event.accepted = true; + } else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) { + if (searchMode === "apps") { + appLauncher.selectNext(); + } else { + fileSearchController.selectNext(); + } + event.accepted = true; + } else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) { + if (searchMode === "apps") { + appLauncher.selectPrevious(); + } else { + fileSearchController.selectPrevious(); + } + event.accepted = true; + } else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") { + appLauncher.selectNextInRow(); + event.accepted = true; + } else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") { + appLauncher.selectPreviousInRow(); + event.accepted = true; + } else if (event.key === Qt.Key_Tab) { + if (searchMode === "apps") { + if (appLauncher.viewMode === "grid") { + appLauncher.selectNextInRow(); + } else { + appLauncher.selectNext(); + } + } else { + fileSearchController.selectNext(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Backtab) { + if (searchMode === "apps") { + if (appLauncher.viewMode === "grid") { + appLauncher.selectPreviousInRow(); + } else { + appLauncher.selectPrevious(); + } + } else { + fileSearchController.selectPrevious(); + } + event.accepted = true; + } else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) { + if (searchMode === "apps") { + if (appLauncher.viewMode === "grid") { + appLauncher.selectNextInRow(); + } else { + appLauncher.selectNext(); + } + } else { + fileSearchController.selectNext(); + } + event.accepted = true; + } else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) { + if (searchMode === "apps") { + if (appLauncher.viewMode === "grid") { + appLauncher.selectPreviousInRow(); + } else { + appLauncher.selectPrevious(); + } + } else { + fileSearchController.selectPrevious(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + if (searchMode === "apps") { + appLauncher.launchSelected(); + } else if (searchMode === "files") { + fileSearchController.openSelected(); + } + event.accepted = true; + } + } AppLauncher { id: appLauncher @@ -156,29 +155,27 @@ Item { viewMode: SettingsData.spotlightModalViewMode gridColumns: SettingsData.appLauncherGridColumns onAppLaunched: () => { - if (parentModal) - parentModal.hide() - - if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) { - NiriService.toggleOverview() - } - } + if (parentModal) + parentModal.hide(); + if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) { + NiriService.toggleOverview(); + } + } onViewModeSelected: mode => { - SettingsData.set("spotlightModalViewMode", mode) - } + SettingsData.set("spotlightModalViewMode", mode); + } } FileSearchController { id: fileSearchController onFileOpened: () => { - if (parentModal) - parentModal.hide() - - if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) { - NiriService.toggleOverview() - } - } + if (parentModal) + parentModal.hide(); + if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) { + NiriService.toggleOverview(); + } + } } Column { @@ -216,34 +213,33 @@ Item { keyForwardTargets: [spotlightKeyHandler] onTextChanged: { if (searchMode === "apps") { - appLauncher.searchQuery = text + appLauncher.searchQuery = text; } } onTextEdited: { - updateSearchMode() + updateSearchMode(); } Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - if (parentModal) - parentModal.hide() + if (event.key === Qt.Key_Escape) { + if (parentModal) + parentModal.hide(); - event.accepted = true - } else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length > 0) { - if (searchMode === "apps") { - if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0) - appLauncher.launchSelected() - else if (appLauncher.model.count > 0) - appLauncher.launchApp(appLauncher.model.get(0)) - } else if (searchMode === "files") { - if (fileSearchController.model.count > 0) - fileSearchController.openSelected() - } - event.accepted = true - } else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key - === Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) { - event.accepted = false - } - } + event.accepted = true; + } else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length > 0) { + if (searchMode === "apps") { + if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0) + appLauncher.launchSelected(); + else if (appLauncher.model.count > 0) + appLauncher.launchApp(appLauncher.model.get(0)); + } else if (searchMode === "files") { + if (fileSearchController.model.count > 0) + fileSearchController.openSelected(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) { + event.accepted = false; + } + } } Row { @@ -271,8 +267,8 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: () => { - appLauncher.setViewMode("list") - } + appLauncher.setViewMode("list"); + } } } @@ -296,8 +292,8 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: () => { - appLauncher.setViewMode("grid") - } + appLauncher.setViewMode("grid"); + } } } } @@ -329,22 +325,22 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: () => { - fileSearchController.searchField = "filename" - } + fileSearchController.searchField = "filename"; + } onEntered: { - filenameTooltipLoader.active = true + filenameTooltipLoader.active = true; Qt.callLater(() => { - if (filenameTooltipLoader.item) { - const p = mapToItem(null, width / 2, height + Theme.spacingXS) - filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null) - } - }) + if (filenameTooltipLoader.item) { + const p = mapToItem(null, width / 2, height + Theme.spacingXS); + filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null); + } + }); } onExited: { if (filenameTooltipLoader.item) - filenameTooltipLoader.item.hide() + filenameTooltipLoader.item.hide(); - filenameTooltipLoader.active = false + filenameTooltipLoader.active = false; } } } @@ -371,22 +367,22 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: () => { - fileSearchController.searchField = "body" - } + fileSearchController.searchField = "body"; + } onEntered: { - contentTooltipLoader.active = true + contentTooltipLoader.active = true; Qt.callLater(() => { - if (contentTooltipLoader.item) { - const p = mapToItem(null, width / 2, height + Theme.spacingXS) - contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null) - } - }) + if (contentTooltipLoader.item) { + const p = mapToItem(null, width / 2, height + Theme.spacingXS); + contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null); + } + }); } onExited: { if (contentTooltipLoader.item) - contentTooltipLoader.item.hide() + contentTooltipLoader.item.hide(); - contentTooltipLoader.active = false + contentTooltipLoader.active = false; } } } @@ -426,8 +422,8 @@ Item { visible: contextMenu.visible z: 999 onClicked: () => { - contextMenu.hide() - } + contextMenu.hide(); + } MouseArea { diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml index 111ce5c2..cfb5381f 100644 --- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml @@ -11,48 +11,65 @@ Scope { property bool searchActive: false property string searchActiveScreen: "" - property bool overlayActive: NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false) + property bool isClosing: false + property bool overlayActive: (NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)) || searchActive function showSpotlight(screenName) { - searchActive = true - searchActiveScreen = screenName + isClosing = false; + searchActive = true; + searchActiveScreen = screenName; } function hideSpotlight() { - searchActive = false - searchActiveScreen = "" + if (!searchActive) + return; + isClosing = true; + } + + function completeHide() { + searchActive = false; + searchActiveScreen = ""; + isClosing = false; } Connections { target: NiriService function onInOverviewChanged() { if (!NiriService.inOverview) { - hideSpotlight() - } else { - searchActive = false - searchActiveScreen = "" + if (searchActive) { + isClosing = true; + return; + } + closeOverviewAfterAnim = false; + searchActive = false; + searchActiveScreen = ""; + isClosing = false; + return; } + searchActive = false; + searchActiveScreen = ""; + isClosing = false; } function onCurrentOutputChanged() { - if (NiriService.inOverview && searchActive && searchActiveScreen !== "" && searchActiveScreen !== NiriService.currentOutput) { - hideSpotlight() - } + if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput) + return; + hideSpotlight(); } } Connections { target: PopoutService.spotlightModal function onSpotlightOpenChanged() { - if (PopoutService.spotlightModal?.spotlightOpen && searchActive) { - hideSpotlight() - } + if (!PopoutService.spotlightModal?.spotlightOpen || !searchActive) + return; + hideSpotlight(); } } Loader { id: niriOverlayLoader - active: overlayActive + active: overlayActive || isClosing asynchronous: false sourceComponent: Variants { @@ -65,29 +82,34 @@ Scope { readonly property real dpr: CompositorService.getScreenScale(screen) readonly property bool isActiveScreen: screen.name === NiriService.currentOutput - readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen + readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing + readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen screen: modelData - visible: NiriService.inOverview + visible: NiriService.inOverview || niriOverviewScope.isClosing color: "transparent" WlrLayershell.namespace: "dms:niri-overview-spotlight" WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { - if (!NiriService.inOverview) return WlrKeyboardFocus.None - if (!isActiveScreen) return WlrKeyboardFocus.None - return WlrKeyboardFocus.Exclusive + if (!NiriService.inOverview) + return WlrKeyboardFocus.None; + if (!isActiveScreen) + return WlrKeyboardFocus.None; + if (niriOverviewScope.isClosing) + return WlrKeyboardFocus.None; + return WlrKeyboardFocus.Exclusive; } mask: Region { - item: shouldShowSpotlight ? spotlightContainer : null + item: spotlightContainer.visible ? spotlightContainer : null } onShouldShowSpotlightChanged: { - if (!shouldShowSpotlight && isActiveScreen) { - Qt.callLater(() => keyboardFocusScope.forceActiveFocus()) - } + if (shouldShowSpotlight || !isActiveScreen) + return; + Qt.callLater(() => keyboardFocusScope.forceActiveFocus()); } anchors { @@ -97,61 +119,62 @@ Scope { bottom: true } - FocusScope { id: keyboardFocusScope anchors.fill: parent focus: true Keys.onPressed: event => { - if (!overlayWindow.shouldShowSpotlight) { - if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) { - NiriService.toggleOverview() - event.accepted = true - return - } - - if (event.key === Qt.Key_Left) { - NiriService.moveColumnLeft() - event.accepted = true - return - } - - if (event.key === Qt.Key_Right) { - NiriService.moveColumnRight() - event.accepted = true - return - } - - if (event.key === Qt.Key_Up) { - NiriService.moveWorkspaceUp() - event.accepted = true - return - } - - if (event.key === Qt.Key_Down) { - NiriService.moveWorkspaceDown() - event.accepted = true - return - } - - if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) { - event.accepted = false - return - } - - if (!event.isAutoRepeat && event.text) { - niriOverviewScope.showSpotlight(overlayWindow.screen.name) - if (spotlightContent?.searchField) { - spotlightContent.searchField.text = event.text.trim() - if (spotlightContent.appLauncher) { - spotlightContent.appLauncher.searchQuery = event.text.trim() - } - Qt.callLater(() => spotlightContent.searchField.forceActiveFocus()) - } - event.accepted = true - } + if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing) + return; + if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) { + NiriService.toggleOverview(); + event.accepted = true; + return; } + + if (event.key === Qt.Key_Left) { + NiriService.moveColumnLeft(); + event.accepted = true; + return; + } + + if (event.key === Qt.Key_Right) { + NiriService.moveColumnRight(); + event.accepted = true; + return; + } + + if (event.key === Qt.Key_Up) { + NiriService.moveWorkspaceUp(); + event.accepted = true; + return; + } + + if (event.key === Qt.Key_Down) { + NiriService.moveWorkspaceDown(); + event.accepted = true; + return; + } + + if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) { + event.accepted = false; + return; + } + + if (event.isAutoRepeat || !event.text) + return; + if (!spotlightContent?.searchField) + return; + const trimmedText = event.text.trim(); + spotlightContainer.waitingForResults = true; + spotlightContent.searchField.text = trimmedText; + if (spotlightContent.appLauncher) { + spotlightContent.appLauncher.searchQuery = trimmedText; + } + niriOverviewScope.showSpotlight(overlayWindow.screen.name); + Qt.callLater(() => spotlightContent.searchField.forceActiveFocus()); + event.accepted = true; } } @@ -162,28 +185,35 @@ Scope { width: Theme.px(500, overlayWindow.dpr) height: Theme.px(600, overlayWindow.dpr) - property real scaleValue: 0.96 + readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen + property bool waitingForResults: false - scale: scaleValue - opacity: overlayWindow.shouldShowSpotlight ? 1 : 0 + Connections { + target: spotlightContent.appLauncher?.model ?? null + function onCountChanged() { + spotlightContainer.waitingForResults = false; + } + } + + scale: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1.0 : 0.96 + opacity: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1 : 0 + visible: (overlayWindow.shouldShowSpotlight && !waitingForResults) || animatingOut enabled: overlayWindow.shouldShowSpotlight layer.enabled: true layer.smooth: false layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr)) - Connections { - target: overlayWindow - function onShouldShowSpotlightChanged() { - spotlightContainer.scaleValue = overlayWindow.shouldShowSpotlight ? 1.0 : 0.96 - } - } - - Behavior on scaleValue { + Behavior on scale { NumberAnimation { duration: Theme.expressiveDurations.expressiveDefaultSpatial easing.type: Easing.BezierSpline - easing.bezierCurve: niriOverviewScope.searchActive ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized + easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized + onRunningChanged: { + if (running || !spotlightContainer.animatingOut) + return; + niriOverviewScope.completeHide(); + } } } @@ -191,7 +221,7 @@ Scope { NumberAnimation { duration: Theme.expressiveDurations.expressiveDefaultSpatial easing.type: Easing.BezierSpline - easing.bezierCurve: niriOverviewScope.searchActive ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized + easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized } } @@ -209,17 +239,14 @@ Scope { anchors.margins: 0 property var fakeParentModal: QtObject { - property bool spotlightOpen: overlayWindow.shouldShowSpotlight + property bool spotlightOpen: spotlightContainer.visible function hide() { - niriOverviewScope.hideSpotlight() - if (overlayWindow.isActiveScreen) { - Qt.callLater(() => keyboardFocusScope.forceActiveFocus()) - } + niriOverviewScope.hideSpotlight(); } } Component.onCompleted: { - parentModal = fakeParentModal + parentModal = fakeParentModal; } } }