#!/bin/sh # SPDX-License-Identifier: AGPL-3.0-only # Copyright 2022 Sxmo Contributors # shellcheck disable=SC2317 disable=SC2329 # include common definitions # shellcheck source=scripts/core/sxmo_common.sh . sxmo_common.sh swi3msg() { case "$SXMO_WM" in sway) swaymsg "$@" ;; i3) i3-msg "$@" ;; esac } # Output Power Management {{{ 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 printf "off\n" else printf "on\n" fi ;; *) printf 'sxmo_wm.sh display: unknown command "%s"\n' "$1" >&2 printf 'Usage: sxmo_wm.sh display [on|off]\n' >&2 ;; esac } wldisplay() { case "$1" in on) wlopm --on "*" ;; off) wlopm --off "*";; "") if wlopm | grep -q "on"; then printf "on\n" else printf "off\n" fi ;; *) printf 'sxmo_wm.sh display: unknown command "%s"\n' "$1" >&2 printf 'Usage: sxmo_wm.sh display [on|off]\n' >&2 ;; esac } wm_generic_dpms() { sxmo_log "WARNING: $0: the dpms subcommand is deprecated, use display instead" # The dpms command was origionally implemented with on/off being the # opposite of what they should have been. Swap them for backwards # compatability. case "$1" in on) shift set -- "off" "$@" ;; off) shift set -- "on" "$@" ;; esac dispatch display "$@" } # }}} # inputevent {{{ xorginputevent() { if [ "$1" = "touchscreen" ]; then TOUCH_POINTER_ID="$SXMO_TOUCHSCREEN_ID" elif [ "$1" = "stylus" ]; then TOUCH_POINTER_ID="$SXMO_STYLUS_ID" fi if [ -z "$TOUCH_POINTER_ID" ]; then echo "not found" return 0 fi STATE=off if xinput list-props "$TOUCH_POINTER_ID" | \ grep "Device Enabled" | \ grep -q "1$"; then STATE=on fi if [ -z "$2" ]; then printf %s "$STATE" elif [ "$2" = on ] && [ "$STATE" != on ]; then xinput enable "$TOUCH_POINTER_ID" elif [ "$2" = off ] && [ "$STATE" != off ] ; then xinput disable "$TOUCH_POINTER_ID" fi } swayinputevent() { if [ "$1" = "touchscreen" ]; then TOUCH_POINTER_ID="touch" elif [ "$1" = "stylus" ]; then TOUCH_POINTER_ID="tablet_tool" fi # If we dont have any matching input if ! swaymsg -t get_inputs \ | jq -r ".[] | select(.type == \"$TOUCH_POINTER_ID\" )" \ | grep -q .; then if [ -z "$2" ]; then printf "not found" exit 0 else exit 0 fi fi STATE=on if swaymsg -t get_inputs \ | jq -r ".[] | select(.type == \"$TOUCH_POINTER_ID\" ) | .libinput.send_events" \ | grep -q "disabled"; then STATE=off fi if [ -z "$2" ]; then printf %s "$STATE" elif [ "$2" = on ] && [ "$STATE" != on ]; then swaymsg "input type:$TOUCH_POINTER_ID events enabled" > /dev/null elif [ "$2" = off ] && [ "$STATE" != off ] ; then swaymsg "input type:$TOUCH_POINTER_ID events disabled" > /dev/null fi } # }}} # focusedwindow {{{ _xorgfocusedwindow() { xprop -id "$(xdotool getactivewindow 2>/dev/null)" 2>/dev/null | awk ' /^WM_CLASS/ { sub(/^WM_CLASS[^=]*= ?"[^"]*", "/, "") sub(/"$/, "") class = $0 } /^WM_NAME/ { sub(/^WM_NAME[^=]*= ?"/, "") sub(/"$/, "") title = $0 } END { printf "%s\n%s\n", tolower(class), tolower(title) } ' } _swi3_focusedwindow() { swi3msg -t get_tree | jq -r ' recurse(.nodes[]) | select(.focused == true) | { app_id: ((if .app_id != null then .app_id else .window_properties.class end) // "" | tostring | gsub("\n"; "\\n") | ascii_downcase), name: ((.name // "") | tostring | gsub("\n"; "\\n") | ascii_downcase), } | select(.app_id != "" or .name != "") | "\(.app_id)\n\(.name)" ' } _raw_focusedwindow() { case "$SXMO_WM" in dwm) _xorgfocusedwindow ;; sway|i3) _swi3_focusedwindow ;; river) lswt -j | jq -r ' .toplevels | map(select(.activated))[0] | (."app-id" | ascii_downcase), (.title | ascii_downcase) ' esac } wm_generic_focusedwindow() { if [ "$1" = "-r" ]; then _raw_focusedwindow else # This script originally output this format, which is a bit # harder to parse. Keep it for backwards compatibility in case # anyone was using it. _raw_focusedwindow | { read -r app read -r title printf "app: %s\ntitle: %s\n" "$app" "$title" } fi } # }}} # paste {{{ wlpaste() { wl-paste } xorgpaste() { xclip -o } # }}} # exec {{{ wm_generic__swi3exec_inner() { cmd="$(cat "$1")" rm "$1" eval "$cmd" } swi3exec() { set -e cmdfile="$(mktemp)" jq -r --null-input '$ARGS.positional | @sh' --args -- "$@" > "$cmdfile" swi3msg exec "sxmo_wm.sh _swi3exec_inner '$cmdfile'" > /dev/null } riverexec() { riverctl spawn "$@" } xorgexec() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi "$@" & } # }}} # execwait {{{ wm_generic__execwait_inner() { notify_file="$1/done" shift # This opens the pipe for writing, when this process exits it will be # closed, which will send eof to the monitoring process. exec 3>"$notify_file" "$@" } _execwait() { set -e runner="$1" shift notify_dir="$(mktemp -d)" mkfifo "$notify_dir/done" "$runner" sxmo_wm.sh _execwait_inner "$notify_dir" "$@" exec 3<"$notify_dir/done" # The exec line won't finish until the inner file has been opened for # writing, so it's safe to remove the temp dir here. rm -r "$notify_dir" # Wait for the notification file to be closed read -r _ <&3 || true } swi3execwait() { _execwait swi3exec "$@" } riverexecwait() { _execwait riverexec "$@" } xorgexecwait() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi exec "$@" } # }}} # toggle layout {{{ swi3togglelayout() { swi3msg "layout toggle splitv splith tabbed" > /dev/null } dwmtogglelayout() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers key Super+space } rivertogglelayout() { riverctl toggle-fullscreen } # }}} # switch focus {{{ i3switchfocus() { sxmo_wmmenu.sh i3windowswitcher } swayswitchfocus() { sxmo_wmmenu.sh swaywindowswitcher } dwmswitchfocus() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers Super+x } # }}} # workspace switching {{{ _swi3getcurrentworkspace() { swi3msg -t get_workspaces | jq -r '.[] | select(.focused).name' } _swi3getnextworkspace() { value="$(($(_swi3getcurrentworkspace)+1))" if [ "$value" -eq "$((${SXMO_WORKSPACE_WRAPPING:-4}+1))" ]; then printf 1 else printf %s "$value" fi } _swi3getpreviousworkspace() { value="$(($(_swi3getcurrentworkspace)-1))" if [ "$value" -lt 1 ]; then if [ "${SXMO_WORKSPACE_WRAPPING:-4}" -ne 0 ]; then printf %s "${SXMO_WORKSPACE_WRAPPING:-4}" else return 1 # cant have previous workspace fi else printf %s "$value" fi } swi3nextworkspace() { swi3msg "workspace $(_swi3getnextworkspace)" > /dev/null } rivernextworkspace() { river-shifttags } dwmnextworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers Super+Shift+r } swi3previousworkspace() { swi3msg "workspace $(_swi3getpreviousworkspace )" > /dev/null } dwmpreviousworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers Super+Shift+e } riverpreviousworkspace() { river-shifttags --shift -1 } swi3movenextworkspace() { swi3msg "move container to workspace $(_swi3getnextworkspace)" > /dev/null } dwmmovenextworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers Super+r } swi3movepreviousworkspace() { swi3msg "move container to workspace $(_swi3getpreviousworkspace )" > /dev/null } dwmmovepreviousworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers Super+e } swi3workspace() { swi3msg "workspace $1" > /dev/null } riverworkspace() { tags=$((1 << ($1 - 1))) riverctl set-focused-tags "$tags" } dwmworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers "Super+$1" } swi3moveworkspace() { swi3msg "move container to workspace $1" > /dev/null } rivermoveworkspace() { tags=$((1 << ($1 - 1))) riverctl set-view-tags "$tags" } dwmmoveworkspace() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers "Super+shift+$1" } # }}} # toggle bar {{{ swi3togglebar() { swi3msg "bar mode toggle" > /dev/null } dwmtogglebar() { if [ -z "$DISPLAY" ]; then export DISPLAY=:0 fi xdotool key --clearmodifiers "Super+b" } rivertogglebar() { if superctl status sxmo_riverbar | grep -q started; then superctl stop sxmo_riverbar else superctl start sxmo_riverbar fi } # }}} # 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" ;; i3) printf "%s\n" "$icon_cfg Edit configuration ^ 0 ^ sxmo_terminal.sh $EDITOR $XDG_CONFIG_HOME/sxmo/i3" ;; river) printf "%s\n" "$icon_cfg Edit configuration ^ 0 ^ sxmo_terminal.sh $EDITOR $XDG_CONFIG_HOME/sxmo/river" ;; sway) printf "%s\n" "$icon_cfg Edit configuration ^ 0 ^ sxmo_terminal.sh $EDITOR $XDG_CONFIG_HOME/sxmo/sway" ;; esac } # }}} dispatch() { if [ "$#" -lt 1 ]; then echo "Usage: sxmo_wm.sh " >&2 return 1 fi action="$1" shift # invoke action covering single wm if type "$SXMO_WM$action" >/dev/null 2>&1; then "$SXMO_WM$action" "$@" return fi # invoke action covering multiple wms if [ "$SXMO_WM" = "sway" ] || [ "$SXMO_WM" = "i3" ]; then if type "swi3$action" >/dev/null 2>&1; then "swi3$action" "$@" return fi fi # invoke action covering all of xorg/wayland case "$SXMO_WM" in dwm|i3) if type "xorg$action" >/dev/null 2>&1; then "xorg$action" "$@" return fi ;; sway|river) # We don't yet support everything if type "wl$action" >/dev/null 2>&1; then "wl$action" "$@" return fi ;; esac # invoke action covering all wms if type "wm_generic_$action" >/dev/null 2>&1; then "wm_generic_$action" "$@" return else printf "%s not implemented for %s\n" "$action" "$SXMO_WM" >&2 return 1 fi } dispatch "$@"