-
-
Save miyl/7c4ebc95c5a02f84f36a769a3690cde6 to your computer and use it in GitHub Desktop.
#! /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 |
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:
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
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 dispatch moveworkspacetomonitor
instead.
Also changed how the new monitor is enabled, which seems to've fixed the issue with the occasional crashes.
I had some issues where the script stopped randomly working and enabled my internal monitor again. Not sure why exactly but i have been working on a different implementation using Hyprlands IPC socket (hyprctl-like requests) and socket2 (live events).
I have not managed to make the hyprctl-like requests work for socket. For example monitors
works exactly like it does with hyprctl but workspaces
returns nothing. What i did make work however was listing to socket2 events, so this would eliminate the need for manual reloading of the config for you script. Here is a example:
# Handle socket events from hyprland socket2
handleEvents() {
case $event in
monitoradded* | monitoraddedv2*)
moveAllWorkspacesToMonitor "$EXTERNAL_MONITOR"
hyprctl keyword monitor "$INTERNAL_MONITOR disable"
;;
monitorremoved*)
hyprctl keyword monitor "$INTERNAL_MONITOR,preferred,0x0,2"
moveAllWorkspacesToMonitor "$INTERNAL_MONITOR"
;;
*)
// ignore all other events or use them somehow else
;;
esac
}
# Listen to live events from hyprland socket2 continuously
socat -U - UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock | while read -r line; do handleEvents "$line"; done
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.
It's something in these three lines (beside the comment) that causes it:
swapactiveworkspaces
is there due to sometimes seeing a crash when there were windows on multiple workspaces.