summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xarchsetup18
-rw-r--r--assets/outbox/2026-02-08-homelab-session-system-changes.txt26
-rw-r--r--dotfiles/common/.bashrc.d/aliases.sh2
-rw-r--r--dotfiles/common/.config/calibre/.gitignore5
-rw-r--r--dotfiles/common/.config/calibre/dynamic.pickle.json21
-rw-r--r--dotfiles/common/.config/calibre/global.py.json82
-rw-r--r--dotfiles/common/.config/calibre/gui.json16
-rw-r--r--dotfiles/common/.config/calibre/plugins/Kobo Utilities.json122
-rw-r--r--dotfiles/common/.config/ncmpcpp/bindings15
-rw-r--r--dotfiles/common/.config/qalculate/qalculate-gtk.cfg24
-rwxr-xr-xdotfiles/common/.local/bin/ai-assistants2
-rwxr-xr-xdotfiles/common/.local/bin/aix8
-rwxr-xr-xdotfiles/common/.local/bin/logitech-brio-settings.sh31
-rw-r--r--dotfiles/common/.stow-local-ignore4
-rw-r--r--dotfiles/common/.zshrc.d/aliases.sh2
-rw-r--r--dotfiles/hyprland/.config/hypr/hyprland.conf14
-rw-r--r--dotfiles/hyprland/.config/waypaper/config.ini6
-rwxr-xr-xdotfiles/hyprland/.local/bin/hypr-refocus-scratchpad24
-rw-r--r--dotfiles/hyprland/.local/share/applications/signal-desktop.desktop12
19 files changed, 409 insertions, 25 deletions
diff --git a/archsetup b/archsetup
index 13afbe7..ffaa1d8 100755
--- a/archsetup
+++ b/archsetup
@@ -1415,6 +1415,8 @@ hyprland() {
pacman_install satty # screenshot annotation
pacman_install wf-recorder # screen recording
pacman_install obs-studio # streaming/recording studio
+ pacman_install cameractrls # webcam controls GUI (white balance, zoom, pan/tilt)
+ pacman_install v4l-utils # video4linux utilities (v4l2-ctl for webcam settings)
pacman_install hyprpicker # color picker
pacman_install gammastep # night light (replaces redshift)
pacman_install brightnessctl # brightness control
@@ -1452,6 +1454,14 @@ HOOKEOF
# Replace placeholder with actual username
sed -i "s/ARCHSETUP_USERNAME/$username/" /etc/pacman.d/hooks/hyprpm.hook
chmod 644 /etc/pacman.d/hooks/hyprpm.hook
+
+ # Logitech BRIO webcam auto-configuration
+ action="creating Logitech BRIO udev rule" && display "task" "$action"
+ cat > /etc/udev/rules.d/99-logitech-brio.rules << UDEVEOF
+# Apply camera settings when Logitech BRIO is connected
+ACTION=="add", SUBSYSTEM=="video4linux", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="085e", ATTR{index}=="0", RUN+="/home/$username/.local/bin/logitech-brio-settings.sh /dev/%k"
+UDEVEOF
+ chmod 644 /etc/udev/rules.d/99-logitech-brio.rules
}
### Display Server (conditional)
@@ -1530,7 +1540,7 @@ desktop_environment() {
pacman_install testdisk
pacman_install tickrs
pacman_install udisks2
- pacman_install flatpak # app sandboxing and distribution
+
aur_install touchpad-indicator-git
aur_install dotpac
aur_install downgrade
@@ -1890,6 +1900,12 @@ supplemental_software() {
pacman_install ranger # terminal file manager (X11, ueberzug)
pacman_install rclone # syncs files from gdrive, s3, dropbox, etc.
pacman_install signal-desktop # secure messenger
+ if [[ "$desktop_env" == "hyprland" ]]; then
+ aur_install slack-desktop-wayland # team messaging (native Wayland)
+ else
+ aur_install slack-desktop # team messaging
+ fi
+ aur_install zoom # video conferencing
pacman_install iperf3 # network bandwidth testing
pacman_install net-tools # network tools (netstat for security auditing)
pacman_install smartmontools # monitors hard drives
diff --git a/assets/outbox/2026-02-08-homelab-session-system-changes.txt b/assets/outbox/2026-02-08-homelab-session-system-changes.txt
new file mode 100644
index 0000000..4092484
--- /dev/null
+++ b/assets/outbox/2026-02-08-homelab-session-system-changes.txt
@@ -0,0 +1,26 @@
+System changes from homelab session 2026-02-08
+==============================================
+
+1. ZOOM: Switched from Flatpak to AUR package
+ - Removed: flatpak uninstall us.zoom.Zoom
+ - Installed: yay -S zoom (AUR, version 6.7.2-1)
+ - Reason: Flatpak sandboxing caused settings to reset and broke theme integration
+ - Config: ~/.config/zoomus.conf
+ - enableWaylandShare=true (for screen sharing on Wayland)
+ - xwayland=true (xwayland=false causes rendering glitches)
+ - useSystemTheme=false (true causes bugs, dark mode not available on Linux anyway)
+
+2. PACKAGE: Installed cameractrls
+ - Installed: sudo pacman -S cameractrls
+ - Purpose: GUI tool for webcam controls (white balance, zoom, pan/tilt, etc.)
+ - Launch: cameractrlsgtk4
+ - Used to configure Logitech BRIO webcam settings
+
+3. UDEV RULE: Logitech BRIO auto-configuration
+ - File: /etc/udev/rules.d/99-logitech-brio.rules
+ - Triggers: ~/.local/bin/logitech-brio-settings.sh
+ - Purpose: Applies saved camera settings (white balance, zoom, pan/tilt) when BRIO is plugged in
+ - BRIO USB ID: 046d:085e
+ - NOTE: Script is at ~/.local/bin/logitech-brio-settings.sh — needs to be adopted
+ into archsetup dotfiles and GNU Stow-symlinked. The udev rule references the
+ full path /home/cjennings/.local/bin/logitech-brio-settings.sh.
diff --git a/dotfiles/common/.bashrc.d/aliases.sh b/dotfiles/common/.bashrc.d/aliases.sh
index 9be16da..1321bf0 100644
--- a/dotfiles/common/.bashrc.d/aliases.sh
+++ b/dotfiles/common/.bashrc.d/aliases.sh
@@ -80,7 +80,7 @@ alias gdbx="gdb --batch --ex r --ex bt --ex q --args"
# =============================================================================
# Claude Code
# =============================================================================
-alias hey='claude "Read ./docs/protocols.org and ./docs/NOTES.org, follow their instructions, then run session startup workflow."'
+alias hey='claude "Read docs/protocols.org and follow all instructions."'
# =============================================================================
# Phenomenology RAG (ollama/deepseek)
diff --git a/dotfiles/common/.config/calibre/.gitignore b/dotfiles/common/.config/calibre/.gitignore
new file mode 100644
index 0000000..f80339c
--- /dev/null
+++ b/dotfiles/common/.config/calibre/.gitignore
@@ -0,0 +1,5 @@
+# Calibre runtime files (not worth tracking)
+caches/
+fonts/scanner_cache.json
+icons-dark.rcc
+viewer/annots/
diff --git a/dotfiles/common/.config/calibre/dynamic.pickle.json b/dotfiles/common/.config/calibre/dynamic.pickle.json
new file mode 100644
index 0000000..fb42097
--- /dev/null
+++ b/dotfiles/common/.config/calibre/dynamic.pickle.json
@@ -0,0 +1,21 @@
+{
+ "sort_history": [
+ [
+ "timestamp",
+ false
+ ],
+ [
+ "ondevice",
+ false
+ ],
+ [
+ "title",
+ true
+ ],
+ [
+ "timestamp",
+ false
+ ]
+ ],
+ "welcome_wizard_was_run": true
+} \ No newline at end of file
diff --git a/dotfiles/common/.config/calibre/global.py.json b/dotfiles/common/.config/calibre/global.py.json
new file mode 100644
index 0000000..43f47a0
--- /dev/null
+++ b/dotfiles/common/.config/calibre/global.py.json
@@ -0,0 +1,82 @@
+{
+ "add_formats_to_existing": false,
+ "case_sensitive": false,
+ "check_for_dupes_on_ctl": false,
+ "database_path": "/home/cjennings/library1.db",
+ "filename_pattern": "(?P<title>.+) - (?P<author>[^_]+)",
+ "input_format_order": [
+ "EPUB",
+ "PDF",
+ "AZW3",
+ "MOBI",
+ "LIT",
+ "PRC",
+ "FB2",
+ "HTML",
+ "HTM",
+ "XHTM",
+ "SHTML",
+ "XHTML",
+ "ZIP",
+ "DOCX",
+ "ODT",
+ "RTF",
+ "TXT",
+ "CB7",
+ "SHTM",
+ "SNB",
+ "PMLZ",
+ "TCR",
+ "FBZ",
+ "DJVU",
+ "DOCM",
+ "LRF",
+ "TXTZ",
+ "KEPUB",
+ "POBI",
+ "PDB",
+ "CHM",
+ "CBR",
+ "HTMLZ",
+ "RB",
+ "MD",
+ "CBC",
+ "MARKDOWN",
+ "TEXT",
+ "AZW",
+ "UPDB",
+ "RECIPE",
+ "PML",
+ "DOWNLOADED_RECIPE",
+ "TEXTILE",
+ "RAR",
+ "CBZ",
+ "OPF",
+ "AZW4",
+ "DJV"
+ ],
+ "installation_uuid": "4c998702-215a-4787-a019-abdee4cdf53c",
+ "isbndb_com_key": "",
+ "language": "en",
+ "library_path": "/home/cjennings/sync/books",
+ "limit_search_columns": false,
+ "limit_search_columns_to": [
+ "title",
+ "authors",
+ "tags",
+ "publisher"
+ ],
+ "manage_device_metadata": "manual",
+ "mark_new_books": true,
+ "migrated": false,
+ "network_timeout": 5,
+ "new_book_tags": [],
+ "numeric_collation": false,
+ "output_format": "epub",
+ "read_file_metadata": true,
+ "saved_searches": {},
+ "swap_author_names": false,
+ "use_primary_find_in_search": true,
+ "user_categories": {},
+ "worker_process_priority": "normal"
+} \ No newline at end of file
diff --git a/dotfiles/common/.config/calibre/gui.json b/dotfiles/common/.config/calibre/gui.json
index 853dbd8..b1e1c40 100644
--- a/dotfiles/common/.config/calibre/gui.json
+++ b/dotfiles/common/.config/calibre/gui.json
@@ -212,28 +212,28 @@
},
"geometry-of-calibre_main_window_geometry": {
"frame_geometry": {
- "height": 1306,
- "width": 1828,
+ "height": 1314,
+ "width": 3374,
"x": 0,
"y": 0
},
"full_screened": false,
"geometry": {
- "height": 1306,
- "width": 1828,
+ "height": 1314,
+ "width": 3374,
"x": 0,
"y": 0
},
"maximized": true,
"normal_geometry": {
- "height": 1306,
+ "height": 1314,
"width": 1828,
"x": 0,
"y": 0
},
"qt": {
"__class__": "bytearray",
- "__value__": "AdnQywADAAAAAAAAAAAAAAAAByMAAAUZAAAAAAAAAAAAAAcjAAAFGQAAAAACAAAADXAAAAAAAAAAAAAAByMAAAUZ"
+ "__value__": "AdnQywADAAAAAAAAAAAAAAAADS0AAAUhAAAAAAAAAAAAAAcjAAAFIQAAAAACAAAADXAAAAAAAAAAAAAADS0AAAUh"
},
"screen": {
"depth": 32,
@@ -247,7 +247,7 @@
"index_in_screens_list": 0,
"manufacturer": "Dell Inc.",
"model": "DELL U3419W",
- "name": "HDMI-A-1",
+ "name": "DP-4",
"serial": "",
"size_in_logical_pixels": {
"height": 1440,
@@ -468,7 +468,7 @@
"grid view visible": false,
"library_usage_stats": {
"/home/cjennings/archive/books": 10,
- "/home/cjennings/sync/books": 10
+ "/home/cjennings/sync/books": 12
},
"light_palette_name": "",
"light_palettes": {
diff --git a/dotfiles/common/.config/calibre/plugins/Kobo Utilities.json b/dotfiles/common/.config/calibre/plugins/Kobo Utilities.json
new file mode 100644
index 0000000..4d9121a
--- /dev/null
+++ b/dotfiles/common/.config/calibre/plugins/Kobo Utilities.json
@@ -0,0 +1,122 @@
+{
+ "BookmarkOptions": {
+ "backgroundJob": false,
+ "clearIfUnread": false,
+ "doNotStoreIfReopened": false,
+ "rating": true,
+ "readingStatus": true,
+ "setDateToNow": true,
+ "storeBookmarks": true,
+ "storeIfMoreRecent": false
+ },
+ "Devices": {
+ "N4181C1037466": {
+ "active": true,
+ "backupOptionsStore": {
+ "backupCopiesToKeepSpin": 10,
+ "backupDestDirectory": "/home/cjennings/documents/kobo",
+ "backupEachCOnnection": true,
+ "backupZipDatabase": true,
+ "doDailyBackp": false
+ },
+ "location_code": "main",
+ "name": "Kobo Libra 2",
+ "serial_no": "N4181C1037466",
+ "type": "Kobo Libra 2",
+ "updateOptionsStore": {
+ "doEarlyFirmwareUpdate": false,
+ "doFirmwareUpdateCheck": true,
+ "firmwareUpdateCheckLastTime": 0
+ },
+ "uuid": "8de75c8a-f9b6-405c-86a3-515afd1e71fa"
+ }
+ },
+ "MetadataOptions": {
+ "author": false,
+ "authourSort": false,
+ "description": false,
+ "descriptionTemplate": "",
+ "descriptionUseTemplate": false,
+ "isbn": false,
+ "language": false,
+ "published_date": false,
+ "publisher": false,
+ "rating": false,
+ "readingStatus": -1,
+ "reading_direction": "Default",
+ "resetPosition": false,
+ "series": false,
+ "setRreadingStatus": false,
+ "set_reading_direction": false,
+ "set_sync_date": false,
+ "subtitle": false,
+ "subtitleTemplate": "",
+ "sync_date_library_date": "timestamp",
+ "title": false,
+ "titleSort": false,
+ "update_KoboEpubs": false,
+ "usePlugboard": false
+ },
+ "ReadingOptions": {
+ "doNotUpdateIfSet": false,
+ "lockMargins": false,
+ "readingAlignment": "Off",
+ "readingFontFamily": "Georgia",
+ "readingFontSize": 22,
+ "readingLeftMargin": 3,
+ "readingLineHeight": 1.3,
+ "readingRightMargin": 3,
+ "updateConfigFile": false
+ },
+ "_version": 2,
+ "backupAnnotations": {
+ "dest_directory": ""
+ },
+ "backupOptionsStore": {
+ "backupCopiesToKeepSpin": 5,
+ "backupDestDirectory": "",
+ "backupEachCOnnection": false,
+ "backupZipDatabase": true,
+ "doDailyBackp": false
+ },
+ "cleanImagesDir": {
+ "delete_extra_covers": false
+ },
+ "commonOptionsStore": {
+ "buttonActionDevice": "",
+ "buttonActionLibrary": "",
+ "individualDeviceOptions": true
+ },
+ "coverUpload": {
+ "blackandwhite": false,
+ "dithered_covers": false,
+ "keep_cover_aspect": false,
+ "kepub_covers": false,
+ "letterbox": false,
+ "letterbox_color": "#000000",
+ "png_covers": false
+ },
+ "fixDuplicatesOptionsStore": {
+ "keepNewestShelf": true,
+ "purgeShelves": false
+ },
+ "getShelvesOptionStore": {
+ "allBooks": true,
+ "replaceShelves": true
+ },
+ "removeAnnotations": {
+ "removeAnnotAction": 0
+ },
+ "removeCovers": {
+ "kepub_covers": false,
+ "remove_fullsize_covers": false
+ },
+ "setRelatedBooksOptionsStore": {
+ "relatedBooksType": 0
+ },
+ "updateOptionsStore": {
+ "doEarlyFirmwareUpdate": false,
+ "doFirmwareUpdateCheck": false,
+ "firmwareUpdateCheckLastTime": 1656213583
+ }
+} \ No newline at end of file
diff --git a/dotfiles/common/.config/ncmpcpp/bindings b/dotfiles/common/.config/ncmpcpp/bindings
index a7ca6c0..25021f1 100644
--- a/dotfiles/common/.config/ncmpcpp/bindings
+++ b/dotfiles/common/.config/ncmpcpp/bindings
@@ -219,6 +219,9 @@
#def_key "space"
# toggle_visualization_type
#
+def_key "space"
+ pause
+
#def_key "delete"
# delete_playlist_items
#
@@ -237,6 +240,9 @@
#def_key "right"
# volume_up
#
+def_key "right"
+ seek_forward
+#
#def_key "+"
# volume_up
#
@@ -249,6 +255,9 @@
#def_key "left"
# volume_down
#
+def_key "left"
+ seek_backward
+#
#def_key "-"
# volume_down
#
@@ -309,6 +318,9 @@ def_key "="
#def_key "p"
# pause
#
+def_key "p"
+ add_item_to_playlist
+
#def_key ">"
# next
#
@@ -453,6 +465,9 @@ def_key "l"
#def_key "v"
# reverse_selection
#
+def_key "v"
+ toggle_visualization_type
+
#def_key "V"
# remove_selection
#
diff --git a/dotfiles/common/.config/qalculate/qalculate-gtk.cfg b/dotfiles/common/.config/qalculate/qalculate-gtk.cfg
index b80636c..2ce75de 100644
--- a/dotfiles/common/.config/qalculate/qalculate-gtk.cfg
+++ b/dotfiles/common/.config/qalculate/qalculate-gtk.cfg
@@ -69,6 +69,10 @@ comma_as_separator=1
use_custom_application_font=0
multiplication_sign=2
division_sign=1
+expression_history=60×60×8
+expression_history=60×60×6
+expression_history=60×60
+expression_history=7200/60
expression_history=1024×8
expression_history=125×7×6
expression_history=7600×4
@@ -105,6 +109,26 @@ expression_history=1024×16
expression_history=3278×12
expression_history=1026×16
expression_history=96×2
+history_time=1770475922
+history_expression=60×60×8
+history_parse=60 × 60 × 8
+history_result=28 800
+history_time=1770475866
+history_expression=60×60×8
+history_parse=60 × 60 × 8
+history_result=28 800
+history_time=1770475857
+history_expression=60×60×6
+history_parse=60 × 60 × 6
+history_result=21 600
+history_time=1770475851
+history_expression=60×60
+history_parse=60 × 60
+history_result=3600
+history_time=1770475838
+history_expression=7200/60
+history_parse=7200 ∕ 60
+history_result=120
history_time=1770329943
history_expression=1024×8
history_parse=1024 × 8
diff --git a/dotfiles/common/.local/bin/ai-assistants b/dotfiles/common/.local/bin/ai-assistants
index 51028fe..3b4d80e 100755
--- a/dotfiles/common/.local/bin/ai-assistants
+++ b/dotfiles/common/.local/bin/ai-assistants
@@ -21,7 +21,7 @@ projects=(
)
# Claude command to run in each window
-CLAUDE_CMD='claude "Read docs/protocols.org and docs/NOTES.org, follow instructions exactly, then begin the session-start workflow"'
+CLAUDE_CMD='claude "Read docs/protocols.org and follow all instructions."'
# Create session with first project
first="${projects[0]}"
diff --git a/dotfiles/common/.local/bin/aix b/dotfiles/common/.local/bin/aix
index 0f70d23..35cab64 100755
--- a/dotfiles/common/.local/bin/aix
+++ b/dotfiles/common/.local/bin/aix
@@ -1,7 +1,7 @@
#!/bin/bash
-# Launch tmux session with Claude in fzf-selected project directories
+# Launch tmux session with an LLM in fzf-selected project directories
-SESSION="claude"
+SESSION="ai"
# If session exists, attach or switch to it
if tmux has-session -t "$SESSION" 2>/dev/null; then
@@ -41,13 +41,13 @@ selections=$(printf '%s\n' "${candidates[@]}" | fzf --multi --height=70% --rever
# Claude command — separated for safe editing
AI_CMD="claude"
-AI_INSTRUCTIONS='Read docs/protocols.org and docs/NOTES.org, follow instructions exactly, then begin the session-start workflow'
+AI_INSTRUCTIONS='Read docs/protocols.org and follow all instructions.'
# Read selections into array
selected=()
while IFS= read -r line; do
selected+=("$line")
-done <<< "$selections"
+done <<<"$selections"
# Create session with first selection
first="${selected[0]}"
diff --git a/dotfiles/common/.local/bin/logitech-brio-settings.sh b/dotfiles/common/.local/bin/logitech-brio-settings.sh
new file mode 100755
index 0000000..104c880
--- /dev/null
+++ b/dotfiles/common/.local/bin/logitech-brio-settings.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Apply saved camera settings for Logitech BRIO
+# Triggered by udev rule on USB connect
+# Settings dialed in via cameractrls on 2026-02-08
+
+DEVICE="$1"
+
+if [ -z "$DEVICE" ]; then
+ # Find the BRIO's main video device
+ DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -A1 "Logitech BRIO" | grep /dev/video | head -1 | tr -d '[:space:]')
+fi
+
+[ -z "$DEVICE" ] && exit 1
+
+sleep 2 # Give the device time to initialize
+
+v4l2-ctl -d "$DEVICE" \
+ --set-ctrl=brightness=85 \
+ --set-ctrl=contrast=88 \
+ --set-ctrl=saturation=128 \
+ --set-ctrl=sharpness=163 \
+ --set-ctrl=backlight_compensation=0 \
+ --set-ctrl=power_line_frequency=2 \
+ --set-ctrl=white_balance_automatic=0 \
+ --set-ctrl=white_balance_temperature=3050 \
+ --set-ctrl=auto_exposure=3 \
+ --set-ctrl=exposure_dynamic_framerate=1 \
+ --set-ctrl=focus_automatic_continuous=1 \
+ --set-ctrl=zoom_absolute=136 \
+ --set-ctrl=pan_absolute=-10800 \
+ --set-ctrl=tilt_absolute=0
diff --git a/dotfiles/common/.stow-local-ignore b/dotfiles/common/.stow-local-ignore
new file mode 100644
index 0000000..12d7e23
--- /dev/null
+++ b/dotfiles/common/.stow-local-ignore
@@ -0,0 +1,4 @@
+# Calibre: managed as a directory symlink, not individual file symlinks.
+# Calibre does atomic writes that replace symlinks with real files,
+# so the entire ~/.config/calibre dir symlinks to the repo instead.
+\.config/calibre
diff --git a/dotfiles/common/.zshrc.d/aliases.sh b/dotfiles/common/.zshrc.d/aliases.sh
index 9be16da..1321bf0 100644
--- a/dotfiles/common/.zshrc.d/aliases.sh
+++ b/dotfiles/common/.zshrc.d/aliases.sh
@@ -80,7 +80,7 @@ alias gdbx="gdb --batch --ex r --ex bt --ex q --args"
# =============================================================================
# Claude Code
# =============================================================================
-alias hey='claude "Read ./docs/protocols.org and ./docs/NOTES.org, follow their instructions, then run session startup workflow."'
+alias hey='claude "Read docs/protocols.org and follow all instructions."'
# =============================================================================
# Phenomenology RAG (ollama/deepseek)
diff --git a/dotfiles/hyprland/.config/hypr/hyprland.conf b/dotfiles/hyprland/.config/hypr/hyprland.conf
index 1c4e17c..f258353 100644
--- a/dotfiles/hyprland/.config/hypr/hyprland.conf
+++ b/dotfiles/hyprland/.config/hypr/hyprland.conf
@@ -10,18 +10,19 @@ monitor=,preferred,auto,auto
# ============================================================================
# Startup Applications
# ============================================================================
-# Portal and D-Bus setup FIRST (other apps depend on these)
+# Portal and D-Bus setup FIRST, then waybar (needs portal for appearance query)
exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE
-exec-once = systemctl --user start xdg-desktop-portal-hyprland xdg-desktop-portal
+# Portal restart (not start) reconnects stale portals on Hyprland restart; waybar
+# chained after so it doesn't block 25s waiting for a dead portal's appearance query
+exec-once = systemctl --user restart xdg-desktop-portal-hyprland xdg-desktop-portal && waybar > ~/.local/var/log/waybar-$(date +%Y-%m-%d-%H%M%S).log 2>&1
# Core services
exec-once = /usr/bin/gnome-keyring-daemon --start --components=pkcs11,secrets,ssh
exec-once = dunst > ~/.local/var/log/dunst-$(date +%Y-%m-%d-%H%M%S).log 2>&1
exec-once = hyprland-plugins-setup && sleep 1 && hyprctl dismissnotify -1
-# Desktop appearance (after portal is ready)
+# Desktop appearance
exec-once = swww-daemon && sleep 1 && swww img ~/pictures/wallpaper/trondheim-norway.jpg
-exec-once = waybar > ~/.local/var/log/waybar-$(date +%Y-%m-%d-%H%M%S).log 2>&1
# Background services
exec-once = hypridle > ~/.local/var/log/hypridle-$(date +%Y-%m-%d-%H%M%S).log 2>&1
@@ -32,9 +33,10 @@ exec-once = mpd
# Pyprland (scratchpads, magnify, etc.)
exec-once = pypr
+exec-once = hypr-refocus-scratchpad
-# Apps that can start later
-exec-once = signal-desktop --start-in-tray --ozone-platform=wayland
+# Apps that can start later (sleep ensures waybar tray is registered)
+exec-once = sleep 1 && signal-desktop --start-in-tray --ozone-platform=wayland
exec-once = protonmail-bridge --no-window
exec-once = insync start
diff --git a/dotfiles/hyprland/.config/waypaper/config.ini b/dotfiles/hyprland/.config/waypaper/config.ini
index 12e60fd..83b9ea4 100644
--- a/dotfiles/hyprland/.config/waypaper/config.ini
+++ b/dotfiles/hyprland/.config/waypaper/config.ini
@@ -2,12 +2,12 @@
language = en
folder = ~/pictures/wallpaper
monitors = All
-wallpaper = ~/pictures/wallpaper/dark-lion.jpg
+wallpaper = ~/pictures/wallpaper/trondheim-norway.jpg
show_path_in_tooltip = True
backend = swww
fill = fill
sort = name
-color = #ffffff
+color = #3D3846
subfolders = False
all_subfolders = False
show_hidden = False
@@ -15,7 +15,7 @@ show_gifs_only = False
zen_mode = False
post_command =
number_of_columns = 3
-swww_transition_type = simple
+swww_transition_type = none
swww_transition_step = 63
swww_transition_angle = 0
swww_transition_duration = 2
diff --git a/dotfiles/hyprland/.local/bin/hypr-refocus-scratchpad b/dotfiles/hyprland/.local/bin/hypr-refocus-scratchpad
new file mode 100755
index 0000000..7a4bb38
--- /dev/null
+++ b/dotfiles/hyprland/.local/bin/hypr-refocus-scratchpad
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Refocus visible scratchpad after a window closes.
+# Without this, closing a regular window while a scratchpad is visible
+# leaves focus on the regular workspace instead of the scratchpad.
+
+SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
+
+socat -U - "UNIX-CONNECT:$SOCKET" | while read -r line; do
+ if [[ "$line" == closewindow* ]]; then
+ # Check if a special workspace is active on the current monitor
+ special=$(hyprctl monitors -j | python3 -c "
+import json, sys
+for m in json.load(sys.stdin):
+ sw = m.get('specialWorkspace', {})
+ if sw.get('id', 0) != 0:
+ print(sw['name'])
+ break
+" 2>/dev/null)
+ if [[ -n "$special" ]]; then
+ # Focus the top window on the special workspace
+ hyprctl dispatch focuswindow "workspace:$special" &>/dev/null
+ fi
+ fi
+done
diff --git a/dotfiles/hyprland/.local/share/applications/signal-desktop.desktop b/dotfiles/hyprland/.local/share/applications/signal-desktop.desktop
new file mode 100644
index 0000000..834c510
--- /dev/null
+++ b/dotfiles/hyprland/.local/share/applications/signal-desktop.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Type=Application
+Name=Signal
+Comment=Signal - Private Messenger
+Icon=signal-desktop
+Exec=signal-desktop --start-in-tray --ozone-platform=wayland -- %u
+Terminal=false
+Categories=Network;InstantMessaging;
+StartupWMClass=signal
+MimeType=x-scheme-handler/sgnl;x-scheme-handler/signalcaptcha;
+Keywords=sgnl;chat;im;messaging;messenger;security;privat;
+X-GNOME-UsesNotifications=true