diff options
20 files changed, 827 insertions, 165 deletions
@@ -3,6 +3,9 @@ /docs/ /inbox/ +# Reference repos (external repos for reference) +/reference-repos/ + # VM Testing Infrastructure /vm-images/ /test-results/ @@ -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 Binary files differnew file mode 100644 index 0000000..2f76c1f --- /dev/null +++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Bold.ttf diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf Binary files differnew file mode 100644 index 0000000..03cf72f --- /dev/null +++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-BoldItalic.ttf diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf Binary files differnew file mode 100644 index 0000000..be5694d --- /dev/null +++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Italic.ttf diff --git a/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf Binary files differnew file mode 100644 index 0000000..a39f1da --- /dev/null +++ b/dotfiles/system/.local/share/fonts/BerkeleyMonoNerdFont-Regular.ttf @@ -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. |
