xbintsc 0.3.25 → 0.3.46

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 (187) hide show
  1. package/README.md +39 -3
  2. package/dist/src/cli/main.js +124 -30
  3. package/dist/src/cli/main.js.map +1 -1
  4. package/dist/src/codegen/generator/calls/access.js +8 -1
  5. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  6. package/dist/src/codegen/generator/module.js +10 -0
  7. package/dist/src/codegen/generator/module.js.map +1 -1
  8. package/dist/src/codegen/generator/state.js +24 -0
  9. package/dist/src/codegen/generator/state.js.map +1 -1
  10. package/dist/src/codegen/generator/tables.d.ts +6 -0
  11. package/dist/src/codegen/generator/tables.js +38 -0
  12. package/dist/src/codegen/generator/tables.js.map +1 -1
  13. package/dist/src/driver/bundler/commonjs.d.ts +52 -0
  14. package/dist/src/driver/bundler/commonjs.js +493 -0
  15. package/dist/src/driver/bundler/commonjs.js.map +1 -0
  16. package/dist/src/driver/bundler/graph.js +14 -0
  17. package/dist/src/driver/bundler/graph.js.map +1 -1
  18. package/dist/src/driver/bundler/merge.js +14 -0
  19. package/dist/src/driver/bundler/merge.js.map +1 -1
  20. package/dist/src/driver/bundler/types.d.ts +8 -0
  21. package/dist/src/driver/compiler.d.ts +8 -1
  22. package/dist/src/driver/compiler.js +73 -5
  23. package/dist/src/driver/compiler.js.map +1 -1
  24. package/dist/src/driver/config.d.ts +53 -0
  25. package/dist/src/driver/config.js +141 -0
  26. package/dist/src/driver/config.js.map +1 -0
  27. package/dist/src/driver/icon.d.ts +62 -0
  28. package/dist/src/driver/icon.js +151 -0
  29. package/dist/src/driver/icon.js.map +1 -0
  30. package/dist/src/driver/index.d.ts +4 -0
  31. package/dist/src/driver/index.js +4 -0
  32. package/dist/src/driver/index.js.map +1 -1
  33. package/dist/src/driver/mac-bundle.d.ts +41 -0
  34. package/dist/src/driver/mac-bundle.js +123 -0
  35. package/dist/src/driver/mac-bundle.js.map +1 -0
  36. package/dist/src/driver/win-icon.d.ts +27 -0
  37. package/dist/src/driver/win-icon.js +80 -0
  38. package/dist/src/driver/win-icon.js.map +1 -0
  39. package/dist/src/parser/statements.js +17 -4
  40. package/dist/src/parser/statements.js.map +1 -1
  41. package/dist/tests/cli/main.test.js +46 -1
  42. package/dist/tests/cli/main.test.js.map +1 -1
  43. package/dist/tests/driver/config.test.d.ts +1 -0
  44. package/dist/tests/driver/config.test.js +124 -0
  45. package/dist/tests/driver/config.test.js.map +1 -0
  46. package/dist/tests/driver/icon.test.d.ts +1 -0
  47. package/dist/tests/driver/icon.test.js +421 -0
  48. package/dist/tests/driver/icon.test.js.map +1 -0
  49. package/dist/tests/driver/modules.test.js +109 -0
  50. package/dist/tests/driver/modules.test.js.map +1 -1
  51. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  52. package/dist/tests/e2e/fetch.test.js +272 -0
  53. package/dist/tests/e2e/fetch.test.js.map +1 -0
  54. package/dist/tests/e2e/gc.test.d.ts +1 -0
  55. package/dist/tests/e2e/gc.test.js +168 -0
  56. package/dist/tests/e2e/gc.test.js.map +1 -0
  57. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  58. package/dist/tests/e2e/gui-dom.test.js +102 -0
  59. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  60. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  61. package/dist/tests/e2e/gui-events.test.js +60 -0
  62. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  63. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  64. package/dist/tests/e2e/gui-helpers.js +74 -0
  65. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  66. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  67. package/dist/tests/e2e/gui-layout.test.js +88 -0
  68. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  69. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  70. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  71. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  72. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  73. package/dist/tests/e2e/gui-paint.test.js +111 -0
  74. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  75. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  76. package/dist/tests/e2e/gui-script.test.js +78 -0
  77. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  78. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  79. package/dist/tests/e2e/gui-style.test.js +175 -0
  80. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  81. package/dist/tests/e2e/harness.d.ts +2 -0
  82. package/dist/tests/e2e/harness.js +1 -0
  83. package/dist/tests/e2e/harness.js.map +1 -1
  84. package/dist/tests/e2e/icon.test.d.ts +7 -0
  85. package/dist/tests/e2e/icon.test.js +80 -0
  86. package/dist/tests/e2e/icon.test.js.map +1 -0
  87. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  88. package/dist/tests/e2e/npm-modules.test.js +47 -1
  89. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  90. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  91. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  92. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  93. package/dist/tests/parser/statements.test.js +11 -0
  94. package/dist/tests/parser/statements.test.js.map +1 -1
  95. package/package.json +3 -2
  96. package/runtime/ext_gui/css.cpp +4 -517
  97. package/runtime/ext_gui/css_internal.h +27 -0
  98. package/runtime/ext_gui/css_match.cpp +195 -0
  99. package/runtime/ext_gui/css_selector.cpp +207 -0
  100. package/runtime/ext_gui/css_sheet.cpp +129 -0
  101. package/runtime/ext_gui/dom.cpp +7 -403
  102. package/runtime/ext_gui/dom_api.cpp +63 -1146
  103. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  104. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  105. package/runtime/ext_gui/dom_api_internal.h +135 -0
  106. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  107. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  108. package/runtime/ext_gui/dom_api_proto.cpp +135 -0
  109. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  110. package/runtime/ext_gui/dom_internal.h +39 -0
  111. package/runtime/ext_gui/dom_parse.cpp +348 -0
  112. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  113. package/runtime/ext_gui/gui.cpp +56 -286
  114. package/runtime/ext_gui/gui_events.cpp +294 -0
  115. package/runtime/ext_gui/gui_internal.h +29 -0
  116. package/runtime/ext_gui/layout.cpp +6 -597
  117. package/runtime/ext_gui/layout_flex.cpp +200 -0
  118. package/runtime/ext_gui/layout_flow.cpp +191 -0
  119. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  120. package/runtime/ext_gui/layout_inline.cpp +181 -0
  121. package/runtime/ext_gui/layout_internal.h +20 -0
  122. package/runtime/ext_gui/renderer.cpp +15 -679
  123. package/runtime/ext_gui/renderer_image.cpp +233 -0
  124. package/runtime/ext_gui/renderer_internal.h +112 -0
  125. package/runtime/ext_gui/renderer_shaders.h +108 -0
  126. package/runtime/ext_gui/renderer_text.cpp +342 -0
  127. package/runtime/ext_gui/style.cpp +12 -660
  128. package/runtime/ext_gui/style_internal.h +33 -0
  129. package/runtime/ext_gui/style_print.cpp +113 -0
  130. package/runtime/ext_gui/style_ua.cpp +98 -0
  131. package/runtime/ext_gui/style_values.cpp +468 -0
  132. package/runtime/ext_gui/window.cpp +1 -0
  133. package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
  134. package/runtime/ext_node/dgram/dgram.c +1 -0
  135. package/runtime/ext_node/events/events.c +1 -0
  136. package/runtime/ext_node/fs/fs_ops.c +10 -25
  137. package/runtime/ext_node/fs/glob.c +13 -30
  138. package/runtime/ext_node/fs/promises.c +1 -0
  139. package/runtime/ext_node/http/parts/prototypes.inc +5 -0
  140. package/runtime/ext_node/net/parts/prototypes.inc +2 -0
  141. package/runtime/ext_node/process/process.c +9 -7
  142. package/runtime/ext_node/stream/stream.c +1 -0
  143. package/runtime/ext_node/util/util.c +6 -6
  144. package/runtime/rt.h +16 -0
  145. package/runtime/rt_internal.h +67 -2
  146. package/runtime/xt_alloc.c +442 -5
  147. package/runtime/xt_builtins.c +1 -0
  148. package/runtime/xt_containers/access.inc +32 -1
  149. package/runtime/xt_fetch/buffer.inc +64 -0
  150. package/runtime/xt_fetch/headers.inc +312 -0
  151. package/runtime/xt_fetch/request.inc +386 -0
  152. package/runtime/xt_fetch/response.inc +107 -0
  153. package/runtime/xt_fetch/socket.inc +72 -0
  154. package/runtime/xt_fetch/url.inc +108 -0
  155. package/runtime/xt_fetch.c +39 -0
  156. package/runtime/xt_generator.c +95 -1
  157. package/runtime/xt_loop.c +35 -1
  158. package/runtime/xt_promise.c +46 -0
  159. package/runtime/xt_stdlib2/error.inc +1 -0
  160. package/runtime/xt_stdlib2/regexp-match.inc +8 -7
  161. package/runtime/xt_stdlib2/set.inc +1 -1
  162. package/runtime/xt_symbol.c +2 -0
  163. package/runtime/xt_typed_array/construction.inc +142 -0
  164. package/runtime/xt_typed_array/elements.inc +92 -0
  165. package/runtime/xt_typed_array/methods.inc +329 -0
  166. package/runtime/xt_typed_array.c +72 -0
  167. package/runtime/xt_values/number-format.inc +26 -0
  168. package/scripts/check-file-length.ts +85 -0
  169. package/src/cli/main.ts +137 -29
  170. package/src/codegen/generator/calls/access.ts +9 -1
  171. package/src/codegen/generator/module.ts +10 -0
  172. package/src/codegen/generator/state.ts +24 -0
  173. package/src/codegen/generator/tables.ts +40 -0
  174. package/src/driver/bundler/commonjs.ts +553 -0
  175. package/src/driver/bundler/graph.ts +14 -0
  176. package/src/driver/bundler/merge.ts +15 -0
  177. package/src/driver/bundler/types.ts +8 -0
  178. package/src/driver/compiler.ts +83 -5
  179. package/src/driver/config.ts +173 -0
  180. package/src/driver/icon.ts +184 -0
  181. package/src/driver/index.ts +30 -0
  182. package/src/driver/mac-bundle.ts +156 -0
  183. package/src/driver/win-icon.ts +96 -0
  184. package/src/parser/statements.ts +17 -4
  185. package/dist/tests/e2e/gui.test.d.ts +0 -12
  186. package/dist/tests/e2e/gui.test.js +0 -702
  187. package/dist/tests/e2e/gui.test.js.map +0 -1
@@ -8,25 +8,65 @@
8
8
  *
9
9
  * The engine is deliberately free of any compiler knowledge: it only uses the
10
10
  * public runtime ABI (`rt.h`).
11
+ *
12
+ * Input dispatch and per-frame rendering live in `gui_events.cpp`; the shared
13
+ * process state is declared in `gui_internal.h`.
11
14
  */
12
15
 
13
- #include "gui_engine.h"
16
+ #include "gui_internal.h"
17
+
18
+ #include "image.h"
14
19
  #include "paint.h"
15
20
 
16
21
  #include <stdio.h>
17
22
  #include <string.h>
18
23
 
19
- #define XT_GUI_MAX_WINDOWS 64
24
+ namespace guidev {
25
+
26
+ SDL_GPUDevice *g_device = NULL;
27
+ int g_sdl_initialized = 0;
28
+ int g_quit = 0;
29
+ XtGuiWindow g_windows[XT_GUI_MAX_WINDOWS];
30
+ int g_window_count = 0;
31
+
32
+ /* Optional application icon embedded at compile time by the driver (`--icon` /
33
+ * `app.icon`). The symbols live in a small object the driver links into every
34
+ * GUI program (an empty object when no icon is configured), so the references
35
+ * are plain: `xt_app_icon_size == 0` means "no icon". */
36
+ extern "C" {
37
+ extern const unsigned char xt_app_icon_data[];
38
+ extern const unsigned long long xt_app_icon_size;
39
+ extern const char xt_app_icon_format[];
40
+ extern const unsigned int xt_app_icon_width;
41
+ extern const unsigned int xt_app_icon_height;
42
+ }
20
43
 
21
- static SDL_GPUDevice *g_device = NULL;
22
- static int g_sdl_initialized = 0;
23
- static int g_quit = 0;
24
- static XtGuiWindow g_windows[XT_GUI_MAX_WINDOWS];
25
- static int g_window_count = 0;
44
+ /**
45
+ * Set the window / taskbar / Dock icon from the embedded PNG, if any. Decoding
46
+ * goes through the same stb_image path as `<img>`, so the icon needs no extra
47
+ * dependency. Failures are silent: an icon is cosmetic and must never stop the
48
+ * program from starting.
49
+ */
50
+ void xt_gui_apply_icon(SDL_Window *window) {
51
+ if (window == NULL) return;
52
+ size_t size = (size_t)xt_app_icon_size;
53
+ if (size == 0) return;
54
+ if (strcmp(xt_app_icon_format, "png") != 0) return;
55
+
56
+ xtgui::Image image;
57
+ if (!xtgui::xt_image_decode(xt_app_icon_data, size, &image)) return;
58
+ if (image.width <= 0 || image.height <= 0) return;
59
+
60
+ SDL_Surface *surface = SDL_CreateSurfaceFrom(
61
+ image.width, image.height, SDL_PIXELFORMAT_RGBA32, image.pixels.data(), image.width * 4);
62
+ if (surface == NULL) return;
63
+ SDL_SetWindowIcon(window, surface);
64
+ SDL_DestroySurface(surface);
65
+ }
26
66
 
27
67
  /* -- initialisation ------------------------------------------------------- */
28
68
 
29
- static int xt_gui_ensure_init(void) {
69
+ static int ensure_init(void) {
30
70
  if (g_sdl_initialized) return 1;
31
71
  if (!SDL_Init(SDL_INIT_VIDEO)) {
32
72
  fprintf(stderr, "xt_gui: SDL_Init failed: %s\n", SDL_GetError());
@@ -48,7 +88,7 @@ static int xt_gui_ensure_init(void) {
48
88
 
49
89
  /* -- window lookup -------------------------------------------------------- */
50
90
 
51
- static XtGuiWindow *xt_gui_window_by_object(xt_value object) {
91
+ static XtGuiWindow *window_by_object(xt_value object) {
52
92
  xt_value index_value = xt_object_get_cstr(object, "__xt_gui_index");
53
93
  if (!XT_IS_NUMBER(index_value)) return NULL;
54
94
  int index = (int)xt_to_number(index_value);
@@ -56,33 +96,12 @@ static XtGuiWindow *xt_gui_window_by_object(xt_value object) {
56
96
  return &g_windows[index];
57
97
  }
58
98
 
59
- XtGuiWindow *xt_gui_window_from_this(xt_value thisValue) {
60
- return xt_gui_window_by_object(thisValue);
61
- }
62
-
63
- /* -- events --------------------------------------------------------------- */
99
+ } // namespace guidev
64
100
 
65
- void xt_gui_emit(XtGuiWindow *win, const char *event) {
66
- xt_gui_emit_payload(win, event, XT_UNDEFINED);
67
- }
101
+ using namespace guidev;
68
102
 
69
- void xt_gui_emit_payload(XtGuiWindow *win, const char *event, xt_value payload) {
70
- if (win == NULL || !XT_IS_OBJECT(win->object)) return;
71
- xt_value listeners = xt_object_get_cstr(win->object, "__xt_gui_events");
72
- if (!XT_IS_OBJECT(listeners)) return;
73
- xt_value array = xt_object_get(listeners, xt_string_from_cstr(event));
74
- if (!XT_IS_ARRAY(array)) return;
75
- xt_value args[1];
76
- int32_t count = 0;
77
- if (!XT_IS_UNDEFINED(payload)) {
78
- args[0] = payload;
79
- count = 1;
80
- }
81
- int32_t listener_count = (int32_t)xt_to_number(xt_array_length(array));
82
- for (int32_t i = 0; i < listener_count; i++) {
83
- xt_value fn = xt_array_get(array, xt_number((double)i));
84
- if (XT_IS_FUNCTION(fn)) xt_call_with_this(fn, win->object, count, args);
85
- }
103
+ XtGuiWindow *xt_gui_window_from_this(xt_value thisValue) {
104
+ return window_by_object(thisValue);
86
105
  }
87
106
 
88
107
  void xt_gui_quit_window(XtGuiWindow *win) {
@@ -114,256 +133,6 @@ void xt_gui_window_viewport(XtGuiWindow *win, float *width, float *height) {
114
133
  if (height != NULL) *height = (float)h;
115
134
  }
116
135
 
117
- void xt_gui_flush_dom(XtGuiWindow *win) {
118
- if (win == NULL || win->document == nullptr) return;
119
- bool mutated = win->struct_dirty != 0;
120
- win->struct_dirty = 0;
121
- if (win->document->takeDirty()) mutated = true;
122
- if (!mutated) return;
123
- float width = 0;
124
- float height = 0;
125
- xt_gui_window_viewport(win, &width, &height);
126
- win->document->restyle(width, height);
127
- win->geometry.dirty = 1;
128
- }
129
-
130
- static XtGuiWindow *xt_gui_find_by_window_id(SDL_WindowID id) {
131
- SDL_Window *window = SDL_GetWindowFromID(id);
132
- if (window == NULL) return NULL;
133
- for (int i = 0; i < g_window_count; i++) {
134
- if (g_windows[i].window == window) return &g_windows[i];
135
- }
136
- return NULL;
137
- }
138
-
139
- /* -- input events --------------------------------------------------------- */
140
-
141
- /** Deepest element under (x, y), or NULL. */
142
- static const xtgui::Node *xt_gui_hit_node(XtGuiWindow *win, float x, float y) {
143
- if (win->document == nullptr) return nullptr;
144
- const xtgui::LayoutBox *box = win->document->layout().hitTest(x, y);
145
- const xtgui::Node *node = box != nullptr ? box->node : nullptr;
146
- while (node != nullptr && !node->isElement()) node = node->parent;
147
- return node;
148
- }
149
-
150
- /** Deepest element under (x, y) as a CSS-like descriptor, or an empty string. */
151
- std::string xt_gui_hit_test(XtGuiWindow *win, float x, float y) {
152
- const xtgui::Node *node = xt_gui_hit_node(win, x, y);
153
- return node == nullptr ? std::string() : xtgui::xt_dom_describe(node);
154
- }
155
-
156
- /** Update the hovered element from the pointer position; marks paint dirty. */
157
- static void xt_gui_update_hover(XtGuiWindow *win, float x, float y) {
158
- if (win->document == nullptr) return;
159
- if (win->document->setHover(xt_gui_hit_node(win, x, y))) win->geometry.dirty = 1;
160
- }
161
-
162
- static xt_value xt_gui_pointer_payload(const char *type, XtGuiWindow *win, float x, float y,
163
- int button, int clicks) {
164
- xt_value payload = xt_object_new();
165
- xt_object_set(payload, xt_string_from_cstr("type"), xt_string_from_cstr(type));
166
- xt_object_set(payload, xt_string_from_cstr("x"), xt_number(x));
167
- xt_object_set(payload, xt_string_from_cstr("y"), xt_number(y));
168
- xt_object_set(payload, xt_string_from_cstr("clientX"), xt_number(x));
169
- xt_object_set(payload, xt_string_from_cstr("clientY"), xt_number(y));
170
- xt_object_set(payload, xt_string_from_cstr("button"), xt_number(button));
171
- xt_object_set(payload, xt_string_from_cstr("clicks"), xt_number(clicks));
172
- std::string target = xt_gui_hit_test(win, x, y);
173
- if (!target.empty()) {
174
- xt_object_set(payload, xt_string_from_cstr("target"), xt_string_from_cstr(target.c_str()));
175
- }
176
- return payload;
177
- }
178
-
179
- void xt_gui_dispatch_pointer(XtGuiWindow *win, const char *type, float x, float y, int button,
180
- int clicks) {
181
- if (win == NULL || !win->open) return;
182
- xt_gui_update_hover(win, x, y);
183
- const xtgui::Node *node = xt_gui_hit_node(win, x, y);
184
- if (strcmp(type, "mousedown") == 0 && win->document != nullptr) {
185
- if (win->document->setFocus(node)) win->geometry.dirty = 1;
186
- }
187
- xt_value payload = xt_gui_pointer_payload(type, win, x, y, button, clicks);
188
- if (node != nullptr) xt_gui_emit_dom_event(win, type, node, payload);
189
- xt_gui_emit_payload(win, type, payload);
190
- }
191
-
192
- void xt_gui_dispatch_wheel(XtGuiWindow *win, float x, float y, float delta_x, float delta_y) {
193
- if (win == NULL || !win->open) return;
194
- xt_value payload = xt_gui_pointer_payload("wheel", win, x, y, -1, 0);
195
- xt_object_set(payload, xt_string_from_cstr("deltaX"), xt_number(delta_x));
196
- xt_object_set(payload, xt_string_from_cstr("deltaY"), xt_number(delta_y));
197
- const xtgui::Node *node = xt_gui_hit_node(win, x, y);
198
- if (node != nullptr) xt_gui_emit_dom_event(win, "wheel", node, payload);
199
- xt_gui_emit_payload(win, "wheel", payload);
200
- }
201
-
202
- static xt_value xt_gui_key_payload(const char *type, const char *key, const char *code, bool repeat,
203
- bool ctrl, bool shift, bool alt, bool meta) {
204
- xt_value payload = xt_object_new();
205
- xt_object_set(payload, xt_string_from_cstr("type"), xt_string_from_cstr(type));
206
- xt_object_set(payload, xt_string_from_cstr("key"), xt_string_from_cstr(key));
207
- xt_object_set(payload, xt_string_from_cstr("code"), xt_string_from_cstr(code));
208
- xt_object_set(payload, xt_string_from_cstr("repeat"), repeat ? XT_TRUE : XT_FALSE);
209
- xt_object_set(payload, xt_string_from_cstr("ctrl"), ctrl ? XT_TRUE : XT_FALSE);
210
- xt_object_set(payload, xt_string_from_cstr("shift"), shift ? XT_TRUE : XT_FALSE);
211
- xt_object_set(payload, xt_string_from_cstr("alt"), alt ? XT_TRUE : XT_FALSE);
212
- xt_object_set(payload, xt_string_from_cstr("meta"), meta ? XT_TRUE : XT_FALSE);
213
- return payload;
214
- }
215
-
216
- void xt_gui_dispatch_key(XtGuiWindow *win, const char *type, const char *key, const char *code) {
217
- if (win == NULL || !win->open) return;
218
- xt_value payload = xt_gui_key_payload(type, key, code, false, false, false, false, false);
219
- const xtgui::Node *node = win->document != nullptr ? win->document->focus() : nullptr;
220
- if (node != nullptr) xt_gui_emit_dom_event(win, type, node, payload);
221
- xt_gui_emit_payload(win, type, payload);
222
- }
223
-
224
- static void xt_gui_handle_event(const SDL_Event *event) {
225
- if (event->type == SDL_EVENT_QUIT) {
226
- g_quit = 1;
227
- return;
228
- }
229
- if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
230
- XtGuiWindow *win = xt_gui_find_by_window_id(event->window.windowID);
231
- if (win != NULL && win->open) xt_gui_quit_window(win);
232
- return;
233
- }
234
- if (event->type == SDL_EVENT_WINDOW_RESIZED) {
235
- XtGuiWindow *win = xt_gui_find_by_window_id(event->window.windowID);
236
- if (win == NULL || !win->open) return;
237
- win->width = event->window.data1;
238
- win->height = event->window.data2;
239
- if (win->document != NULL) win->document->restyle((float)win->width, (float)win->height);
240
- win->geometry.dirty = 1;
241
- return;
242
- }
243
-
244
- if (event->type == SDL_EVENT_MOUSE_MOTION) {
245
- XtGuiWindow *win = xt_gui_find_by_window_id(event->motion.windowID);
246
- xt_gui_dispatch_pointer(win, "mousemove", event->motion.x, event->motion.y, -1, 0);
247
- return;
248
- }
249
- if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
250
- XtGuiWindow *win = xt_gui_find_by_window_id(event->button.windowID);
251
- /* SDL numbers buttons 1/2/3 (left/middle/right); DOM uses 0/1/2. */
252
- xt_gui_dispatch_pointer(win, "mousedown", event->button.x, event->button.y,
253
- (int)event->button.button - 1, event->button.clicks);
254
- return;
255
- }
256
- if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
257
- XtGuiWindow *win = xt_gui_find_by_window_id(event->button.windowID);
258
- if (win == NULL || !win->open) return;
259
- int button = (int)event->button.button - 1;
260
- xt_gui_dispatch_pointer(win, "mouseup", event->button.x, event->button.y, button,
261
- event->button.clicks);
262
- if (button == 0) {
263
- xt_gui_dispatch_pointer(win, "click", event->button.x, event->button.y, button,
264
- event->button.clicks);
265
- }
266
- return;
267
- }
268
- if (event->type == SDL_EVENT_MOUSE_WHEEL) {
269
- XtGuiWindow *win = xt_gui_find_by_window_id(event->wheel.windowID);
270
- /* DOM `deltaY` grows downwards; SDL's grows away from the user. */
271
- xt_gui_dispatch_wheel(win, event->wheel.mouse_x, event->wheel.mouse_y, event->wheel.x,
272
- -event->wheel.y);
273
- return;
274
- }
275
- if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
276
- XtGuiWindow *win = xt_gui_find_by_window_id(event->key.windowID);
277
- if (win == NULL || !win->open) return;
278
- const char *type = event->type == SDL_EVENT_KEY_DOWN ? "keydown" : "keyup";
279
- xt_gui_emit_payload(win, type,
280
- xt_gui_key_payload(type, SDL_GetKeyName(event->key.key),
281
- SDL_GetScancodeName(event->key.scancode),
282
- event->key.repeat, (event->key.mod & SDL_KMOD_CTRL) != 0,
283
- (event->key.mod & SDL_KMOD_SHIFT) != 0,
284
- (event->key.mod & SDL_KMOD_ALT) != 0,
285
- (event->key.mod & SDL_KMOD_GUI) != 0));
286
- return;
287
- }
288
- }
289
-
290
- /* -- rendering ------------------------------------------------------------ */
291
-
292
- void xt_gui_run_animation_frames(XtGuiWindow *win, double timestamp_ms) {
293
- if (win == NULL || win->animation_frames.empty()) return;
294
- /* Swap the queue out first: a callback that calls requestAnimationFrame
295
- * again schedules for the *next* frame, not this one. */
296
- std::vector<XtGuiAnimationFrame> frames;
297
- frames.swap(win->animation_frames);
298
- for (const XtGuiAnimationFrame &frame : frames) {
299
- if (!win->open) break;
300
- xt_value arg = xt_number(timestamp_ms);
301
- xt_call_with_this(frame.fn, win->object, 1, &arg);
302
- }
303
- }
304
-
305
- void xt_gui_render_window(XtGuiWindow *win) {
306
- if (win == NULL || !win->open || win->window == NULL || g_device == NULL) return;
307
- float viewport_width = 0;
308
- float viewport_height = 0;
309
- xt_gui_window_viewport(win, &viewport_width, &viewport_height);
310
-
311
- /* Drive CSS transitions. */
312
- double now = (double)SDL_GetTicks();
313
- double delta = win->last_frame_ms > 0.0 ? now - win->last_frame_ms : 0.0;
314
- win->last_frame_ms = now;
315
- /* Animation-frame callbacks run before layout, so any DOM mutation they make
316
- * is picked up by this same frame. */
317
- xt_gui_run_animation_frames(win, now);
318
- if (win->document != nullptr && win->document->advance(delta)) win->geometry.dirty = 1;
319
-
320
- /* A DOM mutation from a handler invalidates the tree: restyle/relayout
321
- * before (re)building the geometry. */
322
- xt_gui_flush_dom(win);
323
-
324
- /* Rebuild the geometry only when the document or viewport changed. */
325
- bool can_paint = xt_gui_renderer_ensure(g_device, win->window);
326
- if (can_paint && win->geometry.dirty && win->document != nullptr) {
327
- xtgui::DisplayList list;
328
- xtgui::xt_paint_build(win->document->layout().root(), list);
329
- xt_gui_geometry_upload(g_device, &win->geometry, list);
330
- float density = SDL_GetWindowPixelDensity(win->window);
331
- xt_gui_text_upload(g_device, &win->text_geometry, list, density > 0.0f ? density : 1.0f);
332
- xt_gui_image_upload(g_device, &win->image_geometry, list);
333
- win->geometry.dirty = 0;
334
- }
335
-
336
- SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(g_device);
337
- if (cmd == NULL) return;
338
- SDL_GPUTexture *swapchain = NULL;
339
- SDL_AcquireGPUSwapchainTexture(cmd, win->window, &swapchain, NULL, NULL);
340
- bool firstFrame = false;
341
- if (swapchain != NULL) {
342
- SDL_GPUColorTargetInfo target;
343
- memset(&target, 0, sizeof(target));
344
- target.texture = swapchain;
345
- target.clear_color.r = win->background[0];
346
- target.clear_color.g = win->background[1];
347
- target.clear_color.b = win->background[2];
348
- target.clear_color.a = win->background[3];
349
- target.load_op = SDL_GPU_LOADOP_CLEAR;
350
- target.store_op = SDL_GPU_STOREOP_STORE;
351
- SDL_GPURenderPass *pass = SDL_BeginGPURenderPass(cmd, &target, 1, NULL);
352
- if (can_paint) {
353
- xt_gui_renderer_draw(cmd, pass, &win->geometry, viewport_width, viewport_height);
354
- xt_gui_text_draw(cmd, pass, &win->text_geometry, viewport_width, viewport_height);
355
- xt_gui_image_draw(cmd, pass, &win->image_geometry, viewport_width, viewport_height);
356
- }
357
- SDL_EndGPURenderPass(pass);
358
- firstFrame = !win->ready;
359
- win->ready = 1;
360
- }
361
- SDL_SubmitGPUCommandBuffer(cmd);
362
- /* The first presented frame marks the window ready. Emitting after the
363
- * submit lets a `ready` handler safely close/destroy the window. */
364
- if (firstFrame) xt_gui_emit(win, "ready");
365
- }
366
-
367
136
  /* -- createWindow(options) ------------------------------------------------ */
368
137
 
369
138
  static const char *xt_gui_string_or(xt_value value, const char *fallback) {
@@ -377,7 +146,7 @@ static int xt_gui_int_or(xt_value value, int fallback) {
377
146
  }
378
147
 
379
148
  extern "C" xt_value xt_gui_create_window(int32_t argc, xt_value *argv) {
380
- if (!xt_gui_ensure_init()) return XT_UNDEFINED;
149
+ if (!ensure_init()) return XT_UNDEFINED;
381
150
  if (g_window_count >= XT_GUI_MAX_WINDOWS) {
382
151
  fprintf(stderr, "xt_gui: too many windows (max %d)\n", XT_GUI_MAX_WINDOWS);
383
152
  return XT_UNDEFINED;
@@ -408,6 +177,7 @@ extern "C" xt_value xt_gui_create_window(int32_t argc, xt_value *argv) {
408
177
  SDL_DestroyWindow(window);
409
178
  return XT_UNDEFINED;
410
179
  }
180
+ xt_gui_apply_icon(window);
411
181
 
412
182
  int index = g_window_count++;
413
183
  XtGuiWindow *record = &g_windows[index];
@@ -454,7 +224,7 @@ extern "C" xt_value xt_gui_run(int32_t argc, xt_value *argv) {
454
224
  int had_event = 0;
455
225
  while (SDL_PollEvent(&event)) {
456
226
  had_event = 1;
457
- xt_gui_handle_event(&event);
227
+ handle_event(&event);
458
228
  }
459
229
 
460
230
  int open = 0;