@gjsify/gtk-host 0.47.0 → 0.49.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/README.md +158 -2
- package/lib/esm/adjustment.js +1 -0
- package/lib/esm/conformance/diagnostics.js +1 -1
- package/lib/esm/conformance/index.js +1 -2
- package/lib/esm/conformance/tree.js +2 -0
- package/lib/esm/conformance/window-chrome.js +1 -0
- package/lib/esm/descriptors/adw.js +1 -1
- package/lib/esm/descriptors/gtk.js +1 -1
- package/lib/esm/descriptors/index.js +1 -1
- package/lib/esm/errors.js +1 -1
- package/lib/esm/font-families.js +1 -0
- package/lib/esm/fonts.js +1 -1
- package/lib/esm/host.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/list-model.js +1 -0
- package/lib/esm/menu.js +1 -0
- package/lib/esm/policies.js +1 -1
- package/lib/esm/probe.js +1 -1
- package/lib/esm/props.js +1 -1
- package/lib/esm/style/font-family.js +3 -0
- package/lib/esm/style/index.js +1 -1
- package/lib/esm/style/paint.js +1 -1
- package/lib/types/adjustment.d.ts +28 -0
- package/lib/types/adjustment.spec.d.ts +2 -0
- package/lib/types/attrs.d.ts +79 -0
- package/lib/types/conformance/index.d.ts +28 -29
- package/lib/types/conformance/tree.d.ts +30 -0
- package/lib/types/conformance/vectors.d.mts +6 -0
- package/lib/types/conformance/window-chrome.d.ts +29 -0
- package/lib/types/descriptors/gtk.d.ts +32 -1
- package/lib/types/errors.d.ts +43 -0
- package/lib/types/font-families.d.ts +40 -0
- package/lib/types/font-families.spec.d.ts +2 -0
- package/lib/types/fonts.d.ts +45 -1
- package/lib/types/generated/enum-values.d.mts +38 -0
- package/lib/types/generated/methods.d.mts +46 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/jsx-runtime.d.ts +2 -2
- package/lib/types/list-model.d.ts +38 -0
- package/lib/types/list-model.spec.d.ts +2 -0
- package/lib/types/menu.d.ts +43 -0
- package/lib/types/menu.spec.d.ts +2 -0
- package/lib/types/placement.spec.d.ts +2 -0
- package/lib/types/policies.d.ts +241 -1
- package/lib/types/react-jsx-runtime.d.ts +2 -2
- package/lib/types/shared-trees.spec.d.ts +2 -0
- package/lib/types/style/font-family.d.ts +64 -0
- package/lib/types/style/index.d.ts +3 -1
- package/lib/types/style/paint.d.ts +37 -0
- package/lib/types/testing/refusal.d.mts +2 -0
- package/lib/types/types.d.ts +177 -1
- package/lib/types/vue-components.d.ts +2 -2
- package/package.json +8 -5
package/lib/types/types.d.ts
CHANGED
|
@@ -74,8 +74,131 @@ export interface HostElement extends HostNodeBase {
|
|
|
74
74
|
* computes "first" and the whole rendered tree lands ABOVE the app's own chrome.
|
|
75
75
|
*/
|
|
76
76
|
foreign: readonly Gtk.Widget[];
|
|
77
|
+
/**
|
|
78
|
+
* A PORTAL node's subscription to its parent's `root`, or null.
|
|
79
|
+
*
|
|
80
|
+
* Only a `portal` placement ever has one, and it is per-attachment state
|
|
81
|
+
* exactly like `wrapper` — a side table keyed on the element would be a second
|
|
82
|
+
* tree that can disagree with this one. See {@link NodePlacement}'s portal arm
|
|
83
|
+
* for what the subscription is for and what it was measured against.
|
|
84
|
+
*/
|
|
85
|
+
portalWatch: {
|
|
86
|
+
widget: Gtk.Widget;
|
|
87
|
+
id: number;
|
|
88
|
+
} | null;
|
|
77
89
|
}
|
|
78
90
|
export type HostNode = HostElement | HostText | HostAnchor;
|
|
91
|
+
/**
|
|
92
|
+
* The axis ABOVE `ChildPolicy`, and the two are orthogonal on purpose.
|
|
93
|
+
*
|
|
94
|
+
* `ChildPolicy` answers "how does this parent adopt a child". It presumes the
|
|
95
|
+
* answer to a question nobody had to ask until now: *does this node go into its
|
|
96
|
+
* parent at all?* For every widget in the table it does. For an `Adw.Dialog` it
|
|
97
|
+
* does not, and the difference is not a degradation the parent can absorb —
|
|
98
|
+
* MEASURED on libadwaita 1.9.3 / GTK 4.22.4 / gjs 1.88.1, `box.append(dialog)`
|
|
99
|
+
* with the box ROOTED IN A WINDOW reaches
|
|
100
|
+
*
|
|
101
|
+
* Adwaita-ERROR **: Trying to add AdwDialog 0x… to GtkBox 0x…. Use
|
|
102
|
+
* adw_dialog_present() to show dialogs.
|
|
103
|
+
*
|
|
104
|
+
* which is `g_error()`: SIGABRT, exit 134, a core dump. Not an exception a `try`
|
|
105
|
+
* in the reconciler can catch and not a warning a diagnostics gate can count.
|
|
106
|
+
* `adw_dialog_root()` raises it from the ROOT vfunc, which is why a DETACHED box
|
|
107
|
+
* accepts the very same append in silence at exit 0 — re-testing this on a bare
|
|
108
|
+
* box "disproves" it and puts the append back.
|
|
109
|
+
*
|
|
110
|
+
* THE ABORT IS THE LOUD HALF OF A CLASS, and its quiet half arrives through the
|
|
111
|
+
* same door (ADR 0054). MEASURED on the same libraries, one process per case:
|
|
112
|
+
* `box.append(new Gtk.Window())` with the box rooted is **exit 0, silent**, and
|
|
113
|
+
* afterwards `win.get_parent()` is the box while `win.get_root()` is the window
|
|
114
|
+
* ITSELF — a `GtkRoot` with a parent, which is a contradiction GTK states nowhere.
|
|
115
|
+
* Presenting that window then draws it as a toplevel AND leaves it in the box's
|
|
116
|
+
* child list, so the container measures and allocates a window. One node kind
|
|
117
|
+
* aborts, its neighbour says nothing; both are the same question answered wrong,
|
|
118
|
+
* so both are answered here.
|
|
119
|
+
*
|
|
120
|
+
* So the descriptor declares the axis, and `policies.ts` is the only reader.
|
|
121
|
+
* `parented` is every other widget and is what an ABSENT `placement` means; the
|
|
122
|
+
* union still cannot be forgotten because there is exactly one normaliser
|
|
123
|
+
* (`placementOf`) and every switch over it ends in `unhandledPlacement`.
|
|
124
|
+
*/
|
|
125
|
+
export type NodePlacement =
|
|
126
|
+
/**
|
|
127
|
+
* The parent's `ChildPolicy` places it — every widget but the two families below.
|
|
128
|
+
*
|
|
129
|
+
* DECLARING it is not the same as leaving it out, and the difference is an
|
|
130
|
+
* escape hatch rather than a nicety: the host refuses a node whose CLASS says
|
|
131
|
+
* it cannot be parented (`unparentableChild`), and that refusal fires only
|
|
132
|
+
* where the descriptor is SILENT. A consumer whose own widget trips the
|
|
133
|
+
* structural oracle — a `present(parent)` method on a widget that really is a
|
|
134
|
+
* child — writes this arm and is placed by its parent again.
|
|
135
|
+
*/
|
|
136
|
+
{
|
|
137
|
+
readonly kind: 'parented';
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The node places ITSELF against its parent: `present(parent)` / `close()`.
|
|
141
|
+
*
|
|
142
|
+
* Three measurements shape the two method names, all on libadwaita 1.9.3:
|
|
143
|
+
*
|
|
144
|
+
* - `present` TAKES THE PARENT WIDGET (`adw_dialog_present` arity 1, against
|
|
145
|
+
* `gtk_window_present`'s 0). That is what makes this a portal rather than a
|
|
146
|
+
* toplevel: the node has a place in the shadow tree and a different place in
|
|
147
|
+
* the GTK tree, and the parent is what joins them.
|
|
148
|
+
* - `close` IS THE UNCONDITIONAL ONE, `force_close` and not `close`. An
|
|
149
|
+
* unmount is not a user request: with `can-close: false` (which is how
|
|
150
|
+
* `onRequestClose` is honoured one layer up) `adw_dialog_close()` returns
|
|
151
|
+
* FALSE, emits `close-attempt` and LEAVES THE DIALOG ON SCREEN — measured.
|
|
152
|
+
* `force_close()` closes it and emits `closed`.
|
|
153
|
+
* - AND `force_close` IS SAFE ON A NODE THAT WAS NEVER PRESENTED, where
|
|
154
|
+
* `close` is not: measured, `close()` on an unpresented dialog answers
|
|
155
|
+
* `Adwaita-CRITICAL **: Trying to close AdwDialog 0x… that's not presented`
|
|
156
|
+
* at exit 0, and `force_close()` is silent. So the host needs no
|
|
157
|
+
* "is it up?" probe before retracting one.
|
|
158
|
+
*/
|
|
159
|
+
| {
|
|
160
|
+
readonly kind: 'portal';
|
|
161
|
+
readonly present: string;
|
|
162
|
+
readonly close: string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The node IS a root: `present()` / `destroy()`, and no parent anywhere.
|
|
166
|
+
*
|
|
167
|
+
* WHAT SEPARATES IT FROM A PORTAL IS THE ARITY, and that is a fact about the
|
|
168
|
+
* two libraries rather than a convention: measured, `adw_dialog_present` takes
|
|
169
|
+
* 1 argument and `gtk_window_present` takes 0. A portal has two positions in
|
|
170
|
+
* the tree and the parent is what joins them; a toplevel has ONE, its own, so
|
|
171
|
+
* there is nothing to present it against. `descriptorProblems()` holds both
|
|
172
|
+
* arities, so the two arms cannot be swapped by a copy/paste.
|
|
173
|
+
*
|
|
174
|
+
* MEMBERSHIP IS `Gtk.Root`, measured with `GObject.type_is_a` and not read
|
|
175
|
+
* from documentation — `GtkWindow` and `AdwApplicationWindow` down to
|
|
176
|
+
* `GtkPrintUnixDialog`. It is GTK's own word for "this widget is a toplevel",
|
|
177
|
+
* which is why the generic code asks it instead of forming a second opinion,
|
|
178
|
+
* and `placement.spec.ts` is where the membership is walked and counted.
|
|
179
|
+
*
|
|
180
|
+
* `close: 'destroy'` IS THE FORCED ONE, the same choice the portal arm makes
|
|
181
|
+
* and for the same measured reason. On GTK 4.22.4: `gtk_window_close()` emits
|
|
182
|
+
* `close-request`, and a handler returning TRUE leaves the window mapped and
|
|
183
|
+
* visible — which is exactly how an application vetoes a user's close. An
|
|
184
|
+
* unmount is not a user request, so the conditional call is the wrong one;
|
|
185
|
+
* `gtk_window_destroy()` takes it down regardless. Both are silent on a window
|
|
186
|
+
* that was never presented (measured), so the host needs no "is it up?" probe.
|
|
187
|
+
*
|
|
188
|
+
* AND THE FORCED CALL IS TERMINAL HERE, which is where this arm stops being a
|
|
189
|
+
* copy of the portal one. MEASURED: `present()` after either `close()` or
|
|
190
|
+
* `destroy()` answers `Gtk-WARNING **: A window is shown after it has been
|
|
191
|
+
* destroyed. This will leave the window in an inconsistent state.` — GTK4's
|
|
192
|
+
* default `close-request` handler destroys the window, so `close()` is a
|
|
193
|
+
* conditional destroy rather than a hide. A retracted toplevel is therefore
|
|
194
|
+
* gone for good, and a re-mount is a fresh widget (which is what `rebuild`
|
|
195
|
+
* already does for a construct-only write).
|
|
196
|
+
*/
|
|
197
|
+
| {
|
|
198
|
+
readonly kind: 'toplevel';
|
|
199
|
+
readonly present: string;
|
|
200
|
+
readonly close: string;
|
|
201
|
+
};
|
|
79
202
|
export type PolicyKind = 'none' | 'single' | 'ordered' | 'indexed' | 'slotted' | 'keyed' | 'coords';
|
|
80
203
|
/**
|
|
81
204
|
* How a parent adopts children. GTK4 deleted `GtkContainer`, so there is no
|
|
@@ -110,12 +233,52 @@ export type ChildPolicy = {
|
|
|
110
233
|
remove: string;
|
|
111
234
|
reorder: 'native' | 'remove-all';
|
|
112
235
|
}
|
|
113
|
-
/**
|
|
236
|
+
/**
|
|
237
|
+
* `Gtk.ListBox`/`Gtk.FlowBox`: index-addressed, and the parent addresses a WRAPPER row.
|
|
238
|
+
*
|
|
239
|
+
* `perLineCap` names a property the host keeps EQUAL TO THE CHILD COUNT, and
|
|
240
|
+
* `Gtk.FlowBox:max-children-per-line` is the only one. It is a cap, so every
|
|
241
|
+
* value at or above the child count lays the children out identically — and
|
|
242
|
+
* that equivalence is exactly what hid the cost, because GTK MEASURES THE CAP
|
|
243
|
+
* RATHER THAN THE CHILDREN.
|
|
244
|
+
*
|
|
245
|
+
* MEASURED on GTK 4.22.4, one `Gtk.FlowBox` holding TWO children, per
|
|
246
|
+
* HEIGHT-FOR-WIDTH measure — `measure(VERTICAL, 400)`, which is the one a
|
|
247
|
+
* container in a window asks for:
|
|
248
|
+
*
|
|
249
|
+
* | cap | 7 | 64 | 1024 | 8192 | 32768 | 65535 |
|
|
250
|
+
* | --- | --- | --- | --- | --- | --- | --- |
|
|
251
|
+
* | ms | 0.021 | 0.025 | 0.43 | 18.6 | 391.5 | 1393.2 |
|
|
252
|
+
*
|
|
253
|
+
* Quadratic in the cap, so "as many as fit" spelled as G_MAXUINT cost a second
|
|
254
|
+
* and a half to measure two chips, and a real application froze its main loop
|
|
255
|
+
* for 12.7 s at startup over five two-child rows. The ORIENTATION is part of
|
|
256
|
+
* the claim and not a detail: `measure(HORIZONTAL, -1)` stays under 0.1 ms at
|
|
257
|
+
* every one of those caps, so a re-measurement that asks for the width alone
|
|
258
|
+
* reproduces none of this.
|
|
259
|
+
*
|
|
260
|
+
* The cap is wrong in the ANSWER too, not only in what the answer costs.
|
|
261
|
+
* Natural width is `content + column-spacing × (cap - 1)` — measured, exactly,
|
|
262
|
+
* over five caps — so a cap above the child count `n` carries
|
|
263
|
+
* `column-spacing × (cap - n)` px of gaps that do not exist. 12 children at
|
|
264
|
+
* `column-spacing: 8`: 683 px natural at a cap of 12 and 524 867 px at 65535,
|
|
265
|
+
* the excess exactly 8 × 65 523. At `column-spacing: 0` there is no difference
|
|
266
|
+
* at all, which is how a pinned cap passed for as long as it did.
|
|
267
|
+
*
|
|
268
|
+
* The child count is the exact answer rather than a smaller cap chosen to be
|
|
269
|
+
* safe: a line can never hold more children than exist, so it forbids nothing
|
|
270
|
+
* G_MAXUINT allowed, and it is the largest value that costs nothing.
|
|
271
|
+
*
|
|
272
|
+
* An AUTHORED value wins. `<GtkFlowBox maxChildrenPerLine={3}>` is someone
|
|
273
|
+
* asking for three per line, and a sync that overwrote it would be the same
|
|
274
|
+
* silent kind of wrong this field exists to remove.
|
|
275
|
+
*/
|
|
114
276
|
| {
|
|
115
277
|
kind: 'indexed';
|
|
116
278
|
insert: string;
|
|
117
279
|
remove: string;
|
|
118
280
|
wrap: 'list-box-row' | 'flow-box-child' | null;
|
|
281
|
+
perLineCap?: string;
|
|
119
282
|
}
|
|
120
283
|
/**
|
|
121
284
|
* `Adw.HeaderBar`, `Adw.ToolbarView`, `Adw.ActionRow`: named attachment points.
|
|
@@ -261,6 +424,19 @@ export interface WidgetDescriptor {
|
|
|
261
424
|
/** Lazy so `gi://` loads late and an unused descriptor costs nothing. */
|
|
262
425
|
readonly ctor: () => GObject.ObjectClass & (new (props?: Record<string, unknown>) => GObject.Object);
|
|
263
426
|
readonly children: ChildPolicy;
|
|
427
|
+
/**
|
|
428
|
+
* How this node reaches the screen. Absent means `{ kind: 'parented' }`.
|
|
429
|
+
*
|
|
430
|
+
* Optional rather than required, and the reason is the shape of the table
|
|
431
|
+
* rather than convenience: the generated half is the whole GIR widget set and
|
|
432
|
+
* not one row of it is a portal, so a required field would be ~900 identical
|
|
433
|
+
* lines. Nothing is left implicit by that — `placementOf()` normalises the
|
|
434
|
+
* absence in ONE place and every switch over the result has a `never` arm, so
|
|
435
|
+
* a third placement kind cannot be added without every reader failing to
|
|
436
|
+
* compile. `descriptorProblems()` holds the declared methods against the
|
|
437
|
+
* installed class, exactly as it does for `children`.
|
|
438
|
+
*/
|
|
439
|
+
readonly placement?: NodePlacement;
|
|
264
440
|
/**
|
|
265
441
|
* Where a text child goes. Absent means text under this widget is an ERROR
|
|
266
442
|
* that names the tag — never a silent drop.
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
* resolve goes unchecked.
|
|
34
34
|
*/
|
|
35
35
|
import type { DefineComponent } from '@vue/runtime-core';
|
|
36
|
-
import type { VueAttributes, WithOnce } from './attrs.js';
|
|
36
|
+
import type { VueAttributes, WithOnce, WithPortableValues } from './attrs.js';
|
|
37
37
|
import type { WidgetPropsByGType, WidgetPropsVueAliases } from './generated/props.js';
|
|
38
38
|
type VueWidgetProps = WidgetPropsByGType & WidgetPropsVueAliases;
|
|
39
39
|
export type GtkGlobalComponents = {
|
|
40
|
-
[K in keyof VueWidgetProps]: DefineComponent<WithOnce<VueWidgetProps[K]
|
|
40
|
+
[K in keyof VueWidgetProps]: DefineComponent<WithOnce<WithPortableValues<VueWidgetProps[K]>> & VueAttributes>;
|
|
41
41
|
};
|
|
42
42
|
declare module '@vue/runtime-core' {
|
|
43
43
|
interface GlobalComponents extends GtkGlobalComponents {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/gtk-host",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.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",
|
|
@@ -80,7 +80,9 @@
|
|
|
80
80
|
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:gjs",
|
|
81
81
|
"test:gjs": "gjsify run test.gjs.mjs",
|
|
82
82
|
"test:gjs-on-node": "gjsify run build:gjsify && gjsify run build:test:node && node dist/test.node.mjs",
|
|
83
|
-
"generate": "gjsify build src/generator/main.mts --app gjs --outfile tmp/generate.gjs.mjs && gjsify run tmp/generate.gjs.mjs -- --out src/generated && gjsify format src/generated"
|
|
83
|
+
"generate": "gjsify build src/generator/main.mts --app gjs --outfile tmp/generate.gjs.mjs && gjsify run tmp/generate.gjs.mjs -- --out src/generated && gjsify format src/generated",
|
|
84
|
+
"generate:enum-values": "gjs -m ../../../scripts/generate-enum-values.mjs",
|
|
85
|
+
"generate:methods": "gjs -m ../../../scripts/generate-widget-methods.mjs"
|
|
84
86
|
},
|
|
85
87
|
"keywords": [
|
|
86
88
|
"gjs",
|
|
@@ -98,7 +100,8 @@
|
|
|
98
100
|
"@girs/gobject-2.0": "4.6.0",
|
|
99
101
|
"@girs/gtk-4.0": "4.6.0",
|
|
100
102
|
"@girs/pango-1.0": "4.6.0",
|
|
101
|
-
"@girs/pangocairo-1.0": "4.6.0"
|
|
103
|
+
"@girs/pangocairo-1.0": "4.6.0",
|
|
104
|
+
"@gjsify/adwaita-core": "^0.49.0"
|
|
102
105
|
},
|
|
103
106
|
"peerDependencies": {
|
|
104
107
|
"@vue/runtime-core": "^3.5.0",
|
|
@@ -121,10 +124,10 @@
|
|
|
121
124
|
}
|
|
122
125
|
},
|
|
123
126
|
"devDependencies": {
|
|
124
|
-
"@gjsify/cli": "^0.
|
|
127
|
+
"@gjsify/cli": "^0.49.0",
|
|
125
128
|
"@vue/runtime-core": "^3.5.0",
|
|
126
129
|
"solid-js": "^1.9.0",
|
|
127
|
-
"@gjsify/unit": "^0.
|
|
130
|
+
"@gjsify/unit": "^0.49.0",
|
|
128
131
|
"@types/node": "^25.9.2",
|
|
129
132
|
"typescript": "^6.0.3",
|
|
130
133
|
"@gjsify/node-gi": "file:../../node-gi/node-gi",
|