Commit a2fea84

Eric Bower  ·  2026-08-28 21:12:13 -0400 EDT
parent 4bc2206
refactor: replace noctalia

Going minimal: swaybar, swayidle, swaylock
4 files changed,  +246, -28
+76, -25
  1@@ -5,33 +5,52 @@ set $down j
  2 set $up k
  3 set $right l
  4 
  5-set $bg0     #282828
  6-set $bg1     #3c3836
  7-set $bg3     #665c54
  8-set $fg0     #fbf1c7
  9-set $fg2     #d5c4a1
 10-set $fg4     #a89984
 11-set $bred    #fb4934
 12-set $bgreen  #b8bb26
 13-set $bblue   #83a598
 14+# 16-bit Terminal Palette (Monokai Classic)
 15+set $bg         #272822
 16+set $fg         #f8f8f2
 17+
 18+# Standard ANSI (0-7)
 19+set $black      #272822
 20+set $red        #f92672
 21+set $green      #a6e22e
 22+set $yellow     #e6db74
 23+set $blue       #66d9ef
 24+set $magenta    #ae81ff
 25+set $cyan       #a1efe4
 26+set $white      #f8f8f2
 27+
 28+# Bright ANSI (8-15)
 29+set $br_black   #75715e
 30+set $br_red     #fd971f
 31+set $br_green   #a6e22e
 32+set $br_yellow  #e6db74
 33+set $br_blue    #66d9ef
 34+set $br_magenta #ae81ff
 35+set $br_cyan    #a1efe4
 36+set $br_white   #f8f8f2
 37 
 38 # Color scheme               border    bg        text      indicator child_border
 39-client.focused               $bblue    $bg0      $fg0      $bred     $bblue
 40-client.focused_inactive      $bg3      $bg1      $fg2      $bg3      $bg3
 41-client.unfocused             $bg3      $bg0      $fg4      $bg3      $bg3
 42-client.urgent                $bred     $bred     $fg0      $bred     $bred
 43-client.placeholder           $bg3      $bg0      $fg4      $bg3      $bg3
 44-client.background            $bg0
 45+client.focused               $blue     $bg       $fg       $red      $blue
 46+client.focused_inactive      $br_black $bg       $white    $br_black $br_black
 47+client.unfocused             $br_black $bg       $white    $br_black $br_black
 48+client.urgent                $red      $red      $bg       $red      $red
 49+client.placeholder           $br_black $bg       $white    $br_black $br_black
 50+client.background            $bg
 51 
 52 default_border pixel 2
 53 
 54-set $ipc noctalia msg
 55-bindsym $mod+d exec $ipc panel-toggle launcher
 56-bindsym --locked XF86AudioRaiseVolume exec $ipc volume-up
 57-bindsym --locked XF86AudioLowerVolume exec $ipc volume-down
 58-bindsym --locked XF86AudioMute exec $ipc volume-mute
 59-bindsym --locked XF86MonBrightnessUp exec $ipc brightness-up
 60-bindsym --locked XF86MonBrightnessDown exec $ipc brightness-down
 61+# Audio volume controls (pamixer)
 62+bindsym --locked XF86AudioRaiseVolume exec pamixer -i 5
 63+bindsym --locked XF86AudioLowerVolume exec pamixer -d 5
 64+bindsym --locked XF86AudioMute exec pamixer -t
 65+bindsym --locked XF86AudioMicMute exec pamixer --default-source -t
 66+
 67+# Screen brightness controls (brightnessctl)
 68+bindsym --locked XF86MonBrightnessUp exec brightnessctl set +5%
 69+bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
 70+
 71+# Application Launcher (wmenu)
 72+bindsym $mod+d exec wmenu-run -f "JetBrainsMono Nerd Font 10.5" -N "#272822" -n "#f8f8f2" -S "#66d9ef" -s "#272822" -p "run: "
 73 
 74 floating_modifier $mod normal
 75 # bindsym $mod+Return exec foot
 76@@ -95,18 +114,33 @@ set $laptop eDP-1
 77 output $laptop mode 2256x1504@59.999Hz
 78 output $laptop scale 1.5
 79 
 80+output * bg ~/config/wallpapers/webb_telescope.png fill
 81+
 82 # set $cahoots DP-2
 83 # Samsung Electric Company U32J59x HCJTB01080
 84 # output $cahoots scale 1.5
 85 
 86-bindswitch lid:on output $laptop disable
 87-bindswitch --reload lid:off output $laptop enable; exec noctalia
 88+# Lock screen command
 89+set $lock swaylock -F -e \
 90+    -i ~/config/wallpapers/webb_telescope.png \
 91+    --indicator-idle-visible
 92+
 93+bindsym $mod+Alt+l exec $lock
 94 
 95-exec noctalia
 96+# Laptop lid switch bindings
 97+bindswitch lid:on exec $lock; output $laptop disable
 98+bindswitch --reload lid:off output $laptop enable
 99+
100+# Idle management (lock after 5 min, turn off displays after 10 min)
101+exec swayidle -w \
102+    timeout 300 '$lock' \
103+    timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
104+    before-sleep '$lock'
105 
106 # required for xdg-desktop-portal-gtk.service
107 exec systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP DISPLAY MOZ_ENABLE_WAYLAND
108 exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway DISPLAY MOZ_ENABLE_WAYLAND=1
109+exec wlsunset -l 42.3 -L -83.0
110 
111 input "type:touchpad" {
112     tap enabled
113@@ -123,3 +157,20 @@ input "20547:23623:Ploopy_Corporation_Ploopy_Adept_Trackball_Mouse" {
114   accel_profile "flat"
115   pointer_accel -0.5 # between -1 and 1
116 }
117+
118+bar {
119+    position bottom
120+    status_command python3 ~/.config/sway/status.py
121+    font pango:JetBrainsMono Nerd Font 10.5
122+
123+    colors {
124+        background $bg
125+        statusline $fg
126+        separator  $br_black
127+
128+        focused_workspace  $blue     $blue     $bg
129+        active_workspace   $br_black $br_black $fg
130+        inactive_workspace $bg       $bg       $white
131+        urgent_workspace   $red      $red      $bg
132+    }
133+}
+157, -0
  1@@ -0,0 +1,157 @@
  2+#!/usr/bin/env python3
  3+import json
  4+import sys
  5+import os
  6+import subprocess
  7+import threading
  8+import time
  9+
 10+def get_sound():
 11+    try:
 12+        muted = subprocess.check_output(["pamixer", "--get-mute"], text=True).strip() == "true"
 13+        vol = subprocess.check_output(["pamixer", "--get-volume"], text=True).strip()
 14+        if muted:
 15+            return f"MUTED {vol}%"
 16+        return f"VOL {vol}%"
 17+    except Exception:
 18+        pass
 19+    return "VOL ?"
 20+
 21+def get_battery():
 22+    try:
 23+        if not os.path.exists("/sys/class/power_supply"):
 24+            return None
 25+        bat_dirs = [d for d in os.listdir("/sys/class/power_supply") if d.startswith("BAT")]
 26+        if not bat_dirs:
 27+            return None
 28+        bat_path = os.path.join("/sys/class/power_supply", bat_dirs[0])
 29+        cap_file = os.path.join(bat_path, "capacity")
 30+        stat_file = os.path.join(bat_path, "status")
 31+        
 32+        if not os.path.exists(cap_file):
 33+            return None
 34+
 35+        with open(cap_file) as f:
 36+            cap = f.read().strip()
 37+        
 38+        status = "Discharging"
 39+        if os.path.exists(stat_file):
 40+            with open(stat_file) as f:
 41+                status = f.read().strip()
 42+
 43+        label = "CHR" if status == "Charging" else "BAT"
 44+        return f"{label} {cap}%"
 45+    except Exception:
 46+        return None
 47+
 48+def get_brightness():
 49+    try:
 50+        actual = int(subprocess.check_output(["brightnessctl", "get"], text=True).strip())
 51+        max_b = int(subprocess.check_output(["brightnessctl", "max"], text=True).strip())
 52+        pct = int((actual / max_b) * 100)
 53+        return f"BRT {pct}%"
 54+    except Exception:
 55+        return None
 56+
 57+def get_net():
 58+    try:
 59+        out = subprocess.check_output(
 60+            ["nmcli", "-t", "-f", "TYPE,STATE,CONNECTION", "dev"], 
 61+            text=True
 62+        ).strip()
 63+        
 64+        eth_name = None
 65+        wifi_ssid = None
 66+        
 67+        for line in out.splitlines():
 68+            parts = line.split(":")
 69+            if len(parts) >= 3 and parts[1] == "connected":
 70+                dev_type = parts[0]
 71+                conn_name = parts[2]
 72+                if dev_type == "ethernet":
 73+                    eth_name = conn_name if conn_name else "Wired"
 74+                elif dev_type == "wifi":
 75+                    wifi_ssid = conn_name if conn_name else "WiFi"
 76+                    
 77+        if eth_name:
 78+            return f"ETH {eth_name}"
 79+        elif wifi_ssid:
 80+            return f"NET {wifi_ssid}"
 81+        return "NET Disconnected"
 82+    except Exception:
 83+        return "NET ?"
 84+
 85+def get_time():
 86+    return time.strftime("%I:%M %m/%d").lstrip("0")
 87+
 88+def generate_blocks():
 89+    blocks = []
 90+    
 91+    # Sound (Monokai Green #a6e22e)
 92+    blocks.append({"name": "sound", "full_text": get_sound(), "color": "#a6e22e"})
 93+    
 94+    # Battery (Monokai Yellow #e6db74)
 95+    bat = get_battery()
 96+    if bat:
 97+        blocks.append({"name": "battery", "full_text": bat, "color": "#e6db74"})
 98+        
 99+    # Brightness (Monokai Cyan #66d9ef)
100+    bright = get_brightness()
101+    if bright:
102+        blocks.append({"name": "brightness", "full_text": bright, "color": "#66d9ef"})
103+        
104+    # Network (Ethernet / WiFi) (Monokai Purple #ae81ff)
105+    blocks.append({"name": "wifi", "full_text": get_net(), "color": "#ae81ff"})
106+    
107+    # Clock (Monokai White #f8f8f2)
108+    blocks.append({"name": "clock", "full_text": get_time(), "color": "#f8f8f2"})
109+    
110+    return blocks
111+
112+def listen_clicks():
113+    while True:
114+        try:
115+            line = sys.stdin.readline()
116+            if not line:
117+                break
118+            clean_line = line.strip().lstrip("[,").rstrip(",")
119+            if not clean_line:
120+                continue
121+            event = json.loads(clean_line)
122+            block_name = event.get("name")
123+            button = event.get("button", 1)
124+            
125+            if button == 1:
126+                if block_name == "wifi":
127+                    try:
128+                        subprocess.Popen(["monstar", "-e", "nmtui"])
129+                    except FileNotFoundError:
130+                        subprocess.Popen(["foot", "-e", "nmtui"])
131+                elif block_name == "sound":
132+                    try:
133+                        subprocess.Popen(["pavucontrol"])
134+                    except FileNotFoundError:
135+                        subprocess.Popen(["pamixer", "-t"])
136+        except Exception:
137+            pass
138+
139+def main():
140+    try:
141+        # i3bar / swaybar JSON protocol header
142+        print(json.dumps({"version": 1, "click_events": True}))
143+        print("[")
144+        sys.stdout.flush()
145+        
146+        # Thread to handle click events on stdin
147+        threading.Thread(target=listen_clicks, daemon=True).start()
148+        
149+        while True:
150+            blocks = generate_blocks()
151+            print(json.dumps(blocks) + ",")
152+            sys.stdout.flush()
153+            time.sleep(1)
154+    except (BrokenPipeError, KeyboardInterrupt):
155+        sys.exit(0)
156+
157+if __name__ == "__main__":
158+    main()
+8, -2
 1@@ -5,11 +5,11 @@ base-devel
 2 bash-language-server
 3 bat
 4 bats
 5-bemenu
 6 bind
 7 blueprint-compiler
 8 bluez
 9 bluez-utils
10+brightnessctl
11 bun
12 cmake
13 difftastic
14@@ -31,10 +31,10 @@ git-delta
15 go
16 golangci-lint
17 gopls
18+grim
19 gtk4-layer-shell
20 htop
21 hunspell-en_us
22-imv
23 inetutils
24 intel-ucode
25 isync
26@@ -57,6 +57,7 @@ moreutils
27 mpv
28 msmtp
29 ncdu
30+networkmanager
31 nfs-utils
32 nmap
33 nodejs
34@@ -68,6 +69,7 @@ oath-toolkit
35 obs-studio
36 openbsd-netcat
37 openssh
38+pamixer
39 pass
40 pass-otp
41 pavucontrol
42@@ -83,9 +85,12 @@ rsync
43 shellcheck
44 shfmt
45 shotcut
46+slurp
47 smartmontools
48 steam
49 sway
50+swayidle
51+swaylock
52 thunar
53 traceroute
54 ttf-jetbrains-mono-nerd
55@@ -100,6 +105,7 @@ wayland-protocols
56 wireguard-tools
57 wl-clipboard
58 wlsunset
59+wmenu
60 xdg-desktop-portal-wlr
61 xorg-xwayland
62 zfs-linux
+5, -1
 1@@ -40,7 +40,6 @@ mpv
 2 networkmanager
 3 nfs-utils
 4 nm-connection-editor
 5-noctalia
 6 nodejs
 7 noto-fonts-emoji
 8 npm
 9@@ -50,6 +49,7 @@ openssh
10 pamixer
11 pass
12 pass-otp
13+pavucontrol
14 pipewire-pulse
15 power-profiles-daemon
16 reflector
17@@ -59,17 +59,21 @@ shotcut
18 slurp
19 steam
20 sway
21+swayidle
22+swaylock
23 systemd-resolvconf
24 ttf-jetbrains-mono-nerd
25 ttf-noto-nerd
26 unzip
27 vim
28+viu
29 vulkan-radeon
30 wireguard-tools
31 wireless_tools
32 wl-clipboard
33 wlr-randr
34 wlsunset
35+wmenu
36 xdg-utils
37 xorg-xwayland
38 zig