# OpenLogi Actions Ring Overlay: Rendering Pipeline and Communication Protocol

> Explore the OpenLogi Actions Ring rendering pipeline and tarpc communication protocol. Learn how GPUI primitives create this visual overlay in the AprilNEA/OpenLogi repository.

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

---

**The OpenLogi Actions Ring is a cursor-centered, eight-slot visual overlay that renders on a transparent, always-on-top window using GPUI primitives and communicates with the background agent via tarpc IPC channels.**

The Actions Ring provides immediate visual access to Logitech device actions directly from the screen without context switching. Implemented as a lightweight, cross-platform client in the **openlogi-overlay** crate, this component runs alongside the main OpenLogi GUI and maintains real-time synchronization with the background agent through a well-defined RPC contract.

## Rendering Architecture

The overlay renders as a transparent, cursor-following window using GPUI's compositor to ensure it remains always-on-top without capturing input focus. The implementation spans three core components that handle geometry calculation, platform-specific window management, and the render loop.

### Ring UI Geometry and Drawing

The core visual logic resides in [`crates/openlogi-overlay/src/ring.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/ring.rs), which defines the `Ring` struct responsible for drawing eight slots using GPUI primitives. The ring calculates slot positions dynamically based on cursor location, arranging eight equidistant slots in a circle around the pointer.

Each frame, the `Ring::update()` method recomputes geometry based on the current cursor position:

```rust
// openlogi-overlay/src/ring.rs
fn update(&mut self, cursor: Point) {
    let center = cursor;
    for i in 0..8 {
        let angle = std::f32::consts::TAU * i as f32 / 8.0;
        self.slots[i].rect = Rect::from_center_size(
            center + Vec2::from_angle(angle) * self.radius,
            self.slot_size,
        );
    }
}

```

### Platform-Specific Window Creation

[`crates/openlogi-overlay/src/platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/platform.rs) handles the creation of borderless, always-on-top windows tailored to each operating system. On macOS, it creates an `NSWindow`; on Linux, it targets X11 or Wayland; and on Windows, it uses Win32 APIs. This module forwards resize and reposition events to the Ring UI while maintaining transparency and proper z-ordering.

### The GPUI Render Loop

The entry point in [`crates/openlogi-overlay/src/main.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/main.rs) runs a minimal GPUI event loop that drives the rendering pipeline. Each tick invokes `Ring::update()` to recalculate geometry based on the current mouse position, then triggers a redraw through `gpui::Scene` compositor. This ensures the overlay follows cursor movement smoothly while maintaining consistent frame rates.

## Inter-Process Communication with the Agent

OpenLogi enforces a strict separation between UI concerns (the overlay and GUI) and device I/O operations (the **agent**). The overlay communicates with the agent using **tarpc**, a Rust RPC framework, over local Unix sockets or Windows named pipes defined in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs).

### Message Types and Directionality

The IPC contract supports bidirectional message flow to synchronize ring state:

- **Overlay → Agent**: `ShowActionsRing { app_id: String, layout: Layout }` — Activates a ring for a specific application and supplies the slot configuration. This originates from [`crates/openlogi-overlay/src/agent.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/agent.rs).

- **Agent → Overlay**: `RingUpdate { actions: Vec<Action>, highlighted: Option<usize> }` — Pushes the current action list and indicates which slot (if any) is highlighted due to mouse hover. This is handled in [`crates/openlogi-agent/src/overlay.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent/src/overlay.rs).

- **Bidirectional Heartbeat**: `Ping` and `Pong` messages detect lost connections between the overlay client and the background daemon.

### RPC Implementation

The overlay client opens a local socket, registers its RPC service, and issues requests to the agent's RPC server. When the main GUI triggers a ring display, it sends an IPC request that the agent routes to the overlay:

```rust
// In the GUI command handler
let layout = config::load_ring_layout(&app_id);
let _ = ipc_client.show_actions_ring(app_id.clone(), layout).await?;

```

On the overlay side, [`crates/openlogi-overlay/src/agent.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/agent.rs) handles the activation request:

```rust
// openlogi-overlay/src/agent.rs
async fn handle_show_actions_ring(
    ctx: RpcContext,
    req: ShowActionsRing,
) -> Result<(), RpcError> {
    overlay::session::start(req.app_id, req.layout).await?;
    Ok(())
}

```

## Session Lifecycle Management

The complete lifecycle of an Actions Ring session is orchestrated through [`crates/openlogi-overlay/src/session.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/session.rs), which manages creation, state synchronization, and teardown.

### Activation Flow

When a user invokes **ShowActionsRing** via keyboard shortcut or menu item, the sequence proceeds as follows:

1. The GUI sends an IPC request to the agent.
2. The agent spawns an overlay session via `overlay::session::start()`.
3. The session creates the platform-specific window and instantiates a `Ring`.
4. The GPUI event loop begins processing mouse movements and redraws.

### Runtime Synchronization

While visible, the overlay streams mouse-move events to the ring UI and reports hover changes back to the agent. The agent maintains a map of active rings per application and forwards configuration updates (such as modified TOML layouts) through the same RPC channel.

### Dismissal and Cleanup

The ring dismisses when the user presses Escape, clicks outside the ring, or triggers a timeout. This causes the overlay to send a termination RPC, close the platform window, and shut down the GPUI event loop, ensuring no ghost processes remain.

## Key Implementation Files

The Actions Ring overlay implementation spans the following critical source files:

- **[`crates/openlogi-overlay/src/ring.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/ring.rs)** — Core ring UI implementation including geometry calculations, slot painting, and interaction handling using GPUI primitives.

- **[`crates/openlogi-overlay/src/platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/platform.rs)** — Platform-specific window abstraction creating transparent, borderless, always-on-top windows for macOS, Linux, and Windows.

- **[`crates/openlogi-overlay/src/main.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/main.rs)** — Entry point and GPUI event loop runner for the overlay process.

- **[`crates/openlogi-overlay/src/agent.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/agent.rs)** — RPC client implementation that forwards ring commands to the background agent and handles incoming requests.

- **[`crates/openlogi-overlay/src/session.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/session.rs)** — Session lifecycle manager handling ring creation, state synchronization, and graceful shutdown.

- **[`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs)** — Shared tarpc contract defining message structures (`ShowActionsRing`, `RingUpdate`, `Ping`/`Pong`) used by both overlay and agent.

- **[`crates/openlogi-agent/src/overlay.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent/src/overlay.rs)** — Agent-side IPC responder that manages ring state maps and forwards updates to active overlay clients.

## Summary

- The OpenLogi Actions Ring renders eight action slots in a circle around the cursor using GPUI primitives in a transparent, always-on-top window.
- Platform-specific implementations in [`platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/platform.rs) handle window creation for macOS, Linux, and Windows without stealing input focus.
- The overlay communicates with the background agent via tarpc over local sockets, using typed messages like `ShowActionsRing` and `RingUpdate`.
- Session lifecycle management in [`session.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/session.rs) handles activation, real-time hover synchronization, and clean dismissal.
- The architecture separates UI rendering from device I/O, allowing the lightweight overlay to run independently while maintaining state synchronization with the agent.

## Frequently Asked Questions

### How does the overlay maintain always-on-top behavior without stealing focus?

The platform-specific window implementation in [`crates/openlogi-overlay/src/platform.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/platform.rs) creates borderless windows with specific OS-level flags (NSWindow on macOS, X11/Wayland hints on Linux, Win32 extended styles on Windows) that keep the window visible above other applications. The GPUI compositor (`gpui::Scene`) handles rendering without registering the window as an input receiver, ensuring cursor clicks pass through to underlying applications when not interacting with the ring slots.

### What IPC mechanism does OpenLogi use for the Actions Ring?

OpenLogi uses **tarpc**, a Rust-native RPC framework, running over local Unix sockets on macOS/Linux and named pipes on Windows. The shared contract in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) defines strongly-typed messages that allow the overlay to request activation (`ShowActionsRing`) and receive state updates (`RingUpdate`) from the agent. A `Ping`/`Pong` heartbeat detects connection failures and triggers cleanup.

### How are the eight ring slots positioned geometrically?

The `Ring::update()` method in [`crates/openlogi-overlay/src/ring.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/ring.rs) calculates slot positions using polar coordinates around the current cursor point. It divides `2π` (TAU) by eight to determine angular spacing, then offsets each slot center by a fixed radius vector. This ensures the eight slots form a perfect circle around the cursor regardless of screen position or DPI settings.

### What triggers the Actions Ring to dismiss?

The ring dismisses on three conditions: the user presses the Escape key, clicks outside the ring's bounding area, or a timeout expires (if configured). The session manager in [`crates/openlogi-overlay/src/session.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/session.rs) captures these events and initiates a graceful shutdown sequence that sends a termination RPC to the agent, destroys the platform window, and exits the GPUI event loop.