react-x11 2.21.2 → 2.22.0
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 +2 -2
- package/src/gloverlay.js +8 -48
- package/src/node.d.ts +11 -1
- package/src/nodes/damage.js +9 -6
- package/src/nodes/invalidate.js +13 -1
- package/src/nodes/layout.js +24 -49
- package/src/nodes/moveblit.js +610 -0
- package/src/nodes/node.js +14 -15
- package/src/nodes/paint.js +103 -8
- package/src/nodes/position.js +1 -0
- package/src/nodes/rects.js +88 -0
- package/src/nodes/roundclip.js +214 -0
- package/src/nodes/scrollable.js +9 -4
- package/src/nodes/scrollbars.js +9 -3
- package/src/nodes/scrollblit.js +232 -40
- package/src/nodes/window/flush.js +12 -0
- package/src/nodes/window/window.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-x11",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"description": "react renderer with X11 as a target",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"optionalDependencies": {
|
|
111
111
|
"@windowkit/appkit": "^0.13.0",
|
|
112
112
|
"@windowkit/wayland": "^3.1.1",
|
|
113
|
-
"@windowkit/win32": "^0.0.
|
|
113
|
+
"@windowkit/win32": "^0.0.5",
|
|
114
114
|
"dbus-native": "^0.15.1",
|
|
115
115
|
"x11-dri": "^0.9.0"
|
|
116
116
|
},
|
package/src/gloverlay.js
CHANGED
|
@@ -66,8 +66,10 @@ import { FULL_DAMAGE, addDamageRect } from './nodes/damage.js';
|
|
|
66
66
|
import {
|
|
67
67
|
innerPixels,
|
|
68
68
|
intersectRects,
|
|
69
|
+
outside,
|
|
69
70
|
rectArea,
|
|
70
71
|
rectContains,
|
|
72
|
+
shiftRect,
|
|
71
73
|
unionRect,
|
|
72
74
|
} from './nodes/rects.js';
|
|
73
75
|
|
|
@@ -197,48 +199,6 @@ function around(a, b) {
|
|
|
197
199
|
const sameRect = (a, b) =>
|
|
198
200
|
a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
199
201
|
|
|
200
|
-
const shifted = (r, dx, dy) => ({
|
|
201
|
-
x: r.x + dx,
|
|
202
|
-
y: r.y + dy,
|
|
203
|
-
width: r.width,
|
|
204
|
-
height: r.height,
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
/** `a` with `b` taken out of it: up to four rects — the full-width bands
|
|
208
|
-
* above and below `b`, and the pieces either side of it between them. */
|
|
209
|
-
function subtractRect(a, b) {
|
|
210
|
-
const cut = intersectRects(a, b);
|
|
211
|
-
if (!cut) return [a];
|
|
212
|
-
const out = [];
|
|
213
|
-
const right = a.x + a.width;
|
|
214
|
-
const bottom = a.y + a.height;
|
|
215
|
-
const cutRight = cut.x + cut.width;
|
|
216
|
-
const cutBottom = cut.y + cut.height;
|
|
217
|
-
if (cut.y > a.y) {
|
|
218
|
-
out.push({ x: a.x, y: a.y, width: a.width, height: cut.y - a.y });
|
|
219
|
-
}
|
|
220
|
-
if (cutBottom < bottom) {
|
|
221
|
-
out.push({
|
|
222
|
-
x: a.x,
|
|
223
|
-
y: cutBottom,
|
|
224
|
-
width: a.width,
|
|
225
|
-
height: bottom - cutBottom,
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
if (cut.x > a.x) {
|
|
229
|
-
out.push({ x: a.x, y: cut.y, width: cut.x - a.x, height: cut.height });
|
|
230
|
-
}
|
|
231
|
-
if (cutRight < right) {
|
|
232
|
-
out.push({
|
|
233
|
-
x: cutRight,
|
|
234
|
-
y: cut.y,
|
|
235
|
-
width: right - cutRight,
|
|
236
|
-
height: cut.height,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
return out;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
202
|
/** On screen: nothing from here to the window hidden or `display: 'none'`. */
|
|
243
203
|
function shown(node) {
|
|
244
204
|
for (let n = node; n; n = n.parent) {
|
|
@@ -594,7 +554,7 @@ export class GlOverlay {
|
|
|
594
554
|
);
|
|
595
555
|
if (!pane) return false;
|
|
596
556
|
const view = intersectRects(pane.rect, box);
|
|
597
|
-
const dest = intersectRects(
|
|
557
|
+
const dest = intersectRects(shiftRect(was, dx, dy), view);
|
|
598
558
|
if (!dest) return false;
|
|
599
559
|
const cap = root._damageRectCap();
|
|
600
560
|
const claimed = root._paneDamage ?? [];
|
|
@@ -603,14 +563,14 @@ export class GlOverlay {
|
|
|
603
563
|
if (rect) rects = addDamageRect(rects, rect, cap);
|
|
604
564
|
};
|
|
605
565
|
for (const claim of claimed)
|
|
606
|
-
add(intersectRects(
|
|
607
|
-
for (const piece of
|
|
608
|
-
if (now) for (const piece of
|
|
566
|
+
add(intersectRects(shiftRect(claim, dx, dy), dest));
|
|
567
|
+
for (const piece of outside(was, dest)) add(piece);
|
|
568
|
+
if (now) for (const piece of outside(now, dest)) add(piece);
|
|
609
569
|
for (const other of area.paintOrder()) {
|
|
610
570
|
if (other === node) continue;
|
|
611
571
|
const theirs = whole(other.paintBounds());
|
|
612
572
|
add(intersectRects(theirs, dest));
|
|
613
|
-
add(intersectRects(
|
|
573
|
+
add(intersectRects(shiftRect(theirs, dx, dy), dest));
|
|
614
574
|
}
|
|
615
575
|
// the list is disjoint, so the sum is the area it covers
|
|
616
576
|
let repainted = 0;
|
|
@@ -621,7 +581,7 @@ export class GlOverlay {
|
|
|
621
581
|
if (repainted > rectArea(dest) * MOVE_BLIT_MAX_REPAINT) return false;
|
|
622
582
|
// the verb moves the band that survives inside the rect it is handed,
|
|
623
583
|
// so handed where the pixels are and where they go, that band is `dest`
|
|
624
|
-
if (!pane.blit(unionRect(
|
|
584
|
+
if (!pane.blit(unionRect(shiftRect(dest, -dx, -dy), dest), dx, dy)) {
|
|
625
585
|
return false;
|
|
626
586
|
}
|
|
627
587
|
root._paneDamage = rects;
|
package/src/node.d.ts
CHANGED
|
@@ -553,12 +553,22 @@ export declare class Node {
|
|
|
553
553
|
* what it leaves or reaches outside `rect` is repainted, so keep what it
|
|
554
554
|
* can paint inside the element (a box that clips it). Anything else it
|
|
555
555
|
* does is claimed as usual, which declines the blit.
|
|
556
|
+
*
|
|
557
|
+
* `pinned` is the other way round: furniture inside `rect` that stays put
|
|
558
|
+
* while everything around it moves — a minimap, zoom controls — as rects
|
|
559
|
+
* in the same coordinates. The copy drags a stale image of each along, so
|
|
560
|
+
* the frame repaints the pinned rect and that image on every pan frame,
|
|
561
|
+
* changed or not; a claim inside a pinned rect, or a node that lies inside
|
|
562
|
+
* one, leaves the blit standing. Pin furniture in a corner rather than
|
|
563
|
+
* carving it out of `rect`: what shifts is one rectangle, so a carved
|
|
564
|
+
* corner takes the rows beside it too.
|
|
556
565
|
*/
|
|
557
566
|
scrollContents(
|
|
558
567
|
rect: Rect,
|
|
559
568
|
dx: number,
|
|
560
569
|
dy: number,
|
|
561
|
-
riders?: Iterable<Node
|
|
570
|
+
riders?: Iterable<Node> | null,
|
|
571
|
+
pinned?: Iterable<Rect> | null,
|
|
562
572
|
): boolean;
|
|
563
573
|
/**
|
|
564
574
|
* Did anything this node draws change? True damages the whole node, false
|
package/src/nodes/damage.js
CHANGED
|
@@ -50,12 +50,14 @@ export const layoutDiff = {
|
|
|
50
50
|
// else, and restored through `finally` like the sink beside it.
|
|
51
51
|
shift: null,
|
|
52
52
|
|
|
53
|
-
// True when `shift` is a
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
53
|
+
// True when `shift` is a subtree's own move whose pixels a copy may carry,
|
|
54
|
+
// rather than a scroll: a `<glarea>` child's, moved on its pane
|
|
55
|
+
// (src/glnodes.js, `_absolutizeChild`, issue #644), or one the window may
|
|
56
|
+
// copy in its backing (nodes/moveblit.js, issue #681). A node that lands
|
|
57
|
+
// where it was plus the shift is carried by that copy. A node that turns
|
|
58
|
+
// the diff off under a shift — a scroll pane laid out again, whose box
|
|
59
|
+
// would have claimed its children — claims its own box instead, since the
|
|
60
|
+
// move claimed nothing for it.
|
|
59
61
|
ride: false,
|
|
60
62
|
};
|
|
61
63
|
|
|
@@ -65,6 +67,7 @@ export const layoutDiff = {
|
|
|
65
67
|
// DEV validates against this list.
|
|
66
68
|
export const INVALIDATE_REASONS = new Set([
|
|
67
69
|
'props', // a React commit changed what a node draws
|
|
70
|
+
'position', // an absolute box of a set size moved and changed nothing else
|
|
68
71
|
'style-state', // :hover/:focus/:active/:disabled restyle
|
|
69
72
|
'shadow', // a boxShadow got smaller: where it *was* still owes a repaint
|
|
70
73
|
'outline', // …and the same for an outline a style swap took away
|
package/src/nodes/invalidate.js
CHANGED
|
@@ -387,7 +387,7 @@ export class WindowInvalidate {
|
|
|
387
387
|
// viewport — and the wider zone is what keeps it out.
|
|
388
388
|
//
|
|
389
389
|
// The difference is what lets an element carve furniture out of the
|
|
390
|
-
// rect it blits — a
|
|
390
|
+
// rect it blits — a HUD strip along the pane's edge that it repaints
|
|
391
391
|
// itself — and keep the pan at blit cost while that furniture
|
|
392
392
|
// claims beside it.
|
|
393
393
|
const contents = sv._pendingBlitContents;
|
|
@@ -404,6 +404,12 @@ export class WindowInvalidate {
|
|
|
404
404
|
if (sv._blitLedgerOpen() && sv._recordBlitClaim(rect)) {
|
|
405
405
|
continue;
|
|
406
406
|
}
|
|
407
|
+
// …or it lies inside furniture an element pinned over what it
|
|
408
|
+
// shifts (issue #682): the frame repaints the pinned rect, and
|
|
409
|
+
// the image of it the copy drags along, whether or not anything
|
|
410
|
+
// claims there — so a claim inside one changes nothing about
|
|
411
|
+
// the pixels the blit moves.
|
|
412
|
+
if (sv._pinnedHolds(rect)) continue;
|
|
407
413
|
// Poison rather than disarm (react-x11#295): a null here would
|
|
408
414
|
// let a second scrollTo in the same frame re-arm from a
|
|
409
415
|
// mid-frame origin, and the blit would then move pixels that
|
|
@@ -446,6 +452,9 @@ export class WindowInvalidate {
|
|
|
446
452
|
bounds,
|
|
447
453
|
this._damageRectCap(),
|
|
448
454
|
);
|
|
455
|
+
// …and whose claim it was, for a copy of a subtree that moved
|
|
456
|
+
// (`_settleRigidMoves`): what is under the subtree it covers
|
|
457
|
+
this._logClaim(bounds, damage?.kind ? damage : source);
|
|
449
458
|
}
|
|
450
459
|
if (panes) this._addPaneDamage(bounds);
|
|
451
460
|
}
|
|
@@ -497,6 +506,7 @@ export class WindowInvalidate {
|
|
|
497
506
|
let windowTook = false;
|
|
498
507
|
if (reach !== PANES_ONLY && this._damage !== FULL_DAMAGE) {
|
|
499
508
|
this._damage = addDamageRect(this._damage, rect, cap);
|
|
509
|
+
this._logClaim(rect, node ?? null);
|
|
500
510
|
windowTook = true;
|
|
501
511
|
}
|
|
502
512
|
if (reach !== WINDOW_ONLY) this._addPaneDamage(rect);
|
|
@@ -557,6 +567,8 @@ export class WindowInvalidate {
|
|
|
557
567
|
_takeDamage(width, height) {
|
|
558
568
|
const damage = this._damage;
|
|
559
569
|
this._damage = null;
|
|
570
|
+
// the next frame's claims start a log of their own
|
|
571
|
+
this._claimLog = [];
|
|
560
572
|
// what the frame about to run settled on, for the tests and for
|
|
561
573
|
// REACT_X11_DEBUG_LAYOUT to report; null means it repainted everything.
|
|
562
574
|
// `_lastDamage` is the box around the rects, which is what a caller
|
package/src/nodes/layout.js
CHANGED
|
@@ -5,54 +5,9 @@
|
|
|
5
5
|
import { Yoga } from '../yoga.js';
|
|
6
6
|
import { callHandler } from '../errors.js';
|
|
7
7
|
import { DAMAGE_SLOP, layoutDiff } from './damage.js';
|
|
8
|
-
import { insetRect, intersectRects, outerPixels } from './rects.js';
|
|
8
|
+
import { insetRect, intersectRects, outerPixels, outside } from './rects.js';
|
|
9
9
|
import { DEV } from './util.js';
|
|
10
10
|
|
|
11
|
-
/** The parts of `rect` outside `hole`: up to four bands, full width above
|
|
12
|
-
* and below, the rest beside. */
|
|
13
|
-
function outside(rect, hole) {
|
|
14
|
-
const cut = intersectRects(rect, hole);
|
|
15
|
-
if (!cut) return [rect];
|
|
16
|
-
const out = [];
|
|
17
|
-
const right = rect.x + rect.width;
|
|
18
|
-
const bottom = rect.y + rect.height;
|
|
19
|
-
if (cut.y > rect.y) {
|
|
20
|
-
out.push({
|
|
21
|
-
x: rect.x,
|
|
22
|
-
y: rect.y,
|
|
23
|
-
width: rect.width,
|
|
24
|
-
height: cut.y - rect.y,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const cutBottom = cut.y + cut.height;
|
|
28
|
-
if (cutBottom < bottom) {
|
|
29
|
-
out.push({
|
|
30
|
-
x: rect.x,
|
|
31
|
-
y: cutBottom,
|
|
32
|
-
width: rect.width,
|
|
33
|
-
height: bottom - cutBottom,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
if (cut.x > rect.x) {
|
|
37
|
-
out.push({
|
|
38
|
-
x: rect.x,
|
|
39
|
-
y: cut.y,
|
|
40
|
-
width: cut.x - rect.x,
|
|
41
|
-
height: cut.height,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
const cutRight = cut.x + cut.width;
|
|
45
|
-
if (cutRight < right) {
|
|
46
|
-
out.push({
|
|
47
|
-
x: cutRight,
|
|
48
|
-
y: cut.y,
|
|
49
|
-
width: right - cutRight,
|
|
50
|
-
height: cut.height,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return out;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
11
|
export const MEASURE_MODES = [];
|
|
57
12
|
MEASURE_MODES[Yoga.MEASURE_MODE_UNDEFINED] = 'unconstrained';
|
|
58
13
|
MEASURE_MODES[Yoga.MEASURE_MODE_EXACTLY] = 'exactly';
|
|
@@ -264,7 +219,10 @@ export class NodeLayout {
|
|
|
264
219
|
}
|
|
265
220
|
}
|
|
266
221
|
} finally {
|
|
267
|
-
if (move)
|
|
222
|
+
if (move) {
|
|
223
|
+
layoutDiff.shift = null;
|
|
224
|
+
layoutDiff.ride = false;
|
|
225
|
+
}
|
|
268
226
|
}
|
|
269
227
|
if (move) this._claimRigidMove(move);
|
|
270
228
|
}
|
|
@@ -357,6 +315,12 @@ export class NodeLayout {
|
|
|
357
315
|
*
|
|
358
316
|
* Null when the move is not of that kind, or no diff is listening; the
|
|
359
317
|
* walk is then the plain one.
|
|
318
|
+
*
|
|
319
|
+
* A move the window may copy rather than repaint (`_mayBlitMove`, issue
|
|
320
|
+
* #681) is walked as a ride as well, the way a `<glarea>` child's is
|
|
321
|
+
* (`layoutDiff.ride`): a scroll pane inside it that is laid out again
|
|
322
|
+
* claims its viewport, since a copy of the pane would carry rows that
|
|
323
|
+
* moved inside it and nothing else claims them.
|
|
360
324
|
*/
|
|
361
325
|
_beginRigidMove(x, y, width, height) {
|
|
362
326
|
if (!layoutDiff.sink || layoutDiff.shift) return null;
|
|
@@ -379,7 +343,9 @@ export class NodeLayout {
|
|
|
379
343
|
contents && contents.dx === shift.x && contents.dy === shift.y
|
|
380
344
|
? contents.rect
|
|
381
345
|
: null;
|
|
382
|
-
|
|
346
|
+
const defer = !carried && this.root._mayBlitMove(this, shift);
|
|
347
|
+
if (defer) layoutDiff.ride = true;
|
|
348
|
+
return { sink: layoutDiff.sink, was, shift, carried, defer };
|
|
383
349
|
}
|
|
384
350
|
|
|
385
351
|
/**
|
|
@@ -391,9 +357,18 @@ export class NodeLayout {
|
|
|
391
357
|
* Named for the node that moved, which is what sends each claim to the
|
|
392
358
|
* lists that paint it (`_paneReach`): the panes alone inside a
|
|
393
359
|
* `<glarea>`, both for a subtree holding one.
|
|
360
|
+
*
|
|
361
|
+
* A move the window may copy is handed to it instead, and claimed once
|
|
362
|
+
* the frame's other claims are in (`WindowNode._settleRigidMoves`): the
|
|
363
|
+
* copy, and so the question of what is left to paint, needs to know what
|
|
364
|
+
* else changed around the subtree.
|
|
394
365
|
*/
|
|
395
|
-
_claimRigidMove({ sink, was, shift, carried }) {
|
|
366
|
+
_claimRigidMove({ sink, was, shift, carried, defer }) {
|
|
396
367
|
const root = this.root;
|
|
368
|
+
if (defer) {
|
|
369
|
+
root._deferRigidMove(this, was, shift);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
397
372
|
const to = {
|
|
398
373
|
x: was.x + shift.x,
|
|
399
374
|
y: was.y + shift.y,
|