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" = [