Last active
September 22, 2025 17:18
-
-
Save Cdaprod/cb8ee6eaded70a7df6d808093c9df2a3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Autostart tiler: Chromium (LEFT -> $URL) + terminal (RIGHT -> tmux attach to "recent" + optional follow-up) | |
| # - If a tmux session exists, attach to the most-recent one by default. | |
| # - Optionally inject a FOLLOWUP_CMD into that tmux session as a new window or split. | |
| # - Falls back to plain shell if no tmux sessions exist. | |
| # - Preserves your original tiling logic. | |
| set -euo pipefail | |
| # ---------------- config ---------------- | |
| URL="https:app.cdaprod.dev/login" | |
| TERM_TITLE="DeskAuto Tmux" | |
| MAX_TRIES=60 | |
| # ── tmux attach policy ──────────────────────────────────────────────────────── | |
| # TMUX_SESSION: | |
| # "recent" → attach to most recently used session (auto-detected) | |
| # "<name>" → attach to this named session if it exists, else fallback to shell | |
| TMUX_SESSION="recent" | |
| # FOLLOW-UP behavior (runs *inside* tmux if we attach, otherwise in the same shell): | |
| # "tmux:new-window" → create a new tmux window running FOLLOWUP_CMD | |
| # "tmux:split-h" → split horizontally and run FOLLOWUP_CMD | |
| # "tmux:split-v" → split vertically and run FOLLOWUP_CMD | |
| # "shell:sequential" → run AFTER initial command in the same shell | |
| # "off" → do nothing extra | |
| FOLLOWUP_MODE="tmux:new-window" | |
| # Your follow-up command (examples): | |
| FOLLOWUP_CMD="ssh [email protected] 'z that && sleep 10 && dcl -f'" | |
| # FOLLOWUP_CMD="ssh [email protected] 'journalctl -fu capture-daemon'" | |
| # FOLLOWUP_CMD="echo 'No follow-up set'; sleep 1" | |
| # ----------------------------------------------------------------------------- | |
| # --- auto-detach when launched from a TTY (manual run) --- | |
| if [ -t 1 ] && [ "${DESKAUTO_FORKED:-0}" != "1" ]; then | |
| exec setsid -f env DESKAUTO_FORKED=1 "$0" "$@" > /tmp/desk-autostart.log 2>&1 | |
| fi | |
| need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing: $1" >&2; exit 1; }; } | |
| for b in xdotool wmctrl xrandr xwininfo xprop; do need "$b"; done | |
| export DISPLAY="${DISPLAY:-:0}" | |
| # ---- pick browser ---- | |
| CHROMIUM_BIN="$(command -v chromium-browser || true)"; [ -z "$CHROMIUM_BIN" ] && CHROMIUM_BIN="$(command -v chromium || true)" | |
| [ -n "$CHROMIUM_BIN" ] || { echo "Chromium not found"; exit 1; } | |
| # ---- pick terminal ---- | |
| TERM_BIN="$(command -v lxterminal || true)" | |
| if [ -z "$TERM_BIN" ]; then TERM_BIN="$(command -v xfce4-terminal || true)"; fi | |
| [ -n "$TERM_BIN" ] || { echo "No terminal found (need lxterminal or xfce4-terminal)"; exit 1; } | |
| # ---- helpers ---- | |
| find_win() { xdotool search --onlyvisible --name "$1" 2>/dev/null | head -n1 || true; } | |
| recent_tmux_session() { | |
| # Returns the most recently attached tmux session name, or empty if none. | |
| tmux ls -F '#{session_last_attached} #{session_name}' 2>/dev/null \ | |
| | sort -nr \ | |
| | awk 'NR==1{print $2}' | |
| } | |
| resolve_tmux_target() { | |
| local target="${1:-recent}" | |
| if [ "$target" = "recent" ]; then | |
| recent_tmux_session || true | |
| else | |
| echo "$target" | |
| fi | |
| } | |
| tmux_has_session() { | |
| local name="$1" | |
| [ -n "$name" ] || return 1 | |
| tmux has-session -t "$name" 2>/dev/null | |
| } | |
| # ---- (re)use existing windows if they already exist ---- | |
| CHROM_WIN="$(find_win 'Chromium' || true)" | |
| if [ -z "$CHROM_WIN" ]; then | |
| "$CHROMIUM_BIN" --new-window "$URL" --no-first-run --no-default-browser-check \ | |
| --window-size=640,480 --window-position=10,10 >/dev/null 2>&1 & | |
| CHROM_PID=$! | |
| else | |
| CHROM_PID="" | |
| fi | |
| # ── Compose the terminal command ------------------------------------------------ | |
| # INITIAL: attach to tmux "recent" (or named). If no tmux, fall back to login shell. | |
| generate_terminal_exec() { | |
| local target session attach_cmd run_follow="" | |
| session="$(resolve_tmux_target "$TMUX_SESSION")" | |
| if tmux_has_session "$session"; then | |
| attach_cmd="tmux attach -t \"$session\"" | |
| case "$FOLLOWUP_MODE" in | |
| tmux:new-window) | |
| run_follow="tmux new-window -t \"$session\" -n 'AutoCmd' bash -lc $(printf "%q" "$FOLLOWUP_CMD")" | |
| ;; | |
| tmux:split-h) | |
| run_follow="tmux split-window -t \"$session\" -h bash -lc $(printf "%q" "$FOLLOWUP_CMD")" | |
| ;; | |
| tmux:split-v) | |
| run_follow="tmux split-window -t \"$session\" -v bash -lc $(printf "%q" "$FOLLOWUP_CMD")" | |
| ;; | |
| shell:sequential) | |
| # Will run after attach *only when attach fails* (otherwise attach takes control); | |
| # not very useful for tmux, so warn into log and skip. | |
| run_follow="echo '[desk-autostart] FOLLOWUP_MODE shell:sequential is ignored when attaching to tmux'; true" | |
| ;; | |
| off|*) | |
| run_follow="" | |
| ;; | |
| esac | |
| if [ -n "$run_follow" ]; then | |
| # Pre-seed the follow-up inside tmux *before* attaching, so it's visible after attach | |
| echo "bash -lc \"$run_follow; $attach_cmd || exec bash -l\"" | |
| else | |
| echo "bash -lc \"$attach_cmd || exec bash -l\"" | |
| fi | |
| else | |
| # No tmux session available → plain shell path | |
| if [ "$FOLLOWUP_MODE" = "shell:sequential" ]; then | |
| echo "bash -lc \"$FOLLOWUP_CMD; exec bash -l\"" | |
| else | |
| echo "bash -lc \"exec bash -l\"" | |
| fi | |
| fi | |
| } | |
| TERM_CMD="$(generate_terminal_exec)" | |
| # Launch terminal | |
| if [[ "$TERM_BIN" =~ xfce4-terminal$ ]]; then | |
| "$TERM_BIN" --title "$TERM_TITLE" -e "$TERM_CMD" >/dev/null 2>&1 & | |
| else | |
| lxterminal -T "$TERM_TITLE" -e "$TERM_CMD" >/dev/null 2>&1 & | |
| fi | |
| TERM_PID=$! | |
| # ---- wait helpers ---- | |
| wait_for_pid_win() { | |
| local pid="$1" label="$2" tries=200 | |
| [ -z "$pid" ] && return 0 | |
| for _ in $(seq 1 $tries); do | |
| for w in $(xdotool search --onlyvisible --pid "$pid" 2>/dev/null || true); do | |
| xwininfo -id "$w" >/dev/null 2>&1 && echo "$w" && return 0 | |
| done | |
| sleep 0.07 | |
| done | |
| echo "Timed out waiting for $label (pid=$pid)" >&2 | |
| return 1 | |
| } | |
| # resolve window IDs | |
| [ -z "$CHROM_WIN" ] && CHROM_WIN="$(wait_for_pid_win "$CHROM_PID" Chromium || true)" | |
| [ -z "$CHROM_WIN" ] && CHROM_WIN="$(find_win 'Chromium' || true)" | |
| TERM_WIN="$(wait_for_pid_win "$TERM_PID" Terminal || true)" | |
| [ -z "$TERM_WIN" ] && TERM_WIN="$(find_win "$TERM_TITLE" || true)" | |
| [ -n "${CHROM_WIN:-}" ] && [ -n "${TERM_WIN:-}" ] || { echo "Could not resolve window IDs"; exit 0; } | |
| # ---- compute WORKAREA (excludes panels) ---- | |
| read -r WA_X WA_Y WA_W WA_H < <(xprop -root _NET_WORKAREA | awk -F'= ' '{print $2}' | tr ',' ' ' | awk '{print $1,$2,$3,$4}') | |
| if [ -z "${WA_W:-}" ] || [ -z "${WA_H:-}" ]; then | |
| read -r _ _ WA_W WA_H < <(xrandr --query | awk '/ connected primary /{print "0 0 "$3}' | sed 's/[x+]/ /g' | head -n1) | |
| WA_X=0; WA_Y=0 | |
| fi | |
| L_X=$WA_X; L_Y=$WA_Y; L_W=$(( WA_W / 2 )); L_H=$WA_H | |
| R_X=$(( WA_X+L_W )); R_Y=$WA_Y; R_W=$(( WA_W - L_W )); R_H=$WA_H | |
| # ---- normalize & enforce geometry (bounded retries) ---- | |
| normalize() { wmctrl -ir "$1" -b remove,fullscreen,maximized_vert,maximized_horz,hidden,shaded,below || true; } | |
| normalize "$CHROM_WIN"; normalize "$TERM_WIN"; sleep 0.1 | |
| apply() { | |
| local wid="$1" x="$2" y="$3" w="$4" h="$5" | |
| wmctrl -ir "$wid" -e 0,"$x","$y","$w","$h" 2>/dev/null || true | |
| } | |
| ok_after() { | |
| local wid="$1" w="$2" h="$3" | |
| read -r _ _ AW AH < <(xwininfo -id "$wid" | awk '/Width:/ {w=$2} /Height:/ {h=$2} END {print 0,0,w,h}') | |
| [ -n "${AW:-}" ] && [ -n "${AH:-}" ] && [ "$AW" -ge $((w-2)) ] && [ "$AH" -ge $((h-2)) ] | |
| } | |
| wmctrl -ir "$CHROM_WIN" -b add,above || true | |
| wmctrl -ir "$TERM_WIN" -b add,above || true | |
| for _ in $(seq 1 "$MAX_TRIES"); do | |
| apply "$CHROM_WIN" "$L_X" "$L_Y" "$L_W" "$L_H" | |
| apply "$TERM_WIN" "$R_X" "$R_Y" "$R_W" "$R_H" | |
| ok_after "$CHROM_WIN" "$L_W" "$L_H" && ok_after "$TERM_WIN" "$R_W" "$R_H" && break | |
| sleep 0.05 | |
| done | |
| wmctrl -ir "$CHROM_WIN" -b remove,above || true | |
| wmctrl -ir "$TERM_WIN" -b remove,above || true | |
| wmctrl -ia "$TERM_WIN" || true | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment