-
-
Save Diaoul/4a33dfec9d80763a7f74ce8086bf5237 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
set -e | |
declare -i last_called=0 | |
declare -i throttle_by=4 | |
@throttle() { | |
local -i now=$(date +%s) | |
if (($now - $last_called > $throttle_by)) | |
then | |
# delay execution | |
sleep $throttle_by | |
# execute | |
"$@" | |
fi | |
last_called=$(date +%s) | |
} | |
function arrange_workspaces() { | |
# Maintain 10 workspaces across multiple monitors | |
# This script assumes that the monitors are in horizontal layout and already | |
# correctly setup | |
monitors_json=$(hyprctl monitors -j) | |
workspaces_json=$(hyprctl workspaces -j) | |
monitors=($(echo $monitors_json | jq -r '. | sort_by(.x) | .[].name')) | |
workspace_count=$(echo $workspaces_json | jq -r '. | length') | |
active_workspaces=($(echo $monitors_json | jq -r '. | sort_by(.x) | .[].activeWorkspace.id')) | |
echo "Detected ${#monitors[@]} monitors with $workspace_count workspaces and $(IFS=,; echo ${active_workspaces[*]}) active" | |
# create or fix workspaces | |
# this requires support for persistent workspaces | |
# see https://github.com/hyprwm/Hyprland/pull/3346 | |
for ((i = 1; i <= 10; i++)); do | |
workspace=$(echo $workspaces_json | jq -r ".[] | select(.id == $i)") | |
if [ -z "$workspace" ]; then | |
echo "Workspaces $i does not exist, creating it" | |
hyprctl dispatch workspace $i > /dev/null | |
hyprctl dispatch workspaceopt persistent > /dev/null | |
else | |
persistent=$(echo $workspace | jq -r ".persistent") | |
if [ "$persistent" = false ]; then | |
echo "Workspaces $i is not persistent, persisting it" | |
hyprctl dispatch workspace $i > /dev/null | |
hyprctl dispatch workspaceopt persistent > /dev/null | |
fi | |
fi | |
done | |
# assign and move workspaces | |
if [[ "${#monitors[@]}" == 1 ]]; then | |
for ((i = 10; i >= 1; i--)); do | |
echo "Moving workspace $i to ${monitors[0]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[0]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[0]} > /dev/null | |
done | |
elif [[ "${#monitors[@]}" == 2 ]]; then | |
for ((i = 10; i >= 6; i--)); do | |
echo "Moving workspace $i to ${monitors[1]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[1]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[1]} > /dev/null | |
done | |
hyprctl dispatch workspace 6 > /dev/null | |
for ((i = 5; i >= 1; i--)); do | |
echo "Moving workspace $i to ${monitors[0]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[0]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[0]} > /dev/null | |
done | |
elif [[ "${#monitors[@]}" == 3 ]]; then | |
for ((i = 10; i >= 8; i--)); do | |
echo "Moving workspace $i to ${monitors[2]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[2]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[2]} > /dev/null | |
done | |
for ((i = 7; i >= 4; i--)); do | |
echo "Moving workspace $i to ${monitors[1]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[1]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[1]} > /dev/null | |
done | |
for ((i = 3; i >= 1; i--)); do | |
echo "Moving workspace $i to ${monitors[0]}" | |
hyprctl keyword workspace "$i, monitor:${monitors[0]}" > /dev/null | |
hyprctl dispatch moveworkspacetomonitor $i ${monitors[0]} > /dev/null | |
done | |
else # more than 3 monitors... | |
echo "Too many monitors" | |
fi | |
for id in "${active_workspaces[@]}"; do | |
echo "Activating workspace $id" | |
hyprctl dispatch workspace $id > /dev/null | |
done | |
} | |
function configure_monitors() { | |
# rely an kanshi for profile detection and output configuration | |
# see https://todo.sr.ht/~emersion/kanshi/54#event-235509 | |
echo "Configuring monitors..." | |
kanshi > /dev/null 2>&1 & | |
sleep 1 | |
killall kanshi | |
# arrange workspaces to match the new configuration | |
echo "Configuring workspaces..." | |
arrange_workspaces | |
} | |
function handle { | |
if [[ ${1:0:12} == "monitoradded" ]]; then | |
echo "Event detected: monitor added" | |
@throttle configure_monitors | |
elif [[ ${1:0:14} == "monitorremoved" ]]; then | |
echo "Event detected: monitor removed" | |
@throttle configure_monitors | |
fi | |
} | |
cli_help() { | |
cli_name=${0##*/} | |
echo " | |
$cli_name | |
Hyprland monitors control | |
Usage: $cli_name [command] | |
Commands: | |
configure_monitors Configure monitors using kanshi | |
arrange_workspaces Arrange workspaces on monitors | |
listen Listen for hypr monitor events and arrange workspaces automatically | |
* Help | |
" | |
exit 1 | |
} | |
case "$1" in | |
configure_monitors) | |
configure_monitors | |
;; | |
arrange_workspaces) | |
arrange_workspaces | |
;; | |
listen) | |
echo "Listening to monitor events..." | |
socat - UNIX-CONNECT:/tmp/hypr/$(echo $HYPRLAND_INSTANCE_SIGNATURE)/.socket2.sock | while read line; do handle $line; done | |
;; | |
*) | |
cli_help | |
;; | |
esac |
Yes, I have a script that listens to Hyprland's events monitoradded
and monitorremoved
, throttles that a bit (for when I plug multiple monitors at the same time with the dock) and executes:
- Configuring the monitors using kanshi
- Run this script to arrange the workspaces
Works pretty well, I'll share my config in my dotfiles soon ™️
@Diaoul Hey this is great! Could you write a short tutorial with you config for noobs (not me :P) to set this up? Cheers!
Hello @Diaoul,
Good day to you,
Could you share your kanshi.service file and ~/.config/kanshi/config
Thanks for your help,
Boyang Yan
Updated my gist to a newer version that uses a fork with persistent workspaces (PR)
Notable changes:
- CLI format with different functions
configure_monitors
uses kanshi to apply monitor configuration on resolution and scalingarrange_workspace
arranges workspaces on monitors (like previous version)listen
will apply changes on monitor change detected on hyprland socket
- Replace usage of deprecated
wsbind
by a workspace rule - Try to re-activate the previously active workspace
- Create workspaces and flag them as persistent
@yanboyang713 this is just regular kanshi stuff here: my monitor setup. Nothing really special to share.
Associated Hyprland config
exec-once = ~/.config/hypr/scripts/monitors.sh listen
exec= ~/.config/hypr/scripts/monitors.sh configure_monitors
Thanks @Diaoul
Thanks for share
First of all, thank you so much for this script it's really helped! Second of all, I have noticed a odd b
2023-11-21.16-29-18.mp4
ug where if i press super 6 to go to the 6th workspace but my mouse is on the first monitor itll bring the 6th workspace to the first monitors screen. it will also do the same if im on the second monitor and go to say the 4th tab. I have also noticed that it snaps my cursor on the 4th workspace to the second monitor rather than the 6th (super 6) in my case
here is a video recording
and here is my config
// Workspaces
"hyprland/workspaces" : {
"on-click": "activate",
"active-only": false,
"all-outputs": false,
"format": "{}",
"format-icons": {
"urgent": "",
"active": "",
"default": ""
},
"persistent_workspaces": {
"1": ["DP-1"],
"2": ["DP-1"],
"3": ["DP-1"],
"4": ["DP-1"],
"5": ["DP-1"],
"6": ["DP-2"],
"7": ["DP-2"],
"8": ["DP-2"],
"9": ["DP-2"],
"10": ["DP-2"]
}
```
and here are my shortcuts
```
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
again thank you so much for this script @Diaoul
Wow. Thanks for sharing this!
Is there a way to automatically trigger this script on plugging in an external monitor?