Compare commits

...

13 Commits

Author SHA1 Message Date
sam_oneal 2d5a4e9f4c updated waybar power menu list 2026-09-07 20:13:04 -06:00
sam_oneal 8d2aa49668 updated to latest submodule 2026-09-07 20:01:50 -06:00
sam_oneal f60b7e263b hyprland: SUPER+Right creates a new workspace past the end of a monitor
m+1/m-1 only cycle existing workspaces on the active monitor and wrap at
the edges, so SUPER+Right never created a workspace. Replace them with a
Lua helper: advancing past the last workspace on the monitor now creates
a fresh (empty) workspace there; going before the first wraps to the
monitor's last workspace.
2026-09-07 18:26:27 -06:00
sam_oneal b148fcc256 hyprland: add SUPER+arrow workspace cycling and overview binds
SUPER+Left/Right cycle existing workspaces on the active monitor
(m+1/m-1 with cycling enabled), SUPER+Up opens the hyprshell overview
scoped to the current monitor (create/manage workspaces there), and
SUPER+Down closes the overview again. Adds binds-help.sh cheat sheet
(SHIFT+SUPER+H) and overview-close.sh helper.
2026-09-07 18:14:27 -06:00
sam_oneal 09c8706f35 fixed issue with lid closing was not being detected 2026-09-07 15:45:44 -06:00
sam_oneal 9d788d42e1 changed how closing windows worked; updated how the cloudflare access service works 2026-08-31 19:54:42 -06:00
sam_oneal 086097f2a9 waybar: add weather module to bar
Add custom/weather module between battery and clock, polling
weather.sh every 10 minutes.
2026-08-18 08:03:33 -06:00
sam_oneal 1755d17558 hyprlock: disable fingerprint, add battery/weather/notifications
- Disable fingerprint auth (GDM holds the device; hyprlock can't
  claim it, blocking the auth thread).
- Fix date format escaping (single quotes).
- Add battery, weather, and latest mako notification labels.
- Add hyprlock wrapper (crash guard), battery script, notifications
  script, and weather script.
2026-08-18 08:02:50 -06:00
sam_oneal 9e310d2f58 hyprland: prepend PATH, gate idle inhibitors, allow lock restore
- Prepend ~/.local/bin to PATH so user scripts (hyprlock wrapper,
  weather.sh) resolve before system binaries.
- Gate dpms-off and suspend on lock screen running (condition_cmd)
  so idle inhibitors from apps work while unlocked but screen still
  blanks and machine suspends after lock.
- Enable allow_session_lock_restore so a crashed lock client can be
  replaced.
- Temporarily enable debug logging to diagnose re-lock issues.
2026-08-18 08:02:16 -06:00
sam_oneal 21dbb16e8b zsh: add pv-backed mv/cp wrappers with progress and dir creation
Override mv and cp to pipe large transfers through pv for progress.
Directories are streamed via tar+pv; single files go through pv
directly. Parent directories are created (mkdir -p) when the
destination path doesn't exist yet.
2026-08-18 08:01:05 -06:00
sam_oneal 5cfa02ea6b make: exclude local-only packages and use --restow for idempotency
Filter out resources and wluma from PACKAGES since they are
local-only and should not be stowed. Use stow --restow so make link
can be run repeatedly without conflicts from pre-existing symlinks.
2026-08-18 08:00:40 -06:00
sam_oneal f57dc1db3c added ai sessions to gitignore 2026-08-14 23:43:44 -06:00
sam_oneal 260b202d6f update readme with current packages; add AGENTS.md for AI guidance 2026-08-14 21:35:39 -06:00
25 changed files with 924 additions and 85 deletions
+1
View File
@@ -1 +1,2 @@
sunsetr/.config/sunsetr/geo.toml
resources/ai/sessions
+74
View File
@@ -0,0 +1,74 @@
# AGENTS.md
Guidance for AI agents (and humans) working on this repo. This file documents
how AI assistance has been used on this project and the expectations for future
sessions.
## What this repo is
A set of GNU-stow packages containing the user's machine configuration
(Hyprland desktop, terminal, shell, systemd units, scripts, wallpapers). Each
top-level directory is a stow package rooted at `$HOME` (or `/` for system
dirs like `etc`). See `README.md` for the full package table and quick start.
## How AI has been used here
All prior work is captured in session transcripts under
`resources/ai/sessions/`. The main efforts so far:
- **Hyprland migration to Lua** (`session-ses_ffd7.md`): converted the
hyprlang `.conf` configs to Lua configs for Hyprland 0.56.2, migrated
plugins and themes (Catppuccin Mocha palette lives in `hyprmocha/`).
- **uwsm/sddm sign-in debugging** (`session-ses_ffd3.md`): diagnosed why the
uwsm Hyprland session would not allow sign-in; added a `sudo-askpass.sh`
(zenity prompt via `SUDO_ASKPASS`) and disabled linger.
- **Performance work** (`session-ses_ffcb.md`): profiled Hyprland CPU usage,
identified the animated `borderangle` loop as the culprit; added mako
notifications and waybar modules.
- **Monitor management** (`session-ses_ffc9.md`): adopted
[monique](https://github.com/notwidow/monique) for arranging multiple
monitors, including clamshell mode and the `hypr-lid-power` service
(`hyprland/.config/systemd/user/hypr-lid-power.service`).
- **Cloudflare tunnel + secrets** (`session-ses_0098.md`): wired the
`cloudflared-k8s` service to pull the Cloudflare Access service token from
the Homelab 1Password vault at runtime via `op run` — it is never written to
disk.
## Rules for agents
1. **Never commit secrets.** No API keys, tokens, passwords, or private keys
may be committed. Use 1Password references (`op://Vault/Item/...`) and
inject at runtime with `op run -- ...`. `.secrets.baseline` + `detect-secrets`
(via pre-commit) is the guardrail; keep it updated (`detect-secrets scan`
and re-baseline if a benign false positive is added).
2. **Fit every change into the stow layout.** Config files must live under a
package directory mirroring their destination (e.g. a new app config goes
under `<pkg>/.config/<app>/`). After changes, the package must be
committable and stowable (`make link` / `make unlink` must keep working).
3. **`resources/` is untracked and must stay untracked.** Session transcripts
under `resources/ai/sessions/` can contain sensitive values (e.g. a
Cloudflare client secret shown during a session). Do not stage, add, or
commit anything under `resources/`. Note `wluma/` is likewise local-only.
4. **Hyprland config is Lua, not hyprlang.** All `hyprland/.config/hypr/`
configs are `.lua` files driven by `hyprland.lua`. Do not reintroduce
`.conf`/hyprlang syntax.
5. **`nvim/` is a private submodule** pointing at a self-hosted Gitea/GitLab
repo; never replace it with a public fork and don't commit submodule state
changes unless intended. Pull with `make pull-updates`.
6. **Behave like the user's own assistant on this machine.** These dotfiles
reference real hosts (`sams_laptop`, `k8s.samoneal.io`, `git-ssh.samoneal.io`)
and real 1Password vaults — work with them, but keep the repo portable by
leaving secrets and machine-specific absolute paths in comments rather than
committed values where practical.
7. **Verify before finishing.** Run `git status`/`git diff` to confirm only
intended files changed and nothing sensitive is staged. If unsure whether a
value is a secret, treat it as one.
## Workflow
- Pre-commit hooks: `pre-commit install` (runs trailing-whitespace +
detect-secrets).
- Lint/typecheck: this repo is plain config + shell; shell scripts should stay
`sh`/`bash`-compatible and pass `shellcheck` if available.
- Record substantial AI sessions: if a session materially changes this repo,
save the transcript under `resources/ai/sessions/` (keep it untracked).
+3 -3
View File
@@ -1,6 +1,6 @@
HOME_TARGET ?= $(HOME)
SYSTEM_DIRS := etc usr var opt boot
PACKAGES := $(patsubst %/,%,$(wildcard */))
PACKAGES := $(filter-out resources wluma,$(patsubst %/,%,$(wildcard */)))
.PHONY: check-stow pull-updates unlink link
@@ -77,10 +77,10 @@ link: check-stow
done; \
if [ "$$is_sys" -eq 1 ]; then \
echo " [System] Stowing $$pkg/$$sub to $$sub"; \
sudo stow -d "$$pkg" -t "/$$sub" "$$sub"; \
sudo stow --restow -d "$$pkg" -t "/$$sub" "$$sub"; \
else \
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; \
done; \
done
+76 -10
View File
@@ -1,14 +1,80 @@
# Dotfiles
All the configuration files for my current machine setup.
All the configuration files for my current machine setup. Managed with GNU
stow so every package maps directly onto the relevant `~/.config`, `~/.local`,
`/etc`, etc. paths.
## Configurations
## Requirements
- Ghostty
- Hyprland
- Local
- Monique
- NVIM
- SSH
- SystemD
- ZSH
- [GNU stow](https://www.gnu.org/software/stow/)
- `make`
- [op (1Password CLI)](https://developer.1password.com/docs/cli/) for anything
that needs a secret
## Quick start
```sh
# Install stow if missing (auto-detects Arch/Debian/macOS)
make check-stow
# Link every package into $HOME (system dirs like /etc are stowed with sudo)
make link
# Unlink everything again
make unlink
# Pull main plus submodules
make pull-updates
```
## Packages
| Package | Path | Description |
| ----------- | -------------- | ------------------------------------------------------- |
| `backgrounds` | `~/.config/backgrounds` | Wallpaper collection (incl. Dynamic-Wallpapers) |
| `ghostty` | `~/.config/ghostty` | Ghostty terminal config |
| `hosts` | `~/.config/hosts` | Custom `HOSTALIASES` file (`HOSTALIASES=~/.config/hosts`) |
| `hyprland` | `~/.config/hypr`, `~/.local/bin` | Hyprland config (Lua), scripts, `hypr-lid-power` service |
| `hyprlock` | `~/.config/hypr` | Lockscreen config |
| `hyprmocha` | `~/.config/hypr` | Catppuccin Mocha palette as Lua |
| `hyprpaper` | `~/.config/hypr` | Wallpaper daemon config |
| `hyprshell` | `~/.config/hyprshell` | Launcher/overview (Rust, RON config + CSS) |
| `local` | `~/.local/bin` | Local scripts (e.g. `fetch-nas-credentials.sh`) |
| `mako` | `~/.config/mako` | Notifications |
| `monique` | `~/.config/monique` | Monitor/clamshell arrangement |
| `nvim` | `~/.config/nvim` | Git submodule (private repo) |
| `rofi` | `~/.config/rofi` | Launcher (Catppuccin Mocha) |
| `ssh` | `~/.ssh/config` | SSH config (1Password agent + cloudflared proxy) |
| `sunsetr` | `~/.config/sunsetr` | Screen color temperature (`geo.toml` is gitignored) |
| `systemd` | `~/.config/systemd/user`, `/etc/systemd` | User + system units (cloudflared, rclone/GDrive, NAS mounts, 1Password sign-in) |
| `waybar` | `~/.config/waybar` | Top bar |
| `wofi` | `~/.config/wofi` | App menu |
| `yay` | `~/.config/yay` | AUR helper config |
| `zsh` | `~/.zshrc` | Zsh config |
`wluma/` and `resources/` exist locally but are **not** committed (see
`AGENTS.md`).
## Secrets management
No secrets are committed to this repo. Anything secret goes through
[1Password](https://1password.com):
- References look like `op://Vault/Item/field[/section]` (e.g. the Cloudflare
service token in `systemd/.config/systemd/user/cloudflared-k8s.service`).
- Services inject secrets at runtime with `op run -- ...`, so values never hit
disk or git.
- `fetch-nas-credentials.sh` writes fetched NAS credentials to
`~/.nas/.smbcredentials` (chmod 600) at boot.
- `detect-secrets` runs via `pre-commit` against `.secrets.baseline`.
## Submodules
- `nvim/.config/nvim``git@git-ssh.samoneal.io:2222/sam_oneal/nvim-config.git`
(private). Pull with `make pull-updates`.
## AI assistance
This repo is developed with AI assistance. See `AGENTS.md` for how AI has been
used, the conventions it must follow, and where session transcripts are kept
(`resources/ai/sessions/`).
+85 -38
View File
@@ -1,71 +1,118 @@
-- See https://wiki.hypr.land/Configuring/Basics/Binds/ for more
-- Sound through pactl
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("pactl set-sink-volume @DEFAULT_SINK@ +10%"))
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("pactl set-sink-volume @DEFAULT_SINK@ -10%"))
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("pactl set-sink-mute @DEFAULT_SINK@ toggle"))
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"))
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"))
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"))
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("pactl set-sink-volume @DEFAULT_SINK@ +10%"), { desc = "Raise volume" })
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("pactl set-sink-volume @DEFAULT_SINK@ -10%"), { desc = "Lower volume" })
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("pactl set-sink-mute @DEFAULT_SINK@ toggle"), { desc = "Mute audio" })
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { desc = "Play/pause media" })
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { desc = "Previous track" })
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { desc = "Next track" })
-- Brightness through brightnessctl
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl set +5%"))
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl set 5%-"))
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl set +5%"), { desc = "Increase brightness" })
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl set 5%-"), { desc = "Decrease brightness" })
-- Main modifier binds
hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(terminal))
hl.bind(mainMod .. " + B", hl.dsp.exec_cmd(browser))
hl.bind(mainMod .. " + F", hl.dsp.exec_cmd(fileManager))
hl.bind(mainMod .. " + C", hl.dsp.window.kill())
hl.bind(mainMod .. " + M", hl.dsp.exit())
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + space", hl.dsp.exec_cmd(menu))
hl.bind(SUPER_SHIFT .. " + L", hl.dsp.exec_cmd("hyprlock"))
hl.bind(SUPER_SHIFT .. " + R", hl.dsp.exec_cmd("hyprctl reload"))
hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(terminal), { desc = "Open terminal" })
hl.bind(mainMod .. " + B", hl.dsp.exec_cmd(browser), { desc = "Open browser" })
hl.bind(mainMod .. " + F", hl.dsp.exec_cmd(fileManager), { desc = "Open file manager" })
hl.bind(mainMod .. " + C", hl.dsp.window.close(), { desc = "Close active window" })
hl.bind(mainMod .. " + Q", hl.dsp.exec_cmd("hyprctl dispatch closewindow \"class:$(hyprctl activewindow -j | jq -r .class)\""), { desc = "Close active window (by class)" })
hl.bind(mainMod .. " + M", hl.dsp.exit(), { desc = "Exit Hyprland" })
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }), { desc = "Toggle floating" })
hl.bind(mainMod .. " + space", hl.dsp.exec_cmd(menu), { desc = "Open app menu" })
hl.bind(SUPER_SHIFT .. " + L", hl.dsp.exec_cmd("hyprlock"), { desc = "Lock screen" })
hl.bind(SUPER_SHIFT .. " + R", hl.dsp.exec_cmd("hyprctl reload"), { desc = "Reload config" })
-- Monique: GUI monitor arrangement/display settings
hl.bind(SUPER_SHIFT .. " + M", hl.dsp.exec_cmd("monique"))
hl.bind(SUPER_SHIFT .. " + D", hl.dsp.exec_cmd("hyprctl keyword monitor eDP-1, disable"))
hl.bind(SUPER_SHIFT .. " + F", hl.dsp.exec_cmd("hyprctl keyword monitor eDP-1, enable"))
hl.bind(SUPER_SHIFT .. " + M", hl.dsp.exec_cmd("monique"), { desc = "Open monique (monitor settings)" })
hl.bind(SUPER_SHIFT .. " + D", hl.dsp.exec_cmd("hyprctl keyword monitor eDP-1, disable"), { desc = "Disable eDP-1 (clamshell)" })
hl.bind(SUPER_SHIFT .. " + F", hl.dsp.exec_cmd("hyprctl keyword monitor eDP-1, enable"), { desc = "Enable eDP-1" })
-- Screenshots
hl.bind("Print", hl.dsp.exec_cmd("grim -c -o \"$(hyprctl activeworkspace -j | jq -r '.monitor')\" $(xdg-user-dir PICTURES)/Screenshots/$(date +'%s_grim.png')"))
hl.bind("SHIFT + Print", hl.dsp.exec_cmd("grim -g \"$(slurp)\" $(xdg-user-dir PICTURES)/Screenshots/$(date +'%s_grim.png')"))
hl.bind("Print", hl.dsp.exec_cmd("grim -c -o \"$(hyprctl activeworkspace -j | jq -r '.monitor')\" $(xdg-user-dir PICTURES)/Screenshots/$(date +'%s_grim.png')"), { desc = "Screenshot active monitor" })
hl.bind("SHIFT + Print", hl.dsp.exec_cmd("grim -g \"$(slurp)\" $(xdg-user-dir PICTURES)/Screenshots/$(date +'%s_grim.png')"), { desc = "Screenshot region" })
-- Dwindle layout
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo()) -- dwindle
hl.bind(mainMod .. " + E", hl.dsp.layout("togglesplit")) -- dwindle
hl.bind(mainMod .. " + CTRL + F", hl.dsp.window.fullscreen({ action = "toggle" })) -- dwindle
hl.bind(mainMod .. " + W", hl.dsp.group.toggle()) -- dwindle
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo(), { desc = "Toggle pseudo tiling" }) -- dwindle
hl.bind(mainMod .. " + E", hl.dsp.layout("togglesplit"), { desc = "Toggle split" }) -- dwindle
hl.bind(mainMod .. " + CTRL + F", hl.dsp.window.fullscreen({ action = "toggle" }), { desc = "Toggle fullscreen" }) -- dwindle
hl.bind(mainMod .. " + W", hl.dsp.group.toggle(), { desc = "Toggle window group" }) -- dwindle
-- Move focus with mainMod + vim keys
hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "l" }))
hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "r" }))
hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "u" }))
hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "d" }))
hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "l" }), { desc = "Focus left" })
hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "r" }), { desc = "Focus right" })
hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "u" }), { desc = "Focus up" })
hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "d" }), { desc = "Focus down" })
-- Cycle workspaces on the active monitor with mainMod + arrows. Advancing past
-- the last workspace on the monitor creates a fresh (empty) workspace there;
-- going before the first wraps around to the last one on the monitor.
local function step_workspace(dir)
local mon = hl.get_active_monitor()
if not mon then return end
local current = mon.active_workspace.id
local mon_ids, all_max = {}, 0
for _, ws in ipairs(hl.get_workspaces()) do
if ws.id > all_max then all_max = ws.id end
if ws.monitor and ws.monitor.id == mon.id then
table.insert(mon_ids, ws.id)
end
end
table.sort(mon_ids)
local target
if dir > 0 then
for _, id in ipairs(mon_ids) do
if id > current then target = id break end
end
-- No next workspace on this monitor: create one right here.
if not target then target = all_max + 1 end
else
for i = #mon_ids, 1, -1 do
if mon_ids[i] < current then target = mon_ids[i] break end
end
-- No previous workspace on this monitor: wrap to the last one.
if not target and #mon_ids > 0 then target = mon_ids[#mon_ids] end
end
if target then hl.dispatch(hl.dsp.focus({ workspace = target })) end
end
hl.bind(mainMod .. " + Left", function() step_workspace(-1) end, { desc = "Previous workspace (active monitor)" })
hl.bind(mainMod .. " + Right", function() step_workspace(1) end, { desc = "Next workspace (active monitor); creates one past the end" })
-- Switch workspaces with mainMod + [0-9]
for i = 1, 10 do
local key = i % 10 -- 10 maps to key 0
hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i }))
hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i }), { desc = "Go to workspace " .. i })
end
-- Move active window to a workspace with mainMod + SHIFT + [0-9]
for i = 1, 10 do
local key = i % 10 -- 10 maps to key 0
hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }), { desc = "Move window to workspace " .. i })
end
-- Example special workspace (scratchpad)
hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic"))
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" }))
hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic"), { desc = "Toggle scratchpad" })
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" }), { desc = "Move window to scratchpad" })
-- Scroll through existing workspaces with mainMod + scroll
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }), { desc = "Next workspace (scroll)" })
hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }), { desc = "Previous workspace (scroll)" })
-- Keybind cheat sheet
hl.bind(SUPER_SHIFT .. " + H", hl.dsp.exec_cmd("binds-help.sh"), { desc = "Keybind cheat sheet" })
-- Workspace overview (macOS Mission Control style). SUPER + Up is registered by
-- the hyprshell daemon itself ("Open Overview with Super + Up"); SUPER + Down
-- closes the overview again without switching.
hl.bind(mainMod .. " + Down", hl.dsp.exec_cmd("overview-close.sh"), { desc = "Close workspace overview" })
-- Move/resize windows with mainMod + LMB/RMB and dragging
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true, desc = "Drag window" })
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true, desc = "Resize window" })
-- Laptop lid is handled by hypr-lid-power.service (delayed lock/suspend when
-- closed undocked; display/clamshell handling is done by moniqued) instead of
+4
View File
@@ -2,3 +2,7 @@
hl.env("XCURSOR_SIZE", "24")
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")
-- 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"))
+12
View File
@@ -23,14 +23,26 @@ listener {
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 {
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-resume = hyprctl dispatch dpms on && brightnessctl -r # screen on when activity is detected after timeout has fired.
}
listener {
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
}
+14
View File
@@ -39,6 +39,14 @@ hl.config({
},
})
hl.config({
binds = {
-- Let SUPER+scroll workspace cycling wrap around instead of stopping at
-- the edges. (SUPER+Left/Right wrapping is handled directly in binds.lua.)
allow_workspace_cycles = true,
},
})
hl.config({
decoration = {
rounding = 4,
@@ -94,6 +102,9 @@ hl.config({
mouse_move_focuses_monitor = false,
-- Skip drawing the Hyprland logo in the corner of empty workspaces.
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 +114,8 @@ hl.config({
hl.config({
debug = {
vfr = true,
-- Temporarily on to diagnose the mystery re-lock (disable_logs=true
-- default hides dispatch exec lines from hyprland.log).
disable_logs = false,
},
})
+11 -8
View File
@@ -1,8 +1,11 @@
-- Managed by monique (run `monique` or SUPER+SHIFT+M to arrange). The built-in
-- panel is managed at runtime by moniqued's clamshell mode: enabled here, then
-- disabled while the lid is closed with external displays attached.
-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ for more
hl.monitor({ output = "desc:BOE 0x0BC9", mode = "preferred", position = "0x0", scale = 1.0 })
hl.monitor({ output = "desc:Viewteck Co. Ltd. GNV34DB", mode = "3440x1440@50.0", position = "3795x1785", scale = 1.0 })
hl.monitor({ output = "desc:Dell Inc. DELL U2515HX GMDK46C4053L", mode = "2560x1440@59.95", position = "5488x345", scale = 1.0 })
hl.monitor({ output = "desc:Dell Inc. DELL U2518D 0WG2J9C5B3WL", mode = "2560x1440@59.95", position = "2928x345", scale = 1.0 })
-- Generated by Monique - https://github.com/ToRvaLDz/monique
hl.monitor({
output = "desc:BOE 0x0BC9",
mode = "2560x1600@165",
position = "0x0",
scale = 1,
cm = "srgb",
sdr_min_luminance = 0.2,
sdr_max_luminance = 80,
})
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Searchable cheat sheet of Hyprland keybindings, shown in wofi.
#
# The descriptions shown here come from the `desc` option passed to hl.bind()
# in ~/.config/hypr/binds.lua, read back at runtime via `hyprctl binds -j`,
# so the cheat sheet always matches the live config.
set -u
mods_from_mask() {
local mask="$1" out=""
(( mask & 1 )) && out="${out:+$out + }SHIFT"
(( mask & 4 )) && out="${out:+$out + }CTRL"
(( mask & 8 )) && out="${out:+$out + }ALT"
(( mask & 64 )) && out="${out:+$out + }SUPER"
(( mask & 128 )) && out="${out:+$out + }MOD5"
printf "%s" "$out"
}
hyprctl binds -j |
jq -rc '.[] | select(.has_description) | select(.description != "") | [.modmask, .key, .description] | @tsv' |
while IFS=$'\t' read -r mask key desc; do
if (( mask )); then
mods="$(mods_from_mask "$mask")"
printf '%s + %s\t%s\n' "$mods" "$key" "$desc"
else
printf '%s\t%s\n' "$key" "$desc"
fi
done |
sort -k1,1 |
column -t -s $'\t' |
wofi --dmenu --prompt "Hyprland keybinds" >/dev/null
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# macOS-style SUPER+Down: close the hyprshell workspace overview if it is open,
# returning to the current workspace without switching.
#
# hyprshell's overview is a gtk4-layer-shell surface whose namespace is
# "hyprshell_overview", and the OpenOverview IPC message toggles the overview
# closed when it is already open (see OverviewRootInput::OpenOverview).
set -u
if ! hyprctl layers -j | jq -e '
.. | objects | .namespace? // empty | select(. == "hyprshell_overview")
' >/dev/null; then
exit 0
fi
hyprshell socat '"OpenOverview"'
+34
View File
@@ -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
+42 -3
View File
@@ -7,14 +7,17 @@ $font = JetBrainsMono Nerd Font
# General
general {
disable_loading_bar = false
hide_cursor = false
}
# 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 {
fingerprint {
enabled = true
enabled = false
ready_message = Scan fingerprint to unlock
present_message = Scanning...
retry_delay = 250 # in milliseconds
@@ -45,7 +48,7 @@ label {
# Date
label {
monitor =
text = cmd[update:43200000] echo "$(date + "%A, %d %B %Y")"
text = cmd[update:43200000] echo "$(date +'%A, %d %B %Y')"
color = $text
font_size = 25
font_family = $font
@@ -54,6 +57,30 @@ label {
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
image {
monitor =
@@ -66,6 +93,18 @@ image {
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 {
monitor =
+31
View File
@@ -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
+39
View File
@@ -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
View File
@@ -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/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g'
+10 -8
View File
@@ -1,6 +1,6 @@
// Edit with `hyprshell config edit`
(
version: 3,
version: 4,
windows: (
scale: 8.5,
items_per_row: 5,
@@ -43,7 +43,6 @@
actions: (
actions: [
lock_screen,
hibernate,
logout,
reboot,
shutdown,
@@ -69,11 +68,13 @@
),
),
),
key: "Tab",
modifier: "alt",
filter_by: [],
hide_filtered: false,
exclude_special_workspaces: "",
key: "Up",
top_offset: 430,
modifier: "super",
filter_by: [
current_monitor,
],
exclude_workspaces: "special:.*",
),
switch: (
modifier: "alt",
@@ -82,7 +83,8 @@
current_monitor,
],
switch_workspaces: false,
exclude_special_workspaces: "",
exclude_workspaces: "",
kill_key: 'q',
),
switch_2: None,
),
+279
View File
@@ -0,0 +1,279 @@
{
"name": "desk",
"monitors": [
{
"name": "eDP-2",
"description": "BOE 0x0BC9",
"make": "BOE",
"model": "0x0BC9",
"serial": "",
"width": 2560,
"height": 1600,
"refresh_rate": 165.0,
"resolution_mode": "explicit",
"available_modes": [
"2560x1600@165.00Hz",
"2560x1600@60.00Hz",
"1920x1200@165.00Hz",
"1920x1080@165.00Hz",
"1600x1200@165.00Hz",
"1680x1050@165.00Hz",
"1280x1024@165.00Hz",
"1440x900@165.00Hz",
"1280x800@165.00Hz",
"1280x720@165.00Hz",
"1024x768@165.00Hz",
"800x600@165.00Hz",
"640x480@165.00Hz"
],
"x": 0,
"y": 0,
"position_mode": "explicit",
"scale": 1,
"scale_mode": "explicit",
"transform": 0,
"mirror_of": "",
"bitdepth": 8,
"vrr": 0,
"color_management": "srgb",
"icc_profile": "",
"sdr_brightness": 1,
"sdr_saturation": 1,
"sdr_eotf": 0,
"supports_hdr": 0,
"supports_wide_color": 0,
"sdr_min_luminance": 0.2,
"sdr_max_luminance": 80,
"min_luminance": 0.0,
"max_luminance": 0.0,
"max_avg_luminance": 0.0,
"reserved_top": 0,
"reserved_bottom": 0,
"reserved_left": 0,
"reserved_right": 0,
"enabled": true,
"focus_at_startup": false
},
{
"name": "DP-7",
"description": "Dell Inc. DELL U2515HX GMDK46C4053L",
"make": "Dell Inc.",
"model": "DELL U2515HX",
"serial": "GMDK46C4053L",
"width": 2560,
"height": 1440,
"refresh_rate": 59.951,
"resolution_mode": "explicit",
"available_modes": [
"2560x1440@59.95Hz",
"2048x1152@60.00Hz",
"1920x1200@59.88Hz",
"1920x1080@60.00Hz",
"1920x1080@60.00Hz",
"1920x1080@59.94Hz",
"1920x1080@50.00Hz",
"1920x1080@30.00Hz",
"1920x1080@29.97Hz",
"1920x1080@25.00Hz",
"1920x1080@24.00Hz",
"1920x1080@23.98Hz",
"1600x1200@60.00Hz",
"1680x1050@59.95Hz",
"1280x1024@75.03Hz",
"1280x1024@60.02Hz",
"1200x960@59.99Hz",
"1152x864@75.00Hz",
"1280x720@60.00Hz",
"1280x720@60.00Hz",
"1280x720@59.94Hz",
"1280x720@50.00Hz",
"1024x768@75.03Hz",
"1024x768@60.00Hz",
"800x600@75.00Hz",
"800x600@60.32Hz",
"720x576@50.00Hz",
"720x480@60.00Hz",
"720x480@60.00Hz",
"720x480@59.94Hz",
"720x480@59.94Hz",
"720x480@59.94Hz",
"640x480@75.00Hz",
"640x480@60.00Hz",
"640x480@59.94Hz",
"640x480@59.94Hz",
"720x400@70.08Hz"
],
"x": 5488,
"y": 345,
"position_mode": "explicit",
"scale": 1,
"scale_mode": "explicit",
"transform": 0,
"mirror_of": "",
"bitdepth": 8,
"vrr": 0,
"color_management": "srgb",
"icc_profile": "",
"sdr_brightness": 1,
"sdr_saturation": 1,
"sdr_eotf": 0,
"supports_hdr": 0,
"supports_wide_color": 0,
"sdr_min_luminance": 0.2,
"sdr_max_luminance": 80,
"min_luminance": 0.0,
"max_luminance": 0.0,
"max_avg_luminance": 0.0,
"reserved_top": 0,
"reserved_bottom": 0,
"reserved_left": 0,
"reserved_right": 0,
"enabled": true,
"focus_at_startup": false
},
{
"name": "DP-10",
"description": "Dell Inc. DELL U2518D 0WG2J9C5B3WL",
"make": "Dell Inc.",
"model": "DELL U2518D",
"serial": "0WG2J9C5B3WL",
"width": 2560,
"height": 1440,
"refresh_rate": 59.951,
"resolution_mode": "explicit",
"available_modes": [
"2560x1440@59.95Hz",
"2048x1080@60.00Hz",
"2048x1080@24.00Hz",
"1920x1080@60.00Hz",
"1920x1080@60.00Hz",
"1920x1080@59.94Hz",
"1920x1080@50.00Hz",
"1600x1200@60.00Hz",
"1280x1024@75.03Hz",
"1280x1024@60.02Hz",
"1152x864@75.00Hz",
"1280x720@60.00Hz",
"1280x720@60.00Hz",
"1280x720@59.94Hz",
"1280x720@50.00Hz",
"1024x768@75.03Hz",
"1024x768@60.00Hz",
"800x600@75.00Hz",
"800x600@60.32Hz",
"720x576@50.00Hz",
"720x576@50.00Hz",
"720x480@60.00Hz",
"720x480@60.00Hz",
"720x480@59.94Hz",
"720x480@59.94Hz",
"640x480@75.00Hz",
"640x480@60.00Hz",
"640x480@59.94Hz",
"640x480@59.94Hz",
"720x400@70.08Hz"
],
"x": 2928,
"y": 345,
"position_mode": "explicit",
"scale": 1,
"scale_mode": "explicit",
"transform": 0,
"mirror_of": "",
"bitdepth": 8,
"vrr": 0,
"color_management": "srgb",
"icc_profile": "",
"sdr_brightness": 1,
"sdr_saturation": 1,
"sdr_eotf": 0,
"supports_hdr": 0,
"supports_wide_color": 0,
"sdr_min_luminance": 0.2,
"sdr_max_luminance": 80,
"min_luminance": 0.0,
"max_luminance": 0.0,
"max_avg_luminance": 0.0,
"reserved_top": 0,
"reserved_bottom": 0,
"reserved_left": 0,
"reserved_right": 0,
"enabled": true,
"focus_at_startup": false
},
{
"name": "DP-4",
"description": "Viewteck Co. Ltd. GNV34DB",
"make": "Viewteck Co., Ltd.",
"model": "GNV34DB",
"serial": "",
"width": 3440,
"height": 1440,
"refresh_rate": 50.0,
"resolution_mode": "explicit",
"available_modes": [
"3440x1440@30.00Hz",
"3440x1440@50.00Hz",
"3440x1440@50.00Hz",
"2560x1080@60.00Hz",
"2560x1080@59.94Hz",
"1720x1440@60.00Hz",
"1920x1080@60.00Hz",
"1920x1080@60.00Hz",
"1920x1080@59.94Hz",
"1920x1080@50.00Hz",
"1680x1050@59.88Hz",
"1600x900@60.00Hz",
"1280x1024@75.03Hz",
"1280x1024@60.02Hz",
"1440x900@59.90Hz",
"1280x720@60.00Hz",
"1280x720@60.00Hz",
"1280x720@59.94Hz",
"1280x720@50.00Hz",
"1024x768@75.03Hz",
"1024x768@60.00Hz",
"800x600@75.00Hz",
"800x600@60.32Hz",
"720x480@60.00Hz",
"720x480@60.00Hz",
"720x480@59.94Hz",
"720x480@59.94Hz",
"640x480@75.00Hz",
"640x480@60.00Hz",
"640x480@59.94Hz",
"640x480@59.94Hz",
"720x400@70.08Hz"
],
"x": 3795,
"y": 1785,
"position_mode": "explicit",
"scale": 1,
"scale_mode": "explicit",
"transform": 0,
"mirror_of": "",
"bitdepth": 8,
"vrr": 0,
"color_management": "srgb",
"icc_profile": "",
"sdr_brightness": 1,
"sdr_saturation": 1,
"sdr_eotf": 0,
"supports_hdr": 0,
"supports_wide_color": 0,
"sdr_min_luminance": 0.2,
"sdr_max_luminance": 80,
"min_luminance": 0.0,
"max_luminance": 0.0,
"max_avg_luminance": 0.0,
"reserved_top": 0,
"reserved_bottom": 0,
"reserved_left": 0,
"reserved_right": 0,
"enabled": true,
"focus_at_startup": false
}
],
"workspace_rules": [],
"last_applied_time": 1788832961.6364207
}
@@ -0,0 +1,60 @@
{
"name": "laptop",
"monitors": [
{
"name": "eDP-2",
"description": "BOE 0x0BC9",
"make": "BOE",
"model": "0x0BC9",
"serial": "",
"width": 2560,
"height": 1600,
"refresh_rate": 165.0,
"resolution_mode": "explicit",
"available_modes": [
"2560x1600@165.00Hz",
"2560x1600@60.00Hz",
"1920x1200@165.00Hz",
"1920x1080@165.00Hz",
"1600x1200@165.00Hz",
"1680x1050@165.00Hz",
"1280x1024@165.00Hz",
"1440x900@165.00Hz",
"1280x800@165.00Hz",
"1280x720@165.00Hz",
"1024x768@165.00Hz",
"800x600@165.00Hz",
"640x480@165.00Hz"
],
"x": 0,
"y": 0,
"position_mode": "explicit",
"scale": 1,
"scale_mode": "explicit",
"transform": 0,
"mirror_of": "",
"bitdepth": 8,
"vrr": 0,
"color_management": "srgb",
"icc_profile": "",
"sdr_brightness": 1,
"sdr_saturation": 1,
"sdr_eotf": 0,
"supports_hdr": 0,
"supports_wide_color": 0,
"sdr_min_luminance": 0.2,
"sdr_max_luminance": 80,
"min_luminance": 0.0,
"max_luminance": 0.0,
"max_avg_luminance": 0.0,
"reserved_top": 0,
"reserved_bottom": 0,
"reserved_left": 0,
"reserved_right": 0,
"enabled": true,
"focus_at_startup": false
}
],
"workspace_rules": [],
"last_applied_time": 1788832965.6726744
}
+2 -1
View File
@@ -1,5 +1,6 @@
{
"clamshell_mode": true,
"update_sddm": true,
"migrate_workspaces": true
"migrate_workspaces": true,
"active_profile": "laptop"
}
@@ -19,8 +19,8 @@ StartLimitBurst=5
[Service]
PassEnvironment=DISPLAY WAYLAND_DISPLAY DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR
Environment="OP_BIOMETRIC_UNLOCK_ENABLED=true"
Environment="CF_ACCESS_CLIENT_ID=op://Homelab/K8s API Service Token/Service Token/client-id"
Environment="CF_ACCESS_CLIENT_SECRET=op://Homelab/K8s API Service Token/Service Token/client-secret"
Environment="TUNNEL_SERVICE_TOKEN_ID=op://Homelab/K8s API Service Token/Service Token/client-id"
Environment="TUNNEL_SERVICE_TOKEN_SECRET=op://Homelab/K8s API Service Token/Service Token/client-secret"
ExecStart=/usr/bin/op run -- /usr/bin/cloudflared access tcp --hostname k8s.samoneal.io --url localhost:6443
Restart=on-failure
RestartSec=60
+11 -4
View File
@@ -2,7 +2,7 @@
"position": "top",
"modules-left": ["hyprland/workspaces", "mpris"],
"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": {
"format": "<span foreground='#f5c2e7'> </span>{:%a %d %H:%M}",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"
@@ -28,6 +28,12 @@
"memory": {
"on-click": "~/.local/bin/btop.sh"
},
"custom/weather": {
"format": "{}",
"exec": "~/.local/bin/weather.sh",
"interval": 600,
"tooltip": false
},
"tray": {
"icon-size": 16,
"icon-theme": "Papirus-Dark",
@@ -83,10 +89,11 @@
"menu": "on-click",
"menu-file": "~/.config/waybar/power_menu.xml",
"menu-actions": {
"shutdown": "shutdown",
"reboot": "reboot",
"suspend": "systemctl suspend",
"hibernate": "systemctl hibernate",
"lock": "hyprlock",
"logout": "hyprctl dispatch exit",
"reboot": "reboot",
"shutdown": "shutdown",
},
"escape": true
},
+11 -6
View File
@@ -7,21 +7,26 @@
</object>
</child>
<child>
<object class="GtkMenuItem" id="hibernate">
<property name="label">Hibernate</property>
<object class="GtkMenuItem" id="lock">
<property name="label">Lock</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="shutdown">
<property name="label">Shutdown</property>
<object class="GtkMenuItem" id="logout">
<property name="label">Logout</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="reboot">
<property name="label">Restart</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="delimiter1" />
</child>
<child>
<object class="GtkMenuItem" id="reboot">
<property name="label">Reboot</property>
<object class="GtkMenuItem" id="shutdown">
<property name="label">Shutdown</property>
</object>
</child>
</object>
+59
View File
@@ -139,3 +139,62 @@ alias pip=pip3
. "/home/sammieo/.deno/env"
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
}