#!/usr/bin/env python3 """astal-menu — a touch-friendly GTK4 popup control centre (Location, Weather, Bluetooth, Network) plus an application drawer, replacing nwg-dock/nwg-drawer. Single-instance: the first launch builds the (hidden) window and holds. Later invocations forward their arguments to it over D-Bus, so `main.py --toggle` toggles the running instance without spawning a new process. main.py run the resident instance (stays hidden until toggled) main.py --toggle toggle visibility main.py --show show | --hide hide | --appdrawer show with drawer open """ from __future__ import annotations import sys from pathlib import Path # Make sibling modules importable no matter the CWD. sys.path.insert(0, str(Path(__file__).resolve().parent)) import gi # noqa: E402 gi.require_version("Gtk", "4.0") from gi.repository import Gio, GLib, Gtk # noqa: E402 import theme # noqa: E402 from appservices import Services # noqa: E402 from paths import APP_ID, ensure_dirs # noqa: E402 from settings import Settings # noqa: E402 from window import MenuWindow # noqa: E402 class AstalMenuApp(Gtk.Application): def __init__(self) -> None: super().__init__(application_id=APP_ID, flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) self.window: MenuWindow | None = None def do_startup(self) -> None: Gtk.Application.do_startup(self) ensure_dirs() theme.load_css() settings = Settings() services = Services() self.window = MenuWindow(self, settings, services) self.hold() # stay alive with no visible window def do_command_line(self, cmdline: Gio.ApplicationCommandLine) -> int: args = cmdline.get_arguments()[1:] # No args = start (or keep) the resident instance hidden. Only explicit # verbs change visibility, so the autostart launch never pops the menu. action = args[0] if args else "--daemon" if self.window is None: return 0 if action == "--show": self.window.show_menu() elif action == "--hide": self.window.hide_menu() elif action == "--appdrawer": self.window.show_menu(focus_appdrawer=True) elif action == "--toggle": self.window.toggle() # --daemon and anything else: no-op (stay as-is) return 0 def do_activate(self) -> None: # Resident instance: nothing to do on plain activate. pass def main() -> int: GLib.set_prgname("astal-menu") return AstalMenuApp().run(sys.argv) if __name__ == "__main__": raise SystemExit(main())