Theme Engine
Relevant source files
The following files were used as context for generating this wiki page:
The Theme Engine is a core subsystem of FlxOS responsible for managing the visual appearance of the user interface. It leverages the LVGL 9 styling system to provide dynamic switching between different visual themes, such as Material and Hyprland, while supporting both light and dark modes. The engine is decoupled from the hardware layer, allowing the system to run in a headless mode without loading UI-related assets.
This module works in conjunction with the ThemeManager, which handles the persistence of theme settings via the SettingsManager and bridges these settings to the LVGL environment. The Theme Engine ensures that style changes are propagated throughout the UI tree and manages the lifecycle of theme objects to prevent memory leaks during transitions.
Architecture and Data Flow
The architecture consists of a high-level manager (ThemeManager) that interacts with system settings and a low-level engine (ThemeEngine) that manipulates LVGL theme objects. The data flow typically originates from a user interaction (e.g., in the Settings App) or a system event, which updates a "subject" that the ThemeManager observes.
The diagram shows the flow from settings persistence to the final style application on UI components.
Sources: ThemeManager.cpp:18-24, ThemeEngine.cpp:78-105
Key Components
| Component | Description |
|---|---|
| ThemeManager | A singleton namespace class that manages theme-related settings (glass effects, transparency, wallpaper) and bridges them to the GUI. |
| ThemeEngine | The functional core that applies ThemeConfig to the default display and manages the hierarchy of LVGL themes. |
| Themes Namespace | Contains the definitions for specific themes (Material, Hyprland) and their associated color palettes. |
| LvglObserverBridge | A utility used by ThemeManager to synchronize system subjects with LVGL subjects. |
Sources: ThemeManager.cpp:11-16, ThemeEngine.cpp:21-23, Themes.cpp:12-14
Theme Management Logic
Initialization and Application
During system startup, the ThemeEngine::init() function retrieves the default display and applies the current theme. The ThemeManager registers several settings subjects with the SettingsManager, including the theme type, glass effect toggle, and wallpaper path.
This sequence illustrates the initialization flow of the theme system.
Sources: ThemeManager.cpp:18-24, ThemeEngine.cpp:26-33, ThemeEngine.cpp:103
Theme Hierarchy and Stacking
The engine applies themes using a tiered approach. It initializes a base default theme and then creates custom themes that inherit from it.
- Base Theme: Initialized via
lv_theme_default_initusing primary/secondary colors and dark mode flags. - Global Theme: A custom theme created with
lv_theme_createthat sets the base theme as its parent and applies global callbacks likeThemes::ApplyGlobal. - Specific Theme: If the configuration contains a specific
apply_cb, an additional layer is added to the stack.
Sources: ThemeEngine.cpp:86-101, Themes.cpp:55-62
Theme Definitions
FlxOS currently defines two primary theme types: Material and Hyprland. These are defined in the Themes namespace, providing specific color palettes and behavioral flags.
Theme Configurations
| Theme Type | Primary Palette | Secondary Palette | Dark Mode | Surface Color |
|---|---|---|---|---|
MATERIAL | Indigo | Amber | No | White |
HYPRLAND | Cyan | Pink | Yes | Grey (Darken 4) |
Sources: Themes.cpp:15-38
Global Application Callbacks
The Themes::ApplyGlobal callback is used to perform specific logic when a theme is applied to an object. For example, it automatically registers lv_textarea objects with the VirtualKeyboard instance when they are styled.
void Themes::ApplyGlobal(lv_theme_t* th, lv_obj_t* obj) {
LV_UNUSED(th);
if (lv_obj_check_type(obj, &lv_textarea_class)) {
Log::debug(TAG, "Registering textarea for virtual keyboard");
VirtualKeyboard::getInstance().register_input_area(obj);
}
}
Sources: Themes.cpp:55-62
Headless Mode Considerations
The theme engine is conditionally compiled based on the CONFIG_FLXOS_HEADLESS_MODE flag. In the main/CMakeLists.txt, UI-related files (including ThemeEngine.cpp and Themes.cpp) are excluded from the build if headless mode is enabled. This reduces binary size and memory usage for devices acting strictly as backend services.
Sources: CMakeLists.txt:45-66, ThemeManager.cpp:31-48
Memory Management
The ThemeEngine tracks active themes per display using a static map: std::map<lv_display_t*, std::vector<lv_theme_t*>> engine_themes. When a new theme is applied, the cleanup_previous_theme function is called to delete old theme objects (excluding the LVGL default theme) and clear the vector to prevent memory leaks.
Sources: ThemeEngine.cpp:24, ThemeEngine.cpp:66-76
Summary
The Theme Engine provides a structured way to manage the visual identity of FlxOS. By separating configuration (Themes namespace), state management (ThemeManager), and implementation (ThemeEngine), the system achieves a flexible UI that can adapt to user preferences or hardware constraints like headless operation. Its integration with LVGL's observer pattern ensures that theme changes are reactive and efficient.