From a432370277f98e8b48318a0c64a74ffcb8cc6f12 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 6 Jul 2024 00:44:25 +0200 Subject: [PATCH] feat: back on hyprland --- users/common/graphical/wayland/default.nix | 10 +- users/common/graphical/wayland/hyprland.nix | 158 +++++- users/common/graphical/wayland/sway.nix | 4 - .../graphical/wayland/swaync/default.nix | 92 +++ .../graphical/wayland/swaync/swaync.css | 523 ++++++++++++++++++ users/common/graphical/wayland/swww.nix | 54 ++ .../graphical/wayland/waybar/default.nix | 150 +++++ .../graphical/wayland/waybar/waybar.css | 246 ++++++++ users/patrick/default.nix | 1 + 9 files changed, 1207 insertions(+), 31 deletions(-) create mode 100644 users/common/graphical/wayland/swaync/default.nix create mode 100644 users/common/graphical/wayland/swaync/swaync.css create mode 100644 users/common/graphical/wayland/swww.nix create mode 100644 users/common/graphical/wayland/waybar/default.nix create mode 100644 users/common/graphical/wayland/waybar/waybar.css diff --git a/users/common/graphical/wayland/default.nix b/users/common/graphical/wayland/default.nix index ecdbc1d..9ee931b 100644 --- a/users/common/graphical/wayland/default.nix +++ b/users/common/graphical/wayland/default.nix @@ -1,7 +1,15 @@ -{ +{pkgs, ...}: { imports = [ ../. ./fuzzel.nix ./sway.nix + ./hyprland.nix + ./waybar + ./swaync + ./swww.nix + ]; + home.packages = with pkgs; [ + wdisplays + wl-clipboard ]; } diff --git a/users/common/graphical/wayland/hyprland.nix b/users/common/graphical/wayland/hyprland.nix index 8e43d63..43cd656 100644 --- a/users/common/graphical/wayland/hyprland.nix +++ b/users/common/graphical/wayland/hyprland.nix @@ -4,7 +4,15 @@ nixosConfig, ... }: let - inherit (lib) mkMerge optionals elem; + inherit + (lib) + mkMerge + optionals + elem + mkIf + flip + concatMap + ; in { wayland.windowManager.hyprland = { enable = true; @@ -22,18 +30,78 @@ in { accel_profile = "flat"; touchpad = { - natural_scroll = "true"; + natural_scroll = true; disable_while_typing = true; clickfinger_behavior = true; scroll_factor = 0.7; }; }; + gestures = { + workspace_swipe = true; + }; general = { gaps_in = 1; gaps_out = 0; allow_tearing = true; }; + bind = let + monitor_binds = { + "1" = "j"; + "2" = "d"; + "3" = "u"; + "4" = "a"; + "5" = "x"; + "6" = "c"; + "7" = "t"; + "8" = "i"; + "9" = "e"; + }; + in + [ + "SUPER,q,killactive," + "SUPER,return,fullscreen," + "SUPER + SHIFT,return,fakefullscreen," + "SUPER,f,togglefloating" + "SUPER,tab,cyclenext," + "ALT,tab,cyclenext," + "SUPER+SHIFT,r,submap,resize" + + "SUPER,left,movefocus,l" + "SUPER,right,movefocus,r" + "SUPER,up,movefocus,u" + "SUPER,down,movefocus,d" + + "SUPER,n,movefocus,l" + "SUPER,s,movefocus,r" + "SUPER,l,movefocus,u" + "SUPER,r,movefocus,d" + + "SUPER + SHIFT,left,movewindow,l" + "SUPER + SHIFT,right,movewindow,r" + "SUPER + SHIFT,up,movewindow,u" + "SUPER + SHIFT,down,movewindow,d" + + "SUPER + SHIFT,n,movewindow,l" + "SUPER + SHIFT,s,movewindow,r" + "SUPER + SHIFT,l,movewindow,u" + "SUPER + SHIFT,r,movewindow,d" + + "SUPER,comma,workspace,-1" + "SUPER,period,workspace,+1" + + "SUPER,b,exec,firefox" + "SUPER,t,exec,kitty" + ",Menu,exec,fuzzel" + + "SUPER + SHIFT,q,exit" + ] + ++ flip concatMap (map toString (lib.lists.range 1 9)) ( + x: [ + "SUPER,${monitor_binds."${x}"},workspace,${x}" + "SUPER + SHIFT,${monitor_binds."${x}"},movetoworkspacesilent,${x}" + ] + ); cursor.no_warps = true; debug.disable_logs = false; @@ -48,12 +116,12 @@ in { ++ [ "NIXOS_OZONE_WL,1" "MOZ_ENABLE_WAYLAND,1" - "MOZ_WEBRENDER,1" "_JAVA_AWT_WM_NONREPARENTING,1" "QT_WAYLAND_DISABLE_WINDOWDECORATION,1" "QT_QPA_PLATFORM,wayland" "SDL_VIDEODRIVER,wayland" "GDK_BACKEND,wayland" + "WLR_DRM_NO_ATOMIC,1" #retest on newest nvidia driver ]; bindm = [ # mouse movements @@ -73,7 +141,6 @@ in { "workspaces, 1, 4, default" ]; }; - decoration.rounding = 4; exec-once = [ "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP" @@ -83,33 +150,72 @@ in { "${pkgs.swaynotificationcenter}/bin/swaync" ]; misc = { - vfr = 1; vrr = 1; disable_hyprland_logo = true; mouse_move_focuses_monitor = false; }; - extraConfig = '' - submap=resize - binde=,right,resizeactive,80 0 - binde=,left,resizeactive,-80 0 - binde=,up,resizeactive,0 -80 - binde=,down,resizeactive,0 80 - binde=SHIFT,right,resizeactive,10 0 - binde=SHIFT,left,resizeactive,-10 0 - binde=SHIFT,up,resizeactive,0 -10 - binde=SHIFT,down,resizeactive,0 10 - bind=,return,submap,reset - bind=,escape,submap,reset - submap=reset - - env=WLR_DRM_NO_ATOMIC,1 - windowrulev2 = immediate, class:^(cs2)$ - - binds { - focus_preferred_method = 1 - } - ''; } + (mkIf (nixosConfig.node.name == "desktopnix") { + monitor = [ + "DVI-D-1,preferred,0x-1080,1" + "HDMI-A-1,preferred,0x0,1" + "DP-3,2560x1440@144.00Hz,1920x-540,1" + # Thank you NVIDIA for this generous, free-of-charge, extra monitor that + # doesn't exist and crashes yoru session sometimes when moving a window to it. + "Unknown-1, disable" + ]; + + windowrulev2 = [ + "workspace 2,class:^(firefox)$" + "workspace 4,class:^(bottles)$" + "workspace 4,class:^(steam)$" + "workspace 4,class:^(prismlauncher)$" + "workspace 8,class:^(discord)$" + "workspace 8,class:^(WebCord)$" + "workspace 9,class:^(Signal)$" + "workspace 9,class:^(TelegramDesktop)$" + ]; + + workspace = [ + "1, monitor:DP-3, default:true" + "2, monitor:DP-3" + "3, monitor:DP-3" + "4, monitor:DP-3" + "5, monitor:DP-3" + "6, monitor:DVI-D-1, default:true" + "7, monitor:DVI-D-1" + "8, monitor:HDMI-A-1, default: true" + "9, monitor:HDMI-A-1" + ]; + }) + (mkIf (nixosConfig.node.name == "patricknix") { + monitor = [ + ]; + workspace = [ + ]; + }) ]; + extraConfig = '' + submap=resize + binde=,right,resizeactive,80 0 + binde=,left,resizeactive,-80 0 + binde=,up,resizeactive,0 -80 + binde=,down,resizeactive,0 80 + binde=SHIFT,right,resizeactive,10 0 + binde=SHIFT,left,resizeactive,-10 0 + binde=SHIFT,up,resizeactive,0 -10 + binde=SHIFT,down,resizeactive,0 10 + bind=,return,submap,reset + bind=,escape,submap,reset + submap=reset + + windowrulev2 = immediate, class:^(cs2)$ + exec-once = ${pkgs.xorg.xprop}/bin/xprop -root -f _XWAYLAND_GLOBAL_OUTPUT_SCALE 32c -set _XWAYLAND_GLOBAL_OUTPUT_SCALE 2 + env = XCURSOR_SIZE,48 + + binds { + focus_preferred_method = 1 + } + ''; }; } diff --git a/users/common/graphical/wayland/sway.nix b/users/common/graphical/wayland/sway.nix index 96c64bc..0fc5f84 100644 --- a/users/common/graphical/wayland/sway.nix +++ b/users/common/graphical/wayland/sway.nix @@ -1,14 +1,10 @@ { config, - pkgs, nixosConfig, ... }: { # import shared i3 config imports = [../sway3.nix]; - home.packages = [ - pkgs.wdisplays - ]; stylix.targets.sway.enable = true; wayland.windowManager.sway = { enable = true; diff --git a/users/common/graphical/wayland/swaync/default.nix b/users/common/graphical/wayland/swaync/default.nix new file mode 100644 index 0000000..ecd75ae --- /dev/null +++ b/users/common/graphical/wayland/swaync/default.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + ... +}: { + services.swaync = { + enable = true; + settings = { + positionX = "right"; + positionY = "top"; + + layer = "overlay"; + layer-shell = true; + cssPriority = "application"; + + control-center-layer = "top"; + control-center-width = 800; + control-center-height = 1600; + control-center-margin-top = 0; + control-center-margin-bottom = 0; + control-center-margin-right = 0; + control-center-margin-left = 0; + + notification-window-width = 800; + notification-2fa-action = true; + notification-inline-replies = false; + notification-icon-size = 64; + notification-body-image-height = 100; + notification-body-image-width = 200; + + keyboard-shortcuts = true; + image-visibility = "when-available"; + transition-time = 100; + + widgets = [ + "inhibitors" + "dnd" + "mpris" + "notifications" + ]; + + widget-config = { + inhibitors = { + text = "Inhibitors"; + button-text = "Clear All"; + clear-all-button = true; + }; + title = { + text = "Notifications"; + clear-all-button = true; + button-text = "Clear All"; + }; + dnd = { + text = "Do Not Disturb"; + }; + label = { + max-lines = 5; + text = "Label Text"; + }; + mpris = { + image-size = 96; + blur = true; + }; + }; + }; + style = + lib.concatLines ( + map (c: "@define-color ${c} ${config.lib.stylix.colors.withHashtag.${c}};") [ + "base00" + "base01" + "base02" + "base03" + "base04" + "base05" + "base06" + "base07" + "base08" + "base09" + "base0A" + "base0B" + "base0C" + "base0D" + "base0E" + "base0F" + ] + ) + + (builtins.readFile ./swaync.css); + }; + + # Started via hyprland to ensure it restarts properly with hyprland + systemd.user.services.swaync.Install.WantedBy = lib.mkForce []; +} diff --git a/users/common/graphical/wayland/swaync/swaync.css b/users/common/graphical/wayland/swaync/swaync.css new file mode 100644 index 0000000..11ab4fc --- /dev/null +++ b/users/common/graphical/wayland/swaync/swaync.css @@ -0,0 +1,523 @@ +@define-color cc-bg @base00; +@define-color noti-border-color rgba(255, 255, 255, 0.1); +@define-color noti-bg @base01; +@define-color noti-bg-critical lighter(mix(#000, @base08, 0.5)); +@define-color noti-bg-opaque @base01; +@define-color noti-bg-darker @base00; +@define-color noti-bg-hover lighter(@noti-bg); +@define-color noti-bg-hover-critical darker(@noti-bg-critical); +@define-color noti-bg-hover-opaque lighter(@noti-bg); +@define-color noti-close-bg rgba(255, 255, 255, 0.1); +@define-color noti-close-bg-hover rgba(255, 255, 255, 0.2); +@define-color text-color @base07; +@define-color text-color-muted @base05; +@define-color text-color-disabled @base04; +@define-color switch-color alpha(@base07, 0.5); +@define-color bg-selected @base0D; + +*:focus { + outline-style: none; +} + +.notification-row { + outline: none; +} + +.notification-row:focus, +.notification-row:hover { +} + +.notification-row .notification-background { +} + +.notification-row .notification-background .close-button { + /* The notification Close Button */ + background: @noti-close-bg; + color: @text-color; + text-shadow: none; + padding: 0; + border-radius: 100%; + margin-top: 5px; + margin-right: 5px; + box-shadow: none; + border: none; + min-width: 24px; + min-height: 24px; +} + +.notification-row .notification-background .close-button:hover { + box-shadow: none; + background: @noti-close-bg-hover; + transition: background 50ms ease-in-out; + border: none; +} + +.notification-row .notification-background .notification { + /* The actual notification */ + border-radius: 8px; + border: 2px solid @noti-border-color; + padding: 0; + transition: background 50ms ease-in-out; + background: @noti-bg; +} + +.notification-row .notification-background .notification.low { + /* Low Priority Notification */ +} + +.notification-row .notification-background .notification.normal { + /* Normal Priority Notification */ +} + +.notification-row .notification-background .notification.critical { + /* Critical Priority Notification */ + background: @noti-bg-critical; +} + +.notification-row .notification-background .notification .notification-action, +.notification-row .notification-background .notification .notification-default-action { + padding: 4px; + margin: 0; + box-shadow: none; + background: transparent; + border: none; + color: @text-color; + transition: background 50ms ease-in-out; +} + +.notification-row .notification-background .notification .notification-action:hover, +.notification-row .notification-background .notification .notification-default-action:hover { + -gtk-icon-effect: none; + background: @noti-bg-hover; +} + +.notification-row .notification-background .notification.critical .notification-action:hover, +.notification-row .notification-background .notification.critical .notification-default-action:hover { + /* Critical Priority Notification */ + background: @noti-bg-hover-critical; +} + +.notification-row .notification-background .notification .notification-default-action { + /* The large action that also displays the notification summary and body */ + border-radius: 4px; +} + +.notification-row .notification-background .notification .notification-default-action:not(:only-child) { + /* When alternative actions are visible */ + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content { + background: transparent; + border-radius: 12px; + padding: 16px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .image { + /* Notification Primary Image */ + -gtk-icon-effect: none; + border-radius: 100px; + /* Size in px */ + margin: 4px 12px 4px 4px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .app-icon { + /* Notification app icon (only visible when the primary image is set) */ + -gtk-icon-effect: none; + -gtk-icon-shadow: 0 1px 4px black; + margin: 6px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .text-box .summary { + /* Notification summary/title */ + font-size: 1.75rem; + font-weight: bold; + background: transparent; + color: @text-color; + text-shadow: none; + margin-bottom: 8px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .text-box .time { + /* Notification time-ago */ + font-size: 1.5rem; + font-weight: bold; + background: transparent; + color: @text-color-muted; + text-shadow: none; + margin-right: 30px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .text-box .body { + /* Notification body */ + font-size: 1.5rem; + background: transparent; + color: @text-color; + text-shadow: none; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content progressbar { + /* The optional notification progress bar */ + margin-top: 4px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .body-image { + /* The "extra" optional bottom notification image */ + margin-top: 4px; + background-color: white; + border-radius: 12px; + -gtk-icon-effect: none; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .inline-reply { + /* The inline reply section */ + margin-top: 4px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .inline-reply .inline-reply-entry { + background: @noti-bg-darker; + color: @text-color; + caret-color: @text-color; + border: 1px solid @noti-border-color; + border-radius: 12px; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .inline-reply .inline-reply-button { + font-size: 1.5rem; + margin-left: 4px; + background: @noti-bg; + border: 1px solid @noti-border-color; + border-radius: 12px; + color: @text-color; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .inline-reply .inline-reply-button:disabled { + background: initial; + color: @text-color-disabled; + border: 1px solid @noti-border-color; + border-color: transparent; +} + +.notification-row .notification-background .notification .notification-default-action .notification-content .inline-reply .inline-reply-button:hover { + background: @noti-bg-hover; +} + +.notification-row .notification-background .notification .notification-action { + /* The alternative actions below the default action */ + font-size: 1.25rem; + border-top: 1px solid @noti-border-color; + border-radius: 0px; + border-right: 1px solid @noti-border-color; +} + +.notification-row .notification-background .notification .notification-action:first-child { + /* add bottom border radius to eliminate clipping */ + border-bottom-left-radius: 12px; +} + +.notification-row .notification-background .notification .notification-action:last-child { + border-bottom-right-radius: 12px; + border-right: none; +} + +.notification-group { + /* Styling only for Grouped Notifications */ +} + +.notification-group.low { + /* Low Priority Group */ +} + +.notification-group.normal { + /* Low Priority Group */ +} + +.notification-group.critical { + /* Low Priority Group */ +} + +.notification-group .notification-group-buttons, +.notification-group .notification-group-headers { + margin: 0 16px; + color: @text-color; +} + +.notification-group .notification-group-headers { + /* Notification Group Headers */ + padding: 12px 8px; +} + +.notification-group .notification-group-headers .notification-group-icon { + color: @text-color; +} + +.notification-group .notification-group-headers .notification-group-header { + color: @text-color; + font-size: 2rem; +} + +.notification-group .notification-group-buttons { + /* Notification Group Buttons */ +} + +.notification-group.collapsed .notification-row .notification { + background-color: @noti-bg-opaque; +} + +.notification-group.collapsed .notification-row:not(:last-child) { + /* Top notification in stack */ + /* Set lower stacked notifications opacity to 0 */ +} + +.notification-group.collapsed .notification-row:not(:last-child) .notification-action, +.notification-group.collapsed .notification-row:not(:last-child) .notification-default-action { + opacity: 0; +} + +.notification-group.collapsed:hover .notification-row:not(:only-child) .notification { + background-color: @noti-bg-hover-opaque; +} + +.control-center { + /* The Control Center which contains the old notifications + widgets */ + background: @cc-bg; + color: @text-color; + border-radius: 0px; + padding: 6px 12px; +} + +.control-center .control-center-list-placeholder { + /* The placeholder when there are no notifications */ + opacity: 1; +} + +.control-center .control-center-list { + /* List of notifications */ + background: transparent; +} + +.control-center .control-center-list .notification { + box-shadow: none; +} + +.control-center .control-center-list .notification .notification-default-action, +.control-center .control-center-list .notification .notification-action { + transition: opacity 50ms ease-in-out, background 50ms ease-in-out; +} + +.control-center .control-center-list .notification .notification-default-action:hover, +.control-center .control-center-list .notification .notification-action:hover { + background-color: @noti-bg-hover; +} + +.blank-window { + /* Window behind control center and on all other monitors */ + background: transparent; +} + +.floating-notifications { + background: transparent; +} + +.floating-notifications .notification { + box-shadow: none; +} + +/*** Widgets ***/ +/* Title widget */ +.widget-title { + color: @text-color; + margin: 8px; + font-size: 1.5rem; +} + +.widget-title > button { + font-size: initial; + color: @text-color; + text-shadow: none; + background: @noti-bg; + border: 1px solid @noti-border-color; + box-shadow: none; + border-radius: 12px; +} + +.widget-title > button:hover { + background: @noti-bg-hover; +} + +/* DND widget */ +.widget-dnd { + color: @text-color; + margin: 8px; + font-size: 1.5rem; + padding: 8px 16px; +} + +.widget-dnd > switch { + font-size: initial; + border-radius: 9999px; + background: @noti-bg; + border: 1px solid @switch-color; + box-shadow: none; +} + +.widget-dnd > switch:checked { + background: @bg-selected; +} + +.widget-dnd > switch slider { + background: @switch-color; + border-radius: 12px; +} + +/* Label widget */ +.widget-label { + margin: 8px; +} + +.widget-label > label { + font-size: 1.1rem; +} + +/* Mpris widget */ +@define-color mpris-album-art-overlay rgba(0, 0, 0, 0.55); +@define-color mpris-button-hover rgba(0, 0, 0, 0.50); +.widget-mpris { + /* The parent to all players */ +} + +.widget-mpris .widget-mpris-player { + padding: 8px 16px; + margin: 16px 20px; + background-color: @mpris-album-art-overlay; + border-radius: 12px; + box-shadow: none; +} + +.widget-mpris .widget-mpris-player button:hover { + /* The media player buttons (play, pause, next, etc...) */ + background: @noti-bg-hover; +} + +.widget-mpris .widget-mpris-player .widget-mpris-album-art { + border-radius: 12px; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.75); +} + +.widget-mpris .widget-mpris-player .widget-mpris-title { + font-weight: bold; + font-size: 1.25rem; +} + +.widget-mpris .widget-mpris-player .widget-mpris-subtitle { + font-size: 1.1rem; +} + +.widget-mpris .widget-mpris-player > box > button { + /* Change player control buttons */ +} + +.widget-mpris .widget-mpris-player > box > button:hover { + background-color: @mpris-button-hover; +} + +.widget-mpris > box > button { + /* Change player side buttons */ +} + +.widget-mpris > box > button:disabled { + /* Change player side buttons insensitive */ +} + +/* Buttons widget */ +.widget-buttons-grid { + padding: 8px; + margin: 8px; + border-radius: 12px; + background-color: @noti-bg; +} + +.widget-buttons-grid > flowbox > flowboxchild > button { + background: @noti-bg; + border-radius: 12px; +} + +.widget-buttons-grid > flowbox > flowboxchild > button.toggle:checked { + /* style given to the active toggle button */ +} + +/* Menubar widget */ +.widget-menubar > box > .menu-button-bar > button { + border: none; + background: transparent; +} + +/* .AnyName { Name defined in config after # + background-color: @noti-bg; + padding: 8px; + margin: 8px; + border-radius: 12px; +} + +.AnyName>button { + background: transparent; + border: none; +} + +.AnyName>button:hover { + background-color: @noti-bg-hover; +} */ +.topbar-buttons > button { + /* Name defined in config after # */ + border: none; + background: transparent; +} + +/* Volume widget */ +.widget-volume { + background-color: @noti-bg; + padding: 8px; + margin: 8px; + border-radius: 12px; +} + +.widget-volume > box > button { + background: transparent; + border: none; +} + +.per-app-volume { + background-color: @noti-bg-alt; + padding: 4px 8px 8px 8px; + margin: 0px 8px 8px 8px; + border-radius: 12px; +} + +/* Backlight widget */ +.widget-backlight { + background-color: @noti-bg; + padding: 8px; + margin: 8px; + border-radius: 12px; +} + +/* Inhibitors widget */ +.widget-inhibitors { + margin: 8px; + font-size: 1.5rem; +} + +.widget-inhibitors > button { + font-size: initial; + color: @text-color; + text-shadow: none; + background: @noti-bg; + border: 1px solid @switch-color; + box-shadow: none; + border-radius: 12px; +} + +.widget-inhibitors > button:hover { + background: @noti-bg-hover; +} diff --git a/users/common/graphical/wayland/swww.nix b/users/common/graphical/wayland/swww.nix new file mode 100644 index 0000000..3a89cdc --- /dev/null +++ b/users/common/graphical/wayland/swww.nix @@ -0,0 +1,54 @@ +{ + lib, + pkgs, + ... +}: let + swww-update-wallpaper = pkgs.writeShellApplication { + name = "swww-update-wallpaper"; + runtimeInputs = [ + pkgs.swww + ]; + text = '' + FILES=("$HOME/.local/share/wallpapers/"*) + TYPES=("wipe" "any") + ANGLES=(0 15 30 45 60 75 90 105 120 135 150 165 180 195 210 225 240 255 270 285 300 315 330 345) + + swww img "''${FILES[RANDOM%''${#FILES[@]}]}" \ + --transition-type "''${TYPES[RANDOM%''${#TYPES[@]}]}" \ + --transition-angle "''${ANGLES[RANDOM%''${#ANGLES[@]}]}" \ + --transition-fps 144 \ + --transition-duration 1.5 + ''; + }; +in { + systemd.user = { + services = { + swww = { + Install.WantedBy = ["graphical-session.target"]; + Unit = { + Description = "Wayland wallpaper daemon"; + PartOf = ["graphical-session.target"]; + }; + Service = { + ExecStart = "${pkgs.swww}/bin/swww-daemon"; + Restart = "on-failure"; + }; + }; + swww-update-wallpaper = { + Install.WantedBy = ["default.target"]; + Unit.Description = "Update the wallpaper"; + Service = { + Type = "oneshot"; + Restart = "on-failure"; + RestartSec = "2m"; + ExecStart = lib.getExe swww-update-wallpaper; + }; + }; + }; + timers.swww-update-wallpaper = { + Install.WantedBy = ["timers.target"]; + Unit.Description = "Periodically switch to a new wallpaper"; + Timer.OnCalendar = "*:0/3"; # Every 5 minutes + }; + }; +} diff --git a/users/common/graphical/wayland/waybar/default.nix b/users/common/graphical/wayland/waybar/default.nix new file mode 100644 index 0000000..a743923 --- /dev/null +++ b/users/common/graphical/wayland/waybar/default.nix @@ -0,0 +1,150 @@ +{ + pkgs, + lib, + ... +}: { + programs.waybar = { + enable = true; + systemd.enable = false; + style = ./waybar.css; + settings.main = { + layer = "top"; + position = "bottom"; + modules-left = ["privacy" "hyprland/submap" "hyprland/window"]; + modules-center = ["hyprland/workspaces"]; + modules-right = [ + "cpu" + "memory" + "wireplumber" + "network" + #"bluetooth" + "backlight" + "battery" + "clock" + "custom/notifications" + "tray" + ]; + + battery = { + format = "{icon} {capacity}%"; + format-icons = ["" "" "" "" "" "" "" "" ""]; + }; + + backlight = { + device = "intel_backlight"; + format = "{icon} {percent}%"; + format-icons = ["󱩎" "󱩏" "󱩐" "󱩑" "󱩒" "󱩓" "󱩔" "󱩕" "󱩖" "󰛨"]; + on-scroll-up = "${pkgs.acpilight}/bin/xbacklight +5"; + on-scroll-down = "${pkgs.acpilight}/bin/xbacklight -5"; + }; + + clock = { + format = "{:%Y-%m-%d %H:%M:%S}"; + interval = 1; + tooltip = false; + }; + + "custom/notification" = { + tooltip = false; + format = "{icon} {}"; + format-icons = { + notification = ""; + none = ""; + dnd-notification = ""; + dnd-none = ""; + inhibited-notification = ""; + inhibited-none = ""; + dnd-inhibited-notification = ""; + dnd-inhibited-none = ""; + }; + return-type = "json"; + exec = "${pkgs.swaynotificationcenter}/bin/swaync-client -swb"; + on-click = "${pkgs.swaynotificationcenter}/bin/swaync-client -t -sw"; + on-click-right = "${pkgs.swaynotificationcenter}/bin/swaync-client -d -sw"; + on-click-middle = "${pkgs.swaynotificationcenter}/bin/swaync-client --close-all"; + escape = true; + }; + + wireplumber = { + format = "{icon} {volume}%"; + on-click = "${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; + on-click-middle = "${pkgs.hyprland}/bin/hyprctl dispatch exec \"[float;pin;move 80% 50%;size 20% 50%;noborder]\" ${lib.getExe pkgs.pwvucontrol}"; + on-scroll-up = "${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%+"; + on-scroll-down = "${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%-"; + format-muted = "󰖁"; + format-icons = ["󰕿" "󰖀" "󰕾"]; + }; + + "hyprland/workspaces" = { + format = "{icon}"; + format-icons.urgent = ""; + all-outputs = false; + sort-by = "id"; + }; + + "hyprland/window" = { + separate-outputs = true; + }; + + privacy = { + icon-spacing = 4; + icon-size = 18; + transition-duration = 250; + modules = [ + { + type = "screenshare"; + tooltip = true; + tooltip-icon-size = 24; + } + { + type = "audio-out"; + tooltip = true; + tooltip-icon-size = 24; + } + { + type = "audio-in"; + tooltip = true; + tooltip-icon-size = 24; + } + ]; + }; + network = { + interval = 5; + format-ethernet = "󰈀 ↓ {bandwidthDownBytes} ↑ {bandwidthUpBytes}"; + format-disconnected = "⚠ Disconnected"; + tooltip = false; + tooltip-format = "↑ {bandwidthUpBytes}\n↓ {bandwidthDownBytes}"; + }; + + bluetooth = { + format = "  {status} "; + format-connected = " {device_alias}"; + format-connected-battery = " {device_alias} {device_battery_percentage}%"; + tooltip-format = "{controller_alias}\t{controller_address}\n\n{num_connections} connected"; + tooltip-format-connected = "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}"; + tooltip-format-enumerate-connected = "{device_alias}\t{device_address}"; + tooltip-format-enumerate-connected-battery = "{device_alias}\t{device_address}\t{device_battery_percentage}%"; + }; + + memory = { + interval = 5; + format = " {percentage}%"; + states = { + warning = 70; + critical = 90; + }; + }; + + cpu = { + interval = 5; + format = " {usage}%"; + tooltip-format = "{usage}"; + }; + + tray = { + icon-size = 21; + spacing = 10; + }; + }; + }; +} diff --git a/users/common/graphical/wayland/waybar/waybar.css b/users/common/graphical/wayland/waybar/waybar.css new file mode 100644 index 0000000..dbae8b6 --- /dev/null +++ b/users/common/graphical/wayland/waybar/waybar.css @@ -0,0 +1,246 @@ +* { + /* `otf-font-awesome` is required to be installed for icons */ + font-family: "Symbols Nerd Font Mono", "JetBrains Mono"; + font-size: 13px; + transition-duration: .1s; +} + +window#waybar { + background-color: #000000; + border-bottom: 3px solid alpha(#485263, 0.7); + color: #ffffff; + transition-property: background-color; +} + +window#waybar.hidden { + opacity: 0.2; +} + +button { + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +#clock:hover, +#custom-notification:hover, +#custom-pick_color:hover, +#custom-scan_qr:hover, +#custom-cycle_wallpaper:hover, +#wireplumber:hover, +#pulseaudio:hover, +button:hover { + background: inherit; + box-shadow: inset 0 -2px alpha(#ffffff, 0.8); +} + +#backlight, +#battery, +#clock, +#cpu, +#custom-notification, +#custom-pick_color, +#custom-scan_qr, +#custom-cycle_wallpaper, +#disk, +#idle_inhibitor, +#memory, +#mode, +#network, +#power-profiles-daemon, +#privacy-item, +#scratchpad, +#submap, +#temperature, +#tray, +#wireplumber, +#pulseaudio, +#workspaces, +#mpd { + padding: 0 10px; +} + +#cpu, +#memory { + min-width: 44px; +} + +#wireplumber, +#pulseaudio { + min-width: 56px; +} + +#window, +#workspaces { + margin: 0 4px; +} + +/* If workspaces is the leftmost module, omit left margin */ +.modules-left>widget:first-child>#workspaces { + margin-left: 0; +} + +/* If workspaces is the rightmost module, omit right margin */ +.modules-right>widget:last-child>#workspaces { + margin-right: 0; +} + +#submap.resize { + background-color: #ffa000; + color: #000000; +} + +#battery { + background-color: #ffffff; + color: #000000; +} + +#battery.charging, +#battery.plugged { + background-color: #26A65B; +} + +@keyframes blink { + to { + background-color: #ffffff; + color: #000000; + } +} + +/* Using steps() instead of linear as a timing function to limit cpu usage */ +#battery.critical:not(.charging) { + background-color: #e05f65; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: steps(12); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#power-profiles-daemon { + padding-right: 15px; +} + +#power-profiles-daemon.performance { + background-color: #e05f65; +} + +#power-profiles-daemon.balanced { + background-color: #2980b9; +} + +#power-profiles-daemon.power-saver { + background-color: #000000; +} + +#memory.warning { + background-color: #f1c40f; + color: #000000; +} + +/* +#bluetooth.on { + box-shadow: inset 0 -2px alpha(#70a5eb, 0.4); +} +*/ + +#memory.critical, +#network.disconnected, +#pulseaudio.source-muted, +#temperature.critical, +#wireplumber.muted, +#mpd.disconnected { + background-color: #e05f65; +} + +#tray>.passive { + -gtk-icon-effect: dim; +} + +#tray>.needs-attention { + -gtk-icon-effect: highlight; + background-color: #e05f65; +} + +#idle_inhibitor { + background-color: #2d3436; +} + +#idle_inhibitor.activated { + background-color: #ecf0f1; + color: #2d3436; +} + +#mpd.stopped { + background-color: #90b1b1; +} + +#mpd.paused { + background-color: #51a37a; +} + +#language { + background: #00b093; + color: #740864; + padding: 0 5px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state { + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state>label { + padding: 0 5px; +} + +#keyboard-state>label.locked { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad.empty { + background-color: transparent; +} + +#privacy-item { + padding: 0 5px; +} + +#privacy-item.screenshare { + box-shadow: inset 0 -2px #e05f65; +} + +#privacy-item.audio-in { + box-shadow: inset 0 -2px #78dba9; +} + +#privacy-item.audio-out { + box-shadow: inset 0 -2px #70a5eb; +} + +#workspaces button { + padding: 0 5px; + background-color: transparent; + color: #ffffff; +} + +#workspaces button.visible { + background-color: #2770de; + box-shadow: inset 0 -2px #70a5eb; +} + +#workspaces button.urgent { + background-color: #e05f65; +} + +#workspaces button:hover { + box-shadow: inset 0 -2px #ffffff; +} diff --git a/users/patrick/default.nix b/users/patrick/default.nix index e751966..4e915b6 100644 --- a/users/patrick/default.nix +++ b/users/patrick/default.nix @@ -84,6 +84,7 @@ lib.optionalAttrs (!minimal) { ../common/graphical/Xorg ./streamdeck.nix ../common/programs/obs.nix + ../common/graphical/wayland ./smb.nix ]; "patricknix" = [