diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-11 17:00:29 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-11 17:00:29 +0200 |
| commit | d0d878dec69f6e6f99562601b1d6db1c152f724c (patch) | |
| tree | 2b58a247386a63de6a04e982f2be4fc267158d1e /vm-manager | |
| parent | d00f52480b19b714f50b1a017935e94ed1b486b5 (diff) | |
| download | quickshell-d0d878dec69f6e6f99562601b1d6db1c152f724c.tar.gz quickshell-d0d878dec69f6e6f99562601b1d6db1c152f724c.zip | |
fix(vm-manager): close on Escape, and stay running
Two bugs that both looked like the panel ignoring input.
Escape did nothing despite the panel saying it closes. Keys.onEscapePressed
was on the PanelWindow, and key events go to a focused item rather than to
a window, so it never fired. A filled Item with focus: true now catches it
and reclaims focus when a delete confirmation's TextInput releases it.
The shell also exited whenever the drawer was closed, which is most of the
time: with the LazyLoader inactive there is no visible window, and
quickshell quits at that point. Since the keybind reaches the panel over
IPC, that left the key talking to nothing. Same 1x1 transparent keepalive
window as volume-osd, for the same reason.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7NRsGyF9jGfPYS4zPqpN7
Diffstat (limited to 'vm-manager')
| -rw-r--r-- | vm-manager/README.md | 14 | ||||
| -rw-r--r-- | vm-manager/VmPanel.qml | 35 |
2 files changed, 48 insertions, 1 deletions
diff --git a/vm-manager/README.md b/vm-manager/README.md index 1bc20ef..8d817f9 100644 --- a/vm-manager/README.md +++ b/vm-manager/README.md @@ -69,6 +69,20 @@ Statistics do need sampling, on a 2 second timer, but only while the drawer is open: `Virsh.sampling` follows the panel's `open`. A closed panel costs one idle process waiting on an event socket. +## Two things that bite + +**A config with no visible window exits.** The drawer is closed most of the +time, so the shell holds itself open with a 1x1 transparent window with an +empty mask, which is click-through and draws nothing. Without it the shell +loads, reports no error and quits, and since `SUPER+v` reaches it over IPC, +the key then has nothing to talk to and silently does nothing. + +**Key events reach an item, not a window.** Setting `keyboardFocus` on the +layer shell is necessary but not sufficient: `Keys.onEscapePressed` on the +PanelWindow itself never fires, because no item inside holds focus. A filled +`Item` with `focus: true` catches it, and takes focus back when the TextInput +in a delete confirmation gives it up. + ## Destructive actions `Reset`, `Force stop`, snapshot `Revert` and snapshot `Delete` each take one diff --git a/vm-manager/VmPanel.qml b/vm-manager/VmPanel.qml index 7aecaab..cf224d6 100644 --- a/vm-manager/VmPanel.qml +++ b/vm-manager/VmPanel.qml @@ -78,6 +78,20 @@ Scope { else Virsh.act(vm, action); } + // Quickshell exits once no window is visible, and the drawer is closed + // most of the time, so a 1x1 transparent window holds the process open. + // Without it the shell quits and the keybind, which reaches it over IPC, + // has nothing left to talk to. + PanelWindow { + visible: true + implicitWidth: 1 + implicitHeight: 1 + color: "transparent" + exclusionMode: ExclusionMode.Ignore + mask: Region {} + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + } + LazyLoader { active: root.open @@ -102,7 +116,26 @@ Scope { MouseArea { anchors.fill: parent; onClicked: root.close() } } - Keys.onEscapePressed: root.confirming ? root.confirming = null : root.close() + // Keys reach an item, not the window, so something inside has to + // hold focus. The TextInput in a delete confirmation takes it when + // it appears; this takes it back whenever that is gone. + Item { + id: keyCatcher + anchors.fill: parent + focus: true + + Keys.onEscapePressed: { + if (root.confirming) root.confirming = null; + else root.close(); + } + + Connections { + target: root + function onConfirmingChanged() { + if (!root.confirming) keyCatcher.forceActiveFocus(); + } + } + } Rectangle { id: drawer |
