157 lines
4.8 KiB
Nix
157 lines
4.8 KiB
Nix
{ lib, pkgs, ... }:
|
||
let
|
||
# Exact descriptions as reported by: hyprctl -j monitors | jq '.[].description'
|
||
mainDesc = "ASUSTek COMPUTER INC ASUS PG43U 0x01010101";
|
||
secondaryDesc = "Samsung Electric Company C34J79x HTRM900776";
|
||
|
||
mainMonitor = "desc:${mainDesc}";
|
||
secondaryMonitor = "desc:${secondaryDesc}";
|
||
|
||
hyprlandExtraOptions = {
|
||
exec-once = [
|
||
# Wait a moment for monitors/workspaces to settle, then "prime" 6 and return to 1
|
||
"sh -lc 'sleep 0.2; hyprctl dispatch workspace 7; sleep 0.02; hyprctl dispatch workspace 1'"
|
||
|
||
];
|
||
monitor = [
|
||
"${mainMonitor},3840x2160@97.98,0x0,1,transform,0"
|
||
"${secondaryMonitor},3440x1440@99.98,-1440x-640,1,transform,1"
|
||
];
|
||
workspace =
|
||
let
|
||
inherit (builtins) map toString;
|
||
inherit (lib) range;
|
||
mkWs = monitor: i: "${toString i},monitor:${monitor},persistent:true";
|
||
in
|
||
(map (mkWs mainMonitor) (range 1 6)) ++ (map (mkWs secondaryMonitor) (range 7 10));
|
||
};
|
||
|
||
moveScript = pkgs.writeShellScriptBin "hyprland-move-workspaces" ''
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
HYPRCTL='${pkgs.hyprland}/bin/hyprctl'
|
||
JQ='${pkgs.jq}/bin/jq'
|
||
SOCAT='${pkgs.socat}/bin/socat'
|
||
|
||
MAIN_DESC='${mainDesc}'
|
||
SEC_DESC='${secondaryDesc}'
|
||
|
||
get_socket() {
|
||
# socket2 carries the event stream
|
||
echo "${"$"}{XDG_RUNTIME_DIR}/hypr/${"$"}{HYPRLAND_INSTANCE_SIGNATURE}/.socket2.sock"
|
||
}
|
||
|
||
wait_for_hypr() {
|
||
# Wait until hyprctl works (Hyprland is up)
|
||
until ''${HYPRCTL} -j monitors >/dev/null 2>&1; do
|
||
sleep 0.5
|
||
done
|
||
}
|
||
|
||
mon_name_by_desc() {
|
||
# Resolve Hyprland "name" (e.g., DP-2) from human-friendly description
|
||
local desc="${"$"}1"
|
||
''${HYPRCTL} -j monitors \
|
||
| ''${JQ} -r --arg d "${"$"}desc" '.[] | select(.description == $d) | .name' \
|
||
| head -n1
|
||
}
|
||
|
||
place_workspaces() {
|
||
local mainName secName
|
||
mainName="$(mon_name_by_desc "${"$"}MAIN_DESC")"
|
||
secName="$(mon_name_by_desc "${"$"}SEC_DESC" || true)"
|
||
|
||
# Always keep 1–6 on the main monitor
|
||
for ws in 1 2 3 4 5 6; do
|
||
''${HYPRCTL} dispatch moveworkspacetomonitor "${"$"}ws" "${"$"}mainName" || true
|
||
done
|
||
|
||
if [ -n "${"$"}{secName:-}" ]; then
|
||
# Secondary is present ➜ put 7–10 on secondary
|
||
for ws in 7 8 9 10; do
|
||
''${HYPRCTL} dispatch moveworkspacetomonitor "${"$"}ws" "${"$"}secName" || true
|
||
done
|
||
else
|
||
# No secondary ➜ keep 7–10 on main
|
||
for ws in 7 8 9 10; do
|
||
''${HYPRCTL} dispatch moveworkspacetomonitor "${"$"}ws" "${"$"}mainName" || true
|
||
done
|
||
fi
|
||
}
|
||
|
||
watch_events() {
|
||
local sock
|
||
sock="$(get_socket)"
|
||
|
||
# If socket2 is missing for some reason, fall back to polling
|
||
if [ ! -S "${"$"}sock" ]; then
|
||
while :; do
|
||
place_workspaces
|
||
sleep 5
|
||
done
|
||
return
|
||
fi
|
||
|
||
# Subscribe to Hyprland events and react to monitor changes
|
||
''${SOCAT} - "UNIX-CONNECT:${"$"}sock" | while IFS= read -r line; do
|
||
case "${"$"}line" in
|
||
monitoradded*|monitorremoved*|activemonitor*|layoutchange*|createworkspace*)
|
||
place_workspaces
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
if [ "${"$"}{1:-}" = "--oneshot" ]; then
|
||
wait_for_hypr
|
||
place_workspaces
|
||
else
|
||
wait_for_hypr
|
||
place_workspaces
|
||
watch_events
|
||
fi
|
||
'';
|
||
in
|
||
{
|
||
options = { };
|
||
|
||
config = {
|
||
environment.systemPackages = [ moveScript ];
|
||
|
||
ringofstorms_common.desktopEnvironment.hyprland.extraOptions = hyprlandExtraOptions;
|
||
|
||
ringofstorms_common.desktopEnvironment.hyprland.hyprpaperSettings = {
|
||
mode = "fill"; # Wallpaper display mode: fill, fit, stretch, center, tile
|
||
|
||
preload = [
|
||
"${../_shared_assets/wallpapers/pixel_neon.png}"
|
||
];
|
||
|
||
wallpaper = [
|
||
"${mainMonitor},${../_shared_assets/wallpapers/pixel_neon.png}"
|
||
"${secondaryMonitor},${../_shared_assets/wallpapers/pixel_neon_v.png}"
|
||
];
|
||
};
|
||
|
||
# User-level systemd service that follows your Hyprland session and watches for monitor changes
|
||
# systemd.user.services.hyprland-move-workspaces = {
|
||
# description = "Keep workspaces 1–6 on main and 7–10 on secondary; react to monitor changes";
|
||
#
|
||
# # Start/stop with Hyprland specifically
|
||
# wantedBy = [ "hyprland-session.target" ];
|
||
# after = [ "hyprland-session.target" ];
|
||
# partOf = [ "hyprland-session.target" ];
|
||
# bindsTo = [ "hyprland-session.target" ];
|
||
# # Only start once Hyprland's event socket exists
|
||
# unitConfig.ConditionPathExistsGlob = "%t/hypr/*/.socket2.sock";
|
||
#
|
||
# serviceConfig = {
|
||
# Type = "simple";
|
||
# ExecStart = "${moveScript}/bin/hyprland-move-workspaces";
|
||
# Restart = "always";
|
||
# RestartSec = "2s";
|
||
# };
|
||
# };
|
||
};
|
||
}
|