orinium_browser/platform/system/
app.rs1use std::collections::HashMap;
12use std::sync::Arc;
13use winit::application::ApplicationHandler;
14use winit::event::WindowEvent;
15use winit::event_loop::ActiveEventLoop;
16use winit::window::{Cursor, Window, WindowId};
17
18use crate::platform::renderer::draw_sink::DrawSink;
19use crate::platform::renderer::gpu::GpuRenderer;
20use crate::platform::system::shell::{BrowserHost, ShellCommand, WindowGeometry};
21
22pub struct WindowState {
23 pub window: Arc<Window>,
24 pub sink: Box<dyn DrawSink>,
30}
31
32pub struct App {
33 windows: HashMap<WindowId, WindowState>,
34 host: Box<dyn BrowserHost>,
35}
36
37impl App {
38 pub fn new(host: Box<dyn BrowserHost>) -> Self {
40 Self {
41 windows: HashMap::new(),
42 host,
43 }
44 }
45
46 fn create_window(&mut self, event_loop: &ActiveEventLoop, geometry: WindowGeometry) {
52 let WindowGeometry { size, title, .. } = geometry;
53
54 let window = Arc::new(
55 event_loop
56 .create_window(
57 Window::default_attributes()
58 .with_inner_size(winit::dpi::PhysicalSize::new(size.0, size.1))
59 .with_title(&title),
60 )
61 .unwrap(),
62 );
63 let window_id = window.id();
64 let initial_size = window.inner_size();
65 let scale_factor = window.scale_factor();
66 let gpu_renderer = pollster::block_on(GpuRenderer::new(Arc::clone(&window), None)).unwrap();
67
68 self.host.open_window(
69 window_id,
70 WindowGeometry {
71 size: (initial_size.width, initial_size.height),
72 title,
73 scale_factor,
74 },
75 );
76
77 let mut state = WindowState {
78 window,
79 sink: Box::new(gpu_renderer),
80 };
81
82 self.host
83 .apply_draw_commands(window_id, state.sink.as_mut());
84 state.window.request_redraw();
85
86 self.windows.insert(window_id, state);
87 }
88
89 fn default_geometry(&self) -> WindowGeometry {
91 WindowGeometry {
92 size: self.host.default_window_size(),
93 title: self.host.default_window_title(),
94 scale_factor: 1.0,
96 }
97 }
98}
99
100impl ApplicationHandler for App {
101 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
102 if !self.host.has_pending_default_window() {
103 log::error!("BrowserApp has no default UI configured");
104 return;
105 }
106
107 self.create_window(event_loop, self.default_geometry());
108 }
109
110 fn window_event(
111 &mut self,
112 event_loop: &ActiveEventLoop,
113 window_id: WindowId,
114 event: WindowEvent,
115 ) {
116 if !self.windows.contains_key(&window_id) {
117 return;
118 }
119
120 let cmd = {
121 let state = self.windows.get_mut(&window_id).unwrap();
122 self.host
123 .handle_window_event(window_id, event, state.sink.as_mut())
124 };
125
126 match cmd {
127 ShellCommand::Exit => {
128 self.windows.remove(&window_id);
129 self.host.close_window(window_id);
130 if self.windows.is_empty() {
131 event_loop.exit();
132 }
133 }
134 ShellCommand::RequestRedraw => {
135 if let Some(state) = self.windows.get(&window_id) {
136 state.window.request_redraw();
137 state.window.set_title(&self.host.window_title(window_id));
138 }
139 }
140 ShellCommand::RenameWindowTitle => {
141 if let Some(state) = self.windows.get(&window_id) {
142 state.window.set_title(&self.host.window_title(window_id));
143 }
144 }
145 ShellCommand::OpenNewWindow => {
146 let geometry = self.default_geometry();
147 self.create_window(event_loop, geometry);
148 }
149 ShellCommand::SetImeAllowed { allowed, position } => {
150 if let Some(state) = self.windows.get(&window_id) {
151 state.window.set_ime_allowed(allowed);
152 if allowed {
153 state.window.set_ime_cursor_area(
154 winit::dpi::PhysicalPosition::new(position.0, position.1 + 24.0),
155 winit::dpi::PhysicalSize::new(1.0, 1.0),
156 );
157 }
158 state.window.request_redraw();
159 }
160 }
161 ShellCommand::SetCursorIcon(icon) => {
162 if let Some(state) = self.windows.get(&window_id) {
163 state.window.set_cursor(Cursor::from(icon));
164 }
165 }
166 ShellCommand::None => {}
167 }
168 }
169
170 fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
171 let window_ids: Vec<WindowId> = self.windows.keys().copied().collect();
172 for window_id in window_ids {
173 if self.host.poll_window(window_id)
174 && let Some(state) = self.windows.get(&window_id)
175 {
176 state.window.request_redraw();
177 }
178 }
179 }
180}