react-x11 2.21.1 → 2.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/win32/app.js +39 -18
package/package.json
CHANGED
package/src/win32/app.js
CHANGED
|
@@ -48,14 +48,24 @@ import { Win32Window } from './window.js';
|
|
|
48
48
|
// when that is unavailable.
|
|
49
49
|
const FRAME_INTERVAL_MS = 1000 / 60;
|
|
50
50
|
|
|
51
|
-
// How long a promised compositor tick may take
|
|
52
|
-
//
|
|
53
|
-
// would stop every frame in the application for
|
|
54
|
-
// clean event loop, which is the worst kind to be
|
|
55
|
-
// is watched. One timer per frame costs nothing:
|
|
56
|
-
// here was never its cost, only its granularity.
|
|
51
|
+
// How long a promised compositor tick may take, while the clock has been
|
|
52
|
+
// ticking, before a timer answers the frame in its place. A tick that is
|
|
53
|
+
// asked for and never arrives would stop every frame in the application for
|
|
54
|
+
// good — an app frozen with a clean event loop, which is the worst kind to be
|
|
55
|
+
// told about — so the clock is watched. One timer per frame costs nothing:
|
|
56
|
+
// what was wrong with a timer here was never its cost, only its granularity.
|
|
57
57
|
const CLOCK_WATCHDOG_MS = 250;
|
|
58
58
|
|
|
59
|
+
// How long since the clock last ticked before it is not trusted to be
|
|
60
|
+
// ticking. A request made after a quiet spell waited 0.3–3 s for its tick
|
|
61
|
+
// (measured on a 180 Hz panel: 5 of 8 cold starts of the Flow bench, and the
|
|
62
|
+
// first frame after most pauses between its phases), so such a frame races a
|
|
63
|
+
// frame interval's timer, and the tick it asked for, however late, says the
|
|
64
|
+
// clock is back. It used to be the watchdog's to catch, and a watchdog that
|
|
65
|
+
// fired latched the timer for the rest of the session — 34 frames a second,
|
|
66
|
+
// alternating one system tick and two, from then on.
|
|
67
|
+
const CLOCK_IDLE_MS = 50;
|
|
68
|
+
|
|
59
69
|
/**
|
|
60
70
|
* A pointer event's position on the screen, which X carries as `rootx`/
|
|
61
71
|
* `rooty` and Windows does not: WM_MOUSEMOVE and the button messages are all
|
|
@@ -88,9 +98,9 @@ export class Win32App {
|
|
|
88
98
|
/** A frame has been asked for and not yet delivered — one outstanding
|
|
89
99
|
* request at a time, whether the clock or the timer is answering it. */
|
|
90
100
|
this._framePending = false;
|
|
91
|
-
/**
|
|
92
|
-
*
|
|
93
|
-
this.
|
|
101
|
+
/** When the compositor's clock last ticked: within `CLOCK_IDLE_MS` it is
|
|
102
|
+
* trusted to answer the next frame, and otherwise a timer races it. */
|
|
103
|
+
this._clockAt = -Infinity;
|
|
94
104
|
this._closed = false;
|
|
95
105
|
this._atoms = new Map();
|
|
96
106
|
this._appearanceListeners = new Set();
|
|
@@ -473,14 +483,22 @@ export class Win32App {
|
|
|
473
483
|
this._framePending = true;
|
|
474
484
|
// One tick, from the compositor if this Windows has a clock to wait on.
|
|
475
485
|
// It answers false when it has not, and then — and only then — a timer.
|
|
476
|
-
if (
|
|
477
|
-
this
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
486
|
+
if (this._native.frameClockRequest?.()) {
|
|
487
|
+
// A clock that has been ticking answers this frame, and the timer only
|
|
488
|
+
// watches for a tick that never comes. One that has not ticked lately
|
|
489
|
+
// may be asleep, so the timer races it at a frame interval — and a
|
|
490
|
+
// clock that never ticks again paces the app exactly as the timer
|
|
491
|
+
// alone would, which is what a lost clock used to be latched into.
|
|
492
|
+
const ticking = performance.now() - this._clockAt < CLOCK_IDLE_MS;
|
|
493
|
+
this._frameTimer = setTimeout(
|
|
494
|
+
() => {
|
|
495
|
+
this._frameTimer = null;
|
|
496
|
+
if (!this._framePending || this._closed) return;
|
|
497
|
+
this._framePending = false;
|
|
498
|
+
this._tickFrames();
|
|
499
|
+
},
|
|
500
|
+
ticking ? CLOCK_WATCHDOG_MS : FRAME_INTERVAL_MS,
|
|
501
|
+
);
|
|
484
502
|
this._frameTimer.unref?.();
|
|
485
503
|
return;
|
|
486
504
|
}
|
|
@@ -546,8 +564,11 @@ export class Win32App {
|
|
|
546
564
|
switch (event.type) {
|
|
547
565
|
// The compositor is ready for a frame. Carries no id and belongs to no
|
|
548
566
|
// window: it is the clock, and every window that asked for a frame in
|
|
549
|
-
// the meantime is paced by this one tick.
|
|
567
|
+
// the meantime is paced by this one tick. A tick that a timer beat to
|
|
568
|
+
// its frame still says the clock is awake again, and answers whatever
|
|
569
|
+
// frame has been asked for since.
|
|
550
570
|
case 'frame-clock':
|
|
571
|
+
this._clockAt = performance.now();
|
|
551
572
|
if (this._frameTimer) clearTimeout(this._frameTimer);
|
|
552
573
|
this._frameTimer = null;
|
|
553
574
|
this._framePending = false;
|