feat(scripts): add workspace master layout toggle helper

This commit is contained in:
root committed 2026-11-12 10:55:28 -05:00
1 parent f260cfa023
commit e8ff5b3552
3 files changed
+72 -125

No files matched your search

-70
View File
@@ -1,70 +0,0 @@
#!/bin/bash
# omarchy:summary=Toggle a window between picture-in-picture (floating, pinned, bottom-left corner of the focused monitor) and tiled.
# omarchy:args=[toggle|on] [address:0x...]
set -uo pipefail
# Usage: omarchy-pip [toggle|on] [address:0x...]
#
# "on" always fits the window: float, pin, resize to FRACTION of the focused
# monitor on both axes and park it in the bottom-left corner, inset by GAP.
# "toggle" (the default) does that unless the window is already floating and
# pinned, in which case it unpins and tiles it again. The window defaults to
# the active one. omarchy-summon calls "on" after carrying its window to the
# focused monitor; the YouTube window rule in hypr/hyprland.lua mirrors the
# same fraction and inset for the first open, so keep the three in sync.
MODE=${1:-toggle}
WINDOW=${2:-}
case $MODE in
toggle | on) ;;
*)
echo "usage: ${0##*/} [toggle|on] [address:0x...]" >&2
exit 2
;;
esac
FRACTION=0.3
# Matches general:gaps_out so the window lines up with tiled neighbours and
# its border stays on screen.
GAP=10
# Lua dispatcher first, classic name as the pre-lua fallback (same shape as
# the other omarchy-* scripts here).
hypr_dispatch() {
local lua="$1"
shift
hyprctl dispatch "$lua" >/dev/null 2>&1 || hyprctl dispatch "$@" >/dev/null
}
if [[ -z $WINDOW ]]; then
ACTIVE=$(hyprctl activewindow -j 2>/dev/null)
[[ -n $ACTIVE && $ACTIVE != "{}" ]] || exit 0
WINDOW="address:$(jq -r '.address' <<<"$ACTIVE")"
else
ACTIVE=$(hyprctl clients -j | jq -c --arg a "${WINDOW#address:}" 'first(.[] | select(.address == $a)) // empty')
[[ -n $ACTIVE ]] || exit 1
fi
# The wiki documents action = "set", but on Hyprland 0.56 "set" toggles;
# "on" / "off" are what the dispatcher actually honours.
if [[ $MODE == toggle ]] && [[ $(jq -r '.floating and .pinned' <<<"$ACTIVE") == true ]]; then
hypr_dispatch "hl.dsp.window.pin({ action = \"off\", window = \"$WINDOW\" })" pin "$WINDOW"
hypr_dispatch "hl.dsp.window.float({ action = \"off\", window = \"$WINDOW\" })" settiled "$WINDOW"
exit 0
fi
# Focused monitor: origin and logical size.
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))"')
[[ -n ${MON_H:-} ]] || exit 1
WIDTH=$(awk "BEGIN { printf \"%d\", $MON_W * $FRACTION }")
HEIGHT=$(awk "BEGIN { printf \"%d\", $MON_H * $FRACTION }")
X=$((MON_X + GAP))
Y=$((MON_Y + MON_H - HEIGHT - GAP))
hypr_dispatch "hl.dsp.window.float({ action = \"on\", window = \"$WINDOW\" })" setfloating "$WINDOW"
hypr_dispatch "hl.dsp.window.pin({ action = \"on\", window = \"$WINDOW\" })" pin "$WINDOW"
hypr_dispatch "hl.dsp.window.resize({ x = $WIDTH, y = $HEIGHT, window = \"$WINDOW\" })" resizewindowpixel "exact $WIDTH $HEIGHT,$WINDOW"
hypr_dispatch "hl.dsp.window.move({ x = $X, y = $Y, window = \"$WINDOW\" })" movewindowpixel "exact $X $Y,$WINDOW"
-55
View File
@@ -1,55 +0,0 @@
#!/bin/bash
# omarchy:summary=Launch a floating pinned app (youtube) or bring its window to the focused monitor's bottom-left corner.
set -uo pipefail
# Usage: omarchy-summon [youtube]
#
# Each profile is one app kept as a picture-in-picture window: the window
# rule in hypr/hyprland.lua floats, pins, sizes and parks it when it first
# opens, so a plain launch is enough when no window exists. When one does,
# this script carries it to the focused monitor and hands it to omarchy-pip
# to fit it there again: the two panels differ in logical size, and Hyprland
# keeps a floating window's pixel size and offset across a monitor move.
#
# PATTERN is an ERE over the window class. A web app's picture-in-picture
# overlay shares the class, so windows titled Picture-in-Picture are skipped
# (Omarchy's own pip rule owns those).
case ${1:-youtube} in
youtube)
# Chromium derives the class from the app URL, and the same web app has
# shown up under more than one host spelling (youtube.com vs
# www.youtube.com) once a video is playing, so match the family.
PATTERN='^brave-(www\.)?youtube\.com__.*$'
LAUNCH="gtk-launch YouTube"
;;
*)
echo "usage: ${0##*/} [youtube]" >&2
exit 2
;;
esac
# Lua dispatcher first, classic name as the pre-lua fallback (same shape as
# the other omarchy-* scripts here).
hypr_dispatch() {
local lua="$1"
shift
hyprctl dispatch "$lua" >/dev/null 2>&1 || hyprctl dispatch "$@" >/dev/null
}
ADDRESS=$(hyprctl clients -j | jq -r --arg re "$PATTERN" '
first(.[] | select((.class | test($re)) and ((.title | test("Picture.?in.?[Pp]icture")) | not)))
| .address // empty')
if [[ -z $ADDRESS ]]; then
exec setsid uwsm-app -- $LAUNCH >/dev/null 2>&1
fi
WINDOW="address:$ADDRESS"
MON_NAME=$(hyprctl monitors -j | jq -r '.[] | select(.focused) | .name')
[[ -n $MON_NAME ]] || exit 1
hypr_dispatch "hl.dsp.window.move({ monitor = \"$MON_NAME\", window = \"$WINDOW\" })" movewindow "mon:$MON_NAME,$WINDOW"
omarchy-pip on "$WINDOW"
hypr_dispatch "hl.dsp.focus({ window = \"$WINDOW\" })" focuswindow "$WINDOW"
+72
View File
@@ -0,0 +1,72 @@
#!/bin/bash
# omarchy:summary=Toggle the active workspace between the master layout and the layout it had before
set -uo pipefail
# Usage: omarchy-toggle-master
#
# Goes through Omarchy's o.workspace_mode and its saved-mode files, like
# omarchy-hyprland-workspace-layout-toggle (SUPER + W), so the layout survives
# a reload or login and the two keys agree on what the workspace is: SUPER + W
# on a master workspace cycles on to dwindle. The layout master replaced is
# kept under STATE_DIR and restored by the next press; without one, the
# workspace goes back to the default layout. Named workspaces are skipped for
# the same reason Omarchy skips them: their negative id is read as a relative
# selector.
STATE="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy"
MODES_DIR="$STATE/workspace-layouts"
STATE_DIR="$STATE/master-toggle"
# Same replace-in-place notification as Omarchy's layout toggle, sharing its
# id file, so switching with either key leaves one current notification.
notify_layout() {
local state="$STATE/workspace-layout-notification"
local last id
[[ -r $state ]] && read -r last <"$state"
if id=$(omarchy-notification-send -p -r "${last:-0}" -g $'\U000f10ac' "$1") && [[ $id =~ ^[0-9]+$ ]]; then
mkdir -p "$(dirname "$state")" && printf '%s\n' "$id" >"$state"
fi
}
WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id')
[[ $WORKSPACE =~ ^[0-9]+$ ]] || exit 1
MODE_FILE="$MODES_DIR/$WORKSPACE.lua"
PREVIOUS_FILE="$STATE_DIR/$WORKSPACE"
CURRENT=$(omarchy-hyprland-workspace-layout-current)
DEFAULT=$(omarchy-hyprland-workspace-layout-default)
if [[ $CURRENT == master ]]; then
NEW=$(cat "$PREVIOUS_FILE" 2>/dev/null)
[[ $NEW =~ ^(dwindle|scrolling|floating)$ ]] || NEW=$DEFAULT
else
NEW=master
fi
APPLY="o.workspace_mode({ workspace = \"$WORKSPACE\", mode = \"$NEW\" })"
if ! hyprctl eval "$APPLY" >/dev/null 2>&1; then
notify_layout "$(omarchy-i18n layout.needsReload)"
exit 1
fi
if [[ $NEW == master ]]; then
mkdir -p "$STATE_DIR" && printf '%s\n' "$CURRENT" >"$PREVIOUS_FILE"
# A layout change fires no event, so Ghostty is made the master here
# (hypr/master.lua).
hyprctl eval 'require("hypr.master").enforce()' >/dev/null
else
rm -f "$PREVIOUS_FILE"
fi
# Back on the default, the workspace follows it again (as Omarchy does).
if [[ $NEW == "$DEFAULT" ]]; then
rm -f "$MODE_FILE"
else
mkdir -p "$MODES_DIR" && printf '%s\n' "$APPLY" >"$MODE_FILE"
fi
notify_layout "Workspace layout: $NEW"
omarchy-shell -q omarchy.workspaces refresh
omarchy-shell -q omarchy.dock refresh