Skip to main content

webui/
event.rs

1use std::{
2    ffi::{c_char, CStr, CString},
3    marker::PhantomData,
4    ptr::NonNull,
5};
6
7use webui_sys::*;
8
9use crate::{EventType, WebUIError, Window, CONTEXT};
10
11/// The event type.
12#[repr(transparent)]
13pub struct Event<'a> {
14    pub(crate) inner: NonNull<webui_event_t>,
15    _marker: PhantomData<&'a webui_event_t>,
16}
17
18impl<'a> Event<'a> {
19    pub(crate) unsafe fn new(ptr: *mut webui_event_t) -> Option<Self> {
20        NonNull::new(ptr).map(|inner| Self {
21            inner,
22            _marker: std::marker::PhantomData,
23        })
24    }
25
26    /// Get the event.
27    pub(crate) fn get_event(&self) -> &webui_event_t {
28        unsafe { self.inner.as_ref() }
29    }
30
31    /// Get the inner pointer.
32    pub(crate) fn as_ptr(&self) -> *mut webui_event_t {
33        self.inner.as_ptr()
34    }
35
36    /// Get the window.
37    pub fn window(&self) -> Option<Window> {
38        let window = self.get_event().window;
39        CONTEXT
40            .lock()
41            .unwrap()
42            .get(&window)
43            .and_then(|x| x.upgrade())
44            .map(|inner| Window { inner })
45    }
46
47    pub(crate) fn bind_id(&self) -> usize {
48        self.get_event().bind_id
49    }
50
51    /// Get the event type.
52    pub fn event_type(&self) -> EventType {
53        unsafe { std::mem::transmute(self.get_event().event_type) }
54    }
55
56    /// Get the element.
57    pub fn element(&self) -> String {
58        let element = self.get_event().element;
59        unsafe { CStr::from_ptr(element).to_string_lossy().to_string() }
60    }
61
62    /// Get the event number.
63    pub fn event_number(&self) -> usize {
64        self.get_event().event_number
65    }
66
67    /// Get the client ID.
68    pub fn client_id(&self) -> usize {
69        self.get_event().client_id
70    }
71
72    /// Get the connection ID.
73    pub fn connection_id(&self) -> usize {
74        self.get_event().connection_id
75    }
76
77    /// Get the cookies.
78    pub fn cookies(&self) -> Option<String> {
79        let cookies = self.get_event().cookies;
80        (!cookies.is_null()).then_some(unsafe { CStr::from_ptr(cookies).to_string_lossy().to_string() })
81    }
82
83    /// Show a window for a specific single client. Useful in multi-client mode to send different content to different connected
84    /// clients.
85    pub fn show_client(&self, content: &str) -> Result<(), WebUIError> {
86        let content = CString::new(content).unwrap();
87        let result = unsafe { webui_show_client(self.as_ptr(), content.as_ptr()) };
88        WebUIError::from_bool(result)
89    }
90
91    /// Close the connection for a specific single client only, without closing the window for other connected clients.
92    pub fn close_client(&self) {
93        unsafe { webui_close_client(self.as_ptr()) }
94    }
95
96    /// Navigate a specific single client to a URL, without affecting other connected clients.
97    pub fn navigate_client(&self, url: &str) {
98        let url = CString::new(url).unwrap();
99        unsafe { webui_navigate_client(self.as_ptr(), url.as_ptr()) }
100    }
101
102    /// Run JavaScript for a specific single client without waiting for a response.
103    pub fn run_client(&self, script: &str) {
104        let script = CString::new(script).unwrap();
105        unsafe {
106            webui_run_client(self.as_ptr(), script.as_ptr());
107        }
108    }
109
110    /// Run JavaScript for a specific single client and get the response back.
111    pub fn script_client(&self, script: &str, timeout: usize, capacity: usize) -> Result<String, WebUIError> {
112        let mut buffer: Vec<c_char> = Vec::with_capacity(capacity);
113        let script = CString::new(script).unwrap();
114        unsafe { webui_script_client(self.as_ptr(), script.as_ptr(), timeout, buffer.as_mut_ptr(), capacity) }
115            .then(|| unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_string_lossy().to_string())
116            .ok_or(WebUIError::get_last_error())
117    }
118
119    /// Get the number of arguments passed to the callback from JavaScript.
120    pub fn get_count(&self) -> usize {
121        unsafe { webui_get_count(self.as_ptr()) }
122    }
123
124    /// Get the first argument as a 64-bit integer.
125    pub fn get_int(&self) -> i64 {
126        unsafe { webui_get_int(self.as_ptr()) }
127    }
128
129    /// Get an argument as a 64-bit integer at a specific index.
130    pub fn get_int_at(&self, index: usize) -> i64 {
131        unsafe { webui_get_int_at(self.as_ptr(), index) }
132    }
133
134    /// Get the first argument as a double-precision float.
135    pub fn get_float(&self) -> f64 {
136        unsafe { webui_get_float(self.as_ptr()) }
137    }
138
139    /// Get an argument as a double-precision float at a specific index.
140    pub fn get_float_at(&self, index: usize) -> f64 {
141        unsafe { webui_get_float_at(self.as_ptr(), index) }
142    }
143
144    /// Get the first argument as a string slice.
145    pub fn get_string(&self) -> String {
146        unsafe {
147            let ptr = webui_get_string(self.as_ptr());
148            CStr::from_ptr(ptr).to_string_lossy().to_string()
149        }
150    }
151
152    /// Get an argument as a string slice at a specific index.
153    pub fn get_string_at(&self, index: usize) -> String {
154        unsafe {
155            let ptr = webui_get_string_at(self.as_ptr(), index);
156            CStr::from_ptr(ptr).to_string_lossy().to_string()
157        }
158    }
159
160    /// Get the first argument as a boolean.
161    pub fn get_bool(&self) -> bool {
162        unsafe { webui_get_bool(self.as_ptr()) }
163    }
164
165    /// Get an argument as a boolean at a specific index.
166    pub fn get_bool_at(&self, index: usize) -> bool {
167        unsafe { webui_get_bool_at(self.as_ptr(), index) }
168    }
169
170    /// Get the size in bytes of the first argument. Useful for raw binary data.
171    pub fn get_size(&self) -> usize {
172        unsafe { webui_get_size(self.as_ptr()) }
173    }
174
175    /// Get the size in bytes of an argument at a specific index.
176    pub fn get_size_at(&self, index: usize) -> usize {
177        unsafe { webui_get_size_at(self.as_ptr(), index) }
178    }
179
180    /// Return a 64-bit integer as the response to a JavaScript await call.
181    pub fn return_int(&self, value: i64) {
182        unsafe { webui_return_int(self.as_ptr(), value) }
183    }
184
185    /// Return a double-precision float as the response to a JavaScript await call.
186    pub fn return_float(&self, value: f64) {
187        unsafe { webui_return_float(self.as_ptr(), value) }
188    }
189
190    /// Return a string as the response to a JavaScript await call.
191    pub fn return_string<S: AsRef<str>>(&self, value: S) {
192        let c_str = std::ffi::CString::new(value.as_ref()).unwrap_or_default();
193        unsafe { webui_return_string(self.as_ptr(), c_str.as_ptr()) }
194    }
195
196    /// Return a boolean as the response to a JavaScript await call.
197    pub fn return_bool(&self, value: bool) {
198        unsafe { webui_return_bool(self.as_ptr(), value) }
199    }
200
201    /// Send raw binary data to a JavaScript function for a specific single client only.
202    pub fn send_raw<T>(&self, function: &str, data: T)
203    where
204        T: Into<Vec<u8>>,
205    {
206        let function = CString::new(function).unwrap();
207        let data = data.into().into_boxed_slice();
208        unsafe { webui_send_raw_client(self.as_ptr(), function.as_ptr(), data.as_ptr() as _, data.len()) }
209    }
210}