feat(x11): disable X screensaver/DPMS blanking and enforce explicit-only locking

This commit is contained in:
Luxferre
2026-10-22 22:15:28 +03:00
parent c646800dbf
commit 179cc3066b
20 changed files with 38 additions and 227 deletions
+2 -2
View File
@@ -117,8 +117,8 @@ sudo dd if=./images/bananarchy-nokia-argon.img of=/dev/sdX bs=4M status=progress
| **Center OK** | `Return` (`KEY_OK`) | Confirm / Enter, or commit active T9 preedit candidate immediately |
| **Slider close / open** | `SW_LID` (`lid:on` / `lid:off`) | **Close**: close open menu, turn off keypad backlight, and lock/turn screen off; **Open**: restore keypad backlight, unlock, and turn screen on |
> **Waking & unlocking after screen fade**:
> When the screen turns off after inactivity (or when the slider is closed), you can wake and unlock the phone in a single action by either:
> **Explicit locking & waking**:
> X11 screensaver/DPMS blanking and automatic idle locking are disabled so the phone only locks when explicitly requested (`Power -> Lock / Lock (Screen off)`, `XDrawer -> Lock`, `2× End / Power`, or closing the physical slider). When locked, you can wake and unlock the phone in a single action by either:
> - **Opening the slider** (`SW_LID` off), or
> - Pressing **End / Power (red)**, **Left softkey**, **Right softkey**, or **Call (green)** once.
@@ -6,6 +6,12 @@ Section "ServerFlags"
Option "StandbyTime" "0"
Option "SuspendTime" "0"
Option "OffTime" "0"
Option "DPMS" "false"
EndSection
Section "Monitor"
Identifier "DefaultMonitor"
Option "DPMS" "false"
EndSection
Section "Device"
@@ -24,9 +24,6 @@ while ! superctl status > /dev/null 2>&1; do
sleep 0.05
done
# Not dangerous if "locker" isn't an available state
sxmo_state.sh set locker
if [ -n "$SXMO_ROTATE_START" ]; then
sxmo_rotate.sh
fi
@@ -51,7 +51,8 @@ fi
unset WAYLAND_DISPLAY
unset SWAYSOCK
mkdir -p "$XDG_RUNTIME_DIR"
mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CACHE_HOME/sxmo"
touch "$XDG_CACHE_HOME/sxmo/sxmo.noidle"
[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ] && printf "%s\n" "$DBUS_SESSION_BUS_ADDRESS" > "$XDG_RUNTIME_DIR/dbus.bus"
printf "unlock\n" > "$XDG_RUNTIME_DIR/sxmo.state"
@@ -65,15 +66,17 @@ XORG_MODPATH="/usr/lib/xorg/modules/xlibre-25,/usr/lib/xorg/modules"
[ -d /tmp/x11/usr/lib/xorg/modules ] && XORG_MODPATH="/tmp/x11/usr/lib/xorg/modules/xlibre-25,/tmp/x11/usr/lib/xorg/modules"
if ! pidof -s Xorg >/dev/null 2>&1; then
"$XORG_BIN" :0 -nocursor -nolisten tcp -config /tmp/xorg-bananarchy.conf -modulepath "$XORG_MODPATH" -logfile /tmp/Xorg.0.log >/dev/null 2>&1 </dev/null &
"$XORG_BIN" :0 -s 0 -dpms -nocursor -nolisten tcp -config /tmp/xorg-bananarchy.conf -modulepath "$XORG_MODPATH" -logfile /tmp/Xorg.0.log >/dev/null 2>&1 </dev/null &
i=0
while [ "$i" -lt 40 ]; do
if xset s off -dpms >/dev/null 2>&1; then
if xset s off s noblank s 0 0 -dpms >/dev/null 2>&1; then
break
fi
sleep 0.05
i=$((i + 1))
done
else
xset s off s noblank s 0 0 -dpms >/dev/null 2>&1 || true
fi
xrdb -merge "$HOME/.Xresources" >/dev/null 2>&1 || true
Binary file not shown.
-3
View File
@@ -219,8 +219,6 @@ $icon_phl Modem Log^0^sxmo_modemlog.sh"
bt_is_unblocked_fast && _bt_icon="$icon_ton"
_susp_icon="$icon_ton"
[ -e "${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.nosuspend" ] && _susp_icon="$icon_tof"
_idle_icon="$icon_ton"
[ -e "${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.noidle" ] && _idle_icon="$icon_tof"
CHOICES="$icon_cfg Themes^0^xthemes
$icon_aru Brightness^1^sxmo_brightness.sh up
$icon_ard Brightness^1^sxmo_brightness.sh down
@@ -228,7 +226,6 @@ $icon_cfg Toggle Bar^0^sxmo_wm.sh togglebar
$icon_bth Bluetooth $_bt_icon^1^doas sxmo_bluetoothtoggle.sh && sxmo_hook_statusbar.sh bluetooth
$icon_clk Change Timezone^1^sxmo_timezonechange.sh
$icon_zzz Auto-suspend $_susp_icon^1^(rm ${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.nosuspend 2>/dev/null || touch ${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.nosuspend)
$icon_zzz Auto-screen-off $_idle_icon^1^(rm ${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.noidle 2>/dev/null || touch ${XDG_CACHE_HOME:-$HOME/.cache}/sxmo/sxmo.noidle) && sxmo_state.sh set unlock
$icon_trm Hooks^0^sxmo_hookmenu.sh
$icon_cfg Suspend Blockers^0^sxmo_terminal.sh sxmo_debug_suspend.sh
$icon_inf Log^0^sxmo_terminal.sh tail -n 100 -f ${XDG_STATE_HOME:-$HOME}/sxmo.log
+1 -1
View File
@@ -20,7 +20,7 @@ envvars() {
defaults() {
xsetroot -solid '#1c1c1c'
xset s off -dpms
xset s off s noblank s 0 0 -dpms
[ -e "$HOME"/.Xresources ] && xrdb -merge "$HOME"/.Xresources
if [ -f /usr/share/wallpapers/bananarchy.png ] && command -v feh >/dev/null 2>&1; then
feh --no-fehbg --bg-fill /usr/share/wallpapers/bananarchy.png &
+2 -76
View File
@@ -1,78 +1,4 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
_swayidletoidles() {
while [ $# -gt 0 ]; do
case "$1" in
timeout)
printf "%s|%s" "$2" "$3"
shift 3
case "$1" in
resume)
printf "|%s" "$2"
shift 2
;;
esac
printf "\n"
;;
*)
shift
;;
esac
done
}
xorgidle() {
if ! command -v xprintidle >/dev/null 2>&1; then
while : ; do
sleep 3600
done
fi
idles="$(_swayidletoidles "$@")"
resumes=""
tick=0
new_idle="$(xprintidle 2>/dev/null || printf '0')"
[ -n "$new_idle" ] || new_idle=0
last_idle="$new_idle"
finish() {
sh -c "$resumes"
resumes=""
exit
}
trap 'finish' TERM INT EXIT
while : ; do
last_idle="$new_idle"
new_idle="$(xprintidle 2>/dev/null || printf '0')"
[ -n "$new_idle" ] || new_idle=0
if [ "$last_idle" -gt "$new_idle" ] 2>/dev/null; then
sh -c "$resumes"
tick=0
resumes=""
fi
if printf "%b\n" "$idles" | grep -q "^$tick|"; then
printf "%b\n" "$idles" | \
grep "^$tick|" | \
cut -d'|' -f2 | \
xargs -I{} -0 sh -c "{}"
resumes="$(printf "%b\n" "$idles" | grep "^$tick|" | cut -d'|' -f3);$resumes"
fi
sleep 1
tick=$((tick + 1))
done
}
case "$SXMO_WM" in
dwm|i3)
xorgidle "$@"
;;
sway|river)
exec swayidle "$@"
;;
esac
# Automatic idle locking and screen blanking are disabled on Bananarchy.
exit 0
+5 -53
View File
@@ -15,43 +15,8 @@ fi
SXMO_SUSPENDABLE_STATES="${SXMO_SUSPENDABLE_STATES:-screenoff 3}"
transition_can_suspend() {
# shellcheck disable=SC2086
set -- $SXMO_SUSPENDABLE_STATES
tmpstate=
timeout=
while [ $# -gt 0 ]; do
if [ "$1" = "$state" ]; then
tmpstate="$1"
timeout="$2"
break
fi
shift 2
done
stop_idle_suspender() {
sxmo_jobs.sh stop idle_suspender
sxmo_wakelock.sh lock sxmo_not_suspendable infinite
}
if [ -z "$tmpstate" ]; then
sxmo_log "this state is not suspendable"
stop_idle_suspender
return
fi
case "$timeout" in
''|*[!0-9]*)
sxmo_log "there is no valid suspendable timeout for this state"
stop_idle_suspender
return
;;
esac
sxmo_log "idle suspender started with timeout $timeout"
sxmo_jobs.sh start idle_suspender sxmo_idle.sh -w \
timeout "$timeout" 'sxmo_wakelock.sh unlock sxmo_not_suspendable' \
resume 'sxmo_wakelock.sh lock sxmo_not_suspendable infinite'
sxmo_jobs.sh stop idle_suspender 2>/dev/null || true
sxmo_wakelock.sh lock sxmo_not_suspendable infinite 2>/dev/null || true
}
transition() {
@@ -104,22 +69,9 @@ click() {
}
idle() {
count="${1:-1}"
# shellcheck disable=SC2086
set -- $SXMO_STATES
while [ $# -gt 1 ]; do
if [ "$1" = "$state" ]; then
if [ "$count" -ge "$#" ]; then
count=$(($# - 1))
fi
shift "$count"
transition "$1"
return
fi
shift
done
sxmo_log "idle: not transitioning from $state"
sxmo_jobs.sh stop idle_locker 2>/dev/null || true
sxmo_jobs.sh stop idle_suspender 2>/dev/null || true
sxmo_log "idle: automatic idle locking is disabled"
}
store() {
+7 -5
View File
@@ -30,12 +30,10 @@ xorgdisplay() {
if [ -w /sys/class/backlight/backlight/brightness ]; then
printf '0' > /sys/class/backlight/backlight/brightness 2>/dev/null || true
fi
xset dpms 0 0 3
xset dpms force off
xset s off s noblank -dpms >/dev/null 2>&1 || true
;;
on)
xset dpms 0 0 0
xset dpms force on
xset s off s noblank -dpms >/dev/null 2>&1 || true
if [ -w /sys/class/backlight/backlight/bl_power ]; then
printf '0' > /sys/class/backlight/backlight/bl_power 2>/dev/null || true
fi
@@ -54,7 +52,11 @@ xorgdisplay() {
fi
;;
"")
if xset q | grep -q "Off: 3"; then
_cur_bl=14
if [ -r /sys/class/backlight/backlight/brightness ]; then
read -r _cur_bl < /sys/class/backlight/backlight/brightness 2>/dev/null || _cur_bl=14
fi
if [ "${_cur_bl:-0}" -le 0 ] 2>/dev/null; then
printf "off\n"
else
printf "on\n"
Binary file not shown.
@@ -77,9 +77,6 @@ case "$WMCLASS" in
$icon_zzz Auto-suspend $(
[ -e "$XDG_CACHE_HOME"/sxmo/sxmo.nosuspend ] && printf "%s" "$icon_tof" || printf "%s" "$icon_ton"
) ^ 1 ^ (rm $XDG_CACHE_HOME/sxmo/sxmo.nosuspend 2>/dev/null || touch $XDG_CACHE_HOME/sxmo/sxmo.nosuspend)
$icon_zzz Auto-screen-off $(
[ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ] && printf "%s" "$icon_tof" || printf "%s" "$icon_ton"
) ^ 1 ^ (rm $XDG_CACHE_HOME/sxmo/sxmo.noidle 2>/dev/null || touch $XDG_CACHE_HOME/sxmo/sxmo.noidle) && sxmo_state.sh set unlock
$icon_trm Hooks ^ 0 ^ sxmo_hookmenu.sh
$icon_cfg Suspend Blockers ^ 0 ^ sxmo_terminal.sh sxmo_debug_suspend.sh
$icon_inf Log ^ 0 ^ sxmo_terminal.sh tail -n 100 -f ${XDG_STATE_HOME:-$HOME}/sxmo.log
@@ -32,12 +32,7 @@ if [ -z "$SXMO_DISABLE_LEDS" ]; then
fi
sxmo_jobs.sh stop periodic_wakelock_check
# Go down after 8 seconds of inactivity
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
sxmo_jobs.sh stop idle_locker
else
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_LOCK_IDLE_TIME:-8}" "sxmo_state.sh idle"
fi
# Automatic idle transitions are disabled; only explicit locking is used
sxmo_jobs.sh stop idle_locker 2>/dev/null || true
wait
@@ -3,18 +3,5 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout 10 'sxmo_wm.sh display off' \
resume 'sxmo_wm.sh display on'
case "$SXMO_WM" in
sway|river)
swaylockd
;;
dwm)
i3lock
;;
esac
# need & cause we are still holding flock
sxmo_jobs.sh stop idle_locker 2>/dev/null || true
sxmo_state.sh set unlock &
@@ -24,9 +24,6 @@ while ! superctl status > /dev/null 2>&1; do
sleep 0.05
done
# Not dangerous if "locker" isn't an available state
sxmo_state.sh set locker
if [ -n "$SXMO_ROTATE_START" ]; then
sxmo_rotate.sh
fi
@@ -26,35 +26,7 @@ if [ -z "$SXMO_DISABLE_LEDS" ]; then
fi
sxmo_jobs.sh stop periodic_wakelock_check
# Go to the next idle state after 120 seconds of inactivity
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
sxmo_jobs.sh stop idle_locker
else
case "$SXMO_WM" in
river)
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" 'sh -c "
exec sxmo_state.sh idle
"'
;;
sway)
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" 'sh -c "
swaymsg mode default;
exec sxmo_state.sh idle
"'
;;
i3)
# Idle fails to trigger if formatted like sway
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" \
'sh -c "i3-msg mode default; exec sxmo_state.sh idle"'
;;
dwm)
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" "sxmo_state.sh idle"
;;
esac
fi
# Automatic idle locking is disabled; only explicit locking is used
sxmo_jobs.sh stop idle_locker 2>/dev/null || true
wait
Binary file not shown.
Binary file not shown.
-21
View File
@@ -839,23 +839,6 @@ handle_builtin_toggle(const char *toggle_name)
if (fd >= 0)
close(fd);
}
} else if (strcmp(toggle_name, "autoscreenoff") == 0) {
const char *home = getenv("HOME");
if (!home || !home[0])
home = "/home/user";
char path[256];
snprintf(path, sizeof(path), "%s/.cache/sxmo/sxmo.noidle", home);
if (access(path, F_OK) == 0) {
unlink(path);
} else {
char dir[256];
snprintf(dir, sizeof(dir), "%s/.cache/sxmo", home);
mkdir(dir, 0755);
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd >= 0)
close(fd);
}
spawn_detached_sh("sxmo_state.sh set unlock");
} else if (strcmp(toggle_name, "bluetooth") == 0) {
int rc = system("doas sxmo_bluetoothtoggle.sh >/dev/null 2>&1");
(void)rc;
@@ -1829,10 +1812,6 @@ open_builtin_menu(const char *menu_name, int keep_idx)
snprintf(label, sizeof(label), "%s Auto-suspend %s", ICON_ZZZ, (access(pbuf, F_OK) == 0) ? ICON_TOF : ICON_TON);
add_menu_item(label, "@toggle:autosuspend", 1);
snprintf(pbuf, sizeof(pbuf), "%s/.cache/sxmo/sxmo.noidle", home);
snprintf(label, sizeof(label), "%s Auto-screen-off %s", ICON_ZZZ, (access(pbuf, F_OK) == 0) ? ICON_TOF : ICON_TON);
add_menu_item(label, "@toggle:autoscreenoff", 1);
snprintf(label, sizeof(label), "%s Hooks", ICON_TRM);
add_menu_item(label, "sxmo_hookmenu.sh", 0);
snprintf(label, sizeof(label), "%s Suspend Blockers", ICON_CFG);
+4 -3
View File
@@ -1909,7 +1909,7 @@ keypress(XEvent *e)
keysym == XK_Return ||
keysym == XF86XK_KbdLcdMenu1 || keysym == XF86XK_KbdLcdMenu2) &&
is_phone_locked()) {
const Arg unlockcmd = SHCMD("xset dpms 0 0 0; xset dpms force on; sxmo_state.sh set unlock");
const Arg unlockcmd = SHCMD("xset s off s noblank -dpms; sxmo_state.sh set unlock");
softkey_pending = 0;
softkey_first_ms = 0;
softkey_deadline_ms = 0;
@@ -2487,11 +2487,11 @@ run(void)
while (read(lidfd, &ie, sizeof(ie)) == (ssize_t)sizeof(ie)) {
if (ie.type == EV_SW && ie.code == SW_LID) {
if (ie.value == 1) {
const Arg offcmd = SHCMD("sxmo_dmenu.sh close; xset dpms 0 0 3; xset dpms force off; sxmo_state.sh set screenoff");
const Arg offcmd = SHCMD("sxmo_dmenu.sh close; sxmo_state.sh set screenoff");
set_hw_backlight(0);
spawn(&offcmd);
} else if (ie.value == 0) {
const Arg oncmd = SHCMD("xset dpms 0 0 0; xset dpms force on; sxmo_state.sh set unlock");
const Arg oncmd = SHCMD("xset s off s noblank -dpms; sxmo_state.sh set unlock");
set_hw_backlight(1);
spawn(&oncmd);
}
@@ -2659,6 +2659,7 @@ setup(void)
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
root = RootWindow(dpy, screen);
XSetScreenSaver(dpy, 0, 0, DontPreferBlanking, AllowExposures);
drw = drw_create(dpy, screen, root, sw, sh);
snprintf(active_font, sizeof(active_font), "%s", font);