337 lines
12 KiB
Nix
337 lines
12 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
cfg = config.sydnix.users.crumb.niri;
|
|
in {
|
|
options.sydnix.users.crumb.niri = {
|
|
enable = lib.mkEnableOption "Niri, à la crumb";
|
|
wallpaper = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = config.stylix.image;
|
|
};
|
|
# xwayland-satellite implements rootless Xwayland in a separate application,
|
|
# without the host compositor's involvement. It makes X11 windows appear as
|
|
# normal windows, just like a native Xwayland integration. While it is still
|
|
# somewhat experimental, it handles a lot of applications correctly, like
|
|
# Steam, games and Discord.
|
|
xwayland-satellite.enable =
|
|
lib.mkEnableOption "xwayland-satellite starting with Niri"
|
|
// { default = true; };
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
stylix.targets.swaylock.enable = true;
|
|
|
|
services.polkit-gnome.enable = true;
|
|
|
|
# File-picker.
|
|
home.packages = [ pkgs.nautilus ];
|
|
|
|
# Enable the XDG portal, an interface for programs to request
|
|
# permissions/resources. This is necessary to screen-cast on
|
|
# Wayland/Pipewire.
|
|
#
|
|
# See https://github.com/YaLTeR/niri/wiki/Important-Software#portals.
|
|
# Niri's NixOS module automatically brings in xdg-desktop-portal-gnome and
|
|
# gnome-keyring.
|
|
xdg.portal = {
|
|
enable = true;
|
|
xdgOpenUsePortal = true;
|
|
|
|
extraPortals = [
|
|
pkgs.xdg-desktop-portal-gtk
|
|
pkgs.xdg-desktop-portal-gnome
|
|
];
|
|
|
|
# Use xdg-desktop-portal-gtk by default, but fallback to
|
|
# xdg-desktop-portal-gnome for screenshots and screen-casts, two important
|
|
# features unsupported by the GTK implementation. See implementations and
|
|
# their supported interfaces at
|
|
# https://wiki.archlinux.org/title/XDG_Desktop_Portal.
|
|
config.niri = {
|
|
default = [ "gtk" ];
|
|
"org.freedesktop.impl.portal.Screenshot" = [ "gnome" ];
|
|
"org.freedesktop.impl.portal.ScreenCast" = [ "gnome" ];
|
|
};
|
|
};
|
|
|
|
systemd.user.services.xwayland-satellite =
|
|
lib.mkIf cfg.xwayland-satellite.enable {
|
|
Service.ExecStart =
|
|
["${pkgs.xwayland-satellite}/bin/xwayland-satellite"];
|
|
Unit.After = ["niri.service"];
|
|
Unit.PartOf = ["niri.service"];
|
|
Install.WantedBy = ["niri.service"];
|
|
};
|
|
|
|
programs.niri = {
|
|
settings = {
|
|
# Activates some Nixpkgs patches to help run Electron applications under
|
|
# Wayland.
|
|
environment."NIXOS_OZONE_WL" = "1";
|
|
environment."DISPLAY" = ":0";
|
|
|
|
spawn-at-startup =
|
|
[{ command = [ "${pkgs.swaynotificationcenter}/bin/swaync" ]; }
|
|
{ command = [ "${pkgs.gammastep}/bin/gammastep" "-o" "-O" "4000k"
|
|
"-b" "0.9:0.9" "-l" "0:0"]; }]
|
|
++ lib.optional
|
|
(! builtins.isNull cfg.wallpaper)
|
|
{ command = [ "${pkgs.wbg}/bin/wbg" "${cfg.wallpaper}" ]; };
|
|
input = {
|
|
keyboard.xkb = {
|
|
layout = "us";
|
|
options = "ctrl:swapcaps,compose:menu,compose:ralt";
|
|
};
|
|
mouse = {
|
|
accel-speed = -0.5;
|
|
accel-profile = "flat";
|
|
};
|
|
focus-follows-mouse.enable = true;
|
|
};
|
|
outputs."DP-1" = {
|
|
mode.width = 2560;
|
|
mode.height = 1440;
|
|
mode.refresh = 143.912;
|
|
scale = 1;
|
|
};
|
|
layout = {
|
|
background-color = "transparent";
|
|
gaps = 8;
|
|
# center-focused-column = "always";
|
|
center-focused-column = "never";
|
|
preset-column-widths = [
|
|
{ proportion = 1.0 / 3.0; }
|
|
{ proportion = 1.0 / 2.0; }
|
|
{ proportion = 2.0 / 3.0; }
|
|
];
|
|
default-column-width.proportion = 0.5;
|
|
# default-column-width.proportion = {};
|
|
focus-ring = {
|
|
enable = false;
|
|
width = 2;
|
|
};
|
|
border = {
|
|
enable = true;
|
|
width = 2;
|
|
# Override Niri's Stylix integration. Default uses Crystal Blue; we
|
|
# override it with Old White.
|
|
active.color = config.lib.stylix.colors.withHashtag.base06;
|
|
};
|
|
shadow = {
|
|
enable = true;
|
|
softness = 30;
|
|
spread = 5;
|
|
offset.x = 5;
|
|
offset.y = 5;
|
|
};
|
|
tab-indicator = {
|
|
place-within-column = true;
|
|
position = "top";
|
|
# active.color = config.lib.stylix.colors.withHashtag.blue;
|
|
inactive.color = config.lib.stylix.colors.withHashtag.base01;
|
|
width = 8;
|
|
corner-radius = 2.0;
|
|
gaps-between-tabs = 10;
|
|
};
|
|
};
|
|
prefer-no-csd = true;
|
|
screenshot-path = "~/Pictures/Screenshots/%Y-%m-%d %H-%M-%S.png";
|
|
cursor = {
|
|
theme = "default";
|
|
size = 24;
|
|
};
|
|
window-rules = [
|
|
{ # Set red borders to indicate that a window is being captured.
|
|
matches = [
|
|
{ is-window-cast-target = true; }
|
|
];
|
|
focus-ring = {
|
|
enable = true;
|
|
width = 2;
|
|
active.color = "#f38ba8";
|
|
inactive.color = "#7d0d2d";
|
|
};
|
|
border = {
|
|
width = 2;
|
|
inactive.color = "#7d0d2d";
|
|
active.color = "#7d0d2d";
|
|
};
|
|
shadow = {
|
|
color = "#7d0d2d70";
|
|
softness = 30;
|
|
spread = 10;
|
|
offset.x = 0;
|
|
offset.y = 0;
|
|
};
|
|
tab-indicator = {
|
|
active.color = "#f38ba8";
|
|
inactive.color = "#7d0d2d";
|
|
};
|
|
}
|
|
{ # Block private DMs from screencast...
|
|
matches = [
|
|
{ title = "Element.*\\|"; }
|
|
{ title = "Discord.*@"; }
|
|
];
|
|
excludes = [
|
|
# ... except when explicitly targeting the window.
|
|
{ is-window-cast-target = true; }
|
|
];
|
|
block-out-from = "screen-capture";
|
|
}
|
|
{
|
|
# This regular expression is intentionally made as specific as
|
|
# possible, since this is the default config, and we want no false
|
|
# positives. You can get away with just app-id="wezterm" if you
|
|
# want.
|
|
matches = [
|
|
{ app-id = "^org\\.wezfurlong\\.wezterm$"; }
|
|
];
|
|
default-column-width = {};
|
|
}
|
|
{
|
|
# Floating windows.
|
|
matches = [
|
|
# Open the Firefox picture-in-picture player as floating by default.
|
|
{ app-id = "firefox$"; title = "^Picture-in-Picture$"; }
|
|
# Gimp pop-ups.
|
|
{
|
|
app-id = "^Gimp$";
|
|
title = "^(New Layer|Change Foreground Color|Save Image)$";
|
|
}
|
|
];
|
|
open-floating = true;
|
|
}
|
|
{ # Start with low width.
|
|
matches = [
|
|
{ app-id = "com\\.mitchellh\\.ghostty"; }
|
|
];
|
|
default-column-width.proportion = 1.0 / 3.0;
|
|
}
|
|
{
|
|
matches = [
|
|
{ app-id = "^emacs$"; }
|
|
];
|
|
default-column-width.fixed = 640;
|
|
}
|
|
{
|
|
# Enable rounded corners for all windows.
|
|
geometry-corner-radius =
|
|
let r = 8.0;
|
|
in {
|
|
bottom-left = r;
|
|
top-left = r;
|
|
bottom-right = r;
|
|
top-right = r;
|
|
};
|
|
clip-to-geometry = true;
|
|
}
|
|
];
|
|
binds = {
|
|
"Mod+Q".action.close-window = [];
|
|
"Mod+Shift+Q".action.quit = [];
|
|
"Mod+Ctrl+L".action.spawn = ["${pkgs.swaylock}/bin/swaylock"];
|
|
"Mod+D".action.spawn = ["${pkgs.fuzzel}/bin/fuzzel"];
|
|
"Mod+Shift+Slash".action.show-hotkey-overlay = [];
|
|
|
|
# Powers off the monitors. They will be powered back on upon any
|
|
# keyboard/mouse input.
|
|
"Mod+Shift+P".action.power-off-monitors = [];
|
|
|
|
"Mod+I".action.set-dynamic-cast-window = [];
|
|
"Mod+Shift+I".action.set-dynamic-cast-monitor = [];
|
|
"Mod+Ctrl+I".action.clear-dynamic-cast-target = [];
|
|
|
|
"Mod+BracketLeft".action.consume-or-expel-window-left = [];
|
|
"Mod+BracketRight".action.consume-or-expel-window-right = [];
|
|
"Mod+Comma".action.consume-window-into-column = [];
|
|
"Mod+Period".action.expel-window-from-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+C".action.center-column = [];
|
|
"Mod+M".action.maximize-column = [];
|
|
"Mod+Shift+M".action.fullscreen-window = [];
|
|
"Mod+Ctrl+M".action.toggle-windowed-fullscreen = [];
|
|
|
|
"Mod+Shift+S".action.screenshot = [];
|
|
"Print".action.screenshot-screen = [];
|
|
"Mod+Print".action.screenshot-window = [];
|
|
|
|
"Mod+X".action.spawn = [
|
|
"emacsclient-or-emacs"
|
|
"-ce"
|
|
"(eshell t)"
|
|
];
|
|
|
|
"Mod+Shift+F".action.toggle-window-floating = [];
|
|
"Mod+F".action.switch-focus-between-floating-and-tiling = [];
|
|
"Mod+Shift+T".action.toggle-column-tabbed-display = [];
|
|
|
|
"Alt+Tab".action.focus-window-previous = [];
|
|
|
|
"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+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 = [];
|
|
|
|
"XF86MonBrightnessDown".action.spawn =
|
|
[(lib.getExe pkgs.brightnessctl) "s" "5%-"];
|
|
"XF86MonBrightnessUp".action.spawn =
|
|
[(lib.getExe pkgs.brightnessctl) "s" "+5%"];
|
|
|
|
"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+Shift+R".action.switch-preset-window-height = [];
|
|
"Mod+Ctrl+R".action.reset-window-height = [];
|
|
|
|
"XF86AudioRaiseVolume".action.spawn =
|
|
["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"];
|
|
"XF86AudioLowerVolume".action.spawn =
|
|
["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"];
|
|
};
|
|
|
|
layer-rules = [
|
|
# Don't move wallpaper with workspace.
|
|
{
|
|
matches = [{ namespace = "^wallpaper$"; }];
|
|
place-within-backdrop = true;
|
|
}
|
|
];
|
|
|
|
debug = {
|
|
wait-for-frame-completion-in-pipewire = {};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
|