Skip to content

nixos/dwm: init module#470575

Open
20Finger-Squared wants to merge 2 commits into
NixOS:masterfrom
20Finger-Squared:master
Open

nixos/dwm: init module#470575
20Finger-Squared wants to merge 2 commits into
NixOS:masterfrom
20Finger-Squared:master

Conversation

@20Finger-Squared

@20Finger-Squared 20Finger-Squared commented Dec 14, 2025

Copy link
Copy Markdown

Things done

  • Built on platform:
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • Tested, as applicable:
  • Ran nixpkgs-review on this PR. See nixpkgs-review usage.
  • Tested basic functionality of all binary files, usually in ./result/bin/.
  • Nixpkgs Release Notes
    • Package update: when the change is major or breaking.
  • NixOS Release Notes
    • Module addition: when adding a new NixOS module.
    • Module update: when the change is significant.
  • Fits CONTRIBUTING.md, pkgs/README.md, maintainers/README.md and other READMEs.

Add a 👍 reaction to pull requests you find important.

@nixpkgs-ci nixpkgs-ci Bot added 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 12.first-time contribution This PR is the author's first one; please be gentle! 9.needs: reviewer This PR currently has no reviewers requested and needs attention. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Dec 14, 2025
@cybardev

Copy link
Copy Markdown
Contributor

nixpkgs-review result

Generated using nixpkgs-review-gha

Command: nixpkgs-review pr 470575
Commit: e55ffcd1af173a50b9868bd56a3e6525323c34a3 (subsequent changes)
Merge: a6d7a9f8395851c0d2c23dee0f44d4a73c27719e

Logs: https://github.com/cybardev/nixpkgs-review-action/actions/runs/20200594598


x86_64-linux

⏩ 2 packages blacklisted:
  • nixos-install-tools
  • tests.nixos-functions.nixos-test

aarch64-linux

⏩ 2 packages blacklisted:
  • nixos-install-tools
  • tests.nixos-functions.nixos-test

@yzx9

yzx9 commented Dec 14, 2025

Copy link
Copy Markdown
Contributor

please format your PR title and commit message to meet the commit conventions, e.g.: nixos/dwm: add more module

@20Finger-Squared 20Finger-Squared changed the title Create missing dwm module init DWM: init 6.5 Dec 14, 2025
@20Finger-Squared 20Finger-Squared changed the title init DWM: init 6.5 DWM: init 6.5 Dec 14, 2025
@20Finger-Squared 20Finger-Squared changed the title DWM: init 6.5 DWM: init at 6.5 Dec 14, 2025
@mdaniels5757 mdaniels5757 changed the title DWM: init at 6.5 nixos/dwm: init at 6.5 Dec 14, 2025
@mdaniels5757 mdaniels5757 changed the title nixos/dwm: init at 6.5 nixos/dwm: init module Dec 14, 2025

@maevii maevii left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very non-exhaustive first pass, this is a lot to review...

You should also add yourself into the meta.maintainers of the module, I'm not sure this would get maintained particularly well otherwise. The dwm package itself also currently has no maintainers, so you could consider becoming one as well.

Comment thread nixos/modules/programs/dwm/module.nix Outdated
pkgs,
...
}:
with lib;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with lib;

This shouldn't be used (esp. in new modules), see #208242

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be a inherit (lib) ...; instead or just use full names such as lib.mkOption?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either one is fine, I personally prefer specifying full names in my modules but it's up so you.

Comment thread nixos/modules/programs/dwm/module.nix Outdated
options = {
flag = mkOption {
type = types.str;
description = "The flag or argument name";

@maevii maevii Jan 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description = "The flag or argument name";
description = "The flag or argument name.";

Nitpick, but unlike meta.description these should be full sentences. Same with all the other descriptions.

Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment on lines +33 to +44
dwm = pkgs.dwm.overrideAttrs (oldAttrs: {
# if package source defined use it else use normal source
src = if cfg.package.src != null then cfg.package.src else oldAttrs.src;
/*
if you wish to add your own patch to the module then use the following format to do so.
make sure to remove anything editing the `config.def.h` to ensure that no errors occur
++ (if <enable-patch> then [ <patch-dir> ] else [])
*/
patches =
(oldAttrs.patches or [ ])
++ cfg.package.patches
++ (if cfg.patches.gaps.enable then [ ./gaps.diff ] else [ ]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never seen something like this in a module (and a quick search doesn't bring up anything), I'm not sure this should be included.

A package = lib.mkPackageOption ... option that would then be overridden with the postPatch would probably be much better (and much more maintainable, just the gaps patch is pretty big and could break with updates).

@20Finger-Squared 20Finger-Squared Jan 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to do that and turn it into an overlay due to the fact if a person references the package it wouldn't use this one and instead use the default dwm package?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things like this are usually done by adding a readonly finalPackage option, see e.g. the postgresql module:

finalPackage = mkOption {
type = types.package;
readOnly = true;
default =
let
# ensure that
# services.postgresql = {
# enableJIT = true;
# package = pkgs.postgresql_<major>;
# };
# works.
withJit = if cfg.enableJIT then cfg.package.withJIT else cfg.package.withoutJIT;
withJitAndPackages = if cfg.extensions == [ ] then withJit else withJit.withPackages cfg.extensions;
in
withJitAndPackages;
defaultText = "with config.services.postgresql; package.withPackages extensions";
description = ''
The postgresql package that will effectively be used in the system.
It consists of the base package with plugins applied to it.
'';
};

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so that the orignal pkgs are left to be, and the user can use config.programs.dwm.finalPackage instead. Correct how I think it works is wrong

Comment thread nixos/modules/programs/dwm/module.nix Outdated
type = types.int;
default = 10;
example = 12;
description = ''The font size'';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description = ''The font size'';
description = "The font size.";

Another nitpick, using '' on a single line looks weird. Same with the file/package descriptions and a few other things.

Comment thread nixos/modules/programs/dwm/module.nix Outdated
};
appCmd = mkOption {
type = types.str;
default = "dmenu_run";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually installed anywhere in the module? It might be better to omit the default so users set it manually.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dmenu requires a flag inside it's args to know which monitor is open. The reason I made it an option is because inside dwm there is a variable that is for dmenu to know which monitor to spawn on.
Also I noticed that other wm included opts like these and I thought it'd be best to make sure that there is a applaucher as an option to make sure the user defines one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with dwm, is dmenu_run included in its package? That's what I was getting at, if it isn't then I don't think it should be made a default like this.

@20Finger-Squared 20Finger-Squared Jan 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dmenu_run is included as dmenu_run uses the path to find all binaries and runs the one you chose dmenu takes inputs and lets you chose which input to chose typically used for shell script.
Sorry reread your message no dwm doesn't include dmenu but it does have it as the default and as I am trying to keep all dwm defaults as the defaults inside the module.
However st and dmenu are a part of the suckless software which is why I chose to keep it, but yes with you saying this i will turn it into an example instead of a default.

Comment thread nixos/modules/programs/dwm/module.nix Outdated

appCmd = mkOption {
type = types.str;
default = "st";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, doesn't this need to be installed separately?

Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment thread nixos/modules/programs/dwm/module.nix Outdated
argument = ''"#eeeeee"'';
}
];
example = ''

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
example = ''
example = lib.literalExpression ''

Same with all the others.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would you like me to commit these changes?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the nixpkgs commit conventions:
https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#commit-conventions
https://github.com/NixOS/nixpkgs/blob/master/nixos/README.md#commit-conventions

But TLDR, git commit --amend and git push --force usually works.

@nixpkgs-ci nixpkgs-ci Bot removed the 9.needs: reviewer This PR currently has no reviewers requested and needs attention. label Jan 18, 2026
@20Finger-Squared

20Finger-Squared commented Jan 18, 2026 via email

Copy link
Copy Markdown
Author

@nixpkgs-ci nixpkgs-ci Bot added the 8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` label Jan 19, 2026

@maevii maevii left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still non-exhaustive second pass, you can/should also resolve review comments to keep track of them better (non-committer reviewers like me can't).

The actual module commit should also be named nixos/dwm: ... , see conventions

Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment thread maintainers/maintainer-list.nix
Comment thread nixos/modules/services/x11/window-managers/dwm/module.nix Outdated
Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment on lines +604 to +607
windowManager.dwm = {
enable = true;
package = dwm;
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize this was a thing, the functionality from this module should probably be integrated into that one rather than being separate like this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry not sure what you mean with "the module should be integrated into that one rather than being seperate like this"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Means instead of having a programs.dwm and windowManager.dwm, we should implement the features of this PR into the existing windowManager.dwm module to avoid duplication, confusion, fragmentation, and other potential issues.

Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment thread nixos/modules/services/x11/window-managers/dwm/module.nix Outdated
Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment thread nixos/modules/programs/dwm/module.nix Outdated
Comment on lines +141 to +225
/* c */ ''
${cfg.file.prepend}
#define MODKEY ${cfg.modifier}
#define TAGKEYS(KEY, TAG) \
{${cfg.tagKeys.modifiers.viewOnlyThisTag}, KEY, view, {.ui = 1 << TAG} }, \
{${cfg.tagKeys.modifiers.toggleThisTagInView}, KEY, toggleview, {.ui = 1 << TAG} }, \
{${cfg.tagKeys.modifiers.moveWindowToThisTag}, KEY, tag, {.ui = 1 << TAG} }, \
{${cfg.tagKeys.modifiers.toggleWindowOnThisTag}, KEY, toggletag, {.ui = 1 << TAG} },
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
static const unsigned int borderpx = ${toString cfg.borderpx};
${lib.optional (cfg.patches.gaps.enable) ''static const unsigned int gappx = ${toString cfg.patches.gaps.width};''}
static const unsigned int snap = ${toString cfg.snap};
static const int showbar = ${boolToInt cfg.showBar};
static const int topbar = ${boolToInt cfg.topBar};
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *fonts[] = { "${cfg.font.name}:size=${toString cfg.font.size}" };

/* layout(s) */
static const float mfact = ${toString cfg.layout.mfact}; /* factor of master area size [0.05..0.95] */
static const int nmaster = ${toString cfg.layout.nmaster}; /* number of clients in master area */
static const int resizehints = ${toString cfg.layout.resizehints}; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = ${toString cfg.layout.lockfullscreen}; /* 1 will force focus on the fullscreen window */

static const char *colors[][3] = { ${
concatMapStringsSep ",\n" (name: pair: ''
[ ${name} ] = { "${pair.value.fg}", "${pair.value.bg}", "${pair.value.border}" }
'') (cfg.colors)
} };

static const char *dmenucmd[] = { "${cfg.appLauncher.appCmd}",
${lib.optionals (cfg.appLauncher.appArgs != [ ]) concatMapStringsSep " " (
arg: ''"${toString arg.flag}", ${toString arg.argument},''
) cfg.appLauncher.appArgs}
NULL };
static const char *termcmd[] = { "${cfg.terminal.appCmd}",
${lib.optionals (cfg.terminal.appArgs != [ ]) concatMapStringsSep " " (
arg: ''"${toString arg.flag}", ${toString arg.argument},''
) cfg.terminal.appArgs}
NULL };

static const char *tags[] = { ${concatMapStringsSep ", " (tag: ''"${toString tag}"'') cfg.tags} };

static const Layout layouts[] = {
${concatMapStringsSep ",\n " (
layout: ''{"${layout.symbol}", ${layout.arrangeFunction}}''
) cfg.layout.layouts}
};

static const Rule rules[] = {
${concatMapStringsSep ",\n " (rule: ''
{
"${rule.class}", ${rule.instance}, ${rule.title}, ${toString rule.tagsMask}, ${boolToInt rule.isFloating}, ${toString rule.monitor}
}
'') cfg.rules}
};

static const Key keys[] = {
{${cfg.terminal.modifier}, ${cfg.terminal.launchKey}, spawn, {.v=termcmd}},
{${cfg.appLauncher.modifier}, ${cfg.appLauncher.launchKey}, spawn, {.v=dmenucmd}},

${
# create default key bindings before user defined bindings
concatMapStringsSep ",\n " (
key: ''{${toString key.modifier}, ${key.key}, ${key.function}, ${key.argument} }''
) (if cfg.key.useDefault then defaultKeys ++ cfg.key.keys else cfg.key.keys)
},

${
# create tage keys bindings
concatMapStringsSep "\n " (
tag: ''TAGKEYS(${tag.key}, ${toString tag.tag})''
) cfg.tagKeys.definitions
}
};

static const Button buttons[] = {
${
concatMapStringsSep ",\n " (
button: ''{${button.click},${button.mask},${button.button},${button.function},${button.argument}}''
) cfg.buttons
},
};

${cfg.file.append}
''

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the sake of maintainability, the layout of this should probably be based on the upstream example

Comment thread nixos/modules/programs/dwm/module.nix Outdated
(oldAttrs.patches or [ ])
++ cfg.package.patches
++ (lib.optionals (cfg.patches.gaps.enable) [ ./gaps.diff ]);
postPatch = "cp ${file} config.h; cp ${file} config.def.h";

@maevii maevii Jan 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
postPatch = "cp ${file} config.h; cp ${file} config.def.h";
postPatch = "cp ${file} config.h";

In addition to the thing from the first review pass, isn't config.def.h just a fallback for if config.h doesn't exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I was creating this module i had the issue where it wouldn't use the config.h config but i'll see if it's user error

@20Finger-Squared 20Finger-Squared force-pushed the master branch 3 times, most recently from 1a34d4a to 79db688 Compare January 23, 2026 00:48
@20Finger-Squared

20Finger-Squared commented Jan 23, 2026

Copy link
Copy Markdown
Author

Had to remove the patch and options that came with the module due to the gh bot failing it because treefmt doesn't format .diff

@MattSturgeon

Copy link
Copy Markdown
Contributor

Had to remove the patch and optoins that came with the module due to the gh bot failing it because treefmt doesn't format .diff

Be aware that the formatter was recently updated on master. To get the same formatter locally, you'll need to fetch & rebase.

Once you have the up-to-date formatter, nix-shell --run treefmt should match the formatting used in CI.

@20Finger-Squared 20Finger-Squared force-pushed the master branch 2 times, most recently from c2b720e to 79db688 Compare January 23, 2026 02:47
@20Finger-Squared 20Finger-Squared force-pushed the master branch 2 times, most recently from 2a06c7d to 6737a05 Compare January 23, 2026 03:35
@20Finger-Squared 20Finger-Squared force-pushed the master branch 2 times, most recently from 2951c81 to 4558542 Compare January 24, 2026 13:42
@20Finger-Squared 20Finger-Squared force-pushed the master branch 3 times, most recently from 800f69e to ddc4d9e Compare February 13, 2026 10:27
Comment thread nixos/modules/services/x11/window-managers/dwm/module.nix Outdated
tagsMask = 0;
isFloating = true;
monitor = -1;
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type is listOf (submodule ...), this example is incorrect. I'd probably just delete this and make the default an example

useDefault = mkOption {
type = types.bool;
default = true;
example = lib.literalExpresion false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
example = lib.literalExpresion false;
example = false;

Same as in the previous review, literalExpression is only for strings when you want special formatting/comments in the example. This also still isn't the only place where it's still used incorrectly

@20Finger-Squared

20Finger-Squared commented Mar 3, 2026

Copy link
Copy Markdown
Author

Ok after talking with others about this module, people have sugested another way which seems more common within nix. Which is to include the option of a config file instead.
This would mean it would be simple to maintain.

I have no idea on whether I should continue using the current method, or use a "customRC" config option?
For the time being I have made both an option.

Updating 5 files

Co-authored-by: Maevi <me@maevi.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 12.first-time contribution This PR is the author's first one; please be gentle!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants