diff options
Diffstat (limited to 'accounts')
71 files changed, 7553 insertions, 829 deletions
| diff --git a/accounts/gkleen@eostre.nix b/accounts/gkleen@eostre.nix index 72818d44..28daf3fd 100644 --- a/accounts/gkleen@eostre.nix +++ b/accounts/gkleen@eostre.nix | |||
| @@ -1,16 +1,16 @@ | |||
| 1 | { flake, userName, pkgs, ... }: | 1 | { flake, userName, pkgs, ... }: | 
| 2 | { | 2 | { | 
| 3 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 3 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 4 | zsh utils tmux | 4 | utils | 
| 5 | ]; | 5 | ]; | 
| 6 | 6 | ||
| 7 | config = { | 7 | config = { | 
| 8 | home-manager.users.${userName} = { | 8 | home-manager.users.${userName} = { | 
| 9 | home.stateVersion = "20.09"; | 9 | home.stateVersion = "20.09"; | 
| 10 | 10 | ||
| 11 | nixpkgs.config = { | 11 | # nixpkgs.config = { | 
| 12 | allowUnfree = true; | 12 | # allowUnfree = true; | 
| 13 | }; | 13 | # }; | 
| 14 | 14 | ||
| 15 | home.packages = with pkgs; [ | 15 | home.packages = with pkgs; [ | 
| 16 | thunderbird libreoffice element-desktop keepassxc vlc | 16 | thunderbird libreoffice element-desktop keepassxc vlc | 
| diff --git a/accounts/gkleen@installer.nix b/accounts/gkleen@installer.nix index c7a418f8..5fe1db38 100644 --- a/accounts/gkleen@installer.nix +++ b/accounts/gkleen@installer.nix | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | { userName, ... }: | 1 | { flake, userName, ... }: | 
| 2 | 2 | ||
| 3 | { | 3 | { | 
| 4 | home-manager.users.${userName} = { config, ... } : { | 4 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 5 | zsh tmux | ||
| 6 | ]; | ||
| 7 | |||
| 8 | config.home-manager.users.${userName} = { config, ... } : { | ||
| 5 | home.stateVersion = config.home.version.release; | 9 | home.stateVersion = config.home.version.release; | 
| 6 | }; | 10 | }; | 
| 7 | } | 11 | } | 
| diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix index 11f24f31..36b722e4 100644 --- a/accounts/gkleen@sif/default.nix +++ b/accounts/gkleen@sif/default.nix | |||
| @@ -49,10 +49,22 @@ let | |||
| 49 | ]; | 49 | ]; | 
| 50 | }; | 50 | }; | 
| 51 | 51 | ||
| 52 | lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service"; | 52 | # lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service"; | 
| 53 | lockCommand = "${lib.getExe' cfg.programs.quickshell.package "qs"} ipc call Lockscreen setLocked true"; | ||
| 54 | |||
| 55 | editor = pkgs.symlinkJoin { | ||
| 56 | inherit (cfg.services.emacs.package) name; | ||
| 57 | buildInputs = with pkgs; [ makeWrapper ]; | ||
| 58 | paths = [ cfg.services.emacs.package ]; | ||
| 59 | postBuild = '' | ||
| 60 | wrapProgram $out/bin/emacsclient \ | ||
| 61 | --inherit-argv0 \ | ||
| 62 | --add-flags ${lib.escapeShellArg (lib.escapeShellArgs cfg.services.emacs.client.arguments)} | ||
| 63 | ''; | ||
| 64 | }; | ||
| 53 | in { | 65 | in { | 
| 54 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 66 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 55 | mpv yt-dlp (args: import ./xcompose.nix (inputs // args)) | 67 | zsh tmux mpv yt-dlp (args: import ./xcompose.nix (inputs // args)) | 
| 56 | ]; | 68 | ]; | 
| 57 | 69 | ||
| 58 | config = { | 70 | config = { | 
| @@ -60,16 +72,18 @@ in { | |||
| 60 | imports = [ | 72 | imports = [ | 
| 61 | ./libvirt | 73 | ./libvirt | 
| 62 | ./niri | 74 | ./niri | 
| 63 | flakeInputs.nix-index-database.hmModules.nix-index | 75 | ./shell | 
| 76 | ./synadm | ||
| 77 | flakeInputs.nix-index-database.homeModules.nix-index | ||
| 64 | flakeInputs.impermanence.nixosModules.home-manager.impermanence | 78 | flakeInputs.impermanence.nixosModules.home-manager.impermanence | 
| 65 | ]; | 79 | ]; | 
| 66 | 80 | ||
| 67 | home.stateVersion = "20.09"; | 81 | home.stateVersion = "20.09"; | 
| 68 | 82 | ||
| 69 | nixpkgs.config = { | 83 | # nixpkgs.config = { | 
| 70 | allowUnfree = true; | 84 | # allowUnfree = true; | 
| 71 | zathura.useMupdf = false; | 85 | # zathura.useMupdf = false; | 
| 72 | }; | 86 | # }; | 
| 73 | 87 | ||
| 74 | nix.registry = { | 88 | nix.registry = { | 
| 75 | "flk" = { | 89 | "flk" = { | 
| @@ -160,6 +174,7 @@ in { | |||
| 160 | }; | 174 | }; | 
| 161 | }; | 175 | }; | 
| 162 | }; | 176 | }; | 
| 177 | chromium.enable = true; | ||
| 163 | 178 | ||
| 164 | zathura = { | 179 | zathura = { | 
| 165 | enable = true; | 180 | enable = true; | 
| @@ -175,13 +190,93 @@ in { | |||
| 175 | gpu-api = "vulkan"; | 190 | gpu-api = "vulkan"; | 
| 176 | }; | 191 | }; | 
| 177 | 192 | ||
| 178 | zsh.initExtra = '' | 193 | zsh.initContent = let | 
| 179 | source ${./zshrc} | 194 | zshrc = pkgs.resholve.mkDerivation { | 
| 195 | pname = "zshrc"; | ||
| 196 | version = "0.0.0"; | ||
| 197 | |||
| 198 | src = ./zshrc; | ||
| 199 | |||
| 200 | dontUnpack = true; | ||
| 201 | dontConfigure = true; | ||
| 202 | dontBuild = true; | ||
| 203 | |||
| 204 | installPhase = '' | ||
| 205 | mkdir -p $out/share | ||
| 206 | install "$src" $out/share/zshrc | ||
| 207 | ''; | ||
| 208 | |||
| 209 | solutions = { | ||
| 210 | default = { | ||
| 211 | scripts = [ "share/zshrc" ]; | ||
| 212 | interpreter = "none"; | ||
| 213 | inputs = with pkgs; [ | ||
| 214 | coreutils | ||
| 215 | rpm | ||
| 216 | binutils | ||
| 217 | squashfsTools | ||
| 218 | unzip | ||
| 219 | cfg.programs.git.package | ||
| 220 | magickWrapped | ||
| 221 | curl | ||
| 222 | file | ||
| 223 | gnutar | ||
| 224 | cpio | ||
| 225 | magic-wormhole | ||
| 226 | cfg.programs.zsh.package | ||
| 227 | fuse | ||
| 228 | util-linux | ||
| 229 | findutils | ||
| 230 | qrencode | ||
| 231 | tty-clock | ||
| 232 | cfg.programs.jq.package | ||
| 233 | eza | ||
| 234 | less | ||
| 235 | config.systemd.package | ||
| 236 | config.programs.ssh.package | ||
| 237 | gnused | ||
| 238 | miniserve | ||
| 239 | p7zip | ||
| 240 | ]; | ||
| 241 | execer = with pkgs; [ | ||
| 242 | "cannot:${lib.getExe' rpm "rpm2cpio"}" | ||
| 243 | "cannot:${lib.getExe' squashfsTools "unsquashfs"}" | ||
| 244 | "cannot:${lib.getExe' unzip "unzip"}" | ||
| 245 | "cannot:${lib.getExe cfg.programs.git.package}" | ||
| 246 | "cannot:${lib.getExe cpio}" | ||
| 247 | "cannot:${lib.getExe' magic-wormhole "wormhole"}" | ||
| 248 | "cannot:${lib.getExe' fuse "fusermount"}" | ||
| 249 | "cannot:${lib.getExe less}" | ||
| 250 | "cannot:${lib.getExe' config.systemd.package "systemctl"}" | ||
| 251 | "cannot:${lib.getExe config.programs.ssh.package}" | ||
| 252 | "cannot:${lib.getExe' p7zip "7z"}" | ||
| 253 | ]; | ||
| 254 | wrapper = with pkgs; [ | ||
| 255 | "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}" | ||
| 256 | ]; | ||
| 257 | fake = { | ||
| 258 | builtin = ["print"]; | ||
| 259 | external = ["sudo" "umount"]; | ||
| 260 | }; | ||
| 261 | }; | ||
| 262 | }; | ||
| 263 | }; | ||
| 264 | magickWrapped = pkgs.symlinkJoin { | ||
| 265 | inherit (pkgs.imagemagick) name; | ||
| 266 | paths = [ pkgs.imagemagick ]; | ||
| 267 | |||
| 268 | buildInputs = with pkgs; [ makeWrapper ]; | ||
| 269 | postBuild = '' | ||
| 270 | wrapProgram $out/bin/magick \ | ||
| 271 | --prefix PATH : ${lib.makeBinPath (with pkgs; [ ghostscript ])} | ||
| 272 | ''; | ||
| 273 | }; | ||
| 274 | in '' | ||
| 275 | source ${zshrc}/share/zshrc | ||
| 180 | ''; | 276 | ''; | 
| 181 | zsh.dirHashes = let | 277 | zsh.dirHashes = let | 
| 182 | flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs; | 278 | flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs; | 
| 183 | inputNames = { | 279 | inputNames = { | 
| 184 | "nixpkgs" = "nixos"; | ||
| 185 | }; | 280 | }; | 
| 186 | in flakeHashes // { | 281 | in flakeHashes // { | 
| 187 | u2w = "$HOME/projects/uni2work"; | 282 | u2w = "$HOME/projects/uni2work"; | 
| @@ -193,6 +288,16 @@ in { | |||
| 193 | pro = "$HOME/projects/pro"; | 288 | pro = "$HOME/projects/pro"; | 
| 194 | media = "$HOME/media"; | 289 | media = "$HOME/media"; | 
| 195 | }; | 290 | }; | 
| 291 | jq.colors = { | ||
| 292 | arrays = "1;37"; | ||
| 293 | "false" = "0;37"; | ||
| 294 | "null" = "2;37"; | ||
| 295 | numbers = "0;37"; | ||
| 296 | objectKeys = "1;34"; | ||
| 297 | objects = "1;37"; | ||
| 298 | strings = "0;32"; | ||
| 299 | "true" = "0;37"; | ||
| 300 | }; | ||
| 196 | 301 | ||
| 197 | obs-studio = { | 302 | obs-studio = { | 
| 198 | enable = true; | 303 | enable = true; | 
| @@ -202,7 +307,7 @@ in { | |||
| 202 | gh = { | 307 | gh = { | 
| 203 | enable = true; | 308 | enable = true; | 
| 204 | settings = { | 309 | settings = { | 
| 205 | editor = lib.getExe' config.home-manager.users.${userName}.programs.emacs.package "emacsclient"; | 310 | editor = lib.getExe' editor "emacsclient"; | 
| 206 | gitProtocol = "ssh"; | 311 | gitProtocol = "ssh"; | 
| 207 | }; | 312 | }; | 
| 208 | }; | 313 | }; | 
| @@ -228,16 +333,10 @@ in { | |||
| 228 | # notify_on_cmd_finish = "invisible 120"; | 333 | # notify_on_cmd_finish = "invisible 120"; | 
| 229 | }; | 334 | }; | 
| 230 | keybindings = { | 335 | keybindings = { | 
| 231 | "kitty_mod+n" = "detach_window"; | 336 | "kitty_mod+n" = "new_os_window_with_cwd"; | 
| 232 | "kitty_mod+m" = "detach_window ask"; | 337 | "kitty_mod+m" = "detach_window ask"; | 
| 233 | }; | 338 | "kitty_mod+enter" = "new_window_with_cwd"; | 
| 234 | }; | 339 | "kitty_mod+t" = "new_tab_with_cwd"; | 
| 235 | wpaperd = { | ||
| 236 | enable = true; | ||
| 237 | settings.default = { | ||
| 238 | path = "~/.wallpapers"; | ||
| 239 | duration = "15m"; | ||
| 240 | mode = "center"; | ||
| 241 | }; | 340 | }; | 
| 242 | }; | 341 | }; | 
| 243 | fuzzel = { | 342 | fuzzel = { | 
| @@ -250,7 +349,7 @@ in { | |||
| 250 | font = "Fira Sans"; | 349 | font = "Fira Sans"; | 
| 251 | }; | 350 | }; | 
| 252 | colors = { | 351 | colors = { | 
| 253 | background = "000000aa"; | 352 | background = "000000cc"; | 
| 254 | text = "cdd6f4ff"; | 353 | text = "cdd6f4ff"; | 
| 255 | match = "94e2d5ff"; | 354 | match = "94e2d5ff"; | 
| 256 | selection = "585b70ff"; | 355 | selection = "585b70ff"; | 
| @@ -267,15 +366,28 @@ in { | |||
| 267 | enable = true; | 366 | enable = true; | 
| 268 | extraAbbreviations = ["i.A." "d.h." "D.h." "gdw."]; | 367 | extraAbbreviations = ["i.A." "d.h." "D.h." "gdw."]; | 
| 269 | }; | 368 | }; | 
| 369 | nushell = { | ||
| 370 | enable = true; | ||
| 371 | settings.show_banner = false; | ||
| 372 | }; | ||
| 373 | fd.enable = true; | ||
| 270 | }; | 374 | }; | 
| 271 | 375 | ||
| 272 | services = { | 376 | services = { | 
| 377 | wpaperd = { | ||
| 378 | enable = false; | ||
| 379 | settings.default = { | ||
| 380 | path = "~/.wallpapers"; | ||
| 381 | duration = "15m"; | ||
| 382 | mode = "center"; | ||
| 383 | }; | ||
| 384 | }; | ||
| 273 | emacs = { | 385 | emacs = { | 
| 274 | enable = true; | 386 | enable = true; | 
| 275 | socketActivation.enable = true; | 387 | socketActivation.enable = true; | 
| 276 | client = { | 388 | client = { | 
| 277 | enable = true; | 389 | enable = true; | 
| 278 | arguments = mkForce ["--reuse-frame" "--alternate-editor" "\"\""]; | 390 | arguments = mkForce ["--create-frame" "--alternate-editor" (lib.getExe cfg.services.emacs.package)]; | 
| 279 | }; | 391 | }; | 
| 280 | }; | 392 | }; | 
| 281 | gpg-agent = { | 393 | gpg-agent = { | 
| @@ -338,20 +450,6 @@ in { | |||
| 338 | serverUrl = "https://etesync.yggdrasil.li"; | 450 | serverUrl = "https://etesync.yggdrasil.li"; | 
| 339 | }; | 451 | }; | 
| 340 | 452 | ||
| 341 | swayidle = { | ||
| 342 | enable = true; | ||
| 343 | events = [ | ||
| 344 | { event = "before-sleep"; command = lockCommand; } | ||
| 345 | { event = "lock"; command = lockCommand; } | ||
| 346 | ]; | ||
| 347 | timeouts = [ | ||
| 348 | { timeout = 600; command = lockCommand; } | ||
| 349 | ]; | ||
| 350 | extraArgs = [ | ||
| 351 | "-w" | ||
| 352 | "idlehint" "30" | ||
| 353 | ]; | ||
| 354 | }; | ||
| 355 | poweralertd.enable = true; | 453 | poweralertd.enable = true; | 
| 356 | }; | 454 | }; | 
| 357 | 455 | ||
| @@ -383,6 +481,15 @@ in { | |||
| 383 | name = "Paper-Mono-Dark"; | 481 | name = "Paper-Mono-Dark"; | 
| 384 | }; | 482 | }; | 
| 385 | }; | 483 | }; | 
| 484 | qt.enable = true; | ||
| 485 | qt.platformTheme.name = "gtk"; | ||
| 486 | |||
| 487 | qt.kde.settings = { | ||
| 488 | kwalletrc = { | ||
| 489 | KSecretD.Enabled = false; | ||
| 490 | Wallet."Default Wallet" = "store"; | ||
| 491 | }; | ||
| 492 | }; | ||
| 386 | 493 | ||
| 387 | xsession.preferStatusNotifierItems = true; | 494 | xsession.preferStatusNotifierItems = true; | 
| 388 | 495 | ||
| @@ -392,20 +499,19 @@ in { | |||
| 392 | packages = with pkgs; [ | 499 | packages = with pkgs; [ | 
| 393 | fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs | 500 | fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs | 
| 394 | mumble pulseaudio-ctl pamixer libnotify screen-message | 501 | mumble pulseaudio-ctl pamixer libnotify screen-message | 
| 395 | wrappedYTMDesktop libsForQt5.qt5ct playerctl evince | 502 | wrappedYTMDesktop libsForQt5.qt5ct playerctl evince papers | 
| 396 | thunderbird zoom-us xdg-desktop-portal steam steam-run | 503 | thunderbird zoom-us xdg-desktop-portal steam steam-run | 
| 397 | wireshark virt-manager rclone cached-nix-shell worktime | 504 | wireshark virt-manager rclone cached-nix-shell worktime | 
| 398 | fira-code-symbols libreoffice xournalpp google-chrome | 505 | fira-code-symbols libreoffice xournalpp | 
| 399 | nixos-shell virt-viewer freerdp gnome-icon-theme | 506 | nixos-shell virt-viewer freerdp gnome-icon-theme | 
| 400 | paper-icon-theme sshpassSecret weechat element-desktop | 507 | paper-icon-theme sshpassSecret weechat element-desktop | 
| 401 | flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs | 508 | sieve-connect gimp3 inkscape udiskie glab nitrokey-app | 
| 402 | sieve-connect gimp inkscape udiskie glab nitrokey-app | ||
| 403 | pynitrokey gtklock wlrctl remmina openscad spice-record | 509 | pynitrokey gtklock wlrctl remmina openscad spice-record | 
| 404 | libguestfs-with-appliance nerd-fonts.fira-mono | 510 | nerd-fonts.fira-mono | 
| 405 | nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts | 511 | nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts | 
| 406 | swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE])) | 512 | swtpm (hunspell.withDicts (dicts: with dicts; [en_GB-large de_DE])) | 
| 407 | # synadm | 513 | libation libqalculate | 
| 408 | ]; | 514 | ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; }); | 
| 409 | 515 | ||
| 410 | file = { | 516 | file = { | 
| 411 | ".backup-munin".source = ./backup-patterns; | 517 | ".backup-munin".source = ./backup-patterns; | 
| @@ -422,15 +528,12 @@ in { | |||
| 422 | sessionVariables = { | 528 | sessionVariables = { | 
| 423 | # GDK_SCALE = 96.0 / 282.0; | 529 | # GDK_SCALE = 96.0 / 282.0; | 
| 424 | # QT_AUTO_SCREEN_SCALE_FACTOR = 1; | 530 | # QT_AUTO_SCREEN_SCALE_FACTOR = 1; | 
| 425 | QT_QPA_PLATFORMTHEME = "qt5ct"; | 531 | QT_QPA_PLATFORMTHEME = lib.mkForce "gtk3"; | 
| 426 | LIBVIRT_DEFAULT_URI = "qemu:///system"; | 532 | LIBVIRT_DEFAULT_URI = "qemu:///system"; | 
| 427 | STACK_XDG = 1; | 533 | STACK_XDG = 1; | 
| 428 | EDITOR = pkgs.writeShellScript "editor" '' | 534 | EDITOR = lib.getExe' editor "emacsclient"; | 
| 429 | args=("--reuse-frame" "--alternate-editor" "") | ||
| 430 | args+=("$@") | ||
| 431 | exec -a emacsclient ${lib.getExe' cfg.services.emacs.package "emacsclient"} "''${args[@]}" | ||
| 432 | ''; | ||
| 433 | RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone"; | 535 | RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone"; | 
| 536 | SYSTEMD_TINT_BACKGROUND = "false"; | ||
| 434 | }; | 537 | }; | 
| 435 | 538 | ||
| 436 | extraProfileCommands = '' | 539 | extraProfileCommands = '' | 
| @@ -467,13 +570,21 @@ in { | |||
| 467 | General = { | 570 | General = { | 
| 468 | dot_as_separator = 0; | 571 | dot_as_separator = 0; | 
| 469 | }; | 572 | }; | 
| 573 | Mode = { | ||
| 574 | calculate_as_you_type = 1; | ||
| 575 | }; | ||
| 470 | }; | 576 | }; | 
| 471 | }; | 577 | }; | 
| 472 | "emacs/init.el".source = ./emacs.el; | 578 | "emacs/init.el".source = pkgs.substitute { | 
| 473 | "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = '' | 579 | src = ./emacs.el; | 
| 474 | [Unit] | 580 | substitutions = [ | 
| 475 | After=graphical-session.target | 581 | "--subst-var-by" "ksshaskpass" (lib.getExe pkgs.kdePackages.ksshaskpass) | 
| 476 | ''; | 582 | ]; | 
| 583 | }; | ||
| 584 | # "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = '' | ||
| 585 | # [Unit] | ||
| 586 | # After=graphical-session.target | ||
| 587 | # ''; | ||
| 477 | "systemd/user/home-manager.service.d/before-graphical-session.conf".text = '' | 588 | "systemd/user/home-manager.service.d/before-graphical-session.conf".text = '' | 
| 478 | [Unit] | 589 | [Unit] | 
| 479 | Before=graphical-session-pre.target | 590 | Before=graphical-session-pre.target | 
| @@ -487,6 +598,8 @@ in { | |||
| 487 | xdg.dataFile = { | 598 | xdg.dataFile = { | 
| 488 | "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service"; | 599 | "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service"; | 
| 489 | "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service"; | 600 | "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service"; | 
| 601 | "dbus-1/services/org.kde.kwalletd6.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd6.service"; | ||
| 602 | "dbus-1/services/org.kde.kwalletd5.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd5.service"; | ||
| 490 | "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { | 603 | "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { | 
| 491 | inherit (sources.emoji-data) pname src; | 604 | inherit (sources.emoji-data) pname src; | 
| 492 | version = lib.removePrefix "v" sources.emoji-data.version; | 605 | version = lib.removePrefix "v" sources.emoji-data.version; | 
| @@ -574,11 +687,11 @@ in { | |||
| 574 | exec -- \ | 687 | exec -- \ | 
| 575 | ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \ | 688 | ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \ | 
| 576 | --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ | 689 | --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ | 
| 577 | --property 'Environment=DSCP=46' \ | 690 | -E DSCP=46 -E NIXOS_OZONE_WL \ | 
| 578 | -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \ | 691 | -- ${lib.getExe pkgs.dscp} ${lib.getExe cfg.programs.chromium.package} \ | 
| 579 | --class=Rainbow \ | 692 | --class=Rainbow \ | 
| 580 | --kiosk "https://web.openrainbow.com" \ | 693 | --app="https://web.openrainbow.com" \ | 
| 581 | --user-data-dir=''${HOME}/.config/google-chrome-rainbow | 694 | --user-data-dir=''${HOME}/.config/chromium-rainbow | 
| 582 | ''); | 695 | ''); | 
| 583 | icon = pkgs.fetchurl { | 696 | icon = pkgs.fetchurl { | 
| 584 | url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg"; | 697 | url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg"; | 
| @@ -588,6 +701,53 @@ in { | |||
| 588 | StartupWMClass = "Rainbow"; | 701 | StartupWMClass = "Rainbow"; | 
| 589 | }; | 702 | }; | 
| 590 | }; | 703 | }; | 
| 704 | kimai = { | ||
| 705 | name = "Kimai"; | ||
| 706 | exec = toString (pkgs.writeShellScript "kimai" '' | ||
| 707 | exec -- \ | ||
| 708 | ${lib.getExe cfg.programs.chromium.package} \ | ||
| 709 | --class=Kimai \ | ||
| 710 | --app="https://kimai.yggdrasil.li" \ | ||
| 711 | --user-data-dir=''${HOME}/.config/chromium-kimai | ||
| 712 | ''); | ||
| 713 | icon = pkgs.fetchurl { | ||
| 714 | url = "https://www.kimai.org/images/kimai_logo.png"; | ||
| 715 | hash = "sha256-lnlOttzR2SwXA70R+egJUkeKr4U5V0avqTk8uX4bqfs="; | ||
| 716 | }; | ||
| 717 | settings = { | ||
| 718 | StartupWMClass = "Kimai"; | ||
| 719 | StartupNotify = "true"; | ||
| 720 | }; | ||
| 721 | }; | ||
| 722 | audiobookshelf = { | ||
| 723 | name = "Audiobookshelf"; | ||
| 724 | exec = toString (pkgs.writeShellScript "audiobookshelf" '' | ||
| 725 | exec -- \ | ||
| 726 | ${lib.getExe cfg.programs.chromium.package} \ | ||
| 727 | --class=Audiobookshelf \ | ||
| 728 | --app="https://audiobookshelf.yggdrasil.li" \ | ||
| 729 | --user-data-dir=''${HOME}/.config/chromium-audiobookshelf | ||
| 730 | ''); | ||
| 731 | icon = pkgs.fetchurl { | ||
| 732 | url = "https://www.audiobookshelf.org/Logo.png"; | ||
| 733 | hash = "sha256-JGPk+WNT1C4DC4lSMb0K0YmAMT5LvmSOeO0QRzkc7Lk="; | ||
| 734 | }; | ||
| 735 | settings = { | ||
| 736 | StartupWMClass = "Audiobookshelf"; | ||
| 737 | StartupNotify = "true"; | ||
| 738 | }; | ||
| 739 | }; | ||
| 740 | thunderbird-lmu = { | ||
| 741 | name = "Thunderbird (LMU)"; | ||
| 742 | exec = "thunderbird --name thunderbird -P lmu %U"; | ||
| 743 | icon = "thunderbird"; | ||
| 744 | genericName = "Email Client"; | ||
| 745 | categories = [ "Network" "Chat" "Email" "Feed" "GTK" "News" ]; | ||
| 746 | settings = { | ||
| 747 | StartupWMClass = "thunderbird"; | ||
| 748 | StartupNotify = "true"; | ||
| 749 | }; | ||
| 750 | }; | ||
| 591 | }; | 751 | }; | 
| 592 | 752 | ||
| 593 | fonts = { | 753 | fonts = { | 
| diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el index 5cee16b0..3beefba6 100644 --- a/accounts/gkleen@sif/emacs.el +++ b/accounts/gkleen@sif/emacs.el | |||
| @@ -51,7 +51,7 @@ | |||
| 51 | 51 | ||
| 52 | ;; (require 'scratch) | 52 | ;; (require 'scratch) | 
| 53 | (global-set-key (kbd "C-x B") 'scratch-create) | 53 | (global-set-key (kbd "C-x B") 'scratch-create) | 
| 54 | (setq initial-major-mode 'scratch-mode) | 54 | ;; (setq initial-major-mode 'scratch-mode) | 
| 55 | (setq initial-scratch-message "") | 55 | (setq initial-scratch-message "") | 
| 56 | 56 | ||
| 57 | (global-set-key (kbd "C-x K") 'kill-current-buffer) | 57 | (global-set-key (kbd "C-x K") 'kill-current-buffer) | 
| @@ -254,3 +254,5 @@ necessarily running." | |||
| 254 | (bind-key "C-x C-m" #'move-file) | 254 | (bind-key "C-x C-m" #'move-file) | 
| 255 | 255 | ||
| 256 | (let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock)) | 256 | (let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock)) | 
| 257 | (setenv "SSH_ASKPASS_REQUIRE" "prefer") | ||
| 258 | (setenv "SSH_ASKPASS" "@ksshaskpass@") | ||
| diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix index 216a98ea..5ae372c1 100644 --- a/accounts/gkleen@sif/niri/default.nix +++ b/accounts/gkleen@sif/niri/default.nix | |||
| @@ -3,13 +3,10 @@ let | |||
| 3 | cfg = config.programs.niri; | 3 | cfg = config.programs.niri; | 
| 4 | 4 | ||
| 5 | kdl = flakeInputs.niri-flake.lib.kdl; | 5 | kdl = flakeInputs.niri-flake.lib.kdl; | 
| 6 | sleaf = name: arg: kdl.node name [arg] []; | ||
| 6 | 7 | ||
| 7 | niri = cfg.package; | 8 | niri = cfg.package; | 
| 8 | terminal = lib.getExe config.programs.kitty.package; | 9 | terminal = lib.getExe config.programs.kitty.package; | 
| 9 | makoctl = lib.getExe' config.services.mako.package "makoctl"; | ||
| 10 | loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; | ||
| 11 | systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; | ||
| 12 | swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client"; | ||
| 13 | 10 | ||
| 14 | focus_or_spawn = pkgs.writeShellApplication { | 11 | focus_or_spawn = pkgs.writeShellApplication { | 
| 15 | name = "focus-or-spawn"; | 12 | name = "focus-or-spawn"; | 
| @@ -35,7 +32,11 @@ let | |||
| 35 | if jq -e '.is_focused' <<<"$window_json" >/dev/null; then | 32 | if jq -e '.is_focused' <<<"$window_json" >/dev/null; then | 
| 36 | niri msg action focus-workspace-previous | 33 | niri msg action focus-workspace-previous | 
| 37 | else | 34 | else | 
| 38 | niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" | 35 | 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 | 
| 36 | niri msg action focus-workspace "$workspace_name" | ||
| 37 | else | ||
| 38 | niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" | ||
| 39 | fi | ||
| 39 | fi | 40 | fi | 
| 40 | exit 0 | 41 | exit 0 | 
| 41 | fi | 42 | fi | 
| @@ -45,7 +46,6 @@ let | |||
| 45 | ''; | 46 | ''; | 
| 46 | }; | 47 | }; | 
| 47 | focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); | 48 | focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); | 
| 48 | focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")''; | ||
| 49 | 49 | ||
| 50 | with_adjacent_workspace = pkgs.writeShellApplication { | 50 | with_adjacent_workspace = pkgs.writeShellApplication { | 
| 51 | name = "with-adjacent-workspace"; | 51 | name = "with-adjacent-workspace"; | 
| @@ -84,7 +84,7 @@ let | |||
| 84 | }; | 84 | }; | 
| 85 | with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; | 85 | with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; | 
| 86 | focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; | 86 | focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; | 
| 87 | move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; | 87 | move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}''; | 
| 88 | 88 | ||
| 89 | with_unnamed_workspace = pkgs.writeShellApplication { | 89 | with_unnamed_workspace = pkgs.writeShellApplication { | 
| 90 | name = "with-unnamed-workspace"; | 90 | name = "with-unnamed-workspace"; | 
| @@ -131,7 +131,7 @@ let | |||
| 131 | 131 | ||
| 132 | windows_json="$(niri msg -j windows)" | 132 | windows_json="$(niri msg -j windows)" | 
| 133 | active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" | 133 | active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" | 
| 134 | window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --log-level=warning --dmenu --index)" | 134 | 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)" | 
| 135 | # shellcheck disable=SC2016 | 135 | # shellcheck disable=SC2016 | 
| 136 | window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" | 136 | window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" | 
| 137 | 137 | ||
| @@ -141,13 +141,26 @@ let | |||
| 141 | ''; | 141 | ''; | 
| 142 | }; | 142 | }; | 
| 143 | with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); | 143 | with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); | 
| 144 | in { | ||
| 145 | imports = [ | ||
| 146 | ./waybar.nix | ||
| 147 | ./mako.nix | ||
| 148 | ./swayosd.nix | ||
| 149 | ]; | ||
| 150 | 144 | ||
| 145 | with_predicate_window = pred: pkgs.writeShellApplication { | ||
| 146 | name = "with-predicate-window"; | ||
| 147 | runtimeInputs = [ niri pkgs.gojq pkgs.socat ]; | ||
| 148 | text = '' | ||
| 149 | action="$1" | ||
| 150 | shift | ||
| 151 | |||
| 152 | windows_json="$(niri msg -j windows)" | ||
| 153 | window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")" | ||
| 154 | |||
| 155 | [[ -z "$window_json" || $window_json = "null" ]] && exit 1 | ||
| 156 | |||
| 157 | jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET" | ||
| 158 | ''; | ||
| 159 | }; | ||
| 160 | |||
| 161 | with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent")); | ||
| 162 | with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused")); | ||
| 163 | in { | ||
| 151 | options = { | 164 | options = { | 
| 152 | programs.niri.scratchspaces = lib.mkOption { | 165 | programs.niri.scratchspaces = lib.mkOption { | 
| 153 | type = lib.types.listOf (lib.types.submodule ({ config, ... }: { | 166 | type = lib.types.listOf (lib.types.submodule ({ config, ... }: { | 
| @@ -171,6 +184,17 @@ in { | |||
| 171 | type = lib.types.nullOr lib.types.str; | 184 | type = lib.types.nullOr lib.types.str; | 
| 172 | default = null; | 185 | default = null; | 
| 173 | }; | 186 | }; | 
| 187 | moveKey = lib.mkOption { | ||
| 188 | type = lib.types.nullOr lib.types.str; | ||
| 189 | default = let | ||
| 190 | keys = lib.splitString "+" config.key; | ||
| 191 | defMoveKey = lib.concatStringsSep "+" (lib.flatten [ | ||
| 192 | (lib.take (lib.length keys - 1) keys) | ||
| 193 | ["Shift"] | ||
| 194 | (lib.takeEnd 1 keys) | ||
| 195 | ]); | ||
| 196 | in if config.key == null then null else defMoveKey; | ||
| 197 | }; | ||
| 174 | spawn = lib.mkOption { | 198 | spawn = lib.mkOption { | 
| 175 | type = lib.types.nullOr (lib.types.listOf lib.types.str); | 199 | type = lib.types.nullOr (lib.types.listOf lib.types.str); | 
| 176 | default = null; | 200 | default = null; | 
| @@ -197,36 +221,7 @@ in { | |||
| 197 | }; | 221 | }; | 
| 198 | 222 | ||
| 199 | config = { | 223 | config = { | 
| 200 | systemd.user.services.xwayland-satellite = { | 224 | home.packages = [ pkgs.xwayland-satellite-unstable ]; | 
| 201 | Unit = { | ||
| 202 | BindsTo = [ "graphical-session.target" ]; | ||
| 203 | PartOf = [ "graphical-session.target" ]; | ||
| 204 | After = [ "graphical-session.target" ]; | ||
| 205 | Requisite = [ "graphical-session.target" ]; | ||
| 206 | }; | ||
| 207 | Service = { | ||
| 208 | Type = "notify"; | ||
| 209 | NotifyAccess = "all"; | ||
| 210 | Environment = [ "DISPLAY=:0" ]; | ||
| 211 | ExecStart = ''${lib.getExe pkgs.xwayland-satellite-unstable} ''${DISPLAY}''; | ||
| 212 | ExecStartPre = "${systemctl} --user import-environment DISPLAY"; | ||
| 213 | StandardOutput = "journal"; | ||
| 214 | }; | ||
| 215 | Install = { | ||
| 216 | WantedBy = [ "graphical-session.target" ]; | ||
| 217 | }; | ||
| 218 | }; | ||
| 219 | |||
| 220 | services.swayidle = { | ||
| 221 | events = [ | ||
| 222 | { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; } | ||
| 223 | ]; | ||
| 224 | timeouts = [ | ||
| 225 | { timeout = 540; | ||
| 226 | command = "${lib.getExe niri} msg action power-off-monitors"; | ||
| 227 | } | ||
| 228 | ]; | ||
| 229 | }; | ||
| 230 | 225 | ||
| 231 | systemd.user.sockets.niri-workspace-history = { | 226 | systemd.user.sockets.niri-workspace-history = { | 
| 232 | Socket = { | 227 | Socket = { | 
| @@ -245,11 +240,11 @@ in { | |||
| 245 | Service = { | 240 | Service = { | 
| 246 | Type = "simple"; | 241 | Type = "simple"; | 
| 247 | Sockets = [ "niri-workspace-history.socket" ]; | 242 | Sockets = [ "niri-workspace-history.socket" ]; | 
| 248 | ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' | 243 | ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } '' | 
| 249 | import os | 244 | import os | 
| 250 | import socket | 245 | import socket | 
| 251 | import json | 246 | import json | 
| 252 | import sys | 247 | # import sys | 
| 253 | from collections import defaultdict | 248 | from collections import defaultdict | 
| 254 | from threading import Thread, Lock | 249 | from threading import Thread, Lock | 
| 255 | from socketserver import StreamRequestHandler, ThreadingTCPServer | 250 | from socketserver import StreamRequestHandler, ThreadingTCPServer | 
| @@ -273,11 +268,9 @@ in { | |||
| 273 | workspaces = list() | 268 | workspaces = list() | 
| 274 | 269 | ||
| 275 | def focus_workspace(output, workspace): | 270 | def focus_workspace(output, workspace): | 
| 276 | global workspace_history, history_lock | ||
| 277 | |||
| 278 | with history_lock: | 271 | with history_lock: | 
| 279 | workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 | 272 | workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] | 
| 280 | print(json.dumps(workspace_history), file=sys.stderr) | 273 | # print(json.dumps(workspace_history), file=sys.stderr) | 
| 281 | 274 | ||
| 282 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | 275 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | 
| 283 | sock.connect(os.environ["NIRI_SOCKET"]) | 276 | sock.connect(os.environ["NIRI_SOCKET"]) | 
| @@ -299,16 +292,14 @@ in { | |||
| 299 | 292 | ||
| 300 | class RequestHandler(StreamRequestHandler): | 293 | class RequestHandler(StreamRequestHandler): | 
| 301 | def handle(self): | 294 | def handle(self): | 
| 302 | global workspace_history, history_lock | 295 | with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: | 
| 303 | |||
| 304 | with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 | ||
| 305 | with history_lock: | 296 | with history_lock: | 
| 306 | json.dump(workspace_history, out) | 297 | json.dump(workspace_history, out) | 
| 307 | 298 | ||
| 308 | 299 | ||
| 309 | class Server(ThreadingTCPServer): | 300 | class Server(ThreadingTCPServer): | 
| 310 | def __init__(self): | 301 | def __init__(self): | 
| 311 | ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 | 302 | ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) | 
| 312 | self.socket = socket.fromfd(3, self.address_family, self.socket_type) | 303 | self.socket = socket.fromfd(3, self.address_family, self.socket_type) | 
| 313 | 304 | ||
| 314 | 305 | ||
| @@ -334,6 +325,79 @@ in { | |||
| 334 | ''; | 325 | ''; | 
| 335 | }; | 326 | }; | 
| 336 | }; | 327 | }; | 
| 328 | systemd.user.services.niri-workspace-sort = { | ||
| 329 | Unit = { | ||
| 330 | BindsTo = [ "niri.service" ]; | ||
| 331 | After = [ "niri.service" ]; | ||
| 332 | }; | ||
| 333 | Install = { | ||
| 334 | WantedBy = [ "niri.service" ]; | ||
| 335 | }; | ||
| 336 | Service = { | ||
| 337 | Type = "simple"; | ||
| 338 | ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } '' | ||
| 339 | import os | ||
| 340 | import sys | ||
| 341 | import socket | ||
| 342 | import json | ||
| 343 | |||
| 344 | outputs = None | ||
| 345 | only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}} | ||
| 346 | |||
| 347 | |||
| 348 | class Niri(socket.socket): | ||
| 349 | def __init__(self): | ||
| 350 | super().__init__(socket.AF_UNIX, socket.SOCK_STREAM) | ||
| 351 | super().connect(os.environ["NIRI_SOCKET"]) | ||
| 352 | self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8') | ||
| 353 | |||
| 354 | def cmd(self, obj): | ||
| 355 | print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh) | ||
| 356 | |||
| 357 | def event_stream(self): | ||
| 358 | self.cmd("EventStream") | ||
| 359 | return self.fh | ||
| 360 | |||
| 361 | |||
| 362 | with Niri() as niri, Niri().event_stream() as niri_stream: | ||
| 363 | for line in niri_stream: | ||
| 364 | workspaces = None | ||
| 365 | if line_json := json.loads(line): | ||
| 366 | if "WorkspacesChanged" in line_json: | ||
| 367 | workspaces = line_json["WorkspacesChanged"]["workspaces"] | ||
| 368 | |||
| 369 | if workspaces is None: | ||
| 370 | continue | ||
| 371 | |||
| 372 | old_outputs = outputs | ||
| 373 | outputs = {ws["output"] for ws in workspaces} | ||
| 374 | if old_outputs is None: | ||
| 375 | print("Initial outputs: {}".format(outputs), file=sys.stderr) | ||
| 376 | continue | ||
| 377 | |||
| 378 | new_outputs = outputs - old_outputs | ||
| 379 | if not new_outputs: | ||
| 380 | continue | ||
| 381 | print("New outputs: {}".format(new_outputs), file=sys.stderr) | ||
| 382 | |||
| 383 | relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces)) | ||
| 384 | target_output = next(iter(outputs - set(only.keys()))) | ||
| 385 | if not target_output: | ||
| 386 | continue | ||
| 387 | for ws in relevant_workspaces: | ||
| 388 | ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"]) | ||
| 389 | if ws["output"] not in set(only.keys()): | ||
| 390 | continue | ||
| 391 | if ws_ident in only[ws["output"]]: | ||
| 392 | continue | ||
| 393 | |||
| 394 | print("{} -> {}".format(ws_ident, target_output), file=sys.stderr) | ||
| 395 | niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}}) | ||
| 396 | ''; | ||
| 397 | Restart = "on-failure"; | ||
| 398 | RestartSec = 10; | ||
| 399 | }; | ||
| 400 | }; | ||
| 337 | 401 | ||
| 338 | programs.niri.scratchspaces = [ | 402 | programs.niri.scratchspaces = [ | 
| 339 | { name = "pwctl"; | 403 | { name = "pwctl"; | 
| @@ -347,8 +411,8 @@ in { | |||
| 347 | { title = "^Access Request.*"; } | 411 | { title = "^Access Request.*"; } | 
| 348 | { title = ".*Passkey credentials$"; } | 412 | { title = ".*Passkey credentials$"; } | 
| 349 | ]; | 413 | ]; | 
| 350 | windowRuleExtra = [ | 414 | windowRuleExtra = with kdl; [ | 
| 351 | (kdl.leaf "open-focused" false) | 415 | (sleaf "open-focused" false) | 
| 352 | ]; | 416 | ]; | 
| 353 | key = "Mod+Control+P"; | 417 | key = "Mod+Control+P"; | 
| 354 | app-id = "org.keepassxc.KeePassXC"; | 418 | app-id = "org.keepassxc.KeePassXC"; | 
| @@ -375,6 +439,20 @@ in { | |||
| 375 | app-id = "com.github.wwmm.easyeffects"; | 439 | app-id = "com.github.wwmm.easyeffects"; | 
| 376 | spawn = [ "easyeffects" ]; | 440 | spawn = [ "easyeffects" ]; | 
| 377 | } | 441 | } | 
| 442 | { name = "time"; | ||
| 443 | key = "Mod+Control+K"; | ||
| 444 | app-id = "chrome-kimai.yggdrasil.li__-Default"; | ||
| 445 | spawn = [ (toString (pkgs.resholve.writeScript "kimai" { | ||
| 446 | interpreter = pkgs.runtimeShell; | ||
| 447 | inputs = [ pkgs.dex ]; | ||
| 448 | execer = [ "cannot:${lib.getExe pkgs.dex}" ]; | ||
| 449 | } '' | ||
| 450 | exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop | ||
| 451 | '')) ]; | ||
| 452 | windowRuleExtra = with kdl; [ | ||
| 453 | (sleaf "block-out-from" "screencast") | ||
| 454 | ]; | ||
| 455 | } | ||
| 378 | ]; | 456 | ]; | 
| 379 | programs.niri.config = | 457 | programs.niri.config = | 
| 380 | let | 458 | let | 
| @@ -384,10 +462,12 @@ in { | |||
| 384 | then v | 462 | then v | 
| 385 | else null; | 463 | else null; | 
| 386 | opt-props = lib.filterAttrs (lib.const (value: value != null)); | 464 | opt-props = lib.filterAttrs (lib.const (value: value != null)); | 
| 465 | normalize-nodes = nodes: lib.remove null (lib.flatten nodes); | ||
| 387 | in | 466 | in | 
| 388 | [ (flag "prefer-no-csd") | 467 | normalize-nodes [ | 
| 468 | (flag "prefer-no-csd") | ||
| 389 | 469 | ||
| 390 | (leaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png") | 470 | (sleaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png") | 
| 391 | 471 | ||
| 392 | (plain "hotkey-overlay" [ | 472 | (plain "hotkey-overlay" [ | 
| 393 | (flag "skip-at-startup") | 473 | (flag "skip-at-startup") | 
| @@ -395,80 +475,88 @@ in { | |||
| 395 | 475 | ||
| 396 | (plain "input" [ | 476 | (plain "input" [ | 
| 397 | (plain "keyboard" [ | 477 | (plain "keyboard" [ | 
| 398 | (leaf "repeat-delay" 300) | 478 | (sleaf "repeat-delay" 300) | 
| 399 | (leaf "repeat-rate" 50) | 479 | (sleaf "repeat-rate" 50) | 
| 400 | 480 | ||
| 401 | (plain "xkb" [ | 481 | (plain "xkb" [ | 
| 402 | (leaf "layout" "us,us") | 482 | (sleaf "layout" "us,us") | 
| 403 | (leaf "variant" "dvp,") | 483 | (sleaf "variant" "dvp,") | 
| 404 | (leaf "options" "compose:caps,grp:win_space_toggle") | 484 | (sleaf "options" "compose:caps,grp:win_space_toggle") | 
| 405 | ]) | 485 | ]) | 
| 406 | ]) | 486 | ]) | 
| 407 | 487 | ||
| 408 | (flag "workspace-auto-back-and-forth") | 488 | (flag "workspace-auto-back-and-forth") | 
| 409 | # (leaf "focus-follows-mouse" {}) | 489 | # (sleaf "focus-follows-mouse" {}) | 
| 410 | # (flag "warp-mouse-to-focus") | 490 | # (flag "warp-mouse-to-focus") | 
| 411 | 491 | ||
| 412 | # (plain "touchpad" [ (flag "off") ]) | 492 | # (plain "touchpad" [ (flag "off") ]) | 
| 413 | (plain "trackball" [ | 493 | (plain "trackball" [ | 
| 414 | (leaf "scroll-method" "on-button-down") | 494 | (sleaf "scroll-method" "on-button-down") | 
| 415 | (leaf "scroll-button" 278) | 495 | (sleaf "scroll-button" 278) | 
| 416 | ]) | 496 | ]) | 
| 417 | (plain "touch" [ | 497 | (plain "touch" [ | 
| 418 | (leaf "map-to-output" "eDP-1") | 498 | (sleaf "map-to-output" "eDP-1") | 
| 419 | ]) | 499 | ]) | 
| 420 | ]) | 500 | ]) | 
| 421 | 501 | ||
| 422 | (plain "environment" (lib.mapAttrsToList leaf { | 502 | (plain "gestures" [ | 
| 503 | (plain "hot-corners" [(flag "off")]) | ||
| 504 | ]) | ||
| 505 | |||
| 506 | (plain "environment" (lib.mapAttrsToList sleaf { | ||
| 423 | NIXOS_OZONE_WL = "1"; | 507 | NIXOS_OZONE_WL = "1"; | 
| 424 | QT_QPA_PLATFORM = "wayland"; | 508 | QT_QPA_PLATFORM = "wayland"; | 
| 425 | QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; | 509 | QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; | 
| 426 | GDK_BACKEND = "wayland"; | 510 | GDK_BACKEND = "wayland"; | 
| 427 | SDL_VIDEODRIVER = "wayland"; | 511 | SDL_VIDEODRIVER = "wayland"; | 
| 428 | DISPLAY = ":0"; | 512 | DISPLAY = ":0"; | 
| 513 | ELECTRON_OZONE_PLATFORM_HINT = "auto"; | ||
| 514 | SSH_ASKPASS_REQUIRE = "prefer"; | ||
| 515 | SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass; | ||
| 516 | SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass; | ||
| 429 | })) | 517 | })) | 
| 430 | 518 | ||
| 431 | (node "output" "eDP-1" [ | 519 | (node "output" ["eDP-1"] [ | 
| 432 | (leaf "scale" 1.5) | 520 | (sleaf "scale" 1.5) | 
| 433 | (leaf "position" { x = 0; y = 0; }) | 521 | (sleaf "position" { x = 0; y = 0; }) | 
| 434 | ]) | 522 | ]) | 
| 435 | (node "output" "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" [ | 523 | (node "output" ["Ancor Communications Inc ASUS PB287Q 0x0000DD9B"] [ | 
| 436 | (leaf "scale" 1.5) | 524 | (sleaf "scale" 1.5) | 
| 437 | (leaf "position" { x = 2560; y = 0; }) | 525 | (sleaf "position" { x = 2560; y = 0; }) | 
| 438 | ]) | 526 | ]) | 
| 439 | (node "output" "HP Inc. HP 727pu CN4417143K" [ | 527 | (node "output" ["HP Inc. HP 727pu CN4417143K"] [ | 
| 440 | (leaf "mode" "2560x1440@119.998") | 528 | (sleaf "mode" "2560x1440@119.998") | 
| 441 | (leaf "scale" 1) | 529 | (sleaf "scale" 1) | 
| 442 | (leaf "position" { x = 2560; y = 0; }) | 530 | (sleaf "position" { x = 2560; y = 0; }) | 
| 443 | (flag "variable-refresh-rate") | 531 | (flag "variable-refresh-rate") | 
| 444 | ]) | 532 | ]) | 
| 445 | 533 | ||
| 446 | (plain "debug" [ | 534 | (plain "debug" [ | 
| 447 | (leaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render") | 535 | (sleaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render") | 
| 448 | ]) | 536 | ]) | 
| 449 | 537 | ||
| 450 | (plain "animations" [ | 538 | (plain "animations" [ | 
| 451 | (leaf "slowdown" 0.5) | 539 | (sleaf "slowdown" 0.5) | 
| 452 | (plain "workspace-switch" [(flag "off")]) | 540 | (plain "workspace-switch" [(flag "off")]) | 
| 453 | ]) | 541 | ]) | 
| 454 | 542 | ||
| 455 | (plain "layout" [ | 543 | (plain "layout" [ | 
| 456 | (leaf "gaps" 8) | 544 | (sleaf "gaps" 8) | 
| 457 | (plain "struts" [ | 545 | (plain "struts" [ | 
| 458 | (leaf "left" 0) | 546 | (sleaf "left" 26) | 
| 459 | (leaf "right" 0) | 547 | (sleaf "right" 26) | 
| 460 | (leaf "top" 0) | 548 | (sleaf "top" 0) | 
| 461 | (leaf "bottom" 0) | 549 | (sleaf "bottom" 0) | 
| 462 | ]) | 550 | ]) | 
| 463 | (plain "border" [ | 551 | (plain "border" [ | 
| 464 | (leaf "width" 2) | 552 | (sleaf "width" 2) | 
| 465 | (leaf "active-gradient" { | 553 | (sleaf "active-gradient" { | 
| 466 | from = "hsla(195 100% 45% 1)"; | 554 | from = "hsla(195 100% 45% 1)"; | 
| 467 | to = "hsla(155 100% 37.5% 1)"; | 555 | to = "hsla(155 100% 37.5% 1)"; | 
| 468 | angle = 29; | 556 | angle = 29; | 
| 469 | relative-to = "workspace-view"; | 557 | relative-to = "workspace-view"; | 
| 470 | }) | 558 | }) | 
| 471 | (leaf "inactive-gradient" { | 559 | (sleaf "inactive-gradient" { | 
| 472 | from = "hsla(0 0% 27.7% 1)"; | 560 | from = "hsla(0 0% 27.7% 1)"; | 
| 473 | to = "hsla(0 0% 23% 1)"; | 561 | to = "hsla(0 0% 23% 1)"; | 
| 474 | angle = 29; | 562 | angle = 29; | 
| @@ -479,29 +567,29 @@ in { | |||
| 479 | (flag "off") | 567 | (flag "off") | 
| 480 | ]) | 568 | ]) | 
| 481 | 569 | ||
| 482 | (plain "preset-column-widths" (map (prop: leaf "proportion" prop) [ | 570 | (plain "preset-column-widths" (map (prop: sleaf "proportion" prop) [ | 
| 483 | (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.) | 571 | (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.) | 
| 484 | ])) | 572 | ])) | 
| 485 | (plain "default-column-width" [ (leaf "proportion" (1. / 2.)) ]) | 573 | (plain "default-column-width" [ (sleaf "proportion" (1. / 2.)) ]) | 
| 486 | (plain "preset-window-heights" (map (prop: leaf "proportion" prop) [ | 574 | (plain "preset-window-heights" (map (prop: sleaf "proportion" prop) [ | 
| 487 | (1. / 3.) (1. / 2.) (2. / 3.) (1.) | 575 | (1. / 3.) (1. / 2.) (2. / 3.) (1.) | 
| 488 | ])) | 576 | ])) | 
| 489 | 577 | ||
| 490 | (flag "always-center-single-column") | 578 | (flag "always-center-single-column") | 
| 491 | 579 | ||
| 492 | (plain "tab-indicator" [ | 580 | (plain "tab-indicator" [ | 
| 493 | (leaf "gap" 4) | 581 | (sleaf "gap" 4) | 
| 494 | (leaf "width" 8) | 582 | (sleaf "width" 8) | 
| 495 | (leaf "gaps-between-tabs" 4) | 583 | (sleaf "gaps-between-tabs" 4) | 
| 496 | (flag "place-within-column") | 584 | (flag "place-within-column") | 
| 497 | (leaf "length" { total-proportion = 1.; }) | 585 | (sleaf "length" { total-proportion = 1.; }) | 
| 498 | (leaf "active-gradient" { | 586 | (sleaf "active-gradient" { | 
| 499 | from = "hsla(195 100% 60% 0.75)"; | 587 | from = "hsla(195 100% 60% 0.75)"; | 
| 500 | to = "hsla(155 100% 50% 0.75)"; | 588 | to = "hsla(155 100% 50% 0.75)"; | 
| 501 | angle = 29; | 589 | angle = 29; | 
| 502 | relative-to = "workspace-view"; | 590 | relative-to = "workspace-view"; | 
| 503 | }) | 591 | }) | 
| 504 | (leaf "inactive-gradient" { | 592 | (sleaf "inactive-gradient" { | 
| 505 | from = "hsla(0 0% 42% 0.66)"; | 593 | from = "hsla(0 0% 42% 0.66)"; | 
| 506 | to = "hsla(0 0% 35% 0.66)"; | 594 | to = "hsla(0 0% 35% 0.66)"; | 
| 507 | angle = 29; | 595 | angle = 29; | 
| @@ -515,127 +603,140 @@ in { | |||
| 515 | ]) | 603 | ]) | 
| 516 | 604 | ||
| 517 | (map (name: | 605 | (map (name: | 
| 518 | (node "workspace" name [ | 606 | (node "workspace" [name] [ | 
| 519 | (leaf "open-on-output" "eDP-1") | 607 | (sleaf "open-on-output" "eDP-1") | 
| 520 | ]) | 608 | ]) | 
| 521 | ) (map ({name, ...}: name) cfg.scratchspaces)) | 609 | ) (map ({name, ...}: name) cfg.scratchspaces)) | 
| 522 | (map (name: | 610 | (map (name: | 
| 523 | (leaf "workspace" name) | 611 | (sleaf "workspace" name) | 
| 524 | ) ["comm" "web" "vid" "bmr"]) | 612 | ) ["comm" "web" "vid" "bmr"]) | 
| 525 | 613 | ||
| 526 | (plain "window-rule" [ | 614 | (plain "window-rule" [ | 
| 527 | (leaf "clip-to-geometry" true) | 615 | (sleaf "clip-to-geometry" true) | 
| 528 | ]) | 616 | ]) | 
| 529 | 617 | ||
| 530 | (plain "window-rule" [ | 618 | (plain "window-rule" [ | 
| 531 | (leaf "match" { is-floating = true; }) | 619 | (sleaf "match" { is-floating = true; }) | 
| 532 | (leaf "geometry-corner-radius" 8) | 620 | (sleaf "geometry-corner-radius" 8) | 
| 533 | (plain "shadow" [ (flag "on") ]) | 621 | (plain "shadow" [ (flag "on") ]) | 
| 534 | ]) | 622 | ]) | 
| 535 | 623 | ||
| 536 | (plain "window-rule" [ | 624 | (plain "window-rule" [ | 
| 537 | (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; }) | 625 | (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; }) | 
| 538 | (leaf "block-out-from" "screencast") | 626 | (sleaf "block-out-from" "screencast") | 
| 539 | ]) | 627 | ]) | 
| 540 | (plain "window-rule" [ | 628 | (plain "window-rule" (normalize-nodes [ | 
| 541 | (map (title: | 629 | (map (title: | 
| 542 | (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) | 630 | (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) | 
| 543 | ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) | 631 | ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"]) | 
| 544 | (leaf "open-focused" true) | 632 | (sleaf "open-focused" true) | 
| 545 | (leaf "open-floating" true) | 633 | (sleaf "open-floating" true) | 
| 546 | ]) | 634 | ])) | 
| 547 | 635 | ||
| 548 | (map ({ name, match, exclude, windowRuleExtra, ... }: | 636 | (map ({ name, match, exclude, windowRuleExtra, ... }: | 
| 549 | (optional-node (match != []) (plain "window-rule" [ | 637 | (optional-node (match != []) (plain "window-rule" (normalize-nodes [ | 
| 550 | (map (leaf "match") match) | 638 | (map (sleaf "match") match) | 
| 551 | (map (leaf "exclude") exclude) | 639 | (map (sleaf "exclude") exclude) | 
| 552 | (leaf "open-on-workspace" name) | 640 | (sleaf "open-on-workspace" name) | 
| 553 | (leaf "open-maximized" true) | 641 | (sleaf "open-maximized" true) | 
| 554 | windowRuleExtra | 642 | windowRuleExtra | 
| 555 | ])) | 643 | ]))) | 
| 556 | ) cfg.scratchspaces) | 644 | ) cfg.scratchspaces) | 
| 557 | 645 | ||
| 558 | (plain "window-rule" [ | 646 | (plain "window-rule" [ | 
| 559 | (leaf "match" { app-id = "^emacs$"; }) | 647 | (sleaf "match" { app-id = "^emacs$"; }) | 
| 560 | (leaf "match" { app-id = "^firefox$"; }) | 648 | (sleaf "match" { app-id = "^firefox$"; }) | 
| 561 | (plain "default-column-width" [(leaf "proportion" (2. / 3.))]) | 649 | (plain "default-column-width" [(sleaf "proportion" (2. / 3.))]) | 
| 562 | ]) | 650 | ]) | 
| 563 | (plain "window-rule" [ | 651 | (plain "window-rule" [ | 
| 564 | (leaf "match" { app-id = "^kitty$"; }) | 652 | (sleaf "match" { app-id = "^kitty$"; }) | 
| 565 | (leaf "match" { app-id = "^kitty-play$"; }) | 653 | (sleaf "match" { app-id = "^kitty-play$"; }) | 
| 566 | (plain "default-column-width" [(leaf "proportion" (1. / 3.))]) | 654 | (plain "default-column-width" [(sleaf "proportion" (1. / 3.))]) | 
| 567 | ]) | 655 | ]) | 
| 568 | 656 | ||
| 569 | (plain "window-rule" [ | 657 | (plain "window-rule" [ | 
| 570 | (leaf "match" { app-id = "^thunderbird$"; }) | 658 | (sleaf "match" { app-id = "^thunderbird$"; }) | 
| 571 | (leaf "match" { app-id = "^Element$"; }) | 659 | (sleaf "match" { app-id = "^Element$"; }) | 
| 572 | (leaf "match" { app-id = "^Rainbow$"; }) | 660 | (sleaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; }) | 
| 573 | (leaf "open-on-workspace" "comm") | 661 | (sleaf "open-on-workspace" "comm") | 
| 574 | ]) | 662 | ]) | 
| 575 | (plain "window-rule" [ | 663 | (plain "window-rule" [ | 
| 576 | (leaf "match" { app-id = "^firefox$"; }) | 664 | (sleaf "match" { app-id = "^firefox$"; }) | 
| 577 | (leaf "open-on-workspace" "web") | 665 | (sleaf "open-on-workspace" "web") | 
| 578 | (leaf "open-maximized" true) | 666 | (sleaf "open-maximized" true) | 
| 579 | ]) | 667 | ]) | 
| 580 | (plain "window-rule" [ | 668 | (plain "window-rule" [ | 
| 581 | (leaf "match" { app-id = "^mpv$"; }) | 669 | (sleaf "match" { app-id = "^mpv$"; }) | 
| 582 | (leaf "open-on-workspace" "vid") | 670 | (sleaf "open-on-workspace" "vid") | 
| 583 | (plain "default-column-width" [(leaf "proportion" 1.)]) | 671 | (plain "default-column-width" [(sleaf "proportion" 1.)]) | 
| 584 | ]) | 672 | ]) | 
| 585 | (plain "window-rule" [ | 673 | (plain "window-rule" [ | 
| 586 | (leaf "match" { app-id = "^kitty-play$"; }) | 674 | (sleaf "match" { app-id = "^kitty-play$"; }) | 
| 587 | (leaf "open-on-workspace" "vid") | 675 | (sleaf "open-on-workspace" "vid") | 
| 588 | (leaf "open-focused" false) | 676 | (sleaf "open-focused" false) | 
| 589 | ]) | 677 | ]) | 
| 590 | (plain "window-rule" [ | 678 | (plain "window-rule" [ | 
| 591 | (leaf "match" { app-id = "^pdfpc$"; }) | 679 | (sleaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; }) | 
| 592 | (plain "default-column-width" [(leaf "proportion" 1.)]) | 680 | (sleaf "match" { app-id = "^YouTube Music Desktop App$"; }) | 
| 681 | (sleaf "open-on-workspace" "vid") | ||
| 593 | ]) | 682 | ]) | 
| 594 | (plain "window-rule" [ | 683 | (plain "window-rule" [ | 
| 595 | (leaf "match" { app-id = "^pdfpc$"; title = "^pdfpc - presentation$"; }) | 684 | (sleaf "match" { app-id = "^pdfpc$"; }) | 
| 596 | (plain "default-column-width" [(leaf "proportion" 1.)]) | 685 | (plain "default-column-width" [(sleaf "proportion" 1.)]) | 
| 597 | (leaf "open-fullscreen" true) | ||
| 598 | (leaf "open-on-workspace" "bmr") | ||
| 599 | (leaf "open-focused" false) | ||
| 600 | ]) | 686 | ]) | 
| 601 | (plain "window-rule" [ | 687 | (plain "window-rule" [ | 
| 602 | (map (leaf "match") [ | 688 | (sleaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; }) | 
| 689 | (plain "default-column-width" [(sleaf "proportion" 1.)]) | ||
| 690 | (sleaf "open-fullscreen" true) | ||
| 691 | (sleaf "open-on-workspace" "bmr") | ||
| 692 | (sleaf "open-focused" false) | ||
| 693 | ]) | ||
| 694 | (plain "window-rule" (normalize-nodes [ | ||
| 695 | (map (sleaf "match") [ | ||
| 603 | { app-id = "^Gimp-"; title = "^Quit GIMP$"; } | 696 | { app-id = "^Gimp-"; title = "^Quit GIMP$"; } | 
| 604 | { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; } | 697 | { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; } | 
| 605 | { app-id = "^xdg-desktop-portal-gtk$"; } | 698 | { app-id = "^xdg-desktop-portal-gtk$"; } | 
| 606 | ]) | 699 | ]) | 
| 607 | (leaf "open-floating" true) | 700 | (sleaf "open-floating" true) | 
| 608 | ]) | 701 | ])) | 
| 609 | (plain "window-rule" [ | 702 | (plain "window-rule" [ | 
| 610 | (leaf "match" { app-id = "^org\\.pwmt\\.zathura$"; }) | 703 | (sleaf "match" { app-id = "^org\\.pwmt\\.zathura$"; }) | 
| 611 | (leaf "match" { app-id = "^evince$"; }) | 704 | (sleaf "match" { app-id = "^evince$"; }) | 
| 612 | (leaf "default-column-display" "tabbed") | 705 | (sleaf "match" { app-id = "^org\\.gnome\\.Papers$"; }) | 
| 706 | (sleaf "default-column-display" "tabbed") | ||
| 613 | ]) | 707 | ]) | 
| 614 | 708 | ||
| 615 | (plain "layer-rule" [ | 709 | (plain "layer-rule" [ | 
| 616 | (leaf "match" { namespace = "^notifications$"; }) | 710 | (sleaf "match" { namespace = "^notifications$"; }) | 
| 617 | (leaf "match" { namespace = "^waybar$"; }) | 711 | (sleaf "match" { namespace = "^bar$"; }) | 
| 618 | (leaf "match" { namespace = "^launcher$"; }) | 712 | (sleaf "match" { namespace = "^launcher$"; }) | 
| 619 | (leaf "block-out-from" "screencast") | 713 | (sleaf "block-out-from" "screencast") | 
| 620 | ]) | 714 | ]) | 
| 621 | 715 | ||
| 622 | (plain "binds" | 716 | (plain "binds" | 
| 623 | (let | 717 | (let | 
| 624 | bind = name: cfg: node name (opt-props { | 718 | bind = name: cfg: node name [(lib.removeAttrs cfg ["action"])] (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"])); | 
| 625 | cooldown-ms = cfg.cooldown-ms or null; | ||
| 626 | } | ||
| 627 | // (lib.optionalAttrs (!(cfg.repeat or true)) { | ||
| 628 | repeat = false; | ||
| 629 | }) | ||
| 630 | // (lib.optionalAttrs (cfg.allow-when-locked or false) { | ||
| 631 | allow-when-locked = true; | ||
| 632 | })) (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"])); | ||
| 633 | in | 719 | in | 
| 634 | [ | 720 | normalize-nodes [ | 
| 635 | (lib.mapAttrsToList bind (with config.lib.niri.actions; { | 721 | (lib.mapAttrsToList bind (with config.lib.niri.actions; { | 
| 636 | "Mod+Slash".action = show-hotkey-overlay; | 722 | "Mod+Slash".action = show-hotkey-overlay; | 
| 637 | 723 | ||
| 638 | "Mod+Return".action = spawn terminal; | 724 | "Mod+Return".action = spawn terminal; | 
| 725 | "Mod+Shift+Return".action = | ||
| 726 | let | ||
| 727 | nushellKitty = pkgs.symlinkJoin { | ||
| 728 | name = "nushell-kitty"; | ||
| 729 | paths = [ config.programs.kitty.package ]; | ||
| 730 | buildInputs = [ pkgs.makeWrapper ]; | ||
| 731 | postBuild = '' | ||
| 732 | wrapProgram $out/bin/kitty \ | ||
| 733 | --add-flags "--config ${pkgs.writeText "kitty.conf" '' | ||
| 734 | include $HOME/${config.xdg.configFile."kitty/kitty.conf".target} | ||
| 735 | shell ${lib.getExe config.programs.nushell.package} | ||
| 736 | ''}" | ||
| 737 | ''; | ||
| 738 | }; | ||
| 739 | in spawn (lib.getExe' nushellKitty "kitty"); | ||
| 639 | "Mod+Q".action = close-window; | 740 | "Mod+Q".action = close-window; | 
| 640 | "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); | 741 | "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); | 
| 641 | "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; | 742 | "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; | 
| @@ -671,12 +772,12 @@ in { | |||
| 671 | 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) | 772 | 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) | 
| 672 | $FOUND || echo | 773 | $FOUND || echo | 
| 673 | } | 774 | } | 
| 674 | FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? | 775 | FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $? | 
| 675 | if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then | 776 | if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then | 
| 676 | QALC_RES="$FUZZEL_RES" | 777 | QALC_RES="$FUZZEL_RES" | 
| 677 | QALC_RET=0 | 778 | QALC_RET=0 | 
| 678 | else | 779 | else | 
| 679 | QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) | 780 | QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1) | 
| 680 | QALC_RET=$? | 781 | QALC_RET=$? | 
| 681 | fi | 782 | fi | 
| 682 | [[ -n "$QALC_RES" ]] || exit 1 | 783 | [[ -n "$QALC_RES" ]] || exit 1 | 
| @@ -696,18 +797,33 @@ in { | |||
| 696 | notify-send "$QALC_RES" | 797 | notify-send "$QALC_RES" | 
| 697 | ''; | 798 | ''; | 
| 698 | })); | 799 | })); | 
| 800 | "Mod+Shift+U".action = | ||
| 801 | let | ||
| 802 | qalcKitty = pkgs.symlinkJoin { | ||
| 803 | name = "qalc-kitty"; | ||
| 804 | paths = [ config.programs.kitty.package ]; | ||
| 805 | buildInputs = [ pkgs.makeWrapper ]; | ||
| 806 | postBuild = '' | ||
| 807 | wrapProgram $out/bin/kitty \ | ||
| 808 | --add-flags "--config ${pkgs.writeText "kitty.conf" '' | ||
| 809 | include $HOME/${config.xdg.configFile."kitty/kitty.conf".target} | ||
| 810 | shell ${lib.getExe pkgs.libqalculate} | ||
| 811 | ''}" | ||
| 812 | ''; | ||
| 813 | }; | ||
| 814 | in spawn (lib.getExe' qalcKitty "kitty"); | ||
| 699 | "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { | 815 | "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { | 
| 700 | name = "emoji-fuzzel"; | 816 | name = "emoji-fuzzel"; | 
| 701 | runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; | 817 | runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; | 
| 702 | text = '' | 818 | text = '' | 
| 703 | FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? | 819 | FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $? | 
| 704 | [[ -n "$FUZZEL_RES" ]] || exit 1 | 820 | [[ -n "$FUZZEL_RES" ]] || exit 1 | 
| 705 | wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste | 821 | wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste | 
| 706 | ''; | 822 | ''; | 
| 707 | })); | 823 | })); | 
| 708 | "Print".action = screenshot; | 824 | "Print".action = screenshot; | 
| 709 | "Control+Print".action = screenshot-window; | 825 | "Control+Print".action = screenshot-window; | 
| 710 | # "Shift+Print".action = screenshot-screen; | 826 | "Shift+Print".action = kdl.magic-leaf "screenshot-screen"; | 
| 711 | "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; | 827 | "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; | 
| 712 | "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; | 828 | "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; | 
| 713 | 829 | ||
| @@ -746,22 +862,22 @@ in { | |||
| 746 | "Mod+Shift+Control+C".action = move-workspace-up; | 862 | "Mod+Shift+Control+C".action = move-workspace-up; | 
| 747 | 863 | ||
| 748 | "Mod+ParenLeft".action = focus-workspace "comm"; | 864 | "Mod+ParenLeft".action = focus-workspace "comm"; | 
| 749 | "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm"; | 865 | "Mod+Shift+ParenLeft".action = kdl.magic-leaf "move-column-to-workspace" "comm"; | 
| 750 | 866 | ||
| 751 | "Mod+ParenRight".action = focus-workspace "web"; | 867 | "Mod+ParenRight".action = focus-workspace "web"; | 
| 752 | "Mod+Shift+ParenRight".action = move-column-to-workspace "web"; | 868 | "Mod+Shift+ParenRight".action = kdl.magic-leaf "move-column-to-workspace" "web"; | 
| 753 | 869 | ||
| 754 | "Mod+BraceRight".action = focus-workspace "read"; | 870 | "Mod+BraceRight".action = focus-workspace "read"; | 
| 755 | "Mod+Shift+BraceRight".action = move-column-to-workspace "read"; | 871 | "Mod+Shift+BraceRight".action = kdl.magic-leaf "move-column-to-workspace" "read"; | 
| 756 | 872 | ||
| 757 | "Mod+BraceLeft".action = focus-workspace "mon"; | 873 | "Mod+BraceLeft".action = focus-workspace "mon"; | 
| 758 | "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon"; | 874 | "Mod+Shift+BraceLeft".action = kdl.magic-leaf "move-column-to-workspace" "mon"; | 
| 759 | 875 | ||
| 760 | "Mod+Asterisk".action = focus-workspace "vid"; | 876 | "Mod+Asterisk".action = focus-workspace "vid"; | 
| 761 | "Mod+Shift+Asterisk".action = move-column-to-workspace "vid"; | 877 | "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid"; | 
| 762 | 878 | ||
| 763 | "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; | 879 | "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; | 
| 764 | "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; | 880 | "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}''; | 
| 765 | 881 | ||
| 766 | "Mod+M".action = consume-or-expel-window-left; | 882 | "Mod+M".action = consume-or-expel-window-left; | 
| 767 | "Mod+W".action = consume-or-expel-window-right; | 883 | "Mod+W".action = consume-or-expel-window-right; | 
| @@ -769,10 +885,11 @@ in { | |||
| 769 | "Mod+Shift+M".action = toggle-column-tabbed-display; | 885 | "Mod+Shift+M".action = toggle-column-tabbed-display; | 
| 770 | 886 | ||
| 771 | "Mod+R".action = switch-preset-column-width; | 887 | "Mod+R".action = switch-preset-column-width; | 
| 772 | "Mod+Shift+R".action = switch-preset-window-height; | 888 | "Mod+Shift+R".action = maximize-column; | 
| 889 | "Mod+Shift+Ctrl+R".action = switch-preset-window-height; | ||
| 773 | "Mod+F".action = center-column; | 890 | "Mod+F".action = center-column; | 
| 774 | "Mod+Shift+F".action = maximize-column; | 891 | "Mod+Shift+F".action = toggle-windowed-fullscreen; | 
| 775 | "Mod+Shift+Ctrl+F".action = fullscreen-window; | 892 | "Mod+Ctrl+Shift+F".action = fullscreen-window; | 
| 776 | 893 | ||
| 777 | "Mod+V".action = switch-focus-between-floating-and-tiling; | 894 | "Mod+V".action = switch-focus-between-floating-and-tiling; | 
| 778 | "Mod+Shift+V".action = toggle-window-floating; | 895 | "Mod+Shift+V".action = toggle-window-floating; | 
| @@ -783,58 +900,77 @@ in { | |||
| 783 | "Mod+Right".action = set-column-width "+10%"; | 900 | "Mod+Right".action = set-column-width "+10%"; | 
| 784 | 901 | ||
| 785 | "Mod+Shift+Z" = { | 902 | "Mod+Shift+Z" = { | 
| 786 | action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors"; | 903 | action = power-off-monitors; | 
| 787 | allow-when-locked = true; | 904 | allow-when-locked = true; | 
| 788 | }; | 905 | }; | 
| 789 | "Mod+Shift+L".action = spawn loginctl "lock-session"; | ||
| 790 | "Mod+Shift+E".action = quit; | 906 | "Mod+Shift+E".action = quit; | 
| 791 | "Mod+Shift+Minus" = { | 907 | |
| 792 | action = spawn systemctl "suspend"; | 908 | # "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; | 
| 909 | # "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; | ||
| 910 | # "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu"; | ||
| 911 | # "Mod+Comma".action = spawn makoctl "restore"; | ||
| 912 | |||
| 913 | "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; | ||
| 914 | "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}"; | ||
| 915 | |||
| 916 | "Mod+X".action = set-dynamic-cast-window; | ||
| 917 | "Mod+Shift+X".action = set-dynamic-cast-monitor; | ||
| 918 | "Mod+Control+Shift+X".action = clear-dynamic-cast-target; | ||
| 919 | |||
| 920 | "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; | ||
| 921 | "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}"; | ||
| 922 | |||
| 923 | "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui"); | ||
| 924 | "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop"); | ||
| 925 | })) | ||
| 926 | (lib.mapAttrsToList (name: cfg: node name [(lib.removeAttrs cfg ["action"])] [cfg.action]) (let | ||
| 927 | shell = obj: leaf "send-unix" [ | ||
| 928 | { path = ''''${XDG_RUNTIME_DIR}/shell.sock''; } | ||
| 929 | (builtins.toJSON obj + "\n") | ||
| 930 | ]; | ||
| 931 | in { | ||
| 932 | "XF86AudioRaiseVolume" = { | ||
| 793 | allow-when-locked = true; | 933 | allow-when-locked = true; | 
| 934 | action = shell { Volume.volume = "up"; }; | ||
| 794 | }; | 935 | }; | 
| 795 | "Mod+Shift+Control+Minus" = { | 936 | "XF86AudioLowerVolume" = { | 
| 796 | action = spawn systemctl "hibernate"; | ||
| 797 | allow-when-locked = true; | 937 | allow-when-locked = true; | 
| 938 | action = shell { Volume.volume = "down"; }; | ||
| 798 | }; | 939 | }; | 
| 799 | "Mod+Shift+P" = { | 940 | "XF86AudioMute" = { | 
| 800 | action = spawn (lib.getExe pkgs.playerctl) "-a" "pause"; | ||
| 801 | allow-when-locked = true; | 941 | allow-when-locked = true; | 
| 942 | action = shell { Volume.muted = "toggle"; }; | ||
| 802 | }; | 943 | }; | 
| 803 | 944 | "XF86AudioMicMute" = { | |
| 804 | "XF86MonBrightnessUp" = { | ||
| 805 | action = spawn swayosd-client "--brightness" "raise"; | ||
| 806 | allow-when-locked = true; | 945 | allow-when-locked = true; | 
| 946 | action = shell { Volume."mic-muted" = "toggle"; }; | ||
| 807 | }; | 947 | }; | 
| 808 | "XF86MonBrightnessDown" = { | 948 | "XF86MonBrightnessUp" = { | 
| 809 | action = spawn swayosd-client "--brightness" "lower"; | 949 | action = shell { Brightness = "up"; }; | 
| 810 | allow-when-locked = true; | 950 | allow-when-locked = true; | 
| 811 | }; | 951 | }; | 
| 812 | "XF86AudioRaiseVolume" = { | 952 | "XF86MonBrightnessDown" = { | 
| 813 | action = spawn swayosd-client "--output-volume" "raise"; | 953 | action = shell { Brightness = "down"; }; | 
| 814 | allow-when-locked = true; | 954 | allow-when-locked = true; | 
| 815 | }; | 955 | }; | 
| 816 | "XF86AudioLowerVolume" = { | 956 | "Mod+Shift+L".action = shell { LockSession = {}; }; | 
| 817 | action = spawn swayosd-client "--output-volume" "lower"; | 957 | "Mod+Shift+Minus" = { | 
| 958 | action = shell { Suspend = {}; }; | ||
| 818 | allow-when-locked = true; | 959 | allow-when-locked = true; | 
| 819 | }; | 960 | }; | 
| 820 | "XF86AudioMute" = { | 961 | "Mod+Shift+Control+Minus" = { | 
| 821 | action = spawn swayosd-client "--output-volume" "mute-toggle"; | 962 | action = shell { Hibernate = {}; }; | 
| 822 | allow-when-locked = true; | 963 | allow-when-locked = true; | 
| 823 | }; | 964 | }; | 
| 824 | "XF86AudioMicMute" = { | 965 | "Mod+Shift+P" = { | 
| 825 | action = spawn swayosd-client "--input-volume" "mute-toggle"; | 966 | action = shell { Mpris = { PauseAll = {}; }; }; | 
| 826 | allow-when-locked = true; | 967 | allow-when-locked = true; | 
| 827 | }; | 968 | }; | 
| 828 | 969 | "Mod+Semicolon".action = shell { Notifications = { DismissGroup = {}; }; }; | |
| 829 | "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; | 970 | "Mod+Shift+Semicolon".action = shell { Notifications = { DismissAll = {}; }; }; | 
| 830 | "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; | ||
| 831 | "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu"; | ||
| 832 | "Mod+Comma".action = spawn makoctl "restore"; | ||
| 833 | |||
| 834 | "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; | ||
| 835 | "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; | ||
| 836 | })) | 971 | })) | 
| 837 | (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) | 972 | (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) | 
| 973 | (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces) | ||
| 838 | ] | 974 | ] | 
| 839 | )) | 975 | )) | 
| 840 | ]; | 976 | ]; | 
| diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix index 2788fb82..3d246d96 100644 --- a/accounts/gkleen@sif/niri/mako.nix +++ b/accounts/gkleen@sif/niri/mako.nix | |||
| @@ -1,39 +1,32 @@ | |||
| 1 | { config, lib, pkgs, ... }: | 1 | { config, lib, pkgs, ... }: | 
| 2 | { | 2 | { | 
| 3 | config = { | 3 | config = lib.mkIf false { | 
| 4 | services.mako = { | 4 | services.mako = { | 
| 5 | enable = true; | 5 | enable = true; | 
| 6 | font = "Fira Sans 10"; | 6 | settings = { | 
| 7 | format = "<i>%s</i>\\n%b"; | 7 | font = "Fira Sans 10"; | 
| 8 | margin = "2"; | 8 | format = "<i>%s</i>\\n%b"; | 
| 9 | maxVisible = -1; | 9 | margin = "2"; | 
| 10 | backgroundColor = "#000000dd"; | 10 | max-visible = -1; | 
| 11 | progressColor = "source #223544ff"; | 11 | background-color = "#000000dd"; | 
| 12 | width = 384; | 12 | progress-color = "source #223544ff"; | 
| 13 | extraConfig = '' | 13 | width = 384; | 
| 14 | outer-margin=1 | 14 | outer-margin = 1; | 
| 15 | max-history=100 | 15 | max-history = 100; | 
| 16 | max-icon-size=48 | 16 | max-icon-size = 48; | 
| 17 | 17 | ||
| 18 | [grouped] | 18 | grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b"; | 
| 19 | format=<b>(%g)</b> <i>%s</i>\n%b | 19 | "urgency=low".text-color = "#999999ff"; | 
| 20 | 20 | "urgency=critical".background-color = "#900000dd"; | |
| 21 | [urgency=low] | 21 | "app-name=Element".group-by = "summary"; | 
| 22 | text-color=#999999ff | 22 | "app-name=poweralertd" = { | 
| 23 | 23 | history = false; | |
| 24 | [urgency=critical] | 24 | ignore-timeout = true; | 
| 25 | background-color=#900000dd | 25 | default-timeout = 2000; | 
| 26 | 26 | }; | |
| 27 | [app-name=Element] | 27 | "app-name=worktime".history = false; | 
| 28 | group-by=summary | 28 | "mode=silent".invisible = true; | 
| 29 | 29 | }; | |
| 30 | [app-name=poweralertd] | ||
| 31 | ignore-timeout=1 | ||
| 32 | default-timeout=2000 | ||
| 33 | |||
| 34 | [mode=silent] | ||
| 35 | invisible=1 | ||
| 36 | ''; | ||
| 37 | package = pkgs.symlinkJoin { | 30 | package = pkgs.symlinkJoin { | 
| 38 | name = "${pkgs.mako.name}-wrapped"; | 31 | name = "${pkgs.mako.name}-wrapped"; | 
| 39 | paths = with pkgs; [ mako ]; | 32 | paths = with pkgs; [ mako ]; | 
| diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix deleted file mode 100644 index 984927c2..00000000 --- a/accounts/gkleen@sif/niri/swayosd.nix +++ /dev/null | |||
| @@ -1,65 +0,0 @@ | |||
| 1 | { pkgs, ... }: | ||
| 2 | { | ||
| 3 | config = { | ||
| 4 | services.swayosd = { | ||
| 5 | enable = true; | ||
| 6 | topMargin = 0.946154; | ||
| 7 | stylePath = pkgs.runCommand "style.css" { | ||
| 8 | src = pkgs.writeText "style.scss" '' | ||
| 9 | window#osd { | ||
| 10 | padding: 12px 20px; | ||
| 11 | border-radius: 999px; | ||
| 12 | border: none; | ||
| 13 | background: rgba(0, 0, 0, 0.87); | ||
| 14 | |||
| 15 | #container { | ||
| 16 | margin: 16px; | ||
| 17 | } | ||
| 18 | |||
| 19 | image, | ||
| 20 | label { | ||
| 21 | color: rgb(255, 255, 255); | ||
| 22 | |||
| 23 | &:disabled { | ||
| 24 | opacity: 1; | ||
| 25 | color: rgb(84, 84, 84); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | progressbar { | ||
| 30 | min-height: 6px; | ||
| 31 | border-radius: 999px; | ||
| 32 | background: transparent; | ||
| 33 | border: none; | ||
| 34 | |||
| 35 | trough, progress { | ||
| 36 | min-height: inherit; | ||
| 37 | border-radius: inherit; | ||
| 38 | border: none; | ||
| 39 | } | ||
| 40 | |||
| 41 | trough { | ||
| 42 | background: rgb(127, 127, 127); | ||
| 43 | } | ||
| 44 | progress { | ||
| 45 | background: rgb(255, 255, 255); | ||
| 46 | } | ||
| 47 | |||
| 48 | &:disabled { | ||
| 49 | opacity: 1; | ||
| 50 | |||
| 51 | trough { | ||
| 52 | background: rgb(19, 19, 19); | ||
| 53 | } | ||
| 54 | progress { | ||
| 55 | background: rgb(38, 38, 38); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | ''; | ||
| 61 | buildInputs = with pkgs; [sass]; | ||
| 62 | } "scss -C --sourcemap=none --style=compact $src $out"; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | } | ||
| diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix deleted file mode 100644 index bae818f6..00000000 --- a/accounts/gkleen@sif/niri/waybar.nix +++ /dev/null | |||
| @@ -1,347 +0,0 @@ | |||
| 1 | { lib, config, pkgs, ... }: | ||
| 2 | let | ||
| 3 | swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client"; | ||
| 4 | in { | ||
| 5 | config = { | ||
| 6 | programs.waybar = { | ||
| 7 | enable = true; | ||
| 8 | systemd = { | ||
| 9 | enable = true; | ||
| 10 | target = "graphical-session.target"; | ||
| 11 | }; | ||
| 12 | settings = let | ||
| 13 | windowRewrites = { | ||
| 14 | "(.*) — Mozilla Firefox" = "$1"; | ||
| 15 | "(.*) - Mozilla Thunderbird" = "$1"; | ||
| 16 | "(.*) - mpv" = "$1"; | ||
| 17 | }; | ||
| 18 | iconSize = 11; | ||
| 19 | in [ | ||
| 20 | { | ||
| 21 | layer = "top"; | ||
| 22 | position = "top"; | ||
| 23 | height = 14; | ||
| 24 | output = [ "eDP-1" "DP-2" "DP-3" ]; | ||
| 25 | modules-left = [ "niri/workspaces" ]; | ||
| 26 | modules-center = [ "niri/window" ]; | ||
| 27 | modules-right = [ "custom/worktime" "custom/worktime-today" | ||
| 28 | "custom/weather" | ||
| 29 | "custom/keymap" | ||
| 30 | "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; | ||
| 31 | |||
| 32 | "custom/mako" = { | ||
| 33 | format = "{}"; | ||
| 34 | return-type = "json"; | ||
| 35 | exec = pkgs.writers.writePython3 "mako-silent" { libraries = [ pkgs.python3Packages.dbus-next ]; } '' | ||
| 36 | from dbus_next.aio import MessageBus | ||
| 37 | |||
| 38 | import asyncio | ||
| 39 | |||
| 40 | import json | ||
| 41 | |||
| 42 | |||
| 43 | loop = asyncio.new_event_loop() | ||
| 44 | asyncio.set_event_loop(loop) | ||
| 45 | |||
| 46 | |||
| 47 | async def main(): | ||
| 48 | bus = await MessageBus().connect() | ||
| 49 | # the introspection xml would normally be included in your project, but | ||
| 50 | # this is convenient for development | ||
| 51 | introspection = await bus.introspect('org.freedesktop.Notifications', '/fr/emersion/Mako') # noqa: E501 | ||
| 52 | |||
| 53 | obj = bus.get_proxy_object('org.freedesktop.Notifications', '/fr/emersion/Mako', introspection) # noqa: E501 | ||
| 54 | mako = obj.get_interface('fr.emersion.Mako') | ||
| 55 | properties = obj.get_interface('org.freedesktop.DBus.Properties') | ||
| 56 | |||
| 57 | async def print_mode(): | ||
| 58 | modes = await mako.get_modes() | ||
| 59 | is_silent = "silent" in modes | ||
| 60 | icon = "󰂛" if is_silent else "󰂚" | ||
| 61 | text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501 | ||
| 62 | if is_silent: | ||
| 63 | text = f"<span color=\"#ffffff\">{text}</span>" | ||
| 64 | print(json.dumps({'text': text, 'tooltip': ', '.join(modes)}, separators=(',', ':')), flush=True) # noqa: E501 | ||
| 65 | |||
| 66 | async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501 | ||
| 67 | if "Modes" not in invalidated_properties: | ||
| 68 | return | ||
| 69 | |||
| 70 | await print_mode() | ||
| 71 | |||
| 72 | properties.on_properties_changed(on_properties_changed) | ||
| 73 | await print_mode() | ||
| 74 | |||
| 75 | await loop.create_future() | ||
| 76 | |||
| 77 | |||
| 78 | loop.run_until_complete(main()) | ||
| 79 | ''; | ||
| 80 | on-click = "makoctl mode -t silent"; | ||
| 81 | }; | ||
| 82 | "custom/weather" = { | ||
| 83 | format = "{}"; | ||
| 84 | tooltip = true; | ||
| 85 | interval = 3600; | ||
| 86 | exec = "${lib.getExe pkgs.wttrbar} --hide-conditions --nerd --custom-indicator \"<span font=\\\"Symbols Nerd Font Mono\\\" size=\\\"100%\\\">{ICON}</span> {FeelsLikeC}°\""; | ||
| 87 | return-type = "json"; | ||
| 88 | }; | ||
| 89 | "custom/keymap" = { | ||
| 90 | format = "{}"; | ||
| 91 | tooltip = true; | ||
| 92 | return-type = "json"; | ||
| 93 | exec = pkgs.writers.writePython3 "keymap" {} '' | ||
| 94 | import os | ||
| 95 | import socket | ||
| 96 | import json | ||
| 97 | |||
| 98 | |||
| 99 | def output(keymap): | ||
| 100 | short = keymap | ||
| 101 | if keymap == "English (programmer Dvorak)": | ||
| 102 | short = "dvp" | ||
| 103 | elif keymap == "English (US)": | ||
| 104 | short = "<span color=\"#ffffff\">us</span>" | ||
| 105 | print(json.dumps({'text': short, 'tooltip': keymap}, separators=(',', ':')), flush=True) # noqa: E501 | ||
| 106 | |||
| 107 | |||
| 108 | keyboard_layouts = [] | ||
| 109 | |||
| 110 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||
| 111 | sock.connect(os.environ["NIRI_SOCKET"]) | ||
| 112 | sock.send(b"\"EventStream\"\n") | ||
| 113 | for line in sock.makefile(buffering=1, encoding='utf-8'): | ||
| 114 | if line_json := json.loads(line): | ||
| 115 | if "KeyboardLayoutsChanged" in line_json: | ||
| 116 | keyboard_layouts = line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["names"] # noqa: E501 | ||
| 117 | output(keyboard_layouts[line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["current_idx"]]) # noqa: E501 | ||
| 118 | if "KeyboardLayoutSwitched" in line_json: | ||
| 119 | output(keyboard_layouts[line_json["KeyboardLayoutSwitched"]["idx"]]) # noqa: E501 | ||
| 120 | ''; | ||
| 121 | on-click = "niri msg action switch-layout next"; | ||
| 122 | }; | ||
| 123 | "custom/worktime" = { | ||
| 124 | interval = 60; | ||
| 125 | exec = "${lib.getExe pkgs.worktime} time --waybar"; | ||
| 126 | return-type = "json"; | ||
| 127 | }; | ||
| 128 | "custom/worktime-today" = { | ||
| 129 | interval = 60; | ||
| 130 | exec = "${lib.getExe pkgs.worktime} today --waybar"; | ||
| 131 | return-type = "json"; | ||
| 132 | }; | ||
| 133 | "niri/workspaces" = { | ||
| 134 | ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces; | ||
| 135 | }; | ||
| 136 | "niri/window" = { | ||
| 137 | separate-outputs = true; | ||
| 138 | icon = true; | ||
| 139 | icon-size = 14; | ||
| 140 | rewrite = windowRewrites; | ||
| 141 | }; | ||
| 142 | clock = { | ||
| 143 | interval = 1; | ||
| 144 | # timezone = "Europe/Berlin"; | ||
| 145 | format = "W{:%V-%u %F %H:%M:%S%Ez}"; | ||
| 146 | tooltip-format = "<tt><small>{calendar}</small></tt>"; | ||
| 147 | calendar = { | ||
| 148 | mode = "year"; | ||
| 149 | mode-mon-col = 3; | ||
| 150 | weeks-pos = "left"; | ||
| 151 | on-scroll = 1; | ||
| 152 | format = { | ||
| 153 | months = "<span color='#ffead3'><b>{}</b></span>"; | ||
| 154 | days = "{}"; | ||
| 155 | weeks = "<span color='#99ffdd'><b>{}</b></span>"; | ||
| 156 | weekdays = "<span color='#ffcc66'><b>{}</b></span>"; | ||
| 157 | today = "<span color='#ff6699'><b>{}</b></span>"; | ||
| 158 | }; | ||
| 159 | }; | ||
| 160 | }; | ||
| 161 | battery = { | ||
| 162 | format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; | ||
| 163 | icon-size = iconSize - 2; | ||
| 164 | states = { warning = 30; critical = 15; }; | ||
| 165 | format-icons = ["󰂎" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹" ]; | ||
| 166 | format-charging = "󰂄"; | ||
| 167 | format-plugged = "󰚥"; | ||
| 168 | tooltip-format = "{capacity}% {timeTo}"; | ||
| 169 | interval = 20; | ||
| 170 | }; | ||
| 171 | tray = { | ||
| 172 | icon-size = 16; | ||
| 173 | # show-passive-items = true; | ||
| 174 | spacing = 1; | ||
| 175 | }; | ||
| 176 | privacy = { | ||
| 177 | icon-spacing = 7; | ||
| 178 | icon-size = iconSize; | ||
| 179 | modules = [ | ||
| 180 | { type = "screenshare"; } | ||
| 181 | { type = "audio-in"; } | ||
| 182 | ]; | ||
| 183 | }; | ||
| 184 | idle_inhibitor = { | ||
| 185 | format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; | ||
| 186 | icon-size = iconSize; | ||
| 187 | format-icons = { activated = "󰈈"; deactivated = "󰈉"; }; | ||
| 188 | timeout = 120; | ||
| 189 | }; | ||
| 190 | backlight = { | ||
| 191 | format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; | ||
| 192 | icon-size = iconSize; | ||
| 193 | tooltip-format = "{percent}%"; | ||
| 194 | format-icons = ["󰃚" "󰃛" "󰃜" "󰃝" "󰃞" "󰃟" "󰃠"]; | ||
| 195 | on-scroll-up = "${swayosd-client} --brightness raise"; | ||
| 196 | on-scroll-down = "${swayosd-client} --brightness lower"; | ||
| 197 | }; | ||
| 198 | wireplumber = { | ||
| 199 | format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; | ||
| 200 | icon-size = iconSize; | ||
| 201 | tooltip-format = "{volume}% {node_name}"; | ||
| 202 | format-icons = ["󰕿" "󰖀" "󰕾"]; | ||
| 203 | format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">󰝟</span>"; | ||
| 204 | # ignored-sinks = ["Easy Effects Sink"]; | ||
| 205 | on-scroll-up = "${swayosd-client} --output-volume raise"; | ||
| 206 | on-scroll-down = "${swayosd-client} --output-volume lower"; | ||
| 207 | on-click = "${swayosd-client} --output-volume mute-toggle"; | ||
| 208 | }; | ||
| 209 | } | ||
| 210 | { | ||
| 211 | layer = "top"; | ||
| 212 | position = "top"; | ||
| 213 | height = 14; | ||
| 214 | output = [ "!eDP-1" "!DP-2" "!DP-3" ]; | ||
| 215 | modules-left = [ "niri/workspaces" ]; | ||
| 216 | modules-center = [ "niri/window" ]; | ||
| 217 | modules-right = [ "clock" ]; | ||
| 218 | |||
| 219 | "niri/workspaces" = { | ||
| 220 | ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces; | ||
| 221 | }; | ||
| 222 | "niri/window" = { | ||
| 223 | separate-outputs = true; | ||
| 224 | icon = true; | ||
| 225 | icon-size = 14; | ||
| 226 | rewrite = windowRewrites; | ||
| 227 | }; | ||
| 228 | clock = { | ||
| 229 | interval = 1; | ||
| 230 | # timezone = "Europe/Berlin"; | ||
| 231 | format = "{:%H:%M}"; | ||
| 232 | tooltip-format = "W{:%V-%u %F %H:%M:%S%Ez}"; | ||
| 233 | }; | ||
| 234 | } | ||
| 235 | ]; | ||
| 236 | style = '' | ||
| 237 | @define-color white #ffffff; | ||
| 238 | @define-color grey #555555; | ||
| 239 | @define-color blue #1a8fff; | ||
| 240 | @define-color green #23fd00; | ||
| 241 | @define-color orange #f28a21; | ||
| 242 | @define-color red #f2201f; | ||
| 243 | |||
| 244 | * { | ||
| 245 | border: none; | ||
| 246 | font-family: "Fira Sans"; | ||
| 247 | font-size: 10pt; | ||
| 248 | min-height: 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | window#waybar { | ||
| 252 | background-color: rgba(0, 0, 0, 0.66); | ||
| 253 | color: @white; | ||
| 254 | } | ||
| 255 | |||
| 256 | .modules-left { | ||
| 257 | margin-left: 12px; | ||
| 258 | } | ||
| 259 | .modules-right { | ||
| 260 | margin-right: 12px; | ||
| 261 | } | ||
| 262 | |||
| 263 | .module { | ||
| 264 | margin: 0 5px; | ||
| 265 | } | ||
| 266 | |||
| 267 | #workspaces button { | ||
| 268 | color: @white; | ||
| 269 | padding: 2px 5px; | ||
| 270 | } | ||
| 271 | #workspaces button.empty { | ||
| 272 | color: @grey; | ||
| 273 | } | ||
| 274 | #workspaces button.active { | ||
| 275 | color: @green; | ||
| 276 | } | ||
| 277 | #workspaces button.urgent { | ||
| 278 | color: @red; | ||
| 279 | } | ||
| 280 | |||
| 281 | #custom-weather, #custom-keymap, #custom-worktime, #custom-worktime-today { | ||
| 282 | color: @grey; | ||
| 283 | margin: 0 5px; | ||
| 284 | } | ||
| 285 | #custom-weather { | ||
| 286 | margin-right: 3px; | ||
| 287 | } | ||
| 288 | #custom-keymap { | ||
| 289 | margin-left: 3px; | ||
| 290 | margin-right: 3px; | ||
| 291 | } | ||
| 292 | |||
| 293 | #tray { | ||
| 294 | margin: 0; | ||
| 295 | } | ||
| 296 | #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako { | ||
| 297 | color: @grey; | ||
| 298 | margin: 0 5px 0 2px; | ||
| 299 | } | ||
| 300 | #idle_inhibitor { | ||
| 301 | margin-right: 4px; | ||
| 302 | margin-left: 6px; | ||
| 303 | } | ||
| 304 | #custom-mako { | ||
| 305 | margin-right: 2px; | ||
| 306 | margin-left: 3px; | ||
| 307 | } | ||
| 308 | #battery { | ||
| 309 | margin-right: 3px; | ||
| 310 | } | ||
| 311 | #battery.discharging { | ||
| 312 | color: @white; | ||
| 313 | } | ||
| 314 | #battery.warning { | ||
| 315 | color: @orange; | ||
| 316 | } | ||
| 317 | #battery.critical { | ||
| 318 | color: @red; | ||
| 319 | } | ||
| 320 | #battery.charging { | ||
| 321 | color: @white; | ||
| 322 | } | ||
| 323 | #idle_inhibitor.activated { | ||
| 324 | color: @white; | ||
| 325 | } | ||
| 326 | #custom-worktime.running, #custom-worktime-today.running { | ||
| 327 | color: @white; | ||
| 328 | } | ||
| 329 | #custom-worktime.over, #custom-worktime-today.over { | ||
| 330 | color: @orange; | ||
| 331 | } | ||
| 332 | |||
| 333 | #idle_inhibitor { | ||
| 334 | padding-top: 1px; | ||
| 335 | } | ||
| 336 | |||
| 337 | #privacy { | ||
| 338 | color: @red; | ||
| 339 | margin: -1px 4px 0px 3px; | ||
| 340 | } | ||
| 341 | #clock { | ||
| 342 | /* margin-right: 5px; */ | ||
| 343 | } | ||
| 344 | ''; | ||
| 345 | }; | ||
| 346 | }; | ||
| 347 | } | ||
| diff --git a/accounts/gkleen@sif/shell/default.nix b/accounts/gkleen@sif/shell/default.nix new file mode 100644 index 00000000..44462865 --- /dev/null +++ b/accounts/gkleen@sif/shell/default.nix | |||
| @@ -0,0 +1,115 @@ | |||
| 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 QML_IMPORT_PATH : ${pkgs.qt6Packages.callPackage ./quickshell-plugins {}}/${pkgs.qt6.qtbase.qtQmlPrefix} | ||
| 16 | done | ||
| 17 | ''; | ||
| 18 | }; | ||
| 19 | config = { | ||
| 20 | src = ./quickshell; | ||
| 21 | replacements = { | ||
| 22 | ignore_workspaces = builtins.toJSON (map ({ name, ... }: name) config.programs.niri.scratchspaces); | ||
| 23 | wallpapers = builtins.toJSON (pkgs.stdenvNoCC.mkDerivation { | ||
| 24 | name = "wallpapers"; | ||
| 25 | srcs = [ | ||
| 26 | (pkgs.fetchurl { | ||
| 27 | url = "https://esawebb.org/media/archives/images/publicationtiff10k/carinanebula3.tif"; | ||
| 28 | hash = "sha256-YxZEweDKJfvfrdxb/QFmgJhcZDEJYxotoHrG+RRn1tw="; | ||
| 29 | }) | ||
| 30 | (pkgs.fetchurl { | ||
| 31 | url = "https://esawebb.org/media/archives/images/original/pillarsofcreation_composite.tif"; | ||
| 32 | hash = "sha256-qRiODxR0lZWdxgYXna0fNRFFDErpBJDwOJuQl6sNjRc="; | ||
| 33 | }) | ||
| 34 | (pkgs.fetchurl { | ||
| 35 | url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2212a.tif"; | ||
| 36 | hash = "sha256-l2fqE/z//C1a0xkvZwsnwPbTSb+WuA11h+SUl3E1dhw="; | ||
| 37 | }) | ||
| 38 | (pkgs.fetchurl { | ||
| 39 | url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2415a.tif"; | ||
| 40 | hash = "sha256-onBy7cPoUpDuzQStbY2E+qmlGgSLXPwFCLX53ukAb4c="; | ||
| 41 | }) | ||
| 42 | (pkgs.fetchurl { | ||
| 43 | url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2330a.tif"; | ||
| 44 | hash = "sha256-nn0ZtjZIrPcpj3YcLTsrL7XiXvyh3QYgCSmdDMD+3OM="; | ||
| 45 | }) | ||
| 46 | (pkgs.fetchurl { | ||
| 47 | url = "https://esawebb.org/media/archives/images/original/weic2426a.tif"; | ||
| 48 | hash = "sha256-EDnfPn3GE9jt6XPqiGInP7E2F3Az7d25NqATSWltDv0="; | ||
| 49 | }) | ||
| 50 | (pkgs.fetchurl { | ||
| 51 | url = "https://esawebb.org/media/archives/images/original/weic2503a.tif"; | ||
| 52 | hash = "sha256-3/RX6RQp8naELcgReHPd5/zhJkoCjnA10w5BEnNo+qI="; | ||
| 53 | }) | ||
| 54 | (pkgs.fetchurl { | ||
| 55 | url = "https://esawebb.org/media/archives/images/original/weic2506a.tif"; | ||
| 56 | hash = "sha256-aDld0aoY1owRxDVf7Jcyw71TH42M1foYotxn2thyFYw="; | ||
| 57 | }) | ||
| 58 | (pkgs.fetchurl { | ||
| 59 | url = "https://esawebb.org/media/archives/images/original/weic2514a.tif"; | ||
| 60 | hash = "sha256-jTi1G1Ofo5xsF6ggrbtYJHxqLaCQ7edM5B3uORiVQtg="; | ||
| 61 | }) | ||
| 62 | (pkgs.fetchurl { | ||
| 63 | url = "https://esawebb.org/media/archives/images/original/weic2425c.tif"; | ||
| 64 | hash = "sha256-oaEOexSJHEGj090dJF3ct5HAoR+Y5gRiPrUlxdvnTRo="; | ||
| 65 | }) | ||
| 66 | ]; | ||
| 67 | |||
| 68 | dontUnpack = true; | ||
| 69 | |||
| 70 | buildInputs = [ pkgs.imagemagick ]; | ||
| 71 | buildPhase = '' | ||
| 72 | runHook preBuild | ||
| 73 | |||
| 74 | typeset sources=($srcs) | ||
| 75 | |||
| 76 | mkdir -p $out | ||
| 77 | magick ''${sources[0]} -crop 10000x5625+0+79 +repage -define jpeg:extent=10MB $out/carinanebula3.jpeg | ||
| 78 | magick ''${sources[1]} -crop 6716x3778+329+80 +repage -define jpeg:extent=10MB $out/pillarsofcreation_composite.jpeg | ||
| 79 | magick ''${sources[2]} -crop 10000x5625+0+79 +repage -define jpeg:extent=10MB $out/weic2212a.jpeg | ||
| 80 | magick ''${sources[3]} -crop 7650x4302+1166+389 +repage -define jpeg:extent=10MB $out/weic2415a.jpeg | ||
| 81 | magick ''${sources[4]} -crop 8732x4912+0+434 +repage -define jpeg:extent=10MB $out/weic2330a.jpeg | ||
| 82 | magick ''${sources[5]} -crop 5302x2982+636+0 +repage -define jpeg:extent=10MB $out/weic2426a.jpeg | ||
| 83 | magick ''${sources[6]} -crop 4328x2434+0+906 +repage -define jpeg:extent=10MB $out/weic2503a.jpeg | ||
| 84 | magick ''${sources[7]} -crop 4152x2335+0+666 +repage -define jpeg:extent=10MB $out/weic2506a.jpeg | ||
| 85 | magick ''${sources[8]} -crop 4320x2430+0+0 +repage -define jpeg:extent=10MB $out/weic2514a.jpeg | ||
| 86 | magick ''${sources[9]} -crop 5863x3298+0+477 +repage -define jpeg:extent=10MB $out/weic2425c.jpeg | ||
| 87 | |||
| 88 | runHook postBuild | ||
| 89 | ''; | ||
| 90 | }); | ||
| 91 | niri_session = builtins.toJSON [ | ||
| 92 | (pkgs.writeShellScript "niri-session" '' | ||
| 93 | exec ${lib.getExe pkgs.dex} -w ${config.programs.niri.package}/share/wayland-sessions/niri.desktop &>/tmp/niri-session-$$.log | ||
| 94 | '') | ||
| 95 | # (lib.getExe pkgs.dex) | ||
| 96 | # "${config.programs.niri.package}/share/wayland-sessions/niri.desktop" | ||
| 97 | ]; | ||
| 98 | username = builtins.toJSON config.home.username; | ||
| 99 | mdi = builtins.toJSON (pkgs.fetchFromGitHub { | ||
| 100 | owner = "Templarian"; | ||
| 101 | repo = "MaterialDesign"; | ||
| 102 | rev = "2424e748e0cc63ab7b9c095a099b9fe239b737c0"; | ||
| 103 | hash = "sha256-QMGl7soAhErrrnY3aKOZpt49yebkSNzy10p/v5OaqQ0="; | ||
| 104 | }); | ||
| 105 | worktime = builtins.toJSON (lib.getExe pkgs.worktime); | ||
| 106 | }; | ||
| 107 | }; | ||
| 108 | }; | ||
| 109 | systemd.user.services.quickshell = { | ||
| 110 | Service = { | ||
| 111 | RuntimeDirectory = "quickshell"; | ||
| 112 | }; | ||
| 113 | }; | ||
| 114 | }; | ||
| 115 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt new file mode 100644 index 00000000..020c0515 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | set(INSTALL_QMLDIR "" CACHE STRING "QML install dir") | ||
| 2 | set(INSTALL_QML_PREFIX "" CACHE STRING "QML install prefix") | ||
| 3 | |||
| 4 | # There doesn't seem to be a standard cross-distro qml install path. | ||
| 5 | if ("${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.") | ||
| 7 | else() | ||
| 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}") | ||
| 15 | endif() | ||
| 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 | ||
| 20 | function(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() | ||
| 89 | endfunction() | ||
| 90 | |||
| 91 | |||
| 92 | cmake_minimum_required(VERSION 3.20) | ||
| 93 | project(custom LANGUAGES CXX) | ||
| 94 | |||
| 95 | find_package(Qt6 REQUIRED COMPONENTS Core Qml DBus) | ||
| 96 | |||
| 97 | qt_standard_project_setup(REQUIRES 6.6) | ||
| 98 | |||
| 99 | qt6_policy(SET QTP0001 NEW) | ||
| 100 | qt6_add_qml_module(customplugin | ||
| 101 | URI "Custom" | ||
| 102 | PLUGIN_TARGET customplugin | ||
| 103 | ) | ||
| 104 | |||
| 105 | set_source_files_properties(org.keepassxc.KeePassXC.MainWindow.xml PROPERTIES | ||
| 106 | CLASSNAME DBusKeePassXC | ||
| 107 | NO_NAMESPACE TRUE | ||
| 108 | ) | ||
| 109 | qt_add_dbus_interface(DBUS_INTERFACES | ||
| 110 | org.keepassxc.KeePassXC.MainWindow.xml | ||
| 111 | dbus_keepassxc | ||
| 112 | ) | ||
| 113 | |||
| 114 | set_source_files_properties(org.freedesktop.systemd1.Manager.xml PROPERTIES | ||
| 115 | CLASSNAME DBusSystemdManager | ||
| 116 | NO_NAMESPACE TRUE | ||
| 117 | ) | ||
| 118 | qt_add_dbus_interface(DBUS_INTERFACES | ||
| 119 | org.freedesktop.systemd1.Manager.xml | ||
| 120 | dbus_systemd_manager | ||
| 121 | ) | ||
| 122 | |||
| 123 | set_source_files_properties(org.freedesktop.login1.Manager.xml PROPERTIES | ||
| 124 | CLASSNAME DBusLogindManager | ||
| 125 | NO_NAMESPACE TRUE | ||
| 126 | ) | ||
| 127 | qt_add_dbus_interface(DBUS_INTERFACES | ||
| 128 | org.freedesktop.login1.Manager.xml | ||
| 129 | dbus_logind_manager | ||
| 130 | ) | ||
| 131 | |||
| 132 | set_source_files_properties(org.freedesktop.login1.Session.xml PROPERTIES | ||
| 133 | CLASSNAME DBusLogindSession | ||
| 134 | NO_NAMESPACE TRUE | ||
| 135 | ) | ||
| 136 | qt_add_dbus_interface(DBUS_INTERFACES | ||
| 137 | org.freedesktop.login1.Session.xml | ||
| 138 | dbus_logind_session | ||
| 139 | ) | ||
| 140 | |||
| 141 | set_source_files_properties(org.freedesktop.DBus.Properties.xml PROPERTIES | ||
| 142 | CLASSNAME DBusProperties | ||
| 143 | NO_NAMESPACE TRUE | ||
| 144 | ) | ||
| 145 | qt_add_dbus_interface(DBUS_INTERFACES | ||
| 146 | org.freedesktop.DBus.Properties.xml | ||
| 147 | dbus_properties | ||
| 148 | ) | ||
| 149 | |||
| 150 | include_directories(${CMAKE_SOURCE_DIR}/build) | ||
| 151 | |||
| 152 | target_compile_features(customplugin PUBLIC cxx_std_26) | ||
| 153 | |||
| 154 | target_link_libraries(customplugin PRIVATE | ||
| 155 | Qt6::Core | ||
| 156 | Qt6::Qml | ||
| 157 | Qt6::DBus | ||
| 158 | ) | ||
| 159 | |||
| 160 | target_sources(customplugin PRIVATE | ||
| 161 | Chrono.cpp Chrono.hpp | ||
| 162 | FileSelector.cpp FileSelector.hpp | ||
| 163 | KeePassXC.cpp KeePassXC.hpp | ||
| 164 | Systemd.cpp Systemd.hpp | ||
| 165 | ${DBUS_INTERFACES} | ||
| 166 | ) | ||
| 167 | |||
| 168 | install_qml_module(customplugin) | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp new file mode 100644 index 00000000..22b3469b --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include "Chrono.hpp" | ||
| 2 | |||
| 3 | #include <format> | ||
| 4 | #include <iostream> | ||
| 5 | #include <cmath> | ||
| 6 | |||
| 7 | Chrono::Chrono(QObject* parent): QObject(parent) { | ||
| 8 | QObject::connect(&this->timer, &QTimer::timeout, this, &Chrono::onTimeout); | ||
| 9 | this->update(); | ||
| 10 | } | ||
| 11 | |||
| 12 | bool Chrono::enabled() const { return this->mEnabled; } | ||
| 13 | |||
| 14 | void Chrono::setEnabled(bool enabled) { | ||
| 15 | if (enabled == this->mEnabled) return; | ||
| 16 | this->mEnabled = enabled; | ||
| 17 | emit this->enabledChanged(); | ||
| 18 | this->update(); | ||
| 19 | } | ||
| 20 | |||
| 21 | Chrono::Precision Chrono::precision() const { return this->mPrecision; } | ||
| 22 | |||
| 23 | void Chrono::setPrecision(Chrono::Precision precision) { | ||
| 24 | if (precision == this->mPrecision) return; | ||
| 25 | this->mPrecision = precision; | ||
| 26 | emit this->precisionChanged(); | ||
| 27 | this->update(); | ||
| 28 | } | ||
| 29 | |||
| 30 | void Chrono::onTimeout() { | ||
| 31 | this->setTime(this->targetTime); | ||
| 32 | this->schedule(this->targetTime); | ||
| 33 | } | ||
| 34 | |||
| 35 | void 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 | |||
| 44 | void 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 | |||
| 60 | void 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 | |||
| 77 | QString 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 | |||
| 81 | QDateTime Chrono::date() const { | ||
| 82 | return QDateTime::fromStdTimePoint(std::chrono::time_point_cast<std::chrono::milliseconds>(this->currentTime)); | ||
| 83 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp new file mode 100644 index 00000000..04080187 --- /dev/null +++ b/accounts/gkleen@sif/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 | |||
| 11 | class 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 | |||
| 18 | public: | ||
| 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 | |||
| 38 | signals: | ||
| 39 | void enabledChanged(); | ||
| 40 | void precisionChanged(); | ||
| 41 | void dateChanged(); | ||
| 42 | |||
| 43 | private slots: | ||
| 44 | void onTimeout(); | ||
| 45 | |||
| 46 | private: | ||
| 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@sif/shell/quickshell-plugins/FileSelector.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp new file mode 100644 index 00000000..d7051d2a --- /dev/null +++ b/accounts/gkleen@sif/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 | |||
| 11 | namespace fs = std::filesystem; | ||
| 12 | |||
| 13 | FileSelector::FileSelector(QObject* parent): QObject(parent) { | ||
| 14 | QObject::connect(&this->timer, &QTimer::timeout, this, &FileSelector::onTimeout); | ||
| 15 | this->timer.setTimerType(Qt::PreciseTimer); | ||
| 16 | } | ||
| 17 | |||
| 18 | QString FileSelector::directory() const { | ||
| 19 | return QString::fromStdString(this->mDirectory->string()); | ||
| 20 | } | ||
| 21 | void FileSelector::setDirectory(QString directory) { | ||
| 22 | this->mDirectory = directory.toStdString(); | ||
| 23 | if (this->mDirectory && this->mEpoch) | ||
| 24 | this->update(); | ||
| 25 | emit this->directoryChanged(); | ||
| 26 | } | ||
| 27 | |||
| 28 | unsigned int FileSelector::epoch() const { | ||
| 29 | return std::chrono::duration_cast<std::chrono::milliseconds>(*this->mEpoch).count(); | ||
| 30 | } | ||
| 31 | void 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 | |||
| 38 | QString FileSelector::seed() const { | ||
| 39 | return this->mSeed; | ||
| 40 | } | ||
| 41 | void FileSelector::setSeed(QString seed) { | ||
| 42 | this->mSeed = seed; | ||
| 43 | emit this->seedChanged(); | ||
| 44 | if (this->mDirectory && this->mEpoch) | ||
| 45 | emit this->selectedChanged(); | ||
| 46 | } | ||
| 47 | |||
| 48 | QString 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 | |||
| 81 | void 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 | |||
| 93 | void 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@sif/shell/quickshell-plugins/FileSelector.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.hpp new file mode 100644 index 00000000..72c4f2a7 --- /dev/null +++ b/accounts/gkleen@sif/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 | |||
| 13 | class 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 | |||
| 21 | public: | ||
| 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 | |||
| 35 | signals: | ||
| 36 | void directoryChanged(); | ||
| 37 | void epochChanged(); | ||
| 38 | void seedChanged(); | ||
| 39 | void selectedChanged(); | ||
| 40 | |||
| 41 | private slots: | ||
| 42 | void onTimeout(); | ||
| 43 | |||
| 44 | private: | ||
| 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@sif/shell/quickshell-plugins/KeePassXC.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/KeePassXC.cpp new file mode 100644 index 00000000..f6e4dd6e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/KeePassXC.cpp | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #include "KeePassXC.hpp" | ||
| 2 | |||
| 3 | #include <QDBusConnection> | ||
| 4 | |||
| 5 | KeePassXC::KeePassXC() { | ||
| 6 | this->service = new DBusKeePassXC(DBusKeePassXC::staticInterfaceName(), "/keepassxc", QDBusConnection::sessionBus(), this); | ||
| 7 | } | ||
| 8 | KeePassXC::~KeePassXC() { | ||
| 9 | if (this->service) | ||
| 10 | delete this->service; | ||
| 11 | } | ||
| 12 | |||
| 13 | void KeePassXC::lockAllDatabases() { | ||
| 14 | if (!this->service) | ||
| 15 | return; | ||
| 16 | |||
| 17 | this->service->lockAllDatabases(); | ||
| 18 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/KeePassXC.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/KeePassXC.hpp new file mode 100644 index 00000000..c4cd71e0 --- /dev/null +++ b/accounts/gkleen@sif/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 | |||
| 8 | class KeePassXC : public QObject { | ||
| 9 | Q_OBJECT; | ||
| 10 | QML_SINGLETON; | ||
| 11 | QML_ELEMENT; | ||
| 12 | |||
| 13 | public: | ||
| 14 | explicit KeePassXC(); | ||
| 15 | ~KeePassXC(); | ||
| 16 | |||
| 17 | Q_INVOKABLE void lockAllDatabases(); | ||
| 18 | |||
| 19 | private: | ||
| 20 | DBusKeePassXC* service = nullptr; | ||
| 21 | }; | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp new file mode 100644 index 00000000..308659e9 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp | |||
| @@ -0,0 +1,198 @@ | |||
| 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 | Systemd::Systemd(QObject* parent) : QObject(parent) { | ||
| 12 | this->systemdManager = new DBusSystemdManager( | ||
| 13 | "org.freedesktop.systemd1", | ||
| 14 | "/org/freedesktop/systemd1", | ||
| 15 | QDBusConnection::sessionBus(), | ||
| 16 | this | ||
| 17 | ); | ||
| 18 | this->logindManager = new DBusLogindManager( | ||
| 19 | "org.freedesktop.login1", | ||
| 20 | "/org/freedesktop/login1", | ||
| 21 | QDBusConnection::systemBus(), | ||
| 22 | this | ||
| 23 | ); | ||
| 24 | |||
| 25 | QDBusReply<QDBusObjectPath> sessionPath = this->logindManager->GetSession("auto"); | ||
| 26 | qDebug() << sessionPath; | ||
| 27 | this->logindSession = new DBusLogindSession( | ||
| 28 | "org.freedesktop.login1", | ||
| 29 | sessionPath.value().path(), | ||
| 30 | QDBusConnection::systemBus(), | ||
| 31 | this | ||
| 32 | ); | ||
| 33 | this->logindSessionProperties = new DBusProperties( | ||
| 34 | "org.freedesktop.login1", | ||
| 35 | sessionPath.value().path(), | ||
| 36 | QDBusConnection::systemBus(), | ||
| 37 | this | ||
| 38 | ); | ||
| 39 | |||
| 40 | QObject::connect(this->logindManager, &DBusLogindManager::PrepareForShutdown, this, &Systemd::shutdown); | ||
| 41 | QObject::connect(this->logindManager, &DBusLogindManager::PrepareForSleep, this, &Systemd::sleep); | ||
| 42 | QObject::connect(this->logindSession, &DBusLogindSession::Lock, this, &Systemd::lock); | ||
| 43 | QObject::connect(this->logindSession, &DBusLogindSession::Unlock, this, &Systemd::unlock); | ||
| 44 | QObject::connect(this->logindSessionProperties, &DBusProperties::PropertiesChanged, this, &Systemd::onLogindSessionPropertiesChanged); | ||
| 45 | } | ||
| 46 | |||
| 47 | void Systemd::onLogindSessionPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties) { | ||
| 48 | if (changed_properties.contains("IdleHint") || invalidated_properties.contains("IdleHint")) | ||
| 49 | emit this->idleHintChanged(); | ||
| 50 | if (changed_properties.contains("LockedHint") || invalidated_properties.contains("LockedHint")) | ||
| 51 | emit this->lockedHintChanged(); | ||
| 52 | } | ||
| 53 | |||
| 54 | void Systemd::stopUserUnit(const QString& unit, const QString& mode) { this->systemdManager->StopUnit(unit, mode); } | ||
| 55 | |||
| 56 | void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { this->logindSession->SetBrightness(subsystem, name, brightness); } | ||
| 57 | |||
| 58 | bool Systemd::idleHint() { return this->logindSession->idleHint(); } | ||
| 59 | void Systemd::setIdleHint(bool idle) { this->logindSession->SetIdleHint(idle); } | ||
| 60 | bool Systemd::lockedHint() { return this->logindSession->lockedHint(); } | ||
| 61 | void Systemd::setLockedHint(bool locked) { this->logindSession->SetLockedHint(locked); } | ||
| 62 | void Systemd::lockSession() { this->logindSession->call("Lock"); } | ||
| 63 | void Systemd::suspend() { this->logindManager->Suspend(true); } | ||
| 64 | void Systemd::hibernate() { this->logindManager->Hibernate(true); } | ||
| 65 | |||
| 66 | std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::WhatItem what) { | ||
| 67 | if (what == SystemdInhibitorParams::Shutdown) | ||
| 68 | return "shutdown"; | ||
| 69 | else if (what == SystemdInhibitorParams::Sleep) | ||
| 70 | return "sleep"; | ||
| 71 | else if (what == SystemdInhibitorParams::Idle) | ||
| 72 | return "idle"; | ||
| 73 | else if (what == SystemdInhibitorParams::HandlePowerKey) | ||
| 74 | return "handle-power-key"; | ||
| 75 | else if (what == SystemdInhibitorParams::HandleSuspendKey) | ||
| 76 | return "handle-suspend-key"; | ||
| 77 | else if (what == SystemdInhibitorParams::HandleHibernateKey) | ||
| 78 | return "handle-hibernate-key"; | ||
| 79 | else if (what == SystemdInhibitorParams::HandleLidSwitch) | ||
| 80 | return "handle-lid-switch"; | ||
| 81 | return ""; | ||
| 82 | } | ||
| 83 | |||
| 84 | std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::What what) { | ||
| 85 | std::ostringstream res; | ||
| 86 | bool first = true; | ||
| 87 | for (const WhatItem& item: SystemdInhibitorParams::allWhatItems) { | ||
| 88 | if (!(what & item)) | ||
| 89 | continue; | ||
| 90 | |||
| 91 | if (!first) | ||
| 92 | res << ":"; | ||
| 93 | else | ||
| 94 | first = false; | ||
| 95 | res << SystemdInhibitorParams::toString(item); | ||
| 96 | } | ||
| 97 | return res.str(); | ||
| 98 | } | ||
| 99 | |||
| 100 | std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::Mode mode) { | ||
| 101 | if (mode == SystemdInhibitorParams::Block) | ||
| 102 | return "block"; | ||
| 103 | else if (mode == SystemdInhibitorParams::BlockWeak) | ||
| 104 | return "block-weak"; | ||
| 105 | else if (mode == SystemdInhibitorParams::Delay) | ||
| 106 | return "delay"; | ||
| 107 | return ""; | ||
| 108 | } | ||
| 109 | |||
| 110 | bool SystemdInhibitor::enabled() const { return static_cast<bool>(this->activeInhibitor); } | ||
| 111 | void SystemdInhibitor::setEnabled(bool enabled) { | ||
| 112 | this->mEnabled = enabled; | ||
| 113 | |||
| 114 | if (enabled) | ||
| 115 | this->update(); | ||
| 116 | else | ||
| 117 | this->release(); | ||
| 118 | } | ||
| 119 | |||
| 120 | SystemdInhibitorParams::What SystemdInhibitor::what() const { return this->mWhat; } | ||
| 121 | void SystemdInhibitor::setWhat(SystemdInhibitorParams::What what) { | ||
| 122 | this->mWhat = what; | ||
| 123 | this->update(); | ||
| 124 | } | ||
| 125 | |||
| 126 | QString SystemdInhibitor::who() const { return this->mWho; } | ||
| 127 | void SystemdInhibitor::setWho(QString who) { | ||
| 128 | this->mWho = who; | ||
| 129 | this->update(); | ||
| 130 | } | ||
| 131 | |||
| 132 | QString SystemdInhibitor::why() const { return this->mWhy; } | ||
| 133 | void SystemdInhibitor::setWhy(QString why) { | ||
| 134 | this->mWhy = why; | ||
| 135 | this->update(); | ||
| 136 | } | ||
| 137 | |||
| 138 | SystemdInhibitorParams::Mode SystemdInhibitor::mode() const { return this->mMode; } | ||
| 139 | void SystemdInhibitor::setMode(SystemdInhibitorParams::Mode mode) { | ||
| 140 | this->mMode = mode; | ||
| 141 | this->update(); | ||
| 142 | } | ||
| 143 | |||
| 144 | SystemdInhibitor::ActiveSystemdInhibitor::ActiveSystemdInhibitor(SystemdInhibitorParams::What what_, QString who_, QString why_, SystemdInhibitorParams::Mode mode_): what(what_), who(who_), why(why_), mode(mode_) { | ||
| 145 | DBusLogindManager logindManager( | ||
| 146 | "org.freedesktop.login1", | ||
| 147 | "/org/freedesktop/login1", | ||
| 148 | QDBusConnection::systemBus() | ||
| 149 | ); | ||
| 150 | QDBusReply<QDBusUnixFileDescriptor> fd_ = logindManager.Inhibit(QString::fromStdString(SystemdInhibitorParams::toString(what)), who, why, QString::fromStdString(SystemdInhibitorParams::toString(mode))); | ||
| 151 | if (fd_.error().isValid()) | ||
| 152 | throw fd_.error(); | ||
| 153 | this->fd = ::dup(fd_.value().fileDescriptor()); | ||
| 154 | } | ||
| 155 | SystemdInhibitor::ActiveSystemdInhibitor::~ActiveSystemdInhibitor() { | ||
| 156 | if (this->fd != -1) | ||
| 157 | ::close(this->fd); | ||
| 158 | } | ||
| 159 | |||
| 160 | void SystemdInhibitor::release() { | ||
| 161 | if (!this->activeInhibitor) | ||
| 162 | return; | ||
| 163 | |||
| 164 | this->activeInhibitor.reset(); | ||
| 165 | emit this->enabledChanged(); | ||
| 166 | } | ||
| 167 | |||
| 168 | void SystemdInhibitor::update() { | ||
| 169 | if (!this->mWhat || this->mWho.isEmpty() || this->mWhy.isEmpty() || !this->mMode || !this->mEnabled) | ||
| 170 | if (this->activeInhibitor) | ||
| 171 | this->release(); | ||
| 172 | else | ||
| 173 | return; | ||
| 174 | |||
| 175 | if (this->activeInhibitor && this->mWhat == this->activeInhibitor->what && this->mWho == this->activeInhibitor->who && this->mWhy == this->activeInhibitor->why && this->mMode == this->activeInhibitor->mode) | ||
| 176 | return; | ||
| 177 | |||
| 178 | std::unique_ptr<ActiveSystemdInhibitor> otherInhibitor; | ||
| 179 | try { | ||
| 180 | otherInhibitor.reset(new SystemdInhibitor::ActiveSystemdInhibitor(this->mWhat, this->mWho, this->mWhy, this->mMode)); | ||
| 181 | } catch (const QDBusError& err) { | ||
| 182 | qCritical().noquote() | ||
| 183 | << err.name().toStdString() << " " << err.message().toStdString(); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | this->activeInhibitor.swap(otherInhibitor); | ||
| 187 | |||
| 188 | if (!otherInhibitor && this->activeInhibitor) | ||
| 189 | emit this->enabledChanged(); | ||
| 190 | if (otherInhibitor && otherInhibitor->what != this->activeInhibitor->what) | ||
| 191 | emit this->whatChanged(); | ||
| 192 | if (otherInhibitor && otherInhibitor->who != this->activeInhibitor->who) | ||
| 193 | emit this->whoChanged(); | ||
| 194 | if (otherInhibitor && otherInhibitor->why != this->activeInhibitor->why) | ||
| 195 | emit this->whyChanged(); | ||
| 196 | if (otherInhibitor && otherInhibitor->mode != this->activeInhibitor->mode) | ||
| 197 | emit this->modeChanged(); | ||
| 198 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp new file mode 100644 index 00000000..615024d2 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <cstdint> | ||
| 4 | #include <memory> | ||
| 5 | #include <string> | ||
| 6 | |||
| 7 | #include <QObject> | ||
| 8 | #include <QDBusInterface> | ||
| 9 | #include <QtQmlIntegration/qqmlintegration.h> | ||
| 10 | |||
| 11 | #include "dbus_systemd_manager.h" | ||
| 12 | #include "dbus_logind_manager.h" | ||
| 13 | #include "dbus_logind_session.h" | ||
| 14 | #include "dbus_properties.h" | ||
| 15 | |||
| 16 | class Systemd : public QObject { | ||
| 17 | Q_OBJECT; | ||
| 18 | QML_SINGLETON; | ||
| 19 | QML_ELEMENT; | ||
| 20 | |||
| 21 | public: | ||
| 22 | explicit Systemd(QObject* parent = nullptr); | ||
| 23 | |||
| 24 | Q_PROPERTY(bool idleHint READ idleHint WRITE setIdleHint NOTIFY idleHintChanged) | ||
| 25 | Q_PROPERTY(bool lockedHint READ lockedHint WRITE setLockedHint NOTIFY lockedHintChanged) | ||
| 26 | |||
| 27 | Q_INVOKABLE void stopUserUnit(const QString& unit, const QString& mode); | ||
| 28 | Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness); | ||
| 29 | Q_INVOKABLE void setIdleHint(bool idle); | ||
| 30 | Q_INVOKABLE void setLockedHint(bool locked); | ||
| 31 | Q_INVOKABLE void lockSession(); | ||
| 32 | Q_INVOKABLE void suspend(); | ||
| 33 | Q_INVOKABLE void hibernate(); | ||
| 34 | |||
| 35 | bool idleHint(); | ||
| 36 | bool lockedHint(); | ||
| 37 | |||
| 38 | signals: | ||
| 39 | void shutdown(bool before); | ||
| 40 | void sleep(bool before); | ||
| 41 | void lock(); | ||
| 42 | void unlock(); | ||
| 43 | void idleHintChanged(); | ||
| 44 | void lockedHintChanged(); | ||
| 45 | |||
| 46 | private slots: | ||
| 47 | void onLogindSessionPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties); | ||
| 48 | |||
| 49 | private: | ||
| 50 | DBusSystemdManager* systemdManager; | ||
| 51 | DBusLogindManager* logindManager; | ||
| 52 | DBusLogindSession* logindSession; | ||
| 53 | DBusProperties* logindSessionProperties; | ||
| 54 | }; | ||
| 55 | |||
| 56 | class SystemdInhibitorParams : public QObject { | ||
| 57 | Q_OBJECT; | ||
| 58 | QML_ELEMENT; | ||
| 59 | QML_SINGLETON; | ||
| 60 | |||
| 61 | public: | ||
| 62 | enum WhatItem : uint8_t { | ||
| 63 | Shutdown = 0b1, | ||
| 64 | Sleep = 0b10, | ||
| 65 | Idle = 0b100, | ||
| 66 | HandlePowerKey = 0b1000, | ||
| 67 | HandleSuspendKey = 0b10000, | ||
| 68 | HandleHibernateKey = 0b100000, | ||
| 69 | HandleLidSwitch = 0b1000000, | ||
| 70 | }; | ||
| 71 | Q_ENUM(WhatItem); | ||
| 72 | Q_DECLARE_FLAGS(What, WhatItem); | ||
| 73 | |||
| 74 | enum Mode : uint8_t { | ||
| 75 | Block = 1, | ||
| 76 | BlockWeak = 2, | ||
| 77 | Delay = 3, | ||
| 78 | }; | ||
| 79 | Q_ENUM(Mode); | ||
| 80 | |||
| 81 | Q_INVOKABLE static std::string toString(WhatItem what); | ||
| 82 | Q_INVOKABLE static std::string toString(What what); | ||
| 83 | Q_INVOKABLE static std::string toString(Mode mode); | ||
| 84 | |||
| 85 | static constexpr WhatItem allWhatItems[] = { Shutdown, Sleep, Idle, HandlePowerKey, HandleSuspendKey, HandleHibernateKey, HandleLidSwitch }; | ||
| 86 | }; | ||
| 87 | Q_DECLARE_OPERATORS_FOR_FLAGS(SystemdInhibitorParams::What) | ||
| 88 | |||
| 89 | class SystemdInhibitor : public QObject { | ||
| 90 | Q_OBJECT; | ||
| 91 | Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged); | ||
| 92 | Q_PROPERTY(SystemdInhibitorParams::What what READ what WRITE setWhat NOTIFY whatChanged); | ||
| 93 | Q_PROPERTY(QString who READ who WRITE setWho NOTIFY whoChanged); | ||
| 94 | Q_PROPERTY(QString why READ why WRITE setWhy NOTIFY whyChanged); | ||
| 95 | Q_PROPERTY(SystemdInhibitorParams::Mode mode READ mode WRITE setMode NOTIFY modeChanged); | ||
| 96 | QML_ELEMENT; | ||
| 97 | |||
| 98 | public: | ||
| 99 | explicit SystemdInhibitor(QObject* parent = nullptr): QObject(parent) {} | ||
| 100 | |||
| 101 | bool enabled() const; | ||
| 102 | void setEnabled(bool enabled); | ||
| 103 | |||
| 104 | SystemdInhibitorParams::What what() const; | ||
| 105 | void setWhat(SystemdInhibitorParams::What what); | ||
| 106 | |||
| 107 | QString who() const; | ||
| 108 | void setWho(QString who); | ||
| 109 | |||
| 110 | QString why() const; | ||
| 111 | void setWhy(QString why); | ||
| 112 | |||
| 113 | SystemdInhibitorParams::Mode mode() const; | ||
| 114 | void setMode(SystemdInhibitorParams::Mode mode); | ||
| 115 | |||
| 116 | Q_INVOKABLE void release(); | ||
| 117 | |||
| 118 | signals: | ||
| 119 | void enabledChanged(); | ||
| 120 | void whatChanged(); | ||
| 121 | void whoChanged(); | ||
| 122 | void whyChanged(); | ||
| 123 | void modeChanged(); | ||
| 124 | |||
| 125 | private: | ||
| 126 | class ActiveSystemdInhibitor { | ||
| 127 | public: | ||
| 128 | uint32_t fd = -1; | ||
| 129 | SystemdInhibitorParams::What what; | ||
| 130 | QString who; | ||
| 131 | QString why; | ||
| 132 | SystemdInhibitorParams::Mode mode; | ||
| 133 | |||
| 134 | ActiveSystemdInhibitor(SystemdInhibitorParams::What what_, QString who_, QString why_, SystemdInhibitorParams::Mode mode_); | ||
| 135 | ~ActiveSystemdInhibitor(); | ||
| 136 | }; | ||
| 137 | |||
| 138 | void update(); | ||
| 139 | |||
| 140 | bool mEnabled = true; | ||
| 141 | std::unique_ptr<ActiveSystemdInhibitor> activeInhibitor; | ||
| 142 | SystemdInhibitorParams::What mWhat = static_cast<SystemdInhibitorParams::What>(0); | ||
| 143 | QString mWho; | ||
| 144 | QString mWhy; | ||
| 145 | SystemdInhibitorParams::Mode mMode = static_cast<SystemdInhibitorParams::Mode>(0); | ||
| 146 | }; | ||
| 147 | |||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h b/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h new file mode 100644 index 00000000..e66ba9e3 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <QQmlEngineExtensionPlugin> | ||
| 2 | |||
| 3 | class CustomPlugin : public QQmlEngineExtensionPlugin | ||
| 4 | { | ||
| 5 | Q_OBJECT | ||
| 6 | Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) | ||
| 7 | }; | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/default.nix b/accounts/gkleen@sif/shell/quickshell-plugins/default.nix new file mode 100644 index 00000000..20a195eb --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/default.nix | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | { lib | ||
| 2 | , stdenv | ||
| 3 | , cmake | ||
| 4 | , qt6 | ||
| 5 | , fmt | ||
| 6 | , keepassxc | ||
| 7 | , systemd | ||
| 8 | }: | ||
| 9 | |||
| 10 | stdenv.mkDerivation rec { | ||
| 11 | name = "quickshell-custom"; | ||
| 12 | |||
| 13 | src = ./.; | ||
| 14 | |||
| 15 | prePatch = '' | ||
| 16 | cp ${keepassxc.src}/src/gui/org.keepassxc.KeePassXC.MainWindow.xml . | ||
| 17 | ''; | ||
| 18 | |||
| 19 | nativeBuildInputs = [ cmake qt6.wrapQtAppsHook ]; | ||
| 20 | buildInputs = [ | ||
| 21 | qt6.qtbase | ||
| 22 | qt6.qtdeclarative | ||
| 23 | ]; | ||
| 24 | |||
| 25 | cmakeFlags = [ | ||
| 26 | (lib.cmakeFeature "INSTALL_QML_PREFIX" qt6.qtbase.qtQmlPrefix) | ||
| 27 | ]; | ||
| 28 | |||
| 29 | LC_ALL = "C.UTF-8"; | ||
| 30 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml b/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.DBus.Properties.xml new file mode 100644 index 00000000..7588e7a5 --- /dev/null +++ b/accounts/gkleen@sif/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@sif/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml b/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.login1.Manager.xml new file mode 100644 index 00000000..120a06d9 --- /dev/null +++ b/accounts/gkleen@sif/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@sif/shell/quickshell-plugins/org.freedesktop.login1.Session.xml b/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.login1.Session.xml new file mode 100644 index 00000000..7d6fc8ee --- /dev/null +++ b/accounts/gkleen@sif/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@sif/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml b/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml new file mode 100644 index 00000000..b4f84a13 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/org.freedesktop.systemd1.Manager.xml | |||
| @@ -0,0 +1,817 @@ | |||
| 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 | <!-- </method> --> | ||
| 568 | <!-- <method name="ListUnitsFiltered"> --> | ||
| 569 | <!-- <arg type="as" name="states" direction="in"/> --> | ||
| 570 | <!-- <arg type="a(ssssssouso)" name="units" direction="out"/> --> | ||
| 571 | <!-- </method> --> | ||
| 572 | <!-- <method name="ListUnitsByPatterns"> --> | ||
| 573 | <!-- <arg type="as" name="states" direction="in"/> --> | ||
| 574 | <!-- <arg type="as" name="patterns" direction="in"/> --> | ||
| 575 | <!-- <arg type="a(ssssssouso)" name="units" direction="out"/> --> | ||
| 576 | <!-- </method> --> | ||
| 577 | <!-- <method name="ListUnitsByNames"> --> | ||
| 578 | <!-- <arg type="as" name="names" direction="in"/> --> | ||
| 579 | <!-- <arg type="a(ssssssouso)" name="units" direction="out"/> --> | ||
| 580 | <!-- </method> --> | ||
| 581 | <!-- <method name="ListJobs"> --> | ||
| 582 | <!-- <arg type="a(usssoo)" name="jobs" direction="out"/> --> | ||
| 583 | <!-- </method> --> | ||
| 584 | <method name="Subscribe"> | ||
| 585 | </method> | ||
| 586 | <method name="Unsubscribe"> | ||
| 587 | </method> | ||
| 588 | <method name="Dump"> | ||
| 589 | <arg type="s" name="output" direction="out"/> | ||
| 590 | </method> | ||
| 591 | <method name="DumpUnitsMatchingPatterns"> | ||
| 592 | <arg type="as" name="patterns" direction="in"/> | ||
| 593 | <arg type="s" name="output" direction="out"/> | ||
| 594 | </method> | ||
| 595 | <method name="DumpByFileDescriptor"> | ||
| 596 | <arg type="h" name="fd" direction="out"/> | ||
| 597 | </method> | ||
| 598 | <method name="DumpUnitsMatchingPatternsByFileDescriptor"> | ||
| 599 | <arg type="as" name="patterns" direction="in"/> | ||
| 600 | <arg type="h" name="fd" direction="out"/> | ||
| 601 | </method> | ||
| 602 | <method name="Reload"> | ||
| 603 | </method> | ||
| 604 | <method name="Reexecute"> | ||
| 605 | <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/> | ||
| 606 | </method> | ||
| 607 | <method name="Exit"> | ||
| 608 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 609 | </method> | ||
| 610 | <method name="Reboot"> | ||
| 611 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 612 | </method> | ||
| 613 | <method name="SoftReboot"> | ||
| 614 | <arg type="s" name="new_root" direction="in"/> | ||
| 615 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 616 | </method> | ||
| 617 | <method name="PowerOff"> | ||
| 618 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 619 | </method> | ||
| 620 | <method name="Halt"> | ||
| 621 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 622 | </method> | ||
| 623 | <method name="KExec"> | ||
| 624 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 625 | </method> | ||
| 626 | <method name="SwitchRoot"> | ||
| 627 | <arg type="s" name="new_root" direction="in"/> | ||
| 628 | <arg type="s" name="init" direction="in"/> | ||
| 629 | <annotation name="org.freedesktop.systemd1.Privileged" value="true"/> | ||
| 630 | </method> | ||
| 631 | <method name="SetEnvironment"> | ||
| 632 | <arg type="as" name="assignments" direction="in"/> | ||
| 633 | </method> | ||
| 634 | <method name="UnsetEnvironment"> | ||
| 635 | <arg type="as" name="names" direction="in"/> | ||
| 636 | </method> | ||
| 637 | <method name="UnsetAndSetEnvironment"> | ||
| 638 | <arg type="as" name="names" direction="in"/> | ||
| 639 | <arg type="as" name="assignments" direction="in"/> | ||
| 640 | </method> | ||
| 641 | <method name="EnqueueMarkedJobs"> | ||
| 642 | <arg type="ao" name="jobs" direction="out"/> | ||
| 643 | </method> | ||
| 644 | <!-- <method name="ListUnitFiles"> --> | ||
| 645 | <!-- <arg type="a(ss)" name="unit_files" direction="out"/> --> | ||
| 646 | <!-- </method> --> | ||
| 647 | <!-- <method name="ListUnitFilesByPatterns"> --> | ||
| 648 | <!-- <arg type="as" name="states" direction="in"/> --> | ||
| 649 | <!-- <arg type="as" name="patterns" direction="in"/> --> | ||
| 650 | <!-- <arg type="a(ss)" name="unit_files" direction="out"/> --> | ||
| 651 | <!-- </method> --> | ||
| 652 | <method name="GetUnitFileState"> | ||
| 653 | <arg type="s" name="file" direction="in"/> | ||
| 654 | <arg type="s" name="state" direction="out"/> | ||
| 655 | </method> | ||
| 656 | <!-- <method name="EnableUnitFiles"> --> | ||
| 657 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 658 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 659 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 660 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 661 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 662 | <!-- </method> --> | ||
| 663 | <!-- <method name="DisableUnitFiles"> --> | ||
| 664 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 665 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 666 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 667 | <!-- </method> --> | ||
| 668 | <!-- <method name="EnableUnitFilesWithFlags"> --> | ||
| 669 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 670 | <!-- <arg type="t" name="flags" direction="in"/> --> | ||
| 671 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 672 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 673 | <!-- </method> --> | ||
| 674 | <!-- <method name="DisableUnitFilesWithFlags"> --> | ||
| 675 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 676 | <!-- <arg type="t" name="flags" direction="in"/> --> | ||
| 677 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 678 | <!-- </method> --> | ||
| 679 | <!-- <method name="DisableUnitFilesWithFlagsAndInstallInfo"> --> | ||
| 680 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 681 | <!-- <arg type="t" name="flags" direction="in"/> --> | ||
| 682 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 683 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 684 | <!-- </method> --> | ||
| 685 | <!-- <method name="ReenableUnitFiles"> --> | ||
| 686 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 687 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 688 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 689 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 690 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 691 | <!-- </method> --> | ||
| 692 | <!-- <method name="LinkUnitFiles"> --> | ||
| 693 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 694 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 695 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 696 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 697 | <!-- </method> --> | ||
| 698 | <!-- <method name="PresetUnitFiles"> --> | ||
| 699 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 700 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 701 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 702 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 703 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 704 | <!-- </method> --> | ||
| 705 | <!-- <method name="PresetUnitFilesWithMode"> --> | ||
| 706 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 707 | <!-- <arg type="s" name="mode" direction="in"/> --> | ||
| 708 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 709 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 710 | <!-- <arg type="b" name="carries_install_info" direction="out"/> --> | ||
| 711 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 712 | <!-- </method> --> | ||
| 713 | <!-- <method name="MaskUnitFiles"> --> | ||
| 714 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 715 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 716 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 717 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 718 | <!-- </method> --> | ||
| 719 | <!-- <method name="UnmaskUnitFiles"> --> | ||
| 720 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 721 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 722 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 723 | <!-- </method> --> | ||
| 724 | <!-- <method name="RevertUnitFiles"> --> | ||
| 725 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 726 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 727 | <!-- </method> --> | ||
| 728 | <!-- <method name="SetDefaultTarget"> --> | ||
| 729 | <!-- <arg type="s" name="name" direction="in"/> --> | ||
| 730 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 731 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 732 | <!-- </method> --> | ||
| 733 | <method name="GetDefaultTarget"> | ||
| 734 | <arg type="s" name="name" direction="out"/> | ||
| 735 | </method> | ||
| 736 | <!-- <method name="PresetAllUnitFiles"> --> | ||
| 737 | <!-- <arg type="s" name="mode" direction="in"/> --> | ||
| 738 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 739 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 740 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 741 | <!-- </method> --> | ||
| 742 | <!-- <method name="AddDependencyUnitFiles"> --> | ||
| 743 | <!-- <arg type="as" name="files" direction="in"/> --> | ||
| 744 | <!-- <arg type="s" name="target" direction="in"/> --> | ||
| 745 | <!-- <arg type="s" name="type" direction="in"/> --> | ||
| 746 | <!-- <arg type="b" name="runtime" direction="in"/> --> | ||
| 747 | <!-- <arg type="b" name="force" direction="in"/> --> | ||
| 748 | <!-- <arg type="a(sss)" name="changes" direction="out"/> --> | ||
| 749 | <!-- </method> --> | ||
| 750 | <method name="GetUnitFileLinks"> | ||
| 751 | <arg type="s" name="name" direction="in"/> | ||
| 752 | <arg type="b" name="runtime" direction="in"/> | ||
| 753 | <arg type="as" name="links" direction="out"/> | ||
| 754 | </method> | ||
| 755 | <method name="SetExitCode"> | ||
| 756 | <arg type="y" name="number" direction="in"/> | ||
| 757 | </method> | ||
| 758 | <method name="LookupDynamicUserByName"> | ||
| 759 | <arg type="s" name="name" direction="in"/> | ||
| 760 | <arg type="u" name="uid" direction="out"/> | ||
| 761 | </method> | ||
| 762 | <method name="LookupDynamicUserByUID"> | ||
| 763 | <arg type="u" name="uid" direction="in"/> | ||
| 764 | <arg type="s" name="name" direction="out"/> | ||
| 765 | </method> | ||
| 766 | <!-- <method name="GetDynamicUsers"> --> | ||
| 767 | <!-- <arg type="a(us)" name="users" direction="out"/> --> | ||
| 768 | <!-- </method> --> | ||
| 769 | <!-- <method name="DumpUnitFileDescriptorStore"> --> | ||
| 770 | <!-- <arg type="s" name="name" direction="in"/> --> | ||
| 771 | <!-- <arg type="a(suuutuusu)" name="entries" direction="out"/> --> | ||
| 772 | <!-- </method> --> | ||
| 773 | <!-- <method name="StartAuxiliaryScope"> --> | ||
| 774 | <!-- <arg type="s" name="name" direction="in"/> --> | ||
| 775 | <!-- <arg type="ah" name="pidfds" direction="in"/> --> | ||
| 776 | <!-- <arg type="t" name="flags" direction="in"/> --> | ||
| 777 | <!-- <arg type="a(sv)" name="properties" direction="in"/> --> | ||
| 778 | <!-- <arg type="o" name="job" direction="out"/> --> | ||
| 779 | <!-- <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> --> | ||
| 780 | <!-- </method> --> | ||
| 781 | <signal name="UnitNew"> | ||
| 782 | <arg type="s" name="id"/> | ||
| 783 | <arg type="o" name="unit"/> | ||
| 784 | </signal> | ||
| 785 | <signal name="UnitRemoved"> | ||
| 786 | <arg type="s" name="id"/> | ||
| 787 | <arg type="o" name="unit"/> | ||
| 788 | </signal> | ||
| 789 | <signal name="JobNew"> | ||
| 790 | <arg type="u" name="id"/> | ||
| 791 | <arg type="o" name="job"/> | ||
| 792 | <arg type="s" name="unit"/> | ||
| 793 | </signal> | ||
| 794 | <signal name="JobRemoved"> | ||
| 795 | <arg type="u" name="id"/> | ||
| 796 | <arg type="o" name="job"/> | ||
| 797 | <arg type="s" name="unit"/> | ||
| 798 | <arg type="s" name="result"/> | ||
| 799 | </signal> | ||
| 800 | <signal name="StartupFinished"> | ||
| 801 | <arg type="t" name="firmware"/> | ||
| 802 | <arg type="t" name="loader"/> | ||
| 803 | <arg type="t" name="kernel"/> | ||
| 804 | <arg type="t" name="initrd"/> | ||
| 805 | <arg type="t" name="userspace"/> | ||
| 806 | <arg type="t" name="total"/> | ||
| 807 | </signal> | ||
| 808 | <signal name="UnitFilesChanged"> | ||
| 809 | </signal> | ||
| 810 | <signal name="Reloading"> | ||
| 811 | <arg type="b" name="active"/> | ||
| 812 | </signal> | ||
| 813 | </interface> | ||
| 814 | <node name="unit"/> | ||
| 815 | <node name="job"/> | ||
| 816 | </node> | ||
| 817 | |||
| diff --git a/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml b/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml new file mode 100644 index 00000000..dcc23279 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | import QtQuick | ||
| 2 | import qs.Services | ||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Widgets | ||
| 5 | |||
| 6 | Item { | ||
| 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@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml new file mode 100644 index 00000000..9210066c --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | import Quickshell | ||
| 2 | import Quickshell.Wayland | ||
| 3 | import QtQuick | ||
| 4 | |||
| 5 | PanelWindow { | ||
| 6 | id: bar | ||
| 7 | |||
| 8 | required property var modelData | ||
| 9 | screen: modelData | ||
| 10 | |||
| 11 | WlrLayershell.namespace: "bar" | ||
| 12 | |||
| 13 | anchors { | ||
| 14 | top: true | ||
| 15 | left: true | ||
| 16 | right: true | ||
| 17 | } | ||
| 18 | margins { | ||
| 19 | left: 26 + 8 | ||
| 20 | right: 26 + 8 | ||
| 21 | } | ||
| 22 | |||
| 23 | implicitHeight: 21 | ||
| 24 | color: "transparent" | ||
| 25 | |||
| 26 | Rectangle { | ||
| 27 | color: Qt.rgba(0, 0, 0, 0.75) | ||
| 28 | anchors.fill: parent | ||
| 29 | // bottomLeftRadius: 8 | ||
| 30 | // bottomRightRadius: 8 | ||
| 31 | } | ||
| 32 | |||
| 33 | Row { | ||
| 34 | id: left | ||
| 35 | |||
| 36 | height: parent.height | ||
| 37 | width: childrenRect.width | ||
| 38 | anchors.left: parent.left | ||
| 39 | anchors.leftMargin: 8 | ||
| 40 | anchors.verticalCenter: parent.verticalCenter | ||
| 41 | spacing: 8 | ||
| 42 | |||
| 43 | WorkspaceSwitcher { | ||
| 44 | screen: bar.screen | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | Row { | ||
| 49 | id: center | ||
| 50 | |||
| 51 | height: parent.height | ||
| 52 | width: childrenRect.width | ||
| 53 | anchors.centerIn: parent | ||
| 54 | spacing: 5 | ||
| 55 | |||
| 56 | ActiveWindowDisplay { | ||
| 57 | screen: bar.screen | ||
| 58 | maxWidth: bar.width - 2*Math.max(left.width, right.width) - 2*8 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | Row { | ||
| 63 | id: right | ||
| 64 | |||
| 65 | height: parent.height | ||
| 66 | width: childrenRect.width | ||
| 67 | anchors.right: parent.right | ||
| 68 | anchors.rightMargin: 8 | ||
| 69 | anchors.verticalCenter: parent.verticalCenter | ||
| 70 | spacing: 0 | ||
| 71 | |||
| 72 | // WorktimeWidget { command: "time"; } | ||
| 73 | |||
| 74 | // WorktimeWidget { command: "today"; } | ||
| 75 | |||
| 76 | KeyboardLayout {} | ||
| 77 | |||
| 78 | Item { | ||
| 79 | visible: privacy.visible | ||
| 80 | height: parent.height | ||
| 81 | width: 8 - 4 | ||
| 82 | } | ||
| 83 | |||
| 84 | PrivacyWidget { | ||
| 85 | id: privacy | ||
| 86 | } | ||
| 87 | |||
| 88 | Item { | ||
| 89 | visible: privacy.visible | ||
| 90 | height: parent.height | ||
| 91 | width: 8 - 4 | ||
| 92 | } | ||
| 93 | |||
| 94 | SystemTray {} | ||
| 95 | |||
| 96 | PipewireWidget {} | ||
| 97 | |||
| 98 | BrightnessWidget {} | ||
| 99 | |||
| 100 | BatteryWidget {} | ||
| 101 | |||
| 102 | WaylandInhibitorWidget { | ||
| 103 | window: bar | ||
| 104 | } | ||
| 105 | |||
| 106 | NotificationInhibitorWidget {} | ||
| 107 | |||
| 108 | LidSwitchInhibitorWidget {} | ||
| 109 | |||
| 110 | Item { | ||
| 111 | height: parent.height | ||
| 112 | width: 8 - 4 | ||
| 113 | } | ||
| 114 | |||
| 115 | Clock {} | ||
| 116 | } | ||
| 117 | } \ No newline at end of file | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml new file mode 100644 index 00000000..da17df2a --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | import QtQuick | ||
| 2 | import Quickshell | ||
| 3 | import Quickshell.Widgets | ||
| 4 | import Quickshell.Services.UPower | ||
| 5 | |||
| 6 | Item { | ||
| 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 | const stateStr = UPowerDeviceState.toString(root.batteryDevice.state); | ||
| 106 | var outStr = stateStr; | ||
| 107 | if (root.batteryDevice.state != UPowerDeviceState.FullyCharged) | ||
| 108 | outStr += ` ${Math.round(root.batteryDevice.percentage * 100)}%`; | ||
| 109 | |||
| 110 | function formatTime(t) { | ||
| 111 | var res = ""; | ||
| 112 | for (const unit of [{ "s": "h", "v": 3600 }, { "s": "m", "v": 60 }, { "s": "s", "v": 1 }]) { | ||
| 113 | if (t < unit.v) | ||
| 114 | continue; | ||
| 115 | res += Math.floor(t / unit.v) + unit.s; | ||
| 116 | t %= unit.v; | ||
| 117 | } | ||
| 118 | return res; | ||
| 119 | } | ||
| 120 | if (root.batteryDevice.timeToEmpty != 0) { | ||
| 121 | const tStr = formatTime(Math.floor(root.batteryDevice.timeToEmpty / 60) * 60); | ||
| 122 | if (tStr) | ||
| 123 | outStr += " " + tStr; | ||
| 124 | } else if (root.batteryDevice.timeToFull != 0) { | ||
| 125 | const tStr = formatTime(Math.ceil(root.batteryDevice.timeToFull / 60) * 60); | ||
| 126 | if (tStr) | ||
| 127 | outStr += " " + tStr; | ||
| 128 | } | ||
| 129 | |||
| 130 | return outStr; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml b/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml new file mode 100644 index 00000000..a432179e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Layouts | ||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Widgets | ||
| 5 | import qs.Services | ||
| 6 | |||
| 7 | Scope { | ||
| 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@sif/shell/quickshell/BrightnessWidget.qml b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml new file mode 100644 index 00000000..3bb5a80e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | import QtQuick | ||
| 2 | import Quickshell | ||
| 3 | import Quickshell.Widgets | ||
| 4 | import qs.Services | ||
| 5 | |||
| 6 | Item { | ||
| 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@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml new file mode 100644 index 00000000..b7004528 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml | |||
| @@ -0,0 +1,295 @@ | |||
| 1 | import QtQml | ||
| 2 | import QtQuick | ||
| 3 | import Quickshell | ||
| 4 | import Custom as Custom | ||
| 5 | import QtQuick.Controls | ||
| 6 | import QtQuick.Layouts | ||
| 7 | import Quickshell.Widgets | ||
| 8 | |||
| 9 | Item { | ||
| 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@sif/shell/quickshell/KeyboardLayout.qml b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml new file mode 100644 index 00000000..46302e54 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | import Quickshell | ||
| 2 | import QtQuick | ||
| 3 | import qs.Services | ||
| 4 | import Quickshell.Widgets | ||
| 5 | |||
| 6 | Item { | ||
| 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@sif/shell/quickshell/LidSwitchInhibitorWidget.qml b/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml new file mode 100644 index 00000000..8410dcda --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | import Quickshell | ||
| 2 | import QtQuick | ||
| 3 | import Quickshell.Widgets | ||
| 4 | import qs.Services | ||
| 5 | |||
| 6 | Item { | ||
| 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@sif/shell/quickshell/LockSurface.qml b/accounts/gkleen@sif/shell/quickshell/LockSurface.qml new file mode 100644 index 00000000..f4f8f0cd --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/LockSurface.qml | |||
| @@ -0,0 +1,227 @@ | |||
| 1 | import Quickshell.Widgets | ||
| 2 | import QtQuick.Effects | ||
| 3 | import QtQuick.Layouts | ||
| 4 | import QtQuick | ||
| 5 | import QtQuick.Controls | ||
| 6 | import QtQuick.Controls.Fusion | ||
| 7 | import qs.Services | ||
| 8 | import QtQml | ||
| 9 | |||
| 10 | Item { | ||
| 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@sif/shell/quickshell/Lockscreen.qml b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml new file mode 100644 index 00000000..996fd41b --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml | |||
| @@ -0,0 +1,132 @@ | |||
| 1 | import Quickshell | ||
| 2 | import Quickshell.Wayland | ||
| 3 | import Quickshell.Io | ||
| 4 | import Quickshell.Services.Pam | ||
| 5 | import Quickshell.Services.Mpris | ||
| 6 | import Custom as Custom | ||
| 7 | import qs.Services | ||
| 8 | import QtQml | ||
| 9 | |||
| 10 | Scope { | ||
| 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 | IpcHandler { | ||
| 35 | target: "Lockscreen" | ||
| 36 | |||
| 37 | function setLocked(locked: bool): void { lock.locked = locked; } | ||
| 38 | function getLocked(): bool { return lock.locked; } | ||
| 39 | } | ||
| 40 | |||
| 41 | Connections { | ||
| 42 | target: Custom.Systemd | ||
| 43 | function onSleep(before: bool) { | ||
| 44 | console.log(`received prepare for sleep ${before}`); | ||
| 45 | if (before) | ||
| 46 | lock.locked = true; | ||
| 47 | } | ||
| 48 | function onLock() { lock.locked = true; } | ||
| 49 | function onUnlock() { lock.locked = false; } | ||
| 50 | } | ||
| 51 | |||
| 52 | IdleMonitor { | ||
| 53 | id: idleMonitor | ||
| 54 | enabled: !lock.secure | ||
| 55 | timeout: 600 | ||
| 56 | respectInhibitors: true | ||
| 57 | |||
| 58 | onIsIdleChanged: { | ||
| 59 | if (idleMonitor.isIdle) | ||
| 60 | lock.locked = true; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | Custom.SystemdInhibitor { | ||
| 65 | enabled: !lock.secure | ||
| 66 | |||
| 67 | what: Custom.SystemdInhibitorParams.Sleep | ||
| 68 | who: "quickshell" | ||
| 69 | why: "Lock session" | ||
| 70 | mode: Custom.SystemdInhibitorParams.Delay | ||
| 71 | } | ||
| 72 | |||
| 73 | Binding { | ||
| 74 | target: NotificationManager | ||
| 75 | property: "lockscreenActive" | ||
| 76 | value: lock.locked | ||
| 77 | } | ||
| 78 | |||
| 79 | WlSessionLock { | ||
| 80 | id: lock | ||
| 81 | |||
| 82 | onLockStateChanged: { | ||
| 83 | if (!locked && pam.active) | ||
| 84 | pam.abort(); | ||
| 85 | |||
| 86 | if (locked) { | ||
| 87 | NiriService.sendCommand({ "Action": { "PowerOffMonitors": {} } }, _ => {}); | ||
| 88 | Custom.KeePassXC.lockAllDatabases(); | ||
| 89 | Array.from(MprisProxy.players).forEach(player => { | ||
| 90 | if (player.canPause && player.isPlaying) | ||
| 91 | player.pause(); | ||
| 92 | }); | ||
| 93 | // Custom.Systemd.stopUserUnit("gpg-agent.service", "replace"); | ||
| 94 | GpgAgent.reloadAgent(); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | Component.onCompleted: { (_ => {})(MprisProxy.players); } | ||
| 98 | |||
| 99 | onSecureStateChanged: Custom.Systemd.lockedHint = lock.secure | ||
| 100 | |||
| 101 | WlSessionLockSurface { | ||
| 102 | id: lockSurface | ||
| 103 | |||
| 104 | color: "black" | ||
| 105 | |||
| 106 | LockSurface { | ||
| 107 | id: surfaceContent | ||
| 108 | |||
| 109 | onResponse: responseText => pam.respond(responseText) | ||
| 110 | onAuthRunningChanged: { | ||
| 111 | if (authRunning) | ||
| 112 | pam.start(); | ||
| 113 | } | ||
| 114 | Connections { | ||
| 115 | target: pam | ||
| 116 | function onMessagesChanged() { surfaceContent.messages = pam.messages; } | ||
| 117 | function onResponseRequiredChanged() { surfaceContent.responseRequired = pam.responseRequired; } | ||
| 118 | function onActiveChanged() { surfaceContent.authRunning = pam.active; } | ||
| 119 | } | ||
| 120 | onCurrentTextChanged: lockscreen.currentText = currentText | ||
| 121 | Connections { | ||
| 122 | target: lockscreen | ||
| 123 | function onCurrentTextChanged() { surfaceContent.currentText = lockscreen.currentText; } | ||
| 124 | } | ||
| 125 | Connections { | ||
| 126 | target: lockSurface | ||
| 127 | function onScreenChanged() { surfaceContent.screen = lockSurface.screen; } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml b/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml new file mode 100644 index 00000000..155a009e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Effects | ||
| 3 | |||
| 4 | Item { | ||
| 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@sif/shell/quickshell/NiriIdle.qml b/accounts/gkleen@sif/shell/quickshell/NiriIdle.qml new file mode 100644 index 00000000..beff205c --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/NiriIdle.qml | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | import QtQml | ||
| 2 | import Quickshell | ||
| 3 | import Quickshell.Wayland | ||
| 4 | import qs.Services | ||
| 5 | import Custom as Custom | ||
| 6 | |||
| 7 | Scope { | ||
| 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@sif/shell/quickshell/NotificationDisplay.qml b/accounts/gkleen@sif/shell/quickshell/NotificationDisplay.qml new file mode 100644 index 00000000..cc0e49b1 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/NotificationDisplay.qml | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | import QtQml | ||
| 2 | import QtQml.Models | ||
| 3 | import QtQuick | ||
| 4 | import Quickshell | ||
| 5 | import Quickshell.Widgets | ||
| 6 | import Quickshell.Wayland | ||
| 7 | import qs.Services | ||
| 8 | import QtQuick.Layouts | ||
| 9 | import Quickshell.Services.Notifications | ||
| 10 | |||
| 11 | Scope { | ||
| 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@sif/shell/quickshell/NotificationInhibitorWidget.qml b/accounts/gkleen@sif/shell/quickshell/NotificationInhibitorWidget.qml new file mode 100644 index 00000000..b58467b3 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/NotificationInhibitorWidget.qml | |||
| @@ -0,0 +1,266 @@ | |||
| 1 | import Quickshell | ||
| 2 | import QtQuick | ||
| 3 | import Quickshell.Widgets | ||
| 4 | import qs.Services | ||
| 5 | import QtQuick.Controls | ||
| 6 | import QtQuick.Layouts | ||
| 7 | import QtQuick.Shapes | ||
| 8 | |||
| 9 | Item { | ||
| 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 && (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@sif/shell/quickshell/PipewireWidget.qml b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml new file mode 100644 index 00000000..9c6b65a4 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Layouts | ||
| 3 | import QtQuick.Controls.Fusion | ||
| 4 | import Quickshell | ||
| 5 | import Quickshell.Services.Pipewire | ||
| 6 | import Quickshell.Widgets | ||
| 7 | |||
| 8 | Item { | ||
| 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@sif/shell/quickshell/PrivacyWidget.qml b/accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml new file mode 100644 index 00000000..d7ffadfe --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Layouts | ||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Widgets | ||
| 5 | import qs.Services | ||
| 6 | |||
| 7 | Item { | ||
| 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@sif/shell/quickshell/Services/Brightness.qml b/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml new file mode 100644 index 00000000..8318df50 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import QtQml | ||
| 4 | import Quickshell | ||
| 5 | import Quickshell.Io | ||
| 6 | import Custom as Custom | ||
| 7 | |||
| 8 | Singleton { | ||
| 9 | id: root | ||
| 10 | |||
| 11 | property string subsystem: "backlight" | ||
| 12 | property string device: "intel_backlight" | ||
| 13 | |||
| 14 | property real currBrightness | ||
| 15 | property real exponent: 4 | ||
| 16 | |||
| 17 | function calcCurrBrightness() { | ||
| 18 | if (!currFile.loaded || !maxFile.loaded) | ||
| 19 | return undefined; | ||
| 20 | const curr = Number(currFile.text()); | ||
| 21 | const max = Number(maxFile.text()); | ||
| 22 | const val = Math.pow(curr / max, 1 / root.exponent); | ||
| 23 | return val; | ||
| 24 | } | ||
| 25 | |||
| 26 | Connections { | ||
| 27 | target: currFile | ||
| 28 | function onLoaded() { | ||
| 29 | const b = root.calcCurrBrightness(); | ||
| 30 | if (typeof b !== 'undefined') | ||
| 31 | root.currBrightness = b; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | Connections { | ||
| 35 | target: maxFile | ||
| 36 | function onLoaded() { | ||
| 37 | const b = root.calcCurrBrightness(); | ||
| 38 | if (typeof b !== 'undefined') | ||
| 39 | root.currBrightness = b; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | onCurrBrightnessChanged: { | ||
| 44 | root.currBrightness = Math.max(0, Math.min(1, root.currBrightness)); | ||
| 45 | |||
| 46 | const prev = root.calcCurrBrightness(); | ||
| 47 | if (typeof prev === 'undefined' || Math.abs(root.currBrightness - prev) < 0.01) | ||
| 48 | return; | ||
| 49 | |||
| 50 | const max = Number(maxFile.text()); | ||
| 51 | const actual = Number(currFile.text()); | ||
| 52 | let curr = Math.max(0, Math.min(max, Math.pow(root.currBrightness, root.exponent) * max)); | ||
| 53 | if (Math.round(curr) == actual && curr < actual) | ||
| 54 | curr = Math.max(0, actual - 1); | ||
| 55 | else if (Math.round(curr) == actual && curr > actual) | ||
| 56 | curr = Math.min(max, actual + 1); | ||
| 57 | // root.currBrightness = Math.pow(curr / max, 1 / root.exponent); | ||
| 58 | Custom.Systemd.setBrightness(root.subsystem, root.device, Math.round(curr)); | ||
| 59 | } | ||
| 60 | |||
| 61 | FileView { | ||
| 62 | id: currFile | ||
| 63 | path: `/sys/class/${root.subsystem}/${root.device}/brightness` | ||
| 64 | blockAllReads: true | ||
| 65 | watchChanges: true | ||
| 66 | onFileChanged: reload() | ||
| 67 | } | ||
| 68 | FileView { | ||
| 69 | id: maxFile | ||
| 70 | path: `/sys/class/${root.subsystem}/${root.device}/max_brightness` | ||
| 71 | blockAllReads: true | ||
| 72 | watchChanges: true | ||
| 73 | onFileChanged: reload() | ||
| 74 | } | ||
| 75 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/Services/GpgAgent.qml b/accounts/gkleen@sif/shell/quickshell/Services/GpgAgent.qml new file mode 100644 index 00000000..3de69535 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/GpgAgent.qml | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Io | ||
| 5 | |||
| 6 | Singleton { | ||
| 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@sif/shell/quickshell/Services/InhibitorState.qml b/accounts/gkleen@sif/shell/quickshell/Services/InhibitorState.qml new file mode 100644 index 00000000..fe48fd7f --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/InhibitorState.qml | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Custom as Custom | ||
| 5 | |||
| 6 | Singleton { | ||
| 7 | id: inhibitorState | ||
| 8 | |||
| 9 | property bool waylandIdleInhibited: false | ||
| 10 | property alias lidSwitchInhibited: lidSwitchInhibitor.enabled | ||
| 11 | |||
| 12 | Custom.SystemdInhibitor { | ||
| 13 | id: lidSwitchInhibitor | ||
| 14 | |||
| 15 | enabled: false | ||
| 16 | |||
| 17 | what: Custom.SystemdInhibitorParams.HandleLidSwitch | ||
| 18 | who: "quickshell" | ||
| 19 | why: "User request" | ||
| 20 | mode: Custom.SystemdInhibitorParams.BlockWeak | ||
| 21 | } | ||
| 22 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml b/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml new file mode 100644 index 00000000..e3ab9755 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Services.Mpris | ||
| 5 | |||
| 6 | Scope { | ||
| 7 | property list<var> players: Mpris.players.values | ||
| 8 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml new file mode 100644 index 00000000..cce614eb --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Io | ||
| 5 | import QtQuick | ||
| 6 | |||
| 7 | Singleton { | ||
| 8 | id: root | ||
| 9 | |||
| 10 | property var workspaces: [] | ||
| 11 | property var outputs: {} | ||
| 12 | property var keyboardLayouts: {} | ||
| 13 | property var windows: [] | ||
| 14 | readonly property string socketPath: Quickshell.env("NIRI_SOCKET") | ||
| 15 | |||
| 16 | function refreshOutputs() { | ||
| 17 | commandSocket.sendCommand("Outputs", data => { | ||
| 18 | outputs = data.Ok.Outputs; | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | function sendCommand(command, callback) { | ||
| 23 | commandSocket.sendCommand(command, callback); | ||
| 24 | } | ||
| 25 | |||
| 26 | Socket { | ||
| 27 | id: eventStreamSocket | ||
| 28 | path: root.socketPath | ||
| 29 | connected: true | ||
| 30 | |||
| 31 | property bool acked: false | ||
| 32 | |||
| 33 | onConnectionStateChanged: { | ||
| 34 | if (connected) { | ||
| 35 | acked = false; | ||
| 36 | write('"EventStream"\n'); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | parser: SplitParser { | ||
| 41 | onRead: line => { | ||
| 42 | try { | ||
| 43 | const event = JSON.parse(line) | ||
| 44 | |||
| 45 | // console.log(JSON.stringify(event)) | ||
| 46 | |||
| 47 | if (event.WorkspacesChanged) { | ||
| 48 | root.workspaces = event.WorkspacesChanged.workspaces | ||
| 49 | root.refreshOutputs(); | ||
| 50 | } else if (event.WorkspaceActivated) | ||
| 51 | eventWorkspaceActivated(event.WorkspaceActivated); | ||
| 52 | else if (event.WorkspaceUrgencyChanged) | ||
| 53 | eventWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged); | ||
| 54 | else if (event.WorkspaceActiveWindowChanged) | ||
| 55 | eventWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged); | ||
| 56 | else if (event.KeyboardLayoutsChanged) | ||
| 57 | root.keyboardLayouts = event.KeyboardLayoutsChanged.keyboard_layouts; | ||
| 58 | else if (event.KeyboardLayoutSwitched) | ||
| 59 | root.keyboardLayouts = Object.assign({}, root.keyboardLayouts, {"current_idx": event.KeyboardLayoutSwitched.idx }); | ||
| 60 | else if (event.WindowsChanged) | ||
| 61 | root.windows = event.WindowsChanged.windows | ||
| 62 | else if (event.WindowOpenedOrChanged) | ||
| 63 | eventWindowOpenedOrChanged(event.WindowOpenedOrChanged); | ||
| 64 | else if (event.WindowClosed) | ||
| 65 | eventWindowClosed(event.WindowClosed); | ||
| 66 | else if (event.WindowFocusChanged) | ||
| 67 | eventWindowFocusChanged(event.WindowFocusChanged); | ||
| 68 | else if (event.WindowUrgencyChanged) | ||
| 69 | eventWindowUrgencyChanged(event.WindowUrgencyChanged); | ||
| 70 | else if (event.WindowLayoutsChanged) | ||
| 71 | eventWindowLayoutsChanged(event.WindowLayoutsChanged); | ||
| 72 | else if (event.Ok && !eventStreamSocket.acked) { eventStreamSocket.acked = true; } | ||
| 73 | else if (event.OverviewOpenedOrClosed) {} | ||
| 74 | else if (event.ConfigLoaded) {} | ||
| 75 | else | ||
| 76 | console.log(JSON.stringify(event)); | ||
| 77 | } catch (e) { | ||
| 78 | console.warn("NiriService: Failed to parse event:", line, e) | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | Socket { | ||
| 85 | id: commandSocket | ||
| 86 | path: root.socketPath | ||
| 87 | connected: true | ||
| 88 | |||
| 89 | property var awaitingAnswer: null | ||
| 90 | property var cmdQueue: [] | ||
| 91 | |||
| 92 | parser: SplitParser { | ||
| 93 | onRead: line => { | ||
| 94 | if (commandSocket.awaitingAnswer === null) | ||
| 95 | return; | ||
| 96 | |||
| 97 | try { | ||
| 98 | const response = JSON.parse(line); | ||
| 99 | commandSocket.awaitingAnswer.callback(response); | ||
| 100 | commandSocket.awaitingAnswer = null; | ||
| 101 | } catch (e) { | ||
| 102 | console.warn("NiriService: Failed to parse response:", line, e) | ||
| 103 | } | ||
| 104 | commandSocket._handleQueue(); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | onCmdQueueChanged: { | ||
| 109 | _handleQueue(); | ||
| 110 | } | ||
| 111 | onAwaitingAnswerChanged: { | ||
| 112 | _handleQueue(); | ||
| 113 | } | ||
| 114 | |||
| 115 | function _handleQueue() { | ||
| 116 | if (cmdQueue.length <= 0 || awaitingAnswer !== null) | ||
| 117 | return; | ||
| 118 | |||
| 119 | let localQueue = Array.from(cmdQueue); | ||
| 120 | awaitingAnswer = localQueue.shift(); | ||
| 121 | cmdQueue = localQueue; | ||
| 122 | write(JSON.stringify(awaitingAnswer.command) + '\n'); | ||
| 123 | } | ||
| 124 | |||
| 125 | function sendCommand(command, callback) { | ||
| 126 | cmdQueue = Array.from(cmdQueue).concat([{ "command": command, "callback": callback }]) | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | function eventWorkspaceActivated(data) { | ||
| 131 | let relevant_output = null; | ||
| 132 | Array.from(root.workspaces).forEach(ws => { | ||
| 133 | if (data.id === ws.id) | ||
| 134 | relevant_output = ws.output; | ||
| 135 | }); | ||
| 136 | root.workspaces = Array.from(root.workspaces).map(ws => { | ||
| 137 | if (data.focused) | ||
| 138 | ws.is_focused = false; | ||
| 139 | if (ws.output === relevant_output) | ||
| 140 | ws.is_active = false; | ||
| 141 | if (data.id === ws.id) { | ||
| 142 | ws.is_active = true; | ||
| 143 | ws.is_focused = data.focused; | ||
| 144 | } | ||
| 145 | return ws; | ||
| 146 | }); | ||
| 147 | } | ||
| 148 | function eventWorkspaceUrgencyChanged(data) { | ||
| 149 | root.workspaces = Array.from(root.workspaces).map(ws => { | ||
| 150 | if (data.id == ws.id) | ||
| 151 | ws.is_urgent = data.urgent; | ||
| 152 | return ws; | ||
| 153 | }); | ||
| 154 | } | ||
| 155 | function eventWorkspaceActiveWindowChanged(data) { | ||
| 156 | root.workspaces = Array.from(root.workspaces).map(ws => { | ||
| 157 | if (data.workspace_id === ws.id) | ||
| 158 | ws.active_window_id = data.active_window_id; | ||
| 159 | return ws; | ||
| 160 | }); | ||
| 161 | } | ||
| 162 | function eventWindowOpenedOrChanged(data) { | ||
| 163 | root.windows = Array.from(root.windows).map(win => { | ||
| 164 | if (data.window.is_focused) | ||
| 165 | win.is_focused = false; | ||
| 166 | return win; | ||
| 167 | }).filter(win => win.id !== data.window.id).concat([data.window]); | ||
| 168 | } | ||
| 169 | function eventWindowClosed(data) { | ||
| 170 | root.windows = Array.from(root.windows).filter(win => win.id !== data.id); | ||
| 171 | } | ||
| 172 | function eventWindowFocusChanged(data) { | ||
| 173 | root.windows = Array.from(root.windows).map(win => { | ||
| 174 | win.is_focused = win.id === data.id; | ||
| 175 | return win; | ||
| 176 | }); | ||
| 177 | } | ||
| 178 | function eventWindowUrgencyChanged(data) { | ||
| 179 | root.windows = Array.from(root.windows).map(win => { | ||
| 180 | if (win.id === data.id) | ||
| 181 | win.is_urgent = data.urgent; | ||
| 182 | return win; | ||
| 183 | }); | ||
| 184 | } | ||
| 185 | function eventWindowLayoutsChanged(data) { | ||
| 186 | root.windows = Array.from(root.windows).map(win => { | ||
| 187 | Array.from(data.changes).forEach(change => { | ||
| 188 | if (win.id === change[0]) | ||
| 189 | win.layout = change[1]; | ||
| 190 | }); | ||
| 191 | return win; | ||
| 192 | }); | ||
| 193 | } | ||
| 194 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/Services/NotificationManager.qml b/accounts/gkleen@sif/shell/quickshell/Services/NotificationManager.qml new file mode 100644 index 00000000..f02d1695 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/NotificationManager.qml | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import QtQml | ||
| 4 | import Quickshell | ||
| 5 | import Quickshell.Services.Notifications | ||
| 6 | |||
| 7 | Singleton { | ||
| 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.toLocaleTimeString(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@sif/shell/quickshell/Services/Privacy.qml b/accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml new file mode 100644 index 00000000..9c813e49 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | pragma Singleton | ||
| 2 | |||
| 3 | import QtQml | ||
| 4 | import Quickshell | ||
| 5 | import Quickshell.Services.Pipewire | ||
| 6 | |||
| 7 | Singleton { | ||
| 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@sif/shell/quickshell/Services/WallpaperSelector.qml b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml new file mode 100644 index 00000000..3c524955 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | import Custom as Custom | ||
| 2 | |||
| 3 | Custom.FileSelector { | ||
| 4 | id: root | ||
| 5 | |||
| 6 | directory: @wallpapers@ | ||
| 7 | epoch: 72000000 | ||
| 8 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml new file mode 100644 index 00000000..f7b4ed96 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml | |||
| @@ -0,0 +1,201 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Effects | ||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Widgets | ||
| 5 | import Quickshell.Services.SystemTray | ||
| 6 | |||
| 7 | Item { | ||
| 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); | ||
| 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@sif/shell/quickshell/UnixIPC.qml b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml new file mode 100644 index 00000000..05a40dbc --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | import Quickshell | ||
| 2 | import Quickshell.Io | ||
| 3 | import Quickshell.Services.Pipewire | ||
| 4 | import Quickshell.Services.Mpris | ||
| 5 | import qs.Services | ||
| 6 | import Custom as Custom | ||
| 7 | import QtQml | ||
| 8 | |||
| 9 | Scope { | ||
| 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 | ||
| 43 | console.warn("UnixIPC: Command not handled:", JSON.stringify(command)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | onError: e => { | ||
| 48 | if (e == 1) | ||
| 49 | return; | ||
| 50 | console.warn("QLocalSocket::LocalSocketError", e); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | PwObjectTracker { | ||
| 56 | objects: [ Pipewire.defaultAudioSink, Pipewire.defaultAudioSource ] | ||
| 57 | } | ||
| 58 | function onCommandVolume(command) { | ||
| 59 | if (command.muted === "toggle") | ||
| 60 | Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted; | ||
| 61 | if (command.volume === "up") | ||
| 62 | Pipewire.defaultAudioSink.audio.volume += 0.02; | ||
| 63 | if (command.volume === "down") | ||
| 64 | Pipewire.defaultAudioSink.audio.volume -= 0.02; | ||
| 65 | |||
| 66 | if (command["mic-muted"] === "toggle") | ||
| 67 | Pipewire.defaultAudioSource.audio.muted = !Pipewire.defaultAudioSource.audio.muted; | ||
| 68 | } | ||
| 69 | |||
| 70 | function onCommandBrightness(command) { | ||
| 71 | if (command === "up") | ||
| 72 | Brightness.currBrightness += 0.02 | ||
| 73 | if (command === "down") | ||
| 74 | Brightness.currBrightness -= 0.02 | ||
| 75 | } | ||
| 76 | |||
| 77 | function onCommandMpris(command) { | ||
| 78 | if (command.PauseAll) | ||
| 79 | Array.from(MprisProxy.players).forEach(player => { | ||
| 80 | if (player.canPause && player.isPlaying) | ||
| 81 | player.pause(); | ||
| 82 | }); | ||
| 83 | } | ||
| 84 | Component.onCompleted: { (_ => {})(MprisProxy.players); } | ||
| 85 | |||
| 86 | function onCommandNotifications(command) { | ||
| 87 | if (command.DismissGroup && NotificationManager.active) { | ||
| 88 | if (NotificationManager.groups.length > 0) | ||
| 89 | for (const notif of [...NotificationManager.groups[0]]) | ||
| 90 | notif.dismiss(); | ||
| 91 | } | ||
| 92 | if (command.DismissAll && NotificationManager.active) { | ||
| 93 | for (const notif of [...NotificationManager.trackedNotifications.values]) | ||
| 94 | notif.dismiss(); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml b/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml new file mode 100644 index 00000000..653f4763 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | import QtQuick | ||
| 2 | import QtQuick.Layouts | ||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Services.Pipewire | ||
| 5 | import Quickshell.Widgets | ||
| 6 | |||
| 7 | Scope { | ||
| 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 | ||
| 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 | ||
| 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@sif/shell/quickshell/WallpaperBackground.qml b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml new file mode 100644 index 00000000..4f85a900 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | import QtQuick | ||
| 2 | import Quickshell | ||
| 3 | import qs.Services | ||
| 4 | |||
| 5 | Item { | ||
| 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@sif/shell/quickshell/WaylandInhibitorWidget.qml b/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml new file mode 100644 index 00000000..0512ff51 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | import Quickshell | ||
| 2 | import QtQuick | ||
| 3 | import Quickshell.Widgets | ||
| 4 | import Quickshell.Wayland | ||
| 5 | import qs.Services | ||
| 6 | |||
| 7 | Item { | ||
| 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@sif/shell/quickshell/WorkspaceSwitcher.qml b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml new file mode 100644 index 00000000..3ae94346 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | import Quickshell | ||
| 2 | import QtQuick | ||
| 3 | import qs.Services | ||
| 4 | import Quickshell.Widgets | ||
| 5 | import QtQuick.Layouts | ||
| 6 | |||
| 7 | Row { | ||
| 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; | ||
| 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 = Array.from(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; | ||
| 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@sif/shell/quickshell/WorktimeWidget.qml b/accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml new file mode 100644 index 00000000..04bcc581 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | import QtQml | ||
| 2 | import Quickshell | ||
| 3 | import Quickshell.Io | ||
| 4 | import QtQuick | ||
| 5 | import Quickshell.Widgets | ||
| 6 | |||
| 7 | Item { | ||
| 8 | id: root | ||
| 9 | |||
| 10 | required property string command | ||
| 11 | property var state: null | ||
| 12 | |||
| 13 | height: parent.height | ||
| 14 | width: label.contentWidth + 8 | ||
| 15 | anchors.verticalCenter: parent.verticalCenter | ||
| 16 | |||
| 17 | Process { | ||
| 18 | id: process | ||
| 19 | running: true | ||
| 20 | command: [ @worktime@, root.command, "--waybar" ] | ||
| 21 | stdout: StdioCollector { | ||
| 22 | id: processCollector | ||
| 23 | onStreamFinished: { | ||
| 24 | try { | ||
| 25 | root.state = JSON.parse(processCollector.text); | ||
| 26 | } catch (e) { | ||
| 27 | console.warn("Worktime: Failed to parse output:", processCollector.text, e); | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | Timer { | ||
| 34 | running: true | ||
| 35 | interval: 60 | ||
| 36 | repeat: true | ||
| 37 | onTriggered: process.running = true | ||
| 38 | } | ||
| 39 | |||
| 40 | WrapperMouseArea { | ||
| 41 | id: mouseArea | ||
| 42 | |||
| 43 | anchors.fill: parent | ||
| 44 | |||
| 45 | enabled: true | ||
| 46 | hoverEnabled: true | ||
| 47 | |||
| 48 | Item { | ||
| 49 | anchors.fill: parent | ||
| 50 | |||
| 51 | Text { | ||
| 52 | id: label | ||
| 53 | |||
| 54 | anchors.centerIn: parent | ||
| 55 | |||
| 56 | visible: root.state?.text ?? false | ||
| 57 | text: root.state?.text ?? "" | ||
| 58 | |||
| 59 | font.pointSize: 10 | ||
| 60 | font.family: "Fira Sans" | ||
| 61 | color: { | ||
| 62 | if (root.state?.class == "running") | ||
| 63 | return "white"; | ||
| 64 | if (root.state?.class == "over") | ||
| 65 | return "#f28a21"; | ||
| 66 | return "#555"; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | PopupWindow { | ||
| 73 | id: tooltip | ||
| 74 | |||
| 75 | property bool nextVisible: Boolean(root.state?.tooltip ?? false) && (mouseArea.containsMouse || tooltipMouseArea.containsMouse) | ||
| 76 | |||
| 77 | anchor { | ||
| 78 | item: mouseArea | ||
| 79 | edges: Edges.Bottom | Edges.Left | ||
| 80 | } | ||
| 81 | visible: false | ||
| 82 | |||
| 83 | onNextVisibleChanged: hangTimer.restart() | ||
| 84 | |||
| 85 | Timer { | ||
| 86 | id: hangTimer | ||
| 87 | interval: 100 | ||
| 88 | onTriggered: tooltip.visible = tooltip.nextVisible | ||
| 89 | } | ||
| 90 | |||
| 91 | implicitWidth: tooltipText.contentWidth + 16 | ||
| 92 | implicitHeight: tooltipText.contentHeight + 16 | ||
| 93 | color: "black" | ||
| 94 | |||
| 95 | WrapperMouseArea { | ||
| 96 | id: tooltipMouseArea | ||
| 97 | |||
| 98 | enabled: true | ||
| 99 | hoverEnabled: true | ||
| 100 | |||
| 101 | anchors.fill: parent | ||
| 102 | |||
| 103 | Item { | ||
| 104 | anchors.fill: parent | ||
| 105 | |||
| 106 | Text { | ||
| 107 | id: tooltipText | ||
| 108 | |||
| 109 | anchors.centerIn: parent | ||
| 110 | |||
| 111 | font.pointSize: 10 | ||
| 112 | font.family: "Fira Sans" | ||
| 113 | color: "white" | ||
| 114 | |||
| 115 | text: root.state?.tooltip ?? "" | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| diff --git a/accounts/gkleen@sif/shell/quickshell/displaymanager.qml b/accounts/gkleen@sif/shell/quickshell/displaymanager.qml new file mode 100644 index 00000000..b452c03d --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/displaymanager.qml | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | //@ pragma UseQApplication | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Wayland | ||
| 5 | import Quickshell.Io | ||
| 6 | import Quickshell.Services.Greetd | ||
| 7 | import QtQml | ||
| 8 | |||
| 9 | |||
| 10 | ShellRoot { | ||
| 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@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml new file mode 100644 index 00000000..fb8b16dc --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/shell.qml | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | //@ pragma UseQApplication | ||
| 2 | |||
| 3 | import Quickshell | ||
| 4 | import Quickshell.Wayland | ||
| 5 | |||
| 6 | ShellRoot { | ||
| 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 | modelData: 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@sif/synadm/default.nix b/accounts/gkleen@sif/synadm/default.nix new file mode 100644 index 00000000..0a8e0d4c --- /dev/null +++ b/accounts/gkleen@sif/synadm/default.nix | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | { config, pkgs, ... }: | ||
| 2 | { | ||
| 3 | home.packages = with pkgs; [ synadm ]; | ||
| 4 | sops.secrets."synadm.yaml" = { | ||
| 5 | format = "binary"; | ||
| 6 | sopsFile = ./synadm_yaml; | ||
| 7 | path = config.xdg.configHome + "/synadm.yaml"; | ||
| 8 | }; | ||
| 9 | } | ||
| diff --git a/accounts/gkleen@sif/synadm/synadm_yaml b/accounts/gkleen@sif/synadm/synadm_yaml new file mode 100644 index 00000000..8d951ccc --- /dev/null +++ b/accounts/gkleen@sif/synadm/synadm_yaml | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:qJy4Pmbbxja4jmW7OaHsD0mQZ7anZwLhiVmAgkavb+CqwWGDnUBXdz22/MHCbxng5NshcFSpBoCBhgY6B9V2bUiES6bH9AtMlDcs9ebKGMArBTUTnQ2MjWQGfQTqraWdNgy+n327uj9swwCH8EZXdYH/Hlv0t/re470W+VOHeXhGghQ3Y9IGz2sgfvMGr8QxaJNydZz85rgs5QUP/PglCwWIOw2mY1EX2vYwnmiAo49LmIEaxWvRi++KHaeBveDt0nlkJwzUlipL2VOKWxkgpK3yGucQn2mz+FRe1btp+4KGm8H17eUI9FO9sBwq,iv:kgM921ovwCgDYHQj3c5Rupy/8JxHehxUD2jb1k9Ik2Y=,tag:3TLQkJbv679VWy8V2TMugw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bzVHUGNxZTF2WC9MYmZr\neGdVVzJXN3lGdEk3cTBER3J6UTFtcUJna2d3CjdNQmRXd2haZW1MYlJzNkk1dWVD\nVTFQc2gvS0JrejJ6SFh2MXpPWDZpRE0KLS0tIE0wTC85bEpvSnlGdGFkZVFhNjFZ\nbzRiZkxMWUg2ODNVUlBmNFlPNGRrZlkK1VXLJWcssv3ETyZSSM/Hhn5VIaI9iov9\nzShZA9Zx/FX6PYTuUMC29pJ57gKourcIxa/7HwSv/xYn1A6WcYfgSg==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | } | ||
| 9 | ], | ||
| 10 | "lastmodified": "2025-05-18T11:03:42Z", | ||
| 11 | "mac": "ENC[AES256_GCM,data:yonJC68PhilAgEHNNJQ8nO53Qo3rx/LnfiOWfuMm24bOUIH9QM3WZZxpigd7bHI4eC4TqRb4LvcSi0nEURTRAhwiTqGNrWbpw2Iv3n5dhLEN9aTcetG5ZuhaXqfVUoML45/ovdBZG/0l8+XIHqxN2M/g/h4JwKoR/6lqzcrVhgo=,iv:xvxBJwy+E5zUdjhGPdZPdy7tnBIEj50hfiDJFsS3wNg=,tag:L4Fas36ZOg4h0QQwC4gjNA==,type:str]", | ||
| 12 | "unencrypted_suffix": "_unencrypted", | ||
| 13 | "version": "3.10.2" | ||
| 14 | } | ||
| 15 | } | ||
| diff --git a/accounts/gkleen@sif/systemd.nix b/accounts/gkleen@sif/systemd.nix index 2237b708..e601b49c 100644 --- a/accounts/gkleen@sif/systemd.nix +++ b/accounts/gkleen@sif/systemd.nix | |||
| @@ -205,11 +205,6 @@ in { | |||
| 205 | StartLimitBurst = 7; | 205 | StartLimitBurst = 7; | 
| 206 | }; | 206 | }; | 
| 207 | }; | 207 | }; | 
| 208 | swayidle = { | ||
| 209 | Service = { | ||
| 210 | RuntimeDirectory = "swayidle"; | ||
| 211 | }; | ||
| 212 | }; | ||
| 213 | psi-notify = { | 208 | psi-notify = { | 
| 214 | Install = { | 209 | Install = { | 
| 215 | WantedBy = ["graphical-session.target"]; | 210 | WantedBy = ["graphical-session.target"]; | 
| @@ -242,7 +237,7 @@ in { | |||
| 242 | "-${lib.getExe pkgs.playerctl} -a pause" | 237 | "-${lib.getExe pkgs.playerctl} -a pause" | 
| 243 | "-${lib.getExe (pkgs.writeShellApplication { | 238 | "-${lib.getExe (pkgs.writeShellApplication { | 
| 244 | name = "generate-css"; | 239 | name = "generate-css"; | 
| 245 | runtimeInputs = with pkgs; [cfg.programs.wpaperd.package jq coreutils imagemagick findutils]; | 240 | runtimeInputs = with pkgs; [cfg.services.wpaperd.package jq coreutils imagemagick findutils]; | 
| 246 | text = '' | 241 | text = '' | 
| 247 | declare -A monitors | 242 | declare -A monitors | 
| 248 | monitors=() | 243 | monitors=() | 
| @@ -333,26 +328,24 @@ in { | |||
| 333 | ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\""; | 328 | ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\""; | 
| 334 | }; | 329 | }; | 
| 335 | }; | 330 | }; | 
| 336 | wpaperd = { | 331 | # wpaperd = { | 
| 337 | Install = { | 332 | # Install = { | 
| 338 | WantedBy = ["graphical-session.target"]; | 333 | # WantedBy = ["graphical-session.target"]; | 
| 339 | }; | 334 | # }; | 
| 340 | Unit = { | 335 | # Unit = { | 
| 341 | After = [ "graphical-session.target" ]; | 336 | # After = [ "graphical-session.target" ]; | 
| 342 | PartOf = [ "graphical-session.target" ]; | 337 | # PartOf = [ "graphical-session.target" ]; | 
| 343 | }; | 338 | # }; | 
| 344 | Service = { | 339 | # Service = { | 
| 345 | ExecStart = lib.getExe cfg.programs.wpaperd.package; | 340 | # ExecStart = lib.getExe cfg.services.wpaperd.package; | 
| 346 | Type = "simple"; | 341 | # Type = "simple"; | 
| 347 | Restart = "always"; | 342 | # Restart = "always"; | 
| 348 | RestartSec = "2s"; | 343 | # RestartSec = "2s"; | 
| 349 | }; | 344 | # }; | 
| 350 | }; | 345 | # }; | 
| 351 | xembed-sni-proxy = { | 346 | xembed-sni-proxy = { | 
| 352 | Unit = { | 347 | Unit = { | 
| 353 | PartOf = lib.mkForce ["tray.target"]; | 348 | PartOf = lib.mkForce ["tray.target"]; | 
| 354 | BindsTo = ["xwayland-satellite.service"]; | ||
| 355 | After = ["xwayland-satellite.service"]; | ||
| 356 | }; | 349 | }; | 
| 357 | }; | 350 | }; | 
| 358 | poweralertd = { | 351 | poweralertd = { | 
| @@ -385,6 +378,8 @@ in { | |||
| 385 | }; | 378 | }; | 
| 386 | Service = { | 379 | Service = { | 
| 387 | ExecStart = "${config.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString (port + 1)}"; | 380 | ExecStart = "${config.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString (port + 1)}"; | 
| 381 | Restart = "always"; | ||
| 382 | RestartSec = "23s"; | ||
| 388 | }; | 383 | }; | 
| 389 | }) [{ host = "proxy.ssh.math.lmu.de"; port = 8118; } { host = "proxy.vidhar"; port = 8120; } { host = "proxy.mathw0h"; port = 8122; } { host = "proxy.mathw0e"; port = 8124; }]); | 384 | }) [{ host = "proxy.ssh.math.lmu.de"; port = 8118; } { host = "proxy.vidhar"; port = 8120; } { host = "proxy.mathw0h"; port = 8122; } { host = "proxy.mathw0e"; port = 8124; }]); | 
| 390 | sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" { | 385 | sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" { | 
| @@ -439,8 +434,8 @@ in { | |||
| 439 | tray = { | 434 | tray = { | 
| 440 | Unit = { | 435 | Unit = { | 
| 441 | PartOf = [ "graphical-session.target" ]; | 436 | PartOf = [ "graphical-session.target" ]; | 
| 442 | Requires = [ "waybar.service" ]; | 437 | # Requires = [ "waybar.service" ]; | 
| 443 | After = [ "graphical-session.target" "waybar.service" ]; | 438 | After = [ "graphical-session.target" ]; # "waybar.service" ]; | 
| 444 | Wants = ["blueman-applet.service" "udiskie.service" "network-manager-applet.service"]; | 439 | Wants = ["blueman-applet.service" "udiskie.service" "network-manager-applet.service"]; | 
| 445 | }; | 440 | }; | 
| 446 | }; | 441 | }; | 
| diff --git a/accounts/gkleen@sif/utils/async-yt-dlp.nix b/accounts/gkleen@sif/utils/async-yt-dlp.nix new file mode 100644 index 00000000..c3b82ec5 --- /dev/null +++ b/accounts/gkleen@sif/utils/async-yt-dlp.nix | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | { writers, python3Packages, ... }: | ||
| 2 | |||
| 3 | writers.writePython3Bin "async-yt-dlp" { | ||
| 4 | libraries = with python3Packages; [ yt-dlp ]; | ||
| 5 | flakeIgnore = ["E501"]; | ||
| 6 | } '' | ||
| 7 | import sys | ||
| 8 | import os | ||
| 9 | |||
| 10 | import yt_dlp | ||
| 11 | import yt_dlp.options | ||
| 12 | from collections import namedtuple | ||
| 13 | import socket | ||
| 14 | from pathlib import Path | ||
| 15 | import json | ||
| 16 | |||
| 17 | create_parser = yt_dlp.options.create_parser | ||
| 18 | |||
| 19 | |||
| 20 | def parse_patched_options(opts): | ||
| 21 | patched_parser = create_parser() | ||
| 22 | patched_parser.defaults.update({ | ||
| 23 | 'ignoreerrors': False, | ||
| 24 | 'retries': 0, | ||
| 25 | 'fragment_retries': 0, | ||
| 26 | 'extract_flat': False, | ||
| 27 | 'concat_playlist': 'never', | ||
| 28 | }) | ||
| 29 | yt_dlp.options.create_parser = lambda: patched_parser | ||
| 30 | try: | ||
| 31 | return yt_dlp.parse_options(opts) | ||
| 32 | finally: | ||
| 33 | yt_dlp.options.create_parser = create_parser | ||
| 34 | |||
| 35 | |||
| 36 | default_opts = parse_patched_options([]).ydl_opts | ||
| 37 | |||
| 38 | |||
| 39 | def cli_to_api(opts): | ||
| 40 | opts = parse_patched_options(opts) | ||
| 41 | urls = opts.urls | ||
| 42 | opts = opts.ydl_opts | ||
| 43 | |||
| 44 | diff = {k: v for k, v in opts.items() if default_opts[k] != v} | ||
| 45 | if 'postprocessors' in diff: | ||
| 46 | diff['postprocessors'] = [pp for pp in diff['postprocessors'] | ||
| 47 | if pp not in default_opts['postprocessors']] | ||
| 48 | return namedtuple('Options', ('params', 'urls'))(diff, urls) | ||
| 49 | |||
| 50 | |||
| 51 | if __name__ == '__main__': | ||
| 52 | opts = cli_to_api(sys.argv[1:]) | ||
| 53 | with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: | ||
| 54 | sock.connect(str(Path(os.environ["XDG_RUNTIME_DIR"]) / "yt-dlp.sock").encode('utf-8')) | ||
| 55 | with sock.makefile(mode='w', buffering=1, encoding='utf-8') as fh: | ||
| 56 | json.dump(opts._asdict(), fh) | ||
| 57 | '' | ||
| diff --git a/accounts/gkleen@sif/utils/pdf2pdf.nix b/accounts/gkleen@sif/utils/pdf2pdf.nix new file mode 100644 index 00000000..9f4cbc3e --- /dev/null +++ b/accounts/gkleen@sif/utils/pdf2pdf.nix | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | pkgs@{ lib, resholve, zsh, ghostscript_headless, ... }: | ||
| 2 | |||
| 3 | resholve.writeScriptBin "pdf2pdf" { | ||
| 4 | inputs = with pkgs; [ghostscript_headless]; | ||
| 5 | interpreter = lib.getExe zsh; | ||
| 6 | } '' | ||
| 7 | exec gs -dPDFSETTINGS=/prepress -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER -dPreserveAnnots=false "-sOutputFile=''${2}" "''${1}" | ||
| 8 | '' | ||
| diff --git a/accounts/gkleen@sif/utils/sieve-edit.nix b/accounts/gkleen@sif/utils/sieve-edit.nix new file mode 100644 index 00000000..f985a3f6 --- /dev/null +++ b/accounts/gkleen@sif/utils/sieve-edit.nix | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | pkgs@{ lib, resholve, zsh, sieve-connect, sops, ... }: | ||
| 2 | |||
| 3 | resholve.writeScriptBin "sieve-edit" { | ||
| 4 | inputs = with pkgs; [sieve-connect sops]; | ||
| 5 | interpreter = lib.getExe zsh; | ||
| 6 | execer = with pkgs; [ | ||
| 7 | "cannot:${lib.getExe sieve-connect}" | ||
| 8 | "cannot:${lib.getExe sops}" | ||
| 9 | ]; | ||
| 10 | } '' | ||
| 11 | host=$1; shift | ||
| 12 | case "$host" in | ||
| 13 | surtr) | ||
| 14 | sieve-connect -s surtr.yggdrasil.li -m EXTERNAL --clientkey <(sops decrypt $HOME/projects/machines/hosts/surtr/email/ca/gkleen@sif.key) --clientcert $HOME/projects/machines/hosts/surtr/email/ca/gkleen@sif.crt --edit --remotesieve sieve | ||
| 15 | ;; | ||
| 16 | ymir) | ||
| 17 | sieve-connect -s ymir.yggdrasil.li -u gkleen --edit --remotesieve sieve | ||
| 18 | ;; | ||
| 19 | *) | ||
| 20 | echo "Unknown host: ‘$host’" >&2 | ||
| 21 | return 2 | ||
| 22 | ;; | ||
| 23 | esac | ||
| 24 | '' | ||
| diff --git a/accounts/gkleen@sif/zshrc b/accounts/gkleen@sif/zshrc index c628e2e9..702990c3 100644 --- a/accounts/gkleen@sif/zshrc +++ b/accounts/gkleen@sif/zshrc | |||
| @@ -2,17 +2,14 @@ dir() { | |||
| 2 | curlArchive=false | 2 | curlArchive=false | 
| 3 | templateArchive="" | 3 | templateArchive="" | 
| 4 | repoUrl="" | 4 | repoUrl="" | 
| 5 | nixShell="" | ||
| 6 | findNix=false | ||
| 7 | dir="" | 5 | dir="" | 
| 8 | forceShell=false | 6 | forceShell=false | 
| 9 | wormhole=false | 7 | wormhole=false | 
| 10 | gitWorktree="" | 8 | gitWorktree="" | 
| 11 | # notmuchMsg="" | ||
| 12 | quickserve=false | ||
| 13 | modifyPDF="" | 9 | modifyPDF="" | 
| 10 | miniserve=false | ||
| 14 | 11 | ||
| 15 | while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do | 12 | while getopts ':t:a:d:ir:wg:p:m' arg; do | 
| 16 | case $arg in | 13 | case $arg in | 
| 17 | "t") ;; | 14 | "t") ;; | 
| 18 | "a") | 15 | "a") | 
| @@ -23,16 +20,13 @@ dir() { | |||
| 23 | templateArchive=${OPTARG:a} | 20 | templateArchive=${OPTARG:a} | 
| 24 | fi | 21 | fi | 
| 25 | ;; | 22 | ;; | 
| 26 | "s") nixShell=${OPTARG:a} ;; | ||
| 27 | "S") findNix=true ;; | ||
| 28 | "d") dir=${OPTARG} ;; | 23 | "d") dir=${OPTARG} ;; | 
| 29 | "i") forceShell=true ;; | 24 | "i") forceShell=true ;; | 
| 30 | "r") repoUrl=${OPTARG} ;; | 25 | "r") repoUrl=${OPTARG} ;; | 
| 31 | "w") wormhole=true ;; | 26 | "w") wormhole=true ;; | 
| 32 | "g") gitWorktree=${OPTARG} ;; | 27 | "g") gitWorktree=${OPTARG} ;; | 
| 33 | # "n") notmuchMsg=${OPTARG} ;; | ||
| 34 | "q") quickserve=true ;; | ||
| 35 | "p") modifyPDF=${OPTARG:a} ;; | 28 | "p") modifyPDF=${OPTARG:a} ;; | 
| 29 | "m") miniserve=true ;; | ||
| 36 | *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;; | 30 | *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;; | 
| 37 | esac | 31 | esac | 
| 38 | done | 32 | done | 
| @@ -56,20 +50,34 @@ dir() { | |||
| 56 | gitWorktree="" | 50 | gitWorktree="" | 
| 57 | fi | 51 | fi | 
| 58 | 52 | ||
| 53 | miniservePIDFile="" | ||
| 54 | if [[ ${miniserve} = "true" ]]; then | ||
| 55 | miniservePIDFile=$(mktemp --tmpdir --suffix=.pid) | ||
| 56 | fi | ||
| 57 | |||
| 59 | cleanup() | 58 | cleanup() | 
| 60 | { | 59 | { | 
| 61 | cd ${modifyPDF:h} | 60 | if [[ -n ${modifyPDF} ]]; then | 
| 62 | [[ -n ${modifyPDF} ]] && nix shell 'nixos#imagemagick' -c convert -verbose ${dir}/${modifyPDF:t:r}_*.png(on) ${modifyPDF} | 61 | cd ${modifyPDF:h} | 
| 62 | typeset -a pages | ||
| 63 | eval 'pages=(${dir}/${modifyPDF:t:r}_*.png(on))' | ||
| 64 | magick -verbose "$pages" ${modifyPDF} | ||
| 65 | modifyPDF="" | ||
| 66 | fi | ||
| 67 | if [[ -n ${miniservePIDFile} ]]; then | ||
| 68 | command kill --verbose -- $(cat ${miniservePIDFile}) && wait $(cat ${miniservePIDFile}) | ||
| 69 | miniservePIDFile="" | ||
| 70 | fi | ||
| 63 | } | 71 | } | 
| 64 | 72 | ||
| 65 | ( | 73 | ( | 
| 74 | set -o localoptions -o localtraps | ||
| 75 | trap 'return 1' INT TERM | ||
| 66 | trap cleanup EXIT | 76 | trap cleanup EXIT | 
| 67 | 77 | ||
| 68 | cd ${dir} | 78 | cd ${dir} | 
| 69 | export dir; | 79 | export dir; | 
| 70 | 80 | ||
| 71 | ${findNix} && { nixShell=$(findNix) || return $? } | ||
| 72 | |||
| 73 | [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} . | 81 | [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} . | 
| 74 | 82 | ||
| 75 | [[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF} | 83 | [[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF} | 
| @@ -82,23 +90,23 @@ dir() { | |||
| 82 | } | 90 | } | 
| 83 | trap cleanup EXIT | 91 | trap cleanup EXIT | 
| 84 | 92 | ||
| 85 | if ${curlArchive}; then | 93 | if [[ $curlArchive = "true" ]]; then | 
| 86 | archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}") | 94 | archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}") | 
| 87 | 95 | ||
| 88 | curl -L -o ${archiveFile} ${templateArchive} | 96 | curl -SfL -o ${archiveFile} ${templateArchive} | 
| 89 | 97 | ||
| 90 | templateArchive=${archiveFile} | 98 | templateArchive=${archiveFile} | 
| 91 | fi | 99 | fi | 
| 92 | 100 | ||
| 93 | unpack=true | 101 | unpack=true | 
| 94 | while ${unpack}; do | 102 | while [[ $unpack = "true" ]]; do | 
| 95 | case $(file --brief --mime-type --dereference ${templateArchive}) in | 103 | case $(file --brief --mime-type --dereference ${templateArchive}) in | 
| 96 | application/zip) | 104 | application/zip) | 
| 97 | unzip ${templateArchive} | 105 | unzip ${templateArchive} | 
| 98 | unpack=false | 106 | unpack=false | 
| 99 | ;; | 107 | ;; | 
| 100 | application/vnd.debian.binary-package) | 108 | application/vnd.debian.binary-package) | 
| 101 | nix shell 'nixos#binutils' --command ar x ${templateArchive} | 109 | ar x ${templateArchive} | 
| 102 | mkdir control data | 110 | mkdir control data | 
| 103 | tar -C control -xvaf control.* | 111 | tar -C control -xvaf control.* | 
| 104 | tar -C data -xvaf data.* | 112 | tar -C data -xvaf data.* | 
| @@ -106,7 +114,7 @@ dir() { | |||
| 106 | ;; | 114 | ;; | 
| 107 | application/x-rpm) | 115 | application/x-rpm) | 
| 108 | cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio") | 116 | cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio") | 
| 109 | nix shell 'nixos#busybox' --command rpm2cpio ${templateArchive} > ${cpioArchive} | 117 | rpm2cpio ${templateArchive} > ${cpioArchive} | 
| 110 | templateArchive=${cpioArchive} | 118 | templateArchive=${cpioArchive} | 
| 111 | unpack=true | 119 | unpack=true | 
| 112 | ;; | 120 | ;; | 
| @@ -115,15 +123,19 @@ dir() { | |||
| 115 | unpack=false | 123 | unpack=false | 
| 116 | ;; | 124 | ;; | 
| 117 | application/pdf) | 125 | application/pdf) | 
| 118 | nix shell 'nixos#ghostscript' 'nixos#imagemagick' -c convert -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png | 126 | magick -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png | 
| 119 | unpack=false | 127 | unpack=false | 
| 120 | ;; | 128 | ;; | 
| 121 | application/octet-stream) | 129 | application/octet-stream) | 
| 122 | if [[ $(file --brief --dereferenc ${templateArchive}) =~ Squashfs ]]; then | 130 | if [[ $(file --brief --dereference ${templateArchive}) =~ Squashfs ]]; then | 
| 123 | nix shell 'nixos#squashfsTools' -c unsquashfs -d . ${templateArchive} | 131 | unsquashfs -d . ${templateArchive} | 
| 124 | unpack=false | 132 | unpack=false | 
| 125 | fi | 133 | fi | 
| 126 | ;; | 134 | ;; | 
| 135 | application/x-iso9660-image) | ||
| 136 | 7z x ${templateArchive} | ||
| 137 | unpack=false | ||
| 138 | ;; | ||
| 127 | *) | 139 | *) | 
| 128 | tar -xvaf ${templateArchive} | 140 | tar -xvaf ${templateArchive} | 
| 129 | unpack=false | 141 | unpack=false | 
| @@ -134,25 +146,21 @@ dir() { | |||
| 134 | fi | 146 | fi | 
| 135 | 147 | ||
| 136 | 148 | ||
| 137 | ${wormhole} && wormhole receive --accept-file | 149 | [[ $wormhole = "true" ]] && wormhole receive --accept-file | 
| 138 | 150 | ||
| 139 | 151 | ||
| 140 | if ${quickserve}; then | 152 | if [[ ${#@} -gt 0 ]]; then | 
| 141 | quickserve --root . --upload . --show-hidden --tar gz | 153 | ${@} | 
| 142 | fi | 154 | fi | 
| 143 | 155 | ||
| 156 | cd $(pwd) # Needed for mounting to work | ||
| 144 | 157 | ||
| 145 | if [[ ${#@} -eq 0 ]] || ${forceShell}; then | 158 | if [[ ${miniserve} = "true" ]]; then | 
| 146 | if [[ ${#@} -gt 0 ]]; then | 159 | miniserve --random-route --hidden --enable-tar-gz --enable-zip . & | 
| 147 | if [[ -z ${nixShell} ]]; then | 160 | echo $! > "${miniservePIDFile}" | 
| 148 | ${@} | 161 | fi | 
| 149 | else | ||
| 150 | nix-shell ${nixShell} --run "${@}" | ||
| 151 | fi | ||
| 152 | fi | ||
| 153 | |||
| 154 | cd $(pwd) # Needed for mounting to work | ||
| 155 | 162 | ||
| 163 | if [[ ${#@} -eq 0 ]] && [[ ${miniserve} != "true" ]] || [[ $forceShell = "true" ]]; then | ||
| 156 | isSingleDir() { | 164 | isSingleDir() { | 
| 157 | typeset -a contents | 165 | typeset -a contents | 
| 158 | contents=(*(N) .*(N)) | 166 | contents=(*(N) .*(N)) | 
| @@ -166,18 +174,9 @@ dir() { | |||
| 166 | } | 174 | } | 
| 167 | while d=$(isSingleDir); do cd ${d}; done | 175 | while d=$(isSingleDir); do cd ${d}; done | 
| 168 | 176 | ||
| 169 | 177 | zsh | |
| 170 | if [[ -z ${nixShell} ]]; then | 178 | elif [[ ${miniserve} == "true" ]]; then | 
| 171 | zsh | 179 | wait $(cat "${miniservePIDFile}") | 
| 172 | else | ||
| 173 | nix-shell ${nixShell} --run zsh | ||
| 174 | fi | ||
| 175 | else | ||
| 176 | if [[ -z ${nixShell} ]]; then | ||
| 177 | ${@} | ||
| 178 | else | ||
| 179 | nix-shell ${nixShell} --run "${@}" | ||
| 180 | fi | ||
| 181 | fi | 180 | fi | 
| 182 | ) | 181 | ) | 
| 183 | } | 182 | } | 
| @@ -185,27 +184,30 @@ dir() { | |||
| 185 | tmpdir() { | 184 | tmpdir() { | 
| 186 | cleanup() | 185 | cleanup() | 
| 187 | { | 186 | { | 
| 188 | cd / | 187 | cd / | 
| 189 | unmount() { | 188 | unmount() { | 
| 190 | printf "Unmounting %s\n" ${1} >&2 | 189 | printf "Unmounting %s\n" ${1} >&2 | 
| 191 | fusermount -u ${1} || umount ${1} || sudo umount ${1} | 190 | fusermount -u ${1} || umount ${1} || sudo umount ${1} | 
| 192 | } | 191 | } | 
| 193 | 192 | ||
| 194 | if mountpoint -q -- ${dir}; then | 193 | if [[ -n ${dir} ]]; then | 
| 195 | unmount ${dir} || return $? | 194 | if mountpoint -q -- ${dir}; then | 
| 196 | else | 195 | unmount ${dir} || return $? | 
| 197 | while read -d $'\0' subDir; do | 196 | else | 
| 198 | mountpoint -q -- ${subDir} || continue | 197 | while read -d $'\0' subDir; do | 
| 199 | unmount ${subDir} || return $? | 198 | mountpoint -q -- ${subDir} || continue | 
| 200 | done <<<$(find ${dir} -xdev -type d -print0 | sort -zr) | 199 | unmount ${subDir} || return $? | 
| 201 | fi | 200 | done <<<$(find ${dir} -xdev -type d -print0 | sort -zr) | 
| 202 | 201 | fi | |
| 203 | rm -rfv --one-file-system -- ${dir} | 202 | |
| 203 | rm -rfv --one-file-system -- ${dir} | ||
| 204 | dir="" | ||
| 205 | fi | ||
| 204 | } | 206 | } | 
| 205 | 207 | ||
| 206 | local tmpdir="" | 208 | local tmpdir="" | 
| 207 | 209 | ||
| 208 | while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do | 210 | while getopts ':t:a:d:ir:wg:p:m' arg; do | 
| 209 | case $arg in | 211 | case $arg in | 
| 210 | "t") tmpdir="=${OPTARG}" ;; | 212 | "t") tmpdir="=${OPTARG}" ;; | 
| 211 | "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;; | 213 | "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;; | 
| @@ -213,6 +215,8 @@ tmpdir() { | |||
| 213 | done | 215 | done | 
| 214 | 216 | ||
| 215 | ( | 217 | ( | 
| 218 | set -o localoptions -o localtraps | ||
| 219 | trap 'return 1' INT TERM | ||
| 216 | trap cleanup EXIT | 220 | trap cleanup EXIT | 
| 217 | 221 | ||
| 218 | 222 | ||
| @@ -231,17 +235,7 @@ clock() { | |||
| 231 | } | 235 | } | 
| 232 | 236 | ||
| 233 | public-ip() { | 237 | public-ip() { | 
| 234 | curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip' | 238 | curl -sSf -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip' | 
| 235 | } | ||
| 236 | |||
| 237 | nix-ghci() { | ||
| 238 | pkgExpr="" | ||
| 239 | if [[ ${#@} -gt 0 ]]; then | ||
| 240 | pkgExpr="${1}" | ||
| 241 | shift | ||
| 242 | fi | ||
| 243 | |||
| 244 | nix-shell -p "with (import <nixpkgs> {}); pkgs.haskellPackages.ghcWithPackages (p: with p; [${pkgExpr}])" --run "ghci ${@}" | ||
| 245 | } | 239 | } | 
| 246 | 240 | ||
| 247 | swap() { | 241 | swap() { | 
| @@ -271,14 +265,6 @@ l() { | |||
| 271 | ls --long --binary --git --time-style=iso --header $@ | 265 | ls --long --binary --git --time-style=iso --header $@ | 
| 272 | } | 266 | } | 
| 273 | 267 | ||
| 274 | re() { | ||
| 275 | systemctl restart $@ | ||
| 276 | } | ||
| 277 | |||
| 278 | ure() { | ||
| 279 | systemctl --user restart $@ | ||
| 280 | } | ||
| 281 | |||
| 282 | ssh-installer() { | 268 | ssh-installer() { | 
| 283 | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@ | 269 | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@ | 
| 284 | } | 270 | } | 
| diff --git a/accounts/gkleen@surtr.nix b/accounts/gkleen@surtr.nix index 58c4f21d..8f678ac9 100644 --- a/accounts/gkleen@surtr.nix +++ b/accounts/gkleen@surtr.nix | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | { userName, ... }: { | 1 | { flake, userName, ... }: { | 
| 2 | home-manager.users.${userName}.home.stateVersion = "20.09"; | 2 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 3 | zsh tmux | ||
| 4 | ]; | ||
| 5 | |||
| 6 | config.home-manager.users.${userName}.home.stateVersion = "20.09"; | ||
| 3 | } | 7 | } | 
| diff --git a/accounts/gkleen@vidhar.nix b/accounts/gkleen@vidhar.nix index 8509c2f4..3a37c4bd 100644 --- a/accounts/gkleen@vidhar.nix +++ b/accounts/gkleen@vidhar.nix | |||
| @@ -1,4 +1,8 @@ | |||
| 1 | { flake, pkgs, userName, config, ... }: { | 1 | { flake, pkgs, userName, config, ... }: { | 
| 2 | imports = with flake.nixosModules.userProfiles.${userName}; [ | ||
| 3 | zsh tmux | ||
| 4 | ]; | ||
| 5 | |||
| 2 | config = { | 6 | config = { | 
| 3 | users.users.${userName} = { | 7 | users.users.${userName} = { | 
| 4 | uid = 1000; | 8 | uid = 1000; | 
| diff --git a/accounts/mherold@eostre.nix b/accounts/mherold@eostre.nix index 51e4529a..0e2f37aa 100644 --- a/accounts/mherold@eostre.nix +++ b/accounts/mherold@eostre.nix | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | home-manager.users.${userName} = { | 7 | home-manager.users.${userName} = { | 
| 8 | home.stateVersion = "20.09"; | 8 | home.stateVersion = "20.09"; | 
| 9 | 9 | ||
| 10 | nixpkgs.config = { | 10 | # nixpkgs.config = { | 
| 11 | allowUnfree = true; | 11 | # allowUnfree = true; | 
| 12 | }; | 12 | # }; | 
| 13 | 13 | ||
| 14 | home.packages = with pkgs; [ | 14 | home.packages = with pkgs; [ | 
| 15 | thunderbird libreoffice element-desktop keepassxc vlc | 15 | thunderbird libreoffice element-desktop keepassxc vlc | 
| diff --git a/accounts/root@installer.nix b/accounts/root@installer.nix index c7a418f8..5fe1db38 100644 --- a/accounts/root@installer.nix +++ b/accounts/root@installer.nix | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | { userName, ... }: | 1 | { flake, userName, ... }: | 
| 2 | 2 | ||
| 3 | { | 3 | { | 
| 4 | home-manager.users.${userName} = { config, ... } : { | 4 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 5 | zsh tmux | ||
| 6 | ]; | ||
| 7 | |||
| 8 | config.home-manager.users.${userName} = { config, ... } : { | ||
| 5 | home.stateVersion = config.home.version.release; | 9 | home.stateVersion = config.home.version.release; | 
| 6 | }; | 10 | }; | 
| 7 | } | 11 | } | 
| diff --git a/accounts/root@sif.nix b/accounts/root@sif.nix index c9e129a0..bb816230 100644 --- a/accounts/root@sif.nix +++ b/accounts/root@sif.nix | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | { userName, ... }: | 1 | { flake, userName, ... }: | 
| 2 | { | 2 | { | 
| 3 | home-manager.users.${userName} = { | 3 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 4 | zsh tmux | ||
| 5 | ]; | ||
| 6 | |||
| 7 | config.home-manager.users.${userName} = { | ||
| 4 | home.stateVersion = "20.09"; | 8 | home.stateVersion = "20.09"; | 
| 5 | 9 | ||
| 6 | programs.ssh.matchBlocks = { | 10 | programs.ssh.matchBlocks = { | 
| diff --git a/accounts/root@surtr.nix b/accounts/root@surtr.nix index 58c4f21d..8f678ac9 100644 --- a/accounts/root@surtr.nix +++ b/accounts/root@surtr.nix | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | { userName, ... }: { | 1 | { flake, userName, ... }: { | 
| 2 | home-manager.users.${userName}.home.stateVersion = "20.09"; | 2 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 3 | zsh tmux | ||
| 4 | ]; | ||
| 5 | |||
| 6 | config.home-manager.users.${userName}.home.stateVersion = "20.09"; | ||
| 3 | } | 7 | } | 
| diff --git a/accounts/root@vidhar.nix b/accounts/root@vidhar.nix index e82414a8..0fc56633 100644 --- a/accounts/root@vidhar.nix +++ b/accounts/root@vidhar.nix | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | { config, userName, ... }: | 1 | { flake, config, userName, ... }: | 
| 2 | |||
| 2 | { | 3 | { | 
| 3 | home-manager.users.${userName} = { | 4 | imports = with flake.nixosModules.userProfiles.${userName}; [ | 
| 5 | zsh tmux | ||
| 6 | ]; | ||
| 7 | |||
| 8 | config.home-manager.users.${userName} = { | ||
| 4 | home.stateVersion = "20.09"; | 9 | home.stateVersion = "20.09"; | 
| 5 | 10 | ||
| 6 | programs.ssh.matchBlocks = { | 11 | programs.ssh.matchBlocks = { | 
