{ lib, config, pkgs, inputs, system, ... }: with lib; let cfg = config.modules.desktop.waybar; in { options.modules.desktop.waybar = { enable = mkEnableOption "Enable Waybar, a highly customizable wayland bar for wlroots compositors."; package = mkOption { type = types.package; default = pkgs.waybar; example = "pkgs.waybar"; }; }; config = mkIf cfg.enable { # enables playerctld bus, required for waybar to read mpris hm.services.playerctld.enable = true; hm.programs.waybar = { enable = true; # essentially just the service # peculiar how this is a program systemd.enable = true; package = cfg.package; settings = { mainBar = { layer = "top"; position = "top"; spacing = 4; height = 32; margin-top = 6; margin-left = 6; margin-right = 6; margin-bottom = 0; modules-left = [ "niri/workspaces" "niri/window" ]; modules-center = [ "clock" ]; modules-right = [ "group/playback" "group/status" "tray" "group/power" ]; "group/playback" = { orientation = "inherit"; modules = [ "mpris" ]; }; "group/status" = { orientation = "inherit"; modules = [ "pulseaudio" "backlight" "cpu" "memory" "network" "power-profiles-daemon" "battery" "custom/weather" "privacy" "custom/wallpaper" ]; }; "group/power" = { orientation = "inherit"; modules = [ "custom/power" ]; }; "custom/power" = let powerMenuScript = pkgs.writeShellScript "power-menu" '' set -euo pipefail cmd=$(echo '⏻ shutdown|↻ reboot|󰒲 sleep| hibernate| lock|⎋ exit desktop environment' | ${lib.getExe config.modules.desktop.rofi.package} -dmenu -sep '|' -i -p 'what to do ?') case "$cmd" in "⏻ shutdown") poweroff ;; "↻ reboot") reboot ;; "󰒲 sleep") systemctl suspend ;; " hibernate") systemctl hibernate ;; " lock") ${pkgs.systemd}/bin/loginctl lock-session ;; "⎋ exit desktop environment") ${pkgs.systemd}/bin/loginctl terminate-session $XDG_SESSION_ID ;; esac ''; in { format = "⏻"; tooltip = true; tooltip-format = "Power menu"; on-click = "${powerMenuScript}"; }; "custom/wallpaper" = { format = ""; tooltip = true; tooltip-format = "Change wallpaper"; on-click = "${config.modules.desktop.swww.swapScript}"; }; "niri/workspaces" = { format = "{icon}"; format-icons = { urgent = "◈"; focused = "◆"; default = "◇"; }; }; "niri/window" = { format = "{}"; icon = true; icon-size = 16; rewrite = { "(.*) — Mozilla Firefox" = "$1"; # the dash here is SLIGHTLY different. Wow "(.*) - Visual Studio Code" = "$1"; "(.*\\.nix\\s.*)" = " $1"; "(\\S+\\.html\\s.*)" = " $1"; "(\\S+\\.css\\s.*)" = " $1"; "(\\S+\\.js\\s.*)" = " $1"; "(\\S+\\.ts\\s.*)" = " $1"; "(\\S+\\.go\\s.*)" = " $1"; "(\\S+\\.lua\\s.*)" = " $1"; "(\\S+\\.java\\s.*)" = " $1"; "(\\S+\\.rb\\s.*)" = " $1"; "(\\S+\\.php\\s.*)" = " $1"; "(\\S+\\.jsonc?\\s.*)" = " $1"; "(\\S+\\.md\\s.*)" = " $1"; "(\\S+\\.txt\\s.*)" = " $1"; "(\\S+\\.cs\\s.*)" = "󰌛 $1"; "(\\S+\\.c\\s.*)" = " $1"; "(\\S+\\.cpp\\s.*)" = " $1"; "(\\S+\\.zig\\s.*)" = " $1"; "(\\S+\\.rs\\s.*)" = " $1"; "(\\S+\\.hs\\s.*)" = " $1"; ".*Discord \\| (.*)" = "$1"; }; separate-outputs = true; }; pulseaudio = { format = "{icon} {volume}%"; format-bluetooth = "{icon} {volume}%"; format-muted = "婢 {volume}%"; format-icons = { headphone = ""; default = ["" "" ""]; }; scroll-step = 1; on-click = "${lib.getExe pkgs.pwvucontrol}"; ignored-sinks = ["Easy Effects Sink"]; }; backlight = { format = "{icon} {percent}%"; format-icons = ["" ""]; scroll-step = 1; }; cpu = { interval = 4; format = " {usage}%"; on-click = "${lib.getExe pkgs.gnome-system-monitor}"; }; # bluetooth = { # # }; memory = { interval = 4; format = " {percentage}%"; tooltip = true; tooltip-format = "{used:0.1f}GiB/{avail:0.1f}GiB used\n{swapUsed:0.1f}GiB/{swapAvail:0.1f}GiB swap"; on-click = "${lib.getExe pkgs.gnome-system-monitor}"; states = { warning = 80; critical = 90; }; }; network = { format = "{icon}"; tooltip = true; tooltip-format-wifi = "{essid} ({signalStrength}%)"; tooltip-format-ethernet = "{ifname}"; tooltip-format-linked = "{ifname} (no ip)"; tooltip-format-disabled = "Disabled"; tooltip-format-disconnected = "Disconnected"; format-icons = { wifi = ""; ethernet = ""; # TODO: change symbol to ethernet, this represents lan linked = ""; # TODO: this symbol is deprecated disabled = "睊"; disconnected = "睊"; }; on-click = "${pkgs.networkmanagerapplet}/bin/nm-connection-editor"; }; power-profiles-daemon = { format = "{icon}"; tooltip = true; tooltip-format = "Power profile: {profile}\nDriver: {driver}"; format-icons = { default = ""; performance = " perf"; balanced = " balance"; power-saver = " save"; }; }; battery = { interval = 30; states = { warning = 20; critical = 10; }; design-capacity = false; format = "{icon} {capacity}%"; format-icons = ["" "" "" "" ""]; format-critical = " {capacity}%"; format-charging = " {capacity}%"; tooltip = true; tooltip-format = "{timeTo} ({power}W)"; }; privacy = { icon-spacing = 0; icon-size = 12; transition-duration = 250; modules = [ { type = "screenshare"; } { type = "audio-in"; } ]; }; mpris = { format = "{status_icon} {dynamic}"; dynamic-len = 32; title-len = 32; dynamic-order = [ "artist" "title" ]; dynamic-importance-order = [ "title" "artist" ]; tooltip = true; tooltip-format = "{player} | {status_icon} {artist} - {title} from {album} ({position}/{length})"; interval = 1; status-icons = { playing = "⏸"; paused = "▶"; }; }; clock = { format = "{:%H:%M}"; format-alt = "{:%a %b %d %R}"; tooltip = true; tooltip-format = "{calendar}"; calendar = { mode = "year"; mode-mon-col = 3; weeks-pos = "right"; on-scroll = 1; on-click-right = "mode"; format = { months = "{}"; days = "{}"; weeks = "W{}"; weekdays = "{}"; today = "{}"; }; actions = { on-click-right = "mode"; on-click-forward = "tz_up"; on-click-backward = "tz_down"; on-scroll-up = "shift_up"; on-scroll-down = "shift_down"; }; }; }; tray = { icon-size = 16; spacing = 4; }; "custom/weather" = let # this *should* be from coordinates, but we have to make it city because... # https://github.com/chubin/wttr.in/issues/795 # i was NOT going to let ip-based location be a thing. i was suprisingly medicated when i wrote this locationScript = pkgs.writeShellScript "location" '' set -euo pipefail lon="" lat="" while IFS= read -r line; do if [[ "$line" == *"Latitude"* ]]; then lat=$(echo "$line" | awk '{ gsub(/[" ]/, "", $2); printf("%.2f", $2) }') elif [[ "$line" == *"Longitude"* ]]; then lon=$(echo "$line" | awk '{ gsub(/[" ]/, "", $2); printf("%.2f", $2) }') fi if [[ -n "$lat" && -n "$lon" ]]; then break fi # -a 4 -- set accuracy to city done < <(${pkgs.geoclue2}/libexec/geoclue-2.0/demos/where-am-i -a 4) # i've had issues including country *and* state here, so state has higher priority and falls back to country. works fine for my current place and home town, so good enough <3 # zoom=10 -- set zoom to city # addressdetails=1 -- get address details, includes neighborhood (if requested) to city echo $(curl "https://nominatim.openstreetmap.org/reverse?lat=''${lat}&lon=''${lon}&addressdetails=1&zoom=10&format=json" | ${lib.getExe pkgs.jq} -r '.address | "\((to_entries[0].value)), \(.state // "\(.country)")"') ''; in { format = "{}°"; tooltip = true; on-click = "${lib.getExe pkgs.gnome-weather}"; interval = 3600; # doxxing live stream # edit: no longer doxxing, you will be remembered exec = ''${lib.getExe pkgs.wttrbar} --location "$(${locationScript})" --hide-conditions --fahrenheit --mph''; return-type = "json"; }; }; }; }; }; }