Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Resize x11vnc session

Here's a cool trick I devised. This idea is original to me. I remember using spice guest tools in spice guests in libvirt/qemu/kvm/virt-manager to automatically (or at least make available) change screen resolutions.

Remmina as a vnc viewer of course can be resized, and I have a script that I run on the client side, to ssh to the target x11vnc server.

The idea is that on the client x11 instance, you run the following command which finds the window with that hostname as the title (hardcoded to only Remmina windows), and then passwordlessly sshes to that host and uses the XAUTHORITY and DISPLAY info to add a xrandr resolution to this desired window size and then uses that resolution.

files/2024/listings/set-x11vnc-resolution.sh (Source)

#/bin/sh
# File: set-x11vnc-resolution.sh
# Location: /mnt/public/Support/Programs/vnc/
# Author: bgstack15
# Startdate: 2024-08-15-5 13:09
# SPDX-License-Identifier: GPL-3.0-only
# Title: Resize x11vnc server in a vnc client window
# Purpose: Simplify resizing remmina vnc window
# History:
# Usage: run on client side
# Reference:
#    https://unix.stackexchange.com/questions/14159/how-do-i-find-the-window-dimensions-and-position-accurately-including-decoration/14170#14170
#    https://stackoverflow.com/questions/15816/changing-the-resolution-of-a-vnc-session-in-linux
#    https://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced
# Improve:
#    This does not handle any other wm than fluxbox, or client other than remmina
# Dependencies:
#    client: kerberos ticket for ssh to x11vnc server, xwininfo, xdotool,
#    server: /mnt/public/Support/Platforms/devuan/scripts/enable-remote-desktop.sh, xrandr, cvt, fbsetbg
# Documentation:
#    For consistent dpi across custom resolutions, use /etc/X11/Xresources/vnc-dpi contents `Xft.dpi: 96`
_get_geometry() {
   #_id="${_id:-"$( xdotool getactivewindow )"}"
   _id="${_id:-${1}}"
   test -z "${_id}" && return 1
   unset x y w h
      eval $( xwininfo -id "${_id}" | \
      sed -n -e "s/^ \+Absolute upper-left X: \+\([0-9]\+\).*/x=\1/p" \
         -e "s/^ \+Absolute upper-left Y: \+\([0-9]\+\).*/y=\1/p" \
         -e "s/^ \+Width: \+\([0-9]\+\).*/w=\1/p" \
         -e "s/^ \+Height: \+\([0-9]\+\).*/h=\1/p" )
   #printf '%s\n' "${x} ${y} ${w} ${h}"
   # my fluxbox theme uses 35,47 offset to the first pixel of the x11 server in remmina
   # 38, 32
   # I think these numbers cannot get precise. 45 is fairly close and seems to avoid scrollbars.
   echo "_w=$(( w - 45 ))"
   echo "_h=$(( h - 45 ))"
}
_get_important_window() {
   # You might be tempted to let the user click a window, however, it would be painful to guarantee you can learn the correct target host. The titlebar might have the vncserver name, or not. We should just make vncserver required.
   # FUTUREIMPROVEMENT
   # I only use remmina but that might change.
   # return window id
   xwininfo -root -tree | awk "\$0 ~ /${vncserver}/ && /remmina/ && "'!'"/awk/ {print \$1}"
}
_connect_and_add_resolution() {
   # we know we always run x11vnc from script /mnt/public/Support/Platforms/devuan/enable-remote-desktop.sh
   # which uses env vars XAUTHORITY=/tmp/:0 DISPLAY=:0
   # but let us parse in case that ever changes.
   # this ssh depends on kerberos or other passwordless operation
   ssh "${vncserver}" /bin/sh ${VERBOSE:+-x} <<-EOF
   _i="\$( ps -e -o command:180 | grep -E '[x]11vnc' )"
   export XAUTHORITY="\$( echo "\${_i}" | xargs -n1 | awk '/-auth/{getline;print;}' )"
   export DISPLAY="\$( echo "\${_i}" | xargs -n1 | awk '/-display/{getline;print;}' )"
   #xrandr | awk "/${_w}x${_h}/" | grep -qE . && exit 0
   _connected="\$( xrandr | awk '/ connected/{print \$1}' )"
   export _newmode="\$( cvt "${_w}" "${_h}" | awk '{\$1="";print}' | tr -d '"' | tail -n1 )"
   export _newmodename="\$( echo "\${_newmode}" | awk '{print \$1}' )"
   xrandr --newmode \${_newmode} 2>&1 | grep -vE 'of failed request|Current serial number' | grep -e '.'
   xrandr --addmode "\${_connected}" \${_newmodename}
   xrandr -s \${_newmodename}
   # common wallpaper command for stackrpms
   fbsetbg -a /etc/wallpaper
EOF
   # thankfully the XAUTHORITY and DISPLAY lets us run fbsetbg, so we do not need this.
   # get user of root. thankfully we always use fluxbox.
   #_u="\$( ps -ef | awk '\$NF~/[f]luxbox/{print \$1}' )"
}
# BEGIN IF-DOT-SOURCED
sourced=0
if [ -n "$ZSH_VERSION" ]; then
  case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
elif [ -n "$KSH_VERSION" ]; then
  [ "$(cd -- "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd -- "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ] && sourced=1
elif [ -n "$BASH_VERSION" ]; then
  (return 0 2>/dev/null) && sourced=1
else # All other shells: examine $0 for known shell binary filenames.
  # Detects `sh` and `dash`; add additional shell filenames as needed.
  case ${0##*/} in sh|-sh|dash|-dash) sourced=1;; esac
fi
# END IF-DOT-SOURCED
# MAIN
if test "${sourced}" = "0" ;
then
   vncserver="${vncserver:-${1}}"
   test -z "${vncserver}" && { echo "Fatal! Set vncserver to run ${0}. Aborted." 1>&2 ; return 1 ; }
   _id="$( _get_important_window )"
   eval $( _get_geometry "${_id}" )
   echo "working with w=${_w}, h=${_h}"
   _connect_and_add_resolution
fi

It works for me, and that's what software is for. You're welcome to use it too if you're so inclined.

References

  1. command line - How do I find the window dimensions and position accurately including decorations? - Unix & Linux Stack Exchange
  2. Changing the resolution of a VNC session in linux - Stack Overflow
  3. bash - How to detect if a script is being sourced - Stack Overflow

Comments