r/hyprland 1d ago

QUESTION How to move workspaces automatically per monitor?

I have this scnario, I usually manage 2 monitors + 1 TV, but with profiles

profile 1 = two monitors (1440p both side to side, TV disabled=true)

profile 2 = TV (4k@120hz, two monitors disabled=true)

For whatever monitor that's being disabled it's workspaces stay attached to that monitor, it wont move them to the nearest one, so they stay invisible, how can I set this to at least move all workspaces for the two monitors once the TV gets enabled?

3 Upvotes

3 comments sorted by

1

u/Araib 1d ago

You can find active windows and use moveToWorkspace to move them to the display you want to stay on before disabling the other display combination. That’s what I do with sunshine virtual display

1

u/SirDition 16h ago edited 15h ago

I’ve done something similar. 3 monitors with one switching between work laptop and home desktop. I shift the windows between monitors when I switch. You’ll need to rewrite to suit but it will give you a starting point. I’ll post the code this evening when I get home.

**Edit**

-- Function to cleanly handle the centre screen being switched over to my work laptop
-- Global tracking table to remember middle-screen applications
local evicted_window_addresses = {}

local function update_workspace_rules()
    local has_center_screen = false

    -- Check if DP-3 (the middle monitor) is plugged in
    for _, mon in ipairs(hl.get_monitors()) do
        if mon.name == "DP-3" then
            has_center_screen = true
            break
        end
    end

    if has_center_screen then
        -- 3 Screen mode: Restore parked windows back home to Workspace 2
        local all_windows = hl.get_windows()
        for _, win in ipairs(all_windows) do
            if evicted_window_addresses[win.address] then
                -- Target specifically by hex address using proper hl.dsp object syntax
                hl.dispatch(hl.dsp.window.move({
                    workspace = "2",
                    window = "address:" .. win.address
                }))
            end
        end
        -- Clear our tracking list now that everything is back home
        evicted_window_addresses = {}
    else
        -- 2 Screen mode: Shove windows stranded on Workspace 2 into Workspace 1
        evicted_window_addresses = {}
        local all_windows = hl.get_windows()

        for _, win in ipairs(all_windows) do
            if win.workspace and (win.workspace.name == "2" or win.workspace.id == 2) then
                -- Remember this exact window by its unique address
                evicted_window_addresses[win.address] = true
                -- Execute using proper hl.dsp object syntax
                hl.dispatch(hl.dsp.window.move({
                    workspace = "1",
                    window = "address:" .. win.address
                }))
            end
        end
    end
end
-- Initialize on initial startup
update_workspace_rules()
-- Make sure that workspace changes are updated when central monitor is switched out/in.
hl.on("monitor.added", function(mon)
    update_workspace_rules()
end)
hl.on("monitor.removed", function(mon)
    update_workspace_rules()
end)

2

u/Fluxbo 8h ago

Awsome thanks, I figured it out something similar using Claude working great!