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.
- package/README.md +39 -3
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/module.js +10 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +24 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +14 -0
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +14 -0
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +73 -5
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +109 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gc.test.d.ts +1 -0
- package/dist/tests/e2e/gc.test.js +168 -0
- package/dist/tests/e2e/gc.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +2 -0
- package/dist/tests/e2e/harness.js +1 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/package.json +3 -2
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/dom.cpp +7 -403
- package/runtime/ext_gui/dom_api.cpp +63 -1146
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +135 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +56 -286
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/ext_gui/window.cpp +1 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
- package/runtime/ext_node/dgram/dgram.c +1 -0
- package/runtime/ext_node/events/events.c +1 -0
- package/runtime/ext_node/fs/fs_ops.c +10 -25
- package/runtime/ext_node/fs/glob.c +13 -30
- package/runtime/ext_node/fs/promises.c +1 -0
- package/runtime/ext_node/http/parts/prototypes.inc +5 -0
- package/runtime/ext_node/net/parts/prototypes.inc +2 -0
- package/runtime/ext_node/process/process.c +9 -7
- package/runtime/ext_node/stream/stream.c +1 -0
- package/runtime/ext_node/util/util.c +6 -6
- package/runtime/rt.h +16 -0
- package/runtime/rt_internal.h +67 -2
- package/runtime/xt_alloc.c +442 -5
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_generator.c +95 -1
- package/runtime/xt_loop.c +35 -1
- package/runtime/xt_promise.c +46 -0
- package/runtime/xt_stdlib2/error.inc +1 -0
- package/runtime/xt_stdlib2/regexp-match.inc +8 -7
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_symbol.c +2 -0
- package/runtime/xt_typed_array/construction.inc +142 -0
- package/runtime/xt_typed_array/elements.inc +92 -0
- package/runtime/xt_typed_array/methods.inc +329 -0
- package/runtime/xt_typed_array.c +72 -0
- package/runtime/xt_values/number-format.inc +26 -0
- package/scripts/check-file-length.ts +85 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/module.ts +10 -0
- package/src/codegen/generator/state.ts +24 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +14 -0
- package/src/driver/bundler/merge.ts +15 -0
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +83 -5
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -702
- package/dist/tests/e2e/gui.test.js.map +0 -1
package/runtime/ext_gui/gui.cpp
CHANGED
|
@@ -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 "
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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 *
|
|
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
|
-
|
|
60
|
-
return xt_gui_window_by_object(thisValue);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/* -- events --------------------------------------------------------------- */
|
|
99
|
+
} // namespace guidev
|
|
64
100
|
|
|
65
|
-
|
|
66
|
-
xt_gui_emit_payload(win, event, XT_UNDEFINED);
|
|
67
|
-
}
|
|
101
|
+
using namespace guidev;
|
|
68
102
|
|
|
69
|
-
|
|
70
|
-
|
|
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 (!
|
|
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
|
-
|
|
227
|
+
handle_event(&event);
|
|
458
228
|
}
|
|
459
229
|
|
|
460
230
|
int open = 0;
|