Architecture
This page describes Tsumiki’s internal architecture — useful for contributors, custom widget authors, and anyone extending the project.
Project Structure
Section titled “Project Structure”tsumiki/├── main.py # Application entry point├── config.toml # User configuration├── tsumiki.schema.json # JSON Schema for validation├── init.sh # Setup/start utilities├── install.sh # Bootstrap installer├── themes/ # Theme .toml files│ ├── catpuccin-mocha.toml│ ├── gruvbox.toml│ └── ...├── styles/ # SCSS stylesheets│ ├── main.scss # Entry point — imports everything│ ├── _theme.scss # Generated theme variables│ ├── _settings.scss # Generated config variables│ ├── _variable.scss # Shared variable definitions│ ├── _workspace.scss # Per-widget styles│ └── common/ # Shared mixins & functions├── widgets/ # Bar widgets (panel elements)│ ├── workspaces.py│ ├── battery.py│ └── ... # ~45 widgets total├── modules/ # Standalone overlays & windows│ ├── bar.py # Bar window│ ├── dock.py # Dock│ ├── notification.py # Notification system│ ├── overview.py # Workspace overview│ └── ...├── services/ # Background services│ ├── battery.py # UPower D-Bus monitoring│ ├── network.py # NetworkManager D-Bus│ ├── matugen.py # Material You color generation│ ├── mpris.py # Media player control│ └── ...├── shared/ # Reusable UI components│ ├── widget_container.py # Base widget class│ ├── buttons.py # Reusable button types│ ├── popup.py # Popup window helper│ ├── popover.py # Popover menu helper│ └── ...├── utils/ # Utility modules│ ├── config.py # Config loading & parsing│ ├── constants.py # Default values & paths│ ├── widget_settings.py # TypedDict definitions│ ├── functions.py # Shared helper functions│ └── ...└── assets/ # Static assets ├── icons/ # Icon files ├── sounds/ # Notification sounds ├── i18n/ # Internationalization └── matugen/ # Matugen config templateArchitecture Overview
Section titled “Architecture Overview”┌─────────────────────────────────────────────────────┐│ main.py ││ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ ││ │ Config │ │ CSS │ │ Module Init │ ││ │ Loader │──│ Compiler │──│ (dock, overview, │ ││ │ │ │ (sass) │ │ notifications) │ ││ └──────────┘ └──────────┘ └───────────────────┘ │└──────────────────────┬──────────────────────────────┘ │ ┌────────────────┼────────────────┐ ▼ ▼ ▼┌──────────┐ ┌──────────┐ ┌──────────┐│ Services │ │ Widgets │ │ Modules ││ (DBus, │───▶│ (Panel │───▶│ (Overlay ││ polling)│ │ buttons)│ │ windows)│└──────────┘ └──────────┘ └──────────┘Key Design Patterns
Section titled “Key Design Patterns”Signal-Driven Updates
Section titled “Signal-Driven Updates”Most widgets update via signals (GTK or custom Service signals) rather than polling:
# Service emits signal on state changeself.battery_service.connect("changed", self._on_battery_changed)This keeps CPU usage low — widgets only update when their data changes.
Singleton Services
Section titled “Singleton Services”Services are singletons initialized at startup:
from services.base import SingletonService
class BatteryService(SingletonService): # Single instance shared across all widgets pass
battery_service = BatteryService()Widget Lifecycle
Section titled “Widget Lifecycle”Every widget in the bar follows this lifecycle:
- Instantiation —
__init__reads config, sets up UI - Connection — connects to service signals
- Update — reacts to data changes via signal handlers
- Cleanup — disconnects signals and stops timers on destroy
Popover Pattern
Section titled “Popover Pattern”Widgets with popover menus use the PopoverMixin:
from shared.mixins import PopoverMixinfrom shared.widget_container import ButtonWidget
class MyWidget(ButtonWidget, PopoverMixin): def __init__(self, **kwargs): super().__init__(name="my_widget", **kwargs) self.setup_popover(lambda: MyPopoverContent(parent=self))Services Reference
Section titled “Services Reference”| Service | File | Source | Description |
|---|---|---|---|
| Battery | services/battery.py |
UPower D-Bus | Battery level, charging state |
| Network | services/network.py |
NetworkManager D-Bus | WiFi, Ethernet, signal strength |
| Brightness | services/brightness.py |
brightnessctl | Screen/keyboard brightness |
| Weather | services/weather.py |
Open-Meteo / wttr.in | Weather conditions, forecast |
| MPRIS | services/mpris.py |
Playerctl D-Bus | Media playback, track info |
| Screen Record | services/screen_record.py |
wf-recorder, grimblast | Recording, screenshots |
| Matugen | services/matugen.py |
matugen binary | Material You palette generation |
| Privacy | services/privacy.py |
PipeWire, procfs | Mic/camera/screen usage detection |
| Network Speed | services/networkspeed.py |
/proc/net | Real-time bandwidth monitoring |
| Quotes | services/quotes.py |
External API | Inspirational quotes |
| Custom Notification | services/custom_notification.py |
— | Programmatic notification API |
Shared Components
Section titled “Shared Components”| Component | File | Purpose |
|---|---|---|
ButtonWidget |
shared/widget_container.py |
Base class for all panel button widgets |
PopoverMixin |
shared/mixins.py |
Mixin for popover/show-hide behavior |
AnimatedScale |
shared/animated/scale.py |
Animated slider scale |
CircularProgress |
shared/animated/circularprogress.py |
Circular progress ring widget |
ButtonToggle |
shared/button_toggle.py |
Toggle button with on/off icons |
CollapsibleGroup |
shared/collapsible_group.py |
Collapsible widget group container |
MediaPlayer |
shared/media.py |
Reusable MPRIS media player UI |
Submenu |
shared/submenu.py |
Slide-in submenu panel |
TagEntry |
shared/tagentry.py |
Tag/chip input field |
LottieAnimation |
shared/lottie.py |
Lottie/rlottie animation player |
Adding a New Widget
Section titled “Adding a New Widget”- Create
widgets/my_widget.pyextendingButtonWidget(and optionallyPopoverMixin) - Add configuration TypedDict in
utils/widget_settings.py - Add default config in
utils/constants.py - Add schema entry in
tsumiki.schema.json - Register in
modules/bar.pywidget map - Add SCSS styles in
styles/_my_widget.scss - Reference in layout:
left_section = ["my_widget"]
Adding a New Module
Section titled “Adding a New Module”- Create
modules/my_module.pyas a GTK Window - Add config under
[modules.my_module] - Initialize in
main.py - Add schema entry in
tsumiki.schema.json - Add SCSS styles
Validation & Schema
Section titled “Validation & Schema”Config validation happens at startup through tsumiki.schema.json:
from utils.validation import validate_config_enums
validate_config_enums(config_data, "tsumiki.schema.json")The schema validates:
- Enum values (e.g., workspace style, widget mode)
- Type correctness
- Required fields
Widget references in layout sections are also validated — unknown widget names raise clear errors.