foxygit / sxbar Log in
commits tags

/scripts/taskbar.sh · 3.18 KB

raw
#!/bin/sh
# taskbar module -- one clickable entry per window on the current
# workspace, so you can switch focus between them (e.g. sxwm's monocle
# mode only shows one window at a time; this is how you reach the rest).
# Needs wmctrl, and a window manager that actually acts on a
# _NET_ACTIVE_WINDOW client message (as of this writing, that means a
# patched sxwm -- see the "workspace icons"-adjacent commit/PR that adds
# a _NET_ACTIVE_WINDOW handler to hdl_client_msg()).
#   taskbar.sh list [x,y,w,h ...]
#                       -> internal listing, read fresh every refresh
#                          interval -- not meant to be run by hand. sxbar
#                          passes one "x,y,w,h" geometry per monitor
#                          (Xinerama order); this is how the list gets a
#                          monitor tag per window without sxbar itself
#                          having to peek at window geometry. One line per
#                          current-workspace window:
#                          "Title" : "0xWINDOW_ID" : "command" : monitor
#   taskbar.sh focus ID -> activates/raises that window (bar click action)
#
# No `menu` case: unlike every other built-in module, taskbar renders its
# entries directly in the bar itself (see README/wiki), not a hover popup,
# so there's nothing for `<script> menu` to declare -- explicitly a no-op
# below rather than falling through to the listing logic.
mode="${1:-list}"

case "$mode" in
menu)
	exit 0
	;;
focus)
	wmctrl -i -a "$2" 2>/dev/null
	;;
list)
	self="$0"
	[ $# -gt 0 ] && shift
	cur=$(wmctrl -d 2>/dev/null | awk '$2 == "*" { print $1 }')
	[ -z "$cur" ] && exit 0
	wmctrl -lG 2>/dev/null | awk -v cur="$cur" -v self="$self" -v geoms="$*" '
		BEGIN { ngeom = split(geoms, garr, " ") }
		# which monitor (0-based, matching sxbar geometry-arg order)
		# contains window position (wx, wy). -1 only when sxbar gave us no
		# geometries at all (e.g. a custom script not yet updated for this
		# arg) -- that is the "show on every bar" sentinel. If geometries
		# *were* given but wx,wy falls outside all of them (a floating
		# window dragged past the edge of every monitor, a stale position
		# from a since-changed monitor layout, etc.), fall back to
		# whichever monitor centre is nearest, so every window still lands
		# on exactly one bar instead of every bar.
		function monitor_of(wx, wy,    i, n, mx, my, mw, mh, best, bestd, cx, cy, dx, dy, d) {
			if (ngeom == 0)
				return -1
			for (i = 1; i <= ngeom; i++) {
				n = split(garr[i], g, ",")
				if (n != 4)
					continue
				mx = g[1]; my = g[2]; mw = g[3]; mh = g[4]
				if (wx >= mx && wx < mx + mw && wy >= my && wy < my + mh)
					return i - 1
			}
			best = -1
			for (i = 1; i <= ngeom; i++) {
				n = split(garr[i], g, ",")
				if (n != 4)
					continue
				mx = g[1]; my = g[2]; mw = g[3]; mh = g[4]
				cx = mx + mw / 2; cy = my + mh / 2
				dx = wx - cx; dy = wy - cy
				d = dx * dx + dy * dy
				if (best == -1 || d < bestd) { best = i - 1; bestd = d }
			}
			return best
		}
		$2 == cur {
			id = $1
			mon = monitor_of($3, $4)
			title = $0
			sub(/^([^ \t]+[ \t]+){7}/, "", title)
			gsub(/"/, "'"'"'", title)
			printf "\"%s\" : \"%s\" : \"%s focus %s\" : %d\n", title, id, self, id, mon
		}'
	;;
esac