From ce96ec6bf7679c8dbfc068bc6a2911b0f12c75b0 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Fri, 14 Feb 2025 20:24:25 +0000 Subject: [PATCH] Add multi-monitor support Signed-off-by: Nikolaos Karaolidis --- .../user/gui/astal/config/widget/Bar.tsx | 16 ++- .../config/widget/components/Workspaces.tsx | 45 ++++--- .../configs/user/gui/hyprland/default.nix | 118 ++++++++++-------- .../configs/user/gui/hyprland/options.nix | 2 +- .../configs/user/gui/hyprland/scripts/bind.sh | 24 ++++ .../gui/hyprland/{ => scripts}/monitors.sh | 0 hosts/eirene/hardware/display.nix | 39 +++++- 7 files changed, 163 insertions(+), 81 deletions(-) create mode 100644 hosts/common/configs/user/gui/hyprland/scripts/bind.sh rename hosts/common/configs/user/gui/hyprland/{ => scripts}/monitors.sh (100%) diff --git a/hosts/common/configs/user/gui/astal/config/widget/Bar.tsx b/hosts/common/configs/user/gui/astal/config/widget/Bar.tsx index 49953f4..416565d 100644 --- a/hosts/common/configs/user/gui/astal/config/widget/Bar.tsx +++ b/hosts/common/configs/user/gui/astal/config/widget/Bar.tsx @@ -3,12 +3,24 @@ import Launcher from './components/Launcher'; import Workspace from './components/Workspaces'; import Date from './components/Date'; import Systray from './components/Tray'; +import Hyprland from "gi://AstalHyprland"; const anchor = Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT; -export default (monitor: Gdk.Monitor) => - + diff --git a/hosts/common/configs/user/gui/astal/config/widget/components/Workspaces.tsx b/hosts/common/configs/user/gui/astal/config/widget/components/Workspaces.tsx index ab87b6f..976771f 100644 --- a/hosts/common/configs/user/gui/astal/config/widget/components/Workspaces.tsx +++ b/hosts/common/configs/user/gui/astal/config/widget/components/Workspaces.tsx @@ -1,28 +1,23 @@ -import { bind, Binding, Variable } from "astal"; +import { bind, Variable } from "astal"; import Hyprland from "gi://AstalHyprland"; import { range } from '../../lib'; const hyprland = Hyprland.get_default(); -const Workspace = ({ id }: { id: number }) => { +const Workspace = ({ workspace }: { workspace: Hyprland.Workspace }) => { const className = Variable.derive( - [bind(hyprland, "workspaces"), bind(hyprland, "focusedWorkspace")], - (workspaces, focused) => { - const workspace = workspaces.find((w) => w.id === id); - - if (!workspace) return "button"; - - const occupied = workspace.get_clients().length > 0; - const active = focused.id === id; - - return `button ${active ? "active" : occupied && "occupied"}`; + [bind(hyprland, "focusedWorkspace"), bind(workspace, "clients")], + (focused, clients) => { + if (focused.id == workspace.id) return "button active"; + if (clients.length > 0) return "button occupied"; + return "button"; }, ); return hyprland.dispatch("workspace", `${id}`)} + onClickRelease={() => hyprland.dispatch("workspace", `${workspace.id}`)} > ; }; -export default () => { - hyprland.dispatch("workspace", e.delta_y > 0 ? "+1" : "-1"); - }} -> - - {range(10).map((i) => )} - - +export default ({ monitor }: { monitor: Hyprland.Monitor }) => { + const workspaces = hyprland.get_workspaces().filter(w => w.monitor.id == monitor.id).sort((w1, w2) => w1.id - w2.id); + + return { + hyprland.dispatch("workspace", e.delta_y > 0 ? "m+1" : "m-1"); + }} + > + + {workspaces.map((w) => )} + + ; +}; diff --git a/hosts/common/configs/user/gui/hyprland/default.nix b/hosts/common/configs/user/gui/hyprland/default.nix index 22bf89f..bb9cbfa 100644 --- a/hosts/common/configs/user/gui/hyprland/default.nix +++ b/hosts/common/configs/user/gui/hyprland/default.nix @@ -21,67 +21,77 @@ "$mod" = "Super_L"; "$term" = lib.meta.getExe pkgs.kitty; - bind = [ - "$mod, Return, exec, $term" + bind = + let + bindHelper = lib.meta.getExe ( + pkgs.writeShellApplication { + name = "hyprland-bind-helper"; + bashOptions = [ + "errexit" + "pipefail" + ]; + runtimeInputs = with pkgs; [ hyprland ]; + text = builtins.readFile ./scripts/bind.sh; + } + ); + in + [ + "$mod, Return, exec, $term" - "$mod, `, togglespecialworkspace" - "$mod, 1, workspace, 1" - "$mod, 2, workspace, 2" - "$mod, 3, workspace, 3" - "$mod, 4, workspace, 4" - "$mod, 5, workspace, 5" - "$mod, 6, workspace, 6" - "$mod, 7, workspace, 7" - "$mod, 8, workspace, 8" - "$mod, 9, workspace, 9" - "$mod, 0, workspace, 10" + "$mod, 1, exec, ${bindHelper} 1" + "$mod, 2, exec, ${bindHelper} 2" + "$mod, 3, exec, ${bindHelper} 3" + "$mod, 4, exec, ${bindHelper} 4" + "$mod, 5, exec, ${bindHelper} 5" + "$mod, 6, exec, ${bindHelper} 6" + "$mod, 7, exec, ${bindHelper} 7" + "$mod, 8, exec, ${bindHelper} 8" + "$mod, 9, exec, ${bindHelper} 9" + "$mod, 0, exec, ${bindHelper} 10" - "$mod_Shift, `, movetoworkspacesilent, special" - "$mod_Shift, 1, movetoworkspacesilent, 1" - "$mod_Shift, 2, movetoworkspacesilent, 2" - "$mod_Shift, 3, movetoworkspacesilent, 3" - "$mod_Shift, 4, movetoworkspacesilent, 4" - "$mod_Shift, 5, movetoworkspacesilent, 5" - "$mod_Shift, 6, movetoworkspacesilent, 6" - "$mod_Shift, 7, movetoworkspacesilent, 7" - "$mod_Shift, 8, movetoworkspacesilent, 8" - "$mod_Shift, 9, movetoworkspacesilent, 9" - "$mod_Shift, 0, movetoworkspacesilent, 10" + "$mod_Shift, 1, exec, ${bindHelper} 1 move" + "$mod_Shift, 2, exec, ${bindHelper} 2 move" + "$mod_Shift, 3, exec, ${bindHelper} 3 move" + "$mod_Shift, 4, exec, ${bindHelper} 4 move" + "$mod_Shift, 5, exec, ${bindHelper} 5 move" + "$mod_Shift, 6, exec, ${bindHelper} 6 move" + "$mod_Shift, 7, exec, ${bindHelper} 7 move" + "$mod_Shift, 8, exec, ${bindHelper} 8 move" + "$mod_Shift, 9, exec, ${bindHelper} 9 move" + "$mod_Shift, 0, exec, ${bindHelper} 1 move0" - "$mod_Ctrl, Space, workspaceopt, allfloat" + "$mod, left, movefocus, l" + "$mod, h, movefocus, l" + "$mod, down, movefocus, d" + "$mod, j, movefocus, d" + "$mod, up, movefocus, u" + "$mod, k, movefocus, u" + "$mod, right, movefocus, r" + "$mod, l, movefocus, r" - "$mod, left, movefocus, l" - "$mod, h, movefocus, l" - "$mod, down, movefocus, d" - "$mod, j, movefocus, d" - "$mod, up, movefocus, u" - "$mod, k, movefocus, u" - "$mod, right, movefocus, r" - "$mod, l, movefocus, r" + "$mod_Shift, left, movewindow, l" + "$mod_Shift, h, movewindow, l" + "$mod_Shift, down, movewindow, d" + "$mod_Shift, j, movewindow, d" + "$mod_Shift, up, movewindow, u" + "$mod_Shift, k, movewindow, u" + "$mod_Shift, right, movewindow, r" + "$mod_Shift, l, movewindow, r" - "$mod_Shift, left, movewindow, l" - "$mod_Shift, h, movewindow, l" - "$mod_Shift, down, movewindow, d" - "$mod_Shift, j, movewindow, d" - "$mod_Shift, up, movewindow, u" - "$mod_Shift, k, movewindow, u" - "$mod_Shift, right, movewindow, r" - "$mod_Shift, l, movewindow, r" + "$mod, Tab, cyclenext" + "$mod, Tab, bringactivetotop" + "$mod_Shift, Tab, cyclenext, prev" + "$mod_Shift, Tab, bringactivetotop" - "$mod, Tab, cyclenext" - "$mod, Tab, bringactivetotop" - "$mod_Shift, Tab, cyclenext, prev" - "$mod_Shift, Tab, bringactivetotop" + "$mod, f, fullscreen, 0" + "$mod, m, fullscreen, 1" + "$mod, p, pin" + "$mod, Space, togglefloating" + "$mod, Space, centerwindow" + "$mod, q, killactive" - "$mod, f, fullscreen, 0" - "$mod, m, fullscreen, 1" - "$mod, p, pin" - "$mod, Space, togglefloating" - "$mod, Space, centerwindow" - "$mod, q, killactive" - - "Ctrl_Alt, Delete, exit" - ]; + "Ctrl_Alt, Delete, exit" + ]; binde = [ "$mod_Ctrl, left, resizeactive, -20 0" diff --git a/hosts/common/configs/user/gui/hyprland/options.nix b/hosts/common/configs/user/gui/hyprland/options.nix index 17e0120..af9e07d 100644 --- a/hosts/common/configs/user/gui/hyprland/options.nix +++ b/hosts/common/configs/user/gui/hyprland/options.nix @@ -43,7 +43,7 @@ in systemd ]; runtimeEnv.SERVICES = lib.strings.concatStringsSep " " cfg.onMonitorChange.services; - text = builtins.readFile ./monitors.sh; + text = builtins.readFile ./scripts/monitors.sh; } ) } &"; diff --git a/hosts/common/configs/user/gui/hyprland/scripts/bind.sh b/hosts/common/configs/user/gui/hyprland/scripts/bind.sh new file mode 100644 index 0000000..8dbcf1d --- /dev/null +++ b/hosts/common/configs/user/gui/hyprland/scripts/bind.sh @@ -0,0 +1,24 @@ +BASE_WS="$1" +ACTION="$2" + +current_ws_id="$(hyprctl -j activeworkspace | jq -r '.id')" + +ws_json="$(hyprctl -j workspaces)" +max_ws_id="$(echo "$ws_json" | jq -r '[.[] | .id] | max')" + +BLOCK_SIZE=10 + +total_blocks=$(((max_ws_id - 1) / BLOCK_SIZE + 1)) +current_block=$(((current_ws_id - 1) / BLOCK_SIZE)) +target_ws=$((current_block * BLOCK_SIZE + BASE_WS)) + +if [ "$target_ws" -eq "$current_ws_id" ]; then + next_block=$(( (current_block + 1) % total_blocks )) + target_ws=$(( next_block * BLOCK_SIZE + BASE_WS )) +fi + +if [ "$ACTION" = "move" ]; then + hyprctl dispatch movetoworkspacesilent "$target_ws" +else + hyprctl dispatch workspace "$target_ws" +fi diff --git a/hosts/common/configs/user/gui/hyprland/monitors.sh b/hosts/common/configs/user/gui/hyprland/scripts/monitors.sh similarity index 100% rename from hosts/common/configs/user/gui/hyprland/monitors.sh rename to hosts/common/configs/user/gui/hyprland/scripts/monitors.sh diff --git a/hosts/eirene/hardware/display.nix b/hosts/eirene/hardware/display.nix index b73e0e2..994a7b2 100644 --- a/hosts/eirene/hardware/display.nix +++ b/hosts/eirene/hardware/display.nix @@ -17,7 +17,44 @@ home-manager.sharedModules = [ { - wayland.windowManager.hyprland.settings.monitor = "eDP-1, 2560x1600@165, 0x0, 1.25"; + wayland.windowManager.hyprland.settings = { + monitor = [ + "eDP-1, 2560x1600@165, 0x0, 1.25" + "HDMI-A-1, 5120x1440@144, -1536x-1440, 1" + ]; + + general = { + layout = "master"; + }; + + master = { + slave_count_for_center_master = 0; + mfact = 0.5; + }; + + workspace = [ + "1, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "2, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "3, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "4, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "5, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "6, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "7, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "8, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "9, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "10, monitor:eDP-1, layoutopt:orientation:left, persistent:true" + "11, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "12, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "13, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "14, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "15, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "16, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "17, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "18, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "19, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + "20, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" + ]; + }; programs = { vscode.userSettings."window.zoomLevel" = (1.25 - 1) / 0.2;