#!/usr/bin/env bash
# rofi-windows — window switcher for Window Maker.
#
# Why this exists: rofi's native `-show window` mode drops iconified windows
# under Window Maker (WMaker flags minimized windows HIDDEN+SKIP_PAGER and
# rofi's WM-quirk path mishandles them). This bypasses rofi's EWMH logic and
# drives the list from wmctrl, which lists *every* window including minimized.
#
# Features over the naive `wmctrl -l | rofi -dmenu`:
#   - clean labels (no hex id / desktop / hostname noise)
#   - WMaker internal/dockapp junk (empty-title rows) filtered out
#   - per-app icons from WM_CLASS
#   - most-recently-used order (reverse stacking); current window excluded,
#     so Enter on the default row behaves like Alt-Tab "previous window"
#   - off-desktop windows tagged [->N] / [all] so you know it'll jump you
#   - selection mapped by index, so duplicate titles are never ambiguous
#   - reliable de-iconify via xdotool windowmap + windowactivate

set -uo pipefail

# --- EWMH state --------------------------------------------------------------
raw_active=$(xprop -root _NET_ACTIVE_WINDOW 2>/dev/null | grep -o '0x[0-9a-f]*' | head -1)
active_dec=$(( ${raw_active:-0} ))
cur_desk=$(xprop -root _NET_CURRENT_DESKTOP 2>/dev/null | grep -o '[0-9]*$')
cur_desk=${cur_desk:--999}

# bottom -> top stacking order (fall back to client-list order if absent)
mapfile -t stack < <(xprop -root _NET_CLIENT_LIST_STACKING 2>/dev/null | grep -o '0x[0-9a-f]*')
[ ${#stack[@]} -eq 0 ] && mapfile -t stack < <(wmctrl -l 2>/dev/null | awk '{print $1}')

# --- index window metadata: decimal id -> desk \t class \t host \t title -----
declare -A INFO
while read -r id desk cls host title; do
  INFO[$((id))]=$desk$'\t'$cls$'\t'$host$'\t'$title
done < <(wmctrl -l -x 2>/dev/null)

# --- icon name from WM_CLASS (Papirus theme) ---------------------------------
icon_for() {
  local c=${1##*.}; c=${c,,}
  case $c in
    firefox-esr|navigator)   echo firefox ;;
    thunderbird-default|mail) echo thunderbird ;;
    xfce4-terminal)          echo utilities-terminal ;;
    thunar)                  echo system-file-manager ;;
    '')                      echo applications-other ;;
    *)                       echo "$c" ;;
  esac
}

# --- build parallel arrays (top-of-stack first, skip active + junk) ----------
ids=() labels=() icons=() metas=()
for (( i=${#stack[@]}-1; i>=0; i-- )); do
  dec=$(( ${stack[i]} ))
  (( dec == active_dec )) && continue
  meta=${INFO[$dec]:-}; [ -z "$meta" ] && continue
  IFS=$'\t' read -r desk cls host title <<< "$meta"
  [ -z "$title" ] && continue                  # WMaker internals / dockapps

  tag=""
  if   [ "$desk" = "-1" ];        then tag="[all] "
  elif [ "$desk" != "$cur_desk" ]; then tag="[->$desk] "; fi

  ids+=( "$dec" )
  labels+=( "${tag}${title}    (${cls##*.})" )
  icons+=( "$(icon_for "$cls")" )
  metas+=( "${cls} ${host} ws${desk}" )
done

if [ ${#ids[@]} -eq 0 ]; then
  command -v notify-send >/dev/null && notify-send "rofi-windows" "no other windows"
  exit 0
fi

# --- pick (rofi returns the input index) -------------------------------------
idx=$(
  for j in "${!ids[@]}"; do
    printf '%s\0icon\x1f%s\x1fmeta\x1f%s\n' "${labels[j]}" "${icons[j]}" "${metas[j]}"
  done | rofi -dmenu -i -p Windows -show-icons -no-custom -format i \
              -theme-str 'element-icon { size: 1.4em; }'
)
[[ $idx =~ ^[0-9]+$ ]] || exit 0

target=${ids[$idx]}

# --- raise: de-iconify, switch desktop, focus --------------------------------
xdotool windowmap "$target" 2>/dev/null
xdotool windowactivate "$target" 2>/dev/null \
  || wmctrl -i -a "$(printf '0x%08x' "$target")"
