app.dhover×534 error×165all
// F15 popup demo — xdg_popup + xdg_positioner + xdg_popup.grab on top of the
// xdg-shell scaffold (../scaffold/app.d; findings: ../../f15-popup.md).
//
// Four choreographed scenarios, selected by WSI_SCENARIO (input injected by
// ./run.sh through this binary's own `inject` mode — one zwlr_virtual_pointer
// device held across a WHOLE scenario, see ./inject.d):
//
//   menu     right-click opens a 3-item context menu: xdg_positioner with a
//            1x1 anchor rect at the click, gravity bottom_right,
//            constraint_adjustment slide|flip, then xdg_popup.grab with the
//            press serial. Hover highlight from wl_pointer.motion; a
//            reposition probe (xdg_popup v3 reposition/repositioned) fires
//            350 ms after the popup maps; clicking item 2 ("submenu >")
//            opens a NESTED popup parented on the first (the protocol
//            requires the chain) with its own grab; a click OUTSIDE the
//            window then dismisses — the compositor decides, the client only
//            receives xdg_popup.popup_done (topmost first: measured).
//   edge     same right-click menu, but the window sits at the output's
//            bottom-right corner so the requested placement is constrained —
//            the xdg_popup.configure x/y is the COMPOSITOR's solution
//            (slide? flip?); dismissal is Esc, delivered on the grab's
//            wl_keyboard (wtype plugs a virtual keyboard in; libxkbcommon
//            decodes its generated keymap).
//   stale    xdg_popup.grab with serial=1 when NO input event ever happened —
//            what does the compositor do with an invalid grab serial?
//            (protocol error? immediate popup_done? silent grant?) Measured.
//   noinput  headless-weston baseline (no seat → no serial → no grab):
//            plain popup + nested popup + reposition, logging the
//            positioner-solved placements only.
//
// Headless-safe: no compositor → SKIP, exit 0.
module 
(module) app
app
;
import c; // ImportC: wayland-client + xdg-shell glue + xkbcommon + poll
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.atoi = int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
,
(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
;
enum int
(constant) int app.mainWidth = 640
mainWidth
= 640;
enum int
(constant) int app.mainHeight = 480
mainHeight
= 480;
enum uint
(constant) uint app.BTN_LEFT = 272u
BTN_LEFT
= 0x110,
(constant) uint app.BTN_RIGHT = 273u
BTN_RIGHT
= 0x111;
// Menu geometry (also hardcoded in ./inject.d and ./run.sh — keep in sync). enum int
(constant) int app.p1W = 160
p1W
= 160,
(constant) int app.p1H = 96
p1H
= 96; // popup1: 3 items
enum int
(constant) int app.p2W = 140
p2W
= 140,
(constant) int app.p2H = 64
p2H
= 64; // popup2 (submenu): 2 items
enum int
(constant) int app.itemX = 4
itemX
= 4,
(constant) int app.itemW = 152
itemW
= 152,
(constant) int app.itemY0 = 6
itemY0
= 6,
(constant) int app.itemStep = 28
itemStep
= 28,
(constant) int app.itemH = 26
itemH
= 26;
enum
(enum) app.Scenario
Scenario
{
(enum value) app.Scenario.noinput = 0
noinput
,
(enum value) app.Scenario.menu = 1
menu
,
(enum value) app.Scenario.edge = 2
edge
,
(enum value) app.Scenario.stale = 3
stale
,
} __gshared immutable(char*)[4]
(immutable global) immutable(char*[4]) app.g_scenarioNames
g_scenarioNames
= ["noinput", "menu", "edge", "stale"];
// -------------------------------------------------------------------- state struct
(struct) app.Buffer
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
;
} /// One wl_surface with either the toplevel or a popup role. struct
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
{ wl_surface*
(field) _error_ app.Surf.surface
surface
;
undefined identifier `wl_surface`
xdg_surface*
(field) _error_ app.Surf.xdgSurface
xdgSurface
;
undefined identifier `xdg_surface`, did you mean variable `xdgSurface`?
xdg_toplevel*
(field) _error_ app.Surf.toplevel
toplevel
;
undefined identifier `xdg_toplevel`
xdg_popup*
(field) _error_ app.Surf.popup
popup
;
undefined identifier `xdg_popup`
(struct) app.Buffer
Buffer
[2]
(field) _error_ app.Surf.buffers
buffers
;
int
(field) int app.Surf.width
width
,
(field) int app.Surf.height
height
;
int
(field) int app.Surf.items
items
; // popup menu item count (0 for the toplevel)
int
(field) int app.Surf.hoverItem
hoverItem
= -1;
bool
(field) bool app.Surf.configured
configured
;
} enum
(alias) object.size_t = ulong
size_t
(constant) ulong app.IDX_MAIN = 0LU
IDX_MAIN
= 0,
(constant) ulong app.IDX_POPUP1 = 1LU
IDX_POPUP1
= 1,
(constant) ulong app.IDX_POPUP2 = 2LU
IDX_POPUP2
= 2;
__gshared immutable(char*)[3]
(immutable global) immutable(char*[3]) app.g_surfNames
g_surfNames
= ["main", "popup1", "popup2"];
__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`?
xdg_wm_base*
_error_ app.g_wmBase
g_wmBase
;
undefined identifier `xdg_wm_base`
uint
(__gshared global) uint app.g_wmBaseVersion
g_wmBaseVersion
;
wl_seat*
_error_ app.g_seat
g_seat
;
undefined identifier `wl_seat`, did you mean variable `g_seat`?
wl_pointer*
_error_ app.g_pointer
g_pointer
;
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
wl_keyboard*
_error_ app.g_keyboard
g_keyboard
;
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
wl_callback*
_error_ app.g_frameCb
g_frameCb
;
undefined identifier `wl_callback`
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`
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
[3]
_error_ app.g_surfs
g_surfs
;
(enum) app.Scenario
Scenario
(__gshared global) app.Scenario app.g_scenario
g_scenario
= Scenario.
Scenario.noinput
noinput
;
int
(__gshared global) int app.g_focusIdx
g_focusIdx
= -1; // pointer-focused surf index, -1 = none of ours
double
(__gshared global) double app.g_ptrX
g_ptrX
,
(__gshared global) double app.g_ptrY
g_ptrY
; // surface-local, on g_focusIdx
int
(__gshared global) int app.g_pendingW
g_pendingW
,
(__gshared global) int app.g_pendingH
g_pendingH
; // toplevel configure
bool
(__gshared global) bool app.g_running
g_running
= true,
(__gshared global) bool app.g_autoExit
g_autoExit
;
long
(__gshared global) long app.g_runUsCap
g_runUsCap
= 2_500_000;
long
(__gshared global) long app.g_firstPaintUs
g_firstPaintUs
= -1; // epoch for the noinput/stale step machine
long
(__gshared global) long app.g_repositionAtUs
g_repositionAtUs
= -1; // menu/edge: scheduled after popup1 maps
bool
(__gshared global) bool app.g_repositionSent
g_repositionSent
,
(__gshared global) bool app.g_grabUsed
g_grabUsed
;
int
(__gshared global) int app.g_step
g_step
; // noinput/stale step machine
int
(__gshared global) int app.g_doneEvents
g_doneEvents
; // popup_done counter (dismissal ORDER evidence)
int
(__gshared global) int app.g_frames
g_frames
;
bool
(__gshared global) bool app.g_staleConfigured
g_staleConfigured
,
(__gshared global) bool app.g_staleDone
g_staleDone
;
} // ------------------------------------------------------------------ popups /// Create popup `idx` with the given positioner recipe, optionally grabbing /// with `grabSerial` (>= 0). The initial commit carries no buffer (the /// configure/ack contract applies to popups exactly as to toplevels). void
void app.openPopup(ulong idx, ulong parentIdx, int ax, int ay, int aw, int ah, uint anchor, uint gravity, uint adjustment, int w, int h, long grabSerial, const(char)* note) nothrow @nogc

Create popup idx with the given positioner recipe, optionally grabbing with grabSerial (>= 0). The initial commit carries no buffer (the configure/ack contract applies to popups exactly as to toplevels).

openPopup
(
(alias) object.size_t = ulong
size_t
(parameter) ulong idx
idx
,
(alias) object.size_t = ulong
size_t
(parameter) ulong parentIdx
parentIdx
, int
(parameter) int ax
ax
, int
(parameter) int ay
ay
, int
(parameter) int aw
aw
, int
(parameter) int ah
ah
,
uint
(parameter) uint anchor
anchor
, uint
(parameter) uint gravity
gravity
, uint
(parameter) uint adjustment
adjustment
, int
(parameter) int w
w
, int
(parameter) int h
h
, long
(parameter) long grabSerial
grabSerial
,
const(char)*
(parameter) const(char)* note
note
) nothrow @nogc
{
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
*
(local variable) _error_ s
s
= &g_surfs[idx];
s.
s.width
width
= w;
s.
s.height
height
= h;
s.
s.items
items
= idx == IDX_POPUP2 ? 2 : 3;
s.
s.hoverItem
hoverItem
= -1;
s.
s.configured
configured
= false;
xdg_positioner*
(local variable) _error_ pos
pos
= wsi_wm_base_create_positioner(g_wmBase);
undefined identifier `xdg_positioner`
undefined identifier `wsi_wm_base_create_positioner`
wsi_positioner_set_size(pos, w, h);
undefined identifier `wsi_positioner_set_size`
wsi_positioner_set_anchor_rect(pos, ax, ay, aw, ah);
undefined identifier `wsi_positioner_set_anchor_rect`
wsi_positioner_set_anchor(pos, anchor);
undefined identifier `wsi_positioner_set_anchor`
wsi_positioner_set_gravity(pos, gravity);
undefined identifier `wsi_positioner_set_gravity`
wsi_positioner_set_constraint_adjustment(pos, adjustment);
undefined identifier `wsi_positioner_set_constraint_adjustment`
if (
(__gshared global) uint app.g_wmBaseVersion
g_wmBaseVersion
>= 3)
wsi_positioner_set_reactive(pos); // auto-reposition on env change (v3)
undefined identifier `wsi_positioner_set_reactive`
s.
s.surface
surface
= wsi_compositor_create_surface(g_compositor);
s.
s.xdgSurface
xdgSurface
= wsi_wm_base_get_xdg_surface(g_wmBase, s.
s.surface
surface
);
wsi_xdg_surface_add_listener(s.
s.xdgSurface
xdgSurface
, &g_xdgSurfaceListener, cast(void*) idx);
undefined identifier `wsi_xdg_surface_add_listener`
s.
s.popup
popup
= wsi_xdg_surface_get_popup(s.
s.xdgSurface
xdgSurface
, g_surfs[parentIdx].
g_surfs[parentIdx].xdgSurface
xdgSurface
, pos);
wsi_popup_add_listener(s.
s.popup
popup
, &g_popupListener, cast(void*) idx);
undefined identifier `wsi_popup_add_listener`
wsi_positioner_destroy(pos);
undefined identifier `wsi_positioner_destroy`
instrEvent("popup_open",
undefined identifier `instrEvent`, did you mean import `instrument`?
"idx=%s parent=%s anchor_rect=%d,%d %dx%d anchor=%u gravity=%u adjustment=%u size=%dx%d note=%s", g_surfNames[idx], g_surfNames[parentIdx], ax, ay, aw, ah, anchor, gravity, adjustment, w, h, note); if (
(parameter) long grabSerial
grabSerial
>= 0)
{ wsi_popup_grab(s.
s.popup
popup
, g_seat, cast(uint) grabSerial);
undefined identifier `wsi_popup_grab`
(__gshared global) bool app.g_grabUsed
g_grabUsed
= true;
instrEvent("grab", "idx=%s serial=%lld state=requested", g_surfNames[idx], grabSerial);
undefined identifier `instrEvent`, did you mean import `instrument`?
} wsi_surface_commit(s.
s.surface
surface
); // mandatory no-buffer first commit
undefined identifier `wsi_surface_commit`
} /// Client-side dismissal (item click / Esc): topmost first, per the chain /// rule ("they must be destroyed in the reverse order they were created in"). void
void app.dismissPopups(const(char)* cause) nothrow @nogc

Client-side dismissal (item click / Esc): topmost first, per the chain rule ("they must be destroyed in the reverse order they were created in").

dismissPopups
(const(char)*
(parameter) const(char)* cause
cause
) nothrow @nogc
{ foreach_reverse (
(parameter) idx
idx
;
(constant) ulong app.IDX_POPUP1 = 1LU
IDX_POPUP1
.. g_surfs.
(field) _error_ g_surfs.length
length
)
if (g_surfs[idx].
g_surfs[idx].popup
popup
!is null)
{ instrEvent("popup_dismiss", "idx=%s cause=%s", g_surfNames[idx], cause); destroyPopup(idx); } } void
void app.destroyPopup(ulong idx) nothrow @nogc
destroyPopup
(
(alias) object.size_t = ulong
size_t
(parameter) ulong idx
idx
) nothrow @nogc
{
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
*
(local variable) _error_ s
s
= &g_surfs[idx];
if (s.
(field) _error_ s.popup
popup
is null)
return; wsi_popup_destroy(s.
s.popup
popup
);
undefined identifier `wsi_popup_destroy`
wsi_xdg_surface_destroy(s.
s.xdgSurface
xdgSurface
);
undefined identifier `wsi_xdg_surface_destroy`
wsi_surface_destroy(s.
s.surface
surface
);
undefined identifier `wsi_surface_destroy`
foreach (ref
(parameter) b
b
; s.
(field) _error_ s.buffers
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; } s.
s.popup
popup
= null;
s.
s.xdgSurface
xdgSurface
= null;
s.
s.surface
surface
= null;
if (
(__gshared global) int app.g_focusIdx
g_focusIdx
== cast(int)
(parameter) ulong idx
idx
)
(__gshared global) int app.g_focusIdx
g_focusIdx
= -1;
} /// The right-click menu (popup1). Anchor: 1x1 rect at the click position, /// anchor point its bottom-right corner, gravity bottom_right ("down-right /// of the cursor"), constraint_adjustment slide|flip on both axes. void
void app.openMenu(int clickX, int clickY, long serial) nothrow @nogc

The right-click menu (popup1). Anchor: 1x1 rect at the click position, anchor point its bottom-right corner, gravity bottom_right ("down-right of the cursor"), constraint_adjustment slide|flip on both axes.

openMenu
(int
(parameter) int clickX
clickX
, int
(parameter) int clickY
clickY
, long
(parameter) long serial
serial
) nothrow @nogc
{ enum uint
(constant) uint app.openMenu.adj = __error__
adj
= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X`
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y`
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X`
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y`
void app.openPopup(ulong idx, ulong parentIdx, int ax, int ay, int aw, int ah, uint anchor, uint gravity, uint adjustment, int w, int h, long grabSerial, const(char)* note) nothrow @nogc

Create popup idx with the given positioner recipe, optionally grabbing with grabSerial (>= 0). The initial commit carries no buffer (the configure/ack contract applies to popups exactly as to toplevels).

openPopup
(
(constant) ulong app.IDX_POPUP1 = 1LU
IDX_POPUP1
,
(constant) ulong app.IDX_MAIN = 0LU
IDX_MAIN
,
(parameter) int clickX
clickX
,
(parameter) int clickY
clickY
, 1, 1,
XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
undefined identifier `XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT`
undefined identifier `XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT`
adj,
(constant) int app.p1W = 160
p1W
,
(constant) int app.p1H = 96
p1H
,
(parameter) long serial
serial
, "context-menu");
} /// The submenu (popup2), parented on POPUP1 — the chain the protocol /// requires for a second grabbing popup. Anchored to item 2's rect, opening /// to the right; flip_x so a constrained edge would mirror it to the left. void
void app.openSubmenu(long serial) nothrow @nogc

The submenu (popup2), parented on POPUP1 — the chain the protocol requires for a second grabbing popup. Anchored to item 2's rect, opening to the right; flip_x so a constrained edge would mirror it to the left.

openSubmenu
(long
(parameter) long serial
serial
) nothrow @nogc
{ enum uint
(constant) uint app.openSubmenu.adj = __error__
adj
= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X`
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
undefined identifier `XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y`
void app.openPopup(ulong idx, ulong parentIdx, int ax, int ay, int aw, int ah, uint anchor, uint gravity, uint adjustment, int w, int h, long grabSerial, const(char)* note) nothrow @nogc

Create popup idx with the given positioner recipe, optionally grabbing with grabSerial (>= 0). The initial commit carries no buffer (the configure/ack contract applies to popups exactly as to toplevels).

openPopup
(
(constant) ulong app.IDX_POPUP2 = 2LU
IDX_POPUP2
,
(constant) ulong app.IDX_POPUP1 = 1LU
IDX_POPUP1
,
(constant) int app.itemX = 4
itemX
,
(constant) int app.itemY0 = 6
itemY0
+ 2 *
(constant) int app.itemStep = 28
itemStep
,
(constant) int app.itemW = 152
itemW
,
(constant) int app.itemH = 26
itemH
,
XDG_POSITIONER_ANCHOR_TOP_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
undefined identifier `XDG_POSITIONER_ANCHOR_TOP_RIGHT`
undefined identifier `XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT`
adj,
(constant) int app.p2W = 140
p2W
,
(constant) int app.p2H = 64
p2H
,
(parameter) long serial
serial
, "submenu");
} extern (C) void
app.onPopupConfigure
onPopupConfigure
(void* data, xdg_popup* p, int
(parameter) int x
x
, int
(parameter) int y
y
, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc
undefined identifier `xdg_popup`
{ immutable
_error_ idx
idx
= cast(
(unresolved type) size_t
size_t
) data;
// x/y are "relative to the upper left corner of the window geometry of // the parent surface" — this is the compositor's placement DECISION, // not an echo of the request. instrEvent("popup_placed", "idx=%s x=%d y=%d size=%dx%d", g_surfNames[idx], x, y, w, h); if (w > 0 && h > 0) { g_surfs[idx].
g_surfs[idx].width
width
= w;
g_surfs[idx].
g_surfs[idx].height
height
= h;
} if (idx == IDX_POPUP1 && g_scenario == Scenario.
Scenario.stale
stale
)
g_staleConfigured = true; // Schedule the explicit-reposition probe once the menu has mapped. if (idx == IDX_POPUP1 && !g_repositionSent && g_repositionAtUs < 0 && g_scenario != Scenario.
Scenario.edge
edge
&& g_wmBaseVersion >= 3)
g_repositionAtUs = instrNowUs() + 350_000; } extern (C) void
app.onPopupDone
onPopupDone
(void* data, xdg_popup* p) nothrow @nogc
undefined identifier `xdg_popup`
{ immutable
_error_ idx
idx
= cast(
(unresolved type) size_t
size_t
) data;
g_doneEvents++; // The compositor dismissed us; the client merely cleans up. The ORDER of // these events across the chain is the topmost-first evidence. instrEvent("popup_dismiss", "idx=%s cause=popup_done order=%d", g_surfNames[idx], g_doneEvents); if (idx == IDX_POPUP1 && g_scenario == Scenario.
Scenario.stale
stale
)
g_staleDone = true; destroyPopup(idx); } extern (C) void
app.onPopupRepositioned
onPopupRepositioned
(void* data, xdg_popup* p, uint token) nothrow @nogc
undefined identifier `xdg_popup`
{ instrEvent("repositioned", "idx=%s token=%u", g_surfNames[cast(
(unresolved type) size_t
size_t
) data], token);
} __gshared xdg_popup_listener
_error_ app.g_popupListener
g_popupListener
= {
undefined identifier `xdg_popup_listener`
&onPopupConfigure, &onPopupDone, &onPopupRepositioned }; /// The v3 explicit-reposition probe: a fresh positioner (same recipe, /// +24/+16 offset), xdg_popup.reposition(token=7) → expect repositioned(7) /// followed by a new popup configure. void
void app.sendReposition() nothrow @nogc

The v3 explicit-reposition probe: a fresh positioner (same recipe, +24/+16 offset), xdg_popup.reposition(token=7) → expect repositioned(7) followed by a new popup configure.

sendReposition
() nothrow @nogc
{
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
*
(local variable) _error_ s
s
= &g_surfs[IDX_POPUP1];
if (s.
(field) _error_ s.popup
popup
is null)
return; xdg_positioner*
(local variable) _error_ pos
pos
= wsi_wm_base_create_positioner(g_wmBase);
undefined identifier `xdg_positioner`
undefined identifier `wsi_wm_base_create_positioner`
wsi_positioner_set_size(pos, p1W, p1H);
undefined identifier `wsi_positioner_set_size`
wsi_positioner_set_anchor_rect(pos, 180, 180, 1, 1);
undefined identifier `wsi_positioner_set_anchor_rect`
wsi_positioner_set_anchor(pos, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
undefined identifier `wsi_positioner_set_anchor`
wsi_positioner_set_gravity(pos, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
undefined identifier `wsi_positioner_set_gravity`
wsi_positioner_set_constraint_adjustment(pos,
undefined identifier `wsi_positioner_set_constraint_adjustment`
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); wsi_positioner_set_offset(pos, 24, 16);
undefined identifier `wsi_positioner_set_offset`
wsi_positioner_set_reactive(pos);
undefined identifier `wsi_positioner_set_reactive`
wsi_popup_reposition(s.
s.popup
popup
, pos, 7);
undefined identifier `wsi_popup_reposition`
wsi_positioner_destroy(pos);
undefined identifier `wsi_positioner_destroy`
(__gshared global) bool app.g_repositionSent
g_repositionSent
= true;
instrEvent("reposition_request", "idx=popup1 token=7 offset=24,16");
undefined identifier `instrEvent`, did you mean import `instrument`?
} // ----------------------------------------------------------------- pointer int
app.surfIndexOf
surfIndexOf
(wl_surface*
(parameter) wl_surface* s
s
) nothrow @nogc
undefined identifier `wl_surface`
{ foreach (
(parameter) i
i
, ref
(parameter) sf
sf
; g_surfs)
if (sf.
sf.surface
surface
is s)
return cast(int) i; return -1; } int
int app.itemAt(ulong idx, double x, double y) nothrow @nogc
itemAt
(
(alias) object.size_t = ulong
size_t
(parameter) ulong idx
idx
, double
(parameter) double x
x
, double
(parameter) double y
y
) nothrow @nogc
{ if (
(parameter) double x
x
<
(constant) int app.itemX = 4
itemX
||
(parameter) double x
x
>=
(constant) int app.itemX = 4
itemX
+
(constant) int app.itemW = 152
itemW
)
return -1; foreach (
(parameter) i
i
; 0 .. g_surfs[idx].
(field) _error_ (__error)[idx].items
items
)
{ immutable
_error_ top
top
= itemY0 + i * itemStep;
if (y >= top && y < top + itemH) return i; } return -1; } extern (C) void
app.onPointerEnter
onPointerEnter
(void* data, wl_pointer* p, uint
(parameter) uint serial
serial
,
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
wl_surface* surf, int sx, int sy) nothrow @nogc
undefined identifier `wl_surface`
{ g_focusIdx = surfIndexOf(surf); g_ptrX = sx / 256.0; g_ptrY = sy / 256.0; instrEvent("pointer_enter", "surface=%s serial=%u pos=%.1f,%.1f", g_focusIdx >= 0 ? g_surfNames[g_focusIdx] : "other", serial, g_ptrX, g_ptrY); if (g_focusIdx > 0) { immutable
_error_ item
item
= itemAt(g_focusIdx, g_ptrX, g_ptrY);
if (item != g_surfs[g_focusIdx].
g_surfs[g_focusIdx].hoverItem
hoverItem
)
{ g_surfs[g_focusIdx].
g_surfs[g_focusIdx].hoverItem
hoverItem
= item;
instrEvent("hover", "idx=%s item=%d", g_surfNames[g_focusIdx], item); render(g_focusIdx); } } } extern (C) void
app.onPointerLeave
onPointerLeave
(void* data, wl_pointer* p, uint
(parameter) uint serial
serial
, wl_surface* surf) nothrow @nogc
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
undefined identifier `wl_surface`
{ immutable
_error_ idx
idx
= surfIndexOf(surf);
instrEvent("pointer_leave", "surface=%s serial=%u", idx >= 0 ? g_surfNames[idx] : "other", serial); if (idx >= 0 && g_surfs[idx].
g_surfs[idx].popup
popup
!is null && g_surfs[idx].
g_surfs[idx].hoverItem
hoverItem
!= -1)
{ g_surfs[idx].
g_surfs[idx].hoverItem
hoverItem
= -1;
render(idx); } g_focusIdx = -1; } extern (C) void
app.onPointerMotion
onPointerMotion
(void* data, wl_pointer* p, uint time, int sx, int sy) nothrow @nogc
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
{ g_ptrX = sx / 256.0; g_ptrY = sy / 256.0; if (g_focusIdx <= 0) return;
(unresolved type) Surf
Surf
*
_error_ s
s
= &g_surfs[g_focusIdx];
immutable
_error_ item
item
= itemAt(g_focusIdx, g_ptrX, g_ptrY);
if (item != s.
s.hoverItem
hoverItem
)
{ s.
s.hoverItem
hoverItem
= item;
instrEvent("hover", "idx=%s item=%d", g_surfNames[g_focusIdx], item); render(g_focusIdx); } } extern (C) void
app.onPointerButton
onPointerButton
(void* data, wl_pointer* p, uint
(parameter) uint serial
serial
, uint time,
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
uint button, uint
(parameter) uint state
state
) nothrow @nogc
{ instrEvent("button", "surface=%s serial=%u button=0x%x state=%u", g_focusIdx >= 0 ? g_surfNames[g_focusIdx] : "none", serial, button, state); if (state != WL_POINTER_BUTTON_STATE_PRESSED) return; if (g_focusIdx == IDX_MAIN && button == BTN_RIGHT && g_surfs[IDX_POPUP1].
g_surfs[IDX_POPUP1].popup
popup
is null)
{ openMenu(cast(int) g_ptrX, cast(int) g_ptrY, serial); return; } if (g_focusIdx == IDX_POPUP1 && button == BTN_LEFT) { immutable
_error_ item
item
= g_surfs[IDX_POPUP1].
g_surfs[IDX_POPUP1].hoverItem
hoverItem
;
if (item == 2 && g_surfs[IDX_POPUP2].
g_surfs[IDX_POPUP2].popup
popup
is null)
openSubmenu(serial); // nested grab: parent must be the grabbed popup else if (item >= 0) { instrEvent("item_activated", "idx=popup1 item=%d", item); dismissPopups("item-click"); } return; } if (g_focusIdx == IDX_POPUP2 && button == BTN_LEFT) { instrEvent("item_activated", "idx=popup2 item=%d", g_surfs[IDX_POPUP2].
g_surfs[IDX_POPUP2].hoverItem
hoverItem
);
dismissPopups("item-click"); return; } // A press on the parent window while a grab is held: does the grab route // it here at all, and does the compositor treat "inside the same client // but outside the popups" as outside? Logged either way (finding). if (g_focusIdx == IDX_MAIN && g_surfs[IDX_POPUP1].
g_surfs[IDX_POPUP1].popup
popup
!is null)
instrEvent("button_on_parent_during_grab", "serial=%u button=0x%x", serial, button); } extern (C) void
app.onPointerAxis
onPointerAxis
(void* data, wl_pointer* p, uint time, uint axis, int value) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerFrame
onPointerFrame
(void* data, wl_pointer* p) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerAxisSource
onPointerAxisSource
(void* data, wl_pointer* p, uint src) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerAxisStop
onPointerAxisStop
(void* data, wl_pointer* p, uint time, uint axis) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerAxisDiscrete
onPointerAxisDiscrete
(void* data, wl_pointer* p, uint axis, int discrete) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerAxisValue120
onPointerAxisValue120
(void* data, wl_pointer* p, uint axis, int v120) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
extern (C) void
app.onPointerAxisRelDir
onPointerAxisRelDir
(void* data, wl_pointer* p, uint axis, uint dir) nothrow @nogc {}
undefined identifier `wl_pointer`, did you mean variable `g_pointer`?
__gshared wl_pointer_listener
_error_ app.g_pointerListener
g_pointerListener
= {
undefined identifier `wl_pointer_listener`
&onPointerEnter, &onPointerLeave, &onPointerMotion, &onPointerButton, &onPointerAxis, &onPointerFrame, &onPointerAxisSource, &onPointerAxisStop, &onPointerAxisDiscrete, &onPointerAxisValue120, &onPointerAxisRelDir }; // ---------------------------------------------------------------- keyboard extern (C) void
app.onKeymap
onKeymap
(void* data, wl_keyboard* kb, uint format, int
(parameter) int fd
fd
, uint
(parameter) uint size
size
) nothrow @nogc
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
{ instrEvent("keymap", "format=%u size=%u", format, size); if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { void*
_error_ mem
mem
= mmap(null, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem !is cast(void*)-1) { if (g_xkbKeymap !is null) xkb_keymap_unref(g_xkbKeymap); if (g_xkbState !is null) xkb_state_unref(g_xkbState); g_xkbKeymap = xkb_keymap_new_from_string(g_xkbCtx, cast(char*) mem, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); g_xkbState = g_xkbKeymap !is null ? xkb_state_new(g_xkbKeymap) : null; munmap(mem, size); } } close(fd); } extern (C) void
app.onKeyboardEnter
onKeyboardEnter
(void* data, wl_keyboard* kb, uint
(parameter) uint serial
serial
,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
wl_surface* surf, wl_array* keys) nothrow @nogc
undefined identifier `wl_surface`
undefined identifier `wl_array`
{ // Under an xdg_popup.grab the keyboard focus must land on the POPUP — // this line is the proof of where the grab routed it. immutable
_error_ idx
idx
= surfIndexOf(surf);
instrEvent("keyboard_enter", "surface=%s serial=%u keys_down=%zu", idx >= 0 ? g_surfNames[idx] : "other", serial, keys.
keys.size
size
/ uint.sizeof);
// Keys already held at enter arrive in the `keys` array, NOT as key // events — a freshly plugged wtype keyboard's Esc press can land here. foreach (
(parameter) key
key
; (cast(uint*) keys.data)[0 .. keys.size / uint.sizeof])
handleKey(key, WL_KEYBOARD_KEY_STATE_PRESSED); } void
void app.handleKey(uint key, uint state) nothrow @nogc
handleKey
(uint
(parameter) uint key
key
, uint
(parameter) uint state
state
) nothrow @nogc
{ uint
(local variable) uint sym
sym
= 0;
if (g_xkbState !is null)
(local variable) uint sym
sym
= xkb_state_key_get_one_sym(g_xkbState, key + 8);
undefined identifier `xkb_state_key_get_one_sym`
instrEvent("key", "key=%u keysym=0x%x state=%u", key, sym, state);
undefined identifier `instrEvent`, did you mean import `instrument`?
if (
(parameter) uint state
state
== WL_KEYBOARD_KEY_STATE_PRESSED &&
(local variable) uint sym
sym
== XKB_KEY_Escape
undefined identifier `WL_KEYBOARD_KEY_STATE_PRESSED`
undefined identifier `XKB_KEY_Escape`
&& g_surfs[IDX_POPUP1].
(field) _error_ (__error)[IDX_POPUP1].popup
popup
!is null)
void app.dismissPopups(const(char)* cause) nothrow @nogc

Client-side dismissal (item click / Esc): topmost first, per the chain rule ("they must be destroyed in the reverse order they were created in").

dismissPopups
("esc-grab-keyboard");
} extern (C) void
app.onKeyboardLeave
onKeyboardLeave
(void* data, wl_keyboard* kb, uint
(parameter) uint serial
serial
, wl_surface* surf) nothrow @nogc
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
undefined identifier `wl_surface`
{ immutable
_error_ idx
idx
= surfIndexOf(surf);
instrEvent("keyboard_leave", "surface=%s serial=%u", idx >= 0 ? g_surfNames[idx] : "other", serial); } extern (C) void
app.onKey
onKey
(void* data, wl_keyboard* kb, uint
(parameter) uint serial
serial
, uint time,
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
uint
(parameter) uint key
key
, uint
(parameter) uint state
state
) nothrow @nogc
{ handleKey(key, state); } extern (C) void
app.onModifiers
onModifiers
(void* data, wl_keyboard* kb, uint
(parameter) uint serial
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); } extern (C) void
app.onRepeatInfo
onRepeatInfo
(void* data, wl_keyboard* kb, int rate, int delay) nothrow @nogc {}
undefined identifier `wl_keyboard`, did you mean variable `g_keyboard`?
__gshared wl_keyboard_listener
_error_ app.g_keyboardListener
g_keyboardListener
= {
undefined identifier `wl_keyboard_listener`
&onKeymap, &onKeyboardEnter, &onKeyboardLeave, &onKey, &onModifiers, &onRepeatInfo }; // ------------------------------------------------------------------- seat 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=%u", caps); immutable
_error_ hasPointer
hasPointer
= (caps & WL_SEAT_CAPABILITY_POINTER) != 0;
immutable
_error_ hasKeyboard
hasKeyboard
= (caps & WL_SEAT_CAPABILITY_KEYBOARD) != 0;
if (hasPointer && g_pointer is null) { g_pointer = wsi_seat_get_pointer(g_seat); wsi_pointer_add_listener(g_pointer, &g_pointerListener, null); } else if (!hasPointer && g_pointer !is null) { wsi_pointer_destroy(g_pointer); g_pointer = null; g_focusIdx = -1; // Does the device unplug (capability drop) dismiss an active grab // popup? Whatever follows this line in the log is the answer. instrEvent("pointer_dropped", "popup1_open=%d popup2_open=%d", g_surfs[IDX_POPUP1].
g_surfs[IDX_POPUP1].popup
popup
!is null ? 1 : 0,
g_surfs[IDX_POPUP2].
g_surfs[IDX_POPUP2].popup
popup
!is null ? 1 : 0);
} if (hasKeyboard && g_keyboard is null) { g_keyboard = wsi_seat_get_keyboard(g_seat); wsi_keyboard_add_listener(g_keyboard, &g_keyboardListener, null); } else if (!hasKeyboard && g_keyboard !is null) { wsi_keyboard_destroy(g_keyboard); g_keyboard = null; } } 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`?
__gshared wl_seat_listener
_error_ app.g_seatListener
g_seatListener
= {&onSeatCapabilities, &onSeatName};
undefined identifier `wl_seat_listener`
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, 6)); 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) { // v3+ unlocks xdg_popup.reposition/repositioned and set_reactive. g_wmBaseVersion = capped(ver, 5); g_wmBase = cast(xdg_wm_base*) wsi_registry_bind(reg, name, &xdg_wm_base_interface, g_wmBaseVersion); } else if (strcmp(iface, wl_seat_interface.name) == 0 && g_seat is null) { g_seat = cast(wl_seat*) wsi_registry_bind(reg, name, &wl_seat_interface, capped(ver, 5)); wsi_seat_add_listener(g_seat, &g_seatListener, null); } } 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`?
__gshared wl_registry_listener
_error_ app.g_registryListener
g_registryListener
= {&onGlobal, &onGlobalRemove};
undefined identifier `wl_registry_listener`
// ------------------------------------------------ window plumbing (scaffold) bool
app.ensureBuffer
ensureBuffer
(ref
(struct) app.Buffer
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-f15", MFD_CLOEXEC);
if (fd < 0 || ftruncate(fd, cast(long) size) != 0) 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;
return true; } /// Paint surf `idx`: flat background for the main window; solid menu panel /// with item rows + hover highlight for popups. Event-driven redraw only /// (no frame-callback loop — popups repaint on hover changes). void
void app.render(ulong idx) nothrow @nogc

Paint surf idx: flat background for the main window; solid menu panel with item rows + hover highlight for popups. Event-driven redraw only (no frame-callback loop — popups repaint on hover changes).

render
(
(alias) object.size_t = ulong
size_t
(parameter) ulong idx
idx
) nothrow @nogc
{
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
*
(local variable) _error_ s
s
= &g_surfs[idx];
if (s.
(field) _error_ s.surface
surface
is null || !s.
(field) _error_ s.configured
configured
)
return;
(struct) app.Buffer
Buffer
*
(local variable) _error_ buf
buf
= null;
foreach (ref
(parameter) b
b
; s.
(field) _error_ s.buffers
buffers
)
if (!b.
b.busy
busy
)
{ buf = &b; break; } if (buf is null || !ensureBuffer(*buf, s.
s.width
width
, s.
s.height
height
))
return; immutable uint
(local variable) immutable(uint) bg
bg
=
(parameter) ulong idx
idx
==
(constant) ulong app.IDX_MAIN = 0LU
IDX_MAIN
? 0xff20283c : 0xff3a3a44;
foreach (
(parameter) y
y
; 0 .. buf.
(field) _error_ buf.height
height
)
foreach (
(parameter) x
x
; 0 .. buf.
buf.width
width
)
{ uint
_error_ c
c
= bg;
if (idx != IDX_MAIN) { if (x == 0 || y == 0 || x == buf.
buf.width
width
- 1 || y == buf.
buf.height
height
- 1)
c = 0xff8888a0; // panel border else { immutable
_error_ item
item
= itemAt(idx, x, y);
if (item >= 0) c = item == s.
s.hoverItem
hoverItem
? 0xff5a6a92 : 0xff44444e;
} } buf.
buf.pixels
pixels
[cast(
(unresolved type) size_t
size_t
) y * buf.
buf.width
width
+ x] = c;
} wsi_surface_attach(s.
s.surface
surface
, buf.
buf.handle
handle
, 0, 0);
undefined identifier `wsi_surface_attach`
wsi_surface_damage_buffer(s.
s.surface
surface
, 0, 0, buf.
buf.width
width
, buf.
buf.height
height
);
undefined identifier `wsi_surface_damage_buffer`
if (
(parameter) ulong idx
idx
==
(constant) ulong app.IDX_MAIN = 0LU
IDX_MAIN
&&
(__gshared global) int app.g_frames
g_frames
== 0 && g_frameCb is null)
{ g_frameCb = wsi_surface_frame(s.
s.surface
surface
);
wsi_callback_add_listener(g_frameCb, &g_frameListener, null);
undefined identifier `wsi_callback_add_listener`
} wsi_surface_commit(s.
s.surface
surface
);
undefined identifier `wsi_surface_commit`
buf.
buf.busy
busy
= true;
} extern (C) void
app.onWmBasePing
onWmBasePing
(void* data, xdg_wm_base*
(parameter) xdg_wm_base* b
b
, uint
(parameter) uint serial
serial
) nothrow @nogc
undefined identifier `xdg_wm_base`
{ wsi_wm_base_pong(b, serial); } extern (C) void
app.onToplevelConfigure
onToplevelConfigure
(void* data, xdg_toplevel*
(parameter) xdg_toplevel* t
t
, int
(parameter) int w
w
, int
(parameter) int h
h
,
undefined identifier `xdg_toplevel`
wl_array* states) nothrow @nogc
undefined identifier `wl_array`
{ g_pendingW = w; g_pendingH = h; } extern (C) void
app.onXdgSurfaceConfigure
onXdgSurfaceConfigure
(void* data, xdg_surface*
(parameter) xdg_surface* s
s
, uint
(parameter) uint serial
serial
) nothrow @nogc
undefined identifier `xdg_surface`
{ immutable
_error_ idx
idx
= cast(
(unresolved type) size_t
size_t
) data;
(unresolved type) Surf
Surf
*
_error_ sf
sf
= &g_surfs[idx];
if (idx == IDX_MAIN) { sf.
sf.width
width
= g_pendingW > 0 ? g_pendingW : mainWidth;
sf.
sf.height
height
= g_pendingH > 0 ? g_pendingH : mainHeight;
} instrEvent("configure", "idx=%s serial=%u size=%dx%d", g_surfNames[idx], serial, sf.
sf.width
width
, sf.
sf.height
height
);
wsi_xdg_surface_ack_configure(s, serial); immutable
_error_ wasConfigured
wasConfigured
= sf.
sf.configured
configured
;
sf.
sf.configured
configured
= true;
if (idx == IDX_MAIN && !wasConfigured) instrFirstConfigure(); render(idx); if (idx == IDX_MAIN && g_firstPaintUs < 0) g_firstPaintUs = instrNowUs(); } extern (C) void
app.onToplevelClose
onToplevelClose
(void* data, xdg_toplevel*
(parameter) xdg_toplevel* t
t
) nothrow @nogc
undefined identifier `xdg_toplevel`
{ instrCloseRequested(); g_running = false; } extern (C) void
app.onToplevelConfigureBounds
onToplevelConfigureBounds
(void* data, xdg_toplevel*
(parameter) xdg_toplevel* t
t
, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc {}
undefined identifier `xdg_toplevel`
extern (C) void
app.onToplevelWmCapabilities
onToplevelWmCapabilities
(void* data, xdg_toplevel*
(parameter) xdg_toplevel* t
t
, wl_array* caps) nothrow @nogc {}
undefined identifier `xdg_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`
{ (cast(
(unresolved type) Buffer
Buffer
*) data).
(cast(Buffer*)data).busy
busy
= false;
} 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_frames == 1) instrFirstPixelPresented(); } __gshared xdg_wm_base_listener
_error_ app.g_wmBaseListener
g_wmBaseListener
= {&onWmBasePing};
undefined identifier `xdg_wm_base_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`
// ----------------------------------------------------- scenario step machine /// Time-driven steps for the input-less scenarios (noinput, stale) and the /// deferred reposition probe of menu/noinput. void
void app.tick() nothrow @nogc

Time-driven steps for the input-less scenarios (noinput, stale) and the deferred reposition probe of menu/noinput.

tick
() nothrow @nogc
{ immutable
(local variable) immutable(_error_) now
now
= instrNowUs();
undefined identifier `instrNowUs`
if (
(__gshared global) long app.g_repositionAtUs
g_repositionAtUs
>= 0 && now >=
(__gshared global) long app.g_repositionAtUs
g_repositionAtUs
&& !
(__gshared global) bool app.g_repositionSent
g_repositionSent
)
{
(__gshared global) long app.g_repositionAtUs
g_repositionAtUs
= -1;
void app.sendReposition() nothrow @nogc

The v3 explicit-reposition probe: a fresh positioner (same recipe, +24/+16 offset), xdg_popup.reposition(token=7) → expect repositioned(7) followed by a new popup configure.

sendReposition
();
} if (
(__gshared global) long app.g_firstPaintUs
g_firstPaintUs
< 0)
return; immutable
(local variable) immutable(_error_) t
t
= now -
(__gshared global) long app.g_firstPaintUs
g_firstPaintUs
;
final switch (
(__gshared global) app.Scenario app.g_scenario
g_scenario
)
{ case
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.menu = 1
menu
:
case
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.edge = 2
edge
:
break; // input-driven case
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.noinput = 0
noinput
:
if (
(__gshared global) int app.g_step
g_step
== 0 && t > 300_000)
{
(__gshared global) int app.g_step
g_step
= 1;
void app.openMenu(int clickX, int clickY, long serial) nothrow @nogc

The right-click menu (popup1). Anchor: 1x1 rect at the click position, anchor point its bottom-right corner, gravity bottom_right ("down-right of the cursor"), constraint_adjustment slide|flip on both axes.

openMenu
(180, 180, -1); // no seat → no serial → no grab
} else if (
(__gshared global) int app.g_step
g_step
== 1 && t > 1_300_000 && g_surfs[IDX_POPUP1].
(field) _error_ (__error)[IDX_POPUP1].popup
popup
!is null)
{
(__gshared global) int app.g_step
g_step
= 2;
void app.openSubmenu(long serial) nothrow @nogc

The submenu (popup2), parented on POPUP1 — the chain the protocol requires for a second grabbing popup. Anchored to item 2's rect, opening to the right; flip_x so a constrained edge would mirror it to the left.

openSubmenu
(-1);
} else if (
(__gshared global) int app.g_step
g_step
== 2 && t > 2_000_000)
{
(__gshared global) int app.g_step
g_step
= 3;
void app.dismissPopups(const(char)* cause) nothrow @nogc

Client-side dismissal (item click / Esc): topmost first, per the chain rule ("they must be destroyed in the reverse order they were created in").

dismissPopups
("client-teardown");
} break; case
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.stale = 3
stale
:
if (
(__gshared global) int app.g_step
g_step
== 0 && t > 300_000)
{
(__gshared global) int app.g_step
g_step
= 1;
// The probe: a grab serial that never came from any input event.
void app.openMenu(int clickX, int clickY, long serial) nothrow @nogc

The right-click menu (popup1). Anchor: 1x1 rect at the click position, anchor point its bottom-right corner, gravity bottom_right ("down-right of the cursor"), constraint_adjustment slide|flip on both axes.

openMenu
(180, 180, 1);
} else if (
(__gshared global) int app.g_step
g_step
== 1 && t > 1_800_000)
{
(__gshared global) int app.g_step
g_step
= 2;
instrEvent("stale_grab_result",
undefined identifier `instrEvent`, did you mean import `instrument`?
"configure_received=%d popup_done_received=%d connection_alive=%d", g_staleConfigured ? 1 : 0, g_staleDone ? 1 : 0, wl_display_get_error(g_display) == 0 ? 1 : 0);
(__gshared global) bool app.g_running
g_running
= false;
} break; } } // --------------------------------------------------------------------- main int
int D main(string[] args)
main
(
(alias) object.string = string
string
[]
(parameter) string[] args
args
)
{ if (
(parameter) string[] args
args
.
(field) ulong string[].length
length
>= 2 &&
(parameter) string[] args
args
[1].
(field) ulong string.length
length
>= 4 &&
(parameter) string[] args
args
[1][0 .. 4] == "inje")
{ import inject : injectMain;
unable to read module `inject` Expected 'inject.d' or 'inject/package.d' in one of the following import paths:
return injectMain(args.
args.length
length
>= 3 ? args[2] : "menu");
undefined identifier `injectMain`
} instrInit("f15_wayland");
undefined identifier `instrInit`
const
(local variable) const(char*) scen
scen
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_SCENARIO");
if (
(local variable) const(char*) scen
scen
!is null)
foreach (
(parameter) ulong i
i
,
(parameter) immutable(char*) n
n
;
(immutable global) immutable(char*[4]) app.g_scenarioNames
g_scenarioNames
)
if (
int core.stdc.string.strcmp(scope const(char*) s1, scope const(char*) s2) pure nothrow @nogc
strcmp
(
(local variable) const(char*) scen
scen
,
(local variable) immutable(char*) n
n
) == 0)
(__gshared global) app.Scenario app.g_scenario
g_scenario
= cast(
(enum) app.Scenario
Scenario
)
(local variable) ulong i
i
;
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';
const
(local variable) const(char*) runMs
runMs
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_RUN_MS");
if (
(local variable) const(char*) runMs
runMs
!is null)
(__gshared global) long app.g_runUsCap
g_runUsCap
=
int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
(
(local variable) const(char*) runMs
runMs
) * 1000L;
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; } g_xkbCtx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 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); // globals
undefined identifier `wl_display_roundtrip`
wl_display_roundtrip(g_display); // seat capabilities
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\n");
wl_display_disconnect(g_display);
undefined identifier `wl_display_disconnect`
return 0; } instrEvent("globals", "xdg_wm_base_version=%u seat=%d scenario=%s",
undefined identifier `instrEvent`, did you mean import `instrument`?
g_wmBaseVersion, g_seat !is null ? 1 : 0, g_scenarioNames[g_scenario]); if (g_seat is null &&
(__gshared global) app.Scenario app.g_scenario
g_scenario
!=
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.noinput = 0
noinput
)
{ // grab/stale need a wl_seat object; headless weston has none.
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: scenario %s needs a wl_seat; falling back to noinput\n",
(immutable global) immutable(char*[4]) app.g_scenarioNames
g_scenarioNames
[
(__gshared global) app.Scenario app.g_scenario
g_scenario
]);
(__gshared global) app.Scenario app.g_scenario
g_scenario
=
(enum) app.Scenario
Scenario
.
(enum value) app.Scenario.noinput = 0
noinput
;
} wsi_wm_base_add_listener(g_wmBase, &g_wmBaseListener, null);
undefined identifier `wsi_wm_base_add_listener`
(struct) app.Surf

One wl_surface with either the toplevel or a popup role.

Surf
*
(local variable) _error_ m
m
= &g_surfs[IDX_MAIN];
m.
m.width
width
= mainWidth;
m.
m.height
height
= mainHeight;
m.
m.surface
surface
= wsi_compositor_create_surface(g_compositor);
m.
m.xdgSurface
xdgSurface
= wsi_wm_base_get_xdg_surface(g_wmBase, m.
m.surface
surface
);
wsi_xdg_surface_add_listener(m.
m.xdgSurface
xdgSurface
, &g_xdgSurfaceListener, cast(void*) IDX_MAIN);
undefined identifier `wsi_xdg_surface_add_listener`
m.
m.toplevel
toplevel
= wsi_xdg_surface_get_toplevel(m.
m.xdgSurface
xdgSurface
);
wsi_toplevel_add_listener(m.
m.toplevel
toplevel
, &g_toplevelListener, null);
undefined identifier `wsi_toplevel_add_listener`
const
(local variable) const(char*) appIdEnv
appIdEnv
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_APP_ID");
const
(local variable) const(char*) appId
appId
=
(local variable) const(char*) appIdEnv
appIdEnv
!is null ?
(local variable) const(char*) appIdEnv
appIdEnv
: "wsi-f15-popup".
(constant) immutable(char)* "wsi-f15-popup".ptr = "wsi-f15-popup"
ptr
;
wsi_toplevel_set_title(m.
m.toplevel
toplevel
, appId);
undefined identifier `wsi_toplevel_set_title`
wsi_toplevel_set_app_id(m.
m.toplevel
toplevel
, appId);
undefined identifier `wsi_toplevel_set_app_id`
instrWindowCreated();
undefined identifier `instrWindowCreated`
wsi_surface_commit(m.
m.surface
surface
); // mandatory no-buffer first commit
undefined identifier `wsi_surface_commit`
immutable
(local variable) immutable(_error_) dispFd
dispFd
= wl_display_get_fd(g_display);
undefined identifier `wl_display_get_fd`
bool
(local variable) bool displayDead
displayDead
= false;
while (
(__gshared global) bool app.g_running
g_running
)
{ while (wl_display_prepare_read(g_display) != 0)
undefined identifier `wl_display_prepare_read`
wl_display_dispatch_pending(g_display);
undefined identifier `wl_display_dispatch_pending`
wl_display_flush(g_display);
undefined identifier `wl_display_flush`
pollfd
(local variable) _error_ pfd
pfd
= {dispFd, POLLIN, 0};
undefined identifier `pollfd`
if (poll(&pfd, 1, 50) > 0)
undefined identifier `poll`
wl_display_read_events(g_display);
undefined identifier `wl_display_read_events`
else wl_display_cancel_read(g_display);
undefined identifier `wl_display_cancel_read`
if (wl_display_dispatch_pending(g_display) == -1)
undefined identifier `wl_display_dispatch_pending`
{ // A protocol error (the stale-grab probe's possible outcome) // kills the connection — capture WHICH error before exiting. wl_interface*
(local variable) _error_ errIface
errIface
;
undefined identifier `wl_interface`
uint
(local variable) uint errId
errId
;
immutable
(local variable) immutable(_error_) code
code
= wl_display_get_protocol_error(g_display, &errIface, &errId);
undefined identifier `wl_display_get_protocol_error`
instrEvent("display_error", "errno=%d protocol_code=%u interface=%s id=%u",
undefined identifier `instrEvent`, did you mean import `instrument`?
wl_display_get_error(g_display), code, errIface !is null ? errIface.name : "?", errId);
(local variable) bool displayDead
displayDead
= true;
break; }
void app.tick() nothrow @nogc

Time-driven steps for the input-less scenarios (noinput, stale) and the deferred reposition probe of menu/noinput.

tick
();
if (
(__gshared global) bool app.g_autoExit
g_autoExit
&& instrNowUs() >
(__gshared global) long app.g_runUsCap
g_runUsCap
)
undefined identifier `instrNowUs`
(__gshared global) bool app.g_running
g_running
= false;
} instrEvent("summary",
undefined identifier `instrEvent`, did you mean import `instrument`?
"scenario=%s grab_used=%d popup_done_events=%d frames=%d display_dead=%d", g_scenarioNames[g_scenario], g_grabUsed ? 1 : 0, g_doneEvents, g_frames, displayDead ? 1 : 0); if (!
(local variable) bool displayDead
displayDead
)
{
void app.dismissPopups(const(char)* cause) nothrow @nogc

Client-side dismissal (item click / Esc): topmost first, per the chain rule ("they must be destroyed in the reverse order they were created in").

dismissPopups
("client-teardown");
foreach (ref
(parameter) b
b
; g_surfs[IDX_MAIN].
(field) _error_ (__error)[IDX_MAIN].buffers
buffers
)
if (b.
b.handle
handle
!is null)
{ wsi_buffer_destroy(b.
b.handle
handle
);
munmap(b.
b.pixels
pixels
, b.
b.byteSize
byteSize
);
} if (g_frameCb !is null) wsi_callback_destroy(g_frameCb);
undefined identifier `wsi_callback_destroy`
if (g_keyboard !is null) wsi_keyboard_destroy(g_keyboard);
undefined identifier `wsi_keyboard_destroy`
if (g_pointer !is null) wsi_pointer_destroy(g_pointer);
undefined identifier `wsi_pointer_destroy`
if (g_seat !is null) wsi_seat_destroy(g_seat);
undefined identifier `wsi_seat_destroy`
wsi_toplevel_destroy(g_surfs[IDX_MAIN].
g_surfs[IDX_MAIN].toplevel
toplevel
);
undefined identifier `wsi_toplevel_destroy`
wsi_xdg_surface_destroy(g_surfs[IDX_MAIN].
g_surfs[IDX_MAIN].xdgSurface
xdgSurface
);
undefined identifier `wsi_xdg_surface_destroy`
wsi_surface_destroy(g_surfs[IDX_MAIN].
g_surfs[IDX_MAIN].surface
surface
);
undefined identifier `wsi_surface_destroy`
wsi_wm_base_destroy(g_wmBase);
undefined identifier `wsi_wm_base_destroy`
wl_proxy_destroy(cast(wl_proxy*) g_shm);
undefined identifier `wl_proxy_destroy`
wl_proxy_destroy(cast(wl_proxy*) g_compositor);
undefined identifier `wl_proxy_destroy`
wl_proxy_destroy(cast(wl_proxy*) g_registry);
undefined identifier `wl_proxy_destroy`
} 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`
wl_display_disconnect(g_display);
undefined identifier `wl_display_disconnect`
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("ok: scenario=%s popup_done_events=%d display_dead=%d\n",
(immutable global) immutable(char*[4]) app.g_scenarioNames
g_scenarioNames
[
(__gshared global) app.Scenario app.g_scenario
g_scenario
],
(__gshared global) int app.g_doneEvents
g_doneEvents
,
(local variable) bool displayDead
displayDead
? 1 : 0);
return 0; }