Disable Internal (Laptop) Display on Lid Close
My Framework 13 (2.8K Display upgrade) keeps the internal display awake even after the laptop lid is closed. This led to some fairly confusing behavior (including launching windows on the internal display--a LOT of them, since I just kept hitting the keybinds)
The following bindl directives have resolved this for me, in my testing it needs to be in hyprland.conf and not monitors.conf (binds? probably).
bindl=,switch:on:Lid Switch,exec,hyprctl keyword monitor "eDP-1, disable"
bindl=,switch:off:Lid Switch,exec,hyprctl keyword monitor "eDP-1, preferred, auto, auto"
I would like assistance testing this as I only have a single data point:
Framework 13 (I'll edit with stats in a bit) ASUS ProArt 5K Display
PLEASE try if you are experiencing this on any laptop and I'd love non-framework feedback as well. My theory is that this is a problem for all internal displays but I'm unsure.
Prospective PR (in a fork so I can clean it up before I push the branch to upstream): https://github.com/knightoftheoldcode/omarchy/pull/1
TIA!
Ref: #332
Was affected (Using Dell XPS 13). Blindly copied the two lines. Problem solved! Thanks!
Now that there is no turning back for me, I experimented a bit with my displays. Here is what I have (found) beyond the lid close switches off display.
My hardware is:
PC: XPS 13 9310
│ ├: Intel Iris Xe Graphics @ 1.35 GHz [Integrated]
│ ├: 3840x2160 @ 60 Hz (as 1920x1080) in 27" [External]
│ ├: 3456x2160 @ 60 Hz (as 1297x811) in 13" [Built-in]
Using auto might have surprising effects when you close and open the lid.
After opening the lid, eDP-1 appeared right of DP-7, when it was left of it before. This is likely normal behavior, but might still be surprising.
The following hyprland config (getting myself some new glasses today):
env = GDK_SCALE, 2
monitor = eDP-1, preferred, auto-left, 2.666667
monitor = DP-7, preferred, auto, 2
bindl=,switch:on:Lid Switch,exec,hyprctl keyword monitor "eDP-1, disable"
bindl=,switch:off:Lid Switch,exec,hyprctl keyword monitor "eDP-1, preferred, auto-left, 2.666667"
Keeps positioning and resolution stable for me and things a pleasure to read.
It can go in monitors.conf.
Did you not have to make lid switch changes in /etc/systemd/logind.conf ?
I actually have these lines in monitors.conf. Made no changes to logind.conf.
Thanks all!Great feedback. I figured it should be able to go into monitors.conf but it didn’t seem to work for me. And yes. It’s going to have to mirror your resolution and stuff probably. We will get better at auto detecting and recommending things. This is part of the research I want to do on it. I’m personally trying the auto-center-up option for my external above my laptop now that I’m down to one external from three. Thanks!!!On Aug 1, 2025, at 5:41 AM, Andreas Steffan @.***> wrote:deas left a comment (basecamp/omarchy#427) I actually have these lines in monitors.conf. Made no changes to logind.conf.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>
I did a similar thing manually a couple weeks ago so it would behave like a MacBook (and probably Windows) in clamshell mode with all the workspaces usable on the monitor. It was very confusing to close the lid and see how hyprland handles it by default, which is nonsensical to me. I don't think the default is going to be what anybody expects to happen with separate workspaces per monitor even in clamshell mode.
This was amazing thank you. Dell XPS 15 and this worked first try after spending hours trying to come up with a custom solution. It does seem to break if hypridle is triggered however.
@curtisspendlove thanks! placed your directive in monitors.conf saved/quit and worked instantly in MacBookPro 2015. Made afternoon of hacking with my 9yo very enjoyable.
It works amazing, I remove my acpid events. Just change the eDP-1 (to the your specific monitor name) that we can get using hyprctl monitors,
Thank you very much @curtisspendlove, this worked perfectly on first try on my Framework 13 too.
Thanks @curtisspendlove! I tried these directives in hyprland.conf and it worked perfectly for my Framework 13. Thanks!!!
Some testing notes: If the laptop is restarted with closed lid the internal monitor stays on. Probably because the events of open/close are not triggered. If the lid is opened and closed the internal display gets correctly disabled.
right now I'm having a weird issue with firefox on Dell XPS 15: when I open the lid, firefox becomes blurry.
here are my settings:
$main_monitor_id = eDP-1
# tried both
$main_monitor_settings = $main_monitor_id, 3840x2400@60, 0x0, 2.4
# $main_monitor_settings = $main_monitor_id, preferred, auto, 2.4
env = GDK_SCALE,2
monitor = $main_monitor_settings
bindl = , switch:on:Lid Switch, exec, hyprctl keyword monitor "$main_monitor_id, disable"
bindl = , switch:off:Lid Switch, exec, hyprctl keyword monitor "$main_monitor_settings"
if someone knows how to fix this - I'd appreciate your help.
Thank you @curtisspendlove this is a life saver! (it worked for me inside monitors.conf btw)
Using Lenovo Yoga Pro 7 14ASP9
On my Framework 13, the system doesn’t properly distinguish between being docked (connected to an external monitor) and the lid being closed. To work around this, I configured logind to ignore lid events and instead set up my own handling so I can decide whether the laptop should suspend or just disable the internal display when an external monitor is connected.
Here’s what I did in case anyone else runs into the same issue:
- Update
/etc/systemd/logind.confwith the following:
HandleLidSwitch=ignore
HandleLidSwitchDocked=ignore
- Create a scripts directory:
mkdir -p ~/.config/hypr/scripts
- Add these two scripts:
~/.config/hypr/scripts/lid-close.sh
#!/usr/bin/env bash
set -euo pipefail
# Adjust this if your internal panel has a different name:
INTERNAL="eDP-1"
# Count connected EXTERNAL connectors (HDMI/DP/USB-C alt-mode). Exclude eDP/LVDS/DSI.
connected_externals() {
local n=0
while IFS= read -r status; do
[[ "$status" == "connected" ]] && n=$((n+1))
done < <(for s in /sys/class/drm/card*-HDMI-A-*/status \
/sys/class/drm/card*-DP-*/status \
/sys/class/drm/card*-USB-C-*/status; do
[[ -e "$s" ]] && cat "$s"
done 2>/dev/null)
echo "$n"
}
EXT_N="$(connected_externals)"
if [[ "${EXT_N:-0}" -gt 0 ]]; then
# External present: turn off internal, keep running on the external
hyprctl keyword monitor "$INTERNAL,disable" >/dev/null
else
# No external: suspend the system
systemctl suspend
fi
~/.config/hypr/scripts/lid-open.sh
#!/usr/bin/env bash
set -euo pipefail
INTERNAL="eDP-1"
# Re-enable the laptop panel with preferred mode, automatic position, scale 2
hyprctl keyword monitor "$INTERNAL,preferred,auto-center-down,2" >/dev/null
Make them executable:
chmod +x ~/.config/hypr/scripts/lid-*.sh
- Finally, add these bindings to
~/.config/hypr/monitors.conf:
# On lid CLOSE: run our hybrid handler
bindl=,switch:on:Lid Switch,exec,~/.config/hypr/scripts/lid-close.sh
# On lid OPEN: re-enable the laptop panel
bindl=,switch:off:Lid Switch,exec,~/.config/hypr/scripts/lid-open.sh
Using a Thinkpad T480 with a 2560X1440 external monitor, worked perfectly (monitors.conf), including not connecting the display on system restart. Thanks!
I ended up doing .sh script that will monitor lid opening/closing and workspace migration from monitor to monitor
lid-monitor.sh
#!/bin/bash
# -----------------------------
# Configuration
# -----------------------------
LAPTOP_MONITOR="eDP-2"
EXTERNAL_MONITOR="HDMI-A-1"
LID_STATE_FILE="/proc/acpi/button/lid/LID0/state"
SLEEP_INTERVAL=1 # seconds between checks
# -----------------------------
# Helper function to check if external monitor is connected
# -----------------------------
is_external_connected() {
hyprctl monitors | grep -q "$EXTERNAL_MONITOR"
}
get_state() {
grep -oE 'open|closed' "$LID_STATE_FILE"
}
# Helper function to check if laptop monitor is enabled
is_laptop_enabled() {
hyprctl monitors -j | jq -r '.[] | select(.name == "'"$LAPTOP_MONITOR"'") | .disabled' | grep -q "false"
}
PREV_STATE=$(get_state)
# -----------------------------
# Initial state check
# -----------------------------
if [[ "$PREV_STATE" == "closed" ]] && is_laptop_enabled; then
echo "Initial state: Lid is closed and laptop monitor is enabled. Disabling laptop monitor..."
if is_external_connected; then
# Move workspaces from laptop monitor to external monitor
hyprctl workspaces -j | jq -r ".[] | select(.monitor == \"$LAPTOP_MONITOR\") | .id" | while read -r ws; do
hyprctl dispatch moveworkspacetomonitor $ws $EXTERNAL_MONITOR
done
fi
# Disable laptop monitor completely
hyprctl keyword monitor "$LAPTOP_MONITOR,disable"
fi
# -----------------------------
# Infinite loop
# -----------------------------
while true; do
# Make sure the lid file exists
if [[ ! -f "$LID_STATE_FILE" ]]; then
echo "LID state file not found!"
sleep 5
continue
fi
# Read current lid state
state=$(get_state)
if [[ "$state" == "$PREV_STATE" ]]; then
sleep $SLEEP_INTERVAL
continue
fi
echo "Lid state changed: $PREV_STATE -> $state"
PREV_STATE=$(get_state)
if [[ "$state" == "closed" ]]; then
if is_external_connected; then
# Move workspaces from laptop monitor to external monitor
hyprctl workspaces -j | jq -r ".[] | select(.monitor == \"$LAPTOP_MONITOR\") | .id" | while read -r ws; do
hyprctl dispatch moveworkspacetomonitor $ws $EXTERNAL_MONITOR
done
fi
# Disable laptop monitor completely
hyprctl keyword monitor "$LAPTOP_MONITOR,disable"
elif [[ "$state" == "open" ]]; then
# Re-enable laptop monitor
hyprctl keyword monitor "$LAPTOP_MONITOR,preferred,auto,1.25"
if ! is_external_connected; then
# Move all workspaces back to laptop monitor
hyprctl workspaces -j | jq -r ".[] | select(.monitor == \"$EXTERNAL_MONITOR\") | .id" | while read -r ws; do
hyprctl dispatch moveworkspacetomonitor $ws $LAPTOP_MONITOR
done
fi
fi
sleep $SLEEP_INTERVAL
done
and put this in hyrpland.con
exec-once = ~/.config/hypr/lid-monitor.sh
@ryanrhughes I can add @geass94 in a PR, do some testing on my own framework 13 and post my progress here?
I wish I found this topic earlier!
I went from the opposite by disabling internal monitor and setting up the external with a script just to move workspaces to the external monitor.
Thank you, works fine!
@ryanrhughes I can add @geass94 in a PR, do some testing on my own framework 13 and post my progress here?
This needs some kind of auto-detection. My laptop has also Type-C DP available, for second external monitor. That means multiple scenarios can exist. Later I will try to modify this to auto detection and test it with two external monitors. But also that should consider users monitor configuration like refresh rate, scaling etc. from monitors config file, instead of having them hardcoded here.
I applied the suggested bindl lines, but there are cases that cause issues. I have a Framework 13" 2.8k display and an Apple Studio Display:
bindl=,switch:on:Lid Switch,exec,hyprctl keyword monitor "eDP-1, disable" bindl=,switch:off:Lid Switch,exec,hyprctl keyword monitor "eDP-1, preferred, auto, auto"
Problems arise when I suspend the laptop: after an entire night in suspend, and the laptop is disconnected from the external display, Hyprland crashes with a weird screen where it suggests typing Ctrl + Alt + F3 to get a terminal prompt. Gemini suggested a possible cause: _What's happening is a race condition. When you open the lid, two things are happening at almost the same time:
- The System Resumes: The laptop's firmware and
systemdare waking the system from suspend. This involves re-initializing hardware, including the graphics drivers. - The
bindlFires: Your Hyprland config immediately sees theswitch:offsignal from the lid and instantly runshyprctl keyword monitor "eDP-1, preferred, auto, auto".
Hyprland crashes because your bindl command is telling it to reconfigure a monitor before the system's graphics drivers are fully awake and ready to be controlled. It's like trying to talk to someone who is still asleep—you get a crash instead of an answer._
I'm trying addind a delay on wake up:
bindl=,switch:off:Lid Switch,exec,sh -c 'sleep 1 && hyprctl keyword monitor "eDP-1, preferred, auto, auto"'
This is just a workaround, though. Solving this lid-closing problem is more complex than expected. @curtisspendlove , did you experience anything like that?
Now that there is no turning back for me, I experimented a bit with my displays. Here is what I have (found) beyond the lid close switches off display.
My hardware is:
PC: XPS 13 9310 │ ├: Intel Iris Xe Graphics @ 1.35 GHz [Integrated] │ ├: 3840x2160 @ 60 Hz (as 1920x1080) in 27" [External] │ ├: 3456x2160 @ 60 Hz (as 1297x811) in 13" [Built-in]Using
automight have surprising effects when you close and open the lid.After opening the lid, eDP-1 appeared right of DP-7, when it was left of it before. This is likely normal behavior, but might still be surprising.
The following hyprland config (getting myself some new glasses today):
env = GDK_SCALE, 2 monitor = eDP-1, preferred, auto-left, 2.666667 monitor = DP-7, preferred, auto, 2 bindl=,switch:on:Lid Switch,exec,hyprctl keyword monitor "eDP-1, disable" bindl=,switch:off:Lid Switch,exec,hyprctl keyword monitor "eDP-1, preferred, auto-left, 2.666667"Keeps positioning and resolution stable for me and things a pleasure to read.
This worked perfectly on my Thinkpad X1 Carbon 13th Gen! Thank you!