1 use std::cell::RefCell; 2 use std::collections::HashMap; 3 use std::error::Error; 4 use std::process; 5 use std::rc::Rc; 6 use std::time::{Duration, Instant}; 7 8 use sctk::reexports::client::protocol::wl_compositor::WlCompositor; 9 use sctk::reexports::client::protocol::wl_shm::WlShm; 10 use sctk::reexports::client::Display; 11 12 use sctk::reexports::calloop; 13 14 use sctk::environment::Environment; 15 use sctk::seat::pointer::{ThemeManager, ThemeSpec}; 16 use sctk::WaylandSource; 17 18 use crate::event::{Event, StartCause, WindowEvent}; 19 use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget}; 20 use crate::platform_impl::platform::sticky_exit_callback; 21 22 use super::env::{WindowingFeatures, WinitEnv}; 23 use super::output::OutputManager; 24 use super::seat::SeatManager; 25 use super::window::shim::{self, WindowUpdate}; 26 use super::{DeviceId, WindowId}; 27 28 mod proxy; 29 mod sink; 30 mod state; 31 32 pub use proxy::EventLoopProxy; 33 pub use state::WinitState; 34 35 use sink::EventSink; 36 37 pub struct EventLoopWindowTarget<T> { 38 /// Wayland display. 39 pub display: Display, 40 41 /// Environment to handle object creation, etc. 42 pub env: Environment<WinitEnv>, 43 44 /// Event loop handle. 45 pub event_loop_handle: calloop::LoopHandle<WinitState>, 46 47 /// Output manager. 48 pub output_manager: OutputManager, 49 50 /// State that we share across callbacks. 51 pub state: RefCell<WinitState>, 52 53 /// Wayland source. 54 pub wayland_source: Rc<calloop::Source<WaylandSource>>, 55 56 /// A proxy to wake up event loop. 57 pub event_loop_awakener: calloop::ping::Ping, 58 59 /// The available windowing features. 60 pub windowing_features: WindowingFeatures, 61 62 /// Theme manager to manage cursors. 63 /// 64 /// It's being shared amoung all windows to avoid loading 65 /// multiple similar themes. 66 pub theme_manager: ThemeManager, 67 68 _marker: std::marker::PhantomData<T>, 69 } 70 71 pub struct EventLoop<T: 'static> { 72 /// Event loop. 73 event_loop: calloop::EventLoop<WinitState>, 74 75 /// Wayland display. 76 display: Display, 77 78 /// Pending user events. 79 pending_user_events: Rc<RefCell<Vec<T>>>, 80 81 /// Sender of user events. 82 user_events_sender: calloop::channel::Sender<T>, 83 84 /// Wayland source of events. 85 wayland_source: Rc<calloop::Source<WaylandSource>>, 86 87 /// Window target. 88 window_target: RootEventLoopWindowTarget<T>, 89 90 /// Output manager. 91 _seat_manager: SeatManager, 92 } 93 94 impl<T: 'static> EventLoop<T> { new() -> Result<EventLoop<T>, Box<dyn Error>>95 pub fn new() -> Result<EventLoop<T>, Box<dyn Error>> { 96 // Connect to wayland server and setup event queue. 97 let display = Display::connect_to_env()?; 98 let mut event_queue = display.create_event_queue(); 99 let display_proxy = display.attach(event_queue.token()); 100 101 // Setup environment. 102 let env = Environment::new(&display_proxy, &mut event_queue, WinitEnv::new())?; 103 104 // Create event loop. 105 let event_loop = calloop::EventLoop::<WinitState>::new()?; 106 // Build windowing features. 107 let windowing_features = WindowingFeatures::new(&env); 108 109 // Create a theme manager. 110 let compositor = env.require_global::<WlCompositor>(); 111 let shm = env.require_global::<WlShm>(); 112 let theme_manager = ThemeManager::init(ThemeSpec::System, compositor, shm); 113 114 // Setup theme seat and output managers. 115 let seat_manager = SeatManager::new(&env, event_loop.handle(), theme_manager.clone()); 116 let output_manager = OutputManager::new(&env); 117 118 // A source of events that we plug into our event loop. 119 let wayland_source = WaylandSource::new(event_queue).quick_insert(event_loop.handle())?; 120 let wayland_source = Rc::new(wayland_source); 121 122 // A source of user events. 123 let pending_user_events = Rc::new(RefCell::new(Vec::new())); 124 let pending_user_events_clone = pending_user_events.clone(); 125 let (user_events_sender, user_events_channel) = calloop::channel::channel(); 126 127 // User events channel. 128 event_loop 129 .handle() 130 .insert_source(user_events_channel, move |event, _, _| { 131 if let calloop::channel::Event::Msg(msg) = event { 132 pending_user_events_clone.borrow_mut().push(msg); 133 } 134 })?; 135 136 // An event's loop awakener to wake up for window events from winit's windows. 137 let (event_loop_awakener, event_loop_awakener_source) = calloop::ping::make_ping()?; 138 139 // Handler of window requests. 140 event_loop.handle().insert_source( 141 event_loop_awakener_source, 142 move |_, _, winit_state| { 143 shim::handle_window_requests(winit_state); 144 }, 145 )?; 146 147 let event_loop_handle = event_loop.handle(); 148 let window_map = HashMap::new(); 149 let event_sink = EventSink::new(); 150 let window_updates = HashMap::new(); 151 152 // Create event loop window target. 153 let event_loop_window_target = EventLoopWindowTarget { 154 display: display.clone(), 155 env, 156 state: RefCell::new(WinitState { 157 window_map, 158 event_sink, 159 window_updates, 160 }), 161 event_loop_handle, 162 output_manager, 163 event_loop_awakener, 164 wayland_source: wayland_source.clone(), 165 windowing_features, 166 theme_manager, 167 _marker: std::marker::PhantomData, 168 }; 169 170 // Create event loop itself. 171 let event_loop = Self { 172 event_loop, 173 display, 174 pending_user_events, 175 wayland_source, 176 _seat_manager: seat_manager, 177 user_events_sender, 178 window_target: RootEventLoopWindowTarget { 179 p: crate::platform_impl::EventLoopWindowTarget::Wayland(event_loop_window_target), 180 _marker: std::marker::PhantomData, 181 }, 182 }; 183 184 Ok(event_loop) 185 } 186 run<F>(mut self, callback: F) -> ! where F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static,187 pub fn run<F>(mut self, callback: F) -> ! 188 where 189 F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static, 190 { 191 self.run_return(callback); 192 process::exit(0) 193 } 194 run_return<F>(&mut self, mut callback: F) where F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),195 pub fn run_return<F>(&mut self, mut callback: F) 196 where 197 F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow), 198 { 199 // Send pending events to the server. 200 let _ = self.display.flush(); 201 202 let mut control_flow = ControlFlow::default(); 203 204 let pending_user_events = self.pending_user_events.clone(); 205 206 callback( 207 Event::NewEvents(StartCause::Init), 208 &self.window_target, 209 &mut control_flow, 210 ); 211 212 let mut window_updates: Vec<(WindowId, WindowUpdate)> = Vec::new(); 213 let mut event_sink_back_buffer = Vec::new(); 214 215 // NOTE We break on errors from dispatches, since if we've got protocol error 216 // libwayland-client/wayland-rs will inform us anyway, but crashing downstream is not 217 // really an option. Instead we inform that the event loop got destroyed. We may 218 // communicate an error that something was terminated, but winit doesn't provide us 219 // with an API to do that via some event. 220 loop { 221 // Handle pending user events. We don't need back buffer, since we can't dispatch 222 // user events indirectly via callback to the user. 223 for user_event in pending_user_events.borrow_mut().drain(..) { 224 sticky_exit_callback( 225 Event::UserEvent(user_event), 226 &self.window_target, 227 &mut control_flow, 228 &mut callback, 229 ); 230 } 231 232 // Process 'new' pending updates. 233 self.with_state(|state| { 234 window_updates.clear(); 235 window_updates.extend( 236 state 237 .window_updates 238 .iter_mut() 239 .map(|(wid, window_update)| (*wid, window_update.take())), 240 ); 241 }); 242 243 for (window_id, window_update) in window_updates.iter_mut() { 244 if let Some(scale_factor) = window_update.scale_factor.map(|f| f as f64) { 245 let mut physical_size = self.with_state(|state| { 246 let window_handle = state.window_map.get(&window_id).unwrap(); 247 let mut size = window_handle.size.lock().unwrap(); 248 249 // Update the new logical size if it was changed. 250 let window_size = window_update.size.unwrap_or(*size); 251 *size = window_size; 252 253 window_size.to_physical(scale_factor) 254 }); 255 256 sticky_exit_callback( 257 Event::WindowEvent { 258 window_id: crate::window::WindowId( 259 crate::platform_impl::WindowId::Wayland(*window_id), 260 ), 261 event: WindowEvent::ScaleFactorChanged { 262 scale_factor, 263 new_inner_size: &mut physical_size, 264 }, 265 }, 266 &self.window_target, 267 &mut control_flow, 268 &mut callback, 269 ); 270 271 // We don't update size on a window handle since we'll do that later 272 // when handling size update. 273 let new_logical_size = physical_size.to_logical(scale_factor); 274 window_update.size = Some(new_logical_size); 275 } 276 277 if let Some(size) = window_update.size.take() { 278 let physical_size = self.with_state(|state| { 279 let window_handle = state.window_map.get_mut(&window_id).unwrap(); 280 let mut window_size = window_handle.size.lock().unwrap(); 281 282 // Always issue resize event on scale factor change. 283 let physical_size = 284 if window_update.scale_factor.is_none() && *window_size == size { 285 // The size hasn't changed, don't inform downstream about that. 286 None 287 } else { 288 *window_size = size; 289 let scale_factor = 290 sctk::get_surface_scale_factor(&window_handle.window.surface()); 291 let physical_size = size.to_physical(scale_factor as f64); 292 Some(physical_size) 293 }; 294 295 // We still perform all of those resize related logic even if the size 296 // hasn't changed, since GNOME relies on `set_geometry` calls after 297 // configures. 298 window_handle.window.resize(size.width, size.height); 299 window_handle.window.refresh(); 300 301 // Mark that refresh isn't required, since we've done it right now. 302 window_update.refresh_frame = false; 303 304 physical_size 305 }); 306 307 if let Some(physical_size) = physical_size { 308 sticky_exit_callback( 309 Event::WindowEvent { 310 window_id: crate::window::WindowId( 311 crate::platform_impl::WindowId::Wayland(*window_id), 312 ), 313 event: WindowEvent::Resized(physical_size), 314 }, 315 &self.window_target, 316 &mut control_flow, 317 &mut callback, 318 ); 319 } 320 } 321 322 if window_update.close_window { 323 sticky_exit_callback( 324 Event::WindowEvent { 325 window_id: crate::window::WindowId( 326 crate::platform_impl::WindowId::Wayland(*window_id), 327 ), 328 event: WindowEvent::CloseRequested, 329 }, 330 &self.window_target, 331 &mut control_flow, 332 &mut callback, 333 ); 334 } 335 } 336 337 // The purpose of the back buffer and that swap is to not hold borrow_mut when 338 // we're doing callback to the user, since we can double borrow if the user decides 339 // to create a window in one of those callbacks. 340 self.with_state(|state| { 341 std::mem::swap( 342 &mut event_sink_back_buffer, 343 &mut state.event_sink.window_events, 344 ) 345 }); 346 347 // Handle pending window events. 348 for event in event_sink_back_buffer.drain(..) { 349 let event = event.map_nonuser_event().unwrap(); 350 sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback); 351 } 352 353 // Send events cleared. 354 sticky_exit_callback( 355 Event::MainEventsCleared, 356 &self.window_target, 357 &mut control_flow, 358 &mut callback, 359 ); 360 361 // Handle RedrawRequested events. 362 for (window_id, window_update) in window_updates.iter() { 363 // Handle refresh of the frame. 364 if window_update.refresh_frame { 365 self.with_state(|state| { 366 let window_handle = state.window_map.get_mut(&window_id).unwrap(); 367 window_handle.window.refresh(); 368 if !window_update.redraw_requested { 369 window_handle.window.surface().commit(); 370 } 371 }); 372 } 373 374 // Handle redraw request. 375 if window_update.redraw_requested { 376 sticky_exit_callback( 377 Event::RedrawRequested(crate::window::WindowId( 378 crate::platform_impl::WindowId::Wayland(*window_id), 379 )), 380 &self.window_target, 381 &mut control_flow, 382 &mut callback, 383 ); 384 } 385 } 386 387 // Send RedrawEventCleared. 388 sticky_exit_callback( 389 Event::RedrawEventsCleared, 390 &self.window_target, 391 &mut control_flow, 392 &mut callback, 393 ); 394 395 // Send pending events to the server. 396 let _ = self.display.flush(); 397 398 // During the run of the user callback, some other code monitoring and reading the 399 // Wayland socket may have been run (mesa for example does this with vsync), if that 400 // is the case, some events may have been enqueued in our event queue. 401 // 402 // If some messages are there, the event loop needs to behave as if it was instantly 403 // woken up by messages arriving from the Wayland socket, to avoid delaying the 404 // dispatch of these events until we're woken up again. 405 let instant_wakeup = { 406 let handle = self.event_loop.handle(); 407 let source = self.wayland_source.clone(); 408 let dispatched = handle.with_source(&source, |wayland_source| { 409 let queue = wayland_source.queue(); 410 self.with_state(|state| { 411 queue.dispatch_pending(state, |_, _, _| unimplemented!()) 412 }) 413 }); 414 415 if let Ok(dispatched) = dispatched { 416 dispatched > 0 417 } else { 418 break; 419 } 420 }; 421 422 match control_flow { 423 ControlFlow::Exit => break, 424 ControlFlow::Poll => { 425 // Non-blocking dispatch. 426 let timeout = Duration::from_millis(0); 427 if self.loop_dispatch(Some(timeout)).is_err() { 428 break; 429 } 430 431 callback( 432 Event::NewEvents(StartCause::Poll), 433 &self.window_target, 434 &mut control_flow, 435 ); 436 } 437 ControlFlow::Wait => { 438 let timeout = if instant_wakeup { 439 Some(Duration::from_millis(0)) 440 } else { 441 None 442 }; 443 444 if self.loop_dispatch(timeout).is_err() { 445 break; 446 } 447 448 callback( 449 Event::NewEvents(StartCause::WaitCancelled { 450 start: Instant::now(), 451 requested_resume: None, 452 }), 453 &self.window_target, 454 &mut control_flow, 455 ); 456 } 457 ControlFlow::WaitUntil(deadline) => { 458 let start = Instant::now(); 459 460 // Compute the amount of time we'll block for. 461 let duration = if deadline > start && !instant_wakeup { 462 deadline - start 463 } else { 464 Duration::from_millis(0) 465 }; 466 467 if self.loop_dispatch(Some(duration)).is_err() { 468 break; 469 } 470 471 let now = Instant::now(); 472 473 if now < deadline { 474 callback( 475 Event::NewEvents(StartCause::WaitCancelled { 476 start, 477 requested_resume: Some(deadline), 478 }), 479 &self.window_target, 480 &mut control_flow, 481 ) 482 } else { 483 callback( 484 Event::NewEvents(StartCause::ResumeTimeReached { 485 start, 486 requested_resume: deadline, 487 }), 488 &self.window_target, 489 &mut control_flow, 490 ) 491 } 492 } 493 } 494 } 495 496 callback(Event::LoopDestroyed, &self.window_target, &mut control_flow); 497 } 498 499 #[inline] create_proxy(&self) -> EventLoopProxy<T>500 pub fn create_proxy(&self) -> EventLoopProxy<T> { 501 EventLoopProxy::new(self.user_events_sender.clone()) 502 } 503 504 #[inline] window_target(&self) -> &RootEventLoopWindowTarget<T>505 pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> { 506 &self.window_target 507 } 508 with_state<U, F: FnOnce(&mut WinitState) -> U>(&mut self, f: F) -> U509 fn with_state<U, F: FnOnce(&mut WinitState) -> U>(&mut self, f: F) -> U { 510 let state = match &mut self.window_target.p { 511 crate::platform_impl::EventLoopWindowTarget::Wayland(ref mut window_target) => { 512 window_target.state.get_mut() 513 } 514 #[cfg(feature = "x11")] 515 _ => unreachable!(), 516 }; 517 518 f(state) 519 } 520 loop_dispatch<D: Into<Option<std::time::Duration>>>( &mut self, timeout: D, ) -> std::io::Result<()>521 fn loop_dispatch<D: Into<Option<std::time::Duration>>>( 522 &mut self, 523 timeout: D, 524 ) -> std::io::Result<()> { 525 let mut state = match &mut self.window_target.p { 526 crate::platform_impl::EventLoopWindowTarget::Wayland(ref mut window_target) => { 527 window_target.state.get_mut() 528 } 529 #[cfg(feature = "x11")] 530 _ => unreachable!(), 531 }; 532 533 self.event_loop.dispatch(timeout, &mut state) 534 } 535 } 536