From 13968db31c1be9c1952da29e29687b276ef49aaf Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 6 Dec 2025 23:14:08 +0100 Subject: [PATCH] waffles: ctrl alt del menu --- .../quickshell/ii/modules/common/Config.qml | 1 + .../ii/modules/common/functions/Session.qml | 4 + .../ii/sessionScreen/SessionScreen.qml | 179 +++++++++-------- .../bluetooth/BluetoothControl.qml | 2 +- .../waffle/actionCenter/wifi/WifiControl.qml | 2 +- .../ii/modules/waffle/looks/WMenu.qml | 4 + .../waffle/looks/WRectangularShadowThis.qml | 15 ++ .../{FooterMoreButton.qml => WTextButton.qml} | 0 .../sessionScreen/SessionScreenContent.qml | 189 ++++++++++++++++++ .../WSessionScreenTextButton.qml | 54 +++++ .../sessionScreen/WaffleSessionScreen.qml | 117 +++++++++++ .../waffle/startMenu/StartMenuContent.qml | 2 + .../waffle/startMenu/WaffleStartMenu.qml | 31 +++ .../{ => searchPage}/SearchEntryIcon.qml | 0 .../{ => searchPage}/SearchPageContent.qml | 0 .../SearchResultButton.qml} | 0 .../{ => searchPage}/SearchResults.qml | 3 +- .../startMenu/{ => searchPage}/TagStrip.qml | 1 + .../AggregatedAppCategoryModel.qml | 0 .../startMenu/{ => startPage}/AllAppsGrid.qml | 0 .../{ => startPage}/AppCategoryGrid.qml | 17 +- .../startMenu/{ => startPage}/BigAppGrid.qml | 0 .../{ => startPage}/StartAppButton.qml | 0 .../{ => startPage}/StartPageApps.qml | 2 + .../{ => startPage}/StartPageContent.qml | 0 .../{ => startPage}/StartUserButton.qml | 0 .../ii/services/SessionWarnings.qml | 39 ++++ .../quickshell/ii/services/Updates.qml | 1 + dots/.config/quickshell/ii/shell.qml | 5 +- 29 files changed, 578 insertions(+), 90 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WRectangularShadowThis.qml rename dots/.config/quickshell/ii/modules/waffle/looks/{FooterMoreButton.qml => WTextButton.qml} (100%) create mode 100644 dots/.config/quickshell/ii/modules/waffle/sessionScreen/SessionScreenContent.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/sessionScreen/WSessionScreenTextButton.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/sessionScreen/WaffleSessionScreen.qml rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => searchPage}/SearchEntryIcon.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => searchPage}/SearchPageContent.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{WSearchResultButton.qml => searchPage/SearchResultButton.qml} (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => searchPage}/SearchResults.qml (99%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => searchPage}/TagStrip.qml (98%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/AggregatedAppCategoryModel.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/AllAppsGrid.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/AppCategoryGrid.qml (96%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/BigAppGrid.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/StartAppButton.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/StartPageApps.qml (93%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/StartPageContent.qml (100%) rename dots/.config/quickshell/ii/modules/waffle/startMenu/{ => startPage}/StartUserButton.qml (100%) create mode 100644 dots/.config/quickshell/ii/services/SessionWarnings.qml diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 462ee4dfb..859e336e3 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -153,6 +153,7 @@ Singleton { property JsonObject apps: JsonObject { property string bluetooth: "kcmshell6 kcm_bluetooth" + property string changePassword: "kitty -1 --hold=yes fish -i -c 'passwd'" property string network: "kcmshell6 kcm_networkmanagement" property string manageUser: "kcmshell6 kcm_users" property string networkEthernet: "kcmshell6 kcm_networkmanagement" diff --git a/dots/.config/quickshell/ii/modules/common/functions/Session.qml b/dots/.config/quickshell/ii/modules/common/functions/Session.qml index bbb9932c3..184bd34c3 100644 --- a/dots/.config/quickshell/ii/modules/common/functions/Session.qml +++ b/dots/.config/quickshell/ii/modules/common/functions/Session.qml @@ -12,6 +12,10 @@ Singleton { }); } + function changePassword() { + Quickshell.execDetached(["bash", "-c", `${Config.options.apps.changePassword}`]); + } + function lock() { Quickshell.execDetached(["loginctl", "lock-session"]); } diff --git a/dots/.config/quickshell/ii/modules/ii/sessionScreen/SessionScreen.qml b/dots/.config/quickshell/ii/modules/ii/sessionScreen/SessionScreen.qml index 8899c3e75..6350d18a9 100644 --- a/dots/.config/quickshell/ii/modules/ii/sessionScreen/SessionScreen.qml +++ b/dots/.config/quickshell/ii/modules/ii/sessionScreen/SessionScreen.qml @@ -14,61 +14,13 @@ import Quickshell.Hyprland Scope { id: root property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) - property bool packageManagerRunning: false - property bool downloadRunning: false - - component DescriptionLabel: Rectangle { - id: descriptionLabel - property string text - property color textColor: Appearance.colors.colOnTooltip - color: Appearance.colors.colTooltip - clip: true - radius: Appearance.rounding.normal - implicitHeight: descriptionLabelText.implicitHeight + 10 * 2 - implicitWidth: descriptionLabelText.implicitWidth + 15 * 2 - - Behavior on implicitWidth { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) - } - - StyledText { - id: descriptionLabelText - anchors.centerIn: parent - color: descriptionLabel.textColor - text: descriptionLabel.text - } - } - - function detectRunningStuff() { - packageManagerRunning = false; - downloadRunning = false; - detectPackageManagerProc.running = false; - detectPackageManagerProc.running = true; - detectDownloadProc.running = false; - detectDownloadProc.running = true; - } - - Process { - id: detectPackageManagerProc - command: ["bash", "-c", "pidof pacman yay paru dnf zypper apt apx xbps flatpak snap apk yum epsi pikman"] - onExited: (exitCode, exitStatus) => { - root.packageManagerRunning = (exitCode === 0); - } - } - - Process { - id: detectDownloadProc - command: ["bash", "-c", "pidof curl wget aria2c yt-dlp || ls ~/Downloads | grep -E '\.crdownload$|\.part$'"] - onExited: (exitCode, exitStatus) => { - root.downloadRunning = (exitCode === 0); - } - } Loader { id: sessionLoader active: GlobalStates.sessionOpen onActiveChanged: { - if (sessionLoader.active) root.detectRunningStuff(); + if (sessionLoader.active) + SessionWarnings.refresh(); } Connections { @@ -84,7 +36,7 @@ Scope { id: sessionRoot visible: sessionLoader.active property string subtitle - + function hide() { GlobalStates.sessionOpen = false; } @@ -110,7 +62,7 @@ Scope { id: sessionMouseArea anchors.fill: parent onClicked: { - sessionRoot.hide() + sessionRoot.hide(); } } @@ -119,7 +71,7 @@ Scope { anchors.centerIn: parent spacing: 15 - Keys.onPressed: (event) => { + Keys.onPressed: event => { if (event.key === Qt.Key_Escape) { sessionRoot.hide(); } @@ -128,7 +80,8 @@ Scope { ColumnLayout { Layout.alignment: Qt.AlignHCenter spacing: 0 - StyledText { // Title + StyledText { + // Title Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter font { @@ -139,7 +92,8 @@ Scope { text: Translation.tr("Session") } - StyledText { // Small instruction + StyledText { + // Small instruction Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter font.pixelSize: Appearance.font.pixelSize.normal @@ -157,8 +111,14 @@ Scope { focus: sessionRoot.visible buttonIcon: "lock" buttonText: Translation.tr("Lock") - onClicked: { Session.lock(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.lock(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.right: sessionSleep KeyNavigation.down: sessionHibernate } @@ -166,8 +126,14 @@ Scope { id: sessionSleep buttonIcon: "dark_mode" buttonText: Translation.tr("Sleep") - onClicked: { Session.suspend(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.suspend(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.left: sessionLock KeyNavigation.right: sessionLogout KeyNavigation.down: sessionShutdown @@ -176,8 +142,14 @@ Scope { id: sessionLogout buttonIcon: "logout" buttonText: Translation.tr("Logout") - onClicked: { Session.logout(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.logout(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.left: sessionSleep KeyNavigation.right: sessionTaskManager KeyNavigation.down: sessionReboot @@ -186,8 +158,14 @@ Scope { id: sessionTaskManager buttonIcon: "browse_activity" buttonText: Translation.tr("Task Manager") - onClicked: { Session.launchTaskManager(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.launchTaskManager(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.left: sessionLogout KeyNavigation.down: sessionFirmwareReboot } @@ -196,8 +174,14 @@ Scope { id: sessionHibernate buttonIcon: "downloading" buttonText: Translation.tr("Hibernate") - onClicked: { Session.hibernate(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.hibernate(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.up: sessionLock KeyNavigation.right: sessionShutdown } @@ -205,8 +189,14 @@ Scope { id: sessionShutdown buttonIcon: "power_settings_new" buttonText: Translation.tr("Shutdown") - onClicked: { Session.poweroff(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.poweroff(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.left: sessionHibernate KeyNavigation.right: sessionReboot KeyNavigation.up: sessionSleep @@ -215,8 +205,14 @@ Scope { id: sessionReboot buttonIcon: "restart_alt" buttonText: Translation.tr("Reboot") - onClicked: { Session.reboot(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.reboot(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.left: sessionShutdown KeyNavigation.right: sessionFirmwareReboot KeyNavigation.up: sessionLogout @@ -225,8 +221,14 @@ Scope { id: sessionFirmwareReboot buttonIcon: "settings_applications" buttonText: Translation.tr("Reboot to firmware settings") - onClicked: { Session.rebootToFirmware(); sessionRoot.hide() } - onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } + onClicked: { + Session.rebootToFirmware(); + sessionRoot.hide(); + } + onFocusChanged: { + if (focus) + sessionRoot.subtitle = buttonText; + } KeyNavigation.up: sessionTaskManager KeyNavigation.left: sessionReboot } @@ -247,7 +249,7 @@ Scope { spacing: 10 Loader { - active: root.packageManagerRunning + active: SessionWarnings.packageManagerRunning visible: active sourceComponent: DescriptionLabel { text: Translation.tr("Your package manager is running") @@ -256,7 +258,7 @@ Scope { } } Loader { - active: root.downloadRunning + active: SessionWarnings.downloadRunning visible: active sourceComponent: DescriptionLabel { text: Translation.tr("There might be a download in progress") @@ -268,6 +270,28 @@ Scope { } } + component DescriptionLabel: Rectangle { + id: descriptionLabel + property string text + property color textColor: Appearance.colors.colOnTooltip + color: Appearance.colors.colTooltip + clip: true + radius: Appearance.rounding.normal + implicitHeight: descriptionLabelText.implicitHeight + 10 * 2 + implicitWidth: descriptionLabelText.implicitWidth + 15 * 2 + + Behavior on implicitWidth { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + StyledText { + id: descriptionLabelText + anchors.centerIn: parent + color: descriptionLabel.textColor + text: descriptionLabel.text + } + } + IpcHandler { target: "session" @@ -276,11 +300,11 @@ Scope { } function close(): void { - GlobalStates.sessionOpen = false + GlobalStates.sessionOpen = false; } function open(): void { - GlobalStates.sessionOpen = true + GlobalStates.sessionOpen = true; } } @@ -298,7 +322,7 @@ Scope { description: "Opens session screen on press" onPressed: { - GlobalStates.sessionOpen = true + GlobalStates.sessionOpen = true; } } @@ -307,8 +331,7 @@ Scope { description: "Closes session screen on press" onPressed: { - GlobalStates.sessionOpen = false + GlobalStates.sessionOpen = false; } } - } diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml index 72f442b87..05e89dafe 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml @@ -99,7 +99,7 @@ Item { WPanelSeparator {} FooterRectangle { - FooterMoreButton { + WTextButton { anchors { verticalCenter: parent.verticalCenter left: parent.left diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml index c90d06fc0..061c74154 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml @@ -89,7 +89,7 @@ Item { WPanelSeparator {} FooterRectangle { - FooterMoreButton { + WTextButton { anchors { verticalCenter: parent.verticalCenter left: parent.left diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml index a18c59ec9..3b0d2cd42 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml @@ -66,6 +66,10 @@ Menu { } } + Component.onCompleted: { + menuListView.itemAtIndex(0)?.forceActiveFocus(); + } + contentItem: Item { implicitWidth: menuListView.implicitWidth implicitHeight: menuListView.implicitHeight diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WRectangularShadowThis.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WRectangularShadowThis.qml new file mode 100644 index 000000000..5ad46de29 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WRectangularShadowThis.qml @@ -0,0 +1,15 @@ +import QtQuick +import QtQuick.Effects +import qs.modules.common +import qs.modules.common.widgets + +Item { + default property Item contentItem + property Item shadow: WRectangularShadow { + target: contentItem + } + implicitWidth: contentItem.implicitWidth + implicitHeight: contentItem.implicitHeight + + children: [shadow, contentItem] +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/FooterMoreButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WTextButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/looks/FooterMoreButton.qml rename to dots/.config/quickshell/ii/modules/waffle/looks/WTextButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/sessionScreen/SessionScreenContent.qml b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/SessionScreenContent.qml new file mode 100644 index 000000000..ddadb373a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/SessionScreenContent.qml @@ -0,0 +1,189 @@ +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions +import qs.modules.waffle.looks +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io + +Item { + id: root + + Component.onCompleted: { + lockButton.forceActiveFocus(); + } + + ColumnLayout { + anchors.centerIn: parent + spacing: 4 + + WSessionScreenTextButton { + id: lockButton + focus: true + text: Translation.tr("Lock") + onClicked: { + GlobalStates.sessionOpen = false; + Session.lock(); + } + KeyNavigation.up: powerButton + KeyNavigation.down: signOutButton + } + WSessionScreenTextButton { + id: signOutButton + focus: true + text: Translation.tr("Sign out") + onClicked: { + GlobalStates.sessionOpen = false; + Session.logout(); + } + KeyNavigation.up: lockButton + KeyNavigation.down: changePasswordButton + } + + WSessionScreenTextButton { + id: changePasswordButton + focus: true + text: Translation.tr("Change password") + onClicked: { + GlobalStates.sessionOpen = false; + Session.changePassword(); + } + KeyNavigation.up: signOutButton + KeyNavigation.down: taskManagerButton + } + + WSessionScreenTextButton { + id: taskManagerButton + focus: true + text: Translation.tr("Task Manager") + onClicked: { + GlobalStates.sessionOpen = false; + Session.launchTaskManager(); + } + KeyNavigation.up: signOutButton + KeyNavigation.down: cancelButton + } + + CancelButton { + id: cancelButton + Layout.fillWidth: true + Layout.leftMargin: 5 + Layout.rightMargin: 5 + Layout.topMargin: 38 + onClicked: GlobalStates.sessionOpen = false + KeyNavigation.up: taskManagerButton + KeyNavigation.down: powerButton + } + } + + RowLayout { + anchors { + bottom: parent.bottom + right: parent.right + bottomMargin: 21 + rightMargin: 31 + } + PowerButton { + id: powerButton + KeyNavigation.up: cancelButton + KeyNavigation.down: lockButton + } + } + + component PowerButton: WSessionScreenTextButton { + id: root + implicitWidth: 40 + implicitHeight: 40 + focusRingRadius: Looks.radius.large + colBackgroundHover: Looks.colors.bg2Hover + colBackgroundActive: Looks.colors.bg2Active + property color color: { + if (root.down) { + return root.colBackgroundActive; + } else if (root.hovered) { + return root.colBackgroundHover; + } else { + return root.colBackground; + } + } + background: Rectangle { + id: background + radius: Looks.radius.medium + color: root.color + } + contentItem: Item { + FluentIcon { + anchors.centerIn: parent + implicitSize: 20 + icon: "power" + } + } + + onClicked: { + powerMenu.visible = !powerMenu.visible; + } + + WMenu { + id: powerMenu + x: -powerMenu.implicitWidth / 2 + root.implicitWidth / 2 + y: -powerMenu.implicitHeight + + Action { + icon.name: "power" + text: Translation.tr("Shut down") + onTriggered: Session.poweroff() + } + Action { + icon.name: "arrow-counterclockwise" + text: Translation.tr("Restart") + onTriggered: Session.reboot() + } + } + } + + component CancelButton: WBorderlessButton { + id: root + implicitHeight: 32 + colBackground: Looks.colors.bg1Base + colBackgroundHover: Qt.lighter(Looks.colors.bg1Base, 1.2) + colBackgroundActive: Qt.lighter(Looks.colors.bg1Base, 1.1) + + property bool keyboardDown: false + + Keys.onPressed: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + keyboardDown = true; + event.accepted = true; + } + } + Keys.onReleased: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + keyboardDown = false; + root.clicked(); + event.accepted = true; + } + } + + contentItem: WText { + text: Translation.tr("Cancel") + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Looks.font.pixelSize.large + } + + Rectangle { + visible: cancelButton.focus + anchors { + fill: parent + margins: -3 + } + radius: cancelButton.background.radius + 4 + color: "transparent" + border.width: 2 + border.color: "#ffffff" + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WSessionScreenTextButton.qml b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WSessionScreenTextButton.qml new file mode 100644 index 000000000..ec8b58487 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WSessionScreenTextButton.qml @@ -0,0 +1,54 @@ +pragma ComponentBehavior: Bound +import QtQuick +import qs +import qs.modules.waffle.looks + +WTextButton { + id: root + + implicitWidth: 135 + implicitHeight: 40 + horizontalPadding: 5 + + property bool keyboardDown: false + property alias focusRingRadius: focusRing.radius + + Keys.onPressed: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + keyboardDown = true; + event.accepted = true; + } + } + Keys.onReleased: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + keyboardDown = false; + root.clicked(); + event.accepted = true; + } + } + + contentItem: Item { + id: contentItem + implicitWidth: buttonText.implicitWidth + + WText { + id: buttonText + anchors.fill: parent + color: (root.pressed || root.keyboardDown) ? Looks.colors.fg1 : Looks.colors.fg + text: root.text + font.pixelSize: Looks.font.pixelSize.large + } + } + + Rectangle { + id: focusRing + visible: root.focus + anchors { + fill: parent + margins: -4 + } + color: "transparent" + border.width: 2 + border.color: "#ffffff" + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WaffleSessionScreen.qml b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WaffleSessionScreen.qml new file mode 100644 index 000000000..41c52b151 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/sessionScreen/WaffleSessionScreen.qml @@ -0,0 +1,117 @@ +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland + +Scope { + id: root + property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) + + Loader { + id: sessionLoader + active: GlobalStates.sessionOpen + onActiveChanged: { + if (sessionLoader.active) SessionWarnings.refresh(); + } + + Connections { + target: GlobalStates + function onScreenLockedChanged() { + if (GlobalStates.screenLocked) { + GlobalStates.sessionOpen = false; + } + } + } + + sourceComponent: PanelWindow { // Session menu + id: sessionRoot + visible: sessionLoader.active + property string subtitle + + function hide() { + GlobalStates.sessionOpen = false; + } + + exclusionMode: ExclusionMode.Ignore + WlrLayershell.namespace: "quickshell:session" + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive + // This is a big surface so we needa carefully choose the transparency, + // or we'll get a large scary rgb blob + color: "#000000" + + anchors { + top: true + left: true + right: true + bottom: true + } + + Item { + anchors.fill: parent + focus: true + Keys.onPressed: (event) => { + if (event.key === Qt.Key_Escape) { + sessionRoot.hide(); + } + } + + SessionScreenContent { + anchors.fill: parent + } + } + } + } + + IpcHandler { + target: "session" + + function toggle(): void { + GlobalStates.sessionOpen = !GlobalStates.sessionOpen; + } + + function close(): void { + GlobalStates.sessionOpen = false + } + + function open(): void { + GlobalStates.sessionOpen = true + } + } + + GlobalShortcut { + name: "sessionToggle" + description: "Toggles session screen on press" + + onPressed: { + GlobalStates.sessionOpen = !GlobalStates.sessionOpen; + } + } + + GlobalShortcut { + name: "sessionOpen" + description: "Opens session screen on press" + + onPressed: { + GlobalStates.sessionOpen = true + } + } + + GlobalShortcut { + name: "sessionClose" + description: "Closes session screen on press" + + onPressed: { + GlobalStates.sessionOpen = false + } + } + +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml index 2364295fc..fb506dd49 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml @@ -9,6 +9,8 @@ import qs.services import qs.modules.common import qs.modules.common.functions import qs.modules.waffle.looks +import qs.modules.waffle.startMenu.startPage +import qs.modules.waffle.startMenu.searchPage WBarAttachedPanelContent { id: root diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml index 15ffc6f43..62bdc65bf 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml @@ -70,6 +70,19 @@ Scope { } } + function toggleClipboard() { + if (LauncherSearch.query.startsWith(Config.options.search.prefix.clipboard) || !GlobalStates.searchOpen) { + GlobalStates.searchOpen = !GlobalStates.searchOpen; + } + LauncherSearch.ensurePrefix(Config.options.search.prefix.clipboard); + } + function toggleEmojis() { + if (LauncherSearch.query.startsWith(Config.options.search.prefix.emojis) || !GlobalStates.searchOpen) { + GlobalStates.searchOpen = !GlobalStates.searchOpen; + } + LauncherSearch.ensurePrefix(Config.options.search.prefix.emojis); + } + IpcHandler { target: "search" @@ -119,4 +132,22 @@ Scope { GlobalStates.superReleaseMightTrigger = false; } } + + GlobalShortcut { + name: "overviewClipboardToggle" + description: "Toggle clipboard query on overview widget" + + onPressed: { + root.toggleClipboard(); + } + } + + GlobalShortcut { + name: "overviewEmojiToggle" + description: "Toggle emoji query on overview widget" + + onPressed: { + root.toggleEmojis(); + } + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchEntryIcon.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchEntryIcon.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/SearchEntryIcon.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchEntryIcon.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchPageContent.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchPageContent.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchResultButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchResultButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchResults.qml similarity index 99% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchResults.qml index 918534b78..e02d56a50 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/SearchResults.qml @@ -5,6 +5,7 @@ import qs.modules.common import qs.modules.waffle.looks import qs.modules.common.functions import qs.modules.common.models +import qs.modules.waffle.startMenu import Quickshell import QtQuick.Layouts import QtQuick.Controls @@ -119,7 +120,7 @@ RowLayout { onModelChanged: { root.focusFirstItem(); } - delegate: WSearchResultButton { + delegate: SearchResultButton { required property int index required property var modelData entry: modelData diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/TagStrip.qml similarity index 98% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/TagStrip.qml index f1ea82ba1..33aef1906 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/searchPage/TagStrip.qml @@ -8,6 +8,7 @@ import qs.services import qs.modules.common import qs.modules.common.functions import qs.modules.waffle.looks +import qs.modules.waffle.startMenu RowLayout { id: root diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/AggregatedAppCategoryModel.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AggregatedAppCategoryModel.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/AggregatedAppCategoryModel.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AggregatedAppCategoryModel.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/AllAppsGrid.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AllAppsGrid.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/AllAppsGrid.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AllAppsGrid.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/AppCategoryGrid.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AppCategoryGrid.qml similarity index 96% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/AppCategoryGrid.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AppCategoryGrid.qml index 38c8d8d41..e1ab25c54 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/AppCategoryGrid.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/AppCategoryGrid.qml @@ -90,7 +90,7 @@ Rectangle { NumberAnimation { target: categoryFolderPopup property: "x" - from: categoryFolderPopup.originPoint.x - categoryOpenButtonLoader.width * 3 / 2 + from: categoryFolderPopup.originPoint.x - categoryOpenButtonLoader.width * 5 / 2 to: categoryFolderPopup.windowCenterPoint.x - categoryFolderPopup.width / 2 duration: 300 easing.type: Easing.BezierSpline @@ -99,7 +99,7 @@ Rectangle { NumberAnimation { target: categoryFolderPopup property: "y" - from: categoryFolderPopup.originPoint.y - categoryOpenButtonLoader.height / 2 + from: categoryFolderPopup.originPoint.y - categoryOpenButtonLoader.height * 3 / 2 to: categoryFolderPopup.windowCenterPoint.y - categoryFolderPopup.height / 2 duration: 300 easing.type: Easing.BezierSpline @@ -120,7 +120,7 @@ Rectangle { NumberAnimation { target: categoryFolderPopup property: "x" - to: categoryFolderPopup.originPoint.x - categoryOpenButtonLoader.width * 3 / 2 + to: categoryFolderPopup.originPoint.x - categoryOpenButtonLoader.width * 5 / 2 duration: 200 easing.type: Easing.BezierSpline easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut @@ -128,7 +128,7 @@ Rectangle { NumberAnimation { target: categoryFolderPopup property: "y" - to: categoryFolderPopup.originPoint.y - categoryOpenButtonLoader.height / 2 + to: categoryFolderPopup.originPoint.y - categoryOpenButtonLoader.height * 3 / 2 duration: 200 easing.type: Easing.BezierSpline easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut @@ -147,10 +147,13 @@ Rectangle { background: null Loader { + id: folderContentLoader active: categoryFolderPopup.visible - sourceComponent: CategoryFolderContent { - title: root.aggregatedCategory.name - desktopEntries: root.desktopEntries + sourceComponent: WRectangularShadowThis { + CategoryFolderContent { + title: root.aggregatedCategory.name + desktopEntries: root.desktopEntries + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/BigAppGrid.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/BigAppGrid.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/BigAppGrid.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/BigAppGrid.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartAppButton.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartAppButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/StartAppButton.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartAppButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageApps.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartPageApps.qml similarity index 93% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageApps.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartPageApps.qml index 6de65027b..b4539b317 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageApps.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartPageApps.qml @@ -44,6 +44,8 @@ BodyRectangle { component AllApps: PageSection { title: Translation.tr("All") + // TODO: Do we wanna also implement list view and grid view? + // (instead of only category view) AllAppsGrid { Layout.fillWidth: true Layout.fillHeight: true diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartPageContent.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartPageContent.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartUserButton.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartUserButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/startMenu/StartUserButton.qml rename to dots/.config/quickshell/ii/modules/waffle/startMenu/startPage/StartUserButton.qml diff --git a/dots/.config/quickshell/ii/services/SessionWarnings.qml b/dots/.config/quickshell/ii/services/SessionWarnings.qml new file mode 100644 index 000000000..c698d28c7 --- /dev/null +++ b/dots/.config/quickshell/ii/services/SessionWarnings.qml @@ -0,0 +1,39 @@ +pragma Singleton + +import qs.modules.common +import qs.modules.common.functions +import QtQuick +import Quickshell +import Quickshell.Io + +Singleton { + id: root + + property bool packageManagerRunning: false + property bool downloadRunning: false + + function refresh() { + packageManagerRunning = false; + downloadRunning = false; + detectPackageManagerProc.running = false; + detectPackageManagerProc.running = true; + detectDownloadProc.running = false; + detectDownloadProc.running = true; + } + + Process { + id: detectPackageManagerProc + command: ["bash", "-c", "pidof pacman yay paru dnf zypper apt apx xbps snap apk yum epsi pikman"] + onExited: (exitCode, exitStatus) => { + root.packageManagerRunning = (exitCode === 0); + } + } + + Process { + id: detectDownloadProc + command: ["bash", "-c", "pidof curl wget aria2c yt-dlp || ls ~/Downloads | grep -E '\.crdownload$|\.part$'"] + onExited: (exitCode, exitStatus) => { + root.downloadRunning = (exitCode === 0); + } + } +} diff --git a/dots/.config/quickshell/ii/services/Updates.qml b/dots/.config/quickshell/ii/services/Updates.qml index 58b8be892..48549ac3c 100644 --- a/dots/.config/quickshell/ii/services/Updates.qml +++ b/dots/.config/quickshell/ii/services/Updates.qml @@ -13,6 +13,7 @@ Singleton { id: root property bool available: false + property alias checking: checkUpdatesProc.running property int count: 0 readonly property bool updateAdvised: available && count > Config.options.updates.adviseUpdateThreshold diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml index 7bb565d11..55dc7bce9 100644 --- a/dots/.config/quickshell/ii/shell.qml +++ b/dots/.config/quickshell/ii/shell.qml @@ -6,7 +6,6 @@ // Adjust this to make the shell smaller or larger //@ pragma Env QT_SCALE_FACTOR=1 - import qs.modules.common import qs.modules.ii.background import qs.modules.ii.bar @@ -34,6 +33,7 @@ import qs.modules.waffle.bar import qs.modules.waffle.notificationCenter import qs.modules.waffle.onScreenDisplay import qs.modules.waffle.startMenu +import qs.modules.waffle.sessionScreen import QtQuick import QtQuick.Window @@ -85,6 +85,7 @@ ShellRoot { PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} } PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} } PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} } + PanelLoader { identifier: "wSessionScreen"; component: WaffleSessionScreen {} } ReloadPopup {} component PanelLoader: LazyLoader { @@ -97,7 +98,7 @@ ShellRoot { property list families: ["ii", "waffle"] property var panelFamilies: ({ "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], - "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"], + "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "wSessionScreen", "iiWallpaperSelector"], }) function cyclePanelFamily() { const currentIndex = families.indexOf(Config.options.panelFamily)