Skip to content

Instantly share code, notes, and snippets.

@fcorthay
Last active September 12, 2026 13:25
Show Gist options
  • Select an option

  • Save fcorthay/cac6c56ba61adfd76bb0cc8ebcb26150 to your computer and use it in GitHub Desktop.

Select an option

Save fcorthay/cac6c56ba61adfd76bb0cc8ebcb26150 to your computer and use it in GitHub Desktop.
A Wayland partial replacement of "wmctrl"
#!/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