#!/bin/bash # omarchy:summary=Cycle the focused window through preset sizes # omarchy:args=[next|prev] set -uo pipefail DIRECTION="${1:-next}" # Preset widths, as a fraction of the screen. Edit to taste. # These only apply to dwindle and to floating windows. On a scrolling # workspace the layout cycles its own list instead. Set that list with: # hl.config({ scrolling = { explicit_column_widths = "0.333, 0.5, 0.667, 1.0" } }) FRACTIONS=(0.333 0.5 0.667) # Height of a floating window, as a fraction of the screen. FLOATING_HEIGHT=0.8 STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/window-sizes" # Try the Lua dispatcher first, then fall back to the legacy name. hypr_dispatch() { local lua="$1" shift hyprctl dispatch "$lua" >/dev/null 2>&1 || hyprctl dispatch "$@" >/dev/null } calc() { awk "BEGIN { printf \"%s\", $1 }" } ACTIVE=$(hyprctl activewindow -j 2>/dev/null) [[ -n $ACTIVE && $ACTIVE != "{}" ]] || exit 0 ADDRESS=$(jq -r '.address // empty' <<<"$ACTIVE") FLOATING=$(jq -r '.floating // false' <<<"$ACTIVE") WORKSPACE=$(jq -r '.workspace.id // empty' <<<"$ACTIVE") LAYOUT=$(hyprctl activeworkspace -j 2>/dev/null | jq -r '.tiledLayout // empty') # --- Scrolling: the layout keeps its own preset list ------------------------ if [[ $FLOATING != "true" && $LAYOUT == "scrolling" ]]; then if [[ $DIRECTION == "prev" ]]; then MSG="colresize -conf" else MSG="colresize +conf" fi hypr_dispatch "hl.dsp.layout(\"$MSG\")" layoutmsg "$MSG" exit 0 fi # --- Step to the next preset ------------------------------------------------ # Floating windows keep an index of their own. Tiled windows share one index # per workspace, because the split is a property of the workspace. if [[ $FLOATING == "true" ]]; then STATE_KEY="window-${ADDRESS}" else STATE_KEY="workspace-${WORKSPACE}" fi STATE_FILE="$STATE_DIR/${STATE_KEY}.index" COUNT=${#FRACTIONS[@]} INDEX=0 if [[ -f $STATE_FILE ]]; then INDEX=$(<"$STATE_FILE") [[ $INDEX =~ ^[0-9]+$ ]] || INDEX=0 fi if [[ $DIRECTION == "prev" ]]; then INDEX=$(((INDEX - 1 + COUNT) % COUNT)) else INDEX=$(((INDEX + 1) % COUNT)) fi mkdir -p "$STATE_DIR" printf '%s\n' "$INDEX" >"$STATE_FILE" FRACTION=${FRACTIONS[$INDEX]} # --- Floating: set an absolute size and center ------------------------------ if [[ $FLOATING == "true" ]]; then read -r MON_W MON_H < <(hyprctl monitors -j | jq -r '.[] | select(.focused) | "\(((.width / .scale) | floor)) \(((.height / .scale) | floor))"') [[ -n ${MON_W:-} && -n ${MON_H:-} ]] || exit 1 WIDTH=$(calc "int($MON_W * $FRACTION)") HEIGHT=$(calc "int($MON_H * $FLOATING_HEIGHT)") hypr_dispatch "hl.dsp.window.resize({ x = $WIDTH, y = $HEIGHT })" resizeactive exact "$WIDTH" "$HEIGHT" hypr_dispatch "hl.dsp.window.center()" centerwindow exit 0 fi # --- Dwindle: set the split ratio ------------------------------------------- # splitratio 1.0 is an even split, so a fraction of 0.5 maps to 1.0. # With the default split_bias of 0, the ratio goes to the left or top window. # So when the focused window is the right or bottom one, the fraction is # mirrored. Which side the window sits on is read from its position. read -r WIN_X WIN_Y WIN_W WIN_H < <(jq -r '"\(.at[0]) \(.at[1]) \(.size[0]) \(.size[1])"' <<<"$ACTIVE") read -r MON_X MON_Y MON_W MON_H < <(hyprctl monitors -j | jq -r '.[] | select(.focused) | "\(.x) \(.y) \(((.width / .scale) | floor)) \(((.height / .scale) | floor))"') MIRROR=false if ((WIN_W * 100 > MON_W * 90)); then # The window spans the screen, so the split is top and bottom. ((WIN_Y + WIN_H / 2 > MON_Y + MON_H / 2)) && MIRROR=true else ((WIN_X + WIN_W / 2 > MON_X + MON_W / 2)) && MIRROR=true fi if [[ $MIRROR == "true" ]]; then RATIO=$(calc "2 * (1 - $FRACTION)") else RATIO=$(calc "2 * $FRACTION") fi # Hyprland accepts 0.1 to 1.9. RATIO=$(calc "($RATIO < 0.1 ? 0.1 : ($RATIO > 1.9 ? 1.9 : $RATIO))") hypr_dispatch "hl.dsp.layout(\"splitratio $RATIO exact\")" layoutmsg "splitratio $RATIO exact"