summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/niri
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/niri')
-rw-r--r--accounts/gkleen@sif/niri/default.nix1324
-rw-r--r--accounts/gkleen@sif/niri/mako.nix52
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix7
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix47
4 files changed, 916 insertions, 514 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 4a207589..8752f3e3 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -1,6 +1,10 @@
1{ config, hostConfig, pkgs, lib, ... }: 1{ config, hostConfig, pkgs, lib, flakeInputs, ... }:
2let 2let
3 niri = config.programs.niri.package; 3 cfg = config.programs.niri;
4
5 kdl = flakeInputs.niri-flake.lib.kdl;
6
7 niri = cfg.package;
4 terminal = lib.getExe config.programs.kitty.package; 8 terminal = lib.getExe config.programs.kitty.package;
5 makoctl = lib.getExe' config.services.mako.package "makoctl"; 9 makoctl = lib.getExe' config.services.mako.package "makoctl";
6 loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; 10 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
@@ -28,7 +32,15 @@ let
28 32
29 while IFS=$'\n' read -r window_json; do 33 while IFS=$'\n' read -r window_json; do
30 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then 34 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
31 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous
37 else
38 if [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].is_focused' <<<"$workspaces_json") != "true" ]] && [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].id' <<<"$workspaces_json") = $(jq -r '.workspace_id' <<<"$window_json") ]]; then
39 niri msg action focus-workspace "$workspace_name"
40 else
41 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
42 fi
43 fi
32 exit 0 44 exit 0
33 fi 45 fi
34 done < <(niri msg -j windows | jq -c '.[]') 46 done < <(niri msg -j windows | jq -c '.[]')
@@ -37,7 +49,6 @@ let
37 ''; 49 '';
38 }; 50 };
39 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); 51 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
40 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
41 52
42 with_adjacent_workspace = pkgs.writeShellApplication { 53 with_adjacent_workspace = pkgs.writeShellApplication {
43 name = "with-adjacent-workspace"; 54 name = "with-adjacent-workspace";
@@ -74,9 +85,9 @@ let
74 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 85 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
75 ''; 86 '';
76 }; 87 };
77 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|eff|kpxc|bmgr|edit|term$"; 88 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
78 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 89 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
79 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 90 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
80 91
81 with_unnamed_workspace = pkgs.writeShellApplication { 92 with_unnamed_workspace = pkgs.writeShellApplication {
82 name = "with-unnamed-workspace"; 93 name = "with-unnamed-workspace";
@@ -89,13 +100,29 @@ let
89 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 100 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
90 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" 101 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
91 102
92 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" 103 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
104 workspace_json="$(jq -c --arg active_output "$active_output" --argjson history "$history_json" 'map(select(.output == $active_output and .name == null)) | map({"value": ., "history_idx": ((. as $workspace | ($history[$active_output] | index($workspace | .id))) as $active_idx | if $active_idx then $active_idx else ($history[$active_output] | length) + 1 end)}) | sort_by(.history_idx, .value.idx) | map(.value) | .[0]' <<<"$workspaces_json")"
93 [[ -n $workspace_json && $workspace_json != null ]] || exit 0 105 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
94 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 106 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
95 ''; 107 '';
96 }; 108 };
97 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace); 109 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace);
98 110
111 with_empty_unnamed_workspace = pkgs.writeShellApplication {
112 name = "with-empty-unnamed-workspace";
113 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
114 text = ''
115 action="$1"
116 shift
117
118 workspaces_json="$(niri msg -j workspaces)"
119 active_output="$(jq '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
120 target_workspace_id="$(jq --argjson active_output "$active_output" 'map(select(.active_window_id == null and .name == null and .output == $active_output)) | sort_by(.idx) | .[0].id' <<<"$workspaces_json")"
121 jq --argjson workspace_id "$target_workspace_id" -nc "$action" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
122 '';
123 };
124 with-empty-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_empty_unnamed_workspace);
125
99 with_select_window = pkgs.writeShellApplication { 126 with_select_window = pkgs.writeShellApplication {
100 name = "with-select-window"; 127 name = "with-select-window";
101 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ]; 128 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ];
@@ -107,7 +134,7 @@ let
107 134
108 windows_json="$(niri msg -j windows)" 135 windows_json="$(niri msg -j windows)"
109 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 136 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
110 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --log-level=warning --dmenu --index)" 137 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --width=60 --log-level=warning --dmenu --index)"
111 # shellcheck disable=SC2016 138 # shellcheck disable=SC2016
112 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" 139 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
113 140
@@ -117,6 +144,25 @@ let
117 ''; 144 '';
118 }; 145 };
119 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); 146 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
147
148 with_predicate_window = pred: pkgs.writeShellApplication {
149 name = "with-predicate-window";
150 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
151 text = ''
152 action="$1"
153 shift
154
155 windows_json="$(niri msg -j windows)"
156 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
157
158 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
159
160 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
161 '';
162 };
163
164 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
120in { 166in {
121 imports = [ 167 imports = [
122 ./waybar.nix 168 ./waybar.nix
@@ -124,6 +170,65 @@ in {
124 ./swayosd.nix 170 ./swayosd.nix
125 ]; 171 ];
126 172
173 options = {
174 programs.niri.scratchspaces = lib.mkOption {
175 type = lib.types.listOf (lib.types.submodule ({ config, ... }: {
176 options = {
177 name = lib.mkOption {
178 type = lib.types.str;
179 };
180 match = lib.mkOption {
181 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
182 default = [];
183 };
184 exclude = lib.mkOption {
185 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
186 default = [];
187 };
188 windowRuleExtra = lib.mkOption {
189 type = kdl.types.kdl-nodes;
190 default = [];
191 };
192 key = lib.mkOption {
193 type = lib.types.nullOr lib.types.str;
194 default = null;
195 };
196 moveKey = lib.mkOption {
197 type = lib.types.nullOr lib.types.str;
198 default = let
199 keys = lib.splitString "+" config.key;
200 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
201 (lib.take (lib.length keys - 1) keys)
202 ["Shift"]
203 (lib.takeEnd 1 keys)
204 ]);
205 in if config.key == null then null else defMoveKey;
206 };
207 spawn = lib.mkOption {
208 type = lib.types.nullOr (lib.types.listOf lib.types.str);
209 default = null;
210 };
211 app-id = lib.mkOption {
212 type = lib.types.nullOr lib.types.str;
213 default = null;
214 };
215 selector = lib.mkOption {
216 type = lib.types.nullOr lib.types.str;
217 default = null;
218 };
219 };
220
221 config = lib.mkMerge [
222 (lib.mkIf (config.app-id != null) {
223 match = lib.mkDefault [ { app-id = "^${lib.escapeRegex config.app-id}$"; } ];
224 selector = lib.mkDefault "select(.app_id == \"${config.app-id}\")";
225 })
226 ];
227 }));
228 default = [];
229 };
230 };
231
127 config = { 232 config = {
128 systemd.user.services.xwayland-satellite = { 233 systemd.user.services.xwayland-satellite = {
129 Unit = { 234 Unit = {
@@ -150,479 +255,760 @@ in {
150 { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; } 255 { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; }
151 ]; 256 ];
152 timeouts = [ 257 timeouts = [
153 { timeout = 300; 258 { timeout = 540;
154 command = "${lib.getExe niri} msg action power-off-monitors"; 259 command = "${lib.getExe niri} msg action power-off-monitors";
155 } 260 }
156 ]; 261 ];
157 }; 262 };
158 263
159 programs.niri.settings = { 264 systemd.user.sockets.niri-workspace-history = {
160 prefer-no-csd = true; 265 Socket = {
161 screenshot-path = "${config.home.homeDirectory}/screenshots"; 266 ListenStream = "%t/niri-workspace-history.sock";
162 267 SocketMode = "0600";
163 hotkey-overlay.skip-at-startup = true;
164
165 input = {
166 keyboard = {
167 repeat-delay = 300;
168 repeat-rate = 50;
169
170 xkb = {
171 layout = "us,us";
172 variant = "dvp,";
173 options = "compose:caps,grp:win_space_toggle";
174 };
175 };
176
177 workspace-auto-back-and-forth = true;
178 # focus-follows-mouse.enable = true;
179 warp-mouse-to-focus = true;
180 };
181
182 outputs = {
183 "eDP-1" = {
184 scale = 1.5;
185 position = { x = 0; y = 0; };
186 };
187 "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" = {
188 scale = 1.5;
189 position = { x = 2560; y = 0; };
190 };
191 "HP Inc. HP 727pu CN4417143K" = {
192 mode = { width = 2560; height = 1440; refresh = 119.998; };
193 scale = 1;
194 position = { x = 2560; y = 0; };
195 variable-refresh-rate = "on-demand";
196 };
197 }; 268 };
198 269 };
199 environment = { 270 systemd.user.services.niri-workspace-history = {
200 NIXOS_OZONE_WL = "1"; 271 Unit = {
201 QT_QPA_PLATFORM = "wayland"; 272 BindsTo = [ "niri.service" ];
202 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; 273 After = [ "niri.service" ];
203 GDK_BACKEND = "wayland";
204 SDL_VIDEODRIVER = "wayland";
205 DISPLAY = ":0";
206 }; 274 };
207 275 Install = {
208 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render"; 276 WantedBy = [ "niri.service" ];
209
210 animations = {
211 slowdown = 0.5;
212 }; 277 };
213 278 Service = {
214 layout = { 279 Type = "simple";
215 gaps = 8; 280 Sockets = [ "niri-workspace-history.socket" ];
216 struts = { left = 0; right = 0; top = 0; bottom = 0; }; 281 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
217 focus-ring = { 282 import os
218 width = 2; 283 import socket
219 active.gradient = { 284 import json
220 from = "hsla(195 100% 60% 0.75)"; 285 # import sys
221 to = "hsla(155 100% 50% 0.75)"; 286 from collections import defaultdict
222 angle = 29; 287 from threading import Thread, Lock
223 relative-to = "workspace-view"; 288 from socketserver import StreamRequestHandler, ThreadingTCPServer
224 }; 289 from contextlib import contextmanager
225 inactive.gradient = { 290 from io import TextIOWrapper
226 from = "hsla(0 0% 42% 0.66)"; 291
227 to = "hsla(0 0% 35% 0.66)"; 292
228 angle = 29; 293 @contextmanager
229 relative-to = "workspace-view"; 294 def detaching(thing):
230 }; 295 try:
231 }; 296 yield thing
232 297 finally:
233 preset-column-widths = [ 298 thing.detach()
234 { proportion = 1. / 4.; } 299
235 { proportion = 1. / 3.; } 300
236 { proportion = 1. / 2.; } 301 workspace_history = defaultdict(list)
237 { proportion = 2. / 3.; } 302 history_lock = Lock()
238 { proportion = 3. / 4.; } 303
239 ]; 304
240 default-column-width.proportion = 1. / 2.; 305 def monitor_niri():
241 preset-window-heights = [ 306 workspaces = list()
242 { proportion = 1. / 3.; } 307
243 { proportion = 1. / 2.; } 308 def focus_workspace(output, workspace):
244 { proportion = 2. / 3.; } 309 with history_lock:
245 { proportion = 1.; } 310 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
246 ]; 311 # print(json.dumps(workspace_history), file=sys.stderr)
247 312
248 always-center-single-column = true; 313 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
314 sock.connect(os.environ["NIRI_SOCKET"])
315 sock.send(b"\"EventStream\"\n")
316 for line in sock.makefile(buffering=1, encoding='utf-8'):
317 if line_json := json.loads(line):
318 if "WorkspacesChanged" in line_json:
319 workspaces = line_json["WorkspacesChanged"]["workspaces"]
320 for ws in workspaces:
321 if ws["is_focused"]:
322 focus_workspace(ws["output"], ws["id"])
323 if "WorkspaceActivated" in line_json:
324 for ws in workspaces:
325 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
326 continue
327 focus_workspace(ws["output"], ws["id"])
328 break
329
330
331 class RequestHandler(StreamRequestHandler):
332 def handle(self):
333 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
334 with history_lock:
335 json.dump(workspace_history, out)
336
337
338 class Server(ThreadingTCPServer):
339 def __init__(self):
340 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
341 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
342
343
344 def run_server():
345 with Server() as server:
346 server.serve_forever()
347
348
349 niri = Thread(target=monitor_niri)
350 niri.daemon = True
351 niri.start()
352
353 server_thread = Thread(target=run_server)
354 server_thread.daemon = True
355 server_thread.start()
356
357 while True:
358 server_thread.join(timeout=0.5)
359 niri.join(timeout=0.5)
360
361 if not (niri.is_alive() and server_thread.is_alive()):
362 break
363 '';
249 }; 364 };
250 365 };
251 cursor.hide-when-typing = true; 366 systemd.user.services.niri-workspace-sort = {
252 367 Unit = {
253 input = { 368 BindsTo = [ "niri.service" ];
254 touchpad.enable = false; 369 After = [ "niri.service" ];
255 trackball = {
256 scroll-method = "on-button-down";
257 scroll-button = 278;
258 };
259 }; 370 };
260 371 Install = {
261 workspaces = { 372 WantedBy = [ "niri.service" ];
262 "001" = { name = "pwctl"; open-on-output = "eDP-1"; };
263 "002" = { name = "kpxc"; open-on-output = "eDP-1"; };
264 "003" = { name = "bmgr"; open-on-output = "eDP-1"; };
265 "004" = { name = "term"; open-on-output = "eDP-1"; };
266 "005" = { name = "edit"; open-on-output = "eDP-1"; };
267 "006" = { name = "eff"; open-on-output = "eDP-1"; };
268 "101".name = "comm";
269 "102".name = "web";
270 # "104".name = "read";
271 # "105".name = "mon";
272 "110".name = "vid";
273 "120".name = "bmr";
274 }; 373 };
275 374 Service = {
276 window-rules = [ 375 Type = "simple";
277 # { 376 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
278 # geometry-corner-radius = 377 import os
279 # let 378 import sys
280 # allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; }; 379 import socket
281 # in allCorners 4.; 380 import json
282 # clip-to-geometry = true; 381
283 # } 382 outputs = None
284 { 383 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
285 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ]; 384
286 open-on-workspace = "pwctl"; 385
287 open-maximized = true; 386 class Niri(socket.socket):
288 } 387 def __init__(self):
289 { 388 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
290 matches = [ { app-id = "^com\.github\.wwmm\.easyeffects$"; } ]; 389 super().connect(os.environ["NIRI_SOCKET"])
291 open-on-workspace = "eff"; 390 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
292 open-maximized = true; 391
293 } 392 def cmd(self, obj):
294 { 393 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
295 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ]; 394
296 open-on-workspace = "bmgr"; 395 def event_stream(self):
297 open-maximized = true; 396 self.cmd("EventStream")
298 } 397 return self.fh
299 { 398
300 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ]; 399
301 block-out-from = "screencast"; 400 with Niri() as niri, Niri().event_stream() as niri_stream:
302 } 401 for line in niri_stream:
303 { 402 workspaces = None
304 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ]; 403 if line_json := json.loads(line):
305 excludes = [ 404 if "WorkspacesChanged" in line_json:
306 { title = "^Unlock Database.*"; } 405 workspaces = line_json["WorkspacesChanged"]["workspaces"]
307 { title = "^Access Request.*"; } 406
308 { title = ".*Passkey credentials$"; } 407 if workspaces is None:
309 ]; 408 continue
310 open-on-workspace = "kpxc"; 409
311 open-maximized = true; 410 old_outputs = outputs
312 open-focused = false; 411 outputs = {ws["output"] for ws in workspaces}
313 } 412 if old_outputs is None:
314 { 413 print("Initial outputs: {}".format(outputs), file=sys.stderr)
315 matches = [ 414 continue
316 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Unlock Database.*"; } 415
317 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Access Request.*"; } 416 new_outputs = outputs - old_outputs
318 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; } 417 if not new_outputs:
319 ]; 418 continue
320 open-focused = true; 419 print("New outputs: {}".format(new_outputs), file=sys.stderr)
321 open-floating = true; 420
322 } 421 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
323 { 422 target_output = next(iter(outputs - set(only.keys())))
324 matches = [ { app-id = "^kitty-scratch$"; } ]; 423 if not target_output:
325 open-on-workspace = "term"; 424 continue
326 open-maximized = true; 425 for ws in relevant_workspaces:
327 } 426 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
328 { 427 if ws["output"] not in set(only.keys()):
329 matches = [ { title = "^scratch$"; app-id = "^emacs$"; } ]; 428 continue
330 open-on-workspace = "edit"; 429 if ws_ident in only[ws["output"]]:
331 open-maximized = true; 430 continue
332 } 431
333 { 432 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
334 matches = [ 433 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
335 { app-id = "^emacs$"; } 434 '';
336 { app-id = "^firefox$"; } 435 Restart = "on-failure";
337 ]; 436 RestartSec = 10;
338 default-column-width.proportion = 2. / 3.;
339 }
340 {
341 matches = [
342 { app-id = "^kitty$"; }
343 { app-id = "^kitty-play$"; }
344 ];
345 default-column-width.proportion = 1. / 3.;
346 }
347 {
348 matches = [
349 { app-id = "^thunderbird$"; }
350 { app-id = "^Element$"; }
351 { app-id = "^Rainbow$"; }
352 ];
353 open-on-workspace = "comm";
354 }
355 {
356 matches = [ { app-id = "^firefox$"; } ];
357 open-on-workspace = "web";
358 open-maximized = true;
359 variable-refresh-rate = true;
360 }
361 # {
362 # matches = [
363 # { app-id = "^evince$"; }
364 # { app-id = "^imv$"; }
365 # { app-id = "^org\.pwmt\.zathura$"; }
366 # ];
367 # open-on-workspace = "read";
368 # }
369 {
370 matches = [ { app-id = "^mpv$"; } ];
371 open-on-workspace = "vid";
372 default-column-width.proportion = 1.;
373 variable-refresh-rate = true;
374 }
375 {
376 matches = [ { app-id = "^kitty-play$"; } ];
377 open-on-workspace = "vid";
378 open-focused = false;
379 }
380 # {
381 # matches = [
382 # { app-id = "^qemu$"; }
383 # { app-id = "^virt-manager$"; }
384 # ];
385 # open-on-workspace = "mon";
386 # }
387 {
388 matches = [ { app-id = "^pdfpc$"; } ];
389 default-column-width.proportion = 1.;
390 }
391 {
392 matches = [ { app-id = "^pdfpc$"; title = "^pdfpc - presentation"; } ];
393 open-on-workspace = "bmr";
394 open-fullscreen = true;
395 }
396 {
397 matches = [
398 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
399 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; }
400 ];
401 open-floating = true;
402 }
403 ];
404 layer-rules = [
405 { matches = [
406 { namespace = "^notifications$"; }
407 { namespace = "^waybar$"; }
408 ];
409 block-out-from = "screencast";
410 }
411 ];
412
413 binds = with config.lib.niri.actions; {
414 "Mod+Slash".action = show-hotkey-overlay;
415
416 "Mod+Return".action = spawn terminal;
417 "Mod+Q".action = close-window;
418 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
419 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
420
421 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
422 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
423 name = "queue-yt-dlp";
424 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
425 text = ''
426 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
427 '';
428 }));
429 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
430 name = "queue-yt-dlp";
431 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
432 text = ''
433 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
434 '';
435 }));
436
437 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
438 name = "qalc-fuzzel";
439 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
440 text = ''
441 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
442 prev() {
443 FOUND=false
444 while IFS= read -r line; do
445 [[ -n "$line" ]] || continue
446 FOUND=true
447 echo "$line"
448 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
449 $FOUND || echo
450 }
451 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $?
452 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
453 QALC_RES="$FUZZEL_RES"
454 QALC_RET=0
455 else
456 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1)
457 QALC_RET=$?
458 fi
459 [[ -n "$QALC_RES" ]] || exit 1
460 EXISTING=false
461 set +o pipefail
462 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
463 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
464 set -o pipefail
465 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
466 set +o pipefail
467 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
468 set -o pipefail
469 cat >"$RES_FILE" <<<"$QALC_RES"
470 fi
471 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
472 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
473 notify-send "$QALC_RES"
474 '';
475 }));
476 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
477 name = "emoji-fuzzel";
478 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
479 text = ''
480 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
481 [[ -n "$FUZZEL_RES" ]] || exit 1
482 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
483 '';
484 }));
485 "Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
486 name = "screenshot";
487 runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ];
488 text = ''
489 grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \
490 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
491 | wl-copy --type image/png
492 '';
493 }));
494 "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
495 name = "screenshot";
496 runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ];
497 text = ''
498 grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \
499 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
500 | wl-copy --type image/png
501 '';
502 }));
503 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
504 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
505
506 "Mod+H".action = focus-column-left;
507 "Mod+T".action = focus-window-down;
508 "Mod+N".action = focus-window-up;
509 "Mod+S".action = focus-column-right;
510
511 "Mod+Shift+H".action = move-column-left;
512 "Mod+Shift+T".action = move-window-down;
513 "Mod+Shift+N".action = move-window-up;
514 "Mod+Shift+S".action = move-column-right;
515
516 "Mod+Control+H".action = focus-monitor-left;
517 "Mod+Control+T".action = focus-monitor-down;
518 "Mod+Control+N".action = focus-monitor-up;
519 "Mod+Control+S".action = focus-monitor-right;
520
521 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
522 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
523 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
524 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
525
526 "Mod+G".action = focus-adjacent-workspace "down";
527 "Mod+C".action = focus-adjacent-workspace "up";
528
529 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
530 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
531
532 "Mod+Shift+Control+G".action = move-workspace-down;
533 "Mod+Shift+Control+C".action = move-workspace-up;
534
535 "Mod+ParenLeft".action = focus-workspace "comm";
536 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
537
538 "Mod+ParenRight".action = focus-workspace "web";
539 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
540
541 "Mod+BraceRight".action = focus-workspace "read";
542 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
543
544 "Mod+BraceLeft".action = focus-workspace "mon";
545 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
546
547 "Mod+Asterisk".action = focus-workspace "vid";
548 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
549
550 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
551 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
552
553 "Mod+M".action = consume-or-expel-window-left;
554 "Mod+W".action = consume-or-expel-window-right;
555
556 "Mod+R".action = switch-preset-column-width;
557 "Mod+Shift+R".action = switch-preset-window-height;
558 "Mod+F".action = center-column;
559 "Mod+Shift+F".action = maximize-column;
560 "Mod+Shift+Ctrl+F".action = fullscreen-window;
561
562 "Mod+V".action = switch-focus-between-floating-and-tiling;
563 "Mod+Shift+V".action = toggle-window-floating;
564
565 "Mod+Left".action = set-column-width "-10%";
566 "Mod+Down".action = set-window-height "-10%";
567 "Mod+Up".action = set-window-height "+10%";
568 "Mod+Right".action = set-column-width "+10%";
569
570 "Mod+Shift+Z" = {
571 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
572 allow-when-locked = true;
573 };
574 "Mod+Shift+L".action = spawn loginctl "lock-session";
575 "Mod+Shift+E".action = quit;
576 "Mod+Shift+Minus" = {
577 action = spawn systemctl "suspend";
578 allow-when-locked = true;
579 };
580 "Mod+Shift+Control+Minus" = {
581 action = spawn systemctl "hibernate";
582 allow-when-locked = true;
583 };
584 "Mod+Shift+P" = {
585 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
586 allow-when-locked = true;
587 };
588
589 "XF86MonBrightnessUp" = {
590 action = spawn swayosd-client "--brightness" "raise";
591 allow-when-locked = true;
592 };
593 "XF86MonBrightnessDown" = {
594 action = spawn swayosd-client "--brightness" "lower";
595 allow-when-locked = true;
596 };
597 "XF86AudioRaiseVolume" = {
598 action = spawn swayosd-client "--output-volume" "raise";
599 allow-when-locked = true;
600 };
601 "XF86AudioLowerVolume" = {
602 action = spawn swayosd-client "--output-volume" "lower";
603 allow-when-locked = true;
604 };
605 "XF86AudioMute" = {
606 action = spawn swayosd-client "--output-volume" "mute-toggle";
607 allow-when-locked = true;
608 };
609 "XF86AudioMicMute" = {
610 action = spawn swayosd-client "--input-volume" "mute-toggle";
611 allow-when-locked = true;
612 };
613
614 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
615 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
616 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu";
617 "Mod+Comma".action = spawn makoctl "restore";
618
619 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol";
620 "Mod+Control+O".action = focus-or-spawn-action-app_id "com.github.wwmm.easyeffects" "eff" "easyeffects";
621 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc";
622 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager";
623 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch";
624 "Mod+Control+E".action = focus-or-spawn-action "select(.app_id == \"emacs\" and .title == \"scratch\")" "edit" "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))";
625 }; 437 };
626 }; 438 };
439
440 programs.niri.scratchspaces = [
441 { name = "pwctl";
442 key = "Mod+Control+A";
443 spawn = ["pwvucontrol"];
444 app-id = "com.saivert.pwvucontrol";
445 }
446 { name = "kpxc";
447 exclude = [
448 { title = "^Unlock Database.*"; }
449 { title = "^Access Request.*"; }
450 { title = ".*Passkey credentials$"; }
451 ];
452 windowRuleExtra = with kdl; [
453 (kdl.leaf "open-focused" false)
454 ];
455 key = "Mod+Control+P";
456 app-id = "org.keepassxc.KeePassXC";
457 spawn = [ "keepassxc" ];
458 }
459 { name = "bmgr";
460 key = "Mod+Control+B";
461 app-id = ".blueman-manager-wrapped";
462 spawn = [ "blueman-manager" ];
463 }
464 { name = "term";
465 key = "Mod+Control+Return";
466 app-id = "kitty-scratch";
467 spawn = [ "kitty" "--app-id" "kitty-scratch" ];
468 }
469 { name = "edit";
470 match = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
471 key = "Mod+Control+E";
472 selector = "select(.app_id == \"emacs\" and .title == \"scratch\")";
473 spawn = [ "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))" ];
474 }
475 { name = "eff";
476 key = "Mod+Control+O";
477 app-id = "com.github.wwmm.easyeffects";
478 spawn = [ "easyeffects" ];
479 }
480 { name = "time";
481 key = "Mod+Control+K";
482 app-id = "chrome-kimai.yggdrasil.li__-Default";
483 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
484 interpreter = pkgs.runtimeShell;
485 inputs = [ pkgs.dex ];
486 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
487 } ''
488 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
489 '')) ];
490 windowRuleExtra = with kdl; [
491 (leaf "block-out-from" "screencast")
492 ];
493 }
494 ];
495 programs.niri.config =
496 let
497 inherit (kdl) node plain leaf flag;
498 optional-node = cond: v:
499 if cond
500 then v
501 else null;
502 opt-props = lib.filterAttrs (lib.const (value: value != null));
503 in
504 [ (flag "prefer-no-csd")
505
506 (leaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png")
507
508 (plain "hotkey-overlay" [
509 (flag "skip-at-startup")
510 ])
511
512 (plain "input" [
513 (plain "keyboard" [
514 (leaf "repeat-delay" 300)
515 (leaf "repeat-rate" 50)
516
517 (plain "xkb" [
518 (leaf "layout" "us,us")
519 (leaf "variant" "dvp,")
520 (leaf "options" "compose:caps,grp:win_space_toggle")
521 ])
522 ])
523
524 (flag "workspace-auto-back-and-forth")
525 # (leaf "focus-follows-mouse" {})
526 # (flag "warp-mouse-to-focus")
527
528 # (plain "touchpad" [ (flag "off") ])
529 (plain "trackball" [
530 (leaf "scroll-method" "on-button-down")
531 (leaf "scroll-button" 278)
532 ])
533 (plain "touch" [
534 (leaf "map-to-output" "eDP-1")
535 ])
536 ])
537
538 (plain "gestures" [
539 (plain "hot-corners" [(flag "off")])
540 ])
541
542 (plain "environment" (lib.mapAttrsToList leaf {
543 NIXOS_OZONE_WL = "1";
544 QT_QPA_PLATFORM = "wayland";
545 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
546 GDK_BACKEND = "wayland";
547 SDL_VIDEODRIVER = "wayland";
548 DISPLAY = ":0";
549 ELECTRON_OZONE_PLATFORM_HINT = "auto";
550 SSH_ASKPASS_REQUIRE = "prefer";
551 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
552 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
553 }))
554
555 (node "output" "eDP-1" [
556 (leaf "scale" 1.5)
557 (leaf "position" { x = 0; y = 0; })
558 ])
559 (node "output" "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" [
560 (leaf "scale" 1.5)
561 (leaf "position" { x = 2560; y = 0; })
562 ])
563 (node "output" "HP Inc. HP 727pu CN4417143K" [
564 (leaf "mode" "2560x1440@119.998")
565 (leaf "scale" 1)
566 (leaf "position" { x = 2560; y = 0; })
567 (flag "variable-refresh-rate")
568 ])
569
570 (plain "debug" [
571 (leaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render")
572 ])
573
574 (plain "animations" [
575 (leaf "slowdown" 0.5)
576 (plain "workspace-switch" [(flag "off")])
577 ])
578
579 (plain "layout" [
580 (leaf "gaps" 8)
581 (plain "struts" [
582 (leaf "left" 26)
583 (leaf "right" 26)
584 (leaf "top" 0)
585 (leaf "bottom" 0)
586 ])
587 (plain "border" [
588 (leaf "width" 2)
589 (leaf "active-gradient" {
590 from = "hsla(195 100% 45% 1)";
591 to = "hsla(155 100% 37.5% 1)";
592 angle = 29;
593 relative-to = "workspace-view";
594 })
595 (leaf "inactive-gradient" {
596 from = "hsla(0 0% 27.7% 1)";
597 to = "hsla(0 0% 23% 1)";
598 angle = 29;
599 relative-to = "workspace-view";
600 })
601 ])
602 (plain "focus-ring" [
603 (flag "off")
604 ])
605
606 (plain "preset-column-widths" (map (prop: leaf "proportion" prop) [
607 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.)
608 ]))
609 (plain "default-column-width" [ (leaf "proportion" (1. / 2.)) ])
610 (plain "preset-window-heights" (map (prop: leaf "proportion" prop) [
611 (1. / 3.) (1. / 2.) (2. / 3.) (1.)
612 ]))
613
614 (flag "always-center-single-column")
615
616 (plain "tab-indicator" [
617 (leaf "gap" 4)
618 (leaf "width" 8)
619 (leaf "gaps-between-tabs" 4)
620 (flag "place-within-column")
621 (leaf "length" { total-proportion = 1.; })
622 (leaf "active-gradient" {
623 from = "hsla(195 100% 60% 0.75)";
624 to = "hsla(155 100% 50% 0.75)";
625 angle = 29;
626 relative-to = "workspace-view";
627 })
628 (leaf "inactive-gradient" {
629 from = "hsla(0 0% 42% 0.66)";
630 to = "hsla(0 0% 35% 0.66)";
631 angle = 29;
632 relative-to = "workspace-view";
633 })
634 ])
635 ])
636
637 (plain "cursor" [
638 (flag "hide-when-typing")
639 ])
640
641 (map (name:
642 (node "workspace" name [
643 (leaf "open-on-output" "eDP-1")
644 ])
645 ) (map ({name, ...}: name) cfg.scratchspaces))
646 (map (name:
647 (leaf "workspace" name)
648 ) ["comm" "web" "vid" "bmr"])
649
650 (plain "window-rule" [
651 (leaf "clip-to-geometry" true)
652 ])
653
654 (plain "window-rule" [
655 (leaf "match" { is-floating = true; })
656 (leaf "geometry-corner-radius" 8)
657 (plain "shadow" [ (flag "on") ])
658 ])
659
660 (plain "window-rule" [
661 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; })
662 (leaf "block-out-from" "screencast")
663 ])
664 (plain "window-rule" [
665 (map (title:
666 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
667 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
668 (leaf "open-focused" true)
669 (leaf "open-floating" true)
670 ])
671
672 (map ({ name, match, exclude, windowRuleExtra, ... }:
673 (optional-node (match != []) (plain "window-rule" [
674 (map (leaf "match") match)
675 (map (leaf "exclude") exclude)
676 (leaf "open-on-workspace" name)
677 (leaf "open-maximized" true)
678 windowRuleExtra
679 ]))
680 ) cfg.scratchspaces)
681
682 (plain "window-rule" [
683 (leaf "match" { app-id = "^emacs$"; })
684 (leaf "match" { app-id = "^firefox$"; })
685 (plain "default-column-width" [(leaf "proportion" (2. / 3.))])
686 ])
687 (plain "window-rule" [
688 (leaf "match" { app-id = "^kitty$"; })
689 (leaf "match" { app-id = "^kitty-play$"; })
690 (plain "default-column-width" [(leaf "proportion" (1. / 3.))])
691 ])
692
693 (plain "window-rule" [
694 (leaf "match" { app-id = "^thunderbird$"; })
695 (leaf "match" { app-id = "^Element$"; })
696 (leaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
697 (leaf "open-on-workspace" "comm")
698 ])
699 (plain "window-rule" [
700 (leaf "match" { app-id = "^firefox$"; })
701 (leaf "open-on-workspace" "web")
702 (leaf "open-maximized" true)
703 ])
704 (plain "window-rule" [
705 (leaf "match" { app-id = "^mpv$"; })
706 (leaf "open-on-workspace" "vid")
707 (plain "default-column-width" [(leaf "proportion" 1.)])
708 ])
709 (plain "window-rule" [
710 (leaf "match" { app-id = "^kitty-play$"; })
711 (leaf "open-on-workspace" "vid")
712 (leaf "open-focused" false)
713 ])
714 (plain "window-rule" [
715 (leaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
716 (leaf "match" { app-id = "^YouTube Music Desktop App$"; })
717 (leaf "open-on-workspace" "vid")
718 ])
719 (plain "window-rule" [
720 (leaf "match" { app-id = "^pdfpc$"; })
721 (plain "default-column-width" [(leaf "proportion" 1.)])
722 ])
723 (plain "window-rule" [
724 (leaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; })
725 (plain "default-column-width" [(leaf "proportion" 1.)])
726 (leaf "open-fullscreen" true)
727 (leaf "open-on-workspace" "bmr")
728 (leaf "open-focused" false)
729 ])
730 (plain "window-rule" [
731 (map (leaf "match") [
732 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
733 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; }
734 { app-id = "^xdg-desktop-portal-gtk$"; }
735 ])
736 (leaf "open-floating" true)
737 ])
738 (plain "window-rule" [
739 (leaf "match" { app-id = "^org\\.pwmt\\.zathura$"; })
740 (leaf "match" { app-id = "^evince$"; })
741 (leaf "match" { app-id = "^org\\.gnome\\.Papers$"; })
742 (leaf "default-column-display" "tabbed")
743 ])
744
745 (plain "layer-rule" [
746 (leaf "match" { namespace = "^notifications$"; })
747 (leaf "match" { namespace = "^waybar$"; })
748 (leaf "match" { namespace = "^launcher$"; })
749 (leaf "block-out-from" "screencast")
750 ])
751
752 (plain "binds"
753 (let
754 bind = name: cfg: node name (opt-props {
755 cooldown-ms = cfg.cooldown-ms or null;
756 }
757 // (lib.optionalAttrs (!(cfg.repeat or true)) {
758 repeat = false;
759 })
760 // (lib.optionalAttrs (cfg.allow-when-locked or false) {
761 allow-when-locked = true;
762 })) (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
763 in
764 [
765 (lib.mapAttrsToList bind (with config.lib.niri.actions; {
766 "Mod+Slash".action = show-hotkey-overlay;
767
768 "Mod+Return".action = spawn terminal;
769 "Mod+Shift+Return".action =
770 let
771 nushellKitty = pkgs.symlinkJoin {
772 name = "nushell-kitty";
773 paths = [ config.programs.kitty.package ];
774 buildInputs = [ pkgs.makeWrapper ];
775 postBuild = ''
776 wrapProgram $out/bin/kitty \
777 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
778 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
779 shell ${lib.getExe config.programs.nushell.package}
780 ''}"
781 '';
782 };
783 in spawn (lib.getExe' nushellKitty "kitty");
784 "Mod+Q".action = close-window;
785 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
786 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
787
788 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
789 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
790 name = "queue-yt-dlp";
791 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
792 text = ''
793 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
794 '';
795 }));
796 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
797 name = "queue-yt-dlp";
798 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
799 text = ''
800 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
801 '';
802 }));
803 "Mod+Alt+M".action = spawn (lib.getExe' pkgs.screen-message "sm") "-n" "Fira Mono" "-a" "1" "-f" "#fff" "-b" "#000";
804
805 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
806 name = "qalc-fuzzel";
807 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
808 text = ''
809 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
810 prev() {
811 FOUND=false
812 while IFS= read -r line; do
813 [[ -n "$line" ]] || continue
814 FOUND=true
815 echo "$line"
816 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
817 $FOUND || echo
818 }
819 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
820 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
821 QALC_RES="$FUZZEL_RES"
822 QALC_RET=0
823 else
824 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
825 QALC_RET=$?
826 fi
827 [[ -n "$QALC_RES" ]] || exit 1
828 EXISTING=false
829 set +o pipefail
830 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
831 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
832 set -o pipefail
833 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
834 set +o pipefail
835 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
836 set -o pipefail
837 cat >"$RES_FILE" <<<"$QALC_RES"
838 fi
839 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
840 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
841 notify-send "$QALC_RES"
842 '';
843 }));
844 "Mod+Shift+U".action =
845 let
846 qalcKitty = pkgs.symlinkJoin {
847 name = "qalc-kitty";
848 paths = [ config.programs.kitty.package ];
849 buildInputs = [ pkgs.makeWrapper ];
850 postBuild = ''
851 wrapProgram $out/bin/kitty \
852 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
853 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
854 shell ${lib.getExe pkgs.libqalculate}
855 ''}"
856 '';
857 };
858 in spawn (lib.getExe' qalcKitty "kitty");
859 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
860 name = "emoji-fuzzel";
861 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
862 text = ''
863 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
864 [[ -n "$FUZZEL_RES" ]] || exit 1
865 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
866 '';
867 }));
868 "Print".action = screenshot;
869 "Control+Print".action = screenshot-window;
870 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
871 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
872 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
873
874 "Mod+Escape" = {
875 allow-inhibiting = false;
876 action = toggle-keyboard-shortcuts-inhibit;
877 };
878
879 "Mod+H".action = focus-column-left;
880 "Mod+T".action = focus-window-down;
881 "Mod+N".action = focus-window-up;
882 "Mod+S".action = focus-column-right;
883
884 "Mod+Shift+H".action = move-column-left;
885 "Mod+Shift+T".action = move-window-down;
886 "Mod+Shift+N".action = move-window-up;
887 "Mod+Shift+S".action = move-column-right;
888
889 "Mod+Control+H".action = focus-monitor-left;
890 "Mod+Control+T".action = focus-monitor-down;
891 "Mod+Control+N".action = focus-monitor-up;
892 "Mod+Control+S".action = focus-monitor-right;
893
894 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
895 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
896 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
897 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
898
899 "Mod+G".action = focus-adjacent-workspace "down";
900 "Mod+C".action = focus-adjacent-workspace "up";
901
902 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
903 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
904
905 "Mod+Shift+Control+G".action = move-workspace-down;
906 "Mod+Shift+Control+C".action = move-workspace-up;
907
908 "Mod+ParenLeft".action = focus-workspace "comm";
909 "Mod+Shift+ParenLeft".action = kdl.magic-leaf "move-column-to-workspace" "comm";
910
911 "Mod+ParenRight".action = focus-workspace "web";
912 "Mod+Shift+ParenRight".action = kdl.magic-leaf "move-column-to-workspace" "web";
913
914 "Mod+BraceRight".action = focus-workspace "read";
915 "Mod+Shift+BraceRight".action = kdl.magic-leaf "move-column-to-workspace" "read";
916
917 "Mod+BraceLeft".action = focus-workspace "mon";
918 "Mod+Shift+BraceLeft".action = kdl.magic-leaf "move-column-to-workspace" "mon";
919
920 "Mod+Asterisk".action = focus-workspace "vid";
921 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
922
923 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
924 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
925
926 "Mod+M".action = consume-or-expel-window-left;
927 "Mod+W".action = consume-or-expel-window-right;
928
929 "Mod+Shift+M".action = toggle-column-tabbed-display;
930
931 "Mod+R".action = switch-preset-column-width;
932 "Mod+Shift+R".action = maximize-column;
933 "Mod+Shift+Ctrl+R".action = switch-preset-window-height;
934 "Mod+F".action = center-column;
935 "Mod+Shift+F".action = toggle-windowed-fullscreen;
936 "Mod+Ctrl+Shift+F".action = fullscreen-window;
937
938 "Mod+V".action = switch-focus-between-floating-and-tiling;
939 "Mod+Shift+V".action = toggle-window-floating;
940
941 "Mod+Left".action = set-column-width "-10%";
942 "Mod+Down".action = set-window-height "-10%";
943 "Mod+Up".action = set-window-height "+10%";
944 "Mod+Right".action = set-column-width "+10%";
945
946 "Mod+Shift+Z" = {
947 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
948 allow-when-locked = true;
949 };
950 "Mod+Shift+L".action = spawn loginctl "lock-session";
951 "Mod+Shift+E".action = quit;
952 "Mod+Shift+Minus" = {
953 action = spawn systemctl "suspend";
954 allow-when-locked = true;
955 };
956 "Mod+Shift+Control+Minus" = {
957 action = spawn systemctl "hibernate";
958 allow-when-locked = true;
959 };
960 "Mod+Shift+P" = {
961 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
962 allow-when-locked = true;
963 };
964
965 "XF86MonBrightnessUp" = {
966 action = spawn swayosd-client "--brightness" "raise";
967 allow-when-locked = true;
968 };
969 "XF86MonBrightnessDown" = {
970 action = spawn swayosd-client "--brightness" "lower";
971 allow-when-locked = true;
972 };
973 "XF86AudioRaiseVolume" = {
974 action = spawn swayosd-client "--output-volume" "raise";
975 allow-when-locked = true;
976 };
977 "XF86AudioLowerVolume" = {
978 action = spawn swayosd-client "--output-volume" "lower";
979 allow-when-locked = true;
980 };
981 "XF86AudioMute" = {
982 action = spawn swayosd-client "--output-volume" "mute-toggle";
983 allow-when-locked = true;
984 };
985 "XF86AudioMicMute" = {
986 action = spawn swayosd-client "--input-volume" "mute-toggle";
987 allow-when-locked = true;
988 };
989
990 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
991 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
992 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
993 "Mod+Comma".action = spawn makoctl "restore";
994
995 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
996 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
997
998 "Mod+X".action = set-dynamic-cast-window;
999 "Mod+Shift+X".action = set-dynamic-cast-monitor;
1000 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
1001
1002 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
1003 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
1004
1005 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
1006 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
1007 }))
1008 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
1009 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
1010 ]
1011 ))
1012 ];
627 }; 1013 };
628} 1014}
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index 0a10555a..eba26caa 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -3,33 +3,31 @@
3 config = { 3 config = {
4 services.mako = { 4 services.mako = {
5 enable = true; 5 enable = true;
6 font = "Fira Sans 10"; 6 settings = {
7 format = "<i>%s</i>\\n%b"; 7 font = "Fira Sans 10";
8 margin = "2"; 8 format = "<i>%s</i>\\n%b";
9 maxVisible = -1; 9 margin = "2";
10 backgroundColor = "#000000dd"; 10 max-visible = -1;
11 progressColor = "source #223544ff"; 11 background-color = "#000000dd";
12 width = 384; 12 progress-color = "source #223544ff";
13 extraConfig = '' 13 width = 384;
14 outer-margin=1 14 outer-margin = 1;
15 max-history=100 15 max-history = 100;
16 max-icon-size=48 16 max-icon-size = 48;
17 17 };
18 [grouped] 18 criteria = {
19 format=<b>(%g)</b> <i>%s</i>\n%b 19 grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b";
20 20 "urgency=low".text-color = "#999999ff";
21 [urgency=low] 21 "urgency=critical".background-color = "#900000dd";
22 text-color=#999999ff 22 "app-name=Element".group-by = "summary";
23 23 "app-name=poweralertd" = {
24 [urgency=critical] 24 history = false;
25 background-color=#900000dd 25 ignore-timeout = true;
26 26 default-timeout = 2000;
27 [app-name=Element] 27 };
28 group-by=summary 28 "app-name=worktime".history = false;
29 29 "mode=silent".invisible = true;
30 [mode=silent] 30 };
31 invisible=1
32 '';
33 package = pkgs.symlinkJoin { 31 package = pkgs.symlinkJoin {
34 name = "${pkgs.mako.name}-wrapped"; 32 name = "${pkgs.mako.name}-wrapped";
35 paths = with pkgs; [ mako ]; 33 paths = with pkgs; [ mako ];
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
index 984927c2..54ebb302 100644
--- a/accounts/gkleen@sif/niri/swayosd.nix
+++ b/accounts/gkleen@sif/niri/swayosd.nix
@@ -3,9 +3,10 @@
3 config = { 3 config = {
4 services.swayosd = { 4 services.swayosd = {
5 enable = true; 5 enable = true;
6 topMargin = 0.946154; 6 topMargin = 0.4769706078;
7 stylePath = pkgs.runCommand "style.css" { 7 stylePath = pkgs.runCommand "style.css" {
8 src = pkgs.writeText "style.scss" '' 8 passAsFile = [ "src" ];
9 src = ''
9 window#osd { 10 window#osd {
10 padding: 12px 20px; 11 padding: 12px 20px;
11 border-radius: 999px; 12 border-radius: 999px;
@@ -59,7 +60,7 @@
59 } 60 }
60 ''; 61 '';
61 buildInputs = with pkgs; [sass]; 62 buildInputs = with pkgs; [sass];
62 } "scss -C --sourcemap=none --style=compact $src $out"; 63 } "scss -C --sourcemap=none --style=compact $srcPath $out";
63 }; 64 };
64 }; 65 };
65} 66}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index c3820508..c02a9a76 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -20,15 +20,21 @@ in {
20 { 20 {
21 layer = "top"; 21 layer = "top";
22 position = "top"; 22 position = "top";
23 height = 14; 23 height = 21;
24 output = [ "eDP-1" "DP-2" "DP-3" ]; 24 output = [ "eDP-1" "DP-2" "DP-3" ];
25 modules-left = [ "niri/workspaces" ]; 25 modules-left = [ "niri/workspaces" ];
26 modules-center = [ "niri/window" ]; 26 modules-center = [ "niri/window" ];
27 modules-right = [ "custom/worktime" "custom/worktime-today" 27 modules-right = [ "custom/worktime" "custom/worktime-today"
28 "custom/weather" 28 "custom/weather"
29 "custom/keymap" 29 "custom/keymap"
30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; 30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "custom/lid_inhibitor" "clock" ];
31 31
32 "custom/lid_inhibitor" = {
33 format = "{}";
34 return-type = "json";
35 exec = lib.getExe pkgs.waybar-systemd-inhibit;
36 on-click = lib.getExe' pkgs.waybar-systemd-inhibit "waybar-systemd-inhibit-toggle";
37 };
32 "custom/mako" = { 38 "custom/mako" = {
33 format = "{}"; 39 format = "{}";
34 return-type = "json"; 40 return-type = "json";
@@ -61,7 +67,7 @@ in {
61 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501 67 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501
62 if is_silent: 68 if is_silent:
63 text = f"<span color=\"#ffffff\">{text}</span>" 69 text = f"<span color=\"#ffffff\">{text}</span>"
64 print(json.dumps({'text': text}, separators=(',', ':')), flush=True) # noqa: E501 70 print(json.dumps({'text': text, 'tooltip': ', '.join(modes)}, separators=(',', ':')), flush=True) # noqa: E501
65 71
66 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501 72 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501
67 if "Modes" not in invalidated_properties: 73 if "Modes" not in invalidated_properties:
@@ -122,16 +128,16 @@ in {
122 }; 128 };
123 "custom/worktime" = { 129 "custom/worktime" = {
124 interval = 60; 130 interval = 60;
125 exec = lib.getExe pkgs.worktime; 131 exec = "${lib.getExe pkgs.worktime} time --waybar";
126 tooltip = false; 132 return-type = "json";
127 }; 133 };
128 "custom/worktime-today" = { 134 "custom/worktime-today" = {
129 interval = 60; 135 interval = 60;
130 exec = "${lib.getExe pkgs.worktime} today"; 136 exec = "${lib.getExe pkgs.worktime} today --waybar";
131 tooltip = false; 137 return-type = "json";
132 }; 138 };
133 "niri/workspaces" = { 139 "niri/workspaces" = {
134 ignore = ["eff" "pwctl" "kpxc" "bmgr" "edit" "term"]; 140 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
135 }; 141 };
136 "niri/window" = { 142 "niri/window" = {
137 separate-outputs = true; 143 separate-outputs = true;
@@ -211,13 +217,13 @@ in {
211 layer = "top"; 217 layer = "top";
212 position = "top"; 218 position = "top";
213 height = 14; 219 height = 14;
214 output = [ "!eDP-1" "!DP-2" "!DP-3" ]; 220 output = [ "!eDP-1" "!DP-2" "!DP-3" "*" ];
215 modules-left = [ "niri/workspaces" ]; 221 modules-left = [ "niri/workspaces" ];
216 modules-center = [ "niri/window" ]; 222 modules-center = [ "niri/window" ];
217 modules-right = [ "clock" ]; 223 modules-right = [ "clock" ];
218 224
219 "niri/workspaces" = { 225 "niri/workspaces" = {
220 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"]; 226 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
221 }; 227 };
222 "niri/window" = { 228 "niri/window" = {
223 separate-outputs = true; 229 separate-outputs = true;
@@ -254,10 +260,10 @@ in {
254 } 260 }
255 261
256 .modules-left { 262 .modules-left {
257 margin-left: 12px; 263 margin-left: 38px;
258 } 264 }
259 .modules-right { 265 .modules-right {
260 margin-right: 12px; 266 margin-right: 38px;
261 } 267 }
262 268
263 .module { 269 .module {
@@ -293,7 +299,7 @@ in {
293 #tray { 299 #tray {
294 margin: 0; 300 margin: 0;
295 } 301 }
296 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako { 302 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako, #custom-lid_inhibitor {
297 color: @grey; 303 color: @grey;
298 margin: 0 5px 0 2px; 304 margin: 0 5px 0 2px;
299 } 305 }
@@ -302,7 +308,11 @@ in {
302 margin-left: 6px; 308 margin-left: 6px;
303 } 309 }
304 #custom-mako { 310 #custom-mako {
305 margin-right: 2px; 311 margin-right: 4px;
312 margin-left: 3px;
313 }
314 #custom-lid_inhibitor {
315 margin-right: 3px;
306 margin-left: 3px; 316 margin-left: 3px;
307 } 317 }
308 #battery { 318 #battery {
@@ -323,8 +333,14 @@ in {
323 #idle_inhibitor.activated { 333 #idle_inhibitor.activated {
324 color: @white; 334 color: @white;
325 } 335 }
336 #custom-worktime.running, #custom-worktime-today.running {
337 color: @white;
338 }
339 #custom-worktime.over, #custom-worktime-today.over {
340 color: @orange;
341 }
326 342
327 #idle_inhibitor { 343 #idle_inhibitor, #custom-lid_inhibitor {
328 padding-top: 1px; 344 padding-top: 1px;
329 } 345 }
330 346
@@ -334,6 +350,7 @@ in {
334 } 350 }
335 #clock { 351 #clock {
336 /* margin-right: 5px; */ 352 /* margin-right: 5px; */
353 font-feature-settings: "tnum";
337 } 354 }
338 ''; 355 '';
339 }; 356 };