61 lines
3.0 KiB
Markdown
61 lines
3.0 KiB
Markdown
# 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
|