about summary refs log tree commit diff
path: root/modules/user/aszlig/services/i3/default.nix
blob: d11140dd2420358cb898cee483a41de51abb2216 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{ pkgs, lib, config, ... }:

with lib;

let
  cfg = config.vuizvui.user.aszlig.services.i3;
  inherit (config.services.xserver) xrandrHeads;

  # 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 xrandrHeads;
  wsPerHead = wsCount / headCount;
  excessWs = wsCount - (headCount * wsPerHead);
  headModifier = if cfg.reverseHeads then reverseList else id;
  getHeadAt = x: (elemAt (headModifier xrandrHeads) x).output;

  mkSwitchTo = number: "$mod+${if number == 10 then "0" else toString number}";

  mkDefaultWorkspace = number: numberSymbol: {
    name = toString number;
    value = {
      label = mkDefault null;
      labelPrefix = mkDefault "${toString number}: ";
      keys.switchTo = mkDefault (mkSwitchTo number);
      keys.moveTo = mkDefault "$mod+Shift+${numberSymbol}";
      head = if headCount == 0 then mkDefault null
             else mkDefault (getHeadAt ((number - (excessWs + 1)) / wsPerHead));
    };
  };

  wsCfgList = mapAttrsToList (_: getAttr "config") cfg.workspaces;
  wsConfig = concatStrings wsCfgList;
  defaultWorkspaces = listToAttrs (imap mkDefaultWorkspace wsNumberSymbols);

  conky = import ./conky.nix {
    inherit pkgs lib;
    timeout = cfg.networkTimeout;
  };

  mkBar = output: statusCmd: singleton ''
    bar {
      ${optionalString (output != null) "output ${output}"}
      ${optionalString (statusCmd != null) "status_command ${statusCmd}"}
      colors {
        focused_workspace  #5c5cff #e5e5e5
        active_workspace   #ffffff #0000ee
        inactive_workspace #00cdcd #0000ee
        urgent_workspace   #ffff00 #cd0000
      }
    }
  '';

  barConfig = let
    barHeads = map (h: h.output) (headModifier xrandrHeads);
    bars = if headCount == 0 then mkBar null conky.single
      else if headCount == 1 then mkBar (head barHeads) conky.single
      else let inner = take (length barHeads - 2) (tail barHeads);
           in mkBar (head barHeads) conky.left
           ++ map (flip mkBar null) inner
           ++ mkBar (last barHeads) conky.right;
  in concatStrings (headModifier bars);

in
{
  options.vuizvui.user.aszlig.services.i3 = {
    enable = mkEnableOption "i3";

    workspaces = mkOption {
      type = types.attrsOf (types.submodule (import ./workspace.nix));
      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.
      '';
    };

    reverseHeads = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Reverse the order of the heads, so if enabled and you have two heads,
        you'll end up having workspaces 1 to 5 on the right head and 6 to 10 on
        the left head.
      '';
    };

    networkTimeout = mkOption {
      type = types.int;
      default = 300;
      description = ''
        Maximum number of seconds to wait for network device detection.
      '';
    };
  };

  config = mkIf cfg.enable {
    vuizvui.user.aszlig.services.i3.workspaces = defaultWorkspaces;

    services.xserver.windowManager = {
      i3.enable = true;
      i3.configFile = pkgs.substituteAll {
        name = "i3.conf";
        src = ./i3.conf;

        inherit (pkgs) dmenu xterm;
        inherit (pkgs.vuizvui.aszlig) pvolctrl;
        inherit (pkgs.xorg) xsetroot;
        inherit wsConfig barConfig;

        # XXX: Decouple this by making the i3 bindsym directives available to
        #      the NixOS module system.
        flameshot = config.vuizvui.user.aszlig.programs.flameshot.package;

        lockall = pkgs.writeScript "lockvt.sh" ''
          #!${pkgs.stdenv.shell}
          "${pkgs.socat}/bin/socat" - UNIX-CONNECT:/run/console-lock.sock \
            < /dev/null
        '';

        postInstall = ''
          ${pkgs.i3}/bin/i3 -c "$target" -C
        '';
      };
    };
  };
}