summaryrefslogtreecommitdiff
path: root/accounts
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2026-09-23 21:08:35 +0200
committerGregor Kleen <gkleen@yggdrasil.li>2026-09-23 21:08:35 +0200
commitae9a80c1f012686c1f65fce7ce76fdd1b77b0b71 (patch)
tree141f738276cf84c6b7e5633c2bd5f2b44e9b0b75 /accounts
parent6a763272038e637a8a03dd9059d43a1ff44921dd (diff)
downloadnixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.gz
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.bz2
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.xz
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.zip
...
Diffstat (limited to 'accounts')
-rw-r--r--accounts/gkleen@skadhi/default.nix206
-rw-r--r--accounts/gkleen@skadhi/emacs/default.nix67
-rw-r--r--accounts/gkleen@skadhi/emacs/emacs.el262
-rw-r--r--accounts/gkleen@skadhi/greetd.nix92
-rw-r--r--accounts/gkleen@skadhi/niri.nix1005
-rw-r--r--accounts/gkleen@skadhi/shell/default.nix123
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/CMakeLists.txt190
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.cpp83
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.hpp55
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.cpp102
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.hpp52
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.cpp18
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.hpp21
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.cpp41
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.hpp26
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp288
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.hpp193
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/customplugin.h7
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/default.nix32
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml28
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml445
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Session.xml146
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml821
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Service.xml1100
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Unit.xml359
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/ActiveWindowDisplay.qml172
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Bar.qml142
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/BatteryWidget.qml139
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/BrightnessOSD.qml117
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/BrightnessWidget.qml84
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Clock.qml295
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/KeyboardLayout.qml112
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/LidSwitchInhibitorWidget.qml47
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/LockSurface.qml227
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Lockscreen.qml128
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/LockscreenInhibitorWidget.qml48
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/MaterialDesignIcon.qml35
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/NiriIdle.qml30
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/NotificationDisplay.qml340
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/NotificationInhibitorWidget.qml266
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/PipewireWidget.qml483
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/PrivacyWidget.qml49
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/Brightness.qml107
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/GpgAgent.qml18
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/InhibitorState.qml23
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/MprisProxy.qml8
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/NiriService.qml217
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/NotificationManager.qml162
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/Privacy.qml63
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/ScreenRecord.qml63
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/WallpaperSelector.qml8
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/Services/Worktime.qml84
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/SystemTray.qml201
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/UnixIPC.qml106
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/VolumeOSD.qml163
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/WallpaperBackground.qml89
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/WaylandInhibitorWidget.qml56
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/WorkspaceSwitcher.qml204
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/WorktimeWidget.qml212
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/YtDlpWidget.qml190
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/displaymanager.qml115
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell/shell.qml53
-rw-r--r--accounts/gkleen@skadhi/zsh/default.nix106
-rw-r--r--accounts/gkleen@skadhi/zsh/zshrc298
64 files changed, 11001 insertions, 21 deletions
diff --git a/accounts/gkleen@skadhi/default.nix b/accounts/gkleen@skadhi/default.nix
index 4c0c4028..fc969348 100644
--- a/accounts/gkleen@skadhi/default.nix
+++ b/accounts/gkleen@skadhi/default.nix
@@ -1,10 +1,13 @@
1{ flake, flakeInputs, userName, config, lib, ... }: 1{ flake, flakeInputs, userName, config, pkgs, lib, sources, ... }:
2let 2let
3 user = config.users.users.${userName}; 3 user = config.users.users.${userName};
4in { 4in {
5 imports = with flake.nixosModules.userProfiles.${userName}; [ 5 imports = (with flake.nixosModules.userProfiles.${userName}; [
6 zsh 6 zsh mpv yt-dlp ./greetd.nix
7 ]; 7 ]) ++ (with flake.nixosModules.systemProfiles; [
8 niri-unstable
9 flakeInputs.nixVirt.nixosModules.default
10 ]);
8 11
9 config = { 12 config = {
10 users.users.gkleen.group = "gkleen"; 13 users.users.gkleen.group = "gkleen";
@@ -17,9 +20,32 @@ in {
17 }; 20 };
18 }; 21 };
19 22
20 home-manager.users.${userName} = let sysConfig = config; in { config, ... }: { 23 programs = {
24 dconf.enable = true;
25 niri.enable = true;
26 };
27 environment.sessionVariables."GTK_USE_PORTAL" = "1";
28 services.niri-autoselect-portal.enable = true;
29 xdg.portal = {
30 enable = true;
31 extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
32 config.niri = {
33 default = lib.mkForce ["gnome" "gtk"];
34 "org.freedesktop.impl.portal.FileChooser" = ["gtk"];
35 "org.freedesktop.impl.portal.OpenFile" = ["gtk"];
36 "org.freedesktop.impl.portal.Access" = ["gtk"];
37 "org.freedesktop.impl.portal.Notification" = ["gtk"];
38 "org.freedesktop.impl.portal.Secret" = ["none"];
39 "org.freedesktop.impl.portal.Inhibit" = ["none"];
40 };
41 };
42
43 security.pam.services.quickshell = {};
44
45 home-manager.users.${userName} = { sysConfig, config, ... }: {
21 imports = [ 46 imports = [
22 flakeInputs.nix-index-database.homeModules.nix-index 47 flakeInputs.nix-index-database.homeModules.nix-index
48 ./niri.nix ./shell ./emacs ./zsh
23 ]; 49 ];
24 50
25 home.stateVersion = "26.05"; 51 home.stateVersion = "26.05";
@@ -30,26 +56,164 @@ in {
30 ]; 56 ];
31 }; 57 };
32 58
33 programs.zsh.dirHashes = let 59 programs.nix-index.enable = true;
34 flakeHashes = lib.mapAttrs' (n: v: lib.nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs; 60
35 inputNames = { 61 programs.alacritty = {
36 self = "nixos"; 62 enable = true;
63 theme = "kitty";
64 settings = {
65 font = {
66 normal = {
67 family = "Fira Mono";
68 style = "Medium";
69 };
70 size = 10;
71 };
72 hints = {
73 alphabet = "aoeuhtns";
74 enabled = [
75 {
76 command = lib.getExe' pkgs.xdg-utils "xdg-open";
77 hyperlinks = true;
78 post_processing = true;
79 persist = false;
80 mouse.enabled = true;
81 binding = { key = "O"; mods = "Control|Shift"; };
82 regex = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\"\\\\s{-}\\\\^⟨⟩`\\\\\\\\]+";
83 }
84 {
85 command = lib.getExe' pkgs.wl-clipboard-rs "wl-copy";
86 hyperlinks = true;
87 post_processing = true;
88 persist = false;
89 mouse.enabled = true;
90 binding = { key = "Y"; mods = "Control|Shift"; };
91 regex = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\"\\\\s{-}\\\\^⟨⟩`\\\\\\\\]+";
92 }
93 ];
94 };
95 terminal.shell.program = lib.getExe config.programs.zsh.package;
37 }; 96 };
38 in flakeHashes // { 97 };
39 docs = "$HOME/documents"; 98 programs.fuzzel = {
40 dl = "$HOME/Downloads"; 99 enable = true;
41 scrot = "$HOME/screenshots"; 100 settings = {
42 media = "$HOME/media"; 101 main = {
102 terminal = "${lib.getExe config.programs.alacritty.package} msg --socket /run/user/1000/alacritty.sock create-window --command ${lib.getExe' sysConfig.systemd.package "systemd-run"} --user --pty --same-dir --wait --collect --quiet --service-type=exec --expand-environment=no {cmd}";
103 layer = "overlay";
104 icon-theme = "Paper";
105 font = "Fira Sans";
106 };
107 colors = {
108 background = "000000cc";
109 text = "cdd6f4ff";
110 match = "94e2d5ff";
111 selection = "585b70ff";
112 selection-match = "94e2d5ff";
113 selection-text = "cdd6f4ff";
114 border = "b4befeff";
115 };
116 dmenu = {
117 exit-immediately-if-empty = true;
118 };
43 }; 119 };
44 programs.starship.settings = {
45 directory.substitutions = lib.mapAttrs' (name: value: let
46 value' = builtins.unsafeDiscardStringContext value;
47 value'' = if lib.hasPrefix "$HOME/" value' then "~" + lib.removePrefix "$HOME" value' else value';
48 in lib.nameValuePair value'' "~${name}"
49 ) config.programs.zsh.dirHashes;
50 }; 120 };
51 121
52 programs.nix-index.enable = true; 122 services.xembed-sni-proxy = {
123 enable = true;
124 package = pkgs.kdePackages.plasma-workspace;
125 };
126 services.network-manager-applet.enable = true;
127 services.blueman-applet.enable = true;
128
129 home.pointerCursor = {
130 package = pkgs.vanilla-dmz;
131 name = "Vanilla-DMZ-AA";
132 size = 16;
133
134 x11 = {
135 enable = true;
136 defaultCursor = "left_ptr";
137 };
138 gtk.enable = true;
139 };
140
141 gtk = {
142 enable = true;
143 font = {
144 package = pkgs.fira;
145 name = "Fira Sans";
146 size = 10;
147 };
148 theme = {
149 package = pkgs.kdePackages.breeze-gtk;
150 name = "Breeze-Dark";
151 };
152 iconTheme = {
153 package = pkgs.adwaita-icon-theme;
154 name = "Adwaita";
155 };
156 };
157 qt.enable = true;
158 qt.platformTheme.name = "gtk";
159
160 home.sessionVariables = {
161 QT_QPA_PLATFORMTHEME = lib.mkForce "gtk3";
162 };
163 home.extraProfileCommands = ''
164 export XDG_DATA_DIRS="${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}''${XDG_DATA_DIRS:+:''${XDG_DATA_DIRS}}"
165 '';
166
167 xdg.configFile."systemd/user/home-manager.service.d/before-graphical-session.conf".text = ''
168 [Unit]
169 Before=graphical-session-pre.target
170 '';
171
172 fonts = {
173 fontconfig.enable = true;
174 };
175
176 i18n.inputMethod = {
177 enable = true;
178 type = "fcitx5";
179 fcitx5 = {
180 waylandFrontend = true;
181 settings = {
182 globalOptions."Behavior/DisabledAddons" = {
183 "0" = "clipboard";
184 };
185 inputMethod = {
186 "Groups/0" = {
187 Name = "Default";
188 "Default Layout" = "us";
189 DefaultIM = "keyboard-us";
190 };
191 "Groups/0/Items/0" = {
192 Name = "keyboard-us";
193 Layout = "";
194 };
195 "GroupOrder"."0" = "Default";
196 };
197 addons = {
198 classicui.globalSection = {
199 "Vertical Candidate List" = "True";
200 Font = "Fira Sans 10";
201 MenuFont = "Fira Sans 10";
202 TrayFont = "Fira Sans Demi-Bold 10";
203 UseDarkTheme = "True";
204 };
205 quickphrase = {
206 globalSection = {
207 "Choose Modifier" = "None";
208 Spell = "True";
209 FallbackSpellLanguage = "en";
210 };
211 sections.TriggerKey."0" = "Super+E";
212 };
213 };
214 };
215 };
216 };
53 }; 217 };
54 }; 218 };
55} 219}
diff --git a/accounts/gkleen@skadhi/emacs/default.nix b/accounts/gkleen@skadhi/emacs/default.nix
new file mode 100644
index 00000000..4cf6b0b9
--- /dev/null
+++ b/accounts/gkleen@skadhi/emacs/default.nix
@@ -0,0 +1,67 @@
1{ pkgs, lib, config, sources, ... }:
2let
3 editor = pkgs.symlinkJoin {
4 name = "${config.services.emacs.package.name}-editor";
5 buildInputs = with pkgs; [ makeWrapper ];
6 paths = [ config.services.emacs.package ];
7 postBuild = ''
8 wrapProgram $out/bin/emacsclient \
9 --inherit-argv0 \
10 --add-flags ${lib.escapeShellArg (lib.escapeShellArgs config.services.emacs.client.arguments)}
11 '';
12 };
13in {
14 config = {
15 home.persistence."/persistent".directories = [
16 ".local/state/emacs/saves" ".local/state/emacs/undo"
17 ];
18
19 programs.emacs = {
20 enable = true;
21 package = pkgs.emacs-pgtk;
22 extraPackages = epkgs: with epkgs; [
23 evil evil-dvorak undo-tree magit haskell-tng-mode nix-mode
24 yaml-mode json-mode shakespeare-mode smart-mode-line
25 highlight-parentheses highlight-symbol ag sass-mode
26 lua-mode fira-code-mode use-package wanderlust # notmuch
27 git-gutter scratch edit-server mediawiki editorconfig
28 typescript-mode markdown-mode nftables-mode rustic
29 lsp-mode lsp-ui direnv company projectile
30 tomorrow-night-paradise-theme
31 treesit-grammars.with-all-grammars magit-delta scad-mode
32 typst-ts-mode
33 ];
34 overrides = self: super: {
35 tomorrow-night-paradise-theme = super.trivialBuild {
36 inherit (sources.tomorrow-night-paradise-theme) pname version src;
37 };
38 scratch = pkgs.stdenv.mkDerivation {
39 inherit (sources.emacs-scratch_el) pname version src;
40
41 phases = [ "unpackPhase" "installPhase" ];
42
43 installPhase = ''
44 install -Dt $out/share/emacs/site-lisp scratch.el
45 '';
46 };
47 };
48 };
49 xdg.configFile."emacs/init.el".source = pkgs.substitute {
50 src = ./emacs.el;
51 substitutions = [
52 "--subst-var-by" "ksshaskpass" (lib.getExe pkgs.kdePackages.ksshaskpass)
53 ];
54 };
55
56 home.sessionVariables.EDITOR = lib.getExe' editor "emacsclient";
57
58 services.emacs = {
59 enable = true;
60 socketActivation.enable = true;
61 client = {
62 enable = true;
63 arguments = lib.mkForce ["--create-frame" "--alternate-editor" (lib.getExe config.services.emacs.package)];
64 };
65 };
66 };
67}
diff --git a/accounts/gkleen@skadhi/emacs/emacs.el b/accounts/gkleen@skadhi/emacs/emacs.el
new file mode 100644
index 00000000..a9d22621
--- /dev/null
+++ b/accounts/gkleen@skadhi/emacs/emacs.el
@@ -0,0 +1,262 @@
1(menu-bar-mode -1)
2(scroll-bar-mode -1)
3(tool-bar-mode -1)
4
5(setq inhibit-startup-message t)
6(defalias 'yes-or-no-p 'y-or-n-p)
7
8;; (set-face-attribute 'default nil :font "Fira Code" :height 49)
9(set-frame-font "Fira Code 8" nil nil)
10(load-theme 'modus-vivendi t)
11;; (add-to-list 'default-frame-alist '(alpha-background . 90))
12
13(require 'package)
14(setq package-archives nil)
15(package-initialize)
16(require 'use-package)
17;; (use-package use-package-ensure-system-package :ensure t)
18
19(require 'evil)
20(evil-mode 1)
21
22(editorconfig-mode 1)
23
24(require 'edit-server)
25(edit-server-start)
26
27(require 'mediawiki)
28(setq mediawiki-mode-hook
29 (lambda ()
30 (define-key mediawiki-mode-map (kbd "<C-left>") nil)
31 (define-key mediawiki-mode-map (kbd "<C-right>") nil)))
32
33(require 'typescript-mode)
34
35(global-subword-mode)
36(global-undo-tree-mode)
37(global-fira-code-mode)
38
39(evil-set-undo-system 'undo-tree)
40
41(add-hook 'magit-mode-hook (lambda () (magit-delta-mode +1)))
42
43(global-set-key (kbd "RET") 'newline-and-indent)
44(global-set-key (kbd "M-g") 'magit-status)
45(global-set-key (kbd "M-?") 'vc-git-grep)
46
47(require 'git-gutter)
48(global-git-gutter-mode t)
49(custom-set-variables '(git-gutter:update-interval 2))
50(custom-set-variables '(git-gutter:hide-gutter t))
51
52(require 'scratch)
53;; (global-set-key (kbd "C-x b") 'scratch-switch-to-buffer)
54(global-set-key (kbd "C-x B") 'scratch-create)
55;; (setq initial-major-mode 'scratch-mode)
56(setq initial-scratch-message "")
57
58(global-set-key (kbd "C-x K") 'kill-current-buffer)
59
60(setq backup-directory-alist `(("." . "~/.local/state/emacs/saves")))
61(setq undo-tree-history-directory-alist `(("." . "~/.local/state/emacs/undo")))
62(setq delete-old-versions t
63 kept-new-versions 6
64 kept-old-versions 2
65 version-control t)
66
67(setq undo-tree-visualizer-timestamps t
68 undo-tree-visualizer-diff t
69 ;; 10X bump of the undo limits to avoid issues with premature
70 ;; Emacs GC which truncages the undo history very aggresively
71 undo-limit 800000
72 undo-strong-limit 12000000
73 undo-outer-limit 120000000)
74
75(add-hook 'haskell-mode-hook 'haskell-indentation-mode)
76(add-hook 'haskell-mode-hook 'subword-mode)
77(add-hook 'haskell-mode-hook 'highlight-symbol-mode)
78(add-hook 'haskell-mode-hook 'highlight-paretheses-mode)
79
80(add-hook 'js-mode-hook 'highlight-symbol-mode)
81(add-hook 'js-mode-hook 'highlight-parentheses-mode)
82(defun my-js-mode-hook ()
83 "Custom `js-mode' behaviours."
84 (setq js-indent-level 2)
85 )
86(add-hook 'js-mode-hook 'my-js-mode-hook)
87
88(define-derived-mode anansi-mode
89 markdown-mode "Anansi"
90 "Major mode for anansi"
91 (lambda () (setq indent-tabs-mode nil)))
92(add-to-list 'auto-mode-alist '("\\.anansi\\'" . anansi-mode))
93
94(projectile-mode +1)
95(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
96
97(add-hook 'rustic-mode-hook (lambda () (setq indent-tabs-mode nil)))
98(add-hook 'rustic-mode-hook #'lsp-deferred)
99(add-hook 'rustic-mode-hook (lambda () (setq lsp-ui-sideline-enable nil)))
100(setq lsp-auto-guess-root t)
101(setq lsp-inlay-hint-enable t)
102;; (add-hook 'rust-mode-hook 'lsp-inlay-hints-mode)
103(setq lsp-rust-analyzer-server-display-inlay-hints t)
104(setq lsp-rust-analyzer-inlay-hints-mode t)
105(setq lsp-rust-analyzer-display-parameter-hints t)
106(setq lsp-rust-analyzer-display-chaining-hints t)
107(setq lsp-rust-analyzer-hide-named-constructor nil)
108
109(setq undo-tree-auto-save-history t)
110
111(defvar expand-file-name-custom-tilde-alist '(("u2w-srv01" . "/ssh:srv01.uniworx.de:/home/gkleen/projects/uni2work") ("fra-srv01" . "/ssh:srv01.uniworx.de:/home/gkleen/projects/fradrive")))
112(defun my/add-to-tilde-alist (hash)
113 (let* ((tilde:dir (split-string hash "="))
114 (tilde (car tilde:dir))
115 (dir (cadr tilde:dir)))
116 (push (cons tilde dir) expand-file-name-custom-tilde-alist)))
117(mapc #'my/add-to-tilde-alist
118 (split-string (let ((process-environment (cl-copy-list process-environment))) (setenv "TERM" nil) (with-output-to-string (call-process "script" nil standard-output nil "-qec" "zsh -ic \"hash -d\"" "/dev/null")))
119 "\r\n" t))
120
121(defadvice expand-file-name (before expand-file-name-custom-tilde
122 (name &optional default-directory)
123 activate compile)
124 "User-defined expansions for ~NAME in file names."
125 (save-match-data
126 (when (string-match "\\`\\(\\(.*/\\)?~\\([^:/]+\\)\\)/" name)
127 (let ((replacement (assoc (match-string 3 name) expand-file-name-custom-tilde-alist)))
128 (when replacement
129 (setq name (replace-match (cdr replacement) t t name 1)))))))
130
131(setq edit-server-new-frame nil)
132(setq edit-server-url-major-mode-alist '(("rzint\\.mathinst\\.loc" . mediawiki-mode)))
133
134;; (setq notmuch-address-internal-completion '(received nil))
135;; (setq notmuch-always-prompt-for-sender t)
136;; (setq notmuch-command "notmuch-ssh")
137;; (setq notmuch-crypto-process-mime t)
138;; (setq notmuch-draft-tags '("+draft" "-inbox"))
139;; (setq notmuch-fcc-dirs nil)
140;; (setq notmuch-hello-sections '(notmuch-hello-insert-header notmuch-hello-insert-saved-searches))
141;; (setq notmuch-hello-thousands-separator " ")
142;; (setq notmuch-identities '("gkleen@yggdrasil.li" "g@141.li" "kleen@cip.ifi.lmu.de" "Gregor.Kleen@stud.ifi.lmu.de" "G.Kleen@campus.lmu.de" "G.Kleen@lmu.de" "gregor.kleen@ifi.lmu.de" "uni2work@ifi.lmu.de" "gregor@kleen.li"))
143;; (setq notmuch-message-headers '("Subject" "To" "Cc" "Date"))
144;; (setq notmuch-message-replied-tags '("+replied" "-unread" "-inbox"))
145;; (setq notmuch-saved-searches
146;; (quote
147;; ((:name "inbox" :query "tag:inbox" :key "i")
148;; (:name "unread" :query "tag:unread AND tag:inbox" :key "u")
149;; (:name "drafts" :query "tag:draft" :key "d")
150;; (:name "all mail" :query "date:month.." :key "a" :count-query "*")
151;; (:name "sent" :query "is:sent" :key "s" :count-query "is:sent")
152;; )))
153;; (setq notmuch-search-oldest-first nil)
154;; (setq notmuch-show-all-tags-list t)
155;; (setq notmuch-show-logo nil)
156
157(setq send-mail-function 'sendmail-send-it)
158(setq mail-envelope-from 'header)
159(setq mail-specify-envelope-from 't)
160(setq mail-default-headers nil)
161(setq message-default-headers "")
162(setq message-default-mail-headers "")
163(setq message-sendmail-envelope-from 'header)
164
165(setq highlight-symbol-idle-delay 0)
166
167(setq indent-tabs-mode nil)
168
169(setq ido-enable-flex-matching t)
170(setq ido-everywhere t)
171(ido-mode 1)
172
173(setq tramp-default-method "ssh")
174(customize-set-variable 'tramp-use-ssh-controlmaster-options nil)
175(setq tramp-allow-unsafe-temporary-files t)
176
177(direnv-mode)
178(setq direnv-enabled-hosts '("uni2work-dev1"))
179
180(setq auth-sources '())
181
182(setq ring-bell-function 'ignore)
183
184(setq enable-remote-dir-locals 't)
185
186(setq-default indicate-empty-lines t)
187(setq-default show-trailing-whitespace t)
188
189(defun tramp-sh-handle-start-file-process@my-direnv (args)
190 "Enable Direnv for hosts in `direnv-enabled-hosts'."
191 (with-parsed-tramp-file-name (expand-file-name default-directory) nil
192 (if (member host direnv-enabled-hosts)
193 (pcase-let ((`(,name ,buffer ,program . ,args) args))
194 `(,name
195 ,buffer
196 "direnv"
197 "exec"
198 ,localname
199 ,program
200 ,@args))
201 args)))
202
203(with-eval-after-load "tramp-sh"
204 (advice-add 'tramp-sh-handle-start-file-process
205 :filter-args #'tramp-sh-handle-start-file-process@my-direnv))
206
207(setq mail-host-address "sif.midgard.yggdrasil")
208(setq user-full-name "Gregor Kleen")
209
210(defun tell-emacsclients-for-buffer-to-die ()
211 "Sends error exit command to every client for the current buffer."
212 (interactive)
213 (dolist (proc server-buffer-clients)
214 (server-send-string proc "-error die")))
215
216(defun kill-buffer-with-special-emacsclient-handling ()
217 "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks"
218 (interactive)
219 (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t)
220 (kill-buffer))
221
222;; (global-set-key (kbd "C-x k") 'kill-buffer)
223
224(defun install-emacsclient-wrapped-kill-buffer ()
225 "Installs wrapped kill-buffer with special emacsclient handling.
226Best not to install it unconditionally because the server is not
227necessarily running."
228 (interactive)
229 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))
230
231(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer)
232(add-hook 'server-switch-hook #'raise-frame)
233
234(defun move-file (new-location)
235 "Write this file to NEW-LOCATION, and delete the old one."
236 (interactive (list (expand-file-name
237 (if buffer-file-name
238 (read-file-name "Move file to: ")
239 (read-file-name "Move file to: "
240 default-directory
241 (expand-file-name (file-name-nondirectory (buffer-name))
242 default-directory))))))
243 (when (file-exists-p new-location)
244 (delete-file new-location))
245 (let ((old-location (expand-file-name (buffer-file-name))))
246 (message "old file is %s and new file is %s"
247 old-location
248 new-location)
249 (write-file new-location t)
250 (when (and old-location
251 (file-exists-p new-location)
252 (not (string-equal old-location new-location)))
253 (delete-file old-location))))
254
255(bind-key "C-x C-m" #'move-file)
256
257(let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock))
258(setenv "SSH_ASKPASS_REQUIRE" "prefer")
259(setenv "SSH_ASKPASS" "@ksshaskpass@")
260
261(define-key typst-ts-mode-map (kbd "C-<left>") nil)
262(define-key typst-ts-mode-map (kbd "C-<right>") nil)
diff --git a/accounts/gkleen@skadhi/greetd.nix b/accounts/gkleen@skadhi/greetd.nix
new file mode 100644
index 00000000..1972404c
--- /dev/null
+++ b/accounts/gkleen@skadhi/greetd.nix
@@ -0,0 +1,92 @@
1{ config, pkgs, lib, flakeInputs, ... }:
2
3let
4 gkleenConfig = config.home-manager.users."gkleen";
5 toIni = lib.generators.toINI {
6 mkKeyValue =
7 key: value:
8 let
9 value' = if lib.isBool value then lib.boolToString value else toString value;
10 in
11 "${lib.escape [ "=" ] key}=${value'}";
12 };
13 toDconfIni = let
14 gvariant = import (flakeInputs.home-manager + "/modules/lib/gvariant.nix") { inherit lib; };
15 mkIniKeyValue = key: value: "${key}=${toString (gvariant.mkValue value)}";
16 in lib.generators.toINI { mkKeyValue = mkIniKeyValue; };
17in {
18 config = {
19 services.greetd = {
20 enable = true;
21 settings.default_session.command = lib.getExe (pkgs.writeShellApplication {
22 name = "sway";
23 runtimeInputs = [ pkgs.sway pkgs.fontconfig ];
24 runtimeEnv = {
25 XDG_DATA_DIRS = lib.makeSearchPath "share" [
26 pkgs.kdePackages.breeze-gtk pkgs.adwaita-icon-theme pkgs.fira
27 ];
28 QT_PLUGIN_PATH = lib.makeSearchPath (pkgs.qt6.qtbase.qtPluginPrefix) [
29 pkgs.qt6Packages.qtbase
30 ];
31 QML2_IMPORT_PATH = lib.makeSearchPath (pkgs.qt6.qtbase.qtQmlPrefix) [
32 pkgs.qt6Packages.qtbase
33 ];
34 QT_QPA_PLATFORMTHEME = "gtk3";
35 XDG_CONFIG_DIR = pkgs.symlinkJoin {
36 name = "config";
37 paths = [
38 (pkgs.writeTextDir "gtk-3.0/settings.ini" (toIni {
39 Settings = {
40 gtk-font-name = "Fira Sans 10";
41 gtk-theme-name = "Breeze-Dark";
42 gtk-icon-theme-name = "Adwaita";
43 };
44 }))
45 ];
46 };
47 # XDG_CACHE_HOME = "/var/cache/greetd/greeter";
48 # XDG_CONFIG_HOME = "/var/cache/greetd/greeter/config";
49 };
50 text = ''
51 exec &>/tmp/sway-$$.log
52
53 unset MANAGERPID SYSTEMD_EXEC_PID
54
55 # ${lib.getExe' pkgs.coreutils "mkdir"} -p ''${XDG_CONFIG_HOME}/dconf
56 ${lib.getExe pkgs.dconf} load / < ${pkgs.writeText "dconf.ini" (toDconfIni {
57 "org/gnome/desktop/interface" = {
58 "color-scheme" = "prefer-dark";
59 "font-name" = "Fira Sans 10";
60 "gtk-theme" = "Breeze-Dark";
61 "icon-theme" = "Adwaita";
62 };
63 })}
64
65 exec sway --unsupported-gpu --config ${pkgs.writeText "sway-config" ''
66 exec "${lib.getExe' config.systemd.package "systemctl"} --user import-environment {,WAYLAND_}DISPLAY SWAYSOCK; ${lib.getExe gkleenConfig.programs.quickshell.package} --path ${gkleenConfig.xdg.configFile."quickshell".source}/displaymanager.qml; swaymsg exit"
67
68 input type:keyboard {
69 xkb_layout "us,us"
70 xkb_variant "dvp,"
71 xkb_options "compose:caps,grp:win_space_toggle"
72 }
73
74 output eDP-1 scale 1.5
75 ''}
76 '';
77 });
78 };
79
80 # security.pam.services.greetd.fprintAuth = false;
81
82 systemd.services.greetd.serviceConfig = {
83 ExecStartPre = ''${lib.getExe' pkgs.coreutils "install"} -d -o greeter -g greeter -m 0700 ''${CACHE_DIRECTORY}/greeter'';
84 # CacheDirectory = "greetd";
85 };
86
87 users.users.greeter = {
88 home = "/var/lib/greeter";
89 createHome = true;
90 };
91 };
92}
diff --git a/accounts/gkleen@skadhi/niri.nix b/accounts/gkleen@skadhi/niri.nix
new file mode 100644
index 00000000..b30c5701
--- /dev/null
+++ b/accounts/gkleen@skadhi/niri.nix
@@ -0,0 +1,1005 @@
1{ config, hostConfig, pkgs, lib, utils, flakeInputs, ... }:
2let
3 cfg = config.programs.niri;
4
5 kdl = flakeInputs.niri-flake.lib.kdl;
6 sleaf = name: arg: kdl.node name [arg] [];
7
8 niri = cfg.package;
9 spawnTerminal = { command ? lib.getExe config.programs.zsh.package, extraArgs ? [] }:
10 [(lib.getExe config.programs.alacritty.package) "msg" "--socket" "/run/user/1000/alacritty.sock" "create-window"] ++ lib.toList extraArgs ++ ["--command" (lib.getExe' hostConfig.systemd.package "systemd-run") "--user" "--pty" "--same-dir" "--wait" "--collect" "--quiet" "--service-type=exec" "--expand-environment=no"] ++ lib.mapAttrsToList (k: v: "--property=Environment=${utils.escapeSystemdExecArg "${k}=${if v == null then "" else v}"}") execEnvironment ++ lib.toList command;
11
12 execEnvironment = {
13 NIXOS_OZONE_WL = "1";
14 QT_QPA_PLATFORM = "wayland";
15 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
16 GDK_BACKEND = "wayland";
17 SDL_VIDEODRIVER = "wayland";
18 DISPLAY = ":0";
19 ELECTRON_OZONE_PLATFORM_HINT = "auto";
20 SSH_ASKPASS_REQUIRE = "prefer";
21 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
22 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
23 GTK_IM_MODULE = null;
24 QT_IM_MODULE = null;
25 QT_IM_MODULES = null;
26 };
27
28 focus_or_spawn = pkgs.writeShellApplication {
29 name = "focus-or-spawn";
30 runtimeInputs = [ niri pkgs.gojq pkgs.gnugrep pkgs.socat ];
31 text = ''
32 window_select="$1"
33 shift
34 workspace_name="$1"
35 shift
36
37 workspaces_json="$(niri msg -j workspaces)"
38 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")"
39 # active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")"
40 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
41 if [[ $workspace_output != "$active_output" ]]; then
42 niri msg action move-workspace-to-monitor --reference "$workspace_name" "$active_output"
43 # socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}'
44 # niri msg action move-workspace-to-index --reference "$workspace_name" 1
45 fi
46
47 while IFS=$'\n' read -r window_json; do
48 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
49 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
50 niri msg action focus-workspace-previous
51 else
52 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
53 niri msg action focus-workspace "$workspace_name"
54 else
55 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
56 fi
57 fi
58 exit 0
59 fi
60 done < <(niri msg -j windows | jq -c '.[]')
61
62 exec "$@"
63 '';
64 };
65 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
66
67 with_adjacent_workspace = pkgs.writeShellApplication {
68 name = "with-adjacent-workspace";
69 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
70 text = ''
71 blacklist="$1"
72 shift
73 direction="$1"
74 shift
75 action="$1"
76 shift
77
78 workspaces_json="$(niri msg -j workspaces)"
79 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
80 workspace_output="$(jq -r --arg active_workspace "$active_workspace" '.[] | select(.id == ($active_workspace | tonumber)) | .output' <<<"$workspaces_json")"
81 workspace_idx="$(jq -r '.[] | select(.is_focused) | .idx' <<<"$workspaces_json")"
82
83 jq_script='map(select('
84 case "$direction" in
85 down)
86 # shellcheck disable=SC2016
87 jq_script=''${jq_script}'.idx > ($workspace_idx | tonumber)';;
88 up)
89 # shellcheck disable=SC2016
90 jq_script=''${jq_script}'.idx < ($workspace_idx | tonumber)';;
91 esac
92 # shellcheck disable=SC2016
93 jq_script=''${jq_script}' and .output == $workspace_output and ((.name == null) or (.name | test($blacklist) | not)))) | sort_by(.idx)'
94 [[ $direction == "up" ]] && jq_script=''${jq_script}' | reverse'
95 jq_script=''${jq_script}' | .[0]'
96
97 workspace_json=$(jq -c --arg blacklist "$blacklist" --arg workspace_output "$workspace_output" --arg workspace_idx "$workspace_idx" "$jq_script" <<<"$workspaces_json")
98 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
99 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
100 '';
101 };
102 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
103 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
104 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
105
106 with_unnamed_workspace = pkgs.writeShellApplication {
107 name = "with-unnamed-workspace";
108 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
109 text = ''
110 action="$1"
111 shift
112
113 workspaces_json="$(niri msg -j workspaces)"
114 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
115 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
116
117 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
118 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")"
119 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
120 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
121 '';
122 };
123 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace);
124
125 with_empty_unnamed_workspace = pkgs.writeShellApplication {
126 name = "with-empty-unnamed-workspace";
127 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
128 text = ''
129 action="$1"
130 shift
131
132 workspaces_json="$(niri msg -j workspaces)"
133 active_output="$(jq '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
134 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")"
135 jq --argjson workspace_id "$target_workspace_id" -nc "$action" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
136 '';
137 };
138 with-empty-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_empty_unnamed_workspace);
139
140 with_select_window = pkgs.writeShellApplication {
141 name = "with-select-window";
142 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ];
143 text = ''
144 window_select="$1"
145 shift
146 action="$1"
147 shift
148
149 windows_json="$(niri msg -j windows)"
150 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
151 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)"
152 # shellcheck disable=SC2016
153 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
154
155 [[ -z "$window_json" ]] && exit 1
156
157 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
158 '';
159 };
160 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
161
162 with_predicate_window = pred: pkgs.writeShellApplication {
163 name = "with-predicate-window";
164 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
165 text = ''
166 action="$1"
167 shift
168
169 windows_json="$(niri msg -j windows)"
170 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
171
172 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
173
174 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
175 '';
176 };
177
178 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
179 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
180in {
181 options = {
182 programs.niri.scratchspaces = lib.mkOption {
183 type = lib.types.listOf (lib.types.submodule ({ config, ... }: {
184 options = {
185 name = lib.mkOption {
186 type = lib.types.str;
187 };
188 match = lib.mkOption {
189 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
190 default = [];
191 };
192 exclude = lib.mkOption {
193 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
194 default = [];
195 };
196 windowRuleExtra = lib.mkOption {
197 type = kdl.types.kdl-nodes;
198 default = [];
199 };
200 key = lib.mkOption {
201 type = lib.types.nullOr lib.types.str;
202 default = null;
203 };
204 moveKey = lib.mkOption {
205 type = lib.types.nullOr lib.types.str;
206 default = let
207 keys = lib.splitString "+" config.key;
208 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
209 (lib.take (lib.length keys - 1) keys)
210 ["Shift"]
211 (lib.takeEnd 1 keys)
212 ]);
213 in if config.key == null then null else defMoveKey;
214 };
215 spawn = lib.mkOption {
216 type = lib.types.nullOr (lib.types.listOf lib.types.str);
217 default = null;
218 };
219 app-id = lib.mkOption {
220 type = lib.types.nullOr lib.types.str;
221 default = null;
222 };
223 selector = lib.mkOption {
224 type = lib.types.nullOr lib.types.str;
225 default = null;
226 };
227 };
228
229 config = lib.mkMerge [
230 (lib.mkIf (config.app-id != null) {
231 match = lib.mkDefault [ { app-id = "^${lib.escapeRegex config.app-id}$"; } ];
232 selector = lib.mkDefault "select(.app_id == \"${config.app-id}\")";
233 })
234 ];
235 }));
236 default = [];
237 };
238 };
239
240 config = {
241 home.packages = [ pkgs.xwayland-satellite-unstable ];
242
243 systemd.user.sockets.niri-workspace-history = {
244 Socket = {
245 ListenStream = "%t/niri-workspace-history.sock";
246 SocketMode = "0600";
247 };
248 };
249 systemd.user.services.niri-workspace-history = {
250 Unit = {
251 BindsTo = [ "niri.service" ];
252 After = [ "niri.service" ];
253 };
254 Install = {
255 WantedBy = [ "niri.service" ];
256 };
257 Service = {
258 Type = "simple";
259 Sockets = [ "niri-workspace-history.socket" ];
260 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
261 import os
262 import socket
263 import json
264 # import sys
265 from collections import defaultdict
266 from threading import Thread, Lock
267 from socketserver import StreamRequestHandler, ThreadingTCPServer
268 from contextlib import contextmanager
269 from io import TextIOWrapper
270
271
272 @contextmanager
273 def detaching(thing):
274 try:
275 yield thing
276 finally:
277 thing.detach()
278
279
280 workspace_history = defaultdict(list)
281 history_lock = Lock()
282
283
284 def monitor_niri():
285 workspaces = list()
286
287 def focus_workspace(output, workspace):
288 with history_lock:
289 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
290 # print(json.dumps(workspace_history), file=sys.stderr)
291
292 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
293 sock.connect(os.environ["NIRI_SOCKET"])
294 sock.send(b"\"EventStream\"\n")
295 for line in sock.makefile(buffering=1, encoding='utf-8'):
296 if line_json := json.loads(line):
297 if "WorkspacesChanged" in line_json:
298 workspaces = line_json["WorkspacesChanged"]["workspaces"]
299 for ws in workspaces:
300 if ws["is_focused"]:
301 focus_workspace(ws["output"], ws["id"])
302 if "WorkspaceActivated" in line_json:
303 for ws in workspaces:
304 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
305 continue
306 focus_workspace(ws["output"], ws["id"])
307 break
308
309
310 class RequestHandler(StreamRequestHandler):
311 def handle(self):
312 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
313 with history_lock:
314 json.dump(workspace_history, out)
315
316
317 class Server(ThreadingTCPServer):
318 def __init__(self):
319 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
320 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
321
322
323 def run_server():
324 with Server() as server:
325 server.serve_forever()
326
327
328 niri = Thread(target=monitor_niri)
329 niri.daemon = True
330 niri.start()
331
332 server_thread = Thread(target=run_server)
333 server_thread.daemon = True
334 server_thread.start()
335
336 while True:
337 server_thread.join(timeout=0.5)
338 niri.join(timeout=0.5)
339
340 if not (niri.is_alive() and server_thread.is_alive()):
341 break
342 '';
343 };
344 };
345 systemd.user.services.niri-workspace-sort = {
346 Unit = {
347 BindsTo = [ "niri.service" ];
348 After = [ "niri.service" ];
349 };
350 Install = {
351 WantedBy = [ "niri.service" ];
352 };
353 Service = {
354 Type = "simple";
355 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
356 import os
357 import sys
358 import socket
359 import json
360
361 outputs = None
362 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
363
364
365 class Niri(socket.socket):
366 def __init__(self):
367 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
368 super().connect(os.environ["NIRI_SOCKET"])
369 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
370
371 def cmd(self, obj):
372 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
373
374 def event_stream(self):
375 self.cmd("EventStream")
376 return self.fh
377
378
379 with Niri() as niri, Niri().event_stream() as niri_stream:
380 for line in niri_stream:
381 workspaces = None
382 if line_json := json.loads(line):
383 if "WorkspacesChanged" in line_json:
384 workspaces = line_json["WorkspacesChanged"]["workspaces"]
385
386 if workspaces is None:
387 continue
388
389 old_outputs = outputs
390 outputs = {ws["output"] for ws in workspaces}
391 if old_outputs is None:
392 print("Initial outputs: {}".format(outputs), file=sys.stderr)
393 continue
394
395 new_outputs = outputs - old_outputs
396 if not new_outputs:
397 continue
398 print("New outputs: {}".format(new_outputs), file=sys.stderr)
399
400 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
401 target_output = next(iter(outputs - set(only.keys())))
402 if not target_output:
403 continue
404 for ws in relevant_workspaces:
405 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
406 if ws["output"] not in set(only.keys()):
407 continue
408 if ws_ident in only[ws["output"]]:
409 continue
410
411 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
412 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
413 '';
414 Restart = "on-failure";
415 RestartSec = 10;
416 };
417 };
418
419 programs.niri.scratchspaces = [
420 { name = "pwctl";
421 key = "Mod+Control+A";
422 spawn = ["pwvucontrol"];
423 app-id = "com.saivert.pwvucontrol";
424 }
425 { name = "kpxc";
426 exclude = [
427 { title = "^Unlock Database.*"; }
428 { title = "^Access Request.*"; }
429 { title = ".*Passkey credentials$"; }
430 ];
431 windowRuleExtra = with kdl; [
432 (sleaf "open-focused" false)
433 ];
434 key = "Mod+Control+P";
435 app-id = "org.keepassxc.KeePassXC";
436 spawn = [ "keepassxc" ];
437 }
438 { name = "bmgr";
439 key = "Mod+Control+B";
440 app-id = ".blueman-manager-wrapped";
441 spawn = [ "blueman-manager" ];
442 }
443 { name = "term";
444 key = "Mod+Control+Return";
445 app-id = "Alacritty-scratch";
446 spawn = spawnTerminal { extraArgs = ["--class" "Alacritty-scratch"]; };
447 }
448 { name = "edit";
449 match = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
450 key = "Mod+Control+E";
451 selector = "select(.app_id == \"emacs\" and .title == \"scratch\")";
452 spawn = [ "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))" ];
453 }
454 { name = "eff";
455 key = "Mod+Control+O";
456 app-id = "com.github.wwmm.easyeffects";
457 spawn = [ "easyeffects" ];
458 }
459 { name = "time";
460 key = "Mod+Control+K";
461 app-id = "chrome-kimai.yggdrasil.li__-Default";
462 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
463 interpreter = pkgs.runtimeShell;
464 inputs = [ pkgs.dex ];
465 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
466 } ''
467 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
468 '')) ];
469 windowRuleExtra = with kdl; [
470 (sleaf "block-out-from" "screencast")
471 ];
472 }
473 ];
474 programs.niri.config =
475 let
476 inherit (kdl) node plain leaf flag;
477 optional-node = cond: v:
478 if cond
479 then v
480 else null;
481 opt-props = lib.filterAttrs (lib.const (value: value != null));
482 normalize-nodes = nodes: lib.remove null (lib.flatten nodes);
483 in
484 normalize-nodes [
485 (flag "prefer-no-csd")
486
487 (sleaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png")
488
489 (plain "hotkey-overlay" [
490 (flag "skip-at-startup")
491 ])
492
493 (plain "input" [
494 (plain "keyboard" [
495 (sleaf "repeat-delay" 300)
496 (sleaf "repeat-rate" 50)
497
498 (plain "xkb" [
499 (sleaf "layout" "us,us")
500 (sleaf "variant" "dvp,")
501 (sleaf "options" "compose:caps,grp:win_space_toggle")
502 ])
503 ])
504
505 (flag "workspace-auto-back-and-forth")
506 # (sleaf "focus-follows-mouse" {})
507 # (flag "warp-mouse-to-focus")
508
509 # (plain "touchpad" [ (flag "off") ])
510 (plain "trackball" [
511 (sleaf "scroll-method" "on-button-down")
512 (sleaf "scroll-button" 278)
513 ])
514 (plain "touch" [
515 (sleaf "map-to-output" "eDP-1")
516 ])
517 (plain "tablet" [
518 (sleaf "map-to-output" "eDP-1")
519 ])
520 ])
521
522 (plain "gestures" [
523 (plain "hot-corners" [(flag "off")])
524 ])
525
526 (plain "environment" (lib.mapAttrsToList sleaf execEnvironment))
527
528 (node "output" ["eDP-1"] [
529 (sleaf "scale" 1.5)
530 (sleaf "position" { x = 0; y = 0; })
531 ])
532 (node "output" ["Ancor Communications Inc ASUS PB287Q 0x0000DD9B"] [
533 (sleaf "scale" 1.5)
534 (sleaf "position" { x = 2560; y = 0; })
535 ])
536 (node "output" ["HP Inc. HP 727pu CN4417143K"] [
537 (sleaf "mode" "2560x1440@119.998")
538 (sleaf "scale" 1)
539 (sleaf "position" { x = 2560; y = 0; })
540 (flag "variable-refresh-rate")
541 ])
542
543 (plain "debug" [
544 (sleaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render")
545 ])
546
547 (plain "animations" [
548 (sleaf "slowdown" 0.5)
549 (plain "workspace-switch" [(flag "off")])
550 ])
551
552 (plain "layout" [
553 (sleaf "gaps" 8)
554 (plain "struts" [
555 (sleaf "left" 26)
556 (sleaf "right" 26)
557 (sleaf "top" 0)
558 (sleaf "bottom" 0)
559 ])
560 (plain "border" [
561 (sleaf "width" 2)
562 (sleaf "active-gradient" {
563 from = "hsla(195 100% 45% 1)";
564 to = "hsla(155 100% 37.5% 1)";
565 angle = 29;
566 relative-to = "workspace-view";
567 })
568 (sleaf "inactive-gradient" {
569 from = "hsla(0 0% 27.7% 1)";
570 to = "hsla(0 0% 23% 1)";
571 angle = 29;
572 relative-to = "workspace-view";
573 })
574 ])
575 (plain "focus-ring" [
576 (flag "off")
577 ])
578
579 (plain "preset-column-widths" (map (prop: sleaf "proportion" prop) [
580 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.)
581 ]))
582 (plain "default-column-width" [ (sleaf "proportion" (1. / 2.)) ])
583 (plain "preset-window-heights" (map (prop: sleaf "proportion" prop) [
584 (1. / 3.) (1. / 2.) (2. / 3.) (1.)
585 ]))
586
587 (flag "always-center-single-column")
588
589 (plain "tab-indicator" [
590 (sleaf "gap" 4)
591 (sleaf "width" 8)
592 (sleaf "gaps-between-tabs" 4)
593 (flag "place-within-column")
594 (sleaf "length" { total-proportion = 1.; })
595 (sleaf "active-gradient" {
596 from = "hsla(195 100% 60% 0.75)";
597 to = "hsla(155 100% 50% 0.75)";
598 angle = 29;
599 relative-to = "workspace-view";
600 })
601 (sleaf "inactive-gradient" {
602 from = "hsla(0 0% 42% 0.66)";
603 to = "hsla(0 0% 35% 0.66)";
604 angle = 29;
605 relative-to = "workspace-view";
606 })
607 ])
608 ])
609
610 (plain "cursor" [
611 (flag "hide-when-typing")
612 ])
613
614 (map (name:
615 (node "workspace" [name] [
616 (sleaf "open-on-output" "eDP-1")
617 ])
618 ) (map ({name, ...}: name) cfg.scratchspaces))
619 (map (name:
620 (sleaf "workspace" name)
621 ) ["comm" "web" "vid" "bmr"])
622
623 (plain "window-rule" [
624 (sleaf "clip-to-geometry" true)
625 ])
626
627 (plain "window-rule" [
628 (sleaf "match" { is-floating = true; })
629 (sleaf "geometry-corner-radius" 8)
630 (plain "shadow" [ (flag "on") ])
631 ])
632
633 (plain "window-rule" [
634 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; })
635 (sleaf "block-out-from" "screencast")
636 ])
637 (plain "window-rule" (normalize-nodes [
638 (map (title:
639 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
640 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
641 (sleaf "open-focused" true)
642 (sleaf "open-floating" true)
643 ]))
644
645 (map ({ name, match, exclude, windowRuleExtra, ... }:
646 (optional-node (match != []) (plain "window-rule" (normalize-nodes [
647 (map (sleaf "match") match)
648 (map (sleaf "exclude") exclude)
649 (sleaf "open-on-workspace" name)
650 (sleaf "open-maximized" true)
651 windowRuleExtra
652 ])))
653 ) cfg.scratchspaces)
654
655 (plain "window-rule" [
656 (sleaf "match" { app-id = "^emacs$"; })
657 (sleaf "match" { app-id = "^firefox$"; })
658 (sleaf "match" { app-id = "^gnucash$"; })
659 (sleaf "exclude" { app-id = "^gnucash$"; title = "^(Securities|Price Database)$"; })
660 (plain "default-column-width" [(sleaf "proportion" (2. / 3.))])
661 ])
662 (plain "window-rule" [
663 (sleaf "match" { app-id = "^Alacritty$"; })
664 (sleaf "match" { app-id = "^Alacritty-play$"; })
665 (plain "default-column-width" [(sleaf "proportion" (1. / 3.))])
666 ])
667
668 (plain "window-rule" [
669 (sleaf "match" { app-id = "^thunderbird$"; })
670 (sleaf "match" { app-id = "^Element$"; })
671 (sleaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
672 (sleaf "open-on-workspace" "comm")
673 ])
674 (plain "window-rule" [
675 (sleaf "match" { app-id = "^firefox$"; })
676 (sleaf "open-on-workspace" "web")
677 (sleaf "open-maximized" true)
678 ])
679 (plain "window-rule" [
680 (sleaf "match" { app-id = "^mpv$"; })
681 (sleaf "open-on-workspace" "vid")
682 (plain "default-column-width" [(sleaf "proportion" 1.)])
683 ])
684 (plain "window-rule" [
685 (sleaf "match" { app-id = "^Alacritty-play$"; })
686 (sleaf "open-on-workspace" "vid")
687 (sleaf "open-focused" false)
688 ])
689 (plain "window-rule" [
690 (sleaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
691 (sleaf "match" { app-id = "^YouTube Music Desktop App$"; })
692 (sleaf "open-on-workspace" "vid")
693 ])
694 (plain "window-rule" [
695 (sleaf "match" { app-id = "^pdfpc$"; })
696 (plain "default-column-width" [(sleaf "proportion" 1.)])
697 ])
698 (plain "window-rule" [
699 (sleaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; })
700 (plain "default-column-width" [(sleaf "proportion" 1.)])
701 (sleaf "open-fullscreen" true)
702 (sleaf "open-on-workspace" "bmr")
703 (sleaf "open-focused" false)
704 ])
705 (plain "window-rule" (normalize-nodes [
706 (map (sleaf "match") [
707 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
708 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; }
709 { app-id = "^xdg-desktop-portal-gtk$"; }
710 ])
711 (sleaf "open-floating" true)
712 ]))
713 (plain "window-rule" [
714 (sleaf "match" { app-id = "^org\\.pwmt\\.zathura$"; })
715 (sleaf "match" { app-id = "^evince$"; })
716 (sleaf "match" { app-id = "^org\\.gnome\\.Papers$"; })
717 (sleaf "default-column-display" "tabbed")
718 ])
719 (plain "window-rule" [
720 (sleaf "match" { is-window-cast-target = true; })
721 (plain "border" [
722 (sleaf "width" 2)
723 (sleaf "active-gradient" {
724 from = "hsla(20 100% 45% 1)";
725 to = "hsla(340 100% 37.5% 1)";
726 angle = 29;
727 relative-to = "workspace-view";
728 })
729 (sleaf "inactive-gradient" {
730 from = "hsla(20 50% 27.7% 1)";
731 to = "hsla(340 50% 23% 1)";
732 angle = 29;
733 relative-to = "workspace-view";
734 })
735 ])
736 ])
737
738 (plain "layer-rule" [
739 (sleaf "match" { namespace = "^notifications$"; })
740 (sleaf "match" { namespace = "^bar$"; })
741 (sleaf "match" { namespace = "^launcher$"; })
742 (sleaf "block-out-from" "screencast")
743 ])
744
745 (plain "recent-windows" [
746 (flag "off")
747 ])
748
749 (plain "binds"
750 (let
751 bind = name: cfg: node name [(lib.removeAttrs cfg ["action"])] (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
752
753 move-column-to-workspace = kdl.magic-leaf "move-column-to-workspace";
754 screenshot = kdl.magic-leaf "screenshot";
755 screenshot-window = kdl.magic-leaf "screenshot-window";
756 screenshot-screen = kdl.magic-leaf "screenshot-screen";
757 in
758 normalize-nodes [
759 (lib.mapAttrsToList bind (with config.lib.niri.actions; {
760 "Mod+Slash".action = show-hotkey-overlay;
761
762 "Mod+Return".action = spawn (spawnTerminal {});
763 "Mod+Shift+Return".action = spawn (spawnTerminal {
764 command = lib.getExe config.programs.nushell.package;
765 });
766 "Mod+Q".action = close-window;
767 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
768 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
769
770 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
771 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
772 name = "queue-yt-dlp";
773 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
774 text = ''
775 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
776 '';
777 }));
778 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
779 name = "queue-yt-dlp";
780 runtimeInputs = with pkgs; [ wl-clipboard-rs ];
781 text = ''
782 exec -- ${lib.concatStringsSep " " (spawnTerminal {
783 extraArgs = [ "--class" "Alacritty-play" "--working-directory" "\"$HOME\"/media" ];
784 command = ["mpv" "\"$(wl-paste)\""];
785 })}
786 '';
787 }));
788 "Mod+Alt+M".action = spawn (lib.getExe' pkgs.screen-message "sm") "-n" "Fira Mono" "-a" "1" "-f" "#fff" "-b" "#000";
789
790 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
791 name = "qalc-fuzzel";
792 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
793 text = ''
794 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
795 prev() {
796 FOUND=false
797 while IFS= read -r line; do
798 [[ -n "$line" ]] || continue
799 FOUND=true
800 echo "$line"
801 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)
802 $FOUND || echo
803 }
804 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
805 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
806 QALC_RES="$FUZZEL_RES"
807 QALC_RET=0
808 else
809 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
810 QALC_RET=$?
811 fi
812 [[ -n "$QALC_RES" ]] || exit 1
813 EXISTING=false
814 set +o pipefail
815 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
816 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
817 set -o pipefail
818 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
819 set +o pipefail
820 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
821 set -o pipefail
822 cat >"$RES_FILE" <<<"$QALC_RES"
823 fi
824 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
825 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
826 notify-send "$QALC_RES"
827 '';
828 }));
829 "Mod+Shift+U".action = spawn (spawnTerminal {
830 command = lib.getExe pkgs.libqalculate;
831 });
832 # "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
833 # name = "emoji-fuzzel";
834 # runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
835 # text = ''
836 # FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
837 # [[ -n "$FUZZEL_RES" ]] || exit 1
838 # wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
839 # '';
840 # }));
841 "Print".action = screenshot;
842 "Control+Print".action = screenshot-window;
843 "Shift+Print".action = screenshot-screen;
844 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
845 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
846
847 "Mod+Escape" = {
848 allow-inhibiting = false;
849 action = toggle-keyboard-shortcuts-inhibit;
850 };
851
852 "Mod+H".action = focus-column-left;
853 "Mod+T".action = focus-window-down;
854 "Mod+N".action = focus-window-up;
855 "Mod+S".action = focus-column-right;
856
857 "Mod+Shift+H".action = move-column-left;
858 "Mod+Shift+T".action = move-window-down;
859 "Mod+Shift+N".action = move-window-up;
860 "Mod+Shift+S".action = move-column-right;
861
862 "Mod+Control+H".action = focus-monitor-left;
863 "Mod+Control+T".action = focus-monitor-down;
864 "Mod+Control+N".action = focus-monitor-up;
865 "Mod+Control+S".action = focus-monitor-right;
866
867 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
868 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
869 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
870 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
871
872 "Mod+G".action = focus-adjacent-workspace "down";
873 "Mod+C".action = focus-adjacent-workspace "up";
874
875 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
876 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
877
878 "Mod+Shift+Control+G".action = move-workspace-down;
879 "Mod+Shift+Control+C".action = move-workspace-up;
880
881 "Mod+ParenLeft".action = focus-workspace "comm";
882 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
883
884 "Mod+ParenRight".action = focus-workspace "web";
885 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
886
887 "Mod+BraceRight".action = focus-workspace "read";
888 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
889
890 "Mod+BraceLeft".action = focus-workspace "mon";
891 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
892
893 "Mod+Asterisk".action = focus-workspace "vid";
894 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
895
896 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
897 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
898
899 "Mod+M".action = consume-or-expel-window-left;
900 "Mod+W".action = consume-or-expel-window-right;
901
902 "Mod+Shift+M".action = toggle-column-tabbed-display;
903
904 "Mod+L".action = maximize-window-to-edges;
905 "Mod+R".action = switch-preset-column-width;
906 "Mod+Shift+R".action = maximize-column;
907 "Mod+Shift+Ctrl+R".action = switch-preset-window-height;
908 "Mod+F".action = center-column;
909 "Mod+Shift+F".action = toggle-windowed-fullscreen;
910 "Mod+Ctrl+Shift+F".action = fullscreen-window;
911
912 "Mod+V".action = switch-focus-between-floating-and-tiling;
913 "Mod+Shift+V".action = toggle-window-floating;
914
915 "Mod+Left".action = set-column-width "-10%";
916 "Mod+Down".action = set-window-height "-10%";
917 "Mod+Up".action = set-window-height "+10%";
918 "Mod+Right".action = set-column-width "+10%";
919
920 "Mod+Shift+Z" = {
921 action = power-off-monitors;
922 allow-when-locked = true;
923 };
924 "Mod+Shift+E".action = quit;
925
926 # "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
927 # "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
928 # "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
929 # "Mod+Comma".action = spawn makoctl "restore";
930
931 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
932 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
933
934 "Mod+X".action = set-dynamic-cast-window;
935 "Mod+Shift+X".action = set-dynamic-cast-monitor;
936 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
937
938 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
939 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
940
941 "Mod+K".action = spawn (toString (pkgs.resholve.writeScript "worktime-ui" {
942 interpreter = pkgs.runtimeShell;
943 inputs = [ pkgs.worktime config.programs.quickshell.package ];
944 execer = [
945 "cannot:${lib.getExe' config.programs.quickshell.package "qs"}"
946 ];
947 } ''
948 worktime-ui && qs ipc call Worktime refresh
949 ''));
950 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
951 }))
952 (lib.mapAttrsToList (name: cfg: node name [(lib.removeAttrs cfg ["action"])] [cfg.action]) (let
953 shell = obj: leaf "send-unix" [
954 { path = ''''${XDG_RUNTIME_DIR}/shell.sock''; }
955 (builtins.toJSON obj + "\n")
956 ];
957 in {
958 "XF86AudioRaiseVolume" = {
959 allow-when-locked = true;
960 action = shell { Volume.volume = "up"; };
961 };
962 "XF86AudioLowerVolume" = {
963 allow-when-locked = true;
964 action = shell { Volume.volume = "down"; };
965 };
966 "XF86AudioMute" = {
967 allow-when-locked = true;
968 action = shell { Volume.muted = "toggle"; };
969 };
970 "XF86AudioMicMute" = {
971 allow-when-locked = true;
972 action = shell { Volume."mic-muted" = "toggle"; };
973 };
974 "XF86MonBrightnessUp" = {
975 action = shell { Brightness = "up"; };
976 allow-when-locked = true;
977 };
978 "XF86MonBrightnessDown" = {
979 action = shell { Brightness = "down"; };
980 allow-when-locked = true;
981 };
982 "Mod+Shift+L".action = shell { LockSession = {}; };
983 "Mod+Shift+Minus" = {
984 action = shell { Suspend = {}; };
985 allow-when-locked = true;
986 };
987 "Mod+Shift+Control+Minus" = {
988 action = shell { Hibernate = {}; };
989 allow-when-locked = true;
990 };
991 "Mod+Shift+P" = {
992 action = shell { Mpris = { PauseAll = {}; }; };
993 allow-when-locked = true;
994 };
995 "Mod+Semicolon".action = shell { Notifications = { DismissGroup = {}; }; };
996 "Mod+Shift+Semicolon".action = shell { Notifications = { DismissAll = {}; }; };
997 "Mod+Print".action = shell { ScreenRecord = { Toggle = {}; }; };
998 }))
999 (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)
1000 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = move-column-to-workspace name; } else null) cfg.scratchspaces)
1001 ]
1002 ))
1003 ];
1004 };
1005}
diff --git a/accounts/gkleen@skadhi/shell/default.nix b/accounts/gkleen@skadhi/shell/default.nix
new file mode 100644
index 00000000..09eb6863
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/default.nix
@@ -0,0 +1,123 @@
1{ config, pkgs, lib, ... }:
2
3{
4 config = {
5 programs.quickshell = {
6 enable = true;
7 package = pkgs.symlinkJoin {
8 pname = pkgs.quickshell.pname + "-wrapped";
9 inherit (pkgs.quickshell) version meta;
10 paths = [ pkgs.quickshell ];
11 buildInputs = [ pkgs.makeWrapper ];
12 postBuild = ''
13 for binary in quickshell qs; do
14 wrapProgram $out/bin/$binary \
15 --prefix QT_PLUGIN_PATH : ${pkgs.qt6.qtimageformats}/${pkgs.qt6.qtbase.qtPluginPrefix} \
16 --prefix QML_IMPORT_PATH : ${pkgs.qt6Packages.callPackage ./quickshell-plugins {}}/${pkgs.qt6.qtbase.qtQmlPrefix}
17 done
18 '';
19 };
20 config = {
21 src = ./quickshell;
22 replacements = {
23 ignore_workspaces = builtins.toJSON (map ({ name, ... }: name) config.programs.niri.scratchspaces);
24 wallpapers = builtins.toJSON (pkgs.stdenvNoCC.mkDerivation {
25 name = "wallpapers";
26 srcs = [
27 (pkgs.fetchurl {
28 url = "https://esawebb.org/media/archives/images/publicationtiff10k/carinanebula3.tif";
29 hash = "sha256-YxZEweDKJfvfrdxb/QFmgJhcZDEJYxotoHrG+RRn1tw=";
30 })
31 (pkgs.fetchurl {
32 url = "https://esawebb.org/media/archives/images/original/pillarsofcreation_composite.tif";
33 hash = "sha256-qRiODxR0lZWdxgYXna0fNRFFDErpBJDwOJuQl6sNjRc=";
34 })
35 (pkgs.fetchurl {
36 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2212a.tif";
37 hash = "sha256-l2fqE/z//C1a0xkvZwsnwPbTSb+WuA11h+SUl3E1dhw=";
38 })
39 (pkgs.fetchurl {
40 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2415a.tif";
41 hash = "sha256-onBy7cPoUpDuzQStbY2E+qmlGgSLXPwFCLX53ukAb4c=";
42 })
43 (pkgs.fetchurl {
44 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2330a.tif";
45 hash = "sha256-nn0ZtjZIrPcpj3YcLTsrL7XiXvyh3QYgCSmdDMD+3OM=";
46 })
47 (pkgs.fetchurl {
48 url = "https://esawebb.org/media/archives/images/original/weic2426a.tif";
49 hash = "sha256-EDnfPn3GE9jt6XPqiGInP7E2F3Az7d25NqATSWltDv0=";
50 })
51 (pkgs.fetchurl {
52 url = "https://esawebb.org/media/archives/images/original/weic2503a.tif";
53 hash = "sha256-3/RX6RQp8naELcgReHPd5/zhJkoCjnA10w5BEnNo+qI=";
54 })
55 (pkgs.fetchurl {
56 url = "https://esawebb.org/media/archives/images/original/weic2506a.tif";
57 hash = "sha256-aDld0aoY1owRxDVf7Jcyw71TH42M1foYotxn2thyFYw=";
58 })
59 (pkgs.fetchurl {
60 url = "https://esawebb.org/media/archives/images/original/weic2514a.tif";
61 hash = "sha256-jTi1G1Ofo5xsF6ggrbtYJHxqLaCQ7edM5B3uORiVQtg=";
62 })
63 (pkgs.fetchurl {
64 url = "https://esawebb.org/media/archives/images/original/weic2425c.tif";
65 hash = "sha256-oaEOexSJHEGj090dJF3ct5HAoR+Y5gRiPrUlxdvnTRo=";
66 })
67 (pkgs.fetchurl {
68 url = "https://esawebb.org/media/archives/images/original/weic2605c.tif";
69 hash = "sha256-IwWfgkz84LFXkfk77anb5e0Mf0wWiIszum7UC3yZn0U=";
70 })
71 ];
72
73 dontUnpack = true;
74
75 buildInputs = [ pkgs.imagemagick ];
76 buildPhase = ''
77 runHook preBuild
78
79 typeset sources=($srcs)
80
81 mkdir -p $out
82 magick ''${sources[0]} -crop 10000x5625+0+79 +repage -define webp:target-size=10000000 $out/carinanebula3.webp
83 magick ''${sources[1]} -crop 6716x3778+329+80 +repage -define webp:target-size=10000000 $out/pillarsofcreation_composite.webp
84 magick ''${sources[2]} -crop 10000x5625+0+79 +repage -define webp:target-size=10000000 $out/weic2212a.webp
85 magick ''${sources[3]} -crop 7650x4302+1166+389 +repage -define webp:target-size=10000000 $out/weic2415a.webp
86 magick ''${sources[4]} -crop 8732x4912+0+434 +repage -define webp:target-size=10000000 $out/weic2330a.webp
87 magick ''${sources[5]} -crop 5302x2982+636+0 +repage -define webp:target-size=10000000 $out/weic2426a.webp
88 magick ''${sources[6]} -crop 4328x2434+0+906 +repage -define webp:target-size=10000000 $out/weic2503a.webp
89 magick ''${sources[7]} -crop 4152x2335+0+666 +repage -define webp:target-size=10000000 $out/weic2506a.webp
90 magick ''${sources[8]} -crop 4320x2430+0+0 +repage -define webp:target-size=10000000 $out/weic2514a.webp
91 magick ''${sources[9]} -crop 5863x3298+0+477 +repage -define webp:target-size=10000000 $out/weic2425c.webp
92 magick ''${sources[10]} -crop 3990x2244+0+1379 +repage -define webp:target-size=10000000 $out/weic2605c.webp
93
94 runHook postBuild
95 '';
96 });
97 niri_session = builtins.toJSON [
98 (pkgs.writeShellScript "niri-session" ''
99 exec ${lib.getExe pkgs.dex} -w ${config.programs.niri.package}/share/wayland-sessions/niri.desktop &>/tmp/niri-session-$$.log
100 '')
101 # (lib.getExe pkgs.dex)
102 # "${config.programs.niri.package}/share/wayland-sessions/niri.desktop"
103 ];
104 username = builtins.toJSON config.home.username;
105 mdi = builtins.toJSON (pkgs.fetchFromGitHub {
106 owner = "Templarian";
107 repo = "MaterialDesign";
108 rev = "2424e748e0cc63ab7b9c095a099b9fe239b737c0";
109 hash = "sha256-QMGl7soAhErrrnY3aKOZpt49yebkSNzy10p/v5OaqQ0=";
110 });
111 worktime = builtins.toJSON (lib.getExe pkgs.worktime);
112 slurp = builtins.toJSON (lib.getExe pkgs.slurp);
113 wf-recorder = builtins.toJSON (lib.getExe pkgs.wf-recorder);
114 };
115 };
116 };
117 systemd.user.services.quickshell = {
118 Service = {
119 RuntimeDirectory = "quickshell";
120 };
121 };
122 };
123}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/CMakeLists.txt b/accounts/gkleen@skadhi/shell/quickshell-plugins/CMakeLists.txt
new file mode 100644
index 00000000..6b4f0d48
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/CMakeLists.txt
@@ -0,0 +1,190 @@
1set(INSTALL_QMLDIR "" CACHE STRING "QML install dir")
2set(INSTALL_QML_PREFIX "" CACHE STRING "QML install prefix")
3
4# There doesn't seem to be a standard cross-distro qml install path.
5if ("${INSTALL_QMLDIR}" STREQUAL "" AND "${INSTALL_QML_PREFIX}" STREQUAL "")
6 message(WARNING "Neither INSTALL_QMLDIR nor INSTALL_QML_PREFIX is set. QML modules will not be installed.")
7else()
8 if ("${INSTALL_QMLDIR}" STREQUAL "")
9 set(QML_FULL_INSTALLDIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_QML_PREFIX}")
10 else()
11 set(QML_FULL_INSTALLDIR "${INSTALL_QMLDIR}")
12 endif()
13
14 message(STATUS "QML install dir: ${QML_FULL_INSTALLDIR}")
15endif()
16
17# Install a given target as a QML module. This is mostly pulled from ECM, as there does not seem
18# to be an official way to do it.
19# see https://github.com/KDE/extra-cmake-modules/blob/fe0f606bf7f222e36f7560fd7a2c33ef993e23bb/modules/ECMQmlModule6.cmake#L160
20function(install_qml_module arg_TARGET)
21 if (NOT DEFINED QML_FULL_INSTALLDIR)
22 return()
23 endif()
24
25 qt_query_qml_module(${arg_TARGET}
26 URI module_uri
27 VERSION module_version
28 PLUGIN_TARGET module_plugin_target
29 TARGET_PATH module_target_path
30 QMLDIR module_qmldir
31 TYPEINFO module_typeinfo
32 QML_FILES module_qml_files
33 RESOURCES module_resources
34 )
35
36 set(module_dir "${QML_FULL_INSTALLDIR}/${module_target_path}")
37
38 if (NOT TARGET "${module_plugin_target}")
39 message(FATAL_ERROR "install_qml_modules called for a target without a plugin")
40 endif()
41
42 get_target_property(target_type "${arg_TARGET}" TYPE)
43 if (NOT "${target_type}" STREQUAL "STATIC_LIBRARY")
44 install(
45 TARGETS "${arg_TARGET}"
46 LIBRARY DESTINATION "${module_dir}"
47 RUNTIME DESTINATION "${module_dir}"
48 )
49
50 install(
51 TARGETS "${module_plugin_target}"
52 LIBRARY DESTINATION "${module_dir}"
53 RUNTIME DESTINATION "${module_dir}"
54 )
55 endif()
56
57 install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
58 install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")
59
60 # Install QML files
61 list(LENGTH module_qml_files num_files)
62 if (NOT "${module_qml_files}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
63 qt_query_qml_module(${arg_TARGET} QML_FILES_DEPLOY_PATHS qml_files_deploy_paths)
64
65 math(EXPR last_index "${num_files} - 1")
66 foreach(i RANGE 0 ${last_index})
67 list(GET module_qml_files ${i} src_file)
68 list(GET qml_files_deploy_paths ${i} deploy_path)
69 get_filename_component(dst_name "${deploy_path}" NAME)
70 get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
71 install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
72 endforeach()
73 endif()
74
75 # Install resources
76 list(LENGTH module_resources num_files)
77 if (NOT "${module_resources}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
78 qt_query_qml_module(${arg_TARGET} RESOURCES_DEPLOY_PATHS resources_deploy_paths)
79
80 math(EXPR last_index "${num_files} - 1")
81 foreach(i RANGE 0 ${last_index})
82 list(GET module_resources ${i} src_file)
83 list(GET resources_deploy_paths ${i} deploy_path)
84 get_filename_component(dst_name "${deploy_path}" NAME)
85 get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
86 install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
87 endforeach()
88 endif()
89endfunction()
90
91
92cmake_minimum_required(VERSION 3.20)
93project(custom LANGUAGES CXX)
94
95find_package(Qt6 REQUIRED COMPONENTS Core Qml DBus)
96
97qt_standard_project_setup(REQUIRES 6.6)
98
99qt6_policy(SET QTP0001 NEW)
100qt6_add_qml_module(customplugin
101 URI "Custom"
102 PLUGIN_TARGET customplugin
103)
104
105set_source_files_properties(org.keepassxc.KeePassXC.MainWindow.xml PROPERTIES
106 CLASSNAME DBusKeePassXC
107 NO_NAMESPACE TRUE
108)
109qt_add_dbus_interface(DBUS_INTERFACES
110 org.keepassxc.KeePassXC.MainWindow.xml
111 dbus_keepassxc
112)
113
114set_source_files_properties(org.freedesktop.systemd1.Manager.xml PROPERTIES
115 CLASSNAME DBusSystemdManager
116 NO_NAMESPACE TRUE
117 INCLUDE ListUnitsEntry.hpp
118)
119qt_add_dbus_interface(DBUS_INTERFACES
120 org.freedesktop.systemd1.Manager.xml
121 dbus_systemd_manager
122)
123
124set_source_files_properties(org.freedesktop.login1.Manager.xml PROPERTIES
125 CLASSNAME DBusLogindManager
126 NO_NAMESPACE TRUE
127)
128qt_add_dbus_interface(DBUS_INTERFACES
129 org.freedesktop.login1.Manager.xml
130 dbus_logind_manager
131)
132
133set_source_files_properties(org.freedesktop.login1.Session.xml PROPERTIES
134 CLASSNAME DBusLogindSession
135 NO_NAMESPACE TRUE
136)
137qt_add_dbus_interface(DBUS_INTERFACES
138 org.freedesktop.login1.Session.xml
139 dbus_logind_session
140)
141
142set_source_files_properties(org.freedesktop.systemd1.Unit.xml PROPERTIES
143 CLASSNAME DBusSystemdUnit
144 NO_NAMESPACE TRUE
145)
146qt_add_dbus_interface(DBUS_INTERFACES
147 org.freedesktop.systemd1.Unit.xml
148 dbus_systemd_unit
149)
150
151set_source_files_properties(org.freedesktop.systemd1.Service.xml PROPERTIES
152 CLASSNAME DBusSystemdService
153 NO_NAMESPACE TRUE
154)
155qt_add_dbus_interface(DBUS_INTERFACES
156 org.freedesktop.systemd1.Service.xml
157 dbus_systemd_service
158)
159
160set_source_files_properties(org.freedesktop.DBus.Properties.xml PROPERTIES
161 CLASSNAME DBusProperties
162 NO_NAMESPACE TRUE
163)
164qt_add_dbus_interface(DBUS_INTERFACES
165 org.freedesktop.DBus.Properties.xml
166 dbus_properties
167)
168
169include_directories(${CMAKE_SOURCE_DIR}/build)
170include_directories(${QUICKSHELL_SRC}/src)
171
172target_compile_features(customplugin PUBLIC cxx_std_26)
173
174target_link_libraries(customplugin PRIVATE
175 Qt6::Core
176 Qt6::Qml
177 Qt6::DBus
178)
179
180target_sources(customplugin PRIVATE
181 Chrono.cpp Chrono.hpp
182 FileSelector.cpp FileSelector.hpp
183 KeePassXC.cpp KeePassXC.hpp
184 Systemd.cpp Systemd.hpp
185 ListUnitsEntry.cpp ListUnitsEntry.hpp
186 ${DBUS_INTERFACES}
187 ${QUICKSHELL_SRC}/src/core/model.cpp ${QUICKSHELL_SRC}/src/core/model.hpp
188)
189
190install_qml_module(customplugin)
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.cpp
new file mode 100644
index 00000000..22b3469b
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.cpp
@@ -0,0 +1,83 @@
1#include "Chrono.hpp"
2
3#include <format>
4#include <iostream>
5#include <cmath>
6
7Chrono::Chrono(QObject* parent): QObject(parent) {
8 QObject::connect(&this->timer, &QTimer::timeout, this, &Chrono::onTimeout);
9 this->update();
10}
11
12bool Chrono::enabled() const { return this->mEnabled; }
13
14void Chrono::setEnabled(bool enabled) {
15 if (enabled == this->mEnabled) return;
16 this->mEnabled = enabled;
17 emit this->enabledChanged();
18 this->update();
19}
20
21Chrono::Precision Chrono::precision() const { return this->mPrecision; }
22
23void Chrono::setPrecision(Chrono::Precision precision) {
24 if (precision == this->mPrecision) return;
25 this->mPrecision = precision;
26 emit this->precisionChanged();
27 this->update();
28}
29
30void Chrono::onTimeout() {
31 this->setTime(this->targetTime);
32 this->schedule(this->targetTime);
33}
34
35void Chrono::update() {
36 if (this->mEnabled) {
37 this->setTime(std::chrono::time_point<std::chrono::system_clock>());
38 this->schedule(std::chrono::time_point<std::chrono::system_clock>());
39 } else {
40 this->timer.stop();
41 }
42}
43
44void Chrono::setTime(const std::chrono::time_point<std::chrono::system_clock>& targetTime) {
45 using namespace std::chrono_literals;
46
47 auto currentTime = std::chrono::system_clock::now();
48 auto offset = std::chrono::duration_cast<std::chrono::milliseconds>(targetTime - currentTime);
49 this->currentTime = abs(offset) < 500ms ? targetTime : currentTime;
50
51 switch (this->mPrecision) {
52 case Chrono::Hours: this->currentTime = std::chrono::time_point_cast<std::chrono::hours>(this->currentTime);
53 case Chrono::Minutes: this->currentTime = std::chrono::time_point_cast<std::chrono::minutes>(this->currentTime);
54 case Chrono::Seconds: this->currentTime = std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime);
55 }
56
57 emit this->dateChanged();
58}
59
60void Chrono::schedule(const std::chrono::time_point<std::chrono::system_clock>& targetTime) {
61 using namespace std::chrono_literals;
62
63 auto currentTime = std::chrono::system_clock::now();
64 auto offset = std::chrono::duration_cast<std::chrono::milliseconds>(targetTime - currentTime);
65 auto nextTime = abs(offset) < 500ms ? targetTime : currentTime;
66
67 switch (this->mPrecision) {
68 case Chrono::Hours: nextTime = std::chrono::time_point_cast<std::chrono::hours>(nextTime) + 1h;
69 case Chrono::Minutes: nextTime = std::chrono::time_point_cast<std::chrono::minutes>(nextTime) + 1min;
70 case Chrono::Seconds: nextTime = std::chrono::time_point_cast<std::chrono::seconds>(nextTime) + 1s;
71 }
72
73 this->targetTime = nextTime;
74 this->timer.start(std::chrono::duration_cast<std::chrono::milliseconds>(nextTime - currentTime));
75}
76
77QString Chrono::format(const QString& fmt) const {
78 return QString::fromStdString(std::format(std::runtime_format(fmt.toStdString()), std::chrono::zoned_time(std::chrono::current_zone(), std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime))));
79}
80
81QDateTime Chrono::date() const {
82 return QDateTime::fromStdTimePoint(std::chrono::time_point_cast<std::chrono::milliseconds>(this->currentTime));
83}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.hpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.hpp
new file mode 100644
index 00000000..04080187
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/Chrono.hpp
@@ -0,0 +1,55 @@
1#pragma once
2
3#include <chrono>
4
5#include <QDateTime>
6#include <QObject>
7#include <QTimer>
8
9#include <qqmlintegration.h>
10
11class Chrono : public QObject {
12 Q_OBJECT;
13 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
14 Q_PROPERTY(Chrono::Precision precision READ precision WRITE setPrecision NOTIFY precisionChanged);
15 Q_PROPERTY(QDateTime date READ date NOTIFY dateChanged)
16 QML_ELEMENT;
17
18public:
19 enum Precision : quint8 {
20 Hours = 1,
21 Minutes = 2,
22 Seconds = 3,
23 };
24 Q_ENUM(Precision);
25
26 explicit Chrono(QObject* parent = nullptr);
27
28 bool enabled() const;
29 void setEnabled(bool enabled);
30
31 Chrono::Precision precision() const;
32 void setPrecision(Chrono::Precision precision);
33
34 Q_INVOKABLE QString format(const QString& fmt) const;
35
36 QDateTime date() const;
37
38signals:
39 void enabledChanged();
40 void precisionChanged();
41 void dateChanged();
42
43private slots:
44 void onTimeout();
45
46private:
47 bool mEnabled = true;
48 Chrono::Precision mPrecision = Chrono::Seconds;
49 QTimer timer;
50 std::chrono::time_point<std::chrono::system_clock> currentTime, targetTime;
51
52 void update();
53 void setTime(const std::chrono::time_point<std::chrono::system_clock>& targetTime);
54 void schedule(const std::chrono::time_point<std::chrono::system_clock>& targetTime);
55};
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.cpp
new file mode 100644
index 00000000..d7051d2a
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.cpp
@@ -0,0 +1,102 @@
1#include "FileSelector.hpp"
2
3#include <sstream>
4#include <vector>
5#include <random>
6#include <algorithm>
7
8#include <iostream>
9#include <format>
10
11namespace fs = std::filesystem;
12
13FileSelector::FileSelector(QObject* parent): QObject(parent) {
14 QObject::connect(&this->timer, &QTimer::timeout, this, &FileSelector::onTimeout);
15 this->timer.setTimerType(Qt::PreciseTimer);
16}
17
18QString FileSelector::directory() const {
19 return QString::fromStdString(this->mDirectory->string());
20}
21void FileSelector::setDirectory(QString directory) {
22 this->mDirectory = directory.toStdString();
23 if (this->mDirectory && this->mEpoch)
24 this->update();
25 emit this->directoryChanged();
26}
27
28unsigned int FileSelector::epoch() const {
29 return std::chrono::duration_cast<std::chrono::milliseconds>(*this->mEpoch).count();
30}
31void FileSelector::setEpoch(unsigned int epoch) {
32 this->mEpoch = std::chrono::milliseconds{epoch};
33 if (this->mDirectory && this->mEpoch)
34 this->update();
35 emit this->epochChanged();
36}
37
38QString FileSelector::seed() const {
39 return this->mSeed;
40}
41void FileSelector::setSeed(QString seed) {
42 this->mSeed = seed;
43 emit this->seedChanged();
44 if (this->mDirectory && this->mEpoch)
45 emit this->selectedChanged();
46}
47
48QString FileSelector::selected() const {
49 if (!this->mDirectory || !this->mEpoch)
50 return QString();
51
52 std::vector<fs::path> shuffled(this->mFiles.begin(), this->mFiles.end());
53 std::sort(shuffled.begin(), shuffled.end());
54
55 auto currentTime = std::chrono::system_clock::now();
56 uint64_t currentEpoch = currentTime.time_since_epoch() / *this->mEpoch;
57 std::chrono::milliseconds timeInEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime.time_since_epoch()) % *this->mEpoch;
58
59 std::ostringstream seed;
60 seed << this->mSeed.size() << ";" << this->mSeed.toStdString() << ";";
61 seed << *this->mEpoch << ";";
62 seed << currentEpoch << ";";
63 seed << this->mDirectory->string().size() << ";" << *this->mDirectory << ";";
64 seed << this->mFiles.size() << ";";
65 for (const fs::path& p: this->mFiles)
66 seed << p.string().size() << ";" << p << ";";
67
68 std::vector<std::seed_seq::result_type> v;
69 v.reserve(seed.str().size());
70 for (const char& c: seed.str())
71 v.push_back(c);
72
73 std::seed_seq engine_seed(v.begin(), v.end());
74 std::mt19937 g(engine_seed);
75 std::shuffle(shuffled.begin(), shuffled.end(), g);
76
77 std::vector<fs::path>::size_type ix = shuffled.size() * timeInEpoch / *this->mEpoch;
78 return QString::fromStdString((*this->mDirectory / shuffled[ix]).string());
79}
80
81void FileSelector::onTimeout() {
82 if (!this->mFiles.size())
83 return;
84
85 auto currentTime = std::chrono::system_clock::now();
86 uint64_t currentMinorEpoch = currentTime.time_since_epoch() / (*this->mEpoch / this->mFiles.size());
87 auto nextTime = std::chrono::time_point<std::chrono::system_clock>((currentMinorEpoch + 1) * (*this->mEpoch / this->mFiles.size()));
88 this->timer.start(std::chrono::duration_cast<std::chrono::milliseconds>(nextTime - currentTime));
89
90 emit this->selectedChanged();
91}
92
93void FileSelector::update() {
94 this->mFiles = std::set<fs::path>{};
95 for (const fs::directory_entry& entry:
96 fs::recursive_directory_iterator(*this->mDirectory, fs::directory_options::follow_directory_symlink))
97 {
98 this->mFiles.insert(fs::relative(entry, *this->mDirectory));
99 }
100
101 this->onTimeout();
102}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.hpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.hpp
new file mode 100644
index 00000000..72c4f2a7
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/FileSelector.hpp
@@ -0,0 +1,52 @@
1#pragma once
2
3#include <filesystem>
4#include <chrono>
5#include <set>
6#include <optional>
7
8#include <QObject>
9#include <QTimer>
10
11#include <qqmlintegration.h>
12
13class FileSelector : public QObject {
14 Q_OBJECT;
15 Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged REQUIRED);
16 Q_PROPERTY(unsigned int epoch READ epoch WRITE setEpoch NOTIFY epochChanged REQUIRED);
17 Q_PROPERTY(QString seed READ seed WRITE setSeed NOTIFY seedChanged);
18 Q_PROPERTY(QString selected READ selected NOTIFY selectedChanged);
19 QML_ELEMENT;
20
21public:
22 explicit FileSelector(QObject* parent = nullptr);
23
24 QString directory() const;
25 void setDirectory(QString directory);
26
27 unsigned int epoch() const;
28 void setEpoch(unsigned int epoch);
29
30 QString seed() const;
31 void setSeed(QString seed);
32
33 QString selected() const;
34
35signals:
36 void directoryChanged();
37 void epochChanged();
38 void seedChanged();
39 void selectedChanged();
40
41private slots:
42 void onTimeout();
43
44private:
45 std::optional<std::filesystem::path> mDirectory;
46 std::optional<std::chrono::milliseconds> mEpoch;
47 std::set<std::filesystem::path> mFiles;
48 QString mSeed;
49 QTimer timer;
50
51 void update();
52};
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.cpp
new file mode 100644
index 00000000..f6e4dd6e
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.cpp
@@ -0,0 +1,18 @@
1#include "KeePassXC.hpp"
2
3#include <QDBusConnection>
4
5KeePassXC::KeePassXC() {
6 this->service = new DBusKeePassXC(DBusKeePassXC::staticInterfaceName(), "/keepassxc", QDBusConnection::sessionBus(), this);
7}
8KeePassXC::~KeePassXC() {
9 if (this->service)
10 delete this->service;
11}
12
13void KeePassXC::lockAllDatabases() {
14 if (!this->service)
15 return;
16
17 this->service->lockAllDatabases();
18}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.hpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.hpp
new file mode 100644
index 00000000..c4cd71e0
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/KeePassXC.hpp
@@ -0,0 +1,21 @@
1#pragma once
2
3#include "dbus_keepassxc.h"
4
5#include <QObject>
6#include <QtQmlIntegration/qqmlintegration.h>
7
8class KeePassXC : public QObject {
9 Q_OBJECT;
10 QML_SINGLETON;
11 QML_ELEMENT;
12
13public:
14 explicit KeePassXC();
15 ~KeePassXC();
16
17 Q_INVOKABLE void lockAllDatabases();
18
19private:
20 DBusKeePassXC* service = nullptr;
21};
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.cpp
new file mode 100644
index 00000000..c1f9537c
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.cpp
@@ -0,0 +1,41 @@
1#include "ListUnitsEntry.hpp"
2
3void ListUnitsEntry::registerMetaType() {
4 qRegisterMetaType<ListUnitsEntry>("ListUnitsEntry");
5 qDBusRegisterMetaType<ListUnitsEntry>();
6}
7
8QDBusArgument& operator<<(QDBusArgument& argument, const ListUnitsEntry& entry) {
9 argument.beginStructure();
10 argument
11 << entry.primaryName
12 << entry.description
13 << entry.loadState
14 << entry.activeState
15 << entry.subState
16 << entry.followingUnit
17 << entry.unitPath
18 << entry.jobId
19 << entry.jobType
20 << entry.jobPath;
21 argument.endStructure();
22
23 return argument;
24}
25const QDBusArgument& operator>>(const QDBusArgument& argument, ListUnitsEntry& entry) {
26 argument.beginStructure();
27 argument
28 >> entry.primaryName
29 >> entry.description
30 >> entry.loadState
31 >> entry.activeState
32 >> entry.subState
33 >> entry.followingUnit
34 >> entry.unitPath
35 >> entry.jobId
36 >> entry.jobType
37 >> entry.jobPath;
38 argument.endStructure();
39
40 return argument;
41}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.hpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.hpp
new file mode 100644
index 00000000..15d789b9
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/ListUnitsEntry.hpp
@@ -0,0 +1,26 @@
1#pragma once
2
3#include <QtDBus>
4#include <QtTypes>
5
6struct ListUnitsEntry {
7 QString primaryName;
8 QString description;
9 QString loadState;
10 QString activeState;
11 QString subState;
12 QString followingUnit;
13 QDBusObjectPath unitPath;
14 uint jobId;
15 QString jobType;
16 QDBusObjectPath jobPath;
17
18 friend QDBusArgument& operator<<(QDBusArgument& argument, const ListUnitsEntry& entry);
19 friend const QDBusArgument& operator>>(const QDBusArgument& argument, ListUnitsEntry& entry);
20 static void registerMetaType();
21};
22
23Q_DECLARE_METATYPE(ListUnitsEntry)
24
25using ListUnitsResult = QList<ListUnitsEntry>;
26Q_DECLARE_METATYPE(ListUnitsResult)
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
new file mode 100644
index 00000000..6376b527
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
@@ -0,0 +1,288 @@
1#include "Systemd.hpp"
2
3#include <sstream>
4
5#include <QDBusConnection>
6#include <QDBusReply>
7#include <QDebug>
8#include <QDBusUnixFileDescriptor>
9#include <QDBusObjectPath>
10
11#include <set>
12
13Systemd::Systemd(QObject* parent) : QObject(parent) {
14 ListUnitsEntry::registerMetaType();
15 qDBusRegisterMetaType<ListUnitsResult>();
16
17 this->systemdManager = new DBusSystemdManager(
18 "org.freedesktop.systemd1",
19 "/org/freedesktop/systemd1",
20 QDBusConnection::sessionBus(),
21 this
22 );
23 this->logindManager = new DBusLogindManager(
24 "org.freedesktop.login1",
25 "/org/freedesktop/login1",
26 QDBusConnection::systemBus(),
27 this
28 );
29
30
31 QDBusReply<QDBusObjectPath> sessionPath = this->logindManager->GetSession("auto");
32 // qDebug() << sessionPath;
33 this->logindSession = new DBusLogindSession(
34 "org.freedesktop.login1",
35 sessionPath.value().path(),
36 QDBusConnection::systemBus(),
37 this
38 );
39 this->logindSessionProperties = new DBusProperties(
40 "org.freedesktop.login1",
41 sessionPath.value().path(),
42 QDBusConnection::systemBus(),
43 this
44 );
45
46 QObject::connect(this->logindManager, &DBusLogindManager::PrepareForShutdown, this, &Systemd::shutdown);
47 QObject::connect(this->logindManager, &DBusLogindManager::PrepareForSleep, this, &Systemd::sleep);
48 QObject::connect(this->logindSession, &DBusLogindSession::Lock, this, &Systemd::lock);
49 QObject::connect(this->logindSession, &DBusLogindSession::Unlock, this, &Systemd::unlock);
50 QObject::connect(this->logindSessionProperties, &DBusProperties::PropertiesChanged, this, &Systemd::onLogindSessionPropertiesChanged);
51 this->systemdManager->Subscribe();
52 QObject::connect(this->systemdManager, &DBusSystemdManager::UnitNew, this, &Systemd::onUserUnitNew);
53 QObject::connect(this->systemdManager, &DBusSystemdManager::UnitRemoved, this, &Systemd::onUserUnitRemoved);
54
55 for (const auto& unit: this->systemdManager->ListUnits().value())
56 this->onUserUnitNew(unit.primaryName, unit.unitPath);
57}
58
59void Systemd::onLogindSessionPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties) {
60 if (changed_properties.contains("IdleHint") || invalidated_properties.contains("IdleHint"))
61 emit this->idleHintChanged();
62 if (changed_properties.contains("LockedHint") || invalidated_properties.contains("LockedHint"))
63 emit this->lockedHintChanged();
64}
65void Systemd::onUserUnitNew(const QString& id, const QDBusObjectPath& object_path) {
66 for (auto unit: this->mUserUnits.valueList())
67 if (unit->path() == object_path)
68 return;
69
70 for (const auto& unit: this->systemdManager->ListUnits().value())
71 if (unit.unitPath == object_path) {
72 this->mUserUnits.insertObject(new SystemdUnit(this, object_path, id));
73 return;
74 }
75}
76void Systemd::onUserUnitRemoved(const QString& id, const QDBusObjectPath& object_path) {
77 std::set<SystemdUnit*> toRemove;
78 for (auto unit: this->mUserUnits.valueList())
79 if (unit->path() == object_path)
80 toRemove.insert(unit);
81
82 for (auto unit: toRemove) {
83 this->mUserUnits.removeObject(unit);
84 delete unit;
85 }
86}
87
88SystemdUnit::SystemdUnit(QObject* parent, const QDBusObjectPath& path, const QString& id): QObject(parent), mPath(path), mId(id) {
89 this->mUnitProperties = new DBusProperties(
90 "org.freedesktop.systemd1",
91 this->path().path(),
92 QDBusConnection::sessionBus(),
93 this
94 );
95}
96std::unique_ptr<DBusSystemdUnit> SystemdUnit::systemdUnit() {
97 return std::make_unique<DBusSystemdUnit>(
98 "org.freedesktop.systemd1",
99 this->path().path(),
100 QDBusConnection::sessionBus(),
101 nullptr
102 );
103}
104std::unique_ptr<DBusSystemdService> SystemdUnit::systemdService() {
105 if (!this->id().endsWith(".service"))
106 return std::unique_ptr<DBusSystemdService>();
107
108 return std::make_unique<DBusSystemdService>(
109 "org.freedesktop.systemd1",
110 this->path().path(),
111 QDBusConnection::sessionBus(),
112 nullptr
113 );
114}
115QList<QString> SystemdUnit::runtimeDirectory() {
116 if (std::unique_ptr<DBusSystemdService> systemdService = this->systemdService()) {
117 if (!this->mRuntimeDirectory)
118 this->mRuntimeDirectory = systemdService->runtimeDirectory();
119 return *this->mRuntimeDirectory;
120 }
121
122 return QList<QString>{};
123}
124QString SystemdUnit::activeState() {
125 if (!this->mActiveState) {
126 QObject::connect(this->mUnitProperties, &DBusProperties::PropertiesChanged, this, &SystemdUnit::onUnitPropertiesChanged);
127 this->mActiveState = this->systemdUnit()->activeState();
128 }
129
130 return *this->mActiveState;
131}
132
133const QDBusObjectPath& SystemdUnit::path() const { return this->mPath; }
134const QString& SystemdUnit::id() const { return this->mId; }
135void SystemdUnit::onUnitPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties) {
136 if (changed_properties.contains("ActiveState") || invalidated_properties.contains("ActiveState")) {
137 this->mActiveState = this->systemdUnit()->activeState();
138 emit this->activeStateChanged();
139 }
140}
141
142void Systemd::stopUserUnit(const QString& unit, const QString& mode) { this->systemdManager->StopUnit(unit, mode); }
143
144void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { this->logindSession->SetBrightness(subsystem, name, brightness); }
145
146bool Systemd::idleHint() { return this->logindSession->idleHint(); }
147void Systemd::setIdleHint(bool idle) { this->logindSession->SetIdleHint(idle); }
148bool Systemd::lockedHint() { return this->logindSession->lockedHint(); }
149void Systemd::setLockedHint(bool locked) { this->logindSession->SetLockedHint(locked); }
150void Systemd::lockSession() { this->logindSession->call("Lock"); }
151void Systemd::suspend() { this->logindManager->Suspend(true); }
152void Systemd::hibernate() { this->logindManager->Hibernate(true); }
153
154ObjectModel<SystemdUnit>* Systemd::userUnits() { return &this->mUserUnits; }
155
156std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::WhatItem what) {
157 if (what == SystemdInhibitorParams::Shutdown)
158 return "shutdown";
159 else if (what == SystemdInhibitorParams::Sleep)
160 return "sleep";
161 else if (what == SystemdInhibitorParams::Idle)
162 return "idle";
163 else if (what == SystemdInhibitorParams::HandlePowerKey)
164 return "handle-power-key";
165 else if (what == SystemdInhibitorParams::HandleSuspendKey)
166 return "handle-suspend-key";
167 else if (what == SystemdInhibitorParams::HandleHibernateKey)
168 return "handle-hibernate-key";
169 else if (what == SystemdInhibitorParams::HandleLidSwitch)
170 return "handle-lid-switch";
171 return "";
172}
173
174std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::What what) {
175 std::ostringstream res;
176 bool first = true;
177 for (const WhatItem& item: SystemdInhibitorParams::allWhatItems) {
178 if (!(what & item))
179 continue;
180
181 if (!first)
182 res << ":";
183 else
184 first = false;
185 res << SystemdInhibitorParams::toString(item);
186 }
187 return res.str();
188}
189
190std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::Mode mode) {
191 if (mode == SystemdInhibitorParams::Block)
192 return "block";
193 else if (mode == SystemdInhibitorParams::BlockWeak)
194 return "block-weak";
195 else if (mode == SystemdInhibitorParams::Delay)
196 return "delay";
197 return "";
198}
199
200bool SystemdInhibitor::enabled() const { return static_cast<bool>(this->activeInhibitor); }
201void SystemdInhibitor::setEnabled(bool enabled) {
202 this->mEnabled = enabled;
203
204 if (enabled)
205 this->update();
206 else
207 this->release();
208}
209
210SystemdInhibitorParams::What SystemdInhibitor::what() const { return this->mWhat; }
211void SystemdInhibitor::setWhat(SystemdInhibitorParams::What what) {
212 this->mWhat = what;
213 this->update();
214}
215
216QString SystemdInhibitor::who() const { return this->mWho; }
217void SystemdInhibitor::setWho(QString who) {
218 this->mWho = who;
219 this->update();
220}
221
222QString SystemdInhibitor::why() const { return this->mWhy; }
223void SystemdInhibitor::setWhy(QString why) {
224 this->mWhy = why;
225 this->update();
226}
227
228SystemdInhibitorParams::Mode SystemdInhibitor::mode() const { return this->mMode; }
229void SystemdInhibitor::setMode(SystemdInhibitorParams::Mode mode) {
230 this->mMode = mode;
231 this->update();
232}
233
234SystemdInhibitor::ActiveSystemdInhibitor::ActiveSystemdInhibitor(SystemdInhibitorParams::What what_, QString who_, QString why_, SystemdInhibitorParams::Mode mode_): what(what_), who(who_), why(why_), mode(mode_) {
235 DBusLogindManager logindManager(
236 "org.freedesktop.login1",
237 "/org/freedesktop/login1",
238 QDBusConnection::systemBus()
239 );
240 QDBusReply<QDBusUnixFileDescriptor> fd_ = logindManager.Inhibit(QString::fromStdString(SystemdInhibitorParams::toString(what)), who, why, QString::fromStdString(SystemdInhibitorParams::toString(mode)));
241 if (fd_.error().isValid())
242 throw fd_.error();
243 this->fd = ::dup(fd_.value().fileDescriptor());
244}
245SystemdInhibitor::ActiveSystemdInhibitor::~ActiveSystemdInhibitor() {
246 if (this->fd != -1)
247 ::close(this->fd);
248}
249
250void SystemdInhibitor::release() {
251 if (!this->activeInhibitor)
252 return;
253
254 this->activeInhibitor.reset();
255 emit this->enabledChanged();
256}
257
258void SystemdInhibitor::update() {
259 if (!this->mWhat || this->mWho.isEmpty() || this->mWhy.isEmpty() || !this->mMode || !this->mEnabled)
260 if (this->activeInhibitor)
261 this->release();
262 else
263 return;
264
265 if (this->activeInhibitor && this->mWhat == this->activeInhibitor->what && this->mWho == this->activeInhibitor->who && this->mWhy == this->activeInhibitor->why && this->mMode == this->activeInhibitor->mode)
266 return;
267
268 std::unique_ptr<ActiveSystemdInhibitor> otherInhibitor;
269 try {
270 otherInhibitor.reset(new SystemdInhibitor::ActiveSystemdInhibitor(this->mWhat, this->mWho, this->mWhy, this->mMode));
271 } catch (const QDBusError& err) {
272 qCritical().noquote()
273 << err.name().toStdString() << " " << err.message().toStdString();
274 return;
275 }
276 this->activeInhibitor.swap(otherInhibitor);
277
278 if (!otherInhibitor && this->activeInhibitor)
279 emit this->enabledChanged();
280 if (otherInhibitor && otherInhibitor->what != this->activeInhibitor->what)
281 emit this->whatChanged();
282 if (otherInhibitor && otherInhibitor->who != this->activeInhibitor->who)
283 emit this->whoChanged();
284 if (otherInhibitor && otherInhibitor->why != this->activeInhibitor->why)
285 emit this->whyChanged();
286 if (otherInhibitor && otherInhibitor->mode != this->activeInhibitor->mode)
287 emit this->modeChanged();
288}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.hpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.hpp
new file mode 100644
index 00000000..98f73d8f
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.hpp
@@ -0,0 +1,193 @@
1#pragma once
2
3#include <cstdint>
4#include <memory>
5#include <string>
6#include <optional>
7
8#include <QObject>
9#include <QDBusInterface>
10#include <QtQmlIntegration/qqmlintegration.h>
11
12#include "dbus_systemd_manager.h"
13#include "dbus_logind_manager.h"
14#include "dbus_logind_session.h"
15#include "dbus_systemd_unit.h"
16#include "dbus_systemd_service.h"
17#include "dbus_properties.h"
18
19#include "core/model.hpp"
20
21class SystemdUnit : public QObject {
22 Q_OBJECT;
23 QML_ELEMENT;
24 QML_UNCREATABLE("SystemdUnits cannot be created directly");
25
26public:
27 explicit SystemdUnit(QObject* parent, const QDBusObjectPath& path, const QString& id);
28
29 Q_PROPERTY(QDBusObjectPath path READ path CONSTANT);
30 Q_PROPERTY(QString id READ id CONSTANT);
31 Q_PROPERTY(QList<QString> runtimeDirectory READ runtimeDirectory CONSTANT);
32 Q_PROPERTY(QString activeState READ activeState NOTIFY activeStateChanged);
33
34 const QDBusObjectPath& path() const;
35 const QString& id() const;
36 QList<QString> runtimeDirectory();
37 QString activeState();
38
39signals:
40 void activeStateChanged();
41
42private slots:
43 void onUnitPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties);
44
45private:
46 std::unique_ptr<DBusSystemdUnit> systemdUnit();
47 std::unique_ptr<DBusSystemdService> systemdService();
48
49 DBusProperties* mUnitProperties;
50 QDBusObjectPath mPath;
51 QString mId;
52 std::optional<QString> mActiveState;
53 std::optional<QList<QString>> mRuntimeDirectory;
54};
55
56class Systemd : public QObject {
57 Q_OBJECT;
58 QML_SINGLETON;
59 QML_ELEMENT;
60
61public:
62 explicit Systemd(QObject* parent = nullptr);
63
64 Q_PROPERTY(bool idleHint READ idleHint WRITE setIdleHint NOTIFY idleHintChanged)
65 Q_PROPERTY(bool lockedHint READ lockedHint WRITE setLockedHint NOTIFY lockedHintChanged)
66 Q_PROPERTY(UntypedObjectModel* userUnits READ userUnits CONSTANT)
67
68 Q_INVOKABLE void stopUserUnit(const QString& unit, const QString& mode);
69 Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness);
70 Q_INVOKABLE void setIdleHint(bool idle);
71 Q_INVOKABLE void setLockedHint(bool locked);
72 Q_INVOKABLE void lockSession();
73 Q_INVOKABLE void suspend();
74 Q_INVOKABLE void hibernate();
75
76 bool idleHint();
77 bool lockedHint();
78 ObjectModel<SystemdUnit>* userUnits();
79
80signals:
81 void shutdown(bool before);
82 void sleep(bool before);
83 void lock();
84 void unlock();
85 void idleHintChanged();
86 void lockedHintChanged();
87
88private slots:
89 void onLogindSessionPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties);
90 void onUserUnitNew(const QString& id, const QDBusObjectPath& objectPath);
91 void onUserUnitRemoved(const QString& id, const QDBusObjectPath& objectPath);
92
93private:
94 DBusSystemdManager* systemdManager;
95 DBusLogindManager* logindManager;
96 DBusLogindSession* logindSession;
97 DBusProperties* logindSessionProperties;
98
99 ObjectModel<SystemdUnit> mUserUnits{this};
100};
101
102class SystemdInhibitorParams : public QObject {
103 Q_OBJECT;
104 QML_ELEMENT;
105 QML_SINGLETON;
106
107public:
108 enum WhatItem : uint8_t {
109 Shutdown = 0b1,
110 Sleep = 0b10,
111 Idle = 0b100,
112 HandlePowerKey = 0b1000,
113 HandleSuspendKey = 0b10000,
114 HandleHibernateKey = 0b100000,
115 HandleLidSwitch = 0b1000000,
116 };
117 Q_ENUM(WhatItem);
118 Q_DECLARE_FLAGS(What, WhatItem);
119
120 enum Mode : uint8_t {
121 Block = 1,
122 BlockWeak = 2,
123 Delay = 3,
124 };
125 Q_ENUM(Mode);
126
127 Q_INVOKABLE static std::string toString(WhatItem what);
128 Q_INVOKABLE static std::string toString(What what);
129 Q_INVOKABLE static std::string toString(Mode mode);
130
131 static constexpr WhatItem allWhatItems[] = { Shutdown, Sleep, Idle, HandlePowerKey, HandleSuspendKey, HandleHibernateKey, HandleLidSwitch };
132};
133Q_DECLARE_OPERATORS_FOR_FLAGS(SystemdInhibitorParams::What)
134
135class SystemdInhibitor : public QObject {
136 Q_OBJECT;
137 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
138 Q_PROPERTY(SystemdInhibitorParams::What what READ what WRITE setWhat NOTIFY whatChanged);
139 Q_PROPERTY(QString who READ who WRITE setWho NOTIFY whoChanged);
140 Q_PROPERTY(QString why READ why WRITE setWhy NOTIFY whyChanged);
141 Q_PROPERTY(SystemdInhibitorParams::Mode mode READ mode WRITE setMode NOTIFY modeChanged);
142 QML_ELEMENT;
143
144public:
145 explicit SystemdInhibitor(QObject* parent = nullptr): QObject(parent) {}
146
147 bool enabled() const;
148 void setEnabled(bool enabled);
149
150 SystemdInhibitorParams::What what() const;
151 void setWhat(SystemdInhibitorParams::What what);
152
153 QString who() const;
154 void setWho(QString who);
155
156 QString why() const;
157 void setWhy(QString why);
158
159 SystemdInhibitorParams::Mode mode() const;
160 void setMode(SystemdInhibitorParams::Mode mode);
161
162 Q_INVOKABLE void release();
163
164signals:
165 void enabledChanged();
166 void whatChanged();
167 void whoChanged();
168 void whyChanged();
169 void modeChanged();
170
171private:
172 class ActiveSystemdInhibitor {
173 public:
174 uint32_t fd = -1;
175 SystemdInhibitorParams::What what;
176 QString who;
177 QString why;
178 SystemdInhibitorParams::Mode mode;
179
180 ActiveSystemdInhibitor(SystemdInhibitorParams::What what_, QString who_, QString why_, SystemdInhibitorParams::Mode mode_);
181 ~ActiveSystemdInhibitor();
182 };
183
184 void update();
185
186 bool mEnabled = true;
187 std::unique_ptr<ActiveSystemdInhibitor> activeInhibitor;
188 SystemdInhibitorParams::What mWhat = static_cast<SystemdInhibitorParams::What>(0);
189 QString mWho;
190 QString mWhy;
191 SystemdInhibitorParams::Mode mMode = static_cast<SystemdInhibitorParams::Mode>(0);
192};
193
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/customplugin.h b/accounts/gkleen@skadhi/shell/quickshell-plugins/customplugin.h
new file mode 100644
index 00000000..e66ba9e3
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/customplugin.h
@@ -0,0 +1,7 @@
1#include <QQmlEngineExtensionPlugin>
2
3class CustomPlugin : public QQmlEngineExtensionPlugin
4{
5 Q_OBJECT
6 Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
7};
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/default.nix b/accounts/gkleen@skadhi/shell/quickshell-plugins/default.nix
new file mode 100644
index 00000000..dfe93bca
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/default.nix
@@ -0,0 +1,32 @@
1{ lib
2, stdenv
3, cmake
4, qt6
5, fmt
6, keepassxc
7, systemd
8, quickshell
9}:
10
11stdenv.mkDerivation rec {
12 name = "quickshell-custom";
13
14 src = ./.;
15
16 prePatch = ''
17 cp ${keepassxc.src}/src/gui/org.keepassxc.KeePassXC.MainWindow.xml .
18 '';
19
20 nativeBuildInputs = [ cmake qt6.wrapQtAppsHook ];
21 buildInputs = [
22 qt6.qtbase
23 qt6.qtdeclarative
24 ];
25
26 cmakeFlags = [
27 (lib.cmakeFeature "INSTALL_QML_PREFIX" qt6.qtbase.qtQmlPrefix)
28 (lib.cmakeOptionType "string" "QUICKSHELL_SRC" (toString quickshell.src))
29 ];
30
31 LC_ALL = "C.UTF-8";
32}
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml
new file mode 100644
index 00000000..7588e7a5
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml
@@ -0,0 +1,28 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.DBus.Properties">
5 <method name="Get">
6 <arg name="interface_name" direction="in" type="s"/>
7 <arg name="property_name" direction="in" type="s"/>
8 <arg name="value" direction="out" type="v"/>
9 </method>
10 <method name="GetAll">
11 <arg name="interface_name" direction="in" type="s"/>
12 <arg name="props" direction="out" type="a{sv}"/>
13 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
14 </method>
15 <method name="Set">
16 <arg name="interface_name" direction="in" type="s"/>
17 <arg name="property_name" direction="in" type="s"/>
18 <arg name="value" direction="in" type="v"/>
19 </method>
20 <signal name="PropertiesChanged">
21 <arg type="s" name="interface_name"/>
22 <arg type="a{sv}" name="changed_properties"/>
23 <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
24 <arg type="as" name="invalidated_properties"/>
25 </signal>
26 </interface>
27</node>
28
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml
new file mode 100644
index 00000000..120a06d9
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml
@@ -0,0 +1,445 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.login1.Manager">
5 <property name="EnableWallMessages" type="b" access="readwrite">
6 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
7 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
8 </property>
9 <property name="WallMessage" type="s" access="readwrite">
10 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
11 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
12 </property>
13 <property name="NAutoVTs" type="u" access="read">
14 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
15 </property>
16 <property name="KillOnlyUsers" type="as" access="read">
17 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
18 </property>
19 <property name="KillExcludeUsers" type="as" access="read">
20 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
21 </property>
22 <property name="KillUserProcesses" type="b" access="read">
23 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
24 </property>
25 <property name="RebootParameter" type="s" access="read">
26 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
27 </property>
28 <property name="RebootToFirmwareSetup" type="b" access="read">
29 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
30 </property>
31 <property name="RebootToBootLoaderMenu" type="t" access="read">
32 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
33 </property>
34 <property name="RebootToBootLoaderEntry" type="s" access="read">
35 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
36 </property>
37 <property name="BootLoaderEntries" type="as" access="read">
38 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
39 </property>
40 <property name="IdleHint" type="b" access="read">
41 </property>
42 <property name="IdleSinceHint" type="t" access="read">
43 </property>
44 <property name="IdleSinceHintMonotonic" type="t" access="read">
45 </property>
46 <property name="BlockInhibited" type="s" access="read">
47 </property>
48 <property name="BlockWeakInhibited" type="s" access="read">
49 </property>
50 <property name="DelayInhibited" type="s" access="read">
51 </property>
52 <property name="InhibitDelayMaxUSec" type="t" access="read">
53 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
54 </property>
55 <property name="UserStopDelayUSec" type="t" access="read">
56 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
57 </property>
58 <property name="SleepOperation" type="as" access="read">
59 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
60 </property>
61 <property name="HandlePowerKey" type="s" access="read">
62 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
63 </property>
64 <property name="HandlePowerKeyLongPress" type="s" access="read">
65 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
66 </property>
67 <property name="HandleRebootKey" type="s" access="read">
68 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
69 </property>
70 <property name="HandleRebootKeyLongPress" type="s" access="read">
71 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
72 </property>
73 <property name="HandleSuspendKey" type="s" access="read">
74 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
75 </property>
76 <property name="HandleSuspendKeyLongPress" type="s" access="read">
77 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
78 </property>
79 <property name="HandleHibernateKey" type="s" access="read">
80 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
81 </property>
82 <property name="HandleHibernateKeyLongPress" type="s" access="read">
83 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
84 </property>
85 <property name="HandleLidSwitch" type="s" access="read">
86 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
87 </property>
88 <property name="HandleLidSwitchExternalPower" type="s" access="read">
89 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
90 </property>
91 <property name="HandleLidSwitchDocked" type="s" access="read">
92 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
93 </property>
94 <property name="HandleSecureAttentionKey" type="s" access="read">
95 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
96 </property>
97 <property name="HoldoffTimeoutUSec" type="t" access="read">
98 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
99 </property>
100 <property name="IdleAction" type="s" access="read">
101 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
102 </property>
103 <property name="IdleActionUSec" type="t" access="read">
104 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
105 </property>
106 <property name="PreparingForShutdown" type="b" access="read">
107 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
108 </property>
109 <property name="PreparingForShutdownWithMetadata" type="a{sv}" access="read">
110 <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
111 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
112 </property>
113 <property name="PreparingForSleep" type="b" access="read">
114 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
115 </property>
116 <!-- <property name="ScheduledShutdown" type="(st)" access="read"> -->
117 <!-- </property> -->
118 <property name="DesignatedMaintenanceTime" type="s" access="read">
119 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
120 </property>
121 <property name="Docked" type="b" access="read">
122 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
123 </property>
124 <property name="LidClosed" type="b" access="read">
125 </property>
126 <property name="OnExternalPower" type="b" access="read">
127 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
128 </property>
129 <property name="RemoveIPC" type="b" access="read">
130 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
131 </property>
132 <property name="RuntimeDirectorySize" type="t" access="read">
133 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
134 </property>
135 <property name="RuntimeDirectoryInodesMax" type="t" access="read">
136 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
137 </property>
138 <property name="InhibitorsMax" type="t" access="read">
139 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
140 </property>
141 <property name="NCurrentInhibitors" type="t" access="read">
142 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
143 </property>
144 <property name="SessionsMax" type="t" access="read">
145 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
146 </property>
147 <property name="NCurrentSessions" type="t" access="read">
148 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
149 </property>
150 <property name="StopIdleSessionUSec" type="t" access="read">
151 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
152 </property>
153 <method name="GetSession">
154 <arg type="s" name="session_id" direction="in"/>
155 <arg type="o" name="object_path" direction="out"/>
156 </method>
157 <method name="GetSessionByPID">
158 <arg type="u" name="pid" direction="in"/>
159 <arg type="o" name="object_path" direction="out"/>
160 </method>
161 <method name="GetUser">
162 <arg type="u" name="uid" direction="in"/>
163 <arg type="o" name="object_path" direction="out"/>
164 </method>
165 <method name="GetUserByPID">
166 <arg type="u" name="pid" direction="in"/>
167 <arg type="o" name="object_path" direction="out"/>
168 </method>
169 <method name="GetSeat">
170 <arg type="s" name="seat_id" direction="in"/>
171 <arg type="o" name="object_path" direction="out"/>
172 </method>
173 <!-- <method name="ListSessions"> -->
174 <!-- <arg type="a(susso)" name="sessions" direction="out"/> -->
175 <!-- </method> -->
176 <!-- <method name="ListSessionsEx"> -->
177 <!-- <arg type="a(sussussbto)" name="sessions" direction="out"/> -->
178 <!-- </method> -->
179 <!-- <method name="ListUsers"> -->
180 <!-- <arg type="a(uso)" name="users" direction="out"/> -->
181 <!-- </method> -->
182 <!-- <method name="ListSeats"> -->
183 <!-- <arg type="a(so)" name="seats" direction="out"/> -->
184 <!-- </method> -->
185 <!-- <method name="ListInhibitors"> -->
186 <!-- <arg type="a(ssssuu)" name="inhibitors" direction="out"/> -->
187 <!-- </method> -->
188 <!-- <method name="CreateSession"> -->
189 <!-- <arg type="u" name="uid" direction="in"/> -->
190 <!-- <arg type="u" name="pid" direction="in"/> -->
191 <!-- <arg type="s" name="service" direction="in"/> -->
192 <!-- <arg type="s" name="type" direction="in"/> -->
193 <!-- <arg type="s" name="class" direction="in"/> -->
194 <!-- <arg type="s" name="desktop" direction="in"/> -->
195 <!-- <arg type="s" name="seat_id" direction="in"/> -->
196 <!-- <arg type="u" name="vtnr" direction="in"/> -->
197 <!-- <arg type="s" name="tty" direction="in"/> -->
198 <!-- <arg type="s" name="display" direction="in"/> -->
199 <!-- <arg type="b" name="remote" direction="in"/> -->
200 <!-- <arg type="s" name="remote_user" direction="in"/> -->
201 <!-- <arg type="s" name="remote_host" direction="in"/> -->
202 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
203 <!-- <arg type="s" name="session_id" direction="out"/> -->
204 <!-- <arg type="o" name="object_path" direction="out"/> -->
205 <!-- <arg type="s" name="runtime_path" direction="out"/> -->
206 <!-- <arg type="h" name="fifo_fd" direction="out"/> -->
207 <!-- <arg type="u" name="uid" direction="out"/> -->
208 <!-- <arg type="s" name="seat_id" direction="out"/> -->
209 <!-- <arg type="u" name="vtnr" direction="out"/> -->
210 <!-- <arg type="b" name="existing" direction="out"/> -->
211 <!-- <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> -->
212 <!-- </method> -->
213 <!-- <method name="CreateSessionWithPIDFD"> -->
214 <!-- <arg type="u" name="uid" direction="in"/> -->
215 <!-- <arg type="h" name="pidfd" direction="in"/> -->
216 <!-- <arg type="s" name="service" direction="in"/> -->
217 <!-- <arg type="s" name="type" direction="in"/> -->
218 <!-- <arg type="s" name="class" direction="in"/> -->
219 <!-- <arg type="s" name="desktop" direction="in"/> -->
220 <!-- <arg type="s" name="seat_id" direction="in"/> -->
221 <!-- <arg type="u" name="vtnr" direction="in"/> -->
222 <!-- <arg type="s" name="tty" direction="in"/> -->
223 <!-- <arg type="s" name="display" direction="in"/> -->
224 <!-- <arg type="b" name="remote" direction="in"/> -->
225 <!-- <arg type="s" name="remote_user" direction="in"/> -->
226 <!-- <arg type="s" name="remote_host" direction="in"/> -->
227 <!-- <arg type="t" name="flags" direction="in"/> -->
228 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
229 <!-- <arg type="s" name="session_id" direction="out"/> -->
230 <!-- <arg type="o" name="object_path" direction="out"/> -->
231 <!-- <arg type="s" name="runtime_path" direction="out"/> -->
232 <!-- <arg type="h" name="fifo_fd" direction="out"/> -->
233 <!-- <arg type="u" name="uid" direction="out"/> -->
234 <!-- <arg type="s" name="seat_id" direction="out"/> -->
235 <!-- <arg type="u" name="vtnr" direction="out"/> -->
236 <!-- <arg type="b" name="existing" direction="out"/> -->
237 <!-- <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> -->
238 <!-- </method> -->
239 <method name="ReleaseSession">
240 <arg type="s" name="session_id" direction="in"/>
241 </method>
242 <method name="ActivateSession">
243 <arg type="s" name="session_id" direction="in"/>
244 </method>
245 <method name="ActivateSessionOnSeat">
246 <arg type="s" name="session_id" direction="in"/>
247 <arg type="s" name="seat_id" direction="in"/>
248 </method>
249 <method name="LockSession">
250 <arg type="s" name="session_id" direction="in"/>
251 </method>
252 <method name="UnlockSession">
253 <arg type="s" name="session_id" direction="in"/>
254 </method>
255 <method name="LockSessions">
256 </method>
257 <method name="UnlockSessions">
258 </method>
259 <method name="KillSession">
260 <arg type="s" name="session_id" direction="in"/>
261 <arg type="s" name="whom" direction="in"/>
262 <arg type="i" name="signal_number" direction="in"/>
263 </method>
264 <method name="KillUser">
265 <arg type="u" name="uid" direction="in"/>
266 <arg type="i" name="signal_number" direction="in"/>
267 </method>
268 <method name="TerminateSession">
269 <arg type="s" name="session_id" direction="in"/>
270 </method>
271 <method name="TerminateUser">
272 <arg type="u" name="uid" direction="in"/>
273 </method>
274 <method name="TerminateSeat">
275 <arg type="s" name="seat_id" direction="in"/>
276 </method>
277 <method name="SetUserLinger">
278 <arg type="u" name="uid" direction="in"/>
279 <arg type="b" name="enable" direction="in"/>
280 <arg type="b" name="interactive" direction="in"/>
281 </method>
282 <method name="AttachDevice">
283 <arg type="s" name="seat_id" direction="in"/>
284 <arg type="s" name="sysfs_path" direction="in"/>
285 <arg type="b" name="interactive" direction="in"/>
286 </method>
287 <method name="FlushDevices">
288 <arg type="b" name="interactive" direction="in"/>
289 </method>
290 <method name="PowerOff">
291 <arg type="b" name="interactive" direction="in"/>
292 </method>
293 <method name="PowerOffWithFlags">
294 <arg type="t" name="flags" direction="in"/>
295 </method>
296 <method name="Reboot">
297 <arg type="b" name="interactive" direction="in"/>
298 </method>
299 <method name="RebootWithFlags">
300 <arg type="t" name="flags" direction="in"/>
301 </method>
302 <method name="Halt">
303 <arg type="b" name="interactive" direction="in"/>
304 </method>
305 <method name="HaltWithFlags">
306 <arg type="t" name="flags" direction="in"/>
307 </method>
308 <method name="Suspend">
309 <arg type="b" name="interactive" direction="in"/>
310 </method>
311 <method name="SuspendWithFlags">
312 <arg type="t" name="flags" direction="in"/>
313 </method>
314 <method name="Hibernate">
315 <arg type="b" name="interactive" direction="in"/>
316 </method>
317 <method name="HibernateWithFlags">
318 <arg type="t" name="flags" direction="in"/>
319 </method>
320 <method name="HybridSleep">
321 <arg type="b" name="interactive" direction="in"/>
322 </method>
323 <method name="HybridSleepWithFlags">
324 <arg type="t" name="flags" direction="in"/>
325 </method>
326 <method name="SuspendThenHibernate">
327 <arg type="b" name="interactive" direction="in"/>
328 </method>
329 <method name="SuspendThenHibernateWithFlags">
330 <arg type="t" name="flags" direction="in"/>
331 </method>
332 <method name="Sleep">
333 <arg type="t" name="flags" direction="in"/>
334 </method>
335 <method name="CanPowerOff">
336 <arg type="s" name="result" direction="out"/>
337 </method>
338 <method name="CanReboot">
339 <arg type="s" name="result" direction="out"/>
340 </method>
341 <method name="CanHalt">
342 <arg type="s" name="result" direction="out"/>
343 </method>
344 <method name="CanSuspend">
345 <arg type="s" name="result" direction="out"/>
346 </method>
347 <method name="CanHibernate">
348 <arg type="s" name="result" direction="out"/>
349 </method>
350 <method name="CanHybridSleep">
351 <arg type="s" name="result" direction="out"/>
352 </method>
353 <method name="CanSuspendThenHibernate">
354 <arg type="s" name="result" direction="out"/>
355 </method>
356 <method name="CanSleep">
357 <arg type="s" name="result" direction="out"/>
358 </method>
359 <method name="ScheduleShutdown">
360 <arg type="s" name="type" direction="in"/>
361 <arg type="t" name="usec" direction="in"/>
362 </method>
363 <method name="CancelScheduledShutdown">
364 <arg type="b" name="cancelled" direction="out"/>
365 </method>
366 <method name="Inhibit">
367 <arg type="s" name="what" direction="in"/>
368 <arg type="s" name="who" direction="in"/>
369 <arg type="s" name="why" direction="in"/>
370 <arg type="s" name="mode" direction="in"/>
371 <arg type="h" name="pipe_fd" direction="out"/>
372 </method>
373 <method name="CanRebootParameter">
374 <arg type="s" name="result" direction="out"/>
375 </method>
376 <method name="SetRebootParameter">
377 <arg type="s" name="parameter" direction="in"/>
378 </method>
379 <method name="CanRebootToFirmwareSetup">
380 <arg type="s" name="result" direction="out"/>
381 </method>
382 <method name="SetRebootToFirmwareSetup">
383 <arg type="b" name="enable" direction="in"/>
384 </method>
385 <method name="CanRebootToBootLoaderMenu">
386 <arg type="s" name="result" direction="out"/>
387 </method>
388 <method name="SetRebootToBootLoaderMenu">
389 <arg type="t" name="timeout" direction="in"/>
390 </method>
391 <method name="CanRebootToBootLoaderEntry">
392 <arg type="s" name="result" direction="out"/>
393 </method>
394 <method name="SetRebootToBootLoaderEntry">
395 <arg type="s" name="boot_loader_entry" direction="in"/>
396 </method>
397 <method name="SetWallMessage">
398 <arg type="s" name="wall_message" direction="in"/>
399 <arg type="b" name="enable" direction="in"/>
400 </method>
401 <signal name="SecureAttentionKey">
402 <arg type="s" name="seat_id"/>
403 <arg type="o" name="object_path"/>
404 </signal>
405 <signal name="SessionNew">
406 <arg type="s" name="session_id"/>
407 <arg type="o" name="object_path"/>
408 </signal>
409 <signal name="SessionRemoved">
410 <arg type="s" name="session_id"/>
411 <arg type="o" name="object_path"/>
412 </signal>
413 <signal name="UserNew">
414 <arg type="u" name="uid"/>
415 <arg type="o" name="object_path"/>
416 </signal>
417 <signal name="UserRemoved">
418 <arg type="u" name="uid"/>
419 <arg type="o" name="object_path"/>
420 </signal>
421 <signal name="SeatNew">
422 <arg type="s" name="seat_id"/>
423 <arg type="o" name="object_path"/>
424 </signal>
425 <signal name="SeatRemoved">
426 <arg type="s" name="seat_id"/>
427 <arg type="o" name="object_path"/>
428 </signal>
429 <signal name="PrepareForShutdown">
430 <arg type="b" name="start"/>
431 </signal>
432 <signal name="PrepareForShutdownWithMetadata">
433 <arg type="b" name="start"/>
434 <arg type="a{sv}" name="metadata"/>
435 <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
436 </signal>
437 <signal name="PrepareForSleep">
438 <arg type="b" name="start"/>
439 </signal>
440 </interface>
441 <node name="user"/>
442 <node name="session"/>
443 <node name="seat"/>
444</node>
445
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Session.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Session.xml
new file mode 100644
index 00000000..7d6fc8ee
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.login1.Session.xml
@@ -0,0 +1,146 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.login1.Session">
5 <property name="Id" type="s" access="read">
6 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
7 </property>
8 <property name="User" type="o" access="read">
9 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
10 </property>
11 <property name="Name" type="s" access="read">
12 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
13 </property>
14 <property name="Timestamp" type="t" access="read">
15 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
16 </property>
17 <property name="TimestampMonotonic" type="t" access="read">
18 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
19 </property>
20 <property name="VTNr" type="u" access="read">
21 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
22 </property>
23 <property name="Seat" type="o" access="read">
24 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
25 </property>
26 <property name="TTY" type="s" access="read">
27 </property>
28 <property name="Display" type="s" access="read">
29 </property>
30 <property name="Remote" type="b" access="read">
31 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
32 </property>
33 <property name="RemoteHost" type="s" access="read">
34 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
35 </property>
36 <property name="RemoteUser" type="s" access="read">
37 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
38 </property>
39 <property name="Service" type="s" access="read">
40 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
41 </property>
42 <property name="Desktop" type="s" access="read">
43 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
44 </property>
45 <property name="Scope" type="s" access="read">
46 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
47 </property>
48 <property name="Leader" type="u" access="read">
49 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
50 </property>
51 <property name="Audit" type="u" access="read">
52 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
53 </property>
54 <property name="Type" type="s" access="read">
55 </property>
56 <!-- <property name="Class" type="s" access="read"> -->
57 <!-- </property> -->
58 <property name="Active" type="b" access="read">
59 </property>
60 <property name="State" type="s" access="read">
61 </property>
62 <property name="IdleHint" type="b" access="read">
63 </property>
64 <property name="IdleSinceHint" type="t" access="read">
65 </property>
66 <property name="IdleSinceHintMonotonic" type="t" access="read">
67 </property>
68 <property name="CanIdle" type="b" access="read">
69 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
70 </property>
71 <property name="CanLock" type="b" access="read">
72 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
73 </property>
74 <property name="LockedHint" type="b" access="read">
75 </property>
76 <method name="Terminate">
77 </method>
78 <method name="Activate">
79 </method>
80 <!-- <method name="Lock"> -->
81 <!-- </method> -->
82 <!-- <method name="Unlock"> -->
83 <!-- </method> -->
84 <method name="SetIdleHint">
85 <arg type="b" name="idle" direction="in"/>
86 </method>
87 <method name="SetLockedHint">
88 <arg type="b" name="locked" direction="in"/>
89 </method>
90 <method name="Kill">
91 <arg type="s" name="whom" direction="in"/>
92 <arg type="i" name="signal_number" direction="in"/>
93 </method>
94 <method name="TakeControl">
95 <arg type="b" name="force" direction="in"/>
96 </method>
97 <method name="ReleaseControl">
98 </method>
99 <method name="SetType">
100 <arg type="s" name="type" direction="in"/>
101 </method>
102 <!-- <method name="SetClass"> -->
103 <!-- <arg type="s" name="class" direction="in"/> -->
104 <!-- </method> -->
105 <method name="SetDisplay">
106 <arg type="s" name="display" direction="in"/>
107 </method>
108 <method name="SetTTY">
109 <arg type="h" name="tty_fd" direction="in"/>
110 </method>
111 <method name="TakeDevice">
112 <arg type="u" name="major" direction="in"/>
113 <arg type="u" name="minor" direction="in"/>
114 <arg type="h" name="fd" direction="out"/>
115 <arg type="b" name="inactive" direction="out"/>
116 </method>
117 <method name="ReleaseDevice">
118 <arg type="u" name="major" direction="in"/>
119 <arg type="u" name="minor" direction="in"/>
120 </method>
121 <method name="PauseDeviceComplete">
122 <arg type="u" name="major" direction="in"/>
123 <arg type="u" name="minor" direction="in"/>
124 </method>
125 <method name="SetBrightness">
126 <arg type="s" name="subsystem" direction="in"/>
127 <arg type="s" name="name" direction="in"/>
128 <arg type="u" name="brightness" direction="in"/>
129 </method>
130 <signal name="PauseDevice">
131 <arg type="u" name="major"/>
132 <arg type="u" name="minor"/>
133 <arg type="s" name="type"/>
134 </signal>
135 <signal name="ResumeDevice">
136 <arg type="u" name="major"/>
137 <arg type="u" name="minor"/>
138 <arg type="h" name="fd"/>
139 </signal>
140 <signal name="Lock">
141 </signal>
142 <signal name="Unlock">
143 </signal>
144 </interface>
145</node>
146
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml
new file mode 100644
index 00000000..1dadbc55
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml
@@ -0,0 +1,821 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.systemd1.Manager">
5 <property name="Version" type="s" access="read">
6 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
7 </property>
8 <property name="Features" type="s" access="read">
9 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
10 </property>
11 <property name="Virtualization" type="s" access="read">
12 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
13 </property>
14 <property name="ConfidentialVirtualization" type="s" access="read">
15 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
16 </property>
17 <property name="Architecture" type="s" access="read">
18 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
19 </property>
20 <property name="Tainted" type="s" access="read">
21 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
22 </property>
23 <property name="FirmwareTimestamp" type="t" access="read">
24 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
25 </property>
26 <property name="FirmwareTimestampMonotonic" type="t" access="read">
27 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
28 </property>
29 <property name="LoaderTimestamp" type="t" access="read">
30 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
31 </property>
32 <property name="LoaderTimestampMonotonic" type="t" access="read">
33 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
34 </property>
35 <property name="KernelTimestamp" type="t" access="read">
36 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
37 </property>
38 <property name="KernelTimestampMonotonic" type="t" access="read">
39 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
40 </property>
41 <property name="InitRDTimestamp" type="t" access="read">
42 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
43 </property>
44 <property name="InitRDTimestampMonotonic" type="t" access="read">
45 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
46 </property>
47 <property name="UserspaceTimestamp" type="t" access="read">
48 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
49 </property>
50 <property name="UserspaceTimestampMonotonic" type="t" access="read">
51 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
52 </property>
53 <property name="FinishTimestamp" type="t" access="read">
54 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
55 </property>
56 <property name="FinishTimestampMonotonic" type="t" access="read">
57 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
58 </property>
59 <property name="ShutdownStartTimestamp" type="t" access="read">
60 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
61 </property>
62 <property name="ShutdownStartTimestampMonotonic" type="t" access="read">
63 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
64 </property>
65 <property name="SecurityStartTimestamp" type="t" access="read">
66 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
67 </property>
68 <property name="SecurityStartTimestampMonotonic" type="t" access="read">
69 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
70 </property>
71 <property name="SecurityFinishTimestamp" type="t" access="read">
72 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
73 </property>
74 <property name="SecurityFinishTimestampMonotonic" type="t" access="read">
75 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
76 </property>
77 <property name="GeneratorsStartTimestamp" type="t" access="read">
78 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
79 </property>
80 <property name="GeneratorsStartTimestampMonotonic" type="t" access="read">
81 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
82 </property>
83 <property name="GeneratorsFinishTimestamp" type="t" access="read">
84 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
85 </property>
86 <property name="GeneratorsFinishTimestampMonotonic" type="t" access="read">
87 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
88 </property>
89 <property name="UnitsLoadStartTimestamp" type="t" access="read">
90 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
91 </property>
92 <property name="UnitsLoadStartTimestampMonotonic" type="t" access="read">
93 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
94 </property>
95 <property name="UnitsLoadFinishTimestamp" type="t" access="read">
96 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
97 </property>
98 <property name="UnitsLoadFinishTimestampMonotonic" type="t" access="read">
99 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
100 </property>
101 <property name="UnitsLoadTimestamp" type="t" access="read">
102 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
103 </property>
104 <property name="UnitsLoadTimestampMonotonic" type="t" access="read">
105 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
106 </property>
107 <property name="InitRDSecurityStartTimestamp" type="t" access="read">
108 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
109 </property>
110 <property name="InitRDSecurityStartTimestampMonotonic" type="t" access="read">
111 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
112 </property>
113 <property name="InitRDSecurityFinishTimestamp" type="t" access="read">
114 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
115 </property>
116 <property name="InitRDSecurityFinishTimestampMonotonic" type="t" access="read">
117 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
118 </property>
119 <property name="InitRDGeneratorsStartTimestamp" type="t" access="read">
120 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
121 </property>
122 <property name="InitRDGeneratorsStartTimestampMonotonic" type="t" access="read">
123 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
124 </property>
125 <property name="InitRDGeneratorsFinishTimestamp" type="t" access="read">
126 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
127 </property>
128 <property name="InitRDGeneratorsFinishTimestampMonotonic" type="t" access="read">
129 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
130 </property>
131 <property name="InitRDUnitsLoadStartTimestamp" type="t" access="read">
132 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
133 </property>
134 <property name="InitRDUnitsLoadStartTimestampMonotonic" type="t" access="read">
135 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
136 </property>
137 <property name="InitRDUnitsLoadFinishTimestamp" type="t" access="read">
138 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
139 </property>
140 <property name="InitRDUnitsLoadFinishTimestampMonotonic" type="t" access="read">
141 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
142 </property>
143 <property name="LogLevel" type="s" access="readwrite">
144 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
145 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
146 </property>
147 <property name="LogTarget" type="s" access="readwrite">
148 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
149 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
150 </property>
151 <property name="NNames" type="u" access="read">
152 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
153 </property>
154 <property name="NFailedUnits" type="u" access="read">
155 </property>
156 <property name="NJobs" type="u" access="read">
157 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
158 </property>
159 <property name="NInstalledJobs" type="u" access="read">
160 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
161 </property>
162 <property name="NFailedJobs" type="u" access="read">
163 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
164 </property>
165 <property name="Progress" type="d" access="read">
166 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
167 </property>
168 <property name="Environment" type="as" access="read">
169 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
170 </property>
171 <property name="ConfirmSpawn" type="b" access="read">
172 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
173 </property>
174 <property name="ShowStatus" type="b" access="read">
175 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
176 </property>
177 <property name="UnitPath" type="as" access="read">
178 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
179 </property>
180 <property name="DefaultStandardOutput" type="s" access="read">
181 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
182 </property>
183 <property name="DefaultStandardError" type="s" access="read">
184 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
185 </property>
186 <property name="WatchdogDevice" type="s" access="read">
187 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
188 </property>
189 <property name="WatchdogLastPingTimestamp" type="t" access="read">
190 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
191 </property>
192 <property name="WatchdogLastPingTimestampMonotonic" type="t" access="read">
193 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
194 </property>
195 <property name="RuntimeWatchdogUSec" type="t" access="readwrite">
196 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
197 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
198 </property>
199 <property name="RuntimeWatchdogPreUSec" type="t" access="readwrite">
200 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
201 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
202 </property>
203 <property name="RuntimeWatchdogPreGovernor" type="s" access="readwrite">
204 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
205 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
206 </property>
207 <property name="RebootWatchdogUSec" type="t" access="readwrite">
208 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
209 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
210 </property>
211 <property name="KExecWatchdogUSec" type="t" access="readwrite">
212 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
213 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
214 </property>
215 <property name="ServiceWatchdogs" type="b" access="readwrite">
216 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
217 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
218 </property>
219 <property name="ControlGroup" type="s" access="read">
220 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
221 </property>
222 <property name="SystemState" type="s" access="read">
223 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
224 </property>
225 <property name="ExitCode" type="y" access="read">
226 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
227 </property>
228 <property name="DefaultTimerAccuracyUSec" type="t" access="read">
229 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
230 </property>
231 <property name="DefaultTimeoutStartUSec" type="t" access="read">
232 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
233 </property>
234 <property name="DefaultTimeoutStopUSec" type="t" access="read">
235 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
236 </property>
237 <property name="DefaultTimeoutAbortUSec" type="t" access="read">
238 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
239 </property>
240 <property name="DefaultDeviceTimeoutUSec" type="t" access="read">
241 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
242 </property>
243 <property name="DefaultRestartUSec" type="t" access="read">
244 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
245 </property>
246 <property name="DefaultStartLimitIntervalUSec" type="t" access="read">
247 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
248 </property>
249 <property name="DefaultStartLimitBurst" type="u" access="read">
250 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
251 </property>
252 <property name="DefaultCPUAccounting" type="b" access="read">
253 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
254 </property>
255 <property name="DefaultBlockIOAccounting" type="b" access="read">
256 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
257 </property>
258 <property name="DefaultIOAccounting" type="b" access="read">
259 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
260 </property>
261 <property name="DefaultIPAccounting" type="b" access="read">
262 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
263 </property>
264 <property name="DefaultMemoryAccounting" type="b" access="read">
265 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
266 </property>
267 <property name="DefaultTasksAccounting" type="b" access="read">
268 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
269 </property>
270 <property name="DefaultLimitCPU" type="t" access="read">
271 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
272 </property>
273 <property name="DefaultLimitCPUSoft" type="t" access="read">
274 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
275 </property>
276 <property name="DefaultLimitFSIZE" type="t" access="read">
277 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
278 </property>
279 <property name="DefaultLimitFSIZESoft" type="t" access="read">
280 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
281 </property>
282 <property name="DefaultLimitDATA" type="t" access="read">
283 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
284 </property>
285 <property name="DefaultLimitDATASoft" type="t" access="read">
286 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
287 </property>
288 <property name="DefaultLimitSTACK" type="t" access="read">
289 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
290 </property>
291 <property name="DefaultLimitSTACKSoft" type="t" access="read">
292 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
293 </property>
294 <property name="DefaultLimitCORE" type="t" access="read">
295 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
296 </property>
297 <property name="DefaultLimitCORESoft" type="t" access="read">
298 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
299 </property>
300 <property name="DefaultLimitRSS" type="t" access="read">
301 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
302 </property>
303 <property name="DefaultLimitRSSSoft" type="t" access="read">
304 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
305 </property>
306 <property name="DefaultLimitNOFILE" type="t" access="read">
307 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
308 </property>
309 <property name="DefaultLimitNOFILESoft" type="t" access="read">
310 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
311 </property>
312 <property name="DefaultLimitAS" type="t" access="read">
313 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
314 </property>
315 <property name="DefaultLimitASSoft" type="t" access="read">
316 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
317 </property>
318 <property name="DefaultLimitNPROC" type="t" access="read">
319 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
320 </property>
321 <property name="DefaultLimitNPROCSoft" type="t" access="read">
322 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
323 </property>
324 <property name="DefaultLimitMEMLOCK" type="t" access="read">
325 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
326 </property>
327 <property name="DefaultLimitMEMLOCKSoft" type="t" access="read">
328 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
329 </property>
330 <property name="DefaultLimitLOCKS" type="t" access="read">
331 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
332 </property>
333 <property name="DefaultLimitLOCKSSoft" type="t" access="read">
334 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
335 </property>
336 <property name="DefaultLimitSIGPENDING" type="t" access="read">
337 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
338 </property>
339 <property name="DefaultLimitSIGPENDINGSoft" type="t" access="read">
340 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
341 </property>
342 <property name="DefaultLimitMSGQUEUE" type="t" access="read">
343 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
344 </property>
345 <property name="DefaultLimitMSGQUEUESoft" type="t" access="read">
346 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
347 </property>
348 <property name="DefaultLimitNICE" type="t" access="read">
349 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
350 </property>
351 <property name="DefaultLimitNICESoft" type="t" access="read">
352 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
353 </property>
354 <property name="DefaultLimitRTPRIO" type="t" access="read">
355 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
356 </property>
357 <property name="DefaultLimitRTPRIOSoft" type="t" access="read">
358 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
359 </property>
360 <property name="DefaultLimitRTTIME" type="t" access="read">
361 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
362 </property>
363 <property name="DefaultLimitRTTIMESoft" type="t" access="read">
364 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
365 </property>
366 <property name="DefaultTasksMax" type="t" access="read">
367 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
368 </property>
369 <property name="DefaultMemoryPressureThresholdUSec" type="t" access="read">
370 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
371 </property>
372 <property name="DefaultMemoryPressureWatch" type="s" access="read">
373 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
374 </property>
375 <property name="TimerSlackNSec" type="t" access="read">
376 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
377 </property>
378 <property name="DefaultOOMPolicy" type="s" access="read">
379 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
380 </property>
381 <property name="DefaultOOMScoreAdjust" type="i" access="read">
382 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
383 </property>
384 <property name="CtrlAltDelBurstAction" type="s" access="read">
385 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
386 </property>
387 <property name="SoftRebootsCount" type="u" access="read">
388 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
389 </property>
390 <method name="GetUnit">
391 <arg type="s" name="name" direction="in"/>
392 <arg type="o" name="unit" direction="out"/>
393 </method>
394 <method name="GetUnitByPID">
395 <arg type="u" name="pid" direction="in"/>
396 <arg type="o" name="unit" direction="out"/>
397 </method>
398 <method name="GetUnitByInvocationID">
399 <arg type="ay" name="invocation_id" direction="in"/>
400 <arg type="o" name="unit" direction="out"/>
401 </method>
402 <method name="GetUnitByControlGroup">
403 <arg type="s" name="cgroup" direction="in"/>
404 <arg type="o" name="unit" direction="out"/>
405 </method>
406 <method name="GetUnitByPIDFD">
407 <arg type="h" name="pidfd" direction="in"/>
408 <arg type="o" name="unit" direction="out"/>
409 <arg type="s" name="unit_id" direction="out"/>
410 <arg type="ay" name="invocation_id" direction="out"/>
411 </method>
412 <method name="LoadUnit">
413 <arg type="s" name="name" direction="in"/>
414 <arg type="o" name="unit" direction="out"/>
415 </method>
416 <method name="StartUnit">
417 <arg type="s" name="name" direction="in"/>
418 <arg type="s" name="mode" direction="in"/>
419 <arg type="o" name="job" direction="out"/>
420 </method>
421 <method name="StartUnitWithFlags">
422 <arg type="s" name="name" direction="in"/>
423 <arg type="s" name="mode" direction="in"/>
424 <arg type="t" name="flags" direction="in"/>
425 <arg type="o" name="job" direction="out"/>
426 </method>
427 <method name="StartUnitReplace">
428 <arg type="s" name="old_unit" direction="in"/>
429 <arg type="s" name="new_unit" direction="in"/>
430 <arg type="s" name="mode" direction="in"/>
431 <arg type="o" name="job" direction="out"/>
432 </method>
433 <method name="StopUnit">
434 <arg type="s" name="name" direction="in"/>
435 <arg type="s" name="mode" direction="in"/>
436 <arg type="o" name="job" direction="out"/>
437 </method>
438 <method name="ReloadUnit">
439 <arg type="s" name="name" direction="in"/>
440 <arg type="s" name="mode" direction="in"/>
441 <arg type="o" name="job" direction="out"/>
442 </method>
443 <method name="RestartUnit">
444 <arg type="s" name="name" direction="in"/>
445 <arg type="s" name="mode" direction="in"/>
446 <arg type="o" name="job" direction="out"/>
447 </method>
448 <method name="TryRestartUnit">
449 <arg type="s" name="name" direction="in"/>
450 <arg type="s" name="mode" direction="in"/>
451 <arg type="o" name="job" direction="out"/>
452 </method>
453 <method name="ReloadOrRestartUnit">
454 <arg type="s" name="name" direction="in"/>
455 <arg type="s" name="mode" direction="in"/>
456 <arg type="o" name="job" direction="out"/>
457 </method>
458 <method name="ReloadOrTryRestartUnit">
459 <arg type="s" name="name" direction="in"/>
460 <arg type="s" name="mode" direction="in"/>
461 <arg type="o" name="job" direction="out"/>
462 </method>
463 <!-- <method name="EnqueueUnitJob"> -->
464 <!-- <arg type="s" name="name" direction="in"/> -->
465 <!-- <arg type="s" name="job_type" direction="in"/> -->
466 <!-- <arg type="s" name="job_mode" direction="in"/> -->
467 <!-- <arg type="u" name="job_id" direction="out"/> -->
468 <!-- <arg type="o" name="job_path" direction="out"/> -->
469 <!-- <arg type="s" name="unit_id" direction="out"/> -->
470 <!-- <arg type="o" name="unit_path" direction="out"/> -->
471 <!-- <arg type="s" name="job_type" direction="out"/> -->
472 <!-- <arg type="a(uosos)" name="affected_jobs" direction="out"/> -->
473 <!-- </method> -->
474 <method name="KillUnit">
475 <arg type="s" name="name" direction="in"/>
476 <arg type="s" name="whom" direction="in"/>
477 <arg type="i" name="signal" direction="in"/>
478 </method>
479 <method name="QueueSignalUnit">
480 <arg type="s" name="name" direction="in"/>
481 <arg type="s" name="whom" direction="in"/>
482 <arg type="i" name="signal" direction="in"/>
483 <arg type="i" name="value" direction="in"/>
484 </method>
485 <method name="CleanUnit">
486 <arg type="s" name="name" direction="in"/>
487 <arg type="as" name="mask" direction="in"/>
488 </method>
489 <method name="FreezeUnit">
490 <arg type="s" name="name" direction="in"/>
491 </method>
492 <method name="ThawUnit">
493 <arg type="s" name="name" direction="in"/>
494 </method>
495 <method name="ResetFailedUnit">
496 <arg type="s" name="name" direction="in"/>
497 </method>
498 <!-- <method name="SetUnitProperties"> -->
499 <!-- <arg type="s" name="name" direction="in"/> -->
500 <!-- <arg type="b" name="runtime" direction="in"/> -->
501 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
502 <!-- </method> -->
503 <method name="BindMountUnit">
504 <arg type="s" name="name" direction="in"/>
505 <arg type="s" name="source" direction="in"/>
506 <arg type="s" name="destination" direction="in"/>
507 <arg type="b" name="read_only" direction="in"/>
508 <arg type="b" name="mkdir" direction="in"/>
509 </method>
510 <!-- <method name="MountImageUnit"> -->
511 <!-- <arg type="s" name="name" direction="in"/> -->
512 <!-- <arg type="s" name="source" direction="in"/> -->
513 <!-- <arg type="s" name="destination" direction="in"/> -->
514 <!-- <arg type="b" name="read_only" direction="in"/> -->
515 <!-- <arg type="b" name="mkdir" direction="in"/> -->
516 <!-- <arg type="a(ss)" name="options" direction="in"/> -->
517 <!-- </method> -->
518 <method name="RefUnit">
519 <arg type="s" name="name" direction="in"/>
520 </method>
521 <method name="UnrefUnit">
522 <arg type="s" name="name" direction="in"/>
523 </method>
524 <!-- <method name="StartTransientUnit"> -->
525 <!-- <arg type="s" name="name" direction="in"/> -->
526 <!-- <arg type="s" name="mode" direction="in"/> -->
527 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
528 <!-- <arg type="a(sa(sv))" name="aux" direction="in"/> -->
529 <!-- <arg type="o" name="job" direction="out"/> -->
530 <!-- </method> -->
531 <!-- <method name="GetUnitProcesses"> -->
532 <!-- <arg type="s" name="name" direction="in"/> -->
533 <!-- <arg type="a(sus)" name="processes" direction="out"/> -->
534 <!-- </method> -->
535 <!-- <method name="AttachProcessesToUnit"> -->
536 <!-- <arg type="s" name="unit_name" direction="in"/> -->
537 <!-- <arg type="s" name="subcgroup" direction="in"/> -->
538 <!-- <arg type="au" name="pids" direction="in"/> -->
539 <!-- </method> -->
540 <method name="AbandonScope">
541 <arg type="s" name="name" direction="in"/>
542 </method>
543 <method name="GetJob">
544 <arg type="u" name="id" direction="in"/>
545 <arg type="o" name="job" direction="out"/>
546 </method>
547 <!-- <method name="GetJobAfter"> -->
548 <!-- <arg type="u" name="id" direction="in"/> -->
549 <!-- <arg type="a(usssoo)" name="jobs" direction="out"/> -->
550 <!-- </method> -->
551 <!-- <method name="GetJobBefore"> -->
552 <!-- <arg type="u" name="id" direction="in"/> -->
553 <!-- <arg type="a(usssoo)" name="jobs" direction="out"/> -->
554 <!-- </method> -->
555 <method name="CancelJob">
556 <arg type="u" name="id" direction="in"/>
557 </method>
558 <method name="ClearJobs">
559 </method>
560 <method name="ResetFailed">
561 </method>
562 <method name="SetShowStatus">
563 <arg type="s" name="mode" direction="in"/>
564 </method>
565 <method name="ListUnits">
566 <arg type="a(ssssssouso)" name="units" direction="out"/>
567 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ListUnitsResult"/>
568 </method>
569 <method name="ListUnitsFiltered">
570 <arg type="as" name="states" direction="in"/>
571 <arg type="a(ssssssouso)" name="units" direction="out"/>
572 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ListUnitsResult"/>
573 </method>
574 <method name="ListUnitsByPatterns">
575 <arg type="as" name="states" direction="in"/>
576 <arg type="as" name="patterns" direction="in"/>
577 <arg type="a(ssssssouso)" name="units" direction="out"/>
578 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ListUnitsResult"/>
579 </method>
580 <method name="ListUnitsByNames">
581 <arg type="as" name="names" direction="in"/>
582 <arg type="a(ssssssouso)" name="units" direction="out"/>
583 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ListUnitsResult"/>
584 </method>
585 <!-- <method name="ListJobs"> -->
586 <!-- <arg type="a(usssoo)" name="jobs" direction="out"/> -->
587 <!-- </method> -->
588 <method name="Subscribe">
589 </method>
590 <method name="Unsubscribe">
591 </method>
592 <method name="Dump">
593 <arg type="s" name="output" direction="out"/>
594 </method>
595 <method name="DumpUnitsMatchingPatterns">
596 <arg type="as" name="patterns" direction="in"/>
597 <arg type="s" name="output" direction="out"/>
598 </method>
599 <method name="DumpByFileDescriptor">
600 <arg type="h" name="fd" direction="out"/>
601 </method>
602 <method name="DumpUnitsMatchingPatternsByFileDescriptor">
603 <arg type="as" name="patterns" direction="in"/>
604 <arg type="h" name="fd" direction="out"/>
605 </method>
606 <method name="Reload">
607 </method>
608 <method name="Reexecute">
609 <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
610 </method>
611 <method name="Exit">
612 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
613 </method>
614 <method name="Reboot">
615 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
616 </method>
617 <method name="SoftReboot">
618 <arg type="s" name="new_root" direction="in"/>
619 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
620 </method>
621 <method name="PowerOff">
622 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
623 </method>
624 <method name="Halt">
625 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
626 </method>
627 <method name="KExec">
628 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
629 </method>
630 <method name="SwitchRoot">
631 <arg type="s" name="new_root" direction="in"/>
632 <arg type="s" name="init" direction="in"/>
633 <annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
634 </method>
635 <method name="SetEnvironment">
636 <arg type="as" name="assignments" direction="in"/>
637 </method>
638 <method name="UnsetEnvironment">
639 <arg type="as" name="names" direction="in"/>
640 </method>
641 <method name="UnsetAndSetEnvironment">
642 <arg type="as" name="names" direction="in"/>
643 <arg type="as" name="assignments" direction="in"/>
644 </method>
645 <method name="EnqueueMarkedJobs">
646 <arg type="ao" name="jobs" direction="out"/>
647 </method>
648 <!-- <method name="ListUnitFiles"> -->
649 <!-- <arg type="a(ss)" name="unit_files" direction="out"/> -->
650 <!-- </method> -->
651 <!-- <method name="ListUnitFilesByPatterns"> -->
652 <!-- <arg type="as" name="states" direction="in"/> -->
653 <!-- <arg type="as" name="patterns" direction="in"/> -->
654 <!-- <arg type="a(ss)" name="unit_files" direction="out"/> -->
655 <!-- </method> -->
656 <method name="GetUnitFileState">
657 <arg type="s" name="file" direction="in"/>
658 <arg type="s" name="state" direction="out"/>
659 </method>
660 <!-- <method name="EnableUnitFiles"> -->
661 <!-- <arg type="as" name="files" direction="in"/> -->
662 <!-- <arg type="b" name="runtime" direction="in"/> -->
663 <!-- <arg type="b" name="force" direction="in"/> -->
664 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
665 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
666 <!-- </method> -->
667 <!-- <method name="DisableUnitFiles"> -->
668 <!-- <arg type="as" name="files" direction="in"/> -->
669 <!-- <arg type="b" name="runtime" direction="in"/> -->
670 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
671 <!-- </method> -->
672 <!-- <method name="EnableUnitFilesWithFlags"> -->
673 <!-- <arg type="as" name="files" direction="in"/> -->
674 <!-- <arg type="t" name="flags" direction="in"/> -->
675 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
676 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
677 <!-- </method> -->
678 <!-- <method name="DisableUnitFilesWithFlags"> -->
679 <!-- <arg type="as" name="files" direction="in"/> -->
680 <!-- <arg type="t" name="flags" direction="in"/> -->
681 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
682 <!-- </method> -->
683 <!-- <method name="DisableUnitFilesWithFlagsAndInstallInfo"> -->
684 <!-- <arg type="as" name="files" direction="in"/> -->
685 <!-- <arg type="t" name="flags" direction="in"/> -->
686 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
687 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
688 <!-- </method> -->
689 <!-- <method name="ReenableUnitFiles"> -->
690 <!-- <arg type="as" name="files" direction="in"/> -->
691 <!-- <arg type="b" name="runtime" direction="in"/> -->
692 <!-- <arg type="b" name="force" direction="in"/> -->
693 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
694 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
695 <!-- </method> -->
696 <!-- <method name="LinkUnitFiles"> -->
697 <!-- <arg type="as" name="files" direction="in"/> -->
698 <!-- <arg type="b" name="runtime" direction="in"/> -->
699 <!-- <arg type="b" name="force" direction="in"/> -->
700 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
701 <!-- </method> -->
702 <!-- <method name="PresetUnitFiles"> -->
703 <!-- <arg type="as" name="files" direction="in"/> -->
704 <!-- <arg type="b" name="runtime" direction="in"/> -->
705 <!-- <arg type="b" name="force" direction="in"/> -->
706 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
707 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
708 <!-- </method> -->
709 <!-- <method name="PresetUnitFilesWithMode"> -->
710 <!-- <arg type="as" name="files" direction="in"/> -->
711 <!-- <arg type="s" name="mode" direction="in"/> -->
712 <!-- <arg type="b" name="runtime" direction="in"/> -->
713 <!-- <arg type="b" name="force" direction="in"/> -->
714 <!-- <arg type="b" name="carries_install_info" direction="out"/> -->
715 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
716 <!-- </method> -->
717 <!-- <method name="MaskUnitFiles"> -->
718 <!-- <arg type="as" name="files" direction="in"/> -->
719 <!-- <arg type="b" name="runtime" direction="in"/> -->
720 <!-- <arg type="b" name="force" direction="in"/> -->
721 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
722 <!-- </method> -->
723 <!-- <method name="UnmaskUnitFiles"> -->
724 <!-- <arg type="as" name="files" direction="in"/> -->
725 <!-- <arg type="b" name="runtime" direction="in"/> -->
726 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
727 <!-- </method> -->
728 <!-- <method name="RevertUnitFiles"> -->
729 <!-- <arg type="as" name="files" direction="in"/> -->
730 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
731 <!-- </method> -->
732 <!-- <method name="SetDefaultTarget"> -->
733 <!-- <arg type="s" name="name" direction="in"/> -->
734 <!-- <arg type="b" name="force" direction="in"/> -->
735 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
736 <!-- </method> -->
737 <method name="GetDefaultTarget">
738 <arg type="s" name="name" direction="out"/>
739 </method>
740 <!-- <method name="PresetAllUnitFiles"> -->
741 <!-- <arg type="s" name="mode" direction="in"/> -->
742 <!-- <arg type="b" name="runtime" direction="in"/> -->
743 <!-- <arg type="b" name="force" direction="in"/> -->
744 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
745 <!-- </method> -->
746 <!-- <method name="AddDependencyUnitFiles"> -->
747 <!-- <arg type="as" name="files" direction="in"/> -->
748 <!-- <arg type="s" name="target" direction="in"/> -->
749 <!-- <arg type="s" name="type" direction="in"/> -->
750 <!-- <arg type="b" name="runtime" direction="in"/> -->
751 <!-- <arg type="b" name="force" direction="in"/> -->
752 <!-- <arg type="a(sss)" name="changes" direction="out"/> -->
753 <!-- </method> -->
754 <method name="GetUnitFileLinks">
755 <arg type="s" name="name" direction="in"/>
756 <arg type="b" name="runtime" direction="in"/>
757 <arg type="as" name="links" direction="out"/>
758 </method>
759 <method name="SetExitCode">
760 <arg type="y" name="number" direction="in"/>
761 </method>
762 <method name="LookupDynamicUserByName">
763 <arg type="s" name="name" direction="in"/>
764 <arg type="u" name="uid" direction="out"/>
765 </method>
766 <method name="LookupDynamicUserByUID">
767 <arg type="u" name="uid" direction="in"/>
768 <arg type="s" name="name" direction="out"/>
769 </method>
770 <!-- <method name="GetDynamicUsers"> -->
771 <!-- <arg type="a(us)" name="users" direction="out"/> -->
772 <!-- </method> -->
773 <!-- <method name="DumpUnitFileDescriptorStore"> -->
774 <!-- <arg type="s" name="name" direction="in"/> -->
775 <!-- <arg type="a(suuutuusu)" name="entries" direction="out"/> -->
776 <!-- </method> -->
777 <!-- <method name="StartAuxiliaryScope"> -->
778 <!-- <arg type="s" name="name" direction="in"/> -->
779 <!-- <arg type="ah" name="pidfds" direction="in"/> -->
780 <!-- <arg type="t" name="flags" direction="in"/> -->
781 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
782 <!-- <arg type="o" name="job" direction="out"/> -->
783 <!-- <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> -->
784 <!-- </method> -->
785 <signal name="UnitNew">
786 <arg type="s" name="id"/>
787 <arg type="o" name="unit"/>
788 </signal>
789 <signal name="UnitRemoved">
790 <arg type="s" name="id"/>
791 <arg type="o" name="unit"/>
792 </signal>
793 <signal name="JobNew">
794 <arg type="u" name="id"/>
795 <arg type="o" name="job"/>
796 <arg type="s" name="unit"/>
797 </signal>
798 <signal name="JobRemoved">
799 <arg type="u" name="id"/>
800 <arg type="o" name="job"/>
801 <arg type="s" name="unit"/>
802 <arg type="s" name="result"/>
803 </signal>
804 <signal name="StartupFinished">
805 <arg type="t" name="firmware"/>
806 <arg type="t" name="loader"/>
807 <arg type="t" name="kernel"/>
808 <arg type="t" name="initrd"/>
809 <arg type="t" name="userspace"/>
810 <arg type="t" name="total"/>
811 </signal>
812 <signal name="UnitFilesChanged">
813 </signal>
814 <signal name="Reloading">
815 <arg type="b" name="active"/>
816 </signal>
817 </interface>
818 <node name="unit"/>
819 <node name="job"/>
820</node>
821
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Service.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Service.xml
new file mode 100644
index 00000000..316dd080
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Service.xml
@@ -0,0 +1,1100 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.systemd1.Service">
5 <property name="Type" type="s" access="read">
6 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
7 </property>
8 <property name="ExitType" type="s" access="read">
9 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
10 </property>
11 <property name="Restart" type="s" access="read">
12 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
13 </property>
14 <property name="RestartMode" type="s" access="read">
15 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
16 </property>
17 <property name="PIDFile" type="s" access="read">
18 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
19 </property>
20 <property name="NotifyAccess" type="s" access="read">
21 </property>
22 <property name="RestartUSec" type="t" access="read">
23 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
24 </property>
25 <property name="RestartSteps" type="u" access="read">
26 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
27 </property>
28 <property name="RestartMaxDelayUSec" type="t" access="read">
29 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
30 </property>
31 <property name="RestartUSecNext" type="t" access="read">
32 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
33 </property>
34 <property name="TimeoutStartUSec" type="t" access="read">
35 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
36 </property>
37 <property name="TimeoutStopUSec" type="t" access="read">
38 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
39 </property>
40 <property name="TimeoutAbortUSec" type="t" access="read">
41 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
42 </property>
43 <property name="TimeoutStartFailureMode" type="s" access="read">
44 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
45 </property>
46 <property name="TimeoutStopFailureMode" type="s" access="read">
47 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
48 </property>
49 <property name="RuntimeMaxUSec" type="t" access="read">
50 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
51 </property>
52 <property name="RuntimeRandomizedExtraUSec" type="t" access="read">
53 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
54 </property>
55 <property name="WatchdogUSec" type="t" access="read">
56 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
57 </property>
58 <property name="WatchdogTimestamp" type="t" access="read">
59 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
60 </property>
61 <property name="WatchdogTimestampMonotonic" type="t" access="read">
62 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
63 </property>
64 <property name="RootDirectoryStartOnly" type="b" access="read">
65 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
66 </property>
67 <property name="RemainAfterExit" type="b" access="read">
68 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
69 </property>
70 <property name="GuessMainPID" type="b" access="read">
71 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
72 </property>
73 <!-- <property name="RestartPreventExitStatus" type="(aiai)" access="read"> -->
74 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
75 <!-- </property> -->
76 <!-- <property name="RestartForceExitStatus" type="(aiai)" access="read"> -->
77 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
78 <!-- </property> -->
79 <!-- <property name="SuccessExitStatus" type="(aiai)" access="read"> -->
80 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
81 <!-- </property> -->
82 <property name="MainPID" type="u" access="read">
83 </property>
84 <property name="ControlPID" type="u" access="read">
85 </property>
86 <property name="BusName" type="s" access="read">
87 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
88 </property>
89 <property name="FileDescriptorStoreMax" type="u" access="read">
90 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
91 </property>
92 <property name="NFileDescriptorStore" type="u" access="read">
93 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
94 </property>
95 <property name="FileDescriptorStorePreserve" type="s" access="read">
96 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
97 </property>
98 <property name="StatusText" type="s" access="read">
99 </property>
100 <property name="StatusErrno" type="i" access="read">
101 </property>
102 <property name="StatusBusError" type="s" access="read">
103 </property>
104 <property name="StatusVarlinkError" type="s" access="read">
105 </property>
106 <property name="Result" type="s" access="read">
107 </property>
108 <property name="ReloadResult" type="s" access="read">
109 </property>
110 <property name="CleanResult" type="s" access="read">
111 </property>
112 <property name="LiveMountResult" type="s" access="read">
113 </property>
114 <property name="USBFunctionDescriptors" type="s" access="read">
115 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
116 </property>
117 <property name="USBFunctionStrings" type="s" access="read">
118 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
119 </property>
120 <property name="UID" type="u" access="read">
121 </property>
122 <property name="GID" type="u" access="read">
123 </property>
124 <property name="NRestarts" type="u" access="read">
125 </property>
126 <property name="OOMPolicy" type="s" access="read">
127 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
128 </property>
129 <!-- <property name="OpenFile" type="a(sst)" access="read"> -->
130 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
131 <!-- </property> -->
132 <property name="ExtraFileDescriptorNames" type="as" access="read">
133 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
134 </property>
135 <property name="ReloadSignal" type="i" access="read">
136 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
137 </property>
138 <property name="RefreshOnReload" type="as" access="read">
139 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
140 </property>
141 <property name="ExecMainStartTimestamp" type="t" access="read">
142 </property>
143 <property name="ExecMainStartTimestampMonotonic" type="t" access="read">
144 </property>
145 <property name="ExecMainExitTimestamp" type="t" access="read">
146 </property>
147 <property name="ExecMainExitTimestampMonotonic" type="t" access="read">
148 </property>
149 <property name="ExecMainHandoffTimestamp" type="t" access="read">
150 </property>
151 <property name="ExecMainHandoffTimestampMonotonic" type="t" access="read">
152 </property>
153 <property name="ExecMainPID" type="u" access="read">
154 </property>
155 <property name="ExecMainCode" type="i" access="read">
156 </property>
157 <property name="ExecMainStatus" type="i" access="read">
158 </property>
159 <!-- <property name="ExecCondition" type="a(sasbttttuii)" access="read"> -->
160 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
161 <!-- </property> -->
162 <!-- <property name="ExecConditionEx" type="a(sasasttttuii)" access="read"> -->
163 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
164 <!-- </property> -->
165 <!-- <property name="ExecStartPre" type="a(sasbttttuii)" access="read"> -->
166 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
167 <!-- </property> -->
168 <!-- <property name="ExecStartPreEx" type="a(sasasttttuii)" access="read"> -->
169 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
170 <!-- </property> -->
171 <!-- <property name="ExecStart" type="a(sasbttttuii)" access="read"> -->
172 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
173 <!-- </property> -->
174 <!-- <property name="ExecStartEx" type="a(sasasttttuii)" access="read"> -->
175 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
176 <!-- </property> -->
177 <!-- <property name="ExecStartPost" type="a(sasbttttuii)" access="read"> -->
178 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
179 <!-- </property> -->
180 <!-- <property name="ExecStartPostEx" type="a(sasasttttuii)" access="read"> -->
181 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
182 <!-- </property> -->
183 <!-- <property name="ExecReload" type="a(sasbttttuii)" access="read"> -->
184 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
185 <!-- </property> -->
186 <!-- <property name="ExecReloadEx" type="a(sasasttttuii)" access="read"> -->
187 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
188 <!-- </property> -->
189 <!-- <property name="ExecReloadPost" type="a(sasbttttuii)" access="read"> -->
190 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
191 <!-- </property> -->
192 <!-- <property name="ExecReloadPostEx" type="a(sasasttttuii)" access="read"> -->
193 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
194 <!-- </property> -->
195 <!-- <property name="ExecStop" type="a(sasbttttuii)" access="read"> -->
196 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
197 <!-- </property> -->
198 <!-- <property name="ExecStopEx" type="a(sasasttttuii)" access="read"> -->
199 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
200 <!-- </property> -->
201 <!-- <property name="ExecStopPost" type="a(sasbttttuii)" access="read"> -->
202 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
203 <!-- </property> -->
204 <!-- <property name="ExecStopPostEx" type="a(sasasttttuii)" access="read"> -->
205 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
206 <!-- </property> -->
207 <method name="BindMount">
208 <arg type="s" name="source" direction="in"/>
209 <arg type="s" name="destination" direction="in"/>
210 <arg type="b" name="read_only" direction="in"/>
211 <arg type="b" name="mkdir" direction="in"/>
212 </method>
213 <!-- <method name="MountImage"> -->
214 <!-- <arg type="s" name="source" direction="in"/> -->
215 <!-- <arg type="s" name="destination" direction="in"/> -->
216 <!-- <arg type="b" name="read_only" direction="in"/> -->
217 <!-- <arg type="b" name="mkdir" direction="in"/> -->
218 <!-- <arg type="a(ss)" name="options" direction="in"/> -->
219 <!-- </method> -->
220 <!-- <method name="DumpFileDescriptorStore"> -->
221 <!-- <arg type="a(suuutuusu)" name="entries" direction="out"/> -->
222 <!-- </method> -->
223 <property name="Slice" type="s" access="read">
224 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
225 </property>
226 <property name="ControlGroup" type="s" access="read">
227 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
228 </property>
229 <property name="ControlGroupId" type="t" access="read">
230 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
231 </property>
232 <property name="MemoryCurrent" type="t" access="read">
233 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
234 </property>
235 <property name="MemoryPeak" type="t" access="read">
236 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
237 </property>
238 <property name="MemorySwapCurrent" type="t" access="read">
239 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
240 </property>
241 <property name="MemorySwapPeak" type="t" access="read">
242 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
243 </property>
244 <property name="MemoryZSwapCurrent" type="t" access="read">
245 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
246 </property>
247 <property name="MemoryAvailable" type="t" access="read">
248 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
249 </property>
250 <property name="EffectiveMemoryMax" type="t" access="read">
251 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
252 </property>
253 <property name="EffectiveMemoryHigh" type="t" access="read">
254 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
255 </property>
256 <property name="CPUUsageNSec" type="t" access="read">
257 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
258 </property>
259 <property name="EffectiveCPUs" type="ay" access="read">
260 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
261 </property>
262 <property name="EffectiveMemoryNodes" type="ay" access="read">
263 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
264 </property>
265 <property name="TasksCurrent" type="t" access="read">
266 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
267 </property>
268 <property name="EffectiveTasksMax" type="t" access="read">
269 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
270 </property>
271 <property name="IPIngressBytes" type="t" access="read">
272 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
273 </property>
274 <property name="IPIngressPackets" type="t" access="read">
275 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
276 </property>
277 <property name="IPEgressBytes" type="t" access="read">
278 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
279 </property>
280 <property name="IPEgressPackets" type="t" access="read">
281 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
282 </property>
283 <property name="IOReadBytes" type="t" access="read">
284 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
285 </property>
286 <property name="IOReadOperations" type="t" access="read">
287 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
288 </property>
289 <property name="IOWriteBytes" type="t" access="read">
290 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
291 </property>
292 <property name="IOWriteOperations" type="t" access="read">
293 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
294 </property>
295 <property name="OOMKills" type="t" access="read">
296 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
297 </property>
298 <property name="ManagedOOMKills" type="t" access="read">
299 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
300 </property>
301 <!-- <method name="GetProcesses"> -->
302 <!-- <arg type="a(sus)" name="processes" direction="out"/> -->
303 <!-- </method> -->
304 <!-- <method name="AttachProcesses"> -->
305 <!-- <arg type="s" name="subcgroup" direction="in"/> -->
306 <!-- <arg type="au" name="pids" direction="in"/> -->
307 <!-- </method> -->
308 <method name="RemoveSubgroup">
309 <arg type="s" name="subcgroup" direction="in"/>
310 <arg type="t" name="flags" direction="in"/>
311 </method>
312 <property name="Delegate" type="b" access="read">
313 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
314 </property>
315 <property name="DelegateControllers" type="as" access="read">
316 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
317 </property>
318 <property name="DelegateSubgroup" type="s" access="read">
319 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
320 </property>
321 <property name="CPUWeight" type="t" access="read">
322 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
323 </property>
324 <property name="StartupCPUWeight" type="t" access="read">
325 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
326 </property>
327 <property name="CPUQuotaPerSecUSec" type="t" access="read">
328 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
329 </property>
330 <property name="CPUQuotaPeriodUSec" type="t" access="read">
331 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
332 </property>
333 <property name="AllowedCPUs" type="ay" access="read">
334 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
335 </property>
336 <property name="StartupAllowedCPUs" type="ay" access="read">
337 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
338 </property>
339 <property name="AllowedMemoryNodes" type="ay" access="read">
340 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
341 </property>
342 <property name="StartupAllowedMemoryNodes" type="ay" access="read">
343 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
344 </property>
345 <property name="IOAccounting" type="b" access="read">
346 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
347 </property>
348 <property name="IOWeight" type="t" access="read">
349 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
350 </property>
351 <property name="StartupIOWeight" type="t" access="read">
352 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
353 </property>
354 <!-- <property name="IODeviceWeight" type="a(st)" access="read"> -->
355 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
356 <!-- </property> -->
357 <!-- <property name="IOReadBandwidthMax" type="a(st)" access="read"> -->
358 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
359 <!-- </property> -->
360 <!-- <property name="IOWriteBandwidthMax" type="a(st)" access="read"> -->
361 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
362 <!-- </property> -->
363 <!-- <property name="IOReadIOPSMax" type="a(st)" access="read"> -->
364 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
365 <!-- </property> -->
366 <!-- <property name="IOWriteIOPSMax" type="a(st)" access="read"> -->
367 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
368 <!-- </property> -->
369 <!-- <property name="IODeviceLatencyTargetUSec" type="a(st)" access="read"> -->
370 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
371 <!-- </property> -->
372 <property name="MemoryAccounting" type="b" access="read">
373 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
374 </property>
375 <property name="MemoryMin" type="t" access="read">
376 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
377 </property>
378 <property name="MemoryLow" type="t" access="read">
379 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
380 </property>
381 <property name="StartupMemoryLow" type="t" access="read">
382 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
383 </property>
384 <property name="MemoryHigh" type="t" access="read">
385 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
386 </property>
387 <property name="StartupMemoryHigh" type="t" access="read">
388 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
389 </property>
390 <property name="MemoryMax" type="t" access="read">
391 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
392 </property>
393 <property name="StartupMemoryMax" type="t" access="read">
394 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
395 </property>
396 <property name="MemorySwapMax" type="t" access="read">
397 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
398 </property>
399 <property name="StartupMemorySwapMax" type="t" access="read">
400 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
401 </property>
402 <property name="MemoryZSwapMax" type="t" access="read">
403 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
404 </property>
405 <property name="StartupMemoryZSwapMax" type="t" access="read">
406 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
407 </property>
408 <property name="MemoryZSwapWriteback" type="b" access="read">
409 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
410 </property>
411 <property name="DevicePolicy" type="s" access="read">
412 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
413 </property>
414 <!-- <property name="DeviceAllow" type="a(ss)" access="read"> -->
415 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
416 <!-- </property> -->
417 <property name="TasksAccounting" type="b" access="read">
418 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
419 </property>
420 <property name="TasksMax" type="t" access="read">
421 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
422 </property>
423 <property name="IPAccounting" type="b" access="read">
424 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
425 </property>
426 <!-- <property name="IPAddressAllow" type="a(iayu)" access="read"> -->
427 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
428 <!-- </property> -->
429 <!-- <property name="IPAddressDeny" type="a(iayu)" access="read"> -->
430 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
431 <!-- </property> -->
432 <property name="IPIngressFilterPath" type="as" access="read">
433 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
434 </property>
435 <property name="IPEgressFilterPath" type="as" access="read">
436 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
437 </property>
438 <property name="DisableControllers" type="as" access="read">
439 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
440 </property>
441 <property name="ManagedOOMSwap" type="s" access="read">
442 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
443 </property>
444 <property name="ManagedOOMMemoryPressure" type="s" access="read">
445 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
446 </property>
447 <property name="ManagedOOMMemoryPressureLimit" type="u" access="read">
448 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
449 </property>
450 <property name="ManagedOOMMemoryPressureDurationUSec" type="t" access="read">
451 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
452 </property>
453 <property name="ManagedOOMPreference" type="s" access="read">
454 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
455 </property>
456 <!-- <property name="BPFProgram" type="a(ss)" access="read"> -->
457 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
458 <!-- </property> -->
459 <!-- <property name="SocketBindAllow" type="a(iiqq)" access="read"> -->
460 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
461 <!-- </property> -->
462 <!-- <property name="SocketBindDeny" type="a(iiqq)" access="read"> -->
463 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
464 <!-- </property> -->
465 <!-- <property name="RestrictNetworkInterfaces" type="(bas)" access="read"> -->
466 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
467 <!-- </property> -->
468 <property name="BindNetworkInterface" type="s" access="read">
469 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
470 </property>
471 <property name="MemoryPressureWatch" type="s" access="read">
472 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
473 </property>
474 <property name="MemoryPressureThresholdUSec" type="t" access="read">
475 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
476 </property>
477 <!-- <property name="NFTSet" type="a(iiss)" access="read"> -->
478 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
479 <!-- </property> -->
480 <property name="CoredumpReceive" type="b" access="read">
481 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
482 </property>
483 <property name="Environment" type="as" access="read">
484 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
485 </property>
486 <!-- <property name="EnvironmentFiles" type="a(sb)" access="read"> -->
487 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
488 <!-- </property> -->
489 <property name="PassEnvironment" type="as" access="read">
490 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
491 </property>
492 <property name="UnsetEnvironment" type="as" access="read">
493 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
494 </property>
495 <property name="UMask" type="u" access="read">
496 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
497 </property>
498 <property name="LimitCPU" type="t" access="read">
499 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
500 </property>
501 <property name="LimitCPUSoft" type="t" access="read">
502 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
503 </property>
504 <property name="LimitFSIZE" type="t" access="read">
505 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
506 </property>
507 <property name="LimitFSIZESoft" type="t" access="read">
508 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
509 </property>
510 <property name="LimitDATA" type="t" access="read">
511 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
512 </property>
513 <property name="LimitDATASoft" type="t" access="read">
514 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
515 </property>
516 <property name="LimitSTACK" type="t" access="read">
517 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
518 </property>
519 <property name="LimitSTACKSoft" type="t" access="read">
520 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
521 </property>
522 <property name="LimitCORE" type="t" access="read">
523 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
524 </property>
525 <property name="LimitCORESoft" type="t" access="read">
526 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
527 </property>
528 <property name="LimitRSS" type="t" access="read">
529 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
530 </property>
531 <property name="LimitRSSSoft" type="t" access="read">
532 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
533 </property>
534 <property name="LimitNOFILE" type="t" access="read">
535 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
536 </property>
537 <property name="LimitNOFILESoft" type="t" access="read">
538 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
539 </property>
540 <property name="LimitAS" type="t" access="read">
541 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
542 </property>
543 <property name="LimitASSoft" type="t" access="read">
544 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
545 </property>
546 <property name="LimitNPROC" type="t" access="read">
547 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
548 </property>
549 <property name="LimitNPROCSoft" type="t" access="read">
550 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
551 </property>
552 <property name="LimitMEMLOCK" type="t" access="read">
553 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
554 </property>
555 <property name="LimitMEMLOCKSoft" type="t" access="read">
556 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
557 </property>
558 <property name="LimitLOCKS" type="t" access="read">
559 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
560 </property>
561 <property name="LimitLOCKSSoft" type="t" access="read">
562 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
563 </property>
564 <property name="LimitSIGPENDING" type="t" access="read">
565 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
566 </property>
567 <property name="LimitSIGPENDINGSoft" type="t" access="read">
568 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
569 </property>
570 <property name="LimitMSGQUEUE" type="t" access="read">
571 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
572 </property>
573 <property name="LimitMSGQUEUESoft" type="t" access="read">
574 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
575 </property>
576 <property name="LimitNICE" type="t" access="read">
577 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
578 </property>
579 <property name="LimitNICESoft" type="t" access="read">
580 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
581 </property>
582 <property name="LimitRTPRIO" type="t" access="read">
583 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
584 </property>
585 <property name="LimitRTPRIOSoft" type="t" access="read">
586 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
587 </property>
588 <property name="LimitRTTIME" type="t" access="read">
589 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
590 </property>
591 <property name="LimitRTTIMESoft" type="t" access="read">
592 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
593 </property>
594 <property name="WorkingDirectory" type="s" access="read">
595 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
596 </property>
597 <property name="RootDirectory" type="s" access="read">
598 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
599 </property>
600 <property name="RootImage" type="s" access="read">
601 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
602 </property>
603 <!-- <property name="RootImageOptions" type="a(ss)" access="read"> -->
604 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
605 <!-- </property> -->
606 <property name="RootHash" type="ay" access="read">
607 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
608 </property>
609 <property name="RootHashPath" type="s" access="read">
610 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
611 </property>
612 <property name="RootHashSignature" type="ay" access="read">
613 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
614 </property>
615 <property name="RootHashSignaturePath" type="s" access="read">
616 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
617 </property>
618 <property name="RootVerity" type="s" access="read">
619 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
620 </property>
621 <property name="RootEphemeral" type="b" access="read">
622 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
623 </property>
624 <property name="RootMStack" type="s" access="read">
625 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
626 </property>
627 <property name="ExtensionDirectories" type="as" access="read">
628 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
629 </property>
630 <!-- <property name="ExtensionImages" type="a(sba(ss))" access="read"> -->
631 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
632 <!-- </property> -->
633 <!-- <property name="MountImages" type="a(ssba(ss))" access="read"> -->
634 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
635 <!-- </property> -->
636 <property name="OOMScoreAdjust" type="i" access="read">
637 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
638 </property>
639 <property name="CoredumpFilter" type="t" access="read">
640 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
641 </property>
642 <property name="Nice" type="i" access="read">
643 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
644 </property>
645 <property name="IOSchedulingClass" type="i" access="read">
646 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
647 </property>
648 <property name="IOSchedulingPriority" type="i" access="read">
649 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
650 </property>
651 <property name="CPUSchedulingPolicy" type="i" access="read">
652 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
653 </property>
654 <property name="CPUSchedulingPriority" type="i" access="read">
655 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
656 </property>
657 <property name="CPUAffinity" type="ay" access="read">
658 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
659 </property>
660 <property name="CPUAffinityFromNUMA" type="b" access="read">
661 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
662 </property>
663 <property name="NUMAPolicy" type="i" access="read">
664 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
665 </property>
666 <property name="NUMAMask" type="ay" access="read">
667 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
668 </property>
669 <property name="TimerSlackNSec" type="t" access="read">
670 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
671 </property>
672 <property name="CPUSchedulingResetOnFork" type="b" access="read">
673 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
674 </property>
675 <property name="NonBlocking" type="b" access="read">
676 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
677 </property>
678 <property name="StandardInput" type="s" access="read">
679 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
680 </property>
681 <property name="StandardInputFileDescriptorName" type="s" access="read">
682 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
683 </property>
684 <property name="StandardInputData" type="ay" access="read">
685 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
686 </property>
687 <property name="StandardOutput" type="s" access="read">
688 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
689 </property>
690 <property name="StandardOutputFileDescriptorName" type="s" access="read">
691 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
692 </property>
693 <property name="StandardError" type="s" access="read">
694 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
695 </property>
696 <property name="StandardErrorFileDescriptorName" type="s" access="read">
697 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
698 </property>
699 <property name="TTYPath" type="s" access="read">
700 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
701 </property>
702 <property name="TTYReset" type="b" access="read">
703 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
704 </property>
705 <property name="TTYVHangup" type="b" access="read">
706 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
707 </property>
708 <property name="TTYVTDisallocate" type="b" access="read">
709 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
710 </property>
711 <property name="TTYRows" type="q" access="read">
712 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
713 </property>
714 <property name="TTYColumns" type="q" access="read">
715 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
716 </property>
717 <property name="SyslogPriority" type="i" access="read">
718 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
719 </property>
720 <property name="SyslogIdentifier" type="s" access="read">
721 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
722 </property>
723 <property name="SyslogLevelPrefix" type="b" access="read">
724 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
725 </property>
726 <property name="SyslogLevel" type="i" access="read">
727 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
728 </property>
729 <property name="SyslogFacility" type="i" access="read">
730 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
731 </property>
732 <property name="LogLevelMax" type="i" access="read">
733 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
734 </property>
735 <property name="LogRateLimitIntervalUSec" type="t" access="read">
736 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
737 </property>
738 <property name="LogRateLimitBurst" type="u" access="read">
739 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
740 </property>
741 <!-- <property name="LogExtraFields" type="aay" access="read"> -->
742 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
743 <!-- </property> -->
744 <!-- <property name="LogFilterPatterns" type="a(bs)" access="read"> -->
745 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
746 <!-- </property> -->
747 <property name="LogNamespace" type="s" access="read">
748 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
749 </property>
750 <property name="SecureBits" type="i" access="read">
751 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
752 </property>
753 <property name="CapabilityBoundingSet" type="t" access="read">
754 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
755 </property>
756 <property name="AmbientCapabilities" type="t" access="read">
757 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
758 </property>
759 <property name="User" type="s" access="read">
760 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
761 </property>
762 <property name="Group" type="s" access="read">
763 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
764 </property>
765 <property name="DynamicUser" type="b" access="read">
766 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
767 </property>
768 <property name="SetLoginEnvironment" type="b" access="read">
769 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
770 </property>
771 <property name="RemoveIPC" type="b" access="read">
772 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
773 </property>
774 <!-- <property name="SetCredential" type="a(say)" access="read"> -->
775 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
776 <!-- </property> -->
777 <!-- <property name="SetCredentialEncrypted" type="a(say)" access="read"> -->
778 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
779 <!-- </property> -->
780 <!-- <property name="LoadCredential" type="a(ss)" access="read"> -->
781 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
782 <!-- </property> -->
783 <!-- <property name="LoadCredentialEncrypted" type="a(ss)" access="read"> -->
784 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
785 <!-- </property> -->
786 <property name="ImportCredential" type="as" access="read">
787 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
788 </property>
789 <!-- <property name="ImportCredentialEx" type="a(ss)" access="read"> -->
790 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
791 <!-- </property> -->
792 <property name="SupplementaryGroups" type="as" access="read">
793 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
794 </property>
795 <property name="PAMName" type="s" access="read">
796 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
797 </property>
798 <property name="ReadWritePaths" type="as" access="read">
799 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
800 </property>
801 <property name="ReadOnlyPaths" type="as" access="read">
802 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
803 </property>
804 <property name="InaccessiblePaths" type="as" access="read">
805 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
806 </property>
807 <property name="ExecPaths" type="as" access="read">
808 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
809 </property>
810 <property name="NoExecPaths" type="as" access="read">
811 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
812 </property>
813 <property name="ExecSearchPath" type="as" access="read">
814 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
815 </property>
816 <property name="MountFlags" type="t" access="read">
817 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
818 </property>
819 <property name="PrivateTmp" type="b" access="read">
820 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
821 </property>
822 <property name="PrivateTmpEx" type="s" access="read">
823 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
824 </property>
825 <property name="PrivateDevices" type="b" access="read">
826 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
827 </property>
828 <property name="ProtectClock" type="b" access="read">
829 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
830 </property>
831 <property name="ProtectKernelTunables" type="b" access="read">
832 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
833 </property>
834 <property name="ProtectKernelModules" type="b" access="read">
835 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
836 </property>
837 <property name="ProtectKernelLogs" type="b" access="read">
838 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
839 </property>
840 <property name="ProtectControlGroups" type="b" access="read">
841 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
842 </property>
843 <property name="ProtectControlGroupsEx" type="s" access="read">
844 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
845 </property>
846 <property name="PrivateNetwork" type="b" access="read">
847 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
848 </property>
849 <property name="PrivateUsers" type="b" access="read">
850 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
851 </property>
852 <property name="PrivateUsersEx" type="s" access="read">
853 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
854 </property>
855 <property name="PrivateMounts" type="b" access="read">
856 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
857 </property>
858 <property name="PrivateIPC" type="b" access="read">
859 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
860 </property>
861 <property name="PrivatePIDs" type="s" access="read">
862 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
863 </property>
864 <property name="ProtectHome" type="s" access="read">
865 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
866 </property>
867 <property name="ProtectSystem" type="s" access="read">
868 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
869 </property>
870 <property name="SameProcessGroup" type="b" access="read">
871 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
872 </property>
873 <property name="UtmpIdentifier" type="s" access="read">
874 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
875 </property>
876 <property name="UtmpMode" type="s" access="read">
877 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
878 </property>
879 <!-- <property name="SELinuxContext" type="(bs)" access="read"> -->
880 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
881 <!-- </property> -->
882 <!-- <property name="AppArmorProfile" type="(bs)" access="read"> -->
883 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
884 <!-- </property> -->
885 <!-- <property name="SmackProcessLabel" type="(bs)" access="read"> -->
886 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
887 <!-- </property> -->
888 <property name="IgnoreSIGPIPE" type="b" access="read">
889 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
890 </property>
891 <property name="NoNewPrivileges" type="b" access="read">
892 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
893 </property>
894 <!-- <property name="SystemCallFilter" type="(bas)" access="read"> -->
895 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
896 <!-- </property> -->
897 <property name="SystemCallArchitectures" type="as" access="read">
898 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
899 </property>
900 <property name="SystemCallErrorNumber" type="i" access="read">
901 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
902 </property>
903 <!-- <property name="SystemCallLog" type="(bas)" access="read"> -->
904 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
905 <!-- </property> -->
906 <property name="Personality" type="s" access="read">
907 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
908 </property>
909 <property name="LockPersonality" type="b" access="read">
910 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
911 </property>
912 <!-- <property name="RestrictAddressFamilies" type="(bas)" access="read"> -->
913 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
914 <!-- </property> -->
915 <!-- <property name="RuntimeDirectorySymlink" type="a(sst)" access="read"> -->
916 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
917 <!-- </property> -->
918 <property name="RuntimeDirectoryPreserve" type="s" access="read">
919 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
920 </property>
921 <property name="RuntimeDirectoryMode" type="u" access="read">
922 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
923 </property>
924 <property name="RuntimeDirectory" type="as" access="read">
925 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
926 </property>
927 <!-- <property name="StateDirectorySymlink" type="a(sst)" access="read"> -->
928 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
929 <!-- </property> -->
930 <property name="StateDirectoryMode" type="u" access="read">
931 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
932 </property>
933 <property name="StateDirectoryAccounting" type="b" access="read">
934 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
935 </property>
936 <!-- <property name="StateDirectoryQuota" type="(tus)" access="read"> -->
937 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
938 <!-- </property> -->
939 <property name="StateDirectory" type="as" access="read">
940 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
941 </property>
942 <!-- <property name="CacheDirectorySymlink" type="a(sst)" access="read"> -->
943 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
944 <!-- </property> -->
945 <property name="CacheDirectoryMode" type="u" access="read">
946 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
947 </property>
948 <property name="CacheDirectoryAccounting" type="b" access="read">
949 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
950 </property>
951 <!-- <property name="CacheDirectoryQuota" type="(tus)" access="read"> -->
952 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
953 <!-- </property> -->
954 <property name="CacheDirectory" type="as" access="read">
955 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
956 </property>
957 <!-- <property name="LogsDirectorySymlink" type="a(sst)" access="read"> -->
958 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
959 <!-- </property> -->
960 <property name="LogsDirectoryMode" type="u" access="read">
961 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
962 </property>
963 <property name="LogsDirectoryAccounting" type="b" access="read">
964 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
965 </property>
966 <!-- <property name="LogsDirectoryQuota" type="(tus)" access="read"> -->
967 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
968 <!-- </property> -->
969 <property name="LogsDirectory" type="as" access="read">
970 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
971 </property>
972 <property name="ConfigurationDirectoryMode" type="u" access="read">
973 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
974 </property>
975 <property name="ConfigurationDirectory" type="as" access="read">
976 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
977 </property>
978 <property name="TimeoutCleanUSec" type="t" access="read">
979 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
980 </property>
981 <property name="MemoryDenyWriteExecute" type="b" access="read">
982 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
983 </property>
984 <property name="RestrictRealtime" type="b" access="read">
985 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
986 </property>
987 <property name="RestrictSUIDSGID" type="b" access="read">
988 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
989 </property>
990 <property name="RestrictNamespaces" type="t" access="read">
991 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
992 </property>
993 <property name="DelegateNamespaces" type="t" access="read">
994 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
995 </property>
996 <!-- <property name="RestrictFileSystems" type="(bas)" access="read"> -->
997 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
998 <!-- </property> -->
999 <!-- <property name="BindPaths" type="a(ssbt)" access="read"> -->
1000 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
1001 <!-- </property> -->
1002 <!-- <property name="BindReadOnlyPaths" type="a(ssbt)" access="read"> -->
1003 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
1004 <!-- </property> -->
1005 <!-- <property name="TemporaryFileSystem" type="a(ss)" access="read"> -->
1006 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
1007 <!-- </property> -->
1008 <property name="MountAPIVFS" type="b" access="read">
1009 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1010 </property>
1011 <property name="BindLogSockets" type="b" access="read">
1012 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1013 </property>
1014 <property name="KeyringMode" type="s" access="read">
1015 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1016 </property>
1017 <property name="ProtectProc" type="s" access="read">
1018 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1019 </property>
1020 <property name="ProcSubset" type="s" access="read">
1021 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1022 </property>
1023 <property name="ProtectHostname" type="b" access="read">
1024 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1025 </property>
1026 <!-- <property name="ProtectHostnameEx" type="(ss)" access="read"> -->
1027 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
1028 <!-- </property> -->
1029 <property name="PrivateBPF" type="s" access="read">
1030 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1031 </property>
1032 <property name="BPFDelegateCommands" type="s" access="read">
1033 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1034 </property>
1035 <property name="BPFDelegateMaps" type="s" access="read">
1036 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1037 </property>
1038 <property name="BPFDelegatePrograms" type="s" access="read">
1039 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1040 </property>
1041 <property name="BPFDelegateAttachments" type="s" access="read">
1042 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1043 </property>
1044 <property name="MemoryKSM" type="b" access="read">
1045 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1046 </property>
1047 <property name="MemoryTHP" type="s" access="read">
1048 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1049 </property>
1050 <property name="UserNamespacePath" type="s" access="read">
1051 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1052 </property>
1053 <property name="NetworkNamespacePath" type="s" access="read">
1054 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1055 </property>
1056 <property name="IPCNamespacePath" type="s" access="read">
1057 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1058 </property>
1059 <property name="RootImagePolicy" type="s" access="read">
1060 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1061 </property>
1062 <property name="MountImagePolicy" type="s" access="read">
1063 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1064 </property>
1065 <property name="ExtensionImagePolicy" type="s" access="read">
1066 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1067 </property>
1068 <!-- <property name="StateDirectoryQuotaUsage" type="(tt)" access="read"> -->
1069 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
1070 <!-- </property> -->
1071 <!-- <property name="CacheDirectoryQuotaUsage" type="(tt)" access="read"> -->
1072 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
1073 <!-- </property> -->
1074 <!-- <property name="LogsDirectoryQuotaUsage" type="(tt)" access="read"> -->
1075 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/> -->
1076 <!-- </property> -->
1077 <property name="KillMode" type="s" access="read">
1078 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1079 </property>
1080 <property name="KillSignal" type="i" access="read">
1081 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1082 </property>
1083 <property name="RestartKillSignal" type="i" access="read">
1084 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1085 </property>
1086 <property name="FinalKillSignal" type="i" access="read">
1087 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1088 </property>
1089 <property name="SendSIGKILL" type="b" access="read">
1090 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1091 </property>
1092 <property name="SendSIGHUP" type="b" access="read">
1093 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1094 </property>
1095 <property name="WatchdogSignal" type="i" access="read">
1096 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
1097 </property>
1098 </interface>
1099</node>
1100
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Unit.xml b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Unit.xml
new file mode 100644
index 00000000..a554f513
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/org.freedesktop.systemd1.Unit.xml
@@ -0,0 +1,359 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2"https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.systemd1.Unit">
5 <property name="Id" type="s" access="read">
6 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
7 </property>
8 <property name="Names" type="as" access="read">
9 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
10 </property>
11 <property name="Following" type="s" access="read">
12 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
13 </property>
14 <!-- <property name="Requires" type="as" access="read"> -->
15 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
16 <!-- </property> -->
17 <property name="Requisite" type="as" access="read">
18 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
19 </property>
20 <property name="Wants" type="as" access="read">
21 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
22 </property>
23 <property name="BindsTo" type="as" access="read">
24 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
25 </property>
26 <property name="PartOf" type="as" access="read">
27 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
28 </property>
29 <property name="Upholds" type="as" access="read">
30 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
31 </property>
32 <property name="RequiredBy" type="as" access="read">
33 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
34 </property>
35 <property name="RequisiteOf" type="as" access="read">
36 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
37 </property>
38 <property name="WantedBy" type="as" access="read">
39 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
40 </property>
41 <property name="BoundBy" type="as" access="read">
42 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
43 </property>
44 <property name="UpheldBy" type="as" access="read">
45 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
46 </property>
47 <property name="ConsistsOf" type="as" access="read">
48 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
49 </property>
50 <property name="Conflicts" type="as" access="read">
51 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
52 </property>
53 <property name="ConflictedBy" type="as" access="read">
54 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
55 </property>
56 <property name="Before" type="as" access="read">
57 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
58 </property>
59 <property name="After" type="as" access="read">
60 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
61 </property>
62 <property name="OnSuccess" type="as" access="read">
63 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
64 </property>
65 <property name="OnSuccessOf" type="as" access="read">
66 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
67 </property>
68 <property name="OnFailure" type="as" access="read">
69 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
70 </property>
71 <property name="OnFailureOf" type="as" access="read">
72 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
73 </property>
74 <property name="Triggers" type="as" access="read">
75 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
76 </property>
77 <property name="TriggeredBy" type="as" access="read">
78 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
79 </property>
80 <property name="PropagatesReloadTo" type="as" access="read">
81 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
82 </property>
83 <property name="ReloadPropagatedFrom" type="as" access="read">
84 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
85 </property>
86 <property name="PropagatesStopTo" type="as" access="read">
87 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
88 </property>
89 <property name="StopPropagatedFrom" type="as" access="read">
90 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
91 </property>
92 <property name="JoinsNamespaceOf" type="as" access="read">
93 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
94 </property>
95 <property name="SliceOf" type="as" access="read">
96 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
97 </property>
98 <property name="RequiresMountsFor" type="as" access="read">
99 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
100 </property>
101 <property name="WantsMountsFor" type="as" access="read">
102 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
103 </property>
104 <property name="Documentation" type="as" access="read">
105 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
106 </property>
107 <property name="Description" type="s" access="read">
108 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
109 </property>
110 <property name="AccessSELinuxContext" type="s" access="read">
111 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
112 </property>
113 <property name="LoadState" type="s" access="read">
114 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
115 </property>
116 <property name="ActiveState" type="s" access="read">
117 </property>
118 <property name="FreezerState" type="s" access="read">
119 </property>
120 <property name="SubState" type="s" access="read">
121 </property>
122 <property name="FragmentPath" type="s" access="read">
123 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
124 </property>
125 <property name="SourcePath" type="s" access="read">
126 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
127 </property>
128 <property name="DropInPaths" type="as" access="read">
129 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
130 </property>
131 <property name="UnitFileState" type="s" access="read">
132 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
133 </property>
134 <property name="UnitFilePreset" type="s" access="read">
135 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
136 </property>
137 <property name="StateChangeTimestamp" type="t" access="read">
138 </property>
139 <property name="StateChangeTimestampMonotonic" type="t" access="read">
140 </property>
141 <property name="InactiveExitTimestamp" type="t" access="read">
142 </property>
143 <property name="InactiveExitTimestampMonotonic" type="t" access="read">
144 </property>
145 <property name="ActiveEnterTimestamp" type="t" access="read">
146 </property>
147 <property name="ActiveEnterTimestampMonotonic" type="t" access="read">
148 </property>
149 <property name="ActiveExitTimestamp" type="t" access="read">
150 </property>
151 <property name="ActiveExitTimestampMonotonic" type="t" access="read">
152 </property>
153 <property name="InactiveEnterTimestamp" type="t" access="read">
154 </property>
155 <property name="InactiveEnterTimestampMonotonic" type="t" access="read">
156 </property>
157 <property name="CanStart" type="b" access="read">
158 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
159 </property>
160 <property name="CanStop" type="b" access="read">
161 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
162 </property>
163 <property name="CanReload" type="b" access="read">
164 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
165 </property>
166 <property name="CanIsolate" type="b" access="read">
167 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
168 </property>
169 <property name="CanClean" type="as" access="read">
170 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
171 </property>
172 <property name="CanFreeze" type="b" access="read">
173 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
174 </property>
175 <property name="CanLiveMount" type="b" access="read">
176 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
177 </property>
178 <!-- <property name="Job" type="(uo)" access="read"> -->
179 <!-- </property> -->
180 <property name="StopWhenUnneeded" type="b" access="read">
181 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
182 </property>
183 <property name="RefuseManualStart" type="b" access="read">
184 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
185 </property>
186 <property name="RefuseManualStop" type="b" access="read">
187 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
188 </property>
189 <property name="AllowIsolate" type="b" access="read">
190 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
191 </property>
192 <property name="DefaultDependencies" type="b" access="read">
193 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
194 </property>
195 <property name="SurviveFinalKillSignal" type="b" access="read">
196 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
197 </property>
198 <property name="OnSuccessJobMode" type="s" access="read">
199 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
200 </property>
201 <property name="OnFailureJobMode" type="s" access="read">
202 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
203 </property>
204 <property name="IgnoreOnIsolate" type="b" access="read">
205 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
206 </property>
207 <property name="NeedDaemonReload" type="b" access="read">
208 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
209 </property>
210 <property name="Markers" type="as" access="read">
211 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
212 </property>
213 <property name="JobTimeoutUSec" type="t" access="read">
214 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
215 </property>
216 <property name="JobRunningTimeoutUSec" type="t" access="read">
217 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
218 </property>
219 <property name="JobTimeoutAction" type="s" access="read">
220 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
221 </property>
222 <property name="JobTimeoutRebootArgument" type="s" access="read">
223 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
224 </property>
225 <property name="ConditionResult" type="b" access="read">
226 </property>
227 <property name="AssertResult" type="b" access="read">
228 </property>
229 <property name="ConditionTimestamp" type="t" access="read">
230 </property>
231 <property name="ConditionTimestampMonotonic" type="t" access="read">
232 </property>
233 <property name="AssertTimestamp" type="t" access="read">
234 </property>
235 <property name="AssertTimestampMonotonic" type="t" access="read">
236 </property>
237 <!-- <property name="Conditions" type="a(sbbsi)" access="read"> -->
238 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
239 <!-- </property> -->
240 <!-- <property name="Asserts" type="a(sbbsi)" access="read"> -->
241 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> -->
242 <!-- </property> -->
243 <!-- <property name="LoadError" type="(ss)" access="read"> -->
244 <!-- <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/> -->
245 <!-- </property> -->
246 <property name="Transient" type="b" access="read">
247 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
248 </property>
249 <property name="Perpetual" type="b" access="read">
250 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
251 </property>
252 <property name="StartLimitIntervalUSec" type="t" access="read">
253 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
254 </property>
255 <property name="StartLimitBurst" type="u" access="read">
256 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
257 </property>
258 <property name="StartLimitAction" type="s" access="read">
259 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
260 </property>
261 <property name="FailureAction" type="s" access="read">
262 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
263 </property>
264 <property name="FailureActionExitStatus" type="i" access="read">
265 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
266 </property>
267 <property name="SuccessAction" type="s" access="read">
268 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
269 </property>
270 <property name="SuccessActionExitStatus" type="i" access="read">
271 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
272 </property>
273 <property name="RebootArgument" type="s" access="read">
274 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
275 </property>
276 <property name="InvocationID" type="ay" access="read">
277 </property>
278 <property name="CollectMode" type="s" access="read">
279 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
280 </property>
281 <property name="Refs" type="as" access="read">
282 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
283 </property>
284 <!-- <property name="ActivationDetails" type="a(ss)" access="read"> -->
285 <!-- </property> -->
286 <property name="DebugInvocation" type="b" access="read">
287 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
288 </property>
289 <method name="Start">
290 <arg type="s" name="mode" direction="in"/>
291 <arg type="o" name="job" direction="out"/>
292 </method>
293 <method name="Stop">
294 <arg type="s" name="mode" direction="in"/>
295 <arg type="o" name="job" direction="out"/>
296 </method>
297 <method name="Reload">
298 <arg type="s" name="mode" direction="in"/>
299 <arg type="o" name="job" direction="out"/>
300 </method>
301 <method name="Restart">
302 <arg type="s" name="mode" direction="in"/>
303 <arg type="o" name="job" direction="out"/>
304 </method>
305 <method name="TryRestart">
306 <arg type="s" name="mode" direction="in"/>
307 <arg type="o" name="job" direction="out"/>
308 </method>
309 <method name="ReloadOrRestart">
310 <arg type="s" name="mode" direction="in"/>
311 <arg type="o" name="job" direction="out"/>
312 </method>
313 <method name="ReloadOrTryRestart">
314 <arg type="s" name="mode" direction="in"/>
315 <arg type="o" name="job" direction="out"/>
316 </method>
317 <!-- <method name="EnqueueJob"> -->
318 <!-- <arg type="s" name="job_type" direction="in"/> -->
319 <!-- <arg type="s" name="job_mode" direction="in"/> -->
320 <!-- <arg type="u" name="job_id" direction="out"/> -->
321 <!-- <arg type="o" name="job_path" direction="out"/> -->
322 <!-- <arg type="s" name="unit_id" direction="out"/> -->
323 <!-- <arg type="o" name="unit_path" direction="out"/> -->
324 <!-- <arg type="s" name="job_type" direction="out"/> -->
325 <!-- <arg type="a(uosos)" name="affected_jobs" direction="out"/> -->
326 <!-- </method> -->
327 <method name="Kill">
328 <arg type="s" name="whom" direction="in"/>
329 <arg type="i" name="signal" direction="in"/>
330 </method>
331 <method name="KillSubgroup">
332 <arg type="s" name="subgroup" direction="in"/>
333 <arg type="i" name="signal" direction="in"/>
334 </method>
335 <method name="QueueSignal">
336 <arg type="s" name="whom" direction="in"/>
337 <arg type="i" name="signal" direction="in"/>
338 <arg type="i" name="value" direction="in"/>
339 </method>
340 <method name="ResetFailed">
341 </method>
342 <!-- <method name="SetProperties"> -->
343 <!-- <arg type="b" name="runtime" direction="in"/> -->
344 <!-- <arg type="a(sv)" name="properties" direction="in"/> -->
345 <!-- </method> -->
346 <method name="Ref">
347 </method>
348 <method name="Unref">
349 </method>
350 <method name="Clean">
351 <arg type="as" name="mask" direction="in"/>
352 </method>
353 <method name="Freeze">
354 </method>
355 <method name="Thaw">
356 </method>
357 </interface>
358</node>
359
diff --git a/accounts/gkleen@skadhi/shell/quickshell/ActiveWindowDisplay.qml b/accounts/gkleen@skadhi/shell/quickshell/ActiveWindowDisplay.qml
new file mode 100644
index 00000000..ac1cbf3a
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/ActiveWindowDisplay.qml
@@ -0,0 +1,172 @@
1import QtQuick
2import qs.Services
3import Quickshell
4import Quickshell.Widgets
5
6Item {
7 id: activeWindowDisplay
8
9 required property int maxWidth
10 required property var screen
11
12 property var activeWindow: {
13 let currWindowId = Array.from(NiriService.workspaces).find(ws => {
14 return ws.output === screen?.name && ws.is_active;
15 })?.active_window_id;
16
17 return currWindowId ? Array.from(NiriService.windows).find(win => win.id == currWindowId) : null;
18 }
19 property var windowEntry: activeWindow ? DesktopEntries.heuristicLookup(activeWindow.app_id) : null
20
21 anchors.verticalCenter: parent.verticalCenter
22 width: activeWindowDisplayContent.width
23 height: parent.height
24
25 WrapperMouseArea {
26 id: widgetMouseArea
27
28 anchors.fill: parent
29
30 hoverEnabled: true
31
32 Item {
33 anchors.fill: parent
34
35 Row {
36 id: activeWindowDisplayContent
37
38 width: childrenRect.width
39 height: parent.height
40 anchors.verticalCenter: parent.verticalCenter
41 spacing: 8
42
43 IconImage {
44 id: activeWindowIcon
45
46 implicitSize: 14
47
48 anchors.verticalCenter: parent.verticalCenter
49
50 source: {
51 let icon = activeWindowDisplay.windowEntry?.icon
52 if (typeof icon === 'string' || icon instanceof String) {
53 if (icon.includes("?path=")) {
54 const split = icon.split("?path=")
55 if (split.length !== 2)
56 return icon
57 const name = split[0]
58 const path = split[1]
59 const fileName = name.substring(
60 name.lastIndexOf("/") + 1)
61 return `file://${path}/${fileName}`
62 } else
63 icon = Quickshell.iconPath(icon);
64 return icon
65 }
66 return ""
67 }
68 asynchronous: true
69 smooth: true
70 mipmap: true
71 }
72
73 Text {
74 id: windowTitle
75
76 width: Math.min(implicitWidth, activeWindowDisplay.maxWidth - activeWindowIcon.width - activeWindowDisplayContent.spacing)
77
78 property var appAliases: { "Firefox": "Mozilla Firefox", "mpv Media Player": "mpv", "Thunderbird": "Mozilla Thunderbird", "Thunderbird (LMU)": "Mozilla Thunderbird" }
79
80 elide: Text.ElideRight
81 maximumLineCount: 1
82 color: "white"
83 anchors.verticalCenter: parent.verticalCenter
84 text: {
85 if (!activeWindowDisplay.activeWindow)
86 return "";
87
88 var title = activeWindowDisplay.activeWindow.title;
89 var appName = activeWindowDisplay.windowEntry?.name;
90 if (appAliases[appName])
91 appName = appAliases[appName];
92 if (appName && title.endsWith(appName)) {
93 const oldTitle = title;
94 title = title.substring(0, title.length - appName.length);
95 title = title.replace(/\s*(—|-)\s*$/, "");
96 if (!title)
97 title = oldTitle;
98 }
99 return title;
100 }
101 }
102 }
103 }
104 }
105
106 Loader {
107 id: tooltipLoader
108
109 active: false
110
111 Connections {
112 target: widgetMouseArea
113 function onContainsMouseChanged() {
114 if (widgetMouseArea.containsMouse)
115 tooltipLoader.active = true;
116 }
117 }
118
119 PopupWindow {
120 id: tooltip
121
122 property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse
123
124 anchor {
125 item: widgetMouseArea
126 edges: Edges.Bottom | Edges.Left
127 }
128 visible: false
129
130 onNextVisibleChanged: hangTimer.restart()
131
132 Timer {
133 id: hangTimer
134 interval: tooltip.visible ? 100 : 500
135 onTriggered: {
136 tooltip.visible = tooltip.nextVisible;
137 if (!tooltip.visible)
138 tooltipLoader.active = false;
139 }
140 }
141
142 implicitWidth: widgetTooltipText.contentWidth + 16
143 implicitHeight: widgetTooltipText.contentHeight + 16
144 color: "black"
145
146 WrapperMouseArea {
147 id: tooltipMouseArea
148
149 hoverEnabled: true
150 enabled: true
151
152 anchors.fill: parent
153
154 Item {
155 anchors.fill: parent
156
157 Text {
158 id: widgetTooltipText
159
160 anchors.centerIn: parent
161
162 font.pointSize: 10
163 font.family: "Fira Mono"
164 color: "white"
165
166 text: JSON.stringify(Object.assign({}, activeWindowDisplay.activeWindow), null, 2)
167 }
168 }
169 }
170 }
171 }
172}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Bar.qml b/accounts/gkleen@skadhi/shell/quickshell/Bar.qml
new file mode 100644
index 00000000..33909884
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Bar.qml
@@ -0,0 +1,142 @@
1import Quickshell
2import Quickshell.Wayland
3import QtQuick
4import qs.Services
5
6PanelWindow {
7 id: bar
8
9 WlrLayershell.namespace: "bar"
10
11 property bool haveMaximizedWindow: {
12 let currWindowId = Array.from(NiriService.workspaces).find(ws => {
13 return ws.output === bar.screen.name && ws.is_active;
14 })?.active_window_id;
15 let activeWindowTileSize = Array.from(NiriService.windows).find(win => win.id == currWindowId)?.layout?.tile_size;
16
17 if (!activeWindowTileSize)
18 return false;
19 return activeWindowTileSize[0] >= bar.screen.width && activeWindowTileSize[1] >= bar.screen.height - bar.height;
20 }
21
22 anchors {
23 top: true
24 left: true
25 right: true
26 }
27 margins {
28 left: bar.haveMaximizedWindow ? 0 : 26 + 8
29 right: bar.haveMaximizedWindow ? 0 : 26 + 8
30 }
31
32 implicitHeight: 21
33 color: "transparent"
34
35 property bool haveScreenshare: Array.from(NiriService.casts).some(cast => cast.target.Output?.name == bar.screen.name)
36
37 Rectangle {
38 color: {
39 if (bar.haveScreenshare)
40 return bar.haveMaximizedWindow ? Qt.rgba(0.2, 0, 0, 1) : Qt.rgba(0.2, 0, 0, 0.75);
41 return bar.haveMaximizedWindow ? "black" : Qt.rgba(0, 0, 0, 0.75);
42 }
43 anchors.fill: parent
44 // bottomLeftRadius: 8
45 // bottomRightRadius: 8
46 }
47
48 Row {
49 id: left
50
51 height: parent.height
52 width: childrenRect.width
53 anchors.left: parent.left
54 anchors.leftMargin: 8
55 anchors.verticalCenter: parent.verticalCenter
56 spacing: 8
57
58 WorkspaceSwitcher {
59 screen: bar.screen
60 }
61 }
62
63 Row {
64 id: center
65
66 height: parent.height
67 width: childrenRect.width
68 anchors.centerIn: parent
69 spacing: 5
70
71 ActiveWindowDisplay {
72 screen: bar.screen
73 maxWidth: bar.width - 2*Math.max(left.width, right.width) - 2*8
74 }
75 }
76
77 Row {
78 id: right
79
80 height: parent.height
81 width: childrenRect.width
82 anchors.right: parent.right
83 anchors.rightMargin: 8
84 anchors.verticalCenter: parent.verticalCenter
85 spacing: 0
86
87 WorktimeWidget {}
88
89 KeyboardLayout {}
90
91 Item {
92 visible: privacy.visible || ytDlp.visible
93 height: parent.height
94 width: 8 - 4
95 }
96
97 PrivacyWidget {
98 id: privacy
99 }
100
101 Item {
102 visible: privacy.visible && ytDlp.visible
103 height: parent.height
104 width: 8 - 4
105 }
106
107 YtDlpWidget {
108 id: ytDlp
109 }
110
111 Item {
112 visible: privacy.visible || ytDlp.visible
113 height: parent.height
114 width: 8 - 4
115 }
116
117 SystemTray {}
118
119 PipewireWidget {}
120
121 BrightnessWidget {}
122
123 BatteryWidget {}
124
125 LockscreenInhibitorWidget {}
126
127 WaylandInhibitorWidget {
128 window: bar
129 }
130
131 LidSwitchInhibitorWidget {}
132
133 NotificationInhibitorWidget {}
134
135 Item {
136 height: parent.height
137 width: 8 - 4
138 }
139
140 Clock {}
141 }
142} \ No newline at end of file
diff --git a/accounts/gkleen@skadhi/shell/quickshell/BatteryWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/BatteryWidget.qml
new file mode 100644
index 00000000..f465fa20
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/BatteryWidget.qml
@@ -0,0 +1,139 @@
1import QtQuick
2import Quickshell
3import Quickshell.Widgets
4import Quickshell.Services.UPower
5
6Item {
7 id: root
8
9 height: parent.height
10 width: batteryIcon.width + 8
11 anchors.verticalCenter: parent.verticalCenter
12
13 property var batteryDevice: Array.from(UPower.devices.values).find(dev => dev.isLaptopBattery)
14
15 WrapperMouseArea {
16 id: widgetMouseArea
17
18 anchors.fill: parent
19
20 hoverEnabled: true
21
22 Item {
23 anchors.fill: parent
24
25 MaterialDesignIcon {
26 id: batteryIcon
27
28 implicitSize: 14
29 anchors.centerIn: parent
30
31 icon: {
32 if (!root.batteryDevice?.ready)
33 return "battery-unknown";
34
35 if (root.batteryDevice.state == UPowerDeviceState.FullyCharged)
36 return "power-plug-battery";
37
38 const perdec = 10 * Math.max(1, Math.ceil(root.batteryDevice.percentage * 10));
39 if (root.batteryDevice.state == UPowerDeviceState.Charging)
40 return `battery-charging-${perdec}`;
41 if (perdec == 100)
42 return "battery";
43 return `battery-${perdec}`;
44 }
45 color: {
46 if (!root.batteryDevice?.ready)
47 return "#555";
48
49 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 20 * 60)
50 return "#f2201f";
51 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 40 * 60)
52 return "#f28a21";
53 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged)
54 return "#fff";
55 return "#555";
56 }
57 }
58 }
59 }
60
61 PopupWindow {
62 id: tooltip
63
64 property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse
65
66 anchor {
67 item: widgetMouseArea
68 edges: Edges.Bottom | Edges.Left
69 }
70 visible: false
71
72 onNextVisibleChanged: hangTimer.restart()
73
74 Timer {
75 id: hangTimer
76 interval: 100
77 onTriggered: tooltip.visible = tooltip.nextVisible
78 }
79
80 implicitWidth: widgetTooltipText.contentWidth + 16
81 implicitHeight: widgetTooltipText.contentHeight + 16
82 color: "black"
83
84 WrapperMouseArea {
85 id: tooltipMouseArea
86
87 hoverEnabled: true
88 enabled: true
89
90 anchors.fill: parent
91
92 Item {
93 anchors.fill: parent
94
95 Text {
96 id: widgetTooltipText
97
98 anchors.centerIn: parent
99
100 font.pointSize: 10
101 font.family: "Fira Sans"
102 color: "white"
103
104 text: {
105 if (!root.batteryDevice?.ready)
106 return "Not ready";
107
108 const stateStr = UPowerDeviceState.toString(root.batteryDevice.state);
109 var outStr = stateStr;
110 if (root.batteryDevice.state !== UPowerDeviceState.FullyCharged)
111 outStr += ` ${Math.round(root.batteryDevice.percentage * 100)}%`;
112
113 function formatTime(t) {
114 var res = "";
115 for (const unit of [{ "s": "h", "v": 3600 }, { "s": "m", "v": 60 }, { "s": "s", "v": 1 }]) {
116 if (t < unit.v)
117 continue;
118 res += Math.floor(t / unit.v) + unit.s;
119 t %= unit.v;
120 }
121 return res;
122 }
123 if (root.batteryDevice.timeToEmpty != 0) {
124 const tStr = formatTime(Math.floor(root.batteryDevice.timeToEmpty / 60) * 60);
125 if (tStr)
126 outStr += " " + tStr;
127 } else if (root.batteryDevice.timeToFull != 0) {
128 const tStr = formatTime(Math.ceil(root.batteryDevice.timeToFull / 60) * 60);
129 if (tStr)
130 outStr += " " + tStr;
131 }
132
133 return outStr;
134 }
135 }
136 }
137 }
138 }
139}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/BrightnessOSD.qml b/accounts/gkleen@skadhi/shell/quickshell/BrightnessOSD.qml
new file mode 100644
index 00000000..a432179e
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/BrightnessOSD.qml
@@ -0,0 +1,117 @@
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Widgets
5import qs.Services
6
7Scope {
8 id: root
9
10 property bool show: false
11 property bool inhibited: true
12
13 Connections {
14 target: Brightness
15
16 function onCurrBrightnessChanged() {
17 root.show = true;
18 hideTimer.restart();
19 }
20 }
21
22 onShowChanged: {
23 if (show)
24 hideTimer.restart();
25 }
26
27 Timer {
28 id: hideTimer
29 interval: 1000
30 onTriggered: root.show = false
31 }
32
33 Timer {
34 id: startInhibit
35 interval: 100
36 running: true
37 onTriggered: {
38 root.show = false;
39 root.inhibited = false;
40 }
41 }
42
43 LazyLoader {
44 active: root.show && !root.inhibited
45
46 Variants {
47 model: Quickshell.screens
48
49 delegate: Scope {
50 id: screenScope
51
52 required property var modelData
53
54 PanelWindow {
55 id: window
56
57 screen: screenScope.modelData
58
59 anchors.top: true
60 margins.top: screen.height / 2 - 50 + 3.5
61 exclusiveZone: 0
62 exclusionMode: ExclusionMode.Ignore
63
64 implicitWidth: 400
65 implicitHeight: 50
66
67 mask: Region {}
68
69 color: "transparent"
70
71 Rectangle {
72 anchors.fill: parent
73 color: Qt.rgba(0, 0, 0, 0.75)
74 }
75
76 RowLayout {
77 id: layout
78
79 anchors.centerIn: parent
80
81 height: 50 - 8*2
82 width: 400 - 8*2
83
84 MaterialDesignIcon {
85 id: volumeIcon
86
87 implicitWidth: parent.height
88 implicitHeight: parent.height
89
90 icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}`
91 }
92
93 Rectangle {
94 Layout.fillWidth: true
95
96 implicitHeight: 10
97
98 color: "#50ffffff"
99
100 Rectangle {
101 anchors {
102 left: parent.left
103 top: parent.top
104 bottom: parent.bottom
105 }
106
107 color: "white"
108
109 implicitWidth: parent.width * Brightness.currBrightness
110 }
111 }
112 }
113 }
114 }
115 }
116 }
117}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/BrightnessWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/BrightnessWidget.qml
new file mode 100644
index 00000000..3bb5a80e
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/BrightnessWidget.qml
@@ -0,0 +1,84 @@
1import QtQuick
2import Quickshell
3import Quickshell.Widgets
4import qs.Services
5
6Item {
7 height: parent.height
8 width: brightnessIcon.width + 8
9 anchors.verticalCenter: parent.verticalCenter
10
11 WrapperMouseArea {
12 id: widgetMouseArea
13
14 anchors.fill: parent
15
16 hoverEnabled: true
17
18 property real sensitivity: (1 / 50) / 120
19 onWheel: event => Brightness.currBrightness += event.angleDelta.y * sensitivity
20
21 Item {
22 anchors.fill: parent
23
24 MaterialDesignIcon {
25 id: brightnessIcon
26
27 implicitSize: 14
28 anchors.centerIn: parent
29
30 icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}`
31 color: "#555"
32 }
33 }
34 }
35
36 PopupWindow {
37 id: tooltip
38
39 property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse
40
41 anchor {
42 item: widgetMouseArea
43 edges: Edges.Bottom | Edges.Left
44 }
45 visible: false
46
47 onNextVisibleChanged: hangTimer.restart()
48
49 Timer {
50 id: hangTimer
51 interval: 100
52 onTriggered: tooltip.visible = tooltip.nextVisible
53 }
54
55 implicitWidth: widgetTooltipText.contentWidth + 16
56 implicitHeight: widgetTooltipText.contentHeight + 16
57 color: "black"
58
59 WrapperMouseArea {
60 id: tooltipMouseArea
61
62 hoverEnabled: true
63 enabled: true
64
65 anchors.fill: parent
66
67 Item {
68 anchors.fill: parent
69
70 Text {
71 id: widgetTooltipText
72
73 anchors.centerIn: parent
74
75 font.pointSize: 10
76 font.family: "Fira Sans"
77 color: "white"
78
79 text: `${Math.round(Brightness.currBrightness * 100)}%`
80 }
81 }
82 }
83 }
84}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Clock.qml b/accounts/gkleen@skadhi/shell/quickshell/Clock.qml
new file mode 100644
index 00000000..58a80b8b
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Clock.qml
@@ -0,0 +1,295 @@
1import QtQml
2import QtQuick
3import Quickshell
4import Custom as Custom
5import QtQuick.Controls
6import QtQuick.Layouts
7import Quickshell.Widgets
8
9Item {
10 id: clockItem
11
12 property bool calendarPopup: true
13
14 width: clock.contentWidth
15 height: parent.height
16 anchors.verticalCenter: parent.verticalCenter
17
18 WrapperMouseArea {
19 id: clockMouseArea
20
21 anchors.fill: parent
22 hoverEnabled: true
23 enabled: clockItem.calendarPopup
24
25 Item {
26 anchors.fill: parent
27
28 Text {
29 id: clock
30 color: "white"
31
32 anchors.verticalCenter: parent.verticalCenter
33
34 Custom.Chrono {
35 id: chrono
36
37 onDateChanged: clock.text = format("W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}")
38 }
39
40 font.pointSize: 10
41 font.family: "Fira Sans"
42 font.features: { "tnum": 1 }
43 }
44 }
45 }
46
47 Loader {
48 id: tooltipLoader
49
50 active: false
51
52 Connections {
53 target: clockMouseArea
54 function onContainsMouseChanged() {
55 if (clockMouseArea.containsMouse)
56 tooltipLoader.active = true;
57 }
58 }
59
60 sourceComponent: PopupWindow {
61 id: tooltip
62
63 property bool nextVisible: clockMouseArea.containsMouse || tooltipMouseArea.containsMouse
64
65 anchor {
66 item: clockMouseArea
67 edges: Edges.Bottom | Edges.Left
68 }
69 visible: false
70
71 onNextVisibleChanged: hangTimer.restart()
72
73 Timer {
74 id: hangTimer
75 interval: 100
76 onTriggered: {
77 tooltip.visible = tooltip.nextVisible;
78 if (!tooltip.visible)
79 tooltipLoader.active = false;
80 }
81 }
82
83 implicitWidth: tooltipLayout.childrenRect.width + 16
84 implicitHeight: tooltipLayout.childrenRect.height + 16
85 color: "black"
86
87 onVisibleChanged: {
88 yearCalendar.year = chrono.date.getFullYear();
89 yearCalendar.angleRem = 0;
90 }
91
92 WrapperMouseArea {
93 id: tooltipMouseArea
94
95 hoverEnabled: true
96 enabled: true
97
98 onWheel: event => yearCalendar.scrollYear(event)
99
100 anchors.fill: parent
101
102 Item {
103 id: clockTooltipContent
104
105 anchors.fill: parent
106
107 ColumnLayout {
108 id: tooltipLayout
109
110 anchors {
111 left: parent.left
112 top: parent.top
113 leftMargin: 8
114 topMargin: 8
115 }
116
117 Text {
118 id: yearLabel
119
120 horizontalAlignment: Text.AlignHCenter
121
122 font.pointSize: 14
123 font.family: "Fira Sans"
124 font.features: { "tnum": 1 }
125 color: "white"
126
127 text: yearCalendar.year
128
129 Layout.fillWidth: true
130 Layout.bottomMargin: 8
131 }
132
133 GridLayout {
134 property int year: chrono.date.getFullYear()
135
136 id: yearCalendar
137
138 columns: 3
139 columnSpacing: 16
140 rowSpacing: 16
141
142 Layout.alignment: Qt.AlignHCenter
143 Layout.fillWidth: false
144
145 property real angleRem: 0
146 property real sensitivity: 1 / 120
147
148 function scrollYear(event) {
149 angleRem += event.angleDelta.y;
150 const d = Math.round(angleRem * sensitivity);
151 yearCalendar.year -= d;
152 angleRem -= d / sensitivity;
153 }
154
155 Connections {
156 target: clockMouseArea
157 function onWheel(event) { yearCalendar.scrollYear(event); }
158 }
159
160 Repeater {
161 model: 12
162
163 GridLayout {
164 columns: 2
165
166 required property int index
167 property int month: index
168
169 id: monthCalendar
170
171 Layout.alignment: Qt.AlignTop | Qt.AlignRight
172 Layout.fillWidth: false
173
174 Text {
175 Layout.column: 1
176 Layout.fillWidth: true
177
178 horizontalAlignment: Text.AlignHCenter
179
180 font.pointSize: 10
181 font.family: "Fira Sans"
182
183 text: new Date(yearCalendar.year, monthCalendar.month, 1).toLocaleString(Qt.locale("en_DK"), "MMMM")
184
185 color: "#ffead3"
186 }
187
188 DayOfWeekRow {
189 locale: grid.locale
190
191 Layout.row: 1
192 Layout.column: 1
193 Layout.fillWidth: true
194
195 delegate: WrapperItem {
196 required property string shortName
197
198 width: dowLabel.contentWidth + 6
199
200 Text {
201 id: dowLabel
202
203 anchors.fill: parent
204
205 font.pointSize: 10
206 font.family: "Fira Sans"
207
208 text: parent.shortName
209 color: "#ffcc66"
210
211 horizontalAlignment: Text.AlignHCenter
212 verticalAlignment: Text.AlignVCenter
213 }
214 }
215 }
216
217 WeekNumberColumn {
218 month: grid.month
219 year: grid.year
220 locale: grid.locale
221
222 Layout.fillHeight: true
223
224 delegate: Text {
225 required property int weekNumber
226
227 opacity: {
228 const simple = new Date(weekNumber == 1 && monthCalendar.month == 12 ? yearCalendar.year + 1 : yearCalendar.year, 0, 1 + (weekNumber - 1) * 7);
229 const dayOfWeek = simple.getDay();
230 const isoWeekStart = simple;
231
232 isoWeekStart.setDate(simple.getDate() - dayOfWeek + 1);
233 if (dayOfWeek > 4) {
234 isoWeekStart.setDate(isoWeekStart.getDate() + 7);
235 }
236
237 for (let i = 0; i < 7; i++) {
238 const dayInWeek = new Date(isoWeekStart);
239 dayInWeek.setDate(dayInWeek.getDate() + i);
240 if (dayInWeek.getMonth() == monthCalendar.month)
241 return 1;
242 }
243
244 return 0;
245 }
246
247 font.pointSize: 10
248 font.family: "Fira Sans"
249 font.features: { "tnum": 1 }
250
251 text: weekNumber
252 color: "#99ffdd"
253
254 horizontalAlignment: Text.AlignRight
255 verticalAlignment: Text.AlignVCenter
256 }
257 }
258
259 MonthGrid {
260 id: grid
261
262 year: yearCalendar.year
263 month: monthCalendar.month
264 locale: Qt.locale("en_DK")
265
266 Layout.fillWidth: true
267 Layout.fillHeight: true
268
269 delegate: Text {
270 required property var model
271
272 opacity: model.month === monthCalendar.month ? 1 : 0
273
274 font.pointSize: 10
275 font.family: "Fira Sans"
276 font.features: { "tnum": 1 }
277
278 property bool today: chrono.date.getFullYear() == model.year && chrono.date.getMonth() == model.month && chrono.date.getDate() == model.day
279
280 text: model.day
281 color: today ? "#ff6699" : "white"
282
283 horizontalAlignment: Text.AlignRight
284 verticalAlignment: Text.AlignVCenter
285 }
286 }
287 }
288 }
289 }
290 }
291 }
292 }
293 }
294 }
295}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/KeyboardLayout.qml b/accounts/gkleen@skadhi/shell/quickshell/KeyboardLayout.qml
new file mode 100644
index 00000000..46302e54
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/KeyboardLayout.qml
@@ -0,0 +1,112 @@
1import Quickshell
2import QtQuick
3import qs.Services
4import Quickshell.Widgets
5
6Item {
7 width: kbdLabel.contentWidth + 8
8 height: parent.height
9 anchors.verticalCenter: parent.verticalCenter
10
11 WrapperMouseArea {
12 id: kbdMouseArea
13
14 anchors.fill: parent
15
16 hoverEnabled: true
17 cursorShape: Qt.PointingHandCursor
18 enabled: true
19 onClicked: {
20 NiriService.sendCommand({ "Action": { "SwitchLayout": { "layout": "Next" } } }, _ => {})
21 }
22 onWheel: event => {
23 NiriService.sendCommand({ "Action": { "SwitchLayout": { "layout": event.angleDelta > 0 ? "Next" : "Prev" } } }, _ => {})
24 }
25
26 Rectangle {
27 id: kbdWidget
28
29 property var keyboardAbbrev: { "English (programmer Dvorak)": "dvp", "English (US)": "us" }
30
31 anchors.fill: parent
32 color: {
33 if (kbdMouseArea.containsMouse) {
34 return "#33808080";
35 }
36 return "transparent";
37 }
38
39 Text {
40 id: kbdLabel
41
42 font.pointSize: 10
43 font.family: "Fira Sans"
44 color: {
45 if (NiriService.keyboardLayouts?.current_idx === 0)
46 return "#555";
47 return "white";
48 }
49 anchors.centerIn: parent
50
51 text: {
52 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx];
53 if (!currentLayout)
54 return "";
55 return kbdWidget.keyboardAbbrev[currentLayout] ? kbdWidget.keyboardAbbrev[currentLayout] : currentLayout;
56 }
57 }
58 }
59 }
60
61 PopupWindow {
62 id: tooltip
63
64 property bool nextVisible: kbdMouseArea.containsMouse || tooltipMouseArea.containsMouse
65
66 anchor {
67 item: kbdMouseArea
68 edges: Edges.Bottom | Edges.Left
69 }
70 visible: false
71
72 onNextVisibleChanged: hangTimer.restart()
73
74 Timer {
75 id: hangTimer
76 interval: 100
77 onTriggered: tooltip.visible = tooltip.nextVisible
78 }
79
80 implicitWidth: kbdTooltipText.contentWidth + 16
81 implicitHeight: kbdTooltipText.contentHeight + 16
82 color: "black"
83
84 WrapperMouseArea {
85 id: tooltipMouseArea
86
87 hoverEnabled: true
88 enabled: true
89
90 anchors.fill: parent
91
92 Item {
93 anchors.fill: parent
94
95 Text {
96 id: kbdTooltipText
97
98 anchors.centerIn: parent
99
100 font.pointSize: 10
101 font.family: "Fira Sans"
102 color: "white"
103
104 text: {
105 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx];
106 return currentLayout || "";
107 }
108 }
109 }
110 }
111 }
112}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/LidSwitchInhibitorWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/LidSwitchInhibitorWidget.qml
new file mode 100644
index 00000000..8410dcda
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/LidSwitchInhibitorWidget.qml
@@ -0,0 +1,47 @@
1import Quickshell
2import QtQuick
3import Quickshell.Widgets
4import qs.Services
5
6Item {
7 id: root
8
9 width: icon.width + 8
10 height: parent.height
11 anchors.verticalCenter: parent.verticalCenter
12
13 WrapperMouseArea {
14 id: widgetMouseArea
15
16 anchors.fill: parent
17
18 hoverEnabled: true
19 cursorShape: Qt.PointingHandCursor
20
21 onClicked: InhibitorState.lidSwitchInhibited = !InhibitorState.lidSwitchInhibited
22
23 Rectangle {
24 anchors.fill: parent
25 color: {
26 if (widgetMouseArea.containsMouse) {
27 return "#33808080";
28 }
29 return "transparent";
30 }
31
32 Item {
33 anchors.fill: parent
34
35 MaterialDesignIcon {
36 id: icon
37
38 implicitSize: 14
39 anchors.centerIn: parent
40
41 icon: InhibitorState.lidSwitchInhibited ? "laptop-off" : "laptop"
42 color: InhibitorState.lidSwitchInhibited ? "#f28a21" : "#555"
43 }
44 }
45 }
46 }
47}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/LockSurface.qml b/accounts/gkleen@skadhi/shell/quickshell/LockSurface.qml
new file mode 100644
index 00000000..f4f8f0cd
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/LockSurface.qml
@@ -0,0 +1,227 @@
1import Quickshell.Widgets
2import QtQuick.Effects
3import QtQuick.Layouts
4import QtQuick
5import QtQuick.Controls
6import QtQuick.Controls.Fusion
7import qs.Services
8import QtQml
9
10Item {
11 id: lockSurface
12
13 property var screen
14 property list<var> messages: []
15 property bool responseRequired: false
16 property bool responseVisible: false
17 property string currentText: ""
18 property bool authRunning: false
19
20 signal response(string responseText)
21
22 anchors.fill: parent
23
24 Item {
25 id: background
26
27 anchors.fill: parent
28
29 property Img current: one
30 property string source: selector.selected
31
32 WallpaperSelector {
33 id: selector
34 seed: lockSurface.screen?.name || ""
35 }
36
37 onSourceChanged: {
38 if (!source)
39 current = null;
40 else if (current === one)
41 two.update()
42 else
43 one.update()
44 }
45
46 Img { id: one }
47 Img { id: two }
48
49 component Img: Item {
50 id: img
51
52 property string source
53
54 function update() {
55 source = background.source || ""
56 }
57
58 anchors.fill: parent
59
60 Image {
61 id: imageSource
62
63 source: img.source
64 sourceSize: Qt.size(parent.width, parent.height)
65 fillMode: Image.PreserveAspectCrop
66 smooth: true
67 visible: false
68 asynchronous: true
69 cache: false
70
71 onStatusChanged: {
72 if (status === Image.Ready) {
73 background.current = img
74 }
75 }
76 }
77
78 MultiEffect {
79 id: imageEffect
80
81 source: imageSource
82 anchors.fill: parent
83 blurEnabled: true
84 blur: 1
85 blurMax: 64
86 blurMultiplier: 2
87
88 opacity: 0
89
90 states: State {
91 name: "visible"
92 when: background.current === img
93
94 PropertyChanges {
95 imageEffect.opacity: 1
96 }
97 StateChangeScript {
98 name: "unloadOther"
99 script: {
100 if (img === one)
101 two.source = ""
102 if (img === two)
103 one.source = ""
104 }
105 }
106 }
107
108 transitions: Transition {
109 SequentialAnimation {
110 NumberAnimation {
111 target: imageEffect
112 properties: "opacity"
113 duration: {
114 if (img === one && two.source == "" || img === two && one.source == "")
115 return 0;
116 return 5000;
117 }
118 easing.type: Easing.OutCubic
119 }
120 ScriptAction {
121 scriptName: "unloadOther"
122 }
123 }
124 }
125 }
126 }
127 }
128
129 Item {
130 anchors {
131 top: lockSurface.top
132 left: lockSurface.left
133 right: lockSurface.right
134 }
135
136 implicitWidth: lockSurface.width
137 implicitHeight: 21
138
139 Rectangle {
140 anchors.fill: parent
141 color: Qt.rgba(0, 0, 0, 0.75)
142 }
143
144 Clock {
145 anchors.centerIn: parent
146 calendarPopup: false
147 }
148 }
149
150 WrapperRectangle {
151 id: unlockUi
152
153 Keys.onPressed: event => {
154 if (!lockSurface.authRunning) {
155 event.accepted = true;
156 lockSurface.authRunning = true;
157 }
158 }
159 focus: !passwordBox.visible
160
161 visible: lockSurface.authRunning
162
163 color: Qt.rgba(0, 0, 0, 0.75)
164 margin: 8
165
166 anchors.centerIn: parent
167
168 ColumnLayout {
169 spacing: 4
170
171 BusyIndicator {
172 visible: running
173 running: !Array.from(lockSurface.messages).length && !lockSurface.responseRequired
174 }
175
176 Repeater {
177 model: lockSurface.messages
178
179 Text {
180 required property var modelData
181
182 font.pointSize: 10
183 font.family: "Fira Sans"
184 color: modelData.error ? "#f28a21" : "#ffffff"
185
186 text: String(modelData.text).trim()
187
188 Layout.fillWidth: true
189 horizontalAlignment: Text.AlignHCenter
190 }
191 }
192
193 TextField {
194 id: passwordBox
195
196 visible: lockSurface.responseRequired
197 echoMode: lockSurface.responseVisible ? TextInput.Normal : TextInput.Password
198 inputMethodHints: Qt.ImhSensitiveData
199
200 onTextChanged: lockSurface.currentText = passwordBox.text
201 onAccepted: {
202 passwordBox.readOnly = true;
203 lockSurface.response(lockSurface.currentText);
204 }
205
206 Connections {
207 target: lockSurface
208 function onCurrentTextChanged() {
209 passwordBox.text = lockSurface.currentText
210 }
211 }
212 Connections {
213 target: lockSurface
214 function onResponseRequiredChanged() {
215 if (lockSurface.responseRequired)
216 passwordBox.readOnly = false;
217 passwordBox.focus = true;
218 passwordBox.selectAll();
219 }
220 }
221
222 Layout.topMargin: 4
223 Layout.fillWidth: true
224 }
225 }
226 }
227}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Lockscreen.qml b/accounts/gkleen@skadhi/shell/quickshell/Lockscreen.qml
new file mode 100644
index 00000000..0b4a68b2
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Lockscreen.qml
@@ -0,0 +1,128 @@
1import Quickshell
2import Quickshell.Wayland
3import Quickshell.Io
4import Quickshell.Services.Pam
5import Quickshell.Services.Mpris
6import Custom as Custom
7import qs.Services
8import QtQml
9
10Scope {
11 id: lockscreen
12
13 property string currentText: ""
14
15 PamContext {
16 id: pam
17
18 property list<var> messages: []
19
20 config: "quickshell"
21 onCompleted: result => {
22 if (result === PamResult.Success) {
23 lock.locked = false;
24 }
25 }
26 onPamMessage: {
27 messages = Array.from(messages).concat([{ "text": pam.message, "error": pam.messageIsError }])
28 }
29 onActiveChanged: {
30 messages = [];
31 }
32 }
33
34 Connections {
35 target: Custom.Systemd
36 function onSleep(before: bool) {
37 console.log(`received prepare for sleep ${before}`);
38 if (before) {
39 lock.locked = true;
40 if (pam.active)
41 pam.abort();
42 }
43 }
44 function onLock() { lock.locked = true; }
45 function onUnlock() { lock.locked = false; }
46 }
47
48 IdleMonitor {
49 id: idleMonitor
50 enabled: !lock.secure && !InhibitorState.lockscreenInhibited
51 timeout: 600
52 respectInhibitors: true
53
54 onIsIdleChanged: {
55 if (idleMonitor.isIdle)
56 lock.locked = true;
57 }
58 }
59
60 Custom.SystemdInhibitor {
61 enabled: !lock.secure
62
63 what: Custom.SystemdInhibitorParams.Sleep
64 who: "quickshell"
65 why: "Lock session"
66 mode: Custom.SystemdInhibitorParams.Delay
67 }
68
69 Binding {
70 target: NotificationManager
71 property: "lockscreenActive"
72 value: lock.locked
73 }
74
75 WlSessionLock {
76 id: lock
77
78 onLockStateChanged: {
79 if (!locked && pam.active)
80 pam.abort();
81
82 if (locked) {
83 NiriService.sendCommand({ "Action": { "PowerOffMonitors": {} } }, _ => {});
84 Custom.KeePassXC.lockAllDatabases();
85 Array.from(MprisProxy.players).forEach(player => {
86 if (player.canPause && player.isPlaying)
87 player.pause();
88 });
89 // Custom.Systemd.stopUserUnit("gpg-agent.service", "replace");
90 GpgAgent.reloadAgent();
91 }
92 }
93 Component.onCompleted: { (_ => {})(MprisProxy.players); }
94
95 onSecureStateChanged: Custom.Systemd.lockedHint = lock.secure
96
97 WlSessionLockSurface {
98 id: lockSurface
99
100 color: "black"
101
102 LockSurface {
103 id: surfaceContent
104
105 onResponse: responseText => pam.respond(responseText)
106 onAuthRunningChanged: {
107 if (authRunning)
108 pam.start();
109 }
110 Connections {
111 target: pam
112 function onMessagesChanged() { surfaceContent.messages = pam.messages; }
113 function onResponseRequiredChanged() { surfaceContent.responseRequired = pam.responseRequired; }
114 function onActiveChanged() { surfaceContent.authRunning = pam.active; }
115 }
116 onCurrentTextChanged: lockscreen.currentText = currentText
117 Connections {
118 target: lockscreen
119 function onCurrentTextChanged() { surfaceContent.currentText = lockscreen.currentText; }
120 }
121 Connections {
122 target: lockSurface
123 function onScreenChanged() { surfaceContent.screen = lockSurface.screen; }
124 }
125 }
126 }
127 }
128}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/LockscreenInhibitorWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/LockscreenInhibitorWidget.qml
new file mode 100644
index 00000000..1cbf3f16
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/LockscreenInhibitorWidget.qml
@@ -0,0 +1,48 @@
1import Quickshell
2import QtQuick
3import Quickshell.Widgets
4import qs.Services
5
6Item {
7 id: root
8
9 width: icon.width + 8
10 height: parent.height
11 anchors.verticalCenter: parent.verticalCenter
12
13 WrapperMouseArea {
14 id: widgetMouseArea
15
16 anchors.fill: parent
17
18 // enabled: InhibitorState.lockscreenInhibited || !InhibitorState.waylandIdleInhibited
19 hoverEnabled: true
20 cursorShape: widgetMouseArea.enabled ? Qt.PointingHandCursor : undefined
21
22 onClicked: InhibitorState.lockscreenInhibited = !InhibitorState.lockscreenInhibited
23
24 Rectangle {
25 anchors.fill: parent
26 color: {
27 if (widgetMouseArea.containsMouse) {
28 return "#33808080";
29 }
30 return "transparent";
31 }
32
33 Item {
34 anchors.fill: parent
35
36 MaterialDesignIcon {
37 id: icon
38
39 implicitSize: 14
40 anchors.centerIn: parent
41
42 icon: InhibitorState.lockscreenInhibited || InhibitorState.waylandIdleInhibited ? "lock-off" : "lock"
43 color: InhibitorState.lockscreenInhibited ? "#f28a21" : "#555"
44 }
45 }
46 }
47 }
48}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/MaterialDesignIcon.qml b/accounts/gkleen@skadhi/shell/quickshell/MaterialDesignIcon.qml
new file mode 100644
index 00000000..155a009e
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/MaterialDesignIcon.qml
@@ -0,0 +1,35 @@
1import QtQuick
2import QtQuick.Effects
3
4Item {
5 id: root
6
7 required property string icon
8 property color color: "white"
9
10 property real implicitSize: 0
11
12 readonly property real actualSize: Math.min(root.width, root.height)
13
14 implicitWidth: root.implicitSize
15 implicitHeight: root.implicitSize
16
17 Image {
18 id: sourceImage
19 source: "file://" + @mdi@ + "/svg/" + root.icon + ".svg"
20 anchors.fill: parent
21 fillMode: Image.PreserveAspectFit
22
23 sourceSize.width: root.actualSize
24 sourceSize.height: root.actualSize
25
26 layer.enabled: true
27 layer.effect: MultiEffect {
28 id: effect
29
30 brightness: 1
31 colorization: 1
32 colorizationColor: root.color
33 }
34 }
35}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/NiriIdle.qml b/accounts/gkleen@skadhi/shell/quickshell/NiriIdle.qml
new file mode 100644
index 00000000..beff205c
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/NiriIdle.qml
@@ -0,0 +1,30 @@
1import QtQml
2import Quickshell
3import Quickshell.Wayland
4import qs.Services
5import Custom as Custom
6
7Scope {
8 IdleMonitor {
9 id: idleMonitor30
10 timeout: 30
11
12 onIsIdleChanged: Custom.Systemd.setIdleHint(idleMonitor30.isIdle)
13 }
14 IdleMonitor {
15 id: idleMonitor540
16 timeout: 540
17
18 onIsIdleChanged: {
19 if (idleMonitor540.isIdle)
20 NiriService.sendCommand({ "Action": { "PowerOffMonitors": {} } }, _ => {});
21 }
22 }
23 Connections {
24 target: Custom.Systemd
25 function onSleep(before: bool) {
26 if (!before)
27 NiriService.sendCommand({ "Action": { "PowerOnMonitors": {} } }, _ => {});
28 }
29 }
30}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/NotificationDisplay.qml b/accounts/gkleen@skadhi/shell/quickshell/NotificationDisplay.qml
new file mode 100644
index 00000000..cc0e49b1
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/NotificationDisplay.qml
@@ -0,0 +1,340 @@
1import QtQml
2import QtQml.Models
3import QtQuick
4import Quickshell
5import Quickshell.Widgets
6import Quickshell.Wayland
7import qs.Services
8import QtQuick.Layouts
9import Quickshell.Services.Notifications
10
11Scope {
12 id: root
13
14 property var activeScreen: Array.from(Quickshell.screens).find(screen => screen.name === Array.from(NiriService.workspaces).find(ws => ws.is_focused)?.output) ?? null
15
16 Instantiator {
17 id: notifsRepeater
18
19 model: ScriptModel {
20 values: NotificationManager.groups
21 }
22
23 delegate: PanelWindow {
24 id: notifWindow
25
26 visible: NotificationManager.active
27
28 screen: root.activeScreen
29
30 WlrLayershell.namespace: "notifications"
31
32 required property var modelData
33 required property var index
34
35 property int activeIx: modelData.length - 1
36 onModelDataChanged: {
37 notifWindow.activeIx = modelData.length - 1;
38 }
39
40 property color textColor: {
41 if (notifWindow.modelData?.[notifWindow.activeIx]?.urgency == NotificationUrgency.Low)
42 return "#ff999999";
43 return "white";
44 }
45 property color backgroundColor: {
46 if (notifWindow.modelData?.[notifWindow.activeIx]?.urgency == NotificationUrgency.Critical)
47 return "#dd900000";
48 return "black";
49 }
50
51 anchors {
52 right: true
53 top: true
54 }
55
56 readonly property real spaceAbove: {
57 var res = 0;
58 for (let i = 0; i < notifWindow.index; i++) {
59 (_ => {})(notifsRepeater.objectAt(i).modelData);
60 res += notifsRepeater.objectAt(i).height + 8;
61 }
62 return res;
63 }
64
65 margins {
66 right: 26 + 8
67 top: 8 + spaceAbove
68 }
69
70 color: "transparent"
71
72 implicitHeight: Math.max(notifCount.visible ? notifCount.contentHeight : 0, notifSummary.contentHeight) + (notifBody.visible ? 8 + notifBody.contentHeight : 0) + (notifActions.visible ? 8 + notifActions.height : 0) + (notifTime.visible ? 8 + notifTime.contentHeight : 0) + 16
73 implicitWidth: 400
74
75 WrapperMouseArea {
76 enabled: true
77
78 anchors.fill: parent
79
80 cursorShape: Qt.PointingHandCursor
81
82 onClicked: {
83 for (const notif of notifWindow.modelData)
84 notif.dismiss();
85 }
86
87 property real angleRem: 0
88 property real sensitivity: 1 / 120
89 onWheel: event => {
90 angleRem += event.angleDelta.y;
91 const d = Math.round(angleRem * sensitivity);
92 angleRem -= d / sensitivity;
93 notifWindow.activeIx = ((notifWindow.modelData?.length ?? 1) + notifWindow.activeIx - d) % (notifWindow.modelData?.length ?? 1);
94 }
95
96 Rectangle {
97 color: notifWindow.backgroundColor
98 anchors.fill: parent
99 border {
100 color: Qt.hsla(195/360, 1, 0.45, 1)
101 width: 2
102 }
103
104 GridLayout {
105 id: notifLayout
106
107 width: 400 - 16
108 anchors.fill: parent
109 anchors.margins: 8
110 columnSpacing: 8
111 rowSpacing: 8
112
113 columns: notifImage.visible ? 3 : 2
114 rows: {
115 var res = 1;
116 if (notifBody.visible)
117 res += 1;
118 if (notifActions.visible)
119 res += 1;
120 if (notifTime.visible)
121 res += 1;
122 return res;
123 }
124
125 Text {
126 id: notifCount
127
128 visible: notifWindow.modelData?.length > 1 ?? false
129 text: `${notifWindow.activeIx + 1}/${notifWindow.modelData?.length ?? ""}`
130
131 font.pointSize: 10
132 font.family: "Fira Sans"
133 font.bold: true
134 font.features: { "tnum": 1 }
135 color: notifWindow.textColor
136 maximumLineCount: 1
137
138 Layout.fillWidth: false
139 Layout.row: 0
140 Layout.column: notifImage.visible ? 1 : 0
141 }
142
143 Text {
144 id: notifSummary
145
146 text: notifWindow.modelData?.[notifWindow.activeIx]?.summary ?? ""
147
148 font.pointSize: 10
149 font.family: "Fira Sans"
150 font.italic: true
151 color: notifWindow.textColor
152 maximumLineCount: 1
153 elide: Text.ElideRight
154
155 Layout.fillWidth: true
156 Layout.row: 0
157 Layout.column: (notifCount.visible ? 1 : 0) + (notifImage.visible ? 1 : 0)
158 Layout.columnSpan: notifCount.visible ? 1 : 2
159 }
160
161 Image {
162 id: notifImage
163
164 visible: (notifWindow.modelData?.[notifWindow.activeIx]?.image || notifWindow.modelData?.[notifWindow.activeIx]?.appIcon) ?? false
165
166 onStatusChanged: {
167 if (notifImage.status == Image.Error)
168 notifImage.visible = false;
169 }
170
171 source: (notifWindow.modelData?.[notifWindow.activeIx]?.image || notifWindow.modelData?.[notifWindow.activeIx]?.appIcon) ?? ""
172 fillMode: Image.PreserveAspectFit
173 asynchronous: true
174 smooth: true
175 mipmap: true
176
177 Layout.maximumWidth: 50
178 Layout.column: 0
179 Layout.row: 0
180 Layout.fillHeight: true
181 Layout.rowSpan: 1 + (notifBody.visible ? 1 : 0) + (notifTime.visible ? 1 : 0)
182 }
183
184 Text {
185 id: notifBody
186
187 visible: notifWindow.modelData?.[notifWindow.activeIx]?.body ?? false
188 text: notifWindow.modelData?.[notifWindow.activeIx]?.body ?? ""
189 textFormat: Text.RichText
190 wrapMode: Text.Wrap
191
192 font.pointSize: 10
193 font.family: "Fira Sans"
194 color: notifWindow.textColor
195
196 Layout.fillWidth: true
197 Layout.row: 1
198 Layout.column: notifImage.visible ? 1 : 0
199 Layout.columnSpan: notifCount.visible ? 2 : 1
200 }
201
202 Text {
203 id: notifTime
204
205 Connections {
206 target: NotificationManager.clock
207 function onDateChanged() {
208 notifTime.text = NotificationManager.formatTime(notifWindow.modelData?.[notifWindow.activeIx]?.receivedTime);
209 }
210 }
211
212 visible: notifTime.text && notifTime.text !== "now"
213 text: NotificationManager.formatTime(notifWindow.modelData?.[notifWindow.activeIx]?.receivedTime)
214
215 font.pointSize: 8
216 font.family: "Fira Sans"
217 font.italic: true
218 color: "#555"
219 maximumLineCount: 1
220 horizontalAlignment: Text.AlignRight
221
222 Layout.fillWidth: true
223 Layout.row: notifBody.visible ? 2 : 1
224 Layout.column: notifImage.visible ? 1 : 0
225 Layout.columnSpan: 2
226 }
227
228 RowLayout {
229 id: notifActions
230
231 visible: notifWindow.modelData?.[notifWindow.activeIx]?.actions.length > 0 ?? false
232
233 spacing: 8
234 uniformCellSizes: true
235
236 width: 400 - 16
237 Layout.row: 1 + (notifBody.visible ? 1 : 0) + (notifTime.visible ? 1 : 0)
238 Layout.column: 0
239 Layout.columnSpan: 2 + (notifImage.visible ? 1 : 0)
240
241 Repeater {
242 model: ScriptModel {
243 values: notifWindow.modelData?.[notifWindow.activeIx]?.actions
244 }
245
246 delegate: WrapperMouseArea {
247 id: actionMouseArea
248
249 required property var modelData
250
251 height: actionLabelWrapper.implicitHeight
252 Layout.fillWidth: true
253 Layout.horizontalStretchFactor: 1
254
255 hoverEnabled: true
256 cursorShape: Qt.PointingHandCursor
257
258 onClicked: actionMouseArea.modelData?.invoke()
259
260 Rectangle {
261 anchors.fill: parent
262
263 color: actionMouseArea.containsMouse ? "#20ffffff" : "transparent"
264
265 border {
266 width: 2
267 color: "#20ffffff"
268 }
269
270 WrapperItem {
271 id: actionLabelWrapper
272
273 margin: 8
274 anchors.centerIn: parent
275
276 RowLayout {
277 id: actionLabelLayout
278
279 spacing: 8
280
281 IconImage {
282 id: actionIcon
283
284 visible: notifWindow.modelData?.[notifWindow.activeIx]?.hasActionIcons
285
286 onStatusChanged: {
287 if (actionIcon.status == Image.Error)
288 actionIcon.visible = false;
289 }
290
291 implicitSize: 16
292 source: {
293 if (!actionIcon.visible)
294 return "";
295
296 let icon = actionMouseArea.modelData?.identifier ?? ""
297 if (icon.includes("?path=")) {
298 const split = icon.split("?path=")
299 if (split.length !== 2)
300 return icon
301 const name = split[0]
302 const path = split[1]
303 const fileName = name.substring(
304 name.lastIndexOf("/") + 1)
305 return `file://${path}/${fileName}`
306 }
307 return icon
308 }
309 asynchronous: true
310 smooth: true
311 mipmap: true
312
313 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
314 }
315
316 Text {
317 id: actionLabel
318
319 visible: actionMouseArea.modelData?.text ?? false
320
321 text: actionMouseArea.modelData?.text ?? ""
322
323 font.pointSize: 10
324 font.family: "Fira Sans"
325 color: notifWindow.textColor
326 maximumLineCount: 1
327 elide: Text.ElideRight
328 }
329 }
330 }
331 }
332 }
333 }
334 }
335 }
336 }
337 }
338 }
339 }
340}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/NotificationInhibitorWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/NotificationInhibitorWidget.qml
new file mode 100644
index 00000000..80cbba19
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/NotificationInhibitorWidget.qml
@@ -0,0 +1,266 @@
1import Quickshell
2import QtQuick
3import Quickshell.Widgets
4import qs.Services
5import QtQuick.Controls
6import QtQuick.Layouts
7import QtQuick.Shapes
8
9Item {
10 id: root
11
12 width: icon.width + 8
13 height: parent.height
14 anchors.verticalCenter: parent.verticalCenter
15
16 WrapperMouseArea {
17 id: widgetMouseArea
18
19 anchors.fill: parent
20
21 hoverEnabled: true
22 cursorShape: Qt.PointingHandCursor
23
24 onClicked: NotificationManager.displayInhibited = !NotificationManager.displayInhibited
25
26 Rectangle {
27 anchors.fill: parent
28 color: {
29 if (widgetMouseArea.containsMouse) {
30 return "#33808080";
31 }
32 return "transparent";
33 }
34
35 Item {
36 anchors.fill: parent
37
38 MaterialDesignIcon {
39 id: icon
40
41 implicitSize: 14
42 anchors.centerIn: parent
43
44 icon: NotificationManager.active ? "message" : "message-off"
45 color: {
46 if (!NotificationManager.active && !NotificationManager.displayInhibited)
47 return "#f28a21";
48 if (NotificationManager.displayInhibited)
49 return "white";
50 return "#555";
51 }
52 }
53 }
54 }
55 }
56
57 Loader {
58 id: tooltipLoader
59
60 active: false
61
62 Connections {
63 target: widgetMouseArea
64 function onContainsMouseChanged() {
65 if (widgetMouseArea.containsMouse)
66 tooltipLoader.active = true;
67 }
68 }
69
70 sourceComponent: PopupWindow {
71 id: tooltip
72
73 property bool nextVisible: NotificationManager.active && NotificationManager.history.length > 0 && (widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse)
74
75 anchor {
76 item: widgetMouseArea
77 edges: Edges.Bottom | Edges.Left
78 }
79 visible: false
80
81 onNextVisibleChanged: hangTimer.restart()
82
83 Timer {
84 id: hangTimer
85 interval: tooltip.visible ? 100 : 500
86 onTriggered: {
87 tooltip.visible = tooltip.nextVisible;
88 if (!tooltip.visible)
89 tooltipLoader.active = false;
90 }
91 }
92
93 implicitWidth: 400
94 implicitHeight: Math.min(tooltip.screen.height * 0.66, Math.max(100, scroll.contentHeight + 16))
95 color: "black"
96
97 WrapperMouseArea {
98 id: tooltipMouseArea
99
100 hoverEnabled: true
101 enabled: true
102
103 anchors.fill: parent
104
105 WrapperItem {
106 margin: 8
107
108 ScrollView {
109 id: scroll
110
111 contentWidth: availableWidth
112 // ScrollBar.vertical.policy: ScrollBar.AlwaysOn
113
114 ColumnLayout {
115 id: historyLayout
116 anchors {
117 left: parent.left
118 right: parent.right
119 }
120
121 spacing: 8
122
123 Repeater {
124 model: ScriptModel {
125 values: [...NotificationManager.history].reverse().map(o => o.notification)
126 }
127
128 delegate: GridLayout {
129 id: notif
130
131 Layout.fillWidth: true
132 Layout.preferredHeight: notifSummary.contentHeight + (notifBody.visible ? notifBody.contentHeight + 8 : 0) + (notifSep.visible ? notifSep.height + 8 : 0) + notifTime.contentHeight + 8
133
134 required property var modelData
135 required property int index
136
137 columnSpacing: 8
138 rowSpacing: 8
139
140 columns: notifImage.visible ? 2 : 1
141 rows: {
142 var res = 2;
143 if (notifBody.visible)
144 res += 1;
145 if (notifSep.visible)
146 res += 1;
147 return res;
148 }
149
150 Shape {
151 id: notifSep
152
153 visible: notif.index != 0
154
155 height: 2
156 width: 400 - 32
157
158 ShapePath {
159 strokeWidth: 2
160 strokeColor: "#20ffffff"
161 startX: 0; startY: 0;
162 PathLine { x: 400 - 32; y: 0; }
163 }
164
165 Layout.row: 0
166 Layout.column: 0
167 Layout.columnSpan: notifImage.visible ? 2 : 1
168 Layout.alignment: Qt.AlignHCenter
169 }
170
171 Text {
172 id: notifSummary
173
174 text: notif.modelData?.summary ?? ""
175
176 font.pointSize: 10
177 font.family: "Fira Sans"
178 font.italic: true
179 color: "white"
180 maximumLineCount: 1
181 elide: Text.ElideRight
182
183 Layout.fillWidth: true
184 Layout.row: notifSep.visible ? 1 : 0
185 Layout.column: notifImage.visible ? 1 : 0
186 }
187
188 Image {
189 id: notifImage
190
191 visible: (notif.modelData?.image || notif.modelData?.appIcon) ?? false
192
193 onStatusChanged: {
194 if (notifImage.status == Image.Error)
195 notifImage.visible = false;
196 }
197
198 source: (notif.modelData?.image || notif.modelData?.appIcon) ?? ""
199 fillMode: Image.PreserveAspectFit
200 asynchronous: true
201 smooth: true
202 mipmap: true
203
204 Layout.maximumWidth: 50
205 Layout.column: 0
206 Layout.row: notifSep.visible ? 1 : 0
207 Layout.fillHeight: true
208 Layout.rowSpan: notifBody.visible ? 3 : 2
209 }
210
211 Text {
212 id: notifBody
213
214 visible: notif.modelData?.body ?? false
215 text: notif.modelData?.body ?? ""
216 textFormat: Text.RichText
217 wrapMode: Text.Wrap
218
219 font.pointSize: 10
220 font.family: "Fira Sans"
221 color: "white"
222
223 Layout.fillWidth: true
224 Layout.row: notifSep.visible ? 2 : 1
225 Layout.column: notifImage.visible ? 1 : 0
226 }
227
228 Text {
229 id: notifTime
230
231 Connections {
232 target: NotificationManager.clock
233 function onDateChanged() {
234 notifTime.text = NotificationManager.formatTime(notif.modelData?.receivedTime);
235 }
236 }
237
238 text: NotificationManager.formatTime(notif.modelData?.receivedTime)
239
240 font.pointSize: 8
241 font.family: "Fira Sans"
242 font.italic: true
243 color: "#555"
244 maximumLineCount: 1
245 horizontalAlignment: Text.AlignRight
246
247 Layout.fillWidth: true
248 Layout.row: {
249 var res = 1;
250 if (notifSep.visible)
251 res += 1;
252 if (notifBody.visible)
253 res += 1;
254 return res;
255 }
256 Layout.column: notifImage.visible ? 1 : 0
257 }
258 }
259 }
260 }
261 }
262 }
263 }
264 }
265 }
266}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/PipewireWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/PipewireWidget.qml
new file mode 100644
index 00000000..9c6b65a4
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/PipewireWidget.qml
@@ -0,0 +1,483 @@
1import QtQuick
2import QtQuick.Layouts
3import QtQuick.Controls.Fusion
4import Quickshell
5import Quickshell.Services.Pipewire
6import Quickshell.Widgets
7
8Item {
9 height: parent.height
10 width: volumeIcon.width + 8
11 anchors.verticalCenter: parent.verticalCenter
12
13 PwObjectTracker {
14 objects: [Pipewire.defaultAudioSink]
15 }
16
17 WrapperMouseArea {
18 id: widgetMouseArea
19
20 anchors.fill: parent
21 hoverEnabled: true
22 cursorShape: Qt.PointingHandCursor
23
24 onClicked: {
25 if (!Pipewire.defaultAudioSink)
26 return;
27 Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted;
28 }
29
30 property real sensitivity: (1 / 40) / 120
31 onWheel: event => {
32 if (!Pipewire.defaultAudioSink)
33 return;
34 Pipewire.defaultAudioSink.audio.volume += event.angleDelta.y * sensitivity;
35 }
36
37 Rectangle {
38 id: volumeWidget
39
40 anchors.fill: parent
41 color: {
42 if (widgetMouseArea.containsMouse)
43 return "#33808080";
44 return "transparent";
45 }
46
47 Item {
48 anchors.fill: parent
49
50 MaterialDesignIcon {
51 id: volumeIcon
52
53 implicitSize: 14
54 anchors.centerIn: parent
55
56 icon: {
57 if (!Pipewire.defaultAudioSink || Pipewire.defaultAudioSink.audio.muted)
58 return "volume-off";
59 if (Pipewire.defaultAudioSink.audio.volume <= 0.33)
60 return "volume-low";
61 if (Pipewire.defaultAudioSink.audio.volume <= 0.67)
62 return "volume-medium";
63 return "volume-high";
64 }
65 color: "#555"
66 }
67 }
68 }
69 }
70
71 Loader {
72 id: tooltipLoader
73
74 active: false
75
76 Connections {
77 target: widgetMouseArea
78 function onContainsMouseChanged() {
79 if (widgetMouseArea.containsMouse)
80 tooltipLoader.active = true;
81 }
82 }
83
84 PwObjectTracker {
85 objects: Pipewire.devices
86 }
87 PwObjectTracker {
88 objects: Pipewire.nodes
89 }
90
91 sourceComponent: PopupWindow {
92 id: tooltip
93
94 property bool openPopup: false
95 property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse || openPopup
96
97 anchor {
98 item: widgetMouseArea
99 edges: Edges.Bottom | Edges.Left
100 }
101 visible: false
102
103 onNextVisibleChanged: hangTimer.restart()
104
105 Timer {
106 id: hangTimer
107 interval: 100
108 onTriggered: {
109 tooltip.visible = tooltip.nextVisible;
110 if (!tooltip.visible)
111 tooltipLoader.active = false;
112 }
113 }
114
115 implicitWidth: tooltipContent.width
116 implicitHeight: tooltipContent.height
117 color: "transparent"
118
119 Rectangle {
120 width: tooltip.width
121 height: tooltipLayout.childrenRect.height + 16
122 color: "black"
123 }
124
125 WrapperItem {
126 id: tooltipContent
127
128 bottomMargin: Math.max(0, 200 - tooltipLayout.implicitHeight)
129
130 WrapperMouseArea {
131 id: tooltipMouseArea
132
133 hoverEnabled: true
134 enabled: true
135
136 WrapperItem {
137 margin: 8
138 bottomMargin: 8
139
140 GridLayout {
141 id: tooltipLayout
142
143 columns: 4
144
145 Repeater {
146 model: Array.from(Pipewire.devices.values).filter(dev => dev.type == "Audio/Device")
147
148 Item {
149 id: descItem
150
151 required property var modelData
152 required property int index
153
154 Layout.column: 0
155 Layout.row: index
156
157 implicitWidth: descText.contentWidth
158 implicitHeight: descText.contentHeight
159
160 Text {
161 id: descText
162
163 color: "white"
164 font.pointSize: 10
165 font.family: "Fira Sans"
166
167 text: descItem.modelData.description
168 }
169 }
170 }
171
172 Repeater {
173 id: defaultSinkRepeater
174
175 model: {
176 Array.from(Pipewire.devices.values)
177 .filter(dev => dev.type == "Audio/Device")
178 .map(device => Array.from(Pipewire.nodes.values).find(node => node.type == PwNodeType.AudioSink && node.device?.id == device.id ));
179 }
180
181 Item {
182 id: defaultSinkItem
183
184 required property var modelData
185 required property int index
186
187 visible: Boolean(modelData)
188
189 PwObjectTracker {
190 objects: [defaultSinkItem.modelData]
191 }
192
193 Layout.column: 1
194 Layout.row: index
195
196 Layout.fillHeight: true
197
198 implicitWidth: 16 + 8
199
200 WrapperMouseArea {
201 id: defaultSinkMouseArea
202
203 anchors.fill: parent
204 hoverEnabled: true
205 cursorShape: Qt.PointingHandCursor
206
207 onClicked: {
208 Pipewire.preferredDefaultAudioSink = defaultSinkItem.modelData
209 }
210
211 onWheel: event => scrollVolume(event);
212 property real sensitivity: (1 / 40) / 120
213 function scrollVolume(event) {
214 defaultSinkItem.modelData.audio.volume += event.angleDelta.y * sensitivity;
215 }
216
217 Rectangle {
218 id: defaultSinkWidget
219
220 anchors.fill: parent
221 color: {
222 if (defaultSinkMouseArea.containsMouse)
223 return "#33808080";
224 return "transparent";
225 }
226
227 MaterialDesignIcon {
228 width: 16
229 height: 16
230 anchors.centerIn: parent
231
232 icon: {
233 if (defaultSinkItem.modelData?.id == Pipewire.defaultAudioSink?.id)
234 return "speaker";
235 return "speaker-off";
236 }
237 color: icon == "speaker" ? "white" : "#555"
238 }
239 }
240 }
241
242 PopupWindow {
243 id: volumeTooltip
244
245 property bool nextVisible: defaultSinkMouseArea.containsMouse || volumeTooltipMouseArea.containsMouse
246
247 anchor {
248 item: defaultSinkMouseArea
249 edges: Edges.Bottom | Edges.Left
250 }
251 visible: false
252
253 onNextVisibleChanged: volumeHangTimer.restart()
254
255 onVisibleChanged: tooltip.openPopup = volumeTooltip.visible
256
257 Timer {
258 id: volumeHangTimer
259 interval: 100
260 onTriggered: volumeTooltip.visible = volumeTooltip.nextVisible
261 }
262
263 implicitWidth: volumeTooltipText.contentWidth + 16
264 implicitHeight: volumeTooltipText.contentHeight + 16
265 color: "black"
266
267 WrapperMouseArea {
268 id: volumeTooltipMouseArea
269
270 hoverEnabled: true
271 enabled: true
272
273 onWheel: event => defaultSinkMouseArea.scrollVolume(event);
274
275 anchors.fill: parent
276
277 Item {
278 anchors.fill: parent
279
280 Text {
281 id: volumeTooltipText
282
283 anchors.centerIn: parent
284
285 font.pointSize: 10
286 font.family: "Fira Sans"
287 color: "white"
288
289 text: `${Math.round(defaultSinkItem.modelData?.audio?.volume * 100)}%`
290 }
291 }
292 }
293 }
294 }
295 }
296
297 Repeater {
298 id: defaultSourceRepeater
299
300 model: {
301 Array.from(Pipewire.devices.values)
302 .filter(dev => dev.type == "Audio/Device")
303 .map(device => Array.from(Pipewire.nodes.values).find(node => node.type == PwNodeType.AudioSource && node.device?.id == device.id ));
304 }
305
306 Item {
307 id: defaultSourceItem
308
309 required property var modelData
310 required property int index
311
312 visible: Boolean(modelData)
313
314 PwObjectTracker {
315 objects: [defaultSourceItem.modelData]
316 }
317
318 Layout.column: 2
319 Layout.row: index
320
321 Layout.fillHeight: true
322
323 implicitWidth: 16 + 8
324
325 WrapperMouseArea {
326 id: defaultSourceMouseArea
327
328 anchors.fill: parent
329 hoverEnabled: true
330 cursorShape: Qt.PointingHandCursor
331
332 onClicked: {
333 Pipewire.preferredDefaultAudioSource = defaultSourceItem.modelData
334 }
335
336 onWheel: event => scrollVolume(event);
337 property real sensitivity: (1 / 40) / 120
338 function scrollVolume(event) {
339 defaultSourceItem.modelData.audio.volume += event.angleDelta.y * sensitivity;
340 }
341
342 Rectangle {
343 id: defaultSourceWidget
344
345 anchors.fill: parent
346 color: {
347 if (defaultSourceMouseArea.containsMouse)
348 return "#33808080";
349 return "transparent";
350 }
351
352 MaterialDesignIcon {
353 width: 16
354 height: 16
355 anchors.centerIn: parent
356
357 icon: {
358 if (defaultSourceItem.modelData?.id == Pipewire.defaultAudioSource?.id)
359 return "microphone";
360 return "microphone-off";
361 }
362 color: icon == "microphone" ? "white" : "#555"
363 }
364 }
365 }
366
367 PopupWindow {
368 id: volumeTooltip
369
370 property bool nextVisible: defaultSourceMouseArea.containsMouse || volumeTooltipMouseArea.containsMouse
371
372 anchor {
373 item: defaultSourceMouseArea
374 edges: Edges.Bottom | Edges.Left
375 }
376 visible: false
377
378 onNextVisibleChanged: volumeHangTimer.restart()
379
380 onVisibleChanged: tooltip.openPopup = volumeTooltip.visible
381
382 Timer {
383 id: volumeHangTimer
384 interval: 100
385 onTriggered: volumeTooltip.visible = volumeTooltip.nextVisible
386 }
387
388 implicitWidth: volumeTooltipText.contentWidth + 16
389 implicitHeight: volumeTooltipText.contentHeight + 16
390 color: "black"
391
392 WrapperMouseArea {
393 id: volumeTooltipMouseArea
394
395 hoverEnabled: true
396 enabled: true
397
398 onWheel: event => defaultSourceMouseArea.scrollVolume(event);
399
400 anchors.fill: parent
401
402 Item {
403 anchors.fill: parent
404
405 Text {
406 id: volumeTooltipText
407
408 anchors.centerIn: parent
409
410 font.pointSize: 10
411 font.family: "Fira Sans"
412 color: "white"
413
414 text: `${Math.round(defaultSourceItem.modelData?.audio?.volume * 100)}%`
415 }
416 }
417 }
418 }
419 }
420 }
421
422 Repeater {
423 id: profileRepeater
424
425 model: Array.from(Pipewire.devices.values).filter(dev => dev.type == "Audio/Device")
426
427 Item {
428 id: profileItem
429
430 required property var modelData
431 required property int index
432
433 PwObjectTracker {
434 objects: [profileItem.modelData]
435 }
436
437 Layout.column: 3
438 Layout.row: index
439
440 Layout.fillWidth: true
441
442 implicitWidth: Math.max(profileBox.implicitWidth, 300)
443 implicitHeight: profileBox.height
444
445 ComboBox {
446 id: profileBox
447
448 model: profileItem.modelData.profiles
449
450 textRole: "description"
451 valueRole: "index"
452 onActivated: profileItem.modelData.setProfile(currentValue)
453
454 anchors.fill: parent
455
456 implicitContentWidthPolicy: ComboBox.WidestText
457
458 Connections {
459 target: profileItem.modelData
460 function onCurrentProfileChanged() {
461 profileBox.currentIndex = Array.from(profileItem.modelData.profiles).findIndex(profile => profile.index == profileItem.modelData.currentProfile);
462 }
463 }
464 Component.onCompleted: {
465 profileBox.currentIndex = Array.from(profileItem.modelData.profiles).findIndex(profile => profile.index == profileItem.modelData.currentProfile);
466 }
467
468 Connections {
469 target: profileBox.popup
470 function onVisibleChanged() {
471 tooltip.openPopup = profileBox.popup.visible
472 }
473 }
474 }
475 }
476 }
477 }
478 }
479 }
480 }
481 }
482 }
483}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/PrivacyWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/PrivacyWidget.qml
new file mode 100644
index 00000000..d7ffadfe
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/PrivacyWidget.qml
@@ -0,0 +1,49 @@
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Widgets
5import qs.Services
6
7Item {
8 height: parent.height
9 width: layout.childrenRect.width
10 anchors.verticalCenter: parent.verticalCenter
11
12 visible: Array.from(Privacy.activeItems).length > 0
13
14 RowLayout {
15 id: layout
16
17 anchors.fill: parent
18
19 spacing: 8
20
21 Repeater {
22 model: Privacy.activeItems
23
24 Item {
25 id: privacyItem
26
27 required property var modelData;
28
29 height: parent.height
30 width: icon.width
31
32 MaterialDesignIcon {
33 id: icon
34
35 implicitSize: 14
36 anchors.centerIn: parent
37
38 icon: {
39 if (privacyItem.modelData == Privacy.Item.Microphone)
40 return "microphone";
41 if (privacyItem.modelData == Privacy.Item.Screensharing)
42 return "monitor-share";
43 }
44 color: "#f2201f"
45 }
46 }
47 }
48 }
49}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/Brightness.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/Brightness.qml
new file mode 100644
index 00000000..f3ae6804
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/Brightness.qml
@@ -0,0 +1,107 @@
1pragma Singleton
2
3import QtQml
4import Quickshell
5import Quickshell.Io
6import Custom as Custom
7import qs.Services
8
9Singleton {
10 id: root
11
12 property string subsystem: "backlight"
13 property string device: "intel_backlight"
14
15 property real currBrightness
16 property real exponent: 4
17
18 function calcCurrBrightness() {
19 if (!currFile.loaded || !maxFile.loaded)
20 return undefined;
21 const curr = Number(currFile.text());
22 const max = Number(maxFile.text());
23 const val = Math.pow(curr / max, 1 / root.exponent);
24 return val;
25 }
26
27 Connections {
28 target: currFile
29 function onLoaded() {
30 const b = root.calcCurrBrightness();
31 if (typeof b !== 'undefined')
32 root.currBrightness = b;
33 }
34 }
35 Connections {
36 target: maxFile
37 function onLoaded() {
38 const b = root.calcCurrBrightness();
39 if (typeof b !== 'undefined')
40 root.currBrightness = b;
41 }
42 }
43
44 onCurrBrightnessChanged: {
45 root.currBrightness = Math.max(0, Math.min(1, root.currBrightness));
46
47 const prev = root.calcCurrBrightness();
48 if (typeof prev === 'undefined' || Math.abs(root.currBrightness - prev) < 0.01)
49 return;
50
51 const max = Number(maxFile.text());
52 const actual = Number(currFile.text());
53 let curr = Math.max(0, Math.min(max, Math.pow(root.currBrightness, root.exponent) * max));
54 if (Math.round(curr) == actual && curr < actual)
55 curr = Math.max(0, actual - 1);
56 else if (Math.round(curr) == actual && curr > actual)
57 curr = Math.min(max, actual + 1);
58 // root.currBrightness = Math.pow(curr / max, 1 / root.exponent);
59 Custom.Systemd.setBrightness(root.subsystem, root.device, Math.round(curr));
60 }
61
62 FileView {
63 id: currFile
64 path: `/sys/class/${root.subsystem}/${root.device}/brightness`
65 blockAllReads: true
66 watchChanges: true
67 onFileChanged: reload()
68 }
69 FileView {
70 id: maxFile
71 path: `/sys/class/${root.subsystem}/${root.device}/max_brightness`
72 blockAllReads: true
73 watchChanges: true
74 onFileChanged: reload()
75 }
76
77
78 Timer {
79 id: startupDelay
80 interval: 500
81 running: true
82 repeat: false
83 }
84 property bool onlyInternal: true
85 Connections {
86 target: NiriService
87 function onOutputsChanged() {
88 root.onlyInternal = Object.keys(NiriService.outputs).every(oname => oname == "eDP-1");
89 }
90 }
91 onOnlyInternalChanged: {
92 if (startupDelay.running)
93 return;
94
95 if (!root.onlyInternal)
96 root.currBrightness = 1
97 }
98
99
100 IpcHandler {
101 target: "Brightness"
102
103 function set(brightness: real): void {
104 root.currBrightness = brightness;
105 }
106 }
107}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/GpgAgent.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/GpgAgent.qml
new file mode 100644
index 00000000..3de69535
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/GpgAgent.qml
@@ -0,0 +1,18 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Io
5
6Singleton {
7 id: root
8
9 Socket {
10 id: agentSocket
11 connected: true
12 path: `${Quickshell.env("XDG_RUNTIME_DIR")}/gnupg/S.gpg-agent`
13 }
14
15 function reloadAgent() {
16 agentSocket.write("RELOADAGENT\n")
17 }
18}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/InhibitorState.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/InhibitorState.qml
new file mode 100644
index 00000000..60202a29
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/InhibitorState.qml
@@ -0,0 +1,23 @@
1pragma Singleton
2
3import Quickshell
4import Custom as Custom
5
6Singleton {
7 id: inhibitorState
8
9 property bool waylandIdleInhibited: false
10 property alias lidSwitchInhibited: lidSwitchInhibitor.enabled
11 property bool lockscreenInhibited: false
12
13 Custom.SystemdInhibitor {
14 id: lidSwitchInhibitor
15
16 enabled: false
17
18 what: Custom.SystemdInhibitorParams.HandleLidSwitch
19 who: "quickshell"
20 why: "User request"
21 mode: Custom.SystemdInhibitorParams.BlockWeak
22 }
23}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/MprisProxy.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/MprisProxy.qml
new file mode 100644
index 00000000..e3ab9755
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/MprisProxy.qml
@@ -0,0 +1,8 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Services.Mpris
5
6Scope {
7 property list<var> players: Mpris.players.values
8}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/NiriService.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/NiriService.qml
new file mode 100644
index 00000000..e9e86f95
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/NiriService.qml
@@ -0,0 +1,217 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Io
5import QtQuick
6
7Singleton {
8 id: root
9
10 property var workspaces: []
11 property var outputs: {}
12 property var keyboardLayouts: {}
13 property var windows: []
14 property var casts: []
15 readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
16
17 function refreshOutputs() {
18 commandSocket.sendCommand("Outputs", data => {
19 outputs = data.Ok.Outputs;
20 });
21 }
22
23 function sendCommand(command, callback) {
24 commandSocket.sendCommand(command, callback);
25 }
26
27 Socket {
28 id: eventStreamSocket
29 path: root.socketPath
30 connected: true
31
32 property bool acked: false
33
34 onConnectionStateChanged: {
35 if (connected) {
36 acked = false;
37 write('"EventStream"\n');
38 }
39 }
40
41 parser: SplitParser {
42 onRead: line => {
43 try {
44 const event = JSON.parse(line)
45
46 // console.log(JSON.stringify(event))
47
48 if (event.WorkspacesChanged) {
49 root.workspaces = event.WorkspacesChanged.workspaces
50 root.refreshOutputs();
51 } else if (event.WorkspaceActivated)
52 eventWorkspaceActivated(event.WorkspaceActivated);
53 else if (event.WorkspaceUrgencyChanged)
54 eventWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged);
55 else if (event.WorkspaceActiveWindowChanged)
56 eventWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged);
57 else if (event.KeyboardLayoutsChanged)
58 root.keyboardLayouts = event.KeyboardLayoutsChanged.keyboard_layouts;
59 else if (event.KeyboardLayoutSwitched)
60 root.keyboardLayouts = Object.assign({}, root.keyboardLayouts, {"current_idx": event.KeyboardLayoutSwitched.idx });
61 else if (event.WindowsChanged)
62 root.windows = event.WindowsChanged.windows
63 else if (event.WindowOpenedOrChanged)
64 eventWindowOpenedOrChanged(event.WindowOpenedOrChanged);
65 else if (event.WindowClosed)
66 eventWindowClosed(event.WindowClosed);
67 else if (event.WindowFocusChanged)
68 eventWindowFocusChanged(event.WindowFocusChanged);
69 else if (event.WindowUrgencyChanged)
70 eventWindowUrgencyChanged(event.WindowUrgencyChanged);
71 else if (event.WindowLayoutsChanged)
72 eventWindowLayoutsChanged(event.WindowLayoutsChanged);
73 else if (event.WindowFocusTimestampChanged)
74 eventWindowFocusTimestampChanged(event.WindowFocusTimestampChanged);
75 else if (event.CastsChanged)
76 root.casts = event.CastsChanged.casts
77 else if (event.CastStartedOrChanged)
78 eventCastStartedOrChanged(event.CastStartedOrChanged);
79 else if (event.CastStopped)
80 eventCastStopped(event.CastStopped);
81 else if (event.Ok && !eventStreamSocket.acked) { eventStreamSocket.acked = true; }
82 else if (event.OverviewOpenedOrClosed) {}
83 else if (event.ScreenshotCaptured) {}
84 else if (event.ConfigLoaded) {}
85 else
86 console.log(JSON.stringify(event));
87 } catch (e) {
88 console.warn("NiriService: Failed to parse event:", line, e)
89 }
90 }
91 }
92 }
93
94 Socket {
95 id: commandSocket
96 path: root.socketPath
97 connected: true
98
99 property var awaitingAnswer: null
100 property var cmdQueue: []
101
102 parser: SplitParser {
103 onRead: line => {
104 if (commandSocket.awaitingAnswer === null)
105 return;
106
107 try {
108 const response = JSON.parse(line);
109 commandSocket.awaitingAnswer.callback(response);
110 commandSocket.awaitingAnswer = null;
111 } catch (e) {
112 console.warn("NiriService: Failed to parse response:", line, e)
113 }
114 commandSocket._handleQueue();
115 }
116 }
117
118 onCmdQueueChanged: {
119 _handleQueue();
120 }
121 onAwaitingAnswerChanged: {
122 _handleQueue();
123 }
124
125 function _handleQueue() {
126 if (cmdQueue.length <= 0 || awaitingAnswer !== null)
127 return;
128
129 let localQueue = Array.from(cmdQueue);
130 awaitingAnswer = localQueue.shift();
131 cmdQueue = localQueue;
132 write(JSON.stringify(awaitingAnswer.command) + '\n');
133 }
134
135 function sendCommand(command, callback) {
136 cmdQueue = Array.from(cmdQueue).concat([{ "command": command, "callback": callback }])
137 }
138 }
139
140 function eventWorkspaceActivated(data) {
141 let relevant_output = null;
142 Array.from(root.workspaces).forEach(ws => {
143 if (data.id === ws.id)
144 relevant_output = ws.output;
145 });
146 root.workspaces = Array.from(root.workspaces).map(ws => {
147 if (data.focused)
148 ws.is_focused = false;
149 if (ws.output === relevant_output)
150 ws.is_active = false;
151 if (data.id === ws.id) {
152 ws.is_active = true;
153 ws.is_focused = data.focused;
154 }
155 return ws;
156 });
157 }
158 function eventWorkspaceUrgencyChanged(data) {
159 root.workspaces = Array.from(root.workspaces).map(ws => {
160 if (data.id == ws.id)
161 ws.is_urgent = data.urgent;
162 return ws;
163 });
164 }
165 function eventWorkspaceActiveWindowChanged(data) {
166 root.workspaces = Array.from(root.workspaces).map(ws => {
167 if (data.workspace_id === ws.id)
168 ws.active_window_id = data.active_window_id;
169 return ws;
170 });
171 }
172 function eventWindowOpenedOrChanged(data) {
173 root.windows = Array.from(root.windows).map(win => {
174 if (data.window.is_focused)
175 win.is_focused = false;
176 return win;
177 }).filter(win => win.id !== data.window.id).concat([data.window]);
178 }
179 function eventWindowClosed(data) {
180 root.windows = Array.from(root.windows).filter(win => win.id !== data.id);
181 }
182 function eventWindowFocusChanged(data) {
183 root.windows = Array.from(root.windows).map(win => {
184 win.is_focused = win.id === data.id;
185 return win;
186 });
187 }
188 function eventWindowUrgencyChanged(data) {
189 root.windows = Array.from(root.windows).map(win => {
190 if (win.id === data.id)
191 win.is_urgent = data.urgent;
192 return win;
193 });
194 }
195 function eventWindowLayoutsChanged(data) {
196 root.windows = Array.from(root.windows).map(win => {
197 Array.from(data.changes).forEach(change => {
198 if (win.id === change[0])
199 win.layout = change[1];
200 });
201 return win;
202 });
203 }
204 function eventWindowFocusTimestampChanged(data) {
205 root.windows = Array.from(root.windows).map(win => {
206 if (win.id === data.id)
207 win.focus_timestamp = data.focus_timestamp;
208 return win;
209 });
210 }
211 function eventCastStartedOrChanged(data) {
212 root.casts = [...Array.from(root.casts).filter(cast => cast.stream_id !== data.cast.stream_id), data.cast];
213 }
214 function eventCastStopped(data) {
215 root.casts = Array.from(root.casts).filter(cast => cast.stream_id !== data.stream_id);
216 }
217}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/NotificationManager.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/NotificationManager.qml
new file mode 100644
index 00000000..5f8ff419
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/NotificationManager.qml
@@ -0,0 +1,162 @@
1pragma Singleton
2
3import QtQml
4import Quickshell
5import Quickshell.Services.Notifications
6
7Singleton {
8 id: root
9
10 readonly property bool active: !root.lockscreenActive && !root.displayInhibited
11 property bool lockscreenActive: false
12 property bool displayInhibited: false
13 property alias trackedNotifications: server.trackedNotifications
14 readonly property var groups: {
15 function matchesGroupKey(notif, groupKey) {
16 var matches = true;
17 for (const prop in groupKey.test) {
18 if (notif[prop] !== groupKey.test[prop]) {
19 matches = false;
20 break;
21 }
22 }
23 return matches;
24 }
25
26 var groups = new Map();
27 var notifs = new Array();
28 for (const [ix, notif] of server.trackedNotifications.values.entries()) {
29 var didGroup = false;
30 for (const groupKey of root.groupKeys) {
31 if (!matchesGroupKey(notif, groupKey))
32 continue;
33
34 const key = JSON.stringify({
35 "key": groupKey,
36 "values": Object.assign({}, ...(Array.from(groupKey["group-by"]).map(prop => {
37 var res = {};
38 res[prop] = notif[prop];
39 return res;
40 })))
41 });
42 if (!groups.has(key))
43 groups.set(key, new Array());
44 groups.get(key).push({ "ix": ix, "notif": notif });
45 didGroup = true;
46 break;
47 }
48
49 if (!didGroup)
50 notifs.push([{ "ix": ix, "notif": notif }]);
51 }
52 notifs.push(...groups.values());
53 notifs.sort((as, bs) => Math.min(...(as.map(o => o.ix))) - Math.min(...(bs.map(o => o.ix))));
54 return notifs.map(ns => ns.map(n => n.notif));
55 }
56
57 property var groupKeys: [
58 { "test": { "appName": "Element" }, "group-by": [ "summary" ] }
59 ];
60
61 property int historyLimit: 100
62 property var history: []
63
64 Component {
65 id: expirationTimer
66
67 QtObject {
68 id: timer
69
70 required property QtObject parent
71 required property int expirationTime
72
73 property list<QtObject> data: [
74 Timer {
75 running: root.active && !timer.expired
76 interval: timer.expirationTime
77 onTriggered: {
78 timer.parent.expirationTimer.destroy();
79 timer.parent.expirationTimer = null;
80 timer.parent.expire();
81 }
82 }
83 ]
84 }
85 }
86
87 Component {
88 id: notificationLock
89
90 RetainableLock {}
91 }
92
93 readonly property SystemClock clock: SystemClock {
94 precision: SystemClock.Minutes
95 }
96
97 function formatTime(time) {
98 const now = root.clock.date;
99 const diff = now - time;
100 const minutes = Math.ceil(diff / 60000);
101 const hours = Math.floor(minutes / 60);
102
103 if (hours < 1) {
104 if (minutes < 1)
105 return "now";
106 if (minutes == 1)
107 return "1 minute";
108 return `${minutes} minutes`;
109 }
110
111 const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate())
112 const timeDate = new Date(time.getFullYear(), time.getMonth(), time.getDate())
113 const days = Math.floor((nowDate - timeDate) / (1000 * 86400))
114
115 const timeStr = time.toLocaleTimeString(Qt.locale(), "HH:mm");
116
117 if (days === 0)
118 return timeStr;
119 if (days === 1)
120 return `yesterday ${timeStr}`;
121
122 const dateStr = time.toLocaleDateString(Qt.locale(), "YYYY-MM-DD");
123 return `${dateStr} ${timeStr}`;
124 }
125
126 NotificationServer {
127 id: server
128
129 bodySupported: true
130 actionsSupported: true
131 actionIconsSupported: true
132 imageSupported: true
133 bodyMarkupSupported: true
134 bodyImagesSupported: true
135
136 onNotification: notification => {
137 var timeout = notification.expireTimeout * 1000;
138 if (notification.appName == "poweralertd")
139 timeout = 2000;
140 if (timeout > 0) {
141 Object.defineProperty(notification, "expirationTimer", { configurable: true, enumerable: true, writable: true });
142 notification.expirationTimer = expirationTimer.createObject(notification, { parent: notification, expirationTime: timeout });
143 }
144 Object.defineProperty(notification, "receivedTime", { configurable: true, enumerable: true, writable: true });
145 notification.receivedTime = root.clock.date;
146 notification.closed.connect((reason) => server.onNotificationClosed(notification, reason));
147 notification.tracked = true;
148 }
149
150 function onNotificationClosed(notification, reason) {
151 while (root.history.length >= root.historyLimit) {
152 root.history[0].lock.locked = false;
153 root.history.shift();
154 }
155
156 root.history.push({
157 lock: notificationLock.createObject(root, { locked: true, object: notification }),
158 notification: notification
159 });
160 }
161 }
162}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/Privacy.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/Privacy.qml
new file mode 100644
index 00000000..9c813e49
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/Privacy.qml
@@ -0,0 +1,63 @@
1pragma Singleton
2
3import QtQml
4import Quickshell
5import Quickshell.Services.Pipewire
6
7Singleton {
8 id: root
9
10 PwObjectTracker {
11 objects: Pipewire.nodes.values
12 }
13
14 enum Item {
15 Microphone,
16 Screensharing
17 }
18
19 readonly property list<var> activeItems: {
20 var items = [];
21 if (microphoneActive)
22 items.push(Privacy.Item.Microphone);
23 if (screensharingActive)
24 items.push(Privacy.Item.Screensharing);
25 return items;
26 }
27
28 readonly property bool microphoneActive: {
29 if (!Pipewire.ready || !Pipewire.nodes?.values) {
30 return false
31 }
32
33 for (const node of Pipewire.nodes.values) {
34 if (!node || (node.type & PwNodeType.AudioInStream) != PwNodeType.AudioInStream)
35 continue;
36
37 if (node.properties?.["stream.monitor"] === "true")
38 continue;
39
40 if (node.audio?.muted)
41 continue;
42
43 return true;
44 }
45
46 return false;
47 }
48
49 readonly property bool screensharingActive: {
50 if (!Pipewire.ready || !Pipewire.nodes?.values) {
51 return false
52 }
53
54 for (const node of Pipewire.nodes.values) {
55 if (!node || (node.type & PwNodeType.VideoInStream) != PwNodeType.VideoInStream)
56 continue;
57
58 return true;
59 }
60
61 return false;
62 }
63}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/ScreenRecord.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/ScreenRecord.qml
new file mode 100644
index 00000000..eb415452
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/ScreenRecord.qml
@@ -0,0 +1,63 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Io
5
6Singleton {
7 id: root
8 property bool active: false
9 property bool slurpSuccess: false
10
11 onActiveChanged: {
12 if (!active) {
13 slurp.running = false;
14 screenRecorder.running = false;
15 }
16 if (active)
17 slurp.running = true;
18 }
19
20 Process {
21 id: screenRecorder
22 running: false
23 onRunningChanged: {
24 console.log("wf-recorder running: ", screenRecorder.running);
25
26 if (!screenRecorder.running && !slurp.running)
27 root.active = false;
28 }
29 stderr: SplitParser {
30 onRead: line => console.log("wf-recorder stderr: ", line)
31 }
32 stdout: SplitParser {
33 onRead: line => console.log("wf-recorder stdout: ", line)
34 }
35 }
36
37 Process {
38 id: slurp
39 running: false
40 command: [ @slurp@, "-o", "-d" ]
41 stdout: StdioCollector {}
42 stderr: SplitParser {
43 onRead: line => console.log("slurp stderr: ", line)
44 }
45 onExited: exitCode => {
46 if (exitCode !== 0) {
47 console.log("slurp failed: ", exitCode);
48 root.active = false;
49 return;
50 }
51 console.log("slurp succeeded: ", slurp.stdout.text);
52
53 const nowDate = new Date();
54
55 screenRecorder.command = [
56 @wf-recorder@,
57 "-g", slurp.stdout.text,
58 "-f", `${Quickshell.env("HOME")}/screenshots/${nowDate.toLocaleString(Qt.locale(), "yyyy-MM-ddThh:mm:ss")}.mkv`,
59 ];
60 screenRecorder.running = true;
61 }
62 }
63}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/WallpaperSelector.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/WallpaperSelector.qml
new file mode 100644
index 00000000..c71a9cca
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/WallpaperSelector.qml
@@ -0,0 +1,8 @@
1import Custom as Custom
2
3Custom.FileSelector {
4 id: root
5
6 directory: @wallpapers@
7 epoch: 79200000
8}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/Services/Worktime.qml b/accounts/gkleen@skadhi/shell/quickshell/Services/Worktime.qml
new file mode 100644
index 00000000..d98378f1
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/Services/Worktime.qml
@@ -0,0 +1,84 @@
1pragma Singleton
2
3import QtQuick
4import Quickshell
5import Quickshell.Io
6import QtQml
7
8Singleton {
9 id: root
10
11 property alias time: timeState
12 property alias today: todayState
13
14 CommandState {
15 id: timeState
16 command: "time"
17 }
18 CommandState {
19 id: todayState
20 command: "today"
21 }
22
23 IpcHandler {
24 target: "Worktime"
25
26 function refresh(): void {
27 time.running = true;
28 today.running = true;
29 }
30 }
31
32 component CommandState : Scope {
33 id: commandState
34
35 required property string command
36 property var state: null
37
38 property bool strikeout: !strikeoutTimer.running
39 property alias running: process.running
40 property alias updating: updateTimer.running
41
42 Process {
43 id: process
44 running: true
45 command: [ @worktime@, commandState.command, "--waybar" ]
46 stdout: StdioCollector {
47 id: processCollector
48 onStreamFinished: {
49 try {
50 commandState.state = JSON.parse(processCollector.text);
51 strikeoutTimer.restart();
52 } catch (e) {
53 console.warn("Worktime: Failed to parse output:", processCollector.text, e);
54 }
55 }
56 }
57 }
58
59 Timer {
60 id: updateTimer
61 running: commandState.state?.class == "running" || commandState.state?.class == "over"
62 interval: 60000
63 repeat: true
64 onTriggered: process.running = true
65 }
66
67 Timer {
68 id: strikeoutTimer
69 running: false
70 interval: 5 * updateTimer.interval
71 repeat: false
72 }
73 }
74
75 Timer {
76 running: Boolean(timeState.state) && Boolean(todayState.state) && timeState.strikeout && todayState.strikeout
77 interval: 1000
78 repeat: false
79 onTriggered: {
80 timeState.state = null;
81 todayState.state = null;
82 }
83 }
84}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/SystemTray.qml b/accounts/gkleen@skadhi/shell/quickshell/SystemTray.qml
new file mode 100644
index 00000000..f0c50632
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/SystemTray.qml
@@ -0,0 +1,201 @@
1import QtQuick
2import QtQuick.Effects
3import Quickshell
4import Quickshell.Widgets
5import Quickshell.Services.SystemTray
6
7Item {
8 anchors.verticalCenter: parent.verticalCenter
9 width: systemTrayRow.childrenRect.width
10 height: parent.height
11 clip: true
12
13 Row {
14 id: systemTrayRow
15 anchors.centerIn: parent
16 width: childrenRect.width
17 height: parent.height
18 spacing: 0
19
20 Repeater {
21 model: ScriptModel {
22 values: {
23 var trayItems = Array.from(SystemTray.items.values).filter(item => item.status !== Status.Passive && !(["Fcitx"].includes(item.id)));
24 trayItems.sort((a, b) => a.category !== b.category ? b.category - a.category : a.id.localeCompare(b.id))
25 return trayItems;
26 }
27 }
28
29 delegate: Item {
30 id: trayItemWrapper
31
32 required property var modelData
33 required property int index
34
35 property var trayItem: modelData
36 property string iconSource: {
37 let icon = trayItem && trayItem.icon
38 if (typeof icon === 'string' || icon instanceof String) {
39 if (icon.includes("?path=")) {
40 const split = icon.split("?path=")
41 if (split.length !== 2)
42 return icon
43 const name = split[0]
44 const path = split[1]
45 const fileName = name.substring(
46 name.lastIndexOf("/") + 1)
47 return `file://${path}/${fileName}`
48 }
49 return icon
50 }
51 return ""
52 }
53
54 width: icon.width + 6
55 height: parent.height
56 anchors.verticalCenter: parent.verticalCenter
57
58 WrapperMouseArea {
59 id: trayItemArea
60
61 anchors.fill: parent
62 acceptedButtons: Qt.LeftButton | Qt.RightButton
63 hoverEnabled: true
64 cursorShape: trayItem.onlyMenu ? Qt.ArrowCursor : Qt.PointingHandCursor
65 onClicked: mouse => {
66 if (!trayItem)
67 return
68
69 if (mouse.button === Qt.LeftButton
70 && !trayItem.onlyMenu) {
71 trayItem.activate()
72 return
73 }
74
75 if (trayItem.hasMenu) {
76 var globalPos = mapToGlobal(0, 0)
77 var currentScreen = screen || Screen
78 var screenX = currentScreen.x || 0
79 var relativeX = globalPos.x - screenX
80 menuAnchor.menu = trayItem.menu
81 menuAnchor.anchor.window = bar
82 menuAnchor.anchor.rect = Qt.rect(
83 relativeX,
84 21,
85 parent.width, 1)
86 menuAnchor.open()
87 }
88 }
89
90 Rectangle {
91 anchors.fill: parent
92 color: {
93 if (trayItemArea.containsMouse)
94 return "#33808080";
95 return "transparent";
96 }
97
98 Item {
99 anchors.fill: parent
100
101 layer.enabled: true
102 layer.effect: MultiEffect {
103 colorization: 1
104 colorizationColor: "#555"
105 }
106
107 IconImage {
108 id: icon
109
110 anchors.centerIn: parent
111 implicitSize: 16
112 source: trayItemWrapper.iconSource
113 asynchronous: true
114 smooth: true
115 mipmap: true
116
117 layer.enabled: true
118 layer.effect: MultiEffect {
119 id: effect
120
121 brightness: 1
122 }
123 }
124 }
125 }
126 }
127
128 PopupWindow {
129 id: tooltip
130
131 property bool nextVisible: (trayItem.tooltipTitle || trayItem.tooltipDescription) && (trayItemArea.containsMouse || tooltipMouseArea.containsMouse) && !menuAnchor.visible
132
133 anchor {
134 item: trayItemArea
135 edges: Edges.Bottom
136 }
137
138 visible: false
139 onNextVisibleChanged: hangTimer.restart()
140
141 Timer {
142 id: hangTimer
143 interval: 100
144 onTriggered: tooltip.visible = tooltip.nextVisible
145 }
146
147 color: "black"
148
149 implicitWidth: Math.max(tooltipTitle.contentWidth, tooltipDescription.contentWidth) + 16
150 implicitHeight: (trayItem.tooltipTitle ? tooltipTitle.contentHeight : 0) + (trayItem.tooltipDescription ? tooltipDescription.contentHeight : 0) + 16
151
152 WrapperMouseArea {
153 id: tooltipMouseArea
154
155 hoverEnabled: true
156 enabled: true
157
158 margin: 4
159
160 anchors.fill: parent
161
162 Item {
163 anchors.fill: parent
164
165 Column {
166 anchors.centerIn: parent
167 Text {
168 id: tooltipTitle
169
170 enabled: trayItem.tooltipTitle
171
172 font.pointSize: 10
173 font.family: "Fira Sans"
174 font.bold: true
175 color: "white"
176
177 text: trayItem.tooltipTitle
178 }
179
180 Text {
181 id: tooltipDescription
182
183 enabled: trayItem.tooltipDescription
184
185 font.pointSize: 10
186 font.family: "Fira Sans"
187 color: "white"
188
189 text: trayItem.tooltipDescription
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 QsMenuAnchor {
199 id: menuAnchor
200 }
201}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/UnixIPC.qml b/accounts/gkleen@skadhi/shell/quickshell/UnixIPC.qml
new file mode 100644
index 00000000..3d950031
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/UnixIPC.qml
@@ -0,0 +1,106 @@
1import Quickshell
2import Quickshell.Io
3import Quickshell.Services.Pipewire
4import Quickshell.Services.Mpris
5import qs.Services
6import Custom as Custom
7import QtQml
8
9Scope {
10 id: root
11
12 SocketServer {
13 active: true
14 path: `${Quickshell.env("XDG_RUNTIME_DIR")}/shell.sock`
15 handler: Socket {
16 parser: SplitParser {
17 onRead: line => {
18 const command = (() => {
19 try {
20 return JSON.parse(line);
21 } catch (e) {
22 console.warn("UnixIPC: Failed to parse command:", line, e);
23 }
24 })();
25 if (!command)
26 return;
27
28 if (command.Volume)
29 root.onCommandVolume(command.Volume);
30 else if (command.Brightness)
31 root.onCommandBrightness(command.Brightness);
32 else if (command.LockSession)
33 Custom.Systemd.lockSession();
34 else if (command.Suspend)
35 Custom.Systemd.suspend();
36 else if (command.Hibernate)
37 Custom.Systemd.hibernate();
38 else if (command.Mpris)
39 root.onCommandMpris(command.Mpris);
40 else if (command.Notifications)
41 root.onCommandNotifications(command.Notifications);
42 else if (command.ScreenRecord)
43 root.onCommandScreenRecord(command.ScreenRecord);
44 else
45 console.warn("UnixIPC: Command not handled:", JSON.stringify(command));
46 }
47 }
48
49 onError: e => {
50 if (e == 1)
51 return;
52 console.warn("QLocalSocket::LocalSocketError", e);
53 }
54 }
55 }
56
57 PwObjectTracker {
58 objects: [ Pipewire.defaultAudioSink, Pipewire.defaultAudioSource ]
59 }
60 function onCommandVolume(command) {
61 if (command.muted === "toggle")
62 Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted;
63 if (command.volume === "up")
64 Pipewire.defaultAudioSink.audio.volume += 0.02;
65 if (command.volume === "down")
66 Pipewire.defaultAudioSink.audio.volume -= 0.02;
67
68 if (command["mic-muted"] === "toggle")
69 Pipewire.defaultAudioSource.audio.muted = !Pipewire.defaultAudioSource.audio.muted;
70 }
71
72 function onCommandBrightness(command) {
73 if (command === "up")
74 Brightness.currBrightness += 0.02
75 if (command === "down")
76 Brightness.currBrightness -= 0.02
77 }
78
79 function onCommandMpris(command) {
80 if (command.PauseAll)
81 Array.from(MprisProxy.players).forEach(player => {
82 if (player.canPause && player.isPlaying)
83 player.pause();
84 });
85 }
86 Component.onCompleted: { (_ => {})(MprisProxy.players); }
87
88 function onCommandNotifications(command) {
89 if (command.DismissGroup && NotificationManager.active) {
90 if (NotificationManager.groups.length > 0)
91 for (const notif of [...NotificationManager.groups[0]])
92 notif.dismiss();
93 }
94 if (command.DismissAll && NotificationManager.active) {
95 for (const notif of [...NotificationManager.trackedNotifications.values])
96 notif.dismiss();
97 }
98 }
99
100 function onCommandScreenRecord(command) {
101 if (command.Toggle)
102 ScreenRecord.active = !ScreenRecord.active;
103 else
104 console.warn("UnixIPC.ScreenRecord: Command not handled:", JSON.stringify(command));
105 }
106}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/VolumeOSD.qml b/accounts/gkleen@skadhi/shell/quickshell/VolumeOSD.qml
new file mode 100644
index 00000000..91dc9591
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/VolumeOSD.qml
@@ -0,0 +1,163 @@
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Services.Pipewire
5import Quickshell.Widgets
6
7Scope {
8 id: root
9
10 property string show: ""
11 property bool inhibited: true
12
13 PwObjectTracker {
14 objects: [ Pipewire.defaultAudioSink, Pipewire.defaultAudioSource ]
15 }
16
17 Connections {
18 enabled: Pipewire.defaultAudioSink
19 target: Pipewire.defaultAudioSink?.audio || null
20
21 function onVolumeChanged() {
22 root.show = "sink";
23 hideTimer.restart();
24 }
25 function onMutedChanged() {
26 root.show = "sink";
27 hideTimer.restart();
28 }
29 }
30
31 Connections {
32 enabled: Pipewire.defaultAudioSource
33 target: Pipewire.defaultAudioSource?.audio || null
34
35 function onVolumeChanged() {
36 root.show = "source";
37 hideTimer.restart();
38 }
39 function onMutedChanged() {
40 root.show = "source";
41 hideTimer.restart();
42 }
43 }
44
45 onShowChanged: {
46 if (show)
47 hideTimer.restart();
48 }
49
50 Timer {
51 id: hideTimer
52 interval: 1000
53 onTriggered: root.show = ""
54 }
55
56 Timer {
57 id: startInhibit
58 interval: 100
59 running: true
60 onTriggered: {
61 root.show = "";
62 root.inhibited = false;
63 }
64 }
65
66 LazyLoader {
67 active: root.show && !root.inhibited
68
69 Variants {
70 model: Quickshell.screens
71
72 delegate: Scope {
73 id: screenScope
74
75 required property var modelData
76
77 PanelWindow {
78 id: window
79
80 screen: screenScope.modelData
81
82 anchors.top: true
83 margins.top: screen.height / 2 - 50 + 3.5
84 exclusiveZone: 0
85 exclusionMode: ExclusionMode.Ignore
86
87 implicitWidth: 400
88 implicitHeight: 50
89
90 mask: Region {}
91
92 color: "transparent"
93
94 Rectangle {
95 anchors.fill: parent
96 color: Qt.rgba(0, 0, 0, 0.75)
97 }
98
99 RowLayout {
100 id: layout
101
102 anchors.centerIn: parent
103
104 height: 50 - 8*2
105 width: 400 - 8*2
106
107 MaterialDesignIcon {
108 id: volumeIcon
109
110 implicitWidth: parent.height
111 implicitHeight: parent.height
112
113 icon: {
114 if (root.show == "sink") {
115 if (!Pipewire.defaultAudioSink || Pipewire.defaultAudioSink.audio.muted)
116 return "volume-off";
117 if (Pipewire.defaultAudioSink.audio.volume <= 0.33)
118 return "volume-low";
119 if (Pipewire.defaultAudioSink.audio.volume <= 0.67)
120 return "volume-medium";
121 return "volume-high";
122 } else if (root.show == "source") {
123 if (!Pipewire.defaultAudioSource || Pipewire.defaultAudioSource.audio.muted)
124 return "microphone-off";
125 if (Pipewire.defaultAudioSource.audio.volume > 1)
126 return "microphone-plus";
127 return "microphone";
128 }
129 return "volume-high";
130 }
131 }
132
133 Rectangle {
134 Layout.fillWidth: true
135
136 implicitHeight: 10
137
138 color: "#50ffffff"
139
140 Rectangle {
141 anchors {
142 left: parent.left
143 top: parent.top
144 bottom: parent.bottom
145 }
146
147 color: Pipewire.defaultAudioSink?.audio.muted ? "#70ffffff" : "white"
148
149 implicitWidth: {
150 if (root.show == "sink")
151 return parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0);
152 else if (root.show == "source")
153 return parent.width * Math.min(1, (Pipewire.defaultAudioSource?.audio.volume ?? 0));
154 return 0;
155 }
156 }
157 }
158 }
159 }
160 }
161 }
162 }
163}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/WallpaperBackground.qml b/accounts/gkleen@skadhi/shell/quickshell/WallpaperBackground.qml
new file mode 100644
index 00000000..4f85a900
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/WallpaperBackground.qml
@@ -0,0 +1,89 @@
1import QtQuick
2import Quickshell
3import qs.Services
4
5Item {
6 id: root
7
8 anchors.fill: parent
9
10 required property string screen
11
12 property Img current: one
13 property string source: selector.selected
14
15 WallpaperSelector {
16 id: selector
17 seed: screen
18 }
19
20 onSourceChanged: {
21 if (!source)
22 current = null;
23 else if (current === one)
24 two.update()
25 else
26 one.update()
27 }
28
29 Img { id: one }
30 Img { id: two }
31
32 component Img: Image {
33 id: img
34
35 function update() {
36 source = root.source || ""
37 }
38
39 anchors.fill: parent
40 fillMode: Image.PreserveAspectCrop
41 smooth: true
42 asynchronous: true
43 cache: false
44
45 opacity: 0
46
47 onStatusChanged: {
48 if (status === Image.Ready) {
49 root.current = this
50 }
51 }
52
53 states: State {
54 name: "visible"
55 when: root.current === img
56
57 PropertyChanges {
58 img.opacity: 1
59 }
60 StateChangeScript {
61 name: "unloadOther"
62 script: {
63 if (img === one)
64 two.source = ""
65 if (img === two)
66 one.source = ""
67 }
68 }
69 }
70
71 transitions: Transition {
72 SequentialAnimation {
73 NumberAnimation {
74 target: img
75 properties: "opacity"
76 duration: {
77 if (img === one && two.source == "" || img === two && one.source == "")
78 return 0;
79 return 5000;
80 }
81 easing.type: Easing.OutCubic
82 }
83 ScriptAction {
84 scriptName: "unloadOther"
85 }
86 }
87 }
88 }
89}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/WaylandInhibitorWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/WaylandInhibitorWidget.qml
new file mode 100644
index 00000000..0512ff51
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/WaylandInhibitorWidget.qml
@@ -0,0 +1,56 @@
1import Quickshell
2import QtQuick
3import Quickshell.Widgets
4import Quickshell.Wayland
5import qs.Services
6
7Item {
8 id: root
9
10 required property var window
11
12 width: icon.width + 8
13 height: parent.height
14 anchors.verticalCenter: parent.verticalCenter
15
16 IdleInhibitor {
17 id: inhibitor
18 enabled: InhibitorState.waylandIdleInhibited
19 window: root.window
20 }
21
22 WrapperMouseArea {
23 id: widgetMouseArea
24
25 anchors.fill: parent
26
27 hoverEnabled: true
28 cursorShape: Qt.PointingHandCursor
29
30 onClicked: InhibitorState.waylandIdleInhibited = !InhibitorState.waylandIdleInhibited
31
32 Rectangle {
33 anchors.fill: parent
34 color: {
35 if (widgetMouseArea.containsMouse) {
36 return "#33808080";
37 }
38 return "transparent";
39 }
40
41 Item {
42 anchors.fill: parent
43
44 MaterialDesignIcon {
45 id: icon
46
47 implicitSize: 14
48 anchors.centerIn: parent
49
50 icon: inhibitor.enabled ? "eye" : "eye-off"
51 color: inhibitor.enabled ? "white" : "#555"
52 }
53 }
54 }
55 }
56}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/WorkspaceSwitcher.qml b/accounts/gkleen@skadhi/shell/quickshell/WorkspaceSwitcher.qml
new file mode 100644
index 00000000..a893937a
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/WorkspaceSwitcher.qml
@@ -0,0 +1,204 @@
1import Quickshell
2import QtQuick
3import qs.Services
4import Quickshell.Widgets
5import QtQuick.Layouts
6
7Row {
8 id: workspaces
9
10 required property var screen
11
12 property var ignoreWorkspaces: @ignore_workspaces@
13
14 height: parent.height
15 anchors.verticalCenter: parent.verticalCenter
16 spacing: 0
17
18 Repeater {
19 model: ScriptModel {
20 values: {
21 let currWorkspaces = NiriService.workspaces;
22 const ignoreWorkspaces = Array.from(workspaces.ignoreWorkspaces);
23 currWorkspaces = currWorkspaces.filter(ws => ws.output == workspaces.screen?.name).filter(ws => ws.is_active || ignoreWorkspaces.every(iws => iws !== ws.name));
24 currWorkspaces.sort((a, b) => {
25 if (NiriService.outputs?.[a.output]?.logical?.x !== NiriService.outputs?.[b.output]?.logical?.x)
26 return NiriService.outputs?.[a.output]?.logical?.x - NiriService.outputs?.[b.output]?.logical?.x
27 if (NiriService.outputs?.[a.output]?.logical?.y !== NiriService.outputs?.[b.output]?.logical?.y)
28 return NiriService.outputs?.[a.output]?.logical?.y - NiriService.outputs?.[b.output]?.logical?.y
29 return a.idx - b.idx;
30 });
31 return currWorkspaces.map(o => Object.assign({}, o));
32 }
33 }
34
35 Item {
36 id: wsItem
37
38 property var workspaceData: modelData
39
40 width: wsLabel.contentWidth + 8
41 height: parent.height
42 anchors.verticalCenter: parent.verticalCenter
43
44 WrapperMouseArea {
45 id: mouseArea
46
47 anchors.fill: parent
48
49 hoverEnabled: true
50 cursorShape: Qt.PointingHandCursor
51 enabled: true
52 onClicked: {
53 NiriService.sendCommand({ "Action": { "FocusWorkspace": { "reference": { "Id": workspaceData.id } } } }, _ => {});
54 }
55
56 Rectangle {
57 anchors.fill: parent
58
59 color: {
60 if (mouseArea.containsMouse) {
61 return "#33808080";
62 }
63 return "transparent";
64 }
65
66 Text {
67 id: wsLabel
68
69 anchors.centerIn: parent
70
71 font.pointSize: 10
72 font.family: "Fira Sans"
73 color: {
74 if (workspaceData.is_active)
75 return "#23fd00";
76 if (workspaceData.active_window_id === null)
77 return "#555";
78 return "white";
79 }
80
81 text: workspaceData.name ? workspaceData.name : workspaceData.idx
82 }
83 }
84 }
85
86 PopupWindow {
87 id: tooltip
88
89 property bool nextVisible: (mouseArea.containsMouse || tooltipMouseArea.containsMouse) && [...windowsModel.values].length > 0
90
91 anchor {
92 item: mouseArea
93 edges: Edges.Bottom | Edges.Left
94 }
95 visible: false
96
97 onNextVisibleChanged: hangTimer.restart()
98
99 Timer {
100 id: hangTimer
101 interval: 100
102 onTriggered: tooltip.visible = tooltip.nextVisible
103 }
104
105 implicitWidth: tooltipContent.implicitWidth
106 implicitHeight: tooltipContent.implicitHeight
107 color: "black"
108
109 WrapperMouseArea {
110 id: tooltipMouseArea
111
112 hoverEnabled: true
113 enabled: true
114
115 anchors.fill: parent
116
117 WrapperItem {
118 id: tooltipContent
119
120 margin: 0
121
122 ColumnLayout {
123 spacing: 0
124
125 Repeater {
126 model: ScriptModel {
127 id: windowsModel
128
129 values: {
130 let currWindows = NiriService.windows.filter(win => win.workspace_id == wsItem.workspaceData.id);
131 currWindows.sort((a, b) => {
132 if (a.is_floating !== b.is_floating)
133 return b.is_floating - a.is_floating;
134 if (a.layout.tile_pos_in_workspace_view?.[0] !== b.layout.tile_pos_in_workspace_view?.[0])
135 return a.layout.tile_pos_in_workspace_view?.[0] - b.layout.tile_pos_in_workspace_view?.[0]
136 if (a.layout.tile_pos_in_workspace_view?.[1] !== b.layout.tile_pos_in_workspace_view?.[1])
137 return a.layout.tile_pos_in_workspace_view?.[1] - b.layout.tile_pos_in_workspace_view?.[1]
138 if (a.layout.pos_in_scrolling_layout?.[0] !== b.layout.pos_in_scrolling_layout?.[0])
139 return a.layout.pos_in_scrolling_layout?.[0] - b.layout.pos_in_scrolling_layout?.[0]
140 if (a.layout.pos_in_scrolling_layout?.[1] !== b.layout.pos_in_scrolling_layout?.[1])
141 return a.layout.pos_in_scrolling_layout?.[1] - b.layout.pos_in_scrolling_layout?.[1]
142 if (a.app_id !== b.app_id)
143 return a.app_id?.localeCompare(b.app_id);
144
145 return a.title.localeCompare(b.title);
146 });
147 return currWindows.map(o => Object.assign({}, o));
148 }
149 }
150
151 WrapperMouseArea {
152 id: windowMouseArea
153
154 required property int index
155 required property var modelData
156 property var windowData: modelData
157
158 hoverEnabled: true
159 cursorShape: Qt.PointingHandCursor
160 enabled: true
161
162 Layout.fillWidth: true
163
164 onClicked: {
165 NiriService.sendCommand({ "Action": { "FocusWindow": { "id": windowData.id } } }, _ => {})
166 }
167
168 WrapperRectangle {
169 color: windowMouseArea.containsMouse ? "#33808080" : "transparent";
170
171 WrapperItem {
172 rightMargin: 8
173 leftMargin: 8
174 topMargin: windowMouseArea.index == 0 ? 8 : 4
175 bottomMargin: windowMouseArea.index == windowsModel.values.length - 1 ? 8 : 4
176
177 Text {
178 id: windowLabel
179
180 font.pointSize: 10
181 font.family: "Fira Sans"
182 color: {
183 if (windowData.is_focused)
184 return "#23fd00";
185 if (NiriService.workspaces.find(ws => ws.id == windowData.workspace_id)?.active_window_id == windowData.id)
186 return "white";
187 return "#555";
188 }
189
190 text: windowData.title
191
192 horizontalAlignment: Text.AlignLeft
193 }
194 }
195 }
196 }
197 }
198 }
199 }
200 }
201 }
202 }
203 }
204}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/WorktimeWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/WorktimeWidget.qml
new file mode 100644
index 00000000..b7baee34
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/WorktimeWidget.qml
@@ -0,0 +1,212 @@
1import QtQml
2import Quickshell
3import QtQuick
4import Quickshell.Widgets
5import qs.Services
6
7Item {
8 id: root
9
10 height: parent.height
11 width: (timeWidget.visible ? timeWidget.label.contentWidth + 8 : 0) + (todayWidget.visible ? todayWidget.label.contentWidth + 8 : 0) + (icon.visible ? icon.implicitWidth + 8 : 0)
12 anchors.verticalCenter: parent.verticalCenter
13
14 component TextWidget : Item {
15 id: textWidget
16
17 visible: textWidget.state.state?.text ?? false
18
19 required property var state
20 property alias label: label
21 property alias mouseArea: mouseArea
22
23 anchors.verticalCenter: parent.verticalCenter
24 implicitWidth: label.contentWidth + 8
25 height: parent.height
26
27 WrapperMouseArea {
28 id: mouseArea
29
30 anchors.fill: parent
31
32 enabled: true
33 hoverEnabled: true
34 acceptedButtons: Qt.NoButton
35 cursorShape: Qt.PointingHandCursor
36
37 Item {
38 anchors.fill: parent
39
40 Text {
41 id: label
42
43 anchors.centerIn: parent
44
45 text: textWidget.state.state?.text ?? ""
46
47 font.pointSize: 10
48 font.family: "Fira Sans"
49 font.strikeout: textWidget.state.strikeout
50 color: {
51 if (textWidget.state.state?.class == "running")
52 return "white";
53 if (textWidget.state.state?.class == "over")
54 return "#f28a21";
55 return "#555";
56 }
57 }
58 }
59 }
60 }
61
62 WrapperMouseArea {
63 id: mouseArea
64
65 anchors.fill: parent
66 hoverEnabled: true
67
68 cursorShape: Qt.PointingHandCursor
69 onClicked: {
70 Worktime.time.running = true;
71 Worktime.today.running = true;
72 }
73
74 Rectangle {
75 anchors.fill: parent
76 color: {
77 if (mouseArea.containsMouse)
78 return "#33808080";
79 return "transparent";
80 }
81
82 Row {
83 height: parent.height
84 anchors.centerIn: parent
85 spacing: 0
86
87 TextWidget {
88 id: timeWidget
89 state: Worktime.time
90 }
91
92 TextWidget {
93 id: todayWidget
94 state: Worktime.today
95 }
96
97 MaterialDesignIcon {
98 id: icon
99
100 anchors.verticalCenter: parent.verticalCenter
101
102 implicitSize: 14
103
104 visible: !timeWidget.visible && !todayWidget.visible
105
106 icon: (Worktime.time.running || Worktime.today.running) ? "update" : "timer-off"
107 color: "#555"
108 }
109 }
110 }
111 }
112
113 component WorktimePopup : PopupWindow {
114 id: tooltip
115
116 required property var state
117 required property var mouseArea
118
119 property bool iconVisible: tooltip.state.running || !tooltip.state.updating
120 property bool tooltipVisible: tooltip.state.state?.tooltip ?? false
121
122 property bool nextVisible: (tooltip.tooltipVisible || tooltip.iconVisible) && (tooltip.mouseArea.containsMouse || tooltipMouseArea.containsMouse)
123
124 anchor {
125 item: tooltip.mouseArea
126 edges: Edges.Bottom | Edges.Left
127 }
128 visible: false
129
130 onNextVisibleChanged: hangTimer.restart()
131
132 Timer {
133 id: hangTimer
134 interval: 100
135 onTriggered: tooltip.visible = tooltip.nextVisible
136 }
137
138 implicitWidth: (tooltipIcon.visible ? tooltipIcon.implicitWidth : 0) + (tooltipIcon.visible && tooltipText.visible ? 8 : 0) + (tooltipText.visible ? tooltipText.implicitWidth : 0) + 16
139 implicitHeight: tooltipText.implicitHeight + 16
140 color: "black"
141
142 WrapperMouseArea {
143 id: tooltipMouseArea
144
145 enabled: true
146 hoverEnabled: true
147
148 anchors.fill: parent
149
150 Item {
151 anchors.fill: parent
152
153 Row {
154 id: tooltipLayout
155
156 anchors {
157 left: parent.left
158 top: parent.top
159 leftMargin: 8
160 topMargin: 8
161 verticalCenter: parent.verticalCenter
162 }
163
164 height: parent.height
165 width: childrenRect.width
166
167 spacing: 0
168
169 MaterialDesignIcon {
170 id: tooltipIcon
171
172 implicitSize: 14
173 anchors.verticalCenter: parent.verticalCenter
174
175 visible: tooltip.iconVisible
176
177 icon: tooltip.state.running ? "update" : "timer-off"
178 }
179
180 Item {
181 visible: tooltipIcon.visible && tooltipText.visible
182 height: parent.height
183 width: 8
184 }
185
186 Text {
187 id: tooltipText
188
189 visible: tooltip.tooltipVisible
190
191 anchors.verticalCenter: parent.verticalCenter
192
193 font.pointSize: 10
194 font.family: "Fira Sans"
195 color: "white"
196
197 text: tooltip.state.state?.tooltip ?? ""
198 }
199 }
200 }
201 }
202 }
203
204 WorktimePopup {
205 state: Worktime.time
206 mouseArea: timeWidget.mouseArea
207 }
208 WorktimePopup {
209 state: Worktime.today
210 mouseArea: todayWidget.mouseArea
211 }
212}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/YtDlpWidget.qml b/accounts/gkleen@skadhi/shell/quickshell/YtDlpWidget.qml
new file mode 100644
index 00000000..ff338d49
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/YtDlpWidget.qml
@@ -0,0 +1,190 @@
1import QtQml.Models
2import QtQuick
3import QtQuick.Layouts
4import QtQuick.Controls.Material
5import Quickshell
6import Quickshell.Io
7import Quickshell.Widgets
8import Custom as Custom
9
10Item {
11 id: root
12
13 height: parent.height
14 width: icon.width
15 anchors.verticalCenter: parent.verticalCenter
16
17 visible: Boolean(unitsModel.values.length)
18
19 WrapperMouseArea {
20 id: widgetMouseArea
21
22 anchors.fill: parent
23 hoverEnabled: true
24
25 Item {
26 anchors.fill: parent
27
28 MaterialDesignIcon {
29 id: icon
30
31 implicitSize: 14
32 anchors.centerIn: parent
33
34 icon: "tray-arrow-down"
35 color: "white"
36 }
37 }
38 }
39
40 PopupWindow {
41 id: tooltip
42
43 property bool openPopup: false
44 property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse || openPopup
45
46 anchor {
47 item: widgetMouseArea
48 edges: Edges.Bottom | Edges.Left
49 }
50 visible: false
51
52 onNextVisibleChanged: hangTimer.restart()
53
54 Timer {
55 id: hangTimer
56 interval: 100
57 onTriggered: tooltip.visible = tooltip.nextVisible
58 }
59
60 implicitWidth: tooltipContent.width
61 implicitHeight: tooltipContent.height
62 color: "transparent"
63
64 Rectangle {
65 width: tooltip.width
66 height: tooltipLayout.childrenRect.height + 16
67 color: "black"
68 }
69
70 WrapperItem {
71 id: tooltipContent
72
73 WrapperMouseArea {
74 id: tooltipMouseArea
75
76 hoverEnabled: true
77 enabled: true
78
79 WrapperItem {
80 margin: 8
81
82 child: GridLayout {
83 id: tooltipLayout
84
85 columns: 2
86 }
87
88 Repeater {
89 model: ScriptModel {
90 id: unitsModel
91
92 values: [...Custom.Systemd.userUnits.values].filter(unit => unit.id.match(/^yt-dlp@.+\.service$/) && unit.activeState === "active" && unit.runtimeDirectory)
93 }
94
95 Item {
96 id: unitDelegate
97
98 Component.onCompleted: {
99 while (children.length) { children[0].parent = tooltipLayout; }
100 }
101
102 required property var modelData
103 required property int index
104
105 property var state: null
106
107 Socket {
108 id: socket
109
110 path: Quickshell.env("XDG_RUNTIME_DIR") + "/" + unitDelegate.modelData.runtimeDirectory[0] + "/status.sock"
111 connected: true
112 onError: e => {
113 console.warn("YtDlpWidget: Error in Socket:", socket.path, e);
114 }
115 parser: SplitParser {
116 onRead: line => {
117 try {
118 unitDelegate.state = JSON.parse(line)
119 } catch (e) {
120 console.warn("YtDlpWidget: Failed to parse state:", line, e)
121 }
122 }
123 }
124 }
125
126 WrapperItem {
127 Layout.column: 0
128 Layout.row: unitDelegate.index
129
130 implicitWidth: descText.contentWidth
131 implicitHeight: descText.contentHeight
132
133 Text {
134 id: descText
135
136 color: "white"
137 font.pointSize: 10
138 font.family: "Fira Sans"
139
140 text: unitDelegate.state?.title || unitDelegate.modelData.id
141 }
142 }
143
144 /*
145 WrapperItem {
146 Layout.column: 1
147 Layout.row: unitDelegate.index
148
149 implicitWidth: fragText.contentWidth
150 implicitHeight: fragText.contentHeight
151
152 visible: Boolean(unitDelegate.state)
153
154 Text {
155 id: fragText
156
157 color: "white"
158 font.pointSize: 10
159 font.family: "Fira Sans"
160
161 text: `${unitDelegate.state?.fragment_index}/${unitDelegate.state?.fragment_count}`
162 }
163 }
164 */
165
166 WrapperItem {
167 Layout.column: 1
168 Layout.row: unitDelegate.index
169
170 visible: Boolean(unitDelegate.state)
171
172 ProgressBar {
173 id: progress
174
175 Material.background: "black"
176 Material.accent: "white"
177
178 from: 0
179 to: unitDelegate.state?.total_bytes || unitDelegate.state?.total_bytes_estimate || 0
180 value: unitDelegate.state?.downloaded_bytes || 0
181 indeterminate: !Boolean(unitDelegate.state?.total_bytes || unitDelegate.state?.total_bytes_estimate) || unitDelegate.state?.status !== "downloading"
182 }
183 }
184 }
185 }
186 }
187 }
188 }
189 }
190}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/displaymanager.qml b/accounts/gkleen@skadhi/shell/quickshell/displaymanager.qml
new file mode 100644
index 00000000..b452c03d
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/displaymanager.qml
@@ -0,0 +1,115 @@
1//@ pragma UseQApplication
2
3import Quickshell
4import Quickshell.Wayland
5import Quickshell.Io
6import Quickshell.Services.Greetd
7import QtQml
8
9
10ShellRoot {
11 id: displaymanager
12
13 settings.watchFiles: false
14
15 property string currentText: ""
16 property string username: @username@
17 property list<string> command: @niri_session@
18 property list<var> messages: []
19 property bool responseRequired: false
20 property bool responseVisible: false
21
22 signal startAuth()
23
24 onStartAuth: {
25 if (Greetd.state !== GreetdState.Inactive)
26 Greetd.cancelSession();
27 displaymanager.messages = [];
28 Greetd.createSession(displaymanager.username);
29 }
30
31 Connections {
32 target: Greetd
33 function onStateChanged() {
34 console.log("greetd state: ", GreetdState.toString(Greetd.state));
35 if (Greetd.state === GreetdState.ReadyToLaunch)
36 Greetd.launch(displaymanager.command);
37 }
38 function onAuthMessage(message: string, error: bool, responseRequired: bool, echoResponse: bool) {
39 displaymanager.responseVisible = echoResponse;
40 displaymanager.responseRequired = responseRequired;
41 displaymanager.messages = Array.from(displaymanager.messages).concat([{ "text": message, "error": error }]);
42 }
43 function onAuthFailure(message: string) {
44 displaymanager.responseRequired = false;
45 displaymanager.messages = Array.from(displaymanager.messages).concat([{ "text": message, "error": true }]);
46 }
47 }
48
49 Component.onCompleted: {
50 if (Greetd.state !== GreetdState.Inactive)
51 Greetd.cancelSession();
52 }
53
54 Variants {
55 model: Quickshell.screens
56
57 delegate: Scope {
58 id: screenScope
59
60 required property var modelData
61
62 PanelWindow {
63 color: "black"
64
65 screen: screenScope.modelData
66
67 WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
68
69 anchors.top: true
70 anchors.bottom: true
71 anchors.left: true
72 anchors.right: true
73
74 LockSurface {
75 id: surfaceContent
76
77 screen: screenScope.modelData
78
79 onCurrentTextChanged: displaymanager.currentText = currentText
80 Connections {
81 target: displaymanager
82 function onCurrentTextChanged() { surfaceContent.currentText = displaymanager.currentText; }
83 function onMessagesChanged() { surfaceContent.messages = Array.from(displaymanager.messages); }
84 function onResponseRequiredChanged() { surfaceContent.responseRequired = displaymanager.responseRequired; }
85 function onResponseVisibleChanged() { surfaceContent.responseVisible = displaymanager.responseVisible; }
86 }
87
88 onResponse: responseText => Greetd.respond(responseText);
89 Connections {
90 target: Greetd
91 function onStateChanged() {
92 if (Greetd.state === GreetdState.Authenticating) {
93 surfaceContent.authRunning = true;
94 } else {
95 surfaceContent.authRunning = false;
96 }
97 }
98 }
99
100 onAuthRunningChanged: {
101 if (surfaceContent.authRunning && Greetd.state !== GreetdState.Authenticating)
102 displaymanager.startAuth();
103 }
104 Component.onCompleted: {
105 surfaceContent.authRunning = Greetd.state === GreetdState.Authenticating
106 surfaceContent.messages = Array.from(displaymanager.messages);
107 surfaceContent.responseVisible = displaymanager.responseVisible;
108 surfaceContent.responseRequired = displaymanager.responseRequired;
109 surfaceContent.currentText = displaymanager.currentText;
110 }
111 }
112 }
113 }
114 }
115}
diff --git a/accounts/gkleen@skadhi/shell/quickshell/shell.qml b/accounts/gkleen@skadhi/shell/quickshell/shell.qml
new file mode 100644
index 00000000..1a5875f0
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell/shell.qml
@@ -0,0 +1,53 @@
1//@ pragma UseQApplication
2
3import Quickshell
4import Quickshell.Wayland
5
6ShellRoot {
7 settings.watchFiles: false
8
9 Variants {
10 model: Quickshell.screens
11
12 delegate: Scope {
13 id: screenScope
14
15 required property var modelData
16
17 PanelWindow {
18 id: bgWindow
19
20 screen: screenScope.modelData
21
22 WlrLayershell.layer: WlrLayer.Background
23 WlrLayershell.namespace: "background"
24 exclusionMode: ExclusionMode.Ignore
25
26 anchors.top: true
27 anchors.bottom: true
28 anchors.left: true
29 anchors.right: true
30
31 color: "black"
32
33 WallpaperBackground {
34 screen: bgWindow.screen.name
35 }
36 }
37
38 Bar {
39 screen: screenScope.modelData
40 }
41 }
42 }
43
44 Lockscreen {}
45 NiriIdle {}
46
47 VolumeOSD {}
48 BrightnessOSD {}
49
50 NotificationDisplay {}
51
52 UnixIPC {}
53}
diff --git a/accounts/gkleen@skadhi/zsh/default.nix b/accounts/gkleen@skadhi/zsh/default.nix
new file mode 100644
index 00000000..ddc69f0d
--- /dev/null
+++ b/accounts/gkleen@skadhi/zsh/default.nix
@@ -0,0 +1,106 @@
1{ pkgs, lib, config, sysConfig, flakeInputs, ... }:
2let
3 zshrc = pkgs.resholve.mkDerivation {
4 pname = "zshrc";
5 version = "0.0.0";
6
7 src = ./zshrc;
8
9 dontUnpack = true;
10 dontConfigure = true;
11 dontBuild = true;
12
13 installPhase = ''
14 mkdir -p $out/share
15 install "$src" $out/share/zshrc
16 '';
17
18 solutions = {
19 default = {
20 scripts = [ "share/zshrc" ];
21 interpreter = "none";
22 inputs = with pkgs; [
23 coreutils
24 rpm
25 binutils
26 squashfsTools
27 unzip
28 config.programs.git.package
29 magickWrapped
30 curl
31 file
32 gnutar
33 cpio
34 magic-wormhole
35 config.programs.zsh.package
36 util-linux
37 findutils
38 qrencode
39 tty-clock
40 config.programs.jq.package
41 eza
42 less
43 sysConfig.systemd.package
44 sysConfig.programs.ssh.package
45 gnused
46 miniserve
47 p7zip
48 ];
49 execer = with pkgs; [
50 "cannot:${lib.getExe' rpm "rpm2cpio"}"
51 "cannot:${lib.getExe' squashfsTools "unsquashfs"}"
52 "cannot:${lib.getExe' unzip "unzip"}"
53 "cannot:${lib.getExe config.programs.git.package}"
54 "cannot:${lib.getExe cpio}"
55 "cannot:${lib.getExe' magic-wormhole "wormhole"}"
56 "cannot:${lib.getExe' fuse "fusermount"}"
57 "cannot:${lib.getExe less}"
58 "cannot:${lib.getExe' sysConfig.systemd.package "systemctl"}"
59 "cannot:${lib.getExe sysConfig.programs.ssh.package}"
60 "cannot:${lib.getExe' p7zip "7z"}"
61 ];
62 wrapper = with pkgs; [
63 "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}"
64 ];
65 fake = {
66 builtin = ["print"];
67 external = lib.mapAttrsToList (_: cfg: cfg.program) sysConfig.security.wrappers;
68 };
69 };
70 };
71 };
72 magickWrapped = pkgs.symlinkJoin {
73 inherit (pkgs.imagemagick) name;
74 paths = [ pkgs.imagemagick ];
75
76 buildInputs = with pkgs; [ makeWrapper ];
77 postBuild = ''
78 wrapProgram $out/bin/magick \
79 --prefix PATH : ${lib.makeBinPath (with pkgs; [ ghostscript ])}
80 '';
81 };
82in {
83 config = {
84 programs.zsh.initContent = ''
85 source ${zshrc}/share/zshrc
86 '';
87 programs.zsh.dirHashes = let
88 flakeHashes = lib.mapAttrs' (n: v: lib.nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs;
89 inputNames = {
90 self = "nixos";
91 };
92 in flakeHashes // {
93 docs = "$HOME/documents";
94 dl = "$HOME/Downloads";
95 scrot = "$HOME/screenshots";
96 media = "$HOME/media";
97 };
98 programs.starship.settings = {
99 directory.substitutions = lib.mapAttrs' (name: value: let
100 value' = builtins.unsafeDiscardStringContext value;
101 value'' = if lib.hasPrefix "$HOME/" value' then "~" + lib.removePrefix "$HOME" value' else value';
102 in lib.nameValuePair value'' "~${name}"
103 ) config.programs.zsh.dirHashes;
104 };
105 };
106}
diff --git a/accounts/gkleen@skadhi/zsh/zshrc b/accounts/gkleen@skadhi/zsh/zshrc
new file mode 100644
index 00000000..c532b308
--- /dev/null
+++ b/accounts/gkleen@skadhi/zsh/zshrc
@@ -0,0 +1,298 @@
1dir() {
2 curlArchive=false
3 templateArchive=""
4 repoUrl=""
5 dir=""
6 forceShell=false
7 wormhole=false
8 gitWorktree=""
9 modifyPDF=""
10 miniserve=false
11
12 while getopts ':t:a:d:ir:wg:p:m' arg; do
13 case $arg in
14 "t") ;;
15 "a")
16 if [[ ${OPTARG} =~ "://" ]]; then
17 templateArchive=${OPTARG}
18 curlArchive=true
19 else
20 templateArchive=${OPTARG:a}
21 fi
22 ;;
23 "d") dir=${OPTARG} ;;
24 "i") forceShell=true ;;
25 "r") repoUrl=${OPTARG} ;;
26 "w") wormhole=true ;;
27 "g") gitWorktree=${OPTARG} ;;
28 "p") modifyPDF=${OPTARG:a} ;;
29 "m") miniserve=true ;;
30 *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
31 esac
32 done
33
34 shift $((OPTIND - 1))
35
36 if [[ -z ${dir} && ${#@} -ge 1 ]]; then
37 dir=${1}
38 shift
39 fi
40
41 [[ -n ${dir} ]] || return 2;
42
43 if [[ ! -e ${dir} ]]; then
44 if [[ -z "${gitWorktree}" ]]; then
45 mkdir -vp ${dir}
46 else
47 git -C ${gitWorktree} worktree add ${dir}
48 fi
49 else
50 gitWorktree=""
51 fi
52
53 miniservePIDFile=""
54 if [[ ${miniserve} = "true" ]]; then
55 miniservePIDFile=$(mktemp --tmpdir --suffix=.pid)
56 fi
57
58 cleanup()
59 {
60 if [[ -n ${modifyPDF} ]]; then
61 cd ${modifyPDF:h}
62 typeset -a pages
63 eval 'pages=(${dir}/${modifyPDF:t:r}_*.png(on))'
64 magick -verbose "${pages[@]}" $(mktemp --tmpdir=${modifyPDF:h} ${modifyPDF:t:r}_XXXXXXXXXX.${modifyPDF:e})
65 modifyPDF=""
66 fi
67 if [[ -n ${miniservePIDFile} ]]; then
68 command kill --verbose -- $(cat ${miniservePIDFile}) && wait $(cat ${miniservePIDFile})
69 miniservePIDFile=""
70 fi
71 }
72
73 (
74 set -o localoptions -o localtraps
75 trap 'return 1' INT TERM
76 trap cleanup EXIT
77
78 cd ${dir}
79 export dir;
80
81 [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} .
82
83 [[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF}
84
85 if [[ -n ${templateArchive} ]]; then
86 (
87 archiveFile=""
88 cleanup() {
89 [[ -n "${archiveFile}" ]] && rm -fv ${archiveFile}
90 }
91 trap cleanup EXIT
92
93 if [[ $curlArchive = "true" ]]; then
94 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")
95
96 curl -SfL -o ${archiveFile} ${templateArchive}
97
98 templateArchive=${archiveFile}
99 fi
100
101 unpack=true
102 while [[ $unpack = "true" ]]; do
103 case $(file --brief --mime-type --dereference ${templateArchive}) in
104 application/zip)
105 unzip ${templateArchive}
106 unpack=false
107 ;;
108 application/vnd.debian.binary-package)
109 ar x ${templateArchive}
110 mkdir control data
111 tar -C control -xvaf control.*
112 tar -C data -xvaf data.*
113 unpack=false
114 ;;
115 application/x-rpm)
116 cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio")
117 rpm2cpio ${templateArchive} > ${cpioArchive}
118 templateArchive=${cpioArchive}
119 unpack=true
120 ;;
121 application/x-cpio)
122 cpio --extract --make-directories --no-absolute-filenames -F ${templateArchive}
123 unpack=false
124 ;;
125 application/pdf)
126 magick -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png
127 unpack=false
128 ;;
129 application/octet-stream)
130 if [[ $(file --brief --dereference ${templateArchive}) =~ Squashfs ]]; then
131 unsquashfs -d . ${templateArchive}
132 unpack=false
133 fi
134 ;;
135 application/x-iso9660-image)
136 7z x ${templateArchive}
137 unpack=false
138 ;;
139 *)
140 tar -xvaf ${templateArchive}
141 unpack=false
142 ;;
143 esac
144 done
145 )
146 fi
147
148
149 [[ $wormhole = "true" ]] && wormhole receive --accept-file
150
151
152 if [[ ${#@} -gt 0 ]]; then
153 ${@}
154 fi
155
156 cd $(pwd) # Needed for mounting to work
157
158 if [[ ${miniserve} = "true" ]]; then
159 miniserve --random-route --hidden --enable-tar-gz --enable-zip . &
160 echo $! > "${miniservePIDFile}"
161 fi
162
163 if [[ ${#@} -eq 0 ]] && [[ ${miniserve} != "true" ]] || [[ $forceShell = "true" ]]; then
164 isSingleDir() {
165 typeset -a contents
166 contents=(*(N) .*(N))
167
168 if [[ ${#contents} -eq 1 && -d ${contents[1]} ]]; then
169 print ${contents[1]}
170 return 0
171 else
172 return 1
173 fi
174 }
175 while d=$(isSingleDir); do cd ${d}; done
176
177 zsh
178 elif [[ ${miniserve} == "true" ]]; then
179 wait $(cat "${miniservePIDFile}")
180 fi
181 )
182}
183
184tmpdir() {
185 cleanup()
186 {
187 cd /
188 unmount() {
189 printf "Unmounting %s\n" ${1} >&2
190 fusermount3 -u ${1} || umount ${1} || sudo umount ${1}
191 }
192
193 if [[ -n ${dir} ]]; then
194 if mountpoint -q -- ${dir}; then
195 unmount ${dir} || return $?
196 else
197 while read -d $'\0' subDir; do
198 mountpoint -q -- ${subDir} || continue
199 unmount ${subDir} || return $?
200 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
201 fi
202
203 rm -rfv --one-file-system -- ${dir}
204 dir=""
205 fi
206 }
207
208 local tmpdir=""
209
210 while getopts ':t:a:d:ir:wg:p:m' arg; do
211 case $arg in
212 "t") tmpdir="=${OPTARG}" ;;
213 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
214 esac
215 done
216
217 (
218 set -o localoptions -o localtraps
219 trap 'return 1' INT TERM
220 trap cleanup EXIT
221
222
223 local dir=$(mktemp -ud --tmpdir${tmpdir} ${0}.XXXXXXXXXX || return $?)
224
225 ( dir -d ${dir} ${@} )
226 )
227}
228
229qr() {
230 qrencode -l M -o - -t ANSIUTF8 $@
231}
232
233clock() {
234 tty-clock -sSbc -C 7 -d 0 -a 100000000
235}
236
237public-ip() {
238 curl -sSf -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
239}
240
241swap() {
242 f1=${1}
243 f2=${2}
244
245 if [[ -z "${f1}" || ! -e "${f1}" ]]; then
246 printf "‘%s’ does not exist\n" "${f1}" >&2
247 return 2
248 fi
249 if [[ -z "${f2}" || ! -e "${f2}" ]]; then
250 printf "‘%s’ does not exist\n" "${f2}" >&2
251 return 2
252 fi
253
254 tmpfile=$(mktemp --dry-run --tmpdir=${f1:h} .swap.XXXXXXXXXX)
255 mv -v ${f1} ${tmpfile}
256 mv -v ${f2} ${f1}
257 mv -v ${tmpfile} ${f2}
258}
259
260ls() {
261 eza --all --group-directories-first --colour=always --sort=modified --smart-group $@ | less --mouse -FR
262}
263
264l() {
265 ls --long --binary --git --time-style=iso --header $@
266}
267
268ssh-installer() {
269 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@
270}
271
272dichotomic_search() {
273 min=$1; shift
274 max=$1; shift
275
276 while [[ $min -lt $max ]]; do
277 # Compute the mean between min and max, rounded up to the superior unit
278 current=$(( (min + max + 1 ) / 2 ))
279 if $@ $current; then
280 min=$current
281 else
282 max=$((current - 1))
283 fi
284 done
285
286 echo $min
287}
288
289while read -r -d $'\0' d _ s; do
290 hash -d ${s}=${d}
291done < <(find ~/projects ~/uni -regextype posix-extended -maxdepth 2 -type d -regex '\S+/[0-9]{2}[ws]/\S+' -print0 2>/dev/null | \
292 sed -zr 's|(.*/([0-9]{2}[ws])/(.+))|\1 \2 \3|' | \
293 sort -z -r -k2 | sort -z -s -k3 | uniq -z -f 2)
294
295alias rzadm=$'tmpdir -i sh -c \'mkdir adm; sshfs gkleen@mgmt01:/adm adm\''
296alias mathcloud=$'tmpdir -i rclone mount --daemon mathcloud:// .'
297
298export DEFAULT_USER=gkleen