diff --git a/common/desktop_environment/hyprland/home_manager/hyprland.nix b/common/desktop_environment/hyprland/home_manager/hyprland.nix index 4f3de04..409d94f 100644 --- a/common/desktop_environment/hyprland/home_manager/hyprland.nix +++ b/common/desktop_environment/hyprland/home_manager/hyprland.nix @@ -29,8 +29,17 @@ in # "waybar" # ]; - # Default monitor configuration - monitor = "monitor = , preferred, auto, 1"; + # Default monitor configuration + monitor = "monitor = , preferred, auto, 1"; + + # Make workspaces 7-10 always on MONITOR-2 (replace DP-2 if your secondary isn't DP-2) + # You can get the name of your monitor via `hyprctl monitors` + workspace = [ + "7, monitor:DP-2, persistent:true" + "8, monitor:DP-2, persistent:true" + "9, monitor:DP-2, persistent:true" + "10, monitor:DP-2, persistent:true" + ]; windowrulev2 = [ "float, class:^(?i)chrome-nngceckbapebfimnlniiiahkandclblb-Default$, initialtitle:^_crx_nngceckbapebfimnlniiiahkandclblb$" diff --git a/common/flake.lock b/common/flake.lock index c2fa076..a1d6c11 100644 --- a/common/flake.lock +++ b/common/flake.lock @@ -85,11 +85,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1753592768, - "narHash": "sha256-oV695RvbAE4+R9pcsT9shmp6zE/+IZe6evHWX63f2Qg=", + "lastModified": 1755928099, + "narHash": "sha256-OILVkfhRCm8u18IZ2DKR8gz8CVZM2ZcJmQBXmjFLIfk=", "owner": "rycee", "repo": "home-manager", - "rev": "fc3add429f21450359369af74c2375cb34a2d204", + "rev": "4a44fb9f7555da362af9d499817084f4288a957f", "type": "github" }, "original": { diff --git a/hosts/lio/flake.lock b/hosts/lio/flake.lock index be8c94d..b5a5b8e 100644 --- a/hosts/lio/flake.lock +++ b/hosts/lio/flake.lock @@ -25,55 +25,8 @@ "type": "github" } }, - "caelestia": { - "inputs": { - "caelestia-cli": "caelestia-cli", - "nixpkgs": "nixpkgs", - "quickshell": "quickshell" - }, - "locked": { - "lastModified": 1756116835, - "narHash": "sha256-Vs2zMLYoVdUhbL+Wtg+AactV4V7vyeKDCVdibLhRe+Q=", - "owner": "caelestia-dots", - "repo": "shell", - "rev": "783057ab0d694de7f3d79e96851bcdcfe1965cbd", - "type": "github" - }, - "original": { - "owner": "caelestia-dots", - "repo": "shell", - "type": "github" - } - }, - "caelestia-cli": { - "inputs": { - "caelestia-shell": [ - "common", - "caelestia" - ], - "nixpkgs": [ - "common", - "caelestia", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1755952278, - "narHash": "sha256-Y4F8sFJ3P3MExSuwDAnccfG1RxU4VdoW9yDRtDqG8qA=", - "owner": "caelestia-dots", - "repo": "cli", - "rev": "db1e0da5bbd259f1218b4ae54d0327b0c4a46f78", - "type": "github" - }, - "original": { - "owner": "caelestia-dots", - "repo": "cli", - "type": "github" - } - }, "common": { "inputs": { - "caelestia": "caelestia", "home-manager": "home-manager", "nix-flatpak": "nix-flatpak", "ragenix": "ragenix" @@ -147,7 +100,7 @@ }, "home-manager": { "inputs": { - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs" }, "locked": { "lastModified": 1753592768, @@ -205,16 +158,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1755615617, - "narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", - "owner": "nixos", + "lastModified": 1753345091, + "narHash": "sha256-CdX2Rtvp5I8HGu9swBmYuq+ILwRxpXdJwlpg8jvN4tU=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "20075955deac2583bb12f07151c2df830ef346b4", + "rev": "3ff0e34b1383648053bba8ed03f201d3466f90c9", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "NixOS", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } @@ -236,22 +189,6 @@ } }, "nixpkgs_2": { - "locked": { - "lastModified": 1753345091, - "narHash": "sha256-CdX2Rtvp5I8HGu9swBmYuq+ILwRxpXdJwlpg8jvN4tU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "3ff0e34b1383648053bba8ed03f201d3466f90c9", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-25.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { "locked": { "lastModified": 1741379970, "narHash": "sha256-Wh7esNh7G24qYleLvgOSY/7HlDUzWaL/n4qzlBePpiw=", @@ -267,7 +204,7 @@ "type": "github" } }, - "nixpkgs_4": { + "nixpkgs_3": { "locked": { "lastModified": 1755471983, "narHash": "sha256-axUoWcm4cNQ36jOlnkD9D40LTfSQgk8ExfHSRm3rTtg=", @@ -283,7 +220,7 @@ "type": "github" } }, - "nixpkgs_5": { + "nixpkgs_4": { "locked": { "lastModified": 1755648324, "narHash": "sha256-+2TxwJEXWXGC7JBsRGUHtmQ66lRGPcDI2kFKTTU5e2s=", @@ -298,7 +235,7 @@ "type": "github" } }, - "nixpkgs_6": { + "nixpkgs_5": { "locked": { "lastModified": 1755186698, "narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=", @@ -1195,28 +1132,6 @@ } }, "quickshell": { - "inputs": { - "nixpkgs": [ - "common", - "caelestia", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1753595452, - "narHash": "sha256-vqkSDvh7hWhPvNjMjEDV4KbSCv2jyl2Arh73ZXe274k=", - "ref": "refs/heads/master", - "rev": "a5431dd02dc23d9ef1680e67777fed00fe5f7cda", - "revCount": 665, - "type": "git", - "url": "https://git.outfoxxed.me/outfoxxed/quickshell" - }, - "original": { - "type": "git", - "url": "https://git.outfoxxed.me/outfoxxed/quickshell" - } - }, - "quickshell_2": { "inputs": { "nixpkgs": [ "zaphkiel", @@ -1242,7 +1157,7 @@ "agenix": "agenix", "crane": "crane", "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs_3", + "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" }, "locked": { @@ -1262,7 +1177,7 @@ "root": { "inputs": { "common": "common", - "nixpkgs": "nixpkgs_4", + "nixpkgs": "nixpkgs_3", "nixpkgs-unstable": "nixpkgs-unstable", "ros_neovim": "ros_neovim", "zaphkiel": "zaphkiel" @@ -1270,7 +1185,7 @@ }, "ros_neovim": { "inputs": { - "nixpkgs": "nixpkgs_5", + "nixpkgs": "nixpkgs_4", "nvim_plugin-Almo7aya/openingh.nvim": "nvim_plugin-Almo7aya/openingh.nvim", "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim": "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim", "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring": "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring", @@ -1432,8 +1347,8 @@ }, "zaphkiel": { "inputs": { - "nixpkgs": "nixpkgs_6", - "quickshell": "quickshell_2", + "nixpkgs": "nixpkgs_5", + "quickshell": "quickshell", "systems": "systems_3" }, "locked": { diff --git a/hosts/lio/flake.nix b/hosts/lio/flake.nix index 2fe3978..dc9be42 100644 --- a/hosts/lio/flake.nix +++ b/hosts/lio/flake.nix @@ -43,6 +43,7 @@ ./hardware-configuration.nix (import ./containers.nix { inherit inputs; }) # ./jails_text.nix + ./hyprland_customizations.nix ( { config, @@ -104,26 +105,6 @@ enable = true; waybar.enable = true; swaync.enable = true; - extraOptions = - let - main = "desc:ASUSTek COMPUTER INC ASUS PG43U 0x01010101"; - secondary = "desc:Samsung Electric Company C34J79x HTRM900776"; - in - { - # hyprctl monitors all - monitor = [ - "${main},3840x2160@97.98,0x0,1,transform,0" - "${secondary},3440x1440@99.98,-1440x-640,1,transform,1" - ]; - # Pin workspaces 1-6 to main monitor and rest on other monitor - workspace = - let - inherit (builtins) map toString; - inherit (lib) range; - mkWs = monitor: i: "${toString i},monitor:${monitor}"; - in - (map (mkWs main) (range 1 6)) ++ (map (mkWs secondary) (range 7 10)); - }; }; programs = { qFlipper.enable = true; diff --git a/hosts/lio/hyprland_customizations.nix b/hosts/lio/hyprland_customizations.nix new file mode 100644 index 0000000..302a117 --- /dev/null +++ b/hosts/lio/hyprland_customizations.nix @@ -0,0 +1,137 @@ +{ 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 = { + 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}"; + 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*) + 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 ]; + + # Pass the options to home-manager for hyprland (as you already do) + ringofstorms_common.desktopEnvironment.hyprland.extraOptions = hyprlandExtraOptions; + + # 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"; + wants = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + + serviceConfig = { + Type = "simple"; + ExecStart = "${moveScript}/bin/hyprland-move-workspaces"; + Restart = "always"; + RestartSec = "2s"; + }; + + wantedBy = [ "graphical-session.target" ]; + }; + }; +}