Overview

The Window Manager Client (system/wm-client.js) is a Node.js library that provides an IPC client for applications to communicate with the fwcompositor window manager service.

Status:Implemented - The client library is complete and ready to use once the fwcompositor service is implemented.

Usage

Basic Example

const WindowManagerClient = require('./wm-client');

// Create client instance
const wm = new WindowManagerClient();

// Connect to fwcompositor service
await wm.connect();

// Create a window
const hwnd = await wm.createWindow('My Application', 800, 600);

// Show and position window
await wm.showWindow(hwnd);
await wm.moveWindow(hwnd, 100, 100);

// Get window buffer and draw to it
const buffer = await wm.getWindowBuffer(hwnd);
// ... draw to buffer using DeviceContext ...
await wm.updateWindow(hwnd, buffer);

// Cleanup
wm.disconnect();

API Reference

Constructor

const wm = new WindowManagerClient();

Creates a new window manager client instance. Automatically detects the appropriate socket type based on the operating system.

Connection Methods

async connect()

Connects to the fwcompositor service. Automatically tries Unix socket first, then falls back to TCP.

await wm.connect();
// Connected to fwcompositor via Unix socket
// or
// Connected to fwcompositor via TCP (127.0.0.1:8080)

disconnect()

Disconnects from the fwcompositor service.

wm.disconnect();

Window Management Methods

async createWindow(title, width, height, flags = 0)

Creates a new window and returns its HWND.

  • title: Window title string
  • width: Window width in pixels
  • height: Window height in pixels
  • flags: Window creation flags (optional)
  • Returns: HWND (window handle string)
const hwnd = await wm.createWindow('My App', 800, 600);
// Returns: "FW_HWND_abc123"

async destroyWindow(hwnd)

Destroys a window.

await wm.destroyWindow(hwnd);

async moveWindow(hwnd, x, y)

Moves a window to a new position.

await wm.moveWindow(hwnd, 100, 100);

async resizeWindow(hwnd, width, height)

Resizes a window.

await wm.resizeWindow(hwnd, 1024, 768);

async showWindow(hwnd)

Shows a window.

await wm.showWindow(hwnd);

async hideWindow(hwnd)

Hides a window.

await wm.hideWindow(hwnd);

async setFocus(hwnd)

Sets keyboard focus to a window.

await wm.setFocus(hwnd);

async getWindowInfo(hwnd)

Gets information about a window.

const info = await wm.getWindowInfo(hwnd);
// Returns: {
//   hwnd: "FW_HWND_abc123",
//   title: "My App",
//   x: 100,
//   y: 100,
//   width: 800,
//   height: 600,
//   visible: true
// }

async listWindows()

Lists all windows.

const windows = await wm.listWindows();
// Returns: Array of window info objects

Buffer Management Methods

async updateWindow(hwnd, buffer, x = 0, y = 0, width = null, height = null)

Updates a window's buffer content. The buffer can be a Buffer, Array, or base64 string.

// Update entire window
await wm.updateWindow(hwnd, pixelBuffer);

// Update specific region
await wm.updateWindow(hwnd, pixelBuffer, 10, 10, 100, 100);

async getWindowBuffer(hwnd)

Gets a window's drawing buffer.

const buffer = await wm.getWindowBuffer(hwnd);

Connection Details

Socket Detection

The client automatically detects the appropriate connection method:

  • Linux/WSL: Tries Unix socket /tmp/fwcompositor.sock first, falls back to TCP
  • Windows: Uses TCP 127.0.0.1:8080 or named pipe
  • macOS: Tries Unix socket first, falls back to TCP

Protocol

The client uses JSON-RPC 2.0 protocol:

  • Each request has a unique ID
  • Responses match request IDs
  • Errors are returned in standard JSON-RPC format
  • 5-second timeout per request

Error Handling

Connection Errors

try {
    await wm.connect();
} catch (error) {
    if (error.code === 'ENOENT') {
        console.error('fwcompositor service not running');
    } else if (error.code === 'ECONNREFUSED') {
        console.error('Connection refused - service may not be running');
    } else {
        console.error('Connection error:', error);
    }
}

Request Errors

try {
    const hwnd = await wm.createWindow('My App', 800, 600);
} catch (error) {
    if (error.message === 'Request timeout') {
        console.error('Service did not respond in time');
    } else {
        console.error('RPC error:', error);
    }
}

Integration with Existing Code

Updating window.js

The existing system/window.js can be updated to use the client:

const WindowManagerClient = require('./wm-client');

class WindowManager {
    constructor() {
        this.client = new WindowManagerClient();
        this.connected = false;
    }
    
    async init() {
        await this.client.connect();
        this.connected = true;
    }
    
    async createWindow(title, width, height) {
        if (!this.connected) await this.init();
        const hwnd = await this.client.createWindow(title, width, height);
        return new Window(hwnd, this.client);
    }
}

Related Documentation