/ de-omarchy / bin / omarchy-launch-about
swadhinbiswas Initial de-omarchy: Omarchy UI layer for Arch-based distros · 8/22/2026
9f393b2
182 lines · 6.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash

# omarchy:summary=Launch the fastfetch TUI that gives information about the current system.

# The size that hugs the About content depends on the terminal font and the user's
# logo, so it can only be measured from inside the terminal. We remember the size
# that fit and apply it as a window rule before launching, so the window opens at
# it instead of resizing after the first paint. Bash defers WINCH traps while read
# blocks, so poll for size changes and re-render fastfetch whenever it is resized.

LOGO_FILE="$HOME/.config/omarchy/branding/about.txt"
FIT_FILE="$HOME/.local/state/omarchy/windows/about.fit"

# A user-level fastfetch config can relocate or restyle the logo in ways this
# measurement cannot see, so leave sizing to the float rule in that case.
custom_fastfetch_config() {
  [[ -f $HOME/.config/fastfetch/config.jsonc ]]
}

# wc -L counts display columns only in a UTF-8 locale. A session that never set
# one counts every box-drawing and Nerd Font glyph in the About layout as
# nothing, which measures the content narrower than it renders.
display_columns() {
  LC_ALL=C.UTF-8 wc -L
}

logo_dimensions() {
  [[ -f $LOGO_FILE ]] || return 1
  printf '%s %s' "$(display_columns <"$LOGO_FILE")" "$(wc -l <"$LOGO_FILE")"
}

hypr_dispatch() {
  local lua="$1"
  shift
  hyprctl dispatch "$lua" >/dev/null 2>&1 || hyprctl dispatch "$@" >/dev/null
}

remember_fit() {
  local directory tmp
  directory=$(dirname "$FIT_FILE")
  mkdir -p "$directory"
  tmp=$(mktemp "$directory/.about.fit.XXXXXX")
  printf '%s %s %s %s\n' "$1" "$2" "$3" "$4" >"$tmp"
  mv "$tmp" "$FIT_FILE"
}

# Replaces the rule from the last launch so a remembered size never outlives the
# fit it came from. Called without one it only clears, leaving the float rule's
# starting size — where a Hyprland without the Lua API stays too.
apply_size_rule() {
  local rule=""
  (( $# == 2 )) && rule="omarchy_about_size_rule = hl.window_rule({ match = { class = \"org.omarchy.about\" }, size = { $1, $2 } })"

  hyprctl eval "if omarchy_about_size_rule then omarchy_about_size_rule:set_enabled(false) end; omarchy_about_size_rule = nil; $rule" >/dev/null 2>&1
}

# Sized before the terminal is spawned, so the window maps at its final size.
presize_window() {
  local logo_w logo_h fit_logo_w fit_logo_h fit_w fit_h

  if ! custom_fastfetch_config && [[ -r $FIT_FILE ]]; then
    read -r logo_w logo_h <<<"$(logo_dimensions)"
    read -r fit_logo_w fit_logo_h fit_w fit_h <"$FIT_FILE"

    # A different logo needs a different window, so leave that launch to the
    # float rule and let the fit measure the new size.
    if [[ -n ${logo_w:-} && $logo_w == "$fit_logo_w" && $logo_h == "$fit_logo_h" ]] &&
      [[ $fit_w =~ ^[0-9]+$ && $fit_h =~ ^[0-9]+$ ]]; then
      apply_size_rule "$fit_w" "$fit_h"
      return
    fi
  fi

  apply_size_rule
}

# Hyprland animates a resize and the terminal reflows to every step of it, so
# wait for the grid to hold still before measuring it.
settle_grid() {
  local current previous="" held=0

  for _ in {1..20}; do
    current=$(stty size)
    if [[ $current == $previous ]]; then
      (( ++held == 3 )) && break
    else
      held=0
      previous=$current
    fi
    sleep 0.05
  done
}

fit_window() {
  custom_fastfetch_config && return 0

  local logo_w logo_h
  read -r logo_w logo_h <<<"$(logo_dimensions)"
  [[ -n ${logo_w:-} ]] || return 1

  # The guard character keeps command substitution from eating the trailing
  # break line, which provides the bottom padding row.
  local modules module_w module_h
  modules=$(fastfetch --logo none | sed 's/\x1b\[[0-9;?]*[a-zA-Z]//g'; printf X)
  modules=${modules%X}
  module_w=$(printf '%s' "$modules" | display_columns)
  module_h=$(printf '%s' "$modules" | wc -l)

  # Mirror the logo block in the fastfetch config: 2 columns of padding left of
  # the logo, 6 between logo and modules, 2 rows above it. Then 2 columns of
  # right padding to match, and a row for the cursor so the trailing break shows.
  local target_c=$(( 2 + logo_w + 6 + module_w + 2 ))
  local target_r=$(( (logo_h + 2 > module_h ? logo_h + 2 : module_h) + 1 ))

  local nudges=0 rows cols address width height shift_w shift_h target_w target_h
  while :; do
    read -r rows cols <<<"$(stty size)"
    read -r address width height <<<"$(hyprctl clients -j | jq -r '.[] | select(.class == "org.omarchy.about") | "\(.address) \(.size[0]) \(.size[1])"')"
    [[ -n ${address:-} ]] || return 1
    (( cols > 0 && rows > 0 && width > 0 && height > 0 )) || return 1

    # A window has to land on the terminal's cell boundaries, so take a cell of
    # slack over chasing an exact grid, and remember where it came to rest.
    if (( cols >= target_c && cols <= target_c + 1 && rows >= target_r && rows <= target_r + 1 )); then
      remember_fit "$logo_w" "$logo_h" "$width" "$height"
      return 0
    fi

    # Two nudges is the budget, and each one is measured before the next is spent.
    (( ++nudges <= 2 )) || return 1

    # Move by the cells the window is off by, rather than scaling it to the grid,
    # which would multiply up the terminal's padding along with them. Dividing a
    # window that carries that padding still leaves the cell a touch generous, so
    # round the move away from the grid that would clip.
    shift_w=$(( (target_c - cols) * width ))
    shift_h=$(( (target_r - rows) * height ))
    target_w=$(( width + (shift_w >= 0 ? (shift_w + cols - 1) / cols : shift_w / cols) ))
    target_h=$(( height + (shift_h >= 0 ? (shift_h + rows - 1) / rows : shift_h / rows) ))

    hypr_dispatch "hl.dsp.window.resize({ window = \"address:$address\", x = $target_w, y = $target_h })" resizewindowpixel "exact $target_w $target_h,address:$address"
    hypr_dispatch "hl.dsp.window.center({ window = \"address:$address\" })" centerwindow
    settle_grid
  done

  return 1
}

if [[ ${1:-} == "--render" ]]; then
  printf '\e[?25l'

  # Give the compositor a moment to apply the window rules before measuring cells.
  settle_grid

  fitted=false
  passes=0
  while :; do
    size=$(stty size)
    logo_stamp=$(stat -c %Y "$LOGO_FILE" 2>/dev/null)
    clear
    fastfetch
    # A second pass picks up a fit that could not measure the window the first
    # time. Beyond that, a window that will not settle would be fitted again on
    # every repaint.
    if [[ $fitted == false ]] && (( ++passes <= 2 )); then
      fit_window && fitted=true
    fi
    while [[ $(stty size) == $size && $(stat -c %Y "$LOGO_FILE" 2>/dev/null) == $logo_stamp ]]; do
      read -t 0.5 -n 1 -s && exit
      (( $? > 128 )) || exit
    done
    # A rebranded logo changes the content dimensions, so measure again.
    if [[ $(stat -c %Y "$LOGO_FILE" 2>/dev/null) != $logo_stamp ]]; then
      fitted=false
      passes=0
    fi
  done
fi

presize_window
exec omarchy-launch-or-focus-tui --app-id=org.omarchy.about omarchy-launch-about --render