+#!/bin/busybox ash
+
+padding=10
+
+oct8() {
+ [ $1 -lt 0 ] && int=$(($1 + 256)) || int=$1
+ printf '\\0%s' "$(($1 / 64))$(($1 % 64 / 8))$(($1 % 8))"
+}
+oct16(){
+ [ $1 -lt 0 ] && int=$(($1 + 65536)) || int=$1
+ printf '%s%s' "$(oct8 $(($int / 256)))" \
+ "$(oct8 $(($int % 256)))"
+}
+oct32(){
+ [ $1 -lt 0 ] && int=$(($1 + 4294967296)) || int=$1
+ printf '%s%s' "$(oct16 $(($int / 65536)))" \
+ "$(oct16 $(($int % 65536)))"
+}
+
+if info=$(mktemp -td x11sh.XXXXXX); then
+ info="$info/conninfo"
+ fifo="${info%/*}/fifo"
+ mkfifo "$fifo"
+ trap \
+ '[ -f "$info" -a -p "$fifo" ] && rm "$info" "$fifo" && rmdir "${info%/*}"' \
+ EXIT INT TERM KILL
+else
+ printf 'failed to set up temp dir\n' >&2
+ exit 1
+fi
+
+format_info(){
+ fmt="$1"
+ while [ -n "$fmt" ]; do
+ printf 'Format: depth=%2s bpp=%2s slp=%s\n' \
+ $(( 0x${fmt:0:2} )) $(( 0x${fmt:2:2} )) $(( 0x${fmt:4:2} ))
+ fmt="${fmt:16}"
+ done
+}
+
+screen_info(){
+ scrns="$1"
+ scr="$2"
+
+ while [ $scrns -gt 0 ]; do
+ printf 'Screen: root=%s %sx%s:%s\n' \
+ 0x${scr:0:8} $((0x${scr:40:4})) $((0x${scr:44:4})) $((0x${scr:76:2}))
+ printf 'ROOT=%s\n' $((0x${scr:0:8})) >>"$info"
+ printf 'DEPTH=%s\n' $((0x${scr:76:2})) >>"$info"
+
+ dpths=$((0x${scr:78:2}))
+ dptho=80
+ while [ $dpths -gt 0 ]; do
+ #printf ' depth=%s\n' $((0x${scr:${dptho}:2}))
+ dpthl=$(( 16 + 48 * 0x${scr:$(($dptho + 4)):4} ))
+ dptho=$(($dptho + $dpthl))
+ dpths=$(($dpths - 1))
+ done
+ scrns=$(($scrns - 1))
+ scr="${scr:${dptho}}"
+ done
+}
+
+server_info(){
+ msg="$1"
+
+ vl=$(( 0x${msg:48:4} * 2))
+ vp=$(( (8 - $vl % 8) % 8))
+
+ fmto=$(( $vl + $vp + 80 ))
+ fmtl=$(( 0x${msg:58:2} * 16 ))
+
+ scro=$(( $fmto + $fmtl ))
+
+ printf 'X-Protocol: %s.%s r%s\n' \
+ $(( 0x${msg:4:4} )) $(( 0x${msg:8:4} )) $(( 0x${msg:16:8} ))
+ printf 'RessourceID: 0x%s / 0x%s\n' ${msg:24:8} ${msg:32:8}
+ printf "Vendor: $(printf %s "${msg:80:$vl}" |sed 's;..;\\x&;g')\n"
+ printf "RID=%s\n" $((0x${msg:24:8})) >"$info"
+ format_info "${msg:${fmto}:${fmtl}}"
+ screen_info $((0x${msg:56:2})) "${msg:${scro}}"
+}
+
+event_id(){
+ case $1 in
+ 2) printf KeyPress ;;
+ 3) printf KeyRelease ;;
+ 4) printf ButtonPress ;;
+ 5) printf ButtonRelease ;;
+ 6) printf MotionNotify ;;
+ 7) printf EnterNotify ;;
+ 8) printf LeaveNotify ;;
+ 9) printf FocusIn ;;
+ 10) printf FocusOut ;;
+ 11) printf KeymapNotify ;;
+ 12) printf Expose ;;
+ 15) printf VisibilityNotify ;;
+ 19) printf MapNotify ;;
+ 28) printf PropertyNotify ;;
+ *) printf ' %s ' "$1" ;;
+ esac
+}
+
+op_id(){
+ case $1 in
+ 1) printf CreateWindow ;;
+ 2) printf ChangeWindow ;;
+ 8) printf MapWindow ;;
+ 55) printf CreateGC ;;
+ 56) printf ChangeGC ;;
+ *) printf ' %s ' "$1" ;;
+ esac
+}
+
+error_id(){
+ case $1 in
+ 1) printf Request ;;
+ 2) printf Value ;;
+ 3) printf Window ;;
+ 4) printf Pixmap ;;
+ 5) printf Atom ;;
+ 6) printf Cursor ;;
+ 7) printf Font ;;
+ 8) printf Match ;;
+ 9) printf Drawable ;;
+ 10) printf Access ;;
+ 11) printf Alloc ;;
+ 12) printf ColorMap ;;
+ 13) printf GContext ;;
+ 14) printf IDChoice ;;
+ 15) printf Name ;;
+ 16) printf Length ;;
+ 17) printf Implementation ;;
+ *) printf ' %s ' "$1" ;;
+ esac
+}
+
+text_render(){
+ widget="$1" gc="$2"
+ x="$3"; y="$4"; text="$5"
+ l=${#text}
+ while [ $(( ${#text} % 4 )) -gt 0 ]; do
+ text="${text}~"
+ done
+
+ printf '\\0114%s%s%s%s%s%s%s' \
+ $(oct8 $l) $(oct16 $((4 + ${#text} / 4))) \
+ "$widget" "$gc" $(oct16 $x) $(oct16 $y) \
+ "${text}"
+}
+
+case $DISPLAY in
+ '')
+ printf 'No DISPLAY variable, no server to connect to\n' >&2
+ exit 1;;
+ :[0-9]*)
+ unix=${DISPLAY#:}
+ unix="/tmp/.X11-unix/X${unix%.*}"
+ [ -S "$unix" ] || {
+ printf 'could not connect to server at %s\n' "$unix" >&2
+ exit 1
+ };;
+ *:[0-9]*)
+ host=${DISPLAY%:*}
+ port=${DISPLAY#*:}
+ port=$((6000 + ${port%.*}))
+ ;;
+esac
+
+widget(){
+ def="${1##* }"
+ printf '%s' "$(oct32 ${def%%:*})"
+}
+
+set_direction(){
+ stack="${1%:*}"
+ direction="$2"
+ printf '%s:%s%s' "$stack" "$direction" "$padding"
+}
+
+resize(){
+ cstack="$1"; widget="$2"; nw="$3"; nh="$4";
+ if [ "$(widget "$widget")" = "$(widget "$cstack")" ]; then
+ # never resize containers
+ printf '%s %s' "$widget" "$cstack"
+ else
+ dim="${widget#*:}"; dim="${dim%:*}"
+ cw="${dim%x*}"; ch="${dim#*x}"
+ case $nw in
+ +*) nw=$(($cw + ${nw#+}));;
+ -*) nw=$(($cw - ${nw#-}));;
+ esac
+ case $nh in
+ +*) nh=$(($ch + ${nh#+}));;
+ -*) nh=$(($ch - ${nh#-}));;
+ esac
+
+ offset=${cstack##*[NEMWS]}
+ case ${cstack##* } in
+ *[WE]*) no=$(($offset - $cw - $padding));;
+ *[NS]*) no=$(($offset - $ch - $padding));;
+ *M*) no=${padding};;
+ esac
+
+ read nx ny g cstack <<-EOF
+ $(position $nw $nh ${cstack%$offset}${no})
+ EOF
+
+ mapmsg="\\0014~\\0000\\0007$(oct32 ${widget%%:*})\\0000\\0017\\0000\\0000$(oct32 $nx)$(oct32 $ny)$(oct32 $nw)$(oct32 $nh)"
+ printf '%s %s:%sx%s:%s %s' "$mapmsg" \
+ ${widget%%:*} $nw $nh ${widget##*:} "$cstack"
+ fi
+}
+
+position(){
+ w="$1" h="$2"
+ def="${3##* }"
+ stack="${3% *}"
+ container="${def%%:*}"
+ meta="${def#*:}"
+ dir="${meta#*:}"; dir="${dir%%[0-9]*}"
+ offset="${meta##*[NEMWS]}"
+ dim="${meta%:*}"
+ cw="${dim%x*}"; ch="${dim#*x}"
+
+ [ "$stack" = "$def" ] && stack='' || stack="$stack "
+
+ case $def in
+ *NW*)
+ y="$padding"
+ x="$offset"
+ offset="$(( $offset + $w + $padding))"
+ grav=1
+ ;;
+ *NE*)
+ y="$padding"
+ x="$(( $cw - $offset - $w))"
+ offset="$(( $offset + $w + $padding))"
+ grav=3
+ ;;
+ *N*)
+ y="$offset"
+ x="$(( $cw / 2 - $w / 2))"
+ offset="$(( $offset + $h + $padding))"
+ grav=2
+ ;;
+ *SW*)
+ y="$(( $ch - $padding - $h ))"
+ x="$offset"
+ offset="$(( $offset + $w + $padding))"
+ grav=7
+ ;;
+ *SE*)
+ y="$(( $ch - $padding - $h ))"
+ x="$(( $cw - $offset - $w ))"
+ offset="$(( $offset + $w + $padding))"
+ grav=9
+ ;;
+ *S*)
+ y="$(( $ch - $offset - $h ))"
+ x="$(( $cw / 2 - $w / 2 ))"
+ offset="$(( $offset + $h + $padding))"
+ grav=8
+ ;;
+ *W*)
+ y=$(( $ch / 2 - $h / 2))
+ x="$offset"
+ offset="$(( $offset + $w + $padding))"
+ grav=4
+ ;;
+ *M*)
+ y=$(( $ch / 2 - $h / 2))
+ x="$(( $cw / 2 - $w / 2 ))"
+ grav=5
+ ;;
+ *E*)
+ y=$(( $ch / 2 - $h / 2))
+ x="$(( $cw - $offset - $w ))"
+ offset="$(( $offset + $w + $padding))"
+ grav=6
+ ;;
+ esac
+
+ printf '%s %s %s %s%s:%sx%s:%s%s' "$x" "$y" "$grav" \
+ "$stack" "$container" "$cw" "$ch" "$dir" "$offset"
+}
+
+rid=0
+replay=''
+msg=''
+
+{ printf 'B~\000\013\000\000\000\000\000\000~~'
+ while ! grep -q DEPTH "$info"; do
+ sleep 1
+ done
+ . "$info"
+ ROOT=$(oct32 $ROOT)
+
+ rid=$(($rid + 1))
+ gc="$(oct32 $(( $RID + $rid)))"
+ printf '\067~\000\004%b%b\000\000\000\000' ${gc} ${ROOT}
+ replay="\070~\000\005${gc}\000\000\000\014"
+ replay="${replay}\000\000\000\000"
+ replay="${replay}\000\377\377\377"
+ printf %b "$replay"
+
+ while read -r cmd p1 p2 p3 p4; do
+ case "$cmd" in
+ env)
+ env >&2;;
+ dir*)
+ cstack=$(set_direction "$cstack" "$p1")
+ ;;
+ win*)
+ rid=$(($rid + 1))
+ win="$(( $RID + $rid))"
+ w=${p1:-100}
+ h=${p2:-100}
+
+ printf '\001\000\000\013%b%b%b%b%b%b\000\000\000\001\000\000\000\000\000\000\010\102%b%b%b' \
+ $(oct32 ${win}) ${ROOT} \
+ $(oct16 10) $(oct16 10) \
+ $(oct16 ${w}) $(oct16 ${h}) \
+ '\x00\xff\xff\xff' '\000\000\000\002' \
+ '\000\000\200\000'
+ mapmsg="${mapmsg}\\0010~\\0000\\0002$(oct32 ${win})"
+ widget="${win}:${w}x${h}:NW10"
+ cstack="${cstack:+$cstack }${widget}"
+ ;;
+ btn*|button*)
+ rid=$(($rid + 1))
+ btn="$(( $RID + $rid))"
+ text="${p1}${p2:+ $p2}${p3:+ $p3}${p4:+ $p4}"
+ w=$((2 * $padding)); h=16
+ read x y grav cstack <<-EOF
+ $(position "$w" "$h" "$cstack")
+ EOF
+ printf '\001\000\000\015%b%b%b%b%b%b\000\001\000\001\000\000\000\000\000\000\010\152%b%b%b%b%b' \
+ $(oct32 ${btn}) $(widget "${cstack}") \
+ $(oct16 $x) $(oct16 $y) \
+ $(oct16 $w) $(oct16 $h) \
+ '\000\377\377\377' '\000\000\000\000' \
+ $(oct32 $grav) '\000\000\000\002' \
+ '\000\000\000\014'
+ mapmsg="${mapmsg}\\0010~\\0000\\0002$(oct32 ${btn})"
+ widget="${btn}:${w}x${h}:W10"
+ ;;
+ col*)
+ msg="\070~\000\004${gc}\000\000\000\004$(oct32 $((0x${p1})))"
+ ;;
+ bg*|back*)
+ msg="\070~\000\004${gc}\000\000\000\010$(oct32 $((0x${p1})))"
+ ;;
+ text*)
+ text="${p1}${p2:+ $p2}${p3:+ $p3}${p4:+ $p4}"
+ read x y grav widget <<-EOF
+ $(position $((6 * ${#text})) 8 "$widget")
+ EOF
+
+ read -r mm widget cstack <<-EOF
+ $(resize "$cstack" "$widget" +$((6 * ${#text})) +0)
+ EOF
+
+ mapmsg="${mm}${mapmsg}"
+
+ msg="$(
+ text_render "$(widget $widget)" "$gc" \
+ $x $(($y + 8)) "$text"
+ )"
+ ;;
+ font*)
+ spec="$p1"
+ l=${#spec}
+ while [ $(( ${#spec} % 4 )) -gt 0 ]; do spec="${spec}~"; done
+ rid=$(($rid + 1))
+ font="$(oct32 $(( $RID + $rid)))"
+ printf '\055~%b%b%b~~%b' $(oct16 $((3 + ${#spec} / 4))) \
+ ${font} $(oct16 $l) "$spec"
+ msg="\070~\000\004${gc}\000\000\040\000${font}"
+ ;;
+ stroke*)
+ msg="\070~\000\006${gc}\000\000\000\160"
+ msg="${msg}$(oct32 ${p1:-1})$(oct32 ${p2:-0})$(oct32 ${p3:-2})"
+ ;;
+ line*)
+ d="$(widget $widget)"
+ msg="\101\000\000\005${d}${gc}"
+ msg="${msg}$(oct16 ${p1:-0})$(oct16 ${p2:-0})"
+ msg="${msg}$(oct16 ${p3:-0})$(oct16 ${p4:-0})"
+ ;;
+ *) printf %b "$cmd"
+ ;;
+ esac
+ if [ -n "${msg}" ]; then
+ printf %b "$msg"
+ replay="${replay}${msg}"
+ msg=''
+ fi
+ done
+
+ printf %b "$mapmsg"
+
+ while true; do
+ read -r cmd <"$fifo"
+ case $cmd in
+ redraw*)
+ printf %b "${replay}"
+ ;;
+ quit*) exit 0
+ ;;
+ *) printf %b "$cmd"
+ ;;
+ esac
+ done
+} \
+| if [ -n "$unix" ]; then
+ stdbuf -o0 ncat -U "$unix" || {
+ printf 'Cannot connect to %s\n' "$unix" >&2
+ exit 1
+ }
+else
+ stdbuf -o0 ncat "$host" "$port" || {
+ printf 'Cannot connect to %s:%s\n' "$host" "$port" >&2
+ exit 1
+ }
+fi \
+| stdbuf -o0 hexdump -ve '/1 "%02x"' \
+| while read -n16 msg; do
+ case "$msg" in
+ 0[2-9a-f]*|[1-9a-f]*) # Events, will be the most frequent match, handled below
+ read -n48 app
+ msg="${msg}${app}"
+ ;;
+ 00*) # Error messages
+ read -n48 app
+ msg="${msg}${app}"
+ printf 'Error (%s): seq=%s op=%s( %s ) info=%s\n' \
+ $(error_id $((0x${msg:2:2})) ) $((0x${msg:4:4})) \
+ $(op_id $((0x${msg:20:2})) ) $((0x${msg:16:4})) \
+ $((0x${msg:8:8}))
+ ;;
+ 01??000b0000*) # Connection initialisation, very first server reply
+ l=$((0x${msg:12:4} * 8))
+ read -n$l app
+ msg="${msg}${app}"
+ server_info "$msg"
+ . "$info"
+ ;;
+ 01*) # Reply to request
+ l=$((48 + 0x${msg:8} * 8))
+ read -n$l app
+ msg="${msg}${app}"
+ printf 'Reply:\n%s\n' "$msg"
+ printf "[$(printf "$msg" |sed 's;..;\\x&;g')]\n"
+ ;;
+ esac
+ case "$msg" in
+ 0[2-8]*)
+ printf 'Event (%s): %s %sx%s widget=%s\n' \
+ $(event_id $((0x${msg:0:2}))) $((0x${msg:2:2})) \
+ $((0x${msg:48:4})) $((0x${msg:52:4})) \
+ $((0x${msg:24:8} - $RID))
+ ;;
+ 0[9a]*)
+ printf 'Event (%s)\n' $(event_id $((0x${msg:0:2})))
+ ;;
+ 0b*)
+ printf 'Event (%s):' $(event_id $((0x${msg:0:2})))
+ for n in $(seq 2 2 62); do
+ printf ' %s' $(( 0x${msg:$n:2} ))
+ done
+ printf '\n'
+ ;;
+ 0c*) # Expose Event
+ [ "${msg:32:4}" = 0000 ] \
+ && printf 'redraw\n' >"$fifo"
+ ;;
+ 0[2-9a-f]*|[1-9a-f]*)
+ printf 'Event (%s):\n%s\n' $(event_id $((0x${msg:0:2}))) "$msg"
+ ;;
+ esac
+done