Last active
June 19, 2024 14:32
-
-
Save Diaoul/4a33dfec9d80763a7f74ce8086bf5237 to your computer and use it in GitHub Desktop.
Arrange workspace on multiple monitors (Hyprland)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@yanboyang713 this is just regular kanshi stuff here: my monitor setup. Nothing really special to share.