{ config, lib, pkgs, inputs, ... }: let nathan = config.nathan; in with lib; { config = mkIf nathan.programs.swaywm.enable (let swaylock-package = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.swaylock-effects; swaylock-command = '' ${swaylock-package}/bin/swaylock --screenshots --grace 30 --indicator --clock --timestr "%-I:%M:%S %p" --datestr "%A %Y-%M-%d" --effect-blur 20x3''; fuzzel-command = '' fuzzel -f "Iosevka Sans Quasi" -b "103c48ff" -S "adbcbcff" -s "184956ff" -t "72898fff" -B 5 -r 5 -C "ed8649ff" ''; wob-package = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.wob; in { home.packages = with pkgs; [ # Locking and display management wdisplays swaylock-package swayidle # Clipboard wl-clipboard wl-clipboard-x11 # Notifications mako # Terminal alacritty # glib for sound stuff glib # Glpaper for the background (glpaper.overrideAttrs (old: { src = fetchFromSourcehut { owner = "~scoopta"; repo = "glpaper"; vc = "hg"; rev = "14c158c495451bd9dbdc31a8dfc97388db5e7279"; hash = "sha256-jYOUmyXwTffzwUmYEY1SQx2ClZiRiMZLanveE9zWOLI="; }; })) # Screenshots sway-contrib.grimshot # fuzzel for launcher fuzzel # for image viewing inputs.self.packages.${pkgs.system}.swayimg # For private browsing tor-browser-bundle-bin # For non-emacs pdf reading evince # Productivity libreoffice-fresh ## Sway addons font-awesome wob-package hyprpaper # For fancy x11 scaling sommelier # Polkit libsForQt5.polkit-kde-agent polkit_gnome ]; ######################### ## Hyprland ######################### # Enable and configure hyperland wayland.windowManager.hyprland = { enable = true; xwayland = { enable = true; hidpi = true; }; recommendedEnvironment = true; systemdIntegration = false; extraConfig = '' env = XCURSOR_SIZE,24 input { kb_layout = us kb_variant = kb_model = kb_options = kb_rules = follow_mouse = 1 } general { # See https://wiki.hyprland.org/Configuring/Variables/ for more gaps_in = 5 gaps_out = 10 border_size = 3 col.active_border = rgba(3fc5b7ee) rgba(70b433ee) 45deg col.inactive_border = rgba(252525aa) layout = dwindle } decoration { rounding = 10 blur = true blur_size = 3 blur_passes = 1 blur_new_optimizations = true drop_shadow = true shadow_range = 4 shadow_render_power = 3 col.shadow = rgba(181818ee) } animations { enabled = true; bezier = myBezier, 0.05, 0.9, 0.1, 1.05 animation = windows, 1, 7, myBezier animation = windowsOut, 1, 7, default, popin 80% animation = border, 1, 10, default animation = borderangle, 1, 8, default animation = fade, 1, 7, default animation = workspaces, 1, 6, default } dwindle { # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more pseudotile = true # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below preserve_split = true # you probably want this } gestures { workspace_swipe = false } $mainMod = SUPER bind = $mainMod, Q, exec, alacritty bind = $mainMod, C, killactive, bind = $mainMod, M, exit, bind = $mainMod, E, exec, dolphin bind = $mainMod, V, togglefloating, bind = $mainMod, R, exec, fuzzel -f "Iosevka Sans Quasi" -b "103c48ff" -S "adbcbcff" -s "184956ff" -t "72898fff" -B 5 -r 5 -C "ed8649ff" bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, J, togglesplit, # dwindle bind = $mainMod, Z, exec, ${swaylock-command} # Move focus with mainMod + arrow keys bind = $mainMod, h, movefocus, l bind = $mainMod, l, movefocus, r bind = $mainMod, k, movefocus, u bind = $mainMod, j, movefocus, d # Switch workspaces with mainMod + [0-9] bind = $mainMod, 1, workspace, 1 bind = $mainMod, 2, workspace, 2 bind = $mainMod, 3, workspace, 3 bind = $mainMod, 4, workspace, 4 bind = $mainMod, 5, workspace, 5 bind = $mainMod, 6, workspace, 6 bind = $mainMod, 7, workspace, 7 bind = $mainMod, 8, workspace, 8 bind = $mainMod, 9, workspace, 9 bind = $mainMod, 0, workspace, 10 # Move active window to a workspace with mainMod + SHIFT + [0-9] bind = $mainMod SHIFT, 1, movetoworkspace, 1 bind = $mainMod SHIFT, 2, movetoworkspace, 2 bind = $mainMod SHIFT, 3, movetoworkspace, 3 bind = $mainMod SHIFT, 4, movetoworkspace, 4 bind = $mainMod SHIFT, 5, movetoworkspace, 5 bind = $mainMod SHIFT, 6, movetoworkspace, 6 bind = $mainMod SHIFT, 7, movetoworkspace, 7 bind = $mainMod SHIFT, 8, movetoworkspace, 8 bind = $mainMod SHIFT, 9, movetoworkspace, 9 bind = $mainMod SHIFT, 0, movetoworkspace, 10 # Scroll through existing workspaces with mainMod + scroll bind = $mainMod, mouse_down, workspace, e+1 bind = $mainMod, mouse_up, workspace, e-1 # Move/resize windows with mainMod + LMB/RMB and dragging bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow # systemd integration exec-once=dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && sleep 2 && systemctl --user start hyprland-session.target ''; }; # systemd session target # Specified manually so we can work around an issue with the loading systemd.user.targets.hyprland-session = { Unit = { Description = "Hyprland compositor session"; Documentation = [ "man:systemd.special(7)" ]; BindsTo = [ "graphical-session.target" ]; Wants = [ "graphical-session-pre.target" ]; After = [ "graphical-session-pre.target" ]; }; }; ######################### ## Sway ######################### wayland.windowManager.sway = let modifier = "Mod4"; in { enable = true; systemdIntegration = true; wrapperFeatures = { base = true; gtk = true; }; extraSessionCommands = '' # Make qt theming work export QT_QPA_PLATFORMTHEME="qt5ct" # Prepare for wob export WOBSOCK="$XDG_RUNTIME_DIR/wob.sock" rm -rf $WOBSOCK && mkfifo $WOBSOCK ''; config = { # Startup wob startup = [{ command = "tail -f $WOBSOCK | wob"; }]; # Setup gaps gaps = { smartGaps = true; inner = 9; }; # Window configuration window = { # Configure borders border = 2; # Application specific configuration commands = [ # Make pinentry float { command = "floating enable"; criteria = { app_id = "pinentry-qt"; }; } # Make bitwarden float { command = "floating enable"; criteria = { title = ".*Bitwarden.*"; }; } # Make swayimg float, this is required to make it work { command = "floating enable"; criteria = { app_id = "^swayimg.*"; }; } # Work around for chrome ui bug { command = "shortcuts_inhibitor disable"; criteria = { app_id = "chrome-.*"; }; } ]; }; # Use windows key as modifier modifier = "Mod4"; # Alacritty as default terminal terminal = "alacritty"; # Use krunner (from kde) as our launcher menu = '' ${fuzzel-command} ''; # Use waybar, but through systemd bars = [ # { # command = "waybar"; # } ]; # Use Iosevka fonts = { names = [ "Iosevka Sans Quasi" ]; size = 10.0; }; # Selenize it colors = { focused = { border = "75b938"; background = "184956"; text = "adbcbc"; indicator = "84c747"; childBorder = "75b938"; }; focusedInactive = { border = "41c7b9"; background = "#103c48"; text = "adbcbc"; indicator = "53d6c7"; childBorder = "41c7b9"; }; unfocused = { border = "72898f"; background = "103c48"; text = "72898f"; indicator = "adbcbc"; childBorder = "72898f"; }; urgent = { border = "f275be"; background = "184956"; text = "fa5750"; indicator = "fa5750"; childBorder = "f275be"; }; }; # Setup keybindings keybindings = lib.mkOptionDefault { "${modifier}+q" = "kill"; "${modifier}+z" = "exec ${swaylock-command}"; ## Sreenshot keybinds # Copy area to clipboard "${modifier}+x" = "exec ${pkgs.sway-contrib.grimshot}/bin/grimshot copy area"; # Copy window to clipboard "${modifier}+Ctrl+x" = "exec ${pkgs.sway-contrib.grimshot}/bin/grimshot copy window"; # Clpy entire output to clipboard "${modifier}+Alt+x" = "exec ${pkgs.sway-contrib.grimshot}/bin/grimshot copy output"; # Make the mute key work "XF86AudioMute" = "exec pactl set-sink-mute @DEFAULT_SINK@ toggle"; # Make the volume keys work "XF86AudioRaiseVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ +5% && pactl get-sink-volume @DEFAULT_SINK@ | head -n 1| awk '{print substr($5, 1, length($5)-1)}' > $WOBSOCK"; "XF86AudioLowerVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ -5% && pactl get-sink-volume @DEFAULT_SINK@ | head -n 1 | awk '{print substr($5, 1, length($5)-1)}' > $WOBSOCK"; # Play/pause and next song "XF86AudioPlay" = "exec mpc toggle"; "XF86AudioNext" = "exec mpc next"; # Setup scratchpads "${modifier}+n" = "exec sh -c 'swaymsg [app_id=\"emacs\"] scratchpad show'"; "${modifier}+m" = "exec sh -c 'swaymsg [app_id=\"Alacritty\"] scratchpad show'"; # Rebind movement keys to use layman "${modifier}+Shift+h" = "nop layman move left"; "${modifier}+Shift+j" = "nop layman move down"; "${modifier}+Shift+k" = "nop layman move up"; "${modifier}+Shift+l" = "nop layman move right"; # Switch to layman mode "${modifier}+g" = "mode layout"; }; modes = lib.mkOptionDefault { layout = { h = "nop layman layout none; mode default"; j = "nop layman layout Autotiling; mode default"; k = "nop layman layout Grid; mode default"; l = "nop layman layout MasterStack; mode default"; Escape = "mode default"; Return = "mode default"; }; }; # Setup a custom mode for layman operations # Turn on numlock by default input = { "*" = { xkb_numlock = "enable"; }; "type:pointer" = { accel_profile = "flat"; }; }; }; }; ######################### ## Sway Addons ######################### # Setup polkit as a service systemd.user.services.polkit-gnome = { Unit = { Description = "Polkit gnome authentication agent"; After = [ "graphical-session.target" ]; }; Service = { Type = "simple"; ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"; Restart = "on-failure"; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; ######################### ## Mako (notifications) ######################### services.mako = { enable = true; # Selenized color scheme borderColor = "#f275be"; backgroundColor = "#184956"; textColor = "#adbcbc"; # Border configuration borderSize = 3; # Use Iosevka for font font = "Iosevka Sans Quasi 10"; # Group by application groupBy = "app-name"; # Bottom right corner anchor = "bottom-right"; # Maximum visible notifications maxVisible = 10; # Sort by time in descending order (newest first) sort = "-time"; # Don't time out notifications , I want to have to dismiss them defaultTimeout = 0; ignoreTimeout = true; }; systemd.user.services.mako = { Unit = { Description = "mako notification daemon"; After = [ "graphical-session.target" ]; }; Service = { Type = "simple"; ExecStart = '' ${pkgs.mako}/bin/mako ''; Restart = "always"; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; ######################### ## Swayidle ######################### services.swayidle = { enable = true; timeouts = [ # Lock the screen after 5 minutes of inactivity { timeout = 300; command = builtins.replaceStrings [ "%" ] [ "%%" ] swaylock-command; } # Turn off the displays after 10 minutes of inactivity { timeout = 600; command = ''swaymsg "output * dpms off"''; resumeCommand = ''swaymsg "output * dpms on"''; } ]; }; systemd.user.services.swayidle = { Install = { WantedBy = [ "hyprland-session.target" ]; }; }; ######################### ## Waybar ######################### programs.waybar = { enable = true; package = inputs.nixpkgs-unstable.legacyPackages."${pkgs.system}".waybar.overrideAttrs (old: { mesonFlags = old.mesonFlags ++ [ "-Dexperimental=true" ]; }); systemd = { enable = false; }; settings = { mainBar = { layer = "top"; position = "top"; height = 30; spacing = 4; margin-top = 5; margin-bottom = 0; # modules-left = [ "wlr/workspaces" "hyprland/submap" ]; # modules-center = [ "hyprland/window" ]; # modules-right = [ "mpd" "clock" "tray" ]; modules-center = [ "custom/launcher" "wlr/workspaces" "mpd" # "hyprland/window" "idle_inhibitor" "pulseaudio" "network" "cpu" "memory" # "temperature" "tray" "clock" # "custom/power" ]; "custom/launcher" = { format = " "; on-click = fuzzel-command; on-click-right = "killall fuzzel"; }; "idle_inhibitor" = { format = "{icon}"; format-icons = { activated = ""; deactivated = ""; }; }; pulseaudio = { scroll-step = 1; format = "{volume}% {icon}"; format-bluetooth = "{volume}% {icon}"; format-bluetooth-muted = "{icon} {format_source}"; format-muted = "{format_source}"; format-source = ""; format-source-muted = ""; format-icons = { headphone = ""; hands-free = ""; headset = ""; phone = ""; portable = ""; car = ""; default = [ "" "" "" ]; }; on-click = "pavucontrol"; }; network = { # // "interface": "wlp2*", // (Optional) To force the use of this interface format-wifi = "{essid} ({signalStrength}%) "; format-ethernet = "Connected  "; tooltip-format = "{ifname} via {gwaddr} "; format-linked = "{ifname} (No IP) "; format-disconnected = "Disconnected ⚠"; format-alt = "{ifname}: {ipaddr}/{cidr}"; on-click-right = "bash ~/.config/rofi/wifi_menu/rofi_wifi_menu"; }; cpu = { format = "{usage}% "; tooltip = false; }; memory = { format = "{}% ({used}GB/{total}GB) "; }; "tray" = { icon-size = 20; spacing = 10; }; "clock" = { format = "{:%I:%M%p %Y-%m-%d}"; }; "mpd" = { format = "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S})"; format-disconnected = "Disconnected ❌"; format-stopped = "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ⏸"; consume-icons = { on = "🍴"; }; random-icons = { on = "🔀"; }; repeat-icons = { on = "🔁"; }; state-icons = { paused = "⏸"; playing = "▶"; }; }; }; }; style = '' * { border: none; border-radius: 0px; font-family: Roboto, Helvetica, Arial, sans-serif; font-size: 12px; min-height: 0; } window#waybar { background-color: transparent; color: #ffffff; transition-property: background-color; transition-duration: .5s; } window#waybar.hidden { opacity: 0.2; } #workspaces button { background: #1f1f1f; color: #ffffff; border-radius: 20px; } /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ #workspaces button:hover { background: lightblue; color: black; border-bottom: 3px solid #ffffff; } #workspaces button.active { background: #3f3f3f; } #workspaces button.active:hover { background: lightblue; color: black; border-bottom: 3px solid #ffffff; } #workspaces button.urgent { background-color: #eb4d4b; } #mode { background-color: #64727D; border-bottom: 3px solid #ffffff; } #clock, #battery, #cpu, #memory, #disk, #temperature, #backlight, #network, #pulseaudio, #custom-media, #custom-launcher, #custom-power, #tray, #mode, #idle_inhibitor, #mpd { padding: 0 10px; color: black; } #mpd { background-color: #8EC5FC; background-image: linear-gradient(62deg, #8EC5FC 0%, #E0C3FC 100%); color: black; border-radius: 20px; margin-right: 5px; } #window, #workspaces { margin: 0px 4px; } /* If workspaces is the leftmost module, omit left margin */ .modules-left > widget:first-child > #workspaces { margin-left: 0px; } /* If workspaces is the rightmost module, omit right margin */ .modules-right > widget:last-child > #workspaces { margin-right: 0px; } #clock { background-color: #FA8BFF; background-image: linear-gradient(-45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; border-radius: 0px 20px 20px 0px; margin-right: 4px; } #battery { background-color: #ffffff; color: #000000; } #battery.charging, #battery.plugged { color: #ffffff; background-color: #26A65B; } @keyframes blink { to { background-color: #ffffff; color: #000000; } } #battery.critical:not(.charging) { background-color: #f53c3c; color: #ffffff; animation-name: blink; animation-duration: 0.5s; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } label:focus { background-color: #000000; } #cpu { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #memory { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #disk { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #backlight { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); } #network { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #network.disconnected { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: red; } #pulseaudio { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #pulseaudio.muted { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: red; } #custom-media { background-color: #8EC5FC; background-image: linear-gradient(62deg, #8EC5FC 0%, #E0C3FC 100%); color: black; border-radius: 20px; margin-right: 5px; } #custom-media.custom-spotify { background-color: #8EC5FC; background-image: linear-gradient(62deg, #8EC5FC 0%, #E0C3FC 100%); color: black; border-radius: 20px; margin-right: 5px; } #custom-media.custom-vlc { background-color: #8EC5FC; background-image: linear-gradient(62deg, #8EC5FC 0%, #E0C3FC 100%); color: black; border-radius: 20px; margin-right: 5px; } #custom-power{ background-color: #FA8BFF; background-image: linear-gradient(45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); font-size: 16px; border-radius: 19px; } #custom-launcher{ background-color: #FA8BFF; background-image: linear-gradient(-45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); font-size: 18px; border-radius: 20px; } #custom-updater { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #temperature { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #temperature.critical { background-color: #eb4d4b; } #tray { background-color: #FA8BFF; background-image: linear-gradient(-45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #tray > .passive { -gtk-icon-effect: dim; background-color: #FA8BFF; background-image: linear-gradient(-45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #tray > .needs-attention { -gtk-icon-effect: highlight; background-color: #FA8BFF; background-image: linear-gradient(-45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; } #idle_inhibitor { background-color: #FA8BFF; background-image: linear-gradient(45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); border-radius: 20px 0px 0px 20px; } #idle_inhibitor.activated { background-color: #FA8BFF; background-image: linear-gradient(45deg, #FA8BFF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; border-radius: 20px 0px 0px 20px; } #language { background-color: #FA8BFF; background-image: linear-gradient(45deg, #2BD2FF 0%, #2BD2FF 52%, #2BD2FF 90%); color: black; min-width: 16px; } #keyboard-state { background: #97e1ad; color: #000000; min-width: 16px; } #keyboard-state > label { padding: 0px 5px; } #keyboard-state > label.locked { background: rgba(0, 0, 0, 0.2); } ''; }; # Override the service to run during graphical-session-pre.target systemd.user.services.waybar = { Unit = { Description = "Highly customizable Wayland bar for Sway and Wlroots based compositors."; Documentation = "https://github.com/Alexays/Waybar/wiki"; Before = [ "tray.target" ]; }; Service = { ExecStart = "${config.programs.waybar.package}/bin/waybar"; ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID"; ExecStartPost = "${pkgs.coreutils}/bin/sleep 1"; Restart = "on-failure"; KillMode = "mixed"; }; Install = { WantedBy = [ "graphical-session-pre.target" ]; }; }; ######################### ## EasyEffects ######################### services.easyeffects.enable = true; ######################### ## Create tray target to fix some things ######################### systemd.user.targets.tray = { Unit = { Description = "Home Manager System Tray"; Requires = [ "graphical-session-pre.target" "waybar.service" ]; After = [ "waybar.service" ]; }; }; ######################### ## Default applications ######################### xdg.mimeApps.defaultApplications = { # Make all supported images open in swayimg "image/jpeg" = [ "swayimg.desktop" ]; "image/png" = [ "swayimg.desktop" ]; "image/gif" = [ "swayimg.desktop" ]; "image/svg+xml" = [ "swayimg.desktop" ]; "image/webp" = [ "swayimg.desktop" ]; "image/avif" = [ "swayimg.desktop" ]; "image/tiff" = [ "swayimg.desktop" ]; "image/bmp" = [ "swayimg.desktop" ]; "application/pdf" = [ "org.gnome.Evince.desktop" ]; "text/html" = [ "firefox.desktop" ]; }; }); }