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.
- package/README.md +37 -14
- package/dash.config.ts +28 -0
- package/dist/api/browser/global.d.ts +6 -0
- package/dist/api/browser/index.ts +162 -44
- package/dist/api/{bun → config}/ElectrobunConfig.ts +109 -40
- package/dist/api/config/validate.test.ts +31 -0
- package/dist/api/config/validate.ts +19 -0
- package/dist/api/preload/.generated/compiled.ts +8 -0
- package/dist/api/{bun/preload → preload}/build.ts +6 -6
- package/dist/api/{bun/preload → preload}/encryption.ts +11 -5
- package/dist/api/{bun/preload → preload}/globals.d.ts +8 -0
- package/dist/api/{bun/preload → preload}/index.ts +18 -8
- package/dist/api/{bun/preload → preload}/webviewTag.ts +32 -3
- package/dist/api/{bun/preload → preload}/wgpuTag.ts +33 -2
- package/dist/api/{bun → sdks/bun}/__tests__/ffi-contract.test.ts +6 -9
- package/dist/api/{bun → sdks/bun}/core/BrowserView.ts +96 -55
- package/dist/api/{bun → sdks/bun}/core/BrowserWindow.ts +20 -30
- package/dist/api/{bun → sdks/bun}/core/BuildConfig.ts +32 -5
- package/dist/api/{bun → sdks/bun}/core/GpuWindow.ts +20 -7
- package/dist/api/sdks/bun/core/Socket.ts +22 -0
- package/dist/api/{bun → sdks/bun}/core/Tray.ts +33 -32
- package/dist/api/{bun → sdks/bun}/core/Updater.ts +10 -10
- package/dist/api/{bun → sdks/bun}/core/Utils.ts +3 -5
- package/dist/api/{bun → sdks/bun}/core/WGPUView.ts +43 -13
- package/dist/api/{bun → sdks/bun}/index.ts +39 -10
- package/dist/api/{bun → sdks/bun}/proc/native.ts +942 -746
- package/dist/api/{bun → sdks/bun}/webGPU.ts +1 -1
- package/dist/api/{bun → sdks/bun}/webgpuAdapter.ts +40 -33
- package/dist/api/shared/build-dependencies.test.ts +48 -0
- package/dist/api/shared/build-dependencies.ts +46 -0
- package/dist/api/shared/go-version.ts +3 -0
- package/dist/api/shared/odin-version.ts +6 -0
- package/dist/api/shared/rust-version.ts +3 -0
- package/dist/go-sdk/callbacks.go +260 -0
- package/dist/go-sdk/electrobun.go +2021 -0
- package/dist/main.js +35 -28
- package/dist/odin-sdk/electrobun/electrobun.odin +2337 -0
- package/dist/preload-full.js +948 -0
- package/dist/preload-sandboxed.js +111 -0
- package/dist/rust-sdk/electrobun.rs +2396 -0
- package/dist/zig-sdk/electrobun.zig +2005 -0
- package/package.json +5 -29
- package/src/cli/index.ts +868 -654
- package/bin/electrobun.cjs +0 -169
- package/dist/api/bun/core/Socket.ts +0 -205
- package/dist/api/bun/core/windowIds.ts +0 -5
- package/dist/api/bun/preload/.generated/compiled.ts +0 -8
- package/dist/api/shared/bun-version.ts +0 -3
- /package/dist/api/{bun/preload → preload}/dragRegions.ts +0 -0
- /package/dist/api/{bun/preload → preload}/events.ts +0 -0
- /package/dist/api/{bun/preload → preload}/index-sandboxed.ts +0 -0
- /package/dist/api/{bun/preload → preload}/internalRpc.ts +0 -0
- /package/dist/api/{bun/preload → preload}/overlaySync.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/ApplicationMenu.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/ContextMenu.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/Paths.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/menuRoles.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/ApplicationEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/event.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/eventEmitter.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/trayEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/webviewEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/windowEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/proc/linux.md +0 -0
|
@@ -0,0 +1,2396 @@
|
|
|
1
|
+
use std::ffi::{CStr, CString};
|
|
2
|
+
use std::fs;
|
|
3
|
+
use std::os::raw::{c_char, c_int, c_void};
|
|
4
|
+
use std::path::PathBuf;
|
|
5
|
+
|
|
6
|
+
#[cfg(unix)]
|
|
7
|
+
mod dynlib {
|
|
8
|
+
use super::*;
|
|
9
|
+
|
|
10
|
+
const RTLD_NOW: c_int = 2;
|
|
11
|
+
|
|
12
|
+
#[cfg(target_os = "linux")]
|
|
13
|
+
#[link(name = "dl")]
|
|
14
|
+
unsafe extern "C" {
|
|
15
|
+
fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
|
16
|
+
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
|
17
|
+
fn dlclose(handle: *mut c_void) -> c_int;
|
|
18
|
+
fn dlerror() -> *const c_char;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[cfg(not(target_os = "linux"))]
|
|
22
|
+
unsafe extern "C" {
|
|
23
|
+
fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
|
24
|
+
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
|
25
|
+
fn dlclose(handle: *mut c_void) -> c_int;
|
|
26
|
+
fn dlerror() -> *const c_char;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub struct DynamicLibrary {
|
|
30
|
+
handle: *mut c_void,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
unsafe impl Send for DynamicLibrary {}
|
|
34
|
+
unsafe impl Sync for DynamicLibrary {}
|
|
35
|
+
|
|
36
|
+
impl DynamicLibrary {
|
|
37
|
+
pub fn open(path: &PathBuf) -> Result<Self, String> {
|
|
38
|
+
let path = CString::new(path.to_string_lossy().as_bytes())
|
|
39
|
+
.map_err(|_| format!("invalid dynamic library path: {}", path.display()))?;
|
|
40
|
+
let handle = unsafe { dlopen(path.as_ptr(), RTLD_NOW) };
|
|
41
|
+
if handle.is_null() {
|
|
42
|
+
return Err(last_dl_error());
|
|
43
|
+
}
|
|
44
|
+
Ok(Self { handle })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn symbol<T: Copy>(&self, name: &str) -> Result<T, String> {
|
|
48
|
+
let name_c = CString::new(name)
|
|
49
|
+
.map_err(|_| format!("invalid dynamic library symbol: {name}"))?;
|
|
50
|
+
let ptr = unsafe { dlsym(self.handle, name_c.as_ptr()) };
|
|
51
|
+
if ptr.is_null() {
|
|
52
|
+
return Err(format!("missing core symbol {name}: {}", last_dl_error()));
|
|
53
|
+
}
|
|
54
|
+
Ok(unsafe { std::mem::transmute_copy(&ptr) })
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
impl Drop for DynamicLibrary {
|
|
59
|
+
fn drop(&mut self) {
|
|
60
|
+
if !self.handle.is_null() {
|
|
61
|
+
unsafe {
|
|
62
|
+
dlclose(self.handle);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn last_dl_error() -> String {
|
|
69
|
+
let ptr = unsafe { dlerror() };
|
|
70
|
+
if ptr.is_null() {
|
|
71
|
+
return "unknown dynamic loader error".to_string();
|
|
72
|
+
}
|
|
73
|
+
unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[cfg(windows)]
|
|
78
|
+
mod dynlib {
|
|
79
|
+
use super::*;
|
|
80
|
+
use std::os::windows::ffi::OsStrExt;
|
|
81
|
+
|
|
82
|
+
#[link(name = "kernel32")]
|
|
83
|
+
unsafe extern "system" {
|
|
84
|
+
fn LoadLibraryW(lp_lib_file_name: *const u16) -> *mut c_void;
|
|
85
|
+
fn GetProcAddress(h_module: *mut c_void, lp_proc_name: *const c_char) -> *mut c_void;
|
|
86
|
+
fn FreeLibrary(h_lib_module: *mut c_void) -> i32;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub struct DynamicLibrary {
|
|
90
|
+
handle: *mut c_void,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
unsafe impl Send for DynamicLibrary {}
|
|
94
|
+
unsafe impl Sync for DynamicLibrary {}
|
|
95
|
+
|
|
96
|
+
impl DynamicLibrary {
|
|
97
|
+
pub fn open(path: &PathBuf) -> Result<Self, String> {
|
|
98
|
+
let mut path_w: Vec<u16> = path.as_os_str().encode_wide().collect();
|
|
99
|
+
path_w.push(0);
|
|
100
|
+
let handle = unsafe { LoadLibraryW(path_w.as_ptr()) };
|
|
101
|
+
if handle.is_null() {
|
|
102
|
+
return Err(format!(
|
|
103
|
+
"failed to load dynamic library: {}",
|
|
104
|
+
path.display()
|
|
105
|
+
));
|
|
106
|
+
}
|
|
107
|
+
Ok(Self { handle })
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
pub fn symbol<T: Copy>(&self, name: &str) -> Result<T, String> {
|
|
111
|
+
let name_c = CString::new(name)
|
|
112
|
+
.map_err(|_| format!("invalid dynamic library symbol: {name}"))?;
|
|
113
|
+
let ptr = unsafe { GetProcAddress(self.handle, name_c.as_ptr()) };
|
|
114
|
+
if ptr.is_null() {
|
|
115
|
+
return Err(format!("missing core symbol {name}"));
|
|
116
|
+
}
|
|
117
|
+
Ok(unsafe { std::mem::transmute_copy(&ptr) })
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
impl Drop for DynamicLibrary {
|
|
122
|
+
fn drop(&mut self) {
|
|
123
|
+
if !self.handle.is_null() {
|
|
124
|
+
unsafe {
|
|
125
|
+
FreeLibrary(self.handle);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
pub type WindowCloseHandler = extern "C" fn(u32);
|
|
133
|
+
pub type WindowMoveHandler = extern "C" fn(u32, f64, f64);
|
|
134
|
+
pub type WindowResizeHandler = extern "C" fn(u32, f64, f64, f64, f64);
|
|
135
|
+
pub type WindowFocusHandler = extern "C" fn(u32);
|
|
136
|
+
pub type WindowBlurHandler = extern "C" fn(u32);
|
|
137
|
+
pub type WindowKeyHandler = extern "C" fn(u32, u32, u32, u32, u32);
|
|
138
|
+
pub type DecideNavigationHandler = extern "C" fn(u32, *const c_char) -> u32;
|
|
139
|
+
pub type WebviewEventHandler = extern "C" fn(u32, *const c_char, *const c_char);
|
|
140
|
+
pub type WebviewPostMessageHandler = extern "C" fn(u32, *const c_char);
|
|
141
|
+
pub type StatusItemHandler = extern "C" fn(u32, *const c_char);
|
|
142
|
+
pub type GlobalShortcutHandler = extern "C" fn(*const c_char);
|
|
143
|
+
pub type QuitRequestedHandler = extern "C" fn();
|
|
144
|
+
pub type URLOpenHandler = extern "C" fn(*const c_char);
|
|
145
|
+
pub type AppReopenHandler = extern "C" fn();
|
|
146
|
+
|
|
147
|
+
#[derive(Clone, Copy)]
|
|
148
|
+
pub enum Renderer {
|
|
149
|
+
Native,
|
|
150
|
+
Cef,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
impl Renderer {
|
|
154
|
+
fn as_str(self) -> &'static str {
|
|
155
|
+
match self {
|
|
156
|
+
Renderer::Native => "native",
|
|
157
|
+
Renderer::Cef => "cef",
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#[derive(Clone)]
|
|
163
|
+
pub struct AppInfo {
|
|
164
|
+
pub identifier: String,
|
|
165
|
+
pub name: String,
|
|
166
|
+
pub channel: String,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#[derive(Clone, Copy)]
|
|
170
|
+
pub struct Rect {
|
|
171
|
+
pub x: f64,
|
|
172
|
+
pub y: f64,
|
|
173
|
+
pub width: f64,
|
|
174
|
+
pub height: f64,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
impl Rect {
|
|
178
|
+
pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
|
|
179
|
+
Self {
|
|
180
|
+
x,
|
|
181
|
+
y,
|
|
182
|
+
width,
|
|
183
|
+
height,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
impl Default for Rect {
|
|
189
|
+
fn default() -> Self {
|
|
190
|
+
Self {
|
|
191
|
+
x: 0.0,
|
|
192
|
+
y: 0.0,
|
|
193
|
+
width: 800.0,
|
|
194
|
+
height: 600.0,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#[derive(Default)]
|
|
200
|
+
pub struct WindowStyle {
|
|
201
|
+
pub borderless: bool,
|
|
202
|
+
pub titled: bool,
|
|
203
|
+
pub closable: bool,
|
|
204
|
+
pub miniaturizable: bool,
|
|
205
|
+
pub resizable: bool,
|
|
206
|
+
pub unified_title_and_toolbar: bool,
|
|
207
|
+
pub full_screen: bool,
|
|
208
|
+
pub full_size_content_view: bool,
|
|
209
|
+
pub utility_window: bool,
|
|
210
|
+
pub doc_modal_window: bool,
|
|
211
|
+
pub nonactivating_panel: bool,
|
|
212
|
+
pub hud_window: bool,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
impl WindowStyle {
|
|
216
|
+
pub fn standard() -> Self {
|
|
217
|
+
Self {
|
|
218
|
+
borderless: false,
|
|
219
|
+
titled: true,
|
|
220
|
+
closable: true,
|
|
221
|
+
miniaturizable: true,
|
|
222
|
+
resizable: true,
|
|
223
|
+
unified_title_and_toolbar: false,
|
|
224
|
+
full_screen: false,
|
|
225
|
+
full_size_content_view: false,
|
|
226
|
+
utility_window: false,
|
|
227
|
+
doc_modal_window: false,
|
|
228
|
+
nonactivating_panel: false,
|
|
229
|
+
hud_window: false,
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#[derive(Default)]
|
|
235
|
+
pub struct WindowCallbacks {
|
|
236
|
+
pub close: Option<WindowCloseHandler>,
|
|
237
|
+
pub move_handler: Option<WindowMoveHandler>,
|
|
238
|
+
pub resize: Option<WindowResizeHandler>,
|
|
239
|
+
pub focus: Option<WindowFocusHandler>,
|
|
240
|
+
pub blur: Option<WindowBlurHandler>,
|
|
241
|
+
pub key: Option<WindowKeyHandler>,
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#[derive(Default)]
|
|
245
|
+
pub struct TrafficLightOffset {
|
|
246
|
+
pub x: f64,
|
|
247
|
+
pub y: f64,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pub struct WindowOptions<'a> {
|
|
251
|
+
pub title: &'a str,
|
|
252
|
+
pub frame: Rect,
|
|
253
|
+
pub style: WindowStyle,
|
|
254
|
+
pub title_bar_style: &'a str,
|
|
255
|
+
pub transparent: bool,
|
|
256
|
+
pub hidden: bool,
|
|
257
|
+
pub activate: bool,
|
|
258
|
+
pub traffic_light_offset: TrafficLightOffset,
|
|
259
|
+
pub callbacks: WindowCallbacks,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
impl<'a> WindowOptions<'a> {
|
|
263
|
+
pub fn new(title: &'a str, frame: Rect) -> Self {
|
|
264
|
+
Self {
|
|
265
|
+
title,
|
|
266
|
+
frame,
|
|
267
|
+
style: WindowStyle::standard(),
|
|
268
|
+
title_bar_style: "default",
|
|
269
|
+
transparent: false,
|
|
270
|
+
hidden: false,
|
|
271
|
+
activate: true,
|
|
272
|
+
traffic_light_offset: TrafficLightOffset::default(),
|
|
273
|
+
callbacks: WindowCallbacks::default(),
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#[derive(Default)]
|
|
279
|
+
pub struct WebviewCallbacks {
|
|
280
|
+
pub decide_navigation: Option<DecideNavigationHandler>,
|
|
281
|
+
pub event: Option<WebviewEventHandler>,
|
|
282
|
+
pub event_bridge: Option<WebviewPostMessageHandler>,
|
|
283
|
+
pub host_bridge: Option<WebviewPostMessageHandler>,
|
|
284
|
+
pub bun_bridge: Option<WebviewPostMessageHandler>,
|
|
285
|
+
pub internal_bridge: Option<WebviewPostMessageHandler>,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
pub struct WebviewOptions<'a> {
|
|
289
|
+
pub window_id: u32,
|
|
290
|
+
pub host_webview_id: u32,
|
|
291
|
+
pub renderer: Renderer,
|
|
292
|
+
pub url: &'a str,
|
|
293
|
+
pub frame: Rect,
|
|
294
|
+
pub auto_resize: bool,
|
|
295
|
+
pub partition: &'a str,
|
|
296
|
+
pub callbacks: WebviewCallbacks,
|
|
297
|
+
pub secret_key: &'a str,
|
|
298
|
+
pub preload: &'a str,
|
|
299
|
+
pub views_root: &'a str,
|
|
300
|
+
pub sandbox: bool,
|
|
301
|
+
pub start_transparent: bool,
|
|
302
|
+
pub start_passthrough: bool,
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
impl<'a> WebviewOptions<'a> {
|
|
306
|
+
pub fn new(window_id: u32, url: &'a str, frame: Rect) -> Self {
|
|
307
|
+
Self {
|
|
308
|
+
window_id,
|
|
309
|
+
host_webview_id: 0,
|
|
310
|
+
renderer: Renderer::Native,
|
|
311
|
+
url,
|
|
312
|
+
frame,
|
|
313
|
+
auto_resize: true,
|
|
314
|
+
partition: "persist:default",
|
|
315
|
+
callbacks: WebviewCallbacks::default(),
|
|
316
|
+
secret_key: "",
|
|
317
|
+
preload: "",
|
|
318
|
+
views_root: "",
|
|
319
|
+
sandbox: true,
|
|
320
|
+
start_transparent: false,
|
|
321
|
+
start_passthrough: false,
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
pub struct WGPUViewOptions {
|
|
327
|
+
pub window_id: u32,
|
|
328
|
+
pub frame: Rect,
|
|
329
|
+
pub auto_resize: bool,
|
|
330
|
+
pub start_transparent: bool,
|
|
331
|
+
pub start_passthrough: bool,
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
impl WGPUViewOptions {
|
|
335
|
+
pub fn new(window_id: u32, frame: Rect) -> Self {
|
|
336
|
+
Self {
|
|
337
|
+
window_id,
|
|
338
|
+
frame,
|
|
339
|
+
auto_resize: true,
|
|
340
|
+
start_transparent: false,
|
|
341
|
+
start_passthrough: false,
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
pub struct TrayOptions<'a> {
|
|
347
|
+
pub title: &'a str,
|
|
348
|
+
pub image: &'a str,
|
|
349
|
+
pub is_template: bool,
|
|
350
|
+
pub width: u32,
|
|
351
|
+
pub height: u32,
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
pub struct NotificationOptions<'a> {
|
|
355
|
+
pub title: &'a str,
|
|
356
|
+
pub body: &'a str,
|
|
357
|
+
pub subtitle: &'a str,
|
|
358
|
+
pub silent: bool,
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
pub struct MessageBoxOptions<'a> {
|
|
362
|
+
pub box_type: &'a str,
|
|
363
|
+
pub title: &'a str,
|
|
364
|
+
pub message: &'a str,
|
|
365
|
+
pub detail: &'a str,
|
|
366
|
+
pub buttons: &'a [&'a str],
|
|
367
|
+
pub default_id: c_int,
|
|
368
|
+
pub cancel_id: c_int,
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
pub struct OpenFileDialogOptions<'a> {
|
|
372
|
+
pub starting_folder: &'a str,
|
|
373
|
+
pub allowed_file_types: &'a str,
|
|
374
|
+
pub can_choose_files: bool,
|
|
375
|
+
pub can_choose_directory: bool,
|
|
376
|
+
pub allows_multiple_selection: bool,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
#[derive(Clone, Copy, Default)]
|
|
380
|
+
pub struct Point {
|
|
381
|
+
pub x: f64,
|
|
382
|
+
pub y: f64,
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#[derive(Clone, Copy, Default)]
|
|
386
|
+
pub struct Display {
|
|
387
|
+
pub id: i64,
|
|
388
|
+
pub bounds: Rect,
|
|
389
|
+
pub work_area: Rect,
|
|
390
|
+
pub scale_factor: f64,
|
|
391
|
+
pub is_primary: bool,
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#[derive(Clone)]
|
|
395
|
+
pub struct Paths {
|
|
396
|
+
pub home: String,
|
|
397
|
+
pub app_data: String,
|
|
398
|
+
pub config: String,
|
|
399
|
+
pub cache: String,
|
|
400
|
+
pub temp: String,
|
|
401
|
+
pub logs: String,
|
|
402
|
+
pub documents: String,
|
|
403
|
+
pub downloads: String,
|
|
404
|
+
pub desktop: String,
|
|
405
|
+
pub pictures: String,
|
|
406
|
+
pub music: String,
|
|
407
|
+
pub videos: String,
|
|
408
|
+
pub user_data: String,
|
|
409
|
+
pub user_cache: String,
|
|
410
|
+
pub user_logs: String,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
impl Paths {
|
|
414
|
+
pub fn resolve(app_info: &AppInfo) -> Result<Self, String> {
|
|
415
|
+
let home = home_dir()?;
|
|
416
|
+
let app_data = app_data_dir(&home);
|
|
417
|
+
let config = config_dir(&home);
|
|
418
|
+
let cache = cache_dir(&home);
|
|
419
|
+
let temp = temp_dir();
|
|
420
|
+
let logs = logs_dir(&home);
|
|
421
|
+
let documents = user_dir(&home, "Documents");
|
|
422
|
+
let downloads = user_dir(&home, "Downloads");
|
|
423
|
+
let desktop = user_dir(&home, "Desktop");
|
|
424
|
+
let pictures = user_dir(&home, "Pictures");
|
|
425
|
+
let music = user_dir(&home, "Music");
|
|
426
|
+
let videos = user_dir(&home, "Videos");
|
|
427
|
+
let scoped = app_scoped_name(app_info);
|
|
428
|
+
|
|
429
|
+
Ok(Self {
|
|
430
|
+
home,
|
|
431
|
+
user_data: join_path(&app_data, &scoped),
|
|
432
|
+
user_cache: join_path(&cache, &scoped),
|
|
433
|
+
user_logs: join_path(&logs, &scoped),
|
|
434
|
+
app_data,
|
|
435
|
+
config,
|
|
436
|
+
cache,
|
|
437
|
+
temp,
|
|
438
|
+
logs,
|
|
439
|
+
documents,
|
|
440
|
+
downloads,
|
|
441
|
+
desktop,
|
|
442
|
+
pictures,
|
|
443
|
+
music,
|
|
444
|
+
videos,
|
|
445
|
+
})
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
pub struct BundlePaths {
|
|
450
|
+
pub exe_dir: PathBuf,
|
|
451
|
+
pub resources_dir: PathBuf,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
pub struct WgpuAdapterDevice {
|
|
455
|
+
pub adapter: *mut c_void,
|
|
456
|
+
pub device: *mut c_void,
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
pub struct WgpuNative {
|
|
460
|
+
_lib: dynlib::DynamicLibrary,
|
|
461
|
+
create_instance: unsafe extern "C" fn(*const c_void) -> *mut c_void,
|
|
462
|
+
device_get_queue: unsafe extern "C" fn(*mut c_void) -> *mut c_void,
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
unsafe impl Send for WgpuNative {}
|
|
466
|
+
unsafe impl Sync for WgpuNative {}
|
|
467
|
+
|
|
468
|
+
impl WgpuNative {
|
|
469
|
+
pub fn load() -> Result<Self, String> {
|
|
470
|
+
let bundle_paths = resolve_bundle_paths()?;
|
|
471
|
+
let lib_path = bundle_paths.exe_dir.join(wgpu_library_name());
|
|
472
|
+
let lib = dynlib::DynamicLibrary::open(&lib_path)?;
|
|
473
|
+
|
|
474
|
+
Ok(Self {
|
|
475
|
+
create_instance: lib.symbol("wgpuCreateInstance")?,
|
|
476
|
+
device_get_queue: lib.symbol("wgpuDeviceGetQueue")?,
|
|
477
|
+
_lib: lib,
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
pub fn symbol<T: Copy>(&self, name: &str) -> Result<T, String> {
|
|
482
|
+
self._lib.symbol(name)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
pub fn create_instance(&self) -> Result<*mut c_void, String> {
|
|
486
|
+
let instance = unsafe { (self.create_instance)(std::ptr::null()) };
|
|
487
|
+
if instance.is_null() {
|
|
488
|
+
Err("failed to create WGPU instance".to_string())
|
|
489
|
+
} else {
|
|
490
|
+
Ok(instance)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
pub fn device_get_queue(&self, device: *mut c_void) -> Result<*mut c_void, String> {
|
|
495
|
+
let queue = unsafe { (self.device_get_queue)(device) };
|
|
496
|
+
if queue.is_null() {
|
|
497
|
+
Err("failed to get WGPU queue".to_string())
|
|
498
|
+
} else {
|
|
499
|
+
Ok(queue)
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
#[derive(Clone, Copy)]
|
|
505
|
+
pub struct WgpuContext {
|
|
506
|
+
pub view_ptr: *mut c_void,
|
|
507
|
+
pub instance_ptr: *mut c_void,
|
|
508
|
+
pub surface_ptr: *mut c_void,
|
|
509
|
+
pub adapter_ptr: *mut c_void,
|
|
510
|
+
pub device_ptr: *mut c_void,
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
impl WgpuContext {
|
|
514
|
+
pub fn create_for_view(
|
|
515
|
+
core: &Core,
|
|
516
|
+
native: &WgpuNative,
|
|
517
|
+
view_ptr: *mut c_void,
|
|
518
|
+
) -> Result<Self, String> {
|
|
519
|
+
let instance_ptr = native.create_instance()?;
|
|
520
|
+
let surface_ptr = core.wgpu_create_surface_for_view(instance_ptr, view_ptr)?;
|
|
521
|
+
let adapter_device =
|
|
522
|
+
core.wgpu_create_adapter_device_main_thread(instance_ptr, surface_ptr)?;
|
|
523
|
+
|
|
524
|
+
Ok(Self {
|
|
525
|
+
view_ptr,
|
|
526
|
+
instance_ptr,
|
|
527
|
+
surface_ptr,
|
|
528
|
+
adapter_ptr: adapter_device.adapter,
|
|
529
|
+
device_ptr: adapter_device.device,
|
|
530
|
+
})
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
pub fn create_for_wgpu_view(
|
|
534
|
+
core: &Core,
|
|
535
|
+
native: &WgpuNative,
|
|
536
|
+
wgpu_view_id: u32,
|
|
537
|
+
) -> Result<Self, String> {
|
|
538
|
+
let view_ptr = core.get_wgpu_view_pointer(wgpu_view_id)?;
|
|
539
|
+
Self::create_for_view(core, native, view_ptr)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
pub fn get_queue(&self, native: &WgpuNative) -> Result<*mut c_void, String> {
|
|
543
|
+
native.device_get_queue(self.device_ptr)
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
pub fn resolve_bundle_paths() -> Result<BundlePaths, String> {
|
|
548
|
+
let exe_path = std::env::current_exe()
|
|
549
|
+
.map_err(|err| format!("failed to resolve executable path: {err}"))?;
|
|
550
|
+
let exe_dir = exe_path
|
|
551
|
+
.parent()
|
|
552
|
+
.ok_or_else(|| "executable path has no parent".to_string())?
|
|
553
|
+
.to_path_buf();
|
|
554
|
+
let resources_dir = exe_dir.join("..").join("Resources");
|
|
555
|
+
|
|
556
|
+
Ok(BundlePaths {
|
|
557
|
+
exe_dir,
|
|
558
|
+
resources_dir,
|
|
559
|
+
})
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
pub fn resolve_app_info_from_bundle(bundle_paths: &BundlePaths) -> Result<AppInfo, String> {
|
|
563
|
+
let version_json_path = bundle_paths.resources_dir.join("version.json");
|
|
564
|
+
let version_json = fs::read_to_string(&version_json_path)
|
|
565
|
+
.map_err(|err| format!("failed to read {}: {err}", version_json_path.display()))?;
|
|
566
|
+
|
|
567
|
+
Ok(AppInfo {
|
|
568
|
+
identifier: json_string_field(&version_json, "identifier")
|
|
569
|
+
.unwrap_or_else(|| "sh.blackboard.electrobun".to_string()),
|
|
570
|
+
name: json_string_field(&version_json, "name").unwrap_or_else(|| "Electrobun".to_string()),
|
|
571
|
+
channel: json_string_field(&version_json, "channel").unwrap_or_else(|| "dev".to_string()),
|
|
572
|
+
})
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
type LastErrorFn = unsafe extern "C" fn() -> *const c_char;
|
|
576
|
+
type RunMainThreadFn =
|
|
577
|
+
unsafe extern "C" fn(*const c_char, *const c_char, *const c_char, c_int) -> c_int;
|
|
578
|
+
type ConfigureWebviewRuntimeFn = unsafe extern "C" fn(u32, *const c_char, *const c_char) -> bool;
|
|
579
|
+
type GetWindowStyleFn = unsafe extern "C" fn(
|
|
580
|
+
bool,
|
|
581
|
+
bool,
|
|
582
|
+
bool,
|
|
583
|
+
bool,
|
|
584
|
+
bool,
|
|
585
|
+
bool,
|
|
586
|
+
bool,
|
|
587
|
+
bool,
|
|
588
|
+
bool,
|
|
589
|
+
bool,
|
|
590
|
+
bool,
|
|
591
|
+
bool,
|
|
592
|
+
) -> u32;
|
|
593
|
+
type CreateWindowFn = unsafe extern "C" fn(
|
|
594
|
+
f64,
|
|
595
|
+
f64,
|
|
596
|
+
f64,
|
|
597
|
+
f64,
|
|
598
|
+
u32,
|
|
599
|
+
*const c_char,
|
|
600
|
+
bool,
|
|
601
|
+
*const c_char,
|
|
602
|
+
bool,
|
|
603
|
+
bool,
|
|
604
|
+
f64,
|
|
605
|
+
f64,
|
|
606
|
+
Option<WindowCloseHandler>,
|
|
607
|
+
Option<WindowMoveHandler>,
|
|
608
|
+
Option<WindowResizeHandler>,
|
|
609
|
+
Option<WindowFocusHandler>,
|
|
610
|
+
Option<WindowBlurHandler>,
|
|
611
|
+
Option<WindowKeyHandler>,
|
|
612
|
+
) -> u32;
|
|
613
|
+
type CreateWebviewFn = unsafe extern "C" fn(
|
|
614
|
+
u32,
|
|
615
|
+
u32,
|
|
616
|
+
*const c_char,
|
|
617
|
+
*const c_char,
|
|
618
|
+
f64,
|
|
619
|
+
f64,
|
|
620
|
+
f64,
|
|
621
|
+
f64,
|
|
622
|
+
bool,
|
|
623
|
+
*const c_char,
|
|
624
|
+
Option<DecideNavigationHandler>,
|
|
625
|
+
Option<WebviewEventHandler>,
|
|
626
|
+
Option<WebviewPostMessageHandler>,
|
|
627
|
+
Option<WebviewPostMessageHandler>,
|
|
628
|
+
Option<WebviewPostMessageHandler>,
|
|
629
|
+
*const c_char,
|
|
630
|
+
*const c_char,
|
|
631
|
+
*const c_char,
|
|
632
|
+
bool,
|
|
633
|
+
bool,
|
|
634
|
+
bool,
|
|
635
|
+
) -> u32;
|
|
636
|
+
type CreateWGPUViewFn = unsafe extern "C" fn(u32, f64, f64, f64, f64, bool, bool, bool) -> u32;
|
|
637
|
+
type SetWindowTitleFn = unsafe extern "C" fn(u32, *const c_char);
|
|
638
|
+
type MinimizeWindowFn = unsafe extern "C" fn(u32);
|
|
639
|
+
type RestoreWindowFn = unsafe extern "C" fn(u32);
|
|
640
|
+
type IsWindowMinimizedFn = unsafe extern "C" fn(u32) -> bool;
|
|
641
|
+
type MaximizeWindowFn = unsafe extern "C" fn(u32);
|
|
642
|
+
type UnmaximizeWindowFn = unsafe extern "C" fn(u32);
|
|
643
|
+
type IsWindowMaximizedFn = unsafe extern "C" fn(u32) -> bool;
|
|
644
|
+
type SetWindowFullScreenFn = unsafe extern "C" fn(u32, bool);
|
|
645
|
+
type IsWindowFullScreenFn = unsafe extern "C" fn(u32) -> bool;
|
|
646
|
+
type SetWindowAlwaysOnTopFn = unsafe extern "C" fn(u32, bool);
|
|
647
|
+
type IsWindowAlwaysOnTopFn = unsafe extern "C" fn(u32) -> bool;
|
|
648
|
+
type SetWindowVisibleOnAllWorkspacesFn = unsafe extern "C" fn(u32, bool);
|
|
649
|
+
type IsWindowVisibleOnAllWorkspacesFn = unsafe extern "C" fn(u32) -> bool;
|
|
650
|
+
type ShowWindowFn = unsafe extern "C" fn(u32, bool);
|
|
651
|
+
type ActivateWindowFn = unsafe extern "C" fn(u32);
|
|
652
|
+
type HideWindowFn = unsafe extern "C" fn(u32);
|
|
653
|
+
type SetWindowButtonPositionFn = unsafe extern "C" fn(u32, f64, f64);
|
|
654
|
+
type SetWindowPositionFn = unsafe extern "C" fn(u32, f64, f64);
|
|
655
|
+
type SetWindowSizeFn = unsafe extern "C" fn(u32, f64, f64);
|
|
656
|
+
type SetWindowFrameFn = unsafe extern "C" fn(u32, f64, f64, f64, f64);
|
|
657
|
+
type GetWindowFrameFn = unsafe extern "C" fn(u32, *mut f64, *mut f64, *mut f64, *mut f64);
|
|
658
|
+
type CloseWindowFn = unsafe extern "C" fn(u32);
|
|
659
|
+
type ResizeWebviewFn = unsafe extern "C" fn(u32, f64, f64, f64, f64, *const c_char);
|
|
660
|
+
type LoadURLInWebViewFn = unsafe extern "C" fn(u32, *const c_char);
|
|
661
|
+
type LoadHTMLInWebViewFn = unsafe extern "C" fn(u32, *const c_char);
|
|
662
|
+
type WebviewCanGoBackFn = unsafe extern "C" fn(u32) -> bool;
|
|
663
|
+
type WebviewCanGoForwardFn = unsafe extern "C" fn(u32) -> bool;
|
|
664
|
+
type WebviewGoBackFn = unsafe extern "C" fn(u32);
|
|
665
|
+
type WebviewGoForwardFn = unsafe extern "C" fn(u32);
|
|
666
|
+
type WebviewReloadFn = unsafe extern "C" fn(u32);
|
|
667
|
+
type WebviewRemoveFn = unsafe extern "C" fn(u32);
|
|
668
|
+
type SetWebviewHTMLContentFn = unsafe extern "C" fn(u32, *const c_char);
|
|
669
|
+
type WebviewSetTransparentFn = unsafe extern "C" fn(u32, bool);
|
|
670
|
+
type WebviewSetPassthroughFn = unsafe extern "C" fn(u32, bool);
|
|
671
|
+
type WebviewSetHiddenFn = unsafe extern "C" fn(u32, bool);
|
|
672
|
+
type SetWebviewNavigationRulesFn = unsafe extern "C" fn(u32, *const c_char);
|
|
673
|
+
type WebviewFindInPageFn = unsafe extern "C" fn(u32, *const c_char, bool, bool);
|
|
674
|
+
type WebviewStopFindFn = unsafe extern "C" fn(u32);
|
|
675
|
+
type WebviewOpenDevToolsFn = unsafe extern "C" fn(u32);
|
|
676
|
+
type WebviewCloseDevToolsFn = unsafe extern "C" fn(u32);
|
|
677
|
+
type WebviewToggleDevToolsFn = unsafe extern "C" fn(u32);
|
|
678
|
+
type WebviewSetPageZoomFn = unsafe extern "C" fn(u32, f64);
|
|
679
|
+
type WebviewGetPageZoomFn = unsafe extern "C" fn(u32) -> f64;
|
|
680
|
+
type SendInternalMessageToWebviewFn = unsafe extern "C" fn(u32, *const c_char) -> bool;
|
|
681
|
+
type SetWGPUViewFrameFn = unsafe extern "C" fn(u32, f64, f64, f64, f64);
|
|
682
|
+
type ResizeWGPUViewFn = unsafe extern "C" fn(u32, f64, f64, f64, f64, *const c_char);
|
|
683
|
+
type SetWGPUViewTransparentFn = unsafe extern "C" fn(u32, bool);
|
|
684
|
+
type SetWGPUViewPassthroughFn = unsafe extern "C" fn(u32, bool);
|
|
685
|
+
type SetWGPUViewHiddenFn = unsafe extern "C" fn(u32, bool);
|
|
686
|
+
type RemoveWGPUViewFn = unsafe extern "C" fn(u32);
|
|
687
|
+
type GetWGPUViewPointerFn = unsafe extern "C" fn(u32) -> *mut c_void;
|
|
688
|
+
type GetWGPUViewNativeHandleFn = unsafe extern "C" fn(u32) -> *mut c_void;
|
|
689
|
+
type RunWGPUViewTestFn = unsafe extern "C" fn(u32);
|
|
690
|
+
type ToggleWGPUViewTestShaderFn = unsafe extern "C" fn(u32);
|
|
691
|
+
type SendHostMessageToWebviewViaTransportFn = unsafe extern "C" fn(u32, *const c_char) -> bool;
|
|
692
|
+
type PopNextQueuedHostMessageFn = unsafe extern "C" fn(*mut u32) -> *mut c_char;
|
|
693
|
+
type FreeCoreStringFn = unsafe extern "C" fn(*mut c_char);
|
|
694
|
+
type EvaluateJavaScriptWithNoCompletionFn = unsafe extern "C" fn(u32, *const c_char);
|
|
695
|
+
type CreateTrayFn = unsafe extern "C" fn(
|
|
696
|
+
*const c_char,
|
|
697
|
+
*const c_char,
|
|
698
|
+
bool,
|
|
699
|
+
u32,
|
|
700
|
+
u32,
|
|
701
|
+
Option<StatusItemHandler>,
|
|
702
|
+
) -> u32;
|
|
703
|
+
type ShowTrayFn = unsafe extern "C" fn(u32) -> bool;
|
|
704
|
+
type HideTrayFn = unsafe extern "C" fn(u32);
|
|
705
|
+
type SetTrayTitleFn = unsafe extern "C" fn(u32, *const c_char);
|
|
706
|
+
type RemoveTrayFn = unsafe extern "C" fn(u32);
|
|
707
|
+
type GetTrayBoundsFn = unsafe extern "C" fn(u32) -> *const c_char;
|
|
708
|
+
type SetDockIconVisibleFn = unsafe extern "C" fn(bool);
|
|
709
|
+
type IsDockIconVisibleFn = unsafe extern "C" fn() -> bool;
|
|
710
|
+
type GetPrimaryDisplayFn = unsafe extern "C" fn() -> *mut c_char;
|
|
711
|
+
type GetAllDisplaysFn = unsafe extern "C" fn() -> *mut c_char;
|
|
712
|
+
type GetCursorScreenPointFn = unsafe extern "C" fn() -> *mut c_char;
|
|
713
|
+
type MoveToTrashFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
714
|
+
type ShowItemInFolderFn = unsafe extern "C" fn(*const c_char);
|
|
715
|
+
type OpenExternalFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
716
|
+
type OpenPathFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
717
|
+
type ShowNotificationFn = unsafe extern "C" fn(*const c_char, *const c_char, *const c_char, bool);
|
|
718
|
+
type ClipboardReadTextFn = unsafe extern "C" fn() -> *mut c_char;
|
|
719
|
+
type ClipboardWriteTextFn = unsafe extern "C" fn(*const c_char);
|
|
720
|
+
type ClipboardClearFn = unsafe extern "C" fn();
|
|
721
|
+
type ClipboardAvailableFormatsFn = unsafe extern "C" fn() -> *mut c_char;
|
|
722
|
+
type SetApplicationMenuFn = unsafe extern "C" fn(*const c_char, Option<StatusItemHandler>);
|
|
723
|
+
type ShowContextMenuFn = unsafe extern "C" fn(*const c_char, Option<StatusItemHandler>);
|
|
724
|
+
type OpenFileDialogFn =
|
|
725
|
+
unsafe extern "C" fn(*const c_char, *const c_char, c_int, c_int, c_int) -> *mut c_char;
|
|
726
|
+
type ShowMessageBoxFn = unsafe extern "C" fn(
|
|
727
|
+
*const c_char,
|
|
728
|
+
*const c_char,
|
|
729
|
+
*const c_char,
|
|
730
|
+
*const c_char,
|
|
731
|
+
*const c_char,
|
|
732
|
+
c_int,
|
|
733
|
+
c_int,
|
|
734
|
+
) -> c_int;
|
|
735
|
+
type SetGlobalShortcutCallbackFn = unsafe extern "C" fn(Option<GlobalShortcutHandler>);
|
|
736
|
+
type RegisterGlobalShortcutFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
737
|
+
type UnregisterGlobalShortcutFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
738
|
+
type UnregisterAllGlobalShortcutsFn = unsafe extern "C" fn();
|
|
739
|
+
type IsGlobalShortcutRegisteredFn = unsafe extern "C" fn(*const c_char) -> bool;
|
|
740
|
+
type SessionGetCookiesFn = unsafe extern "C" fn(*const c_char, *const c_char) -> *mut c_char;
|
|
741
|
+
type SessionSetCookieFn = unsafe extern "C" fn(*const c_char, *const c_char) -> bool;
|
|
742
|
+
type SessionRemoveCookieFn =
|
|
743
|
+
unsafe extern "C" fn(*const c_char, *const c_char, *const c_char) -> bool;
|
|
744
|
+
type SessionClearCookiesFn = unsafe extern "C" fn(*const c_char);
|
|
745
|
+
type SessionClearStorageDataFn = unsafe extern "C" fn(*const c_char, *const c_char);
|
|
746
|
+
type SetURLOpenHandlerFn = unsafe extern "C" fn(Option<URLOpenHandler>);
|
|
747
|
+
type SetAppReopenHandlerFn = unsafe extern "C" fn(Option<AppReopenHandler>);
|
|
748
|
+
type SetQuitRequestedHandlerFn = unsafe extern "C" fn(Option<QuitRequestedHandler>);
|
|
749
|
+
type StopEventLoopFn = unsafe extern "C" fn();
|
|
750
|
+
type WaitForShutdownCompleteFn = unsafe extern "C" fn(c_int);
|
|
751
|
+
type ForceExitFn = unsafe extern "C" fn(c_int);
|
|
752
|
+
type WgpuCreateSurfaceForViewFn = unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void;
|
|
753
|
+
type WgpuCreateAdapterDeviceMainThreadFn =
|
|
754
|
+
unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void);
|
|
755
|
+
type WgpuSurfaceConfigureMainThreadFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
|
756
|
+
type WgpuSurfaceGetCurrentTextureMainThreadFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
|
757
|
+
type WgpuSurfacePresentMainThreadFn = unsafe extern "C" fn(*mut c_void) -> c_int;
|
|
758
|
+
|
|
759
|
+
struct Symbols {
|
|
760
|
+
last_error: LastErrorFn,
|
|
761
|
+
run_main_thread: RunMainThreadFn,
|
|
762
|
+
configure_webview_runtime: ConfigureWebviewRuntimeFn,
|
|
763
|
+
get_window_style: GetWindowStyleFn,
|
|
764
|
+
create_window: CreateWindowFn,
|
|
765
|
+
create_webview: CreateWebviewFn,
|
|
766
|
+
create_wgpu_view: CreateWGPUViewFn,
|
|
767
|
+
set_window_title: SetWindowTitleFn,
|
|
768
|
+
minimize_window: MinimizeWindowFn,
|
|
769
|
+
restore_window: RestoreWindowFn,
|
|
770
|
+
is_window_minimized: IsWindowMinimizedFn,
|
|
771
|
+
maximize_window: MaximizeWindowFn,
|
|
772
|
+
unmaximize_window: UnmaximizeWindowFn,
|
|
773
|
+
is_window_maximized: IsWindowMaximizedFn,
|
|
774
|
+
set_window_full_screen: SetWindowFullScreenFn,
|
|
775
|
+
is_window_full_screen: IsWindowFullScreenFn,
|
|
776
|
+
set_window_always_on_top: SetWindowAlwaysOnTopFn,
|
|
777
|
+
is_window_always_on_top: IsWindowAlwaysOnTopFn,
|
|
778
|
+
set_window_visible_on_all_workspaces: SetWindowVisibleOnAllWorkspacesFn,
|
|
779
|
+
is_window_visible_on_all_workspaces: IsWindowVisibleOnAllWorkspacesFn,
|
|
780
|
+
show_window: ShowWindowFn,
|
|
781
|
+
activate_window: ActivateWindowFn,
|
|
782
|
+
hide_window: HideWindowFn,
|
|
783
|
+
set_window_button_position: SetWindowButtonPositionFn,
|
|
784
|
+
set_window_position: SetWindowPositionFn,
|
|
785
|
+
set_window_size: SetWindowSizeFn,
|
|
786
|
+
set_window_frame: SetWindowFrameFn,
|
|
787
|
+
get_window_frame: GetWindowFrameFn,
|
|
788
|
+
close_window: CloseWindowFn,
|
|
789
|
+
resize_webview: ResizeWebviewFn,
|
|
790
|
+
load_url_in_webview: LoadURLInWebViewFn,
|
|
791
|
+
load_html_in_webview: LoadHTMLInWebViewFn,
|
|
792
|
+
webview_can_go_back: WebviewCanGoBackFn,
|
|
793
|
+
webview_can_go_forward: WebviewCanGoForwardFn,
|
|
794
|
+
webview_go_back: WebviewGoBackFn,
|
|
795
|
+
webview_go_forward: WebviewGoForwardFn,
|
|
796
|
+
webview_reload: WebviewReloadFn,
|
|
797
|
+
webview_remove: WebviewRemoveFn,
|
|
798
|
+
set_webview_html_content: SetWebviewHTMLContentFn,
|
|
799
|
+
webview_set_transparent: WebviewSetTransparentFn,
|
|
800
|
+
webview_set_passthrough: WebviewSetPassthroughFn,
|
|
801
|
+
webview_set_hidden: WebviewSetHiddenFn,
|
|
802
|
+
set_webview_navigation_rules: SetWebviewNavigationRulesFn,
|
|
803
|
+
webview_find_in_page: WebviewFindInPageFn,
|
|
804
|
+
webview_stop_find: WebviewStopFindFn,
|
|
805
|
+
webview_open_devtools: WebviewOpenDevToolsFn,
|
|
806
|
+
webview_close_devtools: WebviewCloseDevToolsFn,
|
|
807
|
+
webview_toggle_devtools: WebviewToggleDevToolsFn,
|
|
808
|
+
webview_set_page_zoom: WebviewSetPageZoomFn,
|
|
809
|
+
webview_get_page_zoom: WebviewGetPageZoomFn,
|
|
810
|
+
send_internal_message_to_webview: SendInternalMessageToWebviewFn,
|
|
811
|
+
set_wgpu_view_frame: SetWGPUViewFrameFn,
|
|
812
|
+
resize_wgpu_view: ResizeWGPUViewFn,
|
|
813
|
+
set_wgpu_view_transparent: SetWGPUViewTransparentFn,
|
|
814
|
+
set_wgpu_view_passthrough: SetWGPUViewPassthroughFn,
|
|
815
|
+
set_wgpu_view_hidden: SetWGPUViewHiddenFn,
|
|
816
|
+
remove_wgpu_view: RemoveWGPUViewFn,
|
|
817
|
+
get_wgpu_view_pointer: GetWGPUViewPointerFn,
|
|
818
|
+
get_wgpu_view_native_handle: GetWGPUViewNativeHandleFn,
|
|
819
|
+
run_wgpu_view_test: RunWGPUViewTestFn,
|
|
820
|
+
toggle_wgpu_view_test_shader: ToggleWGPUViewTestShaderFn,
|
|
821
|
+
send_host_message_to_webview_via_transport: SendHostMessageToWebviewViaTransportFn,
|
|
822
|
+
pop_next_queued_host_message: PopNextQueuedHostMessageFn,
|
|
823
|
+
free_core_string: FreeCoreStringFn,
|
|
824
|
+
evaluate_javascript_with_no_completion: EvaluateJavaScriptWithNoCompletionFn,
|
|
825
|
+
create_tray: CreateTrayFn,
|
|
826
|
+
show_tray: ShowTrayFn,
|
|
827
|
+
hide_tray: HideTrayFn,
|
|
828
|
+
set_tray_title: SetTrayTitleFn,
|
|
829
|
+
remove_tray: RemoveTrayFn,
|
|
830
|
+
get_tray_bounds: GetTrayBoundsFn,
|
|
831
|
+
set_dock_icon_visible: SetDockIconVisibleFn,
|
|
832
|
+
is_dock_icon_visible: IsDockIconVisibleFn,
|
|
833
|
+
get_primary_display: GetPrimaryDisplayFn,
|
|
834
|
+
get_all_displays: GetAllDisplaysFn,
|
|
835
|
+
get_cursor_screen_point: GetCursorScreenPointFn,
|
|
836
|
+
move_to_trash: MoveToTrashFn,
|
|
837
|
+
show_item_in_folder: ShowItemInFolderFn,
|
|
838
|
+
open_external: OpenExternalFn,
|
|
839
|
+
open_path: OpenPathFn,
|
|
840
|
+
show_notification: ShowNotificationFn,
|
|
841
|
+
clipboard_read_text: ClipboardReadTextFn,
|
|
842
|
+
clipboard_write_text: ClipboardWriteTextFn,
|
|
843
|
+
clipboard_clear: ClipboardClearFn,
|
|
844
|
+
clipboard_available_formats: ClipboardAvailableFormatsFn,
|
|
845
|
+
set_application_menu: SetApplicationMenuFn,
|
|
846
|
+
show_context_menu: ShowContextMenuFn,
|
|
847
|
+
open_file_dialog: OpenFileDialogFn,
|
|
848
|
+
show_message_box: ShowMessageBoxFn,
|
|
849
|
+
set_global_shortcut_callback: SetGlobalShortcutCallbackFn,
|
|
850
|
+
register_global_shortcut: RegisterGlobalShortcutFn,
|
|
851
|
+
unregister_global_shortcut: UnregisterGlobalShortcutFn,
|
|
852
|
+
unregister_all_global_shortcuts: UnregisterAllGlobalShortcutsFn,
|
|
853
|
+
is_global_shortcut_registered: IsGlobalShortcutRegisteredFn,
|
|
854
|
+
session_get_cookies: SessionGetCookiesFn,
|
|
855
|
+
session_set_cookie: SessionSetCookieFn,
|
|
856
|
+
session_remove_cookie: SessionRemoveCookieFn,
|
|
857
|
+
session_clear_cookies: SessionClearCookiesFn,
|
|
858
|
+
session_clear_storage_data: SessionClearStorageDataFn,
|
|
859
|
+
set_url_open_handler: SetURLOpenHandlerFn,
|
|
860
|
+
set_app_reopen_handler: SetAppReopenHandlerFn,
|
|
861
|
+
set_quit_requested_handler: SetQuitRequestedHandlerFn,
|
|
862
|
+
stop_event_loop: StopEventLoopFn,
|
|
863
|
+
wait_for_shutdown_complete: WaitForShutdownCompleteFn,
|
|
864
|
+
force_exit: ForceExitFn,
|
|
865
|
+
wgpu_create_surface_for_view: WgpuCreateSurfaceForViewFn,
|
|
866
|
+
wgpu_create_adapter_device_main_thread: WgpuCreateAdapterDeviceMainThreadFn,
|
|
867
|
+
wgpu_surface_configure_main_thread: WgpuSurfaceConfigureMainThreadFn,
|
|
868
|
+
wgpu_surface_get_current_texture_main_thread: WgpuSurfaceGetCurrentTextureMainThreadFn,
|
|
869
|
+
wgpu_surface_present_main_thread: WgpuSurfacePresentMainThreadFn,
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
pub struct Core {
|
|
873
|
+
_lib: dynlib::DynamicLibrary,
|
|
874
|
+
symbols: Symbols,
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
unsafe impl Send for Core {}
|
|
878
|
+
unsafe impl Sync for Core {}
|
|
879
|
+
|
|
880
|
+
impl Core {
|
|
881
|
+
pub fn load() -> Result<Self, String> {
|
|
882
|
+
let bundle_paths = resolve_bundle_paths()?;
|
|
883
|
+
let lib_path = bundle_paths.exe_dir.join(core_library_name());
|
|
884
|
+
let lib = dynlib::DynamicLibrary::open(&lib_path)?;
|
|
885
|
+
|
|
886
|
+
let symbols = Symbols {
|
|
887
|
+
last_error: lib.symbol("electrobun_core_last_error")?,
|
|
888
|
+
run_main_thread: lib.symbol("electrobun_core_run_main_thread")?,
|
|
889
|
+
configure_webview_runtime: lib.symbol("configureWebviewRuntime")?,
|
|
890
|
+
get_window_style: lib.symbol("getWindowStyle")?,
|
|
891
|
+
create_window: lib.symbol("createWindow")?,
|
|
892
|
+
create_webview: lib.symbol("createWebview")?,
|
|
893
|
+
create_wgpu_view: lib.symbol("createWGPUView")?,
|
|
894
|
+
set_window_title: lib.symbol("setWindowTitle")?,
|
|
895
|
+
minimize_window: lib.symbol("minimizeWindow")?,
|
|
896
|
+
restore_window: lib.symbol("restoreWindow")?,
|
|
897
|
+
is_window_minimized: lib.symbol("isWindowMinimized")?,
|
|
898
|
+
maximize_window: lib.symbol("maximizeWindow")?,
|
|
899
|
+
unmaximize_window: lib.symbol("unmaximizeWindow")?,
|
|
900
|
+
is_window_maximized: lib.symbol("isWindowMaximized")?,
|
|
901
|
+
set_window_full_screen: lib.symbol("setWindowFullScreen")?,
|
|
902
|
+
is_window_full_screen: lib.symbol("isWindowFullScreen")?,
|
|
903
|
+
set_window_always_on_top: lib.symbol("setWindowAlwaysOnTop")?,
|
|
904
|
+
is_window_always_on_top: lib.symbol("isWindowAlwaysOnTop")?,
|
|
905
|
+
set_window_visible_on_all_workspaces: lib.symbol("setWindowVisibleOnAllWorkspaces")?,
|
|
906
|
+
is_window_visible_on_all_workspaces: lib.symbol("isWindowVisibleOnAllWorkspaces")?,
|
|
907
|
+
show_window: lib.symbol("showWindow")?,
|
|
908
|
+
activate_window: lib.symbol("activateWindow")?,
|
|
909
|
+
hide_window: lib.symbol("hideWindow")?,
|
|
910
|
+
set_window_button_position: lib.symbol("setWindowButtonPosition")?,
|
|
911
|
+
set_window_position: lib.symbol("setWindowPosition")?,
|
|
912
|
+
set_window_size: lib.symbol("setWindowSize")?,
|
|
913
|
+
set_window_frame: lib.symbol("setWindowFrame")?,
|
|
914
|
+
get_window_frame: lib.symbol("getWindowFrame")?,
|
|
915
|
+
close_window: lib.symbol("closeWindow")?,
|
|
916
|
+
resize_webview: lib.symbol("resizeWebview")?,
|
|
917
|
+
load_url_in_webview: lib.symbol("loadURLInWebView")?,
|
|
918
|
+
load_html_in_webview: lib.symbol("loadHTMLInWebView")?,
|
|
919
|
+
webview_can_go_back: lib.symbol("webviewCanGoBack")?,
|
|
920
|
+
webview_can_go_forward: lib.symbol("webviewCanGoForward")?,
|
|
921
|
+
webview_go_back: lib.symbol("webviewGoBack")?,
|
|
922
|
+
webview_go_forward: lib.symbol("webviewGoForward")?,
|
|
923
|
+
webview_reload: lib.symbol("webviewReload")?,
|
|
924
|
+
webview_remove: lib.symbol("webviewRemove")?,
|
|
925
|
+
set_webview_html_content: lib.symbol("setWebviewHTMLContent")?,
|
|
926
|
+
webview_set_transparent: lib.symbol("webviewSetTransparent")?,
|
|
927
|
+
webview_set_passthrough: lib.symbol("webviewSetPassthrough")?,
|
|
928
|
+
webview_set_hidden: lib.symbol("webviewSetHidden")?,
|
|
929
|
+
set_webview_navigation_rules: lib.symbol("setWebviewNavigationRules")?,
|
|
930
|
+
webview_find_in_page: lib.symbol("webviewFindInPage")?,
|
|
931
|
+
webview_stop_find: lib.symbol("webviewStopFind")?,
|
|
932
|
+
webview_open_devtools: lib.symbol("webviewOpenDevTools")?,
|
|
933
|
+
webview_close_devtools: lib.symbol("webviewCloseDevTools")?,
|
|
934
|
+
webview_toggle_devtools: lib.symbol("webviewToggleDevTools")?,
|
|
935
|
+
webview_set_page_zoom: lib.symbol("webviewSetPageZoom")?,
|
|
936
|
+
webview_get_page_zoom: lib.symbol("webviewGetPageZoom")?,
|
|
937
|
+
send_internal_message_to_webview: lib.symbol("sendInternalMessageToWebview")?,
|
|
938
|
+
set_wgpu_view_frame: lib.symbol("setWGPUViewFrame")?,
|
|
939
|
+
resize_wgpu_view: lib.symbol("resizeWGPUView")?,
|
|
940
|
+
set_wgpu_view_transparent: lib.symbol("setWGPUViewTransparent")?,
|
|
941
|
+
set_wgpu_view_passthrough: lib.symbol("setWGPUViewPassthrough")?,
|
|
942
|
+
set_wgpu_view_hidden: lib.symbol("setWGPUViewHidden")?,
|
|
943
|
+
remove_wgpu_view: lib.symbol("removeWGPUView")?,
|
|
944
|
+
get_wgpu_view_pointer: lib.symbol("getWGPUViewPointer")?,
|
|
945
|
+
get_wgpu_view_native_handle: lib.symbol("getWGPUViewNativeHandle")?,
|
|
946
|
+
run_wgpu_view_test: lib.symbol("runWGPUViewTest")?,
|
|
947
|
+
toggle_wgpu_view_test_shader: lib.symbol("toggleWGPUViewTestShader")?,
|
|
948
|
+
send_host_message_to_webview_via_transport: lib
|
|
949
|
+
.symbol("sendHostMessageToWebviewViaTransport")?,
|
|
950
|
+
pop_next_queued_host_message: lib.symbol("popNextQueuedHostMessage")?,
|
|
951
|
+
free_core_string: lib.symbol("freeCoreString")?,
|
|
952
|
+
evaluate_javascript_with_no_completion: lib
|
|
953
|
+
.symbol("evaluateJavaScriptWithNoCompletion")?,
|
|
954
|
+
create_tray: lib.symbol("createTray")?,
|
|
955
|
+
show_tray: lib.symbol("showTray")?,
|
|
956
|
+
hide_tray: lib.symbol("hideTray")?,
|
|
957
|
+
set_tray_title: lib.symbol("setTrayTitle")?,
|
|
958
|
+
remove_tray: lib.symbol("removeTray")?,
|
|
959
|
+
get_tray_bounds: lib.symbol("getTrayBounds")?,
|
|
960
|
+
set_dock_icon_visible: lib.symbol("setDockIconVisible")?,
|
|
961
|
+
is_dock_icon_visible: lib.symbol("isDockIconVisible")?,
|
|
962
|
+
get_primary_display: lib.symbol("getPrimaryDisplay")?,
|
|
963
|
+
get_all_displays: lib.symbol("getAllDisplays")?,
|
|
964
|
+
get_cursor_screen_point: lib.symbol("getCursorScreenPoint")?,
|
|
965
|
+
move_to_trash: lib.symbol("moveToTrash")?,
|
|
966
|
+
show_item_in_folder: lib.symbol("showItemInFolder")?,
|
|
967
|
+
open_external: lib.symbol("openExternal")?,
|
|
968
|
+
open_path: lib.symbol("openPath")?,
|
|
969
|
+
show_notification: lib.symbol("showNotification")?,
|
|
970
|
+
clipboard_read_text: lib.symbol("clipboardReadText")?,
|
|
971
|
+
clipboard_write_text: lib.symbol("clipboardWriteText")?,
|
|
972
|
+
clipboard_clear: lib.symbol("clipboardClear")?,
|
|
973
|
+
clipboard_available_formats: lib.symbol("clipboardAvailableFormats")?,
|
|
974
|
+
set_application_menu: lib.symbol("setApplicationMenu")?,
|
|
975
|
+
show_context_menu: lib.symbol("showContextMenu")?,
|
|
976
|
+
open_file_dialog: lib.symbol("openFileDialog")?,
|
|
977
|
+
show_message_box: lib.symbol("showMessageBox")?,
|
|
978
|
+
set_global_shortcut_callback: lib.symbol("setGlobalShortcutCallback")?,
|
|
979
|
+
register_global_shortcut: lib.symbol("registerGlobalShortcut")?,
|
|
980
|
+
unregister_global_shortcut: lib.symbol("unregisterGlobalShortcut")?,
|
|
981
|
+
unregister_all_global_shortcuts: lib.symbol("unregisterAllGlobalShortcuts")?,
|
|
982
|
+
is_global_shortcut_registered: lib.symbol("isGlobalShortcutRegistered")?,
|
|
983
|
+
session_get_cookies: lib.symbol("sessionGetCookies")?,
|
|
984
|
+
session_set_cookie: lib.symbol("sessionSetCookie")?,
|
|
985
|
+
session_remove_cookie: lib.symbol("sessionRemoveCookie")?,
|
|
986
|
+
session_clear_cookies: lib.symbol("sessionClearCookies")?,
|
|
987
|
+
session_clear_storage_data: lib.symbol("sessionClearStorageData")?,
|
|
988
|
+
set_url_open_handler: lib.symbol("setURLOpenHandler")?,
|
|
989
|
+
set_app_reopen_handler: lib.symbol("setAppReopenHandler")?,
|
|
990
|
+
set_quit_requested_handler: lib.symbol("setQuitRequestedHandler")?,
|
|
991
|
+
stop_event_loop: lib.symbol("stopEventLoop")?,
|
|
992
|
+
wait_for_shutdown_complete: lib.symbol("waitForShutdownComplete")?,
|
|
993
|
+
force_exit: lib.symbol("forceExit")?,
|
|
994
|
+
wgpu_create_surface_for_view: lib.symbol("wgpuCreateSurfaceForView")?,
|
|
995
|
+
wgpu_create_adapter_device_main_thread: lib
|
|
996
|
+
.symbol("wgpuCreateAdapterDeviceMainThread")?,
|
|
997
|
+
wgpu_surface_configure_main_thread: lib.symbol("wgpuSurfaceConfigureMainThread")?,
|
|
998
|
+
wgpu_surface_get_current_texture_main_thread: lib
|
|
999
|
+
.symbol("wgpuSurfaceGetCurrentTextureMainThread")?,
|
|
1000
|
+
wgpu_surface_present_main_thread: lib.symbol("wgpuSurfacePresentMainThread")?,
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
Ok(Self { _lib: lib, symbols })
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
pub fn configure_webview_runtime_from_executable_dir(
|
|
1007
|
+
&self,
|
|
1008
|
+
bundle_paths: &BundlePaths,
|
|
1009
|
+
rpc_port: u32,
|
|
1010
|
+
) -> Result<(), String> {
|
|
1011
|
+
let full_path = bundle_paths.resources_dir.join("preload-full.js");
|
|
1012
|
+
let sandboxed_path = bundle_paths.resources_dir.join("preload-sandboxed.js");
|
|
1013
|
+
let full_preload = fs::read_to_string(&full_path)
|
|
1014
|
+
.map_err(|err| format!("failed to read {}: {err}", full_path.display()))?;
|
|
1015
|
+
let sandboxed_preload = fs::read_to_string(&sandboxed_path)
|
|
1016
|
+
.map_err(|err| format!("failed to read {}: {err}", sandboxed_path.display()))?;
|
|
1017
|
+
let full_preload = to_c_string(&full_preload, "preload-full.js")?;
|
|
1018
|
+
let sandboxed_preload = to_c_string(&sandboxed_preload, "preload-sandboxed.js")?;
|
|
1019
|
+
|
|
1020
|
+
let ok = unsafe {
|
|
1021
|
+
(self.symbols.configure_webview_runtime)(
|
|
1022
|
+
rpc_port,
|
|
1023
|
+
full_preload.as_ptr(),
|
|
1024
|
+
sandboxed_preload.as_ptr(),
|
|
1025
|
+
)
|
|
1026
|
+
};
|
|
1027
|
+
if !ok {
|
|
1028
|
+
return Err(self.last_error());
|
|
1029
|
+
}
|
|
1030
|
+
Ok(())
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
pub fn create_window(&self, options: WindowOptions<'_>) -> Result<u32, String> {
|
|
1034
|
+
let title = to_c_string(options.title, "window title")?;
|
|
1035
|
+
let title_bar_style = to_c_string(options.title_bar_style, "title bar style")?;
|
|
1036
|
+
let style = &options.style;
|
|
1037
|
+
|
|
1038
|
+
let style_mask = unsafe {
|
|
1039
|
+
(self.symbols.get_window_style)(
|
|
1040
|
+
style.borderless,
|
|
1041
|
+
style.titled,
|
|
1042
|
+
style.closable,
|
|
1043
|
+
style.miniaturizable,
|
|
1044
|
+
style.resizable,
|
|
1045
|
+
style.unified_title_and_toolbar,
|
|
1046
|
+
style.full_screen,
|
|
1047
|
+
style.full_size_content_view,
|
|
1048
|
+
style.utility_window,
|
|
1049
|
+
style.doc_modal_window,
|
|
1050
|
+
style.nonactivating_panel,
|
|
1051
|
+
style.hud_window,
|
|
1052
|
+
)
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
let window_id = unsafe {
|
|
1056
|
+
(self.symbols.create_window)(
|
|
1057
|
+
options.frame.x,
|
|
1058
|
+
options.frame.y,
|
|
1059
|
+
options.frame.width,
|
|
1060
|
+
options.frame.height,
|
|
1061
|
+
style_mask,
|
|
1062
|
+
title_bar_style.as_ptr(),
|
|
1063
|
+
options.transparent,
|
|
1064
|
+
title.as_ptr(),
|
|
1065
|
+
options.hidden,
|
|
1066
|
+
options.activate,
|
|
1067
|
+
options.traffic_light_offset.x,
|
|
1068
|
+
options.traffic_light_offset.y,
|
|
1069
|
+
options.callbacks.close,
|
|
1070
|
+
options.callbacks.move_handler,
|
|
1071
|
+
options.callbacks.resize,
|
|
1072
|
+
options.callbacks.focus,
|
|
1073
|
+
options.callbacks.blur,
|
|
1074
|
+
options.callbacks.key,
|
|
1075
|
+
)
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
if window_id == 0 {
|
|
1079
|
+
return Err(self.last_error());
|
|
1080
|
+
}
|
|
1081
|
+
Ok(window_id)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
pub fn set_window_title(&self, window_id: u32, title: &str) -> Result<(), String> {
|
|
1085
|
+
let title = to_c_string(title, "window title")?;
|
|
1086
|
+
unsafe {
|
|
1087
|
+
(self.symbols.set_window_title)(window_id, title.as_ptr());
|
|
1088
|
+
}
|
|
1089
|
+
self.ensure_last_call_succeeded()
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
pub fn minimize_window(&self, window_id: u32) -> Result<(), String> {
|
|
1093
|
+
unsafe {
|
|
1094
|
+
(self.symbols.minimize_window)(window_id);
|
|
1095
|
+
}
|
|
1096
|
+
self.ensure_last_call_succeeded()
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
pub fn restore_window(&self, window_id: u32) -> Result<(), String> {
|
|
1100
|
+
unsafe {
|
|
1101
|
+
(self.symbols.restore_window)(window_id);
|
|
1102
|
+
}
|
|
1103
|
+
self.ensure_last_call_succeeded()
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
pub fn is_window_minimized(&self, window_id: u32) -> bool {
|
|
1107
|
+
unsafe { (self.symbols.is_window_minimized)(window_id) }
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
pub fn maximize_window(&self, window_id: u32) -> Result<(), String> {
|
|
1111
|
+
unsafe {
|
|
1112
|
+
(self.symbols.maximize_window)(window_id);
|
|
1113
|
+
}
|
|
1114
|
+
self.ensure_last_call_succeeded()
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
pub fn unmaximize_window(&self, window_id: u32) -> Result<(), String> {
|
|
1118
|
+
unsafe {
|
|
1119
|
+
(self.symbols.unmaximize_window)(window_id);
|
|
1120
|
+
}
|
|
1121
|
+
self.ensure_last_call_succeeded()
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
pub fn is_window_maximized(&self, window_id: u32) -> bool {
|
|
1125
|
+
unsafe { (self.symbols.is_window_maximized)(window_id) }
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
pub fn set_window_full_screen(&self, window_id: u32, full_screen: bool) -> Result<(), String> {
|
|
1129
|
+
unsafe {
|
|
1130
|
+
(self.symbols.set_window_full_screen)(window_id, full_screen);
|
|
1131
|
+
}
|
|
1132
|
+
self.ensure_last_call_succeeded()
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
pub fn is_window_full_screen(&self, window_id: u32) -> bool {
|
|
1136
|
+
unsafe { (self.symbols.is_window_full_screen)(window_id) }
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
pub fn set_window_always_on_top(
|
|
1140
|
+
&self,
|
|
1141
|
+
window_id: u32,
|
|
1142
|
+
always_on_top: bool,
|
|
1143
|
+
) -> Result<(), String> {
|
|
1144
|
+
unsafe {
|
|
1145
|
+
(self.symbols.set_window_always_on_top)(window_id, always_on_top);
|
|
1146
|
+
}
|
|
1147
|
+
self.ensure_last_call_succeeded()
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
pub fn is_window_always_on_top(&self, window_id: u32) -> bool {
|
|
1151
|
+
unsafe { (self.symbols.is_window_always_on_top)(window_id) }
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
pub fn set_window_visible_on_all_workspaces(
|
|
1155
|
+
&self,
|
|
1156
|
+
window_id: u32,
|
|
1157
|
+
visible: bool,
|
|
1158
|
+
) -> Result<(), String> {
|
|
1159
|
+
unsafe {
|
|
1160
|
+
(self.symbols.set_window_visible_on_all_workspaces)(window_id, visible);
|
|
1161
|
+
}
|
|
1162
|
+
self.ensure_last_call_succeeded()
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
pub fn is_window_visible_on_all_workspaces(&self, window_id: u32) -> bool {
|
|
1166
|
+
unsafe { (self.symbols.is_window_visible_on_all_workspaces)(window_id) }
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
pub fn show_window(&self, window_id: u32, activate: bool) -> Result<(), String> {
|
|
1170
|
+
unsafe {
|
|
1171
|
+
(self.symbols.show_window)(window_id, activate);
|
|
1172
|
+
}
|
|
1173
|
+
self.ensure_last_call_succeeded()
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
pub fn activate_window(&self, window_id: u32) -> Result<(), String> {
|
|
1177
|
+
unsafe {
|
|
1178
|
+
(self.symbols.activate_window)(window_id);
|
|
1179
|
+
}
|
|
1180
|
+
self.ensure_last_call_succeeded()
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
pub fn hide_window(&self, window_id: u32) -> Result<(), String> {
|
|
1184
|
+
unsafe {
|
|
1185
|
+
(self.symbols.hide_window)(window_id);
|
|
1186
|
+
}
|
|
1187
|
+
self.ensure_last_call_succeeded()
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
pub fn set_window_button_position(&self, window_id: u32, x: f64, y: f64) -> Result<(), String> {
|
|
1191
|
+
unsafe {
|
|
1192
|
+
(self.symbols.set_window_button_position)(window_id, x, y);
|
|
1193
|
+
}
|
|
1194
|
+
self.ensure_last_call_succeeded()
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
pub fn set_window_position(&self, window_id: u32, x: f64, y: f64) -> Result<(), String> {
|
|
1198
|
+
unsafe {
|
|
1199
|
+
(self.symbols.set_window_position)(window_id, x, y);
|
|
1200
|
+
}
|
|
1201
|
+
self.ensure_last_call_succeeded()
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
pub fn set_window_size(&self, window_id: u32, width: f64, height: f64) -> Result<(), String> {
|
|
1205
|
+
unsafe {
|
|
1206
|
+
(self.symbols.set_window_size)(window_id, width, height);
|
|
1207
|
+
}
|
|
1208
|
+
self.ensure_last_call_succeeded()
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
pub fn set_window_frame(&self, window_id: u32, frame: Rect) -> Result<(), String> {
|
|
1212
|
+
unsafe {
|
|
1213
|
+
(self.symbols.set_window_frame)(window_id, frame.x, frame.y, frame.width, frame.height);
|
|
1214
|
+
}
|
|
1215
|
+
self.ensure_last_call_succeeded()
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
pub fn get_window_frame(&self, window_id: u32) -> Result<Rect, String> {
|
|
1219
|
+
let mut x = 0.0;
|
|
1220
|
+
let mut y = 0.0;
|
|
1221
|
+
let mut width = 0.0;
|
|
1222
|
+
let mut height = 0.0;
|
|
1223
|
+
unsafe {
|
|
1224
|
+
(self.symbols.get_window_frame)(
|
|
1225
|
+
window_id,
|
|
1226
|
+
&mut x as *mut f64,
|
|
1227
|
+
&mut y as *mut f64,
|
|
1228
|
+
&mut width as *mut f64,
|
|
1229
|
+
&mut height as *mut f64,
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
self.ensure_last_call_succeeded()?;
|
|
1233
|
+
Ok(Rect::new(x, y, width, height))
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
pub fn create_webview(&self, options: WebviewOptions<'_>) -> Result<u32, String> {
|
|
1237
|
+
let renderer = to_c_string(options.renderer.as_str(), "renderer")?;
|
|
1238
|
+
let url = to_c_string(options.url, "webview url")?;
|
|
1239
|
+
let partition = to_c_string(options.partition, "partition")?;
|
|
1240
|
+
let secret_key = to_c_string(options.secret_key, "secret key")?;
|
|
1241
|
+
let preload = to_c_string(options.preload, "preload")?;
|
|
1242
|
+
let views_root = to_c_string(options.views_root, "views root")?;
|
|
1243
|
+
|
|
1244
|
+
let webview_id = unsafe {
|
|
1245
|
+
(self.symbols.create_webview)(
|
|
1246
|
+
options.window_id,
|
|
1247
|
+
options.host_webview_id,
|
|
1248
|
+
renderer.as_ptr(),
|
|
1249
|
+
url.as_ptr(),
|
|
1250
|
+
options.frame.x,
|
|
1251
|
+
options.frame.y,
|
|
1252
|
+
options.frame.width,
|
|
1253
|
+
options.frame.height,
|
|
1254
|
+
options.auto_resize,
|
|
1255
|
+
partition.as_ptr(),
|
|
1256
|
+
options.callbacks.decide_navigation,
|
|
1257
|
+
options.callbacks.event,
|
|
1258
|
+
options.callbacks.event_bridge,
|
|
1259
|
+
options
|
|
1260
|
+
.callbacks
|
|
1261
|
+
.host_bridge
|
|
1262
|
+
.or(options.callbacks.bun_bridge),
|
|
1263
|
+
options.callbacks.internal_bridge,
|
|
1264
|
+
secret_key.as_ptr(),
|
|
1265
|
+
preload.as_ptr(),
|
|
1266
|
+
views_root.as_ptr(),
|
|
1267
|
+
options.sandbox,
|
|
1268
|
+
options.start_transparent,
|
|
1269
|
+
options.start_passthrough,
|
|
1270
|
+
)
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
if webview_id == 0 {
|
|
1274
|
+
return Err(self.last_error());
|
|
1275
|
+
}
|
|
1276
|
+
Ok(webview_id)
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
pub fn resize_webview(
|
|
1280
|
+
&self,
|
|
1281
|
+
webview_id: u32,
|
|
1282
|
+
frame: Rect,
|
|
1283
|
+
masks_json: &str,
|
|
1284
|
+
) -> Result<(), String> {
|
|
1285
|
+
let masks_json = to_c_string(masks_json, "resize masks json")?;
|
|
1286
|
+
unsafe {
|
|
1287
|
+
(self.symbols.resize_webview)(
|
|
1288
|
+
webview_id,
|
|
1289
|
+
frame.x,
|
|
1290
|
+
frame.y,
|
|
1291
|
+
frame.width,
|
|
1292
|
+
frame.height,
|
|
1293
|
+
masks_json.as_ptr(),
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
self.ensure_last_call_succeeded()
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
pub fn load_url_in_webview(&self, webview_id: u32, url: &str) -> Result<(), String> {
|
|
1300
|
+
let url = to_c_string(url, "webview url")?;
|
|
1301
|
+
unsafe {
|
|
1302
|
+
(self.symbols.load_url_in_webview)(webview_id, url.as_ptr());
|
|
1303
|
+
}
|
|
1304
|
+
self.ensure_last_call_succeeded()
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
pub fn load_html_in_webview(&self, webview_id: u32, html: &str) -> Result<(), String> {
|
|
1308
|
+
let html = to_c_string(html, "webview html")?;
|
|
1309
|
+
unsafe {
|
|
1310
|
+
(self.symbols.load_html_in_webview)(webview_id, html.as_ptr());
|
|
1311
|
+
}
|
|
1312
|
+
self.ensure_last_call_succeeded()
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
pub fn can_webview_go_back(&self, webview_id: u32) -> bool {
|
|
1316
|
+
unsafe { (self.symbols.webview_can_go_back)(webview_id) }
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
pub fn can_webview_go_forward(&self, webview_id: u32) -> bool {
|
|
1320
|
+
unsafe { (self.symbols.webview_can_go_forward)(webview_id) }
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
pub fn webview_go_back(&self, webview_id: u32) -> Result<(), String> {
|
|
1324
|
+
unsafe {
|
|
1325
|
+
(self.symbols.webview_go_back)(webview_id);
|
|
1326
|
+
}
|
|
1327
|
+
self.ensure_last_call_succeeded()
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
pub fn webview_go_forward(&self, webview_id: u32) -> Result<(), String> {
|
|
1331
|
+
unsafe {
|
|
1332
|
+
(self.symbols.webview_go_forward)(webview_id);
|
|
1333
|
+
}
|
|
1334
|
+
self.ensure_last_call_succeeded()
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
pub fn reload_webview(&self, webview_id: u32) -> Result<(), String> {
|
|
1338
|
+
unsafe {
|
|
1339
|
+
(self.symbols.webview_reload)(webview_id);
|
|
1340
|
+
}
|
|
1341
|
+
self.ensure_last_call_succeeded()
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
pub fn remove_webview(&self, webview_id: u32) -> Result<(), String> {
|
|
1345
|
+
unsafe {
|
|
1346
|
+
(self.symbols.webview_remove)(webview_id);
|
|
1347
|
+
}
|
|
1348
|
+
self.ensure_last_call_succeeded()
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
pub fn set_webview_html_content(&self, webview_id: u32, html: &str) -> Result<(), String> {
|
|
1352
|
+
let html = to_c_string(html, "webview html")?;
|
|
1353
|
+
unsafe {
|
|
1354
|
+
(self.symbols.set_webview_html_content)(webview_id, html.as_ptr());
|
|
1355
|
+
}
|
|
1356
|
+
self.ensure_last_call_succeeded()
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
pub fn set_webview_transparent(
|
|
1360
|
+
&self,
|
|
1361
|
+
webview_id: u32,
|
|
1362
|
+
transparent: bool,
|
|
1363
|
+
) -> Result<(), String> {
|
|
1364
|
+
unsafe {
|
|
1365
|
+
(self.symbols.webview_set_transparent)(webview_id, transparent);
|
|
1366
|
+
}
|
|
1367
|
+
self.ensure_last_call_succeeded()
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
pub fn set_webview_passthrough(
|
|
1371
|
+
&self,
|
|
1372
|
+
webview_id: u32,
|
|
1373
|
+
passthrough: bool,
|
|
1374
|
+
) -> Result<(), String> {
|
|
1375
|
+
unsafe {
|
|
1376
|
+
(self.symbols.webview_set_passthrough)(webview_id, passthrough);
|
|
1377
|
+
}
|
|
1378
|
+
self.ensure_last_call_succeeded()
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
pub fn set_webview_hidden(&self, webview_id: u32, hidden: bool) -> Result<(), String> {
|
|
1382
|
+
unsafe {
|
|
1383
|
+
(self.symbols.webview_set_hidden)(webview_id, hidden);
|
|
1384
|
+
}
|
|
1385
|
+
self.ensure_last_call_succeeded()
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
pub fn set_webview_navigation_rules(
|
|
1389
|
+
&self,
|
|
1390
|
+
webview_id: u32,
|
|
1391
|
+
rules_json: &str,
|
|
1392
|
+
) -> Result<(), String> {
|
|
1393
|
+
let rules_json = to_c_string(rules_json, "navigation rules json")?;
|
|
1394
|
+
unsafe {
|
|
1395
|
+
(self.symbols.set_webview_navigation_rules)(webview_id, rules_json.as_ptr());
|
|
1396
|
+
}
|
|
1397
|
+
self.ensure_last_call_succeeded()
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
pub fn webview_find_in_page(
|
|
1401
|
+
&self,
|
|
1402
|
+
webview_id: u32,
|
|
1403
|
+
search_text: &str,
|
|
1404
|
+
forward: bool,
|
|
1405
|
+
match_case: bool,
|
|
1406
|
+
) -> Result<(), String> {
|
|
1407
|
+
let search_text = to_c_string(search_text, "find text")?;
|
|
1408
|
+
unsafe {
|
|
1409
|
+
(self.symbols.webview_find_in_page)(
|
|
1410
|
+
webview_id,
|
|
1411
|
+
search_text.as_ptr(),
|
|
1412
|
+
forward,
|
|
1413
|
+
match_case,
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
self.ensure_last_call_succeeded()
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
pub fn webview_stop_find(&self, webview_id: u32) -> Result<(), String> {
|
|
1420
|
+
unsafe {
|
|
1421
|
+
(self.symbols.webview_stop_find)(webview_id);
|
|
1422
|
+
}
|
|
1423
|
+
self.ensure_last_call_succeeded()
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
pub fn open_webview_devtools(&self, webview_id: u32) -> Result<(), String> {
|
|
1427
|
+
unsafe {
|
|
1428
|
+
(self.symbols.webview_open_devtools)(webview_id);
|
|
1429
|
+
}
|
|
1430
|
+
self.ensure_last_call_succeeded()
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
pub fn close_webview_devtools(&self, webview_id: u32) -> Result<(), String> {
|
|
1434
|
+
unsafe {
|
|
1435
|
+
(self.symbols.webview_close_devtools)(webview_id);
|
|
1436
|
+
}
|
|
1437
|
+
self.ensure_last_call_succeeded()
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
pub fn toggle_webview_devtools(&self, webview_id: u32) -> Result<(), String> {
|
|
1441
|
+
unsafe {
|
|
1442
|
+
(self.symbols.webview_toggle_devtools)(webview_id);
|
|
1443
|
+
}
|
|
1444
|
+
self.ensure_last_call_succeeded()
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
pub fn set_webview_page_zoom(&self, webview_id: u32, zoom_level: f64) -> Result<(), String> {
|
|
1448
|
+
unsafe {
|
|
1449
|
+
(self.symbols.webview_set_page_zoom)(webview_id, zoom_level);
|
|
1450
|
+
}
|
|
1451
|
+
self.ensure_last_call_succeeded()
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
pub fn get_webview_page_zoom(&self, webview_id: u32) -> f64 {
|
|
1455
|
+
unsafe { (self.symbols.webview_get_page_zoom)(webview_id) }
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
pub fn send_internal_message_to_webview_json(
|
|
1459
|
+
&self,
|
|
1460
|
+
webview_id: u32,
|
|
1461
|
+
message_json: &str,
|
|
1462
|
+
) -> Result<(), String> {
|
|
1463
|
+
let message_json = to_c_string(message_json, "internal message json")?;
|
|
1464
|
+
let sent = unsafe {
|
|
1465
|
+
(self.symbols.send_internal_message_to_webview)(webview_id, message_json.as_ptr())
|
|
1466
|
+
};
|
|
1467
|
+
if sent {
|
|
1468
|
+
Ok(())
|
|
1469
|
+
} else {
|
|
1470
|
+
Err(self.last_error())
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
pub fn create_wgpu_view(&self, options: WGPUViewOptions) -> Result<u32, String> {
|
|
1475
|
+
let wgpu_view_id = unsafe {
|
|
1476
|
+
(self.symbols.create_wgpu_view)(
|
|
1477
|
+
options.window_id,
|
|
1478
|
+
options.frame.x,
|
|
1479
|
+
options.frame.y,
|
|
1480
|
+
options.frame.width,
|
|
1481
|
+
options.frame.height,
|
|
1482
|
+
options.auto_resize,
|
|
1483
|
+
options.start_transparent,
|
|
1484
|
+
options.start_passthrough,
|
|
1485
|
+
)
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
if wgpu_view_id == 0 {
|
|
1489
|
+
return Err(self.last_error());
|
|
1490
|
+
}
|
|
1491
|
+
Ok(wgpu_view_id)
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
pub fn set_wgpu_view_frame(&self, wgpu_view_id: u32, frame: Rect) -> Result<(), String> {
|
|
1495
|
+
unsafe {
|
|
1496
|
+
(self.symbols.set_wgpu_view_frame)(
|
|
1497
|
+
wgpu_view_id,
|
|
1498
|
+
frame.x,
|
|
1499
|
+
frame.y,
|
|
1500
|
+
frame.width,
|
|
1501
|
+
frame.height,
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
self.ensure_last_call_succeeded()
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
pub fn resize_wgpu_view(
|
|
1508
|
+
&self,
|
|
1509
|
+
wgpu_view_id: u32,
|
|
1510
|
+
frame: Rect,
|
|
1511
|
+
masks_json: &str,
|
|
1512
|
+
) -> Result<(), String> {
|
|
1513
|
+
let masks_json = to_c_string(masks_json, "WGPU resize masks json")?;
|
|
1514
|
+
unsafe {
|
|
1515
|
+
(self.symbols.resize_wgpu_view)(
|
|
1516
|
+
wgpu_view_id,
|
|
1517
|
+
frame.x,
|
|
1518
|
+
frame.y,
|
|
1519
|
+
frame.width,
|
|
1520
|
+
frame.height,
|
|
1521
|
+
masks_json.as_ptr(),
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1524
|
+
self.ensure_last_call_succeeded()
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
pub fn set_wgpu_view_transparent(
|
|
1528
|
+
&self,
|
|
1529
|
+
wgpu_view_id: u32,
|
|
1530
|
+
transparent: bool,
|
|
1531
|
+
) -> Result<(), String> {
|
|
1532
|
+
unsafe {
|
|
1533
|
+
(self.symbols.set_wgpu_view_transparent)(wgpu_view_id, transparent);
|
|
1534
|
+
}
|
|
1535
|
+
self.ensure_last_call_succeeded()
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
pub fn set_wgpu_view_passthrough(
|
|
1539
|
+
&self,
|
|
1540
|
+
wgpu_view_id: u32,
|
|
1541
|
+
passthrough: bool,
|
|
1542
|
+
) -> Result<(), String> {
|
|
1543
|
+
unsafe {
|
|
1544
|
+
(self.symbols.set_wgpu_view_passthrough)(wgpu_view_id, passthrough);
|
|
1545
|
+
}
|
|
1546
|
+
self.ensure_last_call_succeeded()
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
pub fn set_wgpu_view_hidden(&self, wgpu_view_id: u32, hidden: bool) -> Result<(), String> {
|
|
1550
|
+
unsafe {
|
|
1551
|
+
(self.symbols.set_wgpu_view_hidden)(wgpu_view_id, hidden);
|
|
1552
|
+
}
|
|
1553
|
+
self.ensure_last_call_succeeded()
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
pub fn remove_wgpu_view(&self, wgpu_view_id: u32) -> Result<(), String> {
|
|
1557
|
+
unsafe {
|
|
1558
|
+
(self.symbols.remove_wgpu_view)(wgpu_view_id);
|
|
1559
|
+
}
|
|
1560
|
+
self.ensure_last_call_succeeded()
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
pub fn get_wgpu_view_pointer(&self, wgpu_view_id: u32) -> Result<*mut c_void, String> {
|
|
1564
|
+
let ptr = unsafe { (self.symbols.get_wgpu_view_pointer)(wgpu_view_id) };
|
|
1565
|
+
self.ensure_last_call_succeeded()?;
|
|
1566
|
+
Ok(ptr)
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
pub fn get_wgpu_view_native_handle(&self, wgpu_view_id: u32) -> Result<*mut c_void, String> {
|
|
1570
|
+
let ptr = unsafe { (self.symbols.get_wgpu_view_native_handle)(wgpu_view_id) };
|
|
1571
|
+
self.ensure_last_call_succeeded()?;
|
|
1572
|
+
Ok(ptr)
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
pub fn run_wgpu_view_test(&self, wgpu_view_id: u32) -> Result<(), String> {
|
|
1576
|
+
unsafe {
|
|
1577
|
+
(self.symbols.run_wgpu_view_test)(wgpu_view_id);
|
|
1578
|
+
}
|
|
1579
|
+
self.ensure_last_call_succeeded()
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
pub fn toggle_wgpu_view_test_shader(&self, wgpu_view_id: u32) -> Result<(), String> {
|
|
1583
|
+
unsafe {
|
|
1584
|
+
(self.symbols.toggle_wgpu_view_test_shader)(wgpu_view_id);
|
|
1585
|
+
}
|
|
1586
|
+
self.ensure_last_call_succeeded()
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
pub fn close_window(&self, window_id: u32) -> Result<(), String> {
|
|
1590
|
+
unsafe {
|
|
1591
|
+
(self.symbols.close_window)(window_id);
|
|
1592
|
+
}
|
|
1593
|
+
self.ensure_last_call_succeeded()
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
pub fn evaluate_javascript_with_no_completion(
|
|
1597
|
+
&self,
|
|
1598
|
+
webview_id: u32,
|
|
1599
|
+
js: &str,
|
|
1600
|
+
) -> Result<(), String> {
|
|
1601
|
+
let js = to_c_string(js, "javascript")?;
|
|
1602
|
+
unsafe {
|
|
1603
|
+
(self.symbols.evaluate_javascript_with_no_completion)(webview_id, js.as_ptr());
|
|
1604
|
+
}
|
|
1605
|
+
self.ensure_last_call_succeeded()
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
pub fn send_host_message_to_webview_json(
|
|
1609
|
+
&self,
|
|
1610
|
+
webview_id: u32,
|
|
1611
|
+
message_json: &str,
|
|
1612
|
+
) -> Result<(), String> {
|
|
1613
|
+
let message_json_c = to_c_string(message_json, "host message json")?;
|
|
1614
|
+
let sent = unsafe {
|
|
1615
|
+
(self.symbols.send_host_message_to_webview_via_transport)(
|
|
1616
|
+
webview_id,
|
|
1617
|
+
message_json_c.as_ptr(),
|
|
1618
|
+
)
|
|
1619
|
+
};
|
|
1620
|
+
if sent {
|
|
1621
|
+
return Ok(());
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
let js = format!("window.__electrobun.receiveMessageFromHost({message_json});");
|
|
1625
|
+
self.evaluate_javascript_with_no_completion(webview_id, &js)
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
pub fn pop_next_queued_host_message_string(&self) -> Option<(u32, String)> {
|
|
1629
|
+
let mut webview_id = 0_u32;
|
|
1630
|
+
let message_ptr =
|
|
1631
|
+
unsafe { (self.symbols.pop_next_queued_host_message)(&mut webview_id as *mut u32) };
|
|
1632
|
+
if message_ptr.is_null() {
|
|
1633
|
+
return None;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
let message = unsafe { CStr::from_ptr(message_ptr).to_string_lossy().into_owned() };
|
|
1637
|
+
unsafe {
|
|
1638
|
+
(self.symbols.free_core_string)(message_ptr);
|
|
1639
|
+
}
|
|
1640
|
+
Some((webview_id, message))
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
pub fn create_tray(&self, options: TrayOptions<'_>) -> Result<u32, String> {
|
|
1644
|
+
let title = to_c_string(options.title, "tray title")?;
|
|
1645
|
+
let image = to_c_string(options.image, "tray image")?;
|
|
1646
|
+
let tray_id = unsafe {
|
|
1647
|
+
(self.symbols.create_tray)(
|
|
1648
|
+
title.as_ptr(),
|
|
1649
|
+
image.as_ptr(),
|
|
1650
|
+
options.is_template,
|
|
1651
|
+
options.width,
|
|
1652
|
+
options.height,
|
|
1653
|
+
None,
|
|
1654
|
+
)
|
|
1655
|
+
};
|
|
1656
|
+
if tray_id == 0 {
|
|
1657
|
+
return Err(self.last_error());
|
|
1658
|
+
}
|
|
1659
|
+
Ok(tray_id)
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
pub fn show_tray(&self, tray_id: u32) -> Result<(), String> {
|
|
1663
|
+
let ok = unsafe { (self.symbols.show_tray)(tray_id) };
|
|
1664
|
+
if ok {
|
|
1665
|
+
Ok(())
|
|
1666
|
+
} else {
|
|
1667
|
+
Err(self.last_error())
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
pub fn hide_tray(&self, tray_id: u32) -> Result<(), String> {
|
|
1672
|
+
unsafe {
|
|
1673
|
+
(self.symbols.hide_tray)(tray_id);
|
|
1674
|
+
}
|
|
1675
|
+
self.ensure_last_call_succeeded()
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
pub fn set_tray_title(&self, tray_id: u32, title: &str) -> Result<(), String> {
|
|
1679
|
+
let title = to_c_string(title, "tray title")?;
|
|
1680
|
+
unsafe {
|
|
1681
|
+
(self.symbols.set_tray_title)(tray_id, title.as_ptr());
|
|
1682
|
+
}
|
|
1683
|
+
self.ensure_last_call_succeeded()
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
pub fn remove_tray(&self, tray_id: u32) -> Result<(), String> {
|
|
1687
|
+
unsafe {
|
|
1688
|
+
(self.symbols.remove_tray)(tray_id);
|
|
1689
|
+
}
|
|
1690
|
+
self.ensure_last_call_succeeded()
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
pub fn get_tray_bounds(&self, tray_id: u32) -> Result<Rect, String> {
|
|
1694
|
+
let ptr = unsafe { (self.symbols.get_tray_bounds)(tray_id) };
|
|
1695
|
+
if ptr.is_null() {
|
|
1696
|
+
return Err(self.last_error());
|
|
1697
|
+
}
|
|
1698
|
+
let json = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1699
|
+
Ok(parse_rect_json(&json))
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
pub fn set_dock_icon_visible(&self, visible: bool) -> Result<(), String> {
|
|
1703
|
+
unsafe {
|
|
1704
|
+
(self.symbols.set_dock_icon_visible)(visible);
|
|
1705
|
+
}
|
|
1706
|
+
self.ensure_last_call_succeeded()
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
pub fn is_dock_icon_visible(&self) -> bool {
|
|
1710
|
+
unsafe { (self.symbols.is_dock_icon_visible)() }
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
pub fn get_primary_display(&self) -> Result<Display, String> {
|
|
1714
|
+
let ptr = unsafe { (self.symbols.get_primary_display)() };
|
|
1715
|
+
if ptr.is_null() {
|
|
1716
|
+
return Err(self.last_error());
|
|
1717
|
+
}
|
|
1718
|
+
let json = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1719
|
+
Ok(parse_display_json(&json))
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
pub fn get_all_displays(&self) -> Result<Vec<Display>, String> {
|
|
1723
|
+
let ptr = unsafe { (self.symbols.get_all_displays)() };
|
|
1724
|
+
if ptr.is_null() {
|
|
1725
|
+
return Err(self.last_error());
|
|
1726
|
+
}
|
|
1727
|
+
let json = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1728
|
+
Ok(parse_display_array_json(&json))
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
pub fn get_cursor_screen_point(&self) -> Result<Point, String> {
|
|
1732
|
+
let ptr = unsafe { (self.symbols.get_cursor_screen_point)() };
|
|
1733
|
+
if ptr.is_null() {
|
|
1734
|
+
return Err(self.last_error());
|
|
1735
|
+
}
|
|
1736
|
+
let json = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1737
|
+
Ok(parse_point_json(&json))
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
pub fn move_to_trash(&self, path: &str) -> Result<bool, String> {
|
|
1741
|
+
let path = to_c_string(path, "path")?;
|
|
1742
|
+
Ok(unsafe { (self.symbols.move_to_trash)(path.as_ptr()) })
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
pub fn show_item_in_folder(&self, path: &str) -> Result<(), String> {
|
|
1746
|
+
let path = to_c_string(path, "path")?;
|
|
1747
|
+
unsafe {
|
|
1748
|
+
(self.symbols.show_item_in_folder)(path.as_ptr());
|
|
1749
|
+
}
|
|
1750
|
+
self.ensure_last_call_succeeded()
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
pub fn open_external(&self, url: &str) -> Result<bool, String> {
|
|
1754
|
+
let url = to_c_string(url, "url")?;
|
|
1755
|
+
Ok(unsafe { (self.symbols.open_external)(url.as_ptr()) })
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
pub fn open_path(&self, path: &str) -> Result<bool, String> {
|
|
1759
|
+
let path = to_c_string(path, "path")?;
|
|
1760
|
+
Ok(unsafe { (self.symbols.open_path)(path.as_ptr()) })
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
pub fn show_notification(&self, options: NotificationOptions<'_>) -> Result<(), String> {
|
|
1764
|
+
let title = to_c_string(options.title, "notification title")?;
|
|
1765
|
+
let body = to_c_string(options.body, "notification body")?;
|
|
1766
|
+
let subtitle = to_c_string(options.subtitle, "notification subtitle")?;
|
|
1767
|
+
unsafe {
|
|
1768
|
+
(self.symbols.show_notification)(
|
|
1769
|
+
title.as_ptr(),
|
|
1770
|
+
body.as_ptr(),
|
|
1771
|
+
subtitle.as_ptr(),
|
|
1772
|
+
options.silent,
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
self.ensure_last_call_succeeded()
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
pub fn clipboard_read_text(&self) -> Result<Option<String>, String> {
|
|
1779
|
+
let ptr = unsafe { (self.symbols.clipboard_read_text)() };
|
|
1780
|
+
if ptr.is_null() {
|
|
1781
|
+
return Ok(None);
|
|
1782
|
+
}
|
|
1783
|
+
let text = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1784
|
+
Ok(Some(text))
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
pub fn clipboard_write_text(&self, text: &str) -> Result<(), String> {
|
|
1788
|
+
let text = to_c_string(text, "clipboard text")?;
|
|
1789
|
+
unsafe {
|
|
1790
|
+
(self.symbols.clipboard_write_text)(text.as_ptr());
|
|
1791
|
+
}
|
|
1792
|
+
self.ensure_last_call_succeeded()
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
pub fn clipboard_clear(&self) -> Result<(), String> {
|
|
1796
|
+
unsafe {
|
|
1797
|
+
(self.symbols.clipboard_clear)();
|
|
1798
|
+
}
|
|
1799
|
+
self.ensure_last_call_succeeded()
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
pub fn clipboard_available_formats_csv(&self) -> Result<String, String> {
|
|
1803
|
+
let ptr = unsafe { (self.symbols.clipboard_available_formats)() };
|
|
1804
|
+
if ptr.is_null() {
|
|
1805
|
+
return Ok(String::new());
|
|
1806
|
+
}
|
|
1807
|
+
let formats = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1808
|
+
Ok(formats)
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
pub fn set_application_menu_json(
|
|
1812
|
+
&self,
|
|
1813
|
+
menu_json: &str,
|
|
1814
|
+
handler: Option<StatusItemHandler>,
|
|
1815
|
+
) -> Result<(), String> {
|
|
1816
|
+
let menu_json = to_c_string(menu_json, "application menu json")?;
|
|
1817
|
+
unsafe {
|
|
1818
|
+
(self.symbols.set_application_menu)(menu_json.as_ptr(), handler);
|
|
1819
|
+
}
|
|
1820
|
+
self.ensure_last_call_succeeded()
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
pub fn show_context_menu_json(
|
|
1824
|
+
&self,
|
|
1825
|
+
menu_json: &str,
|
|
1826
|
+
handler: Option<StatusItemHandler>,
|
|
1827
|
+
) -> Result<(), String> {
|
|
1828
|
+
let menu_json = to_c_string(menu_json, "context menu json")?;
|
|
1829
|
+
unsafe {
|
|
1830
|
+
(self.symbols.show_context_menu)(menu_json.as_ptr(), handler);
|
|
1831
|
+
}
|
|
1832
|
+
self.ensure_last_call_succeeded()
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
pub fn open_file_dialog(&self, options: OpenFileDialogOptions<'_>) -> Result<String, String> {
|
|
1836
|
+
let starting_folder = to_c_string(options.starting_folder, "starting folder")?;
|
|
1837
|
+
let allowed_file_types = to_c_string(options.allowed_file_types, "allowed file types")?;
|
|
1838
|
+
let ptr = unsafe {
|
|
1839
|
+
(self.symbols.open_file_dialog)(
|
|
1840
|
+
starting_folder.as_ptr(),
|
|
1841
|
+
allowed_file_types.as_ptr(),
|
|
1842
|
+
if options.can_choose_files { 1 } else { 0 },
|
|
1843
|
+
if options.can_choose_directory { 1 } else { 0 },
|
|
1844
|
+
if options.allows_multiple_selection {
|
|
1845
|
+
1
|
|
1846
|
+
} else {
|
|
1847
|
+
0
|
|
1848
|
+
},
|
|
1849
|
+
)
|
|
1850
|
+
};
|
|
1851
|
+
if ptr.is_null() {
|
|
1852
|
+
return Ok(String::new());
|
|
1853
|
+
}
|
|
1854
|
+
let value = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1855
|
+
Ok(value)
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
pub fn show_message_box(&self, options: MessageBoxOptions<'_>) -> Result<c_int, String> {
|
|
1859
|
+
let box_type = to_c_string(options.box_type, "message box type")?;
|
|
1860
|
+
let title = to_c_string(options.title, "message box title")?;
|
|
1861
|
+
let message = to_c_string(options.message, "message box message")?;
|
|
1862
|
+
let detail = to_c_string(options.detail, "message box detail")?;
|
|
1863
|
+
let buttons_joined = options.buttons.join(",");
|
|
1864
|
+
let buttons = to_c_string(&buttons_joined, "message box buttons")?;
|
|
1865
|
+
let response = unsafe {
|
|
1866
|
+
(self.symbols.show_message_box)(
|
|
1867
|
+
box_type.as_ptr(),
|
|
1868
|
+
title.as_ptr(),
|
|
1869
|
+
message.as_ptr(),
|
|
1870
|
+
detail.as_ptr(),
|
|
1871
|
+
buttons.as_ptr(),
|
|
1872
|
+
options.default_id,
|
|
1873
|
+
options.cancel_id,
|
|
1874
|
+
)
|
|
1875
|
+
};
|
|
1876
|
+
self.ensure_last_call_succeeded()?;
|
|
1877
|
+
Ok(response)
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
pub fn set_global_shortcut_callback(
|
|
1881
|
+
&self,
|
|
1882
|
+
callback: Option<GlobalShortcutHandler>,
|
|
1883
|
+
) -> Result<(), String> {
|
|
1884
|
+
unsafe {
|
|
1885
|
+
(self.symbols.set_global_shortcut_callback)(callback);
|
|
1886
|
+
}
|
|
1887
|
+
self.ensure_last_call_succeeded()
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
pub fn register_global_shortcut(&self, accelerator: &str) -> Result<bool, String> {
|
|
1891
|
+
let accelerator = to_c_string(accelerator, "accelerator")?;
|
|
1892
|
+
Ok(unsafe { (self.symbols.register_global_shortcut)(accelerator.as_ptr()) })
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
pub fn unregister_global_shortcut(&self, accelerator: &str) -> Result<bool, String> {
|
|
1896
|
+
let accelerator = to_c_string(accelerator, "accelerator")?;
|
|
1897
|
+
Ok(unsafe { (self.symbols.unregister_global_shortcut)(accelerator.as_ptr()) })
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
pub fn unregister_all_global_shortcuts(&self) -> Result<(), String> {
|
|
1901
|
+
unsafe {
|
|
1902
|
+
(self.symbols.unregister_all_global_shortcuts)();
|
|
1903
|
+
}
|
|
1904
|
+
self.ensure_last_call_succeeded()
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
pub fn is_global_shortcut_registered(&self, accelerator: &str) -> Result<bool, String> {
|
|
1908
|
+
let accelerator = to_c_string(accelerator, "accelerator")?;
|
|
1909
|
+
Ok(unsafe { (self.symbols.is_global_shortcut_registered)(accelerator.as_ptr()) })
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
pub fn session_get_cookies(
|
|
1913
|
+
&self,
|
|
1914
|
+
partition: &str,
|
|
1915
|
+
filter_json: &str,
|
|
1916
|
+
) -> Result<String, String> {
|
|
1917
|
+
let partition = to_c_string(partition, "session partition")?;
|
|
1918
|
+
let filter_json = to_c_string(filter_json, "cookie filter json")?;
|
|
1919
|
+
let ptr =
|
|
1920
|
+
unsafe { (self.symbols.session_get_cookies)(partition.as_ptr(), filter_json.as_ptr()) };
|
|
1921
|
+
if ptr.is_null() {
|
|
1922
|
+
return Ok("[]".to_string());
|
|
1923
|
+
}
|
|
1924
|
+
let json = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
|
|
1925
|
+
Ok(json)
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
pub fn session_set_cookie(&self, partition: &str, cookie_json: &str) -> Result<bool, String> {
|
|
1929
|
+
let partition = to_c_string(partition, "session partition")?;
|
|
1930
|
+
let cookie_json = to_c_string(cookie_json, "cookie json")?;
|
|
1931
|
+
Ok(unsafe { (self.symbols.session_set_cookie)(partition.as_ptr(), cookie_json.as_ptr()) })
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
pub fn session_remove_cookie(
|
|
1935
|
+
&self,
|
|
1936
|
+
partition: &str,
|
|
1937
|
+
url: &str,
|
|
1938
|
+
name: &str,
|
|
1939
|
+
) -> Result<bool, String> {
|
|
1940
|
+
let partition = to_c_string(partition, "session partition")?;
|
|
1941
|
+
let url = to_c_string(url, "cookie url")?;
|
|
1942
|
+
let name = to_c_string(name, "cookie name")?;
|
|
1943
|
+
Ok(unsafe {
|
|
1944
|
+
(self.symbols.session_remove_cookie)(partition.as_ptr(), url.as_ptr(), name.as_ptr())
|
|
1945
|
+
})
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
pub fn session_clear_cookies(&self, partition: &str) -> Result<(), String> {
|
|
1949
|
+
let partition = to_c_string(partition, "session partition")?;
|
|
1950
|
+
unsafe {
|
|
1951
|
+
(self.symbols.session_clear_cookies)(partition.as_ptr());
|
|
1952
|
+
}
|
|
1953
|
+
self.ensure_last_call_succeeded()
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
pub fn session_clear_storage_data(
|
|
1957
|
+
&self,
|
|
1958
|
+
partition: &str,
|
|
1959
|
+
storage_types_json: &str,
|
|
1960
|
+
) -> Result<(), String> {
|
|
1961
|
+
let partition = to_c_string(partition, "session partition")?;
|
|
1962
|
+
let storage_types_json = to_c_string(storage_types_json, "storage types json")?;
|
|
1963
|
+
unsafe {
|
|
1964
|
+
(self.symbols.session_clear_storage_data)(
|
|
1965
|
+
partition.as_ptr(),
|
|
1966
|
+
storage_types_json.as_ptr(),
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
self.ensure_last_call_succeeded()
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
pub fn set_url_open_handler(&self, handler: Option<URLOpenHandler>) -> Result<(), String> {
|
|
1973
|
+
unsafe {
|
|
1974
|
+
(self.symbols.set_url_open_handler)(handler);
|
|
1975
|
+
}
|
|
1976
|
+
self.ensure_last_call_succeeded()
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
pub fn set_app_reopen_handler(&self, handler: Option<AppReopenHandler>) -> Result<(), String> {
|
|
1980
|
+
unsafe {
|
|
1981
|
+
(self.symbols.set_app_reopen_handler)(handler);
|
|
1982
|
+
}
|
|
1983
|
+
self.ensure_last_call_succeeded()
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
pub fn set_quit_requested_handler(
|
|
1987
|
+
&self,
|
|
1988
|
+
handler: Option<QuitRequestedHandler>,
|
|
1989
|
+
) -> Result<(), String> {
|
|
1990
|
+
unsafe {
|
|
1991
|
+
(self.symbols.set_quit_requested_handler)(handler);
|
|
1992
|
+
}
|
|
1993
|
+
self.ensure_last_call_succeeded()
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
pub fn stop_event_loop(&self) -> Result<(), String> {
|
|
1997
|
+
unsafe {
|
|
1998
|
+
(self.symbols.stop_event_loop)();
|
|
1999
|
+
}
|
|
2000
|
+
self.ensure_last_call_succeeded()
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
pub fn wait_for_shutdown_complete(&self, timeout_ms: c_int) -> Result<(), String> {
|
|
2004
|
+
unsafe {
|
|
2005
|
+
(self.symbols.wait_for_shutdown_complete)(timeout_ms);
|
|
2006
|
+
}
|
|
2007
|
+
self.ensure_last_call_succeeded()
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
pub fn force_exit(&self, code: c_int) -> ! {
|
|
2011
|
+
unsafe {
|
|
2012
|
+
(self.symbols.force_exit)(code);
|
|
2013
|
+
}
|
|
2014
|
+
std::process::exit(code);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
pub fn wgpu_create_surface_for_view(
|
|
2018
|
+
&self,
|
|
2019
|
+
instance: *mut c_void,
|
|
2020
|
+
view: *mut c_void,
|
|
2021
|
+
) -> Result<*mut c_void, String> {
|
|
2022
|
+
let surface = unsafe { (self.symbols.wgpu_create_surface_for_view)(instance, view) };
|
|
2023
|
+
if surface.is_null() {
|
|
2024
|
+
Err(self.last_error())
|
|
2025
|
+
} else {
|
|
2026
|
+
Ok(surface)
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
pub fn wgpu_create_adapter_device_main_thread(
|
|
2031
|
+
&self,
|
|
2032
|
+
instance: *mut c_void,
|
|
2033
|
+
surface: *mut c_void,
|
|
2034
|
+
) -> Result<WgpuAdapterDevice, String> {
|
|
2035
|
+
let mut adapter_device = [0_usize; 2];
|
|
2036
|
+
unsafe {
|
|
2037
|
+
(self.symbols.wgpu_create_adapter_device_main_thread)(
|
|
2038
|
+
instance,
|
|
2039
|
+
surface,
|
|
2040
|
+
adapter_device.as_mut_ptr() as *mut c_void,
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
let adapter = adapter_device[0] as *mut c_void;
|
|
2044
|
+
let device = adapter_device[1] as *mut c_void;
|
|
2045
|
+
if device.is_null() {
|
|
2046
|
+
Err(self.last_error())
|
|
2047
|
+
} else {
|
|
2048
|
+
Ok(WgpuAdapterDevice { adapter, device })
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
pub fn wgpu_surface_configure_main_thread(
|
|
2053
|
+
&self,
|
|
2054
|
+
surface: *mut c_void,
|
|
2055
|
+
config: *mut c_void,
|
|
2056
|
+
) -> Result<(), String> {
|
|
2057
|
+
unsafe {
|
|
2058
|
+
(self.symbols.wgpu_surface_configure_main_thread)(surface, config);
|
|
2059
|
+
}
|
|
2060
|
+
self.ensure_last_call_succeeded()
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
pub fn wgpu_surface_get_current_texture_main_thread(
|
|
2064
|
+
&self,
|
|
2065
|
+
surface: *mut c_void,
|
|
2066
|
+
surface_texture: *mut c_void,
|
|
2067
|
+
) -> Result<(), String> {
|
|
2068
|
+
unsafe {
|
|
2069
|
+
(self.symbols.wgpu_surface_get_current_texture_main_thread)(surface, surface_texture);
|
|
2070
|
+
}
|
|
2071
|
+
self.ensure_last_call_succeeded()
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
pub fn wgpu_surface_present_main_thread(&self, surface: *mut c_void) -> Result<c_int, String> {
|
|
2075
|
+
let status = unsafe { (self.symbols.wgpu_surface_present_main_thread)(surface) };
|
|
2076
|
+
self.ensure_last_call_succeeded()?;
|
|
2077
|
+
Ok(status)
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
pub fn run_main_thread(&self, app_info: &AppInfo) -> Result<(), String> {
|
|
2081
|
+
let identifier = to_c_string(&app_info.identifier, "app identifier")?;
|
|
2082
|
+
let name = to_c_string(&app_info.name, "app name")?;
|
|
2083
|
+
let channel = to_c_string(&app_info.channel, "app channel")?;
|
|
2084
|
+
let status = unsafe {
|
|
2085
|
+
(self.symbols.run_main_thread)(identifier.as_ptr(), name.as_ptr(), channel.as_ptr(), 0)
|
|
2086
|
+
};
|
|
2087
|
+
if status != 0 {
|
|
2088
|
+
return Err(self.last_error());
|
|
2089
|
+
}
|
|
2090
|
+
Ok(())
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
fn ensure_last_call_succeeded(&self) -> Result<(), String> {
|
|
2094
|
+
let message = self.last_error();
|
|
2095
|
+
if message.is_empty() {
|
|
2096
|
+
Ok(())
|
|
2097
|
+
} else {
|
|
2098
|
+
Err(message)
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
fn last_error(&self) -> String {
|
|
2103
|
+
let ptr = unsafe { (self.symbols.last_error)() };
|
|
2104
|
+
if ptr.is_null() {
|
|
2105
|
+
return String::new();
|
|
2106
|
+
}
|
|
2107
|
+
unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
fn core_library_name() -> &'static str {
|
|
2112
|
+
if cfg!(windows) {
|
|
2113
|
+
"ElectrobunCore.dll"
|
|
2114
|
+
} else if cfg!(target_os = "macos") {
|
|
2115
|
+
"libElectrobunCore.dylib"
|
|
2116
|
+
} else {
|
|
2117
|
+
"libElectrobunCore.so"
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
fn wgpu_library_name() -> &'static str {
|
|
2122
|
+
if cfg!(windows) {
|
|
2123
|
+
"webgpu_dawn.dll"
|
|
2124
|
+
} else if cfg!(target_os = "macos") {
|
|
2125
|
+
"libwebgpu_dawn.dylib"
|
|
2126
|
+
} else {
|
|
2127
|
+
"libwebgpu_dawn.so"
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
fn to_c_string(value: &str, label: &str) -> Result<CString, String> {
|
|
2132
|
+
CString::new(value).map_err(|_| format!("{label} contains an interior null byte"))
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
pub extern "C" fn allow_all_navigation(_: u32, _: *const c_char) -> u32 {
|
|
2136
|
+
1
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
pub extern "C" fn noop_webview_event(_: u32, _: *const c_char, _: *const c_char) {}
|
|
2140
|
+
|
|
2141
|
+
pub extern "C" fn noop_webview_post_message(_: u32, _: *const c_char) {}
|
|
2142
|
+
|
|
2143
|
+
pub fn c_string_to_string(value: *const c_char) -> String {
|
|
2144
|
+
if value.is_null() {
|
|
2145
|
+
return String::new();
|
|
2146
|
+
}
|
|
2147
|
+
unsafe { CStr::from_ptr(value).to_string_lossy().into_owned() }
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
pub fn json_string_literal(value: &str) -> String {
|
|
2151
|
+
let mut out = String::with_capacity(value.len() + 2);
|
|
2152
|
+
out.push('"');
|
|
2153
|
+
for ch in value.chars() {
|
|
2154
|
+
match ch {
|
|
2155
|
+
'"' => out.push_str("\\\""),
|
|
2156
|
+
'\\' => out.push_str("\\\\"),
|
|
2157
|
+
'\n' => out.push_str("\\n"),
|
|
2158
|
+
'\r' => out.push_str("\\r"),
|
|
2159
|
+
'\t' => out.push_str("\\t"),
|
|
2160
|
+
ch if ch < ' ' => out.push_str(&format!("\\u{:04x}", ch as u32)),
|
|
2161
|
+
ch => out.push(ch),
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
out.push('"');
|
|
2165
|
+
out
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
pub fn json_string_field(source: &str, key: &str) -> Option<String> {
|
|
2169
|
+
let needle = format!("\"{key}\"");
|
|
2170
|
+
let key_index = source.find(&needle)?;
|
|
2171
|
+
let after_key = &source[key_index + needle.len()..];
|
|
2172
|
+
let colon_index = after_key.find(':')?;
|
|
2173
|
+
let after_colon = after_key[colon_index + 1..].trim_start();
|
|
2174
|
+
let mut chars = after_colon.char_indices();
|
|
2175
|
+
let (_, first) = chars.next()?;
|
|
2176
|
+
if first != '"' {
|
|
2177
|
+
return None;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
let mut value = String::new();
|
|
2181
|
+
let mut escaped = false;
|
|
2182
|
+
for (_, ch) in chars {
|
|
2183
|
+
if escaped {
|
|
2184
|
+
match ch {
|
|
2185
|
+
'"' => value.push('"'),
|
|
2186
|
+
'\\' => value.push('\\'),
|
|
2187
|
+
'/' => value.push('/'),
|
|
2188
|
+
'b' => value.push('\u{0008}'),
|
|
2189
|
+
'f' => value.push('\u{000c}'),
|
|
2190
|
+
'n' => value.push('\n'),
|
|
2191
|
+
'r' => value.push('\r'),
|
|
2192
|
+
't' => value.push('\t'),
|
|
2193
|
+
'u' => {
|
|
2194
|
+
return None;
|
|
2195
|
+
}
|
|
2196
|
+
other => value.push(other),
|
|
2197
|
+
}
|
|
2198
|
+
escaped = false;
|
|
2199
|
+
continue;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
match ch {
|
|
2203
|
+
'\\' => escaped = true,
|
|
2204
|
+
'"' => return Some(value),
|
|
2205
|
+
other => value.push(other),
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
None
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
pub fn json_number_field(source: &str, key: &str) -> Option<f64> {
|
|
2213
|
+
let needle = format!("\"{key}\"");
|
|
2214
|
+
let key_index = source.find(&needle)?;
|
|
2215
|
+
let after_key = &source[key_index + needle.len()..];
|
|
2216
|
+
let colon_index = after_key.find(':')?;
|
|
2217
|
+
let after_colon = after_key[colon_index + 1..].trim_start();
|
|
2218
|
+
let number: String = after_colon
|
|
2219
|
+
.chars()
|
|
2220
|
+
.take_while(|ch| ch.is_ascii_digit() || matches!(ch, '-' | '+' | '.' | 'e' | 'E'))
|
|
2221
|
+
.collect();
|
|
2222
|
+
number.parse().ok()
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
pub fn json_bool_field(source: &str, key: &str) -> Option<bool> {
|
|
2226
|
+
let needle = format!("\"{key}\"");
|
|
2227
|
+
let key_index = source.find(&needle)?;
|
|
2228
|
+
let after_key = &source[key_index + needle.len()..];
|
|
2229
|
+
let colon_index = after_key.find(':')?;
|
|
2230
|
+
let after_colon = after_key[colon_index + 1..].trim_start();
|
|
2231
|
+
if after_colon.starts_with("true") {
|
|
2232
|
+
Some(true)
|
|
2233
|
+
} else if after_colon.starts_with("false") {
|
|
2234
|
+
Some(false)
|
|
2235
|
+
} else {
|
|
2236
|
+
None
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
fn parse_rect_json(json: &str) -> Rect {
|
|
2241
|
+
Rect {
|
|
2242
|
+
x: json_number_field(json, "x").unwrap_or_default(),
|
|
2243
|
+
y: json_number_field(json, "y").unwrap_or_default(),
|
|
2244
|
+
width: json_number_field(json, "width").unwrap_or_default(),
|
|
2245
|
+
height: json_number_field(json, "height").unwrap_or_default(),
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
fn parse_point_json(json: &str) -> Point {
|
|
2250
|
+
Point {
|
|
2251
|
+
x: json_number_field(json, "x").unwrap_or_default(),
|
|
2252
|
+
y: json_number_field(json, "y").unwrap_or_default(),
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
fn parse_display_json(json: &str) -> Display {
|
|
2257
|
+
let bounds = extract_object_field(json, "bounds")
|
|
2258
|
+
.map(|value| parse_rect_json(value))
|
|
2259
|
+
.unwrap_or_default();
|
|
2260
|
+
let work_area = extract_object_field(json, "workArea")
|
|
2261
|
+
.map(|value| parse_rect_json(value))
|
|
2262
|
+
.unwrap_or_default();
|
|
2263
|
+
Display {
|
|
2264
|
+
id: json_number_field(json, "id").unwrap_or_default() as i64,
|
|
2265
|
+
bounds,
|
|
2266
|
+
work_area,
|
|
2267
|
+
scale_factor: json_number_field(json, "scaleFactor").unwrap_or(1.0),
|
|
2268
|
+
is_primary: json_bool_field(json, "isPrimary").unwrap_or(false),
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
fn parse_display_array_json(json: &str) -> Vec<Display> {
|
|
2273
|
+
let mut displays = Vec::new();
|
|
2274
|
+
let mut depth = 0_i32;
|
|
2275
|
+
let mut object_start: Option<usize> = None;
|
|
2276
|
+
|
|
2277
|
+
for (index, ch) in json.char_indices() {
|
|
2278
|
+
match ch {
|
|
2279
|
+
'{' => {
|
|
2280
|
+
if depth == 0 {
|
|
2281
|
+
object_start = Some(index);
|
|
2282
|
+
}
|
|
2283
|
+
depth += 1;
|
|
2284
|
+
}
|
|
2285
|
+
'}' => {
|
|
2286
|
+
depth -= 1;
|
|
2287
|
+
if depth == 0 {
|
|
2288
|
+
if let Some(start) = object_start.take() {
|
|
2289
|
+
displays.push(parse_display_json(&json[start..=index]));
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
_ => {}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
displays
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
fn extract_object_field<'a>(json: &'a str, key: &str) -> Option<&'a str> {
|
|
2301
|
+
let needle = format!("\"{key}\"");
|
|
2302
|
+
let key_index = json.find(&needle)?;
|
|
2303
|
+
let after_key = &json[key_index + needle.len()..];
|
|
2304
|
+
let colon_index = after_key.find(':')?;
|
|
2305
|
+
let after_colon_offset = key_index + needle.len() + colon_index + 1;
|
|
2306
|
+
let after_colon = json[after_colon_offset..].trim_start();
|
|
2307
|
+
let trim_offset = json[after_colon_offset..].len() - after_colon.len();
|
|
2308
|
+
let start = after_colon_offset + trim_offset;
|
|
2309
|
+
if !json[start..].starts_with('{') {
|
|
2310
|
+
return None;
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
let mut depth = 0_i32;
|
|
2314
|
+
for (relative_index, ch) in json[start..].char_indices() {
|
|
2315
|
+
match ch {
|
|
2316
|
+
'{' => depth += 1,
|
|
2317
|
+
'}' => {
|
|
2318
|
+
depth -= 1;
|
|
2319
|
+
if depth == 0 {
|
|
2320
|
+
return Some(&json[start..=start + relative_index]);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
_ => {}
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
None
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
fn home_dir() -> Result<String, String> {
|
|
2331
|
+
std::env::var(if cfg!(windows) { "USERPROFILE" } else { "HOME" })
|
|
2332
|
+
.or_else(|_| std::env::var("HOME"))
|
|
2333
|
+
.map_err(|_| "failed to resolve home directory".to_string())
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
fn temp_dir() -> String {
|
|
2337
|
+
std::env::var(if cfg!(windows) { "TEMP" } else { "TMPDIR" })
|
|
2338
|
+
.or_else(|_| std::env::var("TMP"))
|
|
2339
|
+
.unwrap_or_else(|_| if cfg!(windows) { "C:\\Temp" } else { "/tmp" }.to_string())
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
fn app_data_dir(home: &str) -> String {
|
|
2343
|
+
if cfg!(target_os = "macos") {
|
|
2344
|
+
join_path(home, "Library/Application Support")
|
|
2345
|
+
} else if cfg!(windows) {
|
|
2346
|
+
std::env::var("APPDATA").unwrap_or_else(|_| join_path(home, "AppData/Roaming"))
|
|
2347
|
+
} else {
|
|
2348
|
+
std::env::var("XDG_DATA_HOME").unwrap_or_else(|_| join_path(home, ".local/share"))
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
fn config_dir(home: &str) -> String {
|
|
2353
|
+
if cfg!(target_os = "macos") {
|
|
2354
|
+
join_path(home, "Library/Application Support")
|
|
2355
|
+
} else if cfg!(windows) {
|
|
2356
|
+
std::env::var("APPDATA").unwrap_or_else(|_| join_path(home, "AppData/Roaming"))
|
|
2357
|
+
} else {
|
|
2358
|
+
std::env::var("XDG_CONFIG_HOME").unwrap_or_else(|_| join_path(home, ".config"))
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
fn cache_dir(home: &str) -> String {
|
|
2363
|
+
if cfg!(target_os = "macos") {
|
|
2364
|
+
join_path(home, "Library/Caches")
|
|
2365
|
+
} else if cfg!(windows) {
|
|
2366
|
+
std::env::var("LOCALAPPDATA").unwrap_or_else(|_| join_path(home, "AppData/Local"))
|
|
2367
|
+
} else {
|
|
2368
|
+
std::env::var("XDG_CACHE_HOME").unwrap_or_else(|_| join_path(home, ".cache"))
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
fn logs_dir(home: &str) -> String {
|
|
2373
|
+
if cfg!(target_os = "macos") {
|
|
2374
|
+
join_path(home, "Library/Logs")
|
|
2375
|
+
} else {
|
|
2376
|
+
cache_dir(home)
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
fn user_dir(home: &str, name: &str) -> String {
|
|
2381
|
+
join_path(home, name)
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
fn join_path(base: &str, child: &str) -> String {
|
|
2385
|
+
let mut path = PathBuf::from(base);
|
|
2386
|
+
path.push(child);
|
|
2387
|
+
path.to_string_lossy().into_owned()
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
fn app_scoped_name(app_info: &AppInfo) -> String {
|
|
2391
|
+
if app_info.identifier.is_empty() {
|
|
2392
|
+
app_info.name.clone()
|
|
2393
|
+
} else {
|
|
2394
|
+
app_info.identifier.clone()
|
|
2395
|
+
}
|
|
2396
|
+
}
|