OpenLogi Actions Ring Overlay: Rendering Pipeline and Communication Protocol

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, 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:

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

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.

  • 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.

  • 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:

// 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 handles the activation request:

// 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, 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:

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

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →