react-x11 2.13.0 → 2.15.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.
Files changed (70) hide show
  1. package/package.json +11 -8
  2. package/src/Reconciler.js +34 -21
  3. package/src/components/Select.js +8 -2
  4. package/src/events.js +8 -2
  5. package/src/glnodes.js +15 -3
  6. package/src/index.d.ts +5 -0
  7. package/src/nodes/boxpaint.js +9 -0
  8. package/src/nodes/preedit.js +64 -14
  9. package/src/ntk.js +10 -1
  10. package/src/scale.js +52 -22
  11. package/src/screencolor.js +104 -17
  12. package/src/types/system.d.ts +14 -1
  13. package/src/wayland/app.js +574 -0
  14. package/src/wayland/backendwindow.js +1199 -0
  15. package/src/wayland/clipboard.js +326 -0
  16. package/src/wayland/connection.js +485 -0
  17. package/src/wayland/context2d.js +2290 -0
  18. package/src/wayland/decorations.js +476 -0
  19. package/src/wayland/device.js +55 -0
  20. package/src/wayland/dmabuf.js +89 -0
  21. package/src/wayland/dnd.js +581 -0
  22. package/src/wayland/fdutil.js +108 -0
  23. package/src/wayland/framestyle.js +257 -0
  24. package/src/wayland/framewatch.js +190 -0
  25. package/src/wayland/glarea.js +372 -0
  26. package/src/wayland/glcontext.js +415 -0
  27. package/src/wayland/glyphatlas.js +237 -0
  28. package/src/wayland/input.js +417 -0
  29. package/src/wayland/keysymnames.js +35 -0
  30. package/src/wayland/layershell.js +363 -0
  31. package/src/wayland/outputs.js +601 -0
  32. package/src/wayland/protocols/cursor-shape-v1.json +1 -0
  33. package/src/wayland/protocols/ext-idle-notify-v1.json +1 -0
  34. package/src/wayland/protocols/ext-image-capture-source-v1.json +1 -0
  35. package/src/wayland/protocols/ext-image-copy-capture-v1.json +1 -0
  36. package/src/wayland/protocols/fractional-scale-v1.json +1 -0
  37. package/src/wayland/protocols/index.json +131 -0
  38. package/src/wayland/protocols/kde-server-decoration.json +1 -0
  39. package/src/wayland/protocols/keyboard-shortcuts-inhibit-unstable-v1.json +1 -0
  40. package/src/wayland/protocols/linux-dmabuf-v1.json +1 -0
  41. package/src/wayland/protocols/pointer-constraints-unstable-v1.json +1 -0
  42. package/src/wayland/protocols/presentation-time.json +1 -0
  43. package/src/wayland/protocols/primary-selection-unstable-v1.json +1 -0
  44. package/src/wayland/protocols/relative-pointer-unstable-v1.json +1 -0
  45. package/src/wayland/protocols/tablet-v2.json +1 -0
  46. package/src/wayland/protocols/text-input-unstable-v3.json +1 -0
  47. package/src/wayland/protocols/viewporter.json +1 -0
  48. package/src/wayland/protocols/wayland.json +1 -0
  49. package/src/wayland/protocols/wlr-layer-shell-unstable-v1.json +1 -0
  50. package/src/wayland/protocols/wlr-screencopy-unstable-v1.json +1 -0
  51. package/src/wayland/protocols/xdg-activation-v1.json +1 -0
  52. package/src/wayland/protocols/xdg-decoration-unstable-v1.json +1 -0
  53. package/src/wayland/protocols/xdg-output-unstable-v1.json +1 -0
  54. package/src/wayland/protocols/xdg-shell.json +1 -0
  55. package/src/wayland/protocols/xdg-toplevel-icon-v1.json +1 -0
  56. package/src/wayland/readback.js +99 -0
  57. package/src/wayland/screencopy.js +584 -0
  58. package/src/wayland/seat.js +584 -0
  59. package/src/wayland/shm.js +226 -0
  60. package/src/wayland/ssd.js +234 -0
  61. package/src/wayland/surface.js +141 -0
  62. package/src/wayland/swapchain.js +411 -0
  63. package/src/wayland/tablet.js +522 -0
  64. package/src/wayland/target.js +269 -0
  65. package/src/wayland/text.js +113 -0
  66. package/src/wayland/textinput.js +671 -0
  67. package/src/wayland/touch.js +284 -0
  68. package/src/wayland/window.js +854 -0
  69. package/src/wayland/xkb.js +425 -0
  70. package/src/windowstate.js +41 -1
@@ -0,0 +1,284 @@
1
+ // Touch: `wl_touch`, the seat's third capability.
2
+ //
3
+ // A touchscreen speaks in *points*. `down` names a surface and gives the
4
+ // point an id, `motion` and `up` refer to the id, and `frame` closes a group
5
+ // of events that happened together — two fingers landing at once are two
6
+ // `down`s and one `frame`. Nothing about a point is a button, there is no
7
+ // cursor, and `cancel` means the compositor took the gesture for itself
8
+ // (a three-finger swipe to the overview) and the client is to forget every
9
+ // point it had.
10
+ //
11
+ // Two things come out of this file, kept deliberately apart:
12
+ //
13
+ // - **Pointer emulation.** Every control in the tree is written against
14
+ // `mousedown`/`mousemove`/`mouseup`, and a finger has to work on all of
15
+ // them without each learning about touch. So the first point of a gesture
16
+ // *becomes the pointer*, the way XI2's pointer emulation makes it the core
17
+ // pointer on X: its `down` is an `enter` and a button-1 press carrying the
18
+ // down's serial (which is what `xdg_toplevel.move` needs when the finger
19
+ // lands on the titlebar), its `motion` is pointer motion, its `up` — or a
20
+ // `cancel` — a release and a `leave`. A second finger while the first is
21
+ // down emulates nothing, so a two-finger gesture never turns into a
22
+ // second click. The emulated events are the seat's own pointer events,
23
+ // shaped identically and routed by `input.js` through exactly the same
24
+ // path — frame hit-testing, popup grabs, cursor hover and all — with
25
+ // `pointerType: 'touch'` and the `touchId` on them, so a handler that
26
+ // cares can tell a finger from a mouse and nothing else has to.
27
+ // - **Raw touch events.** `touchstart`/`touchmove`/`touchend`/`touchcancel`
28
+ // — ntk's names for XI2's TouchBegin/Update/End, with its `touchId` — for
29
+ // every point, each carrying the list of active `touches`, so a gesture
30
+ // that wants more than one finger can be built from them. They ride the
31
+ // same batch as the emulated events and are flushed at `frame`.
32
+ //
33
+ // Coordinates stay surface-local and logical here, as the pointer's are;
34
+ // `input.js` owns the conversion to content-relative device pixels.
35
+
36
+ import { SEAT_CAP, BUTTON_MASK } from './seat.js';
37
+
38
+ /** evdev's code for a touch contact, filling the slot a pointer button has. */
39
+ export const BTN_TOUCH = 0x14a;
40
+
41
+ const BUTTON1 = BUTTON_MASK[1];
42
+
43
+ export class WaylandTouch {
44
+ /**
45
+ * Attach to a seat: `get_touch` now if the capability is already there
46
+ * (the first `capabilities` event arrived during `WaylandSeat.bind`), and
47
+ * follow it as touchscreens come and go.
48
+ *
49
+ * @param {import('./seat.js').WaylandSeat} seat
50
+ */
51
+ static attach(seat) {
52
+ const touch = new WaylandTouch(seat);
53
+ seat.touch = touch;
54
+ touch._sync(seat.capabilities);
55
+ seat.on('capabilities', touch._onCapabilities);
56
+ return touch;
57
+ }
58
+
59
+ constructor(seat) {
60
+ this.seat = seat;
61
+ /** the `wl_touch`, or null while the seat has no touch capability */
62
+ this.touch = null;
63
+ /**
64
+ * Active points by id: `{ id, serial, time, surface, x, y, major, minor,
65
+ * orientation }`, surface-local logical.
66
+ */
67
+ this.points = new Map();
68
+ /** the id of the point standing in for the pointer, or null */
69
+ this.emulated = null;
70
+ this._batch = [];
71
+ this._onCapabilities = (caps) => this._sync(caps);
72
+ }
73
+
74
+ _sync(caps) {
75
+ if (caps & SEAT_CAP.TOUCH) this._acquire();
76
+ else this._release();
77
+ }
78
+
79
+ _acquire() {
80
+ if (this.touch) return;
81
+ const t = this.seat.seat.$.get_touch();
82
+ this.touch = t;
83
+
84
+ t.on('down', (serial, time, surfaceId, id, x, y) => {
85
+ const seat = this.seat;
86
+ seat.lastSerial = serial;
87
+ seat.lastPressSerial = serial;
88
+ const pt = {
89
+ id,
90
+ serial,
91
+ time,
92
+ surface: surfaceId,
93
+ x,
94
+ y,
95
+ major: 0,
96
+ minor: 0,
97
+ orientation: 0,
98
+ };
99
+ this.points.set(id, pt);
100
+ this._raw('touchstart', pt, serial);
101
+ if (this.emulated == null) {
102
+ this.emulated = id;
103
+ this._batch.push({
104
+ type: 'enter',
105
+ serial,
106
+ surface: surfaceId,
107
+ x,
108
+ y,
109
+ device: this._device(pt, true),
110
+ });
111
+ const before = seat.buttonMask;
112
+ seat.buttonMask |= BUTTON1;
113
+ this._batch.push(this._button('buttonpress', pt, serial, before, true));
114
+ }
115
+ });
116
+ t.on('motion', (time, id, x, y) => {
117
+ const pt = this.points.get(id);
118
+ if (!pt) return;
119
+ pt.x = x;
120
+ pt.y = y;
121
+ pt.time = time;
122
+ this._raw('touchmove', pt, this.seat.lastSerial);
123
+ if (this.emulated === id) {
124
+ this._batch.push({
125
+ type: 'motion',
126
+ time,
127
+ x,
128
+ y,
129
+ surface: pt.surface,
130
+ device: this._device(pt, true),
131
+ });
132
+ }
133
+ });
134
+ t.on('up', (serial, time, id) => {
135
+ const pt = this.points.get(id);
136
+ if (!pt) return;
137
+ this.seat.lastSerial = serial;
138
+ pt.time = time;
139
+ this.points.delete(id);
140
+ this._raw('touchend', pt, serial);
141
+ if (this.emulated === id) this._endEmulation(pt, serial);
142
+ });
143
+ t.on('cancel', () => {
144
+ // Every point is gone at once, and no frame need follow: finalise
145
+ // them here, the emulated one with its release.
146
+ const gone = [...this.points.values()];
147
+ this.points.clear();
148
+ const serial = this.seat.lastSerial;
149
+ for (const pt of gone) {
150
+ this._raw('touchcancel', pt, serial);
151
+ if (this.emulated === pt.id) this._endEmulation(pt, serial);
152
+ }
153
+ this._flush();
154
+ });
155
+ // The contact's shape (v6): an ellipse, in surface-local units. It can
156
+ // arrive after the point's own event within the frame, so a raw event
157
+ // still waiting in the batch is brought up to date too.
158
+ t.on('shape', (id, major, minor) => {
159
+ const pt = this.points.get(id);
160
+ if (!pt) return;
161
+ pt.major = major;
162
+ pt.minor = minor;
163
+ for (const ev of this._batch) {
164
+ if (ev.touchId === id) {
165
+ ev.radiusX = major / 2;
166
+ ev.radiusY = minor / 2;
167
+ }
168
+ }
169
+ });
170
+ t.on('orientation', (id, orientation) => {
171
+ const pt = this.points.get(id);
172
+ if (!pt) return;
173
+ pt.orientation = orientation;
174
+ for (const ev of this._batch)
175
+ if (ev.touchId === id) ev.rotationAngle = orientation;
176
+ });
177
+ t.on('frame', () => this._flush());
178
+ }
179
+
180
+ /** The touchscreen went away: whatever was down is cancelled. */
181
+ _release() {
182
+ const t = this.touch;
183
+ if (!t) return;
184
+ this.touch = null;
185
+ t.emit('cancel');
186
+ t.removeAllListeners();
187
+ // `release` is v3; a compositor older than that just sees us stop asking
188
+ t.$.release?.();
189
+ }
190
+
191
+ /**
192
+ * A raw event for the point, with a snapshot of every active point and
193
+ * — as a button event carries it — the buttons held *before* it, so a
194
+ * touchstart does not yet show the press it is about to emulate.
195
+ */
196
+ _raw(type, pt, serial) {
197
+ this._batch.push({
198
+ type,
199
+ id: pt.id,
200
+ touchId: pt.id,
201
+ serial,
202
+ time: pt.time,
203
+ surface: pt.surface,
204
+ x: pt.x,
205
+ y: pt.y,
206
+ state: this.seat.buttonMask,
207
+ radiusX: pt.major / 2,
208
+ radiusY: pt.minor / 2,
209
+ rotationAngle: pt.orientation,
210
+ touches: [...this.points.values()].map((p) => ({
211
+ id: p.id,
212
+ surface: p.surface,
213
+ x: p.x,
214
+ y: p.y,
215
+ })),
216
+ });
217
+ }
218
+
219
+ /** The device tag the emulated events carry. */
220
+ _device(pt, down) {
221
+ // the DOM's answer for hardware without pressure: half while in contact
222
+ return { pointerType: 'touch', touchId: pt.id, pressure: down ? 0.5 : 0 };
223
+ }
224
+
225
+ _button(type, pt, serial, state, down) {
226
+ return {
227
+ type,
228
+ serial,
229
+ time: pt.time,
230
+ button: 1,
231
+ evdev: BTN_TOUCH,
232
+ x: pt.x,
233
+ y: pt.y,
234
+ surface: pt.surface,
235
+ state,
236
+ device: this._device(pt, down),
237
+ };
238
+ }
239
+
240
+ /**
241
+ * The emulating finger lifted: release, leave — and if a real pointer is
242
+ * over one of our surfaces, it is the pointer again, so `input.js` gets
243
+ * its enter back and its window-under-the-pointer is right.
244
+ */
245
+ _endEmulation(pt, serial) {
246
+ const seat = this.seat;
247
+ this.emulated = null;
248
+ const before = seat.buttonMask;
249
+ seat.buttonMask &= ~BUTTON1;
250
+ this._batch.push(this._button('buttonrelease', pt, serial, before, false));
251
+ this._batch.push({
252
+ type: 'leave',
253
+ serial,
254
+ surface: pt.surface,
255
+ device: this._device(pt, false),
256
+ });
257
+ if (seat.pointerSurface != null) {
258
+ this._batch.push({
259
+ type: 'enter',
260
+ serial,
261
+ surface: seat.pointerSurface,
262
+ x: seat.pointerX,
263
+ y: seat.pointerY,
264
+ });
265
+ }
266
+ }
267
+
268
+ _flush() {
269
+ const batch = this._batch;
270
+ if (batch.length === 0) return;
271
+ this._batch = [];
272
+ for (const ev of batch) this.seat.emit(ev.type, ev);
273
+ this.seat.emit('frame', batch);
274
+ }
275
+
276
+ destroy() {
277
+ this.seat.off('capabilities', this._onCapabilities);
278
+ this.points.clear();
279
+ this._batch.length = 0;
280
+ const t = this.touch;
281
+ this.touch = null;
282
+ t?.removeAllListeners();
283
+ }
284
+ }