browser_window_core/browser_window/
c.rs1use super::*;
2
3use std::{
4 error::Error,
5 ffi::CStr,
6 fmt,
7 mem::MaybeUninit,
8 os::raw::*
9};
10
11use browser_window_c::*;
12
13use crate::window::WindowImpl;
14
15
16
17#[derive(Clone,Copy)]
18pub struct BrowserWindowImpl {
19 inner: *mut cbw_BrowserWindow
20}
21
22struct CreationCallbackData {
23 func: CreationCallbackFn,
24 data: *mut ()
25}
26
27struct EvalJsCallbackData {
28 callback: EvalJsCallbackFn,
29 data: *mut ()
30}
31
32#[derive(Debug)]
34pub struct JsEvaluationError {
35 message: String
36 }
38
39struct UserData {
40 func: ExternalInvocationHandlerFn,
41 data: *mut ()
42}
43
44
45impl BrowserWindowExt for BrowserWindowImpl {
46
47 fn cookie_jar(&self) -> CookieJarImpl {
48 let inner = unsafe { cbw_CookieJar_newGlobal() };
49
50 CookieJarImpl {
51 inner
52 }
53 }
54
55 fn eval_js( &self, js: &str, callback: EvalJsCallbackFn, callback_data: *mut () ) {
56 let data = Box::new( EvalJsCallbackData {
57 callback,
58 data: callback_data
59 } );
60
61 let data_ptr = Box::into_raw( data );
62
63 unsafe { cbw_BrowserWindow_evalJs( self.inner, js.into(), Some( ffi_eval_js_callback_handler ), data_ptr as _ ) }
64 }
65
66 fn eval_js_threadsafe( &self, js: &str, callback: EvalJsCallbackFn, callback_data: *mut () ) {
67 let data = Box::new( EvalJsCallbackData {
68 callback,
69 data: callback_data
70 } );
71
72 let data_ptr = Box::into_raw( data );
73
74 unsafe { cbw_BrowserWindow_evalJsThreaded( self.inner, js.into(), Some( ffi_eval_js_callback_handler ), data_ptr as _ ) }
75 }
76
77 fn navigate( &self, uri: &str ) {
78 unsafe { cbw_BrowserWindow_navigate( self.inner, uri.into() ) };
79 }
80
81 fn new(
82 app: ApplicationImpl,
83 parent: WindowImpl,
84 source: Source,
85 title: &str,
86 width: Option<u32>,
87 height: Option<u32>,
88 window_options: &WindowOptions,
89 browser_window_options: &BrowserWindowOptions,
90 handler: ExternalInvocationHandlerFn,
91 _user_data: *mut (),
92 creation_callback: CreationCallbackFn,
93 _callback_data: *mut ()
94 ) {
95 let w: c_int = match width {
98 None => -1,
99 Some(x) => x as _
100 };
101 let h: c_int = match height {
102 None => -1,
103 Some(x) => x as _
104 };
105
106 let user_data = Box::new( UserData {
108 func: handler,
109 data: _user_data
110 } );
111 let callback_data = Box::new( CreationCallbackData {
112 func: creation_callback,
113 data: _callback_data
114 } );
115
116 unsafe { cbw_BrowserWindow_new(
117 app.inner,
118 parent.inner,
119 source,
120 title.into(),
121 w, h,
122 window_options as _,
123 browser_window_options as _,
124 Some( ffi_handler ),
125 Box::into_raw( user_data ) as _,
126 Some( ffi_creation_callback_handler ),
127 Box::into_raw( callback_data ) as _
128 ) };
129 }
130
131 fn user_data( &self ) -> *mut () {
132 let c_user_data_ptr: *mut UserData = unsafe { (*self.inner).user_data as _ };
133
134 unsafe { (*c_user_data_ptr).data }
136 }
137
138 fn url<'a>(&'a self) -> Cow<'a, str> {
139 let mut slice: cbw_StrSlice = unsafe { MaybeUninit::uninit().assume_init() };
140 let owned = unsafe { cbw_BrowserWindow_getUrl(self.inner, &mut slice) };
141
142 if owned > 0 {
143 let url: String = slice.into();
144 unsafe { cbw_string_free(slice) };
145 url.into()
146 }
147 else {
148 let url: &'a str = slice.into();
149 url.into()
150 }
151 }
152
153 fn window( &self ) -> WindowImpl {
154 WindowImpl {
155 inner: unsafe { cbw_BrowserWindow_getWindow( self.inner ) }
156 }
157 }
158}
159
160
161
162impl JsEvaluationError {
163 pub(in super) unsafe fn new( err: *const cbw_Err ) -> Self {
164
165 let msg_ptr = ((*err).alloc_message.unwrap())( (*err).code, (*err).data );
166 let cstr = CStr::from_ptr( msg_ptr );
167 let message: String = cstr.to_string_lossy().into();
168
169 Self {
170 message: message
171 }
172 }
173}
174
175impl Error for JsEvaluationError {
176 fn source(&self) -> Option<&(dyn Error + 'static)> { None }
177}
178
179impl fmt::Display for JsEvaluationError {
180
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182
183 write!(f, "{}", self.message.as_str())
184 }
185}
186
187
188
189unsafe extern "C" fn ffi_creation_callback_handler( bw: *mut cbw_BrowserWindow, _data: *mut c_void ) {
194
195 let data_ptr = _data as *mut CreationCallbackData;
196 let data = Box::from_raw( data_ptr );
197
198 let handle = BrowserWindowImpl { inner: bw };
199
200 (data.func)( handle, data.data );
201}
202
203unsafe extern "C" fn ffi_eval_js_callback_handler( bw: *mut cbw_BrowserWindow, _data: *mut c_void, _result: *const c_char, error: *const cbw_Err ) {
204
205 let data_ptr = _data as *mut EvalJsCallbackData;
206 let data = Box::from_raw( data_ptr );
207
208 let (handle, result) = ffi_eval_js_callback_result( bw, _result, error );
209
210 (data.callback)( handle, data.data, result );
211}
212
213unsafe extern "C" fn ffi_handler( bw: *mut cbw_BrowserWindow, cmd: cbw_CStrSlice, args: *mut cbw_CStrSlice, arg_count: usize ) {
214
215 let handle = BrowserWindowImpl { inner: bw };
216
217 let data_ptr = (*bw).user_data as *mut UserData;
218 let data = &mut *data_ptr;
219
220 let cmd_string: &str = cmd.into();
222 let mut args_vec: Vec<String> = Vec::with_capacity( arg_count as usize );
223 for i in 0..arg_count {
224 args_vec.push( (*args.add( i as usize )).into() );
225 }
226
227 (data.func)( handle, cmd_string, args_vec );
228}
229
230unsafe fn ffi_eval_js_callback_result(
232 bw: *mut cbw_BrowserWindow,
233 result: *const c_char,
234 error: *const cbw_Err
235) -> ( BrowserWindowImpl, Result<String, JsEvaluationError> ) {
236
237
238 let result_val: Result<String, JsEvaluationError> = if error.is_null() {
240 let result_str = CStr::from_ptr( result ).to_string_lossy().to_owned().to_string();
241 Ok( result_str )
242 }
243 else {
244 Err( JsEvaluationError::new( error ) )
245 };
246
247 let handle = BrowserWindowImpl { inner: bw };
248
249 ( handle, result_val )
251}