# How OpenLogi Manages Actions Ring Overlay Geometry with IPC-Driven State

> Learn how OpenLogi manages Actions Ring overlay geometry with IPC-driven state, ensuring atomic updates across processes for synchronized visuals without complex synchronization logic.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-09-02

---

**OpenLogi synchronizes Actions Ring overlay geometry by resolving display coordinates locally in the overlay process via the `CursorDisplay` struct while transmitting full visual state snapshots through the `observe_action_ring` IPC RPC, ensuring atomic updates across processes without incremental synchronization logic.**

The Actions Ring in OpenLogi provides a contextual command palette that appears at the cursor location across multiple displays. Because the overlay runs as a separate lightweight process from the main GUI, the system must coordinate both spatial geometry and visual state across process boundaries. This article examines how the `crates/openlogi-overlay` and `crates/openlogi-ipc` crates collaborate to manage geometry locally while synchronizing ring content via a tarpc-based IPC contract.

## Local Geometry Resolution with CursorDisplay

The overlay process cannot rely on the GUI to calculate screen coordinates because it must respond instantly to cursor movements and display configuration changes. Instead, it resolves geometry independently using the **`CursorDisplay`** struct defined in [`crates/openlogi-overlay/src/platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/platform.rs) (lines 89-99).

This structure encapsulates three critical values in the global coordinate space: the native display identifier, the display's top-left origin point, and its size in points. By using the same global coordinate space that the input hook's `cursor_position()` returns, the overlay ensures pixel-perfect alignment regardless of which screen contains the cursor.

### Platform-Specific Display Detection on macOS

On macOS, the overlay invokes `display_containing(x, y)` to determine which display bounds contain the cursor coordinates. This function queries CoreGraphics directly, calling `CGGetActiveDisplayList` to enumerate active displays and `CGDisplayBounds` to test containment (lines 11-35 of [`platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/platform.rs)).

On other platforms, this function returns a no-op because GPUI already reports global origins natively. This platform abstraction allows the overlay geometry logic to remain agnostic of the underlying windowing system while maintaining precision on macOS through native framework calls.

```rust
// Geometry resolution in the overlay process
use openlogi_overlay::platform::{display_containing, CursorDisplay};
use openlogi_hook::cursor_position;

let (x, y) = cursor_position();
let display: CursorDisplay = display_containing(x, y)
    .expect("cursor must be on a known display");

// Use display.origin and display.size to position the GPUI window

```

## IPC-Driven State Synchronization

While geometry remains local to the overlay, the visual content of the Actions Ring originates from the agent process and travels across the IPC boundary. The contract lives in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) and centers on the **`observe_action_ring`** RPC, introduced in protocol version 21.

### The RingObservation Protocol

When the GUI requests the current ring state, the RPC returns a **`RingObservation`** struct (lines 52-57) containing a **generation** counter and a snapshot of the ring's presentation information. This snapshot includes an **`ActionRingInvocation`** (lines 85-93) that describes the entire ring session, including the `session_id`, per-slot presentation data, and optional UI locale strings.

### ActionRingPresentation Structure

Each slot in the ring maps to an **`ActionRingPresentation`** instance (lines 71-82) within the invocation. This struct carries the slot label, a boolean flag distinguishing literal text from localized keys, and the resolved **`ActionRingIcon`**. By packaging the complete visual specification into a single serializable structure, the IPC contract eliminates the need for the overlay to request additional metadata or resolve resources independently.

```rust
// GUI process requesting ring state from agent via IPC
use openlogi_ipc::ipc::Client;

let obs = client.observe_action_ring(current_generation).await?; // RingObservation
let invocation = obs.ring.invocation; // ActionRingInvocation

// Activate overlay for specific slot
send_overlay_command(OverlayCommand::Hover {
    session_id: invocation.session_id,
    slot: ActionRingSlot::Top,
});

```

## Synchronization Flow and State Consistency

The coordination between processes follows a strict command pattern. When a user triggers **Show Actions Ring**, the GUI dispatches an `OverlayCommand::Hover` or `OverlayCommand::Activate` over the IPC channel to the overlay process. The overlay receives this command, extracts the `session_id`, and renders the ring using the most recent `ActionRingInvocation` obtained from its cached `RingObservation`.

### Handling Geometry Changes

Because the overlay resolves its own geometry via `display_containing`, it responds immediately to display hot-plugging or cursor movement between monitors without IPC round-trips. When the cursor moves to a new display, the overlay queries the native platform APIs locally and adjusts the ring's position instantly. This design keeps the overlay lightweight and responsive, avoiding the latency that would occur if the GUI process had to mediate every display boundary transition.

### Atomic State Updates

The `observe_action_ring` RPC transmits **full snapshots** rather than incremental deltas. When the overlay polls for updates or receives a push notification, it replaces its entire `ActionRingInvocation` reference with the new observation. This atomic update pattern ensures that the overlay never renders inconsistent intermediate states, such as displaying icons from one configuration with labels from another. The generation counter within `RingObservation` allows the overlay to detect and skip stale observations if messages arrive out of order.

```rust
// Overlay process combining IPC state with local geometry
use openlogi_overlay::platform::display_containing;
use openlogi_hook::cursor_position;

// Received from GUI via IPC
let session_id = command.session_id;
let invocation = latest_ring_observation.invocation;

// Local geometry resolution
let (x, y) = cursor_position();
let display = display_containing(x, y).unwrap();

// Render using both IPC-driven content and local geometry
render_ring(&display, &invocation);

```

## Lifecycle Coordination via Session IDs

The ring's lifecycle relies on a shared **session ID** that both the GUI and overlay processes reference in every command. The GUI embeds this ID in `OverlayCommand::Hover`, `OverlayCommand::Activate`, and `OverlayCommand::Cancel` messages. When the user dismisses the ring, the GUI sends a `Cancel` command with the same session ID, guaranteeing that the overlay ignores delayed or out-of-order commands from previous sessions.

This session-based anchoring prevents race conditions during rapid show-hide sequences. The overlay stores the active session ID in its local state and validates incoming commands against it, ensuring that only the current ring session can modify the visual output.

## Summary

- **Local Geometry Resolution**: The overlay calculates its own position using the `CursorDisplay` struct and platform-specific functions like `display_containing`, avoiding IPC latency for cursor tracking.
- **IPC Contract**: The `observe_action_ring` RPC (protocol version 21) transmits `RingObservation` snapshots containing complete `ActionRingInvocation` data, including per-slot `ActionRingPresentation` details.
- **Atomic Updates**: Full state snapshots replace local overlay state atomically, preventing visual corruption from partial updates.
- **Session Safety**: Shared `session_id` values in `OverlayCommand` messages ensure that only the current ring session controls the overlay, preventing stale command execution.

## Frequently Asked Questions

### What is the RingObservation struct in OpenLogi?

The **`RingObservation`** struct is the primary container for Actions Ring state transmitted over IPC in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) (lines 52-57). It contains a generation counter for versioning and a ring snapshot that includes the `ActionRingInvocation`. This struct enables the overlay process to receive a complete, consistent picture of the ring's visual state without requesting individual elements separately.

### How does the overlay determine which display contains the cursor?

The overlay calls **`display_containing(x, y)`** from [`crates/openlogi-overlay/src/platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/platform.rs) (lines 11-35). On macOS, this function queries CoreGraphics using `CGGetActiveDisplayList` and `CGDisplayBounds` to find the display whose rectangle contains the cursor coordinates. On other platforms, the function returns a no-op because GPUI provides global coordinates natively. The function returns a `CursorDisplay` struct containing the display's native ID, origin, and size.

### Why does OpenLogi use full state snapshots instead of incremental updates?

Full state snapshots transmitted through **`observe_action_ring`** eliminate partial update states and race conditions. Because the overlay replaces its entire `ActionRingInvocation` reference when receiving a new `RingObservation`, it never renders a mix of old and new configuration data. This atomic approach simplifies the synchronization logic and ensures visual consistency, particularly when the user rapidly changes contexts or displays.

### What prevents race conditions between the GUI and overlay processes?

**Session IDs** anchor every `OverlayCommand` (`Hover`, `Activate`, `Cancel`) to a specific ring instance. The GUI and overlay both reference the same `session_id` from the `ActionRingInvocation` (lines 85-93). When processing commands, the overlay validates that the incoming session ID matches its current session, discarding stale commands from previous ring invocations. This mechanism prevents visual glitches when users trigger the ring multiple times in quick succession.