diff --git a/modules/desktop/themes/catppuccin/waybar.css b/modules/desktop/themes/catppuccin/waybar.css index f9f3d55..09990f0 100644 --- a/modules/desktop/themes/catppuccin/waybar.css +++ b/modules/desktop/themes/catppuccin/waybar.css @@ -168,7 +168,7 @@ window#waybar.floating #window { color: @red; } -#custom-wallpaper { +#custom-wallpaper, #custom-rgb { color: @overlay1; } diff --git a/modules/desktop/waybar.nix b/modules/desktop/waybar.nix index 4212cd6..066f1b7 100644 --- a/modules/desktop/waybar.nix +++ b/modules/desktop/waybar.nix @@ -24,301 +24,314 @@ in { 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.mission-center}"; - }; - # 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.mission-center}"; - 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; + mainBar = mkMerge [ + { + layer = "top"; + position = "top"; 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 + 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" + ]; - lon="" - lat="" + "group/playback" = { + orientation = "inherit"; + modules = [ + "mpris" + ]; + }; - 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) + "group/status" = { + orientation = "inherit"; + modules = [ + "pulseaudio" + "backlight" + "cpu" + "memory" + "network" + "power-profiles-daemon" + "battery" + "custom/weather" + "privacy" + "custom/wallpaper" + "custom/rgb" + ]; + }; + "group/power" = { + orientation = "inherit"; + modules = [ + "custom/power" + ]; + }; + "custom/power" = let + powerMenuScript = pkgs.writeShellScript "power-menu" '' + set -euo pipefail - # 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 = 600; - exec = ''${lib.getExe pkgs.wttrbar} --location "$(${locationScript})" --hide-conditions --fahrenheit --mph''; - return-type = "json"; - }; - }; + 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}"; + }; + "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.mission-center}"; + }; + # 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.mission-center}"; + 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 = 600; + exec = ''${lib.getExe pkgs.wttrbar} --location "$(${locationScript})" --hide-conditions --fahrenheit --mph''; + return-type = "json"; + }; + } + (mkIf config.modules.desktop.swww.enable { + "custom/wallpaper" = { + format = ""; + tooltip = true; + tooltip-format = "Change wallpaper"; + on-click = "${config.modules.desktop.swww.swapScript}"; + }; + }) + (mkIf config.modules.hardware.rgb.enable { + "custom/rgb" = { + format = "★"; # TODO: better icon (paintbrush or palette?) + tooltip = true; + tooltip-format = "Change OpenRGB profile"; + on-click = "${config.modules.hardware.rgb.swapScript}"; + }; + }) + ]; }; }; }; diff --git a/modules/hardware/rgb.nix b/modules/hardware/rgb.nix index 610723f..85c8f19 100644 --- a/modules/hardware/rgb.nix +++ b/modules/hardware/rgb.nix @@ -5,10 +5,38 @@ let cfg = config.modules.hardware.rgb; in { options.modules.hardware.rgb = { - enable = mkEnableOption "Enable support for rgb devices through openrgb"; + enable = mkEnableOption "Enable support for rgb devices through OpenRGB"; + package = mkOption { + type = types.package; + default = pkgs.openrgb; + example = "pkgs.openrgb"; + }; + swapScript = mkOption { + type = types.package; + default = pkgs.writeShellScript "openrgb-swap" '' + set -euo pipefail + + mapfile -t files < <( + find "$XDG_CONFIG_HOME/OpenRGB" -name "*.orp" + find /var/lib/OpenRGB -name "*.orp" 2>/dev/null + ) + + selected=$(printf '%s\n' "''${files[@]}" | xargs -n1 basename | ${lib.getExe config.modules.desktop.rofi.package} -dmenu -i -p "select profile") + + [[ -z "$selected" ]] && exit 0 + + for f in "''${files[@]}"; do + if [[ $(basename "$f") == "$selected" ]]; then + ${lib.getExe cfg.package} -p "$f" + break + fi + done + ''; + }; }; config = mkIf cfg.enable { services.hardware.openrgb.enable = true; + services.hardware.openrgb.package = cfg.package; }; }