From 1018cd7cc704f08e3329cb758a73e6da98d4e087 Mon Sep 17 00:00:00 2001 From: aszlig Date: Mon, 14 Jul 2014 22:47:14 +0200 Subject: i3: Add NixOS options to configure workspaces. This allows for a more dynamic workspace assignments, especially when varying between the number of heads. We now not only can use the NixOS module system to set workspaces but also assign applications to them. And the default workspace layout is to evenly spread out the heads among the available heads. Signed-off-by: aszlig --- modules/i3/default.nix | 69 ++++++++++++++++++++++-------- modules/i3/i3.conf | 43 +------------------ modules/i3/workspace.nix | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 58 deletions(-) create mode 100644 modules/i3/workspace.nix (limited to 'modules/i3') diff --git a/modules/i3/default.nix b/modules/i3/default.nix index 86ba462c..2c668cc4 100644 --- a/modules/i3/default.nix +++ b/modules/i3/default.nix @@ -1,9 +1,56 @@ -{ pkgs, config, ... }: +{ pkgs, lib, config, ... }: -with pkgs.lib; +with lib; +let + # The symbols if you press shift and a number key. + wsNumberSymbols = [ + "exclam" "at" "numbersign" "dollar" "percent" + "asciicircum" "ampersand" "asterisk" "parenleft" "parenright" + ]; + + wsCount = length wsNumberSymbols; + + headCount = length config.services.xserver.xrandrHeads; + wsPerHead = wsCount / headCount; + excessWs = wsCount - (headCount * wsPerHead); + getHeadAt = elemAt config.services.xserver.xrandrHeads; + + mkDefaultWorkspace = number: numberSymbol: { + name = toString number; + value = mkDefault { + label = null; + labelPrefix = "${toString number}: "; + keys.switchTo = "$mod+${toString number}"; + keys.moveTo = "$mod+Shift+${numberSymbol}"; + head = getHeadAt ((number - (excessWs + 1)) / wsPerHead); + }; + }; + + wsCfgList = mapAttrsToList (_: getAttr "config") config.aszlig.i3.workspaces; + wsConfig = concatStrings wsCfgList; + defaultWorkspaces = listToAttrs (imap mkDefaultWorkspace wsNumberSymbols); +in { - services.xserver.windowManager = { + options.aszlig.i3 = { + workspaces = mkOption { + type = types.attrsOf (types.submodule ./workspace.nix); + default = listToAttrs (imap mkDefaultWorkspace wsNumberSymbols); + description = '' + Workspace to monitor assignment. + + Workspaces are by default assigned starting from the leftmost monitor + being workspace 1 and the rightmost monitor being workspace 10. The + workspaces are divided by the number of available heads, so if you have + a dual head system, you'll end up having workspace 1 to 5 on the left + monitor and 6 to 10 on the right. + ''; + }; + }; + + config.aszlig.i3.workspaces = defaultWorkspaces; + + config.services.xserver.windowManager = { default = "i3"; i3.enable = true; @@ -17,6 +64,7 @@ with pkgs.lib; inherit (pkgs) dmenu xterm pvolctrl; inherit (pkgs.xorg) xsetroot; + inherit wsConfig; leftHead = head config.services.xserver.xrandrHeads; rightHead = last config.services.xserver.xrandrHeads; @@ -30,19 +78,6 @@ with pkgs.lib; in if config.networking.hostName == "mmrnmhrm" then { inherit leftHead rightHead; } else { leftHead = rightHead; rightHead = leftHead; } - ) // (let - wsConfig = if config.networking.hostName == "mmrnmhrm" - then [ "XMPP" null "chromium" null null - null null null null null ] - else [ null null null null null - "chromium" null null null null ]; - - mkWsName = num: name: let - mkPair = nameValuePair "ws${toString num}"; - in if name == null - then mkPair (toString num) - else mkPair "${toString num}: ${name}"; - - in listToAttrs (imap mkWsName wsConfig))); + )); }; } diff --git a/modules/i3/i3.conf b/modules/i3/i3.conf index d6273489..b6780f98 100644 --- a/modules/i3/i3.conf +++ b/modules/i3/i3.conf @@ -74,30 +74,6 @@ bindsym $mod+a focus parent # focus the child container bindsym $mod+semicolon focus child -# switch to workspace -bindsym $mod+1 workspace "@ws1@" -bindsym $mod+2 workspace "@ws2@" -bindsym $mod+3 workspace "@ws3@" -bindsym $mod+4 workspace "@ws4@" -bindsym $mod+5 workspace "@ws5@" -bindsym $mod+6 workspace "@ws6@" -bindsym $mod+7 workspace "@ws7@" -bindsym $mod+8 workspace "@ws8@" -bindsym $mod+9 workspace "@ws9@" -bindsym $mod+0 workspace "@ws10@" - -# move focused container to workspace -bindsym $mod+Shift+exclam move workspace "@ws1@" -bindsym $mod+Shift+at move workspace "@ws2@" -bindsym $mod+Shift+numbersign move workspace "@ws3@" -bindsym $mod+Shift+dollar move workspace "@ws4@" -bindsym $mod+Shift+percent move workspace "@ws5@" -bindsym $mod+Shift+asciicircum move workspace "@ws6@" -bindsym $mod+Shift+ampersand move workspace "@ws7@" -bindsym $mod+Shift+asterisk move workspace "@ws8@" -bindsym $mod+Shift+parenleft move workspace "@ws9@" -bindsym $mod+Shift+parenright move workspace "@ws10@" - # reload the configuration file bindsym $mod+Shift+L reload # restart i3 inplace (preserves your layout/session, can be used to upgrade i3) @@ -138,23 +114,8 @@ mode "resize" { bindsym $mod+r mode "resize" -# workspace assignments -workspace "@ws1@" output @leftHead@ -workspace "@ws2@" output @leftHead@ -workspace "@ws3@" output @leftHead@ -workspace "@ws4@" output @leftHead@ -workspace "@ws5@" output @leftHead@ -workspace "@ws6@" output @rightHead@ -workspace "@ws7@" output @rightHead@ -workspace "@ws8@" output @rightHead@ -workspace "@ws9@" output @rightHead@ -workspace "@ws10@" output @rightHead@ - -# default applications -assign [class="^Tkabber$"] 1: tkabber -#exec --no-startup-id tkabber -assign [class="^Chromium(?:-browser)?$"] 3: chromium -#exec chromium +# workspace configuration +@wsConfig@ # ratmenu should be as unintrusive as possible for_window [class="^ratmenu$"] floating enable diff --git a/modules/i3/workspace.nix b/modules/i3/workspace.nix new file mode 100644 index 00000000..5365bf74 --- /dev/null +++ b/modules/i3/workspace.nix @@ -0,0 +1,106 @@ +{ name, lib, config, ... }: + +with lib; + +let + finalLabel = + if config.label == null then name + else config.labelPrefix + config.label; + + mkDoc = anchor: "http://i3wm.org/docs/userguide.html#${anchor}"; +in +{ + options = { + labelPrefix = mkOption { + type = types.str; + default = ""; + example = "666: "; + description = '' + The value that will be put in front of the . + So if you have a label called bar and a + called foo the + label for the workspace will be foobar. + ''; + }; + + label = mkOption { + type = types.nullOr types.str; + default = name; + description = '' + The label of this workspace, which is its name by default. If the value + is null, the resulting label of the workspace + is just its name and no is applied. + ''; + }; + + assign = mkOption { + type = types.listOf types.attrs; + default = []; + example = [ + { class = "^Chromium(?:-browser)?\$"; } + { instance = "^gajim\$"; } + ]; + description = let + anchor = "_automatically_putting_clients_on_specific_workspaces"; + in '' + Assign windows to this specific workspace using the attribute names + described by . + ''; + }; + + head = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The XRandR head this workspace will be assigned to. + ''; + }; + + keys = let + commonDesc = '' + The $mod placeholder represents the default + modifier key. Details about the syntax of key combinations can be found + at . + ''; + in { + switchTo = mkOption { + type = types.nullOr types.str; + default = null; + example = "$mod+1"; + description = '' + Key combination to switch to this workspace. + '' + commonDesc; + }; + + moveTo = mkOption { + type = types.nullOr types.str; + default = null; + example = "$mod+Shift+exclam"; + description = '' + Key combination to move a container to this workspace. + '' + commonDesc; + }; + }; + + config = mkOption { + type = types.lines; + default = ""; + description = '' + Raw configuration options for this workspace. + ''; + }; + }; + + config.config = let + maybeOutput = optionalString (config.head != null) " output ${config.head}"; + mkAssign = mapAttrsToList (criteria: value: "${criteria}=\"${value}\""); + mkSym = sym: rest: optionalString (sym != null) "bindsym ${sym} ${rest}"; + in '' + workspace "${finalLabel}"${maybeOutput} + ${mkSym config.keys.switchTo "workspace \"${finalLabel}\""} + ${mkSym config.keys.moveTo "move workspace \"${finalLabel}\""} + ${concatMapStrings (assign: '' + assign [${concatStringsSep " " (mkAssign assign)}] ${finalLabel} + '') config.assign} + ''; +} -- cgit 1.4.1