@gtkx/codegen 1.2.2 → 1.4.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 (218) hide show
  1. package/README.md +6 -4
  2. package/dist/analysis/descriptor-render.d.ts +7 -1
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +37 -15
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +5 -1
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +12 -2
  9. package/dist/analysis/descriptor.js.map +1 -1
  10. package/dist/analysis/param-capability.d.ts +5 -2
  11. package/dist/analysis/param-capability.d.ts.map +1 -1
  12. package/dist/analysis/param-capability.js +36 -4
  13. package/dist/analysis/param-capability.js.map +1 -1
  14. package/dist/analysis/param-structure.d.ts +1 -1
  15. package/dist/analysis/param-structure.d.ts.map +1 -1
  16. package/dist/analysis/param-structure.js.map +1 -1
  17. package/dist/analysis/ts-type.d.ts +1 -1
  18. package/dist/analysis/ts-type.d.ts.map +1 -1
  19. package/dist/analysis/ts-type.js +28 -10
  20. package/dist/analysis/ts-type.js.map +1 -1
  21. package/dist/compile.js +1 -1
  22. package/dist/compile.js.map +1 -1
  23. package/dist/docs/api-reference.d.ts +6 -0
  24. package/dist/docs/api-reference.d.ts.map +1 -1
  25. package/dist/docs/api-reference.js +11 -2
  26. package/dist/docs/api-reference.js.map +1 -1
  27. package/dist/docs/pipeline.d.ts +3 -0
  28. package/dist/docs/pipeline.d.ts.map +1 -1
  29. package/dist/docs/pipeline.js +10 -1
  30. package/dist/docs/pipeline.js.map +1 -1
  31. package/dist/fingerprint.d.ts +5 -0
  32. package/dist/fingerprint.d.ts.map +1 -1
  33. package/dist/fingerprint.js +111 -15
  34. package/dist/fingerprint.js.map +1 -1
  35. package/dist/gi.d.ts +3 -0
  36. package/dist/gi.d.ts.map +1 -1
  37. package/dist/gi.js +33 -7
  38. package/dist/gi.js.map +1 -1
  39. package/dist/gir/external-namespaces.d.ts +8 -0
  40. package/dist/gir/external-namespaces.d.ts.map +1 -0
  41. package/dist/gir/external-namespaces.js +4 -0
  42. package/dist/gir/external-namespaces.js.map +1 -0
  43. package/dist/gir/finish-overrides.d.ts +3 -0
  44. package/dist/gir/finish-overrides.d.ts.map +1 -0
  45. package/dist/gir/finish-overrides.js +5 -0
  46. package/dist/gir/finish-overrides.js.map +1 -0
  47. package/dist/gir/function.d.ts +5 -2
  48. package/dist/gir/function.d.ts.map +1 -1
  49. package/dist/gir/function.js +34 -5
  50. package/dist/gir/function.js.map +1 -1
  51. package/dist/gir/hidden-symbols.d.ts +3 -0
  52. package/dist/gir/hidden-symbols.d.ts.map +1 -0
  53. package/dist/gir/hidden-symbols.js +39 -0
  54. package/dist/gir/hidden-symbols.js.map +1 -0
  55. package/dist/gir/library.d.ts +22 -2
  56. package/dist/gir/library.d.ts.map +1 -1
  57. package/dist/gir/library.js +21 -3
  58. package/dist/gir/library.js.map +1 -1
  59. package/dist/gir/ucs4-overrides.d.ts +3 -0
  60. package/dist/gir/ucs4-overrides.d.ts.map +1 -0
  61. package/dist/gir/ucs4-overrides.js +7 -0
  62. package/dist/gir/ucs4-overrides.js.map +1 -0
  63. package/dist/guards.d.ts +2 -1
  64. package/dist/guards.d.ts.map +1 -1
  65. package/dist/guards.js +3 -1
  66. package/dist/guards.js.map +1 -1
  67. package/dist/index.d.ts +2 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +2 -0
  70. package/dist/index.js.map +1 -1
  71. package/dist/jsx.d.ts.map +1 -1
  72. package/dist/jsx.js +27 -8
  73. package/dist/jsx.js.map +1 -1
  74. package/dist/runner.d.ts +8 -0
  75. package/dist/runner.d.ts.map +1 -1
  76. package/dist/runner.js +9 -3
  77. package/dist/runner.js.map +1 -1
  78. package/dist/store/external-package-links.d.ts +6 -0
  79. package/dist/store/external-package-links.d.ts.map +1 -0
  80. package/dist/store/external-package-links.js +158 -0
  81. package/dist/store/external-package-links.js.map +1 -0
  82. package/dist/store/gi/callable-doc.d.ts.map +1 -1
  83. package/dist/store/gi/callable-doc.js +4 -4
  84. package/dist/store/gi/callable-doc.js.map +1 -1
  85. package/dist/store/gi/callables.js +1 -1
  86. package/dist/store/gi/callables.js.map +1 -1
  87. package/dist/store/gi/class.d.ts.map +1 -1
  88. package/dist/store/gi/class.js +17 -0
  89. package/dist/store/gi/class.js.map +1 -1
  90. package/dist/store/gi/constructor-props.js +1 -1
  91. package/dist/store/gi/constructor-props.js.map +1 -1
  92. package/dist/store/gi/function.d.ts.map +1 -1
  93. package/dist/store/gi/function.js +2 -1
  94. package/dist/store/gi/function.js.map +1 -1
  95. package/dist/store/gi/generated-libraries.d.ts +26 -0
  96. package/dist/store/gi/generated-libraries.d.ts.map +1 -0
  97. package/dist/store/gi/generated-libraries.js +53 -0
  98. package/dist/store/gi/generated-libraries.js.map +1 -0
  99. package/dist/store/gi/gtype-binding.d.ts +2 -1
  100. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  101. package/dist/store/gi/gtype-binding.js +6 -1
  102. package/dist/store/gi/gtype-binding.js.map +1 -1
  103. package/dist/store/gi/method.d.ts +7 -2
  104. package/dist/store/gi/method.d.ts.map +1 -1
  105. package/dist/store/gi/method.js +126 -30
  106. package/dist/store/gi/method.js.map +1 -1
  107. package/dist/store/gi/param-marshal.d.ts +8 -1
  108. package/dist/store/gi/param-marshal.d.ts.map +1 -1
  109. package/dist/store/gi/param-marshal.js +52 -4
  110. package/dist/store/gi/param-marshal.js.map +1 -1
  111. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  112. package/dist/store/gi/record-constructor.js +2 -3
  113. package/dist/store/gi/record-constructor.js.map +1 -1
  114. package/dist/store/gi/record-field-accessor.d.ts +2 -1
  115. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  116. package/dist/store/gi/record-field-accessor.js +9 -3
  117. package/dist/store/gi/record-field-accessor.js.map +1 -1
  118. package/dist/store/gi/runtime-override.js +1 -1
  119. package/dist/store/gi/runtime-override.js.map +1 -1
  120. package/dist/store/gi/signal.js +2 -2
  121. package/dist/store/gi/signal.js.map +1 -1
  122. package/dist/store/gi/vtable.d.ts.map +1 -1
  123. package/dist/store/gi/vtable.js +82 -12
  124. package/dist/store/gi/vtable.js.map +1 -1
  125. package/dist/store/gi-store.d.ts +12 -2
  126. package/dist/store/gi-store.d.ts.map +1 -1
  127. package/dist/store/gi-store.js +24 -5
  128. package/dist/store/gi-store.js.map +1 -1
  129. package/dist/store/jsx/jsx.d.ts.map +1 -1
  130. package/dist/store/jsx/jsx.js +3 -1
  131. package/dist/store/jsx/jsx.js.map +1 -1
  132. package/dist/store/jsx/metadata.d.ts.map +1 -1
  133. package/dist/store/jsx/metadata.js +35 -60
  134. package/dist/store/jsx/metadata.js.map +1 -1
  135. package/dist/store/jsx-store.d.ts +8 -1
  136. package/dist/store/jsx-store.d.ts.map +1 -1
  137. package/dist/store/jsx-store.js +9 -2
  138. package/dist/store/jsx-store.js.map +1 -1
  139. package/dist/store/resolve-store.d.ts +2 -1
  140. package/dist/store/resolve-store.d.ts.map +1 -1
  141. package/dist/store/resolve-store.js +3 -1
  142. package/dist/store/resolve-store.js.map +1 -1
  143. package/dist/store/store-fs.d.ts +2 -1
  144. package/dist/store/store-fs.d.ts.map +1 -1
  145. package/dist/store/store-fs.js +8 -3
  146. package/dist/store/store-fs.js.map +1 -1
  147. package/dist/writer/context.d.ts.map +1 -1
  148. package/dist/writer/context.js +8 -0
  149. package/dist/writer/context.js.map +1 -1
  150. package/dist/writer/gtk-doc.d.ts.map +1 -1
  151. package/dist/writer/gtk-doc.js +27 -1
  152. package/dist/writer/gtk-doc.js.map +1 -1
  153. package/overrides/gdk/rgba.ts.ejs +15 -1
  154. package/overrides/glib/index.ts.ejs +3 -0
  155. package/overrides/glib/regex.ts.ejs +66 -0
  156. package/overrides/gobject/index.ts.ejs +3 -0
  157. package/overrides/gobject/object-class.ts.ejs +27 -0
  158. package/overrides/gobject/param-spec-getters.ts.ejs +57 -0
  159. package/overrides/gobject/param-spec.ts.ejs +21 -0
  160. package/overrides/gobject/value.ts.ejs +6 -1
  161. package/overrides/graphene/structs.ts.ejs +38 -3
  162. package/overrides/gtk/index.ts.ejs +2 -0
  163. package/overrides/gtk/widget-class.ts.ejs +28 -0
  164. package/package.json +7 -6
  165. package/src/analysis/descriptor-render.ts +60 -16
  166. package/src/analysis/descriptor.ts +17 -3
  167. package/src/analysis/param-capability.ts +68 -5
  168. package/src/analysis/param-structure.ts +1 -1
  169. package/src/analysis/ts-type.ts +45 -11
  170. package/src/compile.ts +1 -1
  171. package/src/docs/api-reference.ts +20 -2
  172. package/src/docs/pipeline.ts +15 -1
  173. package/src/fingerprint.ts +151 -16
  174. package/src/gi.ts +48 -9
  175. package/src/gir/external-namespaces.ts +8 -0
  176. package/src/gir/finish-overrides.ts +5 -0
  177. package/src/gir/function.ts +52 -14
  178. package/src/gir/hidden-symbols.ts +39 -0
  179. package/src/gir/library.ts +36 -3
  180. package/src/gir/ucs4-overrides.ts +7 -0
  181. package/src/guards.ts +6 -1
  182. package/src/index.ts +2 -0
  183. package/src/jsx.ts +33 -8
  184. package/src/runner.ts +17 -3
  185. package/src/store/external-package-links.ts +226 -0
  186. package/src/store/gi/callable-doc.ts +8 -4
  187. package/src/store/gi/callables.ts +1 -1
  188. package/src/store/gi/class.ts +29 -0
  189. package/src/store/gi/constructor-props.ts +1 -1
  190. package/src/store/gi/function.ts +2 -1
  191. package/src/store/gi/generated-libraries.ts +91 -0
  192. package/src/store/gi/gtype-binding.ts +8 -1
  193. package/src/store/gi/method.ts +189 -36
  194. package/src/store/gi/param-marshal.ts +67 -4
  195. package/src/store/gi/record-constructor.ts +8 -3
  196. package/src/store/gi/record-field-accessor.ts +11 -2
  197. package/src/store/gi/runtime-override.ts +1 -1
  198. package/src/store/gi/signal.ts +2 -2
  199. package/src/store/gi/vtable.ts +118 -11
  200. package/src/store/gi-store.ts +48 -5
  201. package/src/store/jsx/jsx.ts +3 -1
  202. package/src/store/jsx/metadata.ts +46 -99
  203. package/src/store/jsx-store.ts +23 -7
  204. package/src/store/resolve-store.ts +3 -1
  205. package/src/store/store-fs.ts +10 -2
  206. package/src/writer/context.ts +11 -0
  207. package/src/writer/gtk-doc.ts +38 -1
  208. package/overrides/cairo/context.ts.ejs +0 -1269
  209. package/overrides/cairo/font-face.ts.ejs +0 -151
  210. package/overrides/cairo/font-options.ts.ejs +0 -199
  211. package/overrides/cairo/image-surface.ts.ejs +0 -132
  212. package/overrides/cairo/index.ts.ejs +0 -22
  213. package/overrides/cairo/matrix.ts.ejs +0 -171
  214. package/overrides/cairo/pattern.ts.ejs +0 -476
  215. package/overrides/cairo/recording-surface.ts.ejs +0 -102
  216. package/overrides/cairo/region.ts.ejs +0 -237
  217. package/overrides/cairo/scaled-font.ts.ejs +0 -330
  218. package/overrides/cairo/surface.ts.ejs +0 -296
@@ -6,6 +6,7 @@ import { Point as GeneratedPoint, Rect as GeneratedRect, Size as GeneratedSize }
6
6
  * @param x the X coordinate
7
7
  * @param y the Y coordinate
8
8
  * @returns the initialized point
9
+ * @deprecated Since 1.3. Use `new Point({ x, y })` instead. Removed in v2.
9
10
  */
10
11
  const createPoint = (x: number, y: number): GeneratedPoint => {
11
12
  const point = GeneratedPoint.alloc();
@@ -21,6 +22,7 @@ const createPoint = (x: number, y: number): GeneratedPoint => {
21
22
  * @param width the width of the rectangle
22
23
  * @param height the height of the rectangle
23
24
  * @returns the initialized rectangle
25
+ * @deprecated Since 1.3. Use `new Rect()` and `init(x, y, width, height)` instead. Removed in v2.
24
26
  */
25
27
  const createRect = (x: number, y: number, width: number, height: number): GeneratedRect => {
26
28
  const rect = GeneratedRect.alloc();
@@ -34,6 +36,7 @@ const createRect = (x: number, y: number, width: number, height: number): Genera
34
36
  * @param width the width
35
37
  * @param height the height
36
38
  * @returns the initialized size
39
+ * @deprecated Since 1.3. Use `new Size({ width, height })` instead. Removed in v2.
37
40
  */
38
41
  const createSize = (width: number, height: number): GeneratedSize => {
39
42
  const size = GeneratedSize.alloc();
@@ -42,7 +45,17 @@ const createSize = (width: number, height: number): GeneratedSize => {
42
45
  };
43
46
 
44
47
  /** A point with two coordinates. */
45
- export const Point: typeof GeneratedPoint & { create: typeof createPoint } = Object.assign(GeneratedPoint, {
48
+ export const Point: typeof GeneratedPoint & {
49
+ /**
50
+ * Allocates a new `Point` and initializes it to the given coordinates.
51
+ *
52
+ * @param x the X coordinate
53
+ * @param y the Y coordinate
54
+ * @returns the initialized point
55
+ * @deprecated Since 1.3. Use `new Point({ x, y })` instead. Removed in v2.
56
+ */
57
+ create: typeof createPoint;
58
+ } = Object.assign(GeneratedPoint, {
46
59
  create: createPoint,
47
60
  });
48
61
 
@@ -63,7 +76,19 @@ export type Point = GeneratedPoint;
63
76
  * will internally operate on a normalized copy; all functions returning a
64
77
  * `graphene_rect_t` will always return a normalized rectangle.
65
78
  */
66
- export const Rect: typeof GeneratedRect & { create: typeof createRect } = Object.assign(GeneratedRect, {
79
+ export const Rect: typeof GeneratedRect & {
80
+ /**
81
+ * Allocates a new `Rect` and initializes it to the given origin and size.
82
+ *
83
+ * @param x the X coordinate of the origin
84
+ * @param y the Y coordinate of the origin
85
+ * @param width the width of the rectangle
86
+ * @param height the height of the rectangle
87
+ * @returns the initialized rectangle
88
+ * @deprecated Since 1.3. Use `new Rect()` and `init(x, y, width, height)` instead. Removed in v2.
89
+ */
90
+ create: typeof createRect;
91
+ } = Object.assign(GeneratedRect, {
67
92
  create: createRect,
68
93
  });
69
94
 
@@ -84,7 +109,17 @@ export const Rect: typeof GeneratedRect & { create: typeof createRect } = Object
84
109
  export type Rect = GeneratedRect;
85
110
 
86
111
  /** A size. */
87
- export const Size: typeof GeneratedSize & { create: typeof createSize } = Object.assign(GeneratedSize, {
112
+ export const Size: typeof GeneratedSize & {
113
+ /**
114
+ * Allocates a new `Size` and initializes it to the given width and height.
115
+ *
116
+ * @param width the width
117
+ * @param height the height
118
+ * @returns the initialized size
119
+ * @deprecated Since 1.3. Use `new Size({ width, height })` instead. Removed in v2.
120
+ */
121
+ create: typeof createSize;
122
+ } = Object.assign(GeneratedSize, {
88
123
  create: createSize,
89
124
  });
90
125
 
@@ -0,0 +1,2 @@
1
+ export * from "./gtk.js";
2
+ export { WidgetClass } from "./overrides/widget-class.js";
@@ -0,0 +1,28 @@
1
+ import { type AnyClass, peekTypeClass } from "@gtkx/runtime";
2
+ import { type Type } from "../../gobject/gobject.js";
3
+ import { Widget, WidgetClass as GeneratedWidgetClass } from "../gtk.js";
4
+
5
+ const peek = (type: Type | AnyClass): GeneratedWidgetClass => peekTypeClass(type, Widget) as GeneratedWidgetClass;
6
+
7
+ /**
8
+ * The class structure for the GtkWidget type, with a static `peek` that hands back the class
9
+ * struct of any widget type so class-level introspection such as `getCssName` works outside a
10
+ * `classInit` hook.
11
+ */
12
+ export const WidgetClass: typeof GeneratedWidgetClass & {
13
+ /**
14
+ * Returns the class struct of a widget type, referencing the class so it exists even before
15
+ * the type's first instance. The reference is deliberately never released: once created, a
16
+ * class struct lives for the rest of the process.
17
+ *
18
+ * @param type GType to peek the class struct of, or a registered wrapper class of the type.
19
+ * @returns the widget type's class struct
20
+ * @throws when `type` is not a type deriving from `Gtk.Widget`
21
+ */
22
+ peek: typeof peek;
23
+ } = Object.assign(GeneratedWidgetClass, { peek });
24
+
25
+ /**
26
+ * The class structure for the GtkWidget type.
27
+ */
28
+ export type WidgetClass = GeneratedWidgetClass;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gtkx/codegen",
3
- "version": "1.2.2",
4
- "description": "Generates the typed GTKX bindings and API reference from GIR and OpenGL registry data",
3
+ "version": "1.4.0",
4
+ "description": "Generates typed GTK bindings and API docs from GIR and GL registries.",
5
5
  "keywords": [
6
6
  "gtkx",
7
7
  "gtk",
@@ -55,11 +55,12 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "@types/node": "^26.2.0",
58
- "fast-xml-parser": "^5.10.1",
59
- "fast-xml-validator": "^1.4.1",
58
+ "fast-xml-parser": "^5.11.0",
59
+ "fast-xml-validator": "^1.4.2",
60
60
  "typescript": "^6.0.3",
61
- "@gtkx/utils": "1.2.2",
62
- "@gtkx/react": "1.2.2"
61
+ "@gtkx/cairo": "1.4.0",
62
+ "@gtkx/utils": "1.4.0",
63
+ "@gtkx/react": "1.4.0"
63
64
  },
64
65
  "scripts": {
65
66
  "release": "tsx ../../scripts/release-package.ts"
@@ -65,6 +65,7 @@ type ArgIndexOptions = {
65
65
  };
66
66
 
67
67
  type CursorArgIndexOptions = ArgIndexOptions & { cursor: GirCursorBounds };
68
+ type CArrayExpressionOptions = ArgIndexOptions & { isCallerAllocated: boolean };
68
69
 
69
70
  type RenderDescriptorOptions = Partial<ArgIndexOptions> & {
70
71
  isCallerAllocated?: boolean;
@@ -77,6 +78,11 @@ type RecordPlacement = {
77
78
  isInline?: boolean;
78
79
  };
79
80
 
81
+ type RecordLayout = {
82
+ isCallerAllocated: boolean;
83
+ isInline: boolean;
84
+ };
85
+
80
86
  type FundamentalDescriptor = {
81
87
  lib: string;
82
88
  refFunc: string;
@@ -84,6 +90,7 @@ type FundamentalDescriptor = {
84
90
  typeName: string | undefined;
85
91
  ownership: Ownership;
86
92
  wrapperClass?: string | undefined;
93
+ isCallerAllocated?: boolean | undefined;
87
94
  isInline?: boolean | undefined;
88
95
  };
89
96
 
@@ -103,6 +110,7 @@ type FundamentalRecordOptions = {
103
110
  unrefFunc: string;
104
111
  ownership: Ownership;
105
112
  wrapperClass: string | undefined;
113
+ isCallerAllocated: boolean;
106
114
  isInline: boolean;
107
115
  };
108
116
 
@@ -189,7 +197,7 @@ const renderDescriptor = (
189
197
  return tVoid;
190
198
  }
191
199
  case "callback": {
192
- return tUint64;
200
+ return tBiguint64;
193
201
  }
194
202
  case "class":
195
203
  case "interface":
@@ -199,7 +207,10 @@ const renderDescriptor = (
199
207
  return expressionForResolved(context, type, transfer, options);
200
208
  }
201
209
  case "carray": {
202
- return arrayExpression(context, type, transfer, indexOptions);
210
+ return arrayExpression(context, type, transfer, {
211
+ ...indexOptions,
212
+ isCallerAllocated: options.isCallerAllocated === true,
213
+ });
203
214
  }
204
215
  case "list": {
205
216
  return listExpression(context, type, transfer, indexOptions);
@@ -333,7 +344,11 @@ const findUserDataIndex = (parameters: GirParameter[]): number | undefined => {
333
344
  return declared?.closureIndex ?? userDataIndexByName(parameters);
334
345
  };
335
346
 
336
- const callbackOptionsArg = (owningParameter: GirParameter, userDataIndex: number | undefined): string[] => {
347
+ const callbackOptionsArg = (
348
+ owningParameter: GirParameter,
349
+ userDataIndex: number | undefined,
350
+ canThrow: boolean,
351
+ ): string[] => {
337
352
  const options: string[] = [];
338
353
 
339
354
  if (owningParameter.destroyIndex !== undefined) {
@@ -348,6 +363,10 @@ const callbackOptionsArg = (owningParameter: GirParameter, userDataIndex: number
348
363
  options.push(`userDataIndex: ${String(userDataIndex)}`);
349
364
  }
350
365
 
366
+ if (canThrow) {
367
+ options.push("canThrow: true");
368
+ }
369
+
351
370
  if (owningParameter.scope !== undefined) {
352
371
  options.push(`scope: ${sourceStringLiteral(owningParameter.scope)}`);
353
372
  }
@@ -376,7 +395,7 @@ const renderCallbackType = (
376
395
  return tCallback({
377
396
  argTypes,
378
397
  returns: renderDescriptor(context, returnValue.type, returnValue.transferOwnership),
379
- options: callbackOptionsArg(owningParameter, findUserDataIndex(callback.parameters)),
398
+ options: callbackOptionsArg(owningParameter, findUserDataIndex(callback.parameters), callback.throws),
380
399
  });
381
400
  };
382
401
 
@@ -401,12 +420,13 @@ const primitiveExpression = (category: PrimitiveCategory, ownership: Ownership):
401
420
  };
402
421
 
403
422
  const renderFundamental = (descriptor: FundamentalDescriptor): string => {
404
- const { lib, refFunc, unrefFunc, typeName, ownership, wrapperClass, isInline } = descriptor;
423
+ const { lib, refFunc, unrefFunc, typeName, ownership, wrapperClass, isCallerAllocated, isInline } = descriptor;
405
424
 
406
425
  return tFundamental(lib, refFunc, unrefFunc, {
407
426
  ownership,
408
427
  typeName,
409
428
  wrapperClass,
429
+ isCallerAllocated,
410
430
  isInline,
411
431
  });
412
432
  };
@@ -529,6 +549,11 @@ const renderSelfDescriptor = (context: ModuleContext, instance: GirParameter): s
529
549
  return tObject("borrowed");
530
550
  };
531
551
 
552
+ const recordLayout = (placement: RecordPlacement): RecordLayout => ({
553
+ isCallerAllocated: placement.isCallerAllocated ?? false,
554
+ isInline: placement.isInline ?? false,
555
+ });
556
+
532
557
  const recordRefPair = (record: ResolvedRecord): { refFunc: string | undefined; unrefFunc: string | undefined } => ({
533
558
  refFunc: record.glibRefFunc ?? record.copyFunc,
534
559
  unrefFunc: record.glibUnrefFunc ?? record.freeFunc,
@@ -563,7 +588,7 @@ const structExpression = (
563
588
  };
564
589
 
565
590
  const fundamentalRecordExpression = (options: FundamentalRecordOptions): string => {
566
- const { resolved, lib, refFunc, unrefFunc, ownership, wrapperClass, isInline } = options;
591
+ const { resolved, lib, refFunc, unrefFunc, ownership, wrapperClass, isCallerAllocated, isInline } = options;
567
592
 
568
593
  return renderFundamental({
569
594
  lib,
@@ -572,6 +597,7 @@ const fundamentalRecordExpression = (options: FundamentalRecordOptions): string
572
597
  typeName: resolved.value.glibTypeName,
573
598
  ownership,
574
599
  wrapperClass,
600
+ isCallerAllocated,
575
601
  isInline,
576
602
  });
577
603
  };
@@ -593,6 +619,7 @@ const boxedRecordExpression = (options: {
593
619
  ownership,
594
620
  sharedLibrary: resolved.namespace.sharedLibrary,
595
621
  getTypeFnName: typeFnName,
622
+ freeFnName: record.freeFunc,
596
623
  isCallerAllocated,
597
624
  isInline,
598
625
  size: size > 0 ? size : undefined,
@@ -606,11 +633,7 @@ const plainRecordExpression = (
606
633
  placement: RecordPlacement,
607
634
  ): string => {
608
635
  const record = resolved.value;
609
-
610
- const layout = {
611
- isCallerAllocated: placement.isCallerAllocated ?? false,
612
- isInline: placement.isInline ?? false,
613
- };
636
+ const layout = recordLayout(placement);
614
637
 
615
638
  if (record.glibGetType === undefined) {
616
639
  return structExpression(context, resolved, ownership, layout);
@@ -619,6 +642,17 @@ const plainRecordExpression = (
619
642
  return boxedRecordExpression({ context, resolved, ownership, ...layout, typeFnName: record.glibGetType });
620
643
  };
621
644
 
645
+ const isPlainStruct = (resolved: Extract<EntityType, { kind: "record" }>): boolean => {
646
+ const record = resolved.value;
647
+ const { refFunc, unrefFunc } = recordRefPair(record);
648
+
649
+ if (refFunc !== undefined && unrefFunc !== undefined && resolved.namespace.sharedLibrary !== undefined) {
650
+ return false;
651
+ }
652
+
653
+ return record.glibGetType === undefined;
654
+ };
655
+
622
656
  const recordExpression = (
623
657
  context: ModuleContext,
624
658
  resolved: Extract<EntityType, { kind: "record" }>,
@@ -641,7 +675,7 @@ const recordExpression = (
641
675
  unrefFunc,
642
676
  ownership,
643
677
  wrapperClass,
644
- isInline: placement.isInline ?? false,
678
+ ...recordLayout(placement),
645
679
  });
646
680
  }
647
681
 
@@ -650,16 +684,20 @@ const recordExpression = (
650
684
 
651
685
  const rawEnumDescriptor = (isSigned: boolean): string => (isSigned ? tInt32 : tUint32);
652
686
 
687
+ const flagsMask = (resolved: Extract<EntityType, { kind: "enum" }>): number =>
688
+ resolved.value.members.reduce((mask, member) => (mask | Number(member.value)) >>> 0, 0);
689
+
653
690
  const enumExpression = (resolved: Extract<EntityType, { kind: "enum" }>): string => {
654
691
  const getter = resolved.value.glibGetType;
655
692
  const isSigned = resolved.value.members.some((member) => member.value.startsWith("-"));
656
693
  const lib = resolved.namespace.sharedLibrary;
694
+ const isBitfield = resolved.value.kind === "bitfield";
657
695
 
658
696
  if (getter === undefined || getter === "" || lib === undefined) {
659
- return rawEnumDescriptor(isSigned);
697
+ return isBitfield ? tFlags("", "", isSigned, flagsMask(resolved)) : rawEnumDescriptor(isSigned);
660
698
  }
661
699
 
662
- return resolved.value.kind === "bitfield" ? tFlags(lib, getter, isSigned) : tEnum(lib, getter, isSigned);
700
+ return isBitfield ? tFlags(lib, getter, isSigned) : tEnum(lib, getter, isSigned);
663
701
  };
664
702
 
665
703
  const expressionForResolved = (
@@ -700,6 +738,7 @@ const elementExpression = (
700
738
  ...options,
701
739
  cursor: undefined,
702
740
  hasOutIndirection: false,
741
+ isCallerAllocated: false,
703
742
  });
704
743
 
705
744
  const cursorArrayExpression = (
@@ -724,11 +763,14 @@ const arrayLayout = (context: ModuleContext, ref: CArrayType, options: ArgIndexO
724
763
  context.library.isByteArrayTyped && !hasUnknownArrayLength(ref) && isByteSequence(context.library, ref),
725
764
  });
726
765
 
766
+ const fixedArrayLayout = (layout: ArrayLayout, isCallerAllocated: boolean): ArrayLayout =>
767
+ isCallerAllocated ? { ...layout, isCallerAllocated: true } : layout;
768
+
727
769
  const arrayExpression = (
728
770
  context: ModuleContext,
729
771
  ref: CArrayType,
730
772
  transfer: ParameterTransfer,
731
- options: ArgIndexOptions,
773
+ options: CArrayExpressionOptions,
732
774
  ): string => {
733
775
  const { cursor } = options;
734
776
  const layout = arrayLayout(context, ref, options);
@@ -749,7 +791,7 @@ const arrayExpression = (
749
791
  }
750
792
 
751
793
  if (ref.fixedSize !== undefined) {
752
- return tFixedArray(element, ref.fixedSize, ownership, layout);
794
+ return tFixedArray(element, ref.fixedSize, ownership, fixedArrayLayout(layout, options.isCallerAllocated));
753
795
  }
754
796
 
755
797
  return tArray(element, ownership, layout);
@@ -789,6 +831,8 @@ const aliasExpression = (
789
831
  };
790
832
 
791
833
  export {
834
+ isPlainStruct,
835
+ transferOwnership,
792
836
  isInlineCallbackRef,
793
837
  isSkippedPrimaryReturn,
794
838
  isVoidPrimaryReturn,
@@ -66,6 +66,7 @@ type BoxedOptions = {
66
66
  ownership: Ownership;
67
67
  sharedLibrary: string | undefined;
68
68
  getTypeFnName: string;
69
+ freeFnName: string | undefined;
69
70
  isCallerAllocated: boolean;
70
71
  isInline?: boolean;
71
72
  size: number | undefined;
@@ -82,6 +83,7 @@ type FundamentalOptions = {
82
83
  ownership: Ownership;
83
84
  typeName: string | undefined;
84
85
  wrapperClass: string | undefined;
86
+ isCallerAllocated?: boolean | undefined;
85
87
  isInline?: boolean | undefined;
86
88
  };
87
89
 
@@ -90,6 +92,7 @@ type ListDescriptorName = "list" | "slist" | "ptrArray" | "gArray";
90
92
  type ArrayLayout = {
91
93
  elementSize?: number | undefined;
92
94
  isBytes: boolean;
95
+ isCallerAllocated?: boolean | undefined;
93
96
  };
94
97
 
95
98
  type BindArgs = {
@@ -103,6 +106,7 @@ type FnSpecParts = {
103
106
  args: string;
104
107
  returns: string;
105
108
  isReturnSkipped: boolean;
109
+ isReturnUnpacked: boolean;
106
110
  canThrow: boolean;
107
111
  };
108
112
 
@@ -113,6 +117,7 @@ type CallbackSpecParts = {
113
117
  };
114
118
 
115
119
  const SKIPPED_RETURN_ENTRY = "isReturnSkipped: true";
120
+ const UNPACKED_RETURN_ENTRY = "isReturnUnpacked: true";
116
121
 
117
122
  const T: DescriptorNames = {
118
123
  bind: "t.bind",
@@ -189,6 +194,7 @@ const tBoxed = (glibName: string, options: BoxedOptions): string =>
189
194
  ? undefined
190
195
  : `sharedLibrary: ${sourceStringLiteral(options.sharedLibrary)}`,
191
196
  `getTypeFnName: ${sourceStringLiteral(options.getTypeFnName)}`,
197
+ options.freeFnName === undefined ? undefined : `freeFnName: ${sourceStringLiteral(options.freeFnName)}`,
192
198
  options.isCallerAllocated ? "isCallerAllocated: true" : undefined,
193
199
  options.isInline === true ? "isInline: true" : undefined,
194
200
  options.size === undefined ? undefined : `size: ${String(options.size)}`,
@@ -218,6 +224,7 @@ const tFundamental = (lib: string, refFunc: string, unrefFunc: string, options:
218
224
  `ownership: ${sourceStringLiteral(options.ownership)}`,
219
225
  options.typeName === undefined ? undefined : `typeName: ${sourceStringLiteral(options.typeName)}`,
220
226
  options.wrapperClass === undefined ? undefined : `wrapperClass: ${options.wrapperClass}`,
227
+ options.isCallerAllocated === true ? "isCallerAllocated: true" : undefined,
221
228
  options.isInline === true ? "isInline: true" : undefined,
222
229
  ]),
223
230
  ]);
@@ -230,8 +237,13 @@ const tHashTable = (key: string, value: string, ownership: Ownership): string =>
230
237
  const tEnum = (lib: string, typeFnName: string, isSigned: boolean): string =>
231
238
  call("enum", [sourceStringLiteral(lib), sourceStringLiteral(typeFnName), String(isSigned)]);
232
239
 
233
- const tFlags = (lib: string, typeFnName: string, isSigned: boolean): string =>
234
- call("flags", [sourceStringLiteral(lib), sourceStringLiteral(typeFnName), String(isSigned)]);
240
+ const tFlags = (lib: string, typeFnName: string, isSigned: boolean, mask?: number): string =>
241
+ call("flags", [
242
+ sourceStringLiteral(lib),
243
+ sourceStringLiteral(typeFnName),
244
+ String(isSigned),
245
+ mask === undefined ? undefined : `0x${mask.toString(16)}`,
246
+ ]);
235
247
 
236
248
  const tByteArray = (ownership: Ownership): string => call("byteArray", [sourceStringLiteral(ownership)]);
237
249
 
@@ -253,6 +265,7 @@ const arrayLayoutArg = (ownership: Ownership | undefined, layout: ArrayLayout):
253
265
  const entries = [
254
266
  layout.elementSize === undefined ? undefined : `elementSize: ${String(layout.elementSize)}`,
255
267
  layout.isBytes ? "isBytes: true" : undefined,
268
+ layout.isCallerAllocated === true ? "isCallerAllocated: true" : undefined,
256
269
  ].filter((entry): entry is string => entry !== undefined);
257
270
 
258
271
  return entries.length === 0 ? undefined : `{ ${entries.join(", ")} }`;
@@ -311,12 +324,13 @@ const tBind = (args: BindArgs): string =>
311
324
 
312
325
  const tFn = (lib: string, cIdentifier: string, spec: FnSpecParts): string => {
313
326
  const skipEntry = spec.isReturnSkipped ? `, ${SKIPPED_RETURN_ENTRY}` : "";
327
+ const unpackEntry = spec.isReturnUnpacked ? `, ${UNPACKED_RETURN_ENTRY}` : "";
314
328
  const throwsEntry = spec.canThrow ? ", canThrow: true" : "";
315
329
 
316
330
  return call("fn", [
317
331
  sourceStringLiteral(lib),
318
332
  sourceStringLiteral(cIdentifier),
319
- `{ args: ${spec.args}, returns: ${spec.returns}${skipEntry}${throwsEntry} }`,
333
+ `{ args: ${spec.args}, returns: ${spec.returns}${skipEntry}${unpackEntry}${throwsEntry} }`,
320
334
  ]);
321
335
  };
322
336
 
@@ -1,11 +1,20 @@
1
- import type { GirCallable, GirParameter } from "../gir/parameter.js";
1
+ import type { GirCallable, GirParameter, ParameterTransfer } from "../gir/parameter.js";
2
2
  import type { CArrayType, TypeId } from "../gir/type-id.js";
3
3
  import type { GirType } from "../gir/type.js";
4
4
  import type { ModuleContext } from "../writer/context.js";
5
5
  import { isCallerAllocatedOut, isInoutParameter } from "../gir/parameter.js";
6
- import { isCollectibleCallerOut, isHandlePassedInPlace, underlyingType } from "../store/gi/param-marshal.js";
6
+ import {
7
+ isCollectibleCallerOut,
8
+ isFixedArrayCallerOut,
9
+ isHandlePassedInPlace,
10
+ isRecordInout,
11
+ underlyingType,
12
+ } from "../store/gi/param-marshal.js";
7
13
  import { recordInlineSize } from "../store/gi/record-layout.js";
8
- import { isScalarRef } from "./descriptor-render.js";
14
+ import { isPlainStruct, isScalarRef, transferOwnership } from "./descriptor-render.js";
15
+ import { closureAndDestroyIndices } from "./param-structure.js";
16
+
17
+ type UnmarshalableSubject = GirCallable & { instance?: GirParameter | undefined };
9
18
 
10
19
  const POINTER_DEPTH = 1;
11
20
 
@@ -119,6 +128,10 @@ const isUnmarshalableCallerOut = (context: ModuleContext, parameter: GirParamete
119
128
  return true;
120
129
  }
121
130
 
131
+ if (isFixedArrayCallerOut(context, parameter)) {
132
+ return false;
133
+ }
134
+
122
135
  return !isCollectibleCallerOut(context, parameter) && !parameter.optional;
123
136
  };
124
137
 
@@ -143,12 +156,59 @@ const isTypeErasedCallback = (context: ModuleContext, parameter: GirParameter):
143
156
  return type?.kind === "callback" && type.value.parameters.length === 0;
144
157
  };
145
158
 
159
+ const isCallbackParam = (context: ModuleContext, parameter: GirParameter): boolean => {
160
+ const type = parameter.type === undefined ? undefined : underlyingType(context, parameter.type);
161
+
162
+ return type?.kind === "callback";
163
+ };
164
+
165
+ const hasDetachedClosure = (parameter: GirParameter, index: number): boolean => {
166
+ const userDataIndex = parameter.closureIndex;
167
+
168
+ if (userDataIndex !== undefined && userDataIndex !== index + 1) {
169
+ return true;
170
+ }
171
+
172
+ const notifyIndex = parameter.destroyIndex;
173
+
174
+ return notifyIndex !== undefined && notifyIndex !== index + (userDataIndex === undefined ? 1 : 2);
175
+ };
176
+
177
+ const hasDetachedCallback = (context: ModuleContext, parameters: GirParameter[]): boolean => {
178
+ const claimed = closureAndDestroyIndices({ parameters });
179
+
180
+ return parameters.some(
181
+ (parameter, index) =>
182
+ !claimed.has(index) && isCallbackParam(context, parameter) && hasDetachedClosure(parameter, index),
183
+ );
184
+ };
185
+
186
+ const isRefusedTransfer = (
187
+ context: ModuleContext,
188
+ ref: TypeId | undefined,
189
+ transfer: ParameterTransfer,
190
+ ): boolean => {
191
+ if (ref === undefined || transferOwnership(transfer) !== "full") {
192
+ return false;
193
+ }
194
+
195
+ const type = underlyingType(context, ref);
196
+
197
+ return type?.kind === "record" && isPlainStruct(type);
198
+ };
199
+
200
+ const isLentInPlace = (context: ModuleContext, parameter: GirParameter): boolean =>
201
+ isCallerAllocatedOut(parameter) || isRecordInout(context, parameter);
202
+
203
+ const isRefusedParamTransfer = (context: ModuleContext, parameter: GirParameter): boolean =>
204
+ !isLentInPlace(context, parameter) && isRefusedTransfer(context, parameter.type, parameter.transferOwnership);
205
+
146
206
  const isUnmarshalableCallParam = (context: ModuleContext, parameter: GirParameter): boolean => {
147
207
  if (parameter.isVarargs) {
148
208
  return false;
149
209
  }
150
210
 
151
- if (isTypeErasedCallback(context, parameter)) {
211
+ if (isTypeErasedCallback(context, parameter) || isRefusedParamTransfer(context, parameter)) {
152
212
  return true;
153
213
  }
154
214
 
@@ -163,7 +223,10 @@ const isUnmarshalableCallParam = (context: ModuleContext, parameter: GirParamete
163
223
  return hasIndirectionMismatch(context, parameter);
164
224
  };
165
225
 
166
- const hasUnmarshalableParam = (context: ModuleContext, callable: GirCallable): boolean =>
226
+ const hasUnmarshalableParam = (context: ModuleContext, callable: UnmarshalableSubject): boolean =>
227
+ (callable.instance !== undefined && isRefusedParamTransfer(context, callable.instance)) ||
228
+ isRefusedTransfer(context, callable.returnValue.type, callable.returnValue.transferOwnership) ||
229
+ hasDetachedCallback(context, callable.parameters) ||
167
230
  callable.parameters.some((parameter) => isUnmarshalableCallParam(context, parameter));
168
231
 
169
232
  export { hasUnmarshalableParam };
@@ -61,7 +61,7 @@ const inputParameters = (library: Library, fn: GirFunction): InputParameter[] =>
61
61
  return result;
62
62
  };
63
63
 
64
- const closureAndDestroyIndices = (fn: GirFunction): Set<number> => {
64
+ const closureAndDestroyIndices = (fn: Pick<GirCallable, "parameters">): Set<number> => {
65
65
  const indices: Set<number> = new Set();
66
66
 
67
67
  for (const parameter of fn.parameters) {