repose_platform/
window_v2.rs1use repose_core::{Rect, Size};
3use repose_ui::window_v2::{
4 Screen, ScreenInsets, WindowBoundsProvider, WindowGeometryProviderScope, WindowMetrics,
5 WindowPlacement, WindowScreenProviderScope, WindowState,
6};
7
8pub use repose_ui::window_v2::{
9 DialogState, WindowConstraints, WindowPositionProvider, WindowScreenProvider,
10 WindowSizeProvider,
11};
12
13#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
14pub fn collect_screens(
15 event_loop: &winit::event_loop::ActiveEventLoop,
16 fallback_bounds: Rect,
17) -> Vec<Screen> {
18 let mut screens = Vec::new();
19 for monitor in event_loop.available_monitors() {
20 let pos = monitor.position();
21 let size = monitor.size();
22 let scale = monitor.scale_factor() as f32;
23 let bounds = Rect {
24 x: pos.x as f32 / scale,
25 y: pos.y as f32 / scale,
26 w: size.width as f32 / scale,
27 h: size.height as f32 / scale,
28 };
29 let id = monitor
30 .name()
31 .unwrap_or_else(|| format!("monitor-{}", screens.len()));
32 screens.push(Screen::new(id, bounds, ScreenInsets::default()));
33 }
34 if screens.is_empty() {
35 screens.push(Screen::primary(fallback_bounds));
36 }
37 screens
38}
39#[cfg(any(target_os = "android", target_arch = "wasm32"))]
40pub fn collect_screens(_: (), fallback_bounds: Rect) -> Vec<Screen> {
41 vec![Screen::primary(fallback_bounds)]
42}
43
44#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
45pub fn apply_window_state_to_winit(
46 state: &mut WindowState,
47 window: &winit::window::Window,
48 event_loop: Option<&winit::event_loop::ActiveEventLoop>,
49) {
50 let scale = window.scale_factor() as f32;
51 let inner = window.inner_size();
52 let outer_pos = window
53 .outer_position()
54 .map(|p| {
55 winit::dpi::LogicalPosition::new(p.x as f64 / scale as f64, p.y as f64 / scale as f64)
56 })
57 .unwrap_or(winit::dpi::LogicalPosition::new(0.0, 0.0));
58 let current_bounds = Rect {
59 x: outer_pos.x as f32,
60 y: outer_pos.y as f32,
61 w: inner.width as f32 / scale,
62 h: inner.height as f32 / scale,
63 };
64 let screens = if let Some(el) = event_loop {
65 collect_screens(el, current_bounds)
66 } else {
67 vec![Screen::primary(current_bounds)]
68 };
69 let default = screens
70 .first()
71 .cloned()
72 .unwrap_or_else(|| Screen::primary(current_bounds));
73 let screen_scope = WindowScreenProviderScope::new(screens.clone(), default.clone());
74 let screen_for_metrics = screens
75 .iter()
76 .find(|s| state.try_screen_id().map(|id| id == s.id).unwrap_or(false))
77 .cloned()
78 .unwrap_or(default);
79 let metrics = WindowMetrics::new(screen_for_metrics, current_bounds, ScreenInsets::default());
80 let geometry_scope = WindowGeometryProviderScope::new(None, metrics, |_c| Size {
81 width: current_bounds.w,
82 height: current_bounds.h,
83 });
84 if let Some(p) = state.take_pending_screen() {
85 let target = p.get_screen(&screen_scope);
86 let avail = target.available_bounds();
87 let x = avail.x + (avail.w - current_bounds.w) / 2.0;
88 let y = avail.y + (avail.h - current_bounds.h) / 2.0;
89 window.set_outer_position(winit::dpi::LogicalPosition::new(x as f64, y as f64));
90 }
91 if let Some(p) = state.take_pending_placement() {
92 apply_placement_to_winit(window, p);
93 state.on_host_placement_changed(p);
94 }
95 if let Some(m) = state.take_pending_minimized() {
96 window.set_minimized(m);
97 state.on_host_minimized_changed(m);
98 }
99 let pending = state.drain_pending_bounds();
100 for provider in pending {
101 let rect = provider.get_bounds(&geometry_scope);
102 let phys_w = (rect.w * scale).round() as u32;
103 let phys_h = (rect.h * scale).round() as u32;
104 let phys_x = (rect.x * scale).round() as i32;
105 let phys_y = (rect.y * scale).round() as i32;
106 let _ =
107 window.request_inner_size(winit::dpi::PhysicalSize::new(phys_w.max(1), phys_h.max(1)));
108 window.set_outer_position(winit::dpi::PhysicalPosition::new(phys_x, phys_y));
109 state.on_host_bounds_changed(rect, geometry_scope.window_metrics.screen.id.clone());
110 if state.try_placement() != Some(WindowPlacement::Floating) {
111 state.on_host_placement_changed(WindowPlacement::Floating);
112 }
113 }
114 if !state.is_initialized {
115 state.is_initialized = true;
116 }
117}
118#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
119fn apply_placement_to_winit(window: &winit::window::Window, placement: WindowPlacement) {
120 match placement {
121 WindowPlacement::Floating => {
122 window.set_maximized(false);
123 window.set_fullscreen(None);
124 }
125 WindowPlacement::Maximized => {
126 window.set_fullscreen(None);
127 window.set_maximized(true);
128 }
129 WindowPlacement::Fullscreen => {
130 window.set_maximized(false);
131 if let Some(m) = window
132 .current_monitor()
133 .or_else(|| window.available_monitors().next())
134 {
135 window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(Some(m))));
136 }
137 }
138 }
139}
140#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
141pub fn sync_window_state_from_winit(
142 state: &mut WindowState,
143 window: &winit::window::Window,
144 new_inner_size: Option<winit::dpi::PhysicalSize<u32>>,
145 new_outer_position: Option<winit::dpi::PhysicalPosition<i32>>,
146) {
147 let scale = window.scale_factor() as f32;
148 let size = new_inner_size.unwrap_or_else(|| window.inner_size());
149 let pos = new_outer_position
150 .or_else(|| window.outer_position().ok())
151 .map(|p| {
152 winit::dpi::LogicalPosition::new(p.x as f64 / scale as f64, p.y as f64 / scale as f64)
153 })
154 .unwrap_or(winit::dpi::LogicalPosition::new(0.0, 0.0));
155 let bounds = Rect {
156 x: pos.x as f32,
157 y: pos.y as f32,
158 w: size.width as f32 / scale,
159 h: size.height as f32 / scale,
160 };
161 let screen_id = window
162 .current_monitor()
163 .and_then(|m| m.name())
164 .unwrap_or_else(|| "primary".into());
165 state.on_host_bounds_changed(bounds, screen_id);
166}
167pub fn resolve_initial_bounds(
168 provider: &WindowBoundsProvider,
169 screen: Screen,
170 current_bounds: Rect,
171 measure_content: impl Fn(WindowConstraints) -> Size,
172) -> Rect {
173 let metrics = WindowMetrics::new(screen, current_bounds, ScreenInsets::default());
174 let scope = WindowGeometryProviderScope::new(None, metrics, measure_content);
175 provider.get_bounds(&scope)
176}