How to handle docked laptop screens in Hyprland so they are not considered always active

I’ve been running into an issues while testing Noctalia V5 with the latest Hyprland with the built in laptop LCD (eDP-1) being picked up after I login while the screen is closed. This would cause issues like:

  • My mouse cursor would be off screen after sign in.
  • Trying to launch and application like Terminal from a bind would launch off screen and be inaccessible
  • When I would screen shot all my monitors at once, it picked up my laptop lcd as if it was on.

I am not sure if this also caused me issues when ALT-Tab between a full screen game in Steam to my desktop (still testing this).

The fix was adding the following code to disable the internal display based on the state of the lid switch (LUA file format):

-- Define your internal monitor output name (verify with hyprctl devices)
local internalMonitor = "eDP-1" -- Replace with your actual monitor name if different

-- Function to disable the laptop screen
local function disableLaptopScreen()
    hl.monitor({
        output = internalMonitor,
        disabled = true
    })
end

-- Function to enable the laptop screen
local function enableLaptopScreen()
    hl.monitor({
        output = internalMonitor,
        disabled = false
    })
end

-- Bind lid close event (switch turns 'on' when closed on many systems)
hl.bind("switch:on:Lid Switch", disableLaptopScreen, { locked = true })

-- Bind lid open event (switch turns 'off' when opened)
hl.bind("switch:off:Lid Switch", enableLaptopScreen, { locked = true })   

Key Implementation Details:

  • Switch Name: Ensure the switch name (Lid Switch) matches your system’s actual identifier, which can be verified by running hyprctl devices.

  • Locked Flag: The { locked = true } flag is essential to ensure the bind triggers even when the screen is locked (e.g., by hyprlock).

  • Monitor Output: Replace eDP-1 with your specific internal display identifier if it differs.

  • Re-enabling: The corresponding switch:off bind re-enables the monitor when the lid is opened. If you only want to disable the monitor when an external display is active, you should add a condition to check for external monitors within the switch:on function

I did find this answer through a Brave Search. But I tested it before I shared it with our community.

The lid switch bind is a lot cleaner than leaving a ghost workspace around. Also explains those weird fullscreen alt-tab moments, Hyprland happily treats the closed panel like it still exists.

I feel like what was found here should be a bug and something should be incorporated in Hyprland to deal with this internally. For now I just try to play the knowledge forward and post here with the many experts I get to chat with.

This really feels like compositor-side state handling, not something every laptop user should have to script around. Until then, the lid bind is at least less cursed than losing windows to an invisible panel.