#!/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