Skip to content
Taiizor edited this page Jun 5, 2026 · 3 revisions

IPC (Inter-Process Communication)

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.

🖼️ Diagram needed: Producer (Backgroundog) → one of {Pipe, Signal, Transmission} → Consumer (WebView/CefSharp engine) → ExecuteScriptAsync → JavaScript in the wallpaper page. Plus the tray-control side channel (Portal/Backgroundog → Signal → Launcher → TrayIconManager).

Contents

Two categories of IPC

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/).

The shared message payloads

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 = Noneplain JSON text, one message per line.

Backgroundog payload (live system + audio data)

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.

Launcher payload (tray-icon control)

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)

Transport A — Named Pipe

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 raises MessageReceived with MessageReceivedEventArgs { 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 with AutoFlush = true, guarded by a SemaphoreSlim(1,1).
  • PipeT facade: StartClient(), StartClient(string Message), StartServer(), StopClient(), StopServer(), DisposeClient(), DisposeServer(), event MessageReceived. StartClientWithRetry uses exponential backoff (2^i seconds, 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.

Transport B — Signal (filesystem)

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 named Mutex "SignalWriter_{fileName}", 5 s timeout, 3 retries (100 ms apart), FileShare.None.
  • Watch (StartChannel(FileSystemEventHandler)): a FileSystemWatcher on Source, Filter = "*.*", InternalBufferSize = 64 KB, NotifyFilter = LastWrite | FileName | DirectoryName. On Created, files whose name contains the channel base name fire the handler. On startup it deletes old matching files; it handles InternalBufferOverflowException by toggling EnableRaisingEvents.
  • Read (FileRead<T>): a small random 5–50 ms delay to reduce contention, then deserialize via Helper/Reader.cs with named Mutex "SignalReader_{fileName}", 5 s timeout, 3 retries, FileShare.Read. If Delete is true, deletion is scheduled on a 3 s timer; corrupt JSON also triggers deletion.
  • Delete (Helper/Deleter.cs): set attributes to Normal, 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.csLauncherManager.StartChannel). When this transport is active the engine sets setting SignalRequired = true.

Transport C — Transmission (TCP loopback)

  • 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 setting TransmissionPort; the producer reads TransmissionPort back 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 with AutoFlush = true, guarded by SemaphoreSlim(1,1).
  • TransmissionT facade: same API surface as PipeT, plus a public int Port { get; }. Retry/backoff identical to PipeT (exponential, retries on SocketException / TimeoutException).

Loopback only — no remote exposure. This is the default CommunicationType. When active, the engine sets settings TransmissionRequired = true and TransmissionPort = <port>.

Transport selection: CommunicationType

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.

End-to-end live-data flow

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.

Tray-control flow

Simpler: a producer writes Interface.Launcher { Show=true } (e.g. LauncherManager.FileSave) → the Launcher's FileSystemWatcher fires → LauncherSignalService.HandlerTrayIconManager.Show(). Producers include Backgroundog/Helper/Performance.cs (Icon=true), Helper/Condition.cs (Icon=false), and Portal/.../GeneralSettingViewModel.cs (Show / Hide).

Gotchas

  • 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.
  • TransmissionT managers are null until constructed at runtime; PipeT / SignalT managers are static singletons created at type load.

See also

Home

Getting Started

Wallpaper Types

Using Sucrose

Settings Reference

Creating Wallpapers

Engine Reference

Automation & Command Line

Architecture & Internals

Data, Files & Diagnostics

Building & Contributing

Help & Support

Clone this wiki locally