@gtkx/react 0.14.0 → 0.16.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 +28 -27
- package/dist/errors.js +3 -0
- package/dist/factory.d.ts +3 -2
- package/dist/factory.js +1 -1
- package/dist/generated/internal.d.ts +28 -1
- package/dist/generated/internal.js +93 -18
- package/dist/generated/jsx.d.ts +1712 -1516
- package/dist/generated/jsx.js +475 -0
- package/dist/host-config.d.ts +3 -1
- package/dist/host-config.js +31 -11
- package/dist/jsx.d.ts +147 -97
- package/dist/jsx.js +89 -21
- package/dist/node.d.ts +3 -1
- package/dist/node.js +5 -3
- package/dist/nodes/abstract/positional-child.d.ts +9 -0
- package/dist/nodes/abstract/positional-child.js +29 -0
- package/dist/nodes/abstract/positional-parent.d.ts +18 -0
- package/dist/nodes/abstract/positional-parent.js +48 -0
- package/dist/nodes/abstract/virtual-container.d.ts +17 -0
- package/dist/nodes/abstract/virtual-container.js +59 -0
- package/dist/nodes/abstract/virtual-single-child.d.ts +18 -0
- package/dist/nodes/abstract/virtual-single-child.js +54 -0
- package/dist/nodes/action-row-child.d.ts +0 -13
- package/dist/nodes/action-row-child.js +14 -12
- package/dist/nodes/action-row.d.ts +6 -1
- package/dist/nodes/action-row.js +4 -37
- package/dist/nodes/adjustable.d.ts +23 -0
- package/dist/nodes/adjustable.js +62 -0
- package/dist/nodes/alert-dialog-response.d.ts +1 -0
- package/dist/nodes/alert-dialog-response.js +86 -0
- package/dist/nodes/animation/animation-controller.d.ts +17 -0
- package/dist/nodes/animation/animation-controller.js +107 -0
- package/dist/nodes/animation/animation-factory.d.ts +15 -0
- package/dist/nodes/animation/animation-factory.js +25 -0
- package/dist/nodes/animation/animation-node.d.ts +9 -0
- package/dist/nodes/animation/animation-node.js +126 -0
- package/dist/nodes/animation/animation-style-sheet.d.ts +16 -0
- package/dist/nodes/animation/animation-style-sheet.js +74 -0
- package/dist/nodes/animation/index.d.ts +4 -0
- package/dist/nodes/animation/index.js +1 -0
- package/dist/nodes/animation/property-mapper.d.ts +11 -0
- package/dist/nodes/animation/property-mapper.js +36 -0
- package/dist/nodes/animation/transform-state.d.ts +11 -0
- package/dist/nodes/animation/transform-state.js +57 -0
- package/dist/nodes/animation/widget-registry.d.ts +5 -0
- package/dist/nodes/animation/widget-registry.js +42 -0
- package/dist/nodes/application.js +17 -7
- package/dist/nodes/autowrapped.js +37 -43
- package/dist/nodes/calendar.js +16 -55
- package/dist/nodes/color-dialog-button.d.ts +1 -0
- package/dist/nodes/color-dialog-button.js +70 -0
- package/dist/nodes/column-view-column.d.ts +4 -3
- package/dist/nodes/column-view-column.js +5 -1
- package/dist/nodes/column-view.js +40 -43
- package/dist/nodes/dialog.d.ts +11 -0
- package/dist/nodes/dialog.js +20 -0
- package/dist/nodes/drawing-area.d.ts +1 -0
- package/dist/nodes/drawing-area.js +36 -0
- package/dist/nodes/event-controller.d.ts +1 -0
- package/dist/nodes/event-controller.js +96 -0
- package/dist/nodes/expander-row-child.d.ts +0 -14
- package/dist/nodes/expander-row-child.js +14 -12
- package/dist/nodes/expander-row.d.ts +6 -1
- package/dist/nodes/expander-row.js +11 -47
- package/dist/nodes/fixed-child.js +48 -36
- package/dist/nodes/font-dialog-button.d.ts +1 -0
- package/dist/nodes/font-dialog-button.js +90 -0
- package/dist/nodes/grid-child.js +39 -45
- package/dist/nodes/grid.d.ts +1 -0
- package/dist/nodes/grid.js +41 -0
- package/dist/nodes/index.d.ts +22 -6
- package/dist/nodes/index.js +22 -6
- package/dist/nodes/internal/base-item-renderer.d.ts +29 -0
- package/dist/nodes/internal/base-item-renderer.js +88 -0
- package/dist/nodes/internal/base-store.d.ts +9 -0
- package/dist/nodes/internal/base-store.js +20 -0
- package/dist/nodes/internal/child-attachment.d.ts +26 -0
- package/dist/nodes/internal/child-attachment.js +48 -0
- package/dist/nodes/internal/deferred-action.d.ts +8 -0
- package/dist/nodes/internal/deferred-action.js +19 -0
- package/dist/nodes/internal/list-item-renderer.d.ts +14 -14
- package/dist/nodes/internal/list-item-renderer.js +49 -70
- package/dist/nodes/internal/list-store.d.ts +7 -6
- package/dist/nodes/internal/list-store.js +20 -24
- package/dist/nodes/internal/predicates.d.ts +28 -1
- package/dist/nodes/internal/predicates.js +53 -38
- package/dist/nodes/internal/selection-model.d.ts +30 -0
- package/dist/nodes/internal/selection-model.js +91 -0
- package/dist/nodes/internal/signal-store.d.ts +5 -3
- package/dist/nodes/internal/signal-store.js +30 -21
- package/dist/nodes/internal/simple-list-store.js +6 -9
- package/dist/nodes/internal/text-buffer-controller.d.ts +43 -0
- package/dist/nodes/internal/text-buffer-controller.js +287 -0
- package/dist/nodes/internal/text-tag-styles.d.ts +43 -0
- package/dist/nodes/internal/text-tag-styles.js +52 -0
- package/dist/nodes/internal/tree-list-item-renderer.d.ts +16 -14
- package/dist/nodes/internal/tree-list-item-renderer.js +88 -91
- package/dist/nodes/internal/tree-store.d.ts +10 -9
- package/dist/nodes/internal/tree-store.js +31 -35
- package/dist/nodes/internal/utils.d.ts +7 -4
- package/dist/nodes/internal/utils.js +50 -5
- package/dist/nodes/level-bar.js +18 -66
- package/dist/nodes/list-item.d.ts +6 -3
- package/dist/nodes/list-item.js +7 -4
- package/dist/nodes/list-view.js +19 -11
- package/dist/nodes/menu.d.ts +3 -3
- package/dist/nodes/menu.js +3 -3
- package/dist/nodes/models/list.d.ts +11 -13
- package/dist/nodes/models/list.js +16 -73
- package/dist/nodes/models/menu.d.ts +8 -7
- package/dist/nodes/models/menu.js +43 -50
- package/dist/nodes/models/tree-list.d.ts +6 -12
- package/dist/nodes/models/tree-list.js +30 -93
- package/dist/nodes/navigation-page.d.ts +1 -0
- package/dist/nodes/navigation-page.js +7 -3
- package/dist/nodes/navigation-view.js +17 -28
- package/dist/nodes/notebook-page-tab.d.ts +4 -3
- package/dist/nodes/notebook-page-tab.js +5 -2
- package/dist/nodes/notebook-page.d.ts +7 -5
- package/dist/nodes/notebook-page.js +39 -16
- package/dist/nodes/notebook.js +2 -2
- package/dist/nodes/overlay-child.js +90 -30
- package/dist/nodes/pack-child.d.ts +0 -13
- package/dist/nodes/pack-child.js +14 -12
- package/dist/nodes/pack.d.ts +6 -1
- package/dist/nodes/pack.js +4 -37
- package/dist/nodes/popover-menu.js +2 -2
- package/dist/nodes/scale.js +15 -58
- package/dist/nodes/scrolled-window.js +7 -5
- package/dist/nodes/search-bar.d.ts +1 -0
- package/dist/nodes/search-bar.js +40 -0
- package/dist/nodes/shortcut-controller.d.ts +1 -0
- package/dist/nodes/shortcut-controller.js +90 -0
- package/dist/nodes/shortcut.d.ts +39 -0
- package/dist/nodes/shortcut.js +52 -0
- package/dist/nodes/simple-list-view.js +2 -3
- package/dist/nodes/slot.d.ts +6 -9
- package/dist/nodes/slot.js +27 -42
- package/dist/nodes/source-view.d.ts +1 -0
- package/dist/nodes/source-view.js +93 -0
- package/dist/nodes/stack-page.js +17 -13
- package/dist/nodes/stack.js +19 -5
- package/dist/nodes/text-anchor.d.ts +41 -0
- package/dist/nodes/text-anchor.js +59 -0
- package/dist/nodes/text-content.d.ts +10 -0
- package/dist/nodes/text-content.js +1 -0
- package/dist/nodes/text-paintable.d.ts +17 -0
- package/dist/nodes/text-paintable.js +34 -0
- package/dist/nodes/text-segment.d.ts +15 -0
- package/dist/nodes/text-segment.js +29 -0
- package/dist/nodes/text-tag.d.ts +136 -0
- package/dist/nodes/text-tag.js +202 -0
- package/dist/nodes/text-view.d.ts +31 -0
- package/dist/nodes/text-view.js +73 -0
- package/dist/nodes/toggle-group.js +24 -32
- package/dist/nodes/toggle.d.ts +1 -15
- package/dist/nodes/toggle.js +40 -32
- package/dist/nodes/toolbar-child.js +14 -16
- package/dist/nodes/tree-list-item.d.ts +7 -5
- package/dist/nodes/tree-list-item.js +24 -36
- package/dist/nodes/tree-list-view.js +9 -4
- package/dist/nodes/virtual.d.ts +1 -1
- package/dist/nodes/widget.d.ts +3 -13
- package/dist/nodes/widget.js +117 -231
- package/dist/nodes/window.d.ts +9 -3
- package/dist/nodes/window.js +35 -19
- package/dist/registry.d.ts +1 -1
- package/dist/render.js +8 -6
- package/dist/scheduler.d.ts +11 -1
- package/dist/scheduler.js +16 -4
- package/dist/types.d.ts +2 -110
- package/package.json +3 -3
- package/dist/nodes/calendar-mark.d.ts +0 -15
- package/dist/nodes/calendar-mark.js +0 -29
- package/dist/nodes/internal/constants.d.ts +0 -1
- package/dist/nodes/internal/constants.js +0 -21
- package/dist/nodes/level-bar-offset.d.ts +0 -13
- package/dist/nodes/level-bar-offset.js +0 -35
- package/dist/nodes/scale-mark.d.ts +0 -17
- package/dist/nodes/scale-mark.js +0 -38
- package/dist/nodes/virtual-child.d.ts +0 -18
- package/dist/nodes/virtual-child.js +0 -62
package/dist/nodes/widget.js
CHANGED
|
@@ -1,79 +1,81 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { getNativeObject, isObjectEqual } from "@gtkx/ffi";
|
|
2
|
+
import { ObjectClass, ParamSpecString, Type, TypeInstance, typeClassRef, typeFromName, typeFundamental, typeNameFromInstance, } from "@gtkx/ffi/gobject";
|
|
3
3
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
4
4
|
import { CONSTRUCTOR_PROPS } from "../generated/internal.js";
|
|
5
5
|
import { Node } from "../node.js";
|
|
6
6
|
import { registerNodeClass } from "../registry.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import { getAttachmentStrategy, attachChild as performAttachment, detachChild as performDetachment, } from "./internal/child-attachment.js";
|
|
8
|
+
import { isAttachable, isEditable, isInsertable, isRemovable, isReorderable, } from "./internal/predicates.js";
|
|
9
|
+
import { filterProps, matchesAnyClass, propNameToSignalName, resolvePropMeta, resolveSignal, } from "./internal/utils.js";
|
|
10
|
+
const EXCLUDED_PROPS = ["children", "widthRequest", "heightRequest", "grabFocus"];
|
|
11
|
+
function findProperty(obj, key) {
|
|
12
|
+
if (!obj.handle)
|
|
13
|
+
return null;
|
|
14
|
+
const propertyName = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
15
|
+
const typeInstance = getNativeObject(obj.handle, TypeInstance);
|
|
16
|
+
const typeName = typeNameFromInstance(typeInstance);
|
|
17
|
+
const gtype = typeFromName(typeName);
|
|
18
|
+
const typeClass = typeClassRef(gtype);
|
|
19
|
+
const objectClass = getNativeObject(typeClass.handle, ObjectClass);
|
|
20
|
+
return objectClass.findProperty(propertyName) ?? null;
|
|
21
|
+
}
|
|
13
22
|
export class WidgetNode extends Node {
|
|
14
23
|
static priority = 3;
|
|
15
|
-
motionController;
|
|
16
|
-
clickController;
|
|
17
|
-
keyController;
|
|
18
|
-
scrollController;
|
|
19
|
-
dragSourceController;
|
|
20
|
-
dropTargetController;
|
|
21
24
|
static matches(_type, containerOrClass) {
|
|
22
|
-
return
|
|
25
|
+
return matchesAnyClass([Gtk.Widget], containerOrClass);
|
|
23
26
|
}
|
|
24
|
-
static createContainer(props, containerClass) {
|
|
27
|
+
static createContainer(props, containerClass, _rootContainer) {
|
|
25
28
|
const WidgetClass = containerClass;
|
|
26
29
|
const typeName = WidgetClass.glibTypeName;
|
|
27
30
|
const args = (CONSTRUCTOR_PROPS[typeName] ?? []).map((name) => props[name]);
|
|
28
31
|
return new WidgetClass(...args);
|
|
29
32
|
}
|
|
30
33
|
appendChild(child) {
|
|
31
|
-
if (child
|
|
32
|
-
child.
|
|
34
|
+
if (isAttachable(child) && child.canBeChildOf(this)) {
|
|
35
|
+
child.attachTo(this);
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
if (!(child instanceof WidgetNode)) {
|
|
36
|
-
throw new Error(`Cannot append '${child.typeName}' to 'Widget': expected
|
|
39
|
+
throw new Error(`Cannot append '${child.typeName}' to 'Widget': expected Widget`);
|
|
37
40
|
}
|
|
38
41
|
if (child.container instanceof Gtk.Window) {
|
|
39
42
|
throw new Error(`Cannot append 'Window' to '${this.typeName}': windows must be top-level containers`);
|
|
40
43
|
}
|
|
41
|
-
|
|
44
|
+
this.attachChild(child);
|
|
42
45
|
}
|
|
43
46
|
removeChild(child) {
|
|
44
|
-
if (child
|
|
47
|
+
if (isAttachable(child) && child.canBeChildOf(this)) {
|
|
48
|
+
child.detachFrom(this);
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
51
|
if (!(child instanceof WidgetNode)) {
|
|
48
|
-
throw new Error(`Cannot remove '${child.typeName}' from 'Widget': expected
|
|
52
|
+
throw new Error(`Cannot remove '${child.typeName}' from 'Widget': expected Widget`);
|
|
49
53
|
}
|
|
50
54
|
if (child.container instanceof Gtk.Window) {
|
|
51
55
|
throw new Error(`Cannot remove 'Window' from '${this.typeName}': windows must be top-level containers`);
|
|
52
56
|
}
|
|
53
|
-
|
|
57
|
+
this.detachChild(child);
|
|
54
58
|
}
|
|
55
59
|
insertBefore(child, before) {
|
|
56
|
-
if (child
|
|
57
|
-
child.
|
|
60
|
+
if (isAttachable(child) && child.canBeChildOf(this)) {
|
|
61
|
+
child.attachTo(this);
|
|
58
62
|
return;
|
|
59
63
|
}
|
|
60
64
|
if (!(child instanceof WidgetNode) || !(before instanceof WidgetNode)) {
|
|
61
|
-
throw new Error(`Cannot insert '${child.typeName}'
|
|
65
|
+
throw new Error(`Cannot insert '${child.typeName}' into '${this.typeName}': expected Widget`);
|
|
62
66
|
}
|
|
63
67
|
if (child.container instanceof Gtk.Window) {
|
|
64
68
|
throw new Error(`Cannot insert 'Window' into '${this.typeName}': windows must be top-level containers`);
|
|
65
69
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
});
|
|
70
|
+
if (isReorderable(this.container)) {
|
|
71
|
+
this.insertBeforeReorderable(this.container, child, before);
|
|
72
|
+
}
|
|
73
|
+
else if (isInsertable(this.container)) {
|
|
74
|
+
this.insertBeforeInsertable(this.container, child, before);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.appendChild(child);
|
|
78
|
+
}
|
|
77
79
|
}
|
|
78
80
|
insertBeforeReorderable(container, child, before) {
|
|
79
81
|
const previousSibling = this.findPreviousSibling(before);
|
|
@@ -93,52 +95,48 @@ export class WidgetNode extends Node {
|
|
|
93
95
|
container.insert(child.container, position);
|
|
94
96
|
}
|
|
95
97
|
updateProps(oldProps, newProps) {
|
|
98
|
+
if (!this.container) {
|
|
99
|
+
throw new Error(`WidgetNode.updateProps: container is undefined for ${this.typeName}`);
|
|
100
|
+
}
|
|
96
101
|
this.updateSizeRequest(oldProps, newProps);
|
|
102
|
+
this.updateGrabFocus(oldProps, newProps);
|
|
97
103
|
const propNames = new Set([
|
|
98
|
-
...Object.keys(filterProps(oldProps ?? {},
|
|
99
|
-
...Object.keys(filterProps(newProps ?? {},
|
|
104
|
+
...Object.keys(filterProps(oldProps ?? {}, EXCLUDED_PROPS)),
|
|
105
|
+
...Object.keys(filterProps(newProps ?? {}, EXCLUDED_PROPS)),
|
|
100
106
|
]);
|
|
101
107
|
const pendingSignals = [];
|
|
108
|
+
const pendingProperties = [];
|
|
102
109
|
for (const name of propNames) {
|
|
103
110
|
const oldValue = oldProps?.[name];
|
|
104
111
|
const newValue = newProps[name];
|
|
105
112
|
if (oldValue === newValue)
|
|
106
113
|
continue;
|
|
107
|
-
|
|
108
|
-
pendingSignals.push({ name, newValue });
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (name === "onNotify") {
|
|
112
|
-
pendingSignals.push({ name, newValue });
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
const signalName = this.propNameToSignalName(name);
|
|
114
|
+
const signalName = propNameToSignalName(name);
|
|
116
115
|
if (resolveSignal(this.container, signalName)) {
|
|
117
116
|
pendingSignals.push({ name, newValue });
|
|
118
117
|
}
|
|
119
118
|
else if (newValue !== undefined) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
119
|
+
pendingProperties.push({ name, oldValue, newValue });
|
|
120
|
+
}
|
|
121
|
+
else if (oldValue !== undefined) {
|
|
122
|
+
const defaultValue = this.getPropertyDefaultValue(name);
|
|
123
|
+
if (defaultValue !== undefined) {
|
|
124
|
+
pendingProperties.push({ name, oldValue, newValue: defaultValue });
|
|
126
125
|
}
|
|
127
|
-
this.setProperty(name, newValue);
|
|
128
126
|
}
|
|
129
127
|
}
|
|
130
128
|
for (const { name, newValue } of pendingSignals) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
signalStore.set(this, this.container, signalName, handler);
|
|
129
|
+
const signalName = propNameToSignalName(name);
|
|
130
|
+
const handler = typeof newValue === "function" ? newValue : undefined;
|
|
131
|
+
this.signalStore.set(this, this.container, signalName, handler);
|
|
132
|
+
}
|
|
133
|
+
for (const { name, oldValue, newValue } of pendingProperties) {
|
|
134
|
+
if (name === "text" && oldValue !== undefined && isEditable(this.container)) {
|
|
135
|
+
if (oldValue !== this.container.getText()) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
141
138
|
}
|
|
139
|
+
this.setProperty(name, newValue);
|
|
142
140
|
}
|
|
143
141
|
}
|
|
144
142
|
updateSizeRequest(oldProps, newProps) {
|
|
@@ -150,138 +148,46 @@ export class WidgetNode extends Node {
|
|
|
150
148
|
this.container.setSizeRequest(newWidth ?? -1, newHeight ?? -1);
|
|
151
149
|
}
|
|
152
150
|
}
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
case "onEnter":
|
|
159
|
-
case "onLeave":
|
|
160
|
-
case "onMotion": {
|
|
161
|
-
if (!this.motionController) {
|
|
162
|
-
this.motionController = new Gtk.EventControllerMotion();
|
|
163
|
-
this.container.addController(this.motionController);
|
|
164
|
-
}
|
|
165
|
-
const signalName = propName === "onEnter" ? "enter" : propName === "onLeave" ? "leave" : "motion";
|
|
166
|
-
signalStore.set(this, this.motionController, signalName, wrappedHandler);
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
case "onPressed":
|
|
170
|
-
case "onReleased": {
|
|
171
|
-
if (!this.clickController) {
|
|
172
|
-
this.clickController = new Gtk.GestureClick();
|
|
173
|
-
this.container.addController(this.clickController);
|
|
174
|
-
}
|
|
175
|
-
const signalName = propName === "onPressed" ? "pressed" : "released";
|
|
176
|
-
signalStore.set(this, this.clickController, signalName, wrappedHandler);
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
case "onKeyPressed":
|
|
180
|
-
case "onKeyReleased": {
|
|
181
|
-
if (!this.keyController) {
|
|
182
|
-
this.keyController = new Gtk.EventControllerKey();
|
|
183
|
-
this.container.addController(this.keyController);
|
|
184
|
-
}
|
|
185
|
-
const signalName = propName === "onKeyPressed" ? "key-pressed" : "key-released";
|
|
186
|
-
signalStore.set(this, this.keyController, signalName, wrappedHandler);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case "onScroll": {
|
|
190
|
-
if (!this.scrollController) {
|
|
191
|
-
this.scrollController = new Gtk.EventControllerScroll(Gtk.EventControllerScrollFlags.BOTH_AXES);
|
|
192
|
-
this.container.addController(this.scrollController);
|
|
193
|
-
}
|
|
194
|
-
signalStore.set(this, this.scrollController, "scroll", wrappedHandler);
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
case "onDragPrepare":
|
|
198
|
-
case "onDragBegin":
|
|
199
|
-
case "onDragEnd":
|
|
200
|
-
case "onDragCancel":
|
|
201
|
-
case "dragActions": {
|
|
202
|
-
const dragSource = this.ensureDragSource();
|
|
203
|
-
if (propName === "dragActions") {
|
|
204
|
-
dragSource.setActions(handlerOrValue ?? Gdk.DragAction.COPY);
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
const signalName = propName === "onDragPrepare"
|
|
208
|
-
? "prepare"
|
|
209
|
-
: propName === "onDragBegin"
|
|
210
|
-
? "drag-begin"
|
|
211
|
-
: propName === "onDragEnd"
|
|
212
|
-
? "drag-end"
|
|
213
|
-
: "drag-cancel";
|
|
214
|
-
signalStore.set(this, dragSource, signalName, wrappedHandler);
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
case "onDrop":
|
|
219
|
-
case "onDropEnter":
|
|
220
|
-
case "onDropLeave":
|
|
221
|
-
case "onDropMotion":
|
|
222
|
-
case "dropActions":
|
|
223
|
-
case "dropTypes": {
|
|
224
|
-
const dropTarget = this.ensureDropTarget();
|
|
225
|
-
if (propName === "dropActions") {
|
|
226
|
-
dropTarget.setActions(handlerOrValue ?? Gdk.DragAction.COPY);
|
|
227
|
-
}
|
|
228
|
-
else if (propName === "dropTypes") {
|
|
229
|
-
const types = handlerOrValue ?? [];
|
|
230
|
-
dropTarget.setGtypes(types.length, types);
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
const signalName = propName === "onDrop"
|
|
234
|
-
? "drop"
|
|
235
|
-
: propName === "onDropEnter"
|
|
236
|
-
? "enter"
|
|
237
|
-
: propName === "onDropLeave"
|
|
238
|
-
? "leave"
|
|
239
|
-
: "motion";
|
|
240
|
-
signalStore.set(this, dropTarget, signalName, wrappedHandler);
|
|
241
|
-
}
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
ensureDragSource() {
|
|
247
|
-
if (!this.dragSourceController) {
|
|
248
|
-
this.dragSourceController = new Gtk.DragSource();
|
|
249
|
-
this.dragSourceController.setActions(Gdk.DragAction.COPY);
|
|
250
|
-
this.container.addController(this.dragSourceController);
|
|
251
|
-
}
|
|
252
|
-
return this.dragSourceController;
|
|
253
|
-
}
|
|
254
|
-
ensureDropTarget() {
|
|
255
|
-
if (!this.dropTargetController) {
|
|
256
|
-
this.dropTargetController = new Gtk.DropTarget(0, Gdk.DragAction.COPY);
|
|
257
|
-
this.container.addController(this.dropTargetController);
|
|
151
|
+
updateGrabFocus(oldProps, newProps) {
|
|
152
|
+
const oldGrabFocus = oldProps?.grabFocus;
|
|
153
|
+
const newGrabFocus = newProps.grabFocus;
|
|
154
|
+
if (!oldGrabFocus && newGrabFocus) {
|
|
155
|
+
this.container.grabFocus();
|
|
258
156
|
}
|
|
259
|
-
return this.dropTargetController;
|
|
260
157
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
? (obj, pspec) => {
|
|
264
|
-
handler(obj, pspec.getName());
|
|
265
|
-
}
|
|
266
|
-
: undefined;
|
|
267
|
-
signalStore.set(this, this.container, "notify", wrappedHandler);
|
|
268
|
-
}
|
|
269
|
-
propNameToSignalName(name) {
|
|
270
|
-
return name
|
|
271
|
-
.slice(2)
|
|
272
|
-
.replace(/([A-Z])/g, "-$1")
|
|
273
|
-
.toLowerCase()
|
|
274
|
-
.replace(/^-/, "");
|
|
275
|
-
}
|
|
276
|
-
getProperty(key) {
|
|
277
|
-
const propMeta = resolvePropMeta(this.container, key);
|
|
278
|
-
if (!propMeta)
|
|
158
|
+
getPropertyDefaultValue(key) {
|
|
159
|
+
if (!resolvePropMeta(this.container, key))
|
|
279
160
|
return undefined;
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
161
|
+
const pspec = findProperty(this.container, key);
|
|
162
|
+
if (!pspec)
|
|
163
|
+
return undefined;
|
|
164
|
+
const value = pspec.getDefaultValue();
|
|
165
|
+
const gtype = value.getType();
|
|
166
|
+
const fundamental = typeFundamental(gtype);
|
|
167
|
+
if (fundamental === Type.BOOLEAN)
|
|
168
|
+
return value.getBoolean();
|
|
169
|
+
if (fundamental === Type.INT)
|
|
170
|
+
return value.getInt();
|
|
171
|
+
if (fundamental === Type.UINT)
|
|
172
|
+
return value.getUint();
|
|
173
|
+
if (fundamental === Type.LONG)
|
|
174
|
+
return value.getLong();
|
|
175
|
+
if (fundamental === Type.ULONG)
|
|
176
|
+
return value.getUlong();
|
|
177
|
+
if (fundamental === Type.INT64)
|
|
178
|
+
return value.getInt64();
|
|
179
|
+
if (fundamental === Type.UINT64)
|
|
180
|
+
return value.getUint64();
|
|
181
|
+
if (fundamental === Type.FLOAT)
|
|
182
|
+
return value.getFloat();
|
|
183
|
+
if (fundamental === Type.DOUBLE)
|
|
184
|
+
return value.getDouble();
|
|
185
|
+
if (fundamental === Type.STRING)
|
|
186
|
+
return value.getString();
|
|
187
|
+
if (fundamental === Type.ENUM)
|
|
188
|
+
return value.getEnum();
|
|
189
|
+
if (fundamental === Type.FLAGS)
|
|
190
|
+
return value.getFlags();
|
|
285
191
|
return undefined;
|
|
286
192
|
}
|
|
287
193
|
setProperty(key, value) {
|
|
@@ -290,21 +196,17 @@ export class WidgetNode extends Node {
|
|
|
290
196
|
return;
|
|
291
197
|
const [getterName, setterName] = propMeta;
|
|
292
198
|
const setter = this.container[setterName];
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
isObjectEqual(currentValue, value)) {
|
|
302
|
-
return;
|
|
199
|
+
if (!setter || typeof setter !== "function")
|
|
200
|
+
return;
|
|
201
|
+
if (getterName && findProperty(this.container, key) instanceof ParamSpecString) {
|
|
202
|
+
const getter = this.container[getterName];
|
|
203
|
+
if (getter && typeof getter === "function") {
|
|
204
|
+
const currentValue = getter.call(this.container);
|
|
205
|
+
if (currentValue === value)
|
|
206
|
+
return;
|
|
303
207
|
}
|
|
304
208
|
}
|
|
305
|
-
|
|
306
|
-
setter.call(this.container, value);
|
|
307
|
-
}
|
|
209
|
+
setter.call(this.container, value);
|
|
308
210
|
}
|
|
309
211
|
detachChildFromParent(child) {
|
|
310
212
|
const currentParent = child.container.getParent();
|
|
@@ -313,37 +215,21 @@ export class WidgetNode extends Node {
|
|
|
313
215
|
}
|
|
314
216
|
}
|
|
315
217
|
attachChild(child) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
this.container.
|
|
218
|
+
const strategy = getAttachmentStrategy(this.container);
|
|
219
|
+
if (!strategy) {
|
|
220
|
+
throw new Error(`Cannot append '${child.typeName}' to '${this.container.constructor.name}': container does not support children`);
|
|
319
221
|
}
|
|
320
|
-
|
|
222
|
+
if (strategy.type === "appendable" || strategy.type === "addable") {
|
|
321
223
|
this.detachChildFromParent(child);
|
|
322
|
-
this.container.add(child.container);
|
|
323
|
-
}
|
|
324
|
-
else if (hasSingleContent(this.container)) {
|
|
325
|
-
this.container.setContent(child.container);
|
|
326
|
-
}
|
|
327
|
-
else if (isSingleChild(this.container)) {
|
|
328
|
-
this.container.setChild(child.container);
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
throw new Error(`Cannot append '${child.typeName}' to '${this.container.constructor.name}': container does not support children`);
|
|
332
224
|
}
|
|
225
|
+
performAttachment(child.container, strategy);
|
|
333
226
|
}
|
|
334
227
|
detachChild(child) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
else if (hasSingleContent(this.container)) {
|
|
339
|
-
this.container.setContent(null);
|
|
340
|
-
}
|
|
341
|
-
else if (isSingleChild(this.container)) {
|
|
342
|
-
this.container.setChild(null);
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
228
|
+
const strategy = getAttachmentStrategy(this.container);
|
|
229
|
+
if (!strategy) {
|
|
345
230
|
throw new Error(`Cannot remove '${child.typeName}' from '${this.container.constructor.name}': container does not support child removal`);
|
|
346
231
|
}
|
|
232
|
+
performDetachment(child.container, strategy);
|
|
347
233
|
}
|
|
348
234
|
findPreviousSibling(before) {
|
|
349
235
|
let beforeChild = this.container.getFirstChild();
|
package/dist/nodes/window.d.ts
CHANGED
|
@@ -2,22 +2,28 @@ import * as Gtk from "@gtkx/ffi/gtk";
|
|
|
2
2
|
import type { Node } from "../node.js";
|
|
3
3
|
import type { Container, ContainerClass, Props } from "../types.js";
|
|
4
4
|
import { WidgetNode } from "./widget.js";
|
|
5
|
-
type
|
|
5
|
+
type CreditSection = {
|
|
6
|
+
name: string;
|
|
7
|
+
people: string[];
|
|
8
|
+
};
|
|
9
|
+
export type WindowProps = Props & {
|
|
6
10
|
defaultWidth?: number;
|
|
7
11
|
defaultHeight?: number;
|
|
8
12
|
onClose?: () => void;
|
|
13
|
+
creditSections?: CreditSection[];
|
|
9
14
|
};
|
|
10
15
|
export declare class WindowNode extends WidgetNode<Gtk.Window, WindowProps> {
|
|
11
16
|
static priority: number;
|
|
12
17
|
private menu;
|
|
13
18
|
static matches(_type: string, containerOrClass?: Container | ContainerClass | null): boolean;
|
|
14
|
-
static createContainer(props: Props, containerClass: typeof Gtk.Window, rootContainer
|
|
15
|
-
constructor(typeName: string, props: WindowProps, container: Gtk.Window, rootContainer
|
|
19
|
+
static createContainer(props: Props, containerClass: typeof Gtk.Window, rootContainer: Container | undefined): Gtk.Window;
|
|
20
|
+
constructor(typeName: string, props: WindowProps, container: Gtk.Window, rootContainer: Container);
|
|
16
21
|
appendChild(child: Node): void;
|
|
17
22
|
removeChild(child: Node): void;
|
|
18
23
|
insertBefore(child: Node, before: Node): void;
|
|
19
24
|
mount(): void;
|
|
20
25
|
unmount(): void;
|
|
21
26
|
updateProps(oldProps: WindowProps | null, newProps: WindowProps): void;
|
|
27
|
+
protected applyOwnProps(oldProps: WindowProps | null, newProps: WindowProps): void;
|
|
22
28
|
}
|
|
23
29
|
export {};
|
package/dist/nodes/window.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import * as Adw from "@gtkx/ffi/adw";
|
|
2
2
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
3
|
import { registerNodeClass } from "../registry.js";
|
|
4
|
-
import {
|
|
5
|
-
import { filterProps,
|
|
6
|
-
import {
|
|
4
|
+
import { DialogNode } from "./dialog.js";
|
|
5
|
+
import { filterProps, hasChanged, matchesAnyClass } from "./internal/utils.js";
|
|
6
|
+
import { MenuModel } from "./models/menu.js";
|
|
7
7
|
import { WidgetNode } from "./widget.js";
|
|
8
|
-
const
|
|
8
|
+
const OWN_PROPS = ["defaultWidth", "defaultHeight", "onClose"];
|
|
9
9
|
export class WindowNode extends WidgetNode {
|
|
10
10
|
static priority = 1;
|
|
11
11
|
menu;
|
|
12
12
|
static matches(_type, containerOrClass) {
|
|
13
|
-
return
|
|
13
|
+
return matchesAnyClass([Gtk.Window], containerOrClass);
|
|
14
14
|
}
|
|
15
15
|
static createContainer(props, containerClass, rootContainer) {
|
|
16
16
|
const WindowClass = containerClass;
|
|
17
|
-
if (
|
|
18
|
-
|
|
17
|
+
if (matchesAnyClass([Gtk.ApplicationWindow], WindowClass) ||
|
|
18
|
+
matchesAnyClass([Adw.ApplicationWindow], WindowClass)) {
|
|
19
19
|
if (!(rootContainer instanceof Gtk.Application)) {
|
|
20
20
|
throw new Error("Expected ApplicationWindow to be created within Application");
|
|
21
21
|
}
|
|
22
|
-
if (
|
|
22
|
+
if (matchesAnyClass([Adw.ApplicationWindow], WindowClass)) {
|
|
23
23
|
return new Adw.ApplicationWindow(rootContainer);
|
|
24
24
|
}
|
|
25
25
|
return new Gtk.ApplicationWindow(rootContainer);
|
|
@@ -30,13 +30,22 @@ export class WindowNode extends WidgetNode {
|
|
|
30
30
|
super(typeName, props, container, rootContainer);
|
|
31
31
|
const application = rootContainer instanceof Gtk.Application ? rootContainer : undefined;
|
|
32
32
|
const actionMap = container instanceof Gtk.ApplicationWindow ? container : undefined;
|
|
33
|
-
this.menu = new
|
|
33
|
+
this.menu = new MenuModel("root", {}, rootContainer, actionMap, application);
|
|
34
|
+
if (container instanceof Gtk.AboutDialog && props.creditSections) {
|
|
35
|
+
for (const section of props.creditSections) {
|
|
36
|
+
container.addCreditSection(section.name, section.people);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
34
39
|
}
|
|
35
40
|
appendChild(child) {
|
|
36
41
|
if (child.container instanceof Gtk.Window) {
|
|
37
42
|
child.container.setTransientFor(this.container);
|
|
38
43
|
return;
|
|
39
44
|
}
|
|
45
|
+
if (child instanceof DialogNode) {
|
|
46
|
+
child.parent = this.container;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
40
49
|
this.menu.appendChild(child);
|
|
41
50
|
super.appendChild(child);
|
|
42
51
|
}
|
|
@@ -45,6 +54,10 @@ export class WindowNode extends WidgetNode {
|
|
|
45
54
|
child.container.setTransientFor(null);
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
57
|
+
if (child instanceof DialogNode) {
|
|
58
|
+
child.parent = null;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
48
61
|
this.menu.removeChild(child);
|
|
49
62
|
super.removeChild(child);
|
|
50
63
|
}
|
|
@@ -61,22 +74,25 @@ export class WindowNode extends WidgetNode {
|
|
|
61
74
|
super.unmount();
|
|
62
75
|
}
|
|
63
76
|
updateProps(oldProps, newProps) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
77
|
+
super.updateProps(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
|
|
78
|
+
this.applyOwnProps(oldProps, newProps);
|
|
79
|
+
}
|
|
80
|
+
applyOwnProps(oldProps, newProps) {
|
|
81
|
+
if (hasChanged(oldProps, newProps, "defaultWidth") || hasChanged(oldProps, newProps, "defaultHeight")) {
|
|
67
82
|
const width = newProps.defaultWidth ?? -1;
|
|
68
83
|
const height = newProps.defaultHeight ?? -1;
|
|
69
84
|
this.container.setDefaultSize(width, height);
|
|
70
85
|
}
|
|
71
|
-
if (oldProps
|
|
86
|
+
if (hasChanged(oldProps, newProps, "onClose")) {
|
|
72
87
|
const userHandler = newProps.onClose;
|
|
73
|
-
const wrappedHandler =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
const wrappedHandler = userHandler
|
|
89
|
+
? () => {
|
|
90
|
+
userHandler();
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
: undefined;
|
|
94
|
+
this.signalStore.set(this, this.container, "close-request", wrappedHandler);
|
|
78
95
|
}
|
|
79
|
-
super.updateProps(filterProps(oldProps ?? {}, PROPS), filterProps(newProps, PROPS));
|
|
80
96
|
}
|
|
81
97
|
}
|
|
82
98
|
registerNodeClass(WindowNode);
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Node } from "./node.js";
|
|
2
2
|
import type { Container, Props } from "./types.js";
|
|
3
3
|
type NodeClass<T = unknown, P = Props> = {
|
|
4
|
-
new (typeName: string, props: P, container: T, rootContainer
|
|
4
|
+
new (typeName: string, props: P, container: T, rootContainer: Container): Node<T, P>;
|
|
5
5
|
} & Omit<typeof Node, "prototype">;
|
|
6
6
|
export declare const NODE_CLASSES: NodeClass[];
|
|
7
7
|
export declare const registerNodeClass: <T, P>(nodeClass: NodeClass<T, P>) => void;
|
package/dist/render.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { start, stop } from "@gtkx/ffi";
|
|
3
3
|
import { createContext, useContext } from "react";
|
|
4
4
|
import { formatBoundaryError, formatRenderError } from "./errors.js";
|
|
5
|
+
import { getSignalStore } from "./nodes/internal/signal-store.js";
|
|
5
6
|
import { reconciler } from "./reconciler.js";
|
|
6
7
|
/**
|
|
7
8
|
* React Context providing access to the GTK Application instance.
|
|
@@ -96,17 +97,18 @@ export const setHotReloading = (value) => {
|
|
|
96
97
|
* @see {@link update} for hot-reloading the rendered tree
|
|
97
98
|
*/
|
|
98
99
|
export const render = (element, appId, flags) => {
|
|
99
|
-
|
|
100
|
+
const application = start(appId, flags);
|
|
101
|
+
app = application;
|
|
100
102
|
const instance = reconciler.getInstance();
|
|
101
|
-
container = instance.createContainer(
|
|
102
|
-
|
|
103
|
+
container = instance.createContainer(application, 1, null, false, null, "", (error) => {
|
|
104
|
+
getSignalStore(application).forceUnblockAll();
|
|
103
105
|
throw formatRenderError(error);
|
|
104
106
|
}, (error) => {
|
|
105
|
-
|
|
107
|
+
getSignalStore(application).forceUnblockAll();
|
|
106
108
|
const formattedError = formatBoundaryError(error);
|
|
107
109
|
console.error(formattedError.toString());
|
|
108
110
|
}, () => { }, () => { }, null);
|
|
109
|
-
instance.updateContainer(_jsx(ApplicationContext.Provider, { value:
|
|
111
|
+
instance.updateContainer(_jsx(ApplicationContext.Provider, { value: application, children: element }), container, null, () => { });
|
|
110
112
|
};
|
|
111
113
|
/**
|
|
112
114
|
* Updates the rendered React element tree.
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
type Callback = () => void;
|
|
2
|
+
/**
|
|
3
|
+
* Priority levels for scheduling operations after React commit.
|
|
4
|
+
*
|
|
5
|
+
* Priority guidelines:
|
|
6
|
+
* - HIGH: Removals and detachments (must run before additions to avoid conflicts)
|
|
7
|
+
* - NORMAL: Additions and attachments (standard widget operations)
|
|
8
|
+
* - LOW: Sync operations that depend on all additions being complete (e.g., model updates)
|
|
9
|
+
*
|
|
10
|
+
* Within the same priority level, callbacks execute in FIFO order.
|
|
11
|
+
*/
|
|
2
12
|
export declare enum CommitPriority {
|
|
3
13
|
/** Runs first. Used for widget removals to unparent before reparenting. */
|
|
4
14
|
HIGH = 0,
|
|
5
15
|
/** Runs after HIGH priority. Used for widget additions. */
|
|
6
16
|
NORMAL = 1,
|
|
7
|
-
/** Runs
|
|
17
|
+
/** Runs after NORMAL. Used for model sync operations that need all data to be added first. */
|
|
8
18
|
LOW = 2
|
|
9
19
|
}
|
|
10
20
|
/**
|