From df12fa4e8bdc107ee04041f59aa440b0a3377a06 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sat, 13 Oct 2018 12:36:00 +0200 Subject: [PATCH] backends.winit: only expose physical sizes Unify winit with the other backends in only ever dealing with physical sizes. All dimensions and coordinates are provided in the physical space (transformed by the dpi factor provided by winit), and the user is responsible for dealing with the dpi scaling if they want. A compositor using it can deal with it either by following the scaling transmitted by the backend or using some value retrieved by other means (like a command line argument, like weston does). This means that a non-hidpi aware implementation will appear very small on an hidpi screen, but not broken. This is now the current state of anvil. This also changes the WinitEventsHandler trait to merge the resized() and hidpifactorchanged() callbacks into a single one, providing the physical size and the dpi factor whenever either changes. --- src/backend/winit.rs | 141 +++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 9ec9b9a..e15b68a 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -20,7 +20,7 @@ use backend::{ }, }; use nix::libc::c_void; -use std::{cmp, error, fmt, rc::Rc, time::Instant}; +use std::{cell::RefCell, cmp, error, fmt, rc::Rc, time::Instant}; use wayland_client::egl as wegl; use wayland_server::Display; use winit::{ @@ -67,10 +67,16 @@ impl Window { } } +struct WindowSize { + logical_size: LogicalSize, + dpi_factor: f64, +} + /// Window with an active EGL Context created by `winit`. Implements the /// `EGLGraphicsBackend` graphics backend trait pub struct WinitGraphicsBackend { window: Rc, + size: Rc>, logger: ::slog::Logger, } @@ -87,7 +93,7 @@ pub struct WinitInputBackend { input_config: (), handler: Option + 'static>>, logger: ::slog::Logger, - dpi: f64, + size: Rc>, } /// Create a new `WinitGraphicsBackend`, which implements the `EGLGraphicsBackend` @@ -164,9 +170,18 @@ where }, ); + let size = Rc::new(RefCell::new(WindowSize { + logical_size: window + .window() + .get_inner_size() + .expect("Winit window was killed during init."), + dpi_factor: window.window().get_hidpi_factor(), + })); + Ok(( WinitGraphicsBackend { window: window.clone(), + size: size.clone(), logger: log.new(o!("smithay_winit_component" => "graphics")), }, WinitInputBackend { @@ -187,7 +202,7 @@ where input_config: (), handler: None, logger: log.new(o!("smithay_winit_component" => "input")), - dpi: 1.0, + size, }, )) } @@ -195,15 +210,15 @@ where /// Handler trait to recieve window-related events to provide a better *nested* experience. pub trait WinitEventsHandler { /// The window was resized, can be used to adjust the associated `wayland::output::Output`s mode. - fn resized(&mut self, size: LogicalSize); + /// + /// Here are provided the new size (in physical pixels) and the new scale factor provided by winit. + fn resized(&mut self, size: (f64, f64), scale: f64); /// The window was moved fn moved(&mut self, position: LogicalPosition); /// The window gained or lost focus fn focus_changed(&mut self, focused: bool); /// The window needs to be redrawn fn refresh(&mut self); - /// The window's hidpi factor changed - fn hidpi_changed(&mut self, scale: f32); } impl WinitGraphicsBackend { @@ -257,11 +272,8 @@ impl EGLGraphicsBackend for WinitGraphicsBackend { } fn get_framebuffer_dimensions(&self) -> (u32, u32) { - self.window - .window() - .get_inner_size() - .expect("Window does not exist anymore") - .into() + let size = self.size.borrow(); + size.logical_size.to_physical(size.dpi_factor).into() } fn is_current(&self) -> bool { @@ -357,7 +369,7 @@ impl KeyboardKeyEvent for WinitKeyboardInputEvent { #[derive(Clone)] /// Winit-Backend internal event wrapping winit's types into a `PointerMotionAbsoluteEvent` pub struct WinitMouseMovedEvent { - window: Rc, + size: Rc>, time: u32, x: f64, y: f64, @@ -371,35 +383,23 @@ impl BackendEvent for WinitMouseMovedEvent { impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { fn x(&self) -> f64 { - self.x + let wsize = self.size.borrow(); + self.x * wsize.dpi_factor } fn y(&self) -> f64 { - self.y + let wsize = self.size.borrow(); + self.y * wsize.dpi_factor } fn x_transformed(&self, width: u32) -> u32 { - cmp::max( - (self.x * width as f64 / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(width.into(), 0.0)) - .width) as i32, - 0, - ) as u32 + let wsize = self.size.borrow(); + cmp::max((self.x * width as f64 / wsize.logical_size.width) as i32, 0) as u32 } fn y_transformed(&self, height: u32) -> u32 { - cmp::max( - (self.y * height as f64 / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(0.0, height.into())) - .height) as i32, - 0, - ) as u32 + let wsize = self.size.borrow(); + cmp::max((self.y * height as f64 / wsize.logical_size.height) as i32, 0) as u32 } } @@ -468,7 +468,7 @@ impl PointerButtonEvent for WinitMouseInputEvent { #[derive(Clone)] /// Winit-Backend internal event wrapping winit's types into a `TouchDownEvent` pub struct WinitTouchStartedEvent { - window: Rc, + size: Rc>, time: u32, location: (f64, f64), id: u64, @@ -486,33 +486,27 @@ impl TouchDownEvent for WinitTouchStartedEvent { } fn x(&self) -> f64 { - self.location.0 + let wsize = self.size.borrow(); + self.location.0 * wsize.dpi_factor } fn y(&self) -> f64 { - self.location.1 + let wsize = self.size.borrow(); + self.location.1 * wsize.dpi_factor } fn x_transformed(&self, width: u32) -> u32 { + let wsize = self.size.borrow(); cmp::min( - self.location.0 as i32 * width as i32 / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(width.into(), 0.0)) - .width as i32, + self.location.0 as i32 * width as i32 / wsize.logical_size.width as i32, 0, ) as u32 } fn y_transformed(&self, height: u32) -> u32 { + let wsize = self.size.borrow(); cmp::min( - self.location.1 as i32 * height as i32 / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(0.0, height.into())) - .height as i32, + self.location.1 as i32 * height as i32 / wsize.logical_size.height as i32, 0, ) as u32 } @@ -521,7 +515,7 @@ impl TouchDownEvent for WinitTouchStartedEvent { #[derive(Clone)] /// Winit-Backend internal event wrapping winit's types into a `TouchMotionEvent` pub struct WinitTouchMovedEvent { - window: Rc, + size: Rc>, time: u32, location: (f64, f64), id: u64, @@ -539,29 +533,23 @@ impl TouchMotionEvent for WinitTouchMovedEvent { } fn x(&self) -> f64 { - self.location.0 + let wsize = self.size.borrow(); + self.location.0 * wsize.dpi_factor } fn y(&self) -> f64 { - self.location.1 + let wsize = self.size.borrow(); + self.location.1 * wsize.dpi_factor } fn x_transformed(&self, width: u32) -> u32 { - self.location.0 as u32 * width / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(width.into(), 0.0)) - .width as u32 + let wsize = self.size.borrow(); + self.location.0 as u32 * width / wsize.logical_size.width as u32 } fn y_transformed(&self, height: u32) -> u32 { - self.location.1 as u32 * height / self - .window - .window() - .get_inner_size() - .unwrap_or(LogicalSize::new(0.0, height.into())) - .height as u32 + let wsize = self.size.borrow(); + self.location.1 as u32 * height / wsize.logical_size.height as u32 } } @@ -696,7 +684,7 @@ impl InputBackend for WinitInputBackend { let mut handler = self.handler.as_mut(); let mut events_handler = self.events_handler.as_mut(); let logger = &self.logger; - let dpi = &mut self.dpi; + let window_size = &self.size; self.events_loop.poll_events(move |event| { if let Event::WindowEvent { event, .. } = event { @@ -707,12 +695,14 @@ impl InputBackend for WinitInputBackend { (WindowEvent::Resized(size), _, events_handler) => { trace!(logger, "Resizing window to {:?}", size); window.window().set_inner_size(size); + let mut wsize = window_size.borrow_mut(); + wsize.logical_size = size; + let physical_size = size.to_physical(wsize.dpi_factor); if let Window::Wayland { ref surface, .. } = **window { - let physical_size = size.to_physical(*dpi); surface.resize(physical_size.width as i32, physical_size.height as i32, 0, 0); } if let Some(events_handler) = events_handler { - events_handler.resized(size); + events_handler.resized(physical_size.into(), wsize.dpi_factor); } } (WindowEvent::Moved(position), _, Some(events_handler)) => { @@ -722,9 +712,16 @@ impl InputBackend for WinitInputBackend { events_handler.focus_changed(focus) } (WindowEvent::Refresh, _, Some(events_handler)) => events_handler.refresh(), - (WindowEvent::HiDpiFactorChanged(factor), _, Some(events_handler)) => { - *dpi = factor; - events_handler.hidpi_changed(factor as f32) + (WindowEvent::HiDpiFactorChanged(factor), _, events_handler) => { + let mut wsize = window_size.borrow_mut(); + wsize.dpi_factor = factor; + let physical_size = wsize.logical_size.to_physical(factor); + if let Window::Wayland { ref surface, .. } = **window { + surface.resize(physical_size.width as i32, physical_size.height as i32, 0, 0); + } + if let Some(events_handler) = events_handler { + events_handler.resized(physical_size.into(), wsize.dpi_factor); + } } ( WindowEvent::KeyboardInput { @@ -756,7 +753,7 @@ impl InputBackend for WinitInputBackend { handler.on_pointer_move_absolute( seat, WinitMouseMovedEvent { - window: window.clone(), + size: window_size.clone(), time, x: position.x, y: position.y, @@ -786,7 +783,7 @@ impl InputBackend for WinitInputBackend { handler.on_touch_down( seat, WinitTouchStartedEvent { - window: window.clone(), + size: window_size.clone(), time, location: location.into(), id, @@ -807,7 +804,7 @@ impl InputBackend for WinitInputBackend { handler.on_touch_motion( seat, WinitTouchMovedEvent { - window: window.clone(), + size: window_size.clone(), time, location: location.into(), id, @@ -828,7 +825,7 @@ impl InputBackend for WinitInputBackend { handler.on_touch_motion( seat, WinitTouchMovedEvent { - window: window.clone(), + size: window_size.clone(), time, location: location.into(), id,