This guide is the contributor-oriented companion to the user-facing documents in docs/.
It describes how FairWindSK works as a Qt6 application shell for Signal K, how data moves through the runtime, how the GUI is organized, and how to think about cross-platform and touch-friendly development decisions.
Use this guide when you need to:
- understand where a feature belongs before editing code
- trace a value from configuration or Signal K into the visible UI
- add or refactor reusable touch-oriented widgets
- change the shell behavior without breaking marine electronics usability expectations
- prepare changes that must compile across desktop and mobile targets
FairWindSK active work happens on the development branch.
Before you begin coding, switch to it and update your local checkout:
git checkout development
git pullIf you are creating a feature branch, create it from the updated development branch rather than from main or an older local branch.
FairWindSK is a C++17 and Qt6 application designed to host Signal K web applications inside a native shell that is optimized for leisure-boat and helm-adjacent usage. The project sits at the intersection of:
- a native Qt widget shell
- embedded web applications and desktop-local applications
- Signal K REST and websocket data streams
- marine-operation bars such as POB, autopilot, anchor, and alarms
- a configurable comfort-preset system for daypart-aware visibility
The application is intentionally opinionated toward marine multi-functional display (MFD) behavior:
- persistent top and bottom shell bars
- stable spatial layout
- high-contrast comfort presets
- finger-friendly controls
- low-friction modal workflows through the bottom drawer
The most important directories and files are:
| Area | Main files | Responsibility |
|---|---|---|
| Bootstrap | main.cpp |
Qt startup, platform bootstrap, splash behavior, deferred runtime startup |
| Core runtime | FairWindSK.cpp, FairWindSK.hpp |
Singleton orchestration, configuration, Signal K lifecycle, app registry, runtime reconfiguration |
| Configuration | Configuration.cpp, Configuration.hpp |
Persistent JSON and QSettings backed preferences and tokens |
| Signal K client | signalk/Client.cpp, signalk/Client.hpp |
Discovery, REST access, websocket stream, reconnect and resubscribe logic |
| Main shell | ui/MainWindow.* |
Main window composition, overlays, bottom drawer hosting |
| Top shell | ui/topbar/TopBar.* |
Global data widgets, title, time, status surface |
| Bottom shell | ui/bottombar/BottomBar.* and bar widgets |
Main navigation, app shortcuts, vessel-operation entry points |
| Settings | ui/settings/* |
Configuration UI including Comfort, Apps, Connection, Units, System, Signal K |
| MyData | ui/mydata/* |
Files, waypoints, history tracks, resources, previews |
| Web integration | ui/web/* |
Desktop WebEngine path and mobile WebView facade |
| Touch widgets | ui/widgets/* |
Reusable touch-oriented controls and pickers |
| Shared dialog hosting | ui/DrawerDialogHost.* |
Native bottom drawer dialog APIs |
| Resources | resources.qrc, resources/stylesheets/*, resources/svg/*, resources/json/* |
Themes, icons, defaults, configuration seeds |
FairWindSK is best understood as five cooperating layers:
- Platform bootstrap layer
main.cppconfigures Qt attributes, Linux runtime fallbacks, splash handling, desktop WebEngine or mobile WebView initialization, and deferred startup sequencing. - Runtime orchestration layer
FairWindSKowns the configuration, Signal K client, app registry, runtime reconfiguration, comfort preset application, and shared web profile handle. The desktop WebEngine profile must use a stable storage/cache path andForcePersistentCookiesso Signal K, Freeboard-SK, and hosted apps keep session login state across FairWindSK restarts. - Data access layer
Configurationandsignalk::Clientprovide persistent preferences and live vessel/server data. - Shell and navigation layer
MainWindow,TopBar,BottomBar, andLauncherdefine the persistent FairWindSK chrome and page transitions. - Feature/UI layer Settings pages, MyData pages, native bar panels, and reusable touch widgets implement specific workflows.
FairWindSK is the central application service object.
This keeps cross-cutting concerns in one place:
- configuration loading and saving
- current comfort preset resolution
- runtime UI refresh triggers
- app discovery and registry maintenance
- access to the shared
signalk::Client - access to the shared desktop
QWebEngineProfilewhen available
This design means most UI features should ask first:
- Is this state persistent? Then it probably belongs in
Configuration. - Is this state derived from server connectivity or app discovery? Then it probably belongs in
FairWindSKorsignalk::Client. - Is this state local to a page or widget? Then it should stay in the page/widget unless it truly becomes shared runtime behavior.
At startup, the main path is:
main.cppcreatesQApplication.FairWindSK::getInstance()creates the singleton.FairWindSK::loadConfig()loadsfairwindsk.jsonand supportingQSettings.MainWindowis constructed and the shell widgets are created.- A deferred startup task calls:
FairWindSK::startSignalK()FairWindSK::loadApps()MainWindow::applyRuntimeConfiguration()MainWindow::prewarmPersistentPagesAfterStartup()
- The event loop continues with the live websocket and native/widget/web content running together.
Most runtime values follow one of these paths:
Configuration -> FairWindSK::applyUiPreferences() / reconfigureRuntime() -> shell/pages/widgets -> visible UI
Examples:
- comfort presets and generated stylesheets
- app activation and ordering
- units and view preferences
- saved file paths and theme image paths
Signal K server -> signalk::Client websocket or REST -> native widget/page model -> visible UI
Examples:
- top bar data widgets
- bottom bar operational panel data
- reconnect-sensitive MyData resources
- unit preferences synchronized from the server
Signal K apps API plus local configuration -> FairWindSK::loadApps() -> AppItem registry -> launcher and navigation shortcuts
Examples:
- launcher tile set
- open app shortcuts in the Bottom Bar
- application details in Settings
main.cpp configures process-wide behavior before showing the main shell:
- organization and application names
- diagnostics support
- shared OpenGL contexts
- Linux environment fallbacks for runtime directory and Qt platform plugins
- single main-window startup
- desktop WebEngine or mobile WebView backend initialization
The singleton loads configuration and establishes the baseline runtime state. This includes:
- JSON-backed application configuration
- token storage via
QSettings - initial comfort view and runtime preferences
MainWindow creates and wires:
TopBarLauncherBottomBar- persistent overlay pages such as
Settings,MyData, andAboutwhen needed - the bottom horizontal drawer infrastructure
Deferred startup avoids blocking shell construction with server work. The runtime then:
- connects to Signal K
- configures web profile state
- loads or refreshes apps
- prewarms persistent pages
- applies runtime configuration to the shell
During normal operation, the application simultaneously handles:
- websocket updates
- REST refreshes
- web app hosting
- drawer dialogs
- comfort preset changes
- reconnect recovery after Signal K restarts
The runtime supports targeted reconfiguration through FairWindSK::reconfigureRuntime(...).
Use the runtime flags in FairWindSK.hpp when a settings change should refresh only specific domains:
RuntimeUiRuntimeUnitsRuntimeSignalKConnectionRuntimeAppsRuntimeSignalKPaths
Signal K recovery is also lifecycle-aware:
- disconnect triggers reconnect attempts
- rediscovery refreshes endpoints
- subscriptions are re-sent
- exact-path values are hydrated again
- REST-backed models can reload after reconnect
Shutdown is mostly standard Qt shutdown, with diagnostics support notified through aboutToQuit.
The formal shell vocabulary is defined in docs/ui_shell.md.
Contributor work should keep using those names consistently.
- Top Bar Global information, current app identity, time, status icons, and data widgets.
- Application Area The primary working surface for launcher, settings, MyData, and hosted applications.
- Bottom Bar Persistent navigation surface for app shortcuts, core native features, and Signal K server status.
- Bottom Bar horizontal drawer Modal upward-opening dialog host for touch-friendly workflows.
- Application Area vertical drawer Contextual, typically non-modal drawer for app-specific tools.
ui/MainWindow.* coordinates:
- shell composition
- overlay page switching
- active foreground application changes
- dialog drawer execution and completion
- top-bar synchronization
- prewarming of persistent pages
ui/settings/Settings groups the major configuration surfaces:
MainTop BarBottom BarWidgetsComfortConnectionSignalKUnitsAppsSystem
The Comfort page is especially important because it now drives the active UI immediately and is intended to be the single source of truth for configurable UI colors and theme assets.
ui/mydata contains a native data-management suite:
- file browser and viewer
- waypoint and resource management
- history tracks
- preview widgets for geo and JSON resources
This area is important because it exercises both:
- touch-native widgets
- server-backed resource synchronization
FairWindSK should behave like a marine electronics interface first and a desktop utility second. That affects layout, motion, density, and interaction patterns.
- Large hit targets Controls should be comfortably tappable with wet or gloved fingers on compact displays.
- High contrast Text, icons, and active states must remain readable at helm distance and across comfort presets.
- Spatial stability Frequently used controls should not drift, reorder unexpectedly, or collapse into dense clusters.
- Shallow interaction depth Common actions should require as few steps as practical.
- Predictable modal behavior Modal flows should use the bottom drawer consistently, avoiding surprise popups or floating desktop-style dialogs.
- Prefer
QToolButton,QPushButton, and custom touch widgets with clear pressed and selected states. - Avoid tiny list affordances or low-contrast borders.
- Keep the Top Bar and Bottom Bar visible and uncovered.
- Fit drawer content into the available area between the Top Bar and Bottom Bar.
- Use iconography and labels together for critical navigation when possible.
- Keep comfort preset theming coherent across all reusable shell widgets.
The reusable widgets in ui/widgets/ are the primary toolkit for touch-safe workflows.
| Widget | Role |
|---|---|
TouchComboBox |
Touch-friendly preset and option selection |
TouchCheckBox |
Large-state boolean selection |
TouchSpinBox |
Finger-friendly numeric adjustment |
TouchScrollArea |
Scroll container aligned with FairWindSK chrome behavior |
TouchFileBrowser |
Reusable file selection surface designed for the bottom drawer |
TouchIconBrowser |
Icon-selection surface with touch-oriented browsing |
TouchColorPicker |
Color selection surface aligned with drawer-host constraints |
SignalKServerBox |
Reusable server-status surface in the shell |
ui/DrawerDialogHost.* provides FairWindSK-native dialog entry points such as:
- file open/save
- icon browsing
- text entry
- log exploration
- geo coordinate editing
- message dialogs
This layer exists so the application can avoid desktop-default dialogs that do not fit the marine shell model.
When adding a new shared touch widget:
- Design it to fit in the Bottom Bar horizontal drawer if it is modal.
- Keep all colors derived from the Comfort system instead of hardcoded literals.
- Make state changes visible through touch-friendly contrast and spacing.
- Handle platform-neutral sizing first, then document any platform limitation explicitly.
- Prefer layout strategies that avoid vertical scrolling in the drawer when possible.
The comfort system is both a user feature and a core architecture concern. It affects nearly every visible Qt-based shell surface.
- Base preset stylesheets live in
resources/stylesheets/*.qss - Runtime overrides are generated from
ui/settings/Comfort.cpp - Persisted user customizations live in
Configuration
- New visible UI colors should map to comfort preset items.
- Avoid introducing hardcoded colors in shared shell widgets.
- If a widget must derive a computed color, derive it from a comfort-provided semantic color.
- Update shipped
.qssfiles when a new reusable state becomes part of the common shell language.
FairWindSK uses a unified higher-level web-hosting API with two implementation paths:
- Desktop Qt WebEngine Widgets
- Android and iOS
Qt WebView hosted inside
QQuickWidgetcontainers
This split is important because contributor changes should usually target the shared UI contract rather than assuming a single backend.
Desktop builds keep features such as:
QWebEngineProfile- richer shared cookie handling
QHotkey- drawer-hosted download handling and single-window web popups
Mobile builds use the alternate Qt::WebView path and therefore intentionally avoid desktop-specific WebEngine hooks.
When documenting or implementing behavior, call this out explicitly instead of implying identical capabilities.
FairWindSK has one codebase and multiple build/runtime targets.
- Desktop-feature-complete path
- Qt WebEngine Widgets backend
- supports normal desktop and kiosk-like deployments
- Linux startup logic includes runtime directory, Qt platform, and graphics fallbacks
- follows the Linux desktop path
- important target for helm-adjacent touch screens
- kiosk and autostart helpers live in
extras/ - installation now also includes Raspberry Pi OS specific desktop integration: the startup helper is installed into the system autostart path and OpenPlotter-aware menu integration is attempted when OpenPlotter is detected on the target system
- interaction density and rendering performance matter more here than on a desktop workstation
- full desktop feature set
- app bundle output from CMake
- desktop WebEngine path
- full desktop feature set
- standard
windeployqtdeployment flow after building - desktop-local apps remain relevant here
- mobile-safe web backend through
Qt::WebView - surrounding shell remains widget-based
- no desktop-only hotkey/Zeroconf/WebEngine-only integrations
- same architectural split as Android
Qt::WebViewbackend- desktop-specific integrations remain disabled
For any non-trivial change, review impact in these dimensions:
| Concern | Questions |
|---|---|
| Build split | Does this rely on desktop-only Qt modules or APIs? |
| Web backend | Does this assume QWebEngineView when mobile uses Qt::WebView? |
| Touch behavior | Is the control comfortably usable on Raspberry Pi touch displays and tablets? |
| Drawer behavior | Does modal content fit between the Top Bar and Bottom Bar? |
| Comfort presets | Are colors and states mapped through the Comfort system? |
| Operational clarity | Would this still be readable and stable in rough-use marine conditions? |
If a platform is not fully supported by the change, document the limitation clearly.
- Add persistent state to
Configuration. - Expose the option in the relevant
ui/settings/*page. - Route runtime consequences through
FairWindSK::reconfigureRuntime(...)where needed. - If the setting changes visible shell/UI behavior, ensure it updates live when practical.
- Decide whether the interaction belongs in the Bottom Bar horizontal drawer.
- Create or reuse a touch widget in
ui/widgets/. - Expose it through
ui/DrawerDialogHost.*if it is intended to be reusable. - Verify the content fits between the Top Bar and Bottom Bar.
- Add a semantic color or state in
ui/settings/Comfort.cpp. - Persist it through
Configuration. - Update the preset
.qssfiles. - Replace any local hardcoded colors in the affected widgets.
README.mddocs/building.mddocs/architecture.mddocs/ui_shell.mddocs/developing_guide.mdmain.cppFairWindSK.cppui/MainWindow.*- the specific feature area you plan to edit
Contributors should keep these current realities in mind:
- The runtime is singleton-centered, which simplifies access but can make hidden coupling easier to introduce.
- The shell is strongly widget-based even on mobile, with a bridged web layer rather than a full QML rewrite.
- Some custom-rendered or embedded-web surfaces may still require extra work to stay fully aligned with Comfort semantics.
- Desktop and mobile web backends share interfaces, but they do not have identical capabilities.
FairWindSK is a Qt-native marine shell around Signal K and related boat applications. Successful contributions usually respect four principles at the same time:
- keep the runtime flow coherent through
FairWindSK,Configuration, andsignalk::Client - preserve the shell vocabulary and drawer behaviors
- maintain touch-friendly, MFD-consistent interaction design
- keep features honest about desktop versus mobile differences