Recovery from zero monitors (clamshell mode setup)

Hi all! Am getting started with Hyprland and have run into an issue that I can’t seem to hack around - thanks in advance for any help!

I’m trying to set up clamshell mode for my laptop, which involves disabling the laptop screen when the lid is closed and there is another (1) monitor plugged in.

Disabling the laptop screen works like a charm, but when I unplug the laptop, the laptop screen remains disabled despite a hl.bind(“monitor.removed”, …) added to it. A dedicated keybind (SUPER + K) to enable the laptop screen also doesn’t work when the laptop is disconnected from external monitors (but does if it is connected to an external monitor).

The only recovery method that has worked is to plug it back into the external monitor and re-enable the laptop screen when it is plugged in.

Is there any other way to recover from zero monitors?

Here is the relevant config:

----- Monitor management -----

-- Enable clamshell mode
-- HandleLidSwitchDocked=ignore is the default on Arch so no change needed
local lidClosed = false

function laptopScreenOff()
    hl.monitor({
        output   = "eDP-1",
        disabled = true
    })
    hl.exec_cmd("hyprpaper")
end

function laptopScreenOn()
    hl.monitor({
        output   = "eDP-1",
        disabled = false,
        mode     = "preferred",
        position = "auto",
        scale    = "auto"
    })
    hl.exec_cmd("hyprpaper")
end

-- Keybind for laptop screen management
hl.bind(mainMod .. " + K", function()
    local laptopMon = hl.get_monitor("eDP-1")
    if laptopMon then
        laptopScreenOff()
    else
        laptopScreenOn()
    end
end, { locked = true })

-- Turn off laptop screen if lid is closed and monitors are attached
-- Handles case of lid is closed after attaching monitor
hl.bind("switch:on:Lid Switch", function()
    lidClosed = true
    if #(hl.get_monitors()) <= 1 then return end
    laptopScreenOff()
end, { locked = true })

-- Turn on laptop screen if lid is opened 
hl.bind("switch:off:Lid Switch", function()
    lidClosed = false
    laptopScreenOn()
end, { locked = true })

-- Turn off laptop screen if lid is closed and monitors are attached
-- Handles case of attaching after lid already closed
hl.on("monitor.added", function()
    if lidClosed and #(hl.get_monitors()) > 1 then
        laptopScreenOff()
    end
end)

-- Ensuring the monitor count is never 0 (fixing case when no monitors are attached) **THIS DOESN'T WORK**
hl.on("monitor.removed", function()    
    if #(hl.get_monitors()) == 0 then
        laptopScreenOn()
    end
end)

Any ideas? Been working on this for a while and am pretty stumped.

Hi! I’ve also encountered this issue on a laptop with nvidia gpu. And it seems like enabling monitor via hl.monitor() fails when there are no active monitors left.

So the only workaround that I found is just reloading the whole config via hl.exec_cmd("hyprctl reload")

Recovering from zero and things around monitor mode switches are being fixed up here state/monitor: refactor monitor state, init fallback state by vaxerski · Pull Request #14547 · hyprwm/Hyprland · GitHub

you can follow the MR, or even help by testing.

Just like you I’ve had some trouble setting up my laptop for seamless use between an external monitor and its native laptop screen.

Here’s a script that makes things kinda livable.

As you can see I’m also struggling to have a display lock BEFORE suspend (also pardon the old config syntax)

bindl = , switch:on:Lid Switch, exec, ~/.config/hypr/scripts/handle_lid_switch.sh
bindl = , switch:off:Lid Switch, exec, hyprctl keyword monitor “eDP-1, preferred, auto, 1”


#!/bin/bash

# Name of your laptop's built-in display (usually eDP-1)
LAPTOP_DISPLAY="eDP-1"

# Get total number of monitors
MONITOR_COUNT=$(hyprctl monitors -j | jq 'length')

# if count is greater than one
if [ "$MONITOR_COUNT" -gt 1 ]; then
        # External monitor is connected; disable laptop display
        sleep 2 & hyprctl keyword monitor "$LAPTOP_DISPLAY, disable"
else
        # No external display connected; lock screen and suspend
        # Replace this with your preferred locker (e.g., swaylock)
        #swaylock && systemctl suspend
        #swaylock -f -c 000000 & sleep 4 # && systemctl suspend
        pidof hyprlock || hyprlock




fi