dotfiles/nixos/configs/gui/niri.nix

374 lines
11 KiB
Nix

#
# Configure Niri, our wayland compositor.
#
# vim: et:ts=2:sw=2:
{
lib,
pkgs,
niri,
...
}:
let
niri-flake = niri;
in
{
# Add in some basic control utilities to our system config.
environment.systemPackages = [
pkgs.wlrctl
];
# Don't let the niri-flake fuck with our secret provider, kwallet.
services.gnome.gnome-keyring.enable = lib.mkForce false;
#
# Niri configuration.
#
home-manager.users.deprekated =
{
pkgs,
config,
niri,
...
}:
with lib;
let
binds =
{
suffixes,
prefixes,
substitutions ? { },
}:
#
# This quite-useful monstrosity stolen from @sodiboo.
#
let
replacer = replaceStrings (attrNames substitutions) (attrValues substitutions);
format =
prefix: suffix:
let
actual-suffix =
if isList suffix.action then
{
action = head suffix.action;
args = tail suffix.action;
}
else
{
inherit (suffix) action;
args = [ ];
};
action = replacer "${prefix.action}-${actual-suffix.action}";
in
{
name = "${prefix.key}+${suffix.key}";
value.action.${action} = actual-suffix.args;
};
pairs =
attrs: fn:
concatMap (
key:
fn {
inherit key;
action = attrs.${key};
}
) (attrNames attrs);
in
listToAttrs (pairs prefixes (prefix: pairs suffixes (suffix: [ (format prefix suffix) ])));
xwayland-satellite-loop = pkgs.writeScriptBin "xwayland-satellite-loop" ''
#!${pkgs.bash}/bin/bash
while true; do
${pkgs.xwayland-satellite}/bin/xwayland-satellite
done
'';
in
{
# Don't let the niri-flake fuck with our secret provider, kwallet.
services.gnome-keyring.enable = lib.mkForce false;
#
# Core Niri settings.
#
programs.niri.settings = {
# Use Wayland programs when possible.
environment = {
NIXOS_OZONE_WL = "1";
SHELL_TYPE = "prompt_toolkit";
XDG_DATA_DIRS = "/var/lib/flatpak/exports/share:/home/deprekated/.nix-profile/share:/nix/profile/share:/home/deprekated/.local/state/nix/profile/share:/etc/profiles/per-user/deprekated/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share";
# Provided by xwayland-satellite below.
DISPLAY = ":0";
};
# Avoid client-side decorations, when possible.
prefer-no-csd = true;
# Don't show our hotkeys on startup.
hotkey-overlay.skip-at-startup = true;
#
# Adjust our layouts.
#
layout = {
# No wasted space between windows.
gaps = 0;
# Default to half the screen.
default-column-width = {
proportion = 1.0 / 2.0;
};
# Set up the column widths for Meta+R.
preset-column-widths = [
{ proportion = 1.0 / 2.0; }
{ proportion = 2.0 / 3.0; }
{ proportion = 1.0 / 3.0; }
];
# Improve the color of focused windows.
border = {
active = {
color = "#268BD2";
};
};
};
#
# Keyboard, mouse, etc. settings.
#
input = {
# Moving focus with the keyboard should move the mouse.
warp-mouse-to-focus = true;
touchpad = {
# No tap to click, but use the number of fingers to press
# multiple buttons.
tap = false;
tap-button-map = "left-right-middle";
click-method = "clickfinger";
# Disable while typing.
dwt = true;
# Use natural scrolling.
natural-scroll = true;
};
trackpoint = {
accel-speed = 0.2;
accel-profile = "flat";
};
keyboard = {
# Make caps lock a second escape, and ralt a compose.
xkb.options = "caps:escape,compose:ralt";
};
};
#
# Per-application settings.
#
window-rules = [
# Wezterm workaround: wezterm gets sad when it
# doesn't get to set its own width, so let it.
{
matches = [ { app-id = "^org.wezfurlong.wezterm$"; } ];
default-column-width = { };
}
# Make anki flashcard windows modal floats.
{
matches = [{
app-id = "^anki$";
title = "Add";
}];
open-floating = true;
default-floating-position = {
x = 0;
y = 0;
relative-to = "top-right";
};
}
# Talon windows should show over other ones.
{
matches = [ { app-id = "talon"; } ];
}
# Bitwig needs to set its own width.
{
matches = [ { app-id = "^com.bitwig.BitwigStudio$"; } ];
default-column-width = { };
}
# Let gamescope be fullscreen, by default.
{
matches = [ { app-id = "^gamescope$"; } ];
default-column-width = {
proportion = 1.0;
};
}
# Keep our system monitor on the monitoring screen.
{
matches = [ { app-id = "io.missioncenter.MissionCenter"; } ];
open-on-output = "Shenzhen Soogeen Electronics Co., LTD. L01N8A 0x01348C5C";
open-fullscreen = true;
open-focused = false;
}
];
#
# Key bindings.
#
binds =
with config.lib.niri.actions;
let
sh = spawn "sh" "-c";
in
lib.attrsets.mergeAttrsList [
{
# Kate keys.
"Mod+O".action = sh "haxtype 'O>'";
"Mod+T".action = sh "haxtype '🔵T>'";
"Mod+K".action = sh "haxtype '🟣K>'";
"Mod+W".action = sh "haxtype '🟢W>'";
"Mod+S".action = sh "haxtype '🔴S>'";
"Mod+E".action = sh "haxtype 'E>'";
# Kate keys.
"Mod+F1".action = sh "haxtype ";
"Mod+F2".action = sh "haxtype ";
"Mod+F3".action = sh "haxtype ";
"Print".action = screenshot;
"Mod+Return".action = spawn "wezterm";
"Mod+D".action = spawn "fuzzel";
"Mod+Space".action = spawn "fuzzel";
"XF86AudioRaiseVolume".action = sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 0.1+";
"XF86AudioLowerVolume".action = sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 0.1-";
"XF86Launch6".action = sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 0.1-";
"XF86Tools".action = sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 0.1+";
"XF86AudioMute".action = sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
"XF86AudioMicMute".action = sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle";
"XF86MonBrightnessDown".action = sh "brightnessctl set 10%-";
"XF86MonBrightnessUp".action = sh "brightnessctl set 10%+";
"XF86Messenger".action = sh "rfkill toggle bluetooth";
"XF86Go".action = sh "rfkill toggle wwan";
"Cancel".action = sh "rfkill block nfc";
"XF86Favorites".action = sh "mpc toggle";
# Lenovo buttons.
"0x47".action = sh "brightnessctl set 10%-";
"0x48".action = sh "brightnessctl set 10%+";
"Mod+Q".action = close-window;
"XF86AudioPrev".action = sh "mpc prev";
"XF86AudioNext".action = sh "mpc next";
"XF86AudioPlay".action = sh "mpc toggle";
"XF86Launch5".action = sh "mpc toggle";
}
(binds {
suffixes."Left" = "column-left";
suffixes."Down" = "window-down";
suffixes."Up" = "window-up";
suffixes."Right" = "column-right";
prefixes."Mod" = "focus";
prefixes."Mod+Ctrl" = "move";
prefixes."Mod+Shift" = "focus-monitor";
prefixes."Mod+Shift+Ctrl" = "move-window-to-monitor";
substitutions."monitor-column" = "monitor";
substitutions."monitor-window" = "monitor";
})
(binds {
suffixes."Home" = "first";
suffixes."End" = "last";
prefixes."Mod" = "focus-column";
prefixes."Mod+Ctrl" = "move-column-to";
})
(binds {
suffixes."U" = "workspace-down";
suffixes."I" = "workspace-up";
prefixes."Mod" = "focus";
prefixes."Mod+Ctrl" = "move-window-to";
prefixes."Mod+Shift" = "move";
})
(binds {
suffixes = builtins.listToAttrs (
map (n: {
name = toString n;
value = [
"workspace"
n
];
}) (range 1 9)
);
prefixes."Mod" = "focus";
prefixes."Mod+Ctrl" = "move-window-to";
})
{
"Mod+Comma".action = consume-window-into-column;
"Mod+Period".action = expel-window-from-column;
"Mod+R".action = switch-preset-column-width;
"Mod+F".action = maximize-column;
"Mod+Shift+F".action = fullscreen-window;
"Mod+C".action = center-column;
"Mod+L".action = switch-focus-between-floating-and-tiling;
"Mod+Shift+L".action = toggle-window-floating;
"Mod+Minus".action = set-column-width "-10%";
"Mod+Plus".action = set-column-width "+10%";
"Mod+Shift+Minus".action = set-window-height "-10%";
"Mod+Shift+Plus".action = set-window-height "+10%";
"Mod+Print".action = screenshot-window;
"Mod+Shift+E".action = quit;
"Mod+Shift+P".action = power-off-monitors;
"Mod+Shift+Ctrl+T".action = toggle-debug-tint;
}
];
# Startup our wallpaper and our credential manager.
spawn-at-startup =
let
niri-init = pkgs.writeScriptBin "niri-init" ''
#!${pkgs.bash}/bin/bash
systemctl --user restart swaybg
sleep 2
systemctl --user stop waybar
niri msg action spawn -- waybar
sleep 2
niri msg action spawn -- ${xwayland-satellite-loop}/bin/xwayland-satellite-loop
niri msg action spawn -- home-assistant-desktop
niri msg action spawn -- ${pkgs.mission-center}/bin/missioncenter
sleep 10
niri msg action spawn -- kdeconnect-cli -l
'';
in
[ { command = [ "${niri-init}/bin/niri-init" ]; } ];
};
};
}