summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.sops.yaml3
-rw-r--r--_sources/generated.json40
-rw-r--r--_sources/generated.nix28
-rw-r--r--accounts/gkleen@sif/default.nix38
-rw-r--r--accounts/gkleen@sif/emacs.el1
-rw-r--r--accounts/gkleen@sif/niri/default.nix185
-rw-r--r--accounts/gkleen@sif/niri/mako.nix10
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix65
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix49
-rw-r--r--accounts/gkleen@sif/systemd.nix3
-rw-r--r--flake.lock66
-rw-r--r--hosts/sif/default.nix12
-rw-r--r--hosts/sif/greetd/wallpaper.pngbin132 -> 6073128 bytes
-rw-r--r--modules/nix-access-tokens/default.nix24
-rw-r--r--modules/nix-access-tokens/nix.conf32
-rw-r--r--nvfetcher.toml18
-rw-r--r--overlays/batman-adv.nix15
-rw-r--r--overlays/keepassxc/database-open-dialog.patch126
-rw-r--r--overlays/keepassxc/default.nix8
-rw-r--r--overlays/swayosd/default.nix30
-rw-r--r--overlays/swayosd/exponential.patch57
-rwxr-xr-xoverlays/worktime/worktime/__main__.py119
22 files changed, 755 insertions, 174 deletions
diff --git a/.sops.yaml b/.sops.yaml
index 7b0507ee..948383b2 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -26,3 +26,6 @@ creation_rules:
26 - path_regex: ^hosts/sif/ 26 - path_regex: ^hosts/sif/
27 key_groups: 27 key_groups:
28 - age: [ *admin_gkleen, *machine_sif ] 28 - age: [ *admin_gkleen, *machine_sif ]
29 - path_regex: ^modules/nix-access-tokens/
30 key_groups:
31 - age: [ *admin_gkleen, *machine_sif, *machine_surtr, *machine_vidhar ]
diff --git a/_sources/generated.json b/_sources/generated.json
index f73b8190..72f913ec 100644
--- a/_sources/generated.json
+++ b/_sources/generated.json
@@ -20,20 +20,6 @@
20 }, 20 },
21 "version": "8ef9a5b73e5d1063cf912c70027c655fb19d1109" 21 "version": "8ef9a5b73e5d1063cf912c70027c655fb19d1109"
22 }, 22 },
23 "batman-adv": {
24 "cargoLocks": null,
25 "date": null,
26 "extract": null,
27 "name": "batman-adv",
28 "passthru": null,
29 "pinned": false,
30 "src": {
31 "sha256": "sha256-VYyIkH5IFfKN6EOHZxSx6AaepD3a22/hhmLhqkle5Z0=",
32 "type": "tarball",
33 "url": "https://downloads.open-mesh.org/batman/stable/sources/batman-adv/batman-adv-2024.4.tar.gz"
34 },
35 "version": "2024.4"
36 },
37 "bpf-examples": { 23 "bpf-examples": {
38 "cargoLocks": null, 24 "cargoLocks": null,
39 "date": "2025-01-03", 25 "date": "2025-01-03",
@@ -379,6 +365,26 @@
379 }, 365 },
380 "version": "0.2.1" 366 "version": "0.2.1"
381 }, 367 },
368 "swayosd": {
369 "cargoLocks": null,
370 "date": "2025-01-27",
371 "extract": null,
372 "name": "swayosd",
373 "passthru": null,
374 "pinned": false,
375 "src": {
376 "deepClone": false,
377 "fetchSubmodules": false,
378 "leaveDotGit": false,
379 "name": null,
380 "rev": "993180b5e7db1dfc453a556bf208f05b04283c8f",
381 "sha256": "sha256-qwtGkRJlCYu+dO3xCmnRexX+E4QvXRAHXUslLO7mrAI=",
382 "sparseCheckout": [],
383 "type": "git",
384 "url": "https://github.com/ErikReider/SwayOSD"
385 },
386 "version": "993180b5e7db1dfc453a556bf208f05b04283c8f"
387 },
382 "tomorrow-night-paradise-theme": { 388 "tomorrow-night-paradise-theme": {
383 "cargoLocks": null, 389 "cargoLocks": null,
384 "date": "2012-06-04", 390 "date": "2012-06-04",
@@ -450,10 +456,10 @@
450 "pinned": false, 456 "pinned": false,
451 "src": { 457 "src": {
452 "name": null, 458 "name": null,
453 "sha256": "sha256-6OxRXUm7YnBJFdE6Iu5v4DpWWNZR5OZFdOOhfuAfbjs=", 459 "sha256": "sha256-HJc4JmkhrUPFaK0BrDNi+3x69Uknb77JK9cvFA2hYkA=",
454 "type": "url", 460 "type": "url",
455 "url": "https://pypi.org/packages/source/y/yt_dlp/yt_dlp-2025.1.15.tar.gz" 461 "url": "https://pypi.org/packages/source/y/yt_dlp/yt_dlp-2025.1.26.tar.gz"
456 }, 462 },
457 "version": "2025.1.15" 463 "version": "2025.1.26"
458 } 464 }
459} \ No newline at end of file 465} \ No newline at end of file
diff --git a/_sources/generated.nix b/_sources/generated.nix
index fb57de83..e25f1bda 100644
--- a/_sources/generated.nix
+++ b/_sources/generated.nix
@@ -16,14 +16,6 @@
16 }; 16 };
17 date = "2021-05-30"; 17 date = "2021-05-30";
18 }; 18 };
19 batman-adv = {
20 pname = "batman-adv";
21 version = "2024.4";
22 src = fetchTarball {
23 url = "https://downloads.open-mesh.org/batman/stable/sources/batman-adv/batman-adv-2024.4.tar.gz";
24 sha256 = "sha256-VYyIkH5IFfKN6EOHZxSx6AaepD3a22/hhmLhqkle5Z0=";
25 };
26 };
27 bpf-examples = { 19 bpf-examples = {
28 pname = "bpf-examples"; 20 pname = "bpf-examples";
29 version = "8d53e6fc46ae625bd16b38eb1007ece99460eada"; 21 version = "8d53e6fc46ae625bd16b38eb1007ece99460eada";
@@ -232,6 +224,20 @@
232 sha256 = "sha256-7d/0fepOvdswuBGJCCMULB2kXOFBLP78yqX4NmByCF8="; 224 sha256 = "sha256-7d/0fepOvdswuBGJCCMULB2kXOFBLP78yqX4NmByCF8=";
233 }; 225 };
234 }; 226 };
227 swayosd = {
228 pname = "swayosd";
229 version = "993180b5e7db1dfc453a556bf208f05b04283c8f";
230 src = fetchgit {
231 url = "https://github.com/ErikReider/SwayOSD";
232 rev = "993180b5e7db1dfc453a556bf208f05b04283c8f";
233 fetchSubmodules = false;
234 deepClone = false;
235 leaveDotGit = false;
236 sparseCheckout = [ ];
237 sha256 = "sha256-qwtGkRJlCYu+dO3xCmnRexX+E4QvXRAHXUslLO7mrAI=";
238 };
239 date = "2025-01-27";
240 };
235 tomorrow-night-paradise-theme = { 241 tomorrow-night-paradise-theme = {
236 pname = "tomorrow-night-paradise-theme"; 242 pname = "tomorrow-night-paradise-theme";
237 version = "70225a5bf90d495e13a9260bfdc268632ece0801"; 243 version = "70225a5bf90d495e13a9260bfdc268632ece0801";
@@ -272,10 +278,10 @@
272 }; 278 };
273 yt-dlp = { 279 yt-dlp = {
274 pname = "yt-dlp"; 280 pname = "yt-dlp";
275 version = "2025.1.15"; 281 version = "2025.1.26";
276 src = fetchurl { 282 src = fetchurl {
277 url = "https://pypi.org/packages/source/y/yt_dlp/yt_dlp-2025.1.15.tar.gz"; 283 url = "https://pypi.org/packages/source/y/yt_dlp/yt_dlp-2025.1.26.tar.gz";
278 sha256 = "sha256-6OxRXUm7YnBJFdE6Iu5v4DpWWNZR5OZFdOOhfuAfbjs="; 284 sha256 = "sha256-HJc4JmkhrUPFaK0BrDNi+3x69Uknb77JK9cvFA2hYkA=";
279 }; 285 };
280 }; 286 };
281} 287}
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
index 0c0872cc..58cfb425 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -80,7 +80,7 @@ let
80 ]; 80 ];
81 }; 81 };
82 82
83 lockCommand = "${config.systemd.package}/bin/systemctl --user start gtklock.service"; 83 lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service";
84in { 84in {
85 imports = with flake.nixosModules.userProfiles.${userName}; [ 85 imports = with flake.nixosModules.userProfiles.${userName}; [
86 mpv yt-dlp (args: import ./xcompose.nix (inputs // args)) 86 mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
@@ -185,7 +185,12 @@ in {
185 }; 185 };
186 }; 186 };
187 187
188 zathura.enable = true; 188 zathura = {
189 enable = true;
190 options = {
191 scroll-page-aware = true;
192 };
193 };
189 imv.enable = true; 194 imv.enable = true;
190 195
191 mpv.config = { 196 mpv.config = {
@@ -314,6 +319,7 @@ in {
314 }; 319 };
315 device_config = [ 320 device_config = [
316 { loop_file = "/nix/store/*-etc-metadata.erofs"; is_mounted = false; ignore = true; } 321 { loop_file = "/nix/store/*-etc-metadata.erofs"; is_mounted = false; ignore = true; }
322 { mount_path = "/run/nixos-etc-metadata"; ignore = true; }
317 { mount_path = "/run/nixos-etc-metadata.*"; ignore = true; } 323 { mount_path = "/run/nixos-etc-metadata.*"; ignore = true; }
318 ]; 324 ];
319 icon_names.media = ["drive-removable-media-symbolic"]; 325 icon_names.media = ["drive-removable-media-symbolic"];
@@ -353,31 +359,17 @@ in {
353 enable = true; 359 enable = true;
354 events = [ 360 events = [
355 { event = "before-sleep"; command = lockCommand; } 361 { event = "before-sleep"; command = lockCommand; }
356 # { event = "after-resume"; command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms on"; }
357 { event = "lock"; command = lockCommand; } 362 { event = "lock"; command = lockCommand; }
358 ]; 363 ];
359 timeouts = [ 364 timeouts = [
360 # { timeout = 300;
361 # command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms off";
362 # }
363 { timeout = 330; command = lockCommand; } 365 { timeout = 330; command = lockCommand; }
364 ]; 366 ];
365 extraArgs = [ 367 extraArgs = [
368 "-w"
366 "idlehint" "30" 369 "idlehint" "30"
367 ]; 370 ];
368 }; 371 };
369 poweralertd.enable = true; 372 poweralertd.enable = true;
370 avizo = {
371 enable = true;
372 settings.default = {
373 time = "1.0";
374 background = "rgba(0, 0, 0, 0.8)";
375 border-color = "rgba(0, 0, 0, 1)";
376 bar-fg-color = "rgba(160, 160, 160, 1)";
377 bar-bg-color = "rgba(32, 32, 32, 0.96)";
378 # y-offset = "0.25";
379 };
380 };
381 }; 373 };
382 374
383 home.pointerCursor = { 375 home.pointerCursor = {
@@ -499,6 +491,14 @@ in {
499 [Unit] 491 [Unit]
500 After=graphical-session.target 492 After=graphical-session.target
501 ''; 493 '';
494 "systemd/user/home-manager.service.d/before-graphical-session.conf".text = ''
495 [Unit]
496 Before=graphical-session-pre.target
497 '';
498 "pdfpc/pdfpcrc".text = ''
499 mouse 8 prev
500 mouse 9 next
501 '';
502 }; 502 };
503 503
504 xdg.dataFile = { 504 xdg.dataFile = {
@@ -616,7 +616,6 @@ in {
616 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ 616 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
617 --property 'Environment=DSCP=46' \ 617 --property 'Environment=DSCP=46' \
618 -- ${pkgs.dscp}/bin/dscp ${pkgs.google-chrome}/bin/google-chrome-stable \ 618 -- ${pkgs.dscp}/bin/dscp ${pkgs.google-chrome}/bin/google-chrome-stable \
619 --force-device-scale-factor=1.5 \
620 --class=Rainbow \ 619 --class=Rainbow \
621 --kiosk "https://web.openrainbow.com" \ 620 --kiosk "https://web.openrainbow.com" \
622 --user-data-dir=''${HOME}/.config/google-chrome-rainbow 621 --user-data-dir=''${HOME}/.config/google-chrome-rainbow
@@ -625,6 +624,9 @@ in {
625 url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg"; 624 url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg";
626 hash = "sha256-5fmo8rDqVDpzkGaPjk4Y+SsSZpAsY7VUQSFW6WdHwuU="; 625 hash = "sha256-5fmo8rDqVDpzkGaPjk4Y+SsSZpAsY7VUQSFW6WdHwuU=";
627 }; 626 };
627 settings = {
628 StartupWMClass = "Rainbow";
629 };
628 }; 630 };
629 }; 631 };
630 632
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
index 183cb322..5cee16b0 100644
--- a/accounts/gkleen@sif/emacs.el
+++ b/accounts/gkleen@sif/emacs.el
@@ -228,6 +228,7 @@ necessarily running."
228 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling)) 228 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))
229 229
230(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer) 230(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer)
231(add-hook 'server-switch-hook #'raise-frame)
231 232
232(defun move-file (new-location) 233(defun move-file (new-location)
233 "Write this file to NEW-LOCATION, and delete the old one." 234 "Write this file to NEW-LOCATION, and delete the old one."
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 2e9b6909..7e187c84 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -2,11 +2,10 @@
2let 2let
3 niri = config.programs.niri.package; 3 niri = config.programs.niri.package;
4 terminal = lib.getExe config.programs.kitty.package; 4 terminal = lib.getExe config.programs.kitty.package;
5 lightctl = lib.getExe' config.services.avizo.package "lightctl";
6 volumectl = lib.getExe' config.services.avizo.package "volumectl";
7 makoctl = lib.getExe' config.services.mako.package "makoctl"; 5 makoctl = lib.getExe' config.services.mako.package "makoctl";
8 loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; 6 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
9 systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; 7 systemctl = lib.getExe' hostConfig.systemd.package "systemctl";
8 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
10 9
11 focus_or_spawn = pkgs.writeShellApplication { 10 focus_or_spawn = pkgs.writeShellApplication {
12 name = "focus-or-spawn"; 11 name = "focus-or-spawn";
@@ -19,17 +18,21 @@ let
19 18
20 workspaces_json="$(niri msg -j workspaces)" 19 workspaces_json="$(niri msg -j workspaces)"
21 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")" 20 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")"
22 active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")" 21 # active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")"
23 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 22 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
24 if [[ $workspace_output != "$active_output" ]]; then 23 if [[ $workspace_output != "$active_output" ]]; then
25 niri msg action move-workspace-to-monitor --output "$active_output" "$workspace_name" 24 niri msg action move-workspace-to-monitor --reference "$workspace_name" "$active_output"
26 socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}' 25 # socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}'
27 niri msg action move-workspace-to-index --index 1 "$workspace_name" 26 # niri msg action move-workspace-to-index --reference "$workspace_name" 1
28 fi 27 fi
29 28
30 while IFS=$'\n' read -r window_json; do 29 while IFS=$'\n' read -r window_json; do
31 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then 30 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
32 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 31 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
32 niri msg action focus-workspace-previous
33 else
34 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
35 fi
33 exit 0 36 exit 0
34 fi 37 fi
35 done < <(niri msg -j windows | jq -c '.[]') 38 done < <(niri msg -j windows | jq -c '.[]')
@@ -75,7 +78,7 @@ let
75 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 78 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
76 ''; 79 '';
77 }; 80 };
78 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|kpxc|bmgr|edit|term$"; 81 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|eff|kpxc|bmgr|edit|term$";
79 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 82 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
80 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 83 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
81 84
@@ -90,7 +93,8 @@ let
90 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 93 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
91 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" 94 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
92 95
93 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" 96 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
97 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")"
94 [[ -n $workspace_json && $workspace_json != null ]] || exit 0 98 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
95 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 99 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
96 ''; 100 '';
@@ -122,6 +126,7 @@ in {
122 imports = [ 126 imports = [
123 ./waybar.nix 127 ./waybar.nix
124 ./mako.nix 128 ./mako.nix
129 ./swayosd.nix
125 ]; 130 ];
126 131
127 config = { 132 config = {
@@ -156,6 +161,113 @@ in {
156 ]; 161 ];
157 }; 162 };
158 163
164 systemd.user.sockets.niri-workspace-history = {
165 Socket = {
166 ListenStream = "%t/niri-workspace-history.sock";
167 SocketMode = "0600";
168 };
169 };
170 systemd.user.services.niri-workspace-history = {
171 Unit = {
172 BindsTo = [ "niri.service" ];
173 After = [ "niri.service" ];
174 };
175 Install = {
176 WantedBy = [ "niri.service" ];
177 };
178 Service = {
179 Type = "simple";
180 Sockets = [ "niri-workspace-history.socket" ];
181 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} ''
182 import os
183 import socket
184 import json
185 import sys
186 from collections import defaultdict
187 from threading import Thread, Lock
188 from socketserver import StreamRequestHandler, ThreadingTCPServer
189 from contextlib import contextmanager
190 from io import TextIOWrapper
191
192
193 @contextmanager
194 def detaching(thing):
195 try:
196 yield thing
197 finally:
198 thing.detach()
199
200
201 workspace_history = defaultdict(list)
202 history_lock = Lock()
203
204
205 def monitor_niri():
206 workspaces = list()
207
208 def focus_workspace(output, workspace):
209 global workspace_history, history_lock
210
211 with history_lock:
212 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501
213 print(json.dumps(workspace_history), file=sys.stderr)
214
215 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
216 sock.connect(os.environ["NIRI_SOCKET"])
217 sock.send(b"\"EventStream\"\n")
218 for line in sock.makefile(buffering=1, encoding='utf-8'):
219 if line_json := json.loads(line):
220 if "WorkspacesChanged" in line_json:
221 workspaces = line_json["WorkspacesChanged"]["workspaces"]
222 for ws in workspaces:
223 if ws["is_focused"]:
224 focus_workspace(ws["output"], ws["id"])
225 if "WorkspaceActivated" in line_json:
226 for ws in workspaces:
227 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
228 continue
229 focus_workspace(ws["output"], ws["id"])
230 break
231
232
233 class RequestHandler(StreamRequestHandler):
234 def handle(self):
235 global workspace_history, history_lock
236
237 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501
238 with history_lock:
239 json.dump(workspace_history, out)
240
241
242 class Server(ThreadingTCPServer):
243 def __init__(self):
244 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501
245 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
246
247
248 def run_server():
249 with Server() as server:
250 server.serve_forever()
251
252
253 niri = Thread(target=monitor_niri)
254 niri.daemon = True
255 niri.start()
256
257 server_thread = Thread(target=run_server)
258 server_thread.daemon = True
259 server_thread.start()
260
261 while True:
262 server_thread.join(timeout=0.5)
263 niri.join(timeout=0.5)
264
265 if not (niri.is_alive() and server_thread.is_alive()):
266 break
267 '';
268 };
269 };
270
159 programs.niri.settings = { 271 programs.niri.settings = {
160 prefer-no-csd = true; 272 prefer-no-csd = true;
161 screenshot-path = "${config.home.homeDirectory}/screenshots"; 273 screenshot-path = "${config.home.homeDirectory}/screenshots";
@@ -163,10 +275,15 @@ in {
163 hotkey-overlay.skip-at-startup = true; 275 hotkey-overlay.skip-at-startup = true;
164 276
165 input = { 277 input = {
166 keyboard.xkb = { 278 keyboard = {
167 layout = "us,us"; 279 repeat-delay = 300;
168 variant = "dvp,"; 280 repeat-rate = 50;
169 options = "compose:caps,grp:win_space_toggle"; 281
282 xkb = {
283 layout = "us,us";
284 variant = "dvp,";
285 options = "compose:caps,grp:win_space_toggle";
286 };
170 }; 287 };
171 288
172 workspace-auto-back-and-forth = true; 289 workspace-auto-back-and-forth = true;
@@ -202,6 +319,11 @@ in {
202 319
203 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render"; 320 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render";
204 321
322 animations = {
323 slowdown = 0.5;
324 workspace-switch = null;
325 };
326
205 layout = { 327 layout = {
206 gaps = 8; 328 gaps = 8;
207 struts = { left = 0; right = 0; top = 0; bottom = 0; }; 329 struts = { left = 0; right = 0; top = 0; bottom = 0; };
@@ -255,6 +377,7 @@ in {
255 "003" = { name = "bmgr"; open-on-output = "eDP-1"; }; 377 "003" = { name = "bmgr"; open-on-output = "eDP-1"; };
256 "004" = { name = "term"; open-on-output = "eDP-1"; }; 378 "004" = { name = "term"; open-on-output = "eDP-1"; };
257 "005" = { name = "edit"; open-on-output = "eDP-1"; }; 379 "005" = { name = "edit"; open-on-output = "eDP-1"; };
380 "006" = { name = "eff"; open-on-output = "eDP-1"; };
258 "101".name = "comm"; 381 "101".name = "comm";
259 "102".name = "web"; 382 "102".name = "web";
260 # "104".name = "read"; 383 # "104".name = "read";
@@ -264,19 +387,25 @@ in {
264 }; 387 };
265 388
266 window-rules = [ 389 window-rules = [
267 # { 390 {
268 # geometry-corner-radius = 391 matches = [ { is-floating = true; } ];
269 # let 392 geometry-corner-radius =
270 # allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; }; 393 let
271 # in allCorners 4.; 394 allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; };
272 # clip-to-geometry = true; 395 in allCorners 8.;
273 # } 396 clip-to-geometry = true;
397 }
274 { 398 {
275 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ]; 399 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ];
276 open-on-workspace = "pwctl"; 400 open-on-workspace = "pwctl";
277 open-maximized = true; 401 open-maximized = true;
278 } 402 }
279 { 403 {
404 matches = [ { app-id = "^com\.github\.wwmm\.easyeffects$"; } ];
405 open-on-workspace = "eff";
406 open-maximized = true;
407 }
408 {
280 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ]; 409 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ];
281 open-on-workspace = "bmgr"; 410 open-on-workspace = "bmgr";
282 open-maximized = true; 411 open-maximized = true;
@@ -303,6 +432,7 @@ in {
303 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; } 432 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; }
304 ]; 433 ];
305 open-focused = true; 434 open-focused = true;
435 open-floating = true;
306 } 436 }
307 { 437 {
308 matches = [ { app-id = "^kitty-scratch$"; } ]; 438 matches = [ { app-id = "^kitty-scratch$"; } ];
@@ -332,6 +462,7 @@ in {
332 matches = [ 462 matches = [
333 { app-id = "^thunderbird$"; } 463 { app-id = "^thunderbird$"; }
334 { app-id = "^Element$"; } 464 { app-id = "^Element$"; }
465 { app-id = "^Rainbow$"; }
335 ]; 466 ];
336 open-on-workspace = "comm"; 467 open-on-workspace = "comm";
337 } 468 }
@@ -380,6 +511,7 @@ in {
380 matches = [ 511 matches = [
381 { app-id = "^Gimp-"; title = "^Quit GIMP$"; } 512 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
382 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; } 513 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; }
514 { app-id = "^xdg-desktop-portal-gtk$"; }
383 ]; 515 ];
384 open-floating = true; 516 open-floating = true;
385 } 517 }
@@ -570,27 +702,27 @@ in {
570 }; 702 };
571 703
572 "XF86MonBrightnessUp" = { 704 "XF86MonBrightnessUp" = {
573 action = spawn lightctl "-d" "-e4" "-n1" "up"; 705 action = spawn swayosd-client "--brightness" "raise";
574 allow-when-locked = true; 706 allow-when-locked = true;
575 }; 707 };
576 "XF86MonBrightnessDown" = { 708 "XF86MonBrightnessDown" = {
577 action = spawn lightctl "-d" "-e4" "-n1" "down"; 709 action = spawn swayosd-client "--brightness" "lower";
578 allow-when-locked = true; 710 allow-when-locked = true;
579 }; 711 };
580 "XF86AudioRaiseVolume" = { 712 "XF86AudioRaiseVolume" = {
581 action = spawn volumectl "-d" "-u" "up"; 713 action = spawn swayosd-client "--output-volume" "raise";
582 allow-when-locked = true; 714 allow-when-locked = true;
583 }; 715 };
584 "XF86AudioLowerVolume" = { 716 "XF86AudioLowerVolume" = {
585 action = spawn volumectl "-d" "-u" "down"; 717 action = spawn swayosd-client "--output-volume" "lower";
586 allow-when-locked = true; 718 allow-when-locked = true;
587 }; 719 };
588 "XF86AudioMute" = { 720 "XF86AudioMute" = {
589 action = spawn volumectl "-d" "toggle-mute"; 721 action = spawn swayosd-client "--output-volume" "mute-toggle";
590 allow-when-locked = true; 722 allow-when-locked = true;
591 }; 723 };
592 "XF86AudioMicMute" = { 724 "XF86AudioMicMute" = {
593 action = spawn volumectl "-d" "-m" "toggle-mute"; 725 action = spawn swayosd-client "--input-volume" "mute-toggle";
594 allow-when-locked = true; 726 allow-when-locked = true;
595 }; 727 };
596 728
@@ -600,6 +732,7 @@ in {
600 "Mod+Comma".action = spawn makoctl "restore"; 732 "Mod+Comma".action = spawn makoctl "restore";
601 733
602 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol"; 734 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol";
735 "Mod+Control+O".action = focus-or-spawn-action-app_id "com.github.wwmm.easyeffects" "eff" "easyeffects";
603 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc"; 736 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc";
604 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager"; 737 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager";
605 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch"; 738 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch";
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index e06d3b3a..0a10555a 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -1,4 +1,4 @@
1{ config, lib, ... }: 1{ config, lib, pkgs, ... }:
2{ 2{
3 config = { 3 config = {
4 services.mako = { 4 services.mako = {
@@ -30,6 +30,14 @@
30 [mode=silent] 30 [mode=silent]
31 invisible=1 31 invisible=1
32 ''; 32 '';
33 package = pkgs.symlinkJoin {
34 name = "${pkgs.mako.name}-wrapped";
35 paths = with pkgs; [ mako ];
36 inherit (pkgs.mako) meta;
37 postBuild = ''
38 rm -r $out/share/dbus-1
39 '';
40 };
33 }; 41 };
34 systemd.user.services.mako = { 42 systemd.user.services.mako = {
35 Unit = { 43 Unit = {
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
new file mode 100644
index 00000000..984927c2
--- /dev/null
+++ b/accounts/gkleen@sif/niri/swayosd.nix
@@ -0,0 +1,65 @@
1{ pkgs, ... }:
2{
3 config = {
4 services.swayosd = {
5 enable = true;
6 topMargin = 0.946154;
7 stylePath = pkgs.runCommand "style.css" {
8 src = pkgs.writeText "style.scss" ''
9 window#osd {
10 padding: 12px 20px;
11 border-radius: 999px;
12 border: none;
13 background: rgba(0, 0, 0, 0.87);
14
15 #container {
16 margin: 16px;
17 }
18
19 image,
20 label {
21 color: rgb(255, 255, 255);
22
23 &:disabled {
24 opacity: 1;
25 color: rgb(84, 84, 84);
26 }
27 }
28
29 progressbar {
30 min-height: 6px;
31 border-radius: 999px;
32 background: transparent;
33 border: none;
34
35 trough, progress {
36 min-height: inherit;
37 border-radius: inherit;
38 border: none;
39 }
40
41 trough {
42 background: rgb(127, 127, 127);
43 }
44 progress {
45 background: rgb(255, 255, 255);
46 }
47
48 &:disabled {
49 opacity: 1;
50
51 trough {
52 background: rgb(19, 19, 19);
53 }
54 progress {
55 background: rgb(38, 38, 38);
56 }
57 }
58 }
59 }
60 '';
61 buildInputs = with pkgs; [sass];
62 } "scss -C --sourcemap=none --style=compact $src $out";
63 };
64 };
65}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index 79c429f8..3f1f8119 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -1,5 +1,7 @@
1{ lib, pkgs, ... }: 1{ lib, config, pkgs, ... }:
2{ 2let
3 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
4in {
3 config = { 5 config = {
4 programs.waybar = { 6 programs.waybar = {
5 enable = true; 7 enable = true;
@@ -22,7 +24,7 @@
22 output = [ "eDP-1" "DP-2" "DP-3" ]; 24 output = [ "eDP-1" "DP-2" "DP-3" ];
23 modules-left = [ "niri/workspaces" ]; 25 modules-left = [ "niri/workspaces" ];
24 modules-center = [ "niri/window" ]; 26 modules-center = [ "niri/window" ];
25 modules-right = [ # "custom/worktime" "custom/worktime-today" 27 modules-right = [ "custom/worktime" "custom/worktime-today"
26 "custom/weather" 28 "custom/weather"
27 "custom/keymap" 29 "custom/keymap"
28 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; 30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ];
@@ -59,7 +61,7 @@
59 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501 61 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501
60 if is_silent: 62 if is_silent:
61 text = f"<span color=\"#ffffff\">{text}</span>" 63 text = f"<span color=\"#ffffff\">{text}</span>"
62 print(json.dumps({'text': text}, separators=(',', ':')), flush=True) # noqa: E501 64 print(json.dumps({'text': text, 'tooltip': ', '.join(modes)}, separators=(',', ':')), flush=True) # noqa: E501
63 65
64 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501 66 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501
65 if "Modes" not in invalidated_properties: 67 if "Modes" not in invalidated_properties:
@@ -120,16 +122,16 @@
120 }; 122 };
121 "custom/worktime" = { 123 "custom/worktime" = {
122 interval = 60; 124 interval = 60;
123 exec = lib.getExe pkgs.worktime; 125 exec = "${lib.getExe pkgs.worktime} time --waybar";
124 tooltip = false; 126 return-type = "json";
125 }; 127 };
126 "custom/worktime-today" = { 128 "custom/worktime-today" = {
127 interval = 60; 129 interval = 60;
128 exec = "${lib.getExe pkgs.worktime} today"; 130 exec = "${lib.getExe pkgs.worktime} today --waybar";
129 tooltip = false; 131 return-type = "json";
130 }; 132 };
131 "niri/workspaces" = { 133 "niri/workspaces" = {
132 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"]; 134 ignore = ["eff" "pwctl" "kpxc" "bmgr" "edit" "term"];
133 }; 135 };
134 "niri/window" = { 136 "niri/window" = {
135 separate-outputs = true; 137 separate-outputs = true;
@@ -190,8 +192,8 @@
190 icon-size = iconSize; 192 icon-size = iconSize;
191 tooltip-format = "{percent}%"; 193 tooltip-format = "{percent}%";
192 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"]; 194 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"];
193 on-scroll-up = "lightctl -d -e4 -n1 up"; 195 on-scroll-up = "${swayosd-client} --brightness raise";
194 on-scroll-down = "lightctl -d -e4 -n1 down"; 196 on-scroll-down = "${swayosd-client} --brightness lower";
195 }; 197 };
196 wireplumber = { 198 wireplumber = {
197 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; 199 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
@@ -200,9 +202,9 @@
200 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"]; 202 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"];
201 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>"; 203 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>";
202 # ignored-sinks = ["Easy Effects Sink"]; 204 # ignored-sinks = ["Easy Effects Sink"];
203 on-scroll-up = "volumectl -d -u up"; 205 on-scroll-up = "${swayosd-client} --output-volume raise";
204 on-scroll-down = "volumectl -d -u down"; 206 on-scroll-down = "${swayosd-client} --output-volume lower";
205 on-click = "volumectl -d toggle-mute"; 207 on-click = "${swayosd-client} --output-volume mute-toggle";
206 }; 208 };
207 } 209 }
208 { 210 {
@@ -241,7 +243,7 @@
241 243
242 * { 244 * {
243 border: none; 245 border: none;
244 font-family: "Fira Sans Nerd Font"; 246 font-family: "Fira Sans";
245 font-size: 10pt; 247 font-size: 10pt;
246 min-height: 0; 248 min-height: 0;
247 } 249 }
@@ -252,10 +254,10 @@
252 } 254 }
253 255
254 .modules-left { 256 .modules-left {
255 margin-left: 8px; 257 margin-left: 12px;
256 } 258 }
257 .modules-right { 259 .modules-right {
258 margin-right: 8px; 260 margin-right: 12px;
259 } 261 }
260 262
261 .module { 263 .module {
@@ -280,11 +282,12 @@
280 color: @grey; 282 color: @grey;
281 margin: 0 5px; 283 margin: 0 5px;
282 } 284 }
283 #custom-weather, #custom-worktime-today { 285 #custom-weather {
284 margin-right: 3px; 286 margin-right: 3px;
285 } 287 }
286 #custom-keymap, #custom-weather { 288 #custom-keymap {
287 margin-left: 3px; 289 margin-left: 3px;
290 margin-right: 3px;
288 } 291 }
289 292
290 #tray { 293 #tray {
@@ -320,6 +323,12 @@
320 #idle_inhibitor.activated { 323 #idle_inhibitor.activated {
321 color: @white; 324 color: @white;
322 } 325 }
326 #custom-worktime.running, #custom-worktime-today.running {
327 color: @white;
328 }
329 #custom-worktime.over, #custom-worktime-today.over {
330 color: @orange;
331 }
323 332
324 #idle_inhibitor { 333 #idle_inhibitor {
325 padding-top: 1px; 334 padding-top: 1px;
@@ -327,7 +336,7 @@
327 336
328 #privacy { 337 #privacy {
329 color: @red; 338 color: @red;
330 margin: -1px 2px 0px 5px; 339 margin: -1px 4px 0px 3px;
331 } 340 }
332 #clock { 341 #clock {
333 /* margin-right: 5px; */ 342 /* margin-right: 5px; */
diff --git a/accounts/gkleen@sif/systemd.nix b/accounts/gkleen@sif/systemd.nix
index d3a1a4c7..a89b46c2 100644
--- a/accounts/gkleen@sif/systemd.nix
+++ b/accounts/gkleen@sif/systemd.nix
@@ -344,6 +344,9 @@ in {
344 Unit = { 344 Unit = {
345 PartOf = lib.mkForce ["tray.target"]; 345 PartOf = lib.mkForce ["tray.target"];
346 }; 346 };
347 Install = {
348 WantedBy = lib.mkForce ["tray.target"];
349 };
347 }; 350 };
348 } // listToAttrs (map ({host, port}: nameValuePair "proxy-to-autossh-socks@${toString port}" { 351 } // listToAttrs (map ({host, port}: nameValuePair "proxy-to-autossh-socks@${toString port}" {
349 Unit = { 352 Unit = {
diff --git a/flake.lock b/flake.lock
index 1697d69e..876ebecf 100644
--- a/flake.lock
+++ b/flake.lock
@@ -322,11 +322,11 @@
322 ] 322 ]
323 }, 323 },
324 "locked": { 324 "locked": {
325 "lastModified": 1736014120, 325 "lastModified": 1737831749,
326 "narHash": "sha256-ZrI+mcuQfal5IfT4HsxVEiiFNAgV4qYh+B4/NyXxpAs=", 326 "narHash": "sha256-La1xZYZ1yHvT4h5MNl5WC2wxBi2P4vozce2n7V/9+2w=",
327 "owner": "gkleen", 327 "owner": "gkleen",
328 "repo": "home-manager", 328 "repo": "home-manager",
329 "rev": "99e8412a18eb7e0731aa2b77abeed00d6d1863ad", 329 "rev": "8b16ee252e38acc29ba634ab60672a051ebc9f59",
330 "type": "github" 330 "type": "github"
331 }, 331 },
332 "original": { 332 "original": {
@@ -359,11 +359,11 @@
359 }, 359 },
360 "impermanence": { 360 "impermanence": {
361 "locked": { 361 "locked": {
362 "lastModified": 1736688610, 362 "lastModified": 1737831083,
363 "narHash": "sha256-1Zl9xahw399UiZSJ9Vxs1W4WRFjO1SsNdVZQD4nghz0=", 363 "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
364 "owner": "nix-community", 364 "owner": "nix-community",
365 "repo": "impermanence", 365 "repo": "impermanence",
366 "rev": "c64bed13b562fc3bb454b48773d4155023ac31b7", 366 "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
367 "type": "github" 367 "type": "github"
368 }, 368 },
369 "original": { 369 "original": {
@@ -397,11 +397,11 @@
397 "xwayland-satellite-unstable": "xwayland-satellite-unstable" 397 "xwayland-satellite-unstable": "xwayland-satellite-unstable"
398 }, 398 },
399 "locked": { 399 "locked": {
400 "lastModified": 1737627930, 400 "lastModified": 1737961005,
401 "narHash": "sha256-oaAatwNVaX36xmI2AKIVu2oG07XJmHq2T+Y66hEprd8=", 401 "narHash": "sha256-b4hqJNgyx8lnngz7NFcJ1W+59xQnMQYF0EK5g0IOy7c=",
402 "owner": "sodiboo", 402 "owner": "sodiboo",
403 "repo": "niri-flake", 403 "repo": "niri-flake",
404 "rev": "f79aa307f4bc0bfbabee404e6354fd2a1edfcb01", 404 "rev": "e98ae62893568dd31e7a7e4e75e1dbbf23f759a0",
405 "type": "github" 405 "type": "github"
406 }, 406 },
407 "original": { 407 "original": {
@@ -431,11 +431,11 @@
431 "niri-unstable": { 431 "niri-unstable": {
432 "flake": false, 432 "flake": false,
433 "locked": { 433 "locked": {
434 "lastModified": 1736861309, 434 "lastModified": 1737795105,
435 "narHash": "sha256-RSCoXyngYF+7apD5pRq6lZfRbl8vHIUVI57bbihA5Ew=", 435 "narHash": "sha256-OsrjQ8O9t9NjDCwfG/EY8MT+K3lb+A5U6SZZ+4PyKzk=",
436 "owner": "gkleen", 436 "owner": "gkleen",
437 "repo": "niri", 437 "repo": "niri",
438 "rev": "80a7ee2971b2d43622f68dcdc3233ae8365338f6", 438 "rev": "78697d1cea20e6b53013e820999b0403c45d9f00",
439 "type": "github" 439 "type": "github"
440 }, 440 },
441 "original": { 441 "original": {
@@ -472,11 +472,11 @@
472 ] 472 ]
473 }, 473 },
474 "locked": { 474 "locked": {
475 "lastModified": 1736652904, 475 "lastModified": 1737861961,
476 "narHash": "sha256-8uolHABgroXqzs03QdulHp8H9e5kWQZnnhcda1MKbBM=", 476 "narHash": "sha256-LIRtMvAwLGb8pBoamzgEF67oKlNPz4LuXiRPVZf+TpE=",
477 "owner": "Mic92", 477 "owner": "Mic92",
478 "repo": "nix-index-database", 478 "repo": "nix-index-database",
479 "rev": "271e5bd7c57e1f001693799518b10a02d1123b12", 479 "rev": "79b7b8eae3243fc5aa9aad34ba6b9bbb2266f523",
480 "type": "github" 480 "type": "github"
481 }, 481 },
482 "original": { 482 "original": {
@@ -508,11 +508,11 @@
508 }, 508 },
509 "nixos-hardware": { 509 "nixos-hardware": {
510 "locked": { 510 "locked": {
511 "lastModified": 1736441705, 511 "lastModified": 1737751639,
512 "narHash": "sha256-OL7leZ6KBhcDF3nEKe4aZVfIm6xQpb1Kb+mxySIP93o=", 512 "narHash": "sha256-ZEbOJ9iT72iwqXsiEMbEa8wWjyFvRA9Ugx8utmYbpz4=",
513 "owner": "NixOS", 513 "owner": "NixOS",
514 "repo": "nixos-hardware", 514 "repo": "nixos-hardware",
515 "rev": "8870dcaff63dfc6647fb10648b827e9d40b0a337", 515 "rev": "dfad538f751a5aa5d4436d9781ab27a6128ec9d4",
516 "type": "github" 516 "type": "github"
517 }, 517 },
518 "original": { 518 "original": {
@@ -630,11 +630,11 @@
630 }, 630 },
631 "nixpkgs-stable_2": { 631 "nixpkgs-stable_2": {
632 "locked": { 632 "locked": {
633 "lastModified": 1737569578, 633 "lastModified": 1737885640,
634 "narHash": "sha256-6qY0pk2QmUtBT9Mywdvif0i/CLVgpCjMUn6g9vB+f3M=", 634 "narHash": "sha256-GFzPxJzTd1rPIVD4IW+GwJlyGwBDV1Tj5FLYwDQQ9sM=",
635 "owner": "NixOS", 635 "owner": "NixOS",
636 "repo": "nixpkgs", 636 "repo": "nixpkgs",
637 "rev": "47addd76727f42d351590c905d9d1905ca895b82", 637 "rev": "4e96537f163fad24ed9eb317798a79afc85b51b7",
638 "type": "github" 638 "type": "github"
639 }, 639 },
640 "original": { 640 "original": {
@@ -678,11 +678,11 @@
678 }, 678 },
679 "nixpkgs_2": { 679 "nixpkgs_2": {
680 "locked": { 680 "locked": {
681 "lastModified": 1736798957, 681 "lastModified": 1737885589,
682 "narHash": "sha256-qwpCtZhSsSNQtK4xYGzMiyEDhkNzOCz/Vfu4oL2ETsQ=", 682 "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=",
683 "owner": "NixOS", 683 "owner": "NixOS",
684 "repo": "nixpkgs", 684 "repo": "nixpkgs",
685 "rev": "9abb87b552b7f55ac8916b6fc9e5cb486656a2f3", 685 "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8",
686 "type": "github" 686 "type": "github"
687 }, 687 },
688 "original": { 688 "original": {
@@ -748,11 +748,11 @@
748 "treefmt-nix": "treefmt-nix" 748 "treefmt-nix": "treefmt-nix"
749 }, 749 },
750 "locked": { 750 "locked": {
751 "lastModified": 1736774291, 751 "lastModified": 1736884309,
752 "narHash": "sha256-1rEUm7R93L8rltgyBzon2/lzIN2udC/Kd8nyvuDN6ps=", 752 "narHash": "sha256-eiCqmKl0BIRiYk5/ZhZozwn4/7Km9CWTbc15Cv+VX5k=",
753 "owner": "nix-community", 753 "owner": "nix-community",
754 "repo": "poetry2nix", 754 "repo": "poetry2nix",
755 "rev": "499221030113adc5dea05886a1d7aa1cc3a315d1", 755 "rev": "75d0515332b7ca269f6d7abfd2c44c47a7cbca7b",
756 "type": "github" 756 "type": "github"
757 }, 757 },
758 "original": { 758 "original": {
@@ -891,11 +891,11 @@
891 ] 891 ]
892 }, 892 },
893 "locked": { 893 "locked": {
894 "lastModified": 1736808430, 894 "lastModified": 1737411508,
895 "narHash": "sha256-wlgdf/n7bJMLBheqt1jmPoxJFrUP6FByKQFXuM9YvIk=", 895 "narHash": "sha256-j9IdflJwRtqo9WpM0OfAZml47eBblUHGNQTe62OUqTw=",
896 "owner": "Mic92", 896 "owner": "Mic92",
897 "repo": "sops-nix", 897 "repo": "sops-nix",
898 "rev": "553c7cb22fed19fd60eb310423fdc93045c51ba8", 898 "rev": "015d461c16678fc02a2f405eb453abb509d4e1d4",
899 "type": "github" 899 "type": "github"
900 }, 900 },
901 "original": { 901 "original": {
@@ -1000,11 +1000,11 @@
1000 "xwayland-satellite-unstable": { 1000 "xwayland-satellite-unstable": {
1001 "flake": false, 1001 "flake": false,
1002 "locked": { 1002 "locked": {
1003 "lastModified": 1736487362, 1003 "lastModified": 1737837494,
1004 "narHash": "sha256-4kGoOA7FgK9N2mzS+TFEn41kUUNY6KwdiA/0rqlr868=", 1004 "narHash": "sha256-wIMowP8Juas4ZwMRcpc+58sZ0kKTDu8fm13THPmv/F8=",
1005 "owner": "Supreeeme", 1005 "owner": "Supreeeme",
1006 "repo": "xwayland-satellite", 1006 "repo": "xwayland-satellite",
1007 "rev": "8f55e27f63a749881c4bbfbb6b1da028342a91d1", 1007 "rev": "3944c9a0e40e5629f16ad023bbc90dac80d35a0f",
1008 "type": "github" 1008 "type": "github"
1009 }, 1009 },
1010 "original": { 1010 "original": {
diff --git a/hosts/sif/default.nix b/hosts/sif/default.nix
index 9de16de3..32651e14 100644
--- a/hosts/sif/default.nix
+++ b/hosts/sif/default.nix
@@ -470,16 +470,16 @@ in {
470 exportConfiguration = true; 470 exportConfiguration = true;
471 }; 471 };
472 libinput.enable = true; 472 libinput.enable = true;
473 };
474 473
475 programs.niri.enable = true; 474 envfs.enable = false;
475 };
476 476
477 systemd.tmpfiles.settings = { 477 systemd.tmpfiles.settings = {
478 "10-localtime"."/etc/localtime".L.argument = "/.bcachefs/etc/localtime"; 478 "10-localtime"."/etc/localtime".L.argument = "/.bcachefs/etc/localtime";
479 479
480 "10-regreet"."/var/cache/regreet/cache.toml".C.argument = toString ((pkgs.formats.toml {}).generate "cache.toml" { 480 "10-regreet"."/var/cache/regreet/cache.toml".C.argument = toString ((pkgs.formats.toml {}).generate "cache.toml" {
481 last_user = "gkleen"; 481 last_user = "gkleen";
482 user_to_last_sess.gkleen = "Niri"; 482 user_to_last_sess.gkleen = "niri";
483 }); 483 });
484 }; 484 };
485 485
@@ -589,7 +589,7 @@ in {
589 }; 589 };
590 590
591 nvidia = { 591 nvidia = {
592 open = true; 592 open = false;
593 modesetting.enable = true; 593 modesetting.enable = true;
594 powerManagement.enable = true; 594 powerManagement.enable = true;
595 # prime = { 595 # prime = {
@@ -680,6 +680,8 @@ in {
680 light.enable = true; 680 light.enable = true;
681 wireshark.enable = true; 681 wireshark.enable = true;
682 dconf.enable = true; 682 dconf.enable = true;
683 niri.enable = true;
684 fuse.userAllowOther = true;
683 }; 685 };
684 686
685 services.pcscd.enable = true; 687 services.pcscd.enable = true;
@@ -716,11 +718,11 @@ in {
716 directories = [ 718 directories = [
717 "/nix" 719 "/nix"
718 "/root" 720 "/root"
721 "/home"
719 "/var/log" 722 "/var/log"
720 "/var/lib/sops-nix" 723 "/var/lib/sops-nix"
721 "/var/lib/nixos" 724 "/var/lib/nixos"
722 "/var/lib/systemd" 725 "/var/lib/systemd"
723 "/home"
724 "/var/lib/chrony" 726 "/var/lib/chrony"
725 "/var/lib/fprint" 727 "/var/lib/fprint"
726 "/var/lib/bluetooth" 728 "/var/lib/bluetooth"
diff --git a/hosts/sif/greetd/wallpaper.png b/hosts/sif/greetd/wallpaper.png
index f6f6c818..20fc761a 100644
--- a/hosts/sif/greetd/wallpaper.png
+++ b/hosts/sif/greetd/wallpaper.png
Binary files differ
diff --git a/modules/nix-access-tokens/default.nix b/modules/nix-access-tokens/default.nix
new file mode 100644
index 00000000..a3b7abfa
--- /dev/null
+++ b/modules/nix-access-tokens/default.nix
@@ -0,0 +1,24 @@
1{ lib, config, hostName ,... }:
2
3let
4 cfg = config.nix.includeAccessTokens;
5in {
6 options = {
7 nix.includeAccessTokens.enable = lib.mkEnableOption "including access tokens in nix.conf" // { default = lib.elem hostName ["sif" "surtr" "vidhar"]; };
8 };
9
10 config = lib.mkIf cfg.enable {
11 nix = {
12 extraOptions = ''
13 !include ${config.sops.secrets.nixAccessTokens.path}
14 '';
15 };
16
17 sops.secrets.nixAccessTokens = {
18 format = "binary";
19 sopsFile = ./nix.conf;
20 mode = "0440";
21 group = "wheel";
22 };
23 };
24}
diff --git a/modules/nix-access-tokens/nix.conf b/modules/nix-access-tokens/nix.conf
new file mode 100644
index 00000000..f0b394ef
--- /dev/null
+++ b/modules/nix-access-tokens/nix.conf
@@ -0,0 +1,32 @@
1{
2 "data": "ENC[AES256_GCM,data:/cdBpvCAFpgm0YWhy1WYlA09KlU6PzVfBYVLBD0boqGqvP+8wuyDzj5KWbcKsdGhoiklODiKR0ODXNU+fA35y862PFXvSb4xVyfbdKRndYdIA4W6vyobtoC9h7B1yR9pkq9L+1tqlU30Dgy2Gndg9rWHlIo+1lO/1A==,iv:B1Px2+cxCaopHZThkEG5saOib+PNvurPIS6aeAv2uPo=,tag:K3JqRaX3/iIqD3c//YdqSQ==,type:str]",
3 "sops": {
4 "kms": null,
5 "gcp_kms": null,
6 "azure_kv": null,
7 "hc_vault": null,
8 "age": [
9 {
10 "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866",
11 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5NkZUUGI3M2pQYWVXeFV6\na2h2czRTeUJFekJCS012YlBkL1FDdTd3ekZ3ClJsTVh0R2JQM0Jua1JjL285RVA1\nRHhlbjlLdmNBUXVLelFGY2NGYWpLejQKLS0tIDBUWUhJNm8zWGoyQ0pBYnV1ZjBh\ndktNRkNPS1lpWXFITC81aEZJbXlONk0Km2c1xVKwSankaVs7O/utGJwRRX395upz\ndPbsOElTnbGmkb0esGtvGSPboTvK+gjn9w/GhaPyTnNDoos7GaIfyg==\n-----END AGE ENCRYPTED FILE-----\n"
12 },
13 {
14 "recipient": "age1fj65apkhfkrwyv5tx6zcs9nkjg8267fy733qph30sc7zfn7vapjqkd5kne",
15 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bS9iY2lua3U4U3lJa1pK\nSlZNMmFZMEU5M1V2bWRjaXIwajZJVDJPMlM4Cmd3TTNFWjVuSGdtbC9iODltTS91\nOE5XOEVEQkh0SFpVVW5jc3IzbzNpTmMKLS0tIEtrSU54QUVPa2tBZDhLYlRFWitR\nc2x6MFlxL0tobDJTek42dEcyZXpoWDgKXzQfU+o6FkbJBwmm6oaHu4sDPi822uUR\n5VY6gY/h3g2kM4cuS03Q4NJmeRxuh7cx0UqGU3j5Mf8muE1LHpYEPw==\n-----END AGE ENCRYPTED FILE-----\n"
16 },
17 {
18 "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq",
19 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaOVpNZ2lVT0VwbHVZNzFl\nenJsMGpnbkRvU0xOSU5obk5yT2p5ZVNzdXhNCnVlQzZtRjZNVmJLSUpKc3UwVXZs\nWi9EZ3kxZkJNeFJDSjl1L1IweTFNMXcKLS0tIDJUOTBwTldCUmlnU0tWVkZkNzJL\nejM4ajJVbVhvSm1YM2Vxa2JldllYN0UKAzxy2wkzRvCSiTy417AulpCu41z668HG\nto92eGF2ZRFfEG5LGlCKWeDcP3gM8QwKiVlm6wndbOkhMMfc4Sp3wA==\n-----END AGE ENCRYPTED FILE-----\n"
20 },
21 {
22 "recipient": "age1qffdqvy9arld9zd5a5cylt0n98xhcns5shxhrhwjq5g4qa844ejselaa4l",
23 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2ejRHcGttNUxYZnFzTU5J\nMTFvY3daQ1VMM2xxYTgvLzZwT1owazVNenhzCktaWFF6K2s5UjI2b20rSHFNSS9E\nMVlJSmZhQm15eUs3U0hGTGpSRndmSDgKLS0tIDVrcjl4eDhwak1pRithbnRWWEZy\nVE9EOEpKdEJoRTFrTXpQVDc1cmsrU1kK/goTdUmpZPeMRbY1QzLXAa6Qpg4YYYYo\n3v3GK1bzdey8szfgIr1dHTtQEzqE2WX1swzZizDXj/RiUWx01Ky3GA==\n-----END AGE ENCRYPTED FILE-----\n"
24 }
25 ],
26 "lastmodified": "2025-01-25T19:58:58Z",
27 "mac": "ENC[AES256_GCM,data:Oza4XgnTX3vly89nGluLbEytk1dUYAiOhIYewQyDLLLSSlUIpXmWhV+X0HUQ9AX5kUrEhNbVzRdvUG/9YwoWjTJfvd7tw41IYeTqgykMNXJUfGssoutXfeij9YR+t5aJaRhlTkIWcBhUjXSUNyJCl6Z3XmzWstTPZXEU9VmAvuE=,iv:LqVwIiit+WqI5NWSboexWsmPzg7e63nWJYsNFEK1Uog=,tag:ClR6oI62WXEfIYYAY6vL0A==,type:str]",
28 "pgp": null,
29 "unencrypted_suffix": "_unencrypted",
30 "version": "3.9.3"
31 }
32} \ No newline at end of file
diff --git a/nvfetcher.toml b/nvfetcher.toml
index d33040c5..ecaebba0 100644
--- a/nvfetcher.toml
+++ b/nvfetcher.toml
@@ -78,12 +78,12 @@ git.fetchSubmodules = true
78src.git = "https://github.com/jgreco/mpv-youtube-quality" 78src.git = "https://github.com/jgreco/mpv-youtube-quality"
79fetch.git = "https://github.com/jgreco/mpv-youtube-quality" 79fetch.git = "https://github.com/jgreco/mpv-youtube-quality"
80 80
81[batman-adv] 81# [batman-adv]
82src.webpage = "https://www.open-mesh.org/projects/open-mesh/wiki/Download" 82# src.webpage = "https://www.open-mesh.org/projects/open-mesh/wiki/Download"
83src.regex = "The latest version of <a[^\\>]*>batman-adv</a> is <a[^\\>]*>batman-adv-([0-9\\.]+).tar.gz</a>" 83# src.regex = "The latest version of <a[^\\>]*>batman-adv</a> is <a[^\\>]*>batman-adv-([0-9\\.]+).tar.gz</a>"
84src.from_pattern = "^.*batman-adv-([0-9\\.]+).tar.gz.*$" 84# src.from_pattern = "^.*batman-adv-([0-9\\.]+).tar.gz.*$"
85src.to_pattern = "\\1" 85# src.to_pattern = "\\1"
86fetch.tarball = "https://downloads.open-mesh.org/batman/stable/sources/batman-adv/batman-adv-$ver.tar.gz" 86# fetch.tarball = "https://downloads.open-mesh.org/batman/stable/sources/batman-adv/batman-adv-$ver.tar.gz"
87 87
88[scutiger] 88[scutiger]
89src.github_tag = "bk2204/scutiger" 89src.github_tag = "bk2204/scutiger"
@@ -110,4 +110,8 @@ fetch.pypi = "yt_dlp"
110 110
111[mako] 111[mako]
112src.git = "https://github.com/emersion/mako" 112src.git = "https://github.com/emersion/mako"
113fetch.git = "https://github.com/emersion/mako" \ No newline at end of file 113fetch.git = "https://github.com/emersion/mako"
114
115[swayosd]
116src.git = "https://github.com/ErikReider/SwayOSD"
117fetch.git = "https://github.com/ErikReider/SwayOSD"
diff --git a/overlays/batman-adv.nix b/overlays/batman-adv.nix
deleted file mode 100644
index cce7dc4f..00000000
--- a/overlays/batman-adv.nix
+++ /dev/null
@@ -1,15 +0,0 @@
1{ final, prev, sources, ... }: {
2 linuxPackages_latest = prev.linuxPackages_latest.extend (self: super: {
3 batman_adv = super.batman_adv.overrideAttrs (oldAttrs: {
4 version = "${sources.batman-adv.version}-${self.kernel.version}";
5 inherit (sources.batman-adv) src;
6 });
7 });
8
9 linuxPackages_6_2 = prev.linuxPackages_6_2.extend (self: super: {
10 batman_adv = super.batman_adv.overrideAttrs (oldAttrs: {
11 version = "${sources.batman-adv.version}-${self.kernel.version}";
12 inherit (sources.batman-adv) src;
13 });
14 });
15}
diff --git a/overlays/keepassxc/database-open-dialog.patch b/overlays/keepassxc/database-open-dialog.patch
new file mode 100644
index 00000000..4916dc1b
--- /dev/null
+++ b/overlays/keepassxc/database-open-dialog.patch
@@ -0,0 +1,126 @@
1diff -u3 -r source.orig/src/browser/BrowserService.cpp source/src/browser/BrowserService.cpp
2--- source.orig/src/browser/BrowserService.cpp 2025-01-27 20:55:04.128198171 +0100
3+++ source/src/browser/BrowserService.cpp 2025-01-27 21:16:07.068959077 +0100
4@@ -249,7 +249,7 @@
5 return result;
6 }
7
8- auto dialogResult = MessageBox::warning(m_currentDatabaseWidget,
9+ auto dialogResult = MessageBox::warning(nullptr,
10 tr("KeePassXC - Create a new group"),
11 tr("A request for creating a new group \"%1\" has been received.\n"
12 "Do you want to create this group?\n")
13@@ -422,7 +422,7 @@
14
15 m_dialogActive = true;
16 updateWindowState();
17- BrowserAccessControlDialog accessControlDialog(m_currentDatabaseWidget);
18+ BrowserAccessControlDialog accessControlDialog{};
19
20 connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &accessControlDialog, SLOT(reject()));
21
22@@ -512,7 +512,7 @@
23 QString id;
24
25 do {
26- QInputDialog keyDialog(m_currentDatabaseWidget);
27+ QInputDialog keyDialog{};
28 connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &keyDialog, SLOT(reject()));
29 keyDialog.setWindowTitle(tr("KeePassXC - New key association request"));
30 keyDialog.setLabelText(tr("You have received an association request for the following database:\n%1\n\n"
31@@ -535,7 +535,7 @@
32
33 contains = db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + id);
34 if (contains) {
35- dialogResult = MessageBox::warning(m_currentDatabaseWidget,
36+ dialogResult = MessageBox::warning(nullptr,
37 tr("KeePassXC - Overwrite existing key?"),
38 tr("A shared encryption key with the name \"%1\" "
39 "already exists.\nDo you want to overwrite it?")
40@@ -595,7 +595,7 @@
41 const auto existingEntries = getPasskeyEntriesWithUserHandle(rpId, userId, keyList);
42
43 raiseWindow();
44- BrowserPasskeysConfirmationDialog confirmDialog(m_currentDatabaseWidget);
45+ BrowserPasskeysConfirmationDialog confirmDialog{};
46 confirmDialog.registerCredential(username, rpId, existingEntries, timeout);
47
48 auto dialogResult = confirmDialog.exec();
49@@ -612,7 +612,7 @@
50 // If no entry is selected, show the import dialog for manual entry selection
51 auto selectedEntry = confirmDialog.getSelectedEntry();
52 if (!selectedEntry) {
53- PasskeyImporter passkeyImporter(m_currentDatabaseWidget);
54+ PasskeyImporter passkeyImporter{};
55 const auto result = passkeyImporter.showImportDialog(db,
56 nullptr,
57 origin,
58@@ -683,7 +683,7 @@
59 const auto timeout = publicKeyOptions["timeout"].toInt();
60
61 raiseWindow();
62- BrowserPasskeysConfirmationDialog confirmDialog(m_currentDatabaseWidget);
63+ BrowserPasskeysConfirmationDialog confirmDialog{};
64 confirmDialog.authenticateCredential(entries, rpId, timeout);
65 auto dialogResult = confirmDialog.exec();
66 if (dialogResult == QDialog::Accepted) {
67@@ -760,7 +760,7 @@
68
69 // Ask confirmation if entry already contains a Passkey
70 if (entry->hasPasskey()) {
71- if (MessageBox::question(m_currentDatabaseWidget,
72+ if (MessageBox::question(nullptr,
73 tr("KeePassXC - Update passkey"),
74 tr("Entry already has a passkey.\nDo you want to overwrite the passkey in %1 - %2?")
75 .arg(entry->title(), passkeyUtils()->getUsernameFromEntry(entry)),
76@@ -873,7 +873,7 @@
77 MessageBox::Button dialogResult = MessageBox::No;
78 if (!browserSettings()->alwaysAllowUpdate()) {
79 raiseWindow();
80- dialogResult = MessageBox::question(m_currentDatabaseWidget,
81+ dialogResult = MessageBox::question(nullptr,
82 tr("KeePassXC - Update Entry"),
83 tr("Do you want to update the information in %1 - %2?")
84 .arg(QUrl(entryParameters.siteUrl).host(), username),
85@@ -909,7 +909,7 @@
86 return false;
87 }
88
89- auto dialogResult = MessageBox::warning(m_currentDatabaseWidget,
90+ auto dialogResult = MessageBox::warning(nullptr,
91 tr("KeePassXC - Delete entry"),
92 tr("A request for deleting entry \"%1\" has been received.\n"
93 "Do you want to delete the entry?\n")
94@@ -1536,7 +1536,7 @@
95 }
96 }
97
98- BrowserEntrySaveDialog browserEntrySaveDialog(m_currentDatabaseWidget);
99+ BrowserEntrySaveDialog browserEntrySaveDialog{};
100 int openDatabaseCount = browserEntrySaveDialog.setItems(databaseWidgets, m_currentDatabaseWidget);
101 if (openDatabaseCount > 1) {
102 int res = browserEntrySaveDialog.exec();
103diff -u3 -r source.orig/src/fdosecrets/objects/Prompt.cpp source/src/fdosecrets/objects/Prompt.cpp
104--- source.orig/src/fdosecrets/objects/Prompt.cpp 2025-01-27 20:55:04.135942791 +0100
105+++ source/src/fdosecrets/objects/Prompt.cpp 2025-01-27 21:01:37.166710935 +0100
106@@ -313,7 +313,7 @@
107 if (!entries.isEmpty()) {
108 QString app = tr("%1 (PID: %2)").arg(client->name()).arg(client->pid());
109 auto ac = new AccessControlDialog(
110- findWindow(m_windowId), entries, app, client->processInfo(), AuthOption::Remember);
111+ nullptr, entries, app, client->processInfo(), AuthOption::Remember);
112 connect(ac, &AccessControlDialog::finished, this, &UnlockPrompt::itemUnlockFinished);
113 connect(ac, &AccessControlDialog::finished, ac, &AccessControlDialog::deleteLater);
114 ac->open();
115diff -u3 -r source.orig/src/gui/DatabaseTabWidget.cpp source/src/gui/DatabaseTabWidget.cpp
116--- source.orig/src/gui/DatabaseTabWidget.cpp 2025-01-27 20:55:04.134589500 +0100
117+++ source/src/gui/DatabaseTabWidget.cpp 2025-01-27 21:07:09.785284837 +0100
118@@ -41,7 +41,7 @@
119 : QTabWidget(parent)
120 , m_dbWidgetStateSync(new DatabaseWidgetStateSync(this))
121 , m_dbWidgetPendingLock(nullptr)
122- , m_databaseOpenDialog(new DatabaseOpenDialog(this))
123+ , m_databaseOpenDialog(new DatabaseOpenDialog())
124 , m_databaseOpenInProgress(false)
125 {
126 auto* tabBar = new QTabBar(this);
diff --git a/overlays/keepassxc/default.nix b/overlays/keepassxc/default.nix
new file mode 100644
index 00000000..25429a66
--- /dev/null
+++ b/overlays/keepassxc/default.nix
@@ -0,0 +1,8 @@
1{ final, prev, ... }:
2{
3 keepassxc = prev.keepassxc.overrideAttrs (oldAttrs: {
4 patches = (oldAttrs.patches or []) ++ [
5 ./database-open-dialog.patch
6 ];
7 });
8}
diff --git a/overlays/swayosd/default.nix b/overlays/swayosd/default.nix
new file mode 100644
index 00000000..28c8f1b9
--- /dev/null
+++ b/overlays/swayosd/default.nix
@@ -0,0 +1,30 @@
1{ final, prev, sources, ... }: {
2 swayosd = prev.swayosd.overrideAttrs (oldAttrs: rec {
3 inherit (sources.swayosd) version src;
4 cargoDeps = prev.rustPlatform.fetchCargoTarball {
5 inherit (oldAttrs) pname;
6 inherit version src;
7 hash = "sha256-Anrk8p76HKZcNavYdi9l1oYahduLrb7Lf7knQK7Hy5E=";
8 };
9 nativeBuildInputs = with final; [
10 wrapGAppsHook4
11 pkg-config
12 meson
13 rustc
14 cargo
15 ninja
16 rustPlatform.cargoSetupHook
17 ];
18 buildInputs = with final; [
19 gtk4-layer-shell
20 libevdev
21 libinput
22 libpulseaudio
23 udev
24 sassc
25 ];
26 patches = (oldAttrs.patches or []) ++ [
27 ./exponential.patch
28 ];
29 });
30}
diff --git a/overlays/swayosd/exponential.patch b/overlays/swayosd/exponential.patch
new file mode 100644
index 00000000..eb90d739
--- /dev/null
+++ b/overlays/swayosd/exponential.patch
@@ -0,0 +1,57 @@
1diff --git a/src/brightness_backend/brightnessctl.rs b/src/brightness_backend/brightnessctl.rs
2index ccb0e11..740fdb6 100644
3--- a/src/brightness_backend/brightnessctl.rs
4+++ b/src/brightness_backend/brightnessctl.rs
5@@ -107,10 +107,21 @@ impl VirtualDevice {
6 }
7 }
8
9- fn set_percent(&mut self, mut val: u32) -> anyhow::Result<()> {
10- val = val.clamp(0, 100);
11- self.current = self.max.map(|max| val * max / 100);
12- let _: String = self.run(("set", &*format!("{val}%")))?;
13+ fn val_to_percent(&mut self, val: u32) -> u32 {
14+ return ((val as f64 / self.get_max() as f64).powf(0.25) * 100_f64).round() as u32;
15+ }
16+ fn percent_to_val(&mut self, perc: u32) -> u32 {
17+ return ((perc as f64 / 100_f64).powf(4_f64) * self.get_max() as f64).round() as u32;
18+ }
19+
20+ fn set_percent(&mut self, val: u32) -> anyhow::Result<()> {
21+ let new = self.percent_to_val(val);
22+ self.set_val(new)
23+ }
24+ fn set_val(&mut self, val: u32) -> anyhow::Result<()> {
25+ let curr = val.clamp(0, self.get_max());
26+ self.current = Some(curr);
27+ let _: String = self.run(("set", &*format!("{curr}")))?;
28 Ok(())
29 }
30 }
31@@ -134,20 +145,18 @@ impl BrightnessBackend for BrightnessCtl {
32
33 fn lower(&mut self, by: u32) -> anyhow::Result<()> {
34 let curr = self.get_current();
35- let max = self.get_max();
36-
37- let curr = curr * 100 / max;
38+ let mut new = self.device.val_to_percent(curr).saturating_sub(by);
39+ new = self.device.percent_to_val(new).min(curr.saturating_sub(1));
40
41- self.device.set_percent(curr.saturating_sub(by))
42+ self.device.set_val(new)
43 }
44
45 fn raise(&mut self, by: u32) -> anyhow::Result<()> {
46 let curr = self.get_current();
47- let max = self.get_max();
48-
49- let curr = curr * 100 / max;
50+ let mut new = self.device.val_to_percent(curr) + by;
51+ new = self.device.percent_to_val(new).max(curr + 1);
52
53- self.device.set_percent(curr + by)
54+ self.device.set_val(new)
55 }
56
57 fn set(&mut self, val: u32) -> anyhow::Result<()> {
diff --git a/overlays/worktime/worktime/__main__.py b/overlays/worktime/worktime/__main__.py
index 362c8da4..ba6c5ff6 100755
--- a/overlays/worktime/worktime/__main__.py
+++ b/overlays/worktime/worktime/__main__.py
@@ -23,7 +23,7 @@ import argparse
23from copy import deepcopy 23from copy import deepcopy
24 24
25import sys 25import sys
26from sys import stderr 26from sys import stderr, stdout
27 27
28from tabulate import tabulate 28from tabulate import tabulate
29 29
@@ -38,6 +38,7 @@ from collections import defaultdict
38 38
39import jsonpickle 39import jsonpickle
40from hashlib import blake2s 40from hashlib import blake2s
41import json
41 42
42class TogglAPISection(Enum): 43class TogglAPISection(Enum):
43 TOGGL = '/api/v9' 44 TOGGL = '/api/v9'
@@ -223,6 +224,7 @@ class Worktime(object):
223 leave_budget = dict() 224 leave_budget = dict()
224 time_per_day = None 225 time_per_day = None
225 workdays = None 226 workdays = None
227 pull_forward = dict()
226 228
227 @staticmethod 229 @staticmethod
228 @cache 230 @cache
@@ -390,8 +392,6 @@ class Worktime(object):
390 if e.errno != 2: 392 if e.errno != 2:
391 raise e 393 raise e
392 394
393 pull_forward = dict()
394
395 start_day = self.start_date.date() 395 start_day = self.start_date.date()
396 end_day = self.end_date.date() 396 end_day = self.end_date.date()
397 397
@@ -418,15 +418,15 @@ class Worktime(object):
418 if not d == datetime.strptime(c, date_format).replace(tzinfo=tzlocal()).date(): break 418 if not d == datetime.strptime(c, date_format).replace(tzinfo=tzlocal()).date(): break
419 else: 419 else:
420 if d >= self.end_date.date(): 420 if d >= self.end_date.date():
421 pull_forward[d] = min(timedelta(hours = float(hours)), self.time_per_day(d) - (holidays[d] if d in holidays else timedelta())) 421 self.pull_forward[d] = min(timedelta(hours = float(hours)), self.time_per_day(d) - (holidays[d] if d in holidays else timedelta()))
422 except IOError as e: 422 except IOError as e:
423 if e.errno != 2: 423 if e.errno != 2:
424 raise e 424 raise e
425 425
426 self.days_to_work = dict() 426 self.days_to_work = dict()
427 427
428 if pull_forward: 428 if self.pull_forward:
429 end_day = max(end_day, max(list(pull_forward))) 429 end_day = max(end_day, max(list(self.pull_forward)))
430 430
431 for day in [start_day + timedelta(days = x) for x in range(0, (end_day - start_day).days + 1)]: 431 for day in [start_day + timedelta(days = x) for x in range(0, (end_day - start_day).days + 1)]:
432 if day.isoweekday() in self.workdays: 432 if day.isoweekday() in self.workdays:
@@ -470,17 +470,17 @@ class Worktime(object):
470 self.extra_days_to_work[self.now.date()] = timedelta() 470 self.extra_days_to_work[self.now.date()] = timedelta()
471 471
472 self.time_to_work = sum([self.days_to_work[day] for day in self.days_to_work.keys() if day <= self.end_date.date()], timedelta()) 472 self.time_to_work = sum([self.days_to_work[day] for day in self.days_to_work.keys() if day <= self.end_date.date()], timedelta())
473 for day in [d for d in list(pull_forward) if d > self.end_date.date()]: 473 for day in [d for d in list(self.pull_forward) if d > self.end_date.date()]:
474 days_forward = set([d for d in self.days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in pull_forward or d == self.end_date.date())]) 474 days_forward = set([d for d in self.days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in self.pull_forward or d == self.end_date.date())])
475 extra_days_forward = set([d for d in self.extra_days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in pull_forward or d == self.end_date.date())]) 475 extra_days_forward = set([d for d in self.extra_days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in self.pull_forward or d == self.end_date.date())])
476 days_forward = days_forward.union(extra_days_forward) 476 days_forward = days_forward.union(extra_days_forward)
477 477
478 extra_day_time_left = timedelta() 478 extra_day_time_left = timedelta()
479 for extra_day in extra_days_forward: 479 for extra_day in extra_days_forward:
480 day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day]) 480 day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day])
481 extra_day_time_left += day_time 481 extra_day_time_left += day_time
482 extra_day_time = min(extra_day_time_left, pull_forward[day]) 482 extra_day_time = min(extra_day_time_left, self.pull_forward[day])
483 time_forward = pull_forward[day] - extra_day_time 483 time_forward = self.pull_forward[day] - extra_day_time
484 if extra_day_time_left > timedelta(): 484 if extra_day_time_left > timedelta():
485 for extra_day in extra_days_forward: 485 for extra_day in extra_days_forward:
486 day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day]) 486 day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day])
@@ -518,7 +518,14 @@ def format_days(worktime, days, date_format=None):
518 return ', '.join(map(lambda group: ','.join(map(format_group, group)), groups)) 518 return ', '.join(map(lambda group: ','.join(map(format_group, group)), groups))
519 519
520 520
521def worktime(**args): 521def tooltip_timedelta(td):
522 if td < timedelta(seconds = 0):
523 return "-" + tooltip_timedelta(-td)
524 mm, ss = divmod(td.total_seconds(), 60)
525 hh, mm = divmod(mm, 60)
526 return "%d:%02d:%02d" % (hh, mm, ss)
527
528def worktime(pull_forward_cutoff, waybar, **args):
522 worktime = Worktime(**args) 529 worktime = Worktime(**args)
523 530
524 def format_worktime(worktime): 531 def format_worktime(worktime):
@@ -562,7 +569,12 @@ def worktime(**args):
562 else: 569 else:
563 return f"({difference_string})" 570 return f"({difference_string})"
564 571
565 if worktime.time_pulled_forward >= timedelta(minutes = 15): 572 out_class = "running" if worktime.running_entry else "stopped"
573 difference = worktime.time_to_work - worktime.time_worked
574 if worktime.running_entry and -min(timedelta(milliseconds=0), difference) > sum(worktime.pull_forward.values(), start=timedelta(milliseconds=0)) or not worktime.running_entry and max(timedelta(milliseconds=0), difference) > worktime.time_per_day(worktime.now.date()) and worktime.now_is_workday:
575 out_class = "over"
576 tooltip = tooltip_timedelta(difference)
577 if worktime.time_pulled_forward >= min(pull_forward_cutoff, timedelta(seconds = 1)):
566 worktime_no_pulled_forward = deepcopy(worktime) 578 worktime_no_pulled_forward = deepcopy(worktime)
567 worktime_no_pulled_forward.time_to_work -= worktime_no_pulled_forward.time_pulled_forward 579 worktime_no_pulled_forward.time_to_work -= worktime_no_pulled_forward.time_pulled_forward
568 worktime_no_pulled_forward.time_pulled_forward = timedelta() 580 worktime_no_pulled_forward.time_pulled_forward = timedelta()
@@ -570,11 +582,24 @@ def worktime(**args):
570 difference_string = format_worktime(worktime) 582 difference_string = format_worktime(worktime)
571 difference_string_no_pulled_forward = format_worktime(worktime_no_pulled_forward) 583 difference_string_no_pulled_forward = format_worktime(worktime_no_pulled_forward)
572 584
573 print(f"{difference_string_no_pulled_forward}…{difference_string}") 585 tooltip = tooltip_timedelta(worktime_no_pulled_forward.time_to_work - worktime_no_pulled_forward.time_worked) + "…" + tooltip
586 if worktime.time_pulled_forward >= pull_forward_cutoff:
587 out_text = f"{difference_string_no_pulled_forward}…{difference_string}"
588 else:
589 out_text = format_worktime(worktime)
590 else:
591 out_text = format_worktime(worktime)
592
593 if waybar:
594 json.dump({"text": out_text, "class": out_class, "tooltip": tooltip}, stdout)
574 else: 595 else:
575 print(format_worktime(worktime)) 596 print(out_text)
597
598def pull_forward(**args):
599 worktime = Worktime(**args)
600 print(tooltip_timedelta(sum(worktime.pull_forward.values(), start=timedelta(milliseconds=0))))
576 601
577def time_worked(now, **args): 602def time_worked(now, waybar, **args):
578 then = now.replace(hour = 0, minute = 0, second = 0, microsecond = 0) 603 then = now.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
579 if now.time() == time(): 604 if now.time() == time():
580 now = now + timedelta(days = 1) 605 now = now + timedelta(days = 1)
@@ -584,6 +609,9 @@ def time_worked(now, **args):
584 609
585 worked = now.time_worked - then.time_worked 610 worked = now.time_worked - then.time_worked
586 611
612 out_text = None
613 out_class = "stopped"
614 tooltip = tooltip_timedelta(worked)
587 if args['do_round']: 615 if args['do_round']:
588 total_minutes_difference = 5 * ceil(worked / timedelta(minutes = 5)) 616 total_minutes_difference = 5 * ceil(worked / timedelta(minutes = 5))
589 (hours_difference, minutes_difference) = divmod(abs(total_minutes_difference), 60) 617 (hours_difference, minutes_difference) = divmod(abs(total_minutes_difference), 60)
@@ -602,15 +630,25 @@ def time_worked(now, **args):
602 difference = target_time - worked 630 difference = target_time - worked
603 clockout_difference = 5 * ceil(difference / timedelta(minutes = 5)) 631 clockout_difference = 5 * ceil(difference / timedelta(minutes = 5))
604 clockout_time = now.now + difference 632 clockout_time = now.now + difference
633 exact_clockout_time = clockout_time
605 clockout_time += (5 - clockout_time.minute % 5) * timedelta(minutes = 1) 634 clockout_time += (5 - clockout_time.minute % 5) * timedelta(minutes = 1)
606 clockout_time = clockout_time.replace(second = 0, microsecond = 0) 635 clockout_time = clockout_time.replace(second = 0, microsecond = 0)
607 636
608 if now.running_entry and clockout_time and clockout_difference >= 0: 637 if now.running_entry and clockout_time and clockout_difference >= 0:
609 print(f"{difference_string}/{clockout_time:%H:%M}") 638 out_class = "running"
639 out_text = f"{difference_string}/{clockout_time:%H:%M}"
640 tooltip = f"{tooltip_timedelta(worked)}/{exact_clockout_time:%H:%M}"
610 else: 641 else:
611 print(difference_string) 642 if now.running_entry:
643 out_class = "over"
644 out_text = difference_string
645 else:
646 out_text = str(worked)
647
648 if waybar:
649 json.dump({"text": out_text, "class": out_class, "tooltip": tooltip}, stdout)
612 else: 650 else:
613 print(worked) 651 print(out_text)
614 652
615def diff(now, **args): 653def diff(now, **args):
616 now = now.replace(hour = 0, minute = 0, second = 0, microsecond = 0) 654 now = now.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
@@ -798,6 +836,38 @@ def classification(classification_name, table, table_format, **args):
798def main(): 836def main():
799 def isotime(s): 837 def isotime(s):
800 return datetime.fromisoformat(s).replace(tzinfo=tzlocal()) 838 return datetime.fromisoformat(s).replace(tzinfo=tzlocal())
839 def duration_minutes(s):
840 return timedelta(minutes = float(s))
841
842 def set_default_subparser(self, name, args=None, positional_args=0):
843 """default subparser selection. Call after setup, just before parse_args()
844 name: is the name of the subparser to call by default
845 args: if set is the argument list handed to parse_args()
846
847 , tested with 2.7, 3.2, 3.3, 3.4
848 it works with 2.6 assuming argparse is installed
849 """
850 subparser_found = False
851 for arg in sys.argv[1:]:
852 if arg in ['-h', '--help']: # global help if no subparser
853 break
854 else:
855 for x in self._subparsers._actions:
856 if not isinstance(x, argparse._SubParsersAction):
857 continue
858 for sp_name in x._name_parser_map.keys():
859 if sp_name in sys.argv[1:]:
860 subparser_found = True
861 if not subparser_found:
862 # insert default in last position before global positional
863 # arguments, this implies no global options are specified after
864 # first positional argument
865 if args is None:
866 sys.argv.insert(len(sys.argv) - positional_args, name)
867 else:
868 args.insert(len(args) - positional_args, name)
869
870 argparse.ArgumentParser.set_default_subparser = set_default_subparser
801 871
802 config = Worktime.config() 872 config = Worktime.config()
803 873
@@ -807,9 +877,13 @@ def main():
807 parser.add_argument('--no-running', dest = 'include_running', action = 'store_false') 877 parser.add_argument('--no-running', dest = 'include_running', action = 'store_false')
808 parser.add_argument('--no-force-day-to-work', dest = 'force_day_to_work', action = 'store_false') 878 parser.add_argument('--no-force-day-to-work', dest = 'force_day_to_work', action = 'store_false')
809 subparsers = parser.add_subparsers(help = 'Subcommands') 879 subparsers = parser.add_subparsers(help = 'Subcommands')
810 parser.set_defaults(cmd = worktime) 880 worktime_parser = subparsers.add_parser('time_worked', aliases = ['time', 'worked'])
811 time_worked_parser = subparsers.add_parser('time_worked', aliases = ['time', 'worked', 'today']) 881 worktime_parser.add_argument('--pull-forward-cutoff', dest = 'pull_forward_cutoff', metavar = 'MINUTES', type = duration_minutes, default = timedelta(minutes = 15))
882 worktime_parser.add_argument('--waybar', action='store_true')
883 worktime_parser.set_defaults(cmd = worktime)
884 time_worked_parser = subparsers.add_parser('today')
812 time_worked_parser.add_argument('--no-round', dest = 'do_round', action = 'store_false') 885 time_worked_parser.add_argument('--no-round', dest = 'do_round', action = 'store_false')
886 time_worked_parser.add_argument('--waybar', action='store_true')
813 time_worked_parser.set_defaults(cmd = time_worked) 887 time_worked_parser.set_defaults(cmd = time_worked)
814 diff_parser = subparsers.add_parser('diff') 888 diff_parser = subparsers.add_parser('diff')
815 diff_parser.set_defaults(cmd = diff) 889 diff_parser.set_defaults(cmd = diff)
@@ -827,6 +901,9 @@ def main():
827 classification_parser.add_argument('--table', action = 'store_true') 901 classification_parser.add_argument('--table', action = 'store_true')
828 classification_parser.add_argument('--table-format', dest='table_format', type=str, default='fancy_grid') 902 classification_parser.add_argument('--table-format', dest='table_format', type=str, default='fancy_grid')
829 classification_parser.set_defaults(cmd = partial(classification, classification_name=classification_name)) 903 classification_parser.set_defaults(cmd = partial(classification, classification_name=classification_name))
904 pull_forward_parser = subparsers.add_parser('pull-forward')
905 pull_forward_parser.set_defaults(cmd = pull_forward)
906 parser.set_default_subparser('time_worked')
830 args = parser.parse_args() 907 args = parser.parse_args()
831 908
832 args.cmd(**vars(args)) 909 args.cmd(**vars(args))