app.dhover×339 error×110all
// F06 keyboard & keymap on Wayland (../../f06-keyboard.md): scancode → keysym
// → text are three different questions, and Wayland answers NONE of them in
// the protocol — wl_keyboard.key carries a bare evdev scancode, and everything
// above it is the client's job, via libxkbcommon:
//
//   1. wl_keyboard.keymap hands the client an fd + size; the client mmaps it
//      (MAP_PRIVATE, per the protocol) and compiles it with
//      xkb_keymap_new_from_string. The compositor can re-send it at ANY time
//      (layout switch, a new input device with a different map) — the demo
//      logs every `keymap_event` and rebuilds xkb_keymap/xkb_state each time.
//   2. wl_keyboard.modifiers carries raw mask+group; xkb_state_update_mask
//      applies it. Sym and UTF-8 for a key are then
//      xkb_state_key_get_one_sym / xkb_state_key_get_utf8 at keycode
//      (= evdev code + 8, the historical X11 offset xkbcommon keeps).
//   3. KEY REPEAT IS CLIENT-SIDE: wl_keyboard.repeat_info (v4+) only states
//      rate/delay; no repeated key events ever arrive. The demo implements
//      repeat with a timerfd (the F05 external-fd pattern) and proves both
//      mandatory cancellations: on wl_keyboard.key release and on
//      wl_keyboard.leave (focus loss).
//   4. Dead-key compose is ALSO client-side: pressed syms feed an
//      xkb_compose_state (table from the locale); `compose state=…`
//      transitions and the composed text are logged.
//
// Every press/release logs `key code=<evdev+8> sym=<name> text=<utf8>
// state=down|up repeat=0|1`. Headless weston advertises NO wl_seat, so the
// Tier-A run uses a wlroots headless compositor (sway) + wtype's
// zwp_virtual_keyboard_v1 injection — see ../../f06-keyboard.md for the
// choreography. No compositor → SKIP; no seat → SKIP (exit 0 both ways).
//
// Based on the scaffold (../scaffold/app.d, findings ../../scaffold.md);
// instrumentation contract: ./instrument.d.
module 
(module) app
app
;
import c; // ImportC: wayland + xdg-shell + xkbcommon + timerfd/poll + wsi_*
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.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
;
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.atoll = long core.stdc.stdlib.atoll(scope const(char*) nptr) nothrow @nogc
atoll
,
(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;
enum int
(constant) int app.defaultHeight = 480
defaultHeight
= 480;
enum int
(constant) int app.pollTimeoutMs = 250
pollTimeoutMs
= 250;
enum long
(constant) long app.defaultCapUs = 30000000L
defaultCapUs
= 30_000_000; // WSI_AUTO_EXIT=1 run length (override: WSI_F06_CAP_US)
// -------------------------------------------------------------------- state /// One wl_shm-backed ARGB8888 buffer (scaffold pattern). struct
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer (scaffold pattern).

Buffer
{ wl_buffer*
(field) _error_ app.Buffer.handle
handle
;
undefined identifier `wl_buffer`
uint*
(field) uint* app.Buffer.pixels
pixels
;
(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
;
} __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`?
wl_keyboard*
_error_ app.g_keyboard
g_keyboard
;
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
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
;
undefined identifier `wl_callback`
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer (scaffold pattern).

Buffer
[2]
_error_ app.g_buffers
g_buffers
;
int
(__gshared global) int app.g_width
g_width
= defaultWidth;
int
(__gshared global) int app.g_height
g_height
= defaultHeight;
int
(__gshared global) int app.g_pendingWidth
g_pendingWidth
,
(__gshared global) int app.g_pendingHeight
g_pendingHeight
;
bool
(__gshared global) bool app.g_configured
g_configured
,
(__gshared global) bool app.g_presented
g_presented
;
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
,
(__gshared global) int app.g_commits
g_commits
;
// xkbcommon: the client-owned keyboard state machine. xkb_context*
_error_ app.g_xkbCtx
g_xkbCtx
;
undefined identifier `xkb_context`
xkb_keymap*
_error_ app.g_xkbKeymap
g_xkbKeymap
;
undefined identifier `xkb_keymap`
xkb_state*
_error_ app.g_xkbState
g_xkbState
;
undefined identifier `xkb_state`
xkb_compose_table*
_error_ app.g_composeTable
g_composeTable
;
undefined identifier `xkb_compose_table`
xkb_compose_state*
_error_ app.g_composeState
g_composeState
;
undefined identifier `xkb_compose_state`
// Client-side repeat (the F05 timerfd pattern). int
(__gshared global) int app.g_repeatTimerfd
g_repeatTimerfd
= -1;
int
(__gshared global) int app.g_repeatRate
g_repeatRate
; // characters/second, 0 = disabled (repeat_info)
int
(__gshared global) int app.g_repeatDelayMs
g_repeatDelayMs
;
uint
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
; // 0 = no repeat armed
// Findings counters. int
(__gshared global) int app.g_keymapCount
g_keymapCount
,
(__gshared global) int app.g_keyEvents
g_keyEvents
,
(__gshared global) int app.g_repeatSynth
g_repeatSynth
;
int
(__gshared global) int app.g_cancelRelease
g_cancelRelease
,
(__gshared global) int app.g_cancelFocus
g_cancelFocus
;
} // -------------------------------------------------------- key-event helpers /// Escape control bytes as \xNN so `text=` stays one parseable log token. void
void app.sanitize(const(char)* src, char* dst, ulong dstLen) nothrow @nogc

Escape control bytes as \xNN so text= stays one parseable log token.

sanitize
(const(char)*
(parameter) const(char)* src
src
, char*
(parameter) char* dst
dst
,
(alias) object.size_t = ulong
size_t
(parameter) ulong dstLen
dstLen
) nothrow @nogc
{ static char
char app.sanitize.hexDigit(uint v) pure nothrow @nogc @safe
hexDigit
(uint
(parameter) uint v
v
) nothrow @nogc
{ return cast(char)(
(parameter) uint v
v
< 10 ? '0' +
(parameter) uint v
v
: 'a' +
(parameter) uint v
v
- 10);
}
(alias) object.size_t = ulong
size_t
(local variable) ulong j
j
;
for (
(alias) object.size_t = ulong
size_t
(local variable) ulong i
i
= 0; src[i] != 0 && j + 5 < dstLen; i++)
{ immutable ubyte
(local variable) immutable(ubyte) b
b
=
(parameter) const(char)* src
src
[
(local variable) ulong i
i
];
if (
(local variable) immutable(ubyte) b
b
>= 0x20 &&
(local variable) immutable(ubyte) b
b
!= 0x7f)
(parameter) char* dst
dst
[
(local variable) ulong j
j
++] =
(local variable) immutable(ubyte) b
b
;
else {
(parameter) char* dst
dst
[
(local variable) ulong j
j
++] = '\\';
(parameter) char* dst
dst
[
(local variable) ulong j
j
++] = 'x';
(parameter) char* dst
dst
[
(local variable) ulong j
j
++] =
char app.sanitize.hexDigit(uint v) pure nothrow @nogc @safe
hexDigit
(
(local variable) immutable(ubyte) b
b
>> 4);
(parameter) char* dst
dst
[
(local variable) ulong j
j
++] =
char app.sanitize.hexDigit(uint v) pure nothrow @nogc @safe
hexDigit
(
(local variable) immutable(ubyte) b
b
& 0xf);
} }
(parameter) char* dst
dst
[
(local variable) ulong j
j
] = 0;
} /// Resolve keycode → (sym name, UTF-8 text) through the current xkb_state. void
void app.resolveKey(uint keycode, ref char[64] symName, ref char[64] text) nothrow @nogc

Resolve keycode → (sym name, UTF-8 text) through the current xkb_state.

resolveKey
(uint
(parameter) uint keycode
keycode
, ref char[64]
(parameter) char[64] symName
symName
, ref char[64]
(parameter) char[64] text
text
) nothrow @nogc
{
(parameter) char[64] symName
symName
[0] = '?';
(parameter) char[64] symName
symName
[1] = 0;
(parameter) char[64] text
text
[0] = 0;
if (g_xkbState is null) return; immutable
(local variable) immutable(_error_) sym
sym
= xkb_state_key_get_one_sym(g_xkbState, keycode);
undefined identifier `xkb_state_key_get_one_sym`
xkb_keysym_get_name(sym, symName.
symName.ptr
ptr
, symName.
symName.length
length
);
undefined identifier `xkb_keysym_get_name`
xkb_state_key_get_utf8(g_xkbState, keycode, text.
text.ptr
ptr
, text.
text.length
length
);
undefined identifier `xkb_state_key_get_utf8`
} void
void app.logKeyLine(uint keycode, in char[64] symName, const(char)* text, bool down, int repeat) nothrow @nogc
logKeyLine
(uint
(parameter) uint keycode
keycode
, in char[64]
(parameter) const(char[64]) symName
symName
, const(char)*
(parameter) const(char)* text
text
, bool
(parameter) bool down
down
, int
(parameter) int repeat
repeat
) nothrow @nogc
{ char[128]
(local variable) char[128] safe
safe
= void;
void app.sanitize(const(char)* src, char* dst, ulong dstLen) nothrow @nogc

Escape control bytes as \xNN so text= stays one parseable log token.

sanitize
(
(parameter) const(char)* text
text
,
(local variable) char[128] safe
safe
.
(constant) char* char[128].ptr = &safe
ptr
,
(local variable) char[128] safe
safe
.
(constant) ulong char[128].length = 128LU
length
);
instrEvent("key", "code=%u sym=%s text=%s state=%s repeat=%d",
undefined identifier `instrEvent`, did you mean import `instrument`?
keycode, symName.
symName.ptr
ptr
, safe.
safe.ptr
ptr
, down ? "down".
"down".ptr
ptr
: "up".
"up".ptr
ptr
, repeat);
} // --------------------------------------------------- client-side key repeat /// Arm the repeat timerfd: one-shot delay, then the rate interval — exactly /// the contract wl_keyboard.repeat_info describes but does not implement. void
void app.armRepeat(uint keycode) nothrow @nogc

Arm the repeat timerfd: one-shot delay, then the rate interval — exactly the contract wl_keyboard.repeat_info describes but does not implement.

armRepeat
(uint
(parameter) uint keycode
keycode
) nothrow @nogc
{ if (
(__gshared global) int app.g_repeatRate
g_repeatRate
<= 0) // rate 0 = "repeat disabled" per the protocol
return; if (g_xkbKeymap is null || !xkb_keymap_key_repeats(g_xkbKeymap, keycode))
undefined identifier `xkb_keymap_key_repeats`
return; // keymap says this key does not repeat (modifiers etc.)
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
=
(parameter) uint keycode
keycode
;
immutable long
(local variable) immutable(long) periodNs
periodNs
= 1_000_000_000L /
(__gshared global) int app.g_repeatRate
g_repeatRate
;
itimerspec
(local variable) _error_ its
its
;
undefined identifier `itimerspec`
its.it_value.tv_sec = g_repeatDelayMs / 1000; its.it_value.tv_nsec = cast(long)(g_repeatDelayMs % 1000) * 1_000_000; its.it_interval.tv_sec = periodNs / 1_000_000_000; its.it_interval.tv_nsec = periodNs % 1_000_000_000; timerfd_settime(g_repeatTimerfd, 0, &its, null);
undefined identifier `timerfd_settime`
instrEvent("repeat_arm", "code=%u delay_ms=%d rate_hz=%d", keycode,
undefined identifier `instrEvent`, did you mean import `instrument`?
g_repeatDelayMs, g_repeatRate); } void
void app.cancelRepeat(const(char)* reason) nothrow @nogc
cancelRepeat
(const(char)*
(parameter) const(char)* reason
reason
) nothrow @nogc
{ if (
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
== 0)
return; itimerspec
(local variable) _error_ zero
zero
; // all-zero it_value disarms the timer
undefined identifier `itimerspec`
timerfd_settime(g_repeatTimerfd, 0, &zero, null);
undefined identifier `timerfd_settime`
instrEvent("repeat_cancel", "reason=%s code=%u", reason, g_repeatKeycode);
undefined identifier `instrEvent`, did you mean import `instrument`?
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
= 0;
} /// Repeat timer fired: synthesize `repeat=1` key events from the *current* /// xkb_state (so held-key repeats track live modifier changes). void
void app.drainRepeatTimer() nothrow @nogc

Repeat timer fired: synthesize repeat=1 key events from the current xkb_state (so held-key repeats track live modifier changes).

drainRepeatTimer
() nothrow @nogc
{ ulong
(local variable) ulong expirations
expirations
;
if (read(g_repeatTimerfd, &expirations, expirations.
expirations.sizeof
sizeof
) !=
(local variable) ulong expirations
expirations
.sizeof)
undefined identifier `read`
return; if (
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
== 0)
return; // raced with a cancel — the read already cleared the fd char[64]
(local variable) char[64] symName
symName
= void,
(local variable) char[64] text
text
= void;
void app.resolveKey(uint keycode, ref char[64] symName, ref char[64] text) nothrow @nogc

Resolve keycode → (sym name, UTF-8 text) through the current xkb_state.

resolveKey
(
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
,
(local variable) char[64] symName
symName
,
(local variable) char[64] text
text
);
foreach (
(local variable) ulong i
i
; 0 ..
(local variable) ulong expirations
expirations
)
{
(__gshared global) int app.g_repeatSynth
g_repeatSynth
++;
void app.logKeyLine(uint keycode, in char[64] symName, const(char)* text, bool down, int repeat) nothrow @nogc
logKeyLine
(
(__gshared global) uint app.g_repeatKeycode
g_repeatKeycode
,
(local variable) char[64] symName
symName
,
(local variable) char[64] text
text
.
(constant) char* char[64].ptr = &text
ptr
, true, 1);
} } // ------------------------------------------------------ wl_keyboard events /// wl_keyboard.keymap: the compositor serializes the WHOLE keymap into an fd. /// Can arrive again at any time (layout switch / new device) — each arrival /// replaces the client's xkb_keymap + xkb_state. extern (C) void
app.onKbKeymap

wl_keyboard.keymap: the compositor serializes the WHOLE keymap into an fd. Can arrive again at any time (layout switch / new device) — each arrival replaces the client's xkb_keymap + xkb_state.

onKbKeymap
(void* data, wl_keyboard* kb, uint format, int
(parameter) int fd
fd
,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
uint
(parameter) uint size
size
) nothrow @nogc
{ g_keymapCount++; instrEvent("keymap_event", "format=%u size=%u n=%d", format, size, g_keymapCount); if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } // "From version 7 onwards, the fd must be mapped with MAP_PRIVATE." void*
_error_ mem
mem
= mmap(null, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem is cast(void*)-1) { close(fd); return; } auto
_error_ keymap
keymap
= xkb_keymap_new_from_string(g_xkbCtx, cast(const(char)*) mem,
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(mem, size); close(fd); if (keymap is null) { instrEvent("keymap_parse_failed"); return; } if (g_xkbState !is null) xkb_state_unref(g_xkbState); if (g_xkbKeymap !is null) xkb_keymap_unref(g_xkbKeymap); g_xkbKeymap = keymap; g_xkbState = xkb_state_new(keymap); const
_error_ layout0
layout0
= xkb_keymap_layout_get_name(keymap, 0);
instrEvent("keymap_parsed", "layouts=%u layout0=%s", xkb_keymap_num_layouts(keymap), layout0 !is null ? layout0 : "(unnamed)".
"(unnamed)".ptr
ptr
);
cancelRepeat("keymap_replaced"); // old keycode semantics are gone } extern (C) void
app.onKbEnter
onKbEnter
(void* data, wl_keyboard* kb, uint serial,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
wl_surface* s, wl_array* keys) nothrow @nogc
undefined identifier `wl_surface`, did you mean variable `g_surface`?
undefined identifier `wl_array`
{ instrEvent("keyboard_enter", "serial=%u pressed=%zu", serial, keys.
keys.size
size
/ 4);
} /// Focus loss kills the repeat timer — the second mandatory cancellation. extern (C) void
app.onKbLeave

Focus loss kills the repeat timer — the second mandatory cancellation.

onKbLeave
(void* data, wl_keyboard* kb, uint serial,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
wl_surface* s) nothrow @nogc
undefined identifier `wl_surface`, did you mean variable `g_surface`?
{ instrEvent("keyboard_leave", "serial=%u", serial); if (g_repeatKeycode != 0) g_cancelFocus++; cancelRepeat("focus_leave"); } extern (C) void
app.onKbKey
onKbKey
(void* data, wl_keyboard* kb, uint serial, uint time,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
uint key, uint state) nothrow @nogc { immutable
_error_ keycode
keycode
= key + 8; // evdev → XKB keycode (the historical +8)
immutable
_error_ down
down
= state == WL_KEYBOARD_KEY_STATE_PRESSED;
g_keyEvents++; char[64]
_error_ symName
symName
= void,
_error_ text
text
= void;
resolveKey(keycode, symName, text); // Dead-key compose: pressed syms feed the compose state machine; while // composing, the would-be text is withheld; on COMPOSED the machine — // not the keymap — provides the final text. if (down && g_composeState !is null && g_xkbState !is null) { immutable
_error_ sym
sym
= xkb_state_key_get_one_sym(g_xkbState, keycode);
if (xkb_compose_state_feed(g_composeState, sym) == XKB_COMPOSE_FEED_ACCEPTED) { immutable
_error_ status
status
= xkb_compose_state_get_status(g_composeState);
if (status == XKB_COMPOSE_COMPOSING) { instrEvent("compose", "state=composing"); text[0] = 0; // a dead key produces no text of its own } else if (status == XKB_COMPOSE_COMPOSED) { xkb_compose_state_get_utf8(g_composeState, text.
text.ptr
ptr
, text.
text.length
length
);
char[128]
_error_ safe
safe
= void;
sanitize(text.
text.ptr
ptr
, safe.
safe.ptr
ptr
, safe.
safe.length
length
);
instrEvent("compose", "state=composed text=%s", safe.
safe.ptr
ptr
);
xkb_compose_state_reset(g_composeState); } else if (status == XKB_COMPOSE_CANCELLED) { instrEvent("compose", "state=cancelled"); xkb_compose_state_reset(g_composeState); text[0] = 0; } } } logKeyLine(keycode, symName, text.
text.ptr
ptr
, down, 0);
if (down) armRepeat(keycode); // a new press re-targets the repeat else if (keycode == g_repeatKeycode) { g_cancelRelease++; cancelRepeat("release"); // the first mandatory cancellation } } /// Raw masks + group from the compositor; xkb_state_update_mask applies them. /// The client never tracks modifiers itself — pressed keys on *other* clients /// (grabs, compositor shortcuts) would desync it. extern (C) void
app.onKbModifiers

Raw masks + group from the compositor; xkb_state_update_mask applies them. The client never tracks modifiers itself — pressed keys on other clients (grabs, compositor shortcuts) would desync it.

onKbModifiers
(void* data, wl_keyboard* kb, uint serial,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
uint depressed, uint latched, uint locked, uint group) nothrow @nogc { if (g_xkbState !is null) xkb_state_update_mask(g_xkbState, depressed, latched, locked, 0, 0, group); instrEvent("modifiers", "depressed=0x%x latched=0x%x locked=0x%x group=%u", depressed, latched, locked, group); } /// The whole protocol-side repeat story: two integers, no events. extern (C) void
app.onKbRepeatInfo

The whole protocol-side repeat story: two integers, no events.

onKbRepeatInfo
(void* data, wl_keyboard* kb, int rate, int delay) nothrow @nogc
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
{ g_repeatRate = rate; g_repeatDelayMs = delay; instrEvent("repeat_info", "rate_hz=%d delay_ms=%d", rate, delay); } __gshared wl_keyboard_listener
_error_ app.g_keyboardListener
g_keyboardListener
= {
undefined identifier `wl_keyboard_listener`
&onKbKeymap, &onKbEnter, &onKbLeave, &onKbKey, &onKbModifiers, &onKbRepeatInfo }; // ---------------------------------------------------------- shm buffer pool bool
app.ensureBuffer
ensureBuffer
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer (scaffold pattern).

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))
{ 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-f06", 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; } 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;
return true; } void
app.paint
paint
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer (scaffold pattern).

Buffer
(parameter) Buffer b
b
, int frame) nothrow @nogc
{ immutable uint
_error_ color
color
= (frame & 1) ? 0xff30_3050 : 0xff50_3030;
immutable
_error_ n
n
= cast(
(unresolved type) size_t
size_t
) b.
b.width
width
* b.
b.height
height
;
foreach (
(parameter) i
i
; 0 .. n)
b.
b.pixels
pixels
[i] = color;
} void
void app.render() nothrow @nogc
render
() nothrow @nogc
{
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer (scaffold pattern).

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) return; // both busy: the release handler re-renders if (!ensureBuffer(*buf, g_width, g_height)) {
(__gshared global) bool app.g_running
g_running
= false;
return; } paint(*buf, g_frames); assert(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) { 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
++;
} // ------------------------------------------------------ remaining listeners 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)* 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)); 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, 7)); // v4+: wl_keyboard.repeat_info } 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); } /// Capabilities are dynamic: the keyboard is acquired when announced and /// released if it disappears (hotplug semantics, even for virtual devices). extern (C) void
app.onSeatCapabilities

Capabilities are dynamic: the keyboard is acquired when announced and released if it disappears (hotplug semantics, even for virtual devices).

onSeatCapabilities
(void* data, wl_seat* s, uint caps) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ instrEvent("seat_capabilities", "caps=0x%x keyboard=%d", caps, (caps & WL_SEAT_CAPABILITY_KEYBOARD) != 0); if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && g_keyboard is null) { g_keyboard = wsi_seat_get_keyboard(s); wsi_keyboard_add_listener(g_keyboard, &g_keyboardListener, null); instrEvent("keyboard_bound"); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && g_keyboard !is null) { cancelRepeat("capability_lost"); wsi_keyboard_release(g_keyboard); g_keyboard = null; instrEvent("keyboard_released"); } } extern (C) void
app.onSeatName
onSeatName
(void* data, wl_seat* s, const(char)* name) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ instrEvent("seat_name", "name=%s", name); } extern (C) void
app.onToplevelConfigure
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; } extern (C) void
app.onXdgSurfaceConfigure
onXdgSurfaceConfigure
(void* data, xdg_surface* s, uint serial) nothrow @nogc
undefined identifier `xdg_surface`, did you mean variable `g_surface`?
{ immutable
_error_ w
w
= g_pendingWidth > 0 ? g_pendingWidth : defaultWidth;
immutable
_error_ h
h
= g_pendingHeight > 0 ? g_pendingHeight : defaultHeight;
wsi_xdg_surface_ack_configure(s, serial); immutable
_error_ resized
resized
= w != g_width || h != g_height;
g_width = w; g_height = h; if (!g_configured) { g_configured = true; instrFirstConfigure(); render(); } else if (resized) { instrResize(w, h, 1); render(); } } 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; } 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`
{ } extern (C) void
app.onBufferRelease
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;
if (g_running && g_configured && g_frameCb is null) render(); } extern (C) void
app.onFrameDone
onFrameDone
(void* data, wl_callback* cb, uint timeMs) nothrow @nogc
undefined identifier `wl_callback`
{ wsi_callback_destroy(cb); g_frameCb = null; g_frames++; if (!g_presented) { g_presented = true; instrFirstPixelPresented(); } 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`
// ------------------------------------------- the F05 multiplexing loop again /// wl fd + repeat timerfd in one poll — the same canonical /// prepare_read/poll/read_events pump F05 documents; the repeat timer is /// exactly the kind of "external fd" that pattern exists for. bool
bool app.pumpOnce(int timeoutMs) nothrow @nogc

wl fd + repeat timerfd in one poll — the same canonical prepare_read/poll/read_events pump F05 documents; the repeat timer is exactly the kind of "external fd" that pattern exists for.

pumpOnce
(int
(parameter) int timeoutMs
timeoutMs
) nothrow @nogc
{ while (wl_display_prepare_read(g_display) != 0)
undefined identifier `wl_display_prepare_read`
if (wl_display_dispatch_pending(g_display) < 0)
undefined identifier `wl_display_dispatch_pending`
return false; wl_display_flush(g_display);
undefined identifier `wl_display_flush`
pollfd[2]
(local variable) _error_ pfds
pfds
;
undefined identifier `pollfd`
pfds[0].
(__error)[0].fd
fd
= wl_display_get_fd(g_display);
pfds[0].events = POLLIN; pfds[1].
(__error)[1].fd
fd
= g_repeatTimerfd;
pfds[1].events = POLLIN; immutable
(local variable) immutable(_error_) r
r
= poll(pfds.
pfds.ptr
ptr
, 2, timeoutMs);
undefined identifier `poll`, did you mean alias `atoll`?
if (r < 0) { wl_display_cancel_read(g_display);
undefined identifier `wl_display_cancel_read`
return false; } if (pfds[0].revents & POLLIN)
undefined identifier `POLLIN`
{ if (wl_display_read_events(g_display) < 0)
undefined identifier `wl_display_read_events`
return false; if (wl_display_dispatch_pending(g_display) < 0)
undefined identifier `wl_display_dispatch_pending`
return false; } else wl_display_cancel_read(g_display);
undefined identifier `wl_display_cancel_read`
if (pfds[1].revents & POLLIN)
undefined identifier `POLLIN`
void app.drainRepeatTimer() nothrow @nogc

Repeat timer fired: synthesize repeat=1 key events from the current xkb_state (so held-key repeats track live modifier changes).

drainRepeatTimer
();
return true; } // ----------------------------------------------------------------- teardown void
void app.teardown() nothrow @nogc
teardown
() nothrow @nogc
{ if (g_composeState !is null) xkb_compose_state_unref(g_composeState);
undefined identifier `xkb_compose_state_unref`
if (g_composeTable !is null) xkb_compose_table_unref(g_composeTable);
undefined identifier `xkb_compose_table_unref`
if (g_xkbState !is null) xkb_state_unref(g_xkbState);
undefined identifier `xkb_state_unref`
if (g_xkbKeymap !is null) xkb_keymap_unref(g_xkbKeymap);
undefined identifier `xkb_keymap_unref`
if (g_xkbCtx !is null) xkb_context_unref(g_xkbCtx);
undefined identifier `xkb_context_unref`
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_keyboard !is null) wsi_keyboard_release(g_keyboard);
undefined identifier `wsi_keyboard_release`
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`
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`
if (
(__gshared global) int app.g_repeatTimerfd
g_repeatTimerfd
>= 0)
close(g_repeatTimerfd);
undefined identifier `close`
} // --------------------------------------------------------------------- main int
int D main()
main
()
{ instrInit("f06-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';
long
(local variable) long capUs
capUs
=
(constant) long app.defaultCapUs = 30000000L
defaultCapUs
;
if (const
(local variable) const(char*) cap
cap
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_F06_CAP_US"))
if (
long core.stdc.stdlib.atoll(scope const(char*) nptr) nothrow @nogc
atoll
(
(local variable) const(char*) cap
cap
) > 0)
(local variable) long capUs
capUs
=
long core.stdc.stdlib.atoll(scope const(char*) nptr) nothrow @nogc
atoll
(
(local variable) const(char*) cap
cap
);
// 1. Connect (SKIP cleanly on 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; } // 2. Registry: bind the window globals + the seat. g_registry = wsi_display_get_registry(g_display); wsi_registry_add_listener(g_registry, &g_registryListener, null);
undefined identifier `wsi_registry_add_listener`
wl_display_roundtrip(g_display);
undefined identifier `wl_display_roundtrip`
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; } if (g_seat is null) { // Headless weston's documented shape: no input backend, no seat.
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: compositor advertises no wl_seat (headless weston?) — keyboard demo needs a seat\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`
wsi_seat_add_listener(g_seat, &g_seatListener, null);
undefined identifier `wsi_seat_add_listener`
// 3. xkbcommon context + locale compose table (client-side dead keys). g_xkbCtx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); const(char)*
(local variable) const(char)* locale
locale
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("LC_ALL");
if (
(local variable) const(char)* locale
locale
is null || *
(local variable) const(char)* locale
locale
== 0)
(local variable) const(char)* locale
locale
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("LC_CTYPE");
if (
(local variable) const(char)* locale
locale
is null || *
(local variable) const(char)* locale
locale
== 0)
(local variable) const(char)* locale
locale
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("LANG");
if (
(local variable) const(char)* locale
locale
is null || *
(local variable) const(char)* locale
locale
== 0)
(local variable) const(char)* locale
locale
= "C";
g_composeTable = xkb_compose_table_new_from_locale(g_xkbCtx, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); if (g_composeTable !is null) g_composeState = xkb_compose_state_new(g_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); instrEvent("compose_table", "locale=%s status=%s", locale,
undefined identifier `instrEvent`, did you mean import `instrument`?
g_composeTable !is null ? "ok".
"ok".ptr
ptr
: "unavailable".
"unavailable".ptr
ptr
);
// 4. The repeat timerfd (armed/disarmed by key events; see armRepeat).
(__gshared global) int app.g_repeatTimerfd
g_repeatTimerfd
= timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
undefined identifier `timerfd_create`
if (
(__gshared global) int app.g_repeatTimerfd
g_repeatTimerfd
< 0)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: timerfd unavailable\n");
void app.teardown() nothrow @nogc
teardown
();
return 0; } // 5. Window object tree (scaffold handshake) — the demo must be a mapped, // focused toplevel to receive wl_keyboard events at all. g_surface = wsi_compositor_create_surface(g_compositor); g_xdgSurface = wsi_wm_base_get_xdg_surface(g_wmBase, g_surface); 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); wsi_toplevel_add_listener(g_toplevel, &g_toplevelListener, null);
undefined identifier `wsi_toplevel_add_listener`
wsi_toplevel_set_title(g_toplevel, "wsi-f06-keyboard");
undefined identifier `wsi_toplevel_set_title`
wsi_toplevel_set_app_id(g_toplevel, "wsi-f06-keyboard");
undefined identifier `wsi_toplevel_set_app_id`
instrWindowCreated();
undefined identifier `instrWindowCreated`
wsi_surface_commit(g_surface); // mandatory initial no-buffer commit
undefined identifier `wsi_surface_commit`
// 6. Event loop: wl fd + repeat timerfd in one poll (see pumpOnce). while (
(__gshared global) bool app.g_running
g_running
)
{ if (!
bool app.pumpOnce(int timeoutMs) nothrow @nogc

wl fd + repeat timerfd in one poll — the same canonical prepare_read/poll/read_events pump F05 documents; the repeat timer is exactly the kind of "external fd" that pattern exists for.

pumpOnce
(
(constant) int app.pollTimeoutMs = 250
pollTimeoutMs
))
break; if (
(__gshared global) bool app.g_autoExit
g_autoExit
&& instrNowUs() >
(local variable) long capUs
capUs
)
undefined identifier `instrNowUs`
(__gshared global) bool app.g_running
g_running
= false;
} // 7. Teardown + the numbers.
void app.teardown() nothrow @nogc
teardown
();
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("ok: keymaps=%d key_events=%d repeats_synthesized=%d "
~ "cancel_on_release=%d cancel_on_focus_loss=%d\n",
(__gshared global) int app.g_keymapCount
g_keymapCount
,
(__gshared global) int app.g_keyEvents
g_keyEvents
,
(__gshared global) int app.g_repeatSynth
g_repeatSynth
,
(__gshared global) int app.g_cancelRelease
g_cancelRelease
,
(__gshared global) int app.g_cancelFocus
g_cancelFocus
);
return 0; }