Using Hyprland in clamshell mode

Well it's been several years since I posted anything here and looking back at my posts from 2022 I definitely can see some evolution in my interests. Which is a good thing I think!

These days I'm doing less 'front of the frontend' work and more 'back of the frontend' and backend work. And my outside of work interests have definitely turned more towards the backend of the stack. Reckon I might build something in Go soon, as a language the features look really interesting to me.

Anyway, to the topic of today's post. Hyprland and clamshell mode.

What is Hyprland?

Hyprland is a display server for linux systems which uses the Wayland compositor.

A few months back I picked up a Thinkpad T480 for about £400 and I'm running Arch linux on it with Hyprland as the display manager. It's been fun tinkering with it, but I use laptops at my desk in clamshell mode (with the lid closed) pretty frequently and the laptop would suspend when I closed the lid instead of just displaying on the external monitor and staying awake which was frustrating me.

So how can we use this kind of system and implement a working clamshell mode?

How to clamshell with Hyprland and Systemd

Systemd HandleLidSwitch

Since this setup uses systemd to handle lots of system and user functions we'll need to consider how to disable the default behaviour for the laptop lid closing.

To see what systemd is currently configured to do when you close the laptop lid, check the HandleLidSwitch config in /etc/systemd/logind.conf.

We can use cat and grep for this, or a tool like fzf if you prefer.

cat /etc/systemd/logind.conf | grep "HandleLidSwitch="

The output will be something like: #HandleLidSwitch=suspend, meaning that systemd will suspend the system when the lid is closed. Use your editor of choice and edit this file to change suspend to ignore on that line.

Now systemd will ignore the lid close action.

Hyprland config and clamshell script

When I was looking around for a way to implement this I came across this blog post. This was the key to getting clamshell mode working on Hyprland.

Basically the idea is have a script run whenever the state of the lid (open vs closed) changes, and have that script check the currently connected monitors to determine what the display settings should be.

First we need to know the names of our displays as Hyprland sees them.

We can use hyprctl like so:

hyprctl monitors

There'll be some output here that gives you the names of the connected displays according to Hyprland.

Mine were eDP-1 and HDMI-A-2.

Next I modified the script I found so the regex would match my external display name (HDMI-). Here's my version:

#!/usr/bin/env zsh

if [[ "$(hyprctl monitors)" =~ "\sHDMI-+" ]]; then
  if [[ $1 == "open" ]]; then
    hyprctl keyword monitor "eDP-1,1920x1080,2560x0,1"
  else
    hyprctl keyword monitor "eDP-1,disable"
  fi
fi

I put this in a file in the same directory as my hyprland config file and named it clamshell_mode.sh.

Then in the hyprland config itself:

######################
### CLAMSHELL MODE ###
######################

## Lid is opened
bindl=,switch:off:Lid Switch,exec,~/.config/hypr/clamshell_mode.sh open

## Lid is closed
bindl=,switch:on:Lid Switch,exec,~/.config/hypr/clamshell_mode.sh close

And that was it!

There are still a few minor annoyances, for example my lock screen is activated when the lid closes so I have to type my password when I actually enter clamshell mode, but other than that it works great and wasn't particularly complicated to setup.