Technical Reference

Protocol Specification

Complete wire protocol documentation for the PlexyDesk display server. Everything you need to implement a client from scratch.

Overview

The PlexyDesk protocol is a binary protocol designed for minimal latency and maximum throughput between clients and the compositor.

Design Principles

  • Fixed-size headers. Every message starts with a 4-byte header containing opcode and length. No variable-length parsing required for routing.
  • Packed structures. All protocol messages use #pragma pack(1) alignment for wire compatibility across compilers.
  • Zero-copy rendering. Shared memory and DMA-BUF support for buffer sharing without copying pixel data.
  • Explicit acknowledgment. Configure events require acknowledgment before the compositor applies changes. This prevents race conditions.
v1
Protocol Version
4 bytes
Header Size
~90
Message Types

Connection

Socket Path

Clients connect to the compositor via a Unix domain socket at the following path:

#define PLEXY_SOCKET_PATH "/tmp/plexy.sock"
#define PLEXY_PROTOCOL_VERSION 1

Handshake Sequence

Upon connection, clients must send a PLEXY_OP_HELLO message. The compositor responds with PLEXY_OP_HELLO_REPLY containing the client ID and display information.

Client → HELLO version=1, name="MyApp"
Server → HELLO_REPLY client_id=42, ui_scale=1.5, screen=1920×1080

Hello Message Structure

typedef struct {
    PlexyHeader header;    // opcode=1, length=sizeof(PlexyHello)
    uint32_t version;      // Protocol version (must be 1)
    char name[64];         // Client application name (null-terminated)
} PlexyHello;

Hello Reply Structure

typedef struct {
    PlexyHeader header;    // opcode=2
    uint32_t version;      // Compositor protocol version
    uint32_t client_id;    // Unique client identifier
    float ui_scale;        // UI scale factor (e.g., 1.0, 1.5, 2.0)
    uint32_t screen_width; // Screen width in pixels
    uint32_t screen_height;// Screen height in pixels
} PlexyHelloReply;

Message Format

Every protocol message begins with a 4-byte header, followed by message-specific data.

Header Structure

typedef struct {
    uint16_t opcode;   // Message type identifier
    uint16_t length;   // Total message length including header
} PlexyHeader;

Wire Format

Byte 0-1
Byte 2-3
Byte 4+
opcode (LE)
length (LE)
payload...

All multi-byte integers are little-endian. Strings are null-terminated with fixed maximum lengths.

Byte Order

The protocol uses little-endian byte order for all multi-byte integers. This matches the native byte order on x86/x86_64 and ARM (in default configuration).

Opcodes

Message types are identified by 16-bit opcodes. Opcodes are grouped by functionality.

Core Messages (1-29)

Opcode Name Direction Description
1HELLOC→SClient handshake initiation
2HELLO_REPLYS→CServer handshake response
3CREATE_WINDOWC→SRequest window creation
4WINDOW_CREATEDS→CWindow creation confirmed
5ATTACH_BUFFERC→SAttach SHM buffer to window
6BUFFER_ATTACHEDS→CBuffer attachment confirmed
7COMMITC→SCommit pending changes
8FRAME_DONES→CFrame presentation complete
9CONFIGURES→CWindow configuration change
10CONFIGURE_ACKC→SAcknowledge configuration
11DESTROY_WINDOWC→SRequest window destruction
12WINDOW_CLOSEDS→CWindow closed by compositor

Input Events (13-23)

Opcode Name Description
13POINTER_ENTERPointer entered window surface
14POINTER_LEAVEPointer left window surface
15POINTER_MOTIONPointer position update
16POINTER_BUTTONMouse button press/release
17KEYKeyboard key event
18FOCUS_INWindow gained keyboard focus
19FOCUS_OUTWindow lost keyboard focus
22POINTER_AXISScroll wheel / touchpad axis
23MODIFIERSKeyboard modifier state change

Layer Surfaces (30-39)

Opcode Name Description
30CREATE_LAYER_SURFACECreate panel/dock/overlay
31LAYER_SURFACE_CREATEDLayer surface confirmed
32DESTROY_LAYER_SURFACEDestroy layer surface

DMA-BUF (80-89)

Opcode Name Description
80ATTACH_DMABUFAttach DMA-BUF (zero-copy)
81DMABUF_ATTACHEDDMA-BUF attachment confirmed

Window Management

Creating a Window

typedef struct {
    PlexyHeader header;           // opcode=3
    int32_t x;                    // Initial X position (-1 for auto)
    int32_t y;                    // Initial Y position (-1 for auto)
    uint32_t width;               // Window width in pixels
    uint32_t height;              // Window height in pixels
    uint32_t buffer_scale;        // Buffer scale factor (1 or 2)
    char title[128];              // Window title (null-terminated)
} PlexyCreateWindow;

Window Created Response

typedef struct {
    PlexyHeader header;           // opcode=4
    uint32_t window_id;           // Assigned window identifier
    uint32_t width;               // Actual configured width
    uint32_t height;              // Actual configured height
    float scale_factor;           // UI scale factor
    uint32_t buffer_scale;        // Buffer scale for HiDPI
} PlexyWindowCreated;

Configuration Events

The compositor sends CONFIGURE events when window geometry changes (e.g., user resize, display scale change). Clients must acknowledge with CONFIGURE_ACK before the changes take effect.

typedef struct {
    PlexyHeader header;           // opcode=9
    uint32_t window_id;
    uint32_t width;               // New width
    uint32_t height;              // New height
    float scale_factor;           // New scale factor
    uint32_t buffer_scale;        // New buffer scale
    uint32_t serial;              // Configuration serial number
} PlexyConfigure;

typedef struct {
    PlexyHeader header;           // opcode=10
    uint32_t window_id;
    uint32_t serial;              // Must match configure serial
} PlexyConfigureAck;

Important

After receiving a CONFIGURE event, the client should resize its buffer to match the new dimensions, then send CONFIGURE_ACK with the matching serial. The compositor will not display the new size until acknowledgment is received.

Buffer Management

PlexyDesk supports two buffer types: shared memory (SHM) for CPU rendering and DMA-BUF for zero-copy GPU buffer sharing.

Shared Memory Buffers

typedef struct {
    PlexyHeader header;           // opcode=5
    uint32_t window_id;           // Target window
    uint32_t width;               // Buffer width
    uint32_t height;              // Buffer height
    uint32_t stride;              // Bytes per row
    uint32_t format;              // Pixel format (see below)
    uint32_t shm_size;            // Total shared memory size
} PlexyAttachBuffer;

// Pixel format constants
#define PLEXY_FORMAT_ARGB8888  0  // 32-bit with alpha
#define PLEXY_FORMAT_XRGB8888  1  // 32-bit no alpha
#define PLEXY_FORMAT_RGBA8888  2  // 32-bit RGBA order

DMA-BUF Buffers (Zero-Copy)

For GPU-accelerated clients, DMA-BUF allows direct buffer sharing without copying. The file descriptor is passed via SCM_RIGHTS ancillary data.

typedef struct {
    PlexyHeader header;           // opcode=80
    uint32_t window_id;
    uint32_t width;
    uint32_t height;
    uint32_t stride;
    uint32_t format;              // DRM_FORMAT_* fourcc code
    uint64_t modifier;            // DRM format modifier
    uint32_t offset;              // Offset into buffer
    uint32_t flags;               // Reserved
} PlexyAttachDmaBuf;

Committing Changes

After drawing to the buffer, clients must commit to make changes visible. The commit message includes optional damage region and cursor hints.

typedef struct {
    PlexyHeader header;           // opcode=7
    uint32_t window_id;
    int32_t cursor_cell_x;        // Cursor column (for terminals)
    int32_t cursor_cell_y;        // Cursor row (for terminals)
    int32_t cursor_cols;          // Grid columns (optional)
    int32_t cursor_rows;          // Grid rows (optional)
    int32_t damage_x;             // Damaged region X
    int32_t damage_y;             // Damaged region Y
    int32_t damage_width;         // Damaged region width
    int32_t damage_height;        // Damaged region height
} PlexyCommit;

Input Events

Input events are delivered to the focused window. Coordinates are in surface-local pixels.

Pointer Events

typedef struct {
    PlexyHeader header;           // opcode=15
    uint32_t window_id;
    int32_t x;                    // Surface-local X coordinate
    int32_t y;                    // Surface-local Y coordinate
} PlexyPointerMotion;

typedef struct {
    PlexyHeader header;           // opcode=16
    uint32_t window_id;
    uint32_t button;              // Linux input button code
    uint32_t state;               // 0=released, 1=pressed
    int32_t x;                    // X at time of event
    int32_t y;                    // Y at time of event
} PlexyPointerButton;

// Standard button codes
#define PLEXY_BTN_LEFT   0x110
#define PLEXY_BTN_RIGHT  0x111
#define PLEXY_BTN_MIDDLE 0x112

Scroll Events

typedef struct {
    PlexyHeader header;           // opcode=22
    uint32_t window_id;
    int32_t axis;                 // 0=vertical, 1=horizontal
    int32_t value;                // Scroll amount (1/256 pixel units)
    int32_t discrete;             // Discrete steps (for wheel), 0 for smooth
} PlexyPointerAxis;

Keyboard Events

typedef struct {
    PlexyHeader header;           // opcode=17
    uint32_t window_id;
    uint32_t keycode;             // Linux input keycode
    uint32_t state;               // 0=released, 1=pressed
    uint32_t modifiers;           // Active modifier mask
} PlexyKey;

// Modifier flags
#define PLEXY_MOD_SHIFT  (1 << 0)
#define PLEXY_MOD_CTRL   (1 << 1)
#define PLEXY_MOD_ALT    (1 << 2)
#define PLEXY_MOD_SUPER  (1 << 3)

Modifier State

typedef struct {
    PlexyHeader header;           // opcode=23
    uint32_t window_id;
    uint32_t depressed;           // Currently pressed modifiers
    uint32_t latched;             // Latched (sticky) modifiers
    uint32_t locked;              // Locked modifiers (Caps Lock, etc.)
    uint32_t group;               // Keyboard layout group
} PlexyModifiers;

Layer Surfaces

Layer surfaces are special surfaces for panels, docks, overlays, and desktop backgrounds. They have fixed positions and stacking order.

Layer Types

enum PlexyLayer {
    PLEXY_LAYER_BACKGROUND = 0,   // Desktop background
    PLEXY_LAYER_BOTTOM = 1,       // Below windows
    PLEXY_LAYER_TOP = 2,          // Above windows (panels)
    PLEXY_LAYER_OVERLAY = 3       // Topmost (notifications)
};

Anchor Flags

enum PlexyAnchor {
    PLEXY_ANCHOR_NONE   = 0,
    PLEXY_ANCHOR_TOP    = 1,
    PLEXY_ANCHOR_BOTTOM = 2,
    PLEXY_ANCHOR_LEFT   = 4,
    PLEXY_ANCHOR_RIGHT  = 8
};

// Example: dock at bottom
anchor = PLEXY_ANCHOR_BOTTOM | PLEXY_ANCHOR_LEFT | PLEXY_ANCHOR_RIGHT;

Creating a Layer Surface

typedef struct {
    PlexyHeader header;           // opcode=30
    uint32_t layer;               // PlexyLayer enum value
    uint32_t anchor;              // Anchor flags (OR'd together)
    uint32_t width;               // Surface width (0 for auto)
    uint32_t height;              // Surface height (0 for auto)
    int32_t exclusive_zone;       // Reserved screen space
    uint32_t keyboard_interactivity; // Accept keyboard focus?
} PlexyCreateLayerSurface;

HiDPI Support

PlexyDesk provides comprehensive HiDPI support through buffer scaling and output scale factors.

Scale Factors

  • ui_scale — Floating-point scale factor from the compositor (e.g., 1.0, 1.5, 2.0). Use for UI element sizing.
  • buffer_scale — Integer scale for buffer dimensions. A buffer_scale of 2 means the client should allocate 2× pixels.

Output Information

typedef struct {
    PlexyHeader header;           // opcode=70
    uint32_t output_id;
    int32_t x;                    // Output position X
    int32_t y;                    // Output position Y
    uint32_t physical_width_mm;   // Physical width in mm
    uint32_t physical_height_mm;  // Physical height in mm
    uint32_t pixel_width;         // Resolution width
    uint32_t pixel_height;        // Resolution height
    float scale_factor;           // Output scale factor
    uint32_t subpixel;            // Subpixel layout
    uint32_t transform;           // Output transform
    char make[64];                // Monitor manufacturer
    char model[64];               // Monitor model
} PlexyOutputInfo;

Preferred Scale Notification

typedef struct {
    PlexyHeader header;           // opcode=76
    uint32_t window_id;
    uint32_t preferred_scale;     // Recommended integer scale
    float exact_scale;            // Exact fractional scale
} PlexyPreferredBufferScale;

Next Steps

Menu