diff --git a/home/linux/gui/hyprland/default.nix b/home/linux/gui/hyprland/default.nix index 3ed74b7a..7318026f 100644 --- a/home/linux/gui/hyprland/default.nix +++ b/home/linux/gui/hyprland/default.nix @@ -4,13 +4,12 @@ lib, ... }@args: -with lib; let cfg = config.modules.desktop.hyprland; in { options.modules.desktop.hyprland = { - enable = mkEnableOption "hyprland compositor"; + enable = lib.mkEnableOption "hyprland compositor"; settings = lib.mkOption { type = with lib.types; @@ -34,11 +33,13 @@ in }; }; - config = mkIf cfg.enable (mkMerge ([ - { - wayland.windowManager.hyprland.settings = cfg.settings; - } - (import ./hyprland.nix args) - (import ./xdg.nix args) - ])); + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + wayland.windowManager.hyprland.settings = cfg.settings; + } + (import ./hyprland.nix args) + (import ./xdg.nix args) + ] + ); } diff --git a/home/linux/gui/niri/default.nix b/home/linux/gui/niri/default.nix index b88af749..e835d504 100644 --- a/home/linux/gui/niri/default.nix +++ b/home/linux/gui/niri/default.nix @@ -34,567 +34,26 @@ in }; }; - config = lib.mkIf cfg.enable { - # NOTE: this executable is used by greetd to start a wayland session when system boot up - # with such a vendor-no-locking script, we can switch to another wayland compositor without modifying greetd's config in NixOS module - home.file.".wayland-session" = { - source = pkgs.writeScript "init-session" '' - # trying to stop a previous niri session - systemctl --user is-active niri.service && systemctl --user stop niri.service - # and then we start a new one - /run/current-system/sw/bin/niri-session - ''; - executable = true; - }; + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + # NOTE: this executable is used by greetd to start a wayland session when system boot up + # with such a vendor-no-locking script, we can switch to another wayland compositor without modifying greetd's config in NixOS module + home.file.".wayland-session" = { + source = pkgs.writeScript "init-session" '' + # trying to stop a previous niri session + systemctl --user is-active niri.service && systemctl --user stop niri.service + # and then we start a new one + /run/current-system/sw/bin/niri-session + ''; + executable = true; + }; + } + (import ./settings.nix niri) + (import ./keybindings.nix niri) + (import ./spawn-at-startup.nix niri) + (import ./windowrules.nix niri) + ] + ); - programs.niri.config = - let - inherit (niri.lib.kdl) - node - plain - leaf - flag - ; - in - cfg.settings - ++ [ - (plain "input" [ - (plain "keyboard" [ - (plain "xkb" [ - # You can set rules, model, layout, variant and options. - # For more information, see xkeyboard-config(7). - - # For example: - # (leaf "layout" "us,ru") - # (leaf "options" "grp:win_space_toggle,compose:ralt,ctrl:nocaps") - ]) - - # You can set the keyboard repeat parameters. The defaults match wlroots and sway. - # Delay is in milliseconds before the repeat starts. Rate is in characters per second. - # (leaf "repeat-delay" 600) - # (leaf "repeat-rate" 25) - - # Niri can remember the keyboard layout globally (the default) or per-window. - # - "global" - layout change is global for all windows. - # - "window" - layout is tracked for each window individually. - # (leaf "track-layout" "global") - ]) - - # Next sections include libinput settings. - # Omitting settings disables them, or leaves them at their default values. - (plain "touchpad" [ - (flag "tap") - # (flag "dwt") - # (flag "dwtp") - (flag "natural-scroll") - # (leaf "accel-speed" 0.2) - # (leaf "accel-profile" "flat") - # (leaf "tap-button-map" "left-middle-right") - ]) - - (plain "mouse" [ - # (flag "natural-scroll") - # (leaf "accel-speed" 0.2) - # (leaf "accel-profile" "flat") - ]) - - # By default, niri will take over the power button to make it sleep - # instead of power off. - # Uncomment this if you would like to configure the power button elsewhere - # (i.e. logind.conf). - # (flag "disable-power-key-handling") - ]) - - (plain "layout" [ - # By default focus ring and border are rendered as a solid background rectangle - # behind windows. That is, they will show up through semitransparent windows. - # This is because windows using client-side decorations can have an arbitrary shape. - # - # If you don't like that, you should uncomment `prefer-no-csd` below. - # Niri will draw focus ring and border *around* windows that agree to omit their - # client-side decorations. - - # You can change how the focus ring looks. - (plain "focus-ring" [ - # Uncomment this line to disable the focus ring. - # (flag "off") - - # How many logical pixels the ring extends out from the windows. - (leaf "width" 4) - - # Colors can be set in a variety of ways: - # - CSS named colors: "red" - # - RGB hex: "#rgb", "#rgba", "#rrggbb", "#rrggbbaa" - # - CSS-like notation: "rgb(255, 127, 0)", rgba(), hsl() and a few others. - - # Color of the ring on the active monitor. - (leaf "active-color" "#7fc8ff") - - # Color of the ring on inactive monitors. - (leaf "inactive-color" "#505050") - - # Additionally, there's a legacy RGBA syntax: - # (leaf "active-color" [ 127 200 255 255 ]) - - # You can also use gradients. They take precedence over solid colors. - # Gradients are rendered the same as CSS linear-gradient(angle, from, to). - # The angle is the same as in linear-gradient, and is optional, - # defaulting to 180 (top-to-bottom gradient). - # You can use any CSS linear-gradient tool on the web to set these up. - # - # (leaf "active-gradient" { from="#80c8ff"; to="#bbddff"; angle=45; }) - - # You can also color the gradient relative to the entire view - # of the workspace, rather than relative to just the window itself. - # To do that, set relative-to="workspace-view"; - # - # (leaf "inactive-gradient" { from="#505050"; to="#808080"; angle=45; relative-to="workspace-view"; }) - ]) - - # You can also add a border. It's similar to the focus ring, but always visible. - (plain "border" [ - # The settings are the same as for the focus ring. - # If you enable the border, you probably want to disable the focus ring. - (flag "off") - - (leaf "width" 4) - (leaf "active-color" "#ffc87f") - (leaf "inactive-color" "#505050") - - # (leaf "active-gradient" { from="#ffbb66"; to="#ffc880"; angle=45; relative-to="workspace-view"; }) - # (leaf "inactive-gradient" { from="#505050"; to="#808080"; angle=45; relative-to="workspace-view"; }) - ]) - - # You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between. - (plain "preset-column-widths" [ - # Proportion sets the width as a fraction of the output width, taking gaps into account. - # For example, you can perfectly fit four windows sized "proportion 0.25" on an output. - # The default preset widths are 1/3, 1/2 and 2/3 of the output. - (leaf "proportion" (1.0 / 3.0)) - (leaf "proportion" (1.0 / 2.0)) - (leaf "proportion" (2.0 / 3.0)) - - # Fixed sets the width in logical pixels exactly. - # (leaf "fixed" 1920) - ]) - - # You can change the default width of the new windows. - (plain "default-column-width" [ - (leaf "proportion" 0.5) - ]) - # If you leave the children empty, the windows themselves will decide their initial width. - # (plain "default-column-width" []) - - # Set gaps around windows in logical pixels. - (leaf "gaps" 8) - - # Struts shrink the area occupied by windows, similarly to layer-shell panels. - # You can think of them as a kind of outer gaps. They are set in logical pixels. - # Left and right struts will cause the next window to the side to always be visible. - # Top and bottom struts will simply add outer gaps in addition to the area occupied by - # layer-shell panels and regular gaps. - (plain "struts" [ - # (leaf "left" 64) - # (leaf "right" 64) - # (leaf "top" 64) - # (leaf "bottom" 64) - ]) - - # When to center a column when changing focus, options are: - # - "never", default behavior, focusing an off-screen column will keep at the left - # or right edge of the screen. - # - "on-overflow", focusing a column will center it if it doesn't fit - # together with the previously focused column. - # - "always", the focused column will always be centered. - (leaf "center-focused-column" "never") - ]) - - (plain "cursor" [ - # Change the theme and size of the cursor as well as set the - # `XCURSOR_THEME` and `XCURSOR_SIZE` env variables. - # (leaf "xcursor-theme" "default") - # (leaf "xcursor-size" 24) - ]) - - # Uncomment this line to ask the clients to omit their client-side decorations if possible. - # If the client will specifically ask for CSD, the request will be honored. - # Additionally, clients will be informed that they are tiled, removing some rounded corners. - # (flag "prefer-no-csd") - - # You can change the path where screenshots are saved. - # A ~ at the front will be expanded to the home directory. - # The path is formatted with strftime(3) to give you the screenshot date and time. - (leaf "screenshot-path" "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png") - - # You can also set this to null to disable saving screenshots to disk. - # (leaf "screenshot-path" null) - - # Settings for the "Important Hotkeys" overlay. - (plain "hotkey-overlay" [ - # Uncomment this line if you don't want to see the hotkey help at niri startup. - # (flag "skip-at-startup") - ]) - - (plain "layer-rule" [ - (leaf "match" { namespace = "waybar"; }) - (leaf "opacity" 0.8) - ]) - - # Animation settings. - (plain "animations" [ - # Uncomment to turn off all animations. - # (flag "off") - - # Slow down all animations by this factor. Values below 1 speed them up instead. - # (leaf "slowdown" 3.0) - - # You can configure all individual animations. - # Available settings are the same for all of them. - # - off disables the animation. - # - # Niri supports two animation types: easing and spring. - # You can set properties for only ONE of them. - # - # Easing has the following settings: - # - duration-ms sets the duration of the animation in milliseconds. - # - curve sets the easing curve. Currently, available curves - # are "ease-out-cubic" and "ease-out-expo". - # - # Spring animations work better with touchpad gestures, because they - # take into account the velocity of your fingers as you release the swipe. - # The parameters are less obvious and generally should be tuned - # with trial and error. Notably, you cannot directly set the duration. - # You can use this app to help visualize how the spring parameters - # change the animation: https://flathub.org/apps/app.drey.Elastic - # - # A spring animation is configured like this: - # - (leaf "spring" { damping-ratio=1.0; stiffness=1000; epsilon=0.0001; }) - # - # The damping ratio goes from 0.1 to 10.0 and has the following properties: - # - below 1.0: underdamped spring, will oscillate in the end. - # - above 1.0: overdamped spring, won't oscillate. - # - 1.0: critically damped spring, comes to rest in minimum possible time - # without oscillations. - # - # However, even with damping ratio = 1.0 the spring animation may oscillate - # if "launched" with enough velocity from a touchpad swipe. - # - # Lower stiffness will result in a slower animation more prone to oscillation. - # - # Set epsilon to a lower value if the animation "jumps" in the end. - # - # The spring mass is hardcoded to 1.0 and cannot be changed. Instead, change - # stiffness proportionally. E.g. increasing mass by 2x is the same as - # decreasing stiffness by 2x. - - # Animation when switching workspaces up and down, - # including after the touchpad gesture. - (plain "workspace-switch" [ - # (flag "off") - # (leaf "spring" { damping-ratio=1.0; stiffness=1000; epsilon=0.0001; }) - ]) - - # All horizontal camera view movement: - # - When a window off-screen is focused and the camera scrolls to it. - # - When a new window appears off-screen and the camera scrolls to it. - # - When a window resizes bigger and the camera scrolls to show it in full. - # - And so on. - (plain "horizontal-view-movement" [ - # (flag "off") - # (leaf "spring" { damping-ratio=1.0; stiffness=800; epsilon=0.0001; }) - ]) - - # Window opening animation. Note that this one has different defaults. - (plain "window-open" [ - # (flag "off") - # (leaf "duration-ms" 150) - # (leaf "curve" "ease-out-expo") - - # Example for a slightly bouncy window opening: - # (leaf "spring" { damping-ratio=0.8; stiffness=1000; epsilon=0.0001; }) - ]) - - # Config parse error and new default config creation notification - # open/close animation. - (plain "config-notification-open-close" [ - # (flag "off") - # (leaf "spring" { damping-ratio=0.6; stiffness=1000; epsilon=0.001; }) - ]) - ]) - - # Add lines like this to spawn processes at startup. - # Note that running niri as a session supports xdg-desktop-autostart, - # which may be more convenient to use. - # --------------- Terminal --------------- - (leaf "spawn-at-startup" [ "foot" ]) - (leaf "spawn-at-startup" [ "alacritty" ]) - (leaf "spawn-at-startup" [ "ghostty" ]) - # --------------- Networking --------------- - (leaf "spawn-at-startup" [ "clash-verge" ]) - # --------------- Browser --------------- - (leaf "spawn-at-startup" [ "firefox" ]) - (leaf "spawn-at-startup" [ "google-chrome-stable" ]) - (leaf "spawn-at-startup" [ "chromium-browser" ]) - # --------------- Chatting --------------- - (leaf "spawn-at-startup" [ "Telegram" ]) - - # ============= Window Rules ============= - # Get all the window's information via: - # niri msg windows - - # --------------- Terminal --------------- - # foot → ws 13 - (plain "window-rule" [ - (leaf "match" { app-id = "foot"; }) - (leaf "open-on-workspace" "1terminal") - (leaf "open-maximized" true) - ]) - - # Alacritty → ws 10 - (plain "window-rule" [ - (leaf "match" { app-id = "Alacritty"; }) - (leaf "open-on-workspace" "1terminal") - (leaf "open-maximized" true) - ]) - - # Ghostty → ws 14 - (plain "window-rule" [ - (leaf "match" { app-id = "com.mitchellh.ghostty"; }) - (leaf "open-on-workspace" "1terminal") - (leaf "open-maximized" true) - ]) - - # --------------- Networking --------------- - - # Clash Verge → ws 7 - (plain "window-rule" [ - (leaf "match" { app-id = "clash-verge"; }) - (leaf "open-on-workspace" "0other") - ]) - - # --------------- Browser --------------- - - # Firefox → ws 11 - (plain "window-rule" [ - (leaf "match" { app-id = "firefox"; }) - (leaf "open-on-workspace" "2browser") - (leaf "open-maximized" true) - ]) - # Google Chrome → ws 12 - (plain "window-rule" [ - (leaf "match" { app-id = "google-chrome"; }) - (leaf "open-on-workspace" "2browser") - (leaf "open-maximized" true) - ]) - - # --------------- Chatting --------------- - # Telegram → ws 6 - (plain "window-rule" [ - (leaf "match" { app-id = "org.telegram.desktop"; }) - (leaf "open-on-workspace" "3chat") - ]) - - (plain "binds" [ - # Keys consist of modifiers separated by + signs, followed by an XKB key name - # in the end. To find an XKB name for a particular key, you may use a program - # like wev. - # - # "Mod" is a special modifier equal to Super when running on a TTY, and to Alt - # when running as a winit window. - # - # Most actions that you can bind here can also be invoked programmatically with - # `niri msg action do-something`. - - # Mod-Shift-/, which is usually the same as Mod-?, - # shows a list of important hotkeys. - (plain "Mod+Shift+Slash" [ (flag "show-hotkey-overlay") ]) - - # Suggested binds for running programs: terminal, app launcher, screen locker. - (plain "Mod+Return" [ (leaf "spawn" [ "foot" ]) ]) - (plain "Mod+Shift+Return" [ (leaf "spawn" [ "alacritty" ]) ]) - (plain "Mod+D" [ (leaf "spawn" [ "anyrun" ]) ]) - (plain "CTRL+Alt+L" [ (leaf "spawn" [ "swaylock" ]) ]) - - # You can also use a shell: - # (plain "Mod+T" [(leaf "spawn" [ "bash" "-c" "notify-send hello && exec alacritty" ])]) - - # Example volume keys mappings for PipeWire & WirePlumber. - (plain "XF86AudioRaiseVolume" [ - (leaf "spawn" [ - "wpctl" - "set-volume" - "@DEFAULT_AUDIO_SINK@" - "0.1+" - ]) - ]) - (plain "XF86AudioLowerVolume" [ - (leaf "spawn" [ - "wpctl" - "set-volume" - "@DEFAULT_AUDIO_SINK@" - "0.1-" - ]) - ]) - - (plain "Mod+Q" [ (flag "close-window") ]) - - (plain "Mod+Left" [ (flag "focus-column-left") ]) - (plain "Mod+Down" [ (flag "focus-window-down") ]) - (plain "Mod+Up" [ (flag "focus-window-up") ]) - (plain "Mod+Right" [ (flag "focus-column-right") ]) - (plain "Mod+H" [ (flag "focus-column-left") ]) - (plain "Mod+J" [ (flag "focus-window-down") ]) - (plain "Mod+K" [ (flag "focus-window-up") ]) - (plain "Mod+L" [ (flag "focus-column-right") ]) - - (plain "Mod+Ctrl+Left" [ (flag "move-column-left") ]) - (plain "Mod+Ctrl+Down" [ (flag "move-window-down") ]) - (plain "Mod+Ctrl+Up" [ (flag "move-window-up") ]) - (plain "Mod+Ctrl+Right" [ (flag "move-column-right") ]) - (plain "Mod+Ctrl+H" [ (flag "move-column-left") ]) - (plain "Mod+Ctrl+J" [ (flag "move-window-down") ]) - (plain "Mod+Ctrl+K" [ (flag "move-window-up") ]) - (plain "Mod+Ctrl+L" [ (flag "move-column-right") ]) - - # Alternative commands that move across workspaces when reaching - # the first or last window in a column. - # (plain "Mod+J" [(flag "focus-window-or-workspace-down")]) - # (plain "Mod+K" [(flag "focus-window-or-workspace-up")]) - # (plain "Mod+Ctrl+J" [(flag "move-window-down-or-to-workspace-down")]) - # (plain "Mod+Ctrl+K" [(flag "move-window-up-or-to-workspace-up")]) - - (plain "Mod+Home" [ (flag "focus-column-first") ]) - (plain "Mod+End" [ (flag "focus-column-last") ]) - (plain "Mod+Ctrl+Home" [ (flag "move-column-to-first") ]) - (plain "Mod+Ctrl+End" [ (flag "move-column-to-last") ]) - - (plain "Mod+Shift+Left" [ (flag "focus-monitor-left") ]) - (plain "Mod+Shift+Down" [ (flag "focus-monitor-down") ]) - (plain "Mod+Shift+Up" [ (flag "focus-monitor-up") ]) - (plain "Mod+Shift+Right" [ (flag "focus-monitor-right") ]) - (plain "Mod+Shift+H" [ (flag "focus-monitor-left") ]) - (plain "Mod+Shift+J" [ (flag "focus-monitor-down") ]) - (plain "Mod+Shift+K" [ (flag "focus-monitor-up") ]) - (plain "Mod+Shift+L" [ (flag "focus-monitor-right") ]) - - (plain "Mod+Shift+Ctrl+Left" [ (flag "move-column-to-monitor-left") ]) - (plain "Mod+Shift+Ctrl+Down" [ (flag "move-column-to-monitor-down") ]) - (plain "Mod+Shift+Ctrl+Up" [ (flag "move-column-to-monitor-up") ]) - (plain "Mod+Shift+Ctrl+Right" [ (flag "move-column-to-monitor-right") ]) - (plain "Mod+Shift+Ctrl+H" [ (flag "move-column-to-monitor-left") ]) - (plain "Mod+Shift+Ctrl+J" [ (flag "move-column-to-monitor-down") ]) - (plain "Mod+Shift+Ctrl+K" [ (flag "move-column-to-monitor-up") ]) - (plain "Mod+Shift+Ctrl+L" [ (flag "move-column-to-monitor-right") ]) - - # Alternatively, there are commands to move just a single window: - # (plain "Mod+Shift+Ctrl+Left" [(flag "move-window-to-monitor-left")]) - # ... - - # And you can also move a whole workspace to another monitor: - # (plain "Mod+Shift+Ctrl+Left" [(flag "move-workspace-to-monitor-left")]) - # ... - - (plain "Mod+Page_Down" [ (flag "focus-workspace-down") ]) - (plain "Mod+Page_Up" [ (flag "focus-workspace-up") ]) - (plain "Mod+U" [ (flag "focus-workspace-down") ]) - (plain "Mod+I" [ (flag "focus-workspace-up") ]) - (plain "Mod+Ctrl+Page_Down" [ (flag "move-column-to-workspace-down") ]) - (plain "Mod+Ctrl+Page_Up" [ (flag "move-column-to-workspace-up") ]) - (plain "Mod+Ctrl+U" [ (flag "move-column-to-workspace-down") ]) - (plain "Mod+Ctrl+I" [ (flag "move-column-to-workspace-up") ]) - - # Alternatively, there are commands to move just a single window: - # (plain "Mod+Ctrl+Page_Down" [(flag "move-window-to-workspace-down")]) - # ... - - (plain "Mod+Shift+Page_Down" [ (flag "move-workspace-down") ]) - (plain "Mod+Shift+Page_Up" [ (flag "move-workspace-up") ]) - (plain "Mod+Shift+U" [ (flag "move-workspace-down") ]) - (plain "Mod+Shift+I" [ (flag "move-workspace-up") ]) - - # You can refer to workspaces by index. However, keep in mind that - # niri is a dynamic workspace system, so these commands are kind of - # "best effort". Trying to refer to a workspace index bigger than - # the current workspace count will instead refer to the bottommost - # (empty) workspace. - # - # For example, with 2 workspaces + 1 empty, indices 3, 4, 5 and so on - # will all refer to the 3rd workspace. - (plain "Mod+1" [ (leaf "focus-workspace" "1terminal") ]) - (plain "Mod+2" [ (leaf "focus-workspace" "2browser") ]) - (plain "Mod+3" [ (leaf "focus-workspace" "3chat") ]) - (plain "Mod+4" [ (leaf "focus-workspace" "4music") ]) - (plain "Mod+5" [ (leaf "focus-workspace" "5mail") ]) - (plain "Mod+6" [ (leaf "focus-workspace" "6file") ]) - (plain "Mod+7" [ (leaf "focus-workspace" 7) ]) - (plain "Mod+8" [ (leaf "focus-workspace" 8) ]) - (plain "Mod+9" [ (leaf "focus-workspace" 9) ]) - (plain "Mod+0" [ (leaf "focus-workspace" "0other") ]) - (plain "Mod+Ctrl+1" [ (leaf "move-column-to-workspace" "1terminal") ]) - (plain "Mod+Ctrl+2" [ (leaf "move-column-to-workspace" "2browser") ]) - (plain "Mod+Ctrl+3" [ (leaf "move-column-to-workspace" "3chat") ]) - (plain "Mod+Ctrl+4" [ (leaf "move-column-to-workspace" "4music") ]) - (plain "Mod+Ctrl+5" [ (leaf "move-column-to-workspace" "5mail") ]) - (plain "Mod+Ctrl+6" [ (leaf "move-column-to-workspace" "6file") ]) - (plain "Mod+Ctrl+7" [ (leaf "move-column-to-workspace" 7) ]) - (plain "Mod+Ctrl+8" [ (leaf "move-column-to-workspace" 8) ]) - (plain "Mod+Ctrl+9" [ (leaf "move-column-to-workspace" 9) ]) - (plain "Mod+Ctrl+0" [ (leaf "move-column-to-workspace" "0other") ]) - - # Alternatively, there are commands to move just a single window: - # (plain "Mod+Ctrl+1" [(leaf "move-window-to-workspace" 1)]) - - (plain "Mod+Comma" [ (flag "consume-window-into-column") ]) - (plain "Mod+Period" [ (flag "expel-window-from-column") ]) - - # There are also commands that consume or expel a single window to the side. - # (plain "Mod+BracketLeft" [(flag "consume-or-expel-window-left")]) - # (plain "Mod+BracketRight" [(flag "consume-or-expel-window-right")]) - - (plain "Mod+R" [ (flag "switch-preset-column-width") ]) - (plain "Mod+F" [ (flag "maximize-column") ]) - (plain "Mod+Shift+F" [ (flag "fullscreen-window") ]) - (plain "Mod+C" [ (flag "center-column") ]) - - # Finer width adjustments. - # This command can also: - # * set width in pixels: "1000" - # * adjust width in pixels: "-5" or "+5" - # * set width as a percentage of screen width: "25%" - # * adjust width as a percentage of screen width: "-10%" or "+10%" - # Pixel sizes use logical, or scaled, pixels. I.e. on an output with scale 2.0, - # (leaf "set-column-width" "100") will make the column occupy 200 physical screen pixels. - (plain "Mod+Minus" [ (leaf "set-column-width" "-10%") ]) - (plain "Mod+Equal" [ (leaf "set-column-width" "+10%") ]) - - # Finer height adjustments when in column with other windows. - (plain "Mod+Shift+Minus" [ (leaf "set-window-height" "-10%") ]) - (plain "Mod+Shift+Equal" [ (leaf "set-window-height" "+10%") ]) - - # Actions to switch layouts. - # Note: if you uncomment these, make sure you do NOT have - # a matching layout switch hotkey configured in xkb options above. - # Having both at once on the same hotkey will break the switching, - # since it will switch twice upon pressing the hotkey (once by xkb, once by niri). - # (plain "Mod+Space" [(leaf "switch-layout" "next")]) - # (plain "Mod+Shift+Space" [(leaf "switch-layout" "prev")]) - - (plain "Print" [ (flag "screenshot") ]) - (plain "Ctrl+Print" [ (flag "screenshot-screen") ]) - (plain "Alt+Print" [ (flag "screenshot-window") ]) - - # The quit action will show a confirmation dialog to avoid accidental exits. - # If you want to skip the confirmation dialog, set the flag like so: - # (plain "Mod+Shift+E" [(leaf "quit" { skip-confirmation=true; })]) - (plain "Mod+Shift+E" [ (flag "quit") ]) - - (plain "Mod+Shift+P" [ (flag "power-off-monitors") ]) - - # This debug bind will tint all surfaces green, unless they are being - # directly scanned out. It's therefore useful to check if direct scanout - # is working. - # (plain "Mod+Shift+Ctrl+T" [(flag "toggle-debug-tint")]) - ]) - ]; - }; } diff --git a/home/linux/gui/niri/keybindings.nix b/home/linux/gui/niri/keybindings.nix new file mode 100644 index 00000000..c1292daf --- /dev/null +++ b/home/linux/gui/niri/keybindings.nix @@ -0,0 +1,214 @@ +niri: { + programs.niri.config = + let + inherit (niri.lib.kdl) + node + plain + leaf + flag + ; + in + [ + (plain "binds" [ + # Keys consist of modifiers separated by + signs, followed by an XKB key name + # in the end. To find an XKB name for a particular key, you may use a program + # like wev. + # + # "Mod" is a special modifier equal to Super when running on a TTY, and to Alt + # when running as a winit window. + # + # Most actions that you can bind here can also be invoked programmatically with + # `niri msg action do-something`. + + # Mod-Shift-/, which is usually the same as Mod-?, + # shows a list of important hotkeys. + (plain "Mod+Shift+Slash" [ (flag "show-hotkey-overlay") ]) + + # Suggested binds for running programs: terminal, app launcher, screen locker. + (plain "Mod+Return" [ (leaf "spawn" [ "foot" ]) ]) + (plain "Mod+Shift+Return" [ (leaf "spawn" [ "alacritty" ]) ]) + (plain "Mod+D" [ (leaf "spawn" [ "anyrun" ]) ]) + (plain "CTRL+Alt+L" [ (leaf "spawn" [ "swaylock" ]) ]) + + # You can also use a shell: + # (plain "Mod+T" [(leaf "spawn" [ "bash" "-c" "notify-send hello && exec alacritty" ])]) + + # Example volume keys mappings for PipeWire & WirePlumber. + (plain "XF86AudioRaiseVolume" [ + (leaf "spawn" [ + "wpctl" + "set-volume" + "@DEFAULT_AUDIO_SINK@" + "0.1+" + ]) + ]) + (plain "XF86AudioLowerVolume" [ + (leaf "spawn" [ + "wpctl" + "set-volume" + "@DEFAULT_AUDIO_SINK@" + "0.1-" + ]) + ]) + + (plain "Mod+Q" [ (flag "close-window") ]) + + (plain "Mod+Left" [ (flag "focus-column-left") ]) + (plain "Mod+Down" [ (flag "focus-window-down") ]) + (plain "Mod+Up" [ (flag "focus-window-up") ]) + (plain "Mod+Right" [ (flag "focus-column-right") ]) + (plain "Mod+H" [ (flag "focus-column-left") ]) + (plain "Mod+J" [ (flag "focus-window-down") ]) + (plain "Mod+K" [ (flag "focus-window-up") ]) + (plain "Mod+L" [ (flag "focus-column-right") ]) + + (plain "Mod+Ctrl+Left" [ (flag "move-column-left") ]) + (plain "Mod+Ctrl+Down" [ (flag "move-window-down") ]) + (plain "Mod+Ctrl+Up" [ (flag "move-window-up") ]) + (plain "Mod+Ctrl+Right" [ (flag "move-column-right") ]) + (plain "Mod+Ctrl+H" [ (flag "move-column-left") ]) + (plain "Mod+Ctrl+J" [ (flag "move-window-down") ]) + (plain "Mod+Ctrl+K" [ (flag "move-window-up") ]) + (plain "Mod+Ctrl+L" [ (flag "move-column-right") ]) + + # Alternative commands that move across workspaces when reaching + # the first or last window in a column. + # (plain "Mod+J" [(flag "focus-window-or-workspace-down")]) + # (plain "Mod+K" [(flag "focus-window-or-workspace-up")]) + # (plain "Mod+Ctrl+J" [(flag "move-window-down-or-to-workspace-down")]) + # (plain "Mod+Ctrl+K" [(flag "move-window-up-or-to-workspace-up")]) + + (plain "Mod+Home" [ (flag "focus-column-first") ]) + (plain "Mod+End" [ (flag "focus-column-last") ]) + (plain "Mod+Ctrl+Home" [ (flag "move-column-to-first") ]) + (plain "Mod+Ctrl+End" [ (flag "move-column-to-last") ]) + + (plain "Mod+Shift+Left" [ (flag "focus-monitor-left") ]) + (plain "Mod+Shift+Down" [ (flag "focus-monitor-down") ]) + (plain "Mod+Shift+Up" [ (flag "focus-monitor-up") ]) + (plain "Mod+Shift+Right" [ (flag "focus-monitor-right") ]) + (plain "Mod+Shift+H" [ (flag "focus-monitor-left") ]) + (plain "Mod+Shift+J" [ (flag "focus-monitor-down") ]) + (plain "Mod+Shift+K" [ (flag "focus-monitor-up") ]) + (plain "Mod+Shift+L" [ (flag "focus-monitor-right") ]) + + (plain "Mod+Shift+Ctrl+Left" [ (flag "move-column-to-monitor-left") ]) + (plain "Mod+Shift+Ctrl+Down" [ (flag "move-column-to-monitor-down") ]) + (plain "Mod+Shift+Ctrl+Up" [ (flag "move-column-to-monitor-up") ]) + (plain "Mod+Shift+Ctrl+Right" [ (flag "move-column-to-monitor-right") ]) + (plain "Mod+Shift+Ctrl+H" [ (flag "move-column-to-monitor-left") ]) + (plain "Mod+Shift+Ctrl+J" [ (flag "move-column-to-monitor-down") ]) + (plain "Mod+Shift+Ctrl+K" [ (flag "move-column-to-monitor-up") ]) + (plain "Mod+Shift+Ctrl+L" [ (flag "move-column-to-monitor-right") ]) + + # Alternatively, there are commands to move just a single window: + # (plain "Mod+Shift+Ctrl+Left" [(flag "move-window-to-monitor-left")]) + # ... + + # And you can also move a whole workspace to another monitor: + # (plain "Mod+Shift+Ctrl+Left" [(flag "move-workspace-to-monitor-left")]) + # ... + + (plain "Mod+Page_Down" [ (flag "focus-workspace-down") ]) + (plain "Mod+Page_Up" [ (flag "focus-workspace-up") ]) + (plain "Mod+U" [ (flag "focus-workspace-down") ]) + (plain "Mod+I" [ (flag "focus-workspace-up") ]) + (plain "Mod+Ctrl+Page_Down" [ (flag "move-column-to-workspace-down") ]) + (plain "Mod+Ctrl+Page_Up" [ (flag "move-column-to-workspace-up") ]) + (plain "Mod+Ctrl+U" [ (flag "move-column-to-workspace-down") ]) + (plain "Mod+Ctrl+I" [ (flag "move-column-to-workspace-up") ]) + + # Alternatively, there are commands to move just a single window: + # (plain "Mod+Ctrl+Page_Down" [(flag "move-window-to-workspace-down")]) + # ... + + (plain "Mod+Shift+Page_Down" [ (flag "move-workspace-down") ]) + (plain "Mod+Shift+Page_Up" [ (flag "move-workspace-up") ]) + (plain "Mod+Shift+U" [ (flag "move-workspace-down") ]) + (plain "Mod+Shift+I" [ (flag "move-workspace-up") ]) + + # You can refer to workspaces by index. However, keep in mind that + # niri is a dynamic workspace system, so these commands are kind of + # "best effort". Trying to refer to a workspace index bigger than + # the current workspace count will instead refer to the bottommost + # (empty) workspace. + # + # For example, with 2 workspaces + 1 empty, indices 3, 4, 5 and so on + # will all refer to the 3rd workspace. + (plain "Mod+1" [ (leaf "focus-workspace" "1terminal") ]) + (plain "Mod+2" [ (leaf "focus-workspace" "2browser") ]) + (plain "Mod+3" [ (leaf "focus-workspace" "3chat") ]) + (plain "Mod+4" [ (leaf "focus-workspace" "4music") ]) + (plain "Mod+5" [ (leaf "focus-workspace" "5mail") ]) + (plain "Mod+6" [ (leaf "focus-workspace" "6file") ]) + (plain "Mod+7" [ (leaf "focus-workspace" 7) ]) + (plain "Mod+8" [ (leaf "focus-workspace" 8) ]) + (plain "Mod+9" [ (leaf "focus-workspace" 9) ]) + (plain "Mod+0" [ (leaf "focus-workspace" "0other") ]) + (plain "Mod+Ctrl+1" [ (leaf "move-column-to-workspace" "1terminal") ]) + (plain "Mod+Ctrl+2" [ (leaf "move-column-to-workspace" "2browser") ]) + (plain "Mod+Ctrl+3" [ (leaf "move-column-to-workspace" "3chat") ]) + (plain "Mod+Ctrl+4" [ (leaf "move-column-to-workspace" "4music") ]) + (plain "Mod+Ctrl+5" [ (leaf "move-column-to-workspace" "5mail") ]) + (plain "Mod+Ctrl+6" [ (leaf "move-column-to-workspace" "6file") ]) + (plain "Mod+Ctrl+7" [ (leaf "move-column-to-workspace" 7) ]) + (plain "Mod+Ctrl+8" [ (leaf "move-column-to-workspace" 8) ]) + (plain "Mod+Ctrl+9" [ (leaf "move-column-to-workspace" 9) ]) + (plain "Mod+Ctrl+0" [ (leaf "move-column-to-workspace" "0other") ]) + + # Alternatively, there are commands to move just a single window: + # (plain "Mod+Ctrl+1" [(leaf "move-window-to-workspace" 1)]) + + (plain "Mod+Comma" [ (flag "consume-window-into-column") ]) + (plain "Mod+Period" [ (flag "expel-window-from-column") ]) + + # There are also commands that consume or expel a single window to the side. + # (plain "Mod+BracketLeft" [(flag "consume-or-expel-window-left")]) + # (plain "Mod+BracketRight" [(flag "consume-or-expel-window-right")]) + + (plain "Mod+R" [ (flag "switch-preset-column-width") ]) + (plain "Mod+F" [ (flag "maximize-column") ]) + (plain "Mod+Shift+F" [ (flag "fullscreen-window") ]) + (plain "Mod+C" [ (flag "center-column") ]) + + # Finer width adjustments. + # This command can also: + # * set width in pixels: "1000" + # * adjust width in pixels: "-5" or "+5" + # * set width as a percentage of screen width: "25%" + # * adjust width as a percentage of screen width: "-10%" or "+10%" + # Pixel sizes use logical, or scaled, pixels. I.e. on an output with scale 2.0, + # (leaf "set-column-width" "100") will make the column occupy 200 physical screen pixels. + (plain "Mod+Minus" [ (leaf "set-column-width" "-10%") ]) + (plain "Mod+Equal" [ (leaf "set-column-width" "+10%") ]) + + # Finer height adjustments when in column with other windows. + (plain "Mod+Shift+Minus" [ (leaf "set-window-height" "-10%") ]) + (plain "Mod+Shift+Equal" [ (leaf "set-window-height" "+10%") ]) + + # Actions to switch layouts. + # Note: if you uncomment these, make sure you do NOT have + # a matching layout switch hotkey configured in xkb options above. + # Having both at once on the same hotkey will break the switching, + # since it will switch twice upon pressing the hotkey (once by xkb, once by niri). + # (plain "Mod+Space" [(leaf "switch-layout" "next")]) + # (plain "Mod+Shift+Space" [(leaf "switch-layout" "prev")]) + + (plain "Print" [ (flag "screenshot") ]) + (plain "Ctrl+Print" [ (flag "screenshot-screen") ]) + (plain "Alt+Print" [ (flag "screenshot-window") ]) + + # The quit action will show a confirmation dialog to avoid accidental exits. + # If you want to skip the confirmation dialog, set the flag like so: + # (plain "Mod+Shift+E" [(leaf "quit" { skip-confirmation=true; })]) + (plain "Mod+Shift+E" [ (flag "quit") ]) + + (plain "Mod+Shift+P" [ (flag "power-off-monitors") ]) + + # This debug bind will tint all surfaces green, unless they are being + # directly scanned out. It's therefore useful to check if direct scanout + # is working. + # (plain "Mod+Shift+Ctrl+T" [(flag "toggle-debug-tint")]) + ]) + ]; +} diff --git a/home/linux/gui/niri/settings.nix b/home/linux/gui/niri/settings.nix new file mode 100644 index 00000000..ca4547c6 --- /dev/null +++ b/home/linux/gui/niri/settings.nix @@ -0,0 +1,276 @@ +niri: { + programs.niri.config = + let + inherit (niri.lib.kdl) + node + plain + leaf + flag + ; + in + [ + (plain "input" [ + (plain "keyboard" [ + (plain "xkb" [ + # You can set rules, model, layout, variant and options. + # For more information, see xkeyboard-config(7). + + # For example: + # (leaf "layout" "us,ru") + # (leaf "options" "grp:win_space_toggle,compose:ralt,ctrl:nocaps") + ]) + + # You can set the keyboard repeat parameters. The defaults match wlroots and sway. + # Delay is in milliseconds before the repeat starts. Rate is in characters per second. + # (leaf "repeat-delay" 600) + # (leaf "repeat-rate" 25) + + # Niri can remember the keyboard layout globally (the default) or per-window. + # - "global" - layout change is global for all windows. + # - "window" - layout is tracked for each window individually. + # (leaf "track-layout" "global") + ]) + + # Next sections include libinput settings. + # Omitting settings disables them, or leaves them at their default values. + (plain "touchpad" [ + (flag "tap") + # (flag "dwt") + # (flag "dwtp") + (flag "natural-scroll") + # (leaf "accel-speed" 0.2) + # (leaf "accel-profile" "flat") + # (leaf "tap-button-map" "left-middle-right") + ]) + + (plain "mouse" [ + # (flag "natural-scroll") + # (leaf "accel-speed" 0.2) + # (leaf "accel-profile" "flat") + ]) + + # By default, niri will take over the power button to make it sleep + # instead of power off. + # Uncomment this if you would like to configure the power button elsewhere + # (i.e. logind.conf). + # (flag "disable-power-key-handling") + ]) + + (plain "layout" [ + # By default focus ring and border are rendered as a solid background rectangle + # behind windows. That is, they will show up through semitransparent windows. + # This is because windows using client-side decorations can have an arbitrary shape. + # + # If you don't like that, you should uncomment `prefer-no-csd` below. + # Niri will draw focus ring and border *around* windows that agree to omit their + # client-side decorations. + + # You can change how the focus ring looks. + (plain "focus-ring" [ + # Uncomment this line to disable the focus ring. + # (flag "off") + + # How many logical pixels the ring extends out from the windows. + (leaf "width" 4) + + # Colors can be set in a variety of ways: + # - CSS named colors: "red" + # - RGB hex: "#rgb", "#rgba", "#rrggbb", "#rrggbbaa" + # - CSS-like notation: "rgb(255, 127, 0)", rgba(), hsl() and a few others. + + # Color of the ring on the active monitor. + (leaf "active-color" "#7fc8ff") + + # Color of the ring on inactive monitors. + (leaf "inactive-color" "#505050") + + # Additionally, there's a legacy RGBA syntax: + # (leaf "active-color" [ 127 200 255 255 ]) + + # You can also use gradients. They take precedence over solid colors. + # Gradients are rendered the same as CSS linear-gradient(angle, from, to). + # The angle is the same as in linear-gradient, and is optional, + # defaulting to 180 (top-to-bottom gradient). + # You can use any CSS linear-gradient tool on the web to set these up. + # + # (leaf "active-gradient" { from="#80c8ff"; to="#bbddff"; angle=45; }) + + # You can also color the gradient relative to the entire view + # of the workspace, rather than relative to just the window itself. + # To do that, set relative-to="workspace-view"; + # + # (leaf "inactive-gradient" { from="#505050"; to="#808080"; angle=45; relative-to="workspace-view"; }) + ]) + + # You can also add a border. It's similar to the focus ring, but always visible. + (plain "border" [ + # The settings are the same as for the focus ring. + # If you enable the border, you probably want to disable the focus ring. + (flag "off") + + (leaf "width" 4) + (leaf "active-color" "#ffc87f") + (leaf "inactive-color" "#505050") + + # (leaf "active-gradient" { from="#ffbb66"; to="#ffc880"; angle=45; relative-to="workspace-view"; }) + # (leaf "inactive-gradient" { from="#505050"; to="#808080"; angle=45; relative-to="workspace-view"; }) + ]) + + # You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between. + (plain "preset-column-widths" [ + # Proportion sets the width as a fraction of the output width, taking gaps into account. + # For example, you can perfectly fit four windows sized "proportion 0.25" on an output. + # The default preset widths are 1/3, 1/2 and 2/3 of the output. + (leaf "proportion" (1.0 / 3.0)) + (leaf "proportion" (1.0 / 2.0)) + (leaf "proportion" (2.0 / 3.0)) + + # Fixed sets the width in logical pixels exactly. + # (leaf "fixed" 1920) + ]) + + # You can change the default width of the new windows. + (plain "default-column-width" [ + (leaf "proportion" 0.5) + ]) + # If you leave the children empty, the windows themselves will decide their initial width. + # (plain "default-column-width" []) + + # Set gaps around windows in logical pixels. + (leaf "gaps" 8) + + # Struts shrink the area occupied by windows, similarly to layer-shell panels. + # You can think of them as a kind of outer gaps. They are set in logical pixels. + # Left and right struts will cause the next window to the side to always be visible. + # Top and bottom struts will simply add outer gaps in addition to the area occupied by + # layer-shell panels and regular gaps. + (plain "struts" [ + # (leaf "left" 64) + # (leaf "right" 64) + # (leaf "top" 64) + # (leaf "bottom" 64) + ]) + + # When to center a column when changing focus, options are: + # - "never", default behavior, focusing an off-screen column will keep at the left + # or right edge of the screen. + # - "on-overflow", focusing a column will center it if it doesn't fit + # together with the previously focused column. + # - "always", the focused column will always be centered. + (leaf "center-focused-column" "never") + ]) + + (plain "cursor" [ + # Change the theme and size of the cursor as well as set the + # `XCURSOR_THEME` and `XCURSOR_SIZE` env variables. + # (leaf "xcursor-theme" "default") + # (leaf "xcursor-size" 24) + ]) + + # Uncomment this line to ask the clients to omit their client-side decorations if possible. + # If the client will specifically ask for CSD, the request will be honored. + # Additionally, clients will be informed that they are tiled, removing some rounded corners. + # (flag "prefer-no-csd") + + # You can change the path where screenshots are saved. + # A ~ at the front will be expanded to the home directory. + # The path is formatted with strftime(3) to give you the screenshot date and time. + (leaf "screenshot-path" "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png") + + # You can also set this to null to disable saving screenshots to disk. + # (leaf "screenshot-path" null) + + # Settings for the "Important Hotkeys" overlay. + (plain "hotkey-overlay" [ + # Uncomment this line if you don't want to see the hotkey help at niri startup. + # (flag "skip-at-startup") + ]) + + (plain "layer-rule" [ + (leaf "match" { namespace = "waybar"; }) + (leaf "opacity" 0.8) + ]) + + # Animation settings. + (plain "animations" [ + # Uncomment to turn off all animations. + # (flag "off") + + # Slow down all animations by this factor. Values below 1 speed them up instead. + # (leaf "slowdown" 3.0) + + # You can configure all individual animations. + # Available settings are the same for all of them. + # - off disables the animation. + # + # Niri supports two animation types: easing and spring. + # You can set properties for only ONE of them. + # + # Easing has the following settings: + # - duration-ms sets the duration of the animation in milliseconds. + # - curve sets the easing curve. Currently, available curves + # are "ease-out-cubic" and "ease-out-expo". + # + # Spring animations work better with touchpad gestures, because they + # take into account the velocity of your fingers as you release the swipe. + # The parameters are less obvious and generally should be tuned + # with trial and error. Notably, you cannot directly set the duration. + # You can use this app to help visualize how the spring parameters + # change the animation: https://flathub.org/apps/app.drey.Elastic + # + # A spring animation is configured like this: + # - (leaf "spring" { damping-ratio=1.0; stiffness=1000; epsilon=0.0001; }) + # + # The damping ratio goes from 0.1 to 10.0 and has the following properties: + # - below 1.0: underdamped spring, will oscillate in the end. + # - above 1.0: overdamped spring, won't oscillate. + # - 1.0: critically damped spring, comes to rest in minimum possible time + # without oscillations. + # + # However, even with damping ratio = 1.0 the spring animation may oscillate + # if "launched" with enough velocity from a touchpad swipe. + # + # Lower stiffness will result in a slower animation more prone to oscillation. + # + # Set epsilon to a lower value if the animation "jumps" in the end. + # + # The spring mass is hardcoded to 1.0 and cannot be changed. Instead, change + # stiffness proportionally. E.g. increasing mass by 2x is the same as + # decreasing stiffness by 2x. + + # Animation when switching workspaces up and down, + # including after the touchpad gesture. + (plain "workspace-switch" [ + # (flag "off") + # (leaf "spring" { damping-ratio=1.0; stiffness=1000; epsilon=0.0001; }) + ]) + + # All horizontal camera view movement: + # - When a window off-screen is focused and the camera scrolls to it. + # - When a new window appears off-screen and the camera scrolls to it. + # - When a window resizes bigger and the camera scrolls to show it in full. + # - And so on. + (plain "horizontal-view-movement" [ + # (flag "off") + # (leaf "spring" { damping-ratio=1.0; stiffness=800; epsilon=0.0001; }) + ]) + + # Window opening animation. Note that this one has different defaults. + (plain "window-open" [ + # (flag "off") + # (leaf "duration-ms" 150) + # (leaf "curve" "ease-out-expo") + + # Example for a slightly bouncy window opening: + # (leaf "spring" { damping-ratio=0.8; stiffness=1000; epsilon=0.0001; }) + ]) + + # Config parse error and new default config creation notification + # open/close animation. + (plain "config-notification-open-close" [ + # (flag "off") + # (leaf "spring" { damping-ratio=0.6; stiffness=1000; epsilon=0.001; }) + ]) + ]) + ]; +} diff --git a/home/linux/gui/niri/spawn-at-startup.nix b/home/linux/gui/niri/spawn-at-startup.nix new file mode 100644 index 00000000..cadafdf3 --- /dev/null +++ b/home/linux/gui/niri/spawn-at-startup.nix @@ -0,0 +1,28 @@ +niri: { + programs.niri.config = + let + inherit (niri.lib.kdl) + node + plain + leaf + flag + ; + in + [ + # Add lines like this to spawn processes at startup. + # Note that running niri as a session supports xdg-desktop-autostart, + # which may be more convenient to use. + # --------------- Terminal --------------- + (leaf "spawn-at-startup" [ "foot" ]) + (leaf "spawn-at-startup" [ "alacritty" ]) + (leaf "spawn-at-startup" [ "ghostty" ]) + # --------------- Networking --------------- + (leaf "spawn-at-startup" [ "clash-verge" ]) + # --------------- Browser --------------- + (leaf "spawn-at-startup" [ "firefox" ]) + (leaf "spawn-at-startup" [ "google-chrome-stable" ]) + (leaf "spawn-at-startup" [ "chromium-browser" ]) + # --------------- Chatting --------------- + (leaf "spawn-at-startup" [ "Telegram" ]) + ]; +} diff --git a/home/linux/gui/niri/windowrules.nix b/home/linux/gui/niri/windowrules.nix new file mode 100644 index 00000000..cd8fac85 --- /dev/null +++ b/home/linux/gui/niri/windowrules.nix @@ -0,0 +1,68 @@ +niri: { + programs.niri.config = + let + inherit (niri.lib.kdl) + node + plain + leaf + flag + ; + in + [ + # ============= Window Rules ============= + # Get all the window's information via: + # niri msg windows + + # --------------- Terminal --------------- + # foot → ws 13 + (plain "window-rule" [ + (leaf "match" { app-id = "foot"; }) + (leaf "open-on-workspace" "1terminal") + (leaf "open-maximized" true) + ]) + + # Alacritty → ws 10 + (plain "window-rule" [ + (leaf "match" { app-id = "Alacritty"; }) + (leaf "open-on-workspace" "1terminal") + (leaf "open-maximized" true) + ]) + + # Ghostty → ws 14 + (plain "window-rule" [ + (leaf "match" { app-id = "com.mitchellh.ghostty"; }) + (leaf "open-on-workspace" "1terminal") + (leaf "open-maximized" true) + ]) + + # --------------- Networking --------------- + + # Clash Verge → ws 7 + (plain "window-rule" [ + (leaf "match" { app-id = "clash-verge"; }) + (leaf "open-on-workspace" "0other") + ]) + + # --------------- Browser --------------- + + # Firefox → ws 11 + (plain "window-rule" [ + (leaf "match" { app-id = "firefox"; }) + (leaf "open-on-workspace" "2browser") + (leaf "open-maximized" true) + ]) + # Google Chrome → ws 12 + (plain "window-rule" [ + (leaf "match" { app-id = "google-chrome"; }) + (leaf "open-on-workspace" "2browser") + (leaf "open-maximized" true) + ]) + + # --------------- Chatting --------------- + # Telegram → ws 6 + (plain "window-rule" [ + (leaf "match" { app-id = "org.telegram.desktop"; }) + (leaf "open-on-workspace" "3chat") + ]) + ]; +}