Remote Forms Protocol
Overview
Text-based protocol for remote GUI. A C server on Linux sends form/control
commands over a transport layer; a Delphi 1.0 client on Windows 3.1 creates
native controls and sends user events back.
Message Format
- One command per message.
- Transport delivers whole messages (today: newline-delimited over serial).
- Strings are double-quoted with escapes:
\" \\ \n \r \t.
- Bare tokens (IDs, numbers, type names) are whitespace-delimited.
- IDs are positive integers assigned by the server.
Server → Client Commands
FORM.CREATE
FORM.CREATE <formId> <width> <height> "<title>"
Create a new form with the given dimensions and title. The form is not
shown until FORM.SHOW is sent.
FORM.SHOW
FORM.SHOW <formId>
FORM.HIDE
FORM.HIDE <formId>
FORM.DESTROY
FORM.DESTROY <formId>
Free the form and all its controls.
CTRL.CREATE
CTRL.CREATE <formId> <ctrlId> <type> <left> <top> <width> <height> [Key="val" ...]
Create a control on the specified form. Inline key/value properties are
applied immediately after creation. See Control Types and Properties below.
CTRL.SET
CTRL.SET <formId> <ctrlId> Key="val" [Key="val" ...]
Update one or more properties on an existing control.
EVENT.BIND
EVENT.BIND <formId> <ctrlId> <eventName>
Wire an opt-in event handler. Auto-wired events do not need explicit binding.
EVENT.UNBIND
EVENT.UNBIND <formId> <ctrlId> <eventName>
Remove an event handler.
Client → Server Events
EVENT <formId> <ctrlId> <eventName> [<data>]
Event data varies by event type:
| Event |
Data |
| Click |
(none), or <itemIndex> (RadioGroup) |
| DblClick |
(none) |
| Change |
"new text", <position> (ScrollBar), or <index> (TabSet, TabbedNotebook) |
| Select |
<index> "selected text" |
| KeyDown |
<vkCode> |
| KeyUp |
<vkCode> |
| MouseDown |
<x> <y> <button> |
| MouseUp |
<x> <y> <button> |
| MouseMove |
<x> <y> <button> |
| Enter |
(none) |
| Exit |
(none) |
| Close |
(none) |
| Notify |
(none) |
| SelectCell |
<col> <row> |
| SetEditText |
<col> <row> "text" |
Control Types
| Type |
Delphi Class |
Auto-wired Events |
| Label |
TLabel |
(none) |
| Edit |
TEdit |
Change |
| Button |
TButton |
Click |
| CheckBox |
TCheckBox |
Click |
| ListBox |
TListBox |
Select |
| ComboBox |
TComboBox |
Select, Change |
| Memo |
TMemo |
Change |
| Image |
TImage |
(none) |
| GroupBox |
TGroupBox |
(none) |
| RadioButton |
TRadioButton |
Click |
| Panel |
TPanel |
(none) |
| ScrollBar |
TScrollBar |
Change |
| MediaPlayer |
TMediaPlayer |
(none) |
| MainMenu |
TMainMenu |
(none) |
| PopupMenu |
TPopupMenu |
(none) |
| MenuItem |
TMenuItem |
Click |
| RadioGroup |
TRadioGroup |
Click |
| BitBtn |
TBitBtn |
Click |
| SpeedButton |
TSpeedButton |
Click |
| TabSet |
TTabSet |
Change |
| Notebook |
TNotebook |
(none) |
| TabbedNotebook |
TTabbedNotebook |
Change |
| MaskEdit |
TMaskEdit |
Change |
| Outline |
TOutline |
(none) |
| Bevel |
TBevel |
(none) |
| Header |
THeader |
(none) |
| ScrollBox |
TScrollBox |
(none) |
| StringGrid |
TStringGrid |
SelectCell |
MainMenu and PopupMenu use 0 0 0 0 geometry (non-visual). MenuItem
uses 0 0 0 0 geometry and requires a Parent property to specify its
parent menu or menu item. One MainMenu per form (auto-attached).
PopupMenu is associated with any control via the PopupMenu property.
GroupBox and Panel are cosmetic containers (flat parent model — no child
containment in the protocol). RadioButtons are all in one group per form.
Opt-in events (require EVENT.BIND): Click (Image, GroupBox, Panel),
Notify (MediaPlayer), SetEditText (StringGrid), DblClick, KeyDown,
KeyUp, Enter, Exit, MouseDown, MouseUp, MouseMove. Menu and
RadioGroup components do not support opt-in events.
Properties
Common Properties
| Property |
Applies To |
Format |
| Enabled |
All |
0 or 1 |
| Visible |
All |
0 or 1 |
| TabOrder |
All windowed |
Integer |
| PopupMenu |
Any TControl |
Integer (ctrlId of PopupMenu) |
Label, Button, GroupBox
| Property |
Format |
| Caption |
Quoted string |
Edit
| Property |
Format |
| Text |
Quoted string |
| MaxLength |
Integer |
| ReadOnly |
0 or 1 |
CheckBox, RadioButton
| Property |
Format |
| Caption |
Quoted string |
| Checked |
0 or 1 |
ListBox
| Property |
Format |
| Items |
Quoted string (\n-delimited) |
| ItemIndex |
Integer (-1 = none) |
ComboBox
| Property |
Format |
| Text |
Quoted string |
| Items |
Quoted string (\n-delimited) |
| ItemIndex |
Integer (-1 = none) |
Memo
| Property |
Format |
| Text |
Quoted string (\n for line breaks) |
| ReadOnly |
0 or 1 |
| ScrollBars |
0-3 (ssNone..ssBoth) |
Image
| Property |
Format |
| Picture |
Quoted string (filename, BMP only) |
| Stretch |
0 or 1 |
| Center |
0 or 1 |
| Transparent |
0 or 1 |
File path resolved relative to client's BasePath setting.
Panel
| Property |
Format |
| Caption |
Quoted string |
| BevelOuter |
0-2 (bvNone, bvLowered, bvRaised) |
| BevelInner |
0-2 (bvNone, bvLowered, bvRaised) |
| BorderStyle |
0-1 (bsNone, bsSingle) |
ScrollBar
| Property |
Format |
| Kind |
0 (sbHorizontal), 1 (sbVertical) |
| Min |
Integer |
| Max |
Integer |
| Position |
Integer |
| LargeChange |
Integer |
| SmallChange |
Integer |
MediaPlayer
| Property |
Format |
| FileName |
Quoted string (media file path) |
| DeviceType |
Quoted string (e.g., dtWaveAudio) |
| AutoOpen |
0 or 1 |
| Command |
Quoted string (pseudo-property) |
File path resolved relative to client's BasePath setting.
Command triggers a method call rather than setting a value. Valid
commands: Open, Play, Stop, Close, Pause, Resume,
Rewind, Next, Previous.
MainMenu, PopupMenu
No type-specific properties. One MainMenu per form (auto-attached).
PopupMenu is associated with controls via the common PopupMenu
property.
| Property |
Format |
| Caption |
Quoted string |
| Parent |
Integer (ctrlId of parent menu/item) |
| Checked |
0 or 1 |
| ShortCut |
Integer (Delphi ShortCut value) |
RadioGroup
| Property |
Format |
| Caption |
Quoted string |
| Items |
Quoted string (\n-delimited) |
| ItemIndex |
Integer (-1 = none) |
| Columns |
Integer |
BitBtn
| Property |
Format |
| Caption |
Quoted string |
| Kind |
0-10 (bkCustom..bkAll) |
| Layout |
0-3 (blGlyphLeft..blGlyphBottom) |
| NumGlyphs |
Integer (1-4) |
SpeedButton
| Property |
Format |
| Caption |
Quoted string |
| Layout |
0-3 (blGlyphLeft..blGlyphBottom) |
| NumGlyphs |
Integer (1-4) |
| GroupIndex |
Integer (0 = no group) |
| Down |
0 or 1 |
| AllowAllUp |
0 or 1 |
TabSet, Notebook, TabbedNotebook
| Property |
Format |
| Items |
Quoted string (\n-delimited) |
| ItemIndex |
Integer (-1 = none) |
MaskEdit
| Property |
Format |
| Text |
Quoted string |
| MaxLength |
Integer |
| EditMask |
Quoted string |
Outline
| Property |
Format |
| Items |
Quoted string (\n-delimited) |
| OutlineStyle |
0-6 (osText..osTreePictureText) |
Bevel
| Property |
Format |
| Shape |
0-5 (bsBox..bsRightLine) |
| Style |
0-1 (bsLowered, bsRaised) |
| Property |
Format |
| Items |
Quoted string (\n-delimited) |
ScrollBox
No type-specific properties.
StringGrid
| Property |
Format |
| ColCount |
Integer (default 5) |
| RowCount |
Integer (default 5) |
| FixedCols |
Integer (default 1) |
| FixedRows |
Integer (default 1) |
| DefaultColWidth |
Integer (pixels) |
| DefaultRowHeight |
Integer (pixels) |
| Options |
Integer (bitmask, see below) |
| Cells |
Quoted string (tab-delimited cols, \n-delimited rows) |
| Cell |
Quoted string (col,row,value) |
Options is an integer bitmask of TGridOption values:
| Bit |
Value |
Option |
| 0 |
0x0001 |
goFixedVertLine |
| 1 |
0x0002 |
goFixedHorzLine |
| 2 |
0x0004 |
goVertLine |
| 3 |
0x0008 |
goHorzLine |
| 4 |
0x0010 |
goRangeSelect |
| 5 |
0x0020 |
goDrawFocusSelected |
| 6 |
0x0040 |
goRowSizing |
| 7 |
0x0080 |
goColSizing |
| 8 |
0x0100 |
goRowMoving |
| 9 |
0x0200 |
goColMoving |
| 10 |
0x0400 |
goEditing |
| 11 |
0x0800 |
goTabs |
| 12 |
0x1000 |
goThumbTracking |
Cells is a bulk-load property: columns are tab-delimited, rows are
\n-delimited. Cell is an individual update: "col,row,value".
String Encoding
- Strings in the protocol are always double-quoted.
- Escape sequences:
\" (literal quote), \\ (literal backslash),
\n (newline), \r (carriage return), \t (tab).
- Multi-line values (Memo text, ListBox items) use
\n within a single
quoted string.
Transport Layer
The protocol is transport-agnostic. Messages are delivered via:
int ReadMessage(char *buf, int maxLen); // returns bytes read, 0 = none
void WriteMessage(const char *buf); // sends complete message
Current transport: newline-delimited serial (messages terminated by CR+LF).
The transport handles framing; protocol layer never sees delimiters.