{ pkgs, config, inputs, ... }: let inherit (pkgs) lib; tomlFormat = pkgs.formats.toml { }; screenshot = pkgs.writeScript "ib-screenshot" '' set -xeu pipefail ${pkgs.grim}/bin/grim -g "$(${pkgs.slurp}/bin/slurp -d)" -t ppm - | ${pkgs.satty}/bin/satty --filename - ''; in { imports = [ inputs.niri-flake.homeModules.niri ]; # programs.waybar.enable = true; programs.tofi.enable = true; services.mako.enable = true; services.darkman.enable = true; services.wpaperd.enable = true; programs.waybar = { enable = true; systemd = { enable = true; targets = [ "niri.service" ]; }; }; home.packages = [ pkgs.niri-stable pkgs.wpaperd # for wpaperctl pkgs.gnome-keyring pkgs.soteria # Super strange issue with nautilus: the desktop file only works so long as # I have desktop-file-utils installed *anywhere* on the system. As in, just # having them in some random unrelated nix-shell also makes it work. # What the hell. :`D :3 pkgs.desktop-file-utils pkgs.nautilus pkgs.bemoji pkgs.grim pkgs.slurp ]; home.sessionVariables = { BEMOJI_PICKER_CMD = "${pkgs.tofi}/bin/tofi"; BEMOJI_TYPE_CMD = "${pkgs.wtype}/bin/wtype"; BEMOJI_CLIP_CMD = "${pkgs.wl-clipboard}/bin/wl-copy"; BEMOJI_ECHO_NEWLINE = "false"; # wayland compat stuff ELECTRON_OZONE_PLATFORM_HINT = "auto"; }; programs.niri.settings = { input = { keyboard.xkb = { layout = "us,hr"; options = "grp:win_space_toggle"; }; touchpad = { enable = true; tap = true; natural-scroll = true; dwt = true; # disable while typing }; mouse = { enable = true; accel-profile = "flat"; }; }; outputs."eDP-1" = { enable = true; mode = { width = 1920; height = 1200; }; scale = 1; # transform = "normal"; # position = { # # From the default config, no idea why # x = 1280; # y = 0; # }; }; layout = { gaps = 16; center-focused-column = "never"; # You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between. preset-column-widths = [ { proportion = 1. / 3.; } { proportion = 1. / 2.; } { proportion = 2. / 3.; } ]; default-column-width.proportion = 1. / 2.; focus-ring = { width = 4; active.color = "#7fc8ff"; inactive.color = "#505050"; }; }; environment = { QT_QPA_PLATFORM = "wayland"; DISPLAY = ":0"; # for X11 to recognize xwayland-satellite correctly }; screenshot-path = null; # clipboard only workspaces = { "01-dev-1" = { name = "dev-1"; open-on-output = "eDP-1"; }; "02-dev-2" = { name = "dev-2"; open-on-output = "eDP-1"; }; "03-web" = { name = "web"; open-on-output = "eDP-1"; }; "04-chat" = { name = "chat"; open-on-output = "eDP-1"; }; "05-email" = { name = "email"; open-on-output = "eDP-1"; }; "06-misc-1" = { name = "misc-1"; open-on-output = "eDP-1"; }; "07-misc-2" = { name = "misc-2"; open-on-output = "eDP-1"; }; "08-misc-3" = { name = "misc-3"; open-on-output = "eDP-1"; }; "09-misc-4" = { name = "misc-4"; open-on-output = "eDP-1"; }; "10-misc-5" = { name = "misc-5"; open-on-output = "eDP-1"; }; }; window-rules = let default-workspace = app-id: workspace: { matches = [ { at-startup = true; inherit app-id; } ]; open-on-workspace = workspace; }; in [ # Open the Firefox picture-in-picture player as floating by default. { matches = [ { title = "^Picture-in-Picture$"; } ]; open-floating = true; } # Work around WezTerm's initial configure bug by setting an empty default-column-width. { matches = [ { app-id = ''^org\.wezfurlong\.wezterm$''; } ]; default-column-width = null; } { matches = [ { app-id = ''^org\.keepassxc\.KeePassXC$''; } { app-id = ''^org\.gnome\.World\.Secrets$''; } { app-id = ''^Bitwarden$''; } ]; block-out-from = "screen-capture"; } # Default app positions (default-workspace "^firefox$" "web") (default-workspace "^discord$" "chat") (default-workspace "^thunderbird$" "email") (default-workspace "^Bitwarden$" "misc-1") ]; binds = with config.lib.niri.actions; { # Shows a list of important hotkeys "Mod+Shift+Slash".action = show-hotkey-overlay; "Mod+Shift+Return".action = spawn "kitty" "--single-instance"; "Mod+P".action = spawn "tofi-drun"; "Mod+Shift+P".action = spawn "tofi-run"; # Audio stuff "XF86AudioRaiseVolume" = { allow-when-locked = true; action = spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"; }; "XF86AudioLowerVolume" = { allow-when-locked = true; action = spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"; }; "XF86AudioMute" = { allow-when-locked = true; action = spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }; "XF86AudioMicMute" = { allow-when-locked = true; action = spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle"; }; # general window management "Mod+Shift+C".action = close-window; "Mod+Left".action = focus-column-left; "Mod+Down".action = focus-window-down; "Mod+Up".action = focus-window-up; "Mod+Right".action = focus-column-right; "Mod+H".action = focus-column-left; "Mod+J".action = focus-window-down; "Mod+K".action = focus-window-up; "Mod+L".action = focus-column-right; "Mod+Shift+Left".action = move-column-left; "Mod+Shift+Down".action = move-window-down; "Mod+Shift+Up".action = move-window-up; "Mod+Shift+Right".action = move-column-right; "Mod+Shift+H".action = move-column-left; "Mod+Shift+J".action = move-window-down; "Mod+Shift+K".action = move-window-up; "Mod+Shift+L".action = move-column-right; "Mod+Home".action = focus-column-first; "Mod+End".action = focus-column-last; "Mod+Shift+Home".action = move-column-to-first; "Mod+Shift+End".action = move-column-to-last; "Mod+Page_Down".action = focus-workspace-down; "Mod+Page_Up".action = focus-workspace-up; "Mod+U".action = focus-workspace-down; "Mod+I".action = focus-workspace-up; "Mod+Shift+U".action = move-column-to-workspace-down; "Mod+Shift+I".action = move-column-to-workspace-up; "Mod+Shift+Page_Down".action = move-workspace-down; "Mod+Shift+Page_Up".action = move-workspace-up; "Mod+WheelScrollDown".action = focus-workspace-down; "Mod+WheelScrollUp".action = focus-workspace-up; "Mod+Ctrl+WheelScrollDown".action = move-column-to-workspace-down; "Mod+Ctrl+WheelScrollUp".action = move-column-to-workspace-up; "Mod+WheelScrollRight".action = focus-column-right; "Mod+WheelScrollLeft".action = focus-column-left; "Mod+Ctrl+WheelScrollRight".action = move-column-right; "Mod+Ctrl+WheelScrollLeft".action = move-column-left; "Mod+Shift+WheelScrollDown".action = focus-column-right; "Mod+Shift+WheelScrollUp".action = focus-column-left; "Mod+Ctrl+Shift+WheelScrollDown".action = move-column-right; "Mod+Ctrl+Shift+WheelScrollUp".action = move-column-left; "Mod+1".action = focus-workspace 1; "Mod+2".action = focus-workspace 2; "Mod+3".action = focus-workspace 3; "Mod+4".action = focus-workspace 4; "Mod+5".action = focus-workspace 5; "Mod+6".action = focus-workspace 6; "Mod+7".action = focus-workspace 7; "Mod+8".action = focus-workspace 8; "Mod+9".action = focus-workspace 9; "Mod+Shift+1".action.move-column-to-workspace = 1; "Mod+Shift+2".action.move-column-to-workspace = 2; "Mod+Shift+3".action.move-column-to-workspace = 3; "Mod+Shift+4".action.move-column-to-workspace = 4; "Mod+Shift+5".action.move-column-to-workspace = 5; "Mod+Shift+6".action.move-column-to-workspace = 6; "Mod+Shift+7".action.move-column-to-workspace = 7; "Mod+Shift+8".action.move-column-to-workspace = 8; "Mod+Shift+9".action.move-column-to-workspace = 9; "Mod+BracketLeft".action = consume-or-expel-window-left; "Mod+BracketRight".action = consume-or-expel-window-right; # Consume one window from the right to the bottom of the focused column. "Mod+Comma".action = consume-window-into-column; # Expel the bottom window from the focused column to the right. "Mod+Period".action = expel-window-from-column; "Mod+R".action = switch-preset-column-width; "Mod+Shift+R".action = switch-preset-window-height; "Mod+Ctrl+R".action = reset-window-height; "Mod+F".action = maximize-column; "Mod+Shift+F".action = fullscreen-window; # Expand the focused column to space not taken up by other fully visible columns. # Makes the column "fill the rest of the space". "Mod+Ctrl+F".action = expand-column-to-available-width; "Mod+C".action = center-column; "Mod+Minus".action = set-column-width "-10%"; "Mod+Equal".action = set-column-width "+10%"; "Mod+Shift+Minus".action = set-window-height "-10%"; "Mod+Shift+Equal".action = set-window-height "+10%"; "Mod+V".action = toggle-window-floating; "Mod+Shift+V".action = switch-focus-between-floating-and-tiling; "Mod+W".action = toggle-column-tabbed-display; "Print".action = spawn "${screenshot}"; "Mod+Escape" = { allow-inhibiting = false; action = toggle-keyboard-shortcuts-inhibit; }; "Mod+Shift+E".action = quit; "Ctrl+Alt+Delete".action = quit; }; }; xdg.portal = { enable = true; extraPortals = with pkgs; [ xdg-desktop-portal-gtk xdg-desktop-portal-gnome ]; xdgOpenUsePortal = true; config = { niri = { default = [ "gnome" "gtk" ]; "org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ]; }; }; }; # wpaperd manual config # # Can't use the HM module since it doesn't expose the service target as a # config option. If I enabled it, wpaperd would be started for every DE, which # I don't want. xdg.configFile."wpaperd/wallpaper.toml" = { source = tomlFormat.generate "wpaperd-wallpaper" { default = { path = "${config.xdg.userDirs.pictures}/Wallpapers"; duration = "10m"; sorting = "random"; }; }; }; # from: https://github.com/Supreeeme/xwayland-satellite/blob/8575d0ef55d70f9b4c46b6bffb3accf912217e1e/resources/xwayland-satellite.service systemd.user.services.xwayland-satellite = { Unit = { Description = "Xwayland outside your Wayland"; BindsTo = [ "niri.service" ]; PartOf = [ "niri.service" ]; After = [ "niri.service" ]; Requisite = [ "niri.service" ]; }; Service = { Type = "notify"; NotifyAccess = "all"; ExecStart = lib.getExe pkgs.xwayland-satellite; StandardOutput = "journal"; }; Install.WantedBy = lib.mkDefault [ "niri.service" ]; }; systemd.user.services.soteria = { Unit = { Description = "Soteria, Polkit authentication agent for any desktop environment"; Wants = [ "niri.service" ]; After = [ "niri.service" ]; }; Service = { ExecStart = lib.getExe pkgs.soteria; Type = "simple"; Restart = "on-failure"; RestartSec = 1; TimeoutStopSec = 10; }; Install.WantedBy = lib.mkDefault [ "niri.service" ]; }; }