Skip to content
Open

X11 #54

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
219 commits
Select commit Hold shift + click to select a range
3999c58
feat(x11): Initial implementation of in-browser X11 forwarding server
Oct 23, 2025
03267ac
refactor(x11): Separate message structs into dedicated files
google-labs-jules[bot] Nov 5, 2025
52539aa
Refactor: Separate X11 message structs into individual files
google-labs-jules[bot] Nov 5, 2025
51d3d3e
Refactor request parsing
rthellend Nov 5, 2025
7fb45c9
Add parsing tests with real world data
rthellend Nov 5, 2025
407c29e
feat(x11): add comprehensive parsing tests for all request types
google-labs-jules[bot] Nov 5, 2025
5d85be5
feat(x11): Implement all remaining X11 requests
google-labs-jules[bot] Nov 6, 2025
abf518f
feat(x11): Implement all remaining X11 requests
google-labs-jules[bot] Nov 6, 2025
d57559c
feat(x11): Implement all missing X11 error and reply types
google-labs-jules[bot] Nov 6, 2025
42d8c37
Clean up AllocNamedColorRequest; go fmt
rthellend Nov 6, 2025
0dfa3f2
feat: Add slice boundary checks to X11 request parsing
google-labs-jules[bot] Nov 6, 2025
153631a
feat(x11): Add comprehensive tests for reply messages
google-labs-jules[bot] Nov 6, 2025
bd5fe9c
feat: Implement remaining X11 request types (WIP)
google-labs-jules[bot] Nov 6, 2025
dda2422
Fix previous commit
rthellend Nov 6, 2025
62d3618
feat(x11): Implement remaining X11 request parsers
google-labs-jules[bot] Nov 6, 2025
42b4a29
feat(x11): Implement remaining X11 request parsers
google-labs-jules[bot] Nov 6, 2025
cdc05f2
Improve color management
rthellend Nov 7, 2025
e417f41
Fix QueryColors
rthellend Nov 7, 2025
0242791
feat(x11): add stubs for missing request types and sort cases
google-labs-jules[bot] Nov 7, 2025
dbc94c8
feat(x11): Implement CreateCursor and RecolorCursor
google-labs-jules[bot] Nov 7, 2025
191fe18
feat(x11): Implement CopyPlane, SetDashes, and SetClipRectangles
google-labs-jules[bot] Nov 7, 2025
53789df
fix debug
Nov 8, 2025
91e7c79
Handle length < 2 correctly
rthellend Nov 8, 2025
35e6541
Send LengthError when request is short
rthellend Nov 8, 2025
a5d5363
feat(x11): Implement GetGeometryRequest for root window
Nov 8, 2025
7ea4aa4
feat(x11): Implement GetGeometryRequest for root window
Nov 8, 2025
0519eca
feat(x11): Implement Graphics Context drawing features
google-labs-jules[bot] Nov 8, 2025
81dc582
feat(x11): Implement Graphics Context parsing and drawing
google-labs-jules[bot] Nov 8, 2025
01bdb28
Fix the broken
rthellend Nov 8, 2025
c689ed0
Merge branch 'x11-checkpoint-20251105' of https://github.com/c2FmZQ/s…
Nov 8, 2025
dad68fc
CreateGCWithAttributes -> CreateGC
rthellend Nov 8, 2025
8bae675
refactor(x11): merge applyClipping and applyDashes into applyGC
google-labs-jules[bot] Nov 8, 2025
23b7412
Fix CopyPlane to Use All GC Components
google-labs-jules[bot] Nov 9, 2025
8f7c360
fix(x11): Implement GC font changes and logical operations
google-labs-jules[bot] Nov 9, 2025
661cf2a
Simplify compareOperations
rthellend Nov 9, 2025
e3455db
feat(x11): Implement correct mouse event handling
google-labs-jules[bot] Nov 9, 2025
91a50dd
feat: Implement X11 keyboard mapping
google-labs-jules[bot] Nov 9, 2025
babfd9a
feat(x11): Implement EnterNotify and LeaveNotify events
google-labs-jules[bot] Nov 9, 2025
f85eed2
feat(x11): Implement event masks and input grabbing
google-labs-jules[bot] Nov 9, 2025
7c26b13
feat(x11): Implement QueryTextExtents and improve QueryFont
google-labs-jules[bot] Nov 9, 2025
04309b4
feat(x11): Implement ReparentWindow, CirculateWindow, DestroySubwindo…
google-labs-jules[bot] Nov 9, 2025
5dbc2ad
feat(x11): Implement passive input grabs for GrabKey
google-labs-jules[bot] Nov 9, 2025
1ecb34a
Add X11 WASM unit tests
rthellend Nov 9, 2025
bb0ec94
Merge go/internal/x11/wasm_tests and go/internal/x11
rthellend Nov 9, 2025
e043c4e
feat(x11): Implement GetWindowAttributes request
google-labs-jules[bot] Nov 9, 2025
18ba642
feat(x11): Implement GetWindowAttributes request
google-labs-jules[bot] Nov 9, 2025
a24c308
Fix test failure detection
rthellend Nov 9, 2025
5cdb628
ignore tests.x11.wasm
rthellend Nov 9, 2025
1ddf628
feat: Add visual snapshot testing for X11 WASM
Nov 9, 2025
d185f9d
chore: Add .gemini/ to .gitignore
Nov 9, 2025
196bbdd
Merge remote-tracking branch 'origin/feat-get-window-attributes' into…
rthellend Nov 9, 2025
ea33b5e
fix(x11): correct event sequence numbering
google-labs-jules[bot] Nov 9, 2025
9fa5d4d
refactor(x11): eliminate eval from visual tests
google-labs-jules[bot] Nov 9, 2025
ba8e332
fix(x11): resolve race condition in visual tests
google-labs-jules[bot] Nov 10, 2025
f6751a6
Fix X11 WASM unit tests
google-labs-jules[bot] Nov 10, 2025
4b44f2e
feat(x11): Add test coverage for drawing features
google-labs-jules[bot] Nov 10, 2025
e763282
fix test harness
rthellend Nov 10, 2025
5177ab3
feat(x11): Implement GC logical operations
google-labs-jules[bot] Nov 11, 2025
c3ba9a7
feat(x11): Implement GC logical operations
google-labs-jules[bot] Nov 11, 2025
ebe40f5
feat: Add X11 authorization check
google-labs-jules[bot] Nov 11, 2025
8c2278c
Fix broken auth
rthellend Nov 11, 2025
10fe9e2
feat(x11): Implement proper GetProperty reply handling
Nov 11, 2025
98a3d33
fix(x11): Correct GetProperty reply value length
Nov 11, 2025
be4aa5f
Fix: Resolve compilation errors and test failures in x11 package
Nov 11, 2025
0b40520
fix(x11): Correct GrabButton and UngrabButton request parsing
Nov 11, 2025
68f2805
Log all data in client.send
rthellend Nov 11, 2025
1fd5947
Fix X11 request parsing errors
google-labs-jules[bot] Nov 11, 2025
c7ffb2c
Fix X11 request parsing and error handling
google-labs-jules[bot] Nov 12, 2025
4ac2b20
Fix: X11 keyEvent interpreted as Error by client
Nov 12, 2025
4301fc7
Add showMessage
rthellend Nov 12, 2025
b5b0c87
Rollback logical operations
rthellend Nov 12, 2025
9af4fd0
Implemented the `applyBitwiseOperation` function and updated all draw…
google-labs-jules[bot] Nov 12, 2025
a6052d2
feat: Return Length error on extra bytes in requests
google-labs-jules[bot] Nov 13, 2025
90701da
Implemented the `applyBitwiseOperation` function and updated all draw…
google-labs-jules[bot] Nov 13, 2025
ec8982a
feat: Implement GCFunction logical operations
google-labs-jules[bot] Nov 13, 2025
fd9435a
feat: Implement GCFunction logical operations
google-labs-jules[bot] Nov 13, 2025
c018205
feat: Return Length error on extra bytes in requests
google-labs-jules[bot] Nov 13, 2025
2f235d2
Merge remote-tracking branch 'origin/jules-len-error-extra-bytes' int…
rthellend Nov 13, 2025
42f0462
Fix parsing and tests
rthellend Nov 13, 2025
4f12d3c
feat: Implement BIG-REQUESTS X11 extension
google-labs-jules[bot] Nov 13, 2025
b152c52
Fix queryExtensionReply
rthellend Nov 13, 2025
2ab63fe
Fix queryExtensionReply
rthellend Nov 13, 2025
16ef87a
feat: Clean up comments in request_messages.go
rthellend Nov 13, 2025
0e74c12
feat(x11): Implement CopyColormapAndFree request
google-labs-jules[bot] Nov 13, 2025
1856129
feat: Implement stubbed X11 requests
google-labs-jules[bot] Nov 13, 2025
d137048
create output dir
rthellend Nov 13, 2025
3e5bf6d
feat(x11): Implement keyboard, pointer, and selection features
google-labs-jules[bot] Nov 13, 2025
8bea7f5
feat(x11): Implement keyboard, pointer, and selection features
google-labs-jules[bot] Nov 13, 2025
69d087c
Merge remote-tracking branch 'origin/feature-x11-keyboard-pointer-sel…
rthellend Nov 13, 2025
f5c9358
feat(x11): update keysym.go with a complete keycode-to-keysym map
google-labs-jules[bot] Nov 13, 2025
400aa84
feat: Hook up KeyboardMapping requests
google-labs-jules[bot] Nov 14, 2025
50e6c97
feat: Hook up KeyboardMapping requests and refactor tests
google-labs-jules[bot] Nov 14, 2025
f6eb235
feat(x11): Implement XInputExtension and ListExtensions
google-labs-jules[bot] Nov 14, 2025
3f9d109
feat(xinput): Hook up XInput with the wasm frontend
google-labs-jules[bot] Nov 14, 2025
67c928f
feat: Hook up XInput with the wasm frontend
google-labs-jules[bot] Nov 14, 2025
0a8dce9
Fix test
rthellend Nov 14, 2025
414c368
feat: Implement XInput grab/ungrab device
google-labs-jules[bot] Nov 15, 2025
b972e95
Fix test
rthellend Nov 15, 2025
596b556
feat(x11): Implement several XInput opcodes
google-labs-jules[bot] Nov 15, 2025
d913143
Fix tests
Nov 16, 2025
207fb56
feat: refactor x11 protocol messages into wire package
google-labs-jules[bot] Nov 18, 2025
3400a4f
Finish refactoring & fix tests
rthellend Nov 18, 2025
ef4b05e
Fix: Return correct error for unsupported XInput requests
Nov 18, 2025
4cade4f
feat: Add all missing XInput requests
google-labs-jules[bot] Nov 18, 2025
442d0cb
feat: Add all missing XInput requests
google-labs-jules[bot] Nov 18, 2025
5d5163e
fix tests
Nov 19, 2025
b248bfa
Merge branch 'add-xinput-requests' into x11-checkpoint-20251105
rthellend Nov 19, 2025
626c0d9
Fix(x11): Resolve build errors in xinput.go files
Nov 19, 2025
78f4b84
Start implementing XI2 parsing
rthellend Nov 20, 2025
bcd8aa3
Fix test data
rthellend Nov 19, 2025
98f42da
feat(x11): Implement XInput2 property and event opcodes
google-labs-jules[bot] Nov 20, 2025
b86da75
v0.8.2
rthellend Nov 20, 2025
05e45f3
I have successfully implemented the parsing and handling for `XGrabDe…
google-labs-jules[bot] Nov 20, 2025
e04d9fd
feat(x11): Implement XInput extension
google-labs-jules[bot] Nov 20, 2025
63c9f73
Fix GetExtensionVersionRequest
rthellend Nov 20, 2025
e06da97
feat(x11): Add Parse functions for Event and Error structs
google-labs-jules[bot] Nov 21, 2025
11c3347
I have implemented the `Parse` functions for all the `Reply` structs …
google-labs-jules[bot] Nov 21, 2025
6aee0fd
feat: Add Parse functions for Reply structs
google-labs-jules[bot] Nov 21, 2025
2674c88
Add skeleton for ReadServerMessages
rthellend Nov 21, 2025
465ff91
feat(x11): finish implementation of ReadServerMessages and ParseReply
google-labs-jules[bot] Nov 21, 2025
f15cbc4
I have successfully implemented the `EncodeMessage` method for all re…
google-labs-jules[bot] Nov 22, 2025
48cf3e5
I have successfully implemented the `EncodeMessage` method for all re…
google-labs-jules[bot] Nov 22, 2025
a7a991a
Refactor ParseReply
rthellend Nov 22, 2025
931e716
feat(x11): Add EncodeMessage to all X11 wire requests
google-labs-jules[bot] Nov 22, 2025
094030a
Merge remote-tracking branch 'origin/encode-requests' into x11-checkp…
rthellend Nov 22, 2025
c077ed7
refactor(x11): Update tests to use Request structs and EncodeMessage
google-labs-jules[bot] Nov 22, 2025
636ac1d
feat: update x11 tests
google-labs-jules[bot] Nov 22, 2025
7b4f6df
refactor(x11): Update tests to use wire.ParseServerMessages
google-labs-jules[bot] Nov 22, 2025
eab834f
test(x11): Add comprehensive event delivery tests
google-labs-jules[bot] Nov 23, 2025
60f5975
feat(x11): Add comprehensive event delivery tests and fix grab logic
google-labs-jules[bot] Nov 23, 2025
9582a63
fix(x11): Correct QueryFontReply encoding and remove outdated TODO
Nov 23, 2025
d77510e
Implement XInput grab logic and add comprehensive delivery tests
google-labs-jules[bot] Nov 23, 2025
a9a4005
refactor(x11): use Opcodes struct in NewError
google-labs-jules[bot] Nov 23, 2025
1e479f2
Add godoc comments to x11/wire package
google-labs-jules[bot] Nov 23, 2025
c0342b6
Merge branch 'x11-checkpoint-20251105' of https://github.com/c2FmZQ/s…
Nov 23, 2025
6869a0c
Refactor X11 frontend to use offscreen canvas rendering
google-labs-jules[bot] Nov 23, 2025
862c823
Refactor X11 frontend to use offscreen canvas rendering
google-labs-jules[bot] Nov 23, 2025
d0d49aa
Fix XISelectEvents request parsing for XInput2
google-labs-jules[bot] Nov 24, 2025
089b22c
Implement XI 2.x event delivery for xeyes
google-labs-jules[bot] Nov 24, 2025
fd1acb3
Expand available X11 fonts and improve XLFD parsing
google-labs-jules[bot] Nov 24, 2025
8955fdd
Implement XIQueryPointer and improve XInput2 mouse event encoding
google-labs-jules[bot] Nov 24, 2025
a9a2ec2
Implement XInput 2 server-side grabs and protocol completion
google-labs-jules[bot] Nov 24, 2025
c6b40d5
Implement missing X11 protocol requests
google-labs-jules[bot] Nov 24, 2025
5e78a9a
Fix event handling timestamps and complete grab implementation
google-labs-jules[bot] Nov 24, 2025
07c75ed
Standardize X11 server error handling
google-labs-jules[bot] Nov 24, 2025
dcf7069
fix(x11): Resolve xterm "no text" issue by improving font fallback
Nov 24, 2025
37e92f2
Merge touchback:gemini/sshterm into x11-checkpoint-20251105
rthellend Nov 24, 2025
f36535d
Refactor Atoms/Properties to x11Server and implement Selections
google-labs-jules[bot] Nov 24, 2025
4aff2d9
Merge remote-tracking branch 'origin/x11-atoms-selections' into x11-c…
rthellend Nov 24, 2025
4f41d7d
Standardize X11 server error handling and fix Root Window crashes
google-labs-jules[bot] Nov 24, 2025
fc860ad
Merge remote-tracking branch 'origin/x11-error-handling' into x11-che…
rthellend Nov 24, 2025
439ccd6
test(x11): Update font mapping tests for DejaVu Sans Mono
Nov 24, 2025
5524c1e
Merge touchback:gemini/sshterm into x11-checkpoint-20251105
rthellend Nov 24, 2025
48813f6
Fix GetProperty compliance and ChangeProperty race/events
google-labs-jules[bot] Nov 24, 2025
93b0af8
Merge remote-tracking branch 'origin/x11-atoms-selections' into x11-c…
rthellend Nov 24, 2025
4d0d080
Fix ChangeProperty request parsing to correctly calculate data length…
google-labs-jules[bot] Nov 24, 2025
f43b666
Fix invisible text in X11 WASM frontend by correcting resource lookup
google-labs-jules[bot] Nov 24, 2025
4abd05c
Fix X11 WASM text rendering: background fill and resource lookups
google-labs-jules[bot] Nov 24, 2025
a34602b
Fix X11 WASM text rendering: synchronize offscreen canvas to visible …
google-labs-jules[bot] Nov 24, 2025
bccae3f
Implement XInput 2 Raw Events (XI_RawMotion)
google-labs-jules[bot] Nov 25, 2025
34197e4
Merge remote-tracking branch 'origin/xinput-raw-motion' into x11-chec…
rthellend Nov 25, 2025
3e8c0e6
Fix: Correct nDevices offset in ListInputDevices reply
google-labs-jules[bot] Nov 25, 2025
81c2724
refactor: Break down monolithic handleRequest function
google-labs-jules[bot] Nov 25, 2025
82b0a7c
fix(x11): Correct hardcoded values and fix test simulation
google-labs-jules[bot] Nov 25, 2025
2f08e1e
Fix: Clarify and test XInput raw event implementation
google-labs-jules[bot] Nov 25, 2025
09afe4a
feat(x11): Add comments to AllocColorCells and AllocColorPlanes
google-labs-jules[bot] Nov 25, 2025
61927c9
docs: Update go/internal/x11/README.md with current package structure…
Nov 25, 2025
42b8bfc
feat(x11): Implement correct X11 request handlers
google-labs-jules[bot] Nov 25, 2025
a91be38
feat(x11): make server and screen properties dynamic
google-labs-jules[bot] Nov 26, 2025
ee6c05a
feat(x11): make server and screen properties dynamic
google-labs-jules[bot] Nov 26, 2025
9d0d165
Fix: Correct X11 protocol simplifications
google-labs-jules[bot] Nov 26, 2025
522fe0f
This commit adds support for StaticGray, GrayScale, StaticColor, Pseu…
google-labs-jules[bot] Nov 26, 2025
95ef1b6
feat(x11): Enhance request handlers and drawing performance
google-labs-jules[bot] Nov 26, 2025
ed1af10
feat: Add support for PseudoColor visual and implement color allocation
google-labs-jules[bot] Nov 26, 2025
1206b08
feat: Add support for PseudoColor visual and implement color allocation
google-labs-jules[bot] Nov 26, 2025
76bdfd4
feat(x11): Implement Child field in TranslateCoords reply with z-inde…
google-labs-jules[bot] Nov 26, 2025
53988f6
fix(x11): correct XIQueryPointer window traversal
google-labs-jules[bot] Nov 26, 2025
5daef04
refactor: Implement X11 resource base ID
google-labs-jules[bot] Nov 27, 2025
abefa2c
refactor(x11): Implement client-specific resource ID allocation
google-labs-jules[bot] Nov 27, 2025
f1ded3f
xid string
rthellend Nov 27, 2025
3e3692b
Fix X11 simulation tests and window creation handler
google-labs-jules[bot] Nov 27, 2025
1d5b039
Refactor X11 test simulation to use wire package
google-labs-jules[bot] Nov 28, 2025
91e69d3
Fix tests
rthellend Nov 28, 2025
e1aea74
Implement X11 grab/ungrab and optimize GC logical ops
Jan 23, 2026
f42e67a
X11: Optimize rendering and improve fidelity (fonts, dashes)
Jan 24, 2026
069b57c
X11: Fix default colormap initialization and optimize setLineDash
Jan 24, 2026
0b78748
X11: Implement GrabPointer/UngrabPointer, PointerRoot fix, and E2E tests
Jan 24, 2026
3679333
feat(x11): complete high-fidelity implementation and add real-app tes…
rthellend May 18, 2026
fd39651
test(x11): add real-app integration test case with custom config
rthellend May 18, 2026
fcd9c5e
test(x11): add standalone real-app integration test environment
rthellend May 20, 2026
9bc7a4f
test(x11): expand standalone integration test to multiple applications
rthellend May 20, 2026
c002a23
test(x11): position windows and expand viewport in standalone test
rthellend May 20, 2026
ab6b4c7
Remove X11-REAL-TEST-PLAN.md
rthellend May 20, 2026
30f93e2
feat(x11): implement event synchronization and enhance cursor support
rthellend May 20, 2026
fb61f98
fix(x11): address code review issues and protocol compliance
rthellend May 20, 2026
8d1ac5d
fix(x11): resolve compilation error and correct cursor mappings
rthellend May 20, 2026
af5f5be
docs(x11): consolidate X11 implementation details into X11.md
rthellend May 20, 2026
3cfa82c
Merge remote-tracking branch 'origin/main' into x11
rthellend May 20, 2026
878e4a9
fix(x11): address review comments and improve protocol compliance
rthellend May 20, 2026
999da78
Re-add WASM tests
rthellend May 21, 2026
b14a8a0
fix build tags
rthellend May 21, 2026
167ead9
go fmt
rthellend May 21, 2026
b31c498
Remove x11-apps
rthellend May 21, 2026
27bdc08
Address PR feedback: fix coordinate casting, rectangle encoding, and …
rthellend May 21, 2026
8308967
Fix bugs introduced in previous commit: type mismatches and operation…
rthellend May 21, 2026
034ea15
Improve test robustness and X11 request validation
rthellend May 21, 2026
8df1eda
Fix X11 standalone test hang by using correct scanline pad
rthellend May 21, 2026
7102afb
Fix X11 PutImage validation and rendering for various depths
rthellend May 21, 2026
d206293
fix(x11): address protocol compliance issues and integer overflows
rthellend May 21, 2026
7b0d2a6
go fmt
rthellend May 21, 2026
5e7e2df
fix(x11): address security, concurrency, and protocol compliance issues
rthellend May 21, 2026
817a8d2
fix(x11): refactor stacking model and address protocol compliance issues
rthellend May 22, 2026
0a42050
test(x11): add protocol compliance tests and fix per-client event masks
rthellend May 22, 2026
fd349ce
test(x11): fix test window instantiations to use per-client event masks
rthellend May 22, 2026
c8ce63d
Resolve PR 54 code review feedback and server data race issues
rthellend May 22, 2026
a3026a5
fix(x11,webauthn): resolve PR 54 safety, overflow, and cryptographic …
rthellend May 22, 2026
a14d6e1
fix(x11): resolve PR 54 Round 3 review comments
rthellend May 22, 2026
3c7b311
x11: address Round 4 review comments on PR #54
rthellend May 22, 2026
f5754cb
Address round 5 code review comments on PR #54
rthellend May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
output/
ssh.wasm
tests.wasm
tests.x11.wasm
wasm_exec.js
node_modules
xterm.css
xterm.js
xterm.mjs
js_tests/.npm-cache
.gemini/
/testserver
tests/x11-standalone/*.png
2 changes: 1 addition & 1 deletion .goversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.26.2
1.26.3
98 changes: 98 additions & 0 deletions X11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# X11 Forwarding Implementation in SSHTERM

This document provides a comprehensive overview of the X11 server implementation in `sshterm`. It enables running graphical X11 applications on a remote server and displaying their interfaces directly within the web browser.

## Architecture

The system follows a distributed server-client model where the browser itself acts as the X11 server.

### 1. X11 Server (Go/WASM)
The core logic is implemented in Go and compiled to WebAssembly (WASM).
* **Protocol Handling:** Manages the X11 wire protocol, parsing incoming requests from clients and serializing replies, events, and errors.
* **State Management:** Maintains the authoritative state of windows, graphics contexts (GCs), properties, atoms, and resource allocations.
* **Event Routing:** Distributes input events (mouse, keyboard) to the correct clients and windows based on focus and grabs.
* **Abstraction:** Communicates with the rendering layer via the `X11FrontendAPI` interface, ensuring the core logic remains platform-independent.

### 2. Frontend Renderer (HTML5 Canvas)
The rendering layer is implemented as a Go-WASM bridge to the browser's DOM.
* **Canvas Windows:** Each top-level X11 window is represented by an HTML5 `<canvas>` element.
* **WASM-JS Bridge:** Uses `syscall/js` to translate Go drawing commands into high-performance JavaScript Canvas API calls.
* **Window Manager:** A lightweight internal window manager handles decorations (title bars, close buttons), dragging, and resizing for top-level windows.

### 3. SSH Integration
X11 traffic is forwarded over standard SSH channels.
* **Forwarding:** When the `-X` flag is used, `sshterm` requests X11 forwarding from the remote server (`x11-req`).
* **Channel Management:** The application listens for incoming X11 channels and pipes them directly into the internal X11 server instance.

---

## Core Components

### `x11Server` (`go/internal/x11/x11.go`)
The central engine that coordinates client connections and resource management. It handles the initial handshake (supporting both Big and Little Endian) and dispatches opcodes to their respective handlers.

### `wire` Package (`go/internal/x11/wire/`)
An exhaustive definition of the X11 protocol. It contains structs and serialization logic for over 100 requests, replies, events, and errors. It ensures strict protocol compliance and robust input validation.

### `X11FrontendAPI`
A decoupled interface defining all visual and interactive operations:
* **Drawing:** `PolyLine`, `PolyFillRectangle`, `FillPoly`, `PolyArc`, `PutImage`, `ImageText8/16`, etc.
* **Windowing:** `CreateWindow`, `MapWindow`, `ConfigureWindow`, `SetWindowCursor`.
* **Resources:** `CreatePixmap`, `CreateGC`, `OpenFont`.
* **Interaction:** `GrabPointer`, `GrabKeyboard`, `AllowEvents`.

---

## Rendering Engine

### Logical Operations
X11 defines 16 logical functions for drawing (`GXcopy`, `GXxor`, `GXand`, etc.). `sshterm` uses a dual-path approach:
* **Native Path:** Common operations like `GXcopy` and `GXxor` are mapped to Canvas `globalCompositeOperation` (e.g., `source-over`, `difference`) for hardware-accelerated performance.
* **Software Path:** For complex operations not supported by Canvas, an optimized software renderer performs bitwise manipulation on `Uint32Array` views of the pixel data.

### Optimizations
* **Dirty Region Tracking:** The server tracks modified areas of windows to minimize redrawing and data transfer.
* **Bulk Memory Copy:** `PutImage` avoids per-pixel Go-to-JS calls by passing raw byte slices and using `Uint8ClampedArray.set()` for high-speed transfers.
* **Throttling:** High-frequency events like `mousemove` are throttled to 60FPS to prevent flooding the WASM bridge.

---

## Input & Interaction

### Grabs and Synchronization
* **Active Grabs:** Implements `GrabPointer` and `GrabKeyboard` using the browser's `setPointerCapture` API. This ensures that menus and popups correctly capture interaction even outside their window boundaries.
* **Event Queuing:** To support `AllowEvents` and synchronous grabs, the server maintains internal event queues. During a synchronous grab, events are buffered and only released when the client explicitly requests them, preventing race conditions in modal dialogs.

### Fonts
X11 Logical Font Descriptions (XLFD) are mapped to modern CSS web fonts. The server generates accurate font metrics (ascent, descent, character widths) to ensure clients can correctly calculate their layout.

### Clipboard
X11 selections (`CLIPBOARD`, `PRIMARY`) are integrated with the browser's `navigator.clipboard` API. This allows seamless copy-paste between remote graphical applications and local browser/OS applications.

---

## Extensions Support

* **BigRequests:** Fully supported, allowing for requests larger than 256KB.
* **XInput / XInput2:** Implements device state queries, extended event masks, and raw motion events.
* **MIT-SHM:** Reported as unsupported, forcing clients to fall back to standard `PutImage`/`GetImage` paths which are optimized within the WASM environment.

---

## Security

* **MIT-MAGIC-COOKIE-1:** Standard X11 authentication is implemented to verify connections.
* **Isolation:** The X11 server runs entirely within the browser's security sandbox. It has no access to the local filesystem or network beyond what the SSH session and browser APIs allow.

---

## Testing Strategy

### 1. Unit Tests
Located in `go/internal/x11/`, these tests verify protocol parsing, resource state, and logic. They use a mock frontend to assert that X11 requests result in the expected internal state changes.

### 2. Visual Tests
Automated WASM-based tests (`visual_test.go`) that render primitives to a canvas and verify the result by comparing pixel data against expected values. This ensures high-fidelity rendering for all GC functions and drawing modes.

### 3. Integration Tests
Headless browser tests (`tests/run-headless-tests.sh`) use `chromedp` to drive the full application. They connect to a mock SSH server, launch real X11 applications (like `xterm` or `xeyes`), and verify that windows appear and respond to injected input correctly.
6 changes: 5 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#!/bin/bash -e

cd $(dirname $0)

mkdir -p output
exec &> >(tee output/build.log)

if [[ ! -f docroot/xterm.mjs ]]; then
echo "Updating xtermjs..."
./xterm/update.sh
fi
echo "Updating ssh.wasm..."
./go/build.sh
./go/build.sh "$@"
echo "Files in ./docroot/"
ls ./docroot/
echo "Done"
4 changes: 1 addition & 3 deletions docroot/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,4 @@

import { TabManager } from './ssh.mjs';

window.addEventListener('load', () => {
new TabManager(document.getElementById('terminal'));
});
new TabManager(document.getElementById('terminal'));
13 changes: 10 additions & 3 deletions docroot/ssh.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import { Terminal, FitAddon } from './xterm.mjs';
function isTest() {
return window.location.pathname.indexOf('tests.html') !== -1;
}
function isX11Test() {
return window.location.pathname.indexOf('tests.html') !== -1 && window.location.search.indexOf('x11') !== -1;
}

class TerminalManager {
constructor(elem, setTitle, onBell) {
Expand Down Expand Up @@ -183,18 +186,22 @@ export class TabManager {
this.selectScreen(b.id);

const term = terminalManager.getTerm();
const cfg = await fetch('config.json')
const configFile = isX11Test() ? 'tests.x11.config.json' : 'config.json';
const cfg = await fetch(configFile)
.then(r => {
if (r.ok) return r.json();
return {};
})
.catch(e => {
term.writeln('\x1b[31mError reading config.json:\x1b[0m');
term.writeln('\x1b[31mError reading ' + configFile + ':\x1b[0m');
term.writeln('\x1b[31m' + e.message + '\x1b[0m');
term.writeln('');
return {};
});
cfg.term = term;
if (isX11Test()) {
cfg.forwardX11 = true;
}

const app = await window.sshApp.start(cfg);
this.screens[b.id].close = app.close;
Expand Down Expand Up @@ -240,6 +247,6 @@ window.sshApp.ready = new Promise(resolve => {
});

const go = new Go();
const wasmFile = isTest() ? 'tests.wasm' : 'ssh.wasm';
const wasmFile = isTest() && !isX11Test() ? 'tests.wasm' : 'ssh.wasm';
WebAssembly.instantiateStreaming(fetch(wasmFile), go.importObject)
.then(r => go.run(r.instance));
25 changes: 25 additions & 0 deletions docroot/tests.x11.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"persist": false,
"theme": "dark",
"endpoints": [{
"name": "test-server",
"url": "./websocket?cert=true"
}],
"certificateAuthorities": [{
"name": "test-ca",
"publicKey": "===CAKEY===",
"hostnames": [ "test-server" ]
}],
"generateKeys": [{
"name": "default",
"type": "ed25519",
"identityProvider": "/cert",
"addToAgent": true
}],
"autoConnect": {
"username": "testuser",
"hostname": "test-server",
"identity": "default",
"forwardX11": true
}
}
50 changes: 50 additions & 0 deletions docroot/tests.x11.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!doctype html>
<!--
https://github.com/c2FmZQ/sshterm

MIT License

Copyright (c) 2025 TTBT Enterprises LLC
Copyright (c) 2025 Robin Thellend <rthellend@rthellend.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<html>
<head>
<title>SSH Terminal X11 Tests</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="content-security-policy" content="default-src 'self'; style-src 'unsafe-inline' 'self'; script-src 'unsafe-eval' 'self';" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/png" href="ssh.png" />
<script type="module" src="tests.x11.mjs"></script>
<style>
html, body {
height: 100%;
margin: 0;
background-color: black;
}
#terminal {
height: 100%;
}
</style>
</head>
<body>
<div id="terminal"></div>
</body>
</html>
51 changes: 51 additions & 0 deletions docroot/tests.x11.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* MIT License
*
* Copyright (c) 2025 TTBT Enterprises LLC
* Copyright (c) 2025 Robin Thellend <rthellend@rthellend.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import './wasm_exec.js';

window.sshApp = {};
window.sshApp.exited = null;
window.sshApp.ready = new Promise(resolve => {
window.sshApp.sshIsReady = () => {
console.log('SSH WASM is ready');
resolve();
};
});

const go = new Go();
const wasmFile = 'tests.x11.wasm';
WebAssembly.instantiateStreaming(fetch(wasmFile), go.importObject)
.then(r => go.run(r.instance));

window.sshApp.ready
.then(() => window.sshApp.start())
.then(res => {
console.log(`Exit status ${res}`);
let div = document.createElement('div');
div.id = 'x11-wasm-tests-done';
div.textContent = 'X11 WASM TESTS DONE';
div.style = 'position: absolute; top: 0; left: 0; color: white; background-color: black;';
document.body.appendChild(div);
});
Loading
Loading