Dotfiles/desktopenvs/hyprdrive/astro-menu/README.md

61 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# astro-menu
A touch-friendly GTK4 popup control centre for the hyprlua desktop, replacing
`nwg-dock` and `nwg-drawer`. Triggered from the EWW top bar (or `Super+D`).
Layout: a **2×2 quad grid** of feature modules over a full-width **application
drawer**. Any quad can expand to overlay the other three; the drawer can expand to
the bottom of the screen. A single margined root box letterboxes the menu identically
in every state.
## Stack
- **Frontend:** Python + PyGObject + **GTK4**, as a `wlr-layer-shell` surface
(`gtk4-layer-shell`). Chosen over Lua because lgi/Astal-Lua only support GTK3.
- **Location map:** a static OSM image stitched from tiles (`backend/staticmap.py`,
Pillow). libshumate does not paint tiles in this environment (the official
`shumate-demo` shows the same blank map), though tile downloads work — hence the
static fallback.
- **Services:** Astal GObject libraries via introspection — `AstalNetwork`,
`AstalBluetooth`, `AstalApps` — plus our own IP-geolocation singleton.
- **Backends:** Python/Bash scripts in `backend/` (JSON on stdout), run async via
`Gio.Subprocess` so nothing blocks the UI.
- **Theme:** `style/_colors.css` (`@define-color`, generated from
`~/Dotfiles/colors.conf` by `apply-theme.sh`) + `style/style.css`.
## Running
`main.py` is single-instance. The autostart launches a hidden resident daemon;
verbs are forwarded over D-Bus:
scripts/astro-menu-start.sh # resident daemon (hidden); sets LD_PRELOAD
scripts/menu-toggle.sh # --toggle
scripts/menu-toggle.sh appdrawer # open with the app drawer expanded
`astro-menu-start.sh` must `LD_PRELOAD` libgtk4-layer-shell (it loads after
libwayland under PyGObject otherwise).
## Adding a module
1. Create `modules/<name>.py` exposing a top-level `SPEC = ModuleSpec(...)` whose
`build(ctx)` returns a `ModuleInstance(compact=…, expanded=…, …)`.
- `compact` shows in the 2×2 cell; a distinct `expanded` widget enables the
expand button (they must be separate instances — GTK widgets have one parent).
- Declare per-feature toggles via `features=[Feature("id", "Label", default)]`;
read them with `ctx.feature("id")`. A disabled quad never calls `build()`.
- Shared state (network, bluetooth, location) is on `ctx.services`.
2. Append its `SPEC` to `ALL_SPECS` in `registry.py`. Nothing else changes.
## Files
main.py app + single-instance IPC window.py layer-shell + letterbox
registry.py module list (extension seam) settings.py JSON toggles/order
module_base.py ModuleSpec / ModuleInstance / ModuleContext
appservices.py shared Astal services + location
ui/ quadcard, quadgrid, appdrawer
modules/ location, weather, bluetooth, network
services/ location (geolocation singleton)
lib/ ansi (SGR→TextTag), proc (async subprocess)
backend/ geolocate.py, weather.sh, network.sh
style/ _colors.css, style.css