Compare commits

...

3 Commits

Author SHA1 Message Date
Olivier e68321ac1e Add Virtual-1 display configuration to DMS settings
- Included a new display entry for "Virtual-1" in the DMS settings.json file, enhancing display management capabilities.
2026-07-13 12:39:05 -03:00
Olivier 5357ba307b Fix dms-plugins
- Transitioned to an auto-derived plugin registry from flake inputs, simplifying the addition of new plugins by requiring edits only in `flake.nix`.
- Implemented a camelCase transformation for plugin IDs to align with upstream conventions, with exceptions for specific plugins.
- Enhanced the `shipPlugin` function to route plugin sources correctly, ensuring compatibility with the DMS structure.
- Added assertions to validate Obsidian vault paths at build time, improving error handling and user guidance.
2026-07-13 12:39:05 -03:00
Olivier 9960e874c4 Refactor DMS IPC bindings for Niri and Hyprland
- Updated `binds.nix` files for both Niri and Hyprland to utilize a centralized `dmsIpcBinds` structure, improving maintainability and consistency across keybindings.
- Introduced `dmsIpcBinds` in `default.nix` for both modules to streamline the command definitions for DMS IPC calls.
- Enhanced `dms` module to define shared IPC commands, ensuring uniform command formatting for different compositors.
2026-07-13 12:39:05 -03:00
7 changed files with 127 additions and 51 deletions
+10 -12
View File
@@ -1,6 +1,6 @@
{ ... }: { { ... }: {
flake.lib.hyprlandBinds = flake.lib.hyprlandBinds =
{ lib, dmsEnabled ? false }: { lib, dmsEnabled ? false, dmsIpcBinds }:
let let
workspaceBinds = workspaceBinds =
(builtins.map (i: "Super, ${toString i}, workspace, ${toString i}") (builtins.genList (n: n + 1) 9)) (builtins.map (i: "Super, ${toString i}, workspace, ${toString i}") (builtins.genList (n: n + 1) 9))
@@ -28,17 +28,15 @@
"Super, Equal, splitratio, 0.1" "Super, Equal, splitratio, 0.1"
"AltSuper, Space, togglefloating" "AltSuper, Space, togglefloating"
"Super, P, pin" "Super, P, pin"
] ] ++ lib.optionals dmsEnabled [
++ lib.optionals dmsEnabled [ "Super, Space, exec, ${dmsIpcBinds.spotlight}"
"Super, Space, exec, dms ipc call spotlight toggle" "Super, I, exec, ${dmsIpcBinds.settingsFocus}"
"Super, I, exec, dms ipc call settings focusOrToggle" "Super, N, exec, ${dmsIpcBinds.notepad}"
"Super, N, exec, dms ipc call notepad toggle" "ShiftSuper, N, exec, ${dmsIpcBinds.notifications}"
"ShiftSuper, N, exec, dms ipc call notifications toggle" "Super, M, exec, ${dmsIpcBinds.processlistFocus}"
"Super, M, exec, dms ipc call processlist focusOrToggle" "Super, L, exec, ${dmsIpcBinds.lock}"
"Super, L, exec, dms ipc call lock lock" "ShiftSuper, V, exec, ${dmsIpcBinds.clipboard}"
"ShiftSuper, V, exec, dms ipc call clipboard toggle" ] ++ [
]
++ [
"Super, Tab, cyclenext" "Super, Tab, cyclenext"
"Super, Tab, bringactivetotop" "Super, Tab, bringactivetotop"
"Super, left, movefocus, l" "Super, left, movefocus, l"
+4 -1
View File
@@ -101,7 +101,10 @@
"sleep 1 && hyprctl reload" "sleep 1 && hyprctl reload"
]; ];
} }
(self.lib.hyprlandBinds { inherit lib dmsEnabled; }) (self.lib.hyprlandBinds {
inherit lib dmsEnabled;
dmsIpcBinds = self.lib.dmsIpcBinds;
})
{ {
decoration = { decoration = {
rounding = 10; rounding = 10;
+11 -11
View File
@@ -1,6 +1,6 @@
{ ... }: { { ... }: {
flake.lib.niriBinds = flake.lib.niriBinds =
{ pkgs, dmsEnabled ? false }: { pkgs, dmsEnabled ? false, dmsIpcBinds }:
let let
lib = pkgs.lib; lib = pkgs.lib;
in in
@@ -12,16 +12,16 @@
"Mod+E"."spawn-sh" = "nemo"; "Mod+E"."spawn-sh" = "nemo";
} }
// lib.optionalAttrs dmsEnabled { // lib.optionalAttrs dmsEnabled {
"Mod+Space"."spawn-sh" = "dms ipc call spotlight toggle"; "Mod+Space"."spawn-sh" = dmsIpcBinds.spotlight;
"Mod+V"."spawn-sh" = "dms ipc call clipboard toggle"; "Mod+V"."spawn-sh" = dmsIpcBinds.clipboard;
"Mod+N"."spawn-sh" = "dms ipc call notepad toggle"; "Mod+N"."spawn-sh" = dmsIpcBinds.notepad;
"Mod+Shift+N"."spawn-sh" = "dms ipc call notifications toggle"; "Mod+Shift+N"."spawn-sh" = dmsIpcBinds.notifications;
"Mod+M"."spawn-sh" = "dms ipc call processlist toggle"; "Mod+M"."spawn-sh" = dmsIpcBinds.processlist;
"Mod+B"."spawn-sh" = ''dms ipc call bar toggle name "Main Bar"; dms ipc call bar toggle name "Bar 2"''; "Mod+B"."spawn-sh" = dmsIpcBinds.barToggle;
"Mod+Shift+B"."spawn-sh" = ''dms ipc call bar toggle name "Bar 2"''; "Mod+Shift+B"."spawn-sh" = dmsIpcBinds.barToggleBar2;
"Mod+A"."spawn-sh" = "dms ipc call ephemera toggle"; "Mod+A"."spawn-sh" = dmsIpcBinds.ephemera;
"Mod+numbersign"."spawn-sh" = "dms ipc call wallpaperCarousel toggle"; "Mod+numbersign"."spawn-sh" = dmsIpcBinds.wallpaperCarousel;
"Mod+L"."spawn-sh" = "dms ipc call lock lock"; "Mod+L"."spawn-sh" = dmsIpcBinds.lock;
} }
// { // {
"Mod+Q"."close-window" = _: { }; "Mod+Q"."close-window" = _: { };
+4 -1
View File
@@ -21,7 +21,10 @@
niriBaseSettings = niriBaseSettings =
pkgs: dmsEnabled: pkgs: dmsEnabled:
self.lib.niriBaseSettings pkgs // { self.lib.niriBaseSettings pkgs // {
binds = self.lib.niriBinds { inherit pkgs dmsEnabled; }; binds = self.lib.niriBinds {
inherit pkgs dmsEnabled;
dmsIpcBinds = self.lib.dmsIpcBinds;
};
}; };
mergeNiriSettings = mergeNiriSettings =
+73 -26
View File
@@ -124,33 +124,66 @@ let
; ;
}; };
thirdPartyPlugins = { # Plugin registry auto-derived from flake inputs matching `dms-plugin-*`.
dankVault = inputs.dms-plugin-dank-vault; # Adding a plugin now requires editing only `flake.nix`. The on-disk
calculator = inputs.dms-plugin-calculator; # plugin id (= path under ~/.config/DankMaterialShell/plugins/) is camelCase
homeAssistantMonitor = inputs.dms-plugin-home-assistant; # per upstream convention; the kebab→camel transform matches it. The
dropdownMenu = inputs.dms-plugin-dropdown-menu; # `idExceptions` map carries the one plugin whose manifest id does not
ocrScanner = inputs.dms-plugin-ocr-scanner; # follow the default rule.
unifiedTaskbar = inputs.dms-plugin-unified-taskbar; pluginInputs = lib.filterAttrs (n: _: lib.hasPrefix "dms-plugin-" n) inputs;
widgetGroup = inputs.dms-plugin-widget-group;
nixPackageRunner = inputs.dms-plugin-nix-package-runner;
ambientSound = inputs.dms-plugin-ambient-sound;
cavaVisualizer = inputs.dms-plugin-cava-visualizer;
emojiLauncher = inputs.dms-plugin-emoji-launcher;
dankDesktopWeather = inputs.dms-plugin-official + "/DankDesktopWeather";
webSearch = inputs.dms-plugin-web-search;
wallpaperCarousel = inputs.dms-plugin-wallpaper-carousel;
ephemera = inputs.dms-plugin-ephemera;
appShortcut = inputs.dms-plugin-app-shortcut;
wvkbdToggle = inputs.dms-plugin-wvkbd-toggle;
rbwLockToggle = inputs.dms-plugin-rbw-lock-toggle;
};
shipPlugin = # `dank-vault` → `dankVault`. `lib.splitString` yields ≥ 1 element so
_id: src: # `head parts` is safe; `map` runs over the tail only (no-op for
{ # single-word names like `calculator`). `builtins.substring 1 (-1) p`
source = src; # returns the rest of `p` from index 1, dropping the first char
onChange = "${dmsRestartOnceScript}"; # (Nix treats a negative `len` as "rest of string from `start`").
toCamel = s:
let parts = lib.splitString "-" s; in
builtins.head parts
+ lib.concatStrings (map (
p: if p == "" then ""
else lib.toUpper (builtins.substring 0 1 p)
+ builtins.substring 1 (-1) p
) (builtins.tail parts));
# The `home-assistant` plugin ships its manifest under id
# `homeAssistantMonitor` (not the default kebab→camel result).
idExceptions = { "home-assistant" = "homeAssistantMonitor"; };
# NB: don't rewrite as `idExceptions.${stripped} or toCamel stripped`.
# Nix grammar: `or` binds tighter than function application, so the
# `toCamel` and its arg parse as separate postfix args to the select.
# When the lookup succeeds the resolved string is then applied as a
# function, producing `attempt to call something which is not a function
# but a string: "homeAssistantMonitor"`. Explicit `if/hasAttr` sidesteps
# the parse entirely.
camelMap = lib.mapAttrs' (n: src:
let stripped = lib.removePrefix "dms-plugin-" n; in
lib.nameValuePair
(if builtins.hasAttr stripped idExceptions
then idExceptions.${stripped}
else toCamel stripped)
src
) pluginInputs;
# The official plugin pack bundles multiple QML apps. Ship only the
# DankDesktopWeather subdir (verified by its manifest) to slim closure
# and avoid overlapping with future dedicated `dms-plugin-*` flakes.
thirdPartyPlugins =
builtins.removeAttrs camelMap [ "official" ] // {
dankDesktopWeather = inputs.dms-plugin-official + "/DankDesktopWeather";
}; };
# DMS reads plugins from ~/.config/DankMaterialShell/plugins/<id>/, so
# we route each plugin source there via HM's `xdg.configFile.target`.
# The attrset name is scoped under `dms-plugin-${id}` (not the bare
# camelCase id) so unrelated HM modules can ship a same-named file
# (e.g. `xdg.configFile.calculator`) without colliding with us.
shipPlugin = id: src: {
source = src;
target = "DankMaterialShell/plugins/${id}";
onChange = "${dmsRestartOnceScript}";
};
in in
{ {
imports = [ imports = [
@@ -160,7 +193,8 @@ in
config = lib.mkIf dmsEnabled (lib.mkMerge [ config = lib.mkIf dmsEnabled (lib.mkMerge [
(lib.mkIf (dmsOs.bundleThirdPartyPlugins or true) { (lib.mkIf (dmsOs.bundleThirdPartyPlugins or true) {
xdg.configFile = lib.mapAttrs (_id: src: shipPlugin _id src) thirdPartyPlugins; xdg.configFile = lib.mapAttrs' (id: src: lib.nameValuePair
"dms-plugin-${id}" (shipPlugin id src)) thirdPartyPlugins;
}) })
{ {
programs.nix-monitor = { programs.nix-monitor = {
@@ -203,10 +237,23 @@ in
enableDynamicTheming = true; enableDynamicTheming = true;
enableAudioWavelength = true; enableAudioWavelength = true;
enableCalendarEvents = false; enableCalendarEvents = false;
# Empty on purpose: DMS owns ~/.config/DankMaterialShell/{settings,session}.json
# at runtime (seeded by `home.activation.dmsSeedConfig`). Setting these
# to non-empty here would clobber the runtime seed on every activation.
settings = { }; settings = { };
session = { }; session = { };
}; };
# Surface bad obsidianVaults paths at build time instead of at first matugen run.
# Each entry must point at the `<vault>/.obsidian` dir (matugen writes
# `<vault>/.obsidian/snippets/matugen.css` from there).
assertions = lib.mkIf ((dmsOs.obsidianVaults or [ ]) != [ ]) [
{
assertion = builtins.all (v: lib.hasSuffix "/.obsidian" v) (dmsOs.obsidianVaults or [ ]);
message = "chiasson.desktop.shells.dms.obsidianVaults entries must end in '/.obsidian' (matugen writes <vault>/.obsidian/snippets/matugen.css). Example: /home/olivier/Documents/HomeLab/.obsidian";
}
];
home.activation.dmsSeedConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] "${dmsSeedConfigScript}"; home.activation.dmsSeedConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] "${dmsSeedConfigScript}";
systemd.user.services.dms.serviceConfig.ExecStartPre = systemd.user.services.dms.serviceConfig.ExecStartPre =
+21
View File
@@ -46,4 +46,25 @@
}; };
flake.homeManagerModules.desktopShellDms = import ./_private/hm.nix; flake.homeManagerModules.desktopShellDms = import ./_private/hm.nix;
# DMS IPC commands shared between Niri and Hyprland keybind tables.
# Defines flake.lib.dmsIpcBinds so each compositor formats the same
# command string in its native shape — Niri attrs vs Hyprland string-list.
# Adding a new DMS keybind requires editing this file plus the
# per-compositor bind layout, not the command string.
flake.lib.dmsIpcBinds = {
spotlight = "dms ipc call spotlight toggle";
clipboard = "dms ipc call clipboard toggle";
notepad = "dms ipc call notepad toggle";
notifications = "dms ipc call notifications toggle";
processlist = "dms ipc call processlist toggle";
# Hyprland prefers focusOrToggle (window-aware); niri subscribes to toggle.
processlistFocus = "dms ipc call processlist focusOrToggle";
settingsFocus = "dms ipc call settings focusOrToggle";
barToggle = ''dms ipc call bar toggle name "Main Bar"; dms ipc call bar toggle name "Bar 2"'';
barToggleBar2 = ''dms ipc call bar toggle name "Bar 2"'';
ephemera = "dms ipc call ephemera toggle";
wallpaperCarousel = "dms ipc call wallpaperCarousel toggle";
lock = "dms ipc call lock lock";
};
} }
@@ -486,6 +486,10 @@
{ {
"name": "DP-3", "name": "DP-3",
"model": "34GL750" "model": "34GL750"
},
{
"name": "Virtual-1",
"model": "Virtual-1"
} }
], ],
"showOnLastDisplay": false, "showOnLastDisplay": false,