Give a laptop its first week: the keys, the lid, the battery's endgame

The audit's fourth tier -- what a Framework owner reaches for in the first
week and found missing.

The power button stops being an instant, unconfirmed poweroff: a shipped
logind drop-in tells the daemon to stand down and the compositor binds the
key to the power menu, the way GNOME turns it into a question. Holding it
still hard-cuts through firmware. change-settings restarts logind so the
change applies without waiting for a boot, and the Power page says what the
button does now.

The function row fills in: F10 (XF86RFKill) toggles airplane mode through a
new panama-osd verb that blocks or unblocks every radio and says which way it
went; F9 (XF86Display) opens the Displays page, the honest action until
mirroring exists. And the lid becomes a switch bind: closing a docked lid
turns the internal panel off so nothing renders inside a closed shell and no
workspace strands on an invisible output, and opening it restores the panel
with the mode and scale chosen in Settings. panama-lid owns both decisions;
undocked machines suspend via logind before any of it matters.

The battery gets an endgame. On battery the screen dims to 30% two-thirds of
the way to blanking -- GNOME's single largest idle battery saver -- and
restores exactly the level it saved. At the urgent threshold the machine
suspends after a fifteen-second grace, cancelled by plugging in, because a
suspend preserves the session for days and a hard cut at 0% preserves
nothing; "Only warn" remains a choice on the Power page. Hibernate joins the
power menu, but only where logind answers CanHibernate with yes -- an entry
that fails silently is worse than none.

And brightness stops being two code paths: the Displays page now embeds the
same control the quick-settings panel uses, so the built-in backlight and
DDC/CI monitors share one surface that withdraws itself where neither
exists. The lid contract narrows to what its principle protects -- a
HandleLidSwitch drop-in -- so deliberate policy for other keys can ship.

Claude-Session: https://claude.ai/code/session_01Epx9ZC1gwm81K3jm9x9CKh
This commit is contained in:
Gabriel Brown
2026-08-23 12:21:08 -04:00
parent 153554b5df
commit 9530e32326
15 changed files with 244 additions and 35 deletions
@@ -0,0 +1,8 @@
# A stray press of the power button should ask, not act. Fedora's logind
# default is HandlePowerKey=poweroff -- an instant, unconfirmed shutdown.
# Panama binds the key in the compositor to open its power menu instead
# (keybinds.lua), the way GNOME turns the key into a dialog, so logind is
# told to stand down. Holding the button still hard-cuts through firmware,
# which remains the escape hatch this file cannot and should not remove.
[Login]
HandlePowerKey=ignore
+28
View File
@@ -34,6 +34,10 @@ local osd = function(action)
return "$HOME/.config/quickshell/scripts/panama-osd " .. action return "$HOME/.config/quickshell/scripts/panama-osd " .. action
end end
local lid = function(action)
return "$HOME/.config/quickshell/scripts/panama-lid " .. action
end
local dictate = function(action) local dictate = function(action)
return "$HOME/.config/quickshell/scripts/panama-dictate " .. action return "$HOME/.config/quickshell/scripts/panama-dictate " .. action
end end
@@ -458,6 +462,30 @@ bind("XF86AudioStop", hl.dsp.exec_cmd(osd("media stop")), { locked = true , desc
bind("XF86MonBrightnessUp", hl.dsp.exec_cmd(osd("brightness up 5")), { locked = true, repeating = true , description = "Brightness up" }) bind("XF86MonBrightnessUp", hl.dsp.exec_cmd(osd("brightness up 5")), { locked = true, repeating = true , description = "Brightness up" })
bind("XF86MonBrightnessDown", hl.dsp.exec_cmd(osd("brightness down 5")), { locked = true, repeating = true , description = "Brightness down" }) bind("XF86MonBrightnessDown", hl.dsp.exec_cmd(osd("brightness down 5")), { locked = true, repeating = true , description = "Brightness down" })
-- Airplane mode. The Framework's F10 emits exactly this keysym, and for a
-- while it emitted it into silence. panama-osd owns the toggle so the OSD
-- can say which way it went.
bind("XF86RFKill", hl.dsp.exec_cmd(osd("airplane toggle")), { locked = true, description = "Airplane mode" })
-- F9 on the same row. GNOME shows a display-switching OSD here; until
-- mirroring exists (DESKTOP-PARITY gap), the honest action is the page where
-- displays are actually arranged.
bind("XF86Display", hl.dsp.exec_cmd("qs ipc call settings page displays"), { description = "Display settings" })
-- The power button. logind is told to ignore it (config/copy ships the
-- drop-in) so a stray press is a question, not an instant poweroff -- the
-- menu this opens is the question. Until the next boot after that drop-in
-- lands, logind still acts on the key; this bind costs nothing extra then.
bind("XF86PowerOff", hl.dsp.exec_cmd("qs ipc call powermenu toggle"), { locked = true, description = "Power menu" })
-- The lid, as a switch rather than a key. Closing a docked lid turns the
-- internal panel off so nothing renders inside a closed shell and no
-- workspace strands on an invisible output; opening it turns the panel back
-- on. panama-lid owns the decision -- undocked machines suspend via logind
-- before this matters, and the guard's inhibitor handles staying awake.
bind("switch:on:Lid Switch", hl.dsp.exec_cmd(lid("close")), { locked = true, description = "Lid closed" })
bind("switch:off:Lid Switch", hl.dsp.exec_cmd(lid("open")), { locked = true, description = "Lid opened" })
category("Applications") category("Applications")
-- Hardware keys GNOME mapped that have obvious equivalents. -- Hardware keys GNOME mapped that have obvious equivalents.
bind("XF86Tools", hl.dsp.exec_cmd(settings), { description = "Settings" }) bind("XF86Tools", hl.dsp.exec_cmd(settings), { description = "Settings" })
@@ -125,6 +125,20 @@ Singleton {
label: "Urgent at", label: "Urgent at",
detail: "Interrupt at this level, even during Do Not Disturb" detail: "Interrupt at this level, even during Do Not Disturb"
}, },
// What the desktop DOES at the critical threshold, beyond interrupting.
// Suspend by default, which is GNOME's behavior: sleep preserves the
// session at a level the firmware can hold for days, and the
// alternative -- a hard cut at 0% -- preserves nothing.
{
key: "batteryCriticalAction", type: "enum", def: "suspend", group: "battery",
label: "At the urgent level",
detail: "What happens when the battery reaches the urgent threshold while discharging",
options: [
{ value: "suspend", label: "Suspend" },
{ value: "nothing", label: "Only warn" }
]
},
// Only offered where the firmware exposes a ceiling; the Power page // Only offered where the firmware exposes a ceiling; the Power page
// hides the control entirely otherwise. 100 means charge to full. // hides the control entirely otherwise. 100 means charge to full.
{ {
@@ -5,6 +5,7 @@
// (see PowerButton); Lock and Suspend are one press because neither loses work. // (see PowerButton); Lock and Suspend are one press because neither loses work.
import Quickshell import Quickshell
import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
import QtQuick import QtQuick
import qs.config import qs.config
@@ -31,6 +32,23 @@ PanelWindow {
property int currentIndex: 0 property int currentIndex: 0
// Hibernate appears only where it can deliver: logind answers "yes" only
// with a resume-capable swap configured, and a menu entry that fails
// silently is worse than none. Checked once per shell run -- swap does
// not come and go.
property bool canHibernate: false
Process {
id: hibernateProbe
command: ["busctl", "call", "org.freedesktop.login1",
"/org/freedesktop/login1", "org.freedesktop.login1.Manager",
"CanHibernate"]
running: true
stdout: StdioCollector {
onStreamFinished: win.canHibernate = this.text.includes('"yes"')
}
}
// A uwsm-managed session logs out by stopping the uwsm unit; a plain // A uwsm-managed session logs out by stopping the uwsm unit; a plain
// "Hyprland" session must ask the compositor to exit instead. The branch // "Hyprland" session must ask the compositor to exit instead. The branch
// used to test merely that the uwsm BINARY existed -- but uwsm is always // used to test merely that the uwsm BINARY existed -- but uwsm is always
@@ -41,7 +59,11 @@ PanelWindow {
// compositor unit, wayland-wm@*.service, so that is what decides. // compositor unit, wayland-wm@*.service, so that is what decides.
readonly property string logoutScript: 'if systemctl --user list-units --no-legend --state=active "wayland-wm@*.service" 2>/dev/null | grep -q .; then exec uwsm stop; else exec hyprctl dispatch "hl.dsp.exit()"; fi' readonly property string logoutScript: 'if systemctl --user list-units --no-legend --state=active "wayland-wm@*.service" 2>/dev/null | grep -q .; then exec uwsm stop; else exec hyprctl dispatch "hl.dsp.exit()"; fi'
readonly property var entries: [ // The rows actually shown: an entry may declare `available: false` to
// withdraw itself (hibernate on a machine with no resume swap).
readonly property var entries: allEntries.filter(entry => entry.available !== false)
readonly property var allEntries: [
{ {
glyph: "󰌾", glyph: "󰌾",
label: "Lock", label: "Lock",
@@ -60,6 +82,13 @@ PanelWindow {
destructive: false, destructive: false,
cmd: ["systemctl", "suspend"] cmd: ["systemctl", "suspend"]
}, },
{
glyph: "󰋊",
label: "Hibernate",
destructive: false,
available: win.canHibernate,
cmd: ["systemctl", "hibernate"]
},
{ {
glyph: "󰜉", glyph: "󰜉",
label: "Restart", label: "Restart",
@@ -12,6 +12,7 @@
import QtQuick import QtQuick
import qs.config import qs.config
import qs.services import qs.services
import qs.modules.quicksettings
import qs.widgets import qs.widgets
SettingsPage { SettingsPage {
@@ -289,35 +290,21 @@ SettingsPage {
// writing it into settings.json would mean restoring a value the panel had // writing it into settings.json would mean restoring a value the panel had
// already moved on from. So there is no schema key here and no SliderRow -- // already moved on from. So there is no schema key here and no SliderRow --
// the rows read and write the display directly. // the rows read and write the display directly.
// One brightness surface for both kinds this machine may have, shared
// with the quick-settings panel so the two can never disagree. This card
// was DDC/CI-only for a while, which on a laptop meant Settings showed
// an error about external-monitor brightness while the panel's backlight
// worked fine one panel over.
SettingsCard { SettingsCard {
visible: Brightness.available || Brightness.lastError !== "" visible: pageBrightness.visible || Brightness.lastError !== ""
title: "Brightness" title: "Brightness"
subtitle: Brightness.available subtitle: pageBrightness.visible
? "Sent to the monitor over DDC/CI, the same channel its buttons use." ? "The built-in panel through its backlight; external monitors over DDC/CI, the same channel their buttons use."
: Brightness.lastError : Brightness.lastError
Repeater { BrightnessControl {
model: Brightness.displays id: pageBrightness
SettingRow {
id: brightnessRow
required property var modelData
required property int index
label: Displays.monitorNamed(modelData.connector)?.description || modelData.connector
detail: modelData.connector ? modelData.connector + " · " + modelData.value + "%"
: modelData.value + "%"
divider: brightnessRow.index < Brightness.displays.length - 1
controlWidth: 190
ValueSlider {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
width: parent.width width: parent.width
value: brightnessRow.modelData.value / 100
onMoved: v => Brightness.set(brightnessRow.modelData.bus, Math.round(v * 100))
}
}
} }
} }
@@ -53,8 +53,9 @@ SettingsPage {
// page rendered them -- search delivered people to this card and the // page rendered them -- search delivered people to this card and the
// controls were not here. // controls were not here.
SliderRow { setting: "batteryLowPercent" } SliderRow { setting: "batteryLowPercent" }
SliderRow { SliderRow { setting: "batteryCriticalPercent" }
setting: "batteryCriticalPercent" ChoiceRow {
setting: "batteryCriticalAction"
divider: Battery.chargeLimitSupported divider: Battery.chargeLimitSupported
} }
@@ -149,6 +150,15 @@ SettingsPage {
} }
} }
// Informational like the lid card above it: the behavior is a logind
// drop-in plus a compositor bind (see keybinds.lua), not a preference,
// and saying what a physical button does beats leaving it to be
// discovered by pressing it.
SettingsCard {
title: "The power button"
subtitle: "A press opens the power menu instead of powering off immediately. Holding it still forces power off through the firmware, as ever."
}
// Only shown when the numbers are actually contradictory, rather than as a // Only shown when the numbers are actually contradictory, rather than as a
// permanent warning nobody reads. // permanent warning nobody reads.
SettingsCard { SettingsCard {
+19
View File
@@ -117,6 +117,25 @@ generate() {
printf ' inhibit_sleep = 2\n' printf ' inhibit_sleep = 2\n'
printf '}\n' printf '}\n'
# On battery, dim before blanking -- GNOME's single largest idle
# battery saver, and the gentle warning that the screen is about to
# go. Two-thirds of the way to blank, floor of 30 seconds; -s saves
# the level and -r restores exactly it, so a person's brightness
# choice survives the round trip. Only where a real backlight exists:
# a desktop's DDC monitor is not worth waking over this.
if on_battery && (( blank_min > 0 )) \
&& command -v brightnessctl >/dev/null 2>&1 \
&& [[ -n "$(ls /sys/class/backlight 2>/dev/null)" ]]; then
dim_at=$(( blank_min * 60 * 2 / 3 ))
(( dim_at < 30 )) && dim_at=30
printf '\n# %s seconds -> dim, undone on activity.\n' "$dim_at"
printf 'listener {\n'
printf ' timeout = %s\n' "$dim_at"
printf ' on-timeout = brightnessctl -c backlight -s set 30%%\n'
printf ' on-resume = brightnessctl -c backlight -r\n'
printf '}\n'
fi
if (( blank_min > 0 )); then if (( blank_min > 0 )); then
printf '\n# %s minutes -> screen off.\n' "$blank_min" printf '\n# %s minutes -> screen off.\n' "$blank_min"
printf 'listener {\n' printf 'listener {\n'
+49 -1
View File
@@ -68,16 +68,64 @@ cmd_guard() {
sleep infinity sleep infinity
} }
# The internal panel's connector name, from the compositor: eDP, LVDS and
# DSI are built in, everything else arrived through a cable -- the same rule
# panama-hw and LidPolicy use.
internal_connector() {
hyprctl -j monitors all 2>/dev/null \
| jq -r '[.[] | select(.name | test("^(eDP|LVDS|DSI)"; "i"))][0].name // empty'
}
# Bound to the lid switch by keybinds.lua. Closing a DOCKED lid turns the
# internal panel off, so nothing renders inside a closed shell and no
# workspace strands on an invisible output; an undocked lid does nothing here
# because logind is already suspending the machine. Failure direction: if the
# disable never runs, the panel stays lit inside the shell -- wasteful, not
# harmful.
cmd_close() {
"$HW" laptop || exit 0
"$HW" external-monitor || exit 0
local internal
internal="$(internal_connector)"
[[ -n "$internal" ]] || exit 0
hyprctl eval "hl.monitor({ output = \"$internal\", disable = true })" >/dev/null
}
# Re-enable on open, preferring what the person chose for this panel in
# Settings (the same displays store monitors.lua reads at startup) and
# falling back to the panel's preferred mode.
cmd_open() {
"$HW" laptop || exit 0
local internal entry mode scale
internal="$(internal_connector)"
[[ -n "$internal" ]] || exit 0
entry="$(jq -c --arg name "$internal" '.displays[$name] // empty' \
"${XDG_CONFIG_HOME:-$HOME/.config}/panama/settings.json" 2>/dev/null)"
if [[ -n "$entry" ]]; then
mode="$(jq -r '.mode' <<<"$entry")"
scale="$(jq -r '.scale' <<<"$entry")"
hyprctl eval "hl.monitor({ output = \"$internal\", mode = \"$mode\", position = \"auto\", scale = $scale })" >/dev/null
else
hyprctl eval "hl.monitor({ output = \"$internal\", mode = \"preferred\", position = \"auto\", scale = \"auto\" })" >/dev/null
fi
}
case "${1:-status}" in case "${1:-status}" in
status) cmd_status ;; status) cmd_status ;;
guard) cmd_guard ;; guard) cmd_guard ;;
close) cmd_close ;;
open) cmd_open ;;
-h|--help) -h|--help)
cat <<'USAGE' cat <<'USAGE'
usage: panama-lid [status|guard] usage: panama-lid [status|guard|close|open]
status what closing the lid would do right now, as JSON status what closing the lid would do right now, as JSON
guard hold a handle-lid-switch inhibitor while an external display is guard hold a handle-lid-switch inhibitor while an external display is
connected; exits immediately on a machine that needs none connected; exits immediately on a machine that needs none
close docked lid closed: turn the internal panel off (bound to the lid
switch by keybinds.lua); does nothing undocked
open lid opened: turn the internal panel back on, restoring the mode
and scale chosen in Settings
USAGE USAGE
;; ;;
*) printf 'panama-lid: unknown command: %s\n' "$1" >&2; exit 2 ;; *) printf 'panama-lid: unknown command: %s\n' "$1" >&2; exit 2 ;;
+24 -1
View File
@@ -240,11 +240,34 @@ media_action() {
show_message "$kind" "$label" show_message "$kind" "$label"
} }
# Airplane mode: one rfkill state for every radio, with an OSD saying which
# way it went. "Any radio unblocked" reads as radios-on, so toggle means
# "block everything" from a mixed state -- the direction a person reaching
# for airplane mode wants.
airplane_action() {
case "${1:-toggle}" in
toggle)
if rfkill list 2>/dev/null | grep -q 'Soft blocked: no'; then
rfkill block all 2>/dev/null \
&& show_message "airplane-mode-symbolic" "Airplane mode on"
else
rfkill unblock all 2>/dev/null \
&& show_message "network-wireless-symbolic" "Airplane mode off"
fi
;;
*)
printf 'Usage: panama-osd airplane toggle\n' >&2
return 2
;;
esac
}
case "${1:-}" in case "${1:-}" in
volume) shift; adjust_volume "$@" ;; volume) shift; adjust_volume "$@" ;;
microphone) shift; adjust_microphone "$@" ;; microphone) shift; adjust_microphone "$@" ;;
brightness) shift; adjust_brightness "$@" ;; brightness) shift; adjust_brightness "$@" ;;
media) shift; media_action "$@" ;; media) shift; media_action "$@" ;;
airplane) shift; airplane_action "$@" ;;
message) message)
shift shift
kind="${1:-}" kind="${1:-}"
@@ -256,7 +279,7 @@ case "${1:-}" in
show_message "$kind" "$*" show_message "$kind" "$*"
;; ;;
*) *)
printf 'Usage: panama-osd volume|microphone|brightness|media|message ACTION [value]\n' >&2 printf 'Usage: panama-osd volume|microphone|brightness|media|airplane|message ACTION [value]\n' >&2
exit 2 exit 2
;; ;;
esac esac
@@ -7,6 +7,7 @@ import Quickshell.Bluetooth
import Quickshell.Io import Quickshell.Io
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import QtQuick import QtQuick
import qs.config
Singleton { Singleton {
id: root id: root
@@ -146,11 +147,38 @@ Singleton {
// Running out is not ambient. Published at a priority Do Not Disturb does // Running out is not ambient. Published at a priority Do Not Disturb does
// not silence, because the one notification you must not miss is the one // not silence, because the one notification you must not miss is the one
// saying the machine is about to stop. // saying the machine is about to stop.
//
// And then, unless told otherwise, the machine is put to sleep: a suspend
// at the urgent threshold preserves the session for days, a hard cut at
// 0% preserves nothing. The grace timer is what makes the warning above
// readable and the action cancelable -- plugging in during it stands
// everything down.
Timer {
id: criticalSuspend
interval: 15000
onTriggered: {
if (Battery.critical && !Battery.acOnline
&& DesktopPreferences.get("batteryCriticalAction") === "suspend")
Quickshell.execDetached(["systemctl", "suspend"]);
}
}
Connections {
target: Battery
function onAcOnlineChanged(): void {
if (Battery.acOnline)
criticalSuspend.stop();
}
}
Connections { Connections {
target: Battery target: Battery
function onCriticalChanged(): void { function onCriticalChanged(): void {
if (!root.powerInitialized || !Battery.critical) if (!root.powerInitialized || !Battery.critical)
return; return;
if (!Battery.acOnline
&& DesktopPreferences.get("batteryCriticalAction") === "suspend")
criticalSuspend.restart();
StatusEvents.publish({ StatusEvents.publish({
key: "battery-critical", key: "battery-critical",
glyph: "\u{F0083}", glyph: "\u{F0083}",
@@ -5,6 +5,6 @@
# @vicinae.mode silent # @vicinae.mode silent
# @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg # @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg
# @vicinae.description Open Power & Lock in Settings. # @vicinae.description Open Power & Lock in Settings.
# @vicinae.keywords ["settings", "warn at", "urgent at", "stop charging at", "turn the screen off after", "lock the screen after", "suspend after", "lock before sleeping", "lock after"] # @vicinae.keywords ["settings", "warn at", "urgent at", "at the urgent level", "stop charging at", "turn the screen off after", "lock the screen after", "suspend after", "lock before sleeping", "lock after"]
exec "$HOME/.config/quickshell/scripts/panama-action" settings-page power exec "$HOME/.config/quickshell/scripts/panama-action" settings-page power
+2 -1
View File
@@ -4,7 +4,7 @@
Do not edit this file. Run `quickshell/scripts/panama-settings-docs` Do not edit this file. Run `quickshell/scripts/panama-settings-docs`
after changing the schema; a contract fails when this copy is stale. after changing the schema; a contract fails when this copy is stale.
149 settings across 30 groups. 70 of them are applied to the compositor and confirmed by reading the value back. 150 settings across 30 groups. 70 of them are applied to the compositor and confirmed by reading the value back.
## accessibility ## accessibility
@@ -37,6 +37,7 @@ Found on **Power & Lock**.
|---|---|---| |---|---|---|
| **Warn at**<br>`batteryLowPercent` | 20 % | Mention the battery once it drops this low. Range 550. | | **Warn at**<br>`batteryLowPercent` | 20 % | Mention the battery once it drops this low. Range 550. |
| **Urgent at**<br>`batteryCriticalPercent` | 5 % | Interrupt at this level, even during Do Not Disturb. Range 125. | | **Urgent at**<br>`batteryCriticalPercent` | 5 % | Interrupt at this level, even during Do Not Disturb. Range 125. |
| **At the urgent level**<br>`batteryCriticalAction` | suspend | What happens when the battery reaches the urgent threshold while discharging Choices: Suspend, Only warn. |
| **Stop charging at**<br>`batteryChargeLimit` | 100 % | Charging to less than full is easier on the battery over years. Range 50100. | | **Stop charging at**<br>`batteryChargeLimit` | 100 % | Charging to less than full is easier on the battery over years. Range 50100. |
## capture ## capture
+10
View File
@@ -37,6 +37,16 @@ if [[ -f /etc/udev/rules.d/99-panama-gpu.rules ]]; then
sudo udevadm trigger --subsystem-match=drm sudo udevadm trigger --subsystem-match=drm
fi fi
# The power-key drop-in lands via the same copy; logind reads its config only
# at start, so without this the button keeps hard-powering-off until the next
# boot. Restarting logind is what Fedora's own updates do and current systemd
# preserves sessions across it.
if [[ -f /etc/systemd/logind.conf.d/panama-power-key.conf ]]; then
log "Reloading logind so the power button opens the menu instead of powering off"
sudo systemctl try-restart systemd-logind 2>/dev/null \
|| log "Could not restart logind; the power-button change applies at next boot"
fi
# The document-portal drop-in lands via the same copy. A user unit's drop-ins # The document-portal drop-in lands via the same copy. A user unit's drop-ins
# are read at daemon-reload, so without this the guard applies from the next # are read at daemon-reload, so without this the guard applies from the next
# login rather than from now -- and the failure it guards against is one you # login rather than from now -- and the failure it guards against is one you
@@ -36,7 +36,7 @@ SHELL_WORDS='^(if|then|else|elif|fi|for|while|until|do|done|case|esac|in|functio
# authselect is on the list for the same reason: it manages Fedora's PAM and # authselect is on the list for the same reason: it manages Fedora's PAM and
# nsswitch profiles and arrives with fprintd-pam, realmd and nss-mdns, so the # nsswitch profiles and arrives with fprintd-pam, realmd and nss-mdns, so the
# fingerprint aliases in config/bash can rely on it without declaring it. # fingerprint aliases in config/bash can rely on it without declaring it.
BASELINE='^(sh|bash|cat|cut|sed|awk|gawk|grep|egrep|head|tail|sort|uniq|tr|wc|find|xargs|basename|dirname|mkdir|rm|cp|mv|ln|chmod|chown|stat|df|du|date|sleep|env|id|tee|touch|mktemp|readlink|realpath|seq|comm|join|paste|od|file|nl|fold|column|tput|timeout|flock|install|sha256sum|md5sum|base64|nproc|uptime|free|uname|hostname|whoami|ps|pgrep|pkill|kill|killall|lsblk|mount|umount|sudo|su|rpm|dnf|flatpak|git|python3|ss|ip|lsof|authselect|setsid|nohup|grub2-mkconfig)$' BASELINE='^(sh|bash|cat|cut|sed|awk|gawk|grep|egrep|head|tail|sort|uniq|tr|wc|find|xargs|basename|dirname|mkdir|rm|cp|mv|ln|chmod|chown|stat|df|du|date|sleep|env|id|tee|touch|mktemp|readlink|realpath|seq|comm|join|paste|od|file|nl|fold|column|tput|timeout|flock|install|sha256sum|md5sum|base64|nproc|uptime|free|uname|hostname|whoami|ps|pgrep|pkill|kill|killall|lsblk|mount|umount|sudo|su|rpm|dnf|flatpak|git|python3|ss|ip|ls|rfkill|lsof|authselect|setsid|nohup|grub2-mkconfig)$'
SESSION='^(systemctl|busctl|journalctl|loginctl|hostnamectl|localectl|systemd-inhibit|systemd-run|udevadm|gsettings|dconf|dbus-send|dbus-monitor|hyprctl|qs|quickshell|gnf|panama|wl-copy|wl-paste)$' SESSION='^(systemctl|busctl|journalctl|loginctl|hostnamectl|localectl|systemd-inhibit|systemd-run|udevadm|gsettings|dconf|dbus-send|dbus-monitor|hyprctl|qs|quickshell|gnf|panama|wl-copy|wl-paste)$'
+6 -2
View File
@@ -46,8 +46,12 @@ mkdir -p "$fake/bin"
# ── 1. Panama never takes the lid over ─────────────────────────────────────── # ── 1. Panama never takes the lid over ───────────────────────────────────────
if compgen -G "$repo_dir/config/copy/etc/systemd/logind.conf.d/*" >/dev/null 2>&1; then # Specifically the LID. Other keys may be configured there -- the power-key
note 'a logind drop-in is shipped; the inhibitor approach exists so the lid is never left doing nothing' # drop-in is deliberate policy with a compositor bind behind it -- but a
# HandleLidSwitch line would replace the inhibitor design this file protects.
if compgen -G "$repo_dir/config/copy/etc/systemd/logind.conf.d/*" >/dev/null 2>&1 \
&& sed 's/#.*//' "$repo_dir"/config/copy/etc/systemd/logind.conf.d/* | grep -q 'HandleLidSwitch'; then
note 'a logind drop-in sets HandleLidSwitch; the inhibitor approach exists so the lid is never left doing nothing'
fi fi
# Comments are stripped first: these files explain at length what they # Comments are stripped first: these files explain at length what they
# deliberately do NOT do, and prose naming HandleLidSwitch or lock-session is # deliberately do NOT do, and prose naming HandleLidSwitch or lock-session is