From 415f9f859e5ee48bd7e28468b95cd3fadba33f7e Mon Sep 17 00:00:00 2001 From: brustybee Date: Fri, 3 Apr 2026 03:27:14 +0530 Subject: add bspwm and polybar ( kinda ) --- common/modules/bspwm/default.nix | 182 +++++++++++ common/modules/bspwm/polybar.nix | 337 +++++++++++++++++++++ common/modules/default.nix | 1 + common/modules/matugen/default.nix | 12 + common/modules/matugen/templates/matugen-bspwm.nix | 16 + .../modules/matugen/templates/matugen-polybar.nix | 25 ++ 6 files changed, 573 insertions(+) create mode 100644 common/modules/bspwm/default.nix create mode 100644 common/modules/bspwm/polybar.nix create mode 100644 common/modules/matugen/templates/matugen-bspwm.nix create mode 100644 common/modules/matugen/templates/matugen-polybar.nix (limited to 'common/modules') diff --git a/common/modules/bspwm/default.nix b/common/modules/bspwm/default.nix new file mode 100644 index 0000000..9edc85c --- /dev/null +++ b/common/modules/bspwm/default.nix @@ -0,0 +1,182 @@ +{ + homeManager, + inputs, + moduleNameSpace, + ... +}: +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.${moduleNameSpace}.bspwm; + snip = pkgs.writeShellScript "snip" '' + case $1 in + full) + ${pkgs.maim}/bin/maim | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png + ;; + selection) + ${pkgs.maim}/bin/maim -s | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png + ;; + esac + ''; + + smart-alacritty = pkgs.writeShellScript "smart-alacritty" '' + alacritty msg create-window || exec alacritty + ''; + + smart-ghostty = pkgs.writeShellScript "smart-ghostty" '' + ghostty +new-window || exec ghostty + ''; + + terminal = + if config.beeMods.terminal.default == "alacritty" then + "${smart-alacritty}" + else if config.beeMods.terminal.default == "ghostty" then + "${smart-ghostty}" + else + "st"; +in +{ + imports = lib.optionalAttrs homeManager [ ./polybar.nix ]; + + options.${moduleNameSpace}.bspwm = { + enable = lib.mkEnableOption "bspwm setup"; + }; + + config = lib.mkIf cfg.enable ( + if homeManager then + { + xsession.windowManager.bspwm = { + enable = true; + monitors = { + "eDP" = [ + "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + ]; + }; + + rules = { + "Alacritty" = { + desktop = "^1"; + follow = true; + }; + "ghostty" = { + desktop = "^1"; + follow = true; + }; + "zen" = { + desktop = "^2"; + follow = true; + }; + "firefox" = { + desktop = "^2"; + follow = true; + }; + "vesktop" = { + desktop = "^3"; + follow = true; + }; + "discord" = { + desktop = "^3"; + follow = true; + }; + "steam" = { + desktop = "^4"; + follow = true; + }; + }; + + settings = { + border_width = 2; + window_gap = 5; + split_ratio = 0.55; + click_to_focus = "any"; + pointer_modifier = "mod4"; + pointer_action1 = "move"; + pointer_action2 = "resize_side"; + pointer_action3 = "resize_corner"; + focus_follows_pointer = true; + }; + + extraConfig = '' + [ -f ~/.config/bspwm/colors ] && . ~/.config/bspwm/colors + ''; + + startupPrograms = [ + "feh --no-fehbg --bg-fill $(rg wallpaper ~/.config/beeSettings | cut -d'=' -f2)" + "xsetroot -cursor_name left_ptr" + "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" + "gnome-keyring-daemon --start --components=secrets,ssh,pkcs11" + "xrandr --output eDP --set TearFree on" + "polybar" + ]; + }; + + services.sxhkd = { + enable = true; + keybindings = { + "super + Return" = terminal; + "super + r" = "pkill -USR1 -x sxhkd; bspc wm -r"; + "super + q" = "bspc node -c"; + "super + m" = "bspc quit"; + + "super + a" = "rofi -show drun"; + "super + period" = "rofi -show emoji -modi emoji"; + "alt + F4" = "rofi -show power-menu -modi power-menu:rofi-power-menu"; + "super + y" = "beesettings wall"; + "super + comma" = "beesettings settings"; + "super + b" = "zen"; + "super + e" = "nautilus"; + "super + F12" = "gnome-calculator"; + + "Print" = "${snip} full"; + "super + Print" = "${snip} selection"; + + "super + {h,j,k,l}" = "bspc node -f {west,south,north,east}"; + "super + shift + {h,j,k,l}" = "bspc node -s {west,south,north,east}"; + "super + {Left,Down,Up,Right}" = "bspc node -v {-50 0,0 50,0 -50,50 0}"; + + "super + space" = "bspc node -t ~floating"; + "alt + f" = "bspc node -t ~fullscreen"; + "super + i" = "bspc node -g hidden=on"; + + "super + shift + i" = "bspc node any.hidden.local -g hidden=off"; + + "super + {1-9}" = "bspc desktop -f '^{1-9}'"; + "super + shift + {1-9}" = "bspc node -d '^{1-9}'"; + + "XF86AudioRaiseVolume" = "volume-control up"; + "XF86AudioLowerVolume" = "volume-control down"; + "XF86AudioMute" = "volume-control mute"; + "XF86AudioMicMute" = "mic-control toggle"; + "XF86MonBrightnessUp" = "brightness-control up"; + "XF86MonBrightnessDown" = "brightness-control down"; + + "XF86Audio{Play,Next,Prev,Stop}" = "playerctl {play-pause,next,previous,stop}"; + + "alt + h" = "bspc node -z left -50 0 || bspc node -z right -50 0"; + "alt + j" = "bspc node -z bottom 0 50 || bspc node -z top 0 50"; + "alt + k" = "bspc node -z top 0 -50 || bspc node -z bottom 0 -50"; + "alt + l" = "bspc node -z right 50 0 || bspc node -z left 50 0"; + "alt + a" = "bspc desktop -l next"; + }; + }; + } + else + { + services.xserver = { + windowManager.bspwm.enable = true; + }; + } + ); +} diff --git a/common/modules/bspwm/polybar.nix b/common/modules/bspwm/polybar.nix new file mode 100644 index 0000000..09da86e --- /dev/null +++ b/common/modules/bspwm/polybar.nix @@ -0,0 +1,337 @@ +{ + config, + pkgs, + ... +}: +let + polybar-bluetooth = pkgs.writeShellApplication { + name = "polybar-bluetooth"; + runtimeInputs = with pkgs; [ + bluez + dbus + gnugrep + coreutils + findutils + ]; + text = '' + print_status() { + if bluetoothctl show | grep -q "Powered: yes"; then + if bluetoothctl info | grep -q "Connected: yes"; then + dev=$(bluetoothctl info | grep "Alias" | cut -d: -f2 | xargs) + echo "$dev" + else + echo "On" + fi + else + echo "Off" + fi + } + + print_status + + # Subscribe to DBus for instant updates without polling + dbus-monitor --system "type='signal',sender='org.bluez',member='PropertiesChanged'" 2>/dev/null | \ + grep --line-buffered "member=PropertiesChanged" | \ + while read -r _; do + print_status + done + ''; + }; + + polybar-network = pkgs.writeShellApplication { + name = "polybar-network"; + runtimeInputs = with pkgs; [ + iproute2 + networkmanager + gnugrep + coreutils + ]; + text = '' + print_status() { + if ip route | grep -q "^default"; then + ssid=$(nmcli -t -f NAME connection show --active | head -n1) + + if [ -z "$ssid" ]; then + echo "Connected..." + else + echo "$ssid" + fi + else + echo "Offline" + fi + } + + print_status + + ip monitor route address link | \ + grep --line-buffered ".*" | \ + while read -r _; do + print_status + done + ''; + }; + + polybar-power = pkgs.writeShellApplication { + name = "polybar-power"; + runtimeInputs = with pkgs; [ + power-profiles-daemon + dbus + gnugrep + coreutils + ]; + text = '' + print_status() { + # ShellCheck fix: Use POSIX classes [:lower:] instead of a-z + powerprofilesctl get 2>/dev/null | tr '[:lower:]' '[:upper:]' + } + + print_status + + dbus-monitor --system "type='signal',sender='net.hadess.PowerProfiles'" 2>/dev/null | \ + grep --line-buffered "member=PropertiesChanged" | \ + while read -r _; do + print_status + done + ''; + }; + + polybar-audio = pkgs.writeShellApplication { + name = "polybar-audio"; + runtimeInputs = with pkgs; [ + wireplumber + pulseaudio + gawk + gnugrep + coreutils + ]; + text = '' + print_vol() { + vol=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{print int($2*100)}') + if wpctl get-volume @DEFAULT_AUDIO_SINK@ | grep -q MUTED; then + echo "MUTED" + else + echo "$vol%" + fi + } + + print_vol + pactl subscribe | grep --line-buffered "sink" | while read -r _; do + print_vol + done + ''; + }; + + polybar-mic = pkgs.writeShellApplication { + name = "polybar-mic"; + runtimeInputs = with pkgs; [ + wireplumber + pulseaudio + gawk + gnugrep + coreutils + ]; + text = '' + get_mic_status() { + vol=$(wpctl get-volume @DEFAULT_AUDIO_SOURCE@) + if [[ "$vol" == *"MUTED"* ]]; then + echo "MUTED" + else + echo "$vol" | awk '{print int($2*100) "%"}' + fi + } + + sleep 0.2 + get_mic_status + + pactl subscribe 2>/dev/null | grep --line-buffered "Event 'change' on source" | while read -r _; do + get_mic_status + done + ''; + }; +in +{ + services.polybar = { + enable = true; + + # Basic startup script + script = "polybar main &"; + + config = { + # --- BASE SETTINGS --- + "section/base" = { + include-file = "~/.config/polybar/colors.ini"; + }; + + "bar/main" = { + width = "100%"; + height = "20pt"; + radius = 0; + bottom = false; + + background = "\${colors.background}"; + foreground = "\${colors.foreground}"; + + border-size = 0; + padding-left = 2; + padding-right = 2; + module-margin = 1; + + separator = "|"; + separator-foreground = "\${colors.disabled}"; + + font-0 = "IosevkaInput:size=10;3"; + + modules-left = "bspwm"; + modules-center = "date powerprofile"; + modules-right = "memory cpu battery mic audio bluetooth network tray"; + + enable-ipc = true; + wm-restack = "bspwm"; + }; + + "module/tray" = { + type = "internal/tray"; + tray-spacing = "8px"; + tray-size = "14pt"; + }; + + "module/bspwm" = { + type = "internal/bspwm"; + pin-workspaces = true; + inline-mode = false; + label-focused = "%name%"; + label-focused-background = "\${colors.primary}"; + label-focused-foreground = "\${colors.on_primary}"; + label-focused-underline = "\${colors.primary}"; + label-focused-padding = 2; + label-occupied = "%name%"; + label-occupied-foreground = "\${colors.primary}"; + label-occupied-padding = 2; + label-urgent = "%name%"; + label-urgent-background = "\${colors.alert}"; + label-urgent-padding = 2; + label-empty = "%name%"; + label-empty-foreground = "\${colors.disabled}"; + label-empty-padding = 2; + }; + + "module/memory" = { + type = "internal/memory"; + interval = 2; + format-prefix = "RAM "; + format-prefix-foreground = "\${colors.primary}"; + label = "%percentage_used:2%%"; + }; + + "module/cpu" = { + type = "internal/cpu"; + interval = 2; + format-prefix = "CPU "; + format-prefix-foreground = "\${colors.primary}"; + label = "%percentage:2%%"; + }; + + "module/date" = { + type = "internal/date"; + interval = 30; + date = "%I:%M %p"; + date-alt = "%Y-%m-%d %H:%M:%S"; + label = "%date%"; + label-foreground = "\${colors.primary}"; + }; + + "module/battery" = { + type = "internal/battery"; + battery = "BAT1"; + adapter = "ACAD"; + full-at = 99; + low-at = 10; + poll-interval = 5; + format-charging = ""; + format-charging-prefix = "CHR "; + format-charging-prefix-foreground = "\${colors.primary}"; + format-discharging = ""; + format-discharging-prefix = "BAT "; + format-discharging-prefix-foreground = "\${colors.primary}"; + format-full = ""; + format-full-prefix = "BAT "; + format-full-prefix-foreground = "\${colors.primary}"; + label-charging = "%percentage%%"; + label-discharging = "%percentage%%"; + label-full = "100%"; + }; + + "module/bluetooth" = { + type = "custom/script"; + tail = true; + format-prefix = "BT "; + format-prefix-foreground = "\${colors.primary}"; + exec = "${polybar-bluetooth}/bin/polybar-bluetooth"; + + click-left = "${pkgs.writeShellScript "rofi-bt-wrapper" '' + export PATH=$PATH:${pkgs.rofi}/bin + ${pkgs.rofi-bluetooth}/bin/rofi-bluetooth + ''}"; + + click-right = "${pkgs.bluez}/bin/bluetoothctl power off"; + }; + + "module/network" = { + type = "custom/script"; + tail = true; + format-prefix = "WIFI "; + format-prefix-foreground = "\${colors.primary}"; + exec = "${polybar-network}/bin/polybar-network"; + + click-left = "${pkgs.writeShellScript "rofi-net-wrapper" '' + export PATH=$PATH:${pkgs.rofi}/bin:${pkgs.networkmanager}/bin + ${pkgs.rofi-network-manager}/bin/rofi-network-manager + ''}"; + }; + + "module/powerprofile" = { + type = "custom/script"; + tail = true; + format = "