Application Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:The Steam Online Fix Launcher (SOFL) is a GTK4/LibAdwaita application written in Python, designed to simplify launching and managing games on Linux, with a special focus on those requiring "online-fix" support. The architecture is modular, following modern GNOME Human Interface Guidelines (HIG) and emphasizing asynchronous operations to maintain a responsive user interface.
The core of the application revolves around a central data Store that manages game data, an Importer system for discovering games from various sources (like Steam, Lutris, etc.), and a set of managers for handling specific tasks such as cover art downloads and data persistence. The UI is built using Adwaita components, ensuring a native and modern look and feel within the GNOME desktop environment.
Sources: idea.md, conventions.md, CONTRIBUTING.md
Core Components
The project is structured into several key modules, each with a distinct responsibility. This modular design promotes separation of concerns and maintainability.
Sources: CONTRIBUTING.md:70-78, conventions.md:78-86
This diagram shows the high-level project structure and dependencies between core modules.
Component Breakdown
| Component | Path | Description |
|---|---|---|
| Application Entry Point | sofl/main.py | Initializes the Adw.Application, handles command-line arguments, sets up logging, and orchestrates the main application lifecycle. |
| Main Window | sofl/window.py | (Inferred) The main application window class, responsible for the primary UI layout, including the game library view and navigation. |
| Data Store | sofl/store/ | Manages the state of the application, including the list of games and various data processing managers. |
| Game Importer | sofl/importer/ | Handles the discovery and import of games from various sources like Steam, Lutris, and Heroic. |
| Dialogs | sofl/dialogs/ | Contains UI dialogs for user interactions, such as adding, editing, or installing games. The DetailsDialog is a key component here. |
| Preferences | sofl/preferences.py | Manages the application's settings window, allowing users to configure import sources, API keys, and other options. |
| Game Model | sofl/game.py | (Inferred) Defines the Game data model, encapsulating all properties and methods related to a single game. |
Sources: CONTRIBUTING.md:70-78, sofl/main.py, sofl/preferences.py
Application Startup Flow
The application follows a standard GTK application lifecycle, managed by the SOFLApplication class. The startup process involves initializing services, loading data, creating the UI, and handling initial user actions.
Sources: sofl/main.py:82-202
This sequence diagram illustrates the key steps from application launch to the main window being presented to the user.
Command-Line Handling
The application can be launched with specific command-line arguments to perform actions without showing the main UI.
--launch <GAME_ID>: Directly launches a game by its ID. It reads the game's JSON file, executes the command, and updates thelast_playedtimestamp.--search <TERM>: Opens the application with the search bar activated and pre-filled with the given term.
This logic is handled in the do_handle_local_options method of the SOFLApplication class.
Sources: sofl/main.py:91-103, sofl/main.py:204-232
Data Management and Storage
The Store class is the central hub for all game-related data. It maintains the collection of Game objects and uses a pipeline of "manager" classes to process them.
The Store and Managers
The Store holds a list of games and a dictionary of managers. When a game is added or updated, it passes through a pipeline of active managers. Each manager performs a specific task, such as saving data to a file, fetching cover art, or updating the UI.
Key managers include:
FileManager: Saves game data to individual JSON files.DisplayManager: Manages how games are displayed in the UI.CoverManager: Handles local cover art processing.SgdbManager: Fetches cover art from SteamGridDB.SteamAPIManager: Fetches game details from the Steam API.
Sources: sofl/main.py:133-143
Game Data Persistence
Game data is stored as individual JSON files in a local directory (~/.var/app/org.badkiko.sofl/data/sofl/games/ for Flatpak). Each file is named with the game_id (e.g., steam_440.json). On startup, the FileManager reads all JSON files from this directory to populate the initial game library.
Sources: sofl/main.py:234-242
Game Import System
A core feature of SOFL is its ability to import games from multiple launchers and sources. This is orchestrated by the Importer class and a set of Source subclasses.
Import Flow
The import process is initiated from the UI via the on_import_action.
This flowchart shows the process of importing games, from user action to data persistence.
Import Sources
The application supports a wide range of sources, each implemented as a subclass of Source. Users can enable or disable these sources and configure their specific paths in the SOFLPreferences window.
SteamSourceLutrisSourceHeroicSourceBottlesSourceFlatpakSourceDesktopSourceItchSourceLegendarySourceRetroarchSourceOnlineFixSource
Sources: sofl/main.py:350-379, sofl/preferences.py:215-263
UI and Configuration
The user interface is built with GTK4 and LibAdwaita, providing a modern and responsive experience that integrates well with the GNOME desktop.
Preferences Window
The SOFLPreferences class manages all application settings. It is a multi-page dialog where users can configure:
- General Settings: Behavior like exiting after launch.
- Import Sources: Enable/disable sources (Steam, Lutris, etc.) and specify custom paths.
- Online-Fix: Set the installation path for Online-Fix games and choose a Proton version.
- Proton Manager: Download and manage GE-Proton versions.
- SteamGridDB: Configure the API key for fetching cover art.
Settings are persisted using Gio.Settings against a GSettings schema (org.badkiko.sofl).
Sources: sofl/preferences.py
Details Dialog
The DetailsDialog is used for both adding a new game manually and editing an existing one. It allows the user to modify core game properties like name, developer, and executable path. A key feature is the ability to change a game's type between "Online-Fix Game" and "Regular Game", which modifies its source property and moves it within the data store.
When adding a new game, it generates a unique game_id based on the selected source (e.g., online-fix_1, imported_1).
Sources: sofl/details_dialog.py:219-270, sofl/details_dialog.py:315-329
Build and Packaging
The project uses the Meson build system and provides packaging for multiple formats, ensuring wide compatibility across Linux distributions.
Development Environment
The scripts/dev.sh script is a helper for local development. It automates:
- Setup: Configures Meson in a
builddirwith a local prefix (.local). - Build: Compiles the application using
meson compile. - Install: Installs the application into the local
.localprefix. - Run: Executes the application with the correct environment variables (
GSETTINGS_SCHEMA_DIR,XDG_DATA_DIRS) to find local resources.
Sources: scripts/dev.sh
Packaging
SOFL is packaged for several distribution formats, with Flatpak being the recommended method.
| Format | Configuration File | Key Details |
|---|---|---|
| Flatpak | packaging/flatpak/org.badkiko.sofl.yml | Defines the application ID, runtime (org.gnome.Platform), SDK, and sandbox permissions (filesystem, network, D-Bus). It also lists Python dependencies and external tools like unrar. |
| Debian | packaging/debian/build.sh | A script that uses meson to build and dpkg-deb to package the application into a .deb file. It handles dependencies and post-installation scripts. |
| Arch | packaging/arch/build.sh | A script that likely uses a PKGBUILD to create a package for Arch Linux. |
Sources: packaging/flatpak/org.badkiko.sofl.yml, packaging/debian/build.sh, scripts/build_all.sh
Conclusion
The architecture of SOFL is well-structured and modern, leveraging the strengths of the Python and GNOME ecosystems. Its modular design, centered around a Store and Manager pipeline, allows for easy extension with new features and import sources. The clear separation between the data layer, UI, and build system makes the codebase maintainable and developer-friendly. The use of standard tools like Meson and GSettings, combined with comprehensive packaging scripts, ensures a robust development and distribution process.