Rebase to flake parts #8
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
{ self, inputs, ... }: {
|
||||
flake.nixosModules.desktop = {
|
||||
imports = [
|
||||
self.nixosModules.desktopShellDmsOptions
|
||||
self.nixosModules.desktopHyprland
|
||||
self.nixosModules.desktopNiri
|
||||
self.nixosModules.desktopPlasma
|
||||
self.nixosModules.desktopOptions
|
||||
self.nixosModules.desktopGui
|
||||
self.nixosModules.desktopWallpapers
|
||||
self.nixosModules.desktopWaydroid
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
{ ... }: {
|
||||
flake.nixosModules.desktopGui =
|
||||
{ config, lib, pkgs, self, inputs, options, ... }:
|
||||
let
|
||||
pi5Greeter = self.lib.pi5NiriKdl;
|
||||
cfg = config.chiasson.desktop;
|
||||
guiEnabled = cfg.hyprland.enable || cfg.niri.enable || cfg.plasma.enable;
|
||||
hmAvailable = lib.hasAttrByPath [ "home-manager" "sharedModules" ] options;
|
||||
dm = cfg.displayManager;
|
||||
variant = dm.variant or "sddm";
|
||||
useGreeter = variant == "dankgreeter";
|
||||
sddmTheme =
|
||||
if dm.sddm.theme.package == null then
|
||||
"breeze"
|
||||
else
|
||||
"${dm.sddm.theme.package}/share/sddm/themes/${dm.sddm.theme.id}";
|
||||
effectiveDefaultSession =
|
||||
if cfg.defaultSession != null then
|
||||
cfg.defaultSession
|
||||
else if cfg.hyprland.enable then
|
||||
"hyprland"
|
||||
else if cfg.niri.enable then
|
||||
"niri"
|
||||
else
|
||||
"plasma";
|
||||
greeterCompositor =
|
||||
if effectiveDefaultSession == "niri" then
|
||||
"niri"
|
||||
else if effectiveDefaultSession == "hyprland" then
|
||||
"hyprland"
|
||||
else
|
||||
"niri";
|
||||
enabledUsers = config.chiasson.users.enabled or [ ];
|
||||
greeterConfigHome =
|
||||
if dm.greeter.configHome != null then
|
||||
dm.greeter.configHome
|
||||
else if enabledUsers != [ ] then
|
||||
"/home/${builtins.head enabledUsers}"
|
||||
else
|
||||
null;
|
||||
in
|
||||
{
|
||||
# Unconditional imports only — conditional imports that peek at `config` recurse during merge.
|
||||
imports = [
|
||||
inputs.dms.nixosModules.greeter
|
||||
];
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf guiEnabled {
|
||||
services.xserver.enable = true;
|
||||
|
||||
# Chromium/Electron (Edge, Vesktop, etc.) only add native Wayland + IME flags when this is
|
||||
# set; nixpkgs wrappers gate on NIXOS_OZONE_WL and WAYLAND_DISPLAY. Helps PipeWire/desktop
|
||||
# portal screen capture on wlroots-like sessions. Harmless on X11 (flags stay off).
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = lib.mkDefault "1";
|
||||
|
||||
xdg.portal.enable = true;
|
||||
xdg.portal.extraPortals =
|
||||
[ pkgs.xdg-desktop-portal-gtk ]
|
||||
++ lib.optionals cfg.plasma.enable [ pkgs.kdePackages.xdg-desktop-portal-kde ];
|
||||
})
|
||||
(lib.mkIf (guiEnabled && !useGreeter) {
|
||||
services.displayManager.sddm = {
|
||||
enable = true;
|
||||
wayland.enable = dm.sddm.wayland.enable;
|
||||
theme = sddmTheme;
|
||||
inherit (dm.sddm) enableHidpi settings;
|
||||
extraPackages = lib.optionals (dm.sddm.theme.package != null) (
|
||||
with pkgs.kdePackages; [
|
||||
qtdeclarative
|
||||
qtsvg
|
||||
]
|
||||
);
|
||||
};
|
||||
services.displayManager.defaultSession = effectiveDefaultSession;
|
||||
})
|
||||
(lib.mkIf (guiEnabled && useGreeter) {
|
||||
assertions = [
|
||||
{
|
||||
assertion = greeterConfigHome != null;
|
||||
message = "DankGreeter needs chiasson.desktop.displayManager.greeter.configHome or a non-empty chiasson.users.enabled list.";
|
||||
}
|
||||
];
|
||||
|
||||
services.displayManager.defaultSession = effectiveDefaultSession;
|
||||
|
||||
programs.dank-material-shell.greeter = {
|
||||
enable = true;
|
||||
compositor = {
|
||||
name = greeterCompositor;
|
||||
}
|
||||
// lib.optionalAttrs (cfg.niri.raspberryPi5DrmWorkaround && greeterCompositor == "niri") {
|
||||
customConfig = lib.mkDefault pi5Greeter.dankGreeterCompositorConfig;
|
||||
};
|
||||
configHome = greeterConfigHome;
|
||||
};
|
||||
})
|
||||
(lib.mkIf (cfg.defaultPackages.enabled && guiEnabled) {
|
||||
environment.systemPackages = cfg.defaultPackages.packages;
|
||||
})
|
||||
(lib.mkIf (cfg.extraPackages != [ ] && guiEnabled) {
|
||||
environment.systemPackages = cfg.extraPackages;
|
||||
})
|
||||
(lib.mkIf (guiEnabled && cfg.keyring.enable) {
|
||||
services.gnome.gnome-keyring.enable = true;
|
||||
security.pam.services.login.enableGnomeKeyring = true;
|
||||
services.xserver.updateDbusEnvironment = lib.mkDefault true;
|
||||
# Electron apps (Element, Slack, etc.) use libsecret via keytar; without it they report
|
||||
# "unsupported keyring" even if gnome-keyring is enabled.
|
||||
environment.systemPackages = [ pkgs.libsecret ];
|
||||
})
|
||||
(lib.mkIf (guiEnabled && cfg.keyring.enable && !useGreeter) {
|
||||
security.pam.services.sddm.enableGnomeKeyring = true;
|
||||
})
|
||||
(lib.mkIf (guiEnabled && cfg.keyring.enable && useGreeter) {
|
||||
security.pam.services.greetd.enableGnomeKeyring = true;
|
||||
})
|
||||
(lib.mkIf (guiEnabled && cfg.keyring.enable && hmAvailable) {
|
||||
"home-manager".sharedModules = [
|
||||
({ lib, pkgs, ... }: {
|
||||
services.gnome-keyring.enable = lib.mkDefault true;
|
||||
home.packages = [ pkgs.gcr ];
|
||||
})
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
{ self, ... }: {
|
||||
flake.nixosModules.desktopHyprland =
|
||||
{ config, options, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.chiasson.desktop;
|
||||
hmAvailable = lib.hasAttrByPath [ "home-manager" "sharedModules" ] options;
|
||||
in
|
||||
{
|
||||
options.chiasson.desktop.hyprland = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Hyprland session + HM wiring.";
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = { };
|
||||
description = "Extra `wayland.windowManager.hyprland.settings` merged with defaults.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf cfg.hyprland.enable {
|
||||
programs.hyprland.enable = true;
|
||||
})
|
||||
(lib.mkIf (cfg.hyprland.enable && hmAvailable) {
|
||||
"home-manager".sharedModules = [ self.homeManagerModules.desktopHyprland ];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
flake.homeManagerModules.desktopHyprland = {
|
||||
config,
|
||||
lib,
|
||||
osConfig ? { },
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
hyprlandEnabled = osConfig.chiasson.desktop.hyprland.enable or false;
|
||||
# nixpkgs hyprland-plugins pin is stale for current Hyprland — override to a known-good rev.
|
||||
hyprbarsPatched =
|
||||
let
|
||||
hyprlandPluginsSrc = pkgs.fetchFromGitHub {
|
||||
owner = "hyprwm";
|
||||
repo = "hyprland-plugins";
|
||||
rev = "b85a56b9531013c79f2f3846fd6ee2ff014b8960";
|
||||
hash = "sha256-xwNa+1D8WPsDnJtUofDrtyDCZKZotbUymzV/R5s+M0I=";
|
||||
};
|
||||
in
|
||||
pkgs.hyprlandPlugins.hyprbars.overrideAttrs (_: {
|
||||
version = "unstable-2026-02-23";
|
||||
src = "${hyprlandPluginsSrc}/hyprbars";
|
||||
});
|
||||
in
|
||||
{
|
||||
config = lib.mkIf hyprlandEnabled {
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
# null = use NixOS Hyprland/xdg-desktop-portal-hyprland (same versions as the session).
|
||||
package = null;
|
||||
portalPackage = null;
|
||||
plugins = [ hyprbarsPatched ];
|
||||
extraConfig = ''
|
||||
source = ~/.config/hypr/colors.conf
|
||||
'';
|
||||
|
||||
settings = lib.mkMerge [
|
||||
{
|
||||
monitor = [ ",preferred,auto,auto" ];
|
||||
general = {
|
||||
gaps_in = 8;
|
||||
gaps_out = 4;
|
||||
border_size = 2;
|
||||
allow_tearing = false;
|
||||
};
|
||||
cursor.no_hardware_cursors = true;
|
||||
env = [
|
||||
"XCURSOR_THEME,phinger-cursors-dark"
|
||||
"XCURSOR_SIZE,32"
|
||||
];
|
||||
input = {
|
||||
kb_layout = "ca";
|
||||
kb_variant = "";
|
||||
numlock_by_default = true;
|
||||
};
|
||||
binds.scroll_event_delay = 50;
|
||||
exec-once = [
|
||||
"nm-applet --indicator &"
|
||||
"sleep 1 && hyprctl reload"
|
||||
];
|
||||
|
||||
# Default keybinds
|
||||
bind =
|
||||
[
|
||||
"SUPER,T,exec,kitty -e fish"
|
||||
"ControlSuper,T,exec,konsole"
|
||||
"SUPER,D,exec,rofi -show drun"
|
||||
"ControlSuper,D,exec,rofi -show window"
|
||||
"SUPER,E,exec,dolphin"
|
||||
"Super, Q, killactive"
|
||||
"ControlSuper, Q, exec, hyprctl kill"
|
||||
"Super, F, fullscreen, 0"
|
||||
"Super, G, fullscreen, 1"
|
||||
"ShiftSuper, F, fullscreenstate, 0 3"
|
||||
"Super, Minus, splitratio, -0.1"
|
||||
"Super, Equal, splitratio, 0.1"
|
||||
"AltSuper, Space, togglefloating"
|
||||
"Super, P, pin"
|
||||
"Super, Space, exec, dms ipc call spotlight toggle"
|
||||
"Super, I, exec, dms ipc call settings focusOrToggle"
|
||||
"Super, N, exec, dms ipc call notepad toggle"
|
||||
"ShiftSuper, N, exec, dms ipc call notifications toggle"
|
||||
"Super, M, exec, dms ipc call processlist focusOrToggle"
|
||||
"Super, L, exec, dms ipc call lock lock"
|
||||
"ShiftSuper, V, exec, dms ipc call clipboard toggle"
|
||||
"Super, Tab, cyclenext"
|
||||
"Super, Tab, bringactivetotop"
|
||||
"Super, left, movefocus, l"
|
||||
"Super, right, movefocus, r"
|
||||
"Super, up, movefocus, u"
|
||||
"Super, down, movefocus, d"
|
||||
"ShiftSuper, left, movewindow, l"
|
||||
"ShiftSuper, right, movewindow, r"
|
||||
"ShiftSuper, up, movewindow, u"
|
||||
"ShiftSuper, down, movewindow, d"
|
||||
]
|
||||
++ (builtins.map (i: "Super, ${toString i}, workspace, ${toString i}") (builtins.genList (n: n + 1) 9))
|
||||
++ (builtins.map (i: "ControlSuper, ${toString i}, focusworkspaceoncurrentmonitor, ${toString i}") (builtins.genList (n: n + 1) 9))
|
||||
++ (builtins.map (i: "ShiftSuper, ${toString i}, movetoworkspacesilent, ${toString i}") (builtins.genList (n: n + 1) 9));
|
||||
|
||||
bindm = [
|
||||
" , mouse:282, movewindow"
|
||||
"Super, mouse:272, movewindow"
|
||||
"Super, mouse:273, resizewindow"
|
||||
];
|
||||
|
||||
bindl = [
|
||||
"Super, mouse_up, splitratio, -0.1"
|
||||
"Super, mouse_down, splitratio, 0.1"
|
||||
" , XF86AudioPlay, exec, playerctl play-pause"
|
||||
" , XF86AudioPrev, exec, playerctl previous"
|
||||
" , XF86AudioNext, exec, playerctl next"
|
||||
" , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
|
||||
" , XF86MonBrightnessDown, exec, brightnessctl s 10%-"
|
||||
" , XF86MonBrightnessUp, exec, brightnessctl s +10%"
|
||||
];
|
||||
|
||||
bindel = [
|
||||
" , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
|
||||
" , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
|
||||
];
|
||||
|
||||
# Decoration / blur
|
||||
decoration = {
|
||||
rounding = 10;
|
||||
active_opacity = 0.95;
|
||||
inactive_opacity = 0.85;
|
||||
shadow = {
|
||||
enabled = true;
|
||||
range = 5;
|
||||
render_power = 8;
|
||||
};
|
||||
blur = {
|
||||
enabled = true;
|
||||
new_optimizations = true;
|
||||
xray = false;
|
||||
size = 2;
|
||||
passes = 4;
|
||||
vibrancy = 10;
|
||||
};
|
||||
};
|
||||
misc = {
|
||||
disable_hyprland_logo = true;
|
||||
disable_splash_rendering = true;
|
||||
};
|
||||
plugin.hyprbars = {
|
||||
enabled = true;
|
||||
bar_height = 30;
|
||||
bar_blur = true;
|
||||
bar_padding = 10;
|
||||
bar_button_padding = 7;
|
||||
bar_precedence_over_border = true;
|
||||
bar_part_of_window = true;
|
||||
bar_title_enabled = true;
|
||||
bar_text_size = 10;
|
||||
bar_text_font = "Sans";
|
||||
bar_text_align = "center";
|
||||
bar_buttons_alignment = "left";
|
||||
icon_on_hover = true;
|
||||
"hyprbars-button" = [
|
||||
"rgb(ed6a5f), 12, , hyprctl dispatch killactive, rgb(460804)"
|
||||
"rgb(f6be50), 12, , hyprctl dispatch movetoworkspacesilent special:minimized, rgb(90591d)"
|
||||
"rgb(61c555), 12, , hyprctl dispatch fullscreen 1, rgb(2a6218)"
|
||||
];
|
||||
};
|
||||
|
||||
windowrule = [
|
||||
"sync_fullscreen 0, match:class ^(?i)microsoft-edge|Spotify|org.kde.gwenview|zen-beta$"
|
||||
"opacity 1.0 override 0.95 override, match:class ^(?i)microsoft-edge$"
|
||||
"opacity 1.0 override 1.00 override, match:class ^(?i)com.stremio.stremio$"
|
||||
"opacity 1.0 override 0.85 override, match:class ^(?i)zen-beta$"
|
||||
"no_screen_share on, match:class ^(?i)(microsoft-edge|zen-beta)$, match:title ^(?i).*(scotiabank|paypal).*"
|
||||
"no_screen_share on, match:class ^(?i)microsoft-edge$, match:initial_title ^(?i).*(?i)personal 2.*edge.*$"
|
||||
"hyprbars:no_bar on, match:class ^(?i)(microsoft-edge|Cursor|Flow|looking-glass-client|localsend_app)$"
|
||||
];
|
||||
}
|
||||
(osConfig.chiasson.desktop.hyprland.settings or { })
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
{ self, inputs, ... }:
|
||||
let
|
||||
# Keep defaults in this let — a bare niri-settings.nix next to this file would get picked up by import-tree.
|
||||
niriBaseSettings =
|
||||
pkgs:
|
||||
{
|
||||
input.keyboard = {
|
||||
xkb.layout = "ca";
|
||||
xkb.variant = "";
|
||||
};
|
||||
input."focus-follows-mouse" = _: {
|
||||
props."max-scroll-amount" = "45%";
|
||||
content = { };
|
||||
};
|
||||
input."warp-mouse-to-focus" = _: { };
|
||||
layout.gaps = 5;
|
||||
|
||||
window-rules = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
app-id = "^$";
|
||||
title = "^$";
|
||||
}
|
||||
];
|
||||
open-floating = true;
|
||||
open-focused = false;
|
||||
}
|
||||
];
|
||||
#TODO[epic=Binds] Go over binds again
|
||||
binds = {
|
||||
"Mod+T"."spawn-sh" = "${pkgs.lib.getExe pkgs.kitty} -e fish"; #TODO[epic=Binds] This should only be set if having kitty
|
||||
"Mod+Control+T"."spawn-sh" = "konsole"; #TODO[epic=Binds] This should only be set if having konsole
|
||||
"Mod+D"."spawn-sh" = "rofi -show drun"; #TODO[epic=Binds] This should only be set if having rofi
|
||||
"Mod+Space"."spawn-sh" = "dms ipc call spotlight toggle"; #TODO[epic=Binds] This should only be set if having dms
|
||||
"Mod+E"."spawn-sh" = "dolphin"; #TODO[epic=Binds] This should only be set if having dolphin
|
||||
"Mod+Control+O"."spawn-sh" = "rofi -show window"; #TODO[epic=Binds] This should only be set if having rofi
|
||||
"Mod+V"."spawn-sh" = "dms ipc call clipboard toggle"; #TODO[epic=Binds] This should only be set if having dms
|
||||
"Mod+N"."spawn-sh" = "dms ipc call notepad toggle"; #TODO[epic=Binds] This should only be set if having dms
|
||||
"Mod+Shift+N"."spawn-sh" = "dms ipc call notifications toggle"; #TODO[epic=Binds] This should only be set if having dms
|
||||
"Mod+M"."spawn-sh" = "dms ipc call processlist toggle"; #TODO[epic=Binds] This should only be set if having dms
|
||||
"Mod+L"."spawn-sh" = "dms ipc call lock lock"; #TODO[epic=Binds] This should only be set if having dms
|
||||
|
||||
"Mod+Q"."close-window" = _: { };
|
||||
"Mod+F"."maximize-column" = _: { };
|
||||
"Mod+Shift+F"."fullscreen-window" = _: { };
|
||||
"Mod+O"."toggle-overview" = _: { };
|
||||
"Mod+Shift+NumberSign"."show-hotkey-overlay" = _: { };
|
||||
"Mod+Shift+E".quit = _: { };
|
||||
|
||||
"Mod+Left"."focus-column-or-monitor-left" = _: { };
|
||||
"Mod+Down"."focus-window-or-monitor-down" = _: { };
|
||||
"Mod+Up"."focus-window-or-monitor-up" = _: { };
|
||||
"Mod+Right"."focus-column-or-monitor-right" = _: { };
|
||||
|
||||
"Mod+Shift+WheelScrollDown"."focus-workspace-down" = _: { };
|
||||
"Mod+Shift+WheelScrollUp"."focus-workspace-up" = _: { };
|
||||
|
||||
"Mod+WheelScrollDown"."focus-column-or-monitor-right" = _: { };
|
||||
"Mod+WheelScrollUp"."focus-column-or-monitor-left" = _: { };
|
||||
|
||||
"Mod+Shift+Left"."move-column-left-or-to-monitor-left" = _: { };
|
||||
"Mod+Shift+Down"."move-window-down" = _: { };
|
||||
"Mod+Shift+Up"."move-window-up" = _: { };
|
||||
"Mod+Shift+Right"."move-column-right-or-to-monitor-right" = _: { };
|
||||
"Mod+Page_Up"."focus-workspace-up" = _: { };
|
||||
"Mod+Page_Down"."focus-workspace-down" = _: { };
|
||||
"Mod+Shift+Page_Up"."move-column-to-workspace-up" = _: { };
|
||||
"Mod+Shift+Page_Down"."move-column-to-workspace-down" = _: { };
|
||||
"Mod+R"."switch-preset-column-width" = _: { };
|
||||
"Mod+BracketLeft"."consume-or-expel-window-left" = _: { };
|
||||
"Mod+BracketRight"."consume-or-expel-window-right" = _: { };
|
||||
"Mod+Comma"."consume-window-into-column" = _: { };
|
||||
"Mod+Period"."expel-window-from-column" = _: { };
|
||||
"Mod+Alt+Space"."toggle-window-floating" = _: { };
|
||||
#"Mod+Shift+V"."switch-focus-between-floating-and-tiling" = _: { }; #TODO[epic=Binds] Find free bind that is not in the way and not overcomplicated to remember
|
||||
|
||||
"Mod+1"."focus-workspace" = 1;
|
||||
"Mod+2"."focus-workspace" = 2;
|
||||
"Mod+3"."focus-workspace" = 3;
|
||||
"Mod+4"."focus-workspace" = 4;
|
||||
"Mod+5"."focus-workspace" = 5;
|
||||
"Mod+6"."focus-workspace" = 6;
|
||||
"Mod+7"."focus-workspace" = 7;
|
||||
"Mod+8"."focus-workspace" = 8;
|
||||
"Mod+9"."focus-workspace" = 9;
|
||||
"Mod+Ctrl+1"."move-column-to-workspace" = 1;
|
||||
"Mod+Ctrl+2"."move-column-to-workspace" = 2;
|
||||
"Mod+Ctrl+3"."move-column-to-workspace" = 3;
|
||||
"Mod+Ctrl+4"."move-column-to-workspace" = 4;
|
||||
"Mod+Ctrl+5"."move-column-to-workspace" = 5;
|
||||
"Mod+Ctrl+6"."move-column-to-workspace" = 6;
|
||||
"Mod+Ctrl+7"."move-column-to-workspace" = 7;
|
||||
"Mod+Ctrl+8"."move-column-to-workspace" = 8;
|
||||
"Mod+Ctrl+9"."move-column-to-workspace" = 9;
|
||||
|
||||
"XF86AudioRaiseVolume".spawn = [
|
||||
"wpctl"
|
||||
"set-volume"
|
||||
"@DEFAULT_AUDIO_SINK@"
|
||||
"0.05+"
|
||||
];
|
||||
"XF86AudioLowerVolume".spawn = [
|
||||
"wpctl"
|
||||
"set-volume"
|
||||
"@DEFAULT_AUDIO_SINK@"
|
||||
"0.05-"
|
||||
];
|
||||
"XF86AudioMute".spawn = [
|
||||
"wpctl"
|
||||
"set-mute"
|
||||
"@DEFAULT_AUDIO_SINK@"
|
||||
"toggle"
|
||||
];
|
||||
|
||||
Print.screenshot = _: { };
|
||||
"Ctrl+Print"."screenshot-screen" = _: { };
|
||||
"Alt+Print"."screenshot-window" = _: { };
|
||||
};
|
||||
};
|
||||
|
||||
mergeNiriSettings =
|
||||
pkgs: niriCfg:
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
pi5 = self.lib.pi5NiriKdl;
|
||||
rpi5Extra = lib.optionalString (niriCfg.raspberryPi5DrmWorkaround or false) pi5.drmExtraConfig;
|
||||
userExtra = niriCfg.extraSettings or { };
|
||||
extraConfigMerged = rpi5Extra + (userExtra.extraConfig or "");
|
||||
in
|
||||
lib.recursiveUpdate (niriBaseSettings pkgs) (
|
||||
userExtra
|
||||
// lib.optionalAttrs (rpi5Extra != "" || (userExtra.extraConfig or "") != "") {
|
||||
extraConfig = extraConfigMerged;
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
flake.homeManagerModules.desktopNiri =
|
||||
{ lib, pkgs, osConfig ? { }, ... }:
|
||||
let
|
||||
niriOs = osConfig.chiasson.desktop.niri or { };
|
||||
niriEnabled = osConfig.chiasson.desktop.niri.enable or false;
|
||||
mergedSettings = mergeNiriSettings pkgs niriOs;
|
||||
niriConfigPkg = inputs.wrapper-modules.wrappers.niri.wrap {
|
||||
inherit pkgs;
|
||||
settings = mergedSettings;
|
||||
};
|
||||
in
|
||||
{
|
||||
config = lib.mkIf niriEnabled {
|
||||
xdg.configFile."niri/config.kdl".source = "${niriConfigPkg}/niri-config.kdl";
|
||||
};
|
||||
};
|
||||
|
||||
flake.nixosModules.desktopNiri =
|
||||
{ config, options, lib, pkgs, self, ... }:
|
||||
let
|
||||
cfg = config.chiasson.desktop;
|
||||
hmAvailable = lib.hasAttrByPath [ "home-manager" "sharedModules" ] options;
|
||||
in
|
||||
{
|
||||
options.chiasson.desktop.niri = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Niri compositor session + NixOS packages.";
|
||||
};
|
||||
|
||||
raspberryPi5DrmWorkaround = lib.mkEnableOption ''
|
||||
Pi 5 + RP1 DSI: Niri DRM debug rules (renderD128, ignore card1/2) + matching DankGreeter niri config.
|
||||
Opt-in only — HDMI-only / other Pi setups do not need this.
|
||||
'';
|
||||
|
||||
extraSettings = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = { };
|
||||
description = ''
|
||||
Merged into shared defaults → `config.kdl` via wrapper-modules. Put raw KDL in `extraConfig`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = !cfg.niri.raspberryPi5DrmWorkaround || cfg.niri.enable;
|
||||
message = "chiasson.desktop.niri.raspberryPi5DrmWorkaround requires chiasson.desktop.niri.enable.";
|
||||
}
|
||||
];
|
||||
}
|
||||
(lib.mkIf cfg.niri.enable {
|
||||
programs.niri.enable = true;
|
||||
programs.niri.package = pkgs.niri;
|
||||
programs.xwayland.enable = true;
|
||||
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gnome ];
|
||||
# Niri resolves `xwayland-satellite` from PATH to provide XWayland + `$DISPLAY` for X11
|
||||
# clients (Steam, etc.). See https://github.com/YaLTeR/niri/issues/452
|
||||
environment.systemPackages = [ pkgs.xwayland-satellite ];
|
||||
})
|
||||
(lib.mkIf (cfg.niri.enable && hmAvailable) {
|
||||
"home-manager".sharedModules = [ self.homeManagerModules.desktopNiri ];
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
{ ... }: {
|
||||
flake.nixosModules.desktopOptions =
|
||||
{ config, options, lib, pkgs, self, inputs, ... }:
|
||||
let
|
||||
cfg = config.chiasson.desktop;
|
||||
hmAvailable = lib.hasAttrByPath [ "home-manager" "sharedModules" ] options;
|
||||
guiEnabled = cfg.hyprland.enable || cfg.niri.enable || cfg.plasma.enable;
|
||||
dmsEnabled = cfg.shell == "dms";
|
||||
sddmIni = pkgs.formats.ini { };
|
||||
# Pixie SDDM theme — Qt6 main; upstream has a qt5 branch if you need it.
|
||||
pixieSddm = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "pixie-sddm";
|
||||
version = "0-unstable-2026-03-29";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "xCaptaiN09";
|
||||
repo = "pixie-sddm";
|
||||
rev = "12a5f459ebd6d699be42c188c10976c8bb7076d7";
|
||||
hash = "sha256-lmE/49ySuAZDh5xLochWqfSw9qWrIV+fYaK5T2Ckck8=";
|
||||
};
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
installPhase = ''
|
||||
mkdir -p "$out/share/sddm/themes/pixie"
|
||||
cp -r "$src"/. "$out/share/sddm/themes/pixie/"
|
||||
'';
|
||||
meta = {
|
||||
description = "Pixel / Material 3 inspired SDDM theme (Qt6)";
|
||||
homepage = "https://github.com/xCaptaiN09/pixie-sddm";
|
||||
license = lib.licenses.mit;
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.chiasson.desktop = {
|
||||
defaultSession = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.enum [
|
||||
"hyprland"
|
||||
"niri"
|
||||
"plasma"
|
||||
]);
|
||||
default = null;
|
||||
example = "niri";
|
||||
description = ''
|
||||
DM session preference; `null` picks from which compositor flags are enabled. Turn on only
|
||||
the compositor you use so SDDM does not drag in extras.
|
||||
'';
|
||||
};
|
||||
|
||||
shell = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.enum [ "dms" ]);
|
||||
default = null;
|
||||
example = "dms";
|
||||
description = "Desktop shell overlay (e.g. DMS). Extend the enum when you add another.";
|
||||
};
|
||||
|
||||
displayManager = {
|
||||
variant = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.enum [
|
||||
"sddm"
|
||||
"dankgreeter"
|
||||
]);
|
||||
default = null;
|
||||
description = ''
|
||||
SDDM vs DankGreeter (greetd + DMS — [docs](https://danklinux.com/docs/dankgreeter/nixos-flake)).
|
||||
`null`: Plasma-only → SDDM; Hyprland/Niri + `desktop.shell = "dms"` → DankGreeter; else SDDM.
|
||||
'';
|
||||
};
|
||||
|
||||
greeter = {
|
||||
configHome = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/home/olivier";
|
||||
description = ''
|
||||
Whose DMS files to mirror into the greeter cache. `null` → first entry in `chiasson.users.enabled`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
displayManager.sddm = {
|
||||
wayland.enable = lib.mkEnableOption ''
|
||||
SDDM greeter on Wayland (nicer on HiDPI; turn off if the greeter glitches on your GPU).
|
||||
'' // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
enableHidpi = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Passed through to `services.displayManager.sddm.enableHidpi`.";
|
||||
};
|
||||
|
||||
theme = {
|
||||
package = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.package;
|
||||
default = pixieSddm;
|
||||
description = ''
|
||||
Package providing `share/sddm/themes/<id>`. Default: bundled [Pixie](https://github.com/xCaptaiN09/pixie-sddm).
|
||||
`null` → Breeze. Other nixpkgs examples: `catppuccin-sddm`, `sddm-sugar-dark`.
|
||||
'';
|
||||
};
|
||||
|
||||
id = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "pixie";
|
||||
description = ''
|
||||
Subdir under `share/sddm/themes/` (default `pixie`). Match your theme package (e.g. catppuccin ids).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = sddmIni.type;
|
||||
default = { };
|
||||
description = "Extra `services.displayManager.sddm.settings` (INI).";
|
||||
};
|
||||
};
|
||||
|
||||
plasma.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Plasma 6 session bits for this flake.";
|
||||
};
|
||||
|
||||
defaultPackages = {
|
||||
enabled = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Shared desktop utility packages (ntfs3g, cifs-utils, …).";
|
||||
};
|
||||
packages = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
default = with pkgs; [
|
||||
ntfs3g
|
||||
cifs-utils
|
||||
usbutils
|
||||
xhost
|
||||
];
|
||||
description = "Packages merged when `defaultPackages.enabled` is true.";
|
||||
};
|
||||
};
|
||||
|
||||
extraPackages = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
default = [ ];
|
||||
description = "Extra packages on GUI hosts.";
|
||||
};
|
||||
|
||||
homeManager = {
|
||||
bundleWisdom = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Add `wisdom` (baseline + bash) to HM `sharedModules`. Other slices still go in per-user `extraModules`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
keyring = {
|
||||
enable = lib.mkEnableOption ''
|
||||
gnome-keyring + pam (login + sddm or greetd) + HM user service + `gcr` + `services.xserver.updateDbusEnvironment`.
|
||||
niri/hyprland: `dbus-update-activation-environment` at compositor start so libsecret/Electron see `WAYLAND_DISPLAY`.
|
||||
'' // {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.defaultSession != "hyprland" || cfg.hyprland.enable;
|
||||
message = "chiasson.desktop.defaultSession = \"hyprland\" requires chiasson.desktop.hyprland.enable = true.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.defaultSession != "niri" || cfg.niri.enable;
|
||||
message = "chiasson.desktop.defaultSession = \"niri\" requires chiasson.desktop.niri.enable = true.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.defaultSession != "plasma" || cfg.plasma.enable;
|
||||
message = "chiasson.desktop.defaultSession = \"plasma\" requires chiasson.desktop.plasma.enable = true.";
|
||||
}
|
||||
{
|
||||
assertion =
|
||||
cfg.displayManager.variant != "dankgreeter" || cfg.hyprland.enable || cfg.niri.enable;
|
||||
message = "chiasson.desktop.displayManager.variant = \"dankgreeter\" requires chiasson.desktop.hyprland or chiasson.desktop.niri.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.displayManager.variant != "dankgreeter" || cfg.shell == "dms";
|
||||
message = "DankGreeter expects chiasson.desktop.shell = \"dms\" for DMS/matugen sync; use SDDM or enable DMS.";
|
||||
}
|
||||
];
|
||||
}
|
||||
(lib.mkIf guiEnabled {
|
||||
chiasson.desktop.displayManager.variant = lib.mkDefault (
|
||||
if cfg.plasma.enable && !(cfg.hyprland.enable || cfg.niri.enable) then
|
||||
"sddm"
|
||||
else if (cfg.hyprland.enable || cfg.niri.enable) && cfg.shell == "dms" then
|
||||
"dankgreeter"
|
||||
else
|
||||
"sddm"
|
||||
);
|
||||
})
|
||||
(lib.mkIf (guiEnabled && hmAvailable && cfg.homeManager.bundleWisdom) {
|
||||
"home-manager".sharedModules = [ self.homeManagerModules.wisdom ];
|
||||
})
|
||||
(lib.mkIf (dmsEnabled && hmAvailable) {
|
||||
"home-manager".sharedModules = [ self.homeManagerModules.desktopShellDms ];
|
||||
})
|
||||
(lib.mkIf (hmAvailable && (dmsEnabled || cfg.niri.enable)) {
|
||||
"home-manager".extraSpecialArgs = { inherit inputs; };
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{ ... }: {
|
||||
flake.nixosModules.desktopPlasma =
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.chiasson.desktop;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.plasma.enable {
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
environment.etc."xdg/menus/applications.menu".text =
|
||||
builtins.readFile "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{ inputs, ... }: {
|
||||
flake.nixosModules.desktopShellDmsOptions = { lib, ... }: {
|
||||
options.chiasson.desktop.shells.dms = {
|
||||
enableGpuTemp = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "GPU temp in DMS bar.";
|
||||
};
|
||||
obsidianSnippetsDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Legacy single Obsidian snippets dir for matugen.";
|
||||
};
|
||||
obsidianConfigDirs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Vault `.obsidian/` paths for matugen.";
|
||||
};
|
||||
obsidianSnippetsDirs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Explicit `.obsidian/snippets` paths.";
|
||||
};
|
||||
extraRightBarWidgets = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.attrs;
|
||||
default = [ ];
|
||||
description = "Extra right-bar widgets (prepended).";
|
||||
};
|
||||
enableWvkbdToggle = lib.mkEnableOption ''
|
||||
wvkbd DMS plugin + bar toggle (touch / uConsole).
|
||||
'';
|
||||
enableRbwLockToggle = lib.mkEnableOption ''
|
||||
rbw vault lock/unlock button in the DMS bar (Bitwarden CLI via rbw).
|
||||
'';
|
||||
rebuildCommand = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.listOf lib.types.str);
|
||||
default = null;
|
||||
example = [ "sudo" "nixos-rebuild" "switch" "--flake" ".#14900k" ];
|
||||
description = "Command used by DMS nix-monitor widget for rebuild actions.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
flake.homeManagerModules.desktopShellDms = {
|
||||
lib,
|
||||
osConfig ? { },
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = lib.attrByPath [ "chiasson" "desktop" "shells" "dms" ] { } osConfig;
|
||||
selectedShell = lib.attrByPath [ "chiasson" "desktop" "shell" ] null osConfig;
|
||||
dmsEnabled = selectedShell == "dms";
|
||||
hostName = lib.attrByPath [ "networking" "hostName" ] "nixos" osConfig;
|
||||
rebuildCommand =
|
||||
if (cfg.rebuildCommand or null) != null then
|
||||
cfg.rebuildCommand
|
||||
else
|
||||
[ "sudo" "nixos-rebuild" "switch" "--flake" ".#${hostName}" ];
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./home-manager/default.nix
|
||||
];
|
||||
|
||||
config = lib.mkIf dmsEnabled {
|
||||
dms.enable = true;
|
||||
dms.enableGpuTemp = cfg.enableGpuTemp or true;
|
||||
dms.obsidianSnippetsDir = cfg.obsidianSnippetsDir or null;
|
||||
dms.obsidianConfigDirs = cfg.obsidianConfigDirs or [ ];
|
||||
dms.obsidianSnippetsDirs = cfg.obsidianSnippetsDirs or [ ];
|
||||
dms.enableWvkbdToggle = cfg.enableWvkbdToggle or false;
|
||||
dms.enableRbwLockToggle = cfg.enableRbwLockToggle or false;
|
||||
dms.extraRightBarWidgets =
|
||||
(lib.optionals (cfg.enableWvkbdToggle or false) [
|
||||
{
|
||||
id = "wvkbdToggle";
|
||||
enabled = true;
|
||||
}
|
||||
])
|
||||
++ (lib.optionals (cfg.enableRbwLockToggle or false) [
|
||||
{
|
||||
id = "rbwLockToggle";
|
||||
enabled = true;
|
||||
}
|
||||
])
|
||||
++ (cfg.extraRightBarWidgets or [ ]);
|
||||
programs.nix-monitor.rebuildCommand = rebuildCommand;
|
||||
};
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Plugins
|
||||
|
||||
PluginComponent {
|
||||
id: root
|
||||
|
||||
property bool vaultUnlocked: false
|
||||
|
||||
function refreshLockState() {
|
||||
if (!statusProcess.running)
|
||||
statusProcess.exec(["rbw", "unlocked"]);
|
||||
}
|
||||
|
||||
function toggleLock() {
|
||||
if (root.vaultUnlocked) {
|
||||
Quickshell.execDetached(["rbw", "lock"]);
|
||||
} else {
|
||||
Quickshell.execDetached(["rbw", "unlock"]);
|
||||
}
|
||||
}
|
||||
|
||||
pillClickAction: () => root.toggleLock()
|
||||
|
||||
Component.onCompleted: refreshLockState()
|
||||
|
||||
Timer {
|
||||
interval: 2500
|
||||
repeat: true
|
||||
running: true
|
||||
onTriggered: root.refreshLockState()
|
||||
}
|
||||
|
||||
Process {
|
||||
id: statusProcess
|
||||
command: ["rbw", "unlocked"]
|
||||
onExited: (exitCode, _exitStatus) => {
|
||||
root.vaultUnlocked = exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
horizontalBarPill: Component {
|
||||
MouseArea {
|
||||
implicitWidth: iconH.implicitWidth
|
||||
implicitHeight: iconH.implicitHeight
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.toggleLock()
|
||||
|
||||
DankIcon {
|
||||
id: iconH
|
||||
name: root.vaultUnlocked ? "lock_open_right" : "lock"
|
||||
size: root.iconSize
|
||||
color: parent.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
verticalBarPill: Component {
|
||||
MouseArea {
|
||||
implicitWidth: iconV.implicitWidth
|
||||
implicitHeight: iconV.implicitHeight
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.toggleLock()
|
||||
|
||||
DankIcon {
|
||||
id: iconV
|
||||
name: root.vaultUnlocked ? "lock_open_right" : "lock"
|
||||
size: root.iconSize
|
||||
color: parent.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
|
||||
PluginSettings {
|
||||
id: root
|
||||
pluginId: "rbwLockToggle"
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Shows rbw vault state with a closed lock (locked) or open lock (unlocked). Click to run `rbw unlock` (pinentry) or `rbw lock`. Requires `rbw` on PATH in the DMS session and a working pinentry."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "rbwLockToggle",
|
||||
"name": "Bitwarden (rbw) lock",
|
||||
"description": "Bar control for rbw vault: locked/unlocked padlock; click to unlock or lock",
|
||||
"version": "1.0.0",
|
||||
"author": "NixOS-V2",
|
||||
"type": "widget",
|
||||
"capabilities": ["dankbar-widget"],
|
||||
"component": "./RbwLockToggle.qml",
|
||||
"settings": "./RbwLockToggleSettings.qml",
|
||||
"icon": "lock_open",
|
||||
"permissions": ["settings_read"]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Plugins
|
||||
|
||||
PluginComponent {
|
||||
id: root
|
||||
|
||||
function toggleKeyboard() {
|
||||
Quickshell.execDetached(["sh", "-c", "pkill -SIGRTMIN -x wvkbd-mobintl"]);
|
||||
}
|
||||
|
||||
pillClickAction: () => root.toggleKeyboard()
|
||||
|
||||
horizontalBarPill: Component {
|
||||
MouseArea {
|
||||
implicitWidth: icon.implicitWidth
|
||||
implicitHeight: icon.implicitHeight
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.toggleKeyboard()
|
||||
|
||||
DankIcon {
|
||||
id: icon
|
||||
name: "keyboard"
|
||||
size: Theme.iconSize
|
||||
color: parent.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
verticalBarPill: Component {
|
||||
MouseArea {
|
||||
implicitWidth: iconV.implicitWidth
|
||||
implicitHeight: iconV.implicitHeight
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.toggleKeyboard()
|
||||
|
||||
DankIcon {
|
||||
id: iconV
|
||||
name: "keyboard"
|
||||
size: Theme.iconSize
|
||||
color: parent.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
|
||||
PluginSettings {
|
||||
id: root
|
||||
pluginId: "wvkbdToggle"
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Click the keyboard icon in the bar to show or hide the on-screen keyboard (wvkbd)."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "wvkbdToggle",
|
||||
"name": "Virtual Keyboard Toggle",
|
||||
"description": "Bar button to show/hide the wvkbd on-screen keyboard (for touch/tablet)",
|
||||
"version": "1.0.0",
|
||||
"author": "NixOS-V2",
|
||||
"type": "widget",
|
||||
"capabilities": ["dankbar-widget"],
|
||||
"component": "./WvkbdToggle.qml",
|
||||
"settings": "./WvkbdToggleSettings.qml",
|
||||
"icon": "keyboard",
|
||||
"permissions": ["settings_read"]
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Vesktop / Vencord theme — matugen + DMS wallpaper colors.
|
||||
* Derived from pywal-vencord-style mapping (NixOS-New templates/colors-discord.css).
|
||||
*/
|
||||
|
||||
* {
|
||||
/* Surfaces */
|
||||
--background-primary: {{colors.background.default.hex}};
|
||||
--background-secondary: {{colors.surface.default.hex}};
|
||||
--background-tertiary: {{colors.surface_dim.default.hex}};
|
||||
|
||||
--background-primary-alt: {{colors.background.default.hex}};
|
||||
--background-secondary-alt: {{colors.surface.default.hex}};
|
||||
--background-tertiary-alt: {{colors.surface_dim.default.hex}};
|
||||
|
||||
--channeltextarea-background: {{colors.surface.default.hex}};
|
||||
--custom-channel-members-bg: {{colors.surface.default.hex}};
|
||||
|
||||
--profile-gradient-primary-color: {{colors.surface.default.hex}};
|
||||
--profile-gradient-secondary-color: {{colors.surface_variant.default.hex}};
|
||||
|
||||
--__header-bar-background: {{colors.surface.default.hex}} !important;
|
||||
|
||||
--bg-base-tertiary: {{colors.background.default.hex}};
|
||||
|
||||
--card-primary-bg: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--input-background: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--autocomplete-bg: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--background-nested-floating: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--background-floating: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--scrollbar-auto-track: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--scrollbar-thin-track: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
|
||||
--border-subtle: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--background-base-lowest: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
--background-surface-high: color-mix(in srgb, {{colors.surface.default.hex}}, black 20%);
|
||||
|
||||
--button-secondary-background: color-mix(in srgb, {{colors.surface.default.hex}}, black 30%);
|
||||
--background-surface-higher: color-mix(in srgb, {{colors.surface.default.hex}}, black 30%);
|
||||
--background-base-lower: color-mix(in srgb, {{colors.surface.default.hex}}, black 35%);
|
||||
|
||||
--background-message-hover: color-mix(in srgb, {{colors.surface.default.hex}}, black 40%);
|
||||
--button-secondary-background-hover: color-mix(in srgb, {{colors.surface.default.hex}}, black 40%);
|
||||
--background-base-low: color-mix(in srgb, {{colors.surface.default.hex}}, black 40%);
|
||||
--background-surface-highest: color-mix(in srgb, {{colors.surface.default.hex}}, black 40%);
|
||||
--chat-background-default: color-mix(in srgb, {{colors.surface.default.hex}}, black 45%);
|
||||
|
||||
--button-secondary-background-active: color-mix(in srgb, {{colors.surface.default.hex}}, black 60%);
|
||||
|
||||
--primary-630: {{colors.surface_variant.default.hex}};
|
||||
|
||||
/* Muted / secondary chrome */
|
||||
--scrollbar-auto-thumb: {{colors.on_surface_variant.default.hex}};
|
||||
--scrollbar-thin-thumb: {{colors.on_surface_variant.default.hex}};
|
||||
--interactive-muted: {{colors.on_surface_variant.default.hex}};
|
||||
--text-muted: {{colors.on_surface_variant.default.hex}};
|
||||
--background-modifier-hover: color-mix(in srgb, {{colors.on_surface_variant.default.hex}}, black 40%);
|
||||
--background-modifier-active: color-mix(in srgb, {{colors.on_surface_variant.default.hex}}, black 20%);
|
||||
--background-modifier-accent: {{colors.secondary_container.default.hex}};
|
||||
--background-accent: {{colors.secondary.default.hex}};
|
||||
|
||||
--input-border: {{colors.outline.default.hex}};
|
||||
--border-normal: {{colors.outline.default.hex}};
|
||||
--icon-secondary: {{colors.on_surface_variant.default.hex}};
|
||||
--icon-tertiary: {{colors.on_surface_variant.default.hex}};
|
||||
--channel-icon: {{colors.on_surface_variant.default.hex}};
|
||||
--channels-default: {{colors.on_surface_variant.default.hex}};
|
||||
--header-primary: {{colors.on_surface.default.hex}};
|
||||
--__lottieIconColor: {{colors.on_surface_variant.default.hex}};
|
||||
--interactive-normal: {{colors.on_surface_variant.default.hex}};
|
||||
|
||||
/* Selection / highlights */
|
||||
--red-400: {{colors.error.default.hex}};
|
||||
--background-modifier-selected: {{colors.secondary_container.default.hex}};
|
||||
|
||||
--notice-background-positive: color-mix(in srgb, {{colors.tertiary.default.hex}}, black 75%);
|
||||
--notice-text-positive: {{colors.tertiary.default.hex}};
|
||||
|
||||
/* Danger */
|
||||
--status-danger: {{colors.error.default.hex}};
|
||||
--button-outline-danger-border: {{colors.error.default.hex}};
|
||||
--button-outline-danger-text: {{colors.error.default.hex}};
|
||||
--button-danger-background: {{colors.error.default.hex}};
|
||||
|
||||
--yellow-300: {{colors.error.default.hex}};
|
||||
|
||||
/* Brand / accents */
|
||||
--brand-experiment: {{colors.primary.default.hex}};
|
||||
--brand-experiment-360: {{colors.primary.default.hex}};
|
||||
--brand-experiment-500: {{colors.primary.default.hex}};
|
||||
--profile-gradient-button-color: {{colors.primary.default.hex}};
|
||||
|
||||
--green-360: {{colors.primary.default.hex}};
|
||||
|
||||
/* Foreground */
|
||||
--text-normal: {{colors.on_surface.default.hex}};
|
||||
--interactive-active: {{colors.on_surface.default.hex}};
|
||||
}
|
||||
|
||||
/* Status indicators (legacy Discord hex fills) */
|
||||
rect[fill="#d83a41"] {
|
||||
fill: {{colors.error.default.hex}} !important;
|
||||
}
|
||||
|
||||
rect[fill="#cc954c"] {
|
||||
fill: {{colors.secondary.default.hex}} !important;
|
||||
}
|
||||
|
||||
rect[fill="#40a258"] {
|
||||
fill: {{colors.primary.default.hex}} !important;
|
||||
}
|
||||
|
||||
.wrapper_ef3116 {
|
||||
background: {{colors.background.default.hex}} !important;
|
||||
}
|
||||
|
||||
.bar_c38106 {
|
||||
background: {{colors.background.default.hex}} !important;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{ inputs, ... }: {
|
||||
flake.nixosModules.desktopWallpapers =
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.chiasson.desktop.wallpapers;
|
||||
d = config.chiasson.desktop;
|
||||
guiEnabled = d.hyprland.enable || d.niri.enable || d.plasma.enable;
|
||||
|
||||
wallpaperDir = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "nixos-v2-wallpapers";
|
||||
version = "0.1";
|
||||
src = builtins.path {
|
||||
path = cfg.source;
|
||||
name = "wallpapers-src";
|
||||
};
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
installPhase = ''
|
||||
mkdir -p "$out/share/wallpapers"
|
||||
find "$src" -mindepth 1 -maxdepth 1 ! -name .git -exec cp -a {} "$out/share/wallpapers/" \;
|
||||
'';
|
||||
};
|
||||
|
||||
installPath = "${wallpaperDir}/share/wallpapers";
|
||||
in
|
||||
{
|
||||
options.chiasson.desktop.wallpapers = {
|
||||
enable = lib.mkEnableOption ''
|
||||
Copy `source` into the store; sets `NIXOS_V2_WALLPAPERS` and `/etc/wallpapers`.
|
||||
'' // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = inputs.wallpapers;
|
||||
description = ''
|
||||
Directory copied into the store. Default: `inputs.wallpapers`
|
||||
(`git+https://git.chiasson.cloud/Olivier/wallpapers`, pinned in `flake.lock`).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (guiEnabled && cfg.enable) {
|
||||
environment = {
|
||||
variables.NIXOS_V2_WALLPAPERS = installPath;
|
||||
sessionVariables.NIXOS_V2_WALLPAPERS = installPath;
|
||||
etc."wallpapers".source = installPath;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
{ ... }: {
|
||||
flake.nixosModules.desktopWaydroid =
|
||||
{ config, lib, pkgs, ... }:
|
||||
# `virtualisation.waydroid.package` defaults to `waydroid-nftables` when `networking.nftables.enable`
|
||||
# is true — required on recent kernels where legacy `ip_tables` / `waydroid-net.sh` (iptables) fails
|
||||
# with `waydroid session start` (nixpkgs#459520).
|
||||
let
|
||||
cfg = config.chiasson.desktop.waydroid;
|
||||
in
|
||||
{
|
||||
options.chiasson.desktop.waydroid = {
|
||||
enable = lib.mkEnableOption ''
|
||||
Waydroid + synced base props / nav mode. Needs Wayland; desktop hosts only. This module also
|
||||
sets `networking.nftables.enable` (default) so NixOS uses `waydroid-nftables` — needed on newer
|
||||
kernels where `waydroid-net.sh` / iptables fails. For **Google Play** apps (e.g. Hot Wheels
|
||||
Showcase), run `sudo waydroid init -s GAPPS -f` once after the first `nixos-rebuild` (or reset
|
||||
the container if you already initialized without GAPPS); then sign in and install from the Play
|
||||
Store. If `dnsmasq` reports port 53 in use, free that port (Waydroid needs it).
|
||||
'';
|
||||
|
||||
width = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1920;
|
||||
description = "Waydroid rendering width (`persist.waydroid.width`).";
|
||||
};
|
||||
|
||||
height = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1080;
|
||||
description = "Waydroid rendering height (`persist.waydroid.height`).";
|
||||
};
|
||||
|
||||
multiWindows = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable Waydroid multi-window integration.";
|
||||
};
|
||||
|
||||
navigationMode = lib.mkOption {
|
||||
type = lib.types.enum [ "3button" "gestures" ];
|
||||
default = "gestures";
|
||||
description = "Maps to Waydroid `navigation_mode` secure prop (3button=0, gestures=2).";
|
||||
};
|
||||
|
||||
extraBaseProperties = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
description = ''
|
||||
Extra `key = value` pairs written into `/var/lib/waydroid/waydroid_base.prop` on activation
|
||||
(same mechanism as width/height). Use for upstream tweaks — e.g. NVIDIA hosts often need
|
||||
`ro.hardware.gralloc=default` and `ro.hardware.egl=swiftshader`; Linux 5.18+ may need
|
||||
`sys.use_memfd=true` ([NixOS Waydroid wiki](https://wiki.nixos.org/wiki/Waydroid)).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
networking.nftables.enable = lib.mkDefault true;
|
||||
|
||||
virtualisation.waydroid.enable = true;
|
||||
|
||||
system.activationScripts.waydroidProps = {
|
||||
text = ''
|
||||
PROP_FILE="/var/lib/waydroid/waydroid_base.prop"
|
||||
|
||||
if [ ! -f "$PROP_FILE" ]; then
|
||||
echo "waydroid: $PROP_FILE not found yet, skipping prop sync."
|
||||
echo "waydroid: run 'sudo waydroid init' once, then rebuild."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set_prop() {
|
||||
key="$1"
|
||||
value="$2"
|
||||
|
||||
if ${lib.getExe pkgs.gnugrep} -q "^''${key}=" "$PROP_FILE"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^''${key}=.*|''${key}=''${value}|" "$PROP_FILE"
|
||||
else
|
||||
printf "%s=%s\n" "$key" "$value" >> "$PROP_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
set_prop "persist.waydroid.multi_windows" "${if cfg.multiWindows then "true" else "false"}"
|
||||
set_prop "persist.waydroid.width" "${toString cfg.width}"
|
||||
set_prop "persist.waydroid.height" "${toString cfg.height}"
|
||||
${lib.concatStringsSep "\n" (
|
||||
lib.mapAttrsToList (k: v: ''
|
||||
set_prop ${lib.escapeShellArg k} ${lib.escapeShellArg v}'') cfg.extraBaseProperties
|
||||
)}
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.waydroid-navigation-mode = {
|
||||
description = "Set Waydroid Android navigation mode";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "waydroid-container.service" ];
|
||||
wants = [ "waydroid-container.service" ];
|
||||
path = [ config.virtualisation.waydroid.package ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -eu
|
||||
|
||||
nav_mode="${if cfg.navigationMode == "gestures" then "2" else "0"}"
|
||||
|
||||
if ! systemctl -q is-active waydroid-container.service; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 30); do
|
||||
if waydroid shell settings put secure navigation_mode "$nav_mode" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "waydroid: warning: could not set navigation_mode=$nav_mode (container not ready?)" >&2
|
||||
exit 0
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user