1#![warn(missing_docs)]
7use crate::api::{
10 CloseRequestResponse, LogicalPosition, PhysicalPosition, PhysicalSize, PlatformError, Window,
11 WindowPosition, WindowSize,
12};
13use crate::input::{
14 ClickState, FocusEvent, FocusReason, InternalKeyboardModifierState, KeyEvent, KeyEventType,
15 MouseEvent, MouseInputState, PointerEventButton, TextCursorBlinker, key_codes,
16};
17use crate::item_tree::{
18 ItemRc, ItemTreeRc, ItemTreeRef, ItemTreeRefPin, ItemTreeVTable, ItemTreeWeak, ItemWeak,
19 ParentItemTraversalMode,
20};
21use crate::items::{ColorScheme, InputType, ItemRef, MouseCursor, PopupClosePolicy};
22use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, SizeLengths};
23use crate::menus::MenuVTable;
24use crate::properties::{Property, PropertyTracker};
25use crate::renderer::Renderer;
26use crate::{Callback, SharedString};
27use alloc::boxed::Box;
28use alloc::rc::{Rc, Weak};
29use alloc::vec::Vec;
30use core::cell::{Cell, RefCell};
31use core::num::NonZeroU32;
32use core::pin::Pin;
33use euclid::num::Zero;
34use vtable::VRcMapped;
35
36pub mod popup;
37
38fn next_focus_item(item: ItemRc) -> ItemRc {
39 item.next_focus_item()
40}
41
42fn previous_focus_item(item: ItemRc) -> ItemRc {
43 item.previous_focus_item()
44}
45
46pub trait WindowAdapter {
73 fn window(&self) -> &Window;
75
76 fn set_visible(&self, _visible: bool) -> Result<(), PlatformError> {
78 Ok(())
79 }
80
81 fn position(&self) -> Option<PhysicalPosition> {
88 None
89 }
90 fn set_position(&self, _position: WindowPosition) {}
97
98 fn set_size(&self, _size: WindowSize) {}
109
110 fn size(&self) -> PhysicalSize;
112
113 fn request_redraw(&self) {}
125
126 fn renderer(&self) -> &dyn Renderer;
131
132 fn update_window_properties(&self, _properties: WindowProperties<'_>) {}
138
139 #[doc(hidden)]
140 fn internal(&self, _: crate::InternalToken) -> Option<&dyn WindowAdapterInternal> {
141 None
142 }
143
144 #[cfg(feature = "raw-window-handle-06")]
146 fn window_handle_06(
147 &self,
148 ) -> Result<raw_window_handle_06::WindowHandle<'_>, raw_window_handle_06::HandleError> {
149 Err(raw_window_handle_06::HandleError::NotSupported)
150 }
151
152 #[cfg(feature = "raw-window-handle-06")]
154 fn display_handle_06(
155 &self,
156 ) -> Result<raw_window_handle_06::DisplayHandle<'_>, raw_window_handle_06::HandleError> {
157 Err(raw_window_handle_06::HandleError::NotSupported)
158 }
159}
160
161#[doc(hidden)]
166pub trait WindowAdapterInternal: core::any::Any {
167 fn register_item_tree(&self, _: ItemTreeRefPin) {}
169
170 fn unregister_item_tree(
173 &self,
174 _component: ItemTreeRef,
175 _items: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,
176 ) {
177 }
178
179 fn create_popup(&self, _geometry: LogicalRect) -> Option<Rc<dyn WindowAdapter>> {
186 None
187 }
188
189 fn set_mouse_cursor(&self, _cursor: MouseCursor) {}
192
193 fn input_method_request(&self, _: InputMethodRequest) {}
195
196 fn handle_focus_change(&self, _old: Option<ItemRc>, _new: Option<ItemRc>) {}
199
200 fn color_scheme(&self) -> ColorScheme {
202 ColorScheme::Unknown
203 }
204
205 fn supports_native_menu_bar(&self) -> bool {
207 false
208 }
209
210 fn setup_menubar(&self, _menubar: vtable::VRc<MenuVTable>) {}
211
212 fn show_native_popup_menu(
213 &self,
214 _context_menu_item: vtable::VRc<MenuVTable>,
215 _position: LogicalPosition,
216 ) -> bool {
217 false
218 }
219
220 #[cfg(all(feature = "std", feature = "raw-window-handle-06"))]
222 fn window_handle_06_rc(
223 &self,
224 ) -> Result<
225 std::sync::Arc<dyn raw_window_handle_06::HasWindowHandle>,
226 raw_window_handle_06::HandleError,
227 > {
228 Err(raw_window_handle_06::HandleError::NotSupported)
229 }
230
231 #[cfg(all(feature = "std", feature = "raw-window-handle-06"))]
233 fn display_handle_06_rc(
234 &self,
235 ) -> Result<
236 std::sync::Arc<dyn raw_window_handle_06::HasDisplayHandle>,
237 raw_window_handle_06::HandleError,
238 > {
239 Err(raw_window_handle_06::HandleError::NotSupported)
240 }
241
242 fn bring_to_front(&self) -> Result<(), PlatformError> {
244 Ok(())
245 }
246
247 fn safe_area_inset(&self) -> crate::lengths::PhysicalEdges {
250 Default::default()
251 }
252}
253
254#[non_exhaustive]
257#[derive(Debug, Clone)]
258pub enum InputMethodRequest {
259 Enable(InputMethodProperties),
261 Update(InputMethodProperties),
263 Disable,
265}
266
267#[non_exhaustive]
269#[derive(Clone, Default, Debug)]
270pub struct InputMethodProperties {
271 pub text: SharedString,
275 pub cursor_position: usize,
277 pub anchor_position: Option<usize>,
280 pub preedit_text: SharedString,
284 pub preedit_offset: usize,
286 pub cursor_rect_origin: LogicalPosition,
288 pub cursor_rect_size: crate::api::LogicalSize,
290 pub anchor_point: LogicalPosition,
292 pub input_type: InputType,
294 pub clip_rect: Option<LogicalRect>,
296}
297
298#[non_exhaustive]
300#[derive(Copy, Clone, Debug, PartialEq, Default)]
301pub struct LayoutConstraints {
302 pub min: Option<crate::api::LogicalSize>,
304 pub max: Option<crate::api::LogicalSize>,
306 pub preferred: crate::api::LogicalSize,
308}
309
310pub struct WindowProperties<'a>(&'a WindowInner);
313
314impl WindowProperties<'_> {
315 pub fn title(&self) -> SharedString {
317 self.0.window_item().map(|w| w.as_pin_ref().title()).unwrap_or_default()
318 }
319
320 pub fn background(&self) -> crate::Brush {
322 self.0
323 .window_item()
324 .map(|w: VRcMapped<ItemTreeVTable, crate::items::WindowItem>| {
325 w.as_pin_ref().background()
326 })
327 .unwrap_or_default()
328 }
329
330 pub fn layout_constraints(&self) -> LayoutConstraints {
332 let component = self.0.component();
333 let component = ItemTreeRc::borrow_pin(&component);
334 let h = component.as_ref().layout_info(crate::layout::Orientation::Horizontal);
335 let v = component.as_ref().layout_info(crate::layout::Orientation::Vertical);
336 let (min, max) = crate::layout::min_max_size_for_layout_constraints(h, v);
337 LayoutConstraints {
338 min,
339 max,
340 preferred: crate::api::LogicalSize::new(
341 h.preferred_bounded() as f32,
342 v.preferred_bounded() as f32,
343 ),
344 }
345 }
346
347 #[deprecated(note = "Please use `is_fullscreen` instead")]
349 pub fn fullscreen(&self) -> bool {
350 self.is_fullscreen()
351 }
352
353 pub fn is_fullscreen(&self) -> bool {
355 self.0.is_fullscreen()
356 }
357
358 pub fn is_maximized(&self) -> bool {
360 self.0.maximized.get()
361 }
362
363 pub fn is_minimized(&self) -> bool {
365 self.0.minimized.get()
366 }
367}
368
369struct WindowPropertiesTracker {
370 window_adapter_weak: Weak<dyn WindowAdapter>,
371}
372
373impl crate::properties::PropertyDirtyHandler for WindowPropertiesTracker {
374 fn notify(self: Pin<&Self>) {
375 let win = self.window_adapter_weak.clone();
376 crate::timers::Timer::single_shot(Default::default(), move || {
377 if let Some(window_adapter) = win.upgrade() {
378 WindowInner::from_pub(window_adapter.window()).update_window_properties();
379 };
380 })
381 }
382}
383
384struct WindowRedrawTracker {
385 window_adapter_weak: Weak<dyn WindowAdapter>,
386}
387
388impl crate::properties::PropertyDirtyHandler for WindowRedrawTracker {
389 fn notify(self: Pin<&Self>) {
390 if let Some(window_adapter) = self.window_adapter_weak.upgrade() {
391 window_adapter.request_redraw();
392 };
393 }
394}
395
396#[derive(Clone)]
398pub enum PopupWindowLocation {
399 TopLevel(Rc<dyn WindowAdapter>),
401 ChildWindow(LogicalPoint),
403}
404
405#[derive(Clone)]
408pub struct PopupWindow {
409 pub popup_id: NonZeroU32,
411 pub location: PopupWindowLocation,
413 pub component: ItemTreeRc,
415 pub close_policy: PopupClosePolicy,
417 focus_item_in_parent: ItemWeak,
419 pub parent_item: ItemWeak,
421 is_menu: bool,
424}
425
426#[pin_project::pin_project]
427struct WindowPinnedFields {
428 #[pin]
429 redraw_tracker: PropertyTracker<WindowRedrawTracker>,
430 #[pin]
432 window_properties_tracker: PropertyTracker<WindowPropertiesTracker>,
433 #[pin]
434 scale_factor: Property<f32>,
435 #[pin]
436 active: Property<bool>,
437 #[pin]
438 text_input_focused: Property<bool>,
439}
440
441pub struct WindowInner {
443 window_adapter_weak: Weak<dyn WindowAdapter>,
444 component: RefCell<ItemTreeWeak>,
445 strong_component_ref: RefCell<Option<ItemTreeRc>>,
447 mouse_input_state: Cell<MouseInputState>,
448 pub(crate) modifiers: Cell<InternalKeyboardModifierState>,
449
450 pub focus_item: RefCell<crate::item_tree::ItemWeak>,
452 pub(crate) last_ime_text: RefCell<SharedString>,
454 pub(crate) prevent_focus_change: Cell<bool>,
459 cursor_blinker: RefCell<pin_weak::rc::PinWeak<crate::input::TextCursorBlinker>>,
460
461 pinned_fields: Pin<Box<WindowPinnedFields>>,
462 maximized: Cell<bool>,
463 minimized: Cell<bool>,
464
465 active_popups: RefCell<Vec<PopupWindow>>,
467 next_popup_id: Cell<NonZeroU32>,
468 had_popup_on_press: Cell<bool>,
469 close_requested: Callback<(), CloseRequestResponse>,
470 click_state: ClickState,
471 pub(crate) ctx: once_cell::unsync::Lazy<crate::SlintContext>,
472}
473
474impl Drop for WindowInner {
475 fn drop(&mut self) {
476 if let Some(existing_blinker) = self.cursor_blinker.borrow().upgrade() {
477 existing_blinker.stop();
478 }
479 }
480}
481
482impl WindowInner {
483 pub fn new(window_adapter_weak: Weak<dyn WindowAdapter>) -> Self {
485 #![allow(unused_mut)]
486
487 let mut window_properties_tracker =
488 PropertyTracker::new_with_dirty_handler(WindowPropertiesTracker {
489 window_adapter_weak: window_adapter_weak.clone(),
490 });
491
492 let mut redraw_tracker = PropertyTracker::new_with_dirty_handler(WindowRedrawTracker {
493 window_adapter_weak: window_adapter_weak.clone(),
494 });
495
496 #[cfg(slint_debug_property)]
497 {
498 window_properties_tracker
499 .set_debug_name("i_slint_core::Window::window_properties_tracker".into());
500 redraw_tracker.set_debug_name("i_slint_core::Window::redraw_tracker".into());
501 }
502
503 Self {
504 window_adapter_weak,
505 component: Default::default(),
506 strong_component_ref: Default::default(),
507 mouse_input_state: Default::default(),
508 modifiers: Default::default(),
509 pinned_fields: Box::pin(WindowPinnedFields {
510 redraw_tracker,
511 window_properties_tracker,
512 scale_factor: Property::new_named(1., "i_slint_core::Window::scale_factor"),
513 active: Property::new_named(false, "i_slint_core::Window::active"),
514 text_input_focused: Property::new_named(
515 false,
516 "i_slint_core::Window::text_input_focused",
517 ),
518 }),
519 maximized: Cell::new(false),
520 minimized: Cell::new(false),
521 focus_item: Default::default(),
522 last_ime_text: Default::default(),
523 cursor_blinker: Default::default(),
524 active_popups: Default::default(),
525 next_popup_id: Cell::new(NonZeroU32::MIN),
526 had_popup_on_press: Default::default(),
527 close_requested: Default::default(),
528 click_state: ClickState::default(),
529 prevent_focus_change: Default::default(),
530 ctx: once_cell::unsync::Lazy::new(|| {
533 crate::context::GLOBAL_CONTEXT.with(|ctx| ctx.get().unwrap().clone())
534 }),
535 }
536 }
537
538 pub fn set_component(&self, component: &ItemTreeRc) {
541 self.close_all_popups();
542 self.focus_item.replace(Default::default());
543 self.mouse_input_state.replace(Default::default());
544 self.modifiers.replace(Default::default());
545 self.component.replace(ItemTreeRc::downgrade(component));
546 self.pinned_fields.window_properties_tracker.set_dirty(); let window_adapter = self.window_adapter();
548 window_adapter.renderer().set_window_adapter(&window_adapter);
549 let scale_factor = self.scale_factor();
550 self.set_window_item_geometry(window_adapter.size().to_logical(scale_factor).to_euclid());
551 let inset = window_adapter
552 .internal(crate::InternalToken)
553 .map(|internal| internal.safe_area_inset())
554 .unwrap_or_default();
555 self.set_window_item_safe_area(inset.to_logical(scale_factor));
556 window_adapter.request_redraw();
557 let weak = Rc::downgrade(&window_adapter);
558 crate::timers::Timer::single_shot(Default::default(), move || {
559 if let Some(window_adapter) = weak.upgrade() {
560 WindowInner::from_pub(window_adapter.window()).update_window_properties();
561 }
562 })
563 }
564
565 pub fn component(&self) -> ItemTreeRc {
568 self.component.borrow().upgrade().unwrap()
569 }
570
571 pub fn try_component(&self) -> Option<ItemTreeRc> {
573 self.component.borrow().upgrade()
574 }
575
576 pub fn active_popups(&self) -> core::cell::Ref<'_, [PopupWindow]> {
578 core::cell::Ref::map(self.active_popups.borrow(), |v| v.as_slice())
579 }
580
581 pub fn process_mouse_input(&self, mut event: MouseEvent) {
584 crate::animations::update_animations();
585
586 event = self.click_state.check_repeat(event, self.ctx.platform().click_interval());
588
589 let window_adapter = self.window_adapter();
590 let mut mouse_input_state = self.mouse_input_state.take();
591 if let Some(mut drop_event) = mouse_input_state.drag_data.clone() {
592 match &event {
593 MouseEvent::Released { position, button: PointerEventButton::Left, .. } => {
594 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
595 window_adapter.set_mouse_cursor(MouseCursor::Default);
596 }
597 drop_event.position = crate::lengths::logical_position_to_api(*position);
598 event = MouseEvent::Drop(drop_event);
599 mouse_input_state.drag_data = None;
600 }
601 MouseEvent::Moved { position, .. } => {
602 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
603 window_adapter.set_mouse_cursor(MouseCursor::NoDrop);
604 }
605 drop_event.position = crate::lengths::logical_position_to_api(*position);
606 event = MouseEvent::DragMove(drop_event);
607 }
608 MouseEvent::Exit => {
609 mouse_input_state.drag_data = None;
610 }
611 _ => {}
612 }
613 }
614
615 let pressed_event = matches!(event, MouseEvent::Pressed { .. });
616 let released_event = matches!(event, MouseEvent::Released { .. });
617
618 let last_top_item = mouse_input_state.top_item_including_delayed();
619 if released_event {
620 mouse_input_state =
621 crate::input::process_delayed_event(&window_adapter, mouse_input_state);
622 }
623
624 let Some(item_tree) = self.try_component() else { return };
625
626 let mut root_adapter = None;
628 ItemTreeRc::borrow_pin(&item_tree).as_ref().window_adapter(false, &mut root_adapter);
629 let root_adapter = root_adapter.unwrap_or_else(|| window_adapter.clone());
630 let active_popups = &WindowInner::from_pub(root_adapter.window()).active_popups;
631 let native_popup_index = active_popups.borrow().iter().position(|p| {
632 if let PopupWindowLocation::TopLevel(wa) = &p.location {
633 Rc::ptr_eq(wa, &window_adapter)
634 } else {
635 false
636 }
637 });
638
639 if pressed_event {
640 self.had_popup_on_press.set(!active_popups.borrow().is_empty());
641 }
642
643 let mut popup_to_close = active_popups.borrow().last().and_then(|popup| {
644 let mouse_inside_popup = || {
645 if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {
646 event.position().is_none_or(|pos| {
647 ItemTreeRc::borrow_pin(&popup.component)
648 .as_ref()
649 .item_geometry(0)
650 .contains(pos - coordinates.to_vector())
651 })
652 } else {
653 native_popup_index.is_some_and(|idx| idx == active_popups.borrow().len() - 1)
654 && event.position().is_none_or(|pos| {
655 ItemTreeRc::borrow_pin(&item_tree)
656 .as_ref()
657 .item_geometry(0)
658 .contains(pos)
659 })
660 }
661 };
662 match popup.close_policy {
663 PopupClosePolicy::CloseOnClick => {
664 let mouse_inside_popup = mouse_inside_popup();
665 (mouse_inside_popup && released_event && self.had_popup_on_press.get())
666 || (!mouse_inside_popup && pressed_event)
667 }
668 PopupClosePolicy::CloseOnClickOutside => !mouse_inside_popup() && pressed_event,
669 PopupClosePolicy::NoAutoClose => false,
670 }
671 .then_some(popup.popup_id)
672 });
673
674 mouse_input_state = if let Some(mut event) =
675 crate::input::handle_mouse_grab(&event, &window_adapter, &mut mouse_input_state)
676 {
677 let mut item_tree = self.component.borrow().upgrade();
678 let mut offset = LogicalPoint::default();
679 let mut menubar_item = None;
680 for (idx, popup) in active_popups.borrow().iter().enumerate().rev() {
681 item_tree = None;
682 menubar_item = None;
683 if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {
684 let geom = ItemTreeRc::borrow_pin(&popup.component).as_ref().item_geometry(0);
685 let mouse_inside_popup = event
686 .position()
687 .is_none_or(|pos| geom.contains(pos - coordinates.to_vector()));
688 if mouse_inside_popup {
689 item_tree = Some(popup.component.clone());
690 offset = *coordinates;
691 break;
692 }
693 } else if native_popup_index.is_some_and(|i| i == idx) {
694 item_tree = self.component.borrow().upgrade();
695 break;
696 }
697
698 if !popup.is_menu {
699 break;
700 } else if popup_to_close.is_some() {
701 popup_to_close = Some(popup.popup_id);
703 }
704
705 menubar_item = popup.parent_item.upgrade();
706 }
707
708 let root = match menubar_item {
709 None => item_tree.map(|item_tree| ItemRc::new(item_tree.clone(), 0)),
710 Some(menubar_item) => {
711 event.translate(
712 menubar_item
713 .map_to_item_tree(Default::default(), &self.component())
714 .to_vector(),
715 );
716 menubar_item.parent_item(ParentItemTraversalMode::StopAtPopups)
717 }
718 };
719
720 if let Some(root) = root {
721 event.translate(-offset.to_vector());
722 let mut new_input_state = crate::input::process_mouse_input(
723 root,
724 &event,
725 &window_adapter,
726 mouse_input_state,
727 );
728 new_input_state.offset = offset;
729 new_input_state
730 } else {
731 let mut new_input_state = MouseInputState::default();
733 crate::input::send_exit_events(
734 &mouse_input_state,
735 &mut new_input_state,
736 event.position(),
737 &window_adapter,
738 );
739 new_input_state
740 }
741 } else {
742 mouse_input_state
743 };
744
745 if last_top_item != mouse_input_state.top_item_including_delayed() {
746 self.click_state.reset();
747 self.click_state.check_repeat(event, self.ctx.platform().click_interval());
748 }
749
750 self.mouse_input_state.set(mouse_input_state);
751
752 if let Some(popup_id) = popup_to_close {
753 WindowInner::from_pub(root_adapter.window()).close_popup(popup_id);
754 }
755
756 crate::properties::ChangeTracker::run_change_handlers();
757 }
758
759 pub(crate) fn process_delayed_event(&self) {
761 self.mouse_input_state.set(crate::input::process_delayed_event(
762 &self.window_adapter(),
763 self.mouse_input_state.take(),
764 ));
765 }
766
767 pub fn process_key_input(&self, mut event: KeyEvent) -> crate::input::KeyEventResult {
773 if let Some(updated_modifier) = self
774 .modifiers
775 .get()
776 .state_update(event.event_type == KeyEventType::KeyPressed, &event.text)
777 {
778 self.modifiers.set(updated_modifier);
780 }
781
782 event.modifiers = self.modifiers.get().into();
783
784 let mut item = self.focus_item.borrow().clone().upgrade();
785
786 if item.as_ref().is_some_and(|i| !i.is_visible()) {
787 self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation));
789 item = None;
790 }
791
792 let item_list = {
793 let mut tmp = Vec::new();
794 let mut item = item.clone();
795
796 while let Some(i) = item {
797 tmp.push(i.clone());
798 item = i.parent_item(ParentItemTraversalMode::StopAtPopups);
799 }
800
801 tmp
802 };
803
804 for i in item_list.iter().rev() {
806 if i.borrow().as_ref().capture_key_event(&event, &self.window_adapter(), i)
807 == crate::input::KeyEventResult::EventAccepted
808 {
809 crate::properties::ChangeTracker::run_change_handlers();
810 return crate::input::KeyEventResult::EventAccepted;
811 }
812 }
813
814 drop(item_list);
815
816 while let Some(focus_item) = item {
818 if focus_item.borrow().as_ref().key_event(&event, &self.window_adapter(), &focus_item)
819 == crate::input::KeyEventResult::EventAccepted
820 {
821 crate::properties::ChangeTracker::run_change_handlers();
822 return crate::input::KeyEventResult::EventAccepted;
823 }
824 item = focus_item.parent_item(ParentItemTraversalMode::StopAtPopups);
825 }
826
827 let extra_mod = event.modifiers.control || event.modifiers.meta || event.modifiers.alt;
829 if event.text.starts_with(key_codes::Tab)
830 && !event.modifiers.shift
831 && !extra_mod
832 && event.event_type == KeyEventType::KeyPressed
833 {
834 self.focus_next_item();
835 crate::properties::ChangeTracker::run_change_handlers();
836 return crate::input::KeyEventResult::EventAccepted;
837 } else if (event.text.starts_with(key_codes::Backtab)
838 || (event.text.starts_with(key_codes::Tab) && event.modifiers.shift))
839 && event.event_type == KeyEventType::KeyPressed
840 && !extra_mod
841 {
842 self.focus_previous_item();
843 crate::properties::ChangeTracker::run_change_handlers();
844 return crate::input::KeyEventResult::EventAccepted;
845 } else if event.event_type == KeyEventType::KeyPressed
846 && event.text.starts_with(key_codes::Escape)
847 {
848 let mut adapter = self.window_adapter();
852 let item_tree = self.component();
853 let mut a = None;
854 ItemTreeRc::borrow_pin(&item_tree).as_ref().window_adapter(false, &mut a);
855 if let Some(a) = a {
856 adapter = a;
857 }
858 let window = WindowInner::from_pub(adapter.window());
859
860 let close_on_escape = if let Some(popup) = window.active_popups.borrow().last() {
861 popup.close_policy == PopupClosePolicy::CloseOnClick
862 || popup.close_policy == PopupClosePolicy::CloseOnClickOutside
863 } else {
864 false
865 };
866
867 if close_on_escape {
868 window.close_top_popup();
869 }
870 crate::properties::ChangeTracker::run_change_handlers();
871 return crate::input::KeyEventResult::EventAccepted;
872 }
873 crate::properties::ChangeTracker::run_change_handlers();
874 crate::input::KeyEventResult::EventIgnored
875 }
876
877 pub fn set_cursor_blink_binding(&self, prop: &crate::Property<bool>) {
879 let existing_blinker = self.cursor_blinker.borrow().clone();
880
881 let blinker = existing_blinker.upgrade().unwrap_or_else(|| {
882 let new_blinker = TextCursorBlinker::new();
883 *self.cursor_blinker.borrow_mut() =
884 pin_weak::rc::PinWeak::downgrade(new_blinker.clone());
885 new_blinker
886 });
887
888 TextCursorBlinker::set_binding(blinker, prop, self.ctx.platform().cursor_flash_cycle());
889 }
890
891 pub fn set_focus_item(&self, new_focus_item: &ItemRc, set_focus: bool, reason: FocusReason) {
894 if self.prevent_focus_change.get() {
895 return;
896 }
897
898 let popup_wa = self.active_popups.borrow().last().and_then(|p| match &p.location {
899 PopupWindowLocation::TopLevel(wa) => Some(wa.clone()),
900 PopupWindowLocation::ChildWindow(..) => None,
901 });
902 if let Some(popup_wa) = popup_wa {
903 popup_wa.window().0.set_focus_item(new_focus_item, set_focus, reason);
905 return;
906 }
907
908 let current_focus_item = self.focus_item.borrow().clone();
909 if let Some(current_focus_item_rc) = current_focus_item.upgrade() {
910 if set_focus {
911 if current_focus_item_rc == *new_focus_item {
912 return;
914 }
915 } else if current_focus_item_rc != *new_focus_item {
916 return;
918 }
919 }
920
921 let old = self.take_focus_item(&FocusEvent::FocusOut(reason));
922 let new = if set_focus {
923 self.move_focus(new_focus_item.clone(), next_focus_item, reason)
924 } else {
925 None
926 };
927 let window_adapter = self.window_adapter();
928 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
929 window_adapter.handle_focus_change(old, new);
930 }
931 }
932
933 fn take_focus_item(&self, event: &FocusEvent) -> Option<ItemRc> {
937 let focus_item = self.focus_item.take();
938 assert!(matches!(event, FocusEvent::FocusOut(_)));
939
940 if let Some(focus_item_rc) = focus_item.upgrade() {
941 focus_item_rc.borrow().as_ref().focus_event(
942 event,
943 &self.window_adapter(),
944 &focus_item_rc,
945 );
946 Some(focus_item_rc)
947 } else {
948 None
949 }
950 }
951
952 fn publish_focus_item(
956 &self,
957 item: &Option<ItemRc>,
958 reason: FocusReason,
959 ) -> crate::input::FocusEventResult {
960 match item {
961 Some(item) => {
962 *self.focus_item.borrow_mut() = item.downgrade();
963 let result = item.borrow().as_ref().focus_event(
964 &FocusEvent::FocusIn(reason),
965 &self.window_adapter(),
966 item,
967 );
968 if result == crate::input::FocusEventResult::FocusAccepted {
970 item.try_scroll_into_visible();
971 }
972
973 result
974 }
975 None => {
976 *self.focus_item.borrow_mut() = Default::default();
977 crate::input::FocusEventResult::FocusAccepted }
979 }
980 }
981
982 fn move_focus(
983 &self,
984 start_item: ItemRc,
985 forward: impl Fn(ItemRc) -> ItemRc,
986 reason: FocusReason,
987 ) -> Option<ItemRc> {
988 let mut current_item = start_item;
989 let mut visited = Vec::new();
990
991 loop {
992 if (current_item.is_visible() || reason == FocusReason::Programmatic)
993 && self.publish_focus_item(&Some(current_item.clone()), reason)
994 == crate::input::FocusEventResult::FocusAccepted
995 {
996 return Some(current_item); }
998 visited.push(current_item.clone());
999 current_item = forward(current_item);
1000
1001 if visited.contains(¤t_item) {
1002 return None; }
1004 }
1005 }
1006
1007 pub fn focus_next_item(&self) {
1009 let start_item = self
1010 .take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation))
1011 .map(next_focus_item)
1012 .unwrap_or_else(|| {
1013 ItemRc::new(
1014 self.active_popups
1015 .borrow()
1016 .last()
1017 .map_or_else(|| self.component(), |p| p.component.clone()),
1018 0,
1019 )
1020 });
1021 let end_item =
1022 self.move_focus(start_item.clone(), next_focus_item, FocusReason::TabNavigation);
1023 let window_adapter = self.window_adapter();
1024 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
1025 window_adapter.handle_focus_change(Some(start_item), end_item);
1026 }
1027 }
1028
1029 pub fn focus_previous_item(&self) {
1031 let start_item = previous_focus_item(
1032 self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation)).unwrap_or_else(
1033 || {
1034 ItemRc::new(
1035 self.active_popups
1036 .borrow()
1037 .last()
1038 .map_or_else(|| self.component(), |p| p.component.clone()),
1039 0,
1040 )
1041 },
1042 ),
1043 );
1044 let end_item =
1045 self.move_focus(start_item.clone(), previous_focus_item, FocusReason::TabNavigation);
1046 let window_adapter = self.window_adapter();
1047 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
1048 window_adapter.handle_focus_change(Some(start_item), end_item);
1049 }
1050 }
1051
1052 pub fn set_active(&self, have_focus: bool) {
1058 self.pinned_fields.as_ref().project_ref().active.set(have_focus);
1059
1060 let event = if have_focus {
1061 FocusEvent::FocusIn(FocusReason::WindowActivation)
1062 } else {
1063 FocusEvent::FocusOut(FocusReason::WindowActivation)
1064 };
1065
1066 if let Some(focus_item) = self.focus_item.borrow().upgrade() {
1067 focus_item.borrow().as_ref().focus_event(&event, &self.window_adapter(), &focus_item);
1068 }
1069
1070 if !have_focus {
1073 self.modifiers.take();
1074 }
1075 }
1076
1077 pub fn active(&self) -> bool {
1080 self.pinned_fields.as_ref().project_ref().active.get()
1081 }
1082
1083 pub fn update_window_properties(&self) {
1086 let window_adapter = self.window_adapter();
1087
1088 self.pinned_fields
1091 .as_ref()
1092 .project_ref()
1093 .window_properties_tracker
1094 .evaluate_as_dependency_root(|| {
1095 window_adapter.update_window_properties(WindowProperties(self));
1096 });
1097 }
1098
1099 pub fn draw_contents<T>(
1103 &self,
1104 render_components: impl FnOnce(&[(ItemTreeWeak, LogicalPoint)]) -> T,
1105 ) -> Option<T> {
1106 let component_weak = ItemTreeRc::downgrade(&self.try_component()?);
1107 Some(self.pinned_fields.as_ref().project_ref().redraw_tracker.evaluate_as_dependency_root(
1108 || {
1109 if !self
1110 .active_popups
1111 .borrow()
1112 .iter()
1113 .any(|p| matches!(p.location, PopupWindowLocation::ChildWindow(..)))
1114 {
1115 render_components(&[(component_weak, LogicalPoint::default())])
1116 } else {
1117 let borrow = self.active_popups.borrow();
1118 let mut item_trees = Vec::with_capacity(borrow.len() + 1);
1119 item_trees.push((component_weak, LogicalPoint::default()));
1120 for popup in borrow.iter() {
1121 if let PopupWindowLocation::ChildWindow(location) = &popup.location {
1122 item_trees.push((ItemTreeRc::downgrade(&popup.component), *location));
1123 }
1124 }
1125 drop(borrow);
1126 render_components(&item_trees)
1127 }
1128 },
1129 ))
1130 }
1131
1132 pub fn show(&self) -> Result<(), PlatformError> {
1135 if let Some(component) = self.try_component() {
1136 let was_visible = self.strong_component_ref.replace(Some(component)).is_some();
1137 if !was_visible {
1138 *(self.ctx.0.window_count.borrow_mut()) += 1;
1139 }
1140 }
1141
1142 self.update_window_properties();
1143 self.window_adapter().set_visible(true)?;
1144 let size = self.window_adapter().size();
1147 let scale_factor = self.scale_factor();
1148 self.set_window_item_geometry(size.to_logical(scale_factor).to_euclid());
1149 let inset = self
1150 .window_adapter()
1151 .internal(crate::InternalToken)
1152 .map(|internal| internal.safe_area_inset())
1153 .unwrap_or_default();
1154 self.set_window_item_safe_area(inset.to_logical(scale_factor));
1155 self.window_adapter().renderer().resize(size).unwrap();
1156 if let Some(hook) = self.ctx.0.window_shown_hook.borrow_mut().as_mut() {
1157 hook(&self.window_adapter());
1158 }
1159 Ok(())
1160 }
1161
1162 pub fn hide(&self) -> Result<(), PlatformError> {
1164 let result = self.window_adapter().set_visible(false);
1165 let was_visible = self.strong_component_ref.borrow_mut().take().is_some();
1166 if was_visible {
1167 let mut count = self.ctx.0.window_count.borrow_mut();
1168 *count -= 1;
1169 if *count <= 0 {
1170 drop(count);
1171 let _ = self.ctx.event_loop_proxy().and_then(|p| p.quit_event_loop().ok());
1172 }
1173 }
1174 result
1175 }
1176
1177 pub fn color_scheme(&self) -> ColorScheme {
1179 self.window_adapter()
1180 .internal(crate::InternalToken)
1181 .map_or(ColorScheme::Unknown, |x| x.color_scheme())
1182 }
1183
1184 pub fn supports_native_menu_bar(&self) -> bool {
1186 self.window_adapter()
1187 .internal(crate::InternalToken)
1188 .is_some_and(|x| x.supports_native_menu_bar())
1189 }
1190
1191 pub fn setup_menubar(&self, menubar: vtable::VRc<MenuVTable>) {
1193 if let Some(x) = self.window_adapter().internal(crate::InternalToken) {
1194 x.setup_menubar(menubar);
1195 }
1196 }
1197
1198 pub fn show_popup(
1202 &self,
1203 popup_componentrc: &ItemTreeRc,
1204 position: LogicalPosition,
1205 close_policy: PopupClosePolicy,
1206 parent_item: &ItemRc,
1207 is_menu: bool,
1208 ) -> NonZeroU32 {
1209 let position = parent_item
1210 .map_to_window(parent_item.geometry().origin + position.to_euclid().to_vector());
1211 let root_of = |mut item_tree: ItemTreeRc| loop {
1212 if ItemRc::new(item_tree.clone(), 0).downcast::<crate::items::WindowItem>().is_some() {
1213 return item_tree;
1214 }
1215 let mut r = crate::item_tree::ItemWeak::default();
1216 ItemTreeRc::borrow_pin(&item_tree).as_ref().parent_node(&mut r);
1217 match r.upgrade() {
1218 None => return item_tree,
1219 Some(x) => item_tree = x.item_tree().clone(),
1220 }
1221 };
1222
1223 let parent_root_item_tree = root_of(parent_item.item_tree().clone());
1224 let (parent_window_adapter, position) = if let Some(parent_popup) = self
1225 .active_popups
1226 .borrow()
1227 .iter()
1228 .find(|p| ItemTreeRc::ptr_eq(&p.component, &parent_root_item_tree))
1229 {
1230 match &parent_popup.location {
1231 PopupWindowLocation::TopLevel(wa) => (wa.clone(), position),
1232 PopupWindowLocation::ChildWindow(offset) => {
1233 (self.window_adapter(), position + offset.to_vector())
1234 }
1235 }
1236 } else {
1237 (self.window_adapter(), position)
1238 };
1239
1240 let popup_component = ItemTreeRc::borrow_pin(popup_componentrc);
1241 let popup_root = popup_component.as_ref().get_item_ref(0);
1242
1243 let (mut w, mut h) = if let Some(window_item) =
1244 ItemRef::downcast_pin::<crate::items::WindowItem>(popup_root)
1245 {
1246 (window_item.width(), window_item.height())
1247 } else {
1248 (LogicalLength::zero(), LogicalLength::zero())
1249 };
1250
1251 let layout_info_h =
1252 popup_component.as_ref().layout_info(crate::layout::Orientation::Horizontal);
1253 let layout_info_v =
1254 popup_component.as_ref().layout_info(crate::layout::Orientation::Vertical);
1255
1256 if w <= LogicalLength::zero() {
1257 w = LogicalLength::new(layout_info_h.preferred);
1258 }
1259 if h <= LogicalLength::zero() {
1260 h = LogicalLength::new(layout_info_v.preferred);
1261 }
1262 w = w.max(LogicalLength::new(layout_info_h.min)).min(LogicalLength::new(layout_info_h.max));
1263 h = h.max(LogicalLength::new(layout_info_v.min)).min(LogicalLength::new(layout_info_v.max));
1264
1265 let size = crate::lengths::LogicalSize::from_lengths(w, h);
1266
1267 if let Some(window_item) = ItemRef::downcast_pin(popup_root) {
1268 let width_property =
1269 crate::items::WindowItem::FIELD_OFFSETS.width.apply_pin(window_item);
1270 let height_property =
1271 crate::items::WindowItem::FIELD_OFFSETS.height.apply_pin(window_item);
1272 width_property.set(size.width_length());
1273 height_property.set(size.height_length());
1274 };
1275
1276 let popup_id = self.next_popup_id.get();
1277 self.next_popup_id.set(self.next_popup_id.get().checked_add(1).unwrap());
1278
1279 let siblings: Vec<_> = self
1281 .active_popups
1282 .borrow()
1283 .iter()
1284 .filter(|p| p.parent_item == parent_item.downgrade())
1285 .map(|p| p.popup_id)
1286 .collect();
1287
1288 for sibling in siblings {
1289 self.close_popup(sibling);
1290 }
1291
1292 let location = match parent_window_adapter
1293 .internal(crate::InternalToken)
1294 .and_then(|x| x.create_popup(LogicalRect::new(position, size)))
1295 {
1296 None => {
1297 let clip = LogicalRect::new(
1298 LogicalPoint::new(0.0 as crate::Coord, 0.0 as crate::Coord),
1299 self.window_adapter().size().to_logical(self.scale_factor()).to_euclid(),
1300 );
1301 let rect = popup::place_popup(
1302 popup::Placement::Fixed(LogicalRect::new(position, size)),
1303 &Some(clip),
1304 );
1305 self.window_adapter().request_redraw();
1306 PopupWindowLocation::ChildWindow(rect.origin)
1307 }
1308 Some(window_adapter) => {
1309 WindowInner::from_pub(window_adapter.window()).set_component(popup_componentrc);
1310 PopupWindowLocation::TopLevel(window_adapter)
1311 }
1312 };
1313
1314 let focus_item = self
1315 .take_focus_item(&FocusEvent::FocusOut(FocusReason::PopupActivation))
1316 .map(|item| item.downgrade())
1317 .unwrap_or_default();
1318
1319 self.active_popups.borrow_mut().push(PopupWindow {
1320 popup_id,
1321 location,
1322 component: popup_componentrc.clone(),
1323 close_policy,
1324 focus_item_in_parent: focus_item,
1325 parent_item: parent_item.downgrade(),
1326 is_menu,
1327 });
1328
1329 popup_id
1330 }
1331
1332 pub fn show_native_popup_menu(
1338 &self,
1339 context_menu_item: vtable::VRc<MenuVTable>,
1340 position: LogicalPosition,
1341 parent_item: &ItemRc,
1342 ) -> bool {
1343 if let Some(x) = self.window_adapter().internal(crate::InternalToken) {
1344 let position = parent_item
1345 .map_to_window(parent_item.geometry().origin + position.to_euclid().to_vector());
1346 let position = crate::lengths::logical_position_to_api(position);
1347 x.show_native_popup_menu(context_menu_item, position)
1348 } else {
1349 false
1350 }
1351 }
1352
1353 fn close_popup_impl(&self, current_popup: &PopupWindow) {
1355 match ¤t_popup.location {
1356 PopupWindowLocation::ChildWindow(offset) => {
1357 let popup_region = crate::properties::evaluate_no_tracking(|| {
1359 let popup_component = ItemTreeRc::borrow_pin(¤t_popup.component);
1360 popup_component.as_ref().item_geometry(0)
1361 })
1362 .translate(offset.to_vector());
1363
1364 if !popup_region.is_empty() {
1365 let window_adapter = self.window_adapter();
1366 window_adapter.renderer().mark_dirty_region(popup_region.into());
1367 window_adapter.request_redraw();
1368 }
1369 }
1370 PopupWindowLocation::TopLevel(adapter) => {
1371 let _ = adapter.set_visible(false);
1372 }
1373 }
1374 if let Some(focus) = current_popup.focus_item_in_parent.upgrade() {
1375 self.set_focus_item(&focus, true, FocusReason::PopupActivation);
1376 }
1377 }
1378
1379 pub fn close_popup(&self, popup_id: NonZeroU32) {
1381 let mut active_popups = self.active_popups.borrow_mut();
1382 let maybe_index = active_popups.iter().position(|popup| popup.popup_id == popup_id);
1383
1384 if let Some(popup_index) = maybe_index {
1385 let p = active_popups.remove(popup_index);
1386 drop(active_popups);
1387 self.close_popup_impl(&p);
1388 if p.is_menu {
1389 while self.active_popups.borrow().get(popup_index).is_some_and(|p| p.is_menu) {
1391 let p = self.active_popups.borrow_mut().remove(popup_index);
1392 self.close_popup_impl(&p);
1393 }
1394 }
1395 }
1396 }
1397
1398 pub fn close_all_popups(&self) {
1400 for popup in self.active_popups.take() {
1401 self.close_popup_impl(&popup);
1402 }
1403 }
1404
1405 pub fn close_top_popup(&self) {
1407 let popup = self.active_popups.borrow_mut().pop();
1408 if let Some(popup) = popup {
1409 self.close_popup_impl(&popup);
1410 }
1411 }
1412
1413 pub fn scale_factor(&self) -> f32 {
1415 self.pinned_fields.as_ref().project_ref().scale_factor.get()
1416 }
1417
1418 pub(crate) fn set_scale_factor(&self, factor: f32) {
1420 if !self.pinned_fields.scale_factor.is_constant() {
1421 self.pinned_fields.scale_factor.set(factor)
1422 }
1423 }
1424
1425 pub fn set_const_scale_factor(&self, factor: f32) {
1428 if !self.pinned_fields.scale_factor.is_constant() {
1429 self.pinned_fields.scale_factor.set(factor);
1430 self.pinned_fields.scale_factor.set_constant();
1431 }
1432 }
1433
1434 pub fn text_input_focused(&self) -> bool {
1436 self.pinned_fields.as_ref().project_ref().text_input_focused.get()
1437 }
1438
1439 pub fn set_text_input_focused(&self, value: bool) {
1441 self.pinned_fields.text_input_focused.set(value)
1442 }
1443
1444 pub fn is_visible(&self) -> bool {
1446 self.strong_component_ref.borrow().is_some()
1447 }
1448
1449 pub fn window_item_rc(&self) -> Option<ItemRc> {
1452 self.try_component().and_then(|component_rc| {
1453 let item_rc = ItemRc::new(component_rc, 0);
1454 if item_rc.downcast::<crate::items::WindowItem>().is_some() {
1455 Some(item_rc)
1456 } else {
1457 None
1458 }
1459 })
1460 }
1461
1462 pub fn window_item(&self) -> Option<VRcMapped<ItemTreeVTable, crate::items::WindowItem>> {
1464 self.try_component().and_then(|component_rc| {
1465 ItemRc::new(component_rc, 0).downcast::<crate::items::WindowItem>()
1466 })
1467 }
1468
1469 pub(crate) fn set_window_item_geometry(&self, size: crate::lengths::LogicalSize) {
1472 if let Some(component_rc) = self.try_component() {
1473 let component = ItemTreeRc::borrow_pin(&component_rc);
1474 let root_item = component.as_ref().get_item_ref(0);
1475 if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
1476 {
1477 window_item.width.set(size.width_length());
1478 window_item.height.set(size.height_length());
1479 }
1480 }
1481 }
1482
1483 pub fn set_window_item_safe_area(&self, inset: crate::lengths::LogicalEdges) {
1485 if let Some(component_rc) = self.try_component() {
1486 let component = ItemTreeRc::borrow_pin(&component_rc);
1487 let root_item = component.as_ref().get_item_ref(0);
1488 if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
1489 {
1490 window_item.safe_area_insets.set(inset);
1491 }
1492 }
1493 }
1494
1495 pub(crate) fn set_window_item_virtual_keyboard(
1496 &self,
1497 origin: crate::lengths::LogicalPoint,
1498 size: crate::lengths::LogicalSize,
1499 ) {
1500 let Some(component_rc) = self.try_component() else {
1501 return;
1502 };
1503 let component = ItemTreeRc::borrow_pin(&component_rc);
1504 let root_item = component.as_ref().get_item_ref(0);
1505 let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item) else {
1506 return;
1507 };
1508 window_item.virtual_keyboard_position.set(origin);
1509 window_item.virtual_keyboard_size.set(size);
1510 if let Some(focus_item) = self.focus_item.borrow().upgrade() {
1511 focus_item.try_scroll_into_visible();
1512 }
1513 }
1514
1515 pub(crate) fn window_item_virtual_keyboard(
1516 &self,
1517 ) -> Option<(crate::lengths::LogicalPoint, crate::lengths::LogicalSize)> {
1518 let component_rc = self.try_component()?;
1519 let component = ItemTreeRc::borrow_pin(&component_rc);
1520 let root_item = component.as_ref().get_item_ref(0);
1521 let window_item = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)?;
1522 Some((window_item.virtual_keyboard_position(), window_item.virtual_keyboard_size()))
1523 }
1524
1525 pub fn on_close_requested(&self, mut callback: impl FnMut() -> CloseRequestResponse + 'static) {
1527 self.close_requested.set_handler(move |()| callback());
1528 }
1529
1530 pub fn request_close(&self) -> bool {
1534 match self.close_requested.call(&()) {
1535 CloseRequestResponse::HideWindow => true,
1536 CloseRequestResponse::KeepWindowShown => false,
1537 }
1538 }
1539
1540 pub fn is_fullscreen(&self) -> bool {
1542 if let Some(window_item) = self.window_item() {
1543 window_item.as_pin_ref().full_screen()
1544 } else {
1545 false
1546 }
1547 }
1548
1549 pub fn set_fullscreen(&self, enabled: bool) {
1551 if let Some(window_item) = self.window_item() {
1552 window_item.as_pin_ref().full_screen.set(enabled);
1553 self.update_window_properties()
1554 }
1555 }
1556
1557 pub fn is_maximized(&self) -> bool {
1559 self.maximized.get()
1560 }
1561
1562 pub fn set_maximized(&self, maximized: bool) {
1564 self.maximized.set(maximized);
1565 self.update_window_properties()
1566 }
1567
1568 pub fn is_minimized(&self) -> bool {
1570 self.minimized.get()
1571 }
1572
1573 pub fn set_minimized(&self, minimized: bool) {
1575 self.minimized.set(minimized);
1576 self.update_window_properties()
1577 }
1578
1579 pub fn xdg_app_id(&self) -> Option<SharedString> {
1581 self.ctx.xdg_app_id()
1582 }
1583
1584 pub fn window_adapter(&self) -> Rc<dyn WindowAdapter> {
1586 self.window_adapter_weak.upgrade().unwrap()
1587 }
1588
1589 pub fn from_pub(window: &crate::api::Window) -> &Self {
1591 &window.0
1592 }
1593
1594 pub fn context(&self) -> &crate::SlintContext {
1596 &self.ctx
1597 }
1598}
1599
1600pub type WindowAdapterRc = Rc<dyn WindowAdapter>;
1602
1603#[cfg(feature = "ffi")]
1606pub mod ffi {
1607 #![allow(unsafe_code)]
1608 #![allow(clippy::missing_safety_doc)]
1609 #![allow(missing_docs)]
1610
1611 use super::*;
1612 use crate::SharedVector;
1613 use crate::api::{RenderingNotifier, RenderingState, SetRenderingNotifierError};
1614 use crate::graphics::Size;
1615 use crate::graphics::{IntSize, Rgba8Pixel};
1616 use crate::items::WindowItem;
1617
1618 #[repr(u8)]
1621 pub enum GraphicsAPI {
1622 NativeOpenGL,
1624 Inaccessible,
1626 }
1627
1628 #[allow(non_camel_case_types)]
1629 type c_void = ();
1630
1631 #[repr(C)]
1633 pub struct WindowAdapterRcOpaque(*const c_void, *const c_void);
1634
1635 #[unsafe(no_mangle)]
1637 pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut WindowAdapterRcOpaque) {
1638 unsafe {
1639 assert_eq!(
1640 core::mem::size_of::<Rc<dyn WindowAdapter>>(),
1641 core::mem::size_of::<WindowAdapterRcOpaque>()
1642 );
1643 assert_eq!(
1644 core::mem::size_of::<Option<Rc<dyn WindowAdapter>>>(),
1645 core::mem::size_of::<WindowAdapterRcOpaque>()
1646 );
1647 drop(core::ptr::read(handle as *mut Option<Rc<dyn WindowAdapter>>));
1648 }
1649 }
1650
1651 #[unsafe(no_mangle)]
1653 pub unsafe extern "C" fn slint_windowrc_clone(
1654 source: *const WindowAdapterRcOpaque,
1655 target: *mut WindowAdapterRcOpaque,
1656 ) {
1657 unsafe {
1658 assert_eq!(
1659 core::mem::size_of::<Rc<dyn WindowAdapter>>(),
1660 core::mem::size_of::<WindowAdapterRcOpaque>()
1661 );
1662 let window = &*(source as *const Rc<dyn WindowAdapter>);
1663 core::ptr::write(target as *mut Rc<dyn WindowAdapter>, window.clone());
1664 }
1665 }
1666
1667 #[unsafe(no_mangle)]
1669 pub unsafe extern "C" fn slint_windowrc_show(handle: *const WindowAdapterRcOpaque) {
1670 unsafe {
1671 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1672
1673 window_adapter.window().show().unwrap();
1674 }
1675 }
1676
1677 #[unsafe(no_mangle)]
1679 pub unsafe extern "C" fn slint_windowrc_hide(handle: *const WindowAdapterRcOpaque) {
1680 unsafe {
1681 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1682 window_adapter.window().hide().unwrap();
1683 }
1684 }
1685
1686 #[unsafe(no_mangle)]
1689 pub unsafe extern "C" fn slint_windowrc_is_visible(
1690 handle: *const WindowAdapterRcOpaque,
1691 ) -> bool {
1692 unsafe {
1693 let window = &*(handle as *const Rc<dyn WindowAdapter>);
1694 window.window().is_visible()
1695 }
1696 }
1697
1698 #[unsafe(no_mangle)]
1700 pub unsafe extern "C" fn slint_windowrc_get_scale_factor(
1701 handle: *const WindowAdapterRcOpaque,
1702 ) -> f32 {
1703 unsafe {
1704 assert_eq!(
1705 core::mem::size_of::<Rc<dyn WindowAdapter>>(),
1706 core::mem::size_of::<WindowAdapterRcOpaque>()
1707 );
1708 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1709 WindowInner::from_pub(window_adapter.window()).scale_factor()
1710 }
1711 }
1712
1713 #[unsafe(no_mangle)]
1715 pub unsafe extern "C" fn slint_windowrc_set_const_scale_factor(
1716 handle: *const WindowAdapterRcOpaque,
1717 value: f32,
1718 ) {
1719 unsafe {
1720 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1721 WindowInner::from_pub(window_adapter.window()).set_const_scale_factor(value)
1722 }
1723 }
1724
1725 #[unsafe(no_mangle)]
1727 pub unsafe extern "C" fn slint_windowrc_get_text_input_focused(
1728 handle: *const WindowAdapterRcOpaque,
1729 ) -> bool {
1730 unsafe {
1731 assert_eq!(
1732 core::mem::size_of::<Rc<dyn WindowAdapter>>(),
1733 core::mem::size_of::<WindowAdapterRcOpaque>()
1734 );
1735 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1736 WindowInner::from_pub(window_adapter.window()).text_input_focused()
1737 }
1738 }
1739
1740 #[unsafe(no_mangle)]
1742 pub unsafe extern "C" fn slint_windowrc_set_text_input_focused(
1743 handle: *const WindowAdapterRcOpaque,
1744 value: bool,
1745 ) {
1746 unsafe {
1747 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1748 WindowInner::from_pub(window_adapter.window()).set_text_input_focused(value)
1749 }
1750 }
1751
1752 #[unsafe(no_mangle)]
1754 pub unsafe extern "C" fn slint_windowrc_set_focus_item(
1755 handle: *const WindowAdapterRcOpaque,
1756 focus_item: &ItemRc,
1757 set_focus: bool,
1758 reason: FocusReason,
1759 ) {
1760 unsafe {
1761 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1762 WindowInner::from_pub(window_adapter.window())
1763 .set_focus_item(focus_item, set_focus, reason)
1764 }
1765 }
1766
1767 #[unsafe(no_mangle)]
1769 pub unsafe extern "C" fn slint_windowrc_set_component(
1770 handle: *const WindowAdapterRcOpaque,
1771 component: &ItemTreeRc,
1772 ) {
1773 unsafe {
1774 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1775 WindowInner::from_pub(window_adapter.window()).set_component(component)
1776 }
1777 }
1778
1779 #[unsafe(no_mangle)]
1781 pub unsafe extern "C" fn slint_windowrc_show_popup(
1782 handle: *const WindowAdapterRcOpaque,
1783 popup: &ItemTreeRc,
1784 position: LogicalPosition,
1785 close_policy: PopupClosePolicy,
1786 parent_item: &ItemRc,
1787 is_menu: bool,
1788 ) -> NonZeroU32 {
1789 unsafe {
1790 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1791 WindowInner::from_pub(window_adapter.window()).show_popup(
1792 popup,
1793 position,
1794 close_policy,
1795 parent_item,
1796 is_menu,
1797 )
1798 }
1799 }
1800
1801 #[unsafe(no_mangle)]
1803 pub unsafe extern "C" fn slint_windowrc_close_popup(
1804 handle: *const WindowAdapterRcOpaque,
1805 popup_id: NonZeroU32,
1806 ) {
1807 unsafe {
1808 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1809 WindowInner::from_pub(window_adapter.window()).close_popup(popup_id);
1810 }
1811 }
1812
1813 #[unsafe(no_mangle)]
1815 pub unsafe extern "C" fn slint_windowrc_set_rendering_notifier(
1816 handle: *const WindowAdapterRcOpaque,
1817 callback: extern "C" fn(
1818 rendering_state: RenderingState,
1819 graphics_api: GraphicsAPI,
1820 user_data: *mut c_void,
1821 ),
1822 drop_user_data: extern "C" fn(user_data: *mut c_void),
1823 user_data: *mut c_void,
1824 error: *mut SetRenderingNotifierError,
1825 ) -> bool {
1826 unsafe {
1827 struct CNotifier {
1828 callback: extern "C" fn(
1829 rendering_state: RenderingState,
1830 graphics_api: GraphicsAPI,
1831 user_data: *mut c_void,
1832 ),
1833 drop_user_data: extern "C" fn(*mut c_void),
1834 user_data: *mut c_void,
1835 }
1836
1837 impl Drop for CNotifier {
1838 fn drop(&mut self) {
1839 (self.drop_user_data)(self.user_data)
1840 }
1841 }
1842
1843 impl RenderingNotifier for CNotifier {
1844 fn notify(
1845 &mut self,
1846 state: RenderingState,
1847 graphics_api: &crate::api::GraphicsAPI,
1848 ) {
1849 let cpp_graphics_api = match graphics_api {
1850 crate::api::GraphicsAPI::NativeOpenGL { .. } => GraphicsAPI::NativeOpenGL,
1851 crate::api::GraphicsAPI::WebGL { .. } => unreachable!(), #[cfg(feature = "unstable-wgpu-27")]
1853 crate::api::GraphicsAPI::WGPU27 { .. } => GraphicsAPI::Inaccessible, #[cfg(feature = "unstable-wgpu-28")]
1855 crate::api::GraphicsAPI::WGPU28 { .. } => GraphicsAPI::Inaccessible, };
1857 (self.callback)(state, cpp_graphics_api, self.user_data)
1858 }
1859 }
1860
1861 let window = &*(handle as *const Rc<dyn WindowAdapter>);
1862 match window.renderer().set_rendering_notifier(Box::new(CNotifier {
1863 callback,
1864 drop_user_data,
1865 user_data,
1866 })) {
1867 Ok(()) => true,
1868 Err(err) => {
1869 *error = err;
1870 false
1871 }
1872 }
1873 }
1874 }
1875
1876 #[unsafe(no_mangle)]
1878 pub unsafe extern "C" fn slint_windowrc_on_close_requested(
1879 handle: *const WindowAdapterRcOpaque,
1880 callback: extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse,
1881 drop_user_data: extern "C" fn(user_data: *mut c_void),
1882 user_data: *mut c_void,
1883 ) {
1884 unsafe {
1885 struct WithUserData {
1886 callback: extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse,
1887 drop_user_data: extern "C" fn(*mut c_void),
1888 user_data: *mut c_void,
1889 }
1890
1891 impl Drop for WithUserData {
1892 fn drop(&mut self) {
1893 (self.drop_user_data)(self.user_data)
1894 }
1895 }
1896
1897 impl WithUserData {
1898 fn call(&self) -> CloseRequestResponse {
1899 (self.callback)(self.user_data)
1900 }
1901 }
1902
1903 let with_user_data = WithUserData { callback, drop_user_data, user_data };
1904
1905 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1906 window_adapter.window().on_close_requested(move || with_user_data.call());
1907 }
1908 }
1909
1910 #[unsafe(no_mangle)]
1912 pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const WindowAdapterRcOpaque) {
1913 unsafe {
1914 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1915 window_adapter.request_redraw();
1916 }
1917 }
1918
1919 #[unsafe(no_mangle)]
1922 pub unsafe extern "C" fn slint_windowrc_position(
1923 handle: *const WindowAdapterRcOpaque,
1924 pos: &mut euclid::default::Point2D<i32>,
1925 ) {
1926 unsafe {
1927 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1928 *pos = window_adapter.position().unwrap_or_default().to_euclid()
1929 }
1930 }
1931
1932 #[unsafe(no_mangle)]
1936 pub unsafe extern "C" fn slint_windowrc_set_physical_position(
1937 handle: *const WindowAdapterRcOpaque,
1938 pos: &euclid::default::Point2D<i32>,
1939 ) {
1940 unsafe {
1941 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1942 window_adapter.set_position(crate::api::PhysicalPosition::new(pos.x, pos.y).into());
1943 }
1944 }
1945
1946 #[unsafe(no_mangle)]
1950 pub unsafe extern "C" fn slint_windowrc_set_logical_position(
1951 handle: *const WindowAdapterRcOpaque,
1952 pos: &euclid::default::Point2D<f32>,
1953 ) {
1954 unsafe {
1955 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1956 window_adapter.set_position(LogicalPosition::new(pos.x, pos.y).into());
1957 }
1958 }
1959
1960 #[unsafe(no_mangle)]
1963 pub unsafe extern "C" fn slint_windowrc_size(handle: *const WindowAdapterRcOpaque) -> IntSize {
1964 unsafe {
1965 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1966 window_adapter.size().to_euclid().cast()
1967 }
1968 }
1969
1970 #[unsafe(no_mangle)]
1973 pub unsafe extern "C" fn slint_windowrc_set_physical_size(
1974 handle: *const WindowAdapterRcOpaque,
1975 size: &IntSize,
1976 ) {
1977 unsafe {
1978 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1979 window_adapter
1980 .window()
1981 .set_size(crate::api::PhysicalSize::new(size.width, size.height));
1982 }
1983 }
1984
1985 #[unsafe(no_mangle)]
1988 pub unsafe extern "C" fn slint_windowrc_set_logical_size(
1989 handle: *const WindowAdapterRcOpaque,
1990 size: &Size,
1991 ) {
1992 unsafe {
1993 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
1994 window_adapter.window().set_size(crate::api::LogicalSize::new(size.width, size.height));
1995 }
1996 }
1997
1998 #[unsafe(no_mangle)]
2000 pub unsafe extern "C" fn slint_windowrc_color_scheme(
2001 handle: *const WindowAdapterRcOpaque,
2002 ) -> ColorScheme {
2003 unsafe {
2004 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2005 window_adapter
2006 .internal(crate::InternalToken)
2007 .map_or(ColorScheme::Unknown, |x| x.color_scheme())
2008 }
2009 }
2010
2011 #[unsafe(no_mangle)]
2013 pub unsafe extern "C" fn slint_windowrc_supports_native_menu_bar(
2014 handle: *const WindowAdapterRcOpaque,
2015 ) -> bool {
2016 unsafe {
2017 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2018 window_adapter
2019 .internal(crate::InternalToken)
2020 .is_some_and(|x| x.supports_native_menu_bar())
2021 }
2022 }
2023
2024 #[unsafe(no_mangle)]
2026 pub unsafe extern "C" fn slint_windowrc_setup_native_menu_bar(
2027 handle: *const WindowAdapterRcOpaque,
2028 menu_instance: &vtable::VRc<MenuVTable>,
2029 ) {
2030 unsafe {
2031 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2032 if let Some(x) = window_adapter.internal(crate::InternalToken) {
2033 x.setup_menubar(menu_instance.clone())
2034 }
2035 }
2036 }
2037
2038 #[unsafe(no_mangle)]
2040 pub unsafe extern "C" fn slint_windowrc_show_native_popup_menu(
2041 handle: *const WindowAdapterRcOpaque,
2042 context_menu: &vtable::VRc<MenuVTable>,
2043 position: LogicalPosition,
2044 parent_item: &ItemRc,
2045 ) -> bool {
2046 unsafe {
2047 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2048 WindowInner::from_pub(window_adapter.window()).show_native_popup_menu(
2049 context_menu.clone(),
2050 position,
2051 parent_item,
2052 )
2053 }
2054 }
2055
2056 #[unsafe(no_mangle)]
2058 pub unsafe extern "C" fn slint_windowrc_resolved_default_font_size(
2059 item_tree: &ItemTreeRc,
2060 ) -> f32 {
2061 WindowItem::resolved_default_font_size(item_tree.clone()).get()
2062 }
2063
2064 #[unsafe(no_mangle)]
2066 pub unsafe extern "C" fn slint_windowrc_dispatch_key_event(
2067 handle: *const WindowAdapterRcOpaque,
2068 event_type: crate::input::KeyEventType,
2069 text: &SharedString,
2070 repeat: bool,
2071 ) {
2072 unsafe {
2073 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2074 window_adapter.window().0.process_key_input(crate::items::KeyEvent {
2075 text: text.clone(),
2076 repeat,
2077 event_type,
2078 ..Default::default()
2079 });
2080 }
2081 }
2082
2083 #[unsafe(no_mangle)]
2085 pub unsafe extern "C" fn slint_windowrc_dispatch_pointer_event(
2086 handle: *const WindowAdapterRcOpaque,
2087 event: &crate::input::MouseEvent,
2088 ) {
2089 unsafe {
2090 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2091 window_adapter.window().0.process_mouse_input(event.clone());
2092 }
2093 }
2094
2095 #[unsafe(no_mangle)]
2097 pub unsafe extern "C" fn slint_windowrc_dispatch_event(
2098 handle: *const WindowAdapterRcOpaque,
2099 event: &crate::platform::WindowEvent,
2100 ) {
2101 unsafe {
2102 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2103 window_adapter.window().dispatch_event(event.clone());
2104 }
2105 }
2106
2107 #[unsafe(no_mangle)]
2108 pub unsafe extern "C" fn slint_windowrc_is_fullscreen(
2109 handle: *const WindowAdapterRcOpaque,
2110 ) -> bool {
2111 unsafe {
2112 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2113 window_adapter.window().is_fullscreen()
2114 }
2115 }
2116
2117 #[unsafe(no_mangle)]
2118 pub unsafe extern "C" fn slint_windowrc_is_minimized(
2119 handle: *const WindowAdapterRcOpaque,
2120 ) -> bool {
2121 unsafe {
2122 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2123 window_adapter.window().is_minimized()
2124 }
2125 }
2126
2127 #[unsafe(no_mangle)]
2128 pub unsafe extern "C" fn slint_windowrc_is_maximized(
2129 handle: *const WindowAdapterRcOpaque,
2130 ) -> bool {
2131 unsafe {
2132 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2133 window_adapter.window().is_maximized()
2134 }
2135 }
2136
2137 #[unsafe(no_mangle)]
2138 pub unsafe extern "C" fn slint_windowrc_set_fullscreen(
2139 handle: *const WindowAdapterRcOpaque,
2140 value: bool,
2141 ) {
2142 unsafe {
2143 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2144 window_adapter.window().set_fullscreen(value)
2145 }
2146 }
2147
2148 #[unsafe(no_mangle)]
2149 pub unsafe extern "C" fn slint_windowrc_set_minimized(
2150 handle: *const WindowAdapterRcOpaque,
2151 value: bool,
2152 ) {
2153 unsafe {
2154 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2155 window_adapter.window().set_minimized(value)
2156 }
2157 }
2158
2159 #[unsafe(no_mangle)]
2160 pub unsafe extern "C" fn slint_windowrc_set_maximized(
2161 handle: *const WindowAdapterRcOpaque,
2162 value: bool,
2163 ) {
2164 unsafe {
2165 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2166 window_adapter.window().set_maximized(value)
2167 }
2168 }
2169
2170 #[unsafe(no_mangle)]
2172 pub unsafe extern "C" fn slint_windowrc_take_snapshot(
2173 handle: *const WindowAdapterRcOpaque,
2174 data: &mut SharedVector<Rgba8Pixel>,
2175 width: &mut u32,
2176 height: &mut u32,
2177 ) -> bool {
2178 unsafe {
2179 let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2180 if let Ok(snapshot) = window_adapter.window().take_snapshot() {
2181 *data = snapshot.data.clone();
2182 *width = snapshot.width();
2183 *height = snapshot.height();
2184 true
2185 } else {
2186 false
2187 }
2188 }
2189 }
2190}
2191
2192#[cfg(all(feature = "ffi", feature = "raw-window-handle-06"))]
2194pub mod ffi_window {
2195 #![allow(unsafe_code)]
2196 #![allow(clippy::missing_safety_doc)]
2197
2198 use super::ffi::WindowAdapterRcOpaque;
2199 use super::*;
2200 use std::ffi::c_void;
2201 use std::ptr::null_mut;
2202 use std::sync::Arc;
2203
2204 fn has_window_handle(
2206 handle: *const WindowAdapterRcOpaque,
2207 ) -> Option<Arc<dyn raw_window_handle_06::HasWindowHandle>> {
2208 let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2209 let window_adapter = window_adapter.internal(crate::InternalToken)?;
2210 window_adapter.window_handle_06_rc().ok()
2211 }
2212
2213 fn has_display_handle(
2215 handle: *const WindowAdapterRcOpaque,
2216 ) -> Option<Arc<dyn raw_window_handle_06::HasDisplayHandle>> {
2217 let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2218 let window_adapter = window_adapter.internal(crate::InternalToken)?;
2219 window_adapter.display_handle_06_rc().ok()
2220 }
2221
2222 #[unsafe(no_mangle)]
2224 pub unsafe extern "C" fn slint_windowrc_hwnd_win32(
2225 handle: *const WindowAdapterRcOpaque,
2226 ) -> *mut c_void {
2227 use raw_window_handle_06::HasWindowHandle;
2228
2229 if let Some(has_window_handle) = has_window_handle(handle)
2230 && let Ok(window_handle) = has_window_handle.window_handle()
2231 && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()
2232 {
2233 isize::from(win32.hwnd) as *mut c_void
2234 } else {
2235 null_mut()
2236 }
2237 }
2238
2239 #[unsafe(no_mangle)]
2241 pub unsafe extern "C" fn slint_windowrc_hinstance_win32(
2242 handle: *const WindowAdapterRcOpaque,
2243 ) -> *mut c_void {
2244 use raw_window_handle_06::HasWindowHandle;
2245
2246 if let Some(has_window_handle) = has_window_handle(handle)
2247 && let Ok(window_handle) = has_window_handle.window_handle()
2248 && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()
2249 {
2250 win32
2251 .hinstance
2252 .map(|hinstance| isize::from(hinstance) as *mut c_void)
2253 .unwrap_or_default()
2254 } else {
2255 null_mut()
2256 }
2257 }
2258
2259 #[unsafe(no_mangle)]
2261 pub unsafe extern "C" fn slint_windowrc_wlsurface_wayland(
2262 handle: *const WindowAdapterRcOpaque,
2263 ) -> *mut c_void {
2264 use raw_window_handle_06::HasWindowHandle;
2265
2266 if let Some(has_window_handle) = has_window_handle(handle)
2267 && let Ok(window_handle) = has_window_handle.window_handle()
2268 && let raw_window_handle_06::RawWindowHandle::Wayland(wayland) = window_handle.as_raw()
2269 {
2270 wayland.surface.as_ptr()
2271 } else {
2272 null_mut()
2273 }
2274 }
2275
2276 #[unsafe(no_mangle)]
2278 pub unsafe extern "C" fn slint_windowrc_wldisplay_wayland(
2279 handle: *const WindowAdapterRcOpaque,
2280 ) -> *mut c_void {
2281 use raw_window_handle_06::HasDisplayHandle;
2282
2283 if let Some(has_display_handle) = has_display_handle(handle)
2284 && let Ok(display_handle) = has_display_handle.display_handle()
2285 && let raw_window_handle_06::RawDisplayHandle::Wayland(wayland) =
2286 display_handle.as_raw()
2287 {
2288 wayland.display.as_ptr()
2289 } else {
2290 null_mut()
2291 }
2292 }
2293
2294 #[unsafe(no_mangle)]
2296 pub unsafe extern "C" fn slint_windowrc_nsview_appkit(
2297 handle: *const WindowAdapterRcOpaque,
2298 ) -> *mut c_void {
2299 use raw_window_handle_06::HasWindowHandle;
2300
2301 if let Some(has_window_handle) = has_window_handle(handle)
2302 && let Ok(window_handle) = has_window_handle.window_handle()
2303 && let raw_window_handle_06::RawWindowHandle::AppKit(appkit) = window_handle.as_raw()
2304 {
2305 appkit.ns_view.as_ptr()
2306 } else {
2307 null_mut()
2308 }
2309 }
2310}