electrobun 1.18.1 → 1.18.4-beta.10

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 (64) hide show
  1. package/README.md +37 -14
  2. package/dash.config.ts +28 -0
  3. package/dist/api/browser/global.d.ts +6 -0
  4. package/dist/api/browser/index.ts +162 -44
  5. package/dist/api/{bun → config}/ElectrobunConfig.ts +109 -40
  6. package/dist/api/config/validate.test.ts +31 -0
  7. package/dist/api/config/validate.ts +19 -0
  8. package/dist/api/preload/.generated/compiled.ts +8 -0
  9. package/dist/api/{bun/preload → preload}/build.ts +6 -6
  10. package/dist/api/{bun/preload → preload}/encryption.ts +11 -5
  11. package/dist/api/{bun/preload → preload}/globals.d.ts +8 -0
  12. package/dist/api/{bun/preload → preload}/index.ts +18 -8
  13. package/dist/api/{bun/preload → preload}/webviewTag.ts +32 -3
  14. package/dist/api/{bun/preload → preload}/wgpuTag.ts +33 -2
  15. package/dist/api/{bun → sdks/bun}/__tests__/ffi-contract.test.ts +6 -9
  16. package/dist/api/{bun → sdks/bun}/core/BrowserView.ts +96 -55
  17. package/dist/api/{bun → sdks/bun}/core/BrowserWindow.ts +20 -30
  18. package/dist/api/{bun → sdks/bun}/core/BuildConfig.ts +32 -5
  19. package/dist/api/{bun → sdks/bun}/core/GpuWindow.ts +20 -7
  20. package/dist/api/sdks/bun/core/Socket.ts +22 -0
  21. package/dist/api/{bun → sdks/bun}/core/Tray.ts +33 -32
  22. package/dist/api/{bun → sdks/bun}/core/Updater.ts +10 -10
  23. package/dist/api/{bun → sdks/bun}/core/Utils.ts +3 -5
  24. package/dist/api/{bun → sdks/bun}/core/WGPUView.ts +43 -13
  25. package/dist/api/{bun → sdks/bun}/index.ts +39 -10
  26. package/dist/api/{bun → sdks/bun}/proc/native.ts +942 -746
  27. package/dist/api/{bun → sdks/bun}/webGPU.ts +1 -1
  28. package/dist/api/{bun → sdks/bun}/webgpuAdapter.ts +40 -33
  29. package/dist/api/shared/build-dependencies.test.ts +48 -0
  30. package/dist/api/shared/build-dependencies.ts +46 -0
  31. package/dist/api/shared/go-version.ts +3 -0
  32. package/dist/api/shared/odin-version.ts +6 -0
  33. package/dist/api/shared/rust-version.ts +3 -0
  34. package/dist/go-sdk/callbacks.go +260 -0
  35. package/dist/go-sdk/electrobun.go +2021 -0
  36. package/dist/main.js +35 -28
  37. package/dist/odin-sdk/electrobun/electrobun.odin +2337 -0
  38. package/dist/preload-full.js +948 -0
  39. package/dist/preload-sandboxed.js +111 -0
  40. package/dist/rust-sdk/electrobun.rs +2396 -0
  41. package/dist/zig-sdk/electrobun.zig +2005 -0
  42. package/package.json +5 -29
  43. package/src/cli/index.ts +868 -654
  44. package/bin/electrobun.cjs +0 -169
  45. package/dist/api/bun/core/Socket.ts +0 -205
  46. package/dist/api/bun/core/windowIds.ts +0 -5
  47. package/dist/api/bun/preload/.generated/compiled.ts +0 -8
  48. package/dist/api/shared/bun-version.ts +0 -3
  49. /package/dist/api/{bun/preload → preload}/dragRegions.ts +0 -0
  50. /package/dist/api/{bun/preload → preload}/events.ts +0 -0
  51. /package/dist/api/{bun/preload → preload}/index-sandboxed.ts +0 -0
  52. /package/dist/api/{bun/preload → preload}/internalRpc.ts +0 -0
  53. /package/dist/api/{bun/preload → preload}/overlaySync.ts +0 -0
  54. /package/dist/api/{bun → sdks/bun}/core/ApplicationMenu.ts +0 -0
  55. /package/dist/api/{bun → sdks/bun}/core/ContextMenu.ts +0 -0
  56. /package/dist/api/{bun → sdks/bun}/core/Paths.ts +0 -0
  57. /package/dist/api/{bun → sdks/bun}/core/menuRoles.ts +0 -0
  58. /package/dist/api/{bun → sdks/bun}/events/ApplicationEvents.ts +0 -0
  59. /package/dist/api/{bun → sdks/bun}/events/event.ts +0 -0
  60. /package/dist/api/{bun → sdks/bun}/events/eventEmitter.ts +0 -0
  61. /package/dist/api/{bun → sdks/bun}/events/trayEvents.ts +0 -0
  62. /package/dist/api/{bun → sdks/bun}/events/webviewEvents.ts +0 -0
  63. /package/dist/api/{bun → sdks/bun}/events/windowEvents.ts +0 -0
  64. /package/dist/api/{bun → sdks/bun}/proc/linux.md +0 -0
@@ -0,0 +1,2021 @@
1
+ package electrobun
2
+
3
+ /*
4
+ #cgo linux LDFLAGS: -ldl
5
+ #include <stdbool.h>
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+
9
+ #ifdef _WIN32
10
+ #include <windows.h>
11
+ #else
12
+ #include <dlfcn.h>
13
+ #endif
14
+
15
+ extern void electrobunWindowCloseHandler(uint32_t);
16
+ extern void electrobunWindowMoveHandler(uint32_t, double, double);
17
+ extern void electrobunWindowResizeHandler(uint32_t, double, double, double, double);
18
+ extern void electrobunWindowFocusHandler(uint32_t);
19
+ extern void electrobunWindowBlurHandler(uint32_t);
20
+ extern void electrobunWindowKeyHandler(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
21
+ extern uint32_t electrobunDecideNavigationHandler(uint32_t, const char*);
22
+ extern void electrobunWebviewEventHandler(uint32_t, const char*, const char*);
23
+ extern void electrobunWebviewEventBridgeHandler(uint32_t, const char*);
24
+ extern void electrobunWebviewHostBridgeHandler(uint32_t, const char*);
25
+ extern void electrobunWebviewInternalBridgeHandler(uint32_t, const char*);
26
+ extern void electrobunStatusItemHandler(uint32_t, const char*);
27
+ extern void electrobunGlobalShortcutHandler(const char*);
28
+ extern void electrobunURLOpenHandler(const char*);
29
+ extern void electrobunAppReopenHandler(void);
30
+ extern void electrobunQuitRequestedHandler(void);
31
+
32
+ typedef void (*eb_window_close_cb)(uint32_t);
33
+ typedef void (*eb_window_move_cb)(uint32_t, double, double);
34
+ typedef void (*eb_window_resize_cb)(uint32_t, double, double, double, double);
35
+ typedef void (*eb_window_focus_cb)(uint32_t);
36
+ typedef void (*eb_window_blur_cb)(uint32_t);
37
+ typedef void (*eb_window_key_cb)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
38
+ typedef uint32_t (*eb_decide_navigation_cb)(uint32_t, const char*);
39
+ typedef void (*eb_webview_event_cb)(uint32_t, const char*, const char*);
40
+ typedef void (*eb_webview_post_message_cb)(uint32_t, const char*);
41
+ typedef void (*eb_status_item_cb)(uint32_t, const char*);
42
+ typedef void (*eb_global_shortcut_cb)(const char*);
43
+ typedef void (*eb_url_open_cb)(const char*);
44
+ typedef void (*eb_app_reopen_cb)(void);
45
+ typedef void (*eb_quit_requested_cb)(void);
46
+
47
+ static void eb_window_close(uint32_t id) { electrobunWindowCloseHandler(id); }
48
+ static void eb_window_move(uint32_t id, double x, double y) { electrobunWindowMoveHandler(id, x, y); }
49
+ static void eb_window_resize(uint32_t id, double x, double y, double w, double h) { electrobunWindowResizeHandler(id, x, y, w, h); }
50
+ static void eb_window_focus(uint32_t id) { electrobunWindowFocusHandler(id); }
51
+ static void eb_window_blur(uint32_t id) { electrobunWindowBlurHandler(id); }
52
+ static void eb_window_key(uint32_t id, uint32_t key, uint32_t modifiers, uint32_t event_type, uint32_t characters) { electrobunWindowKeyHandler(id, key, modifiers, event_type, characters); }
53
+ static uint32_t eb_decide_navigation(uint32_t id, const char* url) { return electrobunDecideNavigationHandler(id, url); }
54
+ static void eb_webview_event(uint32_t id, const char* event_name, const char* detail) { electrobunWebviewEventHandler(id, event_name, detail); }
55
+ static void eb_webview_event_bridge(uint32_t id, const char* message) { electrobunWebviewEventBridgeHandler(id, message); }
56
+ static void eb_webview_host_bridge(uint32_t id, const char* message) { electrobunWebviewHostBridgeHandler(id, message); }
57
+ static void eb_webview_internal_bridge(uint32_t id, const char* message) { electrobunWebviewInternalBridgeHandler(id, message); }
58
+ static void eb_status_item(uint32_t id, const char* message) { electrobunStatusItemHandler(id, message); }
59
+ static void eb_global_shortcut(const char* accelerator) { electrobunGlobalShortcutHandler(accelerator); }
60
+ static void eb_url_open(const char* url) { electrobunURLOpenHandler(url); }
61
+ static void eb_app_reopen(void) { electrobunAppReopenHandler(); }
62
+ static void eb_quit_requested(void) { electrobunQuitRequestedHandler(); }
63
+
64
+ #ifdef _WIN32
65
+ static void* eb_dlopen(const char* path) { return (void*)LoadLibraryA(path); }
66
+ static void* eb_dlsym(void* handle, const char* name) { return (void*)GetProcAddress((HMODULE)handle, name); }
67
+ static const char* eb_dlerror(void) {
68
+ static char message[512];
69
+ DWORD err = GetLastError();
70
+ if (err == 0) return "unknown dynamic loader error";
71
+ DWORD written = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, message, sizeof(message), NULL);
72
+ if (written == 0) return "unknown dynamic loader error";
73
+ return message;
74
+ }
75
+ #else
76
+ static void* eb_dlopen(const char* path) { return dlopen(path, RTLD_NOW | RTLD_LOCAL); }
77
+ static void* eb_dlsym(void* handle, const char* name) { return dlsym(handle, name); }
78
+ static const char* eb_dlerror(void) { return dlerror(); }
79
+ #endif
80
+
81
+ typedef const char* (*eb_last_error_fn)(void);
82
+ static const char* eb_call_last_error(void* fn) { return ((eb_last_error_fn)fn)(); }
83
+
84
+ typedef int (*eb_run_main_thread_fn)(const char*, const char*, const char*, int);
85
+ static int eb_call_run_main_thread(void* fn, const char* identifier, const char* name, const char* channel, int argc) {
86
+ return ((eb_run_main_thread_fn)fn)(identifier, name, channel, argc);
87
+ }
88
+
89
+ typedef bool (*eb_configure_webview_runtime_fn)(uint32_t, const char*, const char*);
90
+ static bool eb_call_configure_webview_runtime(void* fn, uint32_t rpc_port, const char* full_preload, const char* sandboxed_preload) {
91
+ return ((eb_configure_webview_runtime_fn)fn)(rpc_port, full_preload, sandboxed_preload);
92
+ }
93
+
94
+ typedef uint32_t (*eb_get_window_style_fn)(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool);
95
+ static uint32_t eb_call_get_window_style(void* fn, bool borderless, bool titled, bool closable, bool miniaturizable, bool resizable, bool unified_title_and_toolbar, bool full_screen, bool full_size_content_view, bool utility_window, bool doc_modal_window, bool nonactivating_panel, bool hud_window) {
96
+ return ((eb_get_window_style_fn)fn)(borderless, titled, closable, miniaturizable, resizable, unified_title_and_toolbar, full_screen, full_size_content_view, utility_window, doc_modal_window, nonactivating_panel, hud_window);
97
+ }
98
+
99
+ typedef uint32_t (*eb_create_window_fn)(double, double, double, double, uint32_t, const char*, bool, const char*, bool, bool, double, double, eb_window_close_cb, eb_window_move_cb, eb_window_resize_cb, eb_window_focus_cb, eb_window_blur_cb, eb_window_key_cb);
100
+ static uint32_t eb_call_create_window(void* fn, double x, double y, double width, double height, uint32_t style, const char* title_bar_style, bool transparent, const char* title, bool hidden, bool activate, double traffic_x, double traffic_y, bool close_enabled, bool move_enabled, bool resize_enabled, bool focus_enabled, bool blur_enabled, bool key_enabled) {
101
+ return ((eb_create_window_fn)fn)(x, y, width, height, style, title_bar_style, transparent, title, hidden, activate, traffic_x, traffic_y, close_enabled ? eb_window_close : 0, move_enabled ? eb_window_move : 0, resize_enabled ? eb_window_resize : 0, focus_enabled ? eb_window_focus : 0, blur_enabled ? eb_window_blur : 0, key_enabled ? eb_window_key : 0);
102
+ }
103
+
104
+ typedef uint32_t (*eb_create_webview_fn)(uint32_t, uint32_t, const char*, const char*, double, double, double, double, bool, const char*, eb_decide_navigation_cb, eb_webview_event_cb, eb_webview_post_message_cb, eb_webview_post_message_cb, eb_webview_post_message_cb, const char*, const char*, const char*, bool, bool, bool);
105
+ static uint32_t eb_call_create_webview(void* fn, uint32_t window_id, uint32_t host_webview_id, const char* renderer, const char* url, double x, double y, double width, double height, bool auto_resize, const char* partition, bool decide_enabled, bool event_enabled, bool event_bridge_enabled, bool host_bridge_enabled, bool internal_bridge_enabled, const char* secret_key, const char* preload, const char* views_root, bool sandbox, bool start_transparent, bool start_passthrough) {
106
+ return ((eb_create_webview_fn)fn)(window_id, host_webview_id, renderer, url, x, y, width, height, auto_resize, partition, decide_enabled ? eb_decide_navigation : 0, event_enabled ? eb_webview_event : 0, event_bridge_enabled ? eb_webview_event_bridge : 0, host_bridge_enabled ? eb_webview_host_bridge : 0, internal_bridge_enabled ? eb_webview_internal_bridge : 0, secret_key, preload, views_root, sandbox, start_transparent, start_passthrough);
107
+ }
108
+
109
+ typedef uint32_t (*eb_create_wgpu_view_fn)(uint32_t, double, double, double, double, bool, bool, bool);
110
+ static uint32_t eb_call_create_wgpu_view(void* fn, uint32_t window_id, double x, double y, double width, double height, bool transparent, bool passthrough, bool hidden) {
111
+ return ((eb_create_wgpu_view_fn)fn)(window_id, x, y, width, height, transparent, passthrough, hidden);
112
+ }
113
+
114
+ typedef void (*eb_u32_fn)(uint32_t);
115
+ static void eb_call_u32(void* fn, uint32_t value) { ((eb_u32_fn)fn)(value); }
116
+
117
+ typedef bool (*eb_u32_bool_ret_fn)(uint32_t);
118
+ static bool eb_call_u32_bool_ret(void* fn, uint32_t value) { return ((eb_u32_bool_ret_fn)fn)(value); }
119
+
120
+ typedef void (*eb_u32_bool_fn)(uint32_t, bool);
121
+ static void eb_call_u32_bool(void* fn, uint32_t value, bool flag) { ((eb_u32_bool_fn)fn)(value, flag); }
122
+
123
+ typedef void (*eb_bool_fn)(bool);
124
+ static void eb_call_bool(void* fn, bool flag) { ((eb_bool_fn)fn)(flag); }
125
+
126
+ typedef bool (*eb_bool_ret_fn)(void);
127
+ static bool eb_call_bool_ret(void* fn) { return ((eb_bool_ret_fn)fn)(); }
128
+
129
+ typedef void (*eb_u32_string_fn)(uint32_t, const char*);
130
+ static void eb_call_u32_string(void* fn, uint32_t value, const char* text) { ((eb_u32_string_fn)fn)(value, text); }
131
+
132
+ typedef void (*eb_u32_string_bool_bool_fn)(uint32_t, const char*, bool, bool);
133
+ static void eb_call_u32_string_bool_bool(void* fn, uint32_t value, const char* text, bool a, bool b) { ((eb_u32_string_bool_bool_fn)fn)(value, text, a, b); }
134
+
135
+ typedef void (*eb_u32_f64_f64_fn)(uint32_t, double, double);
136
+ static void eb_call_u32_f64_f64(void* fn, uint32_t value, double x, double y) { ((eb_u32_f64_f64_fn)fn)(value, x, y); }
137
+
138
+ typedef void (*eb_u32_f64_fn)(uint32_t, double);
139
+ static void eb_call_u32_f64(void* fn, uint32_t value, double number) { ((eb_u32_f64_fn)fn)(value, number); }
140
+
141
+ typedef double (*eb_u32_f64_ret_fn)(uint32_t);
142
+ static double eb_call_u32_f64_ret(void* fn, uint32_t value) { return ((eb_u32_f64_ret_fn)fn)(value); }
143
+
144
+ typedef void (*eb_u32_f64_f64_f64_f64_fn)(uint32_t, double, double, double, double);
145
+ static void eb_call_u32_f64_f64_f64_f64(void* fn, uint32_t value, double x, double y, double width, double height) { ((eb_u32_f64_f64_f64_f64_fn)fn)(value, x, y, width, height); }
146
+
147
+ typedef void (*eb_get_window_frame_fn)(uint32_t, double*, double*, double*, double*);
148
+ static void eb_call_get_window_frame(void* fn, uint32_t value, double* x, double* y, double* width, double* height) { ((eb_get_window_frame_fn)fn)(value, x, y, width, height); }
149
+
150
+ typedef void (*eb_resize_webview_fn)(uint32_t, double, double, double, double, const char*);
151
+ static void eb_call_resize_webview(void* fn, uint32_t value, double x, double y, double width, double height, const char* masks_json) { ((eb_resize_webview_fn)fn)(value, x, y, width, height, masks_json); }
152
+
153
+ typedef bool (*eb_send_host_message_fn)(uint32_t, const char*);
154
+ static bool eb_call_send_host_message(void* fn, uint32_t webview_id, const char* message_json) { return ((eb_send_host_message_fn)fn)(webview_id, message_json); }
155
+
156
+ typedef char* (*eb_pop_host_message_fn)(uint32_t*);
157
+ static char* eb_call_pop_host_message(void* fn, uint32_t* webview_id) { return ((eb_pop_host_message_fn)fn)(webview_id); }
158
+
159
+ typedef void (*eb_free_core_string_fn)(char*);
160
+ static void eb_call_free_core_string(void* fn, char* value) { ((eb_free_core_string_fn)fn)(value); }
161
+
162
+ typedef uint32_t (*eb_create_tray_fn)(const char*, const char*, bool, uint32_t, uint32_t, eb_status_item_cb);
163
+ static uint32_t eb_call_create_tray(void* fn, const char* title, const char* image, bool is_template, uint32_t width, uint32_t height, bool handler_enabled) {
164
+ return ((eb_create_tray_fn)fn)(title, image, is_template, width, height, handler_enabled ? eb_status_item : 0);
165
+ }
166
+
167
+ typedef bool (*eb_show_tray_fn)(uint32_t);
168
+ static bool eb_call_show_tray(void* fn, uint32_t tray_id) { return ((eb_show_tray_fn)fn)(tray_id); }
169
+
170
+ typedef char* (*eb_string_ret_fn)(void);
171
+ static char* eb_call_string_ret(void* fn) { return ((eb_string_ret_fn)fn)(); }
172
+
173
+ typedef const char* (*eb_u32_const_string_ret_fn)(uint32_t);
174
+ static const char* eb_call_u32_const_string_ret(void* fn, uint32_t value) { return ((eb_u32_const_string_ret_fn)fn)(value); }
175
+
176
+ typedef bool (*eb_string_bool_ret_fn)(const char*);
177
+ static bool eb_call_string_bool_ret(void* fn, const char* value) { return ((eb_string_bool_ret_fn)fn)(value); }
178
+
179
+ typedef void (*eb_string_fn)(const char*);
180
+ static void eb_call_string(void* fn, const char* value) { ((eb_string_fn)fn)(value); }
181
+
182
+ typedef void (*eb_notification_fn)(const char*, const char*, const char*, bool);
183
+ static void eb_call_notification(void* fn, const char* title, const char* body, const char* subtitle, bool silent) { ((eb_notification_fn)fn)(title, body, subtitle, silent); }
184
+
185
+ typedef void (*eb_menu_fn)(const char*, eb_status_item_cb);
186
+ static void eb_call_menu(void* fn, const char* menu_json, bool handler_enabled) { ((eb_menu_fn)fn)(menu_json, handler_enabled ? eb_status_item : 0); }
187
+
188
+ typedef char* (*eb_open_file_dialog_fn)(const char*, const char*, int, int, int);
189
+ static char* eb_call_open_file_dialog(void* fn, const char* starting_folder, const char* allowed_file_types, int can_choose_files, int can_choose_directory, int allows_multiple_selection) {
190
+ return ((eb_open_file_dialog_fn)fn)(starting_folder, allowed_file_types, can_choose_files, can_choose_directory, allows_multiple_selection);
191
+ }
192
+
193
+ typedef int (*eb_show_message_box_fn)(const char*, const char*, const char*, const char*, const char*, int, int);
194
+ static int eb_call_show_message_box(void* fn, const char* box_type, const char* title, const char* message, const char* detail, const char* buttons, int default_id, int cancel_id) {
195
+ return ((eb_show_message_box_fn)fn)(box_type, title, message, detail, buttons, default_id, cancel_id);
196
+ }
197
+
198
+ typedef void (*eb_set_global_shortcut_callback_fn)(eb_global_shortcut_cb);
199
+ static void eb_call_set_global_shortcut_callback(void* fn, bool enabled) { ((eb_set_global_shortcut_callback_fn)fn)(enabled ? eb_global_shortcut : 0); }
200
+
201
+ typedef bool (*eb_string_string_bool_ret_fn)(const char*, const char*);
202
+ static bool eb_call_string_string_bool_ret(void* fn, const char* a, const char* b) { return ((eb_string_string_bool_ret_fn)fn)(a, b); }
203
+
204
+ typedef char* (*eb_string_string_ret_fn)(const char*, const char*);
205
+ static char* eb_call_string_string_ret(void* fn, const char* a, const char* b) { return ((eb_string_string_ret_fn)fn)(a, b); }
206
+
207
+ typedef bool (*eb_string_string_string_bool_ret_fn)(const char*, const char*, const char*);
208
+ static bool eb_call_string_string_string_bool_ret(void* fn, const char* a, const char* b, const char* c) { return ((eb_string_string_string_bool_ret_fn)fn)(a, b, c); }
209
+
210
+ typedef void (*eb_string_string_fn)(const char*, const char*);
211
+ static void eb_call_string_string(void* fn, const char* a, const char* b) { ((eb_string_string_fn)fn)(a, b); }
212
+
213
+ typedef void (*eb_set_url_open_handler_fn)(eb_url_open_cb);
214
+ static void eb_call_set_url_open_handler(void* fn, bool enabled) { ((eb_set_url_open_handler_fn)fn)(enabled ? eb_url_open : 0); }
215
+
216
+ typedef void (*eb_set_app_reopen_handler_fn)(eb_app_reopen_cb);
217
+ static void eb_call_set_app_reopen_handler(void* fn, bool enabled) { ((eb_set_app_reopen_handler_fn)fn)(enabled ? eb_app_reopen : 0); }
218
+
219
+ typedef void (*eb_set_quit_requested_handler_fn)(eb_quit_requested_cb);
220
+ static void eb_call_set_quit_requested_handler(void* fn, bool enabled) { ((eb_set_quit_requested_handler_fn)fn)(enabled ? eb_quit_requested : 0); }
221
+
222
+ typedef void (*eb_void_fn)(void);
223
+ static void eb_call_void(void* fn) { ((eb_void_fn)fn)(); }
224
+
225
+ typedef void (*eb_int_fn)(int);
226
+ static void eb_call_int(void* fn, int value) { ((eb_int_fn)fn)(value); }
227
+
228
+ typedef void* (*eb_u32_ptr_ret_fn)(uint32_t);
229
+ static void* eb_call_u32_ptr_ret(void* fn, uint32_t value) { return ((eb_u32_ptr_ret_fn)fn)(value); }
230
+
231
+ typedef void* (*eb_ptr_ret_fn)(void*);
232
+ static void* eb_call_ptr_ret(void* fn, void* value) { return ((eb_ptr_ret_fn)fn)(value); }
233
+
234
+ typedef void* (*eb_ptr_ptr_ptr_ret_fn)(void*, void*);
235
+ static void* eb_call_ptr_ptr_ptr_ret(void* fn, void* a, void* b) { return ((eb_ptr_ptr_ptr_ret_fn)fn)(a, b); }
236
+
237
+ typedef void (*eb_ptr_ptr_ptr_fn)(void*, void*, void*);
238
+ static void eb_call_ptr_ptr_ptr(void* fn, void* a, void* b, void* c) { ((eb_ptr_ptr_ptr_fn)fn)(a, b, c); }
239
+
240
+ typedef void (*eb_ptr_ptr_fn)(void*, void*);
241
+ static void eb_call_ptr_ptr(void* fn, void* a, void* b) { ((eb_ptr_ptr_fn)fn)(a, b); }
242
+
243
+ typedef int (*eb_ptr_int_ret_fn)(void*);
244
+ static int eb_call_ptr_int_ret(void* fn, void* value) { return ((eb_ptr_int_ret_fn)fn)(value); }
245
+ */
246
+ import "C"
247
+
248
+ import (
249
+ "encoding/json"
250
+ "errors"
251
+ "fmt"
252
+ "os"
253
+ "path/filepath"
254
+ "runtime"
255
+ "strings"
256
+ "unsafe"
257
+ )
258
+
259
+ type Renderer string
260
+
261
+ const (
262
+ RendererNative Renderer = "native"
263
+ RendererCEF Renderer = "cef"
264
+ )
265
+
266
+ type AppInfo struct {
267
+ Identifier string
268
+ Name string
269
+ Channel string
270
+ }
271
+
272
+ type Rect struct {
273
+ X float64 `json:"x"`
274
+ Y float64 `json:"y"`
275
+ Width float64 `json:"width"`
276
+ Height float64 `json:"height"`
277
+ }
278
+
279
+ func NewRect(x, y, width, height float64) Rect {
280
+ return Rect{X: x, Y: y, Width: width, Height: height}
281
+ }
282
+
283
+ type WindowStyle struct {
284
+ Borderless bool
285
+ Titled bool
286
+ Closable bool
287
+ Miniaturizable bool
288
+ Resizable bool
289
+ UnifiedTitleAndToolbar bool
290
+ FullScreen bool
291
+ FullSizeContentView bool
292
+ UtilityWindow bool
293
+ DocModalWindow bool
294
+ NonactivatingPanel bool
295
+ HUDWindow bool
296
+ }
297
+
298
+ func StandardWindowStyle() WindowStyle {
299
+ return WindowStyle{
300
+ Titled: true,
301
+ Closable: true,
302
+ Miniaturizable: true,
303
+ Resizable: true,
304
+ }
305
+ }
306
+
307
+ type WindowCloseHandler func(uint32)
308
+ type WindowMoveHandler func(uint32, float64, float64)
309
+ type WindowResizeHandler func(uint32, float64, float64, float64, float64)
310
+ type WindowFocusHandler func(uint32)
311
+ type WindowBlurHandler func(uint32)
312
+ type WindowKeyHandler func(uint32, uint32, uint32, uint32, uint32)
313
+
314
+ type WindowCallbacks struct {
315
+ Close WindowCloseHandler
316
+ Move WindowMoveHandler
317
+ Resize WindowResizeHandler
318
+ Focus WindowFocusHandler
319
+ Blur WindowBlurHandler
320
+ Key WindowKeyHandler
321
+ }
322
+
323
+ type TrafficLightOffset struct {
324
+ X float64
325
+ Y float64
326
+ }
327
+
328
+ type WindowOptions struct {
329
+ Title string
330
+ Frame Rect
331
+ Style WindowStyle
332
+ TitleBarStyle string
333
+ Transparent bool
334
+ Hidden bool
335
+ Activate bool
336
+ TrafficLightOffset TrafficLightOffset
337
+ Callbacks WindowCallbacks
338
+ }
339
+
340
+ func NewWindowOptions(title string, frame Rect) WindowOptions {
341
+ return WindowOptions{
342
+ Title: title,
343
+ Frame: frame,
344
+ Style: StandardWindowStyle(),
345
+ TitleBarStyle: "default",
346
+ Activate: true,
347
+ }
348
+ }
349
+
350
+ type DecideNavigationHandler func(uint32, string) uint32
351
+ type WebviewEventHandler func(uint32, string, string)
352
+ type WebviewPostMessageHandler func(uint32, string)
353
+
354
+ type WebviewCallbacks struct {
355
+ DecideNavigation DecideNavigationHandler
356
+ Event WebviewEventHandler
357
+ EventBridge WebviewPostMessageHandler
358
+ HostBridge WebviewPostMessageHandler
359
+ BunBridge WebviewPostMessageHandler
360
+ InternalBridge WebviewPostMessageHandler
361
+ }
362
+
363
+ type WebviewOptions struct {
364
+ WindowID uint32
365
+ HostWebviewID uint32
366
+ Renderer Renderer
367
+ URL string
368
+ Frame Rect
369
+ AutoResize bool
370
+ Partition string
371
+ SecretKey string
372
+ Preload string
373
+ ViewsRoot string
374
+ Sandbox bool
375
+ StartTransparent bool
376
+ StartPassthrough bool
377
+ Callbacks WebviewCallbacks
378
+ }
379
+
380
+ func NewWebviewOptions(windowID uint32, url string, frame Rect) WebviewOptions {
381
+ return WebviewOptions{
382
+ WindowID: windowID,
383
+ Renderer: RendererNative,
384
+ URL: url,
385
+ Frame: frame,
386
+ AutoResize: true,
387
+ }
388
+ }
389
+
390
+ type WGPUViewOptions struct {
391
+ WindowID uint32
392
+ Frame Rect
393
+ StartTransparent bool
394
+ StartPassthrough bool
395
+ Hidden bool
396
+ }
397
+
398
+ func NewWGPUViewOptions(windowID uint32, frame Rect) WGPUViewOptions {
399
+ return WGPUViewOptions{WindowID: windowID, Frame: frame}
400
+ }
401
+
402
+ type StatusItemHandler func(uint32, string)
403
+
404
+ type TrayOptions struct {
405
+ Title string
406
+ Image string
407
+ IsTemplate bool
408
+ Width uint32
409
+ Height uint32
410
+ Handler StatusItemHandler
411
+ }
412
+
413
+ type NotificationOptions struct {
414
+ Title string
415
+ Body string
416
+ Subtitle string
417
+ Silent bool
418
+ }
419
+
420
+ type MessageBoxOptions struct {
421
+ BoxType string
422
+ Title string
423
+ Message string
424
+ Detail string
425
+ Buttons []string
426
+ DefaultID int
427
+ CancelID int
428
+ }
429
+
430
+ type OpenFileDialogOptions struct {
431
+ StartingFolder string
432
+ AllowedFileTypes string
433
+ CanChooseFiles bool
434
+ CanChooseDirectory bool
435
+ AllowsMultipleSelection bool
436
+ }
437
+
438
+ type Point struct {
439
+ X float64 `json:"x"`
440
+ Y float64 `json:"y"`
441
+ }
442
+
443
+ type Display struct {
444
+ ID int64 `json:"id"`
445
+ Bounds Rect `json:"bounds"`
446
+ WorkArea Rect `json:"workArea"`
447
+ ScaleFactor float64 `json:"scaleFactor"`
448
+ IsPrimary bool `json:"isPrimary"`
449
+ }
450
+
451
+ type Paths struct {
452
+ Home string
453
+ AppData string
454
+ Config string
455
+ Cache string
456
+ Temp string
457
+ Logs string
458
+ Documents string
459
+ Downloads string
460
+ Desktop string
461
+ Pictures string
462
+ Music string
463
+ Videos string
464
+ UserData string
465
+ UserCache string
466
+ UserLogs string
467
+ }
468
+
469
+ type BundlePaths struct {
470
+ ExeDir string
471
+ ResourcesDir string
472
+ }
473
+
474
+ type WgpuAdapterDevice struct {
475
+ Adapter unsafe.Pointer
476
+ Device unsafe.Pointer
477
+ }
478
+
479
+ type WgpuNative struct {
480
+ lib unsafe.Pointer
481
+ createInstance unsafe.Pointer
482
+ deviceGetQueue unsafe.Pointer
483
+ }
484
+
485
+ type WgpuContext struct {
486
+ View unsafe.Pointer
487
+ Instance unsafe.Pointer
488
+ Surface unsafe.Pointer
489
+ Adapter unsafe.Pointer
490
+ Device unsafe.Pointer
491
+ }
492
+
493
+ type Core struct {
494
+ lib unsafe.Pointer
495
+ symbols map[string]unsafe.Pointer
496
+ }
497
+
498
+ func LoadWgpuNative() (*WgpuNative, error) {
499
+ bundlePaths, err := ResolveBundlePaths()
500
+ if err != nil {
501
+ return nil, err
502
+ }
503
+ libPath := filepath.Join(bundlePaths.ExeDir, wgpuLibraryName())
504
+ pathCString := C.CString(libPath)
505
+ defer C.free(unsafe.Pointer(pathCString))
506
+
507
+ lib := C.eb_dlopen(pathCString)
508
+ if lib == nil {
509
+ return nil, fmt.Errorf("failed to open %s: %s", libPath, cConstString(C.eb_dlerror()))
510
+ }
511
+
512
+ native := &WgpuNative{lib: lib}
513
+ var ok bool
514
+ native.createInstance, ok = native.Symbol("wgpuCreateInstance")
515
+ if !ok {
516
+ return nil, errors.New("missing WGPU symbol wgpuCreateInstance")
517
+ }
518
+ native.deviceGetQueue, ok = native.Symbol("wgpuDeviceGetQueue")
519
+ if !ok {
520
+ return nil, errors.New("missing WGPU symbol wgpuDeviceGetQueue")
521
+ }
522
+ return native, nil
523
+ }
524
+
525
+ func (n *WgpuNative) Symbol(name string) (unsafe.Pointer, bool) {
526
+ nameCString := C.CString(name)
527
+ defer C.free(unsafe.Pointer(nameCString))
528
+ symbol := C.eb_dlsym(n.lib, nameCString)
529
+ return symbol, symbol != nil
530
+ }
531
+
532
+ func (n *WgpuNative) CreateInstance() (unsafe.Pointer, error) {
533
+ instance := C.eb_call_ptr_ret(n.createInstance, nil)
534
+ if instance == nil {
535
+ return nil, errors.New("failed to create WGPU instance")
536
+ }
537
+ return instance, nil
538
+ }
539
+
540
+ func (n *WgpuNative) DeviceGetQueue(device unsafe.Pointer) (unsafe.Pointer, error) {
541
+ queue := C.eb_call_ptr_ret(n.deviceGetQueue, device)
542
+ if queue == nil {
543
+ return nil, errors.New("failed to get WGPU queue")
544
+ }
545
+ return queue, nil
546
+ }
547
+
548
+ func CreateWgpuContextForView(core *Core, native *WgpuNative, view unsafe.Pointer) (WgpuContext, error) {
549
+ instance, err := native.CreateInstance()
550
+ if err != nil {
551
+ return WgpuContext{}, err
552
+ }
553
+ surface, err := core.WgpuCreateSurfaceForView(instance, view)
554
+ if err != nil {
555
+ return WgpuContext{}, err
556
+ }
557
+ adapterDevice, err := core.WgpuCreateAdapterDeviceMainThread(instance, surface)
558
+ if err != nil {
559
+ return WgpuContext{}, err
560
+ }
561
+ return WgpuContext{
562
+ View: view,
563
+ Instance: instance,
564
+ Surface: surface,
565
+ Adapter: adapterDevice.Adapter,
566
+ Device: adapterDevice.Device,
567
+ }, nil
568
+ }
569
+
570
+ func CreateWgpuContextForWGPUView(core *Core, native *WgpuNative, viewID uint32) (WgpuContext, error) {
571
+ view, err := core.GetWGPUViewPointer(viewID)
572
+ if err != nil {
573
+ return WgpuContext{}, err
574
+ }
575
+ return CreateWgpuContextForView(core, native, view)
576
+ }
577
+
578
+ func (ctx WgpuContext) GetQueue(native *WgpuNative) (unsafe.Pointer, error) {
579
+ return native.DeviceGetQueue(ctx.Device)
580
+ }
581
+
582
+ func LoadCore() (*Core, error) {
583
+ bundlePaths, err := ResolveBundlePaths()
584
+ if err != nil {
585
+ return nil, err
586
+ }
587
+ libPath := filepath.Join(bundlePaths.ExeDir, coreLibraryName())
588
+ pathCString := C.CString(libPath)
589
+ defer C.free(unsafe.Pointer(pathCString))
590
+ lib := C.eb_dlopen(pathCString)
591
+ if lib == nil {
592
+ return nil, fmt.Errorf("failed to open %s: %s", libPath, cConstString(C.eb_dlerror()))
593
+ }
594
+
595
+ core := &Core{lib: lib, symbols: make(map[string]unsafe.Pointer)}
596
+ for _, name := range requiredSymbols {
597
+ nameCString := C.CString(name)
598
+ symbol := C.eb_dlsym(lib, nameCString)
599
+ C.free(unsafe.Pointer(nameCString))
600
+ if symbol == nil {
601
+ return nil, fmt.Errorf("missing core symbol %s", name)
602
+ }
603
+ core.symbols[name] = symbol
604
+ }
605
+ return core, nil
606
+ }
607
+
608
+ var requiredSymbols = []string{
609
+ "electrobun_core_last_error",
610
+ "electrobun_core_run_main_thread",
611
+ "configureWebviewRuntime",
612
+ "getWindowStyle",
613
+ "createWindow",
614
+ "createWebview",
615
+ "createWGPUView",
616
+ "setWindowTitle",
617
+ "minimizeWindow",
618
+ "restoreWindow",
619
+ "isWindowMinimized",
620
+ "maximizeWindow",
621
+ "unmaximizeWindow",
622
+ "isWindowMaximized",
623
+ "setWindowFullScreen",
624
+ "isWindowFullScreen",
625
+ "setWindowAlwaysOnTop",
626
+ "isWindowAlwaysOnTop",
627
+ "setWindowVisibleOnAllWorkspaces",
628
+ "isWindowVisibleOnAllWorkspaces",
629
+ "showWindow",
630
+ "activateWindow",
631
+ "hideWindow",
632
+ "setWindowButtonPosition",
633
+ "setWindowPosition",
634
+ "setWindowSize",
635
+ "setWindowFrame",
636
+ "getWindowFrame",
637
+ "closeWindow",
638
+ "resizeWebview",
639
+ "loadURLInWebView",
640
+ "loadHTMLInWebView",
641
+ "webviewCanGoBack",
642
+ "webviewCanGoForward",
643
+ "webviewGoBack",
644
+ "webviewGoForward",
645
+ "webviewReload",
646
+ "webviewRemove",
647
+ "setWebviewHTMLContent",
648
+ "webviewSetTransparent",
649
+ "webviewSetPassthrough",
650
+ "webviewSetHidden",
651
+ "setWebviewNavigationRules",
652
+ "webviewFindInPage",
653
+ "webviewStopFind",
654
+ "webviewOpenDevTools",
655
+ "webviewCloseDevTools",
656
+ "webviewToggleDevTools",
657
+ "webviewSetPageZoom",
658
+ "webviewGetPageZoom",
659
+ "sendInternalMessageToWebview",
660
+ "setWGPUViewFrame",
661
+ "resizeWGPUView",
662
+ "setWGPUViewTransparent",
663
+ "setWGPUViewPassthrough",
664
+ "setWGPUViewHidden",
665
+ "removeWGPUView",
666
+ "getWGPUViewPointer",
667
+ "getWGPUViewNativeHandle",
668
+ "runWGPUViewTest",
669
+ "toggleWGPUViewTestShader",
670
+ "sendHostMessageToWebviewViaTransport",
671
+ "popNextQueuedHostMessage",
672
+ "freeCoreString",
673
+ "evaluateJavaScriptWithNoCompletion",
674
+ "createTray",
675
+ "showTray",
676
+ "hideTray",
677
+ "setTrayTitle",
678
+ "removeTray",
679
+ "getTrayBounds",
680
+ "setDockIconVisible",
681
+ "isDockIconVisible",
682
+ "getPrimaryDisplay",
683
+ "getAllDisplays",
684
+ "getCursorScreenPoint",
685
+ "moveToTrash",
686
+ "showItemInFolder",
687
+ "openExternal",
688
+ "openPath",
689
+ "showNotification",
690
+ "clipboardReadText",
691
+ "clipboardWriteText",
692
+ "clipboardClear",
693
+ "clipboardAvailableFormats",
694
+ "setApplicationMenu",
695
+ "showContextMenu",
696
+ "openFileDialog",
697
+ "showMessageBox",
698
+ "setGlobalShortcutCallback",
699
+ "registerGlobalShortcut",
700
+ "unregisterGlobalShortcut",
701
+ "unregisterAllGlobalShortcuts",
702
+ "isGlobalShortcutRegistered",
703
+ "sessionGetCookies",
704
+ "sessionSetCookie",
705
+ "sessionRemoveCookie",
706
+ "sessionClearCookies",
707
+ "sessionClearStorageData",
708
+ "setURLOpenHandler",
709
+ "setAppReopenHandler",
710
+ "setQuitRequestedHandler",
711
+ "stopEventLoop",
712
+ "waitForShutdownComplete",
713
+ "forceExit",
714
+ "wgpuCreateSurfaceForView",
715
+ "wgpuCreateAdapterDeviceMainThread",
716
+ "wgpuSurfaceConfigureMainThread",
717
+ "wgpuSurfaceGetCurrentTextureMainThread",
718
+ "wgpuSurfacePresentMainThread",
719
+ }
720
+
721
+ func (c *Core) symbol(name string) unsafe.Pointer {
722
+ return c.symbols[name]
723
+ }
724
+
725
+ func (c *Core) ConfigureWebviewRuntimeFromExecutableDir(bundlePaths BundlePaths, rpcPort uint32) error {
726
+ fullPreload, err := os.ReadFile(filepath.Join(bundlePaths.ResourcesDir, "preload-full.js"))
727
+ if err != nil {
728
+ return err
729
+ }
730
+ sandboxedPreload, err := os.ReadFile(filepath.Join(bundlePaths.ResourcesDir, "preload-sandboxed.js"))
731
+ if err != nil {
732
+ return err
733
+ }
734
+ fullCString, freeFull, err := cString(string(fullPreload), "preload-full.js")
735
+ if err != nil {
736
+ return err
737
+ }
738
+ defer freeFull()
739
+ sandboxedCString, freeSandboxed, err := cString(string(sandboxedPreload), "preload-sandboxed.js")
740
+ if err != nil {
741
+ return err
742
+ }
743
+ defer freeSandboxed()
744
+ ok := C.eb_call_configure_webview_runtime(
745
+ c.symbol("configureWebviewRuntime"),
746
+ C.uint32_t(rpcPort),
747
+ fullCString,
748
+ sandboxedCString,
749
+ )
750
+ if !bool(ok) {
751
+ return errors.New(c.LastError())
752
+ }
753
+ return nil
754
+ }
755
+
756
+ func (c *Core) CreateWindow(options WindowOptions) (uint32, error) {
757
+ title, freeTitle, err := cString(options.Title, "window title")
758
+ if err != nil {
759
+ return 0, err
760
+ }
761
+ defer freeTitle()
762
+ titleBarStyle, freeTitleBarStyle, err := cString(options.TitleBarStyle, "title bar style")
763
+ if err != nil {
764
+ return 0, err
765
+ }
766
+ defer freeTitleBarStyle()
767
+
768
+ style := options.Style
769
+ styleMask := C.eb_call_get_window_style(
770
+ c.symbol("getWindowStyle"),
771
+ cbool(style.Borderless),
772
+ cbool(style.Titled),
773
+ cbool(style.Closable),
774
+ cbool(style.Miniaturizable),
775
+ cbool(style.Resizable),
776
+ cbool(style.UnifiedTitleAndToolbar),
777
+ cbool(style.FullScreen),
778
+ cbool(style.FullSizeContentView),
779
+ cbool(style.UtilityWindow),
780
+ cbool(style.DocModalWindow),
781
+ cbool(style.NonactivatingPanel),
782
+ cbool(style.HUDWindow),
783
+ )
784
+
785
+ windowID := C.eb_call_create_window(
786
+ c.symbol("createWindow"),
787
+ C.double(options.Frame.X),
788
+ C.double(options.Frame.Y),
789
+ C.double(options.Frame.Width),
790
+ C.double(options.Frame.Height),
791
+ styleMask,
792
+ titleBarStyle,
793
+ cbool(options.Transparent),
794
+ title,
795
+ cbool(options.Hidden),
796
+ cbool(options.Activate),
797
+ C.double(options.TrafficLightOffset.X),
798
+ C.double(options.TrafficLightOffset.Y),
799
+ cbool(options.Callbacks.Close != nil),
800
+ cbool(options.Callbacks.Move != nil),
801
+ cbool(options.Callbacks.Resize != nil),
802
+ cbool(options.Callbacks.Focus != nil),
803
+ cbool(options.Callbacks.Blur != nil),
804
+ cbool(options.Callbacks.Key != nil),
805
+ )
806
+ if windowID == 0 {
807
+ return 0, errors.New(c.LastError())
808
+ }
809
+ registerWindowCallbacks(uint32(windowID), options.Callbacks)
810
+ return uint32(windowID), nil
811
+ }
812
+
813
+ func (c *Core) SetWindowTitle(windowID uint32, title string) error {
814
+ titleCString, freeTitle, err := cString(title, "window title")
815
+ if err != nil {
816
+ return err
817
+ }
818
+ defer freeTitle()
819
+ C.eb_call_u32_string(c.symbol("setWindowTitle"), C.uint32_t(windowID), titleCString)
820
+ return c.ensureLastCallSucceeded()
821
+ }
822
+
823
+ func (c *Core) MinimizeWindow(windowID uint32) error {
824
+ C.eb_call_u32(c.symbol("minimizeWindow"), C.uint32_t(windowID))
825
+ return c.ensureLastCallSucceeded()
826
+ }
827
+
828
+ func (c *Core) RestoreWindow(windowID uint32) error {
829
+ C.eb_call_u32(c.symbol("restoreWindow"), C.uint32_t(windowID))
830
+ return c.ensureLastCallSucceeded()
831
+ }
832
+
833
+ func (c *Core) IsWindowMinimized(windowID uint32) bool {
834
+ return bool(C.eb_call_u32_bool_ret(c.symbol("isWindowMinimized"), C.uint32_t(windowID)))
835
+ }
836
+
837
+ func (c *Core) MaximizeWindow(windowID uint32) error {
838
+ C.eb_call_u32(c.symbol("maximizeWindow"), C.uint32_t(windowID))
839
+ return c.ensureLastCallSucceeded()
840
+ }
841
+
842
+ func (c *Core) UnmaximizeWindow(windowID uint32) error {
843
+ C.eb_call_u32(c.symbol("unmaximizeWindow"), C.uint32_t(windowID))
844
+ return c.ensureLastCallSucceeded()
845
+ }
846
+
847
+ func (c *Core) IsWindowMaximized(windowID uint32) bool {
848
+ return bool(C.eb_call_u32_bool_ret(c.symbol("isWindowMaximized"), C.uint32_t(windowID)))
849
+ }
850
+
851
+ func (c *Core) SetWindowFullScreen(windowID uint32, fullScreen bool) error {
852
+ C.eb_call_u32_bool(c.symbol("setWindowFullScreen"), C.uint32_t(windowID), cbool(fullScreen))
853
+ return c.ensureLastCallSucceeded()
854
+ }
855
+
856
+ func (c *Core) IsWindowFullScreen(windowID uint32) bool {
857
+ return bool(C.eb_call_u32_bool_ret(c.symbol("isWindowFullScreen"), C.uint32_t(windowID)))
858
+ }
859
+
860
+ func (c *Core) SetWindowAlwaysOnTop(windowID uint32, alwaysOnTop bool) error {
861
+ C.eb_call_u32_bool(c.symbol("setWindowAlwaysOnTop"), C.uint32_t(windowID), cbool(alwaysOnTop))
862
+ return c.ensureLastCallSucceeded()
863
+ }
864
+
865
+ func (c *Core) IsWindowAlwaysOnTop(windowID uint32) bool {
866
+ return bool(C.eb_call_u32_bool_ret(c.symbol("isWindowAlwaysOnTop"), C.uint32_t(windowID)))
867
+ }
868
+
869
+ func (c *Core) SetWindowVisibleOnAllWorkspaces(windowID uint32, visible bool) error {
870
+ C.eb_call_u32_bool(c.symbol("setWindowVisibleOnAllWorkspaces"), C.uint32_t(windowID), cbool(visible))
871
+ return c.ensureLastCallSucceeded()
872
+ }
873
+
874
+ func (c *Core) IsWindowVisibleOnAllWorkspaces(windowID uint32) bool {
875
+ return bool(C.eb_call_u32_bool_ret(c.symbol("isWindowVisibleOnAllWorkspaces"), C.uint32_t(windowID)))
876
+ }
877
+
878
+ func (c *Core) ShowWindow(windowID uint32, activate bool) error {
879
+ C.eb_call_u32_bool(c.symbol("showWindow"), C.uint32_t(windowID), cbool(activate))
880
+ return c.ensureLastCallSucceeded()
881
+ }
882
+
883
+ func (c *Core) ActivateWindow(windowID uint32) error {
884
+ C.eb_call_u32(c.symbol("activateWindow"), C.uint32_t(windowID))
885
+ return c.ensureLastCallSucceeded()
886
+ }
887
+
888
+ func (c *Core) HideWindow(windowID uint32) error {
889
+ C.eb_call_u32(c.symbol("hideWindow"), C.uint32_t(windowID))
890
+ return c.ensureLastCallSucceeded()
891
+ }
892
+
893
+ func (c *Core) SetWindowButtonPosition(windowID uint32, x, y float64) error {
894
+ C.eb_call_u32_f64_f64(c.symbol("setWindowButtonPosition"), C.uint32_t(windowID), C.double(x), C.double(y))
895
+ return c.ensureLastCallSucceeded()
896
+ }
897
+
898
+ func (c *Core) SetWindowPosition(windowID uint32, x, y float64) error {
899
+ C.eb_call_u32_f64_f64(c.symbol("setWindowPosition"), C.uint32_t(windowID), C.double(x), C.double(y))
900
+ return c.ensureLastCallSucceeded()
901
+ }
902
+
903
+ func (c *Core) SetWindowSize(windowID uint32, width, height float64) error {
904
+ C.eb_call_u32_f64_f64(c.symbol("setWindowSize"), C.uint32_t(windowID), C.double(width), C.double(height))
905
+ return c.ensureLastCallSucceeded()
906
+ }
907
+
908
+ func (c *Core) SetWindowFrame(windowID uint32, frame Rect) error {
909
+ C.eb_call_u32_f64_f64_f64_f64(c.symbol("setWindowFrame"), C.uint32_t(windowID), C.double(frame.X), C.double(frame.Y), C.double(frame.Width), C.double(frame.Height))
910
+ return c.ensureLastCallSucceeded()
911
+ }
912
+
913
+ func (c *Core) GetWindowFrame(windowID uint32) (Rect, error) {
914
+ var x, y, width, height C.double
915
+ C.eb_call_get_window_frame(c.symbol("getWindowFrame"), C.uint32_t(windowID), &x, &y, &width, &height)
916
+ if err := c.ensureLastCallSucceeded(); err != nil {
917
+ return Rect{}, err
918
+ }
919
+ return NewRect(float64(x), float64(y), float64(width), float64(height)), nil
920
+ }
921
+
922
+ func (c *Core) CloseWindow(windowID uint32) error {
923
+ C.eb_call_u32(c.symbol("closeWindow"), C.uint32_t(windowID))
924
+ return c.ensureLastCallSucceeded()
925
+ }
926
+
927
+ func (c *Core) CreateWebview(options WebviewOptions) (uint32, error) {
928
+ renderer, freeRenderer, err := cString(string(options.Renderer), "renderer")
929
+ if err != nil {
930
+ return 0, err
931
+ }
932
+ defer freeRenderer()
933
+ url, freeURL, err := cString(options.URL, "webview url")
934
+ if err != nil {
935
+ return 0, err
936
+ }
937
+ defer freeURL()
938
+ partition, freePartition, err := cString(options.Partition, "partition")
939
+ if err != nil {
940
+ return 0, err
941
+ }
942
+ defer freePartition()
943
+ secretKey, freeSecretKey, err := cString(options.SecretKey, "secret key")
944
+ if err != nil {
945
+ return 0, err
946
+ }
947
+ defer freeSecretKey()
948
+ preload, freePreload, err := cString(options.Preload, "preload")
949
+ if err != nil {
950
+ return 0, err
951
+ }
952
+ defer freePreload()
953
+ viewsRoot, freeViewsRoot, err := cString(options.ViewsRoot, "views root")
954
+ if err != nil {
955
+ return 0, err
956
+ }
957
+ defer freeViewsRoot()
958
+
959
+ hostBridge := options.Callbacks.HostBridge
960
+ if hostBridge == nil {
961
+ hostBridge = options.Callbacks.BunBridge
962
+ }
963
+ webviewID := C.eb_call_create_webview(
964
+ c.symbol("createWebview"),
965
+ C.uint32_t(options.WindowID),
966
+ C.uint32_t(options.HostWebviewID),
967
+ renderer,
968
+ url,
969
+ C.double(options.Frame.X),
970
+ C.double(options.Frame.Y),
971
+ C.double(options.Frame.Width),
972
+ C.double(options.Frame.Height),
973
+ cbool(options.AutoResize),
974
+ partition,
975
+ cbool(options.Callbacks.DecideNavigation != nil),
976
+ cbool(options.Callbacks.Event != nil),
977
+ cbool(options.Callbacks.EventBridge != nil),
978
+ cbool(hostBridge != nil),
979
+ cbool(options.Callbacks.InternalBridge != nil),
980
+ secretKey,
981
+ preload,
982
+ viewsRoot,
983
+ cbool(options.Sandbox),
984
+ cbool(options.StartTransparent),
985
+ cbool(options.StartPassthrough),
986
+ )
987
+ if webviewID == 0 {
988
+ return 0, errors.New(c.LastError())
989
+ }
990
+ callbacks := options.Callbacks
991
+ callbacks.HostBridge = hostBridge
992
+ registerWebviewCallbacks(uint32(webviewID), callbacks)
993
+ return uint32(webviewID), nil
994
+ }
995
+
996
+ func (c *Core) ResizeWebview(webviewID uint32, frame Rect, masksJSON string) error {
997
+ masks, freeMasks, err := cString(masksJSON, "resize masks json")
998
+ if err != nil {
999
+ return err
1000
+ }
1001
+ defer freeMasks()
1002
+ C.eb_call_resize_webview(c.symbol("resizeWebview"), C.uint32_t(webviewID), C.double(frame.X), C.double(frame.Y), C.double(frame.Width), C.double(frame.Height), masks)
1003
+ return c.ensureLastCallSucceeded()
1004
+ }
1005
+
1006
+ func (c *Core) LoadURLInWebview(webviewID uint32, url string) error {
1007
+ urlCString, freeURL, err := cString(url, "webview url")
1008
+ if err != nil {
1009
+ return err
1010
+ }
1011
+ defer freeURL()
1012
+ C.eb_call_u32_string(c.symbol("loadURLInWebView"), C.uint32_t(webviewID), urlCString)
1013
+ return c.ensureLastCallSucceeded()
1014
+ }
1015
+
1016
+ func (c *Core) LoadHTMLInWebview(webviewID uint32, html string) error {
1017
+ htmlCString, freeHTML, err := cString(html, "webview html")
1018
+ if err != nil {
1019
+ return err
1020
+ }
1021
+ defer freeHTML()
1022
+ C.eb_call_u32_string(c.symbol("loadHTMLInWebView"), C.uint32_t(webviewID), htmlCString)
1023
+ return c.ensureLastCallSucceeded()
1024
+ }
1025
+
1026
+ func (c *Core) CanWebviewGoBack(webviewID uint32) bool {
1027
+ return bool(C.eb_call_u32_bool_ret(c.symbol("webviewCanGoBack"), C.uint32_t(webviewID)))
1028
+ }
1029
+
1030
+ func (c *Core) CanWebviewGoForward(webviewID uint32) bool {
1031
+ return bool(C.eb_call_u32_bool_ret(c.symbol("webviewCanGoForward"), C.uint32_t(webviewID)))
1032
+ }
1033
+
1034
+ func (c *Core) WebviewGoBack(webviewID uint32) error {
1035
+ C.eb_call_u32(c.symbol("webviewGoBack"), C.uint32_t(webviewID))
1036
+ return c.ensureLastCallSucceeded()
1037
+ }
1038
+
1039
+ func (c *Core) WebviewGoForward(webviewID uint32) error {
1040
+ C.eb_call_u32(c.symbol("webviewGoForward"), C.uint32_t(webviewID))
1041
+ return c.ensureLastCallSucceeded()
1042
+ }
1043
+
1044
+ func (c *Core) ReloadWebview(webviewID uint32) error {
1045
+ C.eb_call_u32(c.symbol("webviewReload"), C.uint32_t(webviewID))
1046
+ return c.ensureLastCallSucceeded()
1047
+ }
1048
+
1049
+ func (c *Core) RemoveWebview(webviewID uint32) error {
1050
+ C.eb_call_u32(c.symbol("webviewRemove"), C.uint32_t(webviewID))
1051
+ forgetWebviewCallbacks(webviewID)
1052
+ return c.ensureLastCallSucceeded()
1053
+ }
1054
+
1055
+ func (c *Core) SetWebviewHTMLContent(webviewID uint32, html string) error {
1056
+ htmlCString, freeHTML, err := cString(html, "webview html")
1057
+ if err != nil {
1058
+ return err
1059
+ }
1060
+ defer freeHTML()
1061
+ C.eb_call_u32_string(c.symbol("setWebviewHTMLContent"), C.uint32_t(webviewID), htmlCString)
1062
+ return c.ensureLastCallSucceeded()
1063
+ }
1064
+
1065
+ func (c *Core) SetWebviewTransparent(webviewID uint32, transparent bool) error {
1066
+ C.eb_call_u32_bool(c.symbol("webviewSetTransparent"), C.uint32_t(webviewID), cbool(transparent))
1067
+ return c.ensureLastCallSucceeded()
1068
+ }
1069
+
1070
+ func (c *Core) SetWebviewPassthrough(webviewID uint32, passthrough bool) error {
1071
+ C.eb_call_u32_bool(c.symbol("webviewSetPassthrough"), C.uint32_t(webviewID), cbool(passthrough))
1072
+ return c.ensureLastCallSucceeded()
1073
+ }
1074
+
1075
+ func (c *Core) SetWebviewHidden(webviewID uint32, hidden bool) error {
1076
+ C.eb_call_u32_bool(c.symbol("webviewSetHidden"), C.uint32_t(webviewID), cbool(hidden))
1077
+ return c.ensureLastCallSucceeded()
1078
+ }
1079
+
1080
+ func (c *Core) SetWebviewNavigationRules(webviewID uint32, rulesJSON string) error {
1081
+ rules, freeRules, err := cString(rulesJSON, "navigation rules json")
1082
+ if err != nil {
1083
+ return err
1084
+ }
1085
+ defer freeRules()
1086
+ C.eb_call_u32_string(c.symbol("setWebviewNavigationRules"), C.uint32_t(webviewID), rules)
1087
+ return c.ensureLastCallSucceeded()
1088
+ }
1089
+
1090
+ func (c *Core) WebviewFindInPage(webviewID uint32, text string, forward, matchCase bool) error {
1091
+ textCString, freeText, err := cString(text, "find text")
1092
+ if err != nil {
1093
+ return err
1094
+ }
1095
+ defer freeText()
1096
+ C.eb_call_u32_string_bool_bool(c.symbol("webviewFindInPage"), C.uint32_t(webviewID), textCString, cbool(forward), cbool(matchCase))
1097
+ return c.ensureLastCallSucceeded()
1098
+ }
1099
+
1100
+ func (c *Core) WebviewStopFind(webviewID uint32) error {
1101
+ C.eb_call_u32(c.symbol("webviewStopFind"), C.uint32_t(webviewID))
1102
+ return c.ensureLastCallSucceeded()
1103
+ }
1104
+
1105
+ func (c *Core) OpenWebviewDevtools(webviewID uint32) error {
1106
+ C.eb_call_u32(c.symbol("webviewOpenDevTools"), C.uint32_t(webviewID))
1107
+ return c.ensureLastCallSucceeded()
1108
+ }
1109
+
1110
+ func (c *Core) CloseWebviewDevtools(webviewID uint32) error {
1111
+ C.eb_call_u32(c.symbol("webviewCloseDevTools"), C.uint32_t(webviewID))
1112
+ return c.ensureLastCallSucceeded()
1113
+ }
1114
+
1115
+ func (c *Core) ToggleWebviewDevtools(webviewID uint32) error {
1116
+ C.eb_call_u32(c.symbol("webviewToggleDevTools"), C.uint32_t(webviewID))
1117
+ return c.ensureLastCallSucceeded()
1118
+ }
1119
+
1120
+ func (c *Core) SetWebviewPageZoom(webviewID uint32, zoomLevel float64) error {
1121
+ C.eb_call_u32_f64(c.symbol("webviewSetPageZoom"), C.uint32_t(webviewID), C.double(zoomLevel))
1122
+ return c.ensureLastCallSucceeded()
1123
+ }
1124
+
1125
+ func (c *Core) GetWebviewPageZoom(webviewID uint32) float64 {
1126
+ return float64(C.eb_call_u32_f64_ret(c.symbol("webviewGetPageZoom"), C.uint32_t(webviewID)))
1127
+ }
1128
+
1129
+ func (c *Core) SendInternalMessageToWebviewJSON(webviewID uint32, messageJSON string) error {
1130
+ message, freeMessage, err := cString(messageJSON, "internal message")
1131
+ if err != nil {
1132
+ return err
1133
+ }
1134
+ defer freeMessage()
1135
+ ok := C.eb_call_send_host_message(c.symbol("sendInternalMessageToWebview"), C.uint32_t(webviewID), message)
1136
+ if !bool(ok) {
1137
+ return errors.New(c.LastError())
1138
+ }
1139
+ return nil
1140
+ }
1141
+
1142
+ func (c *Core) CreateWGPUView(options WGPUViewOptions) (uint32, error) {
1143
+ viewID := C.eb_call_create_wgpu_view(
1144
+ c.symbol("createWGPUView"),
1145
+ C.uint32_t(options.WindowID),
1146
+ C.double(options.Frame.X),
1147
+ C.double(options.Frame.Y),
1148
+ C.double(options.Frame.Width),
1149
+ C.double(options.Frame.Height),
1150
+ cbool(options.StartTransparent),
1151
+ cbool(options.StartPassthrough),
1152
+ cbool(options.Hidden),
1153
+ )
1154
+ if viewID == 0 {
1155
+ return 0, errors.New(c.LastError())
1156
+ }
1157
+ return uint32(viewID), nil
1158
+ }
1159
+
1160
+ func (c *Core) SetWGPUViewFrame(viewID uint32, frame Rect) error {
1161
+ C.eb_call_u32_f64_f64_f64_f64(c.symbol("setWGPUViewFrame"), C.uint32_t(viewID), C.double(frame.X), C.double(frame.Y), C.double(frame.Width), C.double(frame.Height))
1162
+ return c.ensureLastCallSucceeded()
1163
+ }
1164
+
1165
+ func (c *Core) ResizeWGPUView(viewID uint32, frame Rect, masksJSON string) error {
1166
+ masks, freeMasks, err := cString(masksJSON, "resize masks json")
1167
+ if err != nil {
1168
+ return err
1169
+ }
1170
+ defer freeMasks()
1171
+ C.eb_call_resize_webview(c.symbol("resizeWGPUView"), C.uint32_t(viewID), C.double(frame.X), C.double(frame.Y), C.double(frame.Width), C.double(frame.Height), masks)
1172
+ return c.ensureLastCallSucceeded()
1173
+ }
1174
+
1175
+ func (c *Core) SetWGPUViewTransparent(viewID uint32, transparent bool) error {
1176
+ C.eb_call_u32_bool(c.symbol("setWGPUViewTransparent"), C.uint32_t(viewID), cbool(transparent))
1177
+ return c.ensureLastCallSucceeded()
1178
+ }
1179
+
1180
+ func (c *Core) SetWGPUViewPassthrough(viewID uint32, passthrough bool) error {
1181
+ C.eb_call_u32_bool(c.symbol("setWGPUViewPassthrough"), C.uint32_t(viewID), cbool(passthrough))
1182
+ return c.ensureLastCallSucceeded()
1183
+ }
1184
+
1185
+ func (c *Core) SetWGPUViewHidden(viewID uint32, hidden bool) error {
1186
+ C.eb_call_u32_bool(c.symbol("setWGPUViewHidden"), C.uint32_t(viewID), cbool(hidden))
1187
+ return c.ensureLastCallSucceeded()
1188
+ }
1189
+
1190
+ func (c *Core) RemoveWGPUView(viewID uint32) error {
1191
+ C.eb_call_u32(c.symbol("removeWGPUView"), C.uint32_t(viewID))
1192
+ return c.ensureLastCallSucceeded()
1193
+ }
1194
+
1195
+ func (c *Core) GetWGPUViewPointer(viewID uint32) (unsafe.Pointer, error) {
1196
+ ptr := C.eb_call_u32_ptr_ret(c.symbol("getWGPUViewPointer"), C.uint32_t(viewID))
1197
+ if ptr == nil {
1198
+ return nil, errors.New(c.LastError())
1199
+ }
1200
+ return ptr, nil
1201
+ }
1202
+
1203
+ func (c *Core) GetWGPUViewNativeHandle(viewID uint32) (unsafe.Pointer, error) {
1204
+ ptr := C.eb_call_u32_ptr_ret(c.symbol("getWGPUViewNativeHandle"), C.uint32_t(viewID))
1205
+ if ptr == nil {
1206
+ return nil, errors.New(c.LastError())
1207
+ }
1208
+ return ptr, nil
1209
+ }
1210
+
1211
+ func (c *Core) RunWGPUViewTest(viewID uint32) error {
1212
+ C.eb_call_u32(c.symbol("runWGPUViewTest"), C.uint32_t(viewID))
1213
+ return c.ensureLastCallSucceeded()
1214
+ }
1215
+
1216
+ func (c *Core) ToggleWGPUViewTestShader(viewID uint32) error {
1217
+ C.eb_call_u32(c.symbol("toggleWGPUViewTestShader"), C.uint32_t(viewID))
1218
+ return c.ensureLastCallSucceeded()
1219
+ }
1220
+
1221
+ func (c *Core) EvaluateJavaScriptWithNoCompletion(webviewID uint32, script string) error {
1222
+ scriptCString, freeScript, err := cString(script, "javascript")
1223
+ if err != nil {
1224
+ return err
1225
+ }
1226
+ defer freeScript()
1227
+ C.eb_call_u32_string(c.symbol("evaluateJavaScriptWithNoCompletion"), C.uint32_t(webviewID), scriptCString)
1228
+ return c.ensureLastCallSucceeded()
1229
+ }
1230
+
1231
+ func (c *Core) SendHostMessageToWebviewJSON(webviewID uint32, messageJSON string) error {
1232
+ message, freeMessage, err := cString(messageJSON, "host message")
1233
+ if err != nil {
1234
+ return err
1235
+ }
1236
+ defer freeMessage()
1237
+ ok := C.eb_call_send_host_message(c.symbol("sendHostMessageToWebviewViaTransport"), C.uint32_t(webviewID), message)
1238
+ if !bool(ok) {
1239
+ return c.EvaluateJavaScriptWithNoCompletion(
1240
+ webviewID,
1241
+ fmt.Sprintf("window.__electrobun.receiveMessageFromHost(%s);", messageJSON),
1242
+ )
1243
+ }
1244
+ return nil
1245
+ }
1246
+
1247
+ func (c *Core) PopNextQueuedHostMessageString() (uint32, string, bool) {
1248
+ var webviewID C.uint32_t
1249
+ ptr := C.eb_call_pop_host_message(c.symbol("popNextQueuedHostMessage"), &webviewID)
1250
+ if ptr == nil {
1251
+ return 0, "", false
1252
+ }
1253
+ message := C.GoString(ptr)
1254
+ C.eb_call_free_core_string(c.symbol("freeCoreString"), ptr)
1255
+ return uint32(webviewID), message, true
1256
+ }
1257
+
1258
+ func (c *Core) CreateTray(options TrayOptions) (uint32, error) {
1259
+ title, freeTitle, err := cString(options.Title, "tray title")
1260
+ if err != nil {
1261
+ return 0, err
1262
+ }
1263
+ defer freeTitle()
1264
+ image, freeImage, err := cString(options.Image, "tray image")
1265
+ if err != nil {
1266
+ return 0, err
1267
+ }
1268
+ defer freeImage()
1269
+ setStatusItemHandler(options.Handler)
1270
+ trayID := C.eb_call_create_tray(c.symbol("createTray"), title, image, cbool(options.IsTemplate), C.uint32_t(options.Width), C.uint32_t(options.Height), cbool(options.Handler != nil))
1271
+ if trayID == 0 {
1272
+ return 0, errors.New(c.LastError())
1273
+ }
1274
+ return uint32(trayID), nil
1275
+ }
1276
+
1277
+ func (c *Core) ShowTray(trayID uint32) error {
1278
+ if !bool(C.eb_call_show_tray(c.symbol("showTray"), C.uint32_t(trayID))) {
1279
+ return errors.New(c.LastError())
1280
+ }
1281
+ return nil
1282
+ }
1283
+
1284
+ func (c *Core) HideTray(trayID uint32) error {
1285
+ C.eb_call_u32(c.symbol("hideTray"), C.uint32_t(trayID))
1286
+ return c.ensureLastCallSucceeded()
1287
+ }
1288
+
1289
+ func (c *Core) SetTrayTitle(trayID uint32, title string) error {
1290
+ titleCString, freeTitle, err := cString(title, "tray title")
1291
+ if err != nil {
1292
+ return err
1293
+ }
1294
+ defer freeTitle()
1295
+ C.eb_call_u32_string(c.symbol("setTrayTitle"), C.uint32_t(trayID), titleCString)
1296
+ return c.ensureLastCallSucceeded()
1297
+ }
1298
+
1299
+ func (c *Core) RemoveTray(trayID uint32) error {
1300
+ C.eb_call_u32(c.symbol("removeTray"), C.uint32_t(trayID))
1301
+ return c.ensureLastCallSucceeded()
1302
+ }
1303
+
1304
+ func (c *Core) GetTrayBounds(trayID uint32) (Rect, error) {
1305
+ ptr := C.eb_call_u32_const_string_ret(c.symbol("getTrayBounds"), C.uint32_t(trayID))
1306
+ if ptr == nil {
1307
+ return Rect{}, errors.New(c.LastError())
1308
+ }
1309
+ return ParseRectJSON(C.GoString(ptr)), nil
1310
+ }
1311
+
1312
+ func (c *Core) SetDockIconVisible(visible bool) error {
1313
+ C.eb_call_bool(c.symbol("setDockIconVisible"), cbool(visible))
1314
+ return c.ensureLastCallSucceeded()
1315
+ }
1316
+
1317
+ func (c *Core) IsDockIconVisible() bool {
1318
+ return bool(C.eb_call_bool_ret(c.symbol("isDockIconVisible")))
1319
+ }
1320
+
1321
+ func (c *Core) GetPrimaryDisplay() (Display, error) {
1322
+ ptr := C.eb_call_string_ret(c.symbol("getPrimaryDisplay"))
1323
+ if ptr == nil {
1324
+ return Display{}, errors.New(c.LastError())
1325
+ }
1326
+ jsonValue := C.GoString(ptr)
1327
+ return ParseDisplayJSON(jsonValue), nil
1328
+ }
1329
+
1330
+ func (c *Core) GetAllDisplays() ([]Display, error) {
1331
+ ptr := C.eb_call_string_ret(c.symbol("getAllDisplays"))
1332
+ if ptr == nil {
1333
+ return nil, errors.New(c.LastError())
1334
+ }
1335
+ jsonValue := C.GoString(ptr)
1336
+ var displays []Display
1337
+ if err := json.Unmarshal([]byte(jsonValue), &displays); err != nil {
1338
+ return nil, err
1339
+ }
1340
+ return displays, nil
1341
+ }
1342
+
1343
+ func (c *Core) GetCursorScreenPoint() (Point, error) {
1344
+ ptr := C.eb_call_string_ret(c.symbol("getCursorScreenPoint"))
1345
+ if ptr == nil {
1346
+ return Point{}, errors.New(c.LastError())
1347
+ }
1348
+ jsonValue := C.GoString(ptr)
1349
+ var point Point
1350
+ if err := json.Unmarshal([]byte(jsonValue), &point); err != nil {
1351
+ return Point{}, err
1352
+ }
1353
+ return point, nil
1354
+ }
1355
+
1356
+ func (c *Core) MoveToTrash(path string) (bool, error) {
1357
+ pathCString, freePath, err := cString(path, "path")
1358
+ if err != nil {
1359
+ return false, err
1360
+ }
1361
+ defer freePath()
1362
+ return bool(C.eb_call_string_bool_ret(c.symbol("moveToTrash"), pathCString)), nil
1363
+ }
1364
+
1365
+ func (c *Core) ShowItemInFolder(path string) error {
1366
+ pathCString, freePath, err := cString(path, "path")
1367
+ if err != nil {
1368
+ return err
1369
+ }
1370
+ defer freePath()
1371
+ C.eb_call_string(c.symbol("showItemInFolder"), pathCString)
1372
+ return c.ensureLastCallSucceeded()
1373
+ }
1374
+
1375
+ func (c *Core) OpenExternal(url string) (bool, error) {
1376
+ urlCString, freeURL, err := cString(url, "url")
1377
+ if err != nil {
1378
+ return false, err
1379
+ }
1380
+ defer freeURL()
1381
+ return bool(C.eb_call_string_bool_ret(c.symbol("openExternal"), urlCString)), nil
1382
+ }
1383
+
1384
+ func (c *Core) OpenPath(path string) (bool, error) {
1385
+ pathCString, freePath, err := cString(path, "path")
1386
+ if err != nil {
1387
+ return false, err
1388
+ }
1389
+ defer freePath()
1390
+ return bool(C.eb_call_string_bool_ret(c.symbol("openPath"), pathCString)), nil
1391
+ }
1392
+
1393
+ func (c *Core) ShowNotification(options NotificationOptions) error {
1394
+ title, freeTitle, err := cString(options.Title, "notification title")
1395
+ if err != nil {
1396
+ return err
1397
+ }
1398
+ defer freeTitle()
1399
+ body, freeBody, err := cString(options.Body, "notification body")
1400
+ if err != nil {
1401
+ return err
1402
+ }
1403
+ defer freeBody()
1404
+ subtitle, freeSubtitle, err := cString(options.Subtitle, "notification subtitle")
1405
+ if err != nil {
1406
+ return err
1407
+ }
1408
+ defer freeSubtitle()
1409
+ C.eb_call_notification(c.symbol("showNotification"), title, body, subtitle, cbool(options.Silent))
1410
+ return c.ensureLastCallSucceeded()
1411
+ }
1412
+
1413
+ func (c *Core) ClipboardReadText() (string, bool, error) {
1414
+ ptr := C.eb_call_string_ret(c.symbol("clipboardReadText"))
1415
+ if ptr == nil {
1416
+ return "", false, nil
1417
+ }
1418
+ text := C.GoString(ptr)
1419
+ return text, true, nil
1420
+ }
1421
+
1422
+ func (c *Core) ClipboardWriteText(text string) error {
1423
+ textCString, freeText, err := cString(text, "clipboard text")
1424
+ if err != nil {
1425
+ return err
1426
+ }
1427
+ defer freeText()
1428
+ C.eb_call_string(c.symbol("clipboardWriteText"), textCString)
1429
+ return c.ensureLastCallSucceeded()
1430
+ }
1431
+
1432
+ func (c *Core) ClipboardClear() error {
1433
+ C.eb_call_void(c.symbol("clipboardClear"))
1434
+ return c.ensureLastCallSucceeded()
1435
+ }
1436
+
1437
+ func (c *Core) ClipboardAvailableFormatsCSV() (string, error) {
1438
+ ptr := C.eb_call_string_ret(c.symbol("clipboardAvailableFormats"))
1439
+ if ptr == nil {
1440
+ return "", nil
1441
+ }
1442
+ formats := C.GoString(ptr)
1443
+ return formats, nil
1444
+ }
1445
+
1446
+ func (c *Core) SetApplicationMenuJSON(menuJSON string, handler StatusItemHandler) error {
1447
+ menu, freeMenu, err := cString(menuJSON, "application menu json")
1448
+ if err != nil {
1449
+ return err
1450
+ }
1451
+ defer freeMenu()
1452
+ setStatusItemHandler(handler)
1453
+ C.eb_call_menu(c.symbol("setApplicationMenu"), menu, cbool(handler != nil))
1454
+ return c.ensureLastCallSucceeded()
1455
+ }
1456
+
1457
+ func (c *Core) ShowContextMenuJSON(menuJSON string, handler StatusItemHandler) error {
1458
+ menu, freeMenu, err := cString(menuJSON, "context menu json")
1459
+ if err != nil {
1460
+ return err
1461
+ }
1462
+ defer freeMenu()
1463
+ setStatusItemHandler(handler)
1464
+ C.eb_call_menu(c.symbol("showContextMenu"), menu, cbool(handler != nil))
1465
+ return c.ensureLastCallSucceeded()
1466
+ }
1467
+
1468
+ func (c *Core) OpenFileDialog(options OpenFileDialogOptions) (string, error) {
1469
+ startingFolder, freeStartingFolder, err := cString(options.StartingFolder, "starting folder")
1470
+ if err != nil {
1471
+ return "", err
1472
+ }
1473
+ defer freeStartingFolder()
1474
+ allowedFileTypes, freeAllowedFileTypes, err := cString(options.AllowedFileTypes, "allowed file types")
1475
+ if err != nil {
1476
+ return "", err
1477
+ }
1478
+ defer freeAllowedFileTypes()
1479
+ ptr := C.eb_call_open_file_dialog(
1480
+ c.symbol("openFileDialog"),
1481
+ startingFolder,
1482
+ allowedFileTypes,
1483
+ boolInt(options.CanChooseFiles),
1484
+ boolInt(options.CanChooseDirectory),
1485
+ boolInt(options.AllowsMultipleSelection),
1486
+ )
1487
+ if ptr == nil {
1488
+ return "", nil
1489
+ }
1490
+ value := C.GoString(ptr)
1491
+ return value, nil
1492
+ }
1493
+
1494
+ func (c *Core) ShowMessageBox(options MessageBoxOptions) (int, error) {
1495
+ boxType, freeBoxType, err := cString(options.BoxType, "message box type")
1496
+ if err != nil {
1497
+ return 0, err
1498
+ }
1499
+ defer freeBoxType()
1500
+ title, freeTitle, err := cString(options.Title, "message box title")
1501
+ if err != nil {
1502
+ return 0, err
1503
+ }
1504
+ defer freeTitle()
1505
+ message, freeMessage, err := cString(options.Message, "message box message")
1506
+ if err != nil {
1507
+ return 0, err
1508
+ }
1509
+ defer freeMessage()
1510
+ detail, freeDetail, err := cString(options.Detail, "message box detail")
1511
+ if err != nil {
1512
+ return 0, err
1513
+ }
1514
+ defer freeDetail()
1515
+ buttons, freeButtons, err := cString(strings.Join(options.Buttons, ","), "message box buttons")
1516
+ if err != nil {
1517
+ return 0, err
1518
+ }
1519
+ defer freeButtons()
1520
+ response := C.eb_call_show_message_box(c.symbol("showMessageBox"), boxType, title, message, detail, buttons, C.int(options.DefaultID), C.int(options.CancelID))
1521
+ if err := c.ensureLastCallSucceeded(); err != nil {
1522
+ return 0, err
1523
+ }
1524
+ return int(response), nil
1525
+ }
1526
+
1527
+ func (c *Core) SetGlobalShortcutCallback(handler func(string)) error {
1528
+ setGlobalShortcutHandler(handler)
1529
+ C.eb_call_set_global_shortcut_callback(c.symbol("setGlobalShortcutCallback"), cbool(handler != nil))
1530
+ return c.ensureLastCallSucceeded()
1531
+ }
1532
+
1533
+ func (c *Core) RegisterGlobalShortcut(accelerator string) (bool, error) {
1534
+ value, freeValue, err := cString(accelerator, "accelerator")
1535
+ if err != nil {
1536
+ return false, err
1537
+ }
1538
+ defer freeValue()
1539
+ return bool(C.eb_call_string_bool_ret(c.symbol("registerGlobalShortcut"), value)), nil
1540
+ }
1541
+
1542
+ func (c *Core) UnregisterGlobalShortcut(accelerator string) (bool, error) {
1543
+ value, freeValue, err := cString(accelerator, "accelerator")
1544
+ if err != nil {
1545
+ return false, err
1546
+ }
1547
+ defer freeValue()
1548
+ return bool(C.eb_call_string_bool_ret(c.symbol("unregisterGlobalShortcut"), value)), nil
1549
+ }
1550
+
1551
+ func (c *Core) UnregisterAllGlobalShortcuts() error {
1552
+ C.eb_call_void(c.symbol("unregisterAllGlobalShortcuts"))
1553
+ return c.ensureLastCallSucceeded()
1554
+ }
1555
+
1556
+ func (c *Core) IsGlobalShortcutRegistered(accelerator string) (bool, error) {
1557
+ value, freeValue, err := cString(accelerator, "accelerator")
1558
+ if err != nil {
1559
+ return false, err
1560
+ }
1561
+ defer freeValue()
1562
+ return bool(C.eb_call_string_bool_ret(c.symbol("isGlobalShortcutRegistered"), value)), nil
1563
+ }
1564
+
1565
+ func (c *Core) SessionGetCookies(partition, filterJSON string) (string, error) {
1566
+ partitionCString, freePartition, err := cString(partition, "session partition")
1567
+ if err != nil {
1568
+ return "", err
1569
+ }
1570
+ defer freePartition()
1571
+ filterCString, freeFilter, err := cString(filterJSON, "cookie filter json")
1572
+ if err != nil {
1573
+ return "", err
1574
+ }
1575
+ defer freeFilter()
1576
+ ptr := C.eb_call_string_string_ret(c.symbol("sessionGetCookies"), partitionCString, filterCString)
1577
+ if ptr == nil {
1578
+ return "[]", nil
1579
+ }
1580
+ value := C.GoString(ptr)
1581
+ return value, nil
1582
+ }
1583
+
1584
+ func (c *Core) SessionSetCookie(partition, cookieJSON string) (bool, error) {
1585
+ partitionCString, freePartition, err := cString(partition, "session partition")
1586
+ if err != nil {
1587
+ return false, err
1588
+ }
1589
+ defer freePartition()
1590
+ cookieCString, freeCookie, err := cString(cookieJSON, "cookie json")
1591
+ if err != nil {
1592
+ return false, err
1593
+ }
1594
+ defer freeCookie()
1595
+ return bool(C.eb_call_string_string_bool_ret(c.symbol("sessionSetCookie"), partitionCString, cookieCString)), nil
1596
+ }
1597
+
1598
+ func (c *Core) SessionRemoveCookie(partition, url, name string) (bool, error) {
1599
+ partitionCString, freePartition, err := cString(partition, "session partition")
1600
+ if err != nil {
1601
+ return false, err
1602
+ }
1603
+ defer freePartition()
1604
+ urlCString, freeURL, err := cString(url, "cookie url")
1605
+ if err != nil {
1606
+ return false, err
1607
+ }
1608
+ defer freeURL()
1609
+ nameCString, freeName, err := cString(name, "cookie name")
1610
+ if err != nil {
1611
+ return false, err
1612
+ }
1613
+ defer freeName()
1614
+ return bool(C.eb_call_string_string_string_bool_ret(c.symbol("sessionRemoveCookie"), partitionCString, urlCString, nameCString)), nil
1615
+ }
1616
+
1617
+ func (c *Core) SessionClearCookies(partition string) error {
1618
+ partitionCString, freePartition, err := cString(partition, "session partition")
1619
+ if err != nil {
1620
+ return err
1621
+ }
1622
+ defer freePartition()
1623
+ C.eb_call_string(c.symbol("sessionClearCookies"), partitionCString)
1624
+ return c.ensureLastCallSucceeded()
1625
+ }
1626
+
1627
+ func (c *Core) SessionClearStorageData(partition, storageTypesJSON string) error {
1628
+ partitionCString, freePartition, err := cString(partition, "session partition")
1629
+ if err != nil {
1630
+ return err
1631
+ }
1632
+ defer freePartition()
1633
+ storageCString, freeStorage, err := cString(storageTypesJSON, "storage types json")
1634
+ if err != nil {
1635
+ return err
1636
+ }
1637
+ defer freeStorage()
1638
+ C.eb_call_string_string(c.symbol("sessionClearStorageData"), partitionCString, storageCString)
1639
+ return c.ensureLastCallSucceeded()
1640
+ }
1641
+
1642
+ func (c *Core) SetURLOpenHandler(handler func(string)) error {
1643
+ setURLOpenHandler(handler)
1644
+ C.eb_call_set_url_open_handler(c.symbol("setURLOpenHandler"), cbool(handler != nil))
1645
+ return c.ensureLastCallSucceeded()
1646
+ }
1647
+
1648
+ func (c *Core) SetAppReopenHandler(handler func()) error {
1649
+ setAppReopenHandler(handler)
1650
+ C.eb_call_set_app_reopen_handler(c.symbol("setAppReopenHandler"), cbool(handler != nil))
1651
+ return c.ensureLastCallSucceeded()
1652
+ }
1653
+
1654
+ func (c *Core) SetQuitRequestedHandler(handler func()) error {
1655
+ setQuitRequestedHandler(handler)
1656
+ C.eb_call_set_quit_requested_handler(c.symbol("setQuitRequestedHandler"), cbool(handler != nil))
1657
+ return c.ensureLastCallSucceeded()
1658
+ }
1659
+
1660
+ func (c *Core) StopEventLoop() error {
1661
+ C.eb_call_void(c.symbol("stopEventLoop"))
1662
+ return c.ensureLastCallSucceeded()
1663
+ }
1664
+
1665
+ func (c *Core) WaitForShutdownComplete(timeoutMS int) error {
1666
+ C.eb_call_int(c.symbol("waitForShutdownComplete"), C.int(timeoutMS))
1667
+ return c.ensureLastCallSucceeded()
1668
+ }
1669
+
1670
+ func (c *Core) ForceExit(code int) {
1671
+ C.eb_call_int(c.symbol("forceExit"), C.int(code))
1672
+ os.Exit(code)
1673
+ }
1674
+
1675
+ func (c *Core) WgpuCreateSurfaceForView(instance, viewPtr unsafe.Pointer) (unsafe.Pointer, error) {
1676
+ ptr := C.eb_call_ptr_ptr_ptr_ret(c.symbol("wgpuCreateSurfaceForView"), instance, viewPtr)
1677
+ if ptr == nil {
1678
+ return nil, errors.New(c.LastError())
1679
+ }
1680
+ return ptr, nil
1681
+ }
1682
+
1683
+ func (c *Core) WgpuCreateAdapterDeviceMainThread(instance, surface unsafe.Pointer) (WgpuAdapterDevice, error) {
1684
+ buffer := C.calloc(2, C.size_t(unsafe.Sizeof(uintptr(0))))
1685
+ if buffer == nil {
1686
+ return WgpuAdapterDevice{}, errors.New("failed to allocate WGPU adapter/device buffer")
1687
+ }
1688
+ defer C.free(buffer)
1689
+ C.eb_call_ptr_ptr_ptr(c.symbol("wgpuCreateAdapterDeviceMainThread"), instance, surface, buffer)
1690
+ if err := c.ensureLastCallSucceeded(); err != nil {
1691
+ return WgpuAdapterDevice{}, err
1692
+ }
1693
+ values := (*[2]unsafe.Pointer)(buffer)
1694
+ adapterDevice := WgpuAdapterDevice{Adapter: values[0], Device: values[1]}
1695
+ if adapterDevice.Adapter == nil || adapterDevice.Device == nil {
1696
+ return WgpuAdapterDevice{}, errors.New("missing WGPU adapter or device")
1697
+ }
1698
+ return adapterDevice, nil
1699
+ }
1700
+
1701
+ func (c *Core) WgpuSurfaceConfigureMainThread(surface, config unsafe.Pointer) error {
1702
+ C.eb_call_ptr_ptr(c.symbol("wgpuSurfaceConfigureMainThread"), surface, config)
1703
+ return c.ensureLastCallSucceeded()
1704
+ }
1705
+
1706
+ func (c *Core) WgpuSurfaceGetCurrentTextureMainThread(surface, surfaceTexture unsafe.Pointer) error {
1707
+ C.eb_call_ptr_ptr(c.symbol("wgpuSurfaceGetCurrentTextureMainThread"), surface, surfaceTexture)
1708
+ return c.ensureLastCallSucceeded()
1709
+ }
1710
+
1711
+ func (c *Core) WgpuSurfacePresentMainThread(surface unsafe.Pointer) (int, error) {
1712
+ status := C.eb_call_ptr_int_ret(c.symbol("wgpuSurfacePresentMainThread"), surface)
1713
+ if err := c.ensureLastCallSucceeded(); err != nil {
1714
+ return 0, err
1715
+ }
1716
+ return int(status), nil
1717
+ }
1718
+
1719
+ func (c *Core) RunMainThread(appInfo AppInfo) error {
1720
+ identifier, freeIdentifier, err := cString(appInfo.Identifier, "app identifier")
1721
+ if err != nil {
1722
+ return err
1723
+ }
1724
+ defer freeIdentifier()
1725
+ name, freeName, err := cString(appInfo.Name, "app name")
1726
+ if err != nil {
1727
+ return err
1728
+ }
1729
+ defer freeName()
1730
+ channel, freeChannel, err := cString(appInfo.Channel, "app channel")
1731
+ if err != nil {
1732
+ return err
1733
+ }
1734
+ defer freeChannel()
1735
+ status := C.eb_call_run_main_thread(c.symbol("electrobun_core_run_main_thread"), identifier, name, channel, 0)
1736
+ if status != 0 {
1737
+ return errors.New(c.LastError())
1738
+ }
1739
+ return nil
1740
+ }
1741
+
1742
+ func (c *Core) LastError() string {
1743
+ ptr := C.eb_call_last_error(c.symbol("electrobun_core_last_error"))
1744
+ return cConstString(ptr)
1745
+ }
1746
+
1747
+ func (c *Core) ensureLastCallSucceeded() error {
1748
+ message := c.LastError()
1749
+ if message == "" {
1750
+ return nil
1751
+ }
1752
+ return errors.New(message)
1753
+ }
1754
+
1755
+ func ResolveBundlePaths() (BundlePaths, error) {
1756
+ exePath, err := os.Executable()
1757
+ if err != nil {
1758
+ return BundlePaths{}, fmt.Errorf("failed to resolve executable path: %w", err)
1759
+ }
1760
+ exeDir := filepath.Dir(exePath)
1761
+ return BundlePaths{
1762
+ ExeDir: exeDir,
1763
+ ResourcesDir: filepath.Clean(filepath.Join(exeDir, "..", "Resources")),
1764
+ }, nil
1765
+ }
1766
+
1767
+ func ResolveAppInfoFromBundle(bundlePaths BundlePaths) (AppInfo, error) {
1768
+ versionJSON, err := os.ReadFile(filepath.Join(bundlePaths.ResourcesDir, "version.json"))
1769
+ if err != nil {
1770
+ return AppInfo{}, err
1771
+ }
1772
+ return AppInfo{
1773
+ Identifier: JsonStringField(string(versionJSON), "identifier", "sh.blackboard.electrobun"),
1774
+ Name: JsonStringField(string(versionJSON), "name", "Electrobun"),
1775
+ Channel: JsonStringField(string(versionJSON), "channel", "dev"),
1776
+ }, nil
1777
+ }
1778
+
1779
+ func ResolvePaths(appInfo AppInfo) (Paths, error) {
1780
+ home, err := os.UserHomeDir()
1781
+ if err != nil {
1782
+ return Paths{}, err
1783
+ }
1784
+ appData := appDataDir(home)
1785
+ config := configDir(home)
1786
+ cache := cacheDir(home)
1787
+ logs := logsDir(home)
1788
+ scoped := appInfo.Identifier
1789
+ if scoped == "" {
1790
+ scoped = appInfo.Name
1791
+ }
1792
+ return Paths{
1793
+ Home: home,
1794
+ AppData: appData,
1795
+ Config: config,
1796
+ Cache: cache,
1797
+ Temp: tempDir(),
1798
+ Logs: logs,
1799
+ Documents: filepath.Join(home, "Documents"),
1800
+ Downloads: filepath.Join(home, "Downloads"),
1801
+ Desktop: filepath.Join(home, "Desktop"),
1802
+ Pictures: filepath.Join(home, "Pictures"),
1803
+ Music: filepath.Join(home, "Music"),
1804
+ Videos: filepath.Join(home, "Videos"),
1805
+ UserData: filepath.Join(appData, scoped),
1806
+ UserCache: filepath.Join(cache, scoped),
1807
+ UserLogs: filepath.Join(logs, scoped),
1808
+ }, nil
1809
+ }
1810
+
1811
+ func AllowAllNavigation(_ uint32, _ string) uint32 {
1812
+ return 1
1813
+ }
1814
+
1815
+ func NoopWebviewEvent(_ uint32, _, _ string) {}
1816
+
1817
+ func NoopWebviewPostMessage(_ uint32, _ string) {}
1818
+
1819
+ func JsonStringLiteral(value string) string {
1820
+ bytes, _ := json.Marshal(value)
1821
+ return string(bytes)
1822
+ }
1823
+
1824
+ func JsonStringField(source, key, fallback string) string {
1825
+ var obj map[string]json.RawMessage
1826
+ if json.Unmarshal([]byte(source), &obj) != nil {
1827
+ return fallback
1828
+ }
1829
+ var value string
1830
+ if raw, ok := obj[key]; ok && json.Unmarshal(raw, &value) == nil {
1831
+ return value
1832
+ }
1833
+ return fallback
1834
+ }
1835
+
1836
+ func JsonOptionalStringField(source, key string) (string, bool) {
1837
+ var obj map[string]json.RawMessage
1838
+ if json.Unmarshal([]byte(source), &obj) != nil {
1839
+ return "", false
1840
+ }
1841
+ var value string
1842
+ if raw, ok := obj[key]; ok && json.Unmarshal(raw, &value) == nil {
1843
+ return value, true
1844
+ }
1845
+ return "", false
1846
+ }
1847
+
1848
+ func JsonNumberField(source, key string) (float64, bool) {
1849
+ var obj map[string]json.RawMessage
1850
+ if json.Unmarshal([]byte(source), &obj) != nil {
1851
+ return 0, false
1852
+ }
1853
+ var value float64
1854
+ if raw, ok := obj[key]; ok && json.Unmarshal(raw, &value) == nil {
1855
+ return value, true
1856
+ }
1857
+ return 0, false
1858
+ }
1859
+
1860
+ func JsonBoolField(source, key string) (bool, bool) {
1861
+ var obj map[string]json.RawMessage
1862
+ if json.Unmarshal([]byte(source), &obj) != nil {
1863
+ return false, false
1864
+ }
1865
+ var value bool
1866
+ if raw, ok := obj[key]; ok && json.Unmarshal(raw, &value) == nil {
1867
+ return value, true
1868
+ }
1869
+ return false, false
1870
+ }
1871
+
1872
+ func JsonObjectField(source, key string) (string, bool) {
1873
+ var obj map[string]json.RawMessage
1874
+ if json.Unmarshal([]byte(source), &obj) != nil {
1875
+ return "", false
1876
+ }
1877
+ if raw, ok := obj[key]; ok && len(raw) > 0 && raw[0] == '{' {
1878
+ return string(raw), true
1879
+ }
1880
+ return "", false
1881
+ }
1882
+
1883
+ func ParseRectJSON(source string) Rect {
1884
+ var rect Rect
1885
+ _ = json.Unmarshal([]byte(source), &rect)
1886
+ return rect
1887
+ }
1888
+
1889
+ func ParseDisplayJSON(source string) Display {
1890
+ var display Display
1891
+ _ = json.Unmarshal([]byte(source), &display)
1892
+ return display
1893
+ }
1894
+
1895
+ func cString(value, label string) (*C.char, func(), error) {
1896
+ if strings.ContainsRune(value, '\x00') {
1897
+ return nil, nil, fmt.Errorf("%s contains an interior null byte", label)
1898
+ }
1899
+ ptr := C.CString(value)
1900
+ return ptr, func() { C.free(unsafe.Pointer(ptr)) }, nil
1901
+ }
1902
+
1903
+ func cConstString(ptr *C.char) string {
1904
+ if ptr == nil {
1905
+ return ""
1906
+ }
1907
+ return C.GoString(ptr)
1908
+ }
1909
+
1910
+ func cbool(value bool) C.bool {
1911
+ if value {
1912
+ return C.bool(true)
1913
+ }
1914
+ return C.bool(false)
1915
+ }
1916
+
1917
+ func boolInt(value bool) C.int {
1918
+ if value {
1919
+ return 1
1920
+ }
1921
+ return 0
1922
+ }
1923
+
1924
+ func coreLibraryName() string {
1925
+ switch runtime.GOOS {
1926
+ case "windows":
1927
+ return "ElectrobunCore.dll"
1928
+ case "darwin":
1929
+ return "libElectrobunCore.dylib"
1930
+ default:
1931
+ return "libElectrobunCore.so"
1932
+ }
1933
+ }
1934
+
1935
+ func wgpuLibraryName() string {
1936
+ switch runtime.GOOS {
1937
+ case "windows":
1938
+ return "webgpu_dawn.dll"
1939
+ case "darwin":
1940
+ return "libwebgpu_dawn.dylib"
1941
+ default:
1942
+ return "libwebgpu_dawn.so"
1943
+ }
1944
+ }
1945
+
1946
+ func tempDir() string {
1947
+ if runtime.GOOS == "windows" {
1948
+ if value := os.Getenv("TEMP"); value != "" {
1949
+ return value
1950
+ }
1951
+ if value := os.Getenv("TMP"); value != "" {
1952
+ return value
1953
+ }
1954
+ return `C:\Temp`
1955
+ }
1956
+ if value := os.Getenv("TMPDIR"); value != "" {
1957
+ return value
1958
+ }
1959
+ if value := os.Getenv("TMP"); value != "" {
1960
+ return value
1961
+ }
1962
+ return "/tmp"
1963
+ }
1964
+
1965
+ func appDataDir(home string) string {
1966
+ switch runtime.GOOS {
1967
+ case "darwin":
1968
+ return filepath.Join(home, "Library", "Application Support")
1969
+ case "windows":
1970
+ if value := os.Getenv("APPDATA"); value != "" {
1971
+ return value
1972
+ }
1973
+ return filepath.Join(home, "AppData", "Roaming")
1974
+ default:
1975
+ if value := os.Getenv("XDG_DATA_HOME"); value != "" {
1976
+ return value
1977
+ }
1978
+ return filepath.Join(home, ".local", "share")
1979
+ }
1980
+ }
1981
+
1982
+ func configDir(home string) string {
1983
+ switch runtime.GOOS {
1984
+ case "darwin":
1985
+ return filepath.Join(home, "Library", "Application Support")
1986
+ case "windows":
1987
+ if value := os.Getenv("APPDATA"); value != "" {
1988
+ return value
1989
+ }
1990
+ return filepath.Join(home, "AppData", "Roaming")
1991
+ default:
1992
+ if value := os.Getenv("XDG_CONFIG_HOME"); value != "" {
1993
+ return value
1994
+ }
1995
+ return filepath.Join(home, ".config")
1996
+ }
1997
+ }
1998
+
1999
+ func cacheDir(home string) string {
2000
+ switch runtime.GOOS {
2001
+ case "darwin":
2002
+ return filepath.Join(home, "Library", "Caches")
2003
+ case "windows":
2004
+ if value := os.Getenv("LOCALAPPDATA"); value != "" {
2005
+ return value
2006
+ }
2007
+ return filepath.Join(home, "AppData", "Local")
2008
+ default:
2009
+ if value := os.Getenv("XDG_CACHE_HOME"); value != "" {
2010
+ return value
2011
+ }
2012
+ return filepath.Join(home, ".cache")
2013
+ }
2014
+ }
2015
+
2016
+ func logsDir(home string) string {
2017
+ if runtime.GOOS == "darwin" {
2018
+ return filepath.Join(home, "Library", "Logs")
2019
+ }
2020
+ return cacheDir(home)
2021
+ }