1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial |
3 | |
4 | use alloc::rc::Rc; |
5 | #[cfg (not(feature = "std" ))] |
6 | use alloc::{boxed::Box, string::String}; |
7 | use core::ffi::c_void; |
8 | use i_slint_core::api::{ |
9 | LogicalSize, PhysicalPosition, PhysicalSize, Window, WindowPosition, WindowSize, |
10 | }; |
11 | use i_slint_core::graphics::euclid; |
12 | use i_slint_core::graphics::IntSize; |
13 | use i_slint_core::platform::{Clipboard, Platform, PlatformError}; |
14 | use i_slint_core::renderer::Renderer; |
15 | use i_slint_core::window::ffi::WindowAdapterRcOpaque; |
16 | use i_slint_core::window::{WindowAdapter, WindowProperties}; |
17 | use i_slint_core::SharedString; |
18 | |
19 | type WindowAdapterUserData = *mut c_void; |
20 | |
21 | // FIXME wrapper over &dyn Renderer |
22 | #[repr (C)] |
23 | pub struct RendererPtr { |
24 | _a: *const c_void, |
25 | _b: *const c_void, |
26 | } |
27 | |
28 | pub struct CppWindowAdapter { |
29 | window: Window, |
30 | user_data: WindowAdapterUserData, |
31 | drop: unsafe extern "C" fn(WindowAdapterUserData), |
32 | /// Safety: the returned pointer must live for the lifetime of self |
33 | get_renderer_ref: unsafe extern "C" fn(WindowAdapterUserData) -> RendererPtr, |
34 | set_visible: unsafe extern "C" fn(WindowAdapterUserData, bool), |
35 | request_redraw: unsafe extern "C" fn(WindowAdapterUserData), |
36 | size: unsafe extern "C" fn(WindowAdapterUserData) -> IntSize, |
37 | set_size: unsafe extern "C" fn(WindowAdapterUserData, IntSize), |
38 | update_window_properties: unsafe extern "C" fn(WindowAdapterUserData, &WindowProperties), |
39 | position: |
40 | unsafe extern "C" fn(WindowAdapterUserData, &mut euclid::default::Point2D<i32>) -> bool, |
41 | set_position: unsafe extern "C" fn(WindowAdapterUserData, euclid::default::Point2D<i32>), |
42 | } |
43 | |
44 | impl Drop for CppWindowAdapter { |
45 | fn drop(&mut self) { |
46 | unsafe { (self.drop)(self.user_data) }; |
47 | } |
48 | } |
49 | |
50 | impl WindowAdapter for CppWindowAdapter { |
51 | fn window(&self) -> &Window { |
52 | &self.window |
53 | } |
54 | |
55 | fn set_visible(&self, visible: bool) -> Result<(), PlatformError> { |
56 | unsafe { (self.set_visible)(self.user_data, visible) }; |
57 | Ok(()) |
58 | } |
59 | |
60 | fn position(&self) -> Option<PhysicalPosition> { |
61 | let mut pos = euclid::default::Point2D::<i32>::default(); |
62 | if unsafe { (self.position)(self.user_data, &mut pos) } { |
63 | Some(i_slint_core::graphics::ffi::physical_position_to_api(pos)) |
64 | } else { |
65 | None |
66 | } |
67 | } |
68 | |
69 | fn set_position(&self, position: WindowPosition) { |
70 | let physical_position = i_slint_core::graphics::ffi::physical_position_from_api( |
71 | position.to_physical(self.window.scale_factor()), |
72 | ); |
73 | unsafe { (self.set_position)(self.user_data, physical_position) } |
74 | } |
75 | |
76 | fn set_size(&self, size: WindowSize) { |
77 | let physical_size = i_slint_core::graphics::ffi::physical_size_from_api( |
78 | size.to_physical(self.window.scale_factor()), |
79 | ); |
80 | unsafe { (self.set_size)(self.user_data, physical_size) } |
81 | } |
82 | |
83 | fn size(&self) -> PhysicalSize { |
84 | let s = unsafe { (self.size)(self.user_data) }; |
85 | PhysicalSize::new(s.width, s.height) |
86 | } |
87 | |
88 | fn renderer(&self) -> &dyn Renderer { |
89 | unsafe { core::mem::transmute((self.get_renderer_ref)(self.user_data)) } |
90 | } |
91 | |
92 | fn request_redraw(&self) { |
93 | unsafe { (self.request_redraw)(self.user_data) } |
94 | } |
95 | |
96 | fn update_window_properties(&self, properties: WindowProperties<'_>) { |
97 | unsafe { (self.update_window_properties)(self.user_data, &properties) } |
98 | } |
99 | } |
100 | |
101 | #[no_mangle ] |
102 | pub extern "C" fn slint_window_properties_get_title(wp: &WindowProperties, out: &mut SharedString) { |
103 | *out = wp.title(); |
104 | } |
105 | |
106 | #[no_mangle ] |
107 | pub extern "C" fn slint_window_properties_get_background( |
108 | wp: &WindowProperties, |
109 | out: &mut i_slint_core::Brush, |
110 | ) { |
111 | *out = wp.background(); |
112 | } |
113 | |
114 | #[no_mangle ] |
115 | pub extern "C" fn slint_window_properties_get_fullscreen(wp: &WindowProperties) -> bool { |
116 | wp.is_fullscreen() |
117 | } |
118 | |
119 | #[no_mangle ] |
120 | pub extern "C" fn slint_window_properties_get_minimized(wp: &WindowProperties) -> bool { |
121 | wp.is_minimized() |
122 | } |
123 | |
124 | #[no_mangle ] |
125 | pub extern "C" fn slint_window_properties_get_maximized(wp: &WindowProperties) -> bool { |
126 | wp.is_maximized() |
127 | } |
128 | |
129 | #[repr (C)] |
130 | #[derive (Clone, Copy)] |
131 | /// a Repr(C) variant of slint::platform::LayoutConstraints |
132 | pub struct LayoutConstraintsReprC { |
133 | pub min: i_slint_core::graphics::Size, |
134 | pub max: i_slint_core::graphics::Size, |
135 | pub preferred: i_slint_core::graphics::Size, |
136 | pub has_min: bool, |
137 | pub has_max: bool, |
138 | } |
139 | |
140 | #[no_mangle ] |
141 | pub extern "C" fn slint_window_properties_get_layout_constraints( |
142 | wp: &WindowProperties, |
143 | ) -> LayoutConstraintsReprC { |
144 | let c: LayoutConstraints = wp.layout_constraints(); |
145 | LayoutConstraintsReprC { |
146 | min: i_slint_core::lengths::logical_size_from_api(size:c.min.unwrap_or_default()).to_untyped(), |
147 | max: i_slint_coreSize2D::lengths::logical_size_from_api( |
148 | size:c.max.unwrap_or(default:LogicalSize { width: f32::MAX, height: f32::MAX }), |
149 | ) |
150 | .to_untyped(), |
151 | preferred: i_slint_core::lengths::logical_size_from_api(size:c.preferred).to_untyped(), |
152 | has_min: c.min.is_some(), |
153 | has_max: c.max.is_some(), |
154 | } |
155 | } |
156 | |
157 | #[no_mangle ] |
158 | pub unsafe extern "C" fn slint_window_adapter_new( |
159 | user_data: WindowAdapterUserData, |
160 | drop: unsafe extern "C" fn(WindowAdapterUserData), |
161 | get_renderer_ref: unsafe extern "C" fn(WindowAdapterUserData) -> RendererPtr, |
162 | set_visible: unsafe extern "C" fn(WindowAdapterUserData, bool), |
163 | request_redraw: unsafe extern "C" fn(WindowAdapterUserData), |
164 | size: unsafe extern "C" fn(WindowAdapterUserData) -> IntSize, |
165 | set_size: unsafe extern "C" fn(WindowAdapterUserData, IntSize), |
166 | update_window_properties: unsafe extern "C" fn(WindowAdapterUserData, &WindowProperties), |
167 | position: unsafe extern "C" fn( |
168 | WindowAdapterUserData, |
169 | &mut euclid::default::Point2D<i32>, |
170 | ) -> bool, |
171 | set_position: unsafe extern "C" fn(WindowAdapterUserData, euclid::default::Point2D<i32>), |
172 | target: *mut WindowAdapterRcOpaque, |
173 | ) { |
174 | let window: Rc = Rc::<CppWindowAdapter>::new_cyclic(|w: &Weak| CppWindowAdapter { |
175 | window: Window::new(window_adapter_weak:w.clone()), |
176 | user_data, |
177 | drop, |
178 | get_renderer_ref, |
179 | set_visible, |
180 | request_redraw, |
181 | size, |
182 | set_size, |
183 | update_window_properties, |
184 | position, |
185 | set_position, |
186 | }); |
187 | |
188 | core::ptr::write(dst:target as *mut Rc<dyn WindowAdapter>, src:window); |
189 | } |
190 | |
191 | type PlatformUserData = *mut c_void; |
192 | |
193 | struct CppPlatform { |
194 | user_data: PlatformUserData, |
195 | drop: unsafe extern "C" fn(PlatformUserData), |
196 | window_factory: unsafe extern "C" fn(PlatformUserData, *mut WindowAdapterRcOpaque), |
197 | #[cfg (not(feature = "std" ))] |
198 | duration_since_start: unsafe extern "C" fn(PlatformUserData) -> u64, |
199 | // silent the warning despite `Clipboard` is a `#[non_exhaustive]` enum from another crate. |
200 | #[allow (improper_ctypes_definitions)] |
201 | set_clipboard_text: unsafe extern "C" fn(PlatformUserData, &SharedString, Clipboard), |
202 | #[allow (improper_ctypes_definitions)] |
203 | clipboard_text: unsafe extern "C" fn(PlatformUserData, &mut SharedString, Clipboard) -> bool, |
204 | run_event_loop: unsafe extern "C" fn(PlatformUserData), |
205 | quit_event_loop: unsafe extern "C" fn(PlatformUserData), |
206 | invoke_from_event_loop: unsafe extern "C" fn(PlatformUserData, PlatformTaskOpaque), |
207 | } |
208 | |
209 | impl Drop for CppPlatform { |
210 | fn drop(&mut self) { |
211 | unsafe { (self.drop)(self.user_data) }; |
212 | } |
213 | } |
214 | |
215 | impl Platform for CppPlatform { |
216 | fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> { |
217 | let mut uninit = core::mem::MaybeUninit::<Rc<dyn WindowAdapter>>::uninit(); |
218 | unsafe { |
219 | (self.window_factory)( |
220 | self.user_data, |
221 | uninit.as_mut_ptr() as *mut WindowAdapterRcOpaque, |
222 | ); |
223 | Ok(uninit.assume_init()) |
224 | } |
225 | } |
226 | |
227 | #[cfg (not(feature = "std" ))] |
228 | fn duration_since_start(&self) -> core::time::Duration { |
229 | core::time::Duration::from_millis(unsafe { (self.duration_since_start)(self.user_data) }) |
230 | } |
231 | |
232 | fn run_event_loop(&self) -> Result<(), PlatformError> { |
233 | unsafe { (self.run_event_loop)(self.user_data) }; |
234 | Ok(()) |
235 | } |
236 | |
237 | fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> { |
238 | Some(Box::new(CppEventLoopProxy { |
239 | user_data: self.user_data, |
240 | quit_event_loop: self.quit_event_loop, |
241 | invoke_from_event_loop: self.invoke_from_event_loop, |
242 | })) |
243 | } |
244 | |
245 | fn set_clipboard_text(&self, text: &str, clipboard: Clipboard) { |
246 | let shared_text = SharedString::from(text); |
247 | unsafe { (self.set_clipboard_text)(self.user_data, &shared_text, clipboard) } |
248 | } |
249 | |
250 | fn clipboard_text(&self, clipboard: Clipboard) -> Option<String> { |
251 | let mut out_text = SharedString::new(); |
252 | let status = unsafe { (self.clipboard_text)(self.user_data, &mut out_text, clipboard) }; |
253 | status.then(|| out_text.into()) |
254 | } |
255 | } |
256 | |
257 | struct CppEventLoopProxy { |
258 | user_data: PlatformUserData, |
259 | quit_event_loop: unsafe extern "C" fn(PlatformUserData), |
260 | invoke_from_event_loop: unsafe extern "C" fn(PlatformUserData, PlatformTaskOpaque), |
261 | } |
262 | |
263 | impl i_slint_core::platform::EventLoopProxy for CppEventLoopProxy { |
264 | fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> { |
265 | unsafe { (self.quit_event_loop)(self.user_data) }; |
266 | Ok(()) |
267 | } |
268 | |
269 | fn invoke_from_event_loop( |
270 | &self, |
271 | event: Box<dyn FnOnce() + Send>, |
272 | ) -> Result<(), i_slint_core::api::EventLoopError> { |
273 | unsafe { |
274 | (self.invoke_from_event_loop)( |
275 | self.user_data, |
276 | core::mem::transmute::<*mut dyn FnOnce(), PlatformTaskOpaque>(src:Box::into_raw(event)), |
277 | ) |
278 | }; |
279 | Ok(()) |
280 | } |
281 | } |
282 | |
283 | unsafe impl Send for CppEventLoopProxy {} |
284 | unsafe impl Sync for CppEventLoopProxy {} |
285 | |
286 | // silent the warning depite `Clipboard` is a `#[non_exhaustive]` enum from another crate. |
287 | #[allow (improper_ctypes_definitions)] |
288 | #[no_mangle ] |
289 | pub unsafe extern "C" fn slint_platform_register( |
290 | user_data: PlatformUserData, |
291 | drop: unsafe extern "C" fn(PlatformUserData), |
292 | window_factory: unsafe extern "C" fn(PlatformUserData, *mut WindowAdapterRcOpaque), |
293 | #[allow (unused)] duration_since_start: unsafe extern "C" fn(PlatformUserData) -> u64, |
294 | set_clipboard_text: unsafe extern "C" fn(PlatformUserData, &SharedString, Clipboard), |
295 | clipboard_text: unsafe extern "C" fn(PlatformUserData, &mut SharedString, Clipboard) -> bool, |
296 | run_event_loop: unsafe extern "C" fn(PlatformUserData), |
297 | quit_event_loop: unsafe extern "C" fn(PlatformUserData), |
298 | invoke_from_event_loop: unsafe extern "C" fn(PlatformUserData, PlatformTaskOpaque), |
299 | ) { |
300 | let p: CppPlatform = CppPlatform { |
301 | user_data, |
302 | drop, |
303 | window_factory, |
304 | #[cfg (not(feature = "std" ))] |
305 | duration_since_start, |
306 | set_clipboard_text, |
307 | clipboard_text, |
308 | run_event_loop, |
309 | quit_event_loop, |
310 | invoke_from_event_loop, |
311 | }; |
312 | i_slint_core::platform::set_platform(Box::new(p)).unwrap(); |
313 | } |
314 | |
315 | #[no_mangle ] |
316 | pub unsafe extern "C" fn slint_windowrc_has_active_animations( |
317 | handle: *const WindowAdapterRcOpaque, |
318 | ) -> bool { |
319 | let window_adapter: &Rc = &*(handle as *const Rc<dyn WindowAdapter>); |
320 | window_adapter.window().has_active_animations() |
321 | } |
322 | |
323 | #[no_mangle ] |
324 | pub extern "C" fn slint_platform_update_timers_and_animations() { |
325 | i_slint_core::platform::update_timers_and_animations() |
326 | } |
327 | |
328 | /// Returns the duration in millisecond until the next timer or `u64::MAX` if there is no pending timers |
329 | #[no_mangle ] |
330 | pub extern "C" fn slint_platform_duration_until_next_timer_update() -> u64 { |
331 | i_slint_core::platform::duration_until_next_timer_update() |
332 | .map_or(default:u64::MAX, |d: Duration| d.as_millis() as u64) |
333 | } |
334 | |
335 | #[repr (C)] |
336 | pub struct PlatformTaskOpaque(*const c_void, *const c_void); |
337 | |
338 | #[no_mangle ] |
339 | pub unsafe extern "C" fn slint_platform_task_drop(event: PlatformTaskOpaque) { |
340 | drop(Box::from_raw(core::mem::transmute::<PlatformTaskOpaque, *mut dyn FnOnce()>(src:event))); |
341 | } |
342 | |
343 | #[no_mangle ] |
344 | pub unsafe extern "C" fn slint_platform_task_run(event: PlatformTaskOpaque) { |
345 | let f: Box = Box::from_raw(core::mem::transmute::<PlatformTaskOpaque, *mut dyn FnOnce()>(src:event)); |
346 | f(); |
347 | } |
348 | |
349 | #[cfg (feature = "renderer-software" )] |
350 | mod software_renderer { |
351 | use super::*; |
352 | type SoftwareRendererOpaque = *const c_void; |
353 | use i_slint_core::graphics::{IntRect, Rgb8Pixel}; |
354 | use i_slint_core::software_renderer::{RepaintBufferType, Rgb565Pixel, SoftwareRenderer}; |
355 | |
356 | #[no_mangle ] |
357 | pub unsafe extern "C" fn slint_software_renderer_new( |
358 | buffer_age: u32, |
359 | ) -> SoftwareRendererOpaque { |
360 | let repaint_buffer_type = match buffer_age { |
361 | 0 => RepaintBufferType::NewBuffer, |
362 | 1 => RepaintBufferType::ReusedBuffer, |
363 | 2 => RepaintBufferType::SwappedBuffers, |
364 | _ => unreachable!(), |
365 | }; |
366 | Box::into_raw(Box::new(SoftwareRenderer::new_with_repaint_buffer_type(repaint_buffer_type))) |
367 | as SoftwareRendererOpaque |
368 | } |
369 | |
370 | #[no_mangle ] |
371 | pub unsafe extern "C" fn slint_software_renderer_drop(r: SoftwareRendererOpaque) { |
372 | drop(Box::from_raw(r as *mut SoftwareRenderer)); |
373 | } |
374 | |
375 | #[no_mangle ] |
376 | pub unsafe extern "C" fn slint_software_renderer_render_rgb8( |
377 | r: SoftwareRendererOpaque, |
378 | buffer: *mut Rgb8Pixel, |
379 | buffer_len: usize, |
380 | pixel_stride: usize, |
381 | ) -> IntRect { |
382 | let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len); |
383 | let renderer = &*(r as *const SoftwareRenderer); |
384 | let r = renderer.render(buffer, pixel_stride); |
385 | let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size()); |
386 | i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32) |
387 | } |
388 | |
389 | #[no_mangle ] |
390 | pub unsafe extern "C" fn slint_software_renderer_render_rgb565( |
391 | r: SoftwareRendererOpaque, |
392 | buffer: *mut u16, |
393 | buffer_len: usize, |
394 | pixel_stride: usize, |
395 | ) -> IntRect { |
396 | let buffer = core::slice::from_raw_parts_mut(buffer as *mut Rgb565Pixel, buffer_len); |
397 | let renderer = &*(r as *const SoftwareRenderer); |
398 | let r = renderer.render(buffer, pixel_stride); |
399 | let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size()); |
400 | i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32) |
401 | } |
402 | |
403 | #[cfg (feature = "experimental" )] |
404 | #[no_mangle ] |
405 | pub unsafe extern "C" fn slint_software_renderer_set_rendering_rotation( |
406 | r: SoftwareRendererOpaque, |
407 | rotation: i32, |
408 | ) { |
409 | use i_slint_core::software_renderer::RenderingRotation; |
410 | let renderer = &*(r as *const SoftwareRenderer); |
411 | renderer.set_rendering_rotation(match rotation { |
412 | 90 => RenderingRotation::Rotate90, |
413 | 180 => RenderingRotation::Rotate180, |
414 | 270 => RenderingRotation::Rotate270, |
415 | _ => RenderingRotation::NoRotation, |
416 | }); |
417 | } |
418 | |
419 | #[no_mangle ] |
420 | pub unsafe extern "C" fn slint_software_renderer_handle( |
421 | r: SoftwareRendererOpaque, |
422 | ) -> RendererPtr { |
423 | let r = (r as *const SoftwareRenderer) as *const dyn Renderer; |
424 | core::mem::transmute(r) |
425 | } |
426 | } |
427 | |
428 | #[cfg (all(feature = "i-slint-renderer-skia" , feature = "raw-window-handle" ))] |
429 | pub mod skia { |
430 | use super::*; |
431 | use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; |
432 | |
433 | struct CppRawHandle(RawWindowHandle, RawDisplayHandle); |
434 | |
435 | // the raw handle type are #[non_exhaustive], so they can't be initialize with the convenient syntax. Work that around. |
436 | macro_rules! init_raw { |
437 | ($ty:ty { $($var:ident),* }) => { |
438 | { |
439 | let mut h = <$ty>::empty(); |
440 | $(h.$var = $var;)* |
441 | h |
442 | } |
443 | }; |
444 | } |
445 | |
446 | type CppRawHandleOpaque = *const c_void; |
447 | |
448 | #[no_mangle ] |
449 | pub unsafe extern "C" fn slint_new_raw_window_handle_win32( |
450 | hwnd: *mut c_void, |
451 | hinstance: *mut c_void, |
452 | ) -> CppRawHandleOpaque { |
453 | let handle = CppRawHandle( |
454 | RawWindowHandle::Win32(init_raw!(raw_window_handle::Win32WindowHandle { |
455 | hwnd, |
456 | hinstance |
457 | })), |
458 | RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::empty()), |
459 | ); |
460 | Box::into_raw(Box::new(handle)) as CppRawHandleOpaque |
461 | } |
462 | |
463 | #[no_mangle ] |
464 | pub unsafe extern "C" fn slint_new_raw_window_handle_x11_xcb( |
465 | window: u32, |
466 | visual_id: u32, |
467 | connection: *mut c_void, |
468 | screen: core::ffi::c_int, |
469 | ) -> CppRawHandleOpaque { |
470 | use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle}; |
471 | let handle = CppRawHandle( |
472 | RawWindowHandle::Xcb(init_raw!(XcbWindowHandle { window, visual_id })), |
473 | RawDisplayHandle::Xcb(init_raw!(XcbDisplayHandle { connection, screen })), |
474 | ); |
475 | Box::into_raw(Box::new(handle)) as CppRawHandleOpaque |
476 | } |
477 | |
478 | #[no_mangle ] |
479 | pub unsafe extern "C" fn slint_new_raw_window_handle_x11_xlib( |
480 | window: core::ffi::c_ulong, |
481 | visual_id: core::ffi::c_ulong, |
482 | display: *mut c_void, |
483 | screen: core::ffi::c_int, |
484 | ) -> CppRawHandleOpaque { |
485 | use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle}; |
486 | let handle = CppRawHandle( |
487 | RawWindowHandle::Xlib(init_raw!(XlibWindowHandle { window, visual_id })), |
488 | RawDisplayHandle::Xlib(init_raw!(XlibDisplayHandle { display, screen })), |
489 | ); |
490 | Box::into_raw(Box::new(handle)) as CppRawHandleOpaque |
491 | } |
492 | |
493 | #[no_mangle ] |
494 | pub unsafe extern "C" fn slint_new_raw_window_handle_wayland( |
495 | surface: *mut c_void, |
496 | display: *mut c_void, |
497 | ) -> CppRawHandleOpaque { |
498 | use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; |
499 | let handle = CppRawHandle( |
500 | RawWindowHandle::Wayland(init_raw!(WaylandWindowHandle { surface })), |
501 | RawDisplayHandle::Wayland(init_raw!(WaylandDisplayHandle { display })), |
502 | ); |
503 | Box::into_raw(Box::new(handle)) as CppRawHandleOpaque |
504 | } |
505 | |
506 | #[no_mangle ] |
507 | pub unsafe extern "C" fn slint_new_raw_window_handle_appkit( |
508 | ns_view: *mut c_void, |
509 | ns_window: *mut c_void, |
510 | ) -> CppRawHandleOpaque { |
511 | use raw_window_handle::{AppKitDisplayHandle, AppKitWindowHandle}; |
512 | let handle = CppRawHandle( |
513 | RawWindowHandle::AppKit(init_raw!(AppKitWindowHandle { ns_view, ns_window })), |
514 | RawDisplayHandle::AppKit(AppKitDisplayHandle::empty()), |
515 | ); |
516 | Box::into_raw(Box::new(handle)) as CppRawHandleOpaque |
517 | } |
518 | |
519 | #[no_mangle ] |
520 | pub unsafe extern "C" fn slint_raw_window_handle_drop(handle: CppRawHandleOpaque) { |
521 | drop(Box::from_raw(handle as *mut CppRawHandle)) |
522 | } |
523 | |
524 | type SkiaRendererOpaque = *const c_void; |
525 | type SkiaRenderer = i_slint_renderer_skia::SkiaRenderer; |
526 | |
527 | #[no_mangle ] |
528 | pub unsafe extern "C" fn slint_skia_renderer_new( |
529 | handle_opaque: CppRawHandleOpaque, |
530 | size: IntSize, |
531 | ) -> SkiaRendererOpaque { |
532 | let handle = &*(handle_opaque as *const CppRawHandle); |
533 | |
534 | // Safety: This is safe because the handle remains valid; the next rwh release provides `new()` without unsafe. |
535 | let active_handle = unsafe { raw_window_handle::ActiveHandle::new_unchecked() }; |
536 | |
537 | // Safety: the C++ code should ensure that the handle is valid |
538 | let (window_handle, display_handle) = unsafe { |
539 | ( |
540 | raw_window_handle::WindowHandle::borrow_raw(handle.0, active_handle), |
541 | raw_window_handle::DisplayHandle::borrow_raw(handle.1), |
542 | ) |
543 | }; |
544 | |
545 | let boxed_renderer: Box<SkiaRenderer> = Box::new( |
546 | SkiaRenderer::new( |
547 | window_handle, |
548 | display_handle, |
549 | PhysicalSize { width: size.width, height: size.height }, |
550 | ) |
551 | .unwrap(), |
552 | ); |
553 | Box::into_raw(boxed_renderer) as SkiaRendererOpaque |
554 | } |
555 | |
556 | #[no_mangle ] |
557 | pub unsafe extern "C" fn slint_skia_renderer_drop(r: SkiaRendererOpaque) { |
558 | drop(Box::from_raw(r as *mut SkiaRenderer)) |
559 | } |
560 | |
561 | #[no_mangle ] |
562 | pub unsafe extern "C" fn slint_skia_renderer_render(r: SkiaRendererOpaque) { |
563 | let r = &*(r as *const SkiaRenderer); |
564 | r.render().unwrap(); |
565 | } |
566 | |
567 | #[no_mangle ] |
568 | pub unsafe extern "C" fn slint_skia_renderer_handle(r: SkiaRendererOpaque) -> RendererPtr { |
569 | let r = (r as *const SkiaRenderer) as *const dyn Renderer; |
570 | core::mem::transmute(r) |
571 | } |
572 | } |
573 | |