Last active
September 12, 2026 13:25
-
-
Save fcorthay/cac6c56ba61adfd76bb0cc8ebcb26150 to your computer and use it in GitHub Desktop.
A Wayland partial replacement of "wmctrl"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # A Wayland partial replacement of "wmctrl" | |
| # | |
| # Requires https://extensions.gnome.org/extension/4724/window-calls/ | |
| # | |
| # Most of wmctrl's commands don't work under Wayland, | |
| # but switching to a desktop (wmctrl -s <DESK>) does. | |
| # | |
| gdbusCall='gdbus call --session --dest org.gnome.Shell' | |
| gdbusCall=`echo "$gdbusCall --object-path /org/gnome/Shell/Extensions/Windows"` | |
| gdbusCall=`echo "$gdbusCall --method org.gnome.Shell.Extensions.Windows"` | |
| INDENT=' ' | |
| # ------------------------------------------------------------------------------ | |
| # Command line arguments | |
| # | |
| # default values | |
| listWindows=false | |
| windowReference='' | |
| windowPosition='' | |
| iconify=false | |
| newDesktop='' | |
| verbose=false | |
| # specify arguments | |
| arguments='lr:e:Ys:vh' | |
| declare -A longArguments | |
| longArguments=( | |
| ["l"]="list" ["r"]="reference" ["e"]="resize" ["Y"]="iconify" | |
| ["s"]="switch" | |
| ["v"]="verbose" ["h"]="help" | |
| ) | |
| # show script usage | |
| usage() { | |
| echo "Usage: $(basename "$0") [options] [action]" 1>&2 | |
| echo "Actions:" 1>&2 | |
| echo "${INDENT}-l --list list windows" 1>&2 | |
| echo "${INDENT}-r --reference <REF> select window by reference" 1>&2 | |
| echo "${INDENT}-e --resize <COORDS> move and resize window" 1>&2 | |
| echo "${INDENT}-Y --iconify iconify window" 1>&2 | |
| echo "${INDENT}-s --switch <DESK> switch to the specified desktop" 1>&2 | |
| echo "${INDENT}-v --verbose be verbose" 1>&2 | |
| echo "${INDENT}-h --help print help" 1>&2 | |
| echo | |
| echo "Arguments:" 1>&2 | |
| echo "${INDENT}<COORDS> position and size of the window" 1>&2 | |
| echo "${INDENT} the format is <X>,<Y>,<W>,<H>" 1>&2 | |
| exit | |
| } | |
| # replace long arguments | |
| if [ $# -gt 0 ] ; then | |
| for index in $(eval echo "{1..${#}}") ; do | |
| for argument in "${!longArguments[@]}" ; do | |
| if [ ${!index} = "--${longArguments[$argument]}" ] ; then | |
| set -- "${@:1:((index - 1))}" "-$argument" "${@:((index + 1)):${#}}" | |
| fi | |
| done | |
| done | |
| fi | |
| # parse arguments | |
| while getopts ${arguments} option; do | |
| case ${option} in | |
| l) listWindows=true ;; | |
| r) windowReference="$OPTARG" ;; | |
| e) windowPosition="$OPTARG" ;; | |
| Y) iconify=true ;; | |
| s) newDesktop="$OPTARG" ;; | |
| v) verbose=true ;; | |
| h) usage ;; | |
| ?) usage | |
| esac | |
| done | |
| # ------------------------------------------------------------------------------ | |
| # Main script | |
| # | |
| # get window info list | |
| windowList=`$gdbusCall.List` | |
| windowList=`echo ${windowList:2:-3}` | |
| #echo $windowList | |
| IFS='}' read -r -a windowsInfo <<< "$windowList" | |
| selectedWindowId='' | |
| # ------------------------------------------------------------------------------ | |
| # get window reference | |
| if [ -n "$windowReference" ] ; then | |
| if [[ $windowReference == "0x"* ]]; then | |
| windowReference=`printf '%d' $windowReference` | |
| fi | |
| for windowInfo in "${windowsInfo[@]}" ; do | |
| if [[ $windowInfo == *"$windowReference"* ]]; then | |
| # echo $windowInfo | |
| selectedWindowId=`echo "$windowInfo" | sed 's/.*"id"://'` | |
| selectedWindowId=`echo "$selectedWindowId" | sed 's/,.*//'` | |
| selectedWwindowIdHex=`printf '%08x' $selectedWindowId` | |
| if [ $verbose = 'true' ] ; then | |
| echo "Window id : $selectedWindowId (0x$selectedWwindowIdHex)" | |
| fi | |
| fi | |
| done | |
| fi | |
| # ------------------------------------------------------------------------------ | |
| # list windows info | |
| if [ $listWindows = 'true' ] ; then | |
| if [ $verbose = 'true' ] ; then | |
| echo "Windows:" | |
| fi | |
| for windowInfo in "${windowsInfo[@]}" ; do | |
| windowInfo=`echo "$windowInfo" | sed 's/]//'` | |
| # echo "$windowInfo" | |
| # workspace | |
| workspaceId=`echo "$windowInfo" | sed 's/.*"workspace"://'` | |
| workspaceId=`echo "$workspaceId" | sed 's/,.*//'` | |
| # application | |
| application=`echo "$windowInfo" | sed 's/.*"wm_class"://'` | |
| application=`echo "$application" | sed 's/,.*//'` | |
| # window title | |
| title=`echo "$windowInfo" | sed 's/.*"title"://'` | |
| title=`echo "$title" | sed 's/,.*//'` | |
| # process id | |
| pid=`echo "$windowInfo" | sed 's/.*"pid"://'` | |
| pid=`echo "$pid" | sed 's/,.*//'` | |
| # window id | |
| windowId=`echo "$windowInfo" | sed 's/.*"id"://'` | |
| windowId=`echo "$windowId" | sed 's/,.*//'` | |
| windowIdHex=`printf '%08x' $windowId` | |
| # focus | |
| focus=`echo "$windowInfo" | sed 's/.*"focus"://'` | |
| focus=`echo "$focus" | sed 's/,.*//'` | |
| # display info | |
| displayInfo='true' | |
| if [ -z "$windowId" ] ; then | |
| displayInfo='false' | |
| fi | |
| if [ -n "$selectedWindowId" ] ; then | |
| if [ "$windowId" != "$selectedWindowId" ] ; then | |
| displayInfo='false' | |
| fi | |
| fi | |
| if [ $verbose = 'true' ] ; then | |
| if [ $displayInfo = 'true' ] ; then | |
| echo "${INDENT}workspace $workspaceId" | |
| echo "${INDENT}application $application" | |
| echo "${INDENT}title $title" | |
| echo "${INDENT}process id $pid" | |
| echo "${INDENT}window id $windowId (0x$windowIdHex)" | |
| echo "${INDENT}focus $focus" | |
| echo | |
| fi | |
| else | |
| if [ $displayInfo = 'true' ] ; then | |
| windowInfo="0x$windowIdHex $workspaceId $application $title" | |
| echo $windowInfo | |
| fi | |
| fi | |
| done | |
| fi | |
| # ------------------------------------------------------------------------------ | |
| # move and resize window | |
| if [ -n "$windowPosition" ] ; then | |
| # echo $windowPosition | |
| if [ -z "$selectedWindowId" ] ; then | |
| echo 'Specify window reference with "-r <REF>"' | |
| exit | |
| fi | |
| IFS=',' read -r -a windowCoordinates <<< "$windowPosition" | |
| if [ "${#windowCoordinates[@]}" -eq 2 ] ; then | |
| windowCoordinates+=(0) | |
| windowCoordinates+=(0) | |
| fi | |
| if [ "${#windowCoordinates[@]}" -ne 4 ] ; then | |
| echo 'The number of coordinates is to be equal to 4' | |
| else | |
| windowX=${windowCoordinates[0]} | |
| windowY=${windowCoordinates[1]} | |
| windowWidth=${windowCoordinates[2]} | |
| windowHeight=${windowCoordinates[3]} | |
| if [ $verbose = 'true' ] ; then | |
| echo "Moving window to [$windowX, $windowY], $windowWidth x $windowHeight" | |
| fi | |
| return=`$gdbusCall.Move $selectedWindowId $windowX $windowY` | |
| if [ "$windowWidth" -ne 0 ] ; then | |
| $gdbusCall.Resize $selectedWindowId $windowWidth $windowHeight > /dev/null | |
| fi | |
| fi | |
| fi | |
| # ------------------------------------------------------------------------------ | |
| # iconify window | |
| if [ $iconify = true ] ; then | |
| if [ -z "$selectedWindowId" ] ; then | |
| echo 'Specify window reference with "-r <REF>"' | |
| exit | |
| fi | |
| if [ $verbose = 'true' ] ; then | |
| echo "Reducing window $selectedWwindowIdHex ($windowReference)" | |
| fi | |
| $gdbusCall.Minimize $selectedWindowId > /dev/null | |
| fi | |
| # ------------------------------------------------------------------------------ | |
| # switch to desktop | |
| if [ -n "$newDesktop" ] ; then | |
| if [ $verbose = 'true' ] ; then | |
| echo "Switching to desktop $newDesktop" | |
| fi | |
| wmctrl -s $newDesktop | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment