From c635798c7e782af84ba1cf592e93619376a93d8a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 13 Oct 2026 09:54:18 +0200 Subject: feat(island): controls panel in the status pill, island IPC A settings icon in the status pill opens the controls panel in the same capsule the sound panel uses. Right-click on a tile closes the panel and opens its drawer page. The island IPC target reveals the island and toggles the panel, for the SUPER release bind. Co-Authored-By: Claude Opus 5.5 --- desktop/island/Island.qml | 13 ++++++++++++- desktop/island/StatusPill.qml | 42 ++++++++++++++++++++++++++++++++++++------ desktop/shell.qml | 8 ++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/desktop/island/Island.qml b/desktop/island/Island.qml index 9cee3d5..43422dc 100644 --- a/desktop/island/Island.qml +++ b/desktop/island/Island.qml @@ -36,7 +36,7 @@ PanelWindow { WlrLayershell.namespace: "quickshell-island" WlrLayershell.keyboardFocus: panel !== "" ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None - // "" or "sound". + // "", "sound" or "controls". property string panel: "" // --- reveal and hide ------------------------------------------------- @@ -61,6 +61,15 @@ PanelWindow { else if (!hovered) hideTimer.restart(); } + // The keybind's way in: reveal, and open or close the controls panel. + // Closing goes through onPanelChanged, which starts the hide timer when + // the pointer is elsewhere. + function toggleControls() { + hideTimer.stop(); + shown = true; + panel = panel === "controls" ? "" : "controls"; + } + Timer { id: hideTimer interval: 400 @@ -206,5 +215,7 @@ PanelWindow { onMenuShown: win.menuHeld = true onOpenSound: win.panel = win.panel === "sound" ? "" : "sound" onOpenDrawer: { win.panel = ""; win.drawer.show("sound"); } + onOpenControls: win.toggleControls() + onOpenPage: page => { win.panel = ""; win.drawer.show(page); } } } diff --git a/desktop/island/StatusPill.qml b/desktop/island/StatusPill.qml index 5ab8f95..1b84ec1 100644 --- a/desktop/island/StatusPill.qml +++ b/desktop/island/StatusPill.qml @@ -16,9 +16,9 @@ import QtQuick import ".." import "Logic.js" as Logic -// Volume icon, tray, layout flag. The volume icon is the only way into the -// sound panel and has no other gesture; the tray is a plain tray; the flag -// switches layout on scroll and ignores clicks. +// Controls icon, volume icon, tray, layout flag. The controls and volume +// icons open their panels in this capsule; the tray is a plain tray; the +// flag switches layout on scroll and ignores clicks. Capsule { id: pill @@ -28,14 +28,20 @@ Capsule { property string panel: "" signal openSound() + signal openControls() signal openDrawer() + // A drawer page, from a control tile's right-click. + signal openPage(string page) // Emitted just before a tray menu opens; the menu cannot report its close. signal menuShown() - expanded: panel === "sound" + expanded: panel !== "" restWidth: restRow.implicitWidth + 24 panelWidth: 320 - panelHeight: soundPanel.implicitHeight + 28 + panelHeight: (panel === "controls" ? controlsPanel.implicitHeight : soundPanel.implicitHeight) + 28 + + // Edit mode never outlives its panel. + onPanelChanged: controlsPanel.editing = false Row { id: restRow @@ -45,6 +51,18 @@ Capsule { visible: opacity > 0 Behavior on opacity { NumberAnimation { duration: 120 } } + IconImage { + anchors.verticalCenter: parent.verticalCenter + implicitSize: 18 + source: Quickshell.iconPath("preferences-system", true) + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: pill.openControls() + } + } + IconImage { anchors.verticalCenter: parent.verticalCenter implicitSize: 18 @@ -116,9 +134,21 @@ Capsule { y: 14 width: pill.panelWidth - 28 sound: pill.sound - opacity: pill.expanded ? 1 : 0 + opacity: pill.panel === "sound" ? 1 : 0 visible: opacity > 0 Behavior on opacity { NumberAnimation { duration: 160 } } onOpenDrawer: pill.openDrawer() } + + ControlsPanel { + id: controlsPanel + x: 14 + y: 14 + width: pill.panelWidth - 28 + sound: pill.sound + opacity: pill.panel === "controls" ? 1 : 0 + visible: opacity > 0 + Behavior on opacity { NumberAnimation { duration: 160 } } + onOpenDrawer: page => pill.openPage(page) + } } diff --git a/desktop/shell.qml b/desktop/shell.qml index eac0ddd..d70b338 100644 --- a/desktop/shell.qml +++ b/desktop/shell.qml @@ -67,6 +67,7 @@ ShellRoot { // The island on DP-1. It reads the sound module's service rather than // binding PipeWire a second time. Island { + id: island sound: soundModule.service drawer: drawer } @@ -85,4 +86,11 @@ ShellRoot { function toggle() { drawer.toggle(""); } function close() { drawer.close(); } } + + // The bare SUPER release bind reaches this: + // qs -p ipc call island controls + IpcHandler { + target: "island" + function controls() { island.toggleControls(); } + } } -- cgit v1.2.3