From 9ca8dffa001ece71fedafac4e6d3b0700c6db784 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Sun, 29 Jun 2025 10:43:51 +0200 Subject: [PATCH] separate search and window overview --- .config/quickshell/GlobalStates.qml | 4 +- .../modules/common/ConfigOptions.qml | 4 +- .../quickshell/modules/overview/Overview.qml | 138 ++++++++---------- .../modules/overview/OverviewSearch.qml | 118 +++++++++++++++ .../modules/overview/OverviewWidget.qml | 4 +- .../modules/overview/OverviewWindow.qml | 2 +- .../modules/overview/SearchWidget.qml | 9 +- 7 files changed, 191 insertions(+), 88 deletions(-) create mode 100644 .config/quickshell/modules/overview/OverviewSearch.qml diff --git a/.config/quickshell/GlobalStates.qml b/.config/quickshell/GlobalStates.qml index 1b87942..087c332 100644 --- a/.config/quickshell/GlobalStates.qml +++ b/.config/quickshell/GlobalStates.qml @@ -10,9 +10,11 @@ Singleton { id: root property bool sidebarLeftOpen: false property bool sidebarRightOpen: false - property bool overviewOpen: false + property bool overviewWindowsOpen: false + property bool overviewSearchOpen: false property bool workspaceShowNumbers: false property bool superReleaseMightTrigger: true + property bool dontAutoCancelSearch: false // When user is not reluctant while pressing super, they probably don't need to see workspace numbers onSuperReleaseMightTriggerChanged: { diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml index ec9f8cd..99ec2e1 100644 --- a/.config/quickshell/modules/common/ConfigOptions.qml +++ b/.config/quickshell/modules/common/ConfigOptions.qml @@ -122,8 +122,8 @@ Singleton { property QtObject search: QtObject { property int nonAppResultDelay: 30 // This prevents lagging when typing - property string engineBaseUrl: "https://www.google.com/search?q=" - property list excludedSites: [ "quora.com" ] + property string engineBaseUrl: "https://kagi.com/search?q=" + property list excludedSites: [ ] property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird. property QtObject prefix: QtObject { property string action: "/" diff --git a/.config/quickshell/modules/overview/Overview.qml b/.config/quickshell/modules/overview/Overview.qml index a7817e6..6b642de 100644 --- a/.config/quickshell/modules/overview/Overview.qml +++ b/.config/quickshell/modules/overview/Overview.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import "root:/" import "root:/services" import "root:/modules/common" @@ -12,18 +13,21 @@ import Quickshell.Hyprland Scope { id: overviewScope - property bool dontAutoCancelSearch: false + + OverviewSearch { + id: searchPanel + } + Variants { id: overviewVariants model: Quickshell.screens PanelWindow { id: root required property var modelData - property string searchingText: "" readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen) property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id) screen: modelData - visible: GlobalStates.overviewOpen + visible: GlobalStates.overviewWindowsOpen WlrLayershell.namespace: "quickshell:overview" WlrLayershell.layer: WlrLayer.Overlay @@ -31,10 +35,10 @@ Scope { color: "transparent" mask: Region { - item: GlobalStates.overviewOpen ? columnLayout : null + item: GlobalStates.overviewWindowsOpen ? columnLayout : null } HyprlandWindow.visibleMask: Region { - item: GlobalStates.overviewOpen ? columnLayout : null + item: GlobalStates.overviewWindowsOpen ? columnLayout : null } @@ -49,22 +53,15 @@ Scope { id: grab windows: [ root ] property bool canBeActive: root.monitorIsFocused - active: false onCleared: () => { - if (!active) GlobalStates.overviewOpen = false + if (!active) GlobalStates.overviewWindowsOpen = false } } Connections { target: GlobalStates - function onOverviewOpenChanged() { - if (!GlobalStates.overviewOpen) { - searchWidget.disableExpandAnimation() - overviewScope.dontAutoCancelSearch = false; - } else { - if (!overviewScope.dontAutoCancelSearch) { - searchWidget.cancelSearch() - } + function onOverviewWindowsOpenChanged() { + if (GlobalStates.overviewWindowsOpen) { delayedGrabTimer.start() } } @@ -76,20 +73,16 @@ Scope { repeat: false onTriggered: { if (!grab.canBeActive) return - grab.active = GlobalStates.overviewOpen + grab.active = GlobalStates.overviewWindowsOpen } } implicitWidth: columnLayout.implicitWidth implicitHeight: columnLayout.implicitHeight - function setSearchingText(text) { - searchWidget.setSearchingText(text); - } - ColumnLayout { id: columnLayout - visible: GlobalStates.overviewOpen + visible: GlobalStates.overviewWindowsOpen anchors { horizontalCenter: parent.horizontalCenter top: !ConfigOptions.bar.bottom ? parent.top : undefined @@ -98,11 +91,11 @@ Scope { Keys.onPressed: (event) => { if (event.key === Qt.Key_Escape) { - GlobalStates.overviewOpen = false; + GlobalStates.overviewWindowsOpen = false; } else if (event.key === Qt.Key_Left) { - if (!root.searchingText) Hyprland.dispatch("workspace r-1"); + Hyprland.dispatch("workspace r-1"); } else if (event.key === Qt.Key_Right) { - if (!root.searchingText) Hyprland.dispatch("workspace r+1"); + Hyprland.dispatch("workspace r+1"); } } @@ -111,20 +104,12 @@ Scope { width: 1 // Prevent Wayland protocol error } - SearchWidget { - id: searchWidget - Layout.alignment: Qt.AlignHCenter - onSearchingTextChanged: (text) => { - root.searchingText = searchingText - } - } - Loader { id: overviewLoader - active: GlobalStates.overviewOpen + active: GlobalStates.overviewWindowsOpen sourceComponent: OverviewWidget { panelWindow: root - visible: (root.searchingText == "") + visible: true } } } @@ -132,29 +117,37 @@ Scope { } } - IpcHandler { - target: "overview" - function toggle() { - GlobalStates.overviewOpen = !GlobalStates.overviewOpen - } - function close() { - GlobalStates.overviewOpen = false - } - function open() { - GlobalStates.overviewOpen = true - } - function toggleReleaseInterrupt() { - GlobalStates.superReleaseMightTrigger = false - } - } + // IpcHandler { + // target: "overview" + // function toggle() { + // GlobalStates.overviewOpen = !GlobalStates.overviewOpen + // } + // function close() { + // GlobalStates.overviewOpen = false + // } + // function open() { + // GlobalStates.overviewOpen = true + // } + // function toggleReleaseInterrupt() { + // GlobalStates.superReleaseMightTrigger = false + // } + // } + GlobalShortcut { + name: "overviewSearchToggle" + description: qsTr("Toggles overview on press") + + onPressed: { + GlobalStates.overviewSearchOpen = !GlobalStates.overviewSearchOpen + } + } GlobalShortcut { name: "overviewToggle" description: qsTr("Toggles overview on press") onPressed: { - GlobalStates.overviewOpen = !GlobalStates.overviewOpen + GlobalStates.overviewWindowsOpen = !GlobalStates.overviewWindowsOpen } } GlobalShortcut { @@ -162,7 +155,8 @@ Scope { description: qsTr("Closes overview") onPressed: { - GlobalStates.overviewOpen = false + GlobalStates.overviewSearchOpen = false + GlobalStates.overviewWindowOpen = false } } GlobalShortcut { @@ -178,7 +172,7 @@ Scope { GlobalStates.superReleaseMightTrigger = true return } - GlobalStates.overviewOpen = !GlobalStates.overviewOpen + GlobalStates.overviewWindowsOpen = !GlobalStates.overviewWindowsOpen } } GlobalShortcut { @@ -196,21 +190,15 @@ Scope { description: qsTr("Toggle clipboard query on overview widget") onPressed: { - if (GlobalStates.overviewOpen && overviewScope.dontAutoCancelSearch) { - GlobalStates.overviewOpen = false; + if (GlobalStates.overviewSearchOpen && GlobalStates.dontAutoCancelSearch) { + GlobalStates.overviewSearchOpen = false; return; } - for (let i = 0; i < overviewVariants.instances.length; i++) { - let panelWindow = overviewVariants.instances[i]; - if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) { - overviewScope.dontAutoCancelSearch = true; - panelWindow.setSearchingText( - ConfigOptions.search.prefix.clipboard - ); - GlobalStates.overviewOpen = true; - return - } - } + GlobalStates.dontAutoCancelSearch = true; + searchPanel.setSearchingText( + ConfigOptions.search.prefix.clipboard + ); + GlobalStates.overviewSearchOpen = true; } } @@ -219,21 +207,15 @@ Scope { description: qsTr("Toggle emoji query on overview widget") onPressed: { - if (GlobalStates.overviewOpen && overviewScope.dontAutoCancelSearch) { - GlobalStates.overviewOpen = false; + if (GlobalStates.overviewSearchOpen && GlobalStates.dontAutoCancelSearch) { + GlobalStates.overviewSearchOpen = false; return; } - for (let i = 0; i < overviewVariants.instances.length; i++) { - let panelWindow = overviewVariants.instances[i]; - if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) { - overviewScope.dontAutoCancelSearch = true; - panelWindow.setSearchingText( - ConfigOptions.search.prefix.emojis - ); - GlobalStates.overviewOpen = true; - return - } - } + GlobalStates.dontAutoCancelSearch = true; + searchPanel.setSearchingText( + ConfigOptions.search.prefix.emojis + ); + GlobalStates.overviewSearchOpen = true; } } diff --git a/.config/quickshell/modules/overview/OverviewSearch.qml b/.config/quickshell/modules/overview/OverviewSearch.qml new file mode 100644 index 0000000..463d2ff --- /dev/null +++ b/.config/quickshell/modules/overview/OverviewSearch.qml @@ -0,0 +1,118 @@ +pragma ComponentBehavior: Bound +import "root:/" +import "root:/services" +import "root:/modules/common" +import "root:/modules/common/widgets" +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland + +// Scope { +// id: overviewScope + PanelWindow { + id: root + // required property var modelData + property string searchingText: "" + // readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen) + // property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id) + // property bool searching: overviewScope.previewWindows + // screen: modelData + visible: GlobalStates.overviewSearchOpen + + WlrLayershell.namespace: "quickshell:overview" + WlrLayershell.layer: WlrLayer.Overlay + // WlrLayershell.keyboardFocus: GlobalStates.overviewOpen ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None + color: "transparent" + + mask: Region { + item: GlobalStates.overviewSearchOpen ? columnLayout : null + } + HyprlandWindow.visibleMask: Region { + item: GlobalStates.overviewSearchOpen ? columnLayout : null + } + + + anchors { + top: true + left: true + right: true + bottom: true + } + + HyprlandFocusGrab { + id: grab + windows: [ root ] + // property bool canBeActive: root.monitorIsFocused + onCleared: () => { + if (!active) GlobalStates.overviewSearchOpen = false + } + } + + Connections { + target: GlobalStates + function onOverviewSearchOpenChanged() { + if (!GlobalStates.overviewSearchOpen) { + searchWidget.disableExpandAnimation() + GlobalStates.dontAutoCancelSearch = false; + } else { + if (!GlobalStates.dontAutoCancelSearch) { + searchWidget.cancelSearch() + } + delayedGrabTimer.start() + } + } + } + + Timer { + id: delayedGrabTimer + interval: ConfigOptions.hacks.arbitraryRaceConditionDelay + repeat: false + onTriggered: { + // if (!grab.canBeActive) return + grab.active = GlobalStates.overviewSearchOpen + } + } + + implicitWidth: columnLayout.implicitWidth + implicitHeight: columnLayout.implicitHeight + + function setSearchingText(text) { + searchWidget.setSearchingText(text); + } + + ColumnLayout { + id: columnLayout + visible: GlobalStates.overviewSearchOpen + anchors { + horizontalCenter: parent.horizontalCenter + top: !ConfigOptions.bar.bottom ? parent.top : undefined + bottom: ConfigOptions.bar.bottom ? parent.bottom : undefined + } + + Keys.onPressed: (event) => { + if (event.key === Qt.Key_Escape) { + GlobalStates.overviewSearchOpen = false; + } + } + + Item { + height: 1 // Prevent Wayland protocol error + width: 1 // Prevent Wayland protocol error + } + + SearchWidget { + id: searchWidget + Layout.alignment: Qt.AlignHCenter + onSearchingTextChanged: (text) => { + root.searchingText = searchingText + // root.searching = (searchingText.length > 0) + } + } + } + + } +// } diff --git a/.config/quickshell/modules/overview/OverviewWidget.qml b/.config/quickshell/modules/overview/OverviewWidget.qml index e0999d6..caa6281 100644 --- a/.config/quickshell/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/modules/overview/OverviewWidget.qml @@ -112,7 +112,7 @@ Item { onClicked: { if (root.draggingTargetWorkspace === -1) { // Hyprland.dispatch(`exec qs ipc call overview close`) - GlobalStates.overviewOpen = false + GlobalStates.overviewWindowsOpen = false Hyprland.dispatch(`workspace ${workspaceValue}`) } } @@ -225,7 +225,7 @@ Item { if (!windowData) return; if (event.button === Qt.LeftButton) { - GlobalStates.overviewOpen = false + GlobalStates.overviewWindowsOpen = false Hyprland.dispatch(`focuswindow address:${windowData.address}`) event.accepted = true } else if (event.button === Qt.MiddleButton) { diff --git a/.config/quickshell/modules/overview/OverviewWindow.qml b/.config/quickshell/modules/overview/OverviewWindow.qml index 3b37698..ed18cf6 100644 --- a/.config/quickshell/modules/overview/OverviewWindow.qml +++ b/.config/quickshell/modules/overview/OverviewWindow.qml @@ -70,7 +70,7 @@ Item { // Window ScreencopyView { id: windowPreview anchors.fill: parent - captureSource: GlobalStates.overviewOpen ? root.toplevel : null + captureSource: GlobalStates.overviewWindowsOpen ? root.toplevel : null live: true Rectangle { diff --git a/.config/quickshell/modules/overview/SearchWidget.qml b/.config/quickshell/modules/overview/SearchWidget.qml index 614efa9..5a89ded 100644 --- a/.config/quickshell/modules/overview/SearchWidget.qml +++ b/.config/quickshell/modules/overview/SearchWidget.qml @@ -25,13 +25,14 @@ Item { // Wrapper property string mathResult: "" function disableExpandAnimation() { - searchWidthBehavior.enabled = false; + searchWidthBehavior.enabled = false } function cancelSearch() { - searchInput.selectAll() + // searchInput.selectAll() + searchInput.text = "" root.searchingText = "" - searchWidthBehavior.enabled = true; + searchWidthBehavior.enabled = true } function setSearchingText(text) { @@ -208,7 +209,7 @@ Item { // Wrapper TextField { // Search box id: searchInput - focus: GlobalStates.overviewOpen + focus: GlobalStates.overviewSearchOpen Layout.rightMargin: 15 padding: 15 renderType: Text.NativeRendering