#!/usr/bin/env bash

# Supervise the instantWM X11 process so it can restart without ending the
# display-manager session (and therefore without closing X11 applications).

RTD=""
if command -v instantruntimedir >/dev/null 2>&1; then
    RTD="$(instantruntimedir 2>/dev/null || true)"
fi
if [[ -z "$RTD" ]]; then
    if [[ -n "${XDG_RUNTIME_DIR:-}" ]]; then
        RTD="$XDG_RUNTIME_DIR/instantos"
    else
        RTD="/tmp/instantos-${UID}"
    fi
fi

mkdir -p "$RTD" "$HOME/.local/share"
RUNNING_FILE="$RTD/instantosrunning"
PID_FILE="$RTD/wmpid"
OVERRIDE_FILE="$RTD/wmoverride"
LOG_FILE="$HOME/.local/share/instantos.log"
WMPID=""
REAPPLY_PID=""
FIRST_START=true
SESSION_AUTOSTART="${INSTANTWM_AUTOSTART:-1}"

touch "$RUNNING_FILE"

stop_session() {
    rm -f "$RUNNING_FILE" "$PID_FILE"
    if [[ -n "$WMPID" ]] && kill -0 "$WMPID" 2>/dev/null; then
        kill "$WMPID" 2>/dev/null || true
        wait "$WMPID" 2>/dev/null || true
    fi
    if [[ -n "$REAPPLY_PID" ]] && kill -0 "$REAPPLY_PID" 2>/dev/null; then
        kill "$REAPPLY_PID" 2>/dev/null || true
    fi
    exit 0
}
trap stop_session HUP INT TERM

wm_ipc_socket() {
    if [[ -n "${INSTANTWM_SOCKET:-}" ]]; then
        printf '%s\n' "$INSTANTWM_SOCKET"
    else
        printf '/tmp/instantwm-%s.sock\n' "$(id -u)"
    fi
}

# Wait until the WM has bound its IPC socket so instantwmctl can reach it.
wait_for_wm_socket() {
    local socket i
    socket="$(wm_ipc_socket)"
    for ((i = 0; i < 50; i++)); do
        [[ -S "$socket" ]] && return 0
        sleep 0.1
    done
    return 1
}

# In-place WM restarts skip `ins autostart` (via INSTANTWM_AUTOSTART=0) so a
# crashing WM does not rerun heavyweight session setup. The settings applied
# by autostart — keyboard layouts, wallpaper, mouse behaviour, ... — are
# runtime state of the old WM process though, so reapply just the settings
# to bring the restarted WM back to the user's configuration.
reapply_settings() {
    command -v ins >/dev/null 2>&1 || return 0
    wait_for_wm_socket || return 0
    echo "reapplying settings for restarted window manager" >>"$LOG_FILE"
    ins settings apply >>"$LOG_FILE" 2>&1
}

cd "$HOME" || echo "failed to access home directory" >&2

if command -v iconf >/dev/null 2>&1 && command -v wmname >/dev/null 2>&1; then
    configured_wmname="$(iconf wmname 2>/dev/null || true)"
    if [[ -n "$configured_wmname" ]]; then
        wmname "$configured_wmname"
    fi
fi

if [[ -f "$HOME/.instantsession" ]]; then
    # shellcheck source=/dev/null
    source "$HOME/.instantsession"
fi

if command -v iconf >/dev/null 2>&1 && iconf -i debug; then
    export INSTANTDEBUG=true
fi

if [[ -z "${INSTANTDEBUG:-}" && -f "$LOG_FILE" ]] &&
    [[ "$(du -sm "$LOG_FILE" | awk '{print $1}')" -gt 20 ]]; then
    echo "log file has gotten out of hand, clearing logs"
    echo "start of log file" >"$LOG_FILE"
fi

export XDG_CURRENT_DESKTOP=instantwm
export XDG_SESSION_DESKTOP=instantwm
export DESKTOP_SESSION=instantwm

while [[ -e "$RUNNING_FILE" ]]; do
    if [[ -s "$OVERRIDE_FILE" ]]; then
        wm_command="$(<"$OVERRIDE_FILE")"
        rm -f "$OVERRIDE_FILE"
        if ! command -v "$wm_command" >/dev/null 2>&1; then
            echo "window manager override not found: $wm_command" >>"$LOG_FILE"
            continue
        fi
    else
        wm_command=instantwm
    fi

    if [[ "$wm_command" == instantwm ]]; then
        if [[ "$FIRST_START" == true ]]; then
            export INSTANTWM_AUTOSTART="$SESSION_AUTOSTART"
            FIRST_START=false
        else
            export INSTANTWM_AUTOSTART=0
            if [[ "$SESSION_AUTOSTART" != "0" ]]; then
                reapply_settings &
                REAPPLY_PID=$!
            fi
        fi
        if [[ -n "${INSTANTDEBUG:-}" ]]; then
            instantwm --backend x11 >>"$LOG_FILE" 2>&1 &
        else
            instantwm --backend x11 2>>"$LOG_FILE" &
        fi
    else
        "$wm_command" 2>>"$LOG_FILE" &
    fi

    WMPID=$!
    echo "$WMPID" >"$PID_FILE"
    if wait "$WMPID"; then
        WMEXITCODE=0
    else
        WMEXITCODE=$?
    fi
    WMPID=""
    rm -f "$PID_FILE"

    if [[ -e "$RUNNING_FILE" ]]; then
        printf '%s: window manager exited with code %s; restarting\n' \
            "$(date)" "$WMEXITCODE" >>"$LOG_FILE"
        sleep 1
    fi
done
