// F13 — CSD & decoration modes (see ../../f13-decorations.md and
// ../../../features/f13-decorations.md). One binary, three behaviours:
//
// Mode A (default) bind zxdg_decoration_manager_v1 when offered, request
// server-side, log the compositor's configure mode=…
// answer, honor runtime mode switches (the auto storm
// flips set_mode(client_side) → unset_mode mid-run).
// Mode B (CSD) WSI_FORCE_CSD=1, or whenever SSD is denied or the
// protocol is absent (the source= is logged): draw a
// minimal title bar (solid rect + block-glyph title +
// close box) and a fake-shadow margin ring whose outer
// band is 8 resize zones. Pointer-down on the bar →
// xdg_toplevel.move(seat, serial); on a band zone →
// xdg_toplevel.resize(seat, serial, edge); on the close
// box → client shutdown. xdg_surface.set_window_geometry
// excludes the margin; every commit logs buffer size vs
// geometry so the contract is visible in the trace.
// WSI_NO_GEOMETRY=1 keep the margin but never call set_window_geometry —
// the auto storm's set_maximized then commits a buffer
// larger than the configured size, and the compositor's
// reaction (weston: fatal invalid_surface_state) is the
// "what breaks without it" deliverable.
//
// The libdecor comparison variant lives in ./libdecor-variant/. Headless-safe:
// no compositor → SKIP, exit 0; no seat (headless weston) → the pointer paths
// are unarmed and only the negotiation + geometry story runs.
module (module) appapp;
import c; // ImportC: wayland-client + xdg-shell + xdg-decoration glue (wsi_*)
import instrument;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdioD header file for C99 <stdio.h>
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h
Source
core/stdc/stdio.d
stdio : (alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdlibD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h
Source
core/stdc/stdlib.d
stdlib : (alias) app.getenv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogcgetenv, (alias) app.atoi = int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogcatoi;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stringD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/string.h.html, string.h
Source
core/stdc/string.d
string : (alias) app.strcmp = int core.stdc.string.strcmp(scope const(char*) s1, scope const(char*) s2) pure nothrow @nogcstrcmp;
// ----------------------------------------------------------------- tunables
enum int (constant) int app.defaultWidth = 640defaultWidth = 640; // window *geometry* size (content + title bar)
enum int (constant) int app.defaultHeight = 480defaultHeight = 480;
enum int (constant) int app.margin = 12margin = 12; // fake-shadow ring around the geometry (CSD only)
enum int (constant) int app.bandExtra = 4bandExtra = 4; // resize band reaches this far inside the geometry
enum int (constant) int app.titleH = 28titleH = 28; // title-bar height, inside the geometry
enum int (constant) int app.maximizeAtFrame = 30maximizeAtFrame = 30, (constant) int app.unmaximizeAtFrame = 55unmaximizeAtFrame = 55;
enum int (constant) int app.csdModeAtFrame = 80csdModeAtFrame = 80, (constant) int app.unsetModeAtFrame = 105unsetModeAtFrame = 105; // decoration mode storm
enum uint (constant) uint app.BTN_LEFT = 272uBTN_LEFT = 0x110;
// -------------------------------------------------------------------- state
struct (struct) app.BufferBuffer
{
wl_buffer* (field) _error_ app.Buffer.handlehandle;
uint* (field) uint* app.Buffer.pixelspixels;
(alias) object.size_t = ulongsize_t (field) ulong app.Buffer.byteSizebyteSize;
int (field) int app.Buffer.widthwidth, (field) int app.Buffer.heightheight;
bool (field) bool app.Buffer.busybusy;
}
__gshared
{
wl_display* _error_ app.g_displayg_display;
wl_registry* _error_ app.g_registryg_registry;
wl_compositor* _error_ app.g_compositorg_compositor;
wl_shm* _error_ app.g_shmg_shm;
wl_seat* _error_ app.g_seatg_seat;
wl_pointer* _error_ app.g_pointerg_pointer;
xdg_wm_base* _error_ app.g_wmBaseg_wmBase;
wl_surface* _error_ app.g_surfaceg_surface;
xdg_surface* _error_ app.g_xdgSurfaceg_xdgSurface;
xdg_toplevel* _error_ app.g_toplevelg_toplevel;
zxdg_decoration_manager_v1* _error_ app.g_decoMgrg_decoMgr;
zxdg_toplevel_decoration_v1* _error_ app.g_decog_deco;
wl_callback* _error_ app.g_frameCbg_frameCb;
(struct) app.BufferBuffer[2] _error_ app.g_buffersg_buffers;
int (__gshared global) int app.g_geoWg_geoW = defaultWidth, (__gshared global) int app.g_geoHg_geoH = defaultHeight; // acked geometry size
int (__gshared global) int app.g_pendingWidthg_pendingWidth, (__gshared global) int app.g_pendingHeightg_pendingHeight;
bool (__gshared global) bool app.g_maximizedg_maximized, (__gshared global) bool app.g_fullscreeng_fullscreen, (__gshared global) bool app.g_activatedg_activated;
uint (__gshared global) uint app.g_decoModeg_decoMode; // 0 = no answer yet / protocol absent
bool (__gshared global) bool app.g_forceCsdg_forceCsd, (__gshared global) bool app.g_noGeometryg_noGeometry, (__gshared global) bool app.g_noStormg_noStorm;
bool (__gshared global) bool app.g_configuredg_configured, (__gshared global) bool app.g_runningg_running = true, (__gshared global) bool app.g_autoExitg_autoExit;
long (__gshared global) long app.g_runUsCapg_runUsCap = 2_500_000;
int (__gshared global) int app.g_framesg_frames, (__gshared global) int app.g_commitsg_commits;
int (__gshared global) int app.g_lastLoggedBwg_lastLoggedBw, (__gshared global) int app.g_lastLoggedBhg_lastLoggedBh; // commit-log dedup
int (__gshared global) int app.g_ptrXg_ptrX, (__gshared global) int app.g_ptrYg_ptrY; // surface-local pointer position
int (__gshared global) int app.g_zoneg_zone = -99; // last logged csd_hit zone
}
// ------------------------------------------------------------ CSD geometry
bool bool app.csdActive() nothrow @nogccsdActive() nothrow @nogc
{
return (__gshared global) bool app.g_forceCsdg_forceCsd || (__gshared global) uint app.g_decoModeg_decoMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
}
/// Fake-shadow margin currently in effect. Real CSD drops its shadow when
/// maximized/fullscreen (the geometry must exactly match the configured size
/// anyway); the WSI_NO_GEOMETRY probe keeps it to arm the violation.
int int app.marginNow() nothrow @nogcFake-shadow margin currently in effect. Real CSD drops its shadow when
maximized/fullscreen (the geometry must exactly match the configured size
anyway); the WSI_NO_GEOMETRY probe keeps it to arm the violation.
marginNow() nothrow @nogc
{
if (!bool app.csdActive() nothrow @nogccsdActive())
return 0;
if ((__gshared global) bool app.g_noGeometryg_noGeometry)
return (constant) int app.margin = 12margin;
return ((__gshared global) bool app.g_maximizedg_maximized || (__gshared global) bool app.g_fullscreeng_fullscreen) ? 0 : (constant) int app.margin = 12margin;
}
bool bool app.titleBarNow() nothrow @nogctitleBarNow() nothrow @nogc
{
return bool app.csdActive() nothrow @nogccsdActive() && !(__gshared global) bool app.g_fullscreeng_fullscreen;
}
// Zone codes: 1..10 = xdg_toplevel resize_edge enum, 100 = title bar,
// 101 = close box, 0 = content.
int int app.zoneAt(int x, int y, int bw, int bh) nothrow @nogczoneAt(int (parameter) int xx, int (parameter) int yy, int (parameter) int bwbw, int (parameter) int bhbh) nothrow @nogc
{
immutable (local variable) immutable(int) mm = int app.marginNow() nothrow @nogcFake-shadow margin currently in effect. Real CSD drops its shadow when
maximized/fullscreen (the geometry must exactly match the configured size
anyway); the WSI_NO_GEOMETRY probe keeps it to arm the violation.
marginNow();
if ((local variable) immutable(int) mm > 0)
{
immutable (local variable) immutable(int) bandband = (local variable) immutable(int) mm + (constant) int app.bandExtra = 4bandExtra;
uint (local variable) uint ee = 0;
if ((parameter) int yy < (local variable) immutable(int) bandband)
(local variable) uint ee |= XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else if ((parameter) int yy >= (parameter) int bhbh - (local variable) immutable(int) bandband)
(local variable) uint ee |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
if ((parameter) int xx < (local variable) immutable(int) bandband)
(local variable) uint ee |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
else if ((parameter) int xx >= (parameter) int bwbw - (local variable) immutable(int) bandband)
(local variable) uint ee |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
if ((local variable) uint ee != 0)
return cast(int) (local variable) uint ee;
}
if (bool app.titleBarNow() nothrow @nogctitleBarNow() && (parameter) int yy >= (local variable) immutable(int) mm && (parameter) int yy < (local variable) immutable(int) mm + (constant) int app.titleH = 28titleH && (parameter) int xx >= (local variable) immutable(int) mm && (parameter) int xx < (parameter) int bwbw - (local variable) immutable(int) mm)
return (parameter) int xx >= (parameter) int bwbw - (local variable) immutable(int) mm - (constant) int app.titleH = 28titleH ? 101 : 100;
return 0;
}
const(char)* const(char)* app.zoneName(int z) nothrow @nogczoneName(int (parameter) int zz) nothrow @nogc
{
switch ((parameter) int zz)
{
case 100: return "title";
case 101: return "close";
case XDG_TOPLEVEL_RESIZE_EDGE_TOP: return "top";
case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: return "bottom";
case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: return "left";
case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: return "right";
case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: return "top_left";
case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: return "top_right";
case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: return "bottom_left";
case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: return "bottom_right";
default: return "content";
}
}
// ----------------------------------------------------------------- painting
// 3×5 block glyphs for the title "WSI-F13 CSD"; each row is 3 bits, msb left.
struct (struct) app.GlyphGlyph
{
char (field) char app.Glyph.cc;
ubyte[5] (field) ubyte[5] app.Glyph.rowsrows;
}
__gshared immutable (struct) app.GlyphGlyph[10] (immutable global) immutable(app.Glyph[10]) app.g_fontg_font = [
{'W', [0b101, 0b101, 0b101, 0b111, 0b101]},
{'S', [0b111, 0b100, 0b111, 0b001, 0b111]},
{'I', [0b111, 0b010, 0b010, 0b010, 0b111]},
{'-', [0b000, 0b000, 0b111, 0b000, 0b000]},
{'F', [0b111, 0b100, 0b110, 0b100, 0b100]},
{'1', [0b010, 0b110, 0b010, 0b010, 0b111]},
{'3', [0b111, 0b001, 0b011, 0b001, 0b111]},
{'C', [0b111, 0b100, 0b100, 0b100, 0b111]},
{'D', [0b110, 0b101, 0b101, 0b101, 0b110]},
{' ', [0b000, 0b000, 0b000, 0b000, 0b000]},
];
void app.fillRectfillRect(ref (struct) app.BufferBuffer (parameter) Buffer bb, int (parameter) int x0x0, int (parameter) int y0y0, int (parameter) int ww, int (parameter) int hh, uint argb) nothrow @nogc
{
foreach ((parameter) yy; y0 .. y0 + h)
{
if (y < 0 || y >= b.b.heightheight)
continue;
uint* _error_ rowrow = b.b.pixelspixels + cast((unresolved type) size_tsize_t) y * b.b.widthwidth;
foreach ((parameter) xx; x0 .. x0 + w)
if (x >= 0 && x < b.b.widthwidth)
row[x] = argb;
}
}
void app.drawTitledrawTitle(ref (struct) app.BufferBuffer (parameter) Buffer bb, int (parameter) int xx, int (parameter) int yy) nothrow @nogc
{
enum (constant) scale = 3scale = 3;
static immutable (unresolved type) stringstring string texttext = "WSI-F13 CSD";
foreach ((parameter) chch; text)
{
foreach (ref (parameter) gg; g_font)
if (g.g.cc == ch)
{
foreach ((parameter) ryry; 0 .. 5)
foreach ((parameter) rxrx; 0 .. 3)
if (g.g.rowsrows[ry] & (0b100 >> rx))
fillRect(b, x + rx * scale, y + ry * scale, scale, scale, 0xffe5_e9f0);
break;
}
x += 4 * scale;
}
}
/// Paint the whole buffer: margin ring (fake shadow), title bar + glyphs +
/// close box, content gradient — or just the gradient when SSD is active.
void app.paintPaint the whole buffer: margin ring (fake shadow), title bar + glyphs +
close box, content gradient — or just the gradient when SSD is active.
paint(ref (struct) app.BufferBuffer (parameter) Buffer bb) nothrow @nogc
{
immutable _error_ mm = marginNow();
immutable _error_ tbtb = titleBarNow() ? titleH : 0;
if (m > 0) // semi-transparent "shadow" — ARGB8888 has real alpha
fillRect(b, 0, 0, b.b.widthwidth, b.b.heightheight, 0x4010_1010);
if (tb > 0)
{
fillRect(b, m, m, b.b.widthwidth - 2 * m, tb, 0xff2e_3440);
drawTitle(b, m + 10, m + 6);
// close box: rightmost titleH×titleH square of the bar, with an X
immutable _error_ cxcx = b.b.widthwidth - m - titleH;
fillRect(b, cx, m, titleH, titleH, 0xff8b_2e2e);
foreach ((parameter) ii; 6 .. titleH - 6)
{
fillRect(b, cx + i, m + i, 2, 2, 0xffff_ffff);
fillRect(b, cx + titleH - i - 2, m + i, 2, 2, 0xffff_ffff);
}
}
// content gradient (scaffold pattern), below the title bar
immutable _error_ x0x0 = m, _error_ y0y0 = m + tb, _error_ cwcw = b.b.widthwidth - 2 * m, _error_ chhchh = b.b.heightheight - 2 * m - tb;
foreach ((parameter) yy; 0 .. chh)
{
uint* _error_ rowrow = b.b.pixelspixels + cast((unresolved type) size_tsize_t)(y0 + y) * b.b.widthwidth + x0;
immutable uint _error_ gg = cast(uint)(y * 255 / (chh > 1 ? chh - 1 : 1)) << 8;
foreach ((parameter) xx; 0 .. cw)
row[x] = 0xff00_0000 | (cast(uint)(x * 255 / (cw > 1 ? cw - 1 : 1)) << 16) | g;
}
}
// ---------------------------------------------------------- shm buffer pool
bool app.ensureBufferensureBuffer(ref (struct) app.BufferBuffer (parameter) Buffer bb, int (parameter) int ww, int (parameter) int hh) nothrow @nogc
{
if (b.b.handlehandle !is null && (b.b.widthwidth != w || b.b.heightheight != h))
{
wsi_buffer_destroy(b.b.handlehandle);
munmap(b.b.pixelspixels, b.b.byteSizebyteSize);
b = Buffer.init;
}
if (b.b.handlehandle !is null)
return true;
immutable _error_ stridestride = w * 4;
immutable _error_ sizesize = cast((unresolved type) size_tsize_t) stride * h;
immutable _error_ fdfd = memfd_create("wsi-f13", MFD_CLOEXEC);
if (fd < 0 || ftruncate(fd, cast(long) size) != 0)
return false;
void* _error_ memmem = 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_ poolpool = wsi_shm_create_pool(g_shm, fd, cast(int) size);
b.b.handlehandle = 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.handlehandle, &g_bufferListener, &b);
b.b.pixelspixels = cast(uint*) mem;
b.b.byteSizebyteSize = size;
b.b.widthwidth = w;
b.b.heightheight = h;
return true;
}
/// Paint + commit. Buffer = geometry + 2×margin; set_window_geometry tells the
/// compositor which part of it is "the window" — unless WSI_NO_GEOMETRY=1.
void void app.render() nothrow @nogcPaint + commit. Buffer = geometry + 2×margin; set_window_geometry tells the
compositor which part of it is "the window" — unless WSI_NO_GEOMETRY=1.
render() nothrow @nogc
{
(struct) app.BufferBuffer* (local variable) _error_ bufbuf = null;
foreach (ref (parameter) bb; g_buffers)
if (!b.b.busybusy)
{
buf = &b;
break;
}
if (buf is null)
return; // both held; wl_buffer.release re-renders
immutable (local variable) immutable(int) mm = int app.marginNow() nothrow @nogcFake-shadow margin currently in effect. Real CSD drops its shadow when
maximized/fullscreen (the geometry must exactly match the configured size
anyway); the WSI_NO_GEOMETRY probe keeps it to arm the violation.
marginNow();
immutable (local variable) immutable(int) bwbw = (__gshared global) int app.g_geoWg_geoW + 2 * (local variable) immutable(int) mm, (local variable) immutable(int) bhbh = (__gshared global) int app.g_geoHg_geoH + 2 * (local variable) immutable(int) mm;
if (!ensureBuffer(*buf, bw, bh))
{
(__gshared global) bool app.g_runningg_running = false;
return;
}
paint(*buf);
if (bool app.csdActive() nothrow @nogccsdActive() && !(__gshared global) bool app.g_noGeometryg_noGeometry)
wsi_xdg_surface_set_window_geometry(g_xdgSurface, m, m, g_geoW, g_geoH);
if ((local variable) immutable(int) bwbw != (__gshared global) int app.g_lastLoggedBwg_lastLoggedBw || (local variable) immutable(int) bhbh != (__gshared global) int app.g_lastLoggedBhg_lastLoggedBh)
{
instrEvent("commit", "buffer=%dx%d geometry=%dx%d@%d,%d geometry_set=%d csd=%d",
bw, bh, g_geoW, g_geoH, m, m,
(csdActive() && !g_noGeometry) ? 1 : 0, csdActive() ? 1 : 0);
(__gshared global) int app.g_lastLoggedBwg_lastLoggedBw = (local variable) immutable(int) bwbw;
(__gshared global) int app.g_lastLoggedBhg_lastLoggedBh = (local variable) immutable(int) bhbh;
}
wsi_surface_attach(g_surface, buf.buf.handlehandle, 0, 0);
wsi_surface_damage_buffer(g_surface, 0, 0, bw, bh);
if (g_frameCb is null)
{
g_frameCb = wsi_surface_frame(g_surface);
wsi_callback_add_listener(g_frameCb, &g_frameListener, null);
}
wsi_surface_commit(g_surface);
buf.buf.busybusy = true;
(__gshared global) int app.g_commitsg_commits++;
if ((__gshared global) int app.g_commitsg_commits == 1)
instrEvent("first_commit", "buffer=%dx%d", bw, bh);
}
// ---------------------------------------------------------------- listeners
extern (C) void app.onGlobalonGlobal(void* data, wl_registry* reg, uint name,
const(char)* (parameter) const(char)* ifaceiface, uint ver) nothrow @nogc
{
static uint uint capped(uint a, uint w) nothrow @nogccapped(uint (parameter) uint aa, uint (parameter) uint ww) nothrow @nogc
{
return a < w ? a : w;
}
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 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);
}
else if (strcmp(iface, zxdg_decoration_manager_v1_interface.name) == 0)
g_decoMgr = cast(zxdg_decoration_manager_v1*) wsi_registry_bind(reg, name,
&zxdg_decoration_manager_v1_interface, 1);
else
return;
instrEvent("step", "name=wl_registry_bind iface=%s version=%u", iface, ver);
}
extern (C) void app.onGlobalRemoveonGlobalRemove(void* data, wl_registry* reg, uint name) nothrow @nogc
{
}
extern (C) void app.onWmBasePingonWmBasePing(void* data, xdg_wm_base* (parameter) xdg_wm_base* bb, uint serial) nothrow @nogc
{
wsi_wm_base_pong(b, serial);
}
/// zxdg_toplevel_decoration_v1.configure: the compositor's decoration answer.
/// "The specified mode must be obeyed by the client."
extern (C) void app.onDecorationConfigurezxdg_toplevel_decoration_v1.configure: the compositor's decoration answer.
"The specified mode must be obeyed by the client."
onDecorationConfigure(void* data, zxdg_toplevel_decoration_v1* d,
uint mode) nothrow @nogc
{
immutable _error_ prevprev = g_decoMode;
g_decoMode = mode;
instrEvent("decoration", "mode=%s source=protocol raw=%u",
mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE ? "ssd"."ssd".ptrptr : "csd"."csd".ptrptr, mode);
if (g_configured && prev != mode)
render(); // honor the runtime switch: redraw with/without the frame
}
extern (C) void app.onToplevelConfigureonToplevelConfigure(void* data, xdg_toplevel* t, int (parameter) int ww, int (parameter) int hh,
wl_array* states) nothrow @nogc
{
g_pendingWidth = w;
g_pendingHeight = h;
g_maximized = g_fullscreen = g_activated = false;
const _error_ startstart = cast(const(uint)*) states.data;
foreach ((parameter) ii; 0 .. states.states.sizesize / uint.sizeof)
{
if (start[i] == XDG_TOPLEVEL_STATE_MAXIMIZED)
g_maximized = true;
if (start[i] == XDG_TOPLEVEL_STATE_FULLSCREEN)
g_fullscreen = true;
if (start[i] == XDG_TOPLEVEL_STATE_ACTIVATED)
g_activated = true;
}
instrEvent("xdg_toplevel_configure", "size=%dx%d maximized=%d fullscreen=%d activated=%d",
w, h, g_maximized ? 1 : 0, g_fullscreen ? 1 : 0, g_activated ? 1 : 0);
}
extern (C) void app.onXdgSurfaceConfigureonXdgSurfaceConfigure(void* data, xdg_surface* s, uint serial) nothrow @nogc
{
// The configured size is the *window geometry* size — the buffer adds the
// margin back on top of it (the heart of the set_window_geometry contract).
immutable _error_ ww = g_pendingWidth > 0 ? g_pendingWidth : defaultWidth;
immutable _error_ hh = g_pendingHeight > 0 ? g_pendingHeight : defaultHeight;
instrEvent("configure", "serial=%u size=%dx%d", serial, w, h);
wsi_xdg_surface_ack_configure(s, serial);
immutable _error_ resizedresized = w != g_geoW || h != g_geoH;
g_geoW = w;
g_geoH = h;
if (!g_configured)
{
g_configured = true;
instrFirstConfigure();
render();
}
else if (resized)
render();
}
extern (C) void app.onToplevelCloseonToplevelClose(void* data, xdg_toplevel* t) nothrow @nogc
{
instrCloseRequested();
g_running = false;
}
extern (C) void app.onToplevelConfigureBoundsonToplevelConfigureBounds(void* data, xdg_toplevel* t, int (parameter) int ww, int (parameter) int hh) nothrow @nogc
{
}
extern (C) void app.onToplevelWmCapabilitiesonToplevelWmCapabilities(void* data, xdg_toplevel* t, wl_array* caps) nothrow @nogc
{
}
extern (C) void app.onBufferReleaseonBufferRelease(void* data, wl_buffer* (parameter) wl_buffer* bb) nothrow @nogc
{
(cast((unresolved type) BufferBuffer*) data).(cast(Buffer*)data).busybusy = false;
if (g_running && g_configured && g_frameCb is null)
render();
}
extern (C) void app.onFrameDoneonFrameDone(void* data, wl_callback* cb, uint timeMs) nothrow @nogc
{
wsi_callback_destroy(cb);
g_frameCb = null;
g_frames++;
if (g_frames == 1)
instrFirstPixelPresented();
if (g_autoExit)
{
if (!g_noStorm)
{
if (g_frames == maximizeAtFrame)
{
instrEvent("state_request", "kind=set_maximized");
wsi_toplevel_set_maximized(g_toplevel);
}
else if (g_frames == unmaximizeAtFrame)
{
instrEvent("state_request", "kind=unset_maximized");
wsi_toplevel_unset_maximized(g_toplevel);
}
else if (g_frames == csdModeAtFrame && g_deco !is null)
{
instrEvent("decoration_request", "mode=client_side");
wsi_decoration_set_mode(g_deco, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
}
else if (g_frames == unsetModeAtFrame && g_deco !is null)
{
instrEvent("decoration_request", "mode=unset");
wsi_decoration_unset_mode(g_deco);
}
}
if (instrNowUs() > g_runUsCap) // time-based: sway runs need the injection window
{
g_running = false;
return;
}
}
render();
}
// ------------------------------------------------------- pointer (CSD input)
extern (C) void app.onPointerEnteronPointerEnter(void* data, wl_pointer* p, uint serial,
wl_surface* surf, int sx, int sy) nothrow @nogc
{
g_ptrX = sx / 256;
g_ptrY = sy / 256;
instrEvent("pointer_enter", "serial=%u pos=%d,%d", serial, g_ptrX, g_ptrY);
}
extern (C) void app.onPointerLeaveonPointerLeave(void* data, wl_pointer* p, uint serial, wl_surface* surf) nothrow @nogc
{
g_zone = -99;
}
extern (C) void app.onPointerMotiononPointerMotion(void* data, wl_pointer* p, uint time, int sx, int sy) nothrow @nogc
{
g_ptrX = sx / 256;
g_ptrY = sy / 256;
immutable _error_ mm = marginNow();
immutable _error_ zz = zoneAt(g_ptrX, g_ptrY, g_geoW + 2 * m, g_geoH + 2 * m);
if (z != g_zone)
{
g_zone = z;
instrEvent("csd_hit", "zone=%s pos=%d,%d", zoneName(z), g_ptrX, g_ptrY);
}
}
extern (C) void app.onPointerButtononPointerButton(void* data, wl_pointer* p, uint serial, uint time,
uint button, uint state) nothrow @nogc
{
instrEvent("pointer_button", "serial=%u button=0x%x state=%u", serial, button, state);
if (button != BTN_LEFT || state != WL_POINTER_BUTTON_STATE_PRESSED || !csdActive())
return;
immutable _error_ mm = marginNow();
immutable _error_ zz = zoneAt(g_ptrX, g_ptrY, g_geoW + 2 * m, g_geoH + 2 * m);
if (z == 100)
{
instrEvent("move_start", "serial=%u", serial);
wsi_toplevel_move(g_toplevel, g_seat, serial);
}
else if (z >= 1 && z <= 10)
{
instrEvent("resize_start", "edge=%u name=%s serial=%u", cast(uint) z, zoneName(z), serial);
wsi_toplevel_resize(g_toplevel, g_seat, serial, cast(uint) z);
}
else if (z == 101)
{
// The close box sends *nothing* on the wire — CSD close is a pure
// client-side decision (F14 owns the vetoable-close choreography).
instrEvent("csd_close", "note=client shutdown, no protocol request");
g_running = false;
}
}
extern (C) void app.onPointerAxisonPointerAxis(void* data, wl_pointer* p, uint t, uint (parameter) uint aa, int (parameter) int vv) nothrow @nogc
{
}
extern (C) void app.onPointerFrameonPointerFrame(void* data, wl_pointer* p) nothrow @nogc
{
}
extern (C) void app.onPointerAxisSourceonPointerAxisSource(void* data, wl_pointer* p, uint s) nothrow @nogc
{
}
extern (C) void app.onPointerAxisStoponPointerAxisStop(void* data, wl_pointer* p, uint t, uint (parameter) uint aa) nothrow @nogc
{
}
extern (C) void app.onPointerAxisDiscreteonPointerAxisDiscrete(void* data, wl_pointer* p, uint (parameter) uint aa, int d) nothrow @nogc
{
}
extern (C) void app.onPointerAxisValue120onPointerAxisValue120(void* data, wl_pointer* p, uint (parameter) uint aa, int (parameter) int vv) nothrow @nogc
{
}
extern (C) void app.onPointerAxisRelDironPointerAxisRelDir(void* data, wl_pointer* p, uint (parameter) uint aa, uint dir) nothrow @nogc
{
}
extern (C) void app.onSeatCapabilitiesonSeatCapabilities(void* data, wl_seat* s, uint caps) nothrow @nogc
{
immutable _error_ hasPointerhasPointer = (caps & WL_SEAT_CAPABILITY_POINTER) != 0;
instrEvent("seat_capabilities", "caps=%u pointer=%d", caps, hasPointer ? 1 : 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); // capability flap (wlrctl unplug)
g_pointer = null;
}
}
extern (C) void app.onSeatNameonSeatName(void* data, wl_seat* s, const(char)* name) nothrow @nogc
{
}
__gshared wl_registry_listener _error_ app.g_registryListenerg_registryListener = {&onGlobal, &onGlobalRemove};
__gshared xdg_wm_base_listener _error_ app.g_wmBaseListenerg_wmBaseListener = {&onWmBasePing};
__gshared wl_seat_listener _error_ app.g_seatListenerg_seatListener = {&onSeatCapabilities, &onSeatName};
__gshared xdg_surface_listener _error_ app.g_xdgSurfaceListenerg_xdgSurfaceListener = {&onXdgSurfaceConfigure};
__gshared xdg_toplevel_listener _error_ app.g_toplevelListenerg_toplevelListener = {
&onToplevelConfigure, &onToplevelClose,
&onToplevelConfigureBounds, &onToplevelWmCapabilities
};
__gshared zxdg_toplevel_decoration_v1_listener _error_ app.g_decoListenerg_decoListener = {&onDecorationConfigure};
__gshared wl_buffer_listener _error_ app.g_bufferListenerg_bufferListener = {&onBufferRelease};
__gshared wl_callback_listener _error_ app.g_frameListenerg_frameListener = {&onFrameDone};
__gshared wl_pointer_listener _error_ app.g_pointerListenerg_pointerListener = {
&onPointerEnter, &onPointerLeave, &onPointerMotion, &onPointerButton,
&onPointerAxis, &onPointerFrame, &onPointerAxisSource, &onPointerAxisStop,
&onPointerAxisDiscrete, &onPointerAxisValue120, &onPointerAxisRelDir
};
// ----------------------------------------------------------------- teardown
void void app.teardown() nothrow @nogcteardown() nothrow @nogc
{
foreach (ref (parameter) bb; g_buffers)
if (b.b.handlehandle !is null)
{
wsi_buffer_destroy(b.b.handlehandle);
munmap(b.b.pixelspixels, b.b.byteSizebyteSize);
}
if (g_frameCb !is null)
wsi_callback_destroy(g_frameCb);
if (g_deco !is null) // spec: "must be destroyed before its xdg_toplevel"
wsi_decoration_destroy(g_deco);
if (g_pointer !is null)
wsi_pointer_destroy(g_pointer);
if (g_toplevel !is null)
wsi_toplevel_destroy(g_toplevel);
if (g_xdgSurface !is null)
wsi_xdg_surface_destroy(g_xdgSurface);
if (g_surface !is null)
wsi_surface_destroy(g_surface);
if (g_decoMgr !is null)
wsi_decoration_manager_destroy(g_decoMgr);
if (g_wmBase !is null)
wsi_wm_base_destroy(g_wmBase);
if (g_seat !is null)
wl_proxy_destroy(cast(wl_proxy*) g_seat);
if (g_shm !is null)
wl_proxy_destroy(cast(wl_proxy*) g_shm);
if (g_compositor !is null)
wl_proxy_destroy(cast(wl_proxy*) g_compositor);
if (g_registry !is null)
wl_proxy_destroy(cast(wl_proxy*) g_registry);
wl_display_disconnect(g_display);
}
// --------------------------------------------------------------------- main
int int D main(string[] args)main((alias) object.string = stringstring[] (parameter) string[] argsargs)
{
if ((parameter) string[] argsargs.(field) ulong string[].lengthlength >= 2 && (parameter) string[] argsargs[1] == "inject")
{
import inject : injectMain;
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) to = std.conv.to(T)The to template converts a value from one type _to another.
The source type is deduced and the target type must be specified, for example the
expression to!int(42.0) converts the number 42 from
double _to int. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., to!double(42) does not do
any checking because any int fits in a double.
Conversions from string _to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings _to signed types, the grammar recognized is:
$(PRE $(I Integer):
$(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
$(B +)
$(B -))
For conversion _to unsigned types, the grammar recognized is:
$(PRE $(I UnsignedInteger):
$(I DecimalDigit)
$(I DecimalDigit) $(I UnsignedInteger))
to;
return injectMain(args.args.lengthlength > 2 ? args[2].to!int : 500,
args.args.lengthlength > 3 ? args[3].to!int : 400);
}
instrInit("f13-deco");
bool bool app.main.env(const(char)* n) nothrow @nogc @systemenv(const(char)* (parameter) const(char)* nn)
{
const (local variable) const(char*) vv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogcgetenv((parameter) const(char)* nn);
return (local variable) const(char*) vv !is null && *(local variable) const(char*) vv == '1';
}
(__gshared global) bool app.g_autoExitg_autoExit = bool app.main.env(const(char)* n) nothrow @nogc @systemenv("WSI_AUTO_EXIT");
(__gshared global) bool app.g_forceCsdg_forceCsd = bool app.main.env(const(char)* n) nothrow @nogc @systemenv("WSI_FORCE_CSD");
(__gshared global) bool app.g_noGeometryg_noGeometry = bool app.main.env(const(char)* n) nothrow @nogc @systemenv("WSI_NO_GEOMETRY");
(__gshared global) bool app.g_noStormg_noStorm = bool app.main.env(const(char)* n) nothrow @nogc @systemenv("WSI_NO_STORM");
if (const (local variable) const(char*) msms = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogcgetenv("WSI_RUN_MS"))
(__gshared global) long app.g_runUsCapg_runUsCap = int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogcatoi((local variable) const(char*) msms) * 1000L;
g_display = wl_display_connect(null);
if (g_display is null)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("SKIP: no Wayland compositor (wl_display_connect returned null)\n");
return 0;
}
g_registry = wsi_display_get_registry(g_display);
wsi_registry_add_listener(g_registry, &g_registryListener, null);
wl_display_roundtrip(g_display);
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 @nogcprintf("SKIP: compositor lacks a required global\n");
void app.teardown() nothrow @nogcteardown();
return 0;
}
wsi_wm_base_add_listener(g_wmBase, &g_wmBaseListener, null);
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);
g_toplevel = wsi_xdg_surface_get_toplevel(g_xdgSurface);
wsi_toplevel_add_listener(g_toplevel, &g_toplevelListener, null);
wsi_toplevel_set_title(g_toplevel, "wsi-f13-decorations");
const (local variable) const(char*) appIdappId = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogcgetenv("WSI_APP_ID");
wsi_toplevel_set_app_id(g_toplevel, appId !is null ? appId : "wsi-f13-decorations");
// Decoration negotiation MUST precede any buffer attach ("creating an
// xdg_toplevel_decoration from an xdg_toplevel which has a buffer attached
// or committed is a client error").
if (g_decoMgr !is null)
{
g_deco = wsi_decoration_manager_get_toplevel_decoration(g_decoMgr, g_toplevel);
wsi_decoration_add_listener(g_deco, &g_decoListener, null);
immutable (local variable) immutable(_error_) wantwant = (__gshared global) bool app.g_forceCsdg_forceCsd
? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
: ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
wsi_decoration_set_mode(g_deco, want);
instrEvent("decoration_request", "mode=%s",
want == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
? "server_side"."server_side".ptrptr : "client_side"."client_side".ptrptr);
}
else
instrEvent("decoration", "mode=csd source=absent"); // no global at all
instrWindowCreated();
wsi_surface_commit(g_surface); // mandatory no-buffer commit
while ((__gshared global) bool app.g_runningg_running && wl_display_dispatch(g_display) != -1)
{
if ((__gshared global) bool app.g_autoExitg_autoExit && instrNowUs() > (__gshared global) long app.g_runUsCapg_runUsCap + 2_000_000)
(__gshared global) bool app.g_runningg_running = false;
}
// Error path: a fatal protocol error (the WSI_NO_GEOMETRY probe earns one)
// kills the connection; recover the (interface, code, id) triple.
immutable (local variable) immutable(_error_) errerr = wl_display_get_error(g_display);
if (err != 0)
{
wl_interface* (local variable) _error_ ifaceiface;
uint (local variable) uint idid;
immutable (local variable) immutable(_error_) codecode = wl_display_get_protocol_error(g_display, &iface, &id);
instrEvent("protocol_error", "errno=%d interface=%s code=%u object_id=%u",
err, iface !is null ? iface.name : "none"."none".ptrptr, code, id);
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("outcome: protocol error — interface=%s code=%u (connection killed)\n",
iface !is null ? iface.name : "none".ptr, code);
void app.teardown() nothrow @nogcteardown();
return 0; // the probe *expects* this; the evidence is the log
}
void app.teardown() nothrow @nogcteardown();
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("ok: %d frames, %d commits, final mode=%s geometry=%dx%d\n",
(__gshared global) int app.g_framesg_frames, (__gshared global) int app.g_commitsg_commits, bool app.csdActive() nothrow @nogccsdActive() ? "csd".(constant) immutable(char)* "csd".ptr = "csd"ptr : "ssd".(constant) immutable(char)* "ssd".ptr = "ssd"ptr, (__gshared global) int app.g_geoWg_geoW, (__gshared global) int app.g_geoHg_geoH);
return 0;
}