Min Soe Han

LegalBusinessElse


backTech:


dmmsh-wlr for managing outputs in Wayland using wlr-randr

DATE 20240729

Managing outputs in Wayland is smooth and easy by using wlr-randr while some compositors such as sway and hyprland have their own tools to manage outputs. See: sway-output(5) man page and Monitors - Hyprland Wiki respectively.

#!/bin/dash

# check if it is run as root and exit
if [ $(($(id -u))) -eq 0 ]; then
    exit 0
fi
# test if it is already running and exit
SCRIPTNAME="$(basename -- $0)"
if pidof -x "$SCRIPTNAME" -o $$ > /dev/null 2>&1; then
    notify-send -t 2700 "clean exit" "the script is already running"
    exit 0
fi
# chech if it is in terminal or exit
isinterminal_func () {
    case "$(ps -o stat= -p $$)" in
        *+*) echo "in terminal, continue..." ;;
        *) notify-send -t 2700 "clean exit" "please run it in terminal."; exit 0 ;;
    esac
}

# simplest way to find built-in and extended monitors is
# using wlr-randr, finding and setting manually
# edit as required, use wlr-randr
BUIMONI=eDP-1
EXTMONI=HDMI-A-1
# edit as required the path, it is usually /sys/class/drm
MONIPATH=/sys/class/drm

# check if extended monitor is found
checkextmonifound_func () {
    EXTMONIPATH=$(find $MONIPATH -name "*$EXTMONI*")
    EXTMONISTAT=$(cat "$EXTMONIPATH"/status)
    if [ "$EXTMONISTAT" = "disconnected" ]; then
        notify-send -t 9000 ""$EXTMONI" not found" ""$EXTMONIPATH"/status says disconnected. clean exit."
        exit 0
    fi
    EXTMONIMODES=$(cat "$EXTMONIPATH"/modes | sed 's/i$//')
    if [ -z "$EXTMONIMODES" ]; then
        notify-send -t 9000 "$EXTMONI not found" ""$EXTMONIPATH"/modes is empty. clean exit."
        exit 0
    fi
}
# finding built-in monitor's details
buimonitordetails_func () {
    local ALLDATA=$(wlr-randr --json | jq -r '.[] | select(.name == '\"$BUIMONI\"') |
        (.modes[] | select(.current == true) | .width,.height),(.position | .x,.y)')
    local NUM=1
    for i in $ALLDATA; do
        local VARNAME=$(echo "BUIMONIW BUIMONIH BUIMONIX BUIMONIY" | cut -d ' ' -f $NUM)
        eval $VARNAME=$i
        local NUM=$((NUM+1))
    done
    BUIMONIMODE="$BUIMONIW"x"$BUIMONIH"
}
# finding extended monitor's details
extmonitordetails_func () {
    local ALLDATA=$(wlr-randr --json | jq -r '.[] | select(.name == '\"$EXTMONI\"') |
        (.modes[] | select(.current == true) | .width,.height),(.position | .x,.y)')
    local NUM=1
    for i in $ALLDATA; do
        local VARNAME=$(echo "EXTMONIW EXTMONIH EXTMONIX EXTMONIY" | cut -d ' ' -f $NUM)
        eval $VARNAME=$i
        local NUM=$((NUM+1))
    done
    EXTMONIMODE="$EXTMONIW"x"$EXTMONIH"
}
# show current state (positions and resolutions)
showcurrentstate_func () {
    echo "
    Monitor|--mode Resolution|--pos Position

    "$BUIMONI"|--mode "$BUIMONIW"x"$BUIMONIH"|--pos "$BUIMONIX","$BUIMONIY"
    "$EXTMONI"|--mode "$EXTMONIW"x"$EXTMONIH"|--pos "$EXTMONIX","$EXTMONIY"
" | column -t -L -s '|'
}
selectextmonimode_func () {
    # listing extended monitor's modes
    local RAWMODES=$(echo "EXIT" && echo "$EXTMONIMODES" | awk '!x[$0]++' | head -n 9)
    local NUM=0
    NUMEXTMONIMODES=$(for i in $RAWMODES; do
        echo "    "$NUM". $i"
        local NUM=$((NUM+1))
    done)
    # selecting extended monitor's mode
    echo "available resolutions modes of "$EXTMONI" are;"
    echo; echo "$NUMEXTMONIMODES"; echo
    while true; do
        unset EXTMONIMODE EXTMONIW EXTMONIH SELNUM
        read -p "Select Number of Mode: " SELNUM
        EXTMONIMODE=$(echo "$NUMEXTMONIMODES" | grep "^\s\+"$SELNUM"\." | cut -d ' ' -f 6)
        if [ "$EXTMONIMODE" = "EXIT" ];then
            exit 0
        fi
        if [ -z "$EXTMONIMODE" ]; then
            echo "Oop! invalid selection. select again."
            continue
        fi
        if [ -n "$EXTMONIMODE" ]; then
            break
        fi
    done
    EXTMONIW=$(echo "$EXTMONIMODE" | cut -d 'x' -f 1)
    EXTMONIH=$(echo "$EXTMONIMODE" | cut -d 'x' -f 2)
}
# select side
selectmoniside_func () {
    echo "
    0. EXIT
    1. Left
    2. Right
    3. Up
    4. Down
    "
    while true; do
        echo "Select position of "$EXTMONI" as which side of "$BUIMONI"."
        read -p "Select Number: " ELR
        case $ELR in
            0) exit 0 ;;
            1) set -- "left"; break ;;
            2) set -- "right"; break ;;
            3) set -- "up"; break ;;
            4) set -- "down"; break ;;
            *) echo "invalid selection. just type 0, 1, 2, 3 or 4."; continue ;;
        esac
    done
    managemoniside_func "$1" >/dev/null 2>&1
}
# manage  monitor sides
managemoniside_func () {
    case "$1" in
        left|-l)
            wlr-randr --output "$BUIMONI" --mode "$BUIMONIMODE" --pos "$EXTMONIW",0
            wlr-randr --output "$EXTMONI" --mode "$EXTMONIMODE" --pos 0,0
            ;;
        right|-r)
            wlr-randr --output "$BUIMONI" --mode "$BUIMONIMODE" --pos 0,0
            wlr-randr --output "$EXTMONI" --mode "$EXTMONIMODE" --pos "$BUIMONIW",0
            ;;
        up|-u)
            wlr-randr --output "$BUIMONI" --mode "$BUIMONIMODE" --pos 0,"$EXTMONIH"
            wlr-randr --output "$EXTMONI" --mode "$EXTMONIMODE" --pos 0,0
            ;;
        down|-d)
            wlr-randr --output "$BUIMONI" --mode "$BUIMONIMODE" --pos 0,0
            wlr-randr --output "$EXTMONI" --mode "$EXTMONIMODE" --pos 0,"$BUIMONIH"
            ;;
        *)
            exit 0
            ;;
    esac
    exit 0
}
# toggle horizontal and vertical sides
togglehorizontalside_func () {
    if [ $((EXTMONIX)) -eq 0 ] && [ $((BUIMONIX)) -eq 0 ]; then
        managemoniside_func left >/dev/null 2>&1
    fi
    if [ $((EXTMONIX)) -gt 0 ]; then
        managemoniside_func left >/dev/null 2>&1
    fi
    if [ $((EXTMONIX)) -le 0 ]; then
        managemoniside_func right >/dev/null 2>&1
    fi
}
toggleverticalside_func () {
    if [ $((EXTMONIY)) -eq 0 ] && [ $((BUIMONIY)) -eq 0 ]; then
        managemoniside_func up >/dev/null 2>&1
    fi
    if [ $((EXTMONIY)) -gt 0 ]; then
        managemoniside_func up >/dev/null 2>&1
    fi
    if [ $((EXTMONIY)) -le 0 ]; then
        managemoniside_func down >/dev/null 2>&1
    fi
}
outputtoggle_func () {
    echo "
    00. Exit
    68. "$BUIMONI" output toggle
    43. "$EXTMONI" output toggle
    "
    read -p "Select Number: " SELNUM
    case "$SELNUM" in
        00) exit 0 ;;
        68) wlr-randr --output "$BUIMONI" --toggle ;;
        43) wlr-randr --output "$EXTMONI" --toggle ;;
        *) exit 0 ;;
    esac
}

# main & run pre required functions
if [ -z "$1" ] || [ "$1" = "check" ] || [ "$1" = "-c" ]; then
    isinterminal_func
fi
checkextmonifound_func
buimonitordetails_func
extmonitordetails_func
case "$1" in
    left|-l)
        managemoniside_func left >/dev/null 2>&1
        ;;
    right|-r)
        managemoniside_func right >/dev/null 2>&1
        ;;
    up|-u)
        managemoniside_func up >/dev/null 2>&1
        ;;
    down|-d)
        managemoniside_func down >/dev/null 2>&1
        ;;
    horizontal|-h)
        togglehorizontalside_func
        ;;
    vertical|-v)
        toggleverticalside_func
        ;;
    check|-c)
        showcurrentstate_func
        ;;
    outputtoggle|opt|-t)
        outputtoggle_func
        ;;
    "")
        showcurrentstate_func
        selectextmonimode_func
        selectmoniside_func
        ;;
    *)
        exit 0
        ;;
esac