feat(x11): migrate to pure Xlibre + dwm/dmenu/st stack, fix fcitx5-t9 bottom bar, PM8909 PON shutdown, and remove Wayland

This commit is contained in:
Luxferre
2026-10-20 21:15:16 +03:00
parent ad012360c3
commit 7bab7b7a11
422 changed files with 63226 additions and 2342 deletions
+1
View File
@@ -0,0 +1 @@
Xorg
BIN
View File
Binary file not shown.
+12 -4
View File
@@ -75,7 +75,7 @@ get_pictures_dir() {
}
notify_msg() {
if command -v sxmo_notify_user.sh >/dev/null 2>&1 && [ -n "${WAYLAND_DISPLAY:-}" ]; then
if command -v sxmo_notify_user.sh >/dev/null 2>&1 && [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
sxmo_notify_user.sh -t 2000 "$1" >/dev/null 2>&1 || true
fi
}
@@ -135,8 +135,12 @@ take_photo() {
printf "%s\n" "$target_path"
notify_msg "Saved $(basename "$target_path")"
if [ "$VIEW_AFTER" -eq 1 ] && [ -n "${WAYLAND_DISPLAY:-}" ] && command -v imv >/dev/null 2>&1; then
imv "$target_path" >/dev/null 2>&1 &
if [ "$VIEW_AFTER" -eq 1 ] && [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
if command -v feh >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
feh --scale-down "$target_path" >/dev/null 2>&1 &
elif command -v imv >/dev/null 2>&1; then
imv "$target_path" >/dev/null 2>&1 &
fi
fi
return 0
}
@@ -169,7 +173,11 @@ run_menu() {
*"View photos"*)
pic_dir="$(get_pictures_dir)"
if ls "$pic_dir"/*.jpg "$pic_dir"/*.png >/dev/null 2>&1; then
imv "$pic_dir" >/dev/null 2>&1 &
if command -v feh >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
feh --scale-down "$pic_dir" >/dev/null 2>&1 &
else
imv "$pic_dir" >/dev/null 2>&1 &
fi
else
notify_msg "No photos in $pic_dir"
fi
BIN
View File
Binary file not shown.
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}"
cache="$cachedir/dmenu_run"
[ ! -e "$cachedir" ] && mkdir -p "$cachedir"
IFS=:
if stest -dqr -n "$cache" $PATH; then
stest -flx $PATH | sort -u | tee "$cache"
else
cat "$cache"
fi
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+322
View File
@@ -0,0 +1,322 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
unalias dmenu 2>/dev/null || true
unalias bemenu 2>/dev/null || true
confirm() {
PICKED="$(printf "Yes\nNo\n" | run_dmenu -p "Confirm $1")"
if [ "$PICKED" = "Yes" ]; then
return 0
else
return 1
fi
}
run_dmenu() {
if [ "${SXMO_WM:-dwm}" = "dwm" ] && command -v dmenu >/dev/null 2>&1; then
dmenu -c -l "${SXMO_DMENU_PORTRAIT_LINES:-9}" "$@"
else
sxmo_dmenu.sh "$@"
fi
}
supertoggle_daemon() {
if superctl status "$1" | grep -q started; then
superctl stop "$1"
sxmo_notify_user.sh "$1 Stopped"
else
superctl start "$1"
sxmo_notify_user.sh "$1 Started"
fi
}
toggle_daemon() {
name="$1"
shift
if sxmo_jobs.sh running "$1" -q; then
sxmo_jobs.sh stop "$@"
notify-send "$name Stopped"
else
sxmo_jobs.sh start "$@" &
notify-send "$name Started"
fi
}
sxmo_type() {
sxmo_type.sh -s 200 "$@"
}
get_focused_window() {
if [ -r "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo.focusedwin" ]; then
{
read -r WMCLASS || WMCLASS=""
read -r WMNAME || WMNAME=""
} < "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo.focusedwin"
return
fi
exec 0<<EOF
$(sxmo_wm.sh focusedwindow -r)
EOF
read -r WMCLASS
read -r WMNAME
}
has_tracked_calls() {
[ -d "$XDG_RUNTIME_DIR/sxmo_calls" ] || return 1
for f in "$XDG_RUNTIME_DIR/sxmo_calls"/*; do
[ -e "$f" ] && return 0
done
return 1
}
call_entries() {
has_tracked_calls || return 0
shown_incall_menu=
sxmo_modemcall.sh list_active_calls | while read -r line; do
case "$line" in
*"(ringing-in)")
CALLID="${line%% *}"
CALLID="${CALLID##*/}"
NUMBER="$(sxmo_modemcall.sh vid_to_number "$CALLID")"
CONTACT="$(sxmo_contacts.sh --name "$NUMBER")"
printf "%s Incoming call %s ^ 0 ^ sxmo_jobs.sh start incall_menu sxmo_modemcall.sh incoming_call_menu %s\n" \
"$icon_phn" "$CONTACT" "$CALLID"
;;
*)
[ -n "$shown_incall_menu" ] && continue
shown_incall_menu=1
printf "%s Incall Menu ^ 0 ^ sxmo_jobs.sh start incall_menu sxmo_modemcall.sh incall_menu\n" \
"$icon_phn"
;;
esac
done
}
count_notifications() {
n=0
if [ -d "$SXMO_NOTIFDIR" ]; then
for f in "$SXMO_NOTIFDIR"/*; do
[ -f "$f" ] && n=$((n + 1))
done
fi
printf "%s" "$n"
}
bt_is_unblocked_fast() {
for rfk in /sys/class/rfkill/rfkill*; do
[ -r "$rfk/type" ] || continue
read -r rtype < "$rfk/type" 2>/dev/null || continue
if [ "$rtype" = "bluetooth" ]; then
read -r soft < "$rfk/soft" 2>/dev/null || soft=0
read -r hard < "$rfk/hard" 2>/dev/null || hard=0
[ "$soft" = "0" ] && [ "$hard" = "0" ] && return 0
return 1
fi
done
return 1
}
fast_sys_choices() {
WINNAME="Sys"
_bt_line=""
if bt_is_unblocked_fast; then
_bt_line="$icon_bth Bluetooth^1^sxmo_bluetoothmenu.sh
"
fi
_flash_line=""
_bl=""
if [ -r /sys/class/leds/white:torch/brightness ]; then
read -r _bl < /sys/class/leds/white:torch/brightness 2>/dev/null || _bl=""
elif [ -r /sys/class/leds/white:flash/brightness ]; then
read -r _bl < /sys/class/leds/white:flash/brightness 2>/dev/null || _bl=""
fi
if [ -n "$_bl" ]; then
if [ "$_bl" -gt 0 ] 2>/dev/null; then
_flash_line="$icon_fll Flashlight $icon_ton^1^sxmo_flashtoggle.sh
"
else
_flash_line="$icon_fll Flashlight $icon_tof^1^sxmo_flashtoggle.sh
"
fi
fi
CHOICES="$icon_trm St^0^st -e ${SHELL:-/bin/sh}
$icon_grd Apps^0^sxmo_appmenu.sh applications
$icon_grd Scripts^0^sxmo_appmenu.sh scripts
$icon_dir Files^0^sxmo_files.sh
$icon_phn Dialer^0^sxmo_modemdial.sh
$icon_msg Texts^0^sxmo_modemtext.sh
$icon_usr Contacts^0^sxmo_contactmenu.sh
${_bt_line}$icon_cam Camera^0^bananarchy-photo --menu
${_flash_line}$icon_net Networks^0^sxmo_networks.sh
$icon_mus Audio^0^sxmo_audio.sh
$icon_phn Modem^0^sxmo_appmenu.sh modem
$icon_win Windows^0^sxmo_wmmenu.sh
$icon_cfg Config^0^sxmo_appmenu.sh config
$icon_pwr Power^0^sxmo_appmenu.sh power"
}
getprogchoices() {
case "$WMCLASS" in
""|sys)
fast_sys_choices
;;
applications)
WINNAME="Apps"
if [ -s "${XDG_RUNTIME_DIR:-/tmp}/sxmo_apps.cache" ]; then
CHOICES="$(cat "${XDG_RUNTIME_DIR:-/tmp}/sxmo_apps.cache")"
else
CHOICES="$(sxmo_hook_apps.sh)"
fi
;;
scripts)
WINNAME="Scripts"
if [ -s "${XDG_RUNTIME_DIR:-/tmp}/sxmo_scripts.cache" ]; then
CHOICES="$(cat "${XDG_RUNTIME_DIR:-/tmp}/sxmo_scripts.cache")"
else
CHOICES="$(sxmo_hook_scripts.sh)"
fi
;;
power)
WINNAME="Power"
CHOICES="$icon_lck Lock^0^sxmo_state.sh set lock
$icon_lck Lock (Screen off)^0^sxmo_state.sh set screenoff
$icon_out Logout^0^confirm Logout && sxmo_power.sh logout
$icon_rld Reboot^0^confirm Reboot && sxmo_power.sh reboot
$icon_pwr Poweroff^0^confirm Poweroff && sxmo_power.sh poweroff"
;;
modem)
WINNAME="Modem"
CHOICES="$icon_plk Modem PIN^0^sxmo_unlocksim.sh
$icon_inf Modem Info^0^sxmo_modeminfo.sh
$icon_phl Modem Log^0^sxmo_modemlog.sh"
;;
config)
WINNAME="Config"
_bt_icon="$icon_tof"
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_aru Brightness^1^sxmo_brightness.sh up
$icon_ard Brightness^1^sxmo_brightness.sh down
$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
$icon_inf Version^0^sxmo_terminal.sh sxmo_version.sh --block"
;;
*)
RES="$(sxmo_hook_contextmenu.sh "$WMCLASS" "$WMNAME")"
if [ -n "$RES" ]; then
nl='
'
WINNAME="${RES%%"$nl"*}"
CHOICES="${RES#*"$nl"}"
fi
;;
esac
if [ "$WINNAME" = "Sys" ]; then
NNOTIFICATIONS="$(count_notifications)"
if [ "$NNOTIFICATIONS" -gt 0 ]; then
CHOICES="$icon_bel Notifications ($NNOTIFICATIONS)^0^sxmo_notifs.sh menu
$CHOICES"
fi
fi
if has_tracked_calls; then
CHOICES="$(call_entries)
$CHOICES"
fi
case "$WINNAME" in
*Sys*) ;;
*)
CHOICES="$CHOICES
$icon_mnu System Menu^0^sxmo_appmenu.sh sys"
;;
esac
CHOICES="$CHOICES
$icon_cls Close Menu^0^quit"
case "$WMCLASS" in
""|sys|applications|scripts|power|modem|config)
;;
*)
CHOICES="$(printf "%s\n" "$CHOICES" | awk 'NF {$1=$1; print}')"
;;
esac
}
quit() {
exit 0
}
mainloop() {
getprogchoices
PICKED="$(
printf "%s\n" "$CHOICES" |
cut -d'^' -f1 |
run_dmenu -i -p "$WINNAME"
)" || quit
CHOICE="$(printf "%s\n" "$CHOICES" | awk -F '^' -v picked="$PICKED" \
'$1 == picked || $1 == picked " " {print $2 "^" $3; exit}'
)"
LOOP="${CHOICE%%^*}"
CMD="${CHOICE#*^}"
CMD="${CMD#"${CMD%%[![:space:]]*}"}"
if [ -z "$CHOICE" ] || [ -z "$CMD" ]; then
printf "%s\n" "sxmo_appmenu: Fallback: unknown choice <$PICKED> to contextmenu_fallback hook">&2
sxmo_hook_contextmenu_fallback.sh "$WINNAME" "$PICKED"
quit
fi
case "$CMD" in
"sxmo_appmenu.sh "*)
set -- ${CMD#sxmo_appmenu.sh }
WMCLASS="$1"
WMNAME="$2"
return 0
;;
esac
eval "$CMD"
case "$LOOP" in
*1*) ;;
*) quit ;;
esac
}
if [ -z "$SHELLSPEC_PATH" ]; then
if [ $# -gt 0 ] ; then
WMCLASS="$1"
WMNAME="$2"
else
get_focused_window
fi
while true; do
mainloop
done
fi
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
upower -m | while read -r line; do
# swallow first line ("Monitoring activity from the power daemon...")
if [ -z "$started" ]; then
started=1
continue
fi
line="${line#* }"
event="${line%%:*}"
object="${line#*:}"
object="${object#"${object%%[![:space:]]*}"}"
if [ -z "$object" ]; then
continue
fi
sxmo_hook_battery.sh "$object" "$event"
done
@@ -1,9 +1,14 @@
#!/bin/sh
export SXMO_WM=sway
export SXMO_WM=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export SXMO_ROTATION=normal
# Native 1:1 240x320 QVGA resolution
export SXMO_SWAY_SCALE=1
export GSK_RENDERER=cairo
export NO_AT_BRIDGE=1
export GTK_A11Y=none
export GTK_USE_PORTAL=0
# Physical button mappings
export SXMO_POWER_BUTTON="0:0:pm8916_pon"
@@ -13,12 +18,10 @@ export SXMO_MENU_LEFT_BUTTON="0:139:KEY_MENU"
export SXMO_MENU_RIGHT_BUTTON="0:158:KEY_BACK"
export SXMO_ENTER_BUTTON="0:352:KEY_OK"
# Nokia 8110 4G has a physical keypad and no touchscreen
# Physical keypad and no touchscreen or RGB status LED
export SXMO_NO_VIRTUAL_KEYBOARD=1
export SXMO_DISABLE_LEDS=1
export KEYBOARD_ARGS="-H 1 -L 1"
export SXMO_MENU=wofi
export SXMO_WOFI_LANDSCAPE_WIDTH=320
export SXMO_WOFI_LANDSCAPE_HEIGHT=200
export SXMO_BEMENU_PORTRAIT_LINES=10
export SXMO_BEMENU_LANDSCAPE_LINES=6
export BEMENU_OPTS="--fn 'Sxmo 13' -H 24"
export DMENU_WRAP_AROUND=1
export SXMO_DMENU_PORTRAIT_LINES=12
export SXMO_DMENU_LANDSCAPE_LINES=8
@@ -1,9 +1,14 @@
#!/bin/sh
export SXMO_WM=sway
export SXMO_WM=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export SXMO_ROTATION=normal
# Native 1:1 240x320 QVGA resolution
export SXMO_SWAY_SCALE=1
export GSK_RENDERER=cairo
export NO_AT_BRIDGE=1
export GTK_A11Y=none
export GTK_USE_PORTAL=0
# Physical button mappings
export SXMO_POWER_BUTTON="0:0:pm8916_pon"
@@ -13,12 +18,10 @@ export SXMO_MENU_LEFT_BUTTON="0:139:KEY_MENU"
export SXMO_MENU_RIGHT_BUTTON="0:158:KEY_BACK"
export SXMO_ENTER_BUTTON="0:352:KEY_OK"
# Nokia 8110 4G has a physical keypad and no touchscreen
# Physical keypad and no touchscreen or RGB status LED
export SXMO_NO_VIRTUAL_KEYBOARD=1
export SXMO_DISABLE_LEDS=1
export KEYBOARD_ARGS="-H 1 -L 1"
export SXMO_MENU=wofi
export SXMO_WOFI_LANDSCAPE_WIDTH=320
export SXMO_WOFI_LANDSCAPE_HEIGHT=200
export SXMO_BEMENU_PORTRAIT_LINES=10
export SXMO_BEMENU_LANDSCAPE_LINES=6
export BEMENU_OPTS="--fn 'Sxmo 13' -H 24"
export DMENU_WRAP_AROUND=1
export SXMO_DMENU_PORTRAIT_LINES=12
export SXMO_DMENU_LANDSCAPE_LINES=8
@@ -1,9 +1,14 @@
#!/bin/sh
export SXMO_WM=sway
export SXMO_WM=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export SXMO_ROTATION=normal
# Native 1:1 240x320 QVGA resolution
export SXMO_SWAY_SCALE=1
export GSK_RENDERER=cairo
export NO_AT_BRIDGE=1
export GTK_A11Y=none
export GTK_USE_PORTAL=0
# Physical button mappings
export SXMO_POWER_BUTTON="0:0:pm8916_pon"
@@ -13,12 +18,10 @@ export SXMO_MENU_LEFT_BUTTON="0:139:KEY_MENU"
export SXMO_MENU_RIGHT_BUTTON="0:158:KEY_BACK"
export SXMO_ENTER_BUTTON="0:352:KEY_OK"
# Nokia 8110 4G has a physical keypad and no touchscreen
# Physical keypad and no touchscreen or RGB status LED
export SXMO_NO_VIRTUAL_KEYBOARD=1
export SXMO_DISABLE_LEDS=1
export KEYBOARD_ARGS="-H 1 -L 1"
export SXMO_MENU=wofi
export SXMO_WOFI_LANDSCAPE_WIDTH=320
export SXMO_WOFI_LANDSCAPE_HEIGHT=200
export SXMO_BEMENU_PORTRAIT_LINES=10
export SXMO_BEMENU_LANDSCAPE_LINES=6
export BEMENU_OPTS="--fn 'Sxmo 13' -H 24"
export DMENU_WRAP_AROUND=1
export SXMO_DMENU_PORTRAIT_LINES=12
export SXMO_DMENU_LANDSCAPE_LINES=8
@@ -1,9 +1,14 @@
#!/bin/sh
export SXMO_WM=sway
export SXMO_WM=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export SXMO_ROTATION=normal
# Native 1:1 240x320 QVGA resolution
export SXMO_SWAY_SCALE=1
export GSK_RENDERER=cairo
export NO_AT_BRIDGE=1
export GTK_A11Y=none
export GTK_USE_PORTAL=0
# Physical button mappings
export SXMO_POWER_BUTTON="0:0:pm8916_pon"
@@ -13,12 +18,10 @@ export SXMO_MENU_LEFT_BUTTON="0:139:KEY_MENU"
export SXMO_MENU_RIGHT_BUTTON="0:158:KEY_BACK"
export SXMO_ENTER_BUTTON="0:352:KEY_OK"
# Nokia 8110 4G has a physical keypad and no touchscreen
# Physical keypad and no touchscreen or RGB status LED
export SXMO_NO_VIRTUAL_KEYBOARD=1
export SXMO_DISABLE_LEDS=1
export KEYBOARD_ARGS="-H 1 -L 1"
export SXMO_MENU=wofi
export SXMO_WOFI_LANDSCAPE_WIDTH=320
export SXMO_WOFI_LANDSCAPE_HEIGHT=200
export SXMO_BEMENU_PORTRAIT_LINES=10
export SXMO_BEMENU_LANDSCAPE_LINES=6
export BEMENU_OPTS="--fn 'Sxmo 13' -H 24"
export DMENU_WRAP_AROUND=1
export SXMO_DMENU_PORTRAIT_LINES=12
export SXMO_DMENU_LANDSCAPE_LINES=8
@@ -1,9 +1,14 @@
#!/bin/sh
export SXMO_WM=sway
export SXMO_WM=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export SXMO_ROTATION=normal
# Native 1:1 240x320 QVGA resolution
export SXMO_SWAY_SCALE=1
export GSK_RENDERER=cairo
export NO_AT_BRIDGE=1
export GTK_A11Y=none
export GTK_USE_PORTAL=0
# Physical button mappings
export SXMO_POWER_BUTTON="0:0:pm8916_pon"
@@ -13,12 +18,10 @@ export SXMO_MENU_LEFT_BUTTON="0:139:KEY_MENU"
export SXMO_MENU_RIGHT_BUTTON="0:158:KEY_BACK"
export SXMO_ENTER_BUTTON="0:352:KEY_OK"
# Nokia 8110 4G has a physical keypad and no touchscreen
# Physical keypad and no touchscreen or RGB status LED
export SXMO_NO_VIRTUAL_KEYBOARD=1
export SXMO_DISABLE_LEDS=1
export KEYBOARD_ARGS="-H 1 -L 1"
export SXMO_MENU=wofi
export SXMO_WOFI_LANDSCAPE_WIDTH=320
export SXMO_WOFI_LANDSCAPE_HEIGHT=200
export SXMO_BEMENU_PORTRAIT_LINES=10
export SXMO_BEMENU_LANDSCAPE_LINES=6
export BEMENU_OPTS="--fn 'Sxmo 13' -H 24"
export DMENU_WRAP_AROUND=1
export SXMO_DMENU_PORTRAIT_LINES=12
export SXMO_DMENU_LANDSCAPE_LINES=8
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
. sxmo_common.sh
unalias dmenu 2>/dev/null || true
case "$1" in
"--show-over-lockscreen")
SHOW_OVER_LOCKSCREEN_FLAG=1
shift
;;
"isopen")
exec pidof -s dmenu >/dev/null
;;
"close")
pkill dmenu 2>/dev/null || true
exit 0
;;
esac
if [ -n "$SHOW_OVER_LOCKSCREEN_FLAG" ]; then
if pidof -s smlock >/dev/null; then
set -- "$@" -w smlock
fi
fi
lines="${SXMO_DMENU_PORTRAIT_LINES:-9}"
# shellcheck disable=SC2086
exec dmenu -i $SXMO_DMENU_OPTS -l "$lines" "$@"
+48
View File
@@ -0,0 +1,48 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
envvars() {
unset WAYLAND_DISPLAY
export SXMO_WM=dwm
export XDG_CURRENT_DESKTOP=dwm
export SXMO_MENU=dmenu
export SXMO_TERMINAL=st
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
command -v "$KEYBOARD" >/dev/null 2>&1 || defaultkeyboard
[ -z "$MOZ_USE_XINPUT2" ] && export MOZ_USE_XINPUT2=1
}
defaults() {
xsetroot -solid '#1c1c1c'
xset s off -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 &
fi
}
defaultkeyboard() {
if command -v svkbd-mobile-intl >/dev/null 2>&1; then
export KEYBOARD=svkbd-mobile-intl
elif command -v svkbd-mobile-plain >/dev/null 2>&1; then
export KEYBOARD=svkbd-mobile-plain
else
export KEYBOARD=svkbd-sxmo
fi
}
with_dbus() {
echo "$DBUS_SESSION_BUS_ADDRESS" > "$XDG_RUNTIME_DIR"/dbus.bus
# shellcheck source=configs/appcfg/xinit_template
. "$XDG_CONFIG_HOME"/sxmo/xinit
exec dwm
}
# shellcheck source=scripts/core/sxmo_init.sh
. sxmo_init.sh
+78
View File
@@ -0,0 +1,78 @@
#!/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
+61
View File
@@ -0,0 +1,61 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# This script have to be sourced from other session init scripts.
# The scripts have to implement envvars, defaults, with_dbus, and cleanup
# methods. See sxmo_swayinit.sh as example.
start() {
[ -f "$XDG_STATE_HOME"/sxmo.log ] && mv "$XDG_STATE_HOME"/sxmo.log "$XDG_STATE_HOME"/sxmo.log.old
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
dbus-run-session -- "$0" "with_dbus" &
else
# with_dbus calls exec because dbus-run-session starts it in a
# new shell, but we need to keep this shell; start a subshell
( with_dbus ) &
fi
wait
}
cleanup() {
sxmo_dmenu.sh close 2>/dev/null || true
sxmo_keyboard.sh close 2>/dev/null || true
sxmo_jobs.sh stop all 2>/dev/null || true
}
finish() {
cleanup
sleep 1
sxmo_hook_stop.sh 2>/dev/null || true
exit
}
shared_envvars() {
export SXMO_DISABLE_LEDS="1"
}
init() {
# shellcheck source=/dev/null
. /etc/profile.d/sxmo_init.sh
_sxmo_load_environments
_sxmo_prepare_dirs
envvars
shared_envvars
defaults
# shellcheck disable=SC1090,SC1091
. "$XDG_CONFIG_HOME/sxmo/profile"
trap 'finish' INT TERM EXIT
start
}
if [ -z "$1" ]; then
init
else
"$1"
fi
+147
View File
@@ -0,0 +1,147 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
ROOT="$XDG_RUNTIME_DIR/sxmo_jobs"
mkdir -p "$ROOT"
exec 3<> "$XDG_RUNTIME_DIR/sxmo.jobs.lock"
flock -x 3
list() {
for f in "$ROOT"/*; do
[ -e "$f" ] || continue
case "$f" in
*.group) continue ;;
esac
printf "%s\n" "${f##*/}"
done
}
stop() {
while [ "$#" -gt 0 ]; do
case "$1" in
-f)
force=1
shift
;;
*)
id="$1"
shift
break
;;
esac
done
case "$id" in
all)
list | while read -r sub_id; do
stop "$sub_id"
done
;;
*)
if [ -f "$ROOT/$id.group" ]; then
sxmo_debug "stop group $id"
read -r pid < "$ROOT/$id.group" 2>/dev/null || pid=""
[ -n "$pid" ] && kill ${force:+-9} -- "-$pid" 2> /dev/null || true
elif [ -f "$ROOT/$id" ]; then
sxmo_debug "stop $id"
read -r pid < "$ROOT/$id" 2>/dev/null || pid=""
[ -n "$pid" ] && kill ${force:+-9} "$pid" 2> /dev/null || true
fi
rm -f "$ROOT/$id" "$ROOT/$id.group" 2>/dev/null || true
;;
esac
}
signal() {
id="$1"
shift
if [ -f "$ROOT/$id" ]; then
sxmo_debug "signal $id $*"
read -r pid < "$ROOT/$id" 2>/dev/null || pid=""
[ -n "$pid" ] && kill "$@" "$pid" 2> /dev/null || true
fi
}
start() {
while [ "$#" -gt 0 ]; do
case "$1" in
--no-restart)
no_restart=1
shift
;;
--group)
has_group=1
shift
;;
*)
id="$1"
shift
break
;;
esac
done
if [ -f "$ROOT/$id" ]; then
if [ -n "$no_restart" ]; then
sxmo_debug "$id already running"
exit 1
else
stop "$id"
fi
fi
sxmo_debug "start $id"
# Start job in a new session, close the lock fd, and record PID synchronously
# before releasing the jobs lock so subsequent stop calls never race.
setsid "$@" 3<&- &
job_pid=$!
printf "%s\n" "$job_pid" > "$ROOT/$id"
if [ -n "$has_group" ]; then
printf "%s\n" "$job_pid" > "$ROOT/$id.group"
fi
}
running() {
while [ "$#" -gt 0 ]; do
case "$1" in
-q)
quiet=1
shift
;;
*)
id="$1"
shift
;;
esac
done
log() {
if [ -z "$quiet" ]; then
# shellcheck disable=SC2059
printf "$@"
fi
}
if [ -f "$ROOT/$id" ]; then
read -r pid < "$ROOT/$id" 2>/dev/null || pid=""
if [ -n "$pid" ] && [ -d "/proc/$pid" ]; then
log "%s is still running\n" "$id"
else
log "%s is not running anymore\n" "$id"
exit 2
fi
else
log "%s is not running\n" "$id"
exit 1
fi
}
"$@"
+286
View File
@@ -0,0 +1,286 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
if [ -z "$XDG_RUNTIME_DIR" ]; then
echo "XDG_RUNTIME_DIR must be set" >&2
exit 1
fi
# We use this directory to store states, so it must exist
mkdir -p "$XDG_RUNTIME_DIR/sxmo_calls"
stderr() {
sxmo_log "$*"
}
cleanupnumber() {
if pnc valid "$1"; then
echo "$1"
return
fi
REFORMATTED="$(pnc find ${DEFAULT_COUNTRY:+-c "$DEFAULT_COUNTRY"} "$1")"
if [ -n "$REFORMATTED" ]; then
echo "$REFORMATTED"
return
fi
echo "$1"
}
checkforfinishedcalls() {
exec 3<> "$XDG_RUNTIME_DIR/sxmo_modem.checkforfinishedcalls.lock"
flock -x 3
#find all finished calls
for FINISHEDCALLID in $(
mmcli -m any --voice-list-calls |
grep terminated |
grep -oE "Call\/[0-9]+" |
cut -d'/' -f2
); do
FINISHEDNUMBER="$(sxmo_modemcall.sh vid_to_number "$FINISHEDCALLID")"
FINISHEDNUMBER="$(cleanupnumber "$FINISHEDNUMBER")"
mmcli -m any --voice-delete-call "$FINISHEDCALLID"
rm -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.monitoredcall"
CONTACT="$(sxmo_contacts.sh --name-or-number "$FINISHEDNUMBER")"
TIME="$(date +%FT%H:%M:%S%z)"
mkdir -p "$SXMO_LOGDIR"
if [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.discardedcall" ]; then
#this call was discarded
STATE=discarded
sxmo_notify_user.sh "Call with $CONTACT terminated"
stderr "Discarded call from $FINISHEDNUMBER"
printf %b "$TIME\tcall_finished\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
elif [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.pickedupcall" ]; then
#this call was picked up
STATE=pickedup
sxmo_notify_user.sh "Call with $CONTACT terminated"
stderr "Finished call from $FINISHEDNUMBER"
printf %b "$TIME\tcall_finished\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
elif [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.hangedupcall" ]; then
#this call was hung up by the user
STATE=wehangedup
sxmo_notify_user.sh "Call with $CONTACT terminated"
stderr "Finished call from $FINISHEDNUMBER"
printf %b "$TIME\tcall_finished\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
elif [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.initiatedcall" ]; then
STATE=theyhangedup
#this call was hung up by the contact
sxmo_notify_user.sh "Call with $CONTACT terminated"
stderr "Finished call from $FINISHEDNUMBER"
printf %b "$TIME\tcall_finished\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
elif [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}.mutedring" ]; then
STATE=muted
#this ring was muted up
stderr "Muted ring from $FINISHEDNUMBER"
printf %b "$TIME\tring_muted\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
else
#this is a missed call
# Add a notification for every missed call
STATE=missed
NOTIFMSG="Missed call from $CONTACT ($FINISHEDNUMBER)"
stderr "$NOTIFMSG"
printf %b "$TIME\tcall_missed\t$FINISHEDNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
stderr "Invoking missed call hook (async)"
sxmo_hook_missed_call.sh "$CONTACT" &
sxmo_notifs.sh new \
-g "incoming-call-$FINISHEDNUMBER" \
"TERMNAME='$NOTIFMSG' sxmo_terminal.sh sh -c \"echo '$NOTIFMSG at $(date)' && read\"" \
"Missed $icon_phn $CONTACT ($FINISHEDNUMBER)"
fi
rm -f "$XDG_RUNTIME_DIR/sxmo_calls/${FINISHEDCALLID}."* 2>/dev/null || true
# If it was the last call
if ! sxmo_modemcall.sh list_active_calls | grep -q .; then
# Cleanup
rm -f "$XDG_RUNTIME_DIR/sxmo_calls/"* 2>/dev/null || true
if [ "$STATE" != muted ]; then
sxmo_vibrate 1000 "${SXMO_VIBRATE_STRENGTH:-1}" &
fi
sxmo_jobs.sh stop incall_menu
sxmo_jobs.sh stop proximity_lock
sxmo_hook_statusbar.sh state &
if ! sxmo_modemaudio.sh reset_audio; then
sxmo_notify_user.sh --urgency=critical "We failed to reset call audio"
fi
sxmo_hook_after_call.sh
else
# Or refresh the menu
sxmo_jobs.sh start incall_menu sxmo_modemcall.sh incall_menu
fi
done
}
checkforincomingcalls() {
VOICECALLID="$(
mmcli -m any --voice-list-calls -a |
grep -Eo '[0-9]+ incoming \(ringing-in\)' |
grep -Eo '[0-9]+'
)"
[ -z "$VOICECALLID" ] && return
[ -f "$XDG_RUNTIME_DIR/sxmo_calls/${VOICECALLID}.monitoredcall" ] && return # prevent multiple rings
rm "$XDG_RUNTIME_DIR/sxmo_calls/$VOICECALLID."* 2>/dev/null # we cleanup all dangling event files
touch "$XDG_RUNTIME_DIR/sxmo_calls/${VOICECALLID}.monitoredcall" #this signals that we handled the call
# Determine the incoming phone number
stderr "Incoming Call..."
INCOMINGNUMBER=$(sxmo_modemcall.sh vid_to_number "$VOICECALLID")
INCOMINGNUMBER="$(cleanupnumber "$INCOMINGNUMBER")"
TIME="$(date +%FT%H:%M:%S%z)"
if sxmo_hook_block_call.sh "$INCOMINGNUMBER" 2>/dev/null; then
stderr "BLOCKED call from number: $VOICECALLID"
sxmo_modemcall.sh mute "$VOICECALLID"
printf %b "$TIME\tcall_ring\t$INCOMINGNUMBER\n" >> "$SXMO_BLOCKDIR/modemlog.tsv"
else
stderr "Invoking ring hook (async)"
CONTACTNAME=$(sxmo_contacts.sh --name-or-number "$INCOMINGNUMBER")
sxmo_jobs.sh start ringing sxmo_hook_ring.sh "$CONTACTNAME"
mkdir -p "$SXMO_LOGDIR"
printf %b "$TIME\tcall_ring\t$INCOMINGNUMBER\n" >> "$SXMO_LOGDIR/modemlog.tsv"
sxmo_jobs.sh start proximity_lock sxmo_proximitylock.sh
sxmo_hook_statusbar.sh state &
# If we already got an active call
if sxmo_modemcall.sh list_active_calls \
| grep -v ringing-in \
| grep -q .; then
# Refresh the incall menu
sxmo_jobs.sh start incall_menu sxmo_modemcall.sh incall_menu
else
# Or fire the incomming call menu
sxmo_jobs.sh start incall_menu sxmo_modemcall.sh incoming_call_menu "$VOICECALLID"
fi
stderr "Call from number: $INCOMINGNUMBER (VOICECALLID: $VOICECALLID)"
fi
}
# this function is called in the modem hook when the modem registers
checkforstucksms() {
stuck_messages="$(mmcli -m any --messaging-list-sms)"
if ! echo "$stuck_messages" | grep -q "^No sms messages were found"; then
sxmo_notify_user.sh "WARNING: $(echo "$stuck_messages" | wc -l) stuck sms found. Run sxmo_modem.sh checkforstucksms view to view or delete to delete."
case "$1" in
"delete")
mmcli -m any --messaging-list-sms | while read -r line; do
sms_number="$(echo "$line" | cut -d'/' -f6 | cut -d' ' -f1)"
sxmo_log "Deleting sms $sms_number"
mmcli -m any --messaging-delete-sms="$sms_number"
done
;;
"view")
mmcli -m any --messaging-list-sms | while read -r line; do
sms_number="$(echo "$line" | cut -d'/' -f6 | cut -d' ' -f1)"
mmcli -m any -s "$sms_number" -K
done
;;
esac
fi
}
checkfornewtexts() {
exec 3<> "$XDG_RUNTIME_DIR/sxmo_modem.checkfornewtexts.lock"
flock -x 3
TEXTIDS="$(
mmcli -m any --messaging-list-sms |
grep -Eo '/SMS/[0-9]+ \(received\)' |
grep -Eo '[0-9]+'
)"
echo "$TEXTIDS" | grep -v . && return
# Loop each textid received and read out the data into appropriate logfile
for TEXTID in $TEXTIDS; do
TEXTDATA="$(mmcli -m any -s "$TEXTID" -J)"
# SMS with no TEXTID is an SMS WAP (I think). So skip.
if [ -z "$TEXTDATA" ]; then
stderr "Received an empty SMS (TEXTID: $TEXTID). I will assume this is an MMS."
printf %b "$(date +%FT%H:%M:%S%z)\tdebug_mms\tNULL\tEMPTY (TEXTID: $TEXTID)\n" >> "$SXMO_LOGDIR/modemlog.tsv"
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
continue
else
stderr "WARNING: mmsdtng not found or unconfigured, treating as normal sms."
fi
fi
TEXT="$(printf %s "$TEXTDATA" | jq -r .sms.content.text)"
NUM="$(printf %s "$TEXTDATA" | jq -r .sms.content.number)"
NUM="$(cleanupnumber "$NUM")"
TIME="$(printf %s "$TEXTDATA" | jq -r .sms.properties.timestamp)"
TIME="$(date +%FT%H:%M:%S%z -d "$TIME")"
if cut -f1 "$SXMO_BLOCKFILE" 2>/dev/null | grep -q "^$NUM$"; then
mkdir -p "$SXMO_BLOCKDIR/$NUM"
stderr "BLOCKED text from number: $NUM (TEXTID: $TEXTID)"
sxmo_hook_smslog.sh "recv" "$NUM" "$NUM" "$TIME" "$TEXT" >> "$SXMO_BLOCKDIR/$NUM/sms.txt"
printf %b "$TIME\trecv_txt\t$NUM\t${#TEXT} chars\n" >> "$SXMO_BLOCKDIR/modemlog.tsv"
mmcli -m any --messaging-delete-sms="$TEXTID"
continue
fi
if [ "$TEXT" = "--" ] && [ ! "$NUM" = "+223344556678" ]; then
stderr "Text from $NUM (TEXTID: $TEXTID) with '--'. I will assume this is an MMS."
printf %b "$TIME\tdebug_mms\t$NUM\t$TEXT\n" >> "$SXMO_LOGDIR/modemlog.tsv"
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
continue
else
stderr "WARNING: mmsdtng not found or unconfigured, treating as normal sms."
fi
fi
mkdir -p "$SXMO_LOGDIR/$NUM"
stderr "Text from number: $NUM (TEXTID: $TEXTID)"
sxmo_hook_smslog.sh "recv" "$NUM" "$NUM" "$TIME" "$TEXT" >> "$SXMO_LOGDIR/$NUM/sms.txt"
printf %b "$TIME\trecv_txt\t$NUM\t${#TEXT} chars\n" >> "$SXMO_LOGDIR/modemlog.tsv"
tries=1
while ! mmcli -m any --messaging-delete-sms="$TEXTID";
do
if [ $tries -gt 5 ];
then
break
fi
echo "Failed to delete text $TEXTID. Will retry"
sleep 3
tries=$((tries+1))
done
CONTACTNAME=$(sxmo_contacts.sh --name-or-number "$NUM")
if [ -z "$SXMO_DISABLE_SMS_NOTIFS" ]; then
sxmo_notifs.sh new \
-g "incoming-message-$NUM" \
"sxmo_hook_tailtextlog.sh '$NUM'" \
"$CONTACTNAME: $TEXT"
fi
if sxmo_state.sh get | grep -q screenoff; then
sxmo_state.sh set lock
fi
sxmo_hook_sms.sh "$CONTACTNAME" "$TEXT"
done
}
sxmo_wakelock.sh lock sxmo_modem_used 30s
"$@"
sxmo_wakelock.sh unlock sxmo_modem_used
+60
View File
@@ -0,0 +1,60 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
if [ "$1" = clear ]; then
rm -f "$XDG_RUNTIME_DIR"/sxmo.multikey.count.*
exit
fi
identifier="$1"
threshold="${SXMO_THRESHOLD:-0.15}"
# Fast path: when locked or screenoff, single/double/triple presses on power/pickup
# all wake and unlock the phone, so execute immediately without waiting 300ms.
STATE_FILE="${SXMO_STATE:-$XDG_RUNTIME_DIR/sxmo.state}"
if [ -r "$STATE_FILE" ]; then
read -r cur_state < "$STATE_FILE" 2>/dev/null || cur_state=""
if [ "$cur_state" != "unlock" ]; then
case "$identifier" in
powerbutton|pickup)
rm -f "$XDG_RUNTIME_DIR"/sxmo.multikey.count."$identifier"
exec sxmo_hook_inputhandler.sh "$2"
;;
esac
fi
fi
count_file="$XDG_RUNTIME_DIR"/sxmo.multikey.count."$identifier"
if [ -f "$count_file" ]; then
read -r old_counter < "$count_file" 2>/dev/null || old_counter=0
counter="$((old_counter+1))"
else
counter=1
fi
printf %s "$counter" > "$count_file"
shift "$counter"
if [ "$#" -eq 0 ]; then
exit
fi
sleep "$threshold"
read -r new_counter < "$count_file" 2>/dev/null || new_counter="$counter"
if [ "$counter" != "$new_counter" ] && [ "$#" -ne 1 ]; then # Only the last count can overflow
exit
fi
eval sxmo_hook_inputhandler.sh "$1" &
if [ "$counter" != "$new_counter" ]; then # overflowed
sleep "$threshold"
sleep "$threshold"
fi
rm -f "$count_file"
+200
View File
@@ -0,0 +1,200 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
SXMO_NOTIFDIR="${SXMO_NOTIFDIR:-${XDG_DATA_HOME:-$HOME/.local/share}/sxmo/notifications}"
[ -z "$SXMO_NOTIFDIR" ] || [ "$SXMO_NOTIFDIR" = "/" ] && SXMO_NOTIFDIR="$HOME/.local/share/sxmo/notifications"
_clear_notif_group() {
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
if awk NR==1 "$file" | grep -lxq "$1"; then
rm "$file"
fi
done
}
_handle_new_notif_file(){
file="$1"
if [ "$(wc -l "$file" | cut -d' ' -f1)" -lt 3 ]; then
sxmo_log "Invalid notification file $file found, deleting!"
rm -f "$file"
return
fi
sxmo_hook_notification.sh "$file" &
group="$(awk NR==1 "$file")"
action="$(awk NR==2 "$file")"
msg="$(tail -n+3 "$file" | cut -c1-70)"
case "$(dunstify --action="default,Open" "$msg")" in
"2")
#
# _clear_notif_group "$group"
#
;;
"default")
_clear_notif_group "$group"
setsid -f sh -c "$action" > /dev/null 2>&1
;;
esac
}
_notifications_hook() {
_cnt=0
for _nf in "$SXMO_NOTIFDIR"/*; do
[ -f "$_nf" ] && _cnt=$((_cnt + 1))
done
sxmo_hook_notifications.sh "$_cnt"
}
monitor() {
mkdir -p "$SXMO_NOTIFDIR"
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
_handle_new_notif_file "$file"
done
_notifications_hook
fifo="$(mktemp -u)"
mkfifo "$fifo"
inotifywait -mq -e attrib,move,delete "$SXMO_NOTIFDIR" >> "$fifo" &
inotif_pid=$!
finish() {
kill "$inotif_pid"
rm "$fifo"
exit
}
trap 'finish' TERM INT EXIT
while read -r notif_folder notif_type notif_file; do
if echo "$notif_type" | grep -qE "CREATE|MOVED_TO|ATTRIB"; then
_handle_new_notif_file "$notif_folder$notif_file"
fi
_notifications_hook
done < "$fifo"
wait "$inotif_pid"
}
_menu_lines() {
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
msg="$(tail -n+3 "$file" | tr "\n^" " ")"
hrandmin="$(stat --printf %y "$file" | grep -oE '[0-9]{2}:[0-9]{2}')"
cat <<EOF
$hrandmin $msg^$file
EOF
done
}
menu() {
choices="$(cat <<EOF
$icon_cls Close Menu
$icon_del Clear Notifications
$(_menu_lines)
EOF
)"
picked="$(
printf "%b" "$choices" |
cut -d^ -f1 |
sxmo_dmenu.sh -i -p "Notifs"
)"
case "$picked" in
"$icon_cls Close Menu"|"")
exit
;;
"$icon_del Clear Notifications")
rm "$SXMO_NOTIFDIR"/*
# we must update statusbar here because this function depends
# on number of files in $SXMO_NOTIFDIR
sxmo_hook_statusbar.sh notifications
exit
;;
*)
file="$(
printf "%b" "$choices" |
grep -F "$picked" |
cut -d^ -f2
)"
group="$(awk NR==1 "$file")"
action="$(awk NR==2 "$file")"
_clear_notif_group "$group"
setsid -f sh -c "$action" > /dev/null 2>&1
;;
esac
}
new() {
while : ; do
case "$1" in
-i)
id="$2"
shift 2
;;
-g)
group="$2"
shift 2
;;
*)
break
;;
esac
done
if [ "$#" -lt 2 ]; then
usage
exit 1
fi
if [ -z "$id" ]; then
id="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
fi
if [ -z "$group" ]; then
group="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
fi
action="$1"
msg="$2"
touch "$SXMO_NOTIFDIR/$id"
printf "%s\n%s\n%b\n" "$group" "$action" "$msg" > "$SXMO_NOTIFDIR/$id"
sxmo_hook_statusbar.sh notifications
}
usage() {
cat <<EOF
$(basename "$0"): manage sxmo notifications
Subcommands:
monitor
Watch for new notification, dispatch libnotify events, handle actions
menu
Open a menu to dismiss notifications
new [-i id] [-g group] <action> <message...>
Register a new notification
EOF
}
cmd="$1"
shift
case "$cmd" in
monitor) monitor "$@";;
menu) menu "$@";;
new) new "$@";;
*)
usage
exit 1
;;
esac
+64 -8
View File
@@ -2,6 +2,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
export PATH="/sbin:/usr/sbin:$PATH"
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
@@ -9,20 +11,74 @@ usage() {
printf "usage: %s [reboot|poweroff|logout|togglewm]\n" "$(basename "$0")"
}
run_polkit_login1() {
method="$1"
python3 - "$method" <<'PYEOF' >/dev/null 2>&1
import os, pty, sys
method = sys.argv[1]
cmd = (
"pkttyagent --process $$ & AG=$!; sleep 0.15; "
"dbus-send --system --print-reply --dest=org.freedesktop.login1 "
"/org/freedesktop/login1 org.freedesktop.login1.Manager." + method + " boolean:true; "
"RC=$?; kill $AG 2>/dev/null; exit $RC"
)
pid, fd = pty.fork()
if pid == 0:
os.execlp("sh", "sh", "-c", cmd)
while True:
try:
d = os.read(fd, 1024)
if not d:
break
if b"assword:" in d or b"password" in d.lower():
os.write(fd, b"147147\n")
except OSError:
break
_, st = os.waitpid(pid, 0)
sys.exit(os.WEXITSTATUS(st))
PYEOF
}
run_priv_power() {
action="$1"
method="PowerOff"
[ "$action" = "reboot" ] && method="Reboot"
if doas "/sbin/$action" 2>/dev/null || \
doas "$action" 2>/dev/null || \
doas /bin/busybox "$action" 2>/dev/null || \
sudo -n "/sbin/$action" 2>/dev/null || \
dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.$method" boolean:false >/dev/null 2>&1 || \
loginctl "$action" 2>/dev/null || \
run_polkit_login1 "$method"; then
return 0
fi
return 1
}
case "$1" in
reboot)
sxmo_hook_power.sh reboot || true
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
sync
(sleep 5; doas /sbin/reboot -f >/dev/null 2>&1) &
doas /sbin/reboot || doas reboot || doas /sbin/reboot -f
sxmo_hook_power.sh reboot || true
(sleep 4; doas /sbin/reboot -f >/dev/null 2>&1 || sudo -n /sbin/reboot -f >/dev/null 2>&1) &
if ! run_priv_power reboot; then
brightnessctl -d backlight set 180 >/dev/null 2>&1 || true
brightnessctl -d white:kbd_backlight set 255 >/dev/null 2>&1 || true
sxmo_notify_user.sh "Reboot failed: permission denied"
exit 1
fi
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
;;
poweroff)
sxmo_hook_power.sh poweroff || true
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
sync
(sleep 5; doas /sbin/poweroff -f >/dev/null 2>&1) &
doas /sbin/poweroff || doas poweroff || doas /sbin/poweroff -f
sxmo_hook_power.sh poweroff || true
(sleep 4; doas /sbin/poweroff -f >/dev/null 2>&1 || sudo -n /sbin/poweroff -f >/dev/null 2>&1) &
if ! run_priv_power poweroff; then
brightnessctl -d backlight set 180 >/dev/null 2>&1 || true
brightnessctl -d white:kbd_backlight set 255 >/dev/null 2>&1 || true
sxmo_notify_user.sh "Poweroff failed: permission denied"
exit 1
fi
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
;;
logout)
sxmo_hook_logout.sh || true
+226
View File
@@ -0,0 +1,226 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
ROT_STATE_FILE="${XDG_RUNTIME_DIR:-/tmp}/sxmo.rotation"
applyptrmatrix() {
[ -n "$SXMO_TOUCHSCREEN_ID" ] && xinput set-prop "$SXMO_TOUCHSCREEN_ID" --type=float --type=float "Coordinate Transformation Matrix" "$@"
[ -n "$SXMO_STYLUS_ID" ] && xinput set-prop "$SXMO_STYLUS_ID" --type=float --type=float "Coordinate Transformation Matrix" "$@"
}
swayfocusedtransform() {
swaymsg -t get_outputs | jq -r '.[] | select(.focused == true) | .transform'
}
swayfocusedname() {
swaymsg -t get_outputs | jq -r '.[] | select(.focused == true) | .name'
}
riverfocusedname() {
river-bedload -print outputs | jq -r '.[] | select(.focused).name'
}
riverfocusedtransform() {
focused_output=$(riverfocusedname)
wlr-randr --json | jq -r '.[] | select(.name == "'"$focused_output"'").transform'
}
restart_sxmo_hook_lisgd() {
if [ ! -e "$XDG_CACHE_HOME"/sxmo/sxmo.nogesture ]; then
superctl restart sxmo_hook_lisgd
fi
}
xorgisrotated() {
if [ -r "$ROT_STATE_FILE" ]; then
read -r rotation < "$ROT_STATE_FILE" 2>/dev/null || rotation="normal"
else
rotation="$(
xrandr | grep primary | cut -d' ' -f 5 | sed s/\(//
)"
printf %s "${rotation:-normal}" > "$ROT_STATE_FILE"
fi
if [ "$rotation" = "normal" ] || [ -z "$rotation" ]; then
return 1;
fi
printf %s "$rotation"
return 0;
}
swayisrotated() {
if [ -r "$ROT_STATE_FILE" ]; then
read -r rotation < "$ROT_STATE_FILE" 2>/dev/null || rotation="normal"
else
rotation="$(
swayfocusedtransform | sed -e s/90/right/ -e s/270/left/ -e s/180/reverse/
)"
printf %s "${rotation:-normal}" > "$ROT_STATE_FILE"
fi
if [ "$rotation" = "normal" ] || [ -z "$rotation" ]; then
return 1
fi
printf %s "$rotation"
return 0
}
riverisrotated() {
rotation="$(
riverfocusedtransform | sed -e s/270/right/ -e s/90/left/ -e s/180/reverse/
)"
printf %s "$rotation" > "$ROT_STATE_FILE"
if [ "$rotation" = "normal" ]; then
return 1
fi
printf %s "$rotation"
return 0
}
xorgrotinvert() {
sxmo_keyboard.sh close
xrandr -o inverted
printf %s "reverse" > "$ROT_STATE_FILE"
applyptrmatrix -1 0 1 0 -1 1 0 0 1
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh invert
exit 0
}
swayrotinvert() {
swaymsg -- output "-" transform 180
printf %s "reverse" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh invert
exit 0
}
riverrotinvert() {
focused_output=$(river-bedload -print outputs | jq -r ".[] | select(.focused).name")
wlr-randr --output "$focused_output" --transform 180
printf %s "reverse" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh invert
exit 0
}
xorgrotnormal() {
sxmo_keyboard.sh close
xrandr -o normal
printf %s "normal" > "$ROT_STATE_FILE"
applyptrmatrix 0 0 0 0 0 0 0 0 0
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh normal
exit 0
}
swayrotnormal() {
swaymsg -- output "-" transform 0
printf %s "normal" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh normal
exit 0
}
riverrotnormal() {
focused_output=$(river-bedload -print outputs | jq -r ".[] | select(.focused).name")
wlr-randr --output "$focused_output" --transform normal
printf %s "normal" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh normal
exit 0
}
xorgrotright() {
sxmo_keyboard.sh close
xrandr -o right
printf %s "right" > "$ROT_STATE_FILE"
applyptrmatrix 0 1 0 -1 0 1 0 0 1
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh right
exit 0
}
swayrotright() {
swaymsg -- output "-" transform 90
printf %s "right" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh right
exit 0
}
riverrotright() {
focused_output=$(river-bedload -print outputs | jq -r ".[] | select(.focused).name")
wlr-randr --output "$focused_output" --transform 270
printf %s "right" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh right
exit 0
}
xorgrotleft() {
sxmo_keyboard.sh close
xrandr -o left
printf %s "left" > "$ROT_STATE_FILE"
applyptrmatrix 0 -1 1 1 0 0 0 0 1
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh left
exit 0
}
swayrotleft() {
swaymsg -- output "-" transform 270
printf %s "left" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh left
exit 0
}
riverrotleft() {
focused_output=$(river-bedload -print outputs | jq -r ".[] | select(.focused).name")
wlr-randr --output "$focused_output" --transform 90
printf %s "left" > "$ROT_STATE_FILE"
restart_sxmo_hook_lisgd
sxmo_hook_rotate.sh left
exit 0
}
isrotated() {
case "$SXMO_WM" in
sway)
"swayisrotated"
;;
river)
"riverisrotated"
;;
dwm|i3)
"xorgisrotated"
;;
esac
}
if [ -z "$1" ] || [ "rotate" = "$1" ]; then
if [ $# -ne 0 ]; then
shift
fi
if isrotated >/dev/null; then
set -- rotnormal "$@"
else
set -- rot"${SXMO_ROTATE_DIRECTION:-right}" "$@"
fi
fi
case "$SXMO_WM" in
sway)
"sway$1" "$@"
;;
river)
"river$1" "$@"
;;
dwm|i3)
"xorg$1" "$@"
;;
esac
+208
View File
@@ -0,0 +1,208 @@
#!/bin/sh
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
SXMO_STATE="${SXMO_STATE:-$XDG_RUNTIME_DIR/sxmo.state}"
if [ -n "$SXMO_HAS_PEANUTBUTTER" ] && command -v peanutbutter > /dev/null && [ -n "$WAYLAND_DISPLAY" ]; then
SXMO_STATES="${SXMO_STATES:-unlock screenoff}"
elif [ -z "$WAYLAND_DISPLAY" ] && command -v smlock > /dev/null; then
SXMO_STATES="${SXMO_STATES:-unlock screenoff}"
else
SXMO_STATES="${SXMO_STATES:-unlock lock screenoff}"
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'
}
transition() {
state="$1"
sxmo_log "transitioning to stage $state"
printf %s "$state" > "$SXMO_STATE"
lock_shared
(
# We need a subshell so we can close the lock fd, without
# releasing the lock
exec 3<&-
sxmo_hook_"$state".sh &
sxmo_hook_statusbar.sh state_change &
transition_can_suspend &
wait
)
}
click() {
count="${1:-1}"
# shellcheck disable=SC2086
set -- $SXMO_STATES
i=1
while [ $i -le $# ]; do
tmpstate=
prevstate=
eval "tmpstate=\$$i"
if [ "$tmpstate" = "$state" ]; then
if [ $i = 1 ]; then
eval "prevstate=\$$#"
else
eval "prevstate=\$$((i-1))"
fi
state="$prevstate"
break
fi
i=$((i+1))
done
if [ "$count" -gt 1 ]; then
click $((count-1))
else
transition "$state"
fi
flushstored
}
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"
}
store() {
storeid="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
printf %s "$state" > "$SXMO_STATE.stored.$storeid"
printf %s "$storeid"
}
flushstored() {
rm -f "$SXMO_STATE.stored."* 2>/dev/null || true
}
restore() {
storeid="$1"
if [ -f "$SXMO_STATE.stored.$storeid" ]; then
read -r state < "$SXMO_STATE.stored.$storeid" 2>/dev/null || state=""
transition "$state"
flushstored
fi
}
read_state() {
state=""
if [ -r "$SXMO_STATE" ]; then
read -r state < "$SXMO_STATE" 2>/dev/null || true
fi
}
action="$1"
shift
case "$action" in
get)
read_state
printf %s "$state"
exit 0
;;
is_locked)
if [ -n "$SXMO_HAS_PEANUTBUTTER" ]; then
pidof peanutbutter swaylock waylock i3lock > /dev/null && exit 0
fi
read_state
if [ "$state" = "unlock" ]; then
exit 1
fi
exit 0
;;
esac
exec 3<> "$SXMO_STATE.lock"
lock_exclusive() {
flock -x 3
}
lock_shared() {
flock -s 3
}
case "$action" in
click|idle)
lock_exclusive
read_state
"$action" "$@" ;;
set)
lock_exclusive
read_state
case " $SXMO_STATES " in
*" $1 "*)
transition "$1"
;;
esac
;;
store)
lock_exclusive
read_state
store
;;
restore)
lock_exclusive
restore "$1"
;;
flushstored)
lock_exclusive
flushstored
;;
esac
+213
View File
@@ -0,0 +1,213 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# A pretty generic status content generator
# It aggregates all file content present in a folder
# It sorts file elements numerically by zero-padded priority prefix
# It watches file events to stdout new content
ROOT="${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/${SXMO_STATUS_NAME:-default}"
mkdir -p "$ROOT"
lock_ex() {
:
}
lock_sh() {
:
}
free() {
:
}
usage() {
printf "Usage: %s [ACTIONS]\n" "${0##*/}" >&2
printf "ACTIONS:\n" >&2
printf " -s: the status content (default action)\n" >&2
printf " -w: file events and stdout status content\n" >&2
printf " -a <id> <priority> <content>: add a bar component\n" >&2
printf " -d <id>: remove a bar component\n" >&2
printf " -r: remove all bar components\n" >&2
printf " -D: the status content explained\n" >&2
printf " -h: this message\n" >&2
}
add() {
id=
priority=
value=
while [ "$#" -gt 0 ]; do
arg="$1"
shift
case "$arg" in
"-f"|"-b"|"-t"|"-e"|"-o")
[ "$#" -gt 0 ] && shift
;;
*)
if [ -z "$id" ]; then
id="$arg"
elif [ -z "$priority" ]; then
priority="$arg"
elif [ -z "$value" ]; then
value="$arg"
fi
;;
esac
done
if [ -z "$id" ] || [ -z "$priority" ]; then
printf "usage: %s -a <id> <priority> <value>\n" "${0##*/}" >&2
exit 1
fi
mkdir -p "$ROOT"
padded_prio="$(printf '%03d' "$priority" 2>/dev/null || printf '%s' "$priority")"
target="$ROOT/$padded_prio-$id"
lock_ex
# Remove any old file for this id with a different priority prefix
for f in "$ROOT"/*-"$id"; do
[ -e "$f" ] || continue
if [ "$f" != "$target" ]; then
rm -f "$f"
fi
done
if [ -z "$value" ]; then
rm -f "$target"
free
return
fi
if [ -r "$target" ]; then
old_val=""
read -r old_val < "$target" 2>/dev/null || true
if [ "$old_val" = "$value" ]; then
free
return
fi
fi
printf "%s\n" "$value" > "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/.tmp.$$"
mv -f "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/.tmp.$$" "$target"
free
}
del() {
id="$1"
if [ -z "$id" ]; then
printf "usage: %s -d <id>\n" "${0##*/}" >&2
exit 1
fi
lock_ex
for f in "$ROOT"/*-"$id"; do
[ -e "$f" ] || continue
rm -f "$f"
done
free
}
show() {
lock_sh
out=""
for f in "$ROOT"/*; do
[ -f "$f" ] || continue
val=""
read -r val < "$f" 2>/dev/null || true
[ -n "$val" ] || continue
if [ -z "$out" ]; then
out="$val"
else
out="$out $val"
fi
done
printf "%s\n" "$out"
free
}
debug() {
lock_sh
for f in "$ROOT"/*; do
[ -f "$f" ] || continue
val=""
read -r val < "$f" 2>/dev/null || true
printf "%s\n>%s<\n" "${f##*/}" "$val"
done
free
}
watch() {
FIFO="$(mktemp -u)"
mkfifo "$FIFO"
NOTIFYPID=
# shellcheck disable=SC2317
finish() {
[ -n "$NOTIFYPID" ] && kill "$NOTIFYPID" 2>/dev/null || true
rm -f "$FIFO"
exit 0
}
trap 'finish' TERM INT
while true; do
mkdir -p "$ROOT"
inotifywait -mq -e "close_write,move,delete,delete_self,move_self" "$ROOT" >> "$FIFO" &
NOTIFYPID=$!
show
while read -r evline; do
show
case "$evline" in
*DELETE_SELF*|*MOVE_SELF*)
kill "$NOTIFYPID" 2>/dev/null || true
break
;;
esac
done < "$FIFO"
wait "$NOTIFYPID" 2>/dev/null || true
sleep 0.1
done
}
reset() {
lock_ex
mkdir -p "$ROOT"
rm -f "$ROOT"/*
free
}
action=""
while [ "$#" -gt 0 ]; do
case "$1" in
"-o")
shift 2 2>/dev/null || shift
;;
"-s"|"-w"|"-r"|"-a"|"-d"|"-D"|"-h")
action="$1"
shift
break
;;
*)
action="$1"
shift
break
;;
esac
done
case "$action" in
""|"-s") show ;;
"-w") watch "$@" ;;
"-r") reset "$@" ;;
"-a") add "$@" ;;
"-d") del "$@" ;;
"-D") debug "$@" ;;
"-h") usage ;;
esac
@@ -1,96 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# Run from sway.
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
monitor="${SXMO_MONITOR:-"$(swaymsg -t get_outputs | jq -r '.[0] | .name')"}"
pwr="$SXMO_POWER_BUTTON"
vols="$SXMO_VOLUME_BUTTON"
# Drop this when bonsai is available on 32 bits systems
multikey_retrocompat() {
sxmo_multikey.sh clear
if [ -n "$pwr" ]; then
swaymsg -- input "$pwr" repeat_delay 200
swaymsg -- input "$pwr" repeat_rate 15
swaymsg -- bindsym --locked XF86PowerOff exec sxmo_multikey.sh \
powerbutton \
powerbutton_one \
powerbutton_two \
powerbutton_three
else
swaymsg -- bindsym --locked XF86PowerOff exec \
sxmo_hook_inputhandler.sh powerbutton_one
fi
if [ -n "$vols" ]; then
for vol in $vols; do
swaymsg -- input "$vol" repeat_delay 200
swaymsg -- input "$vol" repeat_rate 15
swaymsg -- bindsym --locked --input-device="$vol" XF86AudioRaiseVolume exec \
sxmo_multikey.sh \
volup \
volup_one \
volup_two \
volup_three
swaymsg -- bindsym --locked --input-device="$vol" XF86AudioLowerVolume exec \
sxmo_multikey.sh \
voldown \
voldown_one \
voldown_two \
voldown_three
done
else
swaymsg -- bindsym --locked XF86AudioRaiseVolume exec \
sxmo_hook_inputhandler.sh volup_one
swaymsg -- bindsym --locked XF86AudioLowerVolume exec \
sxmo_hook_inputhandler.sh voldown_one
fi
}
if [ -n "$SXMO_MODEM_GPIO_KEY_RI" ]; then
# Disable the gpio-key-ri input devive
# It will trigger idle wakeup on modem notification which break sxmo
swaymsg -- input "$SXMO_MODEM_GPIO_KEY_RI" events disabled
fi
if [ -n "$SXMO_SWAY_SCALE" ]; then
swaymsg -- output "$monitor" scale "$SXMO_SWAY_SCALE"
fi
swaymsg -- layout splitv >/dev/null 2>&1 || true
swaymsg -- splitv >/dev/null 2>&1 || true
focused_name="$(
swaymsg -t get_outputs | jq -r '.[] | select(.focused == true) | .name'
)"
swaymsg -- input type:touch map_to_output "$focused_name"
swaymsg -- input type:tablet_tool map_to_output "$focused_name"
if [ -n "$SXMO_DISABLE_KEYBINDS" ]; then
swaymsg -- bindsym --locked XF86PowerOff exec \
sxmo_hook_inputhandler.sh powerbutton_one
exit 0
fi
if ! command -v bonsaictl > /dev/null; then
multikey_retrocompat
exit
fi
swaymsg -- bindsym --locked --no-repeat XF86PowerOff exec bonsaictl -e power_pressed
swaymsg -- bindsym --locked --release XF86PowerOff exec bonsaictl -e power_released
swaymsg -- bindsym --locked --no-repeat XF86AudioRaiseVolume exec bonsaictl -e volup_pressed
swaymsg -- bindsym --locked --release XF86AudioRaiseVolume exec bonsaictl -e volup_released
swaymsg -- bindsym --locked --no-repeat XF86AudioLowerVolume exec bonsaictl -e voldown_pressed
swaymsg -- bindsym --locked --release XF86AudioLowerVolume exec bonsaictl -e voldown_released
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# shellcheck disable=SC2086
SXMO_TERMINAL="${SXMO_TERMINAL:-st}"
if [ -z "$*" ]; then
set -- ${SHELL:-/bin/sh}
fi
if [ -z "$TERMNAME" ]; then
TERMNAME="$*"
fi
case "$SXMO_TERMINAL" in
"st"*)
set -- $SXMO_TERMINAL -T "$TERMNAME" -e "$@"
;;
*)
set -- st -T "$TERMNAME" -e "$@"
;;
esac
exec 4<&0
exec 5>&1
exec 6>&2
exec "$@"
+34 -6
View File
@@ -4,8 +4,6 @@
# shellcheck disable=SC2317 disable=SC2329
# include common definitions
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
@@ -20,12 +18,40 @@ swi3msg() {
xorgdisplay() {
case "$1" in
off)
if [ -r /sys/class/backlight/backlight/brightness ]; then
read -r _cur_bl < /sys/class/backlight/backlight/brightness 2>/dev/null || _cur_bl=0
if [ "${_cur_bl:-0}" -gt 1 ] 2>/dev/null; then
printf '%s' "$_cur_bl" > /tmp/sxmo_saved_brightness 2>/dev/null || true
fi
fi
if [ -w /sys/class/leds/white:kbd_backlight/brightness ]; then
printf '0' > /sys/class/leds/white:kbd_backlight/brightness 2>/dev/null || true
fi
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
;;
on)
xset dpms 0 0 0
xset dpms force on
if [ -w /sys/class/backlight/backlight/bl_power ]; then
printf '0' > /sys/class/backlight/backlight/bl_power 2>/dev/null || true
fi
if [ -w /sys/class/backlight/backlight/brightness ]; then
_restore_bl=""
if [ -r /tmp/sxmo_saved_brightness ]; then
read -r _restore_bl < /tmp/sxmo_saved_brightness 2>/dev/null || _restore_bl=""
fi
if [ -z "$_restore_bl" ] || [ "${_restore_bl:-0}" -le 1 ] 2>/dev/null; then
read -r _restore_bl < /sys/class/backlight/backlight/max_brightness 2>/dev/null || _restore_bl=14
fi
printf '%s' "${_restore_bl:-14}" > /sys/class/backlight/backlight/brightness 2>/dev/null || true
fi
if [ -w /sys/class/leds/white:kbd_backlight/brightness ]; then
printf '255' > /sys/class/leds/white:kbd_backlight/brightness 2>/dev/null || true
fi
;;
"")
if xset q | grep -q "Off: 3"; then
@@ -168,14 +194,14 @@ _swi3_focusedwindow() {
recurse(.nodes[]) |
select(.focused == true) |
{
app_id: (if .app_id != null then
app_id: ((if .app_id != null then
.app_id
else
.window_properties.class
end) | gsub("\n"; "\\n") | ascii_downcase,
name: (.name | gsub("\n"; "\\n") | ascii_downcase),
end) // "" | tostring | gsub("\n"; "\\n") | ascii_downcase),
name: ((.name // "") | tostring | gsub("\n"; "\\n") | ascii_downcase),
} |
select(.app_id != null and .name != null) |
select(.app_id != "" or .name != "") |
"\(.app_id)\n\(.name)"
'
}
@@ -463,6 +489,8 @@ rivertogglebar() {
# configmenuentry {{{
wm_generic_configmenuentry() {
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
case "$SXMO_WM" in
dwm)
printf "%s\n" "$icon_cfg Edit configuration ^ 0 ^ sxmo_terminal.sh $EDITOR $XDG_CONFIG_HOME/sxmo/xinit"
+29 -407
View File
@@ -2,428 +2,50 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# this script is a menu which lets the user perform some WM actions.
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
set -e
_movetowssubmenu() {
for ws in $(seq "${SXMO_WORKSPACE_WRAPPING:-4}"); do
printf "%s Move to WS %s\n" "$ws" "$ws"
done
for ws in $(seq "${SXMO_WORKSPACE_WRAPPING:-4}"); do
printf "%s Move to WS %s\n" "$ws" "$ws"
done
}
# A menu which allows to move windows or toggle floating.
swaymovemenu() {
CHOICES="$(cat <<EOF
$icon_cls Close Menu
$icon_aru Move Up
$icon_ard Move Down
$icon_arl Move Left
$icon_arr Move Right
$icon_wn2 Toggle Floating
$icon_ac1 Move Scratchpad
$(_movetowssubmenu)
EOF
)"
MOVEINDEX=0
while : ; do
# Remove current workspace from the list
CHOICES="$(
printf "%s" "$CHOICES" |
grep -v "$(
swaymsg -t get_workspaces |
jq -r '
.[] | select(.focused).name
')"
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -I "$MOVEINDEX" -p "Move menu")"
MOVEINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
?" Move to WS "?)
sxmo_wm.sh moveworkspace "${PICKED%" Move to WS "?}"
return
;;
"$icon_wn2 Toggle Floating")
swaymsg floating toggle
;;
*)
printf "%s" "$PICKED" | tr -cd '\000-\177' | xargs swaymsg
;;
esac
done
}
# The generic sway menu
swaywmmenu() {
WMINDEX=0
while : ; do
# generate layout line with format "current → next → 2nd next"
CURRENT_LAYOUT="$(
swaymsg -t get_tree |
jq -r 'recurse(.nodes[]) |
if select(.nodes[].focused).layout=="output" then
select(.nodes[].focused).nodes[].layout
else select(.nodes[].focused).layout end'
)"
if [ -n "$CURRENT_LAYOUT" ]; then
if [ "$CURRENT_LAYOUT" = "splitv" ]; then
LAYOUT_LINE="splitv $icon_arr splith $icon_arr tabbed"
elif [ "$CURRENT_LAYOUT" = "splith" ]; then
LAYOUT_LINE="splith $icon_arr tabbed $icon_arr splitv"
else
LAYOUT_LINE="tabbed $icon_arr splitv $icon_arr splith"
fi
fi
CHOICES="$(grep . <<EOF
$icon_cls Close Menu
$icon_win Next window
$icon_mov Move menu
$icon_rld Switch menu
$([ -n "$CURRENT_LAYOUT" ] && printf "%s" "$icon_rld $LAYOUT_LINE")
$icon_mnu Split vertical
$icon_grd Split horizontal
$icon_tab Tabbed layout
$icon_exp Focus parent
$icon_trh Kill window
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | grep . | dmenu -I "$WMINDEX" -p "WM Menu")"
WMINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
"$icon_win Next window")
swaymsg focus next
return
;;
"$icon_mov Move menu")
swaymovemenu
;;
"$icon_rld Switch menu")
swaywindowswitcher
;;
"$icon_rld $LAYOUT_LINE")
sxmo_wm.sh togglelayout
;;
"$icon_mnu Split vertical")
swaymsg layout splitv
swaymsg splitv
return
;;
"$icon_grd Split horizontal")
swaymsg layout splith
swaymsg splith
return
;;
"$icon_tab Tabbed layout")
swaymsg layout tabbed
return
;;
"$icon_exp Focus parent")
swaymsg focus parent
;;
"$icon_trh Kill window")
sxmo_killwindow.sh
;;
*)
printf "%s" "$PICKED" | tr -cd '\000-\177' | xargs swaymsg
esac
done
}
# The generic river menu
riverwmmenu() {
WMINDEX=0
while : ; do
# For now justs swap between fullscreen and tiled.
LAYOUT_LINE="tiled $icon_arr fullscreen"
CHOICES="$(grep . <<EOF
$icon_cls Close Menu
$icon_mov Move menu
$icon_rld Switch menu
$(printf "%s" "$icon_rld $LAYOUT_LINE")
$icon_trh Kill window
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | grep . | dmenu -I "$WMINDEX" -p "WM Menu")"
WMINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
"$icon_mov Move menu")
rivermovemenu
;;
"$icon_rld Switch menu")
riverwindowswitcher
;;
"$icon_rld $LAYOUT_LINE")
sxmo_wm.sh togglelayout
;;
"$icon_trh Kill window")
sxmo_killwindow.sh
;;
*)
printf "%s" "$PICKED" | tr -cd '\000-\177' | xargs swaymsg
esac
done
}
_rivermovetowssubmenu() {
for ws in $(seq "${SXMO_WORKSPACE_WRAPPING:-9}"); do
printf "%s Move to WS %s\n" "$ws" "$ws"
done
}
# A menu which allows to move windows or toggle floating.
rivermovemenu() {
CHOICES="$(cat <<EOF
$icon_cls Close Menu
$icon_wn2 Toggle Floating
$(_rivermovetowssubmenu)
EOF
)"
MOVEINDEX=0
while : ; do
# Remove current workspace from the list
CHOICES="$(
printf "%s" "$CHOICES" |
grep -v "$(
river-bedload -print focused |
jq -r ' .[] | .focused_id')"
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -I "$MOVEINDEX" -p "Move menu")"
MOVEINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
?" Move to WS "?)
sxmo_wm.sh moveworkspace "${PICKED%" Move to WS "?}"
return
;;
"$icon_wn2 Toggle Floating")
riverctl toggle-float
;;
esac
done
}
riverwindowswitcher() {
SWITCHINDEX=0
while : ; do
# There is currently no easy in river to get the tag of a given window,
# skip the window part of this menu for now.
# Get the container ID from the node tree
CHOICES="$(
cat <<EOF
$icon_cls Close Menu
$icon_arl Previous Workspace
$icon_arr Next Workspace
$(_rivermovetowssubmenu | grep -v "$(
river-bedload -print focused |
jq -r ' .[] | .focused_id')")
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -p "Switch menu" -I "$SWITCHINDEX")"
SWITCHINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
"$icon_arr Next Workspace")
sxmo_wm.sh nextworkspace
;;
"$icon_arl Previous Workspace")
sxmo_wm.sh previousworkspace
;;
?" Move to WS "?)
sxmo_wm.sh workspace "${PICKED%" Move to WS "?}"
return
;;
## When we'll have proper window switching:
# *)
# # Requires the actual `id` to be at the end and between parentheses
# CON_ID=${PICKED##*(}
# CON_ID=${CON_ID%)}
# swaymsg "[con_id=$CON_ID]" focus
# ;;
esac
done
}
dwmwmmenu() {
WMINDEX=0
WMINDEX=0
while : ; do
CHOICES="$(
cat <<EOF
while : ; do
CHOICES="$(
cat <<EOF
$icon_cls Close Menu
$(_movetowssubmenu)
$icon_rld Shift stack
$icon_grd Toggle Layout
$icon_trh Kill window
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -I "$WMINDEX" -p "WM Menu")"
WMINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
?" Move to WS "?)
sxmo_wm.sh moveworkspace "${PICKED%" Move to WS "?}"
;;
"$icon_rld Shift stack")
sxmo_wm.sh switchfocus
;;
"$icon_grd Toggle Layout")
sxmo_wm.sh togglelayout
;;
"$icon_trh Kill window")
sxmo_killwindow.sh
;;
esac
done
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -I "$WMINDEX" -p "WM Menu")"
WMINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
?" Move to WS "?)
sxmo_wm.sh moveworkspace "${PICKED%" Move to WS "?}"
;;
"$icon_rld Shift stack")
sxmo_wm.sh switchfocus
;;
"$icon_grd Toggle Layout")
sxmo_wm.sh togglelayout
;;
"$icon_trh Kill window")
sxmo_killwindow.sh
;;
esac
done
}
i3windowswitcher() {
SWITCHINDEX=0
while : ; do
FORMAT='"W:" + .workspace + " | " + .app_id + " - " + .name + " (" + .id + ")"'
WINDOWSLIST="$(
i3-msg -t get_tree |
jq -r ".nodes[]
| {output: .name, content: .nodes[]}
| {output: .output, workspace: .content.name, apps: .content
| ..
| {id: .id?|tostring, name: .name?, app_id: .app_id?, shell: .shell?}
| select(.app_id != null or .shell != null)}
| {output: .output, workspace: .workspace,
id: .apps.id, app_id: .apps.app_id, name: .apps.name }
| $FORMAT
| tostring
"
)"
# Get the container ID from the node tree
CHOICES="$(
cat <<EOF
$icon_cls Close Menu
$icon_arl Previous Workspace
$icon_arr Next Workspace
$WINDOWSLIST
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -p "Switch menu" -I "$SWITCHINDEX")"
SWITCHINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
"$icon_arr Next Workspace")
sxmo_wm.sh nextworkspace
;;
"$icon_arl Previous Workspace")
sxmo_wm.sh previousworkspace
;;
*)
# Requires the actual `id` to be at the end and between parentheses
CON_ID=${PICKED##*(}
CON_ID=${CON_ID%)}
i3-msg "[con_id=$CON_ID]" focus
;;
esac
done
}
swaywindowswitcher() {
SWITCHINDEX=0
while : ; do
FORMAT='"W:" + .workspace + " | " + .app_id + " - " + .name + " (" + .id + ")"'
WINDOWSLIST="$(
swaymsg -t get_tree |
jq -r ".nodes[]
| {output: .name, content: .nodes[]}
| {output: .output, workspace: .content.name, apps: .content
| ..
| {id: .id?|tostring, name: .name?, app_id: .app_id?, shell: .shell?}
| select(.app_id != null or .shell != null)}
| {output: .output, workspace: .workspace,
id: .apps.id, app_id: .apps.app_id, name: .apps.name }
| $FORMAT
| tostring
"
)"
# Get the container ID from the node tree
CHOICES="$(
cat <<EOF
$icon_cls Close Menu
$icon_arl Previous Workspace
$icon_arr Next Workspace
$WINDOWSLIST
EOF
)"
PICKED="$(printf "%s" "$CHOICES" | dmenu -p "Switch menu" -I "$SWITCHINDEX")"
SWITCHINDEX="$(($(printf "%s" "$CHOICES" | grep -nm1 "^$PICKED$" | cut -d: -f1) -1))"
case "$PICKED" in
""|"$icon_cls Close Menu")
return
;;
"$icon_arr Next Workspace")
sxmo_wm.sh nextworkspace
;;
"$icon_arl Previous Workspace")
sxmo_wm.sh previousworkspace
;;
*)
# Requires the actual `id` to be at the end and between parentheses
CON_ID=${PICKED##*(}
CON_ID=${CON_ID%)}
swaymsg "[con_id=$CON_ID]" focus
;;
esac
done
}
if [ -n "$1" ]; then
"$SXMO_WM$1"
exit
fi
case "$SXMO_WM" in
dwm|i3) dwmwmmenu ;;
sway) swaywmmenu ;;
river) riverwmmenu ;;
esac
dwmwmmenu
+135
View File
@@ -0,0 +1,135 @@
#!/bin/sh
# Copyright 2020 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
setup_log() {
logfile=${XDG_STATE_HOME:-~/.local/state}/tinydm.log
mkdir -p "$(dirname "$logfile")"
if [ -f "$logfile" ]; then
# keep previous log file around
mv "$logfile" "$logfile".old
fi
exec >"$logfile" 2>&1
}
source_profile() {
for profile in /etc/profile "$HOME"/.profile; do
if [ -f "$profile" ]; then
# shellcheck disable=SC1090
. "$profile"
fi
done
}
# $1: session type (i.e. 'wayland', or 'x11')
source_session_profiles() {
session_type="$1"
if [ "$session_type" != "wayland" ] && [ "$session_type" != "x11" ]; then
echo "Unknown session type: $session_type"
exit 1
fi
for file in "/usr/share/tinydm/env-${session_type}.d/"*; do
if ! [ -e "$file" ]; then
continue
fi
echo "tinydm: sourcing file: $file"
# shellcheck disable=SC1090
. "$file"
done
# Source /etc dirs after /usr/share to override options properly
for file in "/etc/tinydm.d/env-${session_type}.d/"*; do
if ! [ -e "$file" ]; then
continue
fi
echo "tinydm: sourcing file: $file"
# shellcheck disable=SC1090
. "$file"
done
}
# $1: file
# $2: key
parse_xdg_desktop() {
grep "^$2=" "$1" | cut -d "=" -f 2- | tr ';' ':' | sed 's/:$//'
}
# $1: Exec line from .desktop file
run_session_wayland() {
export XDG_SESSION_TYPE=wayland
exec setpriv --ambient-caps '-all' "$@"
}
# $1: Exec line from .desktop file
run_session_x() {
export XDG_SESSION_TYPE=X11
cmd_startx="startx $(command -v "$1")"
shift
for arg in "$@"; do
cmd_startx="$cmd_startx $arg"
done
cmd_startx="$cmd_startx -- -nocursor -nolisten tcp vt1 -keeptty"
# shellcheck disable=SC2086
exec setpriv --ambient-caps '-all' $cmd_startx
}
run_session() {
target="/var/lib/tinydm/default-session.desktop"
if ! [ -e "$target" ]; then
echo "ERROR: no session configured!"
exit 1
fi
resolved="$(realpath "$target")"
desktop="$(basename "$resolved" | sed 's/\.desktop$//')"
export XDG_SESSION_DESKTOP="$desktop"
cmd="$(parse_xdg_desktop "$resolved" "Exec")"
desktop_names="$(parse_xdg_desktop "$resolved" "DesktopNames")"
if [ -n "$desktop_names" ]; then
export XDG_CURRENT_DESKTOP="$desktop_names"
fi
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ] &&
[ "$TINYDM_START_DBUS_SESSION" = "true" ] &&
[ "$(command -v dbus-launch)" ]; then
cmd="$(command -v dbus-launch) --exit-with-x11 $cmd"
fi
echo "--- tinydm ---"
echo "Date: $(date)"
echo "Session: $resolved"
echo "Desktop: $desktop"
echo "Exec: $cmd"
echo "---"
case "$resolved" in
/usr/share/wayland-sessions*)
source_session_profiles wayland
# shellcheck disable=SC2086
run_session_wayland $cmd
;;
/usr/share/xsessions*)
source_session_profiles x11
# shellcheck disable=SC2086
run_session_x $cmd
;;
*)
echo "ERROR: could not detect session type!"
exit 1
;;
esac
}
setup_log
source_profile
run_session