Desktop PoC (H R1-R3): image output + returnBuffer + DESKTOP-POC.md
The adapter round-trip is now a complete, documented desktop proof of concept: - R2: the adapter stand-in writes the painted shared buffer to an image (out/jihad-poc-render.ppm) and returns the buffer to the daemon (ReturnBuffer 0x150d, wired: asyncCmdReturnBuffer -> BrowserPageGoanna:: returnBuffer). docs/jihad-poc-render.png shows the correct render (blue page, white "Adapter round-trip OK") produced end-to-end through the daemon. - R1/R3 were already proven (daemon builds with LunaService compiled out; real page renders with the load lifecycle in order) -- ROUND-TRIP PASS. docs/DESKTOP-POC.md is the single documented entry point: prerequisites, the engine build, the daemon+adapter round-trip, the focused capability tests, and R4 recorded as [human-review] (no desktop Enyo runtime -> the R2/R3 harness is the Phase-1 acceptance vehicle). Desktop Build & PoC: R1-R3 complete; R4 recorded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
28bb52f98c
commit
36e85137fd
7 files changed
+142
-2
No files matched your search
@@ -19,7 +19,7 @@ last_edited: "2026-06-30"
|
||||
| Input Bridging | **click/key/mouse verified; touch wired** | 5 | ClickAt/KeyEvent/MouseEvent via nsIDOMWindowUtils, wired through daemon; VERIFIED (click fires onclick, INPUT PASS). TouchEvent (SendTouchEvent) implemented + wired but the offscreen desktop GTK widget doesn't route synthetic touch to the DOM — on-device verification pending. Gesture + coord-mapping remain |
|
||||
| Navigation, Loading & Events | 0 | 6 | not started |
|
||||
| Browser Services | **R1 settings + R2 cache/cookies + R3 dialogs** | 5 | R1 complete: setEnableJavaScript, setUserAgent, **setMinFontSize/setBlockPopups/setAcceptCookies** (SETTINGS2 PASS — prefs applied + window.open blocked behaviorally). R2: clearCache/clearCookies (SERVICES PASS). R3: DialogService overrides `@mozilla.org/prompter;1` — alert/confirm/prompt captured + reply routed (DIALOG PASS), installed in EngineHost so the daemon never hangs. **R4 downloads: DownloadService overrides `@mozilla.org/helperapplauncherdialog;1` — every download/unsupported-MIME handoff captured (source URL + MIME + name + length) instead of a chrome window (DOWNLOAD PASS: application/octet-stream captured), installed in EngineHost.** Remaining: R5 TLS, save-to-disk + progress/finished + per-adapter blocking delivery (adapter/device) |
|
||||
| Desktop Build & PoC | 0 | 4 | not started |
|
||||
| Desktop Build & PoC | **R1–R3 done; R4 [human-review]** | 4 | R1: single-entry build produces runnable jihad-browserserver (Goanna backend, LunaService compiled out) — DAEMON_UP. R2: jihad-adapter allocates buffers, Connect+OpenUrl, receives msgPainted, **writes out/jihad-poc-render.ppm** (→ docs/jihad-poc-render.png), returns buffer (0x150d wired). R3: real page renders through the whole pipe, lifecycle in order — ROUND-TRIP PASS. R4 (Enyo UI on desktop) recorded [human-review]: no desktop Enyo runtime → harness is the acceptance vehicle. See docs/DESKTOP-POC.md |
|
||||
| Device Build & Packaging | 0 | 5 | not started |
|
||||
|
||||
## Completed this session (Tier-0, build-independent)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
# Jihad Browser — Desktop PoC (Phase 1)
|
||||
|
||||
*Goanna inside, webOS alive, inshallah.*
|
||||
|
||||
This is the single documented entry point for the **x86_64 Linux desktop proof of
|
||||
concept**: it builds the real render daemon (`jihad-browserserver`) with the
|
||||
Goanna/UXP backend, and drives it with a minimal BrowserAdapter stand-in over the
|
||||
**unchanged YAP IPC contract** — no webOS stack required. It satisfies
|
||||
`cavekit-desktop-build.md` R1–R3; R4 (the Enyo UI on desktop) is recorded below as
|
||||
`[human-review]`.
|
||||
|
||||
## What it proves
|
||||
|
||||
The isis `BrowserAdapter ↔ BrowserServer` contract is byte-identical to upstream;
|
||||
only the engine behind it changed (QtWebKit → Goanna). The daemon renders real web
|
||||
content into a SysV shared framebuffer and speaks the exact YAP command/message
|
||||
surface the webOS UI already uses.
|
||||
|
||||

|
||||
|
||||
*The full pipe: the daemon loads the page in Goanna, paints into shared memory, and
|
||||
the adapter stand-in writes it to an image — `data:` page shown; `https://example.com`
|
||||
over TLS is in `jihad-render-example-com.png`.*
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `podman` (or Docker) — the pinned build container is Ubuntu 20.04 (GCC 9.3,
|
||||
Python 3.8, autoconf2.13, yasm, full X11 dev set + Xvfb). See `build/desktop/Dockerfile`.
|
||||
- The UXP source tree at `../UXP` (mounted read-write; autoconf regenerates configure).
|
||||
- One-time: build the image — `podman build -t jihad-goanna-build build/desktop`.
|
||||
|
||||
## 1. Build the engine (once, ~30–60 min)
|
||||
|
||||
```bash
|
||||
podman run --rm --user 0 -e HOME=/out \
|
||||
-v "$PWD/../UXP:/src/uxp" -v "$PWD:/jihad" \
|
||||
-v "$PWD/build/desktop/out:/out" \
|
||||
jihad-goanna-build bash /jihad/build/desktop/build-goanna.sh
|
||||
```
|
||||
|
||||
Produces `build/desktop/out/obj-jihad-goanna/dist/bin/libxul.so` plus the frozen
|
||||
embedding headers. Engine patches under `build/desktop/patches/` are applied
|
||||
automatically (0002 format-overflow, 0003 OMTC-off, 0004 gfx init).
|
||||
|
||||
## 2. Build + run the daemon and adapter round-trip (R1 + R2 + R3)
|
||||
|
||||
```bash
|
||||
podman run --rm --user 0 -e HOME=/out \
|
||||
-v "$PWD/../UXP:/src/uxp" -v "$PWD:/jihad" \
|
||||
-v "$PWD/build/desktop/out:/out" \
|
||||
jihad-goanna-build bash /jihad/build/desktop/build-adapter-roundtrip.sh
|
||||
```
|
||||
|
||||
This single entry point:
|
||||
|
||||
- **R1** — compiles + links `jihad-browserserver` from the engine-agnostic IPC
|
||||
layer (`Yap/`, `BrowserServerBase`) + the Goanna backend (`JihadBrowserServer`,
|
||||
`BrowserPageGoanna`, `GoannaRenderPage`, `EngineHost`). **LunaService is compiled
|
||||
out for desktop** — `Main.cpp` runs a plain GLib main loop; nothing links
|
||||
`libLunaService`. The daemon starts and prints `DAEMON_UP`.
|
||||
- **R2** — builds `jihad-adapter`, a `YapClient` BrowserAdapter stand-in. It
|
||||
allocates the two shared buffers, sends `Connect (0x1000)` + `OpenUrl (0x1004)`,
|
||||
receives `msgPainted`, **writes the buffer to `out/jihad-poc-render.ppm`**, and
|
||||
**returns the buffer** (`ReturnBuffer 0x150d`) so rendering can continue.
|
||||
- **R3** — a real page renders correctly through the whole pipe; the load-lifecycle
|
||||
messages arrive in order (`msgLoadStarted → msgLoadProgress → msgLoadStopped →
|
||||
msgLocationChanged → msgPainted`). Override the page with `JIHAD_URL=…` (e.g.
|
||||
`https://example.com`). Prints `ROUND-TRIP PASS`.
|
||||
|
||||
`JIHAD_POC_IMAGE=/out/foo.ppm` changes the output path.
|
||||
|
||||
## 3. Focused capability tests
|
||||
|
||||
Each `build/desktop/build-*-test.sh` builds one aspect against the engine and
|
||||
asserts real behavior under Xvfb (all PASS):
|
||||
|
||||
| Script | Proves |
|
||||
|--------|--------|
|
||||
| `build-embed-load.sh` | page load reaches `STATE_STOP` |
|
||||
| `build-page-driver.sh` | `BrowserPageGoanna` bridge drives paint |
|
||||
| `build-input-test.sh` | click/key/mouse fire DOM handlers (INPUT PASS) |
|
||||
| `build-nav-test.sh` | back/forward + `canGo*` + setHtml (NAV PASS) |
|
||||
| `build-history-test.sh` | clearHistory + history-state (HISTORY PASS) |
|
||||
| `build-fail-test.sh` | failed-load + global-history events |
|
||||
| `build-services-test.sh` | JS toggle blocks onclick (SERVICES PASS) |
|
||||
| `build-settings2-test.sh` | min-font / block-popups / accept-cookies |
|
||||
| `build-dialog-test.sh` | alert/confirm/prompt interception (DIALOG PASS) |
|
||||
| `build-download-test.sh` | download / MIME handoff (DOWNLOAD PASS) |
|
||||
| `build-resize-test.sh` / `build-scroll-test.sh` / `build-zoom-test.sh` | surface geometry |
|
||||
| `build-geo-test.sh` | contents-size / meta-viewport / scrolled-to events (GEO PASS) |
|
||||
|
||||
## R4 — isis Enyo UI against the desktop daemon `[human-review]`
|
||||
|
||||
The Enyo UI (`app/`) targets the **webOS Enyo runtime + LunaService/sysmgr**, which
|
||||
do not exist on a stock Linux desktop. A full desktop Enyo runtime is therefore
|
||||
**not available**, so per the cavekit criterion the **R2/R3 harness is the
|
||||
acceptance vehicle** for Phase 1. Driving the real UI is exercised on the device /
|
||||
emulator in Phase 2 (`cavekit-device-build.md`). This is the documented, recorded
|
||||
outcome for R4.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -396,7 +396,7 @@ void JihadBrowserServer::asyncCmdThaw(YapProxy* proxy, int32_t sharedBufferKey1,
|
||||
|
||||
void JihadBrowserServer::asyncCmdReturnBuffer(YapProxy* proxy, int32_t sharedBufferKey)
|
||||
{
|
||||
(void)proxy; // TODO(T-016): route to pageFor(proxy) / GoannaRenderPage per PORT-MAP.md
|
||||
if (auto* p = pageFor(proxy)) p->returnBuffer(sharedBufferKey);
|
||||
}
|
||||
|
||||
void JihadBrowserServer::asyncCmdSetZoomAndScroll(YapProxy* proxy, double zoom, int32_t cx, int32_t cy)
|
||||
|
||||
@@ -24,10 +24,41 @@ public:
|
||||
W(1024), H(768), sz(1024*768*4), key1(0x4a494831), key2(0x4a494832) {}
|
||||
int painted, verified;
|
||||
bool loadStopped;
|
||||
bool wroteImage = false;
|
||||
int W, H, sz, key1, key2;
|
||||
|
||||
void serverConnected() override {} // YapClient never calls this; we drive from start()
|
||||
|
||||
// Write the painted shared buffer to a PPM image (the real adapter blits it to
|
||||
// the card). Proves the desktop pipe produces a correct pixel image (R2/R3).
|
||||
void writeImage(int key) {
|
||||
int id = shmget(key, sz, 0);
|
||||
if (id < 0) return;
|
||||
unsigned char* b = (unsigned char*)shmat(id, nullptr, SHM_RDONLY);
|
||||
if (b == (unsigned char*)-1) return;
|
||||
const char* path = getenv("JIHAD_POC_IMAGE");
|
||||
if (!path || !*path) path = "/out/jihad-poc-render.ppm";
|
||||
FILE* fp = fopen(path, "wb");
|
||||
if (fp) {
|
||||
fprintf(fp, "P6\n%d %d\n255\n", W, H);
|
||||
for (int i = 0; i < W * H; ++i) {
|
||||
unsigned char* p = b + (size_t)i * 4; // B,G,R,A
|
||||
unsigned char rgb[3] = { p[2], p[1], p[0] };
|
||||
fwrite(rgb, 1, 3, fp);
|
||||
}
|
||||
fclose(fp);
|
||||
printf("[adapter] wrote %dx%d render to %s\n", W, H, path);
|
||||
}
|
||||
shmdt(b);
|
||||
}
|
||||
|
||||
// Return a painted buffer to the daemon per the contract (ReturnBuffer 0x150d).
|
||||
void returnBuffer(int key) {
|
||||
YapPacket* r = packetCommand();
|
||||
(*r) << (int16_t)0x150d; (*r) << (int32_t)key;
|
||||
sendAsyncCommand();
|
||||
}
|
||||
|
||||
// Verify the daemon actually rendered content into the shared buffer it named
|
||||
// in msgPainted (the real adapter would blit it to the card). Returns
|
||||
// non-white pixel count, or -1.
|
||||
@@ -77,6 +108,8 @@ public:
|
||||
long nb = verifyBuffer(k);
|
||||
printf("[adapter] <- msgPainted(key=0x%x): %ld non-white px in shared buffer\n", (unsigned)k, nb);
|
||||
if (nb > 100) ++verified;
|
||||
if (nb > 100 && !wroteImage) { writeImage(k); wroteImage = true; }
|
||||
returnBuffer(k); // hand the buffer back so rendering can continue
|
||||
if (loadStopped && verified > 0) {
|
||||
printf("[adapter] verified rendered frame after load; done\n");
|
||||
g_main_loop_quit(mainLoop());
|
||||
|
||||
@@ -70,6 +70,13 @@ void BrowserPageGoanna::setWindowSize(uint32_t width, uint32_t height) {
|
||||
if (mPage->Resize((int)width, (int)height)) { mNeedsPaint = true; emitGeometry(); }
|
||||
}
|
||||
|
||||
void BrowserPageGoanna::returnBuffer(int /*sharedBufferKey*/) {
|
||||
// The adapter is done with a painted buffer. The current model paints once per
|
||||
// load into alternating segments, so there is no in-flight bookkeeping to undo;
|
||||
// accepting the return (without error) satisfies the contract and lets a
|
||||
// subsequent paint proceed. Full double-buffer flow-control is future work.
|
||||
}
|
||||
|
||||
void BrowserPageGoanna::setScrollPosition(int x, int y) {
|
||||
if (!mPage) return;
|
||||
// The javascript: scroll applies asynchronously; the scrolled-to message is
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
bool init(uint32_t width, uint32_t height,
|
||||
int sharedBufferKey1, int sharedBufferKey2, int sharedBufferSize);
|
||||
void setWindowSize(uint32_t width, uint32_t height);
|
||||
void returnBuffer(int sharedBufferKey); // YAP: returnBuffer (adapter freed it)
|
||||
void setScrollPosition(int x, int y); // YAP: setScrollPosition
|
||||
void setZoomAndScroll(double zoom, int x, int y); // YAP: setZoomAndScroll
|
||||
|
||||
|
||||
Reference in new issue
Block a user