# ABOUTME: Configuration loading from moongreet.toml. # ABOUTME: Parses appearance and behavior settings with wallpaper path resolution. import tomllib from contextlib import AbstractContextManager from dataclasses import dataclass from importlib.resources import as_file, files from pathlib import Path DEFAULT_CONFIG_PATHS = [ Path("/etc/moongreet/moongreet.toml"), ] @dataclass class Config: """Greeter configuration loaded from moongreet.toml.""" background: Path | None = None gtk_theme: str | None = None def load_config(config_path: Path | None = None) -> Config: """Load configuration from a TOML file. Relative paths in the config are resolved against the config file's directory. """ if config_path is None: for path in DEFAULT_CONFIG_PATHS: if path.exists(): config_path = path break if config_path is None: return Config() if not config_path.exists(): return Config() try: with open(config_path, "rb") as f: data = tomllib.load(f) except (tomllib.TOMLDecodeError, OSError): return Config() config = Config() appearance = data.get("appearance", {}) bg = appearance.get("background") if bg: bg_path = Path(bg) if not bg_path.is_absolute(): bg_path = config_path.parent / bg_path config.background = bg_path gtk_theme = appearance.get("gtk-theme") if gtk_theme: config.gtk_theme = gtk_theme return config _PACKAGE_DATA = files("moongreet") / "data" _DEFAULT_WALLPAPER_PATH = _PACKAGE_DATA / "wallpaper.jpg" def resolve_wallpaper_path( config: Config, ) -> tuple[Path, AbstractContextManager | None]: """Resolve the wallpaper path from config or fall back to the package default. Returns (path, context_manager). The context_manager is non-None when a package resource was extracted to a temporary file — the caller must keep it alive and call __exit__ when done. """ if config.background and config.background.exists(): return config.background, None ctx = as_file(_DEFAULT_WALLPAPER_PATH) try: path = ctx.__enter__() except Exception: ctx.__exit__(None, None, None) raise return path, ctx