app.dhover×280 error×93all
// F02 — resize correctness (Wayland). Implements
// ../../../features/f02-resize.md on top of the proven xdg-shell scaffold
// (../scaffold/app.d, findings in ../../scaffold.md).
//
// Wayland never *imposes* a size — it *negotiates* one: every
// xdg_surface.configure carries a serial; the client must ack_configure that
// exact serial and then commit a buffer matching the configured size. This
// demo proves that contract under a programmatic resize storm and records
// what the compositor does when the contract is broken on purpose.
//
// What F02 adds over the scaffold:
//   - EVERY configure is logged with its serial, suggested size, and the full
//     xdg_toplevel states array (`configure serial=N size=WxH states=[...]`);
//   - a larger storm: maximize → unmaximize → fullscreen (via
//     xdg_toplevel.set_fullscreen) → unfullscreen → maximize → unmaximize;
//   - buffer (re)allocation strategy is fully logged: `buffer_alloc`,
//     `buffer_destroy reason=stale_size`, and every `wl_buffer.release`;
//   - `--violate`: once, after acking a NEW-size maximized configure (where
//     the size is a hard constraint per the xdg_toplevel.maximized state),
//     commit a buffer of the OLD size and capture the compositor's reaction
//     (protocol error payload, or "tolerated" after a grace period). The
//     violation run is a separate invocation; normal runs stay clean.
//
// Under WSI_AUTO_EXIT=1 the storm is self-driven and the demo exits 0.
// Headless-safe: no compositor → SKIP, exit 0.
module 
(module) app
app
;
import c; // ImportC: <wayland-client.h> + xdg-shell glue + wsi_* wrappers
unable to read module `c` Expected 'c.d' or 'c/package.d' in one of the following import paths:
unable to read module `c` Expected 'c.d' or 'c/package.d' in one of the following import paths:
import instrument;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.errno

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/errno.h.html, errno.h

Source

core/stdc/errno.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
errno
:
(alias constant) app.EPROTO = int core.stdc.errno.EPROTO = 71
EPROTO
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdio

D header file for C99 <stdio.h>

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h

Source

core/stdc/stdio.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
stdio
:
(alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
,
(alias) app.snprintf = int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdlib

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h

Source

core/stdc/stdlib.d

@copyrightCopyright Sean Kelly 2005 - 2014.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
stdlib
:
(alias) app.getenv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.string

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/string.h.html, string.h

Source

core/stdc/string.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
string
:
(alias) app.strcmp = int core.stdc.string.strcmp(scope const(char*) s1, scope const(char*) s2) pure nothrow @nogc
strcmp
;
// ----------------------------------------------------------------- tunables enum int
(constant) int app.defaultWidth = 640
defaultWidth
= 640; // used while the compositor lets us pick (0x0 configure)
enum int
(constant) int app.defaultHeight = 480
defaultHeight
= 480;
// Auto-exit storm choreography (frame-callback numbers, ~60 Hz): enum int
(constant) int app.maximizeAtFrame = 20
maximizeAtFrame
= 20;
enum int
(constant) int app.unmaximizeAtFrame = 40
unmaximizeAtFrame
= 40;
enum int
(constant) int app.fullscreenAtFrame = 60
fullscreenAtFrame
= 60; // xdg_toplevel.set_fullscreen(null) — compositor picks output
enum int
(constant) int app.unfullscreenAtFrame = 80
unfullscreenAtFrame
= 80;
enum int
(constant) int app.maximize2AtFrame = 100
maximize2AtFrame
= 100; // second cycle: prove the machine is re-entrant
enum int
(constant) int app.unmaximize2AtFrame = 115
unmaximize2AtFrame
= 115;
enum int
(constant) int app.autoExitFrames = 140
autoExitFrames
= 140; // ≈ 2.3 s at 60 Hz
enum long
(constant) long app.autoExitUsCap = 3500000L
autoExitUsCap
= 3_500_000; // wall-clock backstop
enum long
(constant) long app.violationGraceUs = 1000000L
violationGraceUs
= 1_000_000; // no error within this → "tolerated"
// -------------------------------------------------------------------- state /// One wl_shm-backed ARGB8888 buffer. `busy` is owned by the compositor /// between wl_surface.commit and the wl_buffer.release event. struct
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
{ wl_buffer*
(field) _error_ app.Buffer.handle
handle
;
undefined identifier `wl_buffer`
uint*
(field) uint* app.Buffer.pixels
pixels
; // mmap'ed, shared with the compositor
(alias) object.size_t = ulong
size_t
(field) ulong app.Buffer.byteSize
byteSize
;
int
(field) int app.Buffer.width
width
,
(field) int app.Buffer.height
height
;
bool
(field) bool app.Buffer.busy
busy
;
} enum
(enum) app.Outcome
Outcome
{
(enum value) app.Outcome.none = 0
none
, // normal run, or violation not yet resolved
(enum value) app.Outcome.protocolError = 1
protocolError
,
(enum value) app.Outcome.tolerated = 2
tolerated
,
} __gshared { wl_display*
_error_ app.g_display
g_display
;
undefined identifier `wl_display`, did you mean variable `g_display`?
wl_registry*
_error_ app.g_registry
g_registry
;
undefined identifier `wl_registry`, did you mean variable `g_registry`?
wl_compositor*
_error_ app.g_compositor
g_compositor
;
undefined identifier `wl_compositor`, did you mean variable `g_compositor`?
wl_shm*
_error_ app.g_shm
g_shm
;
undefined identifier `wl_shm`, did you mean variable `g_shm`?
wl_seat*
_error_ app.g_seat
g_seat
;
undefined identifier `wl_seat`, did you mean variable `g_seat`?
xdg_wm_base*
_error_ app.g_wmBase
g_wmBase
;
undefined identifier `xdg_wm_base`
wl_surface*
_error_ app.g_surface
g_surface
;
undefined identifier `wl_surface`, did you mean variable `g_surface`?
xdg_surface*
_error_ app.g_xdgSurface
g_xdgSurface
;
undefined identifier `xdg_surface`, did you mean variable `g_surface`?
xdg_toplevel*
_error_ app.g_toplevel
g_toplevel
;
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
wl_callback*
_error_ app.g_frameCb
g_frameCb
; // at most one outstanding frame callback
undefined identifier `wl_callback`
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
[2]
_error_ app.g_buffers
g_buffers
; // double buffering: paint one while the other is on screen
int
(__gshared global) int app.g_width
g_width
= defaultWidth; // last *acked* size — buffers must match it
int
(__gshared global) int app.g_height
g_height
= defaultHeight;
int
(__gshared global) int app.g_floatingWidth
g_floatingWidth
= defaultWidth; // remembered for 0x0 ("you pick") configures
int
(__gshared global) int app.g_floatingHeight
g_floatingHeight
= defaultHeight;
int
(__gshared global) int app.g_pendingWidth
g_pendingWidth
; // from xdg_toplevel.configure (0 = client's choice)
int
(__gshared global) int app.g_pendingHeight
g_pendingHeight
;
bool
(__gshared global) bool app.g_pendingMaximized
g_pendingMaximized
; // latched from the xdg_toplevel.configure states array
bool
(__gshared global) bool app.g_pendingFullscreen
g_pendingFullscreen
;
bool
(__gshared global) bool app.g_configured
g_configured
; // first configure acked (may attach buffers from now on)
bool
(__gshared global) bool app.g_presented
g_presented
; // first frame callback after the first buffer commit
bool
(__gshared global) bool app.g_running
g_running
= true;
bool
(__gshared global) bool app.g_autoExit
g_autoExit
;
int
(__gshared global) int app.g_frames
g_frames
; // frame callbacks received
int
(__gshared global) int app.g_commits
g_commits
; // buffer commits sent
int
(__gshared global) int app.g_configures
g_configures
; // xdg_surface.configure events seen (== acks sent)
int
(__gshared global) int app.g_sizeChanges
g_sizeChanges
; // configures that changed the acked size
int
(__gshared global) int app.g_allocs
g_allocs
; // wl_buffer allocations
int
(__gshared global) int app.g_reallocs
g_reallocs
; // stale-size buffer destroys
// --violate machinery: bool
(__gshared global) bool app.g_violate
g_violate
; // armed by the CLI flag
bool
(__gshared global) bool app.g_violationDone
g_violationDone
; // the wrong-sized commit went out
(enum) app.Outcome
Outcome
(__gshared global) app.Outcome app.g_outcome
g_outcome
;
long
(__gshared global) long app.g_violationDeadlineUs
g_violationDeadlineUs
;
uint
(__gshared global) uint app.g_errCode
g_errCode
; // wl_display_get_protocol_error payload
uint
(__gshared global) uint app.g_errObjectId
g_errObjectId
;
const(char)*
(__gshared global) const(char)* app.g_errInterface
g_errInterface
= "?";
char[160]
(__gshared global) char[160] app.g_statesBuf
g_statesBuf
= "\0"; // last states array, formatted
} // -------------------------------------------------- states-array formatting /// xdg_toplevel.state enum names (wayland-protocols 1.47, xdg-shell v6). const(char)*
const(char)* app.stateName(uint s) nothrow @nogc

xdg_toplevel.state enum names (wayland-protocols 1.47, xdg-shell v6).

stateName
(uint
(parameter) uint s
s
) nothrow @nogc
{ switch (
(parameter) uint s
s
)
{ case XDG_TOPLEVEL_STATE_MAXIMIZED:
undefined identifier `XDG_TOPLEVEL_STATE_MAXIMIZED`
return "maximized"; case XDG_TOPLEVEL_STATE_FULLSCREEN:
undefined identifier `XDG_TOPLEVEL_STATE_FULLSCREEN`
return "fullscreen"; case XDG_TOPLEVEL_STATE_RESIZING:
undefined identifier `XDG_TOPLEVEL_STATE_RESIZING`
return "resizing"; case XDG_TOPLEVEL_STATE_ACTIVATED:
undefined identifier `XDG_TOPLEVEL_STATE_ACTIVATED`
return "activated"; case XDG_TOPLEVEL_STATE_TILED_LEFT:
undefined identifier `XDG_TOPLEVEL_STATE_TILED_LEFT`
return "tiled_left"; case XDG_TOPLEVEL_STATE_TILED_RIGHT:
undefined identifier `XDG_TOPLEVEL_STATE_TILED_RIGHT`
return "tiled_right"; case XDG_TOPLEVEL_STATE_TILED_TOP:
undefined identifier `XDG_TOPLEVEL_STATE_TILED_TOP`
return "tiled_top"; case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
undefined identifier `XDG_TOPLEVEL_STATE_TILED_BOTTOM`
return "tiled_bottom"; case XDG_TOPLEVEL_STATE_SUSPENDED:
undefined identifier `XDG_TOPLEVEL_STATE_SUSPENDED`
return "suspended"; default: return "unknown"; } } /// Format the configure states wl_array as `a,b,c` into g_statesBuf (also /// latches maximized/fullscreen for the xdg_surface.configure handler). void
app.latchStates

Format the configure states wl_array as a,b,c into g_statesBuf (also latches maximized/fullscreen for the xdg_surface.configure handler).

latchStates
(const(wl_array)* states) nothrow @nogc
undefined identifier `wl_array`
{ g_pendingMaximized = false; g_pendingFullscreen = false;
(unresolved type) size_t
size_t
_error_ off
off
= 0;
g_statesBuf[0] = '\0'; const
_error_ start
start
= cast(const(uint)*) states.data;
immutable
_error_ n
n
= states.
states.size
size
/ uint.sizeof;
foreach (
(parameter) i
i
; 0 .. n)
{ immutable
_error_ s
s
= start[i];
if (s == XDG_TOPLEVEL_STATE_MAXIMIZED) g_pendingMaximized = true; if (s == XDG_TOPLEVEL_STATE_FULLSCREEN) g_pendingFullscreen = true; if (off + 1 >= g_statesBuf.length) break; immutable
_error_ wrote
wrote
= snprintf(g_statesBuf.ptr + off, g_statesBuf.length - off,
"%s%s", i ? ",".ptr : "".ptr, stateName(s)); if (wrote <= 0) break; off += wrote; } } // ---------------------------------------------------------- shm buffer pool /// (Re)allocate `b` so it matches `w`×`h`. Only ever called on non-busy /// buffers, so destroying a stale-sized wl_buffer here is race-free. The /// strategy — a finding F02 asks for — is per-resize realloc, lazily: a /// stale-sized buffer lives until it is *picked* for reuse, never while the /// compositor holds it. bool
app.ensureBuffer

(Re)allocate b so it matches w×h. Only ever called on non-busy buffers, so destroying a stale-sized wl_buffer here is race-free. The strategy — a finding F02 asks for — is per-resize realloc, lazily: a stale-sized buffer lives until it is picked for reuse, never while the compositor holds it.

ensureBuffer
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
(parameter) Buffer b
b
, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc
{ if (b.
b.handle
handle
!is null && (b.
b.width
width
!= w || b.
b.height
height
!= h))
{ instrEvent("buffer_destroy", "size=%dx%d reason=stale_size", b.
b.width
width
, b.
b.height
height
);
g_reallocs++; wsi_buffer_destroy(b.
b.handle
handle
);
munmap(b.
b.pixels
pixels
, b.
b.byteSize
byteSize
);
b = Buffer.init; } if (b.
b.handle
handle
!is null)
return true; immutable
_error_ stride
stride
= w * 4;
immutable
_error_ size
size
= cast(
(unresolved type) size_t
size_t
)(stride) * h;
immutable
_error_ fd
fd
= memfd_create("wsi-f02", MFD_CLOEXEC);
if (fd < 0) return false; if (ftruncate(fd, cast(long) size) != 0) { close(fd); return false; } void*
_error_ mem
mem
= mmap(null, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem is cast(void*)-1) { close(fd); return false; } // The pool can be destroyed right after create_buffer: the buffer keeps // the backing memory alive, and the compositor has dup'ed the fd. wl_shm_pool*
_error_ pool
pool
= wsi_shm_create_pool(g_shm, fd, cast(int) size);
b.
b.handle
handle
= wsi_shm_pool_create_buffer(pool, 0, w, h, stride, WL_SHM_FORMAT_ARGB8888);
wsi_shm_pool_destroy(pool); close(fd); wsi_buffer_add_listener(b.
b.handle
handle
, &g_bufferListener, &b);
b.
b.pixels
pixels
= cast(uint*) mem;
b.
b.byteSize
byteSize
= size;
b.
b.width
width
= w;
b.
b.height
height
= h;
b.
b.busy
busy
= false;
g_allocs++; instrEvent("buffer_alloc", "size=%dx%d bytes=%zu", w, h, size); return true; } /// Corner-anchored diagonal gradient (F02 §1: geometry must visibly track the /// window size) with a frame-driven blue channel so each redraw is observable. void
app.paint

Corner-anchored diagonal gradient (F02 §1: geometry must visibly track the window size) with a frame-driven blue channel so each redraw is observable.

paint
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
(parameter) Buffer b
b
, int frame) nothrow @nogc
{ immutable
_error_ maxX
maxX
= b.
b.width
width
> 1 ? b.
b.width
width
- 1 : 1;
immutable
_error_ maxY
maxY
= b.
b.height
height
> 1 ? b.
b.height
height
- 1 : 1;
immutable uint
_error_ blue
blue
= (frame * 2) & 0xff;
foreach (
(parameter) y
y
; 0 .. b.
b.height
height
)
{ uint*
_error_ row
row
= b.
b.pixels
pixels
+ cast(
(unresolved type) size_t
size_t
) y * b.
b.width
width
;
immutable uint
_error_ g
g
= cast(uint)(y * 255 / maxY) << 8;
foreach (
(parameter) x
x
; 0 .. b.
b.width
width
)
row[x] = 0xff00_0000 | (cast(uint)(x * 255 / maxX) << 16) | g | blue; } } /// Paint a `w`×`h` buffer and commit it. `violation=true` bypasses the F02 /// size assertion — that is the single deliberate wrong-sized commit. void
void app.renderAt(int w, int h, bool violation) nothrow @nogc

Paint a w×h buffer and commit it. ``violation=true bypasses the F02 size assertion — that is the single deliberate wrong-sized commit.

renderAt
(int
(parameter) int w
w
, int
(parameter) int h
h
, bool
(parameter) bool violation
violation
) nothrow @nogc
{
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
*
(local variable) _error_ buf
buf
= null;
foreach (ref
(parameter) b
b
; g_buffers)
if (!b.
b.busy
busy
)
{ buf = &b; break; } if (buf is null) { // Both buffers held by the compositor: drop this frame. The // wl_buffer.release handler re-renders as soon as one comes back. instrEvent("frame_skipped", "reason=all_buffers_busy");
undefined identifier `instrEvent`, did you mean import `instrument`?
return; } if (!ensureBuffer(*buf, w, h)) {
(__gshared global) bool app.g_running
g_running
= false;
return; } paint(*buf, g_frames); // F02 contract: the committed buffer matches the acked configure size. assert(
(parameter) bool violation
violation
|| (buf.
(field) _error_ buf.width
width
==
(__gshared global) int app.g_width
g_width
&& buf.
(field) _error_ buf.height
height
==
(__gshared global) int app.g_height
g_height
),
"committed buffer size does not match the acked configure size"); wsi_surface_attach(g_surface, buf.
buf.handle
handle
, 0, 0);
undefined identifier `wsi_surface_attach`
wsi_surface_damage_buffer(g_surface, 0, 0, buf.
buf.width
width
, buf.
buf.height
height
);
undefined identifier `wsi_surface_damage_buffer`
if (g_frameCb is null) // keep exactly one frame callback in flight { g_frameCb = wsi_surface_frame(g_surface); wsi_callback_add_listener(g_frameCb, &g_frameListener, null);
undefined identifier `wsi_callback_add_listener`
} wsi_surface_commit(g_surface);
undefined identifier `wsi_surface_commit`
buf.
buf.busy
busy
= true;
(__gshared global) int app.g_commits
g_commits
++;
if (
(__gshared global) int app.g_commits
g_commits
== 1)
instrEvent("first_commit", "size=%dx%d", buf.
buf.width
width
, buf.
buf.height
height
);
undefined identifier `instrEvent`, did you mean import `instrument`?
if (
(parameter) bool violation
violation
)
instrEvent("violation_commit", "size=%dx%d acked=%dx%d", buf.
buf.width
width
, buf.
buf.height
height
,
undefined identifier `instrEvent`, did you mean import `instrument`?
g_width, g_height); } /// Commit a buffer matching the current acked size. void
void app.render() nothrow @nogc

Commit a buffer matching the current acked size.

render
() nothrow @nogc
{
void app.renderAt(int w, int h, bool violation) nothrow @nogc

Paint a w×h buffer and commit it. ``violation=true bypasses the F02 size assertion — that is the single deliberate wrong-sized commit.

renderAt
(
(__gshared global) int app.g_width
g_width
,
(__gshared global) int app.g_height
g_height
, false);
} // ---------------------------------------------------------------- listeners // All callbacks are `extern (C) nothrow @nogc` to match the listener // function-pointer types the ImportC `#pragma attribute` stamped in c.c. extern (C) void
app.onGlobal
onGlobal
(void* data, wl_registry* reg, uint name,
undefined identifier `wl_registry`, did you mean variable `g_registry`?
const(char)*
(parameter) const(char)* iface
iface
, uint ver) nothrow @nogc
{ static uint
uint capped(uint advertised, uint want) nothrow @nogc
capped
(uint
(parameter) uint advertised
advertised
, uint
(parameter) uint want
want
) nothrow @nogc
{ return advertised < want ? advertised : want; } if (strcmp(iface, wl_compositor_interface.name) == 0) g_compositor = cast(wl_compositor*) wsi_registry_bind(reg, name, &wl_compositor_interface, capped(ver, 4)); // v4: wl_surface.damage_buffer else if (strcmp(iface, wl_shm_interface.name) == 0) g_shm = cast(wl_shm*) wsi_registry_bind(reg, name, &wl_shm_interface, 1); else if (strcmp(iface, xdg_wm_base_interface.name) == 0) g_wmBase = cast(xdg_wm_base*) wsi_registry_bind(reg, name, &xdg_wm_base_interface, 1); else if (strcmp(iface, wl_seat_interface.name) == 0) g_seat = cast(wl_seat*) wsi_registry_bind(reg, name, &wl_seat_interface, capped(ver, 2)); // v2: name event else return; instrEvent("step", "name=wl_registry_bind iface=%s version=%u", iface, ver); } extern (C) void
app.onGlobalRemove
onGlobalRemove
(void* data, wl_registry* reg, uint name) nothrow @nogc
undefined identifier `wl_registry`, did you mean variable `g_registry`?
{ } extern (C) void
app.onWmBasePing
onWmBasePing
(void* data, xdg_wm_base*
(parameter) xdg_wm_base* b
b
, uint serial) nothrow @nogc
undefined identifier `xdg_wm_base`
{ wsi_wm_base_pong(b, serial); // liveness check — answer or be killed instrEvent("ping_pong", "serial=%u", serial); } extern (C) void
app.onSeatCapabilities
onSeatCapabilities
(void* data, wl_seat*
(parameter) wl_seat* s
s
, uint caps) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ instrEvent("seat_capabilities", "caps=0x%x", caps); } extern (C) void
app.onSeatName
onSeatName
(void* data, wl_seat*
(parameter) wl_seat* s
s
, const(char)* name) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ instrEvent("seat_name", "name=%s", name); } /// xdg_toplevel.configure: the compositor *suggests* a size (0×0 = "you /// pick") plus the full states array. Only latched here; everything takes /// effect atomically at the following xdg_surface.configure. extern (C) void
app.onToplevelConfigure

xdg_toplevel.configure: the compositor suggests a size (0×0 = "you pick") plus the full states array. Only latched here; everything takes effect atomically at the following xdg_surface.configure.

onToplevelConfigure
(void* data, xdg_toplevel* t, int
(parameter) int w
w
, int
(parameter) int h
h
,
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
wl_array* states) nothrow @nogc
undefined identifier `wl_array`
{ g_pendingWidth = w; g_pendingHeight = h; latchStates(states); instrEvent("xdg_toplevel_configure", "size=%dx%d states=[%s]", w, h, g_statesBuf.ptr); } /// xdg_surface.configure: the atomic "apply everything" event. Protocol /// order proven in the WAYLAND_DEBUG trace: ack_configure(serial) *then* the /// commit of a buffer matching the new size — except for the single armed /// `--violate` commit, which deliberately commits the OLD size after acking. extern (C) void
app.onXdgSurfaceConfigure

xdg_surface.configure: the atomic "apply everything" event. Protocol order proven in the WAYLAND_DEBUG trace: ack_configure(serial) then the commit of a buffer matching the new size — except for the single armed --violate commit, which deliberately commits the OLD size after acking.

onXdgSurfaceConfigure
(void* data, xdg_surface*
(parameter) xdg_surface* s
s
, uint serial) nothrow @nogc
undefined identifier `xdg_surface`, did you mean variable `g_surface`?
{ // 0x0 means "client picks": a robust client restores its remembered // floating size, not a hardcoded default. immutable
_error_ w
w
= g_pendingWidth > 0 ? g_pendingWidth : g_floatingWidth;
immutable
_error_ h
h
= g_pendingHeight > 0 ? g_pendingHeight : g_floatingHeight;
g_configures++; instrEvent("configure", "serial=%u size=%dx%d states=[%s]", serial, w, h, g_statesBuf.ptr); wsi_xdg_surface_ack_configure(s, serial); instrStep("xdg_surface_ack_configure"); immutable
_error_ resized
resized
= w != g_width || h != g_height;
// --violate: maximized makes the configured size a hard constraint // (xdg-shell: "the surface ... must have the configured size") — exactly // the case where a wrong-sized commit is unambiguous. Ack was correct; // the commit below is the one deliberate lie. if (g_violate && !g_violationDone && g_configured && g_pendingMaximized && resized) { g_violationDone = true; immutable
_error_ oldW
oldW
= g_width;
immutable
_error_ oldH
oldH
= g_height;
instrEvent("violation", "acked_serial=%u acked_size=%dx%d committing=%dx%d", serial, w, h, oldW, oldH); g_width = w; // record what we *should* be at, for the recovery path g_height = h; renderAt(oldW, oldH, true); // OLD size, on purpose g_violationDeadlineUs = instrNowUs() + violationGraceUs; return; } g_width = w; g_height = h; if (!g_pendingMaximized && !g_pendingFullscreen) { g_floatingWidth = w; // remember the floating size for 0x0 configures g_floatingHeight = h; } if (!g_configured) { g_configured = true; instrFirstConfigure(); render(); // the first buffer commit — the window becomes visible } else if (resized) { g_sizeChanges++; instrResize(w, h, 1); // no fractional-scale binding in this demo render(); // commit a matching buffer right away, don't wait a frame } } extern (C) void
app.onToplevelClose
onToplevelClose
(void* data, xdg_toplevel* t) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
{ instrCloseRequested(); g_running = false; } // Bound at xdg_wm_base v1, so these v4/v5 events never arrive; the listener // struct generated from wayland-protocols 1.47 still has the slots to fill. extern (C) void
app.onToplevelConfigureBounds
onToplevelConfigureBounds
(void* data, xdg_toplevel* t, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
{ } extern (C) void
app.onToplevelWmCapabilities
onToplevelWmCapabilities
(void* data, xdg_toplevel* t, wl_array* caps) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
undefined identifier `wl_array`
{ } /// wl_buffer.release: the compositor no longer reads the buffer; reuse it. /// Logged because *when* this fires is the buffer-lifetime finding (weston /// copies shm pixels at repaint and releases almost immediately). extern (C) void
app.onBufferRelease

wl_buffer.release: the compositor no longer reads the buffer; reuse it. Logged because when this fires is the buffer-lifetime finding (weston copies shm pixels at repaint and releases almost immediately).

onBufferRelease
(void* data, wl_buffer*
(parameter) wl_buffer* b
b
) nothrow @nogc
undefined identifier `wl_buffer`
{ auto
_error_ buf
buf
= cast(
(unresolved type) Buffer
Buffer
*) data;
buf.
buf.busy
busy
= false;
instrEvent("buffer_release", "size=%dx%d", buf.
buf.width
width
, buf.
buf.height
height
);
// If a frame was dropped because both buffers were busy, recover here. if (g_running && g_configured && g_frameCb is null) render(); } /// wl_surface.frame `done`: the compositor presented the surface and is /// ready for the next frame. Drives the redraw loop, the resize storm, and /// the violation grace-period check. extern (C) void
app.onFrameDone

wl_surface.frame done: the compositor presented the surface and is ready for the next frame. Drives the redraw loop, the resize storm, and the violation grace-period check.

onFrameDone
(void* data, wl_callback* cb, uint timeMs) nothrow @nogc
undefined identifier `wl_callback`
{ wsi_callback_destroy(cb); // one-shot object g_frameCb = null; g_frames++; instrFrameCallback(timeMs); if (!g_presented) { g_presented = true; instrFirstPixelPresented(); } // Violation epilogue: no protocol error within the grace period means // the compositor tolerated the wrong-sized buffer. if (g_violationDone && g_outcome == Outcome.
Outcome.none
none
&& instrNowUs() > g_violationDeadlineUs) { g_outcome = Outcome.
Outcome.tolerated
tolerated
;
instrEvent("violation_outcome", "result=tolerated grace_us=%lld frames_after=%d", violationGraceUs, g_frames); g_running = false; return; } if (g_autoExit && !g_violationDone) { switch (g_frames) { case maximizeAtFrame: case maximize2AtFrame: wsi_toplevel_set_maximized(g_toplevel); instrStep("xdg_toplevel_set_maximized"); break; case unmaximizeAtFrame: case unmaximize2AtFrame: wsi_toplevel_unset_maximized(g_toplevel); instrStep("xdg_toplevel_unset_maximized"); break; case fullscreenAtFrame: wsi_toplevel_set_fullscreen(g_toplevel, null); // compositor picks the output instrStep("xdg_toplevel_set_fullscreen"); break; case unfullscreenAtFrame: wsi_toplevel_unset_fullscreen(g_toplevel); instrStep("xdg_toplevel_unset_fullscreen"); break; default: break; } } if (g_autoExit && g_outcome == Outcome.
Outcome.none
none
&& (g_frames >= autoExitFrames || instrNowUs() > autoExitUsCap)) { g_running = false; return; } render(); } __gshared wl_registry_listener
_error_ app.g_registryListener
g_registryListener
= {&onGlobal, &onGlobalRemove};
undefined identifier `wl_registry_listener`
__gshared xdg_wm_base_listener
_error_ app.g_wmBaseListener
g_wmBaseListener
= {&onWmBasePing};
undefined identifier `xdg_wm_base_listener`
__gshared wl_seat_listener
_error_ app.g_seatListener
g_seatListener
= {&onSeatCapabilities, &onSeatName};
undefined identifier `wl_seat_listener`
__gshared xdg_surface_listener
_error_ app.g_xdgSurfaceListener
g_xdgSurfaceListener
= {&onXdgSurfaceConfigure};
undefined identifier `xdg_surface_listener`
__gshared xdg_toplevel_listener
_error_ app.g_toplevelListener
g_toplevelListener
= {
undefined identifier `xdg_toplevel_listener`
&onToplevelConfigure, &onToplevelClose, &onToplevelConfigureBounds, &onToplevelWmCapabilities }; __gshared wl_buffer_listener
_error_ app.g_bufferListener
g_bufferListener
= {&onBufferRelease};
undefined identifier `wl_buffer_listener`
__gshared wl_callback_listener
_error_ app.g_frameListener
g_frameListener
= {&onFrameDone};
undefined identifier `wl_callback_listener`
// ------------------------------------------------------------ error capture /// wl_display_dispatch returned -1: pull the error off the display. For a /// protocol error, wl_display_get_protocol_error yields the interface, error /// code, and object id (the violation run's headline data; the human-readable /// message only exists in libwayland's stderr log / WAYLAND_DEBUG trace). void
void app.captureDisplayError() nothrow @nogc

wl_display_dispatch returned -1: pull the error off the display. For a protocol error, wl_display_get_protocol_error yields the interface, error code, and object id (the violation run's headline data; the human-readable message only exists in libwayland's stderr log / WAYLAND_DEBUG trace).

captureDisplayError
() nothrow @nogc
{ immutable
(local variable) immutable(_error_) err
err
= wl_display_get_error(g_display);
undefined identifier `wl_display_get_error`
if (err == EPROTO) { wl_interface*
(local variable) _error_ iface
iface
;
undefined identifier `wl_interface`
uint
(local variable) uint id
id
;
immutable
(local variable) immutable(_error_) code
code
= wl_display_get_protocol_error(g_display, &iface, &id);
undefined identifier `wl_display_get_protocol_error`
(__gshared global) uint app.g_errCode
g_errCode
= code;
(__gshared global) uint app.g_errObjectId
g_errObjectId
=
(local variable) uint id
id
;
(__gshared global) const(char)* app.g_errInterface
g_errInterface
= iface !is null ? iface.name : "?";
if (
(__gshared global) bool app.g_violationDone
g_violationDone
&&
(__gshared global) app.Outcome app.g_outcome
g_outcome
==
(enum) app.Outcome
Outcome
.
(enum value) app.Outcome.none = 0
none
)
(__gshared global) app.Outcome app.g_outcome
g_outcome
=
(enum) app.Outcome
Outcome
.
(enum value) app.Outcome.protocolError = 1
protocolError
;
instrEvent("protocol_error", "interface=%s code=%u object_id=%u",
undefined identifier `instrEvent`, did you mean import `instrument`?
g_errInterface, code, id); } else instrEvent("display_error", "errno=%d", err);
undefined identifier `instrEvent`, did you mean import `instrument`?
} // ----------------------------------------------------------------- teardown void
void app.teardown() nothrow @nogc
teardown
() nothrow @nogc
{ instrEvent("teardown_start");
undefined identifier `instrEvent`, did you mean import `instrument`?
foreach (ref
(parameter) b
b
; g_buffers)
if (b.
b.handle
handle
!is null)
{ wsi_buffer_destroy(b.
b.handle
handle
);
munmap(b.
b.pixels
pixels
, b.
b.byteSize
byteSize
);
b = Buffer.init; } if (g_frameCb !is null) wsi_callback_destroy(g_frameCb);
undefined identifier `wsi_callback_destroy`
if (g_toplevel !is null) wsi_toplevel_destroy(g_toplevel);
undefined identifier `wsi_toplevel_destroy`
if (g_xdgSurface !is null) wsi_xdg_surface_destroy(g_xdgSurface);
undefined identifier `wsi_xdg_surface_destroy`
if (g_surface !is null) wsi_surface_destroy(g_surface);
undefined identifier `wsi_surface_destroy`
if (g_wmBase !is null) wsi_wm_base_destroy(g_wmBase);
undefined identifier `wsi_wm_base_destroy`
// The remaining globals have no destructor request at the bound versions; // destroying the client-side proxy is the correct cleanup. if (g_seat !is null) wl_proxy_destroy(cast(wl_proxy*) g_seat);
undefined identifier `wl_proxy_destroy`
if (g_shm !is null) wl_proxy_destroy(cast(wl_proxy*) g_shm);
undefined identifier `wl_proxy_destroy`
if (g_compositor !is null) wl_proxy_destroy(cast(wl_proxy*) g_compositor);
undefined identifier `wl_proxy_destroy`
if (g_registry !is null) wl_proxy_destroy(cast(wl_proxy*) g_registry);
undefined identifier `wl_proxy_destroy`
wl_display_disconnect(g_display);
undefined identifier `wl_display_disconnect`
instrEvent("teardown_done");
undefined identifier `instrEvent`, did you mean import `instrument`?
} // --------------------------------------------------------------------- main int
int D main(string[] args)
main
(
(alias) object.string = string
string
[]
(parameter) string[] args
args
)
{ instrInit("f02-wayland");
undefined identifier `instrInit`
const
(local variable) const(char*) autoEnv
autoEnv
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_AUTO_EXIT");
(__gshared global) bool app.g_autoExit
g_autoExit
=
(local variable) const(char*) autoEnv
autoEnv
!is null && *
(local variable) const(char*) autoEnv
autoEnv
== '1';
foreach (
(parameter) string arg
arg
;
(parameter) string[] args
args
[1 .. $])
if (
(local variable) string arg
arg
== "--violate")
(__gshared global) bool app.g_violate
g_violate
= true;
if (
(__gshared global) bool app.g_violate
g_violate
)
instrEvent("violate_armed");
undefined identifier `instrEvent`, did you mean import `instrument`?
// 1. Connect (SKIP cleanly on headless hosts without a compositor). g_display = wl_display_connect(null); if (g_display is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: no Wayland compositor (wl_display_connect returned null)\n");
return 0; } instrStep("wl_display_connect");
undefined identifier `instrStep`
// 2. Registry: discover and bind the globals a window needs. g_registry = wsi_display_get_registry(g_display); instrStep("wl_display_get_registry");
undefined identifier `instrStep`
wsi_registry_add_listener(g_registry, &g_registryListener, null);
undefined identifier `wsi_registry_add_listener`
wl_display_roundtrip(g_display); // blocks; onGlobal binds during this
undefined identifier `wl_display_roundtrip`
instrStep("wl_display_roundtrip");
undefined identifier `instrStep`
if (g_compositor is null || g_shm is null || g_wmBase is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: compositor lacks a required global (wl_compositor/wl_shm/xdg_wm_base)\n");
void app.teardown() nothrow @nogc
teardown
();
return 0; } wsi_wm_base_add_listener(g_wmBase, &g_wmBaseListener, null);
undefined identifier `wsi_wm_base_add_listener`
if (g_seat !is null) wsi_seat_add_listener(g_seat, &g_seatListener, null);
undefined identifier `wsi_seat_add_listener`
// 3. Build the window object tree: wl_surface → xdg_surface → xdg_toplevel. g_surface = wsi_compositor_create_surface(g_compositor); instrStep("wl_compositor_create_surface");
undefined identifier `instrStep`
g_xdgSurface = wsi_wm_base_get_xdg_surface(g_wmBase, g_surface); instrStep("xdg_wm_base_get_xdg_surface");
undefined identifier `instrStep`
wsi_xdg_surface_add_listener(g_xdgSurface, &g_xdgSurfaceListener, null);
undefined identifier `wsi_xdg_surface_add_listener`
g_toplevel = wsi_xdg_surface_get_toplevel(g_xdgSurface); instrStep("xdg_surface_get_toplevel");
undefined identifier `instrStep`
wsi_toplevel_add_listener(g_toplevel, &g_toplevelListener, null);
undefined identifier `wsi_toplevel_add_listener`
wsi_toplevel_set_title(g_toplevel, "wsi-f02-resize");
undefined identifier `wsi_toplevel_set_title`
instrStep("xdg_toplevel_set_title");
undefined identifier `instrStep`
wsi_toplevel_set_app_id(g_toplevel, "wsi-f02-resize");
undefined identifier `wsi_toplevel_set_app_id`
instrStep("xdg_toplevel_set_app_id");
undefined identifier `instrStep`
instrWindowCreated();
undefined identifier `instrWindowCreated`
// 4. The mandatory initial commit *without* a buffer (attaching one before // the first configure is a protocol error). The compositor answers with // the first xdg_surface.configure; the first pixel happens in its handler. wsi_surface_commit(g_surface);
undefined identifier `wsi_surface_commit`
instrStep("wl_surface_commit");
undefined identifier `instrStep`
// 5. Event loop. wl_display_dispatch flushes requests, blocks on the // socket, and dispatches a batch of events; the listeners above do all // the work. A -1 return after the violation is the compositor killing // the connection — capture the protocol-error payload. while (
(__gshared global) bool app.g_running
g_running
)
{ if (wl_display_dispatch(g_display) == -1)
undefined identifier `wl_display_dispatch`
{
void app.captureDisplayError() nothrow @nogc

wl_display_dispatch returned -1: pull the error off the display. For a protocol error, wl_display_get_protocol_error yields the interface, error code, and object id (the violation run's headline data; the human-readable message only exists in libwayland's stderr log / WAYLAND_DEBUG trace).

captureDisplayError
();
break; } if (
(__gshared global) bool app.g_autoExit
g_autoExit
&& instrNowUs() >
(constant) long app.autoExitUsCap = 3500000L
autoExitUsCap
+ 2_000_000)
undefined identifier `instrNowUs`
(__gshared global) bool app.g_running
g_running
= false; // hard backstop if frame callbacks ever stall
} // 6. Clean teardown: buffers → frame callback → role objects → surface → // globals → registry → disconnect (children before parents).
void app.teardown() nothrow @nogc
teardown
();
if (
(__gshared global) bool app.g_violate
g_violate
)
{ final switch (
(__gshared global) app.Outcome app.g_outcome
g_outcome
)
{ case
(enum) app.Outcome
Outcome
.
(enum value) app.Outcome.protocolError = 1
protocolError
:
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("violation outcome: protocol error — interface=%s code=%u object_id=%u "
~ "(connection killed by the compositor)\n",
(__gshared global) const(char)* app.g_errInterface
g_errInterface
,
(__gshared global) uint app.g_errCode
g_errCode
,
(__gshared global) uint app.g_errObjectId
g_errObjectId
);
break; case
(enum) app.Outcome
Outcome
.
(enum value) app.Outcome.tolerated = 2
tolerated
:
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("violation outcome: tolerated — no protocol error within %lld ms; "
~ "compositor accepted a wrong-sized buffer against a maximized configure\n",
(constant) long app.violationGraceUs = 1000000L
violationGraceUs
/ 1000);
break; case
(enum) app.Outcome
Outcome
.
(enum value) app.Outcome.none = 0
none
:
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("violation outcome: NOT CAPTURED (violation never triggered)\n");
return 1; } // Both reactions are a successfully captured experiment → exit 0. return 0; }
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("ok: %d frames, %d commits, %d configures acked, %d size changes, "
~ "%d buffer allocs (%d stale-size reallocs), final size %dx%d\n",
(__gshared global) int app.g_frames
g_frames
,
(__gshared global) int app.g_commits
g_commits
,
(__gshared global) int app.g_configures
g_configures
,
(__gshared global) int app.g_sizeChanges
g_sizeChanges
,
(__gshared global) int app.g_allocs
g_allocs
,
(__gshared global) int app.g_reallocs
g_reallocs
,
(__gshared global) int app.g_width
g_width
,
(__gshared global) int app.g_height
g_height
);
return 0; }