Replaces the scrolling-preset "columns" with a genuine custom tiling layout
(hl.layout.register "lua:columns"): a row of columns where each column is an
INDEPENDENTLY panning vertical strip. Moving focus up/down inside a column pans
only that column to keep the focus in view; the other columns stay frozen — the
combination-lock behaviour that the built-in scrolling engine (single shared tape
offset) structurally can't do.
- columns.lua: recalculate places every window box; per-workspace state holds each
window's column assignment and each column's pan offset. layout_msg handles the
focus/move/count/orient commands. New windows fill the least-populated column;
changing the column count reflows evenly.
- init.lua: for Lua layouts (lua = true), orientation is sent via layout_msg
("orient h|v") instead of the global scrolling:direction option.
- hypr-nav: forwards focus/move/count for the columns layout to hl.dsp.layout(...);
the built-in scrolling path is unchanged.
- binds.lua: Super+Ctrl+Alt+H/J/K/L manage the column / windows-per-view count
(axes follow the workspace's horizontal/vertical orientation).
Menu dropdown for "Columns" now selects orientation (Horizontal / Vertical).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUN7gg6GGfnToghMijLm5Y
astal-menu: the taskbar ⤢ toggle now collapses the compact strip and mounts
its workspace/window panel as a takeover overlay covering the 2x2 quads (with
a Back button), instead of a popover/inline reveal. QuadGrid gains a generic
takeover overlay; the menu window coordinates show/hide and resets on close.
hypr: new "Columns" layout (scrolling backend presented as independent columns)
with a menu dropdown to pick orientation — "Left / Right" or "Up / Down" — via a
new dir_labels manifest field. The layout menu now tracks direction dropdowns and
fit switches per-layout, so a second directional layout no longer clobbers the
first.
binds/scripts: focus & window-move keys (hjkl + arrows) route through a new
hypr-nav helper so they stay screen-absolute in the scrolling/columns layouts
(the layout otherwise resolves a perpendicular direction onto "scroll the tape",
rotating the keys with scrolling:direction). Adds explicit cross-monitor binds:
Super+,/. focus prev/next monitor, Super+Shift+,/. move the window there.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUN7gg6GGfnToghMijLm5Y
- hypr/layouts/: drop-in layout registry. init.lua auto-discovers layouts/<name>.lua
(each self-describing) and exposes the global `layouts` table: set_default (picked
in hyprland.lua — now scrolling, direction down), set(ws,name,dir) for live
per-workspace switching (verified it re-tiles the active ws), set_fit(0/1). Writes
a manifest + per-ws state for the menu. Ships scrolling/dwindle/master/monocle.
- Scrolling default: column_width 0.5 (active column < viewport so prev/next stay
clickable), focus_fit_method 1 (centered follow), fullscreen_on_one_column.
- astal-menu taskbar pop-open: workspace layout selector + direction + a "Centered"
toggle (focus_fit_method), and a per-window list — [icon+title → jump][⇤ here →
pull to current workspace], keeping jump-to-window intact.
- eww bar menu buttons open the menu explicitly from the top (menu-toggle.sh toggle top).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
- Installer: add python-pillow (map tile stitching) and networkmanager (the Network
quad's nmcli backend) so a fresh install has a working map and network panel.
- Super+D binds explicitly to `menu-toggle.sh toggle top` so it pops in from the top.
The astal-menu config (incl. new backend/nm.py, ui/statsbar.py, etc.) already ships
via the config-updater CONFIGS list and is re-synced by sysupdate.sh; settings live
in XDG_STATE_HOME so updates don't wipe them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
- Main open: enable Hyprland's `layers` animation with the bouncy myBezier curve and
a slide style, so the layer-shell control centre slides in from the top edge with a
little overshoot instead of just appearing. (Also gives notifications/bar the same
springy slide, which suits the DE.) A per-namespace layerrule was tried first but
this hyprlua build doesn't honour its animation timing.
- Quad expand: a CSS @keyframes scale-bounce (scale 0.82 -> 1.05 -> 1.0) added to the
expanded card on expand and cleared on collapse so it replays every time. Verified
GTK4 CSS transforms/keyframes render on this build, and that the card scales during
the animation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
Widget settings popover toggles now take effect immediately. QuadCard only
rebuilt a card when its Enabled state flipped, so per-module feature toggles
(Wi-Fi, discovery, routes, CLI art, …) were persisted but never applied. The
card now rebuilds whenever any of its own feature values change, and the
incomplete partial per-module refresh callbacks (which also leaked a dead
subscription per rebuild) are dropped in favour of that single path.
Make the backmost surface transparent so each module floats on its own drawn
border/background: force `window`/`.background`/`.panel` transparent, since a
plain `.menu-window` rule did not override the GTK theme's solid window node.
Locate via IP now works and uses traceroute: geolocate.py traceroutes to
1.1.1.1, takes the first globally-routable hop (the ISP egress) and resolves it
through a public geolocation API, falling back to self-IP when traceroute is
missing or finds no public hop. The ip_locate toggle gates the lookup entirely
(placeholder when off). Adds `traceroute` to the hyprlua package list.
Autostart: `sleep 1 && hyprctl reload` after all spawns so layer-shell clients
settle on the final config.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
A touch-friendly GTK4 popup control centre (Python + PyGObject, wlr-layer-shell)
launched from the EWW bar or Super+D. Replaces nwg-dock and nwg-drawer.
Layout: a floating, drawn-bordered panel (anchored top-centre so it never blocks
the rest of the screen) with a 2x2 quad grid over a full-width app drawer, plus a
top taskbar. Any quad expands over the others; the drawer expands to the bottom.
Modules:
- Location — static OSM map (backend/staticmap.py) on IP geolocation
(libshumate won't paint tiles in this env; shumate-demo is blank too)
- Weather — wttr.in ANSI art rendered via an SGR parser into a TextView
- Bluetooth — AstalBluetooth: discovery/connect/disconnect + local history
- Network — AstalNetwork wifi + nmcli/ip/ss for IP, DHCP/manual, routes, ports,
public IP; per-feature toggles
- Taskbar — open windows from hyprctl, grouped by app with pop-out per instance
- Favorites — pinned apps (right-click/long-press to pin) atop the app drawer
Notes:
- Frontend is Python/GTK4, not Lua: lgi/Astal-Lua are GTK3-only.
- Module borders are drawn with a Cairo overlay (lib/border.py); this GTK build's
renderer skips CSS border/background on plain container widgets.
- Consumes Astal GObject libs (io/apps/network/bluetooth) via introspection.
Wiring: autostart + Super+D/Super+Shift+A binds, EWW launcher button in all three
bar variants, apply-theme.sh (_colors.css), installer packages, config-updater.
drawer.sh moved to scripts/deprecated/.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dialog was landing off-cursor and at ~half-screen. Two Hyprland
gotchas were fighting each other: `move` is evaluated against the
window's natural size and `size` is applied afterwards from the top-left,
so a cursor_x-(window_w/2) move centred the pre-shrink window. zenity's
file chooser also ignores --width/--height and has a ~738x363 GTK
minimum.
Fix the size at 760x460 and hard-code the move offsets to half that
(380x230) so the shrunk window lands exactly on the pointer. Drop the
dead zenity --width/--height sizing from the script.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a size rule alongside the move so the zenity dialog no longer opens
at its default ~50% size. zenity clamps to its GTK minimum (~738x363),
which is well under half the screen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the at-cursor rule to filepicker and move the dialog to a fixed
position 10% into the display (from the top-left) instead of following
the cursor.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a dedicated at-cursor window rule (float + move to cursor) and point
the Super+F / Super+Shift+F filepicker binds at it, so the zenity dialog
opens centered on the mouse instead of mid-screen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prefix the Super+F / Super+Shift+F filepicker binds with [tag +centered]
so the zenity dialog spawns as a centered floating window (60% x 60%),
matching the centered rule in windowrules.lua. Same tagged-spawn
mechanism as Super+U.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add filepicker-clipboard.sh: a zenity file dialog that copies the
selected file's path (Super+F) or contents (Super+Shift+F) to the
clipboard via wl-copy. Path mode collapses $HOME to ~.
Repoints Super+F / Super+Shift+F from wofi-file-search/foldersearch
(kept as comments) in usr/binds.lua.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the machine-specific DP-1/DP-3/HDMI-A-1 layout with a wildcard
catch-all rule (preferred mode, auto position, auto scale) that brings up
any connected output. Per-machine layout stays the job of monitor-manager,
which overwrites this file.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Installs ydotool via pacman and OpenDeck via Flatpak, wires ydotoold
and OpenDeck into the Hyprland autostart. Registers the module in the
TUI installer, answerfile generator, and docs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The merge agent reverted the switch from usr.monitors to root-level monitors
(managed by hyprmoncfg). Restore main's version and update the surrounding
comment to explain the new arrangement.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hyprctl returns mirrorOf:"none" (string) for non-mirrored monitors.
Python treated it as truthy, causing apply_monitor to always emit a
mirror command, resetting resolution and scale on every keypress.
Also restores monitors.lua with correct mode/scale/transform fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Python curses TUI for managing Hyprland monitors interactively:
- Canvas shows monitors as boxes at their real relative positions
- Tab/Shift+Tab to cycle selection; hjkl/HJKL to move (50/10 px)
- u/i to rotate CCW/CW; n/N to cycle display modes live
- m to mirror (pick target with Tab, confirm with Enter)
- s saves to hypr/usr/monitors.lua atomically
- Scale cached and only recomputed on resize or viewport overflow
- Bound to Super+Shift+M as a centered-L floating kitty popup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- caffeine: inhibit only `idle`, not `sleep`, so lid close still locks
- binds: lid-close unconditionally calls hyprlock; lid-open does dpms on
- hypridle: reduce lock timeout from 3 min to 2.5 min (150 s)
- eww (all 3 variants): add caffeine toggle button (☕/) with tooltip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Start chamel as a daemon in autostart so keybinds (toggle/clear/
clear-and-deactivate) work on first use. Fix stale hyprland script
paths in frequentcommands.list and add all utility scripts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add presence-detect.sh daemon: checks webcam every 2 min via OpenCV haar
cascade (presence_detect.py); holds systemd-inhibit --what=idle lock while a
face is detected so hypridle never fires during an active session
- Add enroll-biometrics.sh: Cyberqueer dialog TUI for camera configuration/test
and howdy face auth enrollment (add/list/remove/test models)
- Rewrite caffeine.sh (hyprlua + niri): replace kill/restart of idle daemon with
systemd-inhibit --what=idle:sleep + PID file; idle daemon stays running
- Fix hypridle.conf: correct ;; → ; in after_sleep_cmd, add
ignore_dbus_inhibit=false, bump lock timeout 120s→180s to account for the
2-min presence detection cycle
- Wire Super+Shift+B keybind for enrollment TUI in both hyprlua and niri
- Fix niri/scripts/python: was real dir with inner symlink causing cp -rL to
create a nested python/python/ hierarchy; replaced with direct symlink
- Add python-opencv and v4l-utils to hyprlua + niri installers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wallpaper-picker now calls write_hyprlock_state() on apply, writing
per-monitor background blocks to ~/.config/hypr/hyprlock-backgrounds.conf.
hyprlock.conf sources that file instead of a hardcoded background block,
with a committed default for first-boot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Duplicates desktopenvs/hyprland/ as desktopenvs/hyprlua/ and converts all
Hyprland-specific configs (.conf) to Lua (.lua) using the 0.55+ hl.* API:
hyprland.lua, envvars.lua, monitors.lua, input.lua, autostart.lua,
windowrules.lua, binds.lua. Non-Hyprland tool configs (hyprpaper, hyprlock,
hypridle, hyprtoolkit) remain as .conf. Adds hyprlua.sh installer (user-side
.lua files install to ~/.config/hypr/ for require() resolution) and registers
HyprLua as the recommended DE option in tui-install.sh, marking the old
hyprlang-based Hyprland install as legacy.
Also consolidates hyprland (legacy) env vars into hypr-usr/envvars.conf,
removing duplicates from hyprland.conf and monitors.conf.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>