// SPDX-License-Identifier: LGPL-2.1-only // Copyright (C) 2026 Liberux Labs, S. L. //! Theming for ltk-based applications. //! //! A *theme* is a directory on disk holding a `theme.json` and any //! supporting assets (wallpapers, fonts, …). The JSON declares `light` //! and `dark` modes — each with its own slot table plus wallpaper, //! lockscreen, launcher and window-controls blocks — plus a shared //! `fonts` registry. The shell picks which mode is active via //! [`ThemeMode`]. //! //! # On-disk layout //! //! ```text //! /usr/share/ltk/themes// (system overlay, lower priority) //! ~/.local/share/ltk/themes// (user overlay, higher priority) //! theme.json //! background-light.png //! background-dark.png //! fonts/ //! Sora-Regular.ttf //! ``` //! //! Paths inside `theme.json` are interpreted relative to the theme's //! directory and are eagerly resolved to absolute paths at load time. //! //! # Process-wide active state //! //! The active theme is published process-wide so widgets can consult their //! colours without every caller threading the palette through their own //! state. Use [`set_active_document`] / [`set_active_mode`] to change it, //! and [`active_document`] / [`active_mode`] / [`active_theme_id`] to read //! it back. Per-slot shorthand accessors ([`color`], [`paint()`], [`surface()`], //! [`palette()`], …) cover the common patterns without going through the //! full document. //! //! There is **no in-code fallback**: if `ensure_active` cannot locate the //! `default` theme in any search path, the process aborts with a message //! pointing at the `ltk-theme-default` Debian package (it `Provides: //! ltk-theme`) or at the `LTK_THEMES_DIR` environment variable for //! development installations. use std::sync::{ Arc, OnceLock }; // ─── Submodules ────────────────────────────────────────────────────────────── // // Paint / Shadow / Surface / TextStyle are the building blocks of the // slot-typed theme schema; the SlotStore (`slots`) indexes them by id; // the JSON loader (`schema`) parses the on-disk shape. `document` holds // the top-level `ThemeDocument` and per-mode `Mode` types. `fonts` + // `font_registry` cover the typed font references and their // runtime-loaded counterparts. `gradient_lut` is the small CPU helper // the GPU gradient shaders consume. pub mod paint; pub mod shadow; pub mod surface; pub mod text_style; pub mod fonts; pub mod font_registry; pub mod gradient_lut; pub mod slots; pub mod document; pub ( crate ) mod schema; pub ( crate ) mod fallback; pub mod accessors; pub mod active; pub mod assets; pub mod error; pub mod palette; pub mod prefs; pub mod search; pub mod typography; pub use paint::{ ColorStop, GradientSpace, LinearGradient, Paint, RadialGradient }; pub use shadow::{ BlendMode, InsetShadow, Shadow, ShadowsRef }; pub use surface::Surface; pub use text_style::{ FontRef, FontStyle, LineHeight, TextDecoration, TextStyle, TextTransform }; pub use fonts::{ FontFamilyDef, FontSource }; pub use font_registry::{ FontKey, FontLoadError, FontRegistry }; pub use slots::{ Metadata, Slot, SlotStore }; pub use document::{ Mode, ThemeDocument }; pub use accessors::{ color, color_or, paint, palette, resolve_surface, shadows, surface, text_style, window_controls }; pub use active::{ active_document, active_mode, active_theme_id, is_fallback_active, set_active_document, set_active_mode }; pub use assets::{ app_default_icon, app_icon, branding_asset, branding_image, branding_raster, decode_svg_bytes, icon_path, icon_rgba, launcher_icon, lockscreen, logo, logo_horizontal, logo_square, tint_symbolic, wallpaper }; pub use error::ThemeError; pub use palette::Palette; pub use prefs::{ LauncherSpec, ThemeMode, ThemePreference, WallpaperFit, WallpaperSpec, WindowControlsSpec }; pub use search::{ build_font_registry, search_paths }; /// Shared `usvg` font database, lazily populated from the host's system /// fonts. resvg's default `Options::fontdb` is empty, so SVGs containing /// `` would otherwise rasterise with no glyphs at all. pub ( crate ) fn system_fontdb() -> Arc { static DB: OnceLock> = OnceLock::new(); DB.get_or_init( || { let mut db = resvg::usvg::fontdb::Database::new(); db.load_system_fonts(); Arc::new( db ) } ).clone() }