@gjsify/gtk-host 0.53.0 → 0.54.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.
@@ -13,11 +13,7 @@ export interface HostText extends HostNodeBase {
13
13
  readonly kind: 'text';
14
14
  data: string;
15
15
  }
16
- /**
17
- * A position marker. Vue's `createComment` and Svelte's comment markers land here.
18
- * An anchor NEVER enters the GTK tree; `insert` resolves forward past it to the
19
- * next node that actually owns a widget.
20
- */
16
+ /** A position marker. Vue's `createComment` and Svelte's comment markers land here. */
21
17
  export interface HostAnchor extends HostNodeBase {
22
18
  readonly kind: 'anchor';
23
19
  data: string;
@@ -36,9 +32,9 @@ export interface HostElement extends HostNodeBase {
36
32
  /**
37
33
  * signal name -> the one native handler, and the prop that owns it.
38
34
  *
39
- * One handler per signal name, ever. The owner is recorded because two props
40
- * can resolve to the same signal (`onClicked` and `on:clicked`), and the
41
- * second used to disconnect the first without saying so.
35
+ * One handler per signal name, ever. The owner is recorded because two props can
36
+ * resolve to the same signal (`onClicked` and `on:clicked`), and the second used
37
+ * to disconnect the first without saying so.
42
38
  */
43
39
  handlers: Map<string, {
44
40
  id: number;
@@ -54,10 +50,10 @@ export interface HostElement extends HostNodeBase {
54
50
  /**
55
51
  * The authored ARIA object, or null — the accessibility GTK holds for this widget.
56
52
  *
57
- * A field of its own and NOT a key in `props`, for the reason `layout` is one: `props`
58
- * is replayed into `g_object_new` by `materialize`, and none of these names is a
59
- * construct property. It is the LAST authored value, so a patch can compute which
60
- * slots the new object no longer sets and reset exactly those.
53
+ * A field of its own and NOT a key in `props`, because `props` is replayed into
54
+ * `g_object_new` by `materialize` and none of these names is a construct property. It is
55
+ * the LAST authored value, so a patch can compute which slots the new object no longer
56
+ * sets and reset exactly those.
61
57
  */
62
58
  accessibility: Record<string, unknown> | null;
63
59
  /** True once text CHILDREN wrote the sink, so removing the last one clears it
@@ -66,11 +62,10 @@ export interface HostElement extends HostNodeBase {
66
62
  /**
67
63
  * True while this element is actually IN its parent's GTK tree.
68
64
  *
69
- * Owning a widget is not the same thing: every framework builds bottom-up,
70
- * so a subtree is materialised long before it is inserted. Deriving "is my
71
- * sibling in the tree" from `widget !== null` made the remove-all policy
72
- * detach non-children and re-add already-parented ones — two Adwaita
73
- * criticals per replay, at exit 0.
65
+ * Owning a widget is not the same thing: every framework builds bottom-up, so a subtree
66
+ * is materialised long before it is inserted. Deriving "is my sibling in the tree" from
67
+ * `widget !== null` made the remove-all policy detach non-children and re-add
68
+ * already-parented ones — two Adwaita criticals per replay, at exit 0.
74
69
  */
75
70
  attached: boolean;
76
71
  /** True once `destroy` has torn this element down. It never comes back. */
@@ -78,19 +73,18 @@ export interface HostElement extends HostNodeBase {
78
73
  /**
79
74
  * Children this element already had before the host adopted it.
80
75
  *
81
- * Only an ADOPTED root has any: a renderer mounts into a container the
82
- * application built, and those children are in the GTK tree while being absent
83
- * from the shadow tree. Placement offsets past them, or the first insertion
84
- * computes "first" and the whole rendered tree lands ABOVE the app's own chrome.
76
+ * Only an ADOPTED root has any: a renderer mounts into a container the application built,
77
+ * and those children are in the GTK tree while being absent from the shadow tree.
78
+ * Placement offsets past them, or the first insertion computes "first" and the whole
79
+ * rendered tree lands ABOVE the app's own chrome.
85
80
  */
86
81
  foreign: readonly Gtk.Widget[];
87
82
  /**
88
83
  * A PORTAL node's subscription to its parent's `root`, or null.
89
84
  *
90
- * Only a `portal` placement ever has one, and it is per-attachment state
91
- * exactly like `wrapper` — a side table keyed on the element would be a second
92
- * tree that can disagree with this one. See {@link NodePlacement}'s portal arm
93
- * for what the subscription is for and what it was measured against.
85
+ * Only a `portal` placement ever has one, and it is per-attachment state exactly like
86
+ * `wrapper` — a side table keyed on the element would be a second tree that can disagree
87
+ * with this one. See {@link NodePlacement}'s portal arm for what the subscription is for.
94
88
  */
95
89
  portalWatch: {
96
90
  widget: Gtk.Widget;
@@ -101,36 +95,36 @@ export type HostNode = HostElement | HostText | HostAnchor;
101
95
  /**
102
96
  * The axis ABOVE `ChildPolicy`, and the two are orthogonal on purpose.
103
97
  *
104
- * `ChildPolicy` answers "how does this parent adopt a child". It presumes the
105
- * answer to a question nobody had to ask until now: *does this node go into its
106
- * parent at all?* For every widget in the table it does. For an `Adw.Dialog` it
107
- * does not, and the difference is not a degradation the parent can absorb —
108
- * MEASURED on libadwaita 1.9.3 / GTK 4.22.4 / gjs 1.88.1, `box.append(dialog)`
109
- * with the box ROOTED IN A WINDOW reaches
98
+ * `ChildPolicy` answers "how does this parent adopt a child". It presumes the answer
99
+ * to a question nobody had to ask until now: *does this node go into its parent at
100
+ * all?* For every widget in the table it does. For an `Adw.Dialog` it does not, and
101
+ * the difference is not a degradation the parent can absorb — MEASURED on libadwaita
102
+ * 1.9.3 / GTK 4.22.4 / gjs 1.88.1, `box.append(dialog)` with the box ROOTED IN A WINDOW
103
+ * reaches
110
104
  *
111
105
  * Adwaita-ERROR **: Trying to add AdwDialog 0x… to GtkBox 0x…. Use
112
106
  * adw_dialog_present() to show dialogs.
113
107
  *
114
- * which is `g_error()`: SIGABRT, exit 134, a core dump. Not an exception a `try`
115
- * in the reconciler can catch and not a warning a diagnostics gate can count.
108
+ * which is `g_error()`: SIGABRT, exit 134, a core dump. Not an exception a `try` in
109
+ * the reconciler can catch and not a warning a diagnostics gate can count.
116
110
  * `adw_dialog_root()` raises it from the ROOT vfunc, which is why a DETACHED box
117
- * accepts the very same append in silence at exit 0 — re-testing this on a bare
118
- * box "disproves" it and puts the append back.
111
+ * accepts the very same append in silence at exit 0 — re-testing this on a bare box
112
+ * "disproves" it and puts the append back.
119
113
  *
120
- * THE ABORT IS THE LOUD HALF OF A CLASS, and its quiet half arrives through the
121
- * same door (ADR 0054). MEASURED on the same libraries, one process per case:
114
+ * THE ABORT IS THE LOUD HALF OF A CLASS, and its quiet half arrives through the same
115
+ * door (ADR 0054). MEASURED on the same libraries, one process per case:
122
116
  * `box.append(new Gtk.Window())` with the box rooted is **exit 0, silent**, and
123
117
  * afterwards `win.get_parent()` is the box while `win.get_root()` is the window
124
118
  * ITSELF — a `GtkRoot` with a parent, which is a contradiction GTK states nowhere.
125
- * Presenting that window then draws it as a toplevel AND leaves it in the box's
126
- * child list, so the container measures and allocates a window. One node kind
127
- * aborts, its neighbour says nothing; both are the same question answered wrong,
128
- * so both are answered here.
119
+ * Presenting that window then draws it as a toplevel AND leaves it in the box's child
120
+ * list, so the container measures and allocates a window. One node kind aborts, its
121
+ * neighbour says nothing; both are the same question answered wrong, so both are
122
+ * answered here.
129
123
  *
130
124
  * So the descriptor declares the axis, and `policies.ts` is the only reader.
131
- * `parented` is every other widget and is what an ABSENT `placement` means; the
132
- * union still cannot be forgotten because there is exactly one normaliser
133
- * (`placementOf`) and every switch over it ends in `unhandledPlacement`.
125
+ * `parented` is every other widget and is what an ABSENT `placement` means; the union
126
+ * still cannot be forgotten because there is exactly one normaliser (`placementOf`)
127
+ * and every switch over it ends in `unhandledPlacement`.
134
128
  */
135
129
  export type NodePlacement =
136
130
  /**
@@ -152,19 +146,17 @@ export type NodePlacement =
152
146
  * Three measurements shape the two method names, all on libadwaita 1.9.3:
153
147
  *
154
148
  * - `present` TAKES THE PARENT WIDGET (`adw_dialog_present` arity 1, against
155
- * `gtk_window_present`'s 0). That is what makes this a portal rather than a
156
- * toplevel: the node has a place in the shadow tree and a different place in
157
- * the GTK tree, and the parent is what joins them.
158
- * - `close` IS THE UNCONDITIONAL ONE, `force_close` and not `close`. An
159
- * unmount is not a user request: with `can-close: false` (which is how
160
- * `onRequestClose` is honoured one layer up) `adw_dialog_close()` returns
161
- * FALSE, emits `close-attempt` and LEAVES THE DIALOG ON SCREEN — measured.
162
- * `force_close()` closes it and emits `closed`.
163
- * - AND `force_close` IS SAFE ON A NODE THAT WAS NEVER PRESENTED, where
164
- * `close` is not: measured, `close()` on an unpresented dialog answers
165
- * `Adwaita-CRITICAL **: Trying to close AdwDialog 0x… that's not presented`
166
- * at exit 0, and `force_close()` is silent. So the host needs no
167
- * "is it up?" probe before retracting one.
149
+ * `gtk_window_present`'s 0). That is what makes this a portal rather than a toplevel:
150
+ * the node has a place in the shadow tree and a different place in the GTK tree, and
151
+ * the parent is what joins them.
152
+ * - `close` IS THE UNCONDITIONAL ONE, `force_close` and not `close`. An unmount is not
153
+ * a user request: with `can-close: false` (how `onRequestClose` is honoured one layer
154
+ * up) `adw_dialog_close()` returns FALSE, emits `close-attempt` and LEAVES THE DIALOG
155
+ * ON SCREEN — measured. `force_close()` closes it and emits `closed`.
156
+ * - `force_close` IS SAFE ON A NODE THAT WAS NEVER PRESENTED, where `close` is not:
157
+ * measured, `close()` on an unpresented dialog answers `Adwaita-CRITICAL **: Trying to
158
+ * close AdwDialog 0x… that's not presented` at exit 0, and `force_close()` is silent.
159
+ * So the host needs no "is it up?" probe before retracting one.
168
160
  */
169
161
  | {
170
162
  readonly kind: 'portal';
@@ -174,34 +166,33 @@ export type NodePlacement =
174
166
  /**
175
167
  * The node IS a root: `present()` / `destroy()`, and no parent anywhere.
176
168
  *
177
- * WHAT SEPARATES IT FROM A PORTAL IS THE ARITY, and that is a fact about the
178
- * two libraries rather than a convention: measured, `adw_dialog_present` takes
179
- * 1 argument and `gtk_window_present` takes 0. A portal has two positions in
180
- * the tree and the parent is what joins them; a toplevel has ONE, its own, so
181
- * there is nothing to present it against. `descriptorProblems()` holds both
182
- * arities, so the two arms cannot be swapped by a copy/paste.
169
+ * WHAT SEPARATES IT FROM A PORTAL IS THE ARITY, and that is a fact about the two
170
+ * libraries rather than a convention: measured, `adw_dialog_present` takes 1 argument
171
+ * and `gtk_window_present` takes 0. A portal has two positions in the tree and the
172
+ * parent is what joins them; a toplevel has ONE, its own, so there is nothing to
173
+ * present it against. `descriptorProblems()` holds both arities, so the two arms
174
+ * cannot be swapped by a copy/paste.
183
175
  *
184
- * MEMBERSHIP IS `Gtk.Root`, measured with `GObject.type_is_a` and not read
185
- * from documentation — `GtkWindow` and `AdwApplicationWindow` down to
186
- * `GtkPrintUnixDialog`. It is GTK's own word for "this widget is a toplevel",
187
- * which is why the generic code asks it instead of forming a second opinion,
188
- * and `placement.spec.ts` is where the membership is walked and counted.
176
+ * MEMBERSHIP IS `Gtk.Root`, measured with `GObject.type_is_a` and not read from
177
+ * documentation — `GtkWindow` and `AdwApplicationWindow` down to
178
+ * `GtkPrintUnixDialog`. It is GTK's own word for "this widget is a toplevel", which
179
+ * is why the generic code asks it instead of forming a second opinion, and
180
+ * `placement.spec.ts` walks and counts the membership.
189
181
  *
190
- * `close: 'destroy'` IS THE FORCED ONE, the same choice the portal arm makes
191
- * and for the same measured reason. On GTK 4.22.4: `gtk_window_close()` emits
192
- * `close-request`, and a handler returning TRUE leaves the window mapped and
193
- * visible — which is exactly how an application vetoes a user's close. An
194
- * unmount is not a user request, so the conditional call is the wrong one;
195
- * `gtk_window_destroy()` takes it down regardless. Both are silent on a window
196
- * that was never presented (measured), so the host needs no "is it up?" probe.
182
+ * `close: 'destroy'` IS THE FORCED ONE, the same choice the portal arm makes and for
183
+ * the same measured reason. On GTK 4.22.4: `gtk_window_close()` emits `close-request`,
184
+ * and a handler returning TRUE leaves the window mapped and visible — exactly how an
185
+ * application vetoes a user's close. An unmount is not a user request, so the
186
+ * conditional call is the wrong one; `gtk_window_destroy()` takes it down regardless.
187
+ * Both are silent on a window that was never presented (measured), so the host needs
188
+ * no "is it up?" probe.
197
189
  *
198
- * AND THE FORCED CALL IS TERMINAL HERE, which is where this arm stops being a
199
- * copy of the portal one. MEASURED: `present()` after either `close()` or
200
- * `destroy()` answers `Gtk-WARNING **: A window is shown after it has been
201
- * destroyed. This will leave the window in an inconsistent state.` — GTK4's
202
- * default `close-request` handler destroys the window, so `close()` is a
203
- * conditional destroy rather than a hide. A retracted toplevel is therefore
204
- * gone for good, and a re-mount is a fresh widget (which is what `rebuild`
190
+ * AND THE FORCED CALL IS TERMINAL HERE, which is where this arm stops being a copy of
191
+ * the portal one. MEASURED: `present()` after either `close()` or `destroy()` answers
192
+ * `Gtk-WARNING **: A window is shown after it has been destroyed. This will leave the
193
+ * window in an inconsistent state.` — GTK4's default `close-request` handler destroys
194
+ * the window, so `close()` is a conditional destroy rather than a hide. A retracted
195
+ * toplevel is gone for good, and a re-mount is a fresh widget (which is what `rebuild`
205
196
  * already does for a construct-only write).
206
197
  */
207
198
  | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/gtk-host",
3
- "version": "0.53.0",
3
+ "version": "0.54.0",
4
4
  "description": "Framework-agnostic GTK4/Adwaita host: the element model UI-framework renderers bind to",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -102,7 +102,8 @@
102
102
  "@girs/gtk-4.0": "5.4.0",
103
103
  "@girs/pango-1.0": "5.4.0",
104
104
  "@girs/pangocairo-1.0": "5.4.0",
105
- "@gjsify/adwaita-core": "^0.53.0"
105
+ "@gjsify/adwaita-core": "^0.54.0",
106
+ "@gjsify/utils": "^0.54.0"
106
107
  },
107
108
  "peerDependencies": {
108
109
  "@vue/runtime-core": "^3.5.0",
@@ -125,11 +126,10 @@
125
126
  }
126
127
  },
127
128
  "devDependencies": {
128
- "@gjsify/cli": "^0.53.0",
129
- "@gjsify/utils": "^0.53.0",
129
+ "@gjsify/cli": "^0.54.0",
130
130
  "@vue/runtime-core": "^3.5.0",
131
131
  "solid-js": "^1.9.0",
132
- "@gjsify/unit": "^0.53.0",
132
+ "@gjsify/unit": "^0.54.0",
133
133
  "@types/node": "^25.9.2",
134
134
  "typescript": "^6.0.3",
135
135
  "@gjsify/node-gi": "file:../../node-gi/node-gi",