@gtkx/testing 1.0.0-rc.4 → 1.1.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 (212) hide show
  1. package/README.md +5 -5
  2. package/dist/accessible-native.d.ts +16 -0
  3. package/dist/accessible-native.d.ts.map +1 -0
  4. package/dist/accessible-native.js +206 -0
  5. package/dist/accessible-native.js.map +1 -0
  6. package/dist/act.d.ts +1 -3
  7. package/dist/act.d.ts.map +1 -1
  8. package/dist/act.js +1 -1
  9. package/dist/act.js.map +1 -1
  10. package/dist/build-queries.d.ts +27 -10
  11. package/dist/build-queries.d.ts.map +1 -1
  12. package/dist/build-queries.js +22 -24
  13. package/dist/build-queries.js.map +1 -1
  14. package/dist/cleanup-registry.d.ts +1 -1
  15. package/dist/cleanup-registry.d.ts.map +1 -1
  16. package/dist/cleanup-registry.js.map +1 -1
  17. package/dist/config.d.ts +8 -1
  18. package/dist/config.d.ts.map +1 -1
  19. package/dist/config.js +1 -0
  20. package/dist/config.js.map +1 -1
  21. package/dist/errors.d.ts +10 -1
  22. package/dist/errors.d.ts.map +1 -1
  23. package/dist/errors.js +10 -1
  24. package/dist/errors.js.map +1 -1
  25. package/dist/fire-event.d.ts +35 -6
  26. package/dist/fire-event.d.ts.map +1 -1
  27. package/dist/fire-event.js +23 -7
  28. package/dist/fire-event.js.map +1 -1
  29. package/dist/frame-sync.d.ts +3 -2
  30. package/dist/frame-sync.d.ts.map +1 -1
  31. package/dist/frame-sync.js +19 -9
  32. package/dist/frame-sync.js.map +1 -1
  33. package/dist/harness-window.d.ts +5 -0
  34. package/dist/harness-window.d.ts.map +1 -0
  35. package/dist/harness-window.js +17 -0
  36. package/dist/harness-window.js.map +1 -0
  37. package/dist/index.d.ts +14 -7
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +9 -5
  40. package/dist/index.js.map +1 -1
  41. package/dist/internal.d.ts +5 -0
  42. package/dist/internal.d.ts.map +1 -0
  43. package/dist/internal.js +5 -0
  44. package/dist/internal.js.map +1 -0
  45. package/dist/matchers.d.ts +88 -46
  46. package/dist/matchers.d.ts.map +1 -1
  47. package/dist/matchers.js +178 -20
  48. package/dist/matchers.js.map +1 -1
  49. package/dist/pretty-format.d.ts +2 -0
  50. package/dist/pretty-format.d.ts.map +1 -0
  51. package/dist/pretty-format.js +2 -0
  52. package/dist/pretty-format.js.map +1 -0
  53. package/dist/pretty-widget.d.ts +5 -2
  54. package/dist/pretty-widget.d.ts.map +1 -1
  55. package/dist/pretty-widget.js +75 -57
  56. package/dist/pretty-widget.js.map +1 -1
  57. package/dist/production.d.ts +8 -0
  58. package/dist/production.d.ts.map +1 -0
  59. package/dist/production.js +34 -0
  60. package/dist/production.js.map +1 -0
  61. package/dist/queries.d.ts +98 -56
  62. package/dist/queries.d.ts.map +1 -1
  63. package/dist/queries.js +123 -83
  64. package/dist/queries.js.map +1 -1
  65. package/dist/query-helpers.d.ts +44 -0
  66. package/dist/query-helpers.d.ts.map +1 -0
  67. package/dist/query-helpers.js +57 -0
  68. package/dist/query-helpers.js.map +1 -0
  69. package/dist/render-children.d.ts +9 -0
  70. package/dist/render-children.d.ts.map +1 -0
  71. package/dist/render-children.js +11 -0
  72. package/dist/render-children.js.map +1 -0
  73. package/dist/render.d.ts +12 -1
  74. package/dist/render.d.ts.map +1 -1
  75. package/dist/render.js +52 -16
  76. package/dist/render.js.map +1 -1
  77. package/dist/role-helpers.d.ts +12 -3
  78. package/dist/role-helpers.d.ts.map +1 -1
  79. package/dist/role-helpers.js +15 -5
  80. package/dist/role-helpers.js.map +1 -1
  81. package/dist/role-naming.d.ts +5 -0
  82. package/dist/role-naming.d.ts.map +1 -0
  83. package/dist/role-naming.js +96 -0
  84. package/dist/role-naming.js.map +1 -0
  85. package/dist/screenshot.d.ts +12 -20
  86. package/dist/screenshot.d.ts.map +1 -1
  87. package/dist/screenshot.js +179 -93
  88. package/dist/screenshot.js.map +1 -1
  89. package/dist/timers.d.ts +9 -0
  90. package/dist/timers.d.ts.map +1 -0
  91. package/dist/timers.js +21 -0
  92. package/dist/timers.js.map +1 -0
  93. package/dist/traversal.d.ts +7 -1
  94. package/dist/traversal.d.ts.map +1 -1
  95. package/dist/traversal.js +40 -6
  96. package/dist/traversal.js.map +1 -1
  97. package/dist/types.d.ts +32 -15
  98. package/dist/types.d.ts.map +1 -1
  99. package/dist/types.js.map +1 -1
  100. package/dist/user-event/adjustment.d.ts +3 -0
  101. package/dist/user-event/adjustment.d.ts.map +1 -1
  102. package/dist/user-event/adjustment.js +25 -3
  103. package/dist/user-event/adjustment.js.map +1 -1
  104. package/dist/user-event/click.d.ts +44 -8
  105. package/dist/user-event/click.d.ts.map +1 -1
  106. package/dist/user-event/click.js +176 -44
  107. package/dist/user-event/click.js.map +1 -1
  108. package/dist/user-event/column-header-click.d.ts +4 -0
  109. package/dist/user-event/column-header-click.d.ts.map +1 -0
  110. package/dist/user-event/column-header-click.js +55 -0
  111. package/dist/user-event/column-header-click.js.map +1 -0
  112. package/dist/user-event/event-wrapper.d.ts.map +1 -1
  113. package/dist/user-event/event-wrapper.js +34 -20
  114. package/dist/user-event/event-wrapper.js.map +1 -1
  115. package/dist/user-event/index.d.ts +80 -13
  116. package/dist/user-event/index.d.ts.map +1 -1
  117. package/dist/user-event/index.js +44 -26
  118. package/dist/user-event/index.js.map +1 -1
  119. package/dist/user-event/indexed-children.d.ts +10 -0
  120. package/dist/user-event/indexed-children.d.ts.map +1 -0
  121. package/dist/user-event/indexed-children.js +50 -0
  122. package/dist/user-event/indexed-children.js.map +1 -0
  123. package/dist/user-event/keyboard.d.ts.map +1 -1
  124. package/dist/user-event/keyboard.js +115 -31
  125. package/dist/user-event/keyboard.js.map +1 -1
  126. package/dist/user-event/list-row-click.d.ts +4 -0
  127. package/dist/user-event/list-row-click.d.ts.map +1 -0
  128. package/dist/user-event/list-row-click.js +38 -0
  129. package/dist/user-event/list-row-click.js.map +1 -0
  130. package/dist/user-event/native-click.d.ts +6 -0
  131. package/dist/user-event/native-click.d.ts.map +1 -0
  132. package/dist/user-event/native-click.js +36 -0
  133. package/dist/user-event/native-click.js.map +1 -0
  134. package/dist/user-event/notebook-tab-click.d.ts +5 -0
  135. package/dist/user-event/notebook-tab-click.d.ts.map +1 -0
  136. package/dist/user-event/notebook-tab-click.js +39 -0
  137. package/dist/user-event/notebook-tab-click.js.map +1 -0
  138. package/dist/user-event/pointer.d.ts +1 -1
  139. package/dist/user-event/pointer.d.ts.map +1 -1
  140. package/dist/user-event/pointer.js +33 -9
  141. package/dist/user-event/pointer.js.map +1 -1
  142. package/dist/user-event/selection.d.ts +11 -8
  143. package/dist/user-event/selection.d.ts.map +1 -1
  144. package/dist/user-event/selection.js +49 -38
  145. package/dist/user-event/selection.js.map +1 -1
  146. package/dist/user-event/text.d.ts +12 -5
  147. package/dist/user-event/text.d.ts.map +1 -1
  148. package/dist/user-event/text.js +151 -46
  149. package/dist/user-event/text.js.map +1 -1
  150. package/dist/wait-for.d.ts.map +1 -1
  151. package/dist/wait-for.js +4 -3
  152. package/dist/wait-for.js.map +1 -1
  153. package/dist/widget-accessible-properties.d.ts +14 -26
  154. package/dist/widget-accessible-properties.d.ts.map +1 -1
  155. package/dist/widget-accessible-properties.js +135 -190
  156. package/dist/widget-accessible-properties.js.map +1 -1
  157. package/dist/widget-getters.d.ts +11 -0
  158. package/dist/widget-getters.d.ts.map +1 -0
  159. package/dist/widget-getters.js +46 -0
  160. package/dist/widget-getters.js.map +1 -0
  161. package/dist/window-state.d.ts +10 -0
  162. package/dist/window-state.d.ts.map +1 -0
  163. package/dist/window-state.js +41 -0
  164. package/dist/window-state.js.map +1 -0
  165. package/dist/within.d.ts +3 -2
  166. package/dist/within.d.ts.map +1 -1
  167. package/dist/within.js +3 -2
  168. package/dist/within.js.map +1 -1
  169. package/package.json +21 -8
  170. package/src/accessible-native.ts +333 -0
  171. package/src/act.ts +1 -1
  172. package/src/build-queries.ts +47 -41
  173. package/src/cleanup-registry.ts +1 -1
  174. package/src/config.ts +10 -1
  175. package/src/errors.ts +12 -1
  176. package/src/fire-event.ts +61 -8
  177. package/src/frame-sync.ts +30 -9
  178. package/src/harness-window.ts +23 -0
  179. package/src/index.ts +18 -11
  180. package/src/internal.ts +12 -0
  181. package/src/matchers.ts +457 -72
  182. package/src/pretty-format.ts +1 -0
  183. package/src/pretty-widget.ts +98 -70
  184. package/src/production.ts +51 -0
  185. package/src/queries.ts +127 -89
  186. package/src/query-helpers.ts +97 -0
  187. package/src/render-children.ts +25 -0
  188. package/src/render.tsx +77 -17
  189. package/src/role-helpers.ts +16 -5
  190. package/src/role-naming.ts +99 -0
  191. package/src/screenshot.ts +266 -104
  192. package/src/timers.ts +31 -0
  193. package/src/traversal.ts +66 -6
  194. package/src/types.ts +34 -17
  195. package/src/user-event/adjustment.ts +31 -3
  196. package/src/user-event/click.ts +248 -52
  197. package/src/user-event/column-header-click.ts +76 -0
  198. package/src/user-event/event-wrapper.ts +41 -23
  199. package/src/user-event/index.ts +130 -40
  200. package/src/user-event/indexed-children.ts +75 -0
  201. package/src/user-event/keyboard.ts +161 -43
  202. package/src/user-event/list-row-click.ts +54 -0
  203. package/src/user-event/native-click.ts +51 -0
  204. package/src/user-event/notebook-tab-click.ts +57 -0
  205. package/src/user-event/pointer.ts +48 -9
  206. package/src/user-event/selection.ts +67 -41
  207. package/src/user-event/text.ts +192 -46
  208. package/src/wait-for.ts +4 -4
  209. package/src/widget-accessible-properties.ts +183 -230
  210. package/src/widget-getters.ts +85 -0
  211. package/src/window-state.ts +70 -0
  212. package/src/within.ts +3 -2
@@ -1,7 +1,14 @@
1
+ import * as Gdk from "@gtkx/gi/gdk";
1
2
  import * as Gtk from "@gtkx/gi/gtk";
2
- import { getOrCreateControllers, queryController } from "./controller.js";
3
+ import { hasSignalListener } from "@gtkx/runtime/internal";
4
+ import { callBooleanGetter, getCallableMethod, hasWidgetMethod } from "../widget-getters.js";
5
+ import { queryAllControllers } from "./controller.js";
3
6
  import { wrapEvent } from "./event-wrapper.js";
4
- const getPressPoint = (widget) => {
7
+ import { hasIndexedChildren, selectContainerChild, SELECTED_PROBE, unselectOtherChildren } from "./indexed-children.js";
8
+ import { isClickTransparent, nativeClickFor } from "./native-click.js";
9
+ const CLICK_SIGNALS = ["pressed", "released"];
10
+ const PRIMARY_BUTTONS = new Set([0, Gdk.BUTTON_PRIMARY]);
11
+ const getCenterPoint = (widget) => {
5
12
  const width = widget.getWidth();
6
13
  const height = widget.getHeight();
7
14
  if (width > 0 && height > 0) {
@@ -9,35 +16,139 @@ const getPressPoint = (widget) => {
9
16
  }
10
17
  return { x: 0, y: 0 };
11
18
  };
12
- const emitGesture = (widget, controllers, nPress, signal) => {
13
- const { x, y } = getPressPoint(widget);
19
+ const getClickPoint = (clicked, carrier) => {
20
+ if (clicked === carrier) {
21
+ return getCenterPoint(clicked);
22
+ }
23
+ const [isComputed, bounds] = clicked.computeBounds(carrier);
24
+ if (!isComputed) {
25
+ return getCenterPoint(carrier);
26
+ }
27
+ return { x: bounds.getX() + bounds.getWidth() / 2, y: bounds.getY() + bounds.getHeight() / 2 };
28
+ };
29
+ const emitGesture = (point, controllers, nPress, signal) => {
14
30
  for (const controller of controllers) {
15
- controller.emit(signal, nPress, x, y);
31
+ controller.emit(signal, nPress, point.x, point.y);
16
32
  }
17
33
  };
18
- const emitPress = (widget, controllers, nPress) => {
19
- emitGesture(widget, controllers, nPress, "pressed");
34
+ const emitClickPhase = (widget, controllers, nPress, phase) => {
35
+ emitGesture(getCenterPoint(widget), controllers, nPress, phase);
20
36
  };
21
- const emitRelease = (widget, controllers, nPress) => {
22
- emitGesture(widget, controllers, nPress, "released");
37
+ const emitSitePhase = (sites, nPress, phase) => {
38
+ for (const site of sites) {
39
+ emitGesture(site.point, site.gestures, nPress, phase);
40
+ }
23
41
  };
24
- const emitClickSequence = (widget, target, nPress) => wrapEvent(widget, () => {
25
- const controllers = getOrCreateControllers(target, Gtk.GestureClick);
42
+ const emitClickSequence = (sites, nPress) => {
26
43
  for (let i = 1; i <= nPress; i++) {
27
- emitPress(target, controllers, i);
28
- emitRelease(target, controllers, i);
44
+ emitSitePhase(sites, i, "pressed");
45
+ emitSitePhase(sites, i, "released");
29
46
  }
30
- });
31
- const findClickableAncestor = (widget) => {
32
- let current = widget.getParent();
33
- while (current) {
34
- if (current instanceof Gtk.Button || queryController(current, Gtk.GestureClick) !== null) {
35
- return current;
36
- }
37
- current = current.getParent();
47
+ };
48
+ const containerFor = (widget) => {
49
+ const parent = widget.getParent();
50
+ return parent !== null && hasWidgetMethod(widget, SELECTED_PROBE) && hasIndexedChildren(parent) ? parent : null;
51
+ };
52
+ const hasClickHandlers = (gesture) => hasSignalListener(gesture, CLICK_SIGNALS);
53
+ const isInternalGesture = (gesture) => !hasSignalListener(gesture);
54
+ const isPrimaryGesture = (gesture) => PRIMARY_BUTTONS.has(gesture.getButton());
55
+ const clickGestures = (widget) => queryAllControllers(widget, Gtk.GestureClick).filter((gesture) => isPrimaryGesture(gesture));
56
+ const getAuthoredClickGestures = (widget) => clickGestures(widget).filter((gesture) => hasClickHandlers(gesture));
57
+ const isClaimingTarget = (widget) => widget instanceof Gtk.Button || containerFor(widget) !== null;
58
+ const gestureTargetFor = (widget, isInternalAllowed) => {
59
+ const gestures = clickGestures(widget);
60
+ if (isClaimingTarget(widget)) {
61
+ return { widget, container: containerFor(widget), gestures, isClaiming: true, native: null };
62
+ }
63
+ const authored = gestures.filter((gesture) => hasClickHandlers(gesture));
64
+ if (authored.length > 0) {
65
+ return { widget, container: null, gestures: authored, isClaiming: false, native: null };
66
+ }
67
+ if (isInternalAllowed && gestures.some((gesture) => isInternalGesture(gesture))) {
68
+ return { widget, container: null, gestures, isClaiming: true, native: null };
38
69
  }
39
70
  return null;
40
71
  };
72
+ const clickTargetFor = (widget, scope) => {
73
+ if (isClickTransparent(widget)) {
74
+ return null;
75
+ }
76
+ const native = nativeClickFor(widget, scope.isClicked);
77
+ if (native !== null) {
78
+ return { widget, container: null, gestures: getAuthoredClickGestures(widget), isClaiming: true, native };
79
+ }
80
+ return gestureTargetFor(widget, scope.isInternalAllowed);
81
+ };
82
+ const isSelfClickTarget = (widget) => isClickTransparent(widget) || clickTargetFor(widget, { isClicked: true, isInternalAllowed: false }) !== null;
83
+ const nextClickWidget = (current, target) => target?.isClaiming === true ? null : current.getParent();
84
+ const collectClickTargets = (widget) => {
85
+ const targets = [];
86
+ let current = widget;
87
+ while (current !== null) {
88
+ const isClicked = current === widget;
89
+ const scope = { isClicked, isInternalAllowed: !isClicked && targets.length === 0 };
90
+ const target = clickTargetFor(current, scope);
91
+ const next = nextClickWidget(current, target);
92
+ if (target !== null) {
93
+ targets.push(target);
94
+ }
95
+ current = next;
96
+ }
97
+ return targets;
98
+ };
99
+ const targetSites = (clicked, target) => {
100
+ const { container } = target;
101
+ const site = { gestures: target.gestures, point: getClickPoint(clicked, target.widget) };
102
+ if (container === null) {
103
+ return [site];
104
+ }
105
+ return [site, { gestures: getAuthoredClickGestures(container), point: getClickPoint(clicked, container) }];
106
+ };
107
+ const isSingleClickActivating = (container) => callBooleanGetter(container, "getActivateOnSingleClick") ?? true;
108
+ const isMultipleSelection = (container) => getCallableMethod(container, "getSelectionMode")?.() === Gtk.SelectionMode.MULTIPLE;
109
+ const isChildSelectable = (child) => callBooleanGetter(child, "getSelectable") ?? true;
110
+ const replaceContainerSelection = (container, child) => {
111
+ if (!isChildSelectable(child)) {
112
+ return;
113
+ }
114
+ selectContainerChild(container, child);
115
+ if (isMultipleSelection(container)) {
116
+ unselectOtherChildren(container, child);
117
+ }
118
+ };
119
+ const isActivatedByClick = (container, nPress) => isSingleClickActivating(container) || nPress > 1;
120
+ const isSelectionReplacedByClick = (container, nPress) => nPress > 1 || !isSingleClickActivating(container);
121
+ const applyContainerOutcome = (target, nPress) => {
122
+ const { container, widget } = target;
123
+ if (container === null || widget.getParent() !== container) {
124
+ return;
125
+ }
126
+ if (isActivatedByClick(container, nPress)) {
127
+ widget.activate();
128
+ }
129
+ if (isSelectionReplacedByClick(container, nPress)) {
130
+ replaceContainerSelection(container, widget);
131
+ }
132
+ };
133
+ const applyClickOutcome = (target, nPress) => {
134
+ if (target.native === null) {
135
+ applyContainerOutcome(target, nPress);
136
+ return;
137
+ }
138
+ target.native(target.widget, nPress);
139
+ };
140
+ const applyClickOutcomes = (targets, nPress) => {
141
+ for (const target of targets) {
142
+ applyClickOutcome(target, nPress);
143
+ }
144
+ };
145
+ const deliverClick = (widget, nPress) => wrapEvent(widget, () => {
146
+ const targets = collectClickTargets(widget);
147
+ const sites = targets.flatMap((target) => targetSites(widget, target));
148
+ emitClickSequence(sites, nPress);
149
+ applyClickOutcomes(targets, nPress);
150
+ });
151
+ /* eslint-disable-next-line unicorn/consistent-boolean-name -- the boolean reports whether activation succeeded */
41
152
  const tryActivate = async (widget) => {
42
153
  if (widget.getAccessibleRole() === Gtk.AccessibleRole.LABEL) {
43
154
  return false;
@@ -49,32 +160,53 @@ const tryActivate = async (widget) => {
49
160
  return isActivated;
50
161
  };
51
162
  /**
52
- * Presses and releases a Gtk.Button, flips a Gtk.Switch, and otherwise activates the widget,
53
- * falling back to a click gesture on the nearest Gtk.Button or click-gesture ancestor when
54
- * activation does nothing. A widget with the label role is never activated.
163
+ * Activates a widget that neither claims the click nor carries a click gesture of its own, and
164
+ * otherwise delivers a press and release. The press travels outwards from the clicked widget
165
+ * through every widget carrying a click gesture with a pressed or released handler, the way GTK
166
+ * hands the same press to each of them, and stops at the first Gtk.Button or indexed child of a
167
+ * list box or flow box, which claims it. A gesture GTK attached itself takes the press only when no
168
+ * widget below it handles one, and stops it there, so an expander or a notebook tab nested in a row
169
+ * opens instead of activating the row. Coordinates are the clicked widget's position in each
170
+ * carrier, so a gesture the container of an indexed child carries reads the child's position rather
171
+ * than the container's center. An indexed child that the press reaches is then activated, or
172
+ * exclusively selected when its container does not activate on a single click. A widget with the
173
+ * label role is never activated, but does consume the click when it carries a gesture of its own.
174
+ *
175
+ * The press also stops at a widget whose click GTK4 implements in C on a gesture it attached
176
+ * itself, reading a GdkEvent that off-screen synthesis cannot produce. Gestures that widget carries
177
+ * of its own still take the press and release, the way GTK hands them the press before its own
178
+ * gesture claims it, and the same outcome is then applied through the public action GTK's own
179
+ * handler invokes: a list, grid, or column-view row is focused and selected, and activated as well
180
+ * on a second press or when its view activates on a single click; an expandable tree expander
181
+ * toggles its expansion, once per press, and only when it is the widget clicked, so a click on its
182
+ * child falls through to the enclosing row; a notebook tab, clicked directly or through its label,
183
+ * focuses its notebook and switches to its page; a column header sorts by its column. Sorting goes
184
+ * through Gtk.ColumnView.sortByColumn, so the primary sort column and order match what a pointer
185
+ * produces while previously sorted columns are dropped rather than kept as secondary keys. A
186
+ * column-view cell and the row that carries the column headers stand in the way of the click rather
187
+ * than taking it, so a click on either reaches the row or the view behind it.
55
188
  */
56
189
  const click = async (widget) => {
57
- if (widget instanceof Gtk.Button) {
58
- await emitClickSequence(widget, widget, 1);
59
- return;
60
- }
61
- if (widget instanceof Gtk.Switch) {
62
- await wrapEvent(widget, () => {
63
- widget.setActive(!widget.getActive());
64
- });
65
- return;
66
- }
67
- if (await tryActivate(widget)) {
190
+ if (!isSelfClickTarget(widget) && (await tryActivate(widget))) {
68
191
  return;
69
192
  }
70
- const target = findClickableAncestor(widget);
71
- if (target) {
72
- await emitClickSequence(widget, target, 1);
73
- }
193
+ await deliverClick(widget, 1);
74
194
  };
75
- /** Emits a two-press click gesture at the widget's center, adding a Gtk.GestureClick when it has none. */
76
- const dblClick = (widget) => emitClickSequence(widget, widget, 2);
77
- /** Emits a three-press click gesture at the widget's center, adding a Gtk.GestureClick when it has none. */
78
- const tripleClick = (widget) => emitClickSequence(widget, widget, 3);
79
- export { emitPress, emitRelease, click, dblClick, tripleClick };
195
+ /**
196
+ * Delivers a two-press click gesture the way {@link click} delivers a single press, without trying
197
+ * activation first. A list box row or flow box child the presses reach, clicked directly or through
198
+ * a descendant, is activated and exclusively selected, as GTK's double-click path does whether or
199
+ * not the container activates on a single click. A widget whose click GTK4 implements itself
200
+ * receives that outcome once per press, so a list, grid, or column-view row is selected and then
201
+ * activated by the second press, a tree expander ends back where it started, a notebook tab stays on
202
+ * the page the first press opened, and a column header sorts and then inverts its order.
203
+ */
204
+ const dblClick = (widget) => deliverClick(widget, 2);
205
+ /**
206
+ * Delivers a three-press click gesture the same way a double click is delivered, applying the same
207
+ * outcome to a list box row or flow box child the presses reach, and applying the outcome GTK4
208
+ * implements itself once per press to a row, tree expander, notebook tab, or column header.
209
+ */
210
+ const tripleClick = (widget) => deliverClick(widget, 3);
211
+ export { clickGestures, emitClickPhase, getAuthoredClickGestures, click, dblClick, tripleClick };
80
212
  //# sourceMappingURL=click.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"click.js","sourceRoot":"","sources":["../../src/user-event/click.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { getOrCreateControllers, queryController } from \"./controller.js\";\nimport { wrapEvent } from \"./event-wrapper.js\";\n\nconst getPressPoint = (widget: Gtk.Widget): { x: number; y: number } => {\n const width = widget.getWidth();\n const height = widget.getHeight();\n\n if (width > 0 && height > 0) {\n return { x: width / 2, y: height / 2 };\n }\n\n return { x: 0, y: 0 };\n};\n\nconst emitGesture = (widget: Gtk.Widget, controllers: Gtk.GestureClick[], nPress: number, signal: string): void => {\n const { x, y } = getPressPoint(widget);\n\n for (const controller of controllers) {\n controller.emit(signal, nPress, x, y);\n }\n};\n\nconst emitPress = (widget: Gtk.Widget, controllers: Gtk.GestureClick[], nPress: number): void => {\n emitGesture(widget, controllers, nPress, \"pressed\");\n};\n\nconst emitRelease = (widget: Gtk.Widget, controllers: Gtk.GestureClick[], nPress: number): void => {\n emitGesture(widget, controllers, nPress, \"released\");\n};\n\nconst emitClickSequence = (widget: Gtk.Widget, target: Gtk.Widget, nPress: number): Promise<void> =>\n wrapEvent(widget, () => {\n const controllers = getOrCreateControllers(target, Gtk.GestureClick);\n\n for (let i = 1; i <= nPress; i++) {\n emitPress(target, controllers, i);\n emitRelease(target, controllers, i);\n }\n });\n\nconst findClickableAncestor = (widget: Gtk.Widget): Gtk.Widget | null => {\n let current = widget.getParent();\n\n while (current) {\n if (current instanceof Gtk.Button || queryController(current, Gtk.GestureClick) !== null) {\n return current;\n }\n\n current = current.getParent();\n }\n\n return null;\n};\n\nconst tryActivate = async (widget: Gtk.Widget): Promise<boolean> => {\n if (widget.getAccessibleRole() === Gtk.AccessibleRole.LABEL) {\n return false;\n }\n\n let isActivated = false;\n\n await wrapEvent(widget, () => {\n isActivated = widget.activate();\n });\n\n return isActivated;\n};\n\n/**\n * Presses and releases a Gtk.Button, flips a Gtk.Switch, and otherwise activates the widget,\n * falling back to a click gesture on the nearest Gtk.Button or click-gesture ancestor when\n * activation does nothing. A widget with the label role is never activated.\n */\nconst click = async (widget: Gtk.Widget): Promise<void> => {\n if (widget instanceof Gtk.Button) {\n await emitClickSequence(widget, widget, 1);\n\n return;\n }\n\n if (widget instanceof Gtk.Switch) {\n await wrapEvent(widget, () => {\n widget.setActive(!widget.getActive());\n });\n\n return;\n }\n\n if (await tryActivate(widget)) {\n return;\n }\n\n const target = findClickableAncestor(widget);\n\n if (target) {\n await emitClickSequence(widget, target, 1);\n }\n};\n\n/** Emits a two-press click gesture at the widget's center, adding a Gtk.GestureClick when it has none. */\nconst dblClick = (widget: Gtk.Widget): Promise<void> => emitClickSequence(widget, widget, 2);\n/** Emits a three-press click gesture at the widget's center, adding a Gtk.GestureClick when it has none. */\nconst tripleClick = (widget: Gtk.Widget): Promise<void> => emitClickSequence(widget, widget, 3);\n\nexport { emitPress, emitRelease, click, dblClick, tripleClick };\n"]}
1
+ {"version":3,"file":"click.js","sourceRoot":"","sources":["../../src/user-event/click.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gdk from \"@gtkx/gi/gdk\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { hasSignalListener } from \"@gtkx/runtime/internal\";\nimport { callBooleanGetter, getCallableMethod, hasWidgetMethod } from \"../widget-getters.js\";\nimport { queryAllControllers } from \"./controller.js\";\nimport { wrapEvent } from \"./event-wrapper.js\";\nimport { hasIndexedChildren, selectContainerChild, SELECTED_PROBE, unselectOtherChildren } from \"./indexed-children.js\";\nimport { isClickTransparent, type NativeClick, nativeClickFor } from \"./native-click.js\";\n\ntype PressPoint = { x: number; y: number };\ntype ClickPhase = \"pressed\" | \"released\";\ntype ClickSite = { gestures: Gtk.GestureClick[]; point: PressPoint };\ntype ClickScope = { isClicked: boolean; isInternalAllowed: boolean };\n\ntype ClickTarget = {\n widget: Gtk.Widget;\n container: Gtk.Widget | null;\n gestures: Gtk.GestureClick[];\n isClaiming: boolean;\n native: NativeClick | null;\n};\n\nconst CLICK_SIGNALS = [\"pressed\", \"released\"];\nconst PRIMARY_BUTTONS: Set<number> = new Set([0, Gdk.BUTTON_PRIMARY]);\n\nconst getCenterPoint = (widget: Gtk.Widget): PressPoint => {\n const width = widget.getWidth();\n const height = widget.getHeight();\n\n if (width > 0 && height > 0) {\n return { x: width / 2, y: height / 2 };\n }\n\n return { x: 0, y: 0 };\n};\n\nconst getClickPoint = (clicked: Gtk.Widget, carrier: Gtk.Widget): PressPoint => {\n if (clicked === carrier) {\n return getCenterPoint(clicked);\n }\n\n const [isComputed, bounds] = clicked.computeBounds(carrier);\n\n if (!isComputed) {\n return getCenterPoint(carrier);\n }\n\n return { x: bounds.getX() + bounds.getWidth() / 2, y: bounds.getY() + bounds.getHeight() / 2 };\n};\n\nconst emitGesture = (point: PressPoint, controllers: Gtk.GestureClick[], nPress: number, signal: string): void => {\n for (const controller of controllers) {\n controller.emit(signal, nPress, point.x, point.y);\n }\n};\n\nconst emitClickPhase = (\n widget: Gtk.Widget,\n controllers: Gtk.GestureClick[],\n nPress: number,\n phase: ClickPhase,\n): void => {\n emitGesture(getCenterPoint(widget), controllers, nPress, phase);\n};\n\nconst emitSitePhase = (sites: ClickSite[], nPress: number, phase: ClickPhase): void => {\n for (const site of sites) {\n emitGesture(site.point, site.gestures, nPress, phase);\n }\n};\n\nconst emitClickSequence = (sites: ClickSite[], nPress: number): void => {\n for (let i = 1; i <= nPress; i++) {\n emitSitePhase(sites, i, \"pressed\");\n emitSitePhase(sites, i, \"released\");\n }\n};\n\nconst containerFor = (widget: Gtk.Widget): Gtk.Widget | null => {\n const parent = widget.getParent();\n\n return parent !== null && hasWidgetMethod(widget, SELECTED_PROBE) && hasIndexedChildren(parent) ? parent : null;\n};\n\nconst hasClickHandlers = (gesture: Gtk.GestureClick): boolean => hasSignalListener(gesture, CLICK_SIGNALS);\nconst isInternalGesture = (gesture: Gtk.GestureClick): boolean => !hasSignalListener(gesture);\nconst isPrimaryGesture = (gesture: Gtk.GestureClick): boolean => PRIMARY_BUTTONS.has(gesture.getButton());\n\nconst clickGestures = (widget: Gtk.Widget): Gtk.GestureClick[] =>\n queryAllControllers(widget, Gtk.GestureClick).filter((gesture) => isPrimaryGesture(gesture));\n\nconst getAuthoredClickGestures = (widget: Gtk.Widget): Gtk.GestureClick[] =>\n clickGestures(widget).filter((gesture) => hasClickHandlers(gesture));\n\nconst isClaimingTarget = (widget: Gtk.Widget): boolean =>\n widget instanceof Gtk.Button || containerFor(widget) !== null;\n\nconst gestureTargetFor = (widget: Gtk.Widget, isInternalAllowed: boolean): ClickTarget | null => {\n const gestures = clickGestures(widget);\n\n if (isClaimingTarget(widget)) {\n return { widget, container: containerFor(widget), gestures, isClaiming: true, native: null };\n }\n\n const authored = gestures.filter((gesture) => hasClickHandlers(gesture));\n\n if (authored.length > 0) {\n return { widget, container: null, gestures: authored, isClaiming: false, native: null };\n }\n\n if (isInternalAllowed && gestures.some((gesture) => isInternalGesture(gesture))) {\n return { widget, container: null, gestures, isClaiming: true, native: null };\n }\n\n return null;\n};\n\nconst clickTargetFor = (widget: Gtk.Widget, scope: ClickScope): ClickTarget | null => {\n if (isClickTransparent(widget)) {\n return null;\n }\n\n const native = nativeClickFor(widget, scope.isClicked);\n\n if (native !== null) {\n return { widget, container: null, gestures: getAuthoredClickGestures(widget), isClaiming: true, native };\n }\n\n return gestureTargetFor(widget, scope.isInternalAllowed);\n};\n\nconst isSelfClickTarget = (widget: Gtk.Widget): boolean =>\n isClickTransparent(widget) || clickTargetFor(widget, { isClicked: true, isInternalAllowed: false }) !== null;\n\nconst nextClickWidget = (current: Gtk.Widget, target: ClickTarget | null): Gtk.Widget | null =>\n target?.isClaiming === true ? null : current.getParent();\n\nconst collectClickTargets = (widget: Gtk.Widget): ClickTarget[] => {\n const targets: ClickTarget[] = [];\n let current: Gtk.Widget | null = widget;\n\n while (current !== null) {\n const isClicked = current === widget;\n const scope = { isClicked, isInternalAllowed: !isClicked && targets.length === 0 };\n const target = clickTargetFor(current, scope);\n const next = nextClickWidget(current, target);\n\n if (target !== null) {\n targets.push(target);\n }\n\n current = next;\n }\n\n return targets;\n};\n\nconst targetSites = (clicked: Gtk.Widget, target: ClickTarget): ClickSite[] => {\n const { container } = target;\n const site = { gestures: target.gestures, point: getClickPoint(clicked, target.widget) };\n\n if (container === null) {\n return [site];\n }\n\n return [site, { gestures: getAuthoredClickGestures(container), point: getClickPoint(clicked, container) }];\n};\n\nconst isSingleClickActivating = (container: Gtk.Widget): boolean =>\n callBooleanGetter(container, \"getActivateOnSingleClick\") ?? true;\n\nconst isMultipleSelection = (container: Gtk.Widget): boolean =>\n getCallableMethod<[], Gtk.SelectionMode>(container, \"getSelectionMode\")?.() === Gtk.SelectionMode.MULTIPLE;\n\nconst isChildSelectable = (child: Gtk.Widget): boolean => callBooleanGetter(child, \"getSelectable\") ?? true;\n\nconst replaceContainerSelection = (container: Gtk.Widget, child: Gtk.Widget): void => {\n if (!isChildSelectable(child)) {\n return;\n }\n\n selectContainerChild(container, child);\n\n if (isMultipleSelection(container)) {\n unselectOtherChildren(container, child);\n }\n};\n\nconst isActivatedByClick = (container: Gtk.Widget, nPress: number): boolean =>\n isSingleClickActivating(container) || nPress > 1;\n\nconst isSelectionReplacedByClick = (container: Gtk.Widget, nPress: number): boolean =>\n nPress > 1 || !isSingleClickActivating(container);\n\nconst applyContainerOutcome = (target: ClickTarget, nPress: number): void => {\n const { container, widget } = target;\n\n if (container === null || widget.getParent() !== container) {\n return;\n }\n\n if (isActivatedByClick(container, nPress)) {\n widget.activate();\n }\n\n if (isSelectionReplacedByClick(container, nPress)) {\n replaceContainerSelection(container, widget);\n }\n};\n\nconst applyClickOutcome = (target: ClickTarget, nPress: number): void => {\n if (target.native === null) {\n applyContainerOutcome(target, nPress);\n\n return;\n }\n\n target.native(target.widget, nPress);\n};\n\nconst applyClickOutcomes = (targets: ClickTarget[], nPress: number): void => {\n for (const target of targets) {\n applyClickOutcome(target, nPress);\n }\n};\n\nconst deliverClick = (widget: Gtk.Widget, nPress: number): Promise<void> =>\n wrapEvent(widget, () => {\n const targets = collectClickTargets(widget);\n const sites = targets.flatMap((target) => targetSites(widget, target));\n emitClickSequence(sites, nPress);\n applyClickOutcomes(targets, nPress);\n });\n\n/* eslint-disable-next-line unicorn/consistent-boolean-name -- the boolean reports whether activation succeeded */\nconst tryActivate = async (widget: Gtk.Widget): Promise<boolean> => {\n if (widget.getAccessibleRole() === Gtk.AccessibleRole.LABEL) {\n return false;\n }\n\n let isActivated = false;\n\n await wrapEvent(widget, () => {\n isActivated = widget.activate();\n });\n\n return isActivated;\n};\n\n/**\n * Activates a widget that neither claims the click nor carries a click gesture of its own, and\n * otherwise delivers a press and release. The press travels outwards from the clicked widget\n * through every widget carrying a click gesture with a pressed or released handler, the way GTK\n * hands the same press to each of them, and stops at the first Gtk.Button or indexed child of a\n * list box or flow box, which claims it. A gesture GTK attached itself takes the press only when no\n * widget below it handles one, and stops it there, so an expander or a notebook tab nested in a row\n * opens instead of activating the row. Coordinates are the clicked widget's position in each\n * carrier, so a gesture the container of an indexed child carries reads the child's position rather\n * than the container's center. An indexed child that the press reaches is then activated, or\n * exclusively selected when its container does not activate on a single click. A widget with the\n * label role is never activated, but does consume the click when it carries a gesture of its own.\n *\n * The press also stops at a widget whose click GTK4 implements in C on a gesture it attached\n * itself, reading a GdkEvent that off-screen synthesis cannot produce. Gestures that widget carries\n * of its own still take the press and release, the way GTK hands them the press before its own\n * gesture claims it, and the same outcome is then applied through the public action GTK's own\n * handler invokes: a list, grid, or column-view row is focused and selected, and activated as well\n * on a second press or when its view activates on a single click; an expandable tree expander\n * toggles its expansion, once per press, and only when it is the widget clicked, so a click on its\n * child falls through to the enclosing row; a notebook tab, clicked directly or through its label,\n * focuses its notebook and switches to its page; a column header sorts by its column. Sorting goes\n * through Gtk.ColumnView.sortByColumn, so the primary sort column and order match what a pointer\n * produces while previously sorted columns are dropped rather than kept as secondary keys. A\n * column-view cell and the row that carries the column headers stand in the way of the click rather\n * than taking it, so a click on either reaches the row or the view behind it.\n */\nconst click = async (widget: Gtk.Widget): Promise<void> => {\n if (!isSelfClickTarget(widget) && (await tryActivate(widget))) {\n return;\n }\n\n await deliverClick(widget, 1);\n};\n\n/**\n * Delivers a two-press click gesture the way {@link click} delivers a single press, without trying\n * activation first. A list box row or flow box child the presses reach, clicked directly or through\n * a descendant, is activated and exclusively selected, as GTK's double-click path does whether or\n * not the container activates on a single click. A widget whose click GTK4 implements itself\n * receives that outcome once per press, so a list, grid, or column-view row is selected and then\n * activated by the second press, a tree expander ends back where it started, a notebook tab stays on\n * the page the first press opened, and a column header sorts and then inverts its order.\n */\nconst dblClick = (widget: Gtk.Widget): Promise<void> => deliverClick(widget, 2);\n/**\n * Delivers a three-press click gesture the same way a double click is delivered, applying the same\n * outcome to a list box row or flow box child the presses reach, and applying the outcome GTK4\n * implements itself once per press to a row, tree expander, notebook tab, or column header.\n */\nconst tripleClick = (widget: Gtk.Widget): Promise<void> => deliverClick(widget, 3);\n\nexport { clickGestures, emitClickPhase, getAuthoredClickGestures, click, dblClick, tripleClick };\n"]}
@@ -0,0 +1,4 @@
1
+ import * as Gtk from "@gtkx/gi/gtk";
2
+ declare const applyHeaderClick: (header: Gtk.Widget, nPress: number) => void;
3
+ export { applyHeaderClick };
4
+ //# sourceMappingURL=column-header-click.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-header-click.d.ts","sourceRoot":"","sources":["../../src/user-event/column-header-click.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AA8DpC,QAAA,MAAM,gBAAgB,GAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,QAAQ,MAAM,KAAG,IAW9D,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,55 @@
1
+ import * as Gtk from "@gtkx/gi/gtk";
2
+ import { ancestorFor, children } from "../traversal.js";
3
+ import { getWidgetTextContent } from "../widget-accessible-properties.js";
4
+ const columnsFor = (view) => {
5
+ const model = view.getColumns();
6
+ const columns = [];
7
+ for (let index = 0; index < model.getNItems(); index++) {
8
+ const column = model.getItem(index);
9
+ if (column instanceof Gtk.ColumnViewColumn) {
10
+ columns.push(column);
11
+ }
12
+ }
13
+ return columns;
14
+ };
15
+ const headerIndexFor = (header) => {
16
+ const parent = header.getParent();
17
+ return parent === null ? -1 : [...children(parent)].indexOf(header);
18
+ };
19
+ const titledColumnFor = (columns, title) => {
20
+ const matches = columns.filter((column) => column.getTitle() === title);
21
+ return matches.length === 1 ? matches[0] ?? null : null;
22
+ };
23
+ const columnFor = (header, view) => {
24
+ const columns = columnsFor(view);
25
+ const picked = columns[headerIndexFor(header)] ?? null;
26
+ const title = getWidgetTextContent(header);
27
+ if (picked !== null && picked.getTitle() === title) {
28
+ return picked;
29
+ }
30
+ return titledColumnFor(columns, title) ?? picked;
31
+ };
32
+ const sortableColumnFor = (header, view) => {
33
+ const column = columnFor(header, view);
34
+ return column !== null && column.getSorter() !== null ? column : null;
35
+ };
36
+ const invertedSortDirection = (order) => order === Gtk.SortType.ASCENDING ? Gtk.SortType.DESCENDING : Gtk.SortType.ASCENDING;
37
+ const nextSortDirection = (view, column) => {
38
+ const sorter = view.getSorter();
39
+ if (!(sorter instanceof Gtk.ColumnViewSorter) || sorter.getPrimarySortColumn() !== column) {
40
+ return Gtk.SortType.ASCENDING;
41
+ }
42
+ return invertedSortDirection(sorter.getPrimarySortOrder());
43
+ };
44
+ const applyHeaderClick = (header, nPress) => {
45
+ const view = ancestorFor(header, Gtk.ColumnView);
46
+ const column = view === null ? null : sortableColumnFor(header, view);
47
+ if (view === null || column === null) {
48
+ return;
49
+ }
50
+ for (let press = 1; press <= nPress; press++) {
51
+ view.sortByColumn(column, nextSortDirection(view, column));
52
+ }
53
+ };
54
+ export { applyHeaderClick };
55
+ //# sourceMappingURL=column-header-click.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-header-click.js","sourceRoot":"","sources":["../../src/user-event/column-header-click.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { ancestorFor, children } from \"../traversal.js\";\nimport { getWidgetTextContent } from \"../widget-accessible-properties.js\";\n\nconst columnsFor = (view: Gtk.ColumnView): Gtk.ColumnViewColumn[] => {\n const model = view.getColumns();\n const columns: Gtk.ColumnViewColumn[] = [];\n\n for (let index = 0; index < model.getNItems(); index++) {\n const column = model.getItem(index);\n\n if (column instanceof Gtk.ColumnViewColumn) {\n columns.push(column);\n }\n }\n\n return columns;\n};\n\nconst headerIndexFor = (header: Gtk.Widget): number => {\n const parent = header.getParent();\n\n return parent === null ? -1 : [...children(parent)].indexOf(header);\n};\n\nconst titledColumnFor = (columns: Gtk.ColumnViewColumn[], title: string | null): Gtk.ColumnViewColumn | null => {\n const matches = columns.filter((column) => column.getTitle() === title);\n\n return matches.length === 1 ? matches[0] ?? null : null;\n};\n\nconst columnFor = (header: Gtk.Widget, view: Gtk.ColumnView): Gtk.ColumnViewColumn | null => {\n const columns = columnsFor(view);\n const picked = columns[headerIndexFor(header)] ?? null;\n const title = getWidgetTextContent(header);\n\n if (picked !== null && picked.getTitle() === title) {\n return picked;\n }\n\n return titledColumnFor(columns, title) ?? picked;\n};\n\nconst sortableColumnFor = (header: Gtk.Widget, view: Gtk.ColumnView): Gtk.ColumnViewColumn | null => {\n const column = columnFor(header, view);\n\n return column !== null && column.getSorter() !== null ? column : null;\n};\n\nconst invertedSortDirection = (order: Gtk.SortType): Gtk.SortType =>\n order === Gtk.SortType.ASCENDING ? Gtk.SortType.DESCENDING : Gtk.SortType.ASCENDING;\n\nconst nextSortDirection = (view: Gtk.ColumnView, column: Gtk.ColumnViewColumn): Gtk.SortType => {\n const sorter = view.getSorter();\n\n if (!(sorter instanceof Gtk.ColumnViewSorter) || sorter.getPrimarySortColumn() !== column) {\n return Gtk.SortType.ASCENDING;\n }\n\n return invertedSortDirection(sorter.getPrimarySortOrder());\n};\n\nconst applyHeaderClick = (header: Gtk.Widget, nPress: number): void => {\n const view = ancestorFor(header, Gtk.ColumnView);\n const column = view === null ? null : sortableColumnFor(header, view);\n\n if (view === null || column === null) {\n return;\n }\n\n for (let press = 1; press <= nPress; press++) {\n view.sortByColumn(column, nextSortDirection(view, column));\n }\n};\n\nexport { applyHeaderClick };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"event-wrapper.d.ts","sourceRoot":"","sources":["../../src/user-event/event-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAuEpC,QAAA,MAAM,SAAS,GAAU,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAM/F,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"event-wrapper.d.ts","sourceRoot":"","sources":["../../src/user-event/event-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAyFpC,QAAA,MAAM,SAAS,GAAU,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAM/F,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -2,46 +2,60 @@ import * as Gtk from "@gtkx/gi/gtk";
2
2
  import { runInAct } from "../act.js";
3
3
  import { getConfig } from "../config.js";
4
4
  import { formatRole } from "../role-helpers.js";
5
+ import { delay, now } from "../timers.js";
6
+ import { getWidgetAccessibleName } from "../widget-accessible-properties.js";
7
+ import { getTypeTag, isDefaultWidgetName } from "../widget-getters.js";
8
+ import { isWindowAllocated, isWindowBlockedByModal } from "../window-state.js";
5
9
  const NOT_SENSITIVE = "it is not sensitive (the widget or one of its ancestors is disabled)";
10
+ const NOT_ROOTED = "it is not inside a toplevel (it was removed from the widget tree, or was never added to one)";
11
+ const WINDOW_NOT_VISIBLE = "its window is not visible (it was hidden, or it was never shown)";
6
12
  const WINDOW_NOT_ALLOCATED = "its window has not been allocated a size";
7
13
  const NOT_MAPPED = "it is not mapped (it is not shown on screen, e.g. it is hidden or on a non-visible page)";
8
- const WINDOW_NOT_ACTIVE = "its window never became active";
9
- const actionableHop = () => new Promise((resolve) => setTimeout(resolve, 1));
10
- const canDisplayDeliverActivation = (window) => window.getDisplay().getDefaultSeat() !== null;
11
- const findWindowActionabilityFailure = (widget, root) => {
12
- if (root.getAllocatedWidth() === 0) {
13
- return WINDOW_NOT_ALLOCATED;
14
+ const BLOCKED_BY_MODAL = "its window is blocked by a modal window holding the grab";
15
+ const ACTIONABLE_HOP_MS = 1;
16
+ const findWindowActionabilityFailure = (window) => {
17
+ if (!window.getVisible()) {
18
+ return WINDOW_NOT_VISIBLE;
14
19
  }
15
- if (!widget.getMapped()) {
16
- return NOT_MAPPED;
20
+ if (!isWindowAllocated(window)) {
21
+ return WINDOW_NOT_ALLOCATED;
17
22
  }
18
- if (canDisplayDeliverActivation(root) && !root.isActive()) {
19
- return WINDOW_NOT_ACTIVE;
23
+ if (isWindowBlockedByModal(window)) {
24
+ return BLOCKED_BY_MODAL;
20
25
  }
21
26
  return null;
22
27
  };
28
+ const findRootActionabilityFailure = (root) => root instanceof Gtk.Window ? findWindowActionabilityFailure(root) : null;
23
29
  const findActionabilityFailure = (widget) => {
24
30
  if (!widget.isSensitive()) {
25
31
  return NOT_SENSITIVE;
26
32
  }
27
33
  const root = widget.getRoot();
28
- if (!(root instanceof Gtk.Window) || !root.getVisible()) {
29
- return null;
34
+ if (root === null) {
35
+ return NOT_ROOTED;
36
+ }
37
+ const rootFailure = findRootActionabilityFailure(root);
38
+ if (rootFailure !== null) {
39
+ return rootFailure;
30
40
  }
31
- return findWindowActionabilityFailure(widget, root);
41
+ return widget.getMapped() ? null : NOT_MAPPED;
32
42
  };
33
- const describeWidget = (widget) => {
34
- const tag = widget.constructor.name;
43
+ const attribute = (key, value) => (value === null ? "" : ` ${key}="${value}"`);
44
+ const widgetNameAttribute = (widget) => {
35
45
  const name = widget.getName();
36
- const nameAttribute = name && !name.endsWith(tag) ? ` name="${name}"` : "";
37
- return `<${tag}${nameAttribute} role="${formatRole(widget.getAccessibleRole())}">`;
46
+ return attribute("name", isDefaultWidgetName(widget, name) ? null : name);
47
+ };
48
+ const describeWidget = (widget) => {
49
+ const accessibleName = attribute("accessible-name", getWidgetAccessibleName(widget));
50
+ const role = attribute("role", formatRole(widget.getAccessibleRole()));
51
+ return `<${getTypeTag(widget)}${accessibleName}${widgetNameAttribute(widget)}${role}>`;
38
52
  };
39
53
  const waitForActionable = async (widget) => {
40
54
  const timeout = getConfig().actionabilityTimeout;
41
- const deadline = Date.now() + timeout;
55
+ const deadline = now() + timeout;
42
56
  let failure = findActionabilityFailure(widget);
43
- while (failure !== null && Date.now() < deadline) {
44
- await actionableHop();
57
+ while (failure !== null && now() < deadline) {
58
+ await delay(ACTIONABLE_HOP_MS);
45
59
  failure = findActionabilityFailure(widget);
46
60
  }
47
61
  if (failure !== null) {
@@ -1 +1 @@
1
- {"version":3,"file":"event-wrapper.js","sourceRoot":"","sources":["../../src/user-event/event-wrapper.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { runInAct } from \"../act.js\";\nimport { getConfig } from \"../config.js\";\nimport { formatRole } from \"../role-helpers.js\";\n\nconst NOT_SENSITIVE = \"it is not sensitive (the widget or one of its ancestors is disabled)\";\nconst WINDOW_NOT_ALLOCATED = \"its window has not been allocated a size\";\nconst NOT_MAPPED = \"it is not mapped (it is not shown on screen, e.g. it is hidden or on a non-visible page)\";\nconst WINDOW_NOT_ACTIVE = \"its window never became active\";\n\nconst actionableHop = (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 1));\n\nconst canDisplayDeliverActivation = (window: Gtk.Window): boolean =>\n window.getDisplay().getDefaultSeat() !== null;\n\nconst findWindowActionabilityFailure = (widget: Gtk.Widget, root: Gtk.Window): string | null => {\n if (root.getAllocatedWidth() === 0) {\n return WINDOW_NOT_ALLOCATED;\n }\n\n if (!widget.getMapped()) {\n return NOT_MAPPED;\n }\n\n if (canDisplayDeliverActivation(root) && !root.isActive()) {\n return WINDOW_NOT_ACTIVE;\n }\n\n return null;\n};\n\nconst findActionabilityFailure = (widget: Gtk.Widget): string | null => {\n if (!widget.isSensitive()) {\n return NOT_SENSITIVE;\n }\n\n const root = widget.getRoot();\n\n if (!(root instanceof Gtk.Window) || !root.getVisible()) {\n return null;\n }\n\n return findWindowActionabilityFailure(widget, root);\n};\n\nconst describeWidget = (widget: Gtk.Widget): string => {\n const tag = widget.constructor.name;\n const name = widget.getName();\n const nameAttribute = name && !name.endsWith(tag) ? ` name=\"${name}\"` : \"\";\n\n return `<${tag}${nameAttribute} role=\"${formatRole(widget.getAccessibleRole())}\">`;\n};\n\nconst waitForActionable = async (widget: Gtk.Widget): Promise<void> => {\n const timeout = getConfig().actionabilityTimeout;\n const deadline = Date.now() + timeout;\n let failure = findActionabilityFailure(widget);\n\n while (failure !== null && Date.now() < deadline) {\n await actionableHop();\n failure = findActionabilityFailure(widget);\n }\n\n if (failure !== null) {\n throw new Error(\n `Cannot dispatch user event: ${describeWidget(widget)} did not become actionable ` +\n `within ${String(timeout)}ms because ${failure}`,\n );\n }\n};\n\nconst wrapEvent = async (widget: Gtk.Widget, body: () => void | PromiseLike<void>): Promise<void> => {\n await waitForActionable(widget);\n\n await runInAct(async () => {\n await body();\n });\n};\n\nexport { wrapEvent };\n"]}
1
+ {"version":3,"file":"event-wrapper.js","sourceRoot":"","sources":["../../src/user-event/event-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,MAAM,aAAa,GAAG,sEAAsE,CAAC;AAC7F,MAAM,UAAU,GAAG,8FAA8F,CAAC;AAClH,MAAM,kBAAkB,GAAG,kEAAkE,CAAC;AAC9F,MAAM,oBAAoB,GAAG,0CAA0C,CAAC;AACxE,MAAM,UAAU,GAAG,0FAA0F,CAAC;AAC9G,MAAM,gBAAgB,GAAG,0DAA0D,CAAC;AACpF,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,MAAM,8BAA8B,GAAG,CAAC,MAAkB,EAAiB,EAAE;IACzE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;QACvB,OAAO,kBAAkB,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,oBAAoB,CAAC;IAChC,CAAC;IAED,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,gBAAgB,CAAC;IAC5B,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,4BAA4B,GAAG,CAAC,IAAc,EAAiB,EAAE,CACnE,IAAI,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAE7E,MAAM,wBAAwB,GAAG,CAAC,MAAkB,EAAiB,EAAE;IACnE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,OAAO,aAAa,CAAC;IACzB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAE9B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAChB,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,MAAM,WAAW,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;IAEvD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,WAAW,CAAC;IACvB,CAAC;IAED,OAAO,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,KAAoB,EAAU,EAAE,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC;AAE9G,MAAM,mBAAmB,GAAG,CAAC,MAAkB,EAAU,EAAE;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAE9B,OAAO,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9E,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAU,EAAE;IAClD,MAAM,cAAc,GAAG,SAAS,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;IAEvE,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,GAAG,cAAc,GAAG,mBAAmB,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC;AAC3F,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,KAAK,EAAE,MAAkB,EAAiB,EAAE;IAClE,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC,oBAAoB,CAAC;IACjD,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IACjC,IAAI,OAAO,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAE/C,OAAO,OAAO,KAAK,IAAI,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC1C,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACX,+BAA+B,cAAc,CAAC,MAAM,CAAC,6BAA6B;YAClF,UAAU,MAAM,CAAC,OAAO,CAAC,cAAc,OAAO,EAAE,CACnD,CAAC;IACN,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,KAAK,EAAE,MAAkB,EAAE,IAAoC,EAAiB,EAAE;IAChG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAEhC,MAAM,QAAQ,CAAC,KAAK,IAAI,EAAE;QACtB,MAAM,IAAI,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { runInAct } from \"../act.js\";\nimport { getConfig } from \"../config.js\";\nimport { formatRole } from \"../role-helpers.js\";\nimport { delay, now } from \"../timers.js\";\nimport { getWidgetAccessibleName } from \"../widget-accessible-properties.js\";\nimport { getTypeTag, isDefaultWidgetName } from \"../widget-getters.js\";\nimport { isWindowAllocated, isWindowBlockedByModal } from \"../window-state.js\";\n\nconst NOT_SENSITIVE = \"it is not sensitive (the widget or one of its ancestors is disabled)\";\nconst NOT_ROOTED = \"it is not inside a toplevel (it was removed from the widget tree, or was never added to one)\";\nconst WINDOW_NOT_VISIBLE = \"its window is not visible (it was hidden, or it was never shown)\";\nconst WINDOW_NOT_ALLOCATED = \"its window has not been allocated a size\";\nconst NOT_MAPPED = \"it is not mapped (it is not shown on screen, e.g. it is hidden or on a non-visible page)\";\nconst BLOCKED_BY_MODAL = \"its window is blocked by a modal window holding the grab\";\nconst ACTIONABLE_HOP_MS = 1;\n\nconst findWindowActionabilityFailure = (window: Gtk.Window): string | null => {\n if (!window.getVisible()) {\n return WINDOW_NOT_VISIBLE;\n }\n\n if (!isWindowAllocated(window)) {\n return WINDOW_NOT_ALLOCATED;\n }\n\n if (isWindowBlockedByModal(window)) {\n return BLOCKED_BY_MODAL;\n }\n\n return null;\n};\n\nconst findRootActionabilityFailure = (root: Gtk.Root): string | null =>\n root instanceof Gtk.Window ? findWindowActionabilityFailure(root) : null;\n\nconst findActionabilityFailure = (widget: Gtk.Widget): string | null => {\n if (!widget.isSensitive()) {\n return NOT_SENSITIVE;\n }\n\n const root = widget.getRoot();\n\n if (root === null) {\n return NOT_ROOTED;\n }\n\n const rootFailure = findRootActionabilityFailure(root);\n\n if (rootFailure !== null) {\n return rootFailure;\n }\n\n return widget.getMapped() ? null : NOT_MAPPED;\n};\n\nconst attribute = (key: string, value: string | null): string => (value === null ? \"\" : ` ${key}=\"${value}\"`);\n\nconst widgetNameAttribute = (widget: Gtk.Widget): string => {\n const name = widget.getName();\n\n return attribute(\"name\", isDefaultWidgetName(widget, name) ? null : name);\n};\n\nconst describeWidget = (widget: Gtk.Widget): string => {\n const accessibleName = attribute(\"accessible-name\", getWidgetAccessibleName(widget));\n const role = attribute(\"role\", formatRole(widget.getAccessibleRole()));\n\n return `<${getTypeTag(widget)}${accessibleName}${widgetNameAttribute(widget)}${role}>`;\n};\n\nconst waitForActionable = async (widget: Gtk.Widget): Promise<void> => {\n const timeout = getConfig().actionabilityTimeout;\n const deadline = now() + timeout;\n let failure = findActionabilityFailure(widget);\n\n while (failure !== null && now() < deadline) {\n await delay(ACTIONABLE_HOP_MS);\n failure = findActionabilityFailure(widget);\n }\n\n if (failure !== null) {\n throw new Error(\n `Cannot dispatch user event: ${describeWidget(widget)} did not become actionable ` +\n `within ${String(timeout)}ms because ${failure}`,\n );\n }\n};\n\nconst wrapEvent = async (widget: Gtk.Widget, body: () => void | PromiseLike<void>): Promise<void> => {\n await waitForActionable(widget);\n\n await runInAct(async () => {\n await body();\n });\n};\n\nexport { wrapEvent };\n"]}