Draw idle as one timeline, and let the power button answer to its owner
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -63,26 +63,34 @@ PanelWindow {
|
||||
// withdraw itself (hibernate on a machine with no resume swap).
|
||||
readonly property var entries: allEntries.filter(entry => entry.available !== false)
|
||||
|
||||
// `entryId` is the stable name outside code can address an entry by --
|
||||
// the power-button bind asks for "poweroff" and gets Power Off wherever it
|
||||
// happens to sit. Labels are copy and hibernate comes and goes, so neither
|
||||
// is something an IPC call can be built on.
|
||||
readonly property var allEntries: [
|
||||
{
|
||||
entryId: "lock",
|
||||
glyph: "",
|
||||
label: "Lock",
|
||||
destructive: false,
|
||||
cmd: ["loginctl", "lock-session"]
|
||||
},
|
||||
{
|
||||
entryId: "logout",
|
||||
glyph: "",
|
||||
label: "Log Out",
|
||||
destructive: true,
|
||||
cmd: ["sh", "-c", win.logoutScript]
|
||||
},
|
||||
{
|
||||
entryId: "suspend",
|
||||
glyph: "",
|
||||
label: "Suspend",
|
||||
destructive: false,
|
||||
cmd: ["systemctl", "suspend"]
|
||||
},
|
||||
{
|
||||
entryId: "hibernate",
|
||||
glyph: "",
|
||||
label: "Hibernate",
|
||||
destructive: false,
|
||||
@@ -90,12 +98,14 @@ PanelWindow {
|
||||
cmd: ["systemctl", "hibernate"]
|
||||
},
|
||||
{
|
||||
entryId: "restart",
|
||||
glyph: "",
|
||||
label: "Restart",
|
||||
destructive: true,
|
||||
cmd: ["systemctl", "reboot"]
|
||||
},
|
||||
{
|
||||
entryId: "poweroff",
|
||||
glyph: "",
|
||||
label: "Power Off",
|
||||
destructive: true,
|
||||
@@ -103,14 +113,70 @@ PanelWindow {
|
||||
}
|
||||
]
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!win.visible)
|
||||
// The entry to arm once the menu is on screen, set by preselect() before
|
||||
// opening. Cleared as soon as it is applied, and again on close, so an
|
||||
// interrupted open can never arm something on the next unrelated one.
|
||||
property string armOnOpen: ""
|
||||
|
||||
function indexOfEntry(entryId: string): int {
|
||||
for (let i = 0; i < win.entries.length; i++) {
|
||||
if (win.entries[i].entryId === entryId)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open the menu with one entry pre-armed, addressed by its id.
|
||||
//
|
||||
// This is what the power button's "Powers off" setting binds to: the first
|
||||
// press opens the menu with Power Off selected and armed, and the second
|
||||
// press is the confirm the menu already asks for. Nothing here goes around
|
||||
// that confirm -- it calls the same trigger() a click calls, so a
|
||||
// destructive entry still takes two presses and a harmless one still takes
|
||||
// one. Pre-arming only removes the reach for the mouse, not the question.
|
||||
function preselect(entryId: string): void {
|
||||
const index = win.indexOfEntry(entryId);
|
||||
if (index < 0) {
|
||||
// An id this machine has no entry for -- hibernate without a
|
||||
// resume swap. Open the menu rather than doing nothing at all.
|
||||
win.armOnOpen = "";
|
||||
ShellState.open("powermenu");
|
||||
return;
|
||||
}
|
||||
if (!win.visible) {
|
||||
win.armOnOpen = entryId;
|
||||
ShellState.open("powermenu");
|
||||
return;
|
||||
}
|
||||
// Already open: this press is the next one in the sequence.
|
||||
win.currentIndex = index;
|
||||
const button = rep.itemAt(index);
|
||||
if (button)
|
||||
button.trigger();
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!win.visible) {
|
||||
win.armOnOpen = "";
|
||||
return;
|
||||
}
|
||||
// Never reopen with a destructive button still armed from last time.
|
||||
win.currentIndex = 0;
|
||||
for (let i = 0; i < rep.count; i++)
|
||||
rep.itemAt(i).disarm();
|
||||
keys.forceActiveFocus();
|
||||
|
||||
const wanted = win.armOnOpen;
|
||||
win.armOnOpen = "";
|
||||
if (wanted === "")
|
||||
return;
|
||||
const index = win.indexOfEntry(wanted);
|
||||
if (index < 0)
|
||||
return;
|
||||
win.currentIndex = index;
|
||||
const button = rep.itemAt(index);
|
||||
if (button)
|
||||
button.trigger();
|
||||
}
|
||||
|
||||
function run(index: int): void {
|
||||
|
||||
Reference in New Issue
Block a user