#!/bin/bash # omarchy:summary=Play the current background's matching theme intro # omarchy:hidden=true set -euo pipefail state_home="$HOME/.local/state" current_dir="$state_home/omarchy/current" current_background_link="$current_dir/background" marker="$state_home/omarchy/background-intro.session-id" toggle="$state_home/omarchy/toggles/background-intros-off" video_extensions=(mp4 m4v mov webm mkv avi) resolve_intro() { local background local stem local extension local intro background=$(readlink -f "${1:-$current_background_link}" 2>/dev/null) || return 1 [[ -f $background ]] || return 1 case ${background,,} in *.jpg | *.jpeg | *.png | *.bmp | *.webp) ;; *) return 1 ;; esac stem=${background##*/} stem=${stem%.*} for extension in "${video_extensions[@]}"; do intro="${background%/*}/intros/$stem.$extension" if [[ -f $intro ]]; then printf '%s\n' "$intro" return 0 fi done return 1 } # Preparation is speculative: the selected staged clip is compared again by OWE. prepare_theme_intro() { local theme="$1" background remembered name source intro local -a names=() [[ -n $theme && $theme != .* && $theme != */* ]] || return 0 [[ ! -f $toggle ]] && ! animations_off || return 0 owe warm >/dev/null 2>&1 || return 0 [[ $(cat "$current_dir/theme.name" 2>/dev/null) != "$theme" ]] || return 0 remembered=$(cat "$state_home/omarchy/theme-backgrounds/$theme" 2>/dev/null || true) if [[ ${remembered%/*} == "$current_dir/theme/backgrounds" ]]; then name=${remembered##*/} elif [[ -f $remembered ]]; then background="$remembered" else mapfile -d '' -t names < <( find -L "$HOME/.config/omarchy/backgrounds/$theme" -maxdepth 1 -type f -print0 2>/dev/null | sort -z ) if (( ${#names[@]} > 0 )); then background=${names[0]} else mapfile -d '' -t names < <( find -L "$OMARCHY_PATH/themes/$theme/backgrounds" "$HOME/.config/omarchy/themes/$theme/backgrounds" -maxdepth 1 -type f \ \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.bmp' -o -iname '*.webp' \) -printf '%f\0' 2>/dev/null | sort -zu ) (( ${#names[@]} > 0 )) || return 0 name=${names[0]} fi fi if [[ -n ${name:-} ]]; then for source in "$HOME/.config/omarchy/themes/$theme" "$OMARCHY_PATH/themes/$theme"; do if [[ -f $source/backgrounds/$name ]]; then background="$source/backgrounds/$name" break fi done fi [[ -n ${background:-} ]] || return 0 intro=$(resolve_intro "$background" || true) [[ -z $intro ]] || owe intro-prepare "$intro" >/dev/null 2>&1 || true } animations_off() { [[ $(hyprctl -j getoption animations:enabled 2>/dev/null | jq -r '.bool' 2>/dev/null) == "false" ]] } theme_switch=false intro_prepared=false expected_background="" expected_theme="" case ${1:-} in "") ;; --prepare-theme) prepare_theme_intro "${2:-}" exit 0 ;; --resolve-only) resolve_intro "${2:-}" || true exit 0 ;; --resolve-startup) if [[ ! -f $toggle ]] && ! animations_off; then resolve_intro || true fi exit 0 ;; --theme-switch) theme_switch=true expected_background=$(readlink -f "${2:-}" 2>/dev/null) || exit 1 expected_theme=${3:-} intro_prepared=${4:-false} [[ -n $expected_theme ]] || exit 1 ;; *) echo "Usage: omarchy-theme-bg-boot-intro [--resolve-only [background]|--resolve-startup|--prepare-theme theme|--theme-switch background theme-id [prepared]]" >&2 exit 1 ;; esac if [[ $theme_switch == false ]]; then mkdir -p "$(dirname "$marker")" exec 9>"$state_home/omarchy/background-intro.lock" flock 9 session_id=${OMARCHY_SESSION_ID:-${HYPRLAND_INSTANCE_SIGNATURE:-}} [[ -n $session_id ]] || exit 0 if [[ -f $marker && $(<"$marker") == "$session_id" ]]; then exit 0 fi marker_staged=$(mktemp "$state_home/omarchy/.background-intro.session-id.XXXXXX") trap 'rm -f "$marker_staged"' EXIT printf '%s\n' "$session_id" >"$marker_staged" mv -f "$marker_staged" "$marker" trap - EXIT exec 9>&- fi selection_current() { [[ $(readlink -f "$current_background_link") == "$expected_background" && $(stat -Lc '%d:%i' "$current_dir/theme" 2>/dev/null) == "$expected_theme" ]] } if [[ $theme_switch == true ]] && ! selection_current; then exit 0 fi if [[ -f $toggle ]] || animations_off; then [[ $theme_switch == false ]] || exit 1 exit 0 fi intro=$(resolve_intro || true) if [[ -z $intro ]]; then [[ $theme_switch == false ]] || exit 1 exit 0 fi if [[ $theme_switch == true && $intro_prepared != "true" ]]; then owe refresh >/dev/null || exit 1 elif [[ $theme_switch == false ]]; then deadline=$((SECONDS + 5)) while ! timeout 1 owe status >/dev/null 2>&1; do if (( SECONDS >= deadline )); then exit 0 fi sleep 0.2 done (( SECONDS < deadline )) || exit 0 fi # The asynchronous outgoing cover must reach the compositor before playback # can hide the shell background. Older shells have no readiness method. if [[ $theme_switch == true ]]; then deadline=$((SECONDS + 3)) while true; do cover_status=$(omarchy-shell shell themeIntroCoverStatus "$expected_theme" 2>/dev/null || true) case $cover_status in loading) (( SECONDS < deadline )) || exit 1 sleep 0.01 ;; error) exit 1 ;; superseded) exit 0 ;; *) break ;; esac done fi if [[ $theme_switch == true ]] && ! selection_current; then exit 0 fi # A selection or setting changed while OWE was starting no longer permits this intro. if [[ ! -f $toggle && $intro == "$(resolve_intro || true)" ]] && ! animations_off; then if [[ $theme_switch == true && $intro_prepared == "true" ]]; then owe intro --start first-frame --refresh "$intro" else owe intro --start first-frame "$intro" fi elif [[ $theme_switch == true ]]; then exit 1 fi