mirror of
https://github.com/nix-community/home-manager
synced 2024-11-30 15:09:46 +01:00
bspwm: various improvements (#2095)
* bspwm: various improvements - fixes shell escaping issues and general style issues - allow reloading the config on-the-fly by exposing bspwmrc to the user * bspwm: add configuration test
This commit is contained in:
parent
2f6d5c90f4
commit
e70524cd2b
7 changed files with 126 additions and 59 deletions
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
@ -293,6 +293,9 @@
|
||||||
|
|
||||||
/modules/services/unison.nix @pacien
|
/modules/services/unison.nix @pacien
|
||||||
|
|
||||||
|
/modules/services/window-managers/bspwm @ncfavier
|
||||||
|
/tests/modules/services/window-managers/bspwm @ncfavier
|
||||||
|
|
||||||
/modules/services/window-managers/i3-sway/i3.nix @sumnerevans
|
/modules/services/window-managers/i3-sway/i3.nix @sumnerevans
|
||||||
/tests/modules/services/window-managers/i3 @sumnerevans
|
/tests/modules/services/window-managers/i3 @sumnerevans
|
||||||
|
|
||||||
|
|
|
@ -5,70 +5,72 @@ with lib;
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.xsession.windowManager.bspwm;
|
cfg = config.xsession.windowManager.bspwm;
|
||||||
bspwm = cfg.package;
|
|
||||||
|
|
||||||
camelToSnake = s:
|
camelToSnake =
|
||||||
builtins.replaceStrings lib.upperChars (map (c: "_${c}") lib.lowerChars) s;
|
builtins.replaceStrings upperChars (map (c: "_${c}") lowerChars);
|
||||||
|
|
||||||
formatConfig = n: v:
|
formatMonitor = monitor: desktops:
|
||||||
|
"bspc monitor ${strings.escapeShellArg monitor} -d ${
|
||||||
|
strings.escapeShellArgs desktops
|
||||||
|
}";
|
||||||
|
|
||||||
|
formatSetting = n: v:
|
||||||
let
|
let
|
||||||
formatList = x:
|
vStr = if isBool v then
|
||||||
if isList x then
|
boolToString v
|
||||||
throw "can not convert 2-dimensional lists to bspwm format"
|
else if isInt v || isFloat v then
|
||||||
else
|
toString v
|
||||||
formatValue x;
|
|
||||||
|
|
||||||
formatValue = v:
|
|
||||||
if isBool v then
|
|
||||||
(if v then "true" else "false")
|
|
||||||
else if isList v then
|
|
||||||
concatMapStringsSep ", " formatList v
|
|
||||||
else if isString v then
|
else if isString v then
|
||||||
"${lib.strings.escapeShellArg v}"
|
strings.escapeShellArg v
|
||||||
else
|
else
|
||||||
toString v;
|
throw "unsupported setting type for ${n}";
|
||||||
in "bspc config ${n} ${formatValue v}";
|
in "bspc config ${strings.escapeShellArg n} ${vStr}";
|
||||||
|
|
||||||
formatMonitors = n: v: "bspc monitor ${n} -d ${concatStringsSep " " v}";
|
formatRule = target: directives:
|
||||||
|
|
||||||
formatRules = target: directiveOptions:
|
|
||||||
let
|
let
|
||||||
formatDirective = n: v:
|
formatDirective = n: v:
|
||||||
if isBool v then
|
let
|
||||||
(if v then "${camelToSnake n}=on" else "${camelToSnake n}=off")
|
vStr = if isBool v then
|
||||||
else if (n == "desktop" || n == "node") then
|
if v then "on" else "off"
|
||||||
"${camelToSnake n}='${v}'"
|
else if isInt v || isFloat v then
|
||||||
|
toString v
|
||||||
|
else if isString v then
|
||||||
|
v
|
||||||
else
|
else
|
||||||
"${camelToSnake n}=${lib.strings.escapeShellArg v}";
|
throw "unsupported rule attribute type for ${n}";
|
||||||
|
in "${camelToSnake n}=${vStr}";
|
||||||
|
|
||||||
directives =
|
directivesStr = strings.escapeShellArgs (mapAttrsToList formatDirective
|
||||||
filterAttrs (n: v: v != null && !(lib.strings.hasPrefix "_" n))
|
(filterAttrs (n: v: v != null) directives));
|
||||||
directiveOptions;
|
in "bspc rule -a ${strings.escapeShellArg target} ${directivesStr}";
|
||||||
directivesStr = builtins.concatStringsSep " "
|
|
||||||
(mapAttrsToList formatDirective directives);
|
|
||||||
in "bspc rule -a ${target} ${directivesStr}";
|
|
||||||
|
|
||||||
formatStartupPrograms = map (s: "${s} &");
|
formatStartupProgram = s: "${s} &";
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options = import ./options.nix {
|
meta.maintainers = [ maintainers.ncfavier ];
|
||||||
inherit pkgs;
|
|
||||||
inherit lib;
|
options = import ./options.nix { inherit pkgs lib; };
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = [ bspwm ];
|
home.packages = [ cfg.package ];
|
||||||
xsession.windowManager.command = let
|
|
||||||
configFile = pkgs.writeShellScript "bspwmrc" (concatStringsSep "\n"
|
xdg.configFile."bspwm/bspwmrc".source = pkgs.writeShellScript "bspwmrc" ''
|
||||||
((mapAttrsToList formatMonitors cfg.monitors)
|
${concatStringsSep "\n" (mapAttrsToList formatMonitor cfg.monitors)}
|
||||||
++ (mapAttrsToList formatConfig cfg.settings)
|
|
||||||
++ (mapAttrsToList formatRules cfg.rules) ++ [''
|
${concatStringsSep "\n" (mapAttrsToList formatSetting cfg.settings)}
|
||||||
|
|
||||||
|
bspc rule -r '*'
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList formatRule cfg.rules)}
|
||||||
|
|
||||||
# java gui fixes
|
# java gui fixes
|
||||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
bspc rule -a sun-awt-X11-XDialogPeer state=floating
|
bspc rule -a sun-awt-X11-XDialogPeer state=floating
|
||||||
''] ++ [ cfg.extraConfig ]
|
|
||||||
++ (formatStartupPrograms cfg.startupPrograms)));
|
${cfg.extraConfig}
|
||||||
configCmdOpt = optionalString (cfg.settings != null) "-c ${configFile}";
|
${concatMapStringsSep "\n" formatStartupProgram cfg.startupPrograms}
|
||||||
in "${cfg.package}/bin/bspwm ${configCmdOpt}";
|
'';
|
||||||
|
|
||||||
|
xsession.windowManager.command =
|
||||||
|
"${cfg.package}/bin/bspwm -c ${config.xdg.configHome}/bspwm/bspwmrc";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,16 +150,16 @@ in {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.bspwm;
|
default = pkgs.bspwm;
|
||||||
defaultText = literalExample "pkgs.bspwm";
|
defaultText = literalExample "pkgs.bspwm";
|
||||||
description = "bspwm package to use.";
|
description = "The bspwm package to use.";
|
||||||
example = literalExample "pkgs.bspwm-unstable";
|
example = literalExample "pkgs.bspwm-unstable";
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = with types;
|
type = with types;
|
||||||
let primitive = either bool (either int (either float str));
|
let primitive = either bool (either int (either float str));
|
||||||
in attrsOf (either primitive (listOf primitive));
|
in attrsOf primitive;
|
||||||
default = { };
|
default = { };
|
||||||
description = "bspwm configuration";
|
description = "General settings given to <literal>bspc config</literal>.";
|
||||||
example = {
|
example = {
|
||||||
"border_width" = 2;
|
"border_width" = 2;
|
||||||
"split_ratio" = 0.52;
|
"split_ratio" = 0.52;
|
||||||
|
@ -170,7 +170,8 @@ in {
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
description = "Additional configuration to add.";
|
description =
|
||||||
|
"Additional shell commands to be run at the end of the config file.";
|
||||||
example = ''
|
example = ''
|
||||||
bspc subscribe all > ~/bspc-report.log &
|
bspc subscribe all > ~/bspc-report.log &
|
||||||
'';
|
'';
|
||||||
|
@ -179,14 +180,16 @@ in {
|
||||||
monitors = mkOption {
|
monitors = mkOption {
|
||||||
type = types.attrsOf (types.listOf types.str);
|
type = types.attrsOf (types.listOf types.str);
|
||||||
default = { };
|
default = { };
|
||||||
description = "bspc monitor configurations";
|
description =
|
||||||
|
"Specifies the names of desktops to create on each monitor.";
|
||||||
example = { "HDMI-0" = [ "web" "terminal" "III" "IV" ]; };
|
example = { "HDMI-0" = [ "web" "terminal" "III" "IV" ]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
rules = mkOption {
|
rules = mkOption {
|
||||||
type = types.attrsOf rule;
|
type = types.attrsOf rule;
|
||||||
default = { };
|
default = { };
|
||||||
description = "bspc rules";
|
description =
|
||||||
|
"Rule configuration. The keys of the attribute set are the targets of the rules.";
|
||||||
example = literalExample ''
|
example = literalExample ''
|
||||||
{
|
{
|
||||||
"Gimp" = {
|
"Gimp" = {
|
||||||
|
|
|
@ -123,6 +123,7 @@ import nmt {
|
||||||
./modules/services/redshift-gammastep
|
./modules/services/redshift-gammastep
|
||||||
./modules/services/sxhkd
|
./modules/services/sxhkd
|
||||||
./modules/services/syncthing
|
./modules/services/syncthing
|
||||||
|
./modules/services/window-managers/bspwm
|
||||||
./modules/services/window-managers/i3
|
./modules/services/window-managers/i3
|
||||||
./modules/services/window-managers/sway
|
./modules/services/window-managers/sway
|
||||||
./modules/services/wlsunset
|
./modules/services/wlsunset
|
||||||
|
|
18
tests/modules/services/window-managers/bspwm/bspwmrc
Executable file
18
tests/modules/services/window-managers/bspwm/bspwmrc
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
bspc monitor 'focused' -d 'desktop 1' 'd'\''esk top'
|
||||||
|
|
||||||
|
bspc config 'border_width' 2
|
||||||
|
bspc config 'external_rules_command' '/path/to/external rules command'
|
||||||
|
bspc config 'gapless_monocle' true
|
||||||
|
bspc config 'split_ratio' 0.520000
|
||||||
|
|
||||||
|
bspc rule -r '*'
|
||||||
|
bspc rule -a '*' 'center=off' 'desktop=d'\''esk top#next' 'split_dir=north' 'sticky=on'
|
||||||
|
|
||||||
|
# java gui fixes
|
||||||
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
|
bspc rule -a sun-awt-X11-XDialogPeer state=floating
|
||||||
|
|
||||||
|
extra config
|
||||||
|
|
||||||
|
foo &
|
||||||
|
bar || qux &
|
|
@ -0,0 +1,39 @@
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
xsession.windowManager.bspwm = {
|
||||||
|
enable = true;
|
||||||
|
monitors.focused =
|
||||||
|
[ "desktop 1" "d'esk top" ]; # pathological desktop names
|
||||||
|
settings = {
|
||||||
|
border_width = 2;
|
||||||
|
split_ratio = 0.52;
|
||||||
|
gapless_monocle = true;
|
||||||
|
external_rules_command = "/path/to/external rules command";
|
||||||
|
};
|
||||||
|
rules."*" = {
|
||||||
|
sticky = true;
|
||||||
|
center = false;
|
||||||
|
desktop = "d'esk top#next";
|
||||||
|
splitDir = "north";
|
||||||
|
border = null;
|
||||||
|
};
|
||||||
|
extraConfig = ''
|
||||||
|
extra config
|
||||||
|
'';
|
||||||
|
startupPrograms = [ "foo" "bar || qux" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
bspwmrc=home-files/.config/bspwm/bspwmrc
|
||||||
|
assertFileExists "$bspwmrc"
|
||||||
|
assertFileIsExecutable "$bspwmrc"
|
||||||
|
assertFileContent "$bspwmrc" ${
|
||||||
|
pkgs.writeShellScript "bspwmrc-expected" (readFile ./bspwmrc)
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
1
tests/modules/services/window-managers/bspwm/default.nix
Normal file
1
tests/modules/services/window-managers/bspwm/default.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{ bspwm-configuration = ./configuration.nix; }
|
Loading…
Reference in a new issue