Skip to content

allow events while waiting for a synchronous reply - #68

Merged
marler8997 merged 1 commit into
masterfrom
sync-event-handler
Oct 18, 2026
Merged

marler8997 merged 1 commit into
masterfrom
sync-event-handler

Conversation

@marler8997

@marler8997 marler8997 commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Fixes #66. Supersedes #65.

Source.readSynchronousReplyOrEvent(sequence) returns a tagged union: either the reply or an event that arrived before it. Callers that can receive events read in a loop and handle the event as a case of the result, then read the rest of the reply with the new readReplyFull/readReplyHeader:

const reply = while (true) switch (try source.readSynchronousReplyOrEvent(sink.sequence)) {
    .reply => |reply| break reply,
    .event => |kind| switch (kind) {
        .ConfigureNotify => { ... },
        else => try source.rejectEvent(kind),
    },
};
const extents, _ = try source.readReplyFull(reply, .QueryTextExtents);

Source.rejectEvent keeps the previous behavior for unexpected events (skip MappingNotify, log and fail on anything else). The existing helpers (readSynchronousReply1/Full/Header, draft.synchronousQueryExtension, synchronousGetKeyboardMapping, keymap.Full.initSynchronous) keep their signatures and use it, so this is an additive API change and examples that can't receive events are unchanged.

Moba/X sends a ConfigureNotify as soon as a window is created, which crashed the examples that select StructureNotify and then do synchronous requests:

  • present and draw track the window size from it while waiting for their QueryTextExtents reply
  • testexample logs it (like its event loop) through a small local readReply helper used by all its synchronous requests
  • dbe queries the DOUBLE-BUFFER extension before creating the window, since it doesn't need the window

Verification

  • zig build install install-xauth test-non-interactive passes; x86_64 windows compiles.
  • Through a proxy in front of Xvfb that injects a 600x400 ConfigureNotify after any CreateWindow selecting StructureNotify (mimicking Moba/X): dbe, present, draw, testexample and text all keep running (before this change the first four failed with expected Reply but got ConfigureNotify); a temporary log showed present and draw picking up the 600x400 size. All other examples run normally.
  • ReleaseSmall stripped size: hello 163240 → 163400, dbe 175424 → 175496, present 180968 → 181488, testexample 188968 → 189264 bytes.

https://ampcode.com/threads/T-01a14b88-aff8-717e-bb9f-364137832240

Source.readSynchronousReplyOrEvent returns either the reply or an event
that arrived before it, so callers that can receive events read in a
loop and handle them as a case of the result. readReplyFull/readReplyHeader
read the rest of the reply. Source.rejectEvent handles unexpected events
(skips MappingNotify, fails on anything else), and the existing helpers
(readSynchronousReply1/Full/Header, synchronousQueryExtension, ...) keep
their signatures and behavior on top of it.

Some servers (e.g. MobaXterm's Moba/X) send ConfigureNotify as soon as a
window is created. present and draw now track the window size from it
while waiting for their QueryTextExtents reply, testexample logs it, and
dbe queries its extension before creating the window.

Fixes #66

Amp-Thread-ID: https://ampcode.com/threads/T-01a14b88-aff8-717e-bb9f-364137832240
Co-authored-by: Amp <amp@ampcode.com>
@marler8997 marler8997 changed the title pass events received during synchronous reads to an event handler allow events while waiting for a synchronous reply Oct 18, 2026
@marler8997
marler8997 merged commit d65ea0c into master Oct 18, 2026
4 checks passed
@marler8997
marler8997 deleted the sync-event-handler branch October 18, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Events received during synchronous requests fail with UnexpectedMessage

1 participant