app.dhover×369 error×57all
// X11 F11 demo — scroll fidelity (the feature contract:
// ../../../features/f11-scroll.md; findings: ../../f11-scroll.md). Built on
// the scaffold (../scaffold/app.d), drawing reduced to a server-side ruler.
//
// X11 represents one physical scroll TWICE: legacy core buttons 4/5/6/7 and
// XI2 smooth-scroll valuators (XIScrollClass; deltas ride XI_Motion). This
// demo captures both streams for the same physical event, and measures the
// dedupe machinery between them:
//
//   * device query: XIQueryDevice dump of every XIScrollClass (number,
//     scroll_type, increment, flags) and XIValuatorClass — on Xvfb the
//     honest answer is `scroll_class … none=1` for every device
//   * two connections, one window: dpy (this client) selects XI2 button +
//     motion events; dpy2 (a *second* client) selects core ButtonPress —
//     core ButtonPressMask is one-client-exclusive per window, so splitting
//     clients is also the only way to capture both streams concurrently
//   * phase A `dual_client`:    core stream on dpy2, XI2 stream on dpy
//   * phase B `dual_selection`: dpy2 deselects; dpy selects BOTH core and
//     XI2 button events — measures which representation(s) one client gets
//   * phase C `core_only`:      dpy clears its XI2 selection — does core
//     delivery resume once no XI2 selection exists on the window?
//   * XIPointerEmulated: logged (`emulated=0|1`) on every XI2 button event —
//     are xdotool's `click 4/5` wheel events tagged as emulated?
//   * a scrollable ruler (1 detent = 20 px) + per-gesture totals
//     (`gesture_summary …`, gestures split on a 400 ms idle gap)
//   * built-in pass (no xdotool): XSendEvent-fabricated button 4/5 presses —
//     delivered with send_event=1 to core selectors only, never as XI2
//
// WSI_DRIVEN=1 stretches the phases to 4 s each so xdotool (see ./run.sh)
// can deliver real XTest wheel clicks. Headless-safe: no display, or no
// XInputExtension -> prints `SKIP:`, exit 0.
module 
(module) app
app
;
import
(module) c
c
; // ImportC: Xlib + Xutil + XInput2 + poll
C preprocess command `cpp` failed for file `/home/runner/work/sparkles/sparkles/docs/research/window-system-integration/os-apis/x11/examples/f11-scroll/c.c`, exit status 1
import
(module) instrument
instrument
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.config

D compatible types that correspond to various basic types in associated C and C++ compilers.

Source

core/stdc/config.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)
config
: c_long, c_ulong;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdio

D header file for C99 <stdio.h>

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

Source

core/stdc/stdio.d

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

D header file for C99.

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

Source

core/stdc/stdlib.d

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

D header file for C99.

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

Source

core/stdc/string.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
string
:
(alias) app.strlen = ulong core.stdc.string.strlen(scope const(char*) s) pure nothrow @nogc
strlen
;
// --------------------------------------------------------------------------- // Constants ImportC cannot export (all #defines), re-declared per the // scaffold gotcha: core masks/types and the whole of <X11/extensions/XI2.h>. enum : c_long {
(enum value) app.KeyPressMask = 1L
KeyPressMask
= 1L << 0,
(enum value) app.ButtonPressMask = 4L
ButtonPressMask
= 1L << 2,
(enum value) app.ButtonReleaseMask = 8L
ButtonReleaseMask
= 1L << 3,
(enum value) app.ExposureMask = 32768L
ExposureMask
= 1L << 15,
(enum value) app.StructureNotifyMask = 131072L
StructureNotifyMask
= 1L << 17,
} enum // core XEvent.type discriminators; GenericEvent carries all XI2 events {
(enum value) app.KeyPress = 2
KeyPress
= 2,
(enum value) app.ButtonPress = 4
ButtonPress
= 4,
(enum value) app.ButtonRelease = 5
ButtonRelease
= 5,
(enum value) app.Expose = 12
Expose
= 12,
(enum value) app.ClientMessage = 33
ClientMessage
= 33,
(enum value) app.GenericEvent = 35
GenericEvent
= 35,
} enum
(constant) int app.False = 0
False
= 0;
enum
(constant) int app.True = 1
True
= 1;
enum
(constant) int app.POLLIN = 1
POLLIN
= 0x001;
enum // XI2.h {
(enum value) app.XIAllDevices = 0
XIAllDevices
= 0,
(enum value) app.XIMasterPointer = 1
XIMasterPointer
= 1,
(enum value) app.XIMasterKeyboard = 2
XIMasterKeyboard
= 2,
(enum value) app.XISlavePointer = 3
XISlavePointer
= 3,
(enum value) app.XISlaveKeyboard = 4
XISlaveKeyboard
= 4,
(enum value) app.XIFloatingSlave = 5
XIFloatingSlave
= 5,
(enum value) app.XI_ButtonPress = 4
XI_ButtonPress
= 4,
(enum value) app.XI_ButtonRelease = 5
XI_ButtonRelease
= 5,
(enum value) app.XI_Motion = 6
XI_Motion
= 6,
(enum value) app.XIButtonClass = 1
XIButtonClass
= 1,
(enum value) app.XIValuatorClass = 2
XIValuatorClass
= 2,
(enum value) app.XIScrollClass = 3
XIScrollClass
= 3,
(enum value) app.XIScrollTypeVertical = 1
XIScrollTypeVertical
= 1,
(enum value) app.XIScrollTypeHorizontal = 2
XIScrollTypeHorizontal
= 2,
(enum value) app.XIScrollFlagNoEmulation = 1 << 0
XIScrollFlagNoEmulation
= 1 << 0,
(enum value) app.XIScrollFlagPreferred = 1 << 1
XIScrollFlagPreferred
= 1 << 1,
(enum value) app.XIPointerEmulated = 1 << 16
XIPointerEmulated
= 1 << 16, // event flag: emulated from another event
} immutable
(alias) object.string = string
string
[5]
(immutable global) immutable(string[5]) app.useName
useName
=
["MasterPointer", "MasterKeyboard", "SlavePointer", "SlaveKeyboard", "FloatingSlave"]; /// XISetMask is a macro; same bit math, D-side. void
void app.xiSetMask(scope ubyte[] mask, int event) nothrow @nogc

XISetMask is a macro; same bit math, D-side.

xiSetMask
(scope ubyte[]
(parameter) ubyte[] mask
mask
, int
(parameter) int event
event
) @nogc nothrow
{
(parameter) ubyte[] mask
mask
[
(parameter) int event
event
>> 3] |= cast(ubyte)(1 << (
(parameter) int event
event
& 7));
} /// One smooth-scroll axis discovered via XIQueryDevice: XI_Motion carries the /// axis as an *absolute accumulating* valuator; one detent = `increment`. struct
(struct) app.ScrollAxis

One smooth-scroll axis discovered via XIQueryDevice: XI_Motion carries the axis as an absolute accumulating valuator; one detent = increment.

ScrollAxis
{ int
(field) int app.ScrollAxis.deviceid
deviceid
,
(field) int app.ScrollAxis.number
number
,
(field) int app.ScrollAxis.scrollType
scrollType
;
double
(field) double app.ScrollAxis.increment
increment
;
double
(field) double app.ScrollAxis.last
last
; // last absolute valuator value seen (NaN until primed)
} int
int D main()
main
()
{
void instrument.initInstrument(const(char)* demoName) nothrow @nogc

Names the demo, starts the monotonic clock, and emits init_start. Call this first, before any platform API call.

initInstrument
("x11_f11");
const
(local variable) const(bool) autoExit
autoExit
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_AUTO_EXIT") !is null;
const
(local variable) const(bool) driven
driven
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_DRIVEN") !is null; // xdotool owns the input
const
(local variable) const(int) phaseUs
phaseUs
=
(local variable) const(bool) driven
driven
? 4_000_000 : 600_000;
Display*
(local variable) _error_ dpy
dpy
= XOpenDisplay(null); // client 1: the XI2 listener
undefined identifier `Display`
undefined identifier `XOpenDisplay`
if (dpy is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: no X11 display (XOpenDisplay returned null)\n");
return 0; } int
(local variable) int xiOpcode
xiOpcode
,
(local variable) int xiEventBase
xiEventBase
,
(local variable) int xiErrorBase
xiErrorBase
;
if (!XQueryExtension(dpy, "XInputExtension", &xiOpcode, &xiEventBase, &xiErrorBase))
undefined identifier `XQueryExtension`
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: no XInputExtension on this display\n");
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
return 0; } int
(local variable) int xiMajor
xiMajor
= 2,
(local variable) int xiMinor
xiMinor
= 3;
const
(local variable) const(_error_) xiStatus
xiStatus
= XIQueryVersion(dpy, &xiMajor, &xiMinor);
undefined identifier `XIQueryVersion`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=XIQueryVersion status=%d server=%d.%d", xiStatus,
(local variable) int xiMajor
xiMajor
,
(local variable) int xiMinor
xiMinor
);
if (xiStatus != 0 ||
(local variable) int xiMajor
xiMajor
< 2)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: server does not speak XI2 (got %d.%d)\n",
(local variable) int xiMajor
xiMajor
,
(local variable) int xiMinor
xiMinor
);
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
return 0; } const
(local variable) const(_error_) screen
screen
= XDefaultScreen(dpy);
undefined identifier `XDefaultScreen`
const
(local variable) const(_error_) root
root
= XRootWindow(dpy, screen);
undefined identifier `XRootWindow`
// -- Scroll capability dump: which devices have XIScrollClass? ------------ // (Per the XI 2.1 smooth-scrolling spec a wheel device exposes one scroll // class per axis; Xvfb's virtual pointers expose none — logged honestly.)
(struct) app.ScrollAxis

One smooth-scroll axis discovered via XIQueryDevice: XI_Motion carries the axis as an absolute accumulating valuator; one detent = increment.

ScrollAxis
[16]
(local variable) app.ScrollAxis[16] axes
axes
;
int
(local variable) int nAxes
nAxes
;
int
(local variable) int nDevs
nDevs
;
int
(local variable) int masterPtr
masterPtr
= 2; // conventional VCP id; replaced by the query below
XIDeviceInfo*
(local variable) _error_ devs
devs
= XIQueryDevice(dpy, XIAllDevices, &nDevs);
undefined identifier `XIDeviceInfo`
undefined identifier `XIQueryDevice`
foreach (
(local variable) int i
i
; 0 ..
(local variable) int nDevs
nDevs
)
{ const
(local variable) const(_error_) d
d
= devs +
(local variable) int i
i
;
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("device", "id=%d use=%s name=%s", d.
(field) _error_ d.deviceid
deviceid
,
(immutable global) immutable(string[5]) app.useName
useName
[d.use - 1].
(field) _error_ useName[d.use - 1].ptr
ptr
, d.name);
if (d.use ==
(enum value) app.XIMasterPointer = 1
XIMasterPointer
)
(local variable) int masterPtr
masterPtr
= d.
(field) _error_ d.deviceid
deviceid
;
int
(local variable) int found
found
;
foreach (
(parameter) k
k
; 0 .. d.num_classes)
{ const
_error_ any
any
= d.classes[k];
if (any.type == XIScrollClass) { const
_error_ sc
sc
= cast(const(XIScrollClassInfo)*) any;
emitf("scroll_class", "device=%d number=%d type=%s increment=%g " ~ "flags=0x%x no_emulation=%d preferred=%d", d.
d.deviceid
deviceid
, sc.
sc.number
number
,
sc.scroll_type == XIScrollTypeVertical ? "vertical".
"vertical".ptr
ptr
: "horizontal".
"horizontal".ptr
ptr
,
sc.
sc.increment
increment
, sc.flags,
cast(int)((sc.flags & XIScrollFlagNoEmulation) != 0), cast(int)((sc.flags & XIScrollFlagPreferred) != 0)); if (nAxes < axes.
axes.length
length
)
axes[nAxes++] = ScrollAxis(d.
d.deviceid
deviceid
, sc.
sc.number
number
,
sc.scroll_type, sc.
sc.increment
increment
, double.nan);
++found; } else if (any.type == XIValuatorClass) { const
_error_ vc
vc
= cast(const(XIValuatorClassInfo)*) any;
char*
_error_ label
label
= vc.
vc.label
label
? XGetAtomName(dpy, vc.
vc.label
label
) : null;
emitf("valuator_class", "device=%d number=%d label=%s min=%g max=%g mode=%d", d.
d.deviceid
deviceid
, vc.
vc.number
number
, label ? label : "-".
"-".ptr
ptr
, vc.min, vc.max, vc.mode);
if (label) XFree(label); } } if (!
(local variable) int found
found
)
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("scroll_class", "device=%d none=1", d.
(field) _error_ d.deviceid
deviceid
);
} XIFreeDeviceInfo(devs);
undefined identifier `XIFreeDeviceInfo`
// -- Window + the two-client selection split -------------------------------- const int
(local variable) const(int) width
width
= 480,
(local variable) const(int) height
height
= 320;
Window
(local variable) _error_ win
win
= XCreateSimpleWindow(dpy, root, 20, 20, width, height, 1,
undefined identifier `Window`
undefined identifier `XCreateSimpleWindow`
XBlackPixel(dpy, screen), XWhitePixel(dpy, screen)); XStoreName(dpy, win, "Sparkles · X11 F11 scroll");
undefined identifier `XStoreName`
Atom
(local variable) _error_ wmDelete
wmDelete
= XInternAtom(dpy, "WM_DELETE_WINDOW", False);
undefined identifier `Atom`
undefined identifier `XInternAtom`
XSetWMProtocols(dpy, win, &wmDelete, 1);
undefined identifier `XSetWMProtocols`
const c_long
(local variable) const(long) baseMask
baseMask
=
(enum value) app.ExposureMask = 32768L
ExposureMask
|
(enum value) app.KeyPressMask = 1L
KeyPressMask
|
(enum value) app.StructureNotifyMask = 131072L
StructureNotifyMask
;
XSelectInput(dpy, win, baseMask); // NO core buttons yet: dpy2 owns those
undefined identifier `XSelectInput`
ubyte[4]
(local variable) ubyte[4] bits
bits
= 0;
void app.xiSetMask(scope ubyte[] mask, int event) nothrow @nogc

XISetMask is a macro; same bit math, D-side.

xiSetMask
(
(local variable) ubyte[4] bits
bits
[],
(enum value) app.XI_ButtonPress = 4
XI_ButtonPress
);
void app.xiSetMask(scope ubyte[] mask, int event) nothrow @nogc

XISetMask is a macro; same bit math, D-side.

xiSetMask
(
(local variable) ubyte[4] bits
bits
[],
(enum value) app.XI_ButtonRelease = 5
XI_ButtonRelease
);
void app.xiSetMask(scope ubyte[] mask, int event) nothrow @nogc

XISetMask is a macro; same bit math, D-side.

xiSetMask
(
(local variable) ubyte[4] bits
bits
[],
(enum value) app.XI_Motion = 6
XI_Motion
);
XIEventMask
(local variable) _error_ m
m
;
undefined identifier `XIEventMask`
m.
m.deviceid
deviceid
= XIAllDevices;
m.mask_len = bits.
bits.length
length
;
m.
m.mask
mask
= bits.
bits.ptr
ptr
;
XISelectEvents(dpy, win, &m, 1);
undefined identifier `XISelectEvents`
XMapWindow(dpy, win);
undefined identifier `XMapWindow`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("window_created", "xid=0x%lx size=%dx%d", win,
(local variable) const(int) width
width
,
(local variable) const(int) height
height
);
// Client 2: core-protocol-only listener on the *same* window. Core // ButtonPressMask is one-client-per-window-exclusive, so a second // connection is the only way to hold core + XI2 selections concurrently. Display*
(local variable) _error_ dpy2
dpy2
= XOpenDisplay(null);
undefined identifier `Display`
undefined identifier `XOpenDisplay`
if (dpy2 is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: could not open second display connection\n");
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
return 0; } XSelectInput(dpy2, win, ButtonPressMask | ButtonReleaseMask);
undefined identifier `XSelectInput`
XFlush(dpy2);
undefined identifier `XFlush`
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("step name=XSelectInput conn=core_client mask=ButtonPress|ButtonRelease");
GC
(local variable) _error_ gc
gc
= XDefaultGC(dpy, screen);
undefined identifier `GC`
undefined identifier `XDefaultGC`
// -- Ruler + gesture state --------------------------------------------------- enum
(constant) int app.main.detentPx = 20
detentPx
= 20; // 1 wheel detent scrolls the ruler by 20 px
int
(local variable) int vOffset
vOffset
,
(local variable) int hOffset
hOffset
; // ruler offsets in px
long
(local variable) long lastScrollUs
lastScrollUs
= -1,
(local variable) long gestureStartUs
gestureStartUs
;
int
(local variable) int gEvents
gEvents
,
(local variable) int gCore
gCore
,
(local variable) int gXi2
gXi2
,
(local variable) int gEmulated
gEmulated
,
(local variable) int gVDetents
gVDetents
,
(local variable) int gHDetents
gHDetents
;
double
(local variable) double gSmoothV
gSmoothV
= 0,
(local variable) double gSmoothH
gSmoothH
= 0;
void
void app.main.redraw() nothrow @nogc @system
redraw
()
{ XClearWindow(dpy, win);
undefined identifier `XClearWindow`
foreach (
(local variable) int y
y
; 0 ..
(local variable) const(int) height
height
/
(constant) int app.main.detentPx = 20
detentPx
+ 2)
{ const
(local variable) const(int) v
v
=
(local variable) int y
y
*
(constant) int app.main.detentPx = 20
detentPx
- (
(local variable) int vOffset
vOffset
% (
(constant) int app.main.detentPx = 20
detentPx
* 5)) -
(constant) int app.main.detentPx = 20
detentPx
;
const
(local variable) const(int) lineNo
lineNo
= (
(local variable) const(int) v
v
+
(local variable) int vOffset
vOffset
) /
(constant) int app.main.detentPx = 20
detentPx
;
const
(local variable) const(bool) major
major
=
(local variable) const(int) lineNo
lineNo
% 5 == 0;
XDrawLine(dpy, win, gc, 40 + hOffset, v, (major ? 90 : 70) + hOffset, v);
undefined identifier `XDrawLine`
if (
(local variable) const(bool) major
major
)
{ char[16]
(local variable) char[16] buf
buf
;
const
(local variable) const(int) n
n
=
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(local variable) char[16] buf
buf
.
(constant) char* char[16].ptr = &buf
ptr
,
(local variable) char[16] buf
buf
.
(constant) ulong char[16].length = 16LU
length
, "%d",
(local variable) const(int) lineNo
lineNo
);
XDrawString(dpy, win, gc, 96 + hOffset, v + 4, buf.
buf.ptr
ptr
, n);
undefined identifier `XDrawString`
} } XFlush(dpy);
undefined identifier `XFlush`
} void
void app.main.endGesture() nothrow @nogc @system
endGesture
()
{ if (
(local variable) int gEvents
gEvents
== 0)
return;
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("gesture_summary", "events=%d core=%d xi2=%d emulated=%d "
~ "v_detents=%d h_detents=%d smooth_v=%g smooth_h=%g dur_ms=%lld",
(local variable) int gEvents
gEvents
,
(local variable) int gCore
gCore
,
(local variable) int gXi2
gXi2
,
(local variable) int gEmulated
gEmulated
,
(local variable) int gVDetents
gVDetents
,
(local variable) int gHDetents
gHDetents
,
(local variable) double gSmoothV
gSmoothV
,
(local variable) double gSmoothH
gSmoothH
, (
(local variable) long lastScrollUs
lastScrollUs
-
(local variable) long gestureStartUs
gestureStartUs
) / 1000);
(local variable) int gEvents
gEvents
=
(local variable) int gCore
gCore
=
(local variable) int gXi2
gXi2
=
(local variable) int gEmulated
gEmulated
=
(local variable) int gVDetents
gVDetents
=
(local variable) int gHDetents
gHDetents
= 0;
(local variable) double gSmoothV
gSmoothV
=
(local variable) double gSmoothH
gSmoothH
= 0;
} /// Fold one scroll event into the running gesture (and the ruler, when it /// is the stream that owns the ruler in the current phase). void
void app.main.countScroll(uint button, bool isXi2, bool emulated, bool moveRuler) nothrow @nogc @system

Fold one scroll event into the running gesture (and the ruler, when it is the stream that owns the ruler in the current phase).

countScroll
(uint
(parameter) uint button
button
, bool
(parameter) bool isXi2
isXi2
, bool
(parameter) bool emulated
emulated
, bool
(parameter) bool moveRuler
moveRuler
)
{ const
(local variable) const(long) now
now
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
if (
(local variable) long lastScrollUs
lastScrollUs
>= 0 &&
(local variable) const(long) now
now
-
(local variable) long lastScrollUs
lastScrollUs
> 400_000)
void app.main.endGesture() nothrow @nogc @system
endGesture
();
if (
(local variable) int gEvents
gEvents
== 0)
(local variable) long gestureStartUs
gestureStartUs
=
(local variable) const(long) now
now
;
(local variable) long lastScrollUs
lastScrollUs
=
(local variable) const(long) now
now
;
++
(local variable) int gEvents
gEvents
;
(parameter) bool isXi2
isXi2
? ++
(local variable) int gXi2
gXi2
: ++
(local variable) int gCore
gCore
;
if (
(parameter) bool emulated
emulated
)
++
(local variable) int gEmulated
gEmulated
;
const
(local variable) const(int) step
step
= (
(parameter) uint button
button
== 4 ||
(parameter) uint button
button
== 6) ? -1 : 1;
if (
(parameter) uint button
button
== 4 ||
(parameter) uint button
button
== 5)
(local variable) int gVDetents
gVDetents
+=
(local variable) const(int) step
step
;
else
(local variable) int gHDetents
gHDetents
+=
(local variable) const(int) step
step
;
if (
(parameter) bool moveRuler
moveRuler
)
{ if (
(parameter) uint button
button
== 4 ||
(parameter) uint button
button
== 5)
(local variable) int vOffset
vOffset
+=
(local variable) const(int) step
step
*
(constant) int app.main.detentPx = 20
detentPx
;
else
(local variable) int hOffset
hOffset
+=
(local variable) const(int) step
step
*
(constant) int app.main.detentPx = 20
detentPx
;
void app.main.redraw() nothrow @nogc @system
redraw
();
} } immutable(char)*
immutable(char)* app.main.axisOf(uint b) pure nothrow @nogc @system
axisOf
(uint
(parameter) uint b
b
) => (
(parameter) uint b
b
== 4 ||
(parameter) uint b
b
== 5) ? "v".
(constant) immutable(char)* "v".ptr = "v"
ptr
: "h".
(constant) immutable(char)* "h".ptr = "h"
ptr
;
// -- Phases -------------------------------------------------------------- // A dual_client: core -> dpy2, XI2 -> dpy (both streams, one event?) // B dual_selection: dpy2 deselects; dpy holds core AND XI2 selections // C core_only: dpy clears the XI2 selection, keeps the core one int
(local variable) int phase
phase
= -1;
long
(local variable) long phaseStartUs
phaseStartUs
;
bool
(local variable) bool sawExpose
sawExpose
,
(local variable) bool running
running
= true;
int
(local variable) int sendProbes
sendProbes
;
void
void app.main.enterPhase(int p) nothrow @nogc @system
enterPhase
(int
(parameter) int p
p
)
{
(local variable) int phase
phase
=
(parameter) int p
p
;
(local variable) long phaseStartUs
phaseStartUs
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
if (
(parameter) int p
p
== 0)
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("phase name=dual_client");
else if (
(parameter) int p
p
== 1)
{ XSelectInput(dpy2, win, 0);
undefined identifier `XSelectInput`
// XSync, not XFlush: the server must have *processed* dpy2's // deselect before dpy selects ButtonPress — only one client may // hold a window's ButtonPress selection, so a still-queued // deselect makes the next line's ChangeWindowAttributes die with // BadAccess (seen on CI's Xvfb). XSync(dpy2, False);
undefined identifier `XSync`
XSelectInput(dpy, win, baseMask | ButtonPressMask | ButtonReleaseMask);
undefined identifier `XSelectInput`
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("phase name=dual_selection core_client=deselected "
~ "xi2_client=core+xi2"); } else if (
(parameter) int p
p
== 2)
{ ubyte[4]
(local variable) ubyte[4] none
none
= 0;
XIEventMask
(local variable) _error_ m0
m0
;
undefined identifier `XIEventMask`
m0.
m0.deviceid
deviceid
= XIAllDevices;
m0.mask_len = none.
none.length
length
;
m0.
m0.mask
mask
= none.
none.ptr
ptr
;
XISelectEvents(dpy, win, &m0, 1);
undefined identifier `XISelectEvents`
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("phase name=core_only xi2_selection=cleared");
} else {
void app.main.endGesture() nothrow @nogc @system
endGesture
();
(local variable) bool running
running
= false;
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("auto_exit");
} } /// Built-in probe (no xdotool): fabricate a core wheel press/release pair /// with XSendEvent. It reaches core selectors only — fabricated events /// never enter the input pipeline, so no XI2 twin and no ruler motion /// from the server's point of view (this is why drivers use XTest). void
void app.main.sendEventProbe(uint button) nothrow @nogc @system

Built-in probe (no xdotool): fabricate a core wheel press/release pair with XSendEvent. It reaches core selectors only — fabricated events never enter the input pipeline, so no XI2 twin and no ruler motion from the server's point of view (this is why drivers use XTest).

sendEventProbe
(uint
(parameter) uint button
button
)
{ XEvent
(local variable) _error_ se
se
;
undefined identifier `XEvent`
se.xbutton.type = ButtonPress; se.xbutton.display = dpy; se.xbutton.window = win; se.xbutton.
se.xbutton.button
button
= button;
se.xbutton.same_screen = True; XSendEvent(dpy, win, True, ButtonPressMask, &se);
undefined identifier `XSendEvent`
se.xbutton.type = ButtonRelease; XSendEvent(dpy, win, True, ButtonReleaseMask, &se);
undefined identifier `XSendEvent`
XFlush(dpy);
undefined identifier `XFlush`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=XSendEvent button=%u",
(parameter) uint button
button
);
} void
app.main.handleCoreButton
handleCoreButton
(const(XButtonEvent)* be, const(char)* conn, bool
(parameter) bool moveRuler
moveRuler
)
undefined identifier `XButtonEvent`
{ if (be.type == ButtonRelease) return; // wheel scrolls are press+release pairs; count presses if (be.
be.button
button
>= 4 && be.
be.button
button
<= 7)
{ emitf("scroll", "conn=%s kind=core axis=%s button=%u value=%+d send_event=%d", conn, axisOf(be.
be.button
button
), be.
be.button
button
,
(be.
be.button
button
== 4 || be.
be.button
button
== 6) ? -1 : 1, cast(int) be.send_event);
countScroll(be.
be.button
button
, false, false, moveRuler);
} else emitf("button", "conn=%s kind=core button=%u send_event=%d", conn, be.
be.button
button
, cast(int) be.send_event);
} // -- Event loop: poll both connections ---------------------------------- const
(local variable) const(_error_) fd1
fd1
= XConnectionNumber(dpy),
(local variable) const(_error_) fd2
fd2
= XConnectionNumber(dpy2);
undefined identifier `XConnectionNumber`
undefined identifier `XConnectionNumber`
while (
(local variable) bool running
running
)
{ while (XPending(dpy) > 0)
undefined identifier `XPending`
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(dpy, &ev);
undefined identifier `XNextEvent`
switch (ev.type) { case Expose: if (ev.xexpose.count == 0) { redraw(); if (!sawExpose) { sawExpose = true; if (autoExit) enterPhase(0); } } break; case ButtonPress: case ButtonRelease: // only selected in phases B and C handleCoreButton(&ev.xbutton, "xi2_client", phase >= 1); break; case KeyPress: const
_error_ ks
ks
= XLookupKeysym(&ev.xkey, 0);
if (ks == 'q' || ks == 0xff1b /* XK_Escape */ ) running = false; break; case ClientMessage: if (cast(Atom) ev.xclient.data.l[0] == wmDelete) running = false; break; case GenericEvent: auto
_error_ cookie
cookie
= &ev.xcookie;
if (XGetEventData(dpy, cookie) && cookie.extension == xiOpcode) { const
_error_ de
de
= cast(const(XIDeviceEvent)*) cookie.data;
if (cookie.evtype == XI_ButtonPress) { const
_error_ emulated
emulated
= (de.flags & XIPointerEmulated) != 0;
// XIAllDevices delivers every event twice: once from // the slave, once as the master copy. Dedupe by // counting only the master copy (the measured trap). const
_error_ masterCopy
masterCopy
= de.
de.deviceid
deviceid
== masterPtr;
if (de.detail >= 4 && de.detail <= 7) { emitf("scroll", "conn=xi2_client kind=xi2 axis=%s button=%d " ~ "value=%+d emulated=%d flags=0x%x device=%d source=%d", axisOf(de.detail), de.detail, (de.detail == 4 || de.detail == 6) ? -1 : 1, cast(int) emulated, de.flags, de.
de.deviceid
deviceid
, de.sourceid);
if (masterCopy) countScroll(de.detail, true, emulated, true); } else emitf("button", "conn=xi2_client kind=xi2 button=%d emulated=%d", de.detail, cast(int) emulated); } else if (cookie.evtype == XI_Motion) { // Smooth scrolling: scroll axes ride XI_Motion as // absolute accumulating valuators; delta/increment // = detents. (No XIScrollClass on Xvfb -> never hit.) int
_error_ idx
idx
;
foreach (
(parameter) i
i
; 0 .. de.valuators.mask_len * 8)
{ if (!(de.valuators.
de.valuators.mask
mask
[i >> 3] & (1 << (i & 7))))
continue; const
_error_ v
v
= de.valuators.values[idx++];
foreach (ref
(parameter) ax
ax
; axes[0 .. nAxes])
{ if (ax.
ax.number
number
!= i
|| (ax.
ax.deviceid
deviceid
!= de.
de.deviceid
deviceid
&& ax.
ax.deviceid
deviceid
!= de.sourceid))
continue; if (ax.
ax.last
last
== ax.
ax.last
last
) // !NaN: delta is meaningful
emitf("scroll", "conn=xi2_client kind=smooth axis=%s " ~ "value=%g delta=%g detents=%g emulated=%d", ax.
ax.scrollType
scrollType
== XIScrollTypeVertical ? "v".
"v".ptr
ptr
: "h".
"h".ptr
ptr
,
v, v - ax.
ax.last
last
, (v - ax.
ax.last
last
) / ax.
ax.increment
increment
,
cast(int)((de.flags & XIPointerEmulated) != 0)); ax.
ax.last
last
= v;
} } } } XFreeEventData(dpy, cookie); break; default: break; } } while (XPending(dpy2) > 0) // the core-only second client
undefined identifier `XPending`
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(dpy2, &ev);
undefined identifier `XNextEvent`
if (ev.type ==
(enum value) app.ButtonPress = 4
ButtonPress
|| ev.type ==
(enum value) app.ButtonRelease = 5
ButtonRelease
)
handleCoreButton(&ev.xbutton, "core_client", phase == 0); } if (
(local variable) const(bool) autoExit
autoExit
&&
(local variable) bool sawExpose
sawExpose
&&
(local variable) bool running
running
)
{ const
(local variable) const(long) now
now
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
if (
(local variable) const(long) now
now
-
(local variable) long phaseStartUs
phaseStartUs
>=
(local variable) const(int) phaseUs
phaseUs
)
void app.main.enterPhase(int p) nothrow @nogc @system
enterPhase
(
(local variable) int phase
phase
+ 1);
else if (!
(local variable) const(bool) driven
driven
&&
(local variable) int sendProbes
sendProbes
< 3 * (
(local variable) int phase
phase
+ 1)
&&
(local variable) const(long) now
now
-
(local variable) long phaseStartUs
phaseStartUs
>= 100_000 * (
(local variable) int sendProbes
sendProbes
% 3 + 1))
{
void app.main.sendEventProbe(uint button) nothrow @nogc @system

Built-in probe (no xdotool): fabricate a core wheel press/release pair with XSendEvent. It reaches core selectors only — fabricated events never enter the input pipeline, so no XI2 twin and no ruler motion from the server's point of view (this is why drivers use XTest).

sendEventProbe
(
(local variable) int sendProbes
sendProbes
% 3 == 2 ? 6 : (
(local variable) int sendProbes
sendProbes
% 2 == 0 ? 4 : 5));
++
(local variable) int sendProbes
sendProbes
;
} if (
(local variable) long lastScrollUs
lastScrollUs
>= 0 &&
(local variable) const(long) now
now
-
(local variable) long lastScrollUs
lastScrollUs
> 400_000)
void app.main.endGesture() nothrow @nogc @system
endGesture
();
} XFlush(dpy);
undefined identifier `XFlush`
pollfd[2]
(local variable) _error_ pfds
pfds
;
undefined identifier `pollfd`
pfds[0].fd = fd1; pfds[1].fd = fd2; pfds[0].events = pfds[1].events = POLLIN; pfds[0].revents = pfds[1].revents = 0; poll(pfds.
pfds.ptr
ptr
, 2, autoExit ? 5 : -1);
undefined identifier `poll`
}
void app.main.endGesture() nothrow @nogc @system
endGesture
();
XCloseDisplay(dpy2);
undefined identifier `XCloseDisplay`
XDestroyWindow(dpy, win);
undefined identifier `XDestroyWindow`
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("teardown");
return 0; }