Skip to content

Instantly share code, notes, and snippets.

@miyl
Last active November 10, 2024 15:33
Show Gist options
  • Save miyl/7c4ebc95c5a02f84f36a769a3690cde6 to your computer and use it in GitHub Desktop.
Save miyl/7c4ebc95c5a02f84f36a769a3690cde6 to your computer and use it in GitHub Desktop.
A hyprland script for a laptop-external-monitor setup, toggling between which is in use
#! /usr/bin/env sh
# A hyprland script for a laptop-external-monitor setup, toggling between which is in use
# Launch at startup to make hyprland disable the internal monitor if an external monitor is detected and enabled
# Additionally it's called with a keybind to switch between a laptop monitor and an external display
# Ideally the conditional monitor behaviour was instead done directly in hyprland.conf, but I'm not sure whether that's possible
#
# Relevant info:
# - hyprctl monitors: identifies currently enabled monitors
# - hyprctl monitors all: identifies ALL connected monitors - including those not in use
#
# Suggested use:
# Add this line somewhere after the regular monitor configuration in hyprland.conf:
# exec = /path/to/hyprland-monitors-toggle.sh
# Add a keybind to run this script on demand:
# bind =,SomeKeyHere, exec, /path/to/hyprland-monitors-toggle.sh
move_all_workspaces_to_monitor() {
TARGET_MONITOR="$1"
hyprctl workspaces | grep ^workspace | cut --delimiter ' ' --fields 3 | xargs -I '{}' hyprctl dispatch moveworkspacetomonitor '{}' "$TARGET_MONITOR"
# Previous approach
#hyprctl swapactiveworkspaces $EXTERNAL_MONITOR $INTERNAL_MONITOR
}
# TODO: Detect these instead of hardcoding them
INTERNAL_MONITOR="ADD YOUR INTERNAL MONITOR NAME HERE"
EXTERNAL_MONITOR="ADD YOUR EXTERNAL MONITOR NAME HERE"
NUM_MONITORS=$(hyprctl monitors all | grep --count Monitor)
NUM_MONITORS_ACTIVE=$(hyprctl monitors | grep --count Monitor)
# For initial startup if you use hyprland's default monitor settings:
# Turn off the laptop monitor if it + another monitor is active
if [ "$NUM_MONITORS_ACTIVE" -ge 2 ] && hyprctl monitors | cut --delimiter ' ' --fields 2 | grep --quiet ^$INTERNAL_MONITOR; then
# Doing this I hopefully end up on workspace 1 on the external monitor rather than 2 at startup
move_all_workspaces_to_monitor $EXTERNAL_MONITOR
hyprctl keyword monitor "$INTERNAL_MONITOR, disable"
# Alternate fix to ensure I start on workspace 1
#hyprctl dispatch workspace 1
exit
fi
# For dynamically toggling which monitor is active later via a keybind
if [ "$NUM_MONITORS" -gt 1 ]; then # Handling multiple monitors
if hyprctl monitors | cut --delimiter ' ' --fields 2 | grep --quiet ^$EXTERNAL_MONITOR; then
hyprctl keyword monitor $INTERNAL_MONITOR,preferred,0x0,1
move_all_workspaces_to_monitor $INTERNAL_MONITOR
hyprctl keyword monitor "$EXTERNAL_MONITOR, disable"
else
hyprctl keyword monitor $EXTERNAL_MONITOR,preferred,0x0,1
move_all_workspaces_to_monitor $EXTERNAL_MONITOR
hyprctl keyword monitor "$INTERNAL_MONITOR, disable"
fi
else # If the external monitor is disconnected without running this script first, it might become the case that no monitor is on - therefore turn on the laptop monitor!
hyprctl keyword monitor $INTERNAL_MONITOR,preferred,0x0,1
move_all_workspaces_to_monitor $INTERNAL_MONITOR
fi
@stinobook
Copy link

Hello,

I edited line 36 to:
if hyprctl monitors | grep --quiet "\s$EXTERNAL_MONITOR"; then

Case:
INTERNAL_MONITOR="eDP-1"
EXTERNAL_MONITOR="DP-1"

line 36 would always be true due to the naming of my monitors, with the \s it will force a space before the name in the grep and thus work as intended!

thx for the script btw, loving it !

@miyl
Copy link
Author

miyl commented Jun 8, 2024

Thanks1

I just did a rewrite that will hopefully solve that issue, but strangely during testing I also noticed that the monitor switch - or at least the version above - occasionally crashes either Hyprland itself or XWayland. Very strange.
XWayland crashes should no longer bring Hyprland down with it in the upcoming version, though, but still.

  # Jun 08 12:37:38 cpu kernel: traps: Hyprland[54550] trap invalid opcode ip:64776e17ed94 sp:7fff2fcec150 error:0 in Hyprland[64776e17c000+338000]
  # Jun 08 12:37:38 cpu systemd[1]: Started Process Core Dump (PID 55366/UID 0).
  # Jun 08 12:37:39 cpu systemd-coredump[55367]: [🡕] Process 54550 (Hyprland) of user 1000 dumped core.

It's something in these three lines (beside the comment) that causes it:

    hyprctl keyword monitor "$INTERNAL_MONITOR, preferred, 0, auto"
    # Move workspaces from the external monitor to the internal
    hyprctl swapactiveworkspaces $EXTERNAL_MONITOR $INTERNAL_MONITOR
    hyprctl keyword monitor "$EXTERNAL_MONITOR, disable"

swapactiveworkspaces is there due to sometimes seeing a crash when there were windows on multiple workspaces.

@stinobook
Copy link

swapactiveworkspaces 1 0 (or 0 1, dont know which direction hyperland uses) instead of their names maybe ?

keep in mind it completely swaps workspaces.. see:

image

i think you're better off moving all (hidden) windows to a different workspace?
maybe with this: https://hyprland-community.github.io/pyprland/lost_windows.html

@miyl
Copy link
Author

miyl commented Jun 8, 2024

Good point, while it probably would work in my case since I only have one monitor open at a time it doesn't seem ideal.
I've put up a new version which moves them via the dispact moveworkspacetomonitor instead.

Also changed how the new monitor is enabled, which seems to've fixed the issue with the occasional crashes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment