summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rwxr-xr-xarchsetup60
-rw-r--r--archsetup.conf.example13
-rw-r--r--dotfiles/hyprland/.config/foot/foot.ini38
-rw-r--r--dotfiles/hyprland/.config/fuzzel/fuzzel.ini31
-rw-r--r--dotfiles/hyprland/.config/hypr/hyprland.conf177
-rw-r--r--dotfiles/hyprland/.config/hypr/hyprlock.conf78
-rw-r--r--dotfiles/hyprland/.config/waybar/config116
-rw-r--r--dotfiles/hyprland/.config/waybar/style.css97
-rw-r--r--dotfiles/hyprland/.gnupg/gpg-agent.conf18
-rwxr-xr-xdotfiles/hyprland/.local/bin/cycle-layout30
-rwxr-xr-xdotfiles/hyprland/.local/bin/pinentry-fuzzel107
-rwxr-xr-xdotfiles/hyprland/.local/bin/toggle-scratchpad29
-rwxr-xr-xdotfiles/hyprland/.local/bin/waybar-layout54
-rwxr-xr-xdotfiles/hyprland/.local/bin/waybar-netspeed52
-rw-r--r--dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Bold.ttfbin0 -> 2294328 bytes
-rw-r--r--dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttfbin0 -> 2295172 bytes
-rw-r--r--dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttfbin0 -> 2294116 bytes
-rw-r--r--dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttfbin0 -> 2293800 bytes
-rw-r--r--todo.org89
20 files changed, 827 insertions, 165 deletions
diff --git a/.gitignore b/.gitignore
index 9a36d8d..af69c66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
/docs/
/inbox/
+# Reference repos (external repos for reference)
+/reference-repos/
+
# VM Testing Infrastructure
/vm-images/
/test-results/
diff --git a/archsetup b/archsetup
index afaf00c..c0f95ca 100755
--- a/archsetup
+++ b/archsetup
@@ -128,8 +128,8 @@ load_config() {
### Configuration Defaults
# These can be overridden via --config-file
-username="${username:-cjennings}"
-password="${password:-welcome}" # CHANGE ON FIRST LOGIN
+username="${username:-}" # prompted if not set
+password="${password:-}" # prompted if not set
locale="${locale:-}" # set via prompt if not configured
desktop_env="${desktop_env:-hyprland}" # options: dwm, hyprland, none
@@ -146,7 +146,7 @@ dotemacs_repo="${dotemacs_repo:-https://git.cjennings.net/dotemacs.git}"
archsetup_repo="${archsetup_repo:-https://git.cjennings.net/archsetup.git}"
logfile="/var/log/archsetup-$(date +'%Y-%m-%d-%H-%M-%S').log"
-source_dir="/home/$username/.local/src" # aur/git source goes here
+source_dir="" # set in preflight_checks after username is known
packages_before="/var/log/archsetup-preexisting-package-list.txt"
packages_after="/var/log/archsetup-post-install-package-list.txt"
archsetup_packages="/var/log/archsetup-installed-packages.txt"
@@ -315,6 +315,51 @@ preflight_checks() {
echo " [OK] Locale: $locale (selected)"
fi
+ # Prompt for username if not set
+ if [[ -z "$username" ]]; then
+ echo ""
+ read -r -p "Enter username for primary account: " username
+ if [[ -z "$username" ]]; then
+ echo "ERROR: Username cannot be empty"
+ exit 1
+ fi
+ # Validate username (lowercase, starts with letter, alphanumeric + underscore)
+ if [[ ! "$username" =~ ^[a-z][a-z0-9_]*$ ]]; then
+ echo "ERROR: Invalid username"
+ echo " Must start with lowercase letter, contain only lowercase letters, numbers, underscores"
+ exit 1
+ fi
+ echo " [OK] Username: $username"
+ else
+ echo " [OK] Username: $username (from config)"
+ fi
+
+ # Prompt for password if not set
+ if [[ -z "$password" ]]; then
+ echo ""
+ while true; do
+ read -r -s -p "Enter password for $username: " password
+ echo ""
+ read -r -s -p "Confirm password: " password_confirm
+ echo ""
+ if [[ "$password" != "$password_confirm" ]]; then
+ echo " Passwords do not match. Try again."
+ continue
+ fi
+ if [[ -z "$password" ]]; then
+ echo " Password cannot be empty. Try again."
+ continue
+ fi
+ break
+ done
+ echo " [OK] Password: set"
+ else
+ echo " [OK] Password: (from config)"
+ fi
+
+ # Set paths that depend on username
+ source_dir="/home/$username/.local/src"
+
echo "Pre-flight checks passed."
echo ""
}
@@ -1260,16 +1305,14 @@ hyprland() {
action="Hyprland Utilities" && display "subtitle" "$action"
pacman_install waybar # status bar
- pacman_install wofi # app launcher
+ pacman_install fuzzel # app launcher (native Wayland, pinentry support)
pacman_install swww # wallpaper
pacman_install grim # screenshot
pacman_install slurp # region select
pacman_install gammastep # night light (replaces redshift)
pacman_install brightnessctl # brightness control
pacman_install pamixer # audio control
-
- # st terminal still works on Wayland via XWayland
- git_install "$st_repo"
+ pacman_install foot # native Wayland terminal
}
### Display Server (conditional)
@@ -1845,9 +1888,6 @@ outro() {
action="Cleanup" && display "title" "$action"
- action="forcing user password change on first login" && display "task" "$action"
- chage -d 0 "$username" >> "$logfile" 2>&1 || error_warn "$action" "$?"
-
display "subtitle" "Statistics"
action="identifying newly installed packages" && display "task" "$action"
pacman -Q > "$packages_after" || error_warn "$action" "$?"
diff --git a/archsetup.conf.example b/archsetup.conf.example
index 0fff4d8..fe8cd26 100644
--- a/archsetup.conf.example
+++ b/archsetup.conf.example
@@ -12,11 +12,14 @@
# User Configuration
#############################
-# Username for the primary user account (default: cjennings)
-USERNAME=cjennings
-
-# Initial password - CHANGE ON FIRST LOGIN (default: welcome)
-PASSWORD=welcome
+# Username for the primary user account
+# If not set, you will be prompted during installation
+#USERNAME=myusername
+
+# Password for the primary user account
+# If not set, you will be prompted during installation (recommended)
+# For automated installs, set this to your desired password
+#PASSWORD=mysecurepassword
#############################
# System Options
diff --git a/dotfiles/hyprland/.config/foot/foot.ini b/dotfiles/hyprland/.config/foot/foot.ini
new file mode 100644
index 0000000..a96778c
--- /dev/null
+++ b/dotfiles/hyprland/.config/foot/foot.ini
@@ -0,0 +1,38 @@
+# foot terminal configuration
+# Minimal config matching DWM color scheme
+
+[main]
+term=xterm-256color
+font=Berkeley Mono:size=14
+pad=8x8
+
+[scrollback]
+lines=10000
+
+[colors]
+# DWM-inspired colors: gray1=#222222, gray2=#444444, gray3=#bbbbbb, gray4=#eeeeee, cyan=#daa520
+background=222222
+foreground=eeeeee
+
+# Regular colors (0-7)
+regular0=222222 # black
+regular1=cc6666 # red
+regular2=b5bd68 # green
+regular3=f0c674 # yellow
+regular4=81a2be # blue
+regular5=b294bb # magenta
+regular6=8abeb7 # cyan
+regular7=c5c8c6 # white
+
+# Bright colors (8-15)
+bright0=444444 # bright black
+bright1=d54e53 # bright red
+bright2=b9ca4a # bright green
+bright3=e7c547 # bright yellow
+bright4=7aa6da # bright blue
+bright5=c397d8 # bright magenta
+bright6=70c0b1 # bright cyan
+bright7=eeeeee # bright white
+
+# Cursor: background foreground (golden on dark)
+cursor=222222 daa520
diff --git a/dotfiles/hyprland/.config/fuzzel/fuzzel.ini b/dotfiles/hyprland/.config/fuzzel/fuzzel.ini
new file mode 100644
index 0000000..ce46448
--- /dev/null
+++ b/dotfiles/hyprland/.config/fuzzel/fuzzel.ini
@@ -0,0 +1,31 @@
+# Fuzzel config - matching waybar DWM-inspired theme
+# Colors from waybar: bg=#222222, cpu=#bbbbbb, clock=#eeeeee, accent=#daa520
+
+[main]
+font=BerkeleyMono Nerd Font:size=14
+prompt=Search:
+icon-theme=hicolor
+icons-enabled=yes
+width=30
+lines=12
+horizontal-pad=20
+vertical-pad=12
+inner-pad=8
+layer=overlay
+exit-on-keyboard-focus-loss=yes
+
+[colors]
+# Format: RRGGBBAA
+background=222222f0
+text=eeeeeeff
+selection=daa520ff
+selection-text=222222ff
+border=daa520ff
+match=daa520ff
+prompt=bbbbbbff
+placeholder=888888ff
+input=eeeeeeff
+
+[border]
+width=2
+radius=16
diff --git a/dotfiles/hyprland/.config/hypr/hyprland.conf b/dotfiles/hyprland/.config/hypr/hyprland.conf
index ce45088..e2afa07 100644
--- a/dotfiles/hyprland/.config/hypr/hyprland.conf
+++ b/dotfiles/hyprland/.config/hypr/hyprland.conf
@@ -15,7 +15,6 @@ exec-once = swww-daemon && sleep 1 && swww img ~/pictures/wallpaper/dark-lion.jp
exec-once = dunst
exec-once = hypridle
exec-once = gammastep
-exec-once = nm-applet
exec-once = blueman-applet
exec-once = /usr/bin/gnome-keyring-daemon --start --components=pkcs11,secrets,ssh
exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
@@ -39,8 +38,8 @@ env = _JAVA_AWT_WM_NONREPARENTING,1
# DWM colors: gray1=#222222, gray2=#444444, gray3=#bbbbbb, gray4=#eeeeee, cyan=#daa520
general {
- gaps_in = 5
- gaps_out = 10
+ gaps_in = 25
+ gaps_out = 30
border_size = 3
col.active_border = rgba(daa520ff)
col.inactive_border = rgba(444444ff)
@@ -49,7 +48,7 @@ general {
}
decoration {
- rounding = 0
+ rounding = 10
blur {
enabled = false
}
@@ -86,7 +85,7 @@ dwindle {
input {
kb_layout = us
kb_options = ctrl:nocaps
- follow_mouse = 1
+ follow_mouse = 0
touchpad {
natural_scroll = true
}
@@ -108,15 +107,15 @@ xwayland {
}
# ============================================================================
-# Window Rules
+# Window Rules (Hyprland 0.53+ syntax: match:CONDITION, RULE)
# ============================================================================
# Floating windows (from DWM rules)
-windowrulev2 = float, class:^(Gimp)$
-windowrulev2 = float, class:^(caffeine)$
-windowrulev2 = float, class:^(blueman-services)$
-windowrulev2 = float, class:^(Blueman-manager)$
-windowrulev2 = float, class:^(qalculate-gtk)$
-windowrulev2 = float, title:^(Event Tester)$
+windowrule = match:class ^(Gimp)$, float on
+windowrule = match:class ^(caffeine)$, float on
+windowrule = match:class ^(blueman-services)$, float on
+windowrule = match:class ^(Blueman-manager)$, float on
+windowrule = match:class ^(qalculate-gtk)$, float on
+windowrule = match:title ^(Event Tester)$, float on
# ============================================================================
# Key Bindings
@@ -124,47 +123,62 @@ windowrulev2 = float, title:^(Event Tester)$
$mod = SUPER
# Terminal and core apps (from DWM)
-bind = $mod, T, exec, st
+bind = $mod, T, exec, foot
bind = $mod, E, exec, emacsclient -c -a "" || emacs
bind = $mod, W, exec, $BROWSER
-bind = $mod, P, exec, wofi --show drun
+bind = $mod, P, exec, fuzzel
# From sxhkdrc
-bind = $mod, SPACE, exec, wofi --show drun
-bind = $mod SHIFT, S, exec, wofi --show ssh
+bind = $mod, SPACE, exec, fuzzel
+bind = $mod SHIFT, S, exec, fuzzel --dmenu < ~/.ssh/config | grep -oP '^Host\s+\K\S+' | fuzzel --dmenu --prompt "SSH: " | xargs -I{} foot ssh {}
bind = $mod SHIFT, W, exec, $ALTBROWSER
bind = CTRL ALT, W, exec, tor-browser
bind = CTRL ALT, F, exec, thunar
bind = $mod, V, exec, virtualbox
bind = $mod SHIFT, L, exec, calibre
bind = $mod SHIFT, R, exec, shortwave
+bind = $mod SHIFT, P, exec, waypaper
# Window management (from DWM)
bind = $mod, J, layoutmsg, cyclenext
bind = $mod, K, layoutmsg, cycleprev
bind = $mod SHIFT, J, layoutmsg, swapnext
bind = $mod SHIFT, K, layoutmsg, swapprev
-bind = $mod, H, resizeactive, -50 0
-bind = $mod, L, resizeactive, 50 0
-bind = $mod, RETURN, layoutmsg, swapwithmaster
+bind = $mod, H, splitratio, -0.05
+bind = $mod, L, splitratio, +0.05
+bind = $mod, RETURN, layoutmsg, swapwithmaster master
bind = $mod, G, centerwindow
bind = $mod, TAB, workspace, previous
bind = $mod SHIFT, C, killactive
# Layouts (from DWM)
-bind = $mod SHIFT, M, exec, hyprctl keyword general:layout master
-bind = $mod SHIFT, T, exec, hyprctl keyword general:layout master
+# monocle [M] - maximize window
+bind = $mod SHIFT, M, fullscreen, 1
+# tile []= - master on left (default master orientation)
+bind = $mod SHIFT, T, exec, hyprctl keyword general:layout master && hyprctl keyword master:orientation left
+# floating ><> - toggle floating for current window
bind = $mod SHIFT, F, togglefloating
bind = $mod SHIFT, SPACE, togglefloating
+# bstack TTT - master on top
+bind = $mod SHIFT, U, exec, hyprctl keyword general:layout master && hyprctl keyword master:orientation top
+# bstackhoriz === - same as bstack in Hyprland
+bind = $mod, U, exec, hyprctl keyword general:layout master && hyprctl keyword master:orientation top
+# deck [D] - use dwindle layout as approximation
+bind = $mod SHIFT, D, exec, hyprctl keyword general:layout dwindle
+# centeredmaster |M| - master in center
+bind = $mod SHIFT, I, exec, hyprctl keyword general:layout master && hyprctl keyword master:orientation center
+# centeredfloatingmaster >M> - no direct equivalent, use centered master
+bind = $mod SHIFT, O, exec, hyprctl keyword general:layout master && hyprctl keyword master:orientation center
# Master layout adjustments
bind = $mod, I, layoutmsg, addmaster
bind = $mod, D, layoutmsg, removemaster
# Gaps (from DWM)
-bind = $mod, MINUS, exec, hyprctl keyword general:gaps_out $(( $(hyprctl getoption general:gaps_out -j | jq '.int') - 5 ))
-bind = $mod, EQUAL, exec, hyprctl keyword general:gaps_out $(( $(hyprctl getoption general:gaps_out -j | jq '.int') + 5 ))
-bind = $mod SHIFT, EQUAL, exec, hyprctl keyword general:gaps_out 10
+bind = $mod, MINUS, exec, hyprctl keyword general:gaps_out $(( $(hyprctl getoption general:gaps_out -j | jq -r '.custom' | cut -d' ' -f1) - 5 )) && hyprctl keyword general:gaps_in $(( $(hyprctl getoption general:gaps_in -j | jq -r '.custom' | cut -d' ' -f1) - 5 ))
+bind = $mod, EQUAL, exec, hyprctl keyword general:gaps_out $(( $(hyprctl getoption general:gaps_out -j | jq -r '.custom' | cut -d' ' -f1) + 5 )) && hyprctl keyword general:gaps_in $(( $(hyprctl getoption general:gaps_in -j | jq -r '.custom' | cut -d' ' -f1) + 5 ))
+bind = $mod SHIFT, EQUAL, exec, hyprctl keyword general:gaps_out 30 && hyprctl keyword general:gaps_in 25
+bind = $mod SHIFT, MINUS, exec, hyprctl keyword general:gaps_out 0 && hyprctl keyword general:gaps_in 0
# Toggle bar
bind = $mod, B, exec, killall -SIGUSR1 waybar
@@ -185,16 +199,16 @@ bind = $mod, 9, workspace, 9
bind = $mod, 0, workspace, 10
# Move window to workspace (from DWM tag)
-bind = $mod SHIFT, 1, movetoworkspace, 1
-bind = $mod SHIFT, 2, movetoworkspace, 2
-bind = $mod SHIFT, 3, movetoworkspace, 3
-bind = $mod SHIFT, 4, movetoworkspace, 4
-bind = $mod SHIFT, 5, movetoworkspace, 5
-bind = $mod SHIFT, 6, movetoworkspace, 6
-bind = $mod SHIFT, 7, movetoworkspace, 7
-bind = $mod SHIFT, 8, movetoworkspace, 8
-bind = $mod SHIFT, 9, movetoworkspace, 9
-bind = $mod SHIFT, 0, movetoworkspace, 10
+bind = $mod SHIFT, 1, movetoworkspacesilent, 1
+bind = $mod SHIFT, 2, movetoworkspacesilent, 2
+bind = $mod SHIFT, 3, movetoworkspacesilent, 3
+bind = $mod SHIFT, 4, movetoworkspacesilent, 4
+bind = $mod SHIFT, 5, movetoworkspacesilent, 5
+bind = $mod SHIFT, 6, movetoworkspacesilent, 6
+bind = $mod SHIFT, 7, movetoworkspacesilent, 7
+bind = $mod SHIFT, 8, movetoworkspacesilent, 8
+bind = $mod SHIFT, 9, movetoworkspacesilent, 9
+bind = $mod SHIFT, 0, movetoworkspacesilent, 10
# Monitor focus (from DWM focusmon)
bind = $mod, COMMA, focusmonitor, -1
@@ -202,54 +216,69 @@ bind = $mod, PERIOD, focusmonitor, +1
bind = $mod SHIFT, COMMA, movewindow, mon:-1
bind = $mod SHIFT, PERIOD, movewindow, mon:+1
+# ============================================================================
# Scratchpads (from DWM togglescratch)
-# Audio mixer (was MODKEY+a -> spaudio/pulsemixer)
+# ============================================================================
+# Using on-created-empty workspace rules - app launches on first toggle,
+# subsequent toggles just show/hide the workspace
+
+# Workspace rules (auto-launch apps when workspace first accessed)
+workspace = special:term, on-created-empty:foot --app-id foot-term tmux
+workspace = special:audio, on-created-empty:foot --app-id foot-audio pulsemixer
+workspace = special:monitor, on-created-empty:foot --app-id foot-monitor gotop
+workspace = special:music, on-created-empty:foot --app-id foot-music ncmpcpp
+workspace = special:files, on-created-empty:foot --app-id foot-files ranger
+workspace = special:htop, on-created-empty:foot --app-id foot-htop htop
+workspace = special:network, on-created-empty:foot --app-id foot-network nmtui
+
+# Keybindings (single bind per scratchpad - just toggle visibility)
+bind = $mod SHIFT, RETURN, togglespecialworkspace, term
bind = $mod, A, togglespecialworkspace, audio
-bind = $mod, A, exec, [workspace special:audio] pgrep -x pulsemixer || st -n spaudio -e pulsemixer
-windowrulev2 = float, class:^(st)$, title:^(spaudio)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(spaudio)$
-windowrulev2 = center, class:^(st)$, title:^(spaudio)$
-windowrulev2 = workspace special:audio, class:^(st)$, title:^(spaudio)$
-
-# System monitor (was MODKEY+m -> spmon/gotop)
bind = $mod, M, togglespecialworkspace, monitor
-bind = $mod, M, exec, [workspace special:monitor] pgrep -x gotop || st -n spmon -e gotop
-windowrulev2 = float, class:^(st)$, title:^(spmon)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(spmon)$
-windowrulev2 = workspace special:monitor, class:^(st)$, title:^(spmon)$
-
-# Music player (was MODKEY+slash -> spmp/ncmpcpp)
bind = $mod, SLASH, togglespecialworkspace, music
-bind = $mod, SLASH, exec, [workspace special:music] pgrep -x ncmpcpp || st -n spmp -e ncmpcpp
-windowrulev2 = float, class:^(st)$, title:^(spmp)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(spmp)$
-windowrulev2 = workspace special:music, class:^(st)$, title:^(spmp)$
-
-# Terminal scratchpad (was MODKEY+Shift+Return -> spterm/tmux)
-bind = $mod SHIFT, RETURN, togglespecialworkspace, term
-bind = $mod SHIFT, RETURN, exec, [workspace special:term] pgrep -f "st.*spterm" || st -n spterm -e tmux
-windowrulev2 = float, class:^(st)$, title:^(spterm)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(spterm)$
-windowrulev2 = workspace special:term, class:^(st)$, title:^(spterm)$
-
-# File manager (was MODKEY+f -> spfm/ranger)
bind = $mod, F, togglespecialworkspace, files
-bind = $mod, F, exec, [workspace special:files] pgrep -x ranger || st -n spfm -e ranger
-windowrulev2 = float, class:^(st)$, title:^(spfm)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(spfm)$
-windowrulev2 = workspace special:files, class:^(st)$, title:^(spfm)$
+bind = $mod SHIFT, H, togglespecialworkspace, htop
-# Calculator (was MODKEY+x or MODKEY+c -> qalculate)
+# Window rules (using app-id/class matching, Hyprland 0.53+ syntax)
+# Terminal scratchpad
+windowrule = match:class ^(foot-term)$, float on
+windowrule = match:class ^(foot-term)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-term)$, center on
+
+# Audio mixer
+windowrule = match:class ^(foot-audio)$, float on
+windowrule = match:class ^(foot-audio)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-audio)$, center on
+
+# System monitor
+windowrule = match:class ^(foot-monitor)$, float on
+windowrule = match:class ^(foot-monitor)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-monitor)$, center on
+
+# Music player
+windowrule = match:class ^(foot-music)$, float on
+windowrule = match:class ^(foot-music)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-music)$, center on
+
+# File manager
+windowrule = match:class ^(foot-files)$, float on
+windowrule = match:class ^(foot-files)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-files)$, center on
+
+# Htop
+windowrule = match:class ^(foot-htop)$, float on
+windowrule = match:class ^(foot-htop)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-htop)$, center on
+
+# Network manager
+windowrule = match:class ^(foot-network)$, float on
+windowrule = match:class ^(foot-network)$, size (monitor_w*0.6) (monitor_h*0.6)
+windowrule = match:class ^(foot-network)$, center on
+
+# Calculator (not a scratchpad, just launches app)
bind = $mod, X, exec, qalculate-gtk
bind = $mod, C, exec, qalculate-gtk
-# Htop (was MODKEY+Shift+h -> sptop/htop)
-bind = $mod SHIFT, H, togglespecialworkspace, htop
-bind = $mod SHIFT, H, exec, [workspace special:htop] pgrep -x htop || st -n sptop -e htop
-windowrulev2 = float, class:^(st)$, title:^(sptop)$
-windowrulev2 = size 60% 60%, class:^(st)$, title:^(sptop)$
-windowrulev2 = workspace special:htop, class:^(st)$, title:^(sptop)$
-
# Media/hardware keys
bindel = , XF86AudioRaiseVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ +5%
bindel = , XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -5%
@@ -277,7 +306,7 @@ bind = $mod, ESCAPE, exec, hyprlock
bind = $mod, F9, exec, toggle-touchpad
# Exit/session (from DWM)
-bind = $mod SHIFT, Q, exec, wofi --show dmenu --prompt "Exit?" -D dmenu/exit="0" < /dev/null && hyprctl dispatch exit
+bind = $mod SHIFT, Q, exec, printf "Exit\nCancel" | fuzzel --dmenu --prompt "Exit Hyprland? " | grep -q "Exit" && hyprctl dispatch exit
bind = $mod SHIFT, BACKSPACE, exit
bind = $mod SHIFT, ESCAPE, exec, hyprctl reload
diff --git a/dotfiles/hyprland/.config/hypr/hyprlock.conf b/dotfiles/hyprland/.config/hypr/hyprlock.conf
index b4dcfb8..4f1c5df 100644
--- a/dotfiles/hyprland/.config/hypr/hyprlock.conf
+++ b/dotfiles/hyprland/.config/hypr/hyprlock.conf
@@ -1,5 +1,6 @@
# Hyprlock configuration
# Matching DWM colors: gray1=#222222, accent=#daa520
+# Using percentages for proportional sizing across monitors
general {
disable_loading_bar = false
@@ -20,22 +21,65 @@ background {
vibrancy_darkness = 0.0
}
+# Clock (top)
+label {
+ monitor =
+ text = $TIME12
+ text_align = center
+ color = rgb(bbbbbb)
+ font_size = 64
+ font_family = BerkeleyMono Nerd Font
+ position = 0, 15%
+ halign = center
+ valign = center
+}
+
+# Profile image
+image {
+ monitor =
+ path = ~/pictures/devilman.jpg
+ size = 120
+ rounding = -1
+ border_size = 3
+ border_color = rgb(daa520)
+ position = 0, 0%
+ halign = center
+ valign = center
+ shadow_passes = 2
+ shadow_size = 3
+ shadow_color = rgba(0, 0, 0, 0.5)
+}
+
+# Username
+label {
+ monitor =
+ text = $USER
+ text_align = center
+ color = rgb(daa520)
+ font_size = 36
+ font_family = BerkeleyMono Nerd Font
+ position = 0, -7%
+ halign = center
+ valign = center
+}
+
+# Password input (no outline)
input-field {
monitor =
- size = 300, 50
- outline_thickness = 3
+ size = 20%, 4%
+ outline_thickness = 0
dots_size = 0.33
dots_spacing = 0.15
dots_center = true
dots_rounding = -1
- outer_color = rgb(444444)
+ outer_color = rgb(222222)
inner_color = rgb(222222)
font_color = rgb(bbbbbb)
fade_on_empty = true
fade_timeout = 1000
placeholder_text = <i>Password...</i>
hide_input = false
- rounding = 0
+ rounding = 8
check_color = rgb(daa520)
fail_color = rgb(d9534f)
fail_text = <i>$FAIL <b>($ATTEMPTS)</b></i>
@@ -45,31 +89,7 @@ input-field {
bothlock_color = -1
invert_numlock = false
swap_font_color = false
- position = 0, -20
- halign = center
- valign = center
-}
-
-label {
- monitor =
- text = $TIME
- text_align = center
- color = rgb(bbbbbb)
- font_size = 64
- font_family = FiraCode Nerd Font Mono
- position = 0, 80
- halign = center
- valign = center
-}
-
-label {
- monitor =
- text = $USER
- text_align = center
- color = rgb(daa520)
- font_size = 20
- font_family = FiraCode Nerd Font Mono
- position = 0, -80
+ position = 0, -12%
halign = center
valign = center
}
diff --git a/dotfiles/hyprland/.config/waybar/config b/dotfiles/hyprland/.config/waybar/config
index 3b3a90f..c7cc0a7 100644
--- a/dotfiles/hyprland/.config/waybar/config
+++ b/dotfiles/hyprland/.config/waybar/config
@@ -3,48 +3,124 @@
"position": "top",
"height": 30,
"spacing": 4,
+ "margin-top": 6,
+ "margin-left": 10,
+ "margin-right": 10,
- "modules-left": ["hyprland/workspaces"],
- "modules-center": ["hyprland/window"],
- "modules-right": ["tray", "battery", "disk", "clock"],
+ "modules-left": [
+ "hyprland/workspaces",
+ "custom/layout",
+ "hyprland/window"
+ ],
+ "modules-center": [],
+ "modules-right": [
+ "group/sysmonitor",
+ "custom/netspeed",
+ "wireplumber",
+ "tray",
+ "clock"
+ ],
+
+ "group/sysmonitor": {
+ "orientation": "horizontal",
+ "modules": [
+ "cpu",
+ "temperature",
+ "memory",
+ "disk",
+ "battery"
+ ]
+ },
"hyprland/workspaces": {
+ "disable-scroll": true,
+ "all-outputs": true,
"format": "{name}",
- "on-click": "activate",
"sort-by-number": true
},
+ "custom/layout": {
+ "exec": "waybar-layout",
+ "return-type": "json",
+ "interval": 1,
+ "on-click": "cycle-layout"
+ },
+
"hyprland/window": {
- "format": "{}",
- "max-length": 50
+ "max-length": 50,
+ "separate-outputs": true
},
- "tray": {
- "spacing": 10
+ "cpu": {
+ "interval": 10,
+ "format": "<span size='large'>󰍛</span> {}%",
+ "on-click": "toggle-scratchpad monitor"
+ },
+
+ "temperature": {
+ "interval": 10,
+ "hwmon-path-abs": "/sys/devices/pci0000:00/0000:00:18.3/hwmon",
+ "input-filename": "temp1_input",
+ "critical-threshold": 80,
+ "format": "<span size='large'>󰔏</span> {temperatureC}°C",
+ "format-critical": "<span size='large'>󰸁</span> {temperatureC}°C",
+ "on-click": "toggle-scratchpad monitor"
+ },
+
+ "memory": {
+ "interval": 30,
+ "format": "<span size='large'>󰘚</span> {}%",
+ "on-click": "toggle-scratchpad monitor"
+ },
+
+ "disk": {
+ "interval": 30,
+ "format": "<span size='large'>󰆼</span> {percentage_used}%",
+ "path": "/",
+ "on-click": "toggle-scratchpad monitor"
+ },
+
+ "custom/netspeed": {
+ "exec": "waybar-netspeed",
+ "return-type": "json",
+ "interval": 2,
+ "on-click": "toggle-scratchpad network"
},
"battery": {
- "bat": "BAT0",
"interval": 30,
"states": {
"warning": 30,
"critical": 15
},
- "format": "󱊣 {capacity}% {icon}",
- "format-charging": "󱊣 {capacity}% ",
- "format-plugged": "󱊣 {capacity}% ",
- "format-icons": ["", "", "", "", ""]
+ "format": "<span size='large'>{icon}</span> {capacity}%",
+ "format-charging": "<span size='large'>󰂄</span> {capacity}%",
+ "format-plugged": "<span size='large'>󰚥</span> {capacity}%",
+ "format-icons": ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"],
+ "tooltip-format": "{timeTo}"
},
- "disk": {
- "interval": 30,
- "format": " {used}/{total}",
- "path": "/"
+ "tray": {
+ "icon-size": 22,
+ "spacing": 10
},
"clock": {
- "interval": 30,
- "format": " {:%a %B %d} 󰥔 {:%I:%M %p %Z}",
- "tooltip-format": "<tt>{calendar}</tt>"
+ "format": "{:%a, %b %d %Y %I:%M %p %Z}",
+ "tooltip-format": "<small>{calendar}</small>",
+ "calendar": {
+ "format": {
+ "today": "<span color='#daa520'><b><u>{}</u></b></span>"
+ }
+ }
+ },
+
+ "wireplumber": {
+ "format": "<span size='large'>󰕾</span> {volume}%",
+ "format-muted": "<span size='large'>󰝟</span> Muted",
+ "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
+ "on-click-right": "toggle-scratchpad audio",
+ "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
}
}
diff --git a/dotfiles/hyprland/.config/waybar/style.css b/dotfiles/hyprland/.config/waybar/style.css
index 9411b46..6b760a2 100644
--- a/dotfiles/hyprland/.config/waybar/style.css
+++ b/dotfiles/hyprland/.config/waybar/style.css
@@ -1,61 +1,104 @@
-/* Waybar style - matching DWM colors */
-/* gray1=#222222, gray2=#444444, gray3=#bbbbbb, gray4=#eeeeee, accent=#daa520 */
+/* Waybar style - Hyprland-Rice inspired with DWM colors */
+/* Based on: github.com/CtrlLuzzio/Hyprland-Rice */
* {
- font-family: "FiraCode Nerd Font Mono", monospace;
- font-size: 12px;
border: none;
border-radius: 0;
+ font-size: 14px;
min-height: 0;
+ font-family: "BerkeleyMono Nerd Font", "Berkeley Mono", monospace;
}
window#waybar {
- background-color: #222222;
- color: #bbbbbb;
+ background: transparent;
}
-#workspaces button {
- padding: 0 8px;
- color: #bbbbbb;
- background-color: transparent;
+#workspaces {
+ padding: 0.2rem;
}
-#workspaces button:hover {
- background-color: #444444;
+#workspaces button {
+ padding: 0.5rem;
+ margin: 0.2rem;
+ background-color: transparent;
+ color: #bbbbbb;
+ border-radius: 1rem;
+ transition: all 0.3s ease;
}
#workspaces button.active {
- color: #eeeeee;
- background-color: #daa520;
+ background: #daa520;
+ color: #222222;
+ border-radius: 1rem;
}
#workspaces button.urgent {
- background-color: #900000;
+ background-color: rgba(255, 88, 88, 0.4);
+}
+
+.modules-right, .modules-left {
+ background-color: #222222;
+ border-radius: 1rem;
+ padding: 0.2rem 0.6rem;
+ margin: 0.3rem;
+ border: 0.095rem solid #daa520;
+ box-shadow: 0rem 0.2rem 0.4rem rgba(0,0,0,0.5);
}
+#cpu,
+#temperature,
+#memory,
+#disk,
+#custom-netspeed,
+#battery,
+#wireplumber,
+#tray,
+#clock,
+#custom-layout,
#window {
+ padding: 0.4rem;
+ margin: 0.3rem;
color: #bbbbbb;
- padding: 0 10px;
+ background-color: transparent;
+ border-radius: 1rem;
}
-#clock,
-#battery,
-#disk,
-#tray {
- padding: 0 10px;
+#sysmonitor {
+ margin: 0.3rem;
+ background-color: transparent;
+ border-radius: 1rem;
+}
+
+#cpu:hover,
+#temperature:hover,
+#memory:hover,
+#disk:hover,
+#custom-netspeed:hover,
+#wireplumber:hover,
+#sysmonitor:hover,
+#custom-layout:hover {
+ background-color: #444444;
+ border-radius: 1rem;
+}
+
+#clock {
+ color: #eeeeee;
+}
+
+#wireplumber {
color: #bbbbbb;
}
-#battery.charging {
- color: #daa520;
+#wireplumber.muted {
+ color: #666666;
}
-#battery.warning:not(.charging) {
- color: #f0ad4e;
+#battery.warning {
+ color: #daa520;
}
-#battery.critical:not(.charging) {
- color: #d9534f;
+#battery.critical {
+ color: #ff5858;
}
#tray > .passive {
diff --git a/dotfiles/hyprland/.gnupg/gpg-agent.conf b/dotfiles/hyprland/.gnupg/gpg-agent.conf
new file mode 100644
index 0000000..068f889
--- /dev/null
+++ b/dotfiles/hyprland/.gnupg/gpg-agent.conf
@@ -0,0 +1,18 @@
+# Pinentry configuration (Wayland/Hyprland)
+pinentry-program ~/.local/bin/pinentry-fuzzel
+pinentry-timeout 10
+allow-loopback-pinentry
+
+# Cache passphrases for entire login session (400 days)
+default-cache-ttl 34560000
+max-cache-ttl 34560000
+
+# Enable SSH support (use gpg-agent for SSH keys too)
+enable-ssh-support
+
+# Prevent external programs from clearing cache
+no-allow-external-cache
+
+# Keep running even when no connections
+keep-display
+keep-tty
diff --git a/dotfiles/hyprland/.local/bin/cycle-layout b/dotfiles/hyprland/.local/bin/cycle-layout
new file mode 100755
index 0000000..a3b1b1a
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/cycle-layout
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Cycle through Hyprland layouts
+
+LAYOUT=$(hyprctl getoption general:layout -j | jq -r '.str')
+ORIENTATION=""
+
+if [ "$LAYOUT" = "master" ]; then
+ ORIENTATION=$(hyprctl getoption master:orientation -j | jq -r '.str')
+fi
+
+# Cycle: master-left -> master-top -> master-center -> dwindle -> master-left
+if [ "$LAYOUT" = "dwindle" ]; then
+ hyprctl keyword general:layout master
+ hyprctl keyword master:orientation left
+elif [ "$LAYOUT" = "master" ]; then
+ case "$ORIENTATION" in
+ left)
+ hyprctl keyword master:orientation top
+ ;;
+ top)
+ hyprctl keyword master:orientation center
+ ;;
+ center)
+ hyprctl keyword general:layout dwindle
+ ;;
+ *)
+ hyprctl keyword master:orientation left
+ ;;
+ esac
+fi
diff --git a/dotfiles/hyprland/.local/bin/pinentry-fuzzel b/dotfiles/hyprland/.local/bin/pinentry-fuzzel
new file mode 100755
index 0000000..4cbe6b7
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/pinentry-fuzzel
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+ENABLE_LOGGING="TRUE"
+logger() {
+ if [ "$ENABLE_LOGGING" == "TRUE" ]; then
+ /usr/bin/logger -t "${0} [$]" "$@";
+ fi
+}
+
+# Decode URL-encoded characters (%0A = newline, %20 = space, etc.)
+decode() {
+ printf '%b' "$(echo "$1" | sed 's/%\([0-9A-Fa-f][0-9A-Fa-f]\)/\\x\1/g')"
+}
+
+# Base command and misc variables
+DESC=""
+PROMPT=""
+COUNTFILE="/tmp/pinentry-fuzzel-count-$$"
+
+# Check if this is a repeat prompt (within 5 seconds of last)
+LASTFILE="/tmp/pinentry-fuzzel-last"
+NOW=$(date +%s)
+if [ -f "$LASTFILE" ]; then
+ LAST=$(cat "$LASTFILE")
+ if [ $((NOW - LAST)) -lt 5 ]; then
+ REPEAT=1
+ else
+ REPEAT=0
+ fi
+else
+ REPEAT=0
+fi
+echo "$NOW" > "$LASTFILE"
+
+echo "OK Please go ahead"
+while read cmd rest; do
+ logger "RAW=< ${cmd} ${rest} >"
+ logger "cmd=<${cmd}> rest=<${rest}>"
+
+ case $cmd in
+ GETINFO)
+ case "$rest" in
+ flavor)
+ echo "D fuzzel"
+ echo "OK"
+ ;;
+ version)
+ echo "D 0.1"
+ echo "OK"
+ ;;
+ ttyinfo)
+ echo "D - - -"
+ echo "OK"
+ ;;
+ pid)
+ echo "D $$"
+ echo "OK"
+ ;;
+ esac
+ ;;
+
+ SETDESC)
+ DESC=$(decode "$rest")
+ echo "OK"
+ ;;
+
+ SETERROR)
+ logger "ERROR $rest"
+ # Silently acknowledge errors (e.g., empty passphrase on escape)
+ echo "OK"
+ ;;
+
+ SETPROMPT)
+ PROMPT=$(decode "$rest")
+ # Remove trailing colon if present (we add our own)
+ PROMPT="${PROMPT%:}"
+ echo "OK"
+ ;;
+
+ GETPIN | getpin)
+ if [ "$REPEAT" -eq 0 ]; then
+ LABEL="password: "
+ else
+ LABEL="reenter: "
+ fi
+ PASS=$(fuzzel --prompt "$LABEL" --width 25 --lines 0 --cache /dev/null --password --dmenu)
+ if [ -z "$PASS" ]; then
+ # User cancelled - return error to GPG
+ rm -f "$LASTFILE"
+ echo "ERR 83886179 Operation cancelled"
+ else
+ echo "D $PASS"
+ echo "OK"
+ fi
+ ;;
+
+ BYE|bye)
+ echo "OK closing connection"
+ logger "EXITING"
+ exit 0
+ ;;
+
+ *)
+ echo "OK"
+ ;;
+ esac
+done
diff --git a/dotfiles/hyprland/.local/bin/toggle-scratchpad b/dotfiles/hyprland/.local/bin/toggle-scratchpad
new file mode 100755
index 0000000..bb10ef7
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/toggle-scratchpad
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Toggle a special workspace from waybar click
+# Tracks state to handle focus-loss auto-close issue
+# Usage: toggle-scratchpad <name>
+
+NAME="$1"
+if [ -z "$NAME" ]; then
+ echo "Usage: toggle-scratchpad <name>"
+ exit 1
+fi
+
+STATEFILE="/tmp/scratchpad-$NAME-open"
+NOW=$(date +%s)
+
+# If state file exists and recent, scratchpad was open and just closed by focus loss
+# Don't reopen it - user intended to close
+if [ -f "$STATEFILE" ]; then
+ LAST=$(cat "$STATEFILE")
+ AGE=$((NOW - LAST))
+ rm -f "$STATEFILE"
+ if [ "$AGE" -lt 2 ]; then
+ # Was just open, user clicked to close - don't reopen
+ exit 0
+ fi
+fi
+
+# Opening the scratchpad - mark timestamp
+echo "$NOW" > "$STATEFILE"
+hyprctl dispatch togglespecialworkspace "$NAME"
diff --git a/dotfiles/hyprland/.local/bin/waybar-layout b/dotfiles/hyprland/.local/bin/waybar-layout
new file mode 100755
index 0000000..7ffb8a8
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/waybar-layout
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Hyprland layout indicator for waybar
+# Shows current layout with nerd font icons
+
+# Get current layout
+LAYOUT=$(hyprctl getoption general:layout -j | jq -r '.str')
+
+# Get master orientation if using master layout
+ORIENTATION=""
+if [ "$LAYOUT" = "master" ]; then
+ ORIENTATION=$(hyprctl getoption master:orientation -j | jq -r '.str')
+fi
+
+# Check if active window is fullscreen (monocle)
+FULLSCREEN=$(hyprctl activewindow -j | jq -r '.fullscreen')
+
+# Check if active window is floating
+FLOATING=$(hyprctl activewindow -j | jq -r '.floating')
+
+# Determine icon and tooltip
+if [ "$FULLSCREEN" = "2" ] || [ "$FULLSCREEN" = "1" ]; then
+ ICON="󰊓"
+ TOOLTIP="Monocle (fullscreen)"
+elif [ "$FLOATING" = "true" ]; then
+ ICON="󰖲"
+ TOOLTIP="Floating"
+elif [ "$LAYOUT" = "dwindle" ]; then
+ ICON="󱒎"
+ TOOLTIP="Dwindle"
+elif [ "$LAYOUT" = "master" ]; then
+ case "$ORIENTATION" in
+ left)
+ ICON="󰕰"
+ TOOLTIP="Master (left)"
+ ;;
+ top)
+ ICON="󱂩"
+ TOOLTIP="Master (top)"
+ ;;
+ center)
+ ICON="󰘸"
+ TOOLTIP="Master (center)"
+ ;;
+ *)
+ ICON="󰕰"
+ TOOLTIP="Master"
+ ;;
+ esac
+else
+ ICON="󰕰"
+ TOOLTIP="Unknown"
+fi
+
+echo "{\"text\": \"<span size='large'>$ICON</span>\", \"tooltip\": \"$TOOLTIP\"}"
diff --git a/dotfiles/hyprland/.local/bin/waybar-netspeed b/dotfiles/hyprland/.local/bin/waybar-netspeed
new file mode 100755
index 0000000..504ad8c
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/waybar-netspeed
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Network speed monitor with fixed-width output for waybar
+# Outputs JSON with upload/download speeds padded to consistent width
+
+INTERFACE=$(ip route | awk '/default/ {print $5; exit}')
+
+if [ -z "$INTERFACE" ]; then
+ echo '{"text": "No network", "class": "disconnected"}'
+ exit 0
+fi
+
+RX1=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
+TX1=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
+sleep 1
+RX2=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
+TX2=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
+
+RX_RATE=$((RX2 - RX1))
+TX_RATE=$((TX2 - TX1))
+
+format_speed() {
+ local bytes=$1
+ if [ $bytes -ge 1073741824 ]; then
+ printf "%6.2f G" $(echo "scale=2; $bytes / 1073741824" | bc)
+ elif [ $bytes -ge 1048576 ]; then
+ printf "%6.2f M" $(echo "scale=2; $bytes / 1048576" | bc)
+ elif [ $bytes -ge 1024 ]; then
+ printf "%6.2f K" $(echo "scale=2; $bytes / 1024" | bc)
+ else
+ printf "%6d B" $bytes
+ fi
+}
+
+UP=$(format_speed $TX_RATE)
+DOWN=$(format_speed $RX_RATE)
+
+# Get IP for tooltip
+IP=$(ip -4 addr show $INTERFACE | awk '/inet / {print $2}')
+
+# Check if WiFi and get SSID
+SSID=""
+if command -v iwgetid >/dev/null 2>&1; then
+ SSID=$(iwgetid -r 2>/dev/null)
+fi
+
+if [ -n "$SSID" ]; then
+ TOOLTIP="$SSID ($INTERFACE: $IP)"
+else
+ TOOLTIP="$INTERFACE: $IP"
+fi
+
+echo "{\"text\": \"${UP} 󰕒 ${DOWN} 󰇚\", \"tooltip\": \"$TOOLTIP\", \"class\": \"connected\"}"
diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Bold.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Bold.ttf
new file mode 100644
index 0000000..2f76c1f
--- /dev/null
+++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Bold.ttf
Binary files differ
diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf
new file mode 100644
index 0000000..03cf72f
--- /dev/null
+++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf
Binary files differ
diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf
new file mode 100644
index 0000000..be5694d
--- /dev/null
+++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf
Binary files differ
diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf
new file mode 100644
index 0000000..a39f1da
--- /dev/null
+++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf
Binary files differ
diff --git a/todo.org b/todo.org
index 14ee07d..c4055bd 100644
--- a/todo.org
+++ b/todo.org
@@ -964,3 +964,92 @@ Add lexend-fonts-git package to archsetup font installation.
Package: =yay -S lexend-fonts-git=
Captured On: [2025-11-12 Tue 13:52]
RESOLVED: Added aur_install lexend-fonts-git to archsetup (fonts section)
+
+** TODO [#C] Patch Berkeley Mono to nerd font
+Use nerd-fonts patcher to add glyphs to Berkeley Mono for icon support in waybar/terminal.
+Options:
+- Full repo: https://github.com/ryanoasis/nerd-fonts (includes font-patcher script)
+- Lightweight: https://github.com/betaboon/nerd-fonts-patcher (just patcher + glyphs)
+- Docker: =docker run --rm -v /path/to/fonts:/in:Z -v /path/for/output:/out:Z nerdfonts/patcher=
+Output will be "BerkeleyMono Nerd Font" with all icon glyphs.
+
+** TODO [#B] Test archsetup username/password prompts
+Test the username and password prompt functionality added to archsetup.
+Verify prompts work correctly on fresh install simulation.
+
+** TODO [#B] Modularize theming for consistent colors and fonts
+Create a unified theming system so all apps share the same color scheme and fonts.
+Goals:
+- Single source of truth for colors (background, foreground, accent, etc.)
+- Single source of truth for fonts (monospace, UI, etc.)
+- Apps to theme: hyprland, waybar, wofi, foot, dunst, hyprlock, rofi, etc.
+Options:
+- Manual: central config file sourced by all app configs
+- pywal: generate schemes from wallpaper (see pywal task below)
+- nwg-look + GTK theming for GUI apps
+
+** DONE [#A] Fix Hyprland configuration issues
+Issues discovered during live testing on ratio. Add sub-items as "hyprland config issue".
+
+*** DONE Scratchpads not spawning on keybind
+mod+shift+return toggles special workspace (screen dims) but foot terminal doesn't spawn.
+- Manual spawn works: =foot -T spterm tmux=
+- Fixed pgrep self-match issue (bracket trick)
+- Fixed windowrule syntax (match:class first, then rule)
+- Still not working - need further investigation
+
+*** TODO Wofi launcher can't be dismissed
+mod+space launches wofi but mod+space and mod+shift+c don't dismiss it.
+Need to configure proper dismiss keybinding.
+
+*** DONE No wallpaper displaying
+Desktop has no wallpaper. Need to set up swww or similar.
+
+*** DONE Verify foot -T flag sets window title correctly
+Need to confirm foot uses -T for title (vs -t or --title).
+
+*** DONE [#D] Pulsemixer scratchpad sizing different from others
+mod+a pulsemixer scratchpad appears to be sized differently than other scratchpads.
+All use same rules: size (monitor_w*0.6) (monitor_h*0.6). Investigate why it differs.
+
+*** TODO [#C] Consider pywal for dynamic theming
+Use pywal to generate color schemes from wallpaper. Reference: reference-repos/kastrbl4nik-dots/
+Tools: swww (wallpaper), wal (colors), pywalfox (Firefox), pywal-spicetify (Spotify)
+
+*** TODO Waybar wireplumber volume control not working
+Click to mute and scroll to adjust not responding. Config uses wpctl commands.
+May need to verify wpctl is working or try different approach.
+
+*** DONE Waybar clock not displaying
+Clock module is configured correctly but not showing on bar.
+- Config and style.css are stowed correctly
+- Font (FiraCode Nerd Font Mono) is installed
+- Removed battery module (desktop has no battery)
+- Other modules (tray, disk, workspaces) appear to work
+- Reference config in reference-repos/hyprland-dotfiles/waybar/
+
+*** TODO [#D] Consider "show desktop" toggle via empty special workspace
+Toggle to an empty special workspace to temporarily hide all windows (shows desktop).
+Toggle again to return to windows.
+Implementation:
+#+begin_src conf
+bind = $mod, Z, togglespecialworkspace, desktop
+#+end_src
+
+** Favorite Reference Repos (Hyprland/Waybar)
+These repos stood out for clean code, aesthetics, or useful features. Return to these for inspiration.
+
+*** FAVORITE: Hyprland-Rice (currently using for waybar)
+URL: https://github.com/CtrlLuzzio/Hyprland-Rice
+Location: reference-repos/Hyprland-Rice/
+Notes: Clean minimal waybar, good color scheme, easy to implement. DWM-style colors applied.
+
+*** FAVORITE: hyprcraft (archived)
+URL: https://github.com/zhaleff/hyprcraft
+Location: reference-repos/hyprcraft/
+Notes: User's second favorite. Review for additional inspiration.
+
+*** FAVORITE: BlackNode (latest version of hyprcraft)
+URL: https://github.com/zhaleff/BlackNode
+Location: reference-repos/BlackNode/
+Notes: Updated/moved repo from hyprcraft. Use this for latest versions.