Remote Interface

pgwidgets can be controlled from a Python server over WebSocket using the pgwidgets-python package. The browser page connects to the server, which sends JSON messages to create widgets, call methods, and receive callbacks.

Setup

Install the Python remote package:

pip install pgwidgets-python

Synchronous Example

from pgwidgets.sync import Application

app = Application()

@app.on_connect
def setup(session):
    W = session.get_widgets()

    top = W.TopLevel(title="Remote App", resizable=True)
    top.resize(400, 300)

    vbox = W.VBox(spacing=8)
    btn = W.Button("Click me")
    status = W.Label("Ready")

    btn.on("activated", lambda: status.set_text("Clicked!"))

    vbox.add_widget(btn, 0)
    vbox.add_widget(status, 1)
    top.set_widget(vbox)
    top.show()

app.run()

Async Example

import asyncio
from pgwidgets.async_ import Application

app = Application()

@app.on_connect
async def setup(session):
    W = session.get_widgets()

    top = await W.TopLevel(title="Async App", resizable=True)
    await top.resize(400, 300)

    vbox = await W.VBox(spacing=8)
    btn = await W.Button("Press me")
    label = await W.Label("Waiting...")

    btn.on("activated", lambda: label.set_text("Pressed!"))

    await vbox.add_widget(btn, 0)
    await vbox.add_widget(label, 1)
    await top.set_widget(vbox)
    await top.show()

asyncio.run(app.run())

How It Works

  1. The Python server starts a WebSocket server.

  2. The browser page includes Widgets.js and connects via the RemoteInterface class.

  3. The Python side sends JSON commands (create, call, destroy) and the browser executes them.

  4. When a widget fires a callback, the browser sends the event back over the WebSocket to the Python server.

The protocol is language-agnostic – any WebSocket client that speaks the JSON protocol can drive the UI.

Session Persistence and Reconnection

Sessions on the Python side persist independently of browser connections. The Python process is the source of truth for all widget state. When a browser disconnects (page refresh, network drop) and reconnects, the server replays the entire widget tree so the UI reappears in its current state.

The browser stores the session ID and security token (received via a session-info message after the handshake). On reconnection, the browser sends these back in the ack message so the server can match it to the existing session. The RemoteInterface on the JS side handles reconstruct-start / reconstruct-end brackets to suppress callback echo during reconstruction.

Multi-Browser Synchronization

Multiple browsers can connect to the same session by navigating to the session URL. When one browser triggers a state change (slider move, tab switch, text edit, etc.), the Python server pushes the update to all other connected browsers using silent calls. When a call includes "silent": true, the RemoteInterface sets a _syncing flag so the JS side executes the method but suppresses callback dispatch, preventing infinite feedback loops.