The unix control socket treats any update whose rect satisfies x1 == x2 && y1 == y2 as a liveness "init check" and returns true without drawing (Server.cpp, readControlMessage path):
// Emtpy message, just to check init.
if (msg.x1 == msg.x2 && msg.y1 == msg.y2) {
std::cerr << "Got init check!\n";
return sock.writeAll(true);
}
Since UpdateParams coordinates are inclusive, that condition also matches a legitimate 1×1 damage rect — which real clients produce (e.g. a single pen dot committed between coalesced flushes). The update is silently dropped: the client gets a true ack, the pixel never reaches the panel, and the server log fills with spurious Got init check! lines.
Observed live on OS 3.22.4.2 with the v0.1.4 server, driving it from a native Rust client for a handwriting app (riddle-rm2 — background in its docs/PORT_HISTORY.md). Reproduce by sending any update with x1==x2 && y1==y2 and nonzero coordinates while the shared buffer has a black pixel there: ack arrives, nothing draws.
Suggested fixes, either works:
- reserve the init check for the all-zero struct only (
x1==x2==y1==y2==0 && waveform==0 && flags==0 — what waitForInit() in Client.cpp actually sends), or
- add a dedicated liveness message type instead of overloading
UpdateParams.
Client-side workaround we ship meanwhile: widen degenerate rects by one pixel before sending. Happy to PR the server-side check if you'd take it.
The unix control socket treats any update whose rect satisfies
x1 == x2 && y1 == y2as a liveness "init check" and returnstruewithout drawing (Server.cpp,readControlMessagepath):Since
UpdateParamscoordinates are inclusive, that condition also matches a legitimate 1×1 damage rect — which real clients produce (e.g. a single pen dot committed between coalesced flushes). The update is silently dropped: the client gets atrueack, the pixel never reaches the panel, and the server log fills with spuriousGot init check!lines.Observed live on OS 3.22.4.2 with the v0.1.4 server, driving it from a native Rust client for a handwriting app (riddle-rm2 — background in its docs/PORT_HISTORY.md). Reproduce by sending any update with
x1==x2 && y1==y2and nonzero coordinates while the shared buffer has a black pixel there: ack arrives, nothing draws.Suggested fixes, either works:
x1==x2==y1==y2==0 && waveform==0 && flags==0— whatwaitForInit()in Client.cpp actually sends), orUpdateParams.Client-side workaround we ship meanwhile: widen degenerate rects by one pixel before sending. Happy to PR the server-side check if you'd take it.