headless-primary: relocate workspaces stranded on a mirrored output
On swap-back Hyprland brings DP-1 up normal, binds a workspace to it, then apply mirrors DP-1 — trapping that workspace on a layout-excluded mirror (unreachable; symptom: 'can't make workspace 1 show'). apply now moves any workspace off a mirrored output onto the headless primary. Verified the heal operation (move-off-mirror) manually. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,18 +113,32 @@ apply() {
|
|||||||
log "DP-1 mirroring $head"
|
log "DP-1 mirroring $head"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 4. Rescue orphaned workspaces (monitorID == -1) onto the headless primary.
|
# 4. Relocate any workspace that lives on a MIRRORED output onto the headless
|
||||||
|
# primary. A mirror is excluded from the layout, so a workspace bound to it
|
||||||
|
# is trapped and unreachable — exactly what happens on swap-back when
|
||||||
|
# Hyprland brings DP-1 up normal, binds a workspace to it, then we mirror
|
||||||
|
# it. (tostring guards mirrorOf being null | "None" | a numeric id.)
|
||||||
|
local mon ws
|
||||||
|
for mon in $(hyprctl monitors all -j \
|
||||||
|
| jq -r '.[] | select(((.mirrorOf // "None") | tostring | ascii_downcase) != "none") | .name'); do
|
||||||
|
[[ "$mon" == "$head" ]] && continue
|
||||||
|
for ws in $(hyprctl workspaces -j | jq -r --arg m "$mon" '.[] | select(.monitor==$m) | .id'); do
|
||||||
|
log "relocating workspace $ws off mirror $mon -> $head"
|
||||||
|
hyprctl dispatch moveworkspacetomonitor "$ws $head" >/dev/null 2>&1 || true
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# 5. Rescue orphaned workspaces (monitorID == -1) onto the headless primary.
|
||||||
# Narrow by design — a healthy second monitor (DP-2) is left alone.
|
# Narrow by design — a healthy second monitor (DP-2) is left alone.
|
||||||
local ws
|
|
||||||
for ws in $(hyprctl workspaces -j | jq -r '.[] | select(.monitorID == -1) | .id'); do
|
for ws in $(hyprctl workspaces -j | jq -r '.[] | select(.monitorID == -1) | .id'); do
|
||||||
log "rescuing orphaned workspace $ws -> $head"
|
log "rescuing orphaned workspace $ws -> $head"
|
||||||
hyprctl dispatch moveworkspacetomonitor "$ws $head" >/dev/null 2>&1 || true
|
hyprctl dispatch moveworkspacetomonitor "$ws $head" >/dev/null 2>&1 || true
|
||||||
done
|
done
|
||||||
|
|
||||||
# 5. Rescue any floating windows stranded off-screen by the topology change.
|
# 6. Rescue any floating windows stranded off-screen by the topology change.
|
||||||
rescue_offscreen_windows
|
rescue_offscreen_windows
|
||||||
|
|
||||||
# 6. Keep Sunshine's output_name pointed at the live headless name.
|
# 7. Keep Sunshine's output_name pointed at the live headless name.
|
||||||
if [[ -f "$CONF" ]] && grep -qF '# managed-by: omarchy-moonlight' "$CONF"; then
|
if [[ -f "$CONF" ]] && grep -qF '# managed-by: omarchy-moonlight' "$CONF"; then
|
||||||
local cur; cur="$(awk '/^output_name = / {print $3; exit}' "$CONF" 2>/dev/null || true)"
|
local cur; cur="$(awk '/^output_name = / {print $3; exit}' "$CONF" 2>/dev/null || true)"
|
||||||
if [[ "$cur" != "$head" ]]; then
|
if [[ "$cur" != "$head" ]]; then
|
||||||
|
|||||||
@@ -62,7 +62,12 @@ clients. Inherent to cloning an ultrawide.
|
|||||||
`hyprctl output remove` is unreliable for these, returns "output not found").
|
`hyprctl output remove` is unreliable for these, returns "output not found").
|
||||||
2. Sizes it `5120x1440@60` at `0x0`.
|
2. Sizes it `5120x1440@60` at `0x0`.
|
||||||
3. If `DP-1` is present → `hyprctl keyword monitor "DP-1,…,mirror,HEADLESS-1"`.
|
3. If `DP-1` is present → `hyprctl keyword monitor "DP-1,…,mirror,HEADLESS-1"`.
|
||||||
4. Rescues any **orphaned** workspace (`monitorID == -1`) onto the headless
|
4. **Relocates any workspace stranded on a mirrored output** onto the primary.
|
||||||
|
On swap-back Hyprland brings `DP-1` up *normal*, binds a workspace to it, and
|
||||||
|
then we mirror it — leaving that workspace trapped on a layout-excluded
|
||||||
|
mirror (unreachable). This moves it off. (You can move a workspace *off* a
|
||||||
|
mirror but not *onto* one, which is why this only bites via hotplug.)
|
||||||
|
5. Rescues any **orphaned** workspace (`monitorID == -1`) onto the headless
|
||||||
primary — deliberately narrow, so a healthy second monitor (DP-2) is left
|
primary — deliberately narrow, so a healthy second monitor (DP-2) is left
|
||||||
alone.
|
alone.
|
||||||
5. **Rescues off-screen floating windows** — recenters any floating, mapped
|
5. **Rescues off-screen floating windows** — recenters any floating, mapped
|
||||||
|
|||||||
Reference in New Issue
Block a user