dotfiles/scripts/.local/bin/powermenu
Marty Oehme 47a96a2d42
scripts: Fix powermenu log out without elogind
On my current voidlinux system I have no access to elogind and riverwm
will just be restarted when I exit it (since it is watched over by a
user service).

My session is started by the display manager 'greetd' (which in turn
runs tuigreet but that is not important here). So, to log out of the
session - we do a search for the 'greetd' process and if we find it we
search its _child_ processes which are the ones that we can kill without
being a super user.

If we kill the right process here, the session will close (since the
'watched' process exits and greetd just takes over again). This would be
a little easier if we started riverwm through greetd directly but I like
this indirection for stability (automatic service restarts), flexibility
(I can stop the riverwm service independent of my session), and adaption
(we can use Turnstile environment variables between my session
services).

So we just close all the processes that are children of greetd --
perhaps we accidentally catch a process which is _not_ the root session
process run by greetd but we'll kill it nevertheless since all child
processes might stop greetd from taking over (and they would be closed
anyway when ending the session afaik).

I have no linger enabled on my system so far (user processes staying
enabled after log-out) and I do not know how that would interact with
this method.
2025-03-10 20:22:00 +01:00

113 lines
3.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# A simple powermenu listing.
# Uses bemenu to display the powermenu on X11, Wayland and terminal.
#### Environment Variable Options ###
# Interface options
# POWERMENU_SHOW_ICONS=1
# POWERMENU_SHOW_TEXT=1
# POWERMENU_SHOW_UPTIME=1
# Command options
# POWERMENU_SHUTDOWN_CMD=""
# POWERMENU_REBOOT_CMD=""
# POWERMENU_LOCKSCREEN_CMD=""
# POWERMENU_LOGOUT_CMD=""
# POWERMENU_SUSPEND_CMD=""
# POWERMENU_HIBERNATE_CMD=""
# Command chooser options
# POWERMENU_PICKER_CMD=""
# POWERMENU_PICKER_OPTS=""
#### Menu Options ###
if [ "${POWERMENU_SHOW_TEXT:-0}" -eq 0 ] && [ "${POWERMENU_SHOW_ICONS:-1}" -eq 0 ]; then
echo "You disabled both text and icons for rofi-powermenu, nothing can be shown."
exit 1
elif [ "${POWERMENU_SHOW_ICONS:-1}" -eq 1 ]; then
power_off_btn="⏻"
reboot_btn=""
lock_btn=""
suspend_btn="󰒲"
hibernate_btn="⏾"
logout_btn="󰍃"
fi
if [ "${POWERMENU_SHOW_TEXT:-1}" -eq 1 ]; then
power_off_btn="${power_off_btn} Shut Down"
reboot_btn="${reboot_btn} Restart"
lock_btn="${lock_btn} Lock Screen"
suspend_btn="${suspend_btn} Suspend"
hibernate_btn="${hibernate_btn} Hibernate"
logout_btn="${logout_btn} Log Out"
fi
## SET PROMPT
if [ "${POWERMENU_SHOW_UPTIME:-1}" -eq 1 ]; then
prompt="Uptime $(uptime -p | sed -e 's/up //g') >"
else
prompt="Power >"
fi
selector_program="${POWERMENU_PICKER_CMD:-bemenu}"
selector_opts="${POWERMENU_PICKER_OPTS:--i}"
menu=$(printf "%s\n" "$lock_btn" "$suspend_btn" "$power_off_btn" "$reboot_btn" "$hibernate_btn" "$logout_btn")
# shellcheck disable=SC2086
result=$(printf "%s" "$menu" | $selector_program $selector_opts --prompt "$prompt")
# grep -a since it assumes with our nullcodes etc that this is a binary file
# grep -o to only leave the things we grep for
case "$result" in
"Shutdown" | "$power_off_btn")
if [ -n "$POWERMENU_SHUTDOWN_CMD" ]; then eval "$POWERMENU_SHUTDOWN_CMD"; else
if [ -x /usr/bin/systemctl ]; then
systemctl poweroff
else
sudo poweroff
fi
fi
;;
"Reboot" | "$reboot_btn")
if [ -n "$POWERMENU_REBOOT_CMD" ]; then eval "$POWERMENU_REBOOT_CMD"; else
if [ -x /usr/bin/systemctl ]; then
systemctl reboot
else
sudo reboot
fi
fi
;;
"Lockscreen" | "$lock_btn")
# Completely detach from the parent script
# If in/outputs are not redirected, rofi will wait for the forked process as well.
if [ -n "$POWERMENU_LOCKSCREEN_CMD" ]; then eval "$POWERMENU_LOCKSCREEN_CMD"; else
lockscreen
fi
;;
"Logout" | "$logout_btn")
if [ -n "$POWERMENU_LOGOUT_CMD" ]; then eval "$POWERMENU_LOGOUT_CMD"; else
command -v i3 >/dev/null 2>&1 && i3-msg exit
command -v riverctl >/dev/null 2>&1 && riverctl exit
# Try to heuristically find the program started by greetd and shut it down.
# Generally this will just be a 'pause' program on my system.
if command -v pgrep >/dev/null 2>&1 && pgrep greetd; then
kill $(pgrep -P "$(pgrep greetd | tr '\n' ',')" pause)
fi
fi
;;
"Suspend" | "$suspend_btn")
if [ -n "$POWERMENU_SUSPEND_CMD" ]; then eval "$POWERMENU_SUSPEND_CMD"; else
if [ -x /usr/bin/systemctl ]; then
systemctl suspend-then-hibernate
else
sudo zzz
fi
fi
;;
"Hibernate" | "$hibernate_btn")
if [ -n "$POWERMENU_HIBERNATE_CMD" ]; then eval "$POWERMENU_HIBERNATE_CMD"; else
if [ -x /usr/bin/systemctl ]; then
systemctl hibernate
else
sudo ZZZ
fi
fi
;;
esac