Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 086097f2a9 | |||
| 1755d17558 | |||
| 9e310d2f58 | |||
| 21dbb16e8b | |||
| 5cfa02ea6b |
@@ -1,6 +1,6 @@
|
|||||||
HOME_TARGET ?= $(HOME)
|
HOME_TARGET ?= $(HOME)
|
||||||
SYSTEM_DIRS := etc usr var opt boot
|
SYSTEM_DIRS := etc usr var opt boot
|
||||||
PACKAGES := $(patsubst %/,%,$(wildcard */))
|
PACKAGES := $(filter-out resources wluma,$(patsubst %/,%,$(wildcard */)))
|
||||||
|
|
||||||
.PHONY: check-stow pull-updates unlink link
|
.PHONY: check-stow pull-updates unlink link
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ link: check-stow
|
|||||||
done; \
|
done; \
|
||||||
if [ "$$is_sys" -eq 1 ]; then \
|
if [ "$$is_sys" -eq 1 ]; then \
|
||||||
echo " [System] Stowing $$pkg/$$sub to $$sub"; \
|
echo " [System] Stowing $$pkg/$$sub to $$sub"; \
|
||||||
sudo stow -d "$$pkg" -t "/$$sub" "$$sub"; \
|
sudo stow --restow -d "$$pkg" -t "/$$sub" "$$sub"; \
|
||||||
else \
|
else \
|
||||||
echo " [USER] Stowing $$pkg/$$sub to $(HOME_TARGET)/$$sub"; \
|
echo " [USER] Stowing $$pkg/$$sub to $(HOME_TARGET)/$$sub"; \
|
||||||
stow -d "$$pkg" -t "$(HOME_TARGET)/$$sub" "$$sub"; \
|
stow --restow -d "$$pkg" -t "$(HOME_TARGET)/$$sub" "$$sub"; \
|
||||||
fi; \
|
fi; \
|
||||||
done; \
|
done; \
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -2,3 +2,7 @@
|
|||||||
hl.env("XCURSOR_SIZE", "24")
|
hl.env("XCURSOR_SIZE", "24")
|
||||||
hl.env("QT_QPA_PLATFORMTHEME", "qt5ct") -- change to qt6ct if you have that
|
hl.env("QT_QPA_PLATFORMTHEME", "qt5ct") -- change to qt6ct if you have that
|
||||||
hl.env("SUDO_ASKPASS", os.getenv("HOME") .. "/.local/bin/sudo-askpass.sh")
|
hl.env("SUDO_ASKPASS", os.getenv("HOME") .. "/.local/bin/sudo-askpass.sh")
|
||||||
|
-- Prepend ~/.local/bin so `hyprlock` (and other user scripts) resolve to the
|
||||||
|
-- crash-guard wrapper instead of /usr/bin/hyprlock. Hyprland's exec/keybind
|
||||||
|
-- PATH is otherwise the system PATH and misses user-local binaries.
|
||||||
|
hl.env("PATH", os.getenv("HOME") .. "/.local/bin:" .. (os.getenv("PATH") or "/usr/bin:/bin"))
|
||||||
|
|||||||
@@ -23,14 +23,26 @@ listener {
|
|||||||
on-timeout = loginctl lock-session # lock screen when timeout has passed
|
on-timeout = loginctl lock-session # lock screen when timeout has passed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The dpms-off and suspend listeners ignore idle inhibitors (Steam, browsers,
|
||||||
|
# etc. hold them) so the screen still blanks and the machine still suspends
|
||||||
|
# after the screen is locked -- otherwise a held inhibitor would keep the
|
||||||
|
# locked screen on forever. `condition_cmd` gates them on the lock screen
|
||||||
|
# actually running, so inhibitors keep working as intended while unlocked
|
||||||
|
# (e.g. a video keeps the screen awake).
|
||||||
listener {
|
listener {
|
||||||
timeout = 330 # 5.5min
|
timeout = 330 # 5.5min
|
||||||
|
ignore_inhibit = true # fire even while apps hold idle inhibitors
|
||||||
|
condition_cmd = pidof hyprlock > /dev/null # ...but only once the session is locked
|
||||||
|
condition_retry = 30 # if not locked yet, re-check every 30s while idle
|
||||||
on-timeout = hyprctl dispatch dpms off # screen off when timeout has passed
|
on-timeout = hyprctl dispatch dpms off # screen off when timeout has passed
|
||||||
on-resume = hyprctl dispatch dpms on && brightnessctl -r # screen on when activity is detected after timeout has fired.
|
on-resume = hyprctl dispatch dpms on && brightnessctl -r # screen on when activity is detected after timeout has fired.
|
||||||
}
|
}
|
||||||
|
|
||||||
listener {
|
listener {
|
||||||
timeout = 1800 # 30min
|
timeout = 1800 # 30min
|
||||||
|
ignore_inhibit = true # fire even while apps hold idle inhibitors
|
||||||
|
condition_cmd = pidof hyprlock > /dev/null # ...but only while the session is locked
|
||||||
|
condition_retry = 60 # if not locked yet, re-check every 60s while idle
|
||||||
on-timeout = systemctl suspend # suspend pc
|
on-timeout = systemctl suspend # suspend pc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ hl.config({
|
|||||||
mouse_move_focuses_monitor = false,
|
mouse_move_focuses_monitor = false,
|
||||||
-- Skip drawing the Hyprland logo in the corner of empty workspaces.
|
-- Skip drawing the Hyprland logo in the corner of empty workspaces.
|
||||||
disable_hyprland_logo = true,
|
disable_hyprland_logo = true,
|
||||||
|
-- Allow a new hyprlock to take over the lock after a crash; without this a
|
||||||
|
-- dead lock client leaves the session permanently locked (no lockscreen).
|
||||||
|
allow_session_lock_restore = true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -103,5 +106,8 @@ hl.config({
|
|||||||
hl.config({
|
hl.config({
|
||||||
debug = {
|
debug = {
|
||||||
vfr = true,
|
vfr = true,
|
||||||
|
-- Temporarily on to diagnose the mystery re-lock (disable_logs=true
|
||||||
|
-- default hides dispatch exec lines from hyprland.log).
|
||||||
|
disable_logs = false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Executable
+34
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Print the current weather as a short icon+temp string, e.g. "🌦️ +83°F".
|
||||||
|
# Caches the wttr.in response for CACHE_MAX_AGE seconds so the lock screen and
|
||||||
|
# waybar don't hit the network on every refresh. Override the location with
|
||||||
|
# WEATHER_CITY or edit CITY below.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
CITY="${WEATHER_CITY:-Denver}"
|
||||||
|
CACHE_DIR="${XDG_RUNTIME_DIR:-/tmp}"
|
||||||
|
CACHE="${CACHE_DIR}/wttr.cache"
|
||||||
|
CACHE_MAX_AGE=1800 # 30 minutes
|
||||||
|
URL="https://wttr.in/${CITY}?format=%c+%t"
|
||||||
|
|
||||||
|
cache_age() {
|
||||||
|
[ -f "${CACHE}" ] || return 1
|
||||||
|
now=$(date +%s)
|
||||||
|
mtime=$(stat -c %Y "${CACHE}")
|
||||||
|
[ "$(( now - mtime ))" -lt "${CACHE_MAX_AGE}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if cache_age; then
|
||||||
|
cat "${CACHE}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP="${CACHE}.tmp.$$"
|
||||||
|
if curl -fsS --max-time 10 "${URL}" > "${TMP}" 2>/dev/null; then
|
||||||
|
mv "${TMP}" "${CACHE}"
|
||||||
|
cat "${CACHE}"
|
||||||
|
else
|
||||||
|
rm -f "${TMP}" || true
|
||||||
|
# Offline: fall back to whatever we cached last, even if stale.
|
||||||
|
[ -f "${CACHE}" ] && cat "${CACHE}"
|
||||||
|
fi
|
||||||
@@ -7,14 +7,17 @@ $font = JetBrainsMono Nerd Font
|
|||||||
|
|
||||||
# General
|
# General
|
||||||
general {
|
general {
|
||||||
disable_loading_bar = false
|
|
||||||
hide_cursor = false
|
hide_cursor = false
|
||||||
}
|
}
|
||||||
|
|
||||||
# Authentication
|
# Authentication
|
||||||
|
# Fingerprint is disabled: GDM's login worker (pam/gdm-fingerprint) holds the
|
||||||
|
# device for the whole session, so hyprlock can never claim it -- the failed
|
||||||
|
# claim blocked the auth thread and made unlocks appear stuck. Fingerprint is
|
||||||
|
# still available at the GDM login screen; hyprlock is password-only.
|
||||||
auth {
|
auth {
|
||||||
fingerprint {
|
fingerprint {
|
||||||
enabled = true
|
enabled = false
|
||||||
ready_message = Scan fingerprint to unlock
|
ready_message = Scan fingerprint to unlock
|
||||||
present_message = Scanning...
|
present_message = Scanning...
|
||||||
retry_delay = 250 # in milliseconds
|
retry_delay = 250 # in milliseconds
|
||||||
@@ -45,7 +48,7 @@ label {
|
|||||||
# Date
|
# Date
|
||||||
label {
|
label {
|
||||||
monitor =
|
monitor =
|
||||||
text = cmd[update:43200000] echo "$(date + "%A, %d %B %Y")"
|
text = cmd[update:43200000] echo "$(date +'%A, %d %B %Y')"
|
||||||
color = $text
|
color = $text
|
||||||
font_size = 25
|
font_size = 25
|
||||||
font_family = $font
|
font_family = $font
|
||||||
@@ -54,6 +57,30 @@ label {
|
|||||||
valign = top
|
valign = top
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Battery
|
||||||
|
label {
|
||||||
|
monitor =
|
||||||
|
text = cmd[update:60000] $HOME/.local/bin/hyprlock-battery.sh
|
||||||
|
color = $subtext1
|
||||||
|
font_size = 20
|
||||||
|
font_family = $font
|
||||||
|
position = -30, -190
|
||||||
|
halign = right
|
||||||
|
valign = top
|
||||||
|
}
|
||||||
|
|
||||||
|
# Weather
|
||||||
|
label {
|
||||||
|
monitor =
|
||||||
|
text = cmd[update:600000] $HOME/.local/bin/weather.sh
|
||||||
|
color = $subtext1
|
||||||
|
font_size = 20
|
||||||
|
font_family = $font
|
||||||
|
position = -30, -215
|
||||||
|
halign = right
|
||||||
|
valign = top
|
||||||
|
}
|
||||||
|
|
||||||
# User Avatar
|
# User Avatar
|
||||||
image {
|
image {
|
||||||
monitor =
|
monitor =
|
||||||
@@ -66,6 +93,18 @@ image {
|
|||||||
valign = center
|
valign = center
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Notifications (latest mako notification; empty when none)
|
||||||
|
label {
|
||||||
|
monitor =
|
||||||
|
text = cmd[update:5000] $HOME/.local/bin/hyprlock-notifications.sh
|
||||||
|
color = $subtext0
|
||||||
|
font_size = 16
|
||||||
|
font_family = $font
|
||||||
|
position = 0, 60
|
||||||
|
halign = center
|
||||||
|
valign = bottom
|
||||||
|
}
|
||||||
|
|
||||||
# Input Field
|
# Input Field
|
||||||
input-field {
|
input-field {
|
||||||
monitor =
|
monitor =
|
||||||
|
|||||||
Executable
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Guard wrapper for hyprlock (0.9.x): upstream has crashes on DPMS-off / monitor
|
||||||
|
# power transitions while the lock screen is running (hyprlock#991, #953, #695).
|
||||||
|
# If the real hyprlock dies, this restarts it so the session doesn't end up in a
|
||||||
|
# "lockscreen app died" state. Requires misc:allow_session_lock_restore = true
|
||||||
|
# in Hyprland config for the replacement lock to be accepted.
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
REAL_HYPRLOCK=/usr/bin/hyprlock
|
||||||
|
MAX_RESTARTS=20
|
||||||
|
|
||||||
|
restart=0
|
||||||
|
while true; do
|
||||||
|
"$REAL_HYPRLOCK" "$@"
|
||||||
|
code=$?
|
||||||
|
|
||||||
|
# 0: exited cleanly (e.g. unlocked) -- done.
|
||||||
|
# 1: auth failed, retry -- let the loop back off and try again.
|
||||||
|
if [ "$code" -eq 0 ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
restart=$((restart + 1))
|
||||||
|
if [ "$restart" -ge "$MAX_RESTARTS" ]; then
|
||||||
|
exit "$code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Brief pause so a crash loop doesn't burn CPU (fade back in quickly).
|
||||||
|
sleep 0.5
|
||||||
|
done
|
||||||
Executable
+39
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Battery status for the hyprlock screen, e.g. " 18%".
|
||||||
|
# Uses the first battery found under /sys/class/power_supply (BAT0/BAT1, ...);
|
||||||
|
# prints nothing on desktops without a battery.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
bat=""
|
||||||
|
for b in /sys/class/power_supply/BAT*; do
|
||||||
|
if [ -r "${b}/capacity" ]; then
|
||||||
|
bat="${b}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -z "${bat}" ] && exit 0
|
||||||
|
|
||||||
|
cap="$(cat "${bat}/capacity" 2>/dev/null || echo 0)"
|
||||||
|
status="$(cat "${bat}/status" 2>/dev/null || echo Unknown)"
|
||||||
|
|
||||||
|
case "${status}" in
|
||||||
|
Charging|Full)
|
||||||
|
icon=""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "${cap}" -ge 80 ]; then
|
||||||
|
icon=""
|
||||||
|
elif [ "${cap}" -ge 60 ]; then
|
||||||
|
icon=""
|
||||||
|
elif [ "${cap}" -ge 40 ]; then
|
||||||
|
icon=""
|
||||||
|
elif [ "${cap}" -ge 20 ]; then
|
||||||
|
icon=""
|
||||||
|
else
|
||||||
|
icon=""
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '%s %s%%' "${icon}" "${cap}"
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Latest mako notification for the hyprlock screen, Pango-escaped, e.g.
|
||||||
|
# "Battery test: Battery at 18%". Prints nothing when there are no
|
||||||
|
# notifications, so the label renders empty.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
makoctl list -j 2>/dev/null | jq -r '
|
||||||
|
if length == 0 then
|
||||||
|
empty
|
||||||
|
else
|
||||||
|
.[-1] as $n |
|
||||||
|
(if $n.app_name != null and $n.app_name != "" then $n.app_name + ": " else "" end) +
|
||||||
|
($n.summary // "") +
|
||||||
|
(if $n.body != null and $n.body != "" then " — " + $n.body[0:80] else "" end)
|
||||||
|
end' 2>/dev/null | sed 's/&/\&/g; s/</\</g; s/>/\>/g'
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"position": "top",
|
"position": "top",
|
||||||
"modules-left": ["hyprland/workspaces", "mpris"],
|
"modules-left": ["hyprland/workspaces", "mpris"],
|
||||||
"modules-center": ["hyprland/window"],
|
"modules-center": ["hyprland/window"],
|
||||||
"modules-right": ["cpu", "memory", "tray", "bluetooth", "network", "pulseaudio", "battery", "clock", "power-profiles-daemon", "custom/power"],
|
"modules-right": ["cpu", "memory", "tray", "bluetooth", "network", "pulseaudio", "battery", "custom/weather", "clock", "power-profiles-daemon", "custom/power"],
|
||||||
"clock": {
|
"clock": {
|
||||||
"format": "<span foreground='#f5c2e7'> </span>{:%a %d %H:%M}",
|
"format": "<span foreground='#f5c2e7'> </span>{:%a %d %H:%M}",
|
||||||
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"
|
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"
|
||||||
@@ -28,6 +28,12 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"on-click": "~/.local/bin/btop.sh"
|
"on-click": "~/.local/bin/btop.sh"
|
||||||
},
|
},
|
||||||
|
"custom/weather": {
|
||||||
|
"format": "{}",
|
||||||
|
"exec": "~/.local/bin/weather.sh",
|
||||||
|
"interval": 600,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
"icon-size": 16,
|
"icon-size": 16,
|
||||||
"icon-theme": "Papirus-Dark",
|
"icon-theme": "Papirus-Dark",
|
||||||
|
|||||||
+59
@@ -139,3 +139,62 @@ alias pip=pip3
|
|||||||
. "/home/sammieo/.deno/env"
|
. "/home/sammieo/.deno/env"
|
||||||
|
|
||||||
export LC_ALL="en_US.UTF-8"
|
export LC_ALL="en_US.UTF-8"
|
||||||
|
|
||||||
|
# Make sure no alias hides the real mv / cp
|
||||||
|
unalias mv 2>/dev/null
|
||||||
|
unalias cp 2>/dev/null
|
||||||
|
|
||||||
|
# Custom 'move' command that incorporates the pv command
|
||||||
|
mv() {
|
||||||
|
if (( $# > 2 )); then
|
||||||
|
command mv "$@"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local src=$1 dest=$2
|
||||||
|
|
||||||
|
if [ -d "$src" ]; then
|
||||||
|
mkdir -p "$dest"
|
||||||
|
|
||||||
|
# Total size in bytes (du -sb)
|
||||||
|
local total=$(du -sb "$src" | awk '{print $1}')
|
||||||
|
|
||||||
|
# Pipe through pv and extract at destination
|
||||||
|
tar -cf - -C "$(dirname "$src")" "$(basename "$src")" |
|
||||||
|
pv -s "$total" |
|
||||||
|
tar -xf - -C "$dest"
|
||||||
|
|
||||||
|
# Remove the original directory
|
||||||
|
rm -rf "$src"
|
||||||
|
else
|
||||||
|
mkdir -p "$(dirname "$dest")"
|
||||||
|
command mv "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Custom 'cp' command that incorporates the pv command
|
||||||
|
cp() {
|
||||||
|
if (( $# > 2 )); then
|
||||||
|
command cp "$@"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local src=$1 dst=$2
|
||||||
|
|
||||||
|
if [ -d "$src" ]; then
|
||||||
|
mkdir -p "$dst"
|
||||||
|
|
||||||
|
# ---- 1️⃣ Total size of the directory ---------------------------------
|
||||||
|
local total=$(du -sb "$src" | awk '{print $1}')
|
||||||
|
|
||||||
|
# ---- 2️⃣ Stream the dir through pv into the destination ---------------
|
||||||
|
tar -cf - -C "$(dirname "$src")" "$(basename "$src")" |
|
||||||
|
pv -s "$total" |
|
||||||
|
tar -xf - -C "$dst"
|
||||||
|
else
|
||||||
|
# ---- 3️⃣ Single file -------------------------------------------------
|
||||||
|
mkdir -p "$(dirname "$dst")"
|
||||||
|
local fsize=$(stat -c%s "$src" 2>/dev/null || wc -c <"$src")
|
||||||
|
pv -s "$fsize" < "$src" > "$dst"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user