-
-
Notifications
You must be signed in to change notification settings - Fork 60
IPC
Sucrose's separate Windows processes coordinate through four distinct mechanisms that fall into two categories. The first category is live-data channels — three functionally interchangeable transports (Pipe, Signal, Transmission) that push live system/audio data from Backgroundog to the running web engine, plus a tray-control channel that lets the Portal and Backgroundog drive the Launcher's tray icon. The second category is the command bus — the one-shot, process-launch string protocol handled by Sucrose.Commandog, described separately on the Commandog Dispatcher and Command Reference pages. This page is the developer reference for the live-data channels: the exact pipe/signal/port names, the shared payload schema, and the end-to-end flow.
flowchart LR
BG["Sucrose.Backgroundog<br/>Specification.Start()"]
BG -->|PipeRequired| Pipe["Named Pipe<br/>...Backgroundog.Pipe"]
BG -->|SignalRequired| Signal["Signal file<br/>Backgroundog-<guid>.sgnl"]
BG -->|TransmissionRequired| Trans["TCP loopback<br/>127.0.0.1 : TransmissionPort"]
Pipe --> Eng
Signal --> Eng
Trans --> Eng
Eng["WebView / CefSharp engine<br/>Web.StartCompatible()"] --> Exec["ExecuteScriptAsync"]
Exec --> JS["Wallpaper JavaScript<br/>audio + system API"]
Prod2["Portal / Backgroundog"] -->|"Launcher flags: Show / Hide / Icon / Release"| Sig2["Signal: Launcher.sgnl"]
Sig2 --> Launcher2["Launcher<br/>TrayIconManager"]
- Two categories of IPC
- The shared message payloads
- Transport A — Named Pipe
- Transport B — Signal (filesystem)
- Transport C — Transmission (TCP loopback)
- Transport selection: CommunicationType
- End-to-end live-data flow
- Tray-control flow
- Gotchas
- See also
| Concern | Mechanism | Direction | Default |
|---|---|---|---|
| Push live system + audio data to the running engine | Pipe or Signal or Transmission (user-selectable) | Backgroundog (producer) → Engine (consumer) |
Transmission is the default CommunicationType
|
| Control the Launcher tray icon (show/hide/release/icon) | Signal / Pipe / Transmission (Launcher interface) |
Portal / Backgroundog (producer) → Launcher (consumer) | Launcher listens on Signal |
| Fire-and-forget commands (set/restart wallpaper, kill, import/export, open Portal, scheduler, etc.) | Command bus (CommandType, string args via process args) |
Any process → target .exe (often Commandog) |
n/a (launch-based) |
The three live-data transports are functionally interchangeable and carry the same payload object. The active transport is chosen by the CommunicationType setting. Both CommunicationType and CommandType enums are internal.
The Backgroundog data channel is web-engine-only — it is compiled under
#if LIVE_WEBVIEW || LIVE_CEFSHARP. MpvPlayer, Aurora, Nebula, Vexana, and Xavier do not consume this data channel.
Source libraries: Sucrose.Pipe, Sucrose.Signal, Sucrose.Transmission (under src/Library/); the decoding handler services live in Sucrose.Shared.Pipe, Sucrose.Shared.Signal, Sucrose.Shared.Transmission (under src/Shared/).
Every transport defines identical Interface/Backgroundog.cs and Interface/Launcher.cs classes (one copy per library; the namespaces differ but the shapes are identical). They are JSON-serialized with Newtonsoft.Json, TypeNameHandling = None, Formatting = None — plain JSON text, one message per line.
Ten nullable Newtonsoft.Json.Linq.JObject properties:
Bios, Date, Audio, Memory, Battery, Graphic, Network, Storage, Processor, Motherboard
On receipt, each non-null sub-object is re-serialized with Formatting.Indented and stored into the engine's static Sucrose.Shared.Engine.Manage.Internal fields: BiosData, DateData, AudioData, MemoryData, BatteryData, GraphicData, NetworkData, StorageData, ProcessorData, MotherboardData (all JSON strings). The Audio field is the audio-reactive data — the audio-visualization channel for Web wallpapers. For the inner field schema of each section, see Create System API and Create Audio API.
Four bool flags, all default false:
Hide, Icon, Show, Release
The handler (LauncherSignalService / LauncherPipeService / LauncherTransmissionService) maps them to SSLMI.TrayIconManager:
| Flag | Effect |
|---|---|
Hide |
TrayIconManager.Hide() |
Show |
TrayIconManager.Show() |
Release |
TrayIconManager.Release() |
Icon (always evaluated) |
TrayIconManager.Icon(Data.Icon) |
Pipe names (exact), defined in Sucrose.Pipe.Manage.Internal:
LauncherManager = new PipeT("Sucrose.Wallpaper.Engine.Launcher.Pipe");
BackgroundogManager = new PipeT("Sucrose.Wallpaper.Engine.Backgroundog.Pipe");-
Server name / host:
Sucrose.Memory.Manage.Readonly.General.PipeServerName = "."(the local machine). -
Server (
PipeServer.cs):NamedPipeServerStream(pipeName, PipeDirection.In, 10, PipeTransmissionMode.Byte, PipeOptions.Asynchronous)— max 10 server instances. Reads line-by-line; each line raisesMessageReceivedwithMessageReceivedEventArgs { Message }. Accept timeout 5 s, read timeout 15 s; on error it recreates the pipe with a 1 s backoff. -
Client (
PipeClient.cs):NamedPipeClientStream(".", pipeName, PipeDirection.Out, PipeOptions.Asynchronous), connect timeout 5 s; writes one line per message withAutoFlush = true, guarded by aSemaphoreSlim(1,1). -
PipeTfacade:StartClient(),StartClient(string Message),StartServer(),StopClient(),StopServer(),DisposeClient(),DisposeServer(),event MessageReceived.StartClientWithRetryuses exponential backoff (2^iseconds, default 3 retries).
The pipe is half-duplex / one-way here (producer = client/Out, engine = server/In); there is no reply channel. Transmission mode is Byte, but messages are newline-delimited JSON text. When this transport is active the engine sets setting PipeRequired = true.
The simplest, most robust transport: write a JSON file, watch a folder. Channel file names (exact), defined in Sucrose.Signal.Manage.Internal:
LauncherManager = new SignalT("Launcher.sgnl");
BackgroundogManager = new SignalT("Backgroundog.sgnl");-
Directory:
SignalT.Source=%AppData%\Sucrose\Cache\SignalT. -
Write (
FileSave<T>): serialize (TypeNameHandling = None,Formatting = None) to a unique file"{nameWithoutExt}-{Guid.NewGuid()}{ext}", e.g.Backgroundog-<guid>.sgnl. The write (Helper/Writer.cs) uses a cross-process namedMutex"SignalWriter_{fileName}", 5 s timeout, 3 retries (100 ms apart),FileShare.None. -
Watch (
StartChannel(FileSystemEventHandler)): aFileSystemWatcheronSource,Filter = "*.*",InternalBufferSize = 64 KB,NotifyFilter = LastWrite | FileName | DirectoryName. OnCreated, files whose name contains the channel base name fire the handler. On startup it deletes old matching files; it handlesInternalBufferOverflowExceptionby togglingEnableRaisingEvents. -
Read (
FileRead<T>): a small random 5–50 ms delay to reduce contention, then deserialize viaHelper/Reader.cswith namedMutex"SignalReader_{fileName}", 5 s timeout, 3 retries,FileShare.Read. IfDeleteis true, deletion is scheduled on a 3 s timer; corrupt JSON also triggers deletion. -
Delete (
Helper/Deleter.cs): set attributes toNormal, delete, 3 retries with 50–200 ms random backoff, swallow failures.
The .sgnl extension is the signal marker. This is the only transport the Launcher actually uses for tray control (App.xaml.cs → LauncherManager.StartChannel). When this transport is active the engine sets setting SignalRequired = true.
-
Host:
Sucrose.Memory.Manage.Readonly.General.Loopback = IPAddress.Loopback(127.0.0.1). -
Port: dynamically allocated at engine startup via
Sucrose.Shared.Space.Helper.Port.Available(Loopback)and saved to the settingTransmissionPort; the producer readsTransmissionPortback to connect. - Unlike Pipe/Signal,
Transmission.Manage.Internal.{LauncherManager, BackgroundogManager}are not pre-constructed — they are created on demand:new TransmissionT(Loopback, port). -
Server (
TransmissionServer.cs):TcpListener(host, port), accepts one client, reads newline-delimited messages. Accept timeout 5 s, read timeout 15 s; keep-alive on (TcpKeepAliveTime=10,TcpKeepAliveInterval=2),SendTimeout=5000,ReceiveTimeout=15000. -
Client (
TransmissionClient.cs):TcpClient.ConnectAsync(host, port), connect timeout 5 s;SendTimeout=2500,ReceiveTimeout=5000; one line per message withAutoFlush = true, guarded bySemaphoreSlim(1,1). -
TransmissionTfacade: same API surface asPipeT, plus a publicint Port { get; }. Retry/backoff identical toPipeT(exponential, retries onSocketException/TimeoutException).
Loopback only — no remote exposure. This is the default CommunicationType. When active, the engine sets settings TransmissionRequired = true and TransmissionPort = <port>.
Enum Sucrose.Shared.Dependency.Enum.CommunicationType (internal):
Pipe, Signal, Transmission
Read through Sucrose.Shared.Dependency.Manage.Manager.Backgroundog.CommunicationType, which calls BackgroundogSettingManager.GetSetting(SMMCB.CommunicationType, /*default*/ Transmission). The setting key constant is Sucrose.Memory.Manage.Constant.Backgroundog.CommunicationType = "CommunicationType". The engine (Web.cs::StartCompatible()) branches on it to spin up exactly one server.
Related setting keys (all in Sucrose.Memory.Manage.Constant.Backgroundog): PipeRequired, SignalRequired, TransmissionRequired, TransmissionPort, AudioRequired, CommunicationType. Producer and consumer must independently agree: the engine sets *Required / TransmissionPort, and the producer reads them.
The canonical flow — "audio-reactive / system data reaches a Web wallpaper":
[Sucrose.Backgroundog process]
Specification.Start()
collects Bios/Date/Audio/Memory/Battery/Graphic/Network/Storage/Processor/Motherboard (JObject)
builds Interface.Backgroundog, JSON-serializes (TypeNameHandling=None)
branches by which *Required flag is set:
PipeRequired -> BackgroundogManager.StartClient(json) (pipe "Sucrose.Wallpaper.Engine.Backgroundog.Pipe")
SignalRequired -> BackgroundogManager.FileSave(payload) (writes Backgroundog-<guid>.sgnl)
TransmissionRequired -> BackgroundogManager.StartClient(json) (TCP loopback : TransmissionPort)
|
v (one of three transports — must match the engine's choice)
[Sucrose.Live.WebView | Sucrose.Live.CefSharp process]
Web.StartCompatible() switch(CommunicationType):
Pipe: MessageReceived += Handler; StartServer()
Signal: StartChannel(Handler)
Transmission: new TransmissionT(Loopback, Port.Available); StartServer()
|
v
Backgroundog{Pipe|Signal|Transmission}Service.Handler(e)
JSON -> Interface.Backgroundog
for each non-null field: <X>Data = JsonConvert.SerializeObject(field, Indented)
|
v
Compatible.ExecuteTask(...) -> Compatible.ExecuteNormal(...)
for each Compatible.<Hook> placeholder, string.Format(hook, <X>Data) -> ExecuteScriptAsync(js)
|
v
JavaScript inside the wallpaper page receives the data (audio API, system status API)
See Create Web Architecture for the JS-bridge side of this flow.
Simpler: a producer writes Interface.Launcher { Show=true } (e.g. LauncherManager.FileSave) → the Launcher's FileSystemWatcher fires → LauncherSignalService.Handler → TrayIconManager.Show(). Producers include Backgroundog/Helper/Performance.cs (Icon=true), Helper/Condition.cs (Icon=false), and Portal/.../GeneralSettingViewModel.cs (Show / Hide).
- The Backgroundog data channel is web-engine-only (
#if LIVE_WEBVIEW || LIVE_CEFSHARP). - The three transports carry the exact same JSON payload; only the carrier differs.
- The Signal transport writes a new GUID-named file per message and self-cleans on a 3 s timer — files can momentarily pile up under
%AppData%\Sucrose\Cache\SignalT. - All Signal file I/O is guarded by named mutexes (
SignalReader_*,SignalWriter_*) with abandoned-mutex handling. - Pipe and Transmission are one-way (producer = client/Out, engine = server/In); no response over the same channel.
- The command bus is not related to these channels despite the similar "command" wording — it is process-argument based and handled by Commandog.
-
TransmissionTmanagers arenulluntil constructed at runtime;PipeT/SignalTmanagers are static singletons created at type load.
- Commandog Dispatcher — the separate, process-launch command bus.
- Backgroundog Service — the data producer (FFT audio + system sensors).
- Create Web Architecture — the JS-bridge consumer side.
-
Create Audio API — the
Audiopayload for wallpaper authors. - Create System API — the system-status payload fields.
- Architecture Overview — the multi-process model.
Getting Started
- Installation
- System Requirements
- Quick Start
- Portal Interface Tour
- Updating Sucrose
- Uninstalling Sucrose
Wallpaper Types
Using Sucrose
- Managing Library
- Using Store
- Customizing Wallpaper
- Multi-Monitor
- Wallpaper Cycling
- Choosing Engines
- Performance Rules
- Theme, Tray & Startup
- Discord Rich Presence
Settings Reference
- Settings Overview
- Settings: General
- Settings: Personal
- Settings: Performance
- Settings: Wallpaper
- Settings: System
- Settings: Other
- Settings: All Keys
Creating Wallpapers
- Create Overview
- Create: Step By Step
- Create: Package Format
- Create: Customization Controls
- Create: JS Bridge
- Create: Audio API
- Create: System API
- Create: Property Listener & Filters
- Create: Web Architecture
- Create: Compatibility
- Create: Example Wallpapers
- Create: Sharing & Publishing
Engine Reference
- Engines Overview
- Engine: MpvPlayer
- Engine: VlcPlayer
- Engine: WebView
- Engine: CefSharp
- Engine: Nebula
- Engine: Vexana
- Engine: Xavier
- Engine: Aurora
- Engine Comparison
Automation & Command Line
Architecture & Internals
- Architecture Overview
- Lifecycle
- Commandog Dispatcher
- Single-Instance Mutexes
- IPC
- Backgroundog Service
- Crash Reporting
- Update Internals
- Property Service
- Undo Internals
Data, Files & Diagnostics
Building & Contributing
- Building From Source
- Repository Layout
- Shared Item Projects
- Code Conventions
- Preprocessor Symbols
- Publish Pipeline
- Bundle Installer Internals
- Extending Sucrose
- Contributing
- Translating with Localizer
- Localization Coverage
- Security Policy
- Privacy & Telemetry
Help & Support