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.
This commit is contained in:
Victor Berger 2018-10-13 12:36:00 +02:00 committed by Victor Berger
parent f9bd83c3b5
commit df12fa4e8b
1 changed files with 69 additions and 72 deletions

View File

@ -20,7 +20,7 @@ use backend::{
}, },
}; };
use nix::libc::c_void; 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_client::egl as wegl;
use wayland_server::Display; use wayland_server::Display;
use winit::{ 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 /// Window with an active EGL Context created by `winit`. Implements the
/// `EGLGraphicsBackend` graphics backend trait /// `EGLGraphicsBackend` graphics backend trait
pub struct WinitGraphicsBackend { pub struct WinitGraphicsBackend {
window: Rc<Window>, window: Rc<Window>,
size: Rc<RefCell<WindowSize>>,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
@ -87,7 +93,7 @@ pub struct WinitInputBackend {
input_config: (), input_config: (),
handler: Option<Box<InputHandler<WinitInputBackend> + 'static>>, handler: Option<Box<InputHandler<WinitInputBackend> + 'static>>,
logger: ::slog::Logger, logger: ::slog::Logger,
dpi: f64, size: Rc<RefCell<WindowSize>>,
} }
/// Create a new `WinitGraphicsBackend`, which implements the `EGLGraphicsBackend` /// 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(( Ok((
WinitGraphicsBackend { WinitGraphicsBackend {
window: window.clone(), window: window.clone(),
size: size.clone(),
logger: log.new(o!("smithay_winit_component" => "graphics")), logger: log.new(o!("smithay_winit_component" => "graphics")),
}, },
WinitInputBackend { WinitInputBackend {
@ -187,7 +202,7 @@ where
input_config: (), input_config: (),
handler: None, handler: None,
logger: log.new(o!("smithay_winit_component" => "input")), 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. /// Handler trait to recieve window-related events to provide a better *nested* experience.
pub trait WinitEventsHandler { pub trait WinitEventsHandler {
/// The window was resized, can be used to adjust the associated `wayland::output::Output`s mode. /// 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 /// The window was moved
fn moved(&mut self, position: LogicalPosition); fn moved(&mut self, position: LogicalPosition);
/// The window gained or lost focus /// The window gained or lost focus
fn focus_changed(&mut self, focused: bool); fn focus_changed(&mut self, focused: bool);
/// The window needs to be redrawn /// The window needs to be redrawn
fn refresh(&mut self); fn refresh(&mut self);
/// The window's hidpi factor changed
fn hidpi_changed(&mut self, scale: f32);
} }
impl WinitGraphicsBackend { impl WinitGraphicsBackend {
@ -257,11 +272,8 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
} }
fn get_framebuffer_dimensions(&self) -> (u32, u32) { fn get_framebuffer_dimensions(&self) -> (u32, u32) {
self.window let size = self.size.borrow();
.window() size.logical_size.to_physical(size.dpi_factor).into()
.get_inner_size()
.expect("Window does not exist anymore")
.into()
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -357,7 +369,7 @@ impl KeyboardKeyEvent for WinitKeyboardInputEvent {
#[derive(Clone)] #[derive(Clone)]
/// Winit-Backend internal event wrapping winit's types into a `PointerMotionAbsoluteEvent` /// Winit-Backend internal event wrapping winit's types into a `PointerMotionAbsoluteEvent`
pub struct WinitMouseMovedEvent { pub struct WinitMouseMovedEvent {
window: Rc<Window>, size: Rc<RefCell<WindowSize>>,
time: u32, time: u32,
x: f64, x: f64,
y: f64, y: f64,
@ -371,35 +383,23 @@ impl BackendEvent for WinitMouseMovedEvent {
impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent {
fn x(&self) -> f64 { fn x(&self) -> f64 {
self.x let wsize = self.size.borrow();
self.x * wsize.dpi_factor
} }
fn y(&self) -> f64 { fn y(&self) -> f64 {
self.y let wsize = self.size.borrow();
self.y * wsize.dpi_factor
} }
fn x_transformed(&self, width: u32) -> u32 { fn x_transformed(&self, width: u32) -> u32 {
cmp::max( let wsize = self.size.borrow();
(self.x * width as f64 / self cmp::max((self.x * width as f64 / wsize.logical_size.width) as i32, 0) as u32
.window
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(width.into(), 0.0))
.width) as i32,
0,
) as u32
} }
fn y_transformed(&self, height: u32) -> u32 { fn y_transformed(&self, height: u32) -> u32 {
cmp::max( let wsize = self.size.borrow();
(self.y * height as f64 / self cmp::max((self.y * height as f64 / wsize.logical_size.height) as i32, 0) as u32
.window
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(0.0, height.into()))
.height) as i32,
0,
) as u32
} }
} }
@ -468,7 +468,7 @@ impl PointerButtonEvent for WinitMouseInputEvent {
#[derive(Clone)] #[derive(Clone)]
/// Winit-Backend internal event wrapping winit's types into a `TouchDownEvent` /// Winit-Backend internal event wrapping winit's types into a `TouchDownEvent`
pub struct WinitTouchStartedEvent { pub struct WinitTouchStartedEvent {
window: Rc<Window>, size: Rc<RefCell<WindowSize>>,
time: u32, time: u32,
location: (f64, f64), location: (f64, f64),
id: u64, id: u64,
@ -486,33 +486,27 @@ impl TouchDownEvent for WinitTouchStartedEvent {
} }
fn x(&self) -> f64 { fn x(&self) -> f64 {
self.location.0 let wsize = self.size.borrow();
self.location.0 * wsize.dpi_factor
} }
fn y(&self) -> f64 { 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 { fn x_transformed(&self, width: u32) -> u32 {
let wsize = self.size.borrow();
cmp::min( cmp::min(
self.location.0 as i32 * width as i32 / self self.location.0 as i32 * width as i32 / wsize.logical_size.width as i32,
.window
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(width.into(), 0.0))
.width as i32,
0, 0,
) as u32 ) as u32
} }
fn y_transformed(&self, height: u32) -> u32 { fn y_transformed(&self, height: u32) -> u32 {
let wsize = self.size.borrow();
cmp::min( cmp::min(
self.location.1 as i32 * height as i32 / self self.location.1 as i32 * height as i32 / wsize.logical_size.height as i32,
.window
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(0.0, height.into()))
.height as i32,
0, 0,
) as u32 ) as u32
} }
@ -521,7 +515,7 @@ impl TouchDownEvent for WinitTouchStartedEvent {
#[derive(Clone)] #[derive(Clone)]
/// Winit-Backend internal event wrapping winit's types into a `TouchMotionEvent` /// Winit-Backend internal event wrapping winit's types into a `TouchMotionEvent`
pub struct WinitTouchMovedEvent { pub struct WinitTouchMovedEvent {
window: Rc<Window>, size: Rc<RefCell<WindowSize>>,
time: u32, time: u32,
location: (f64, f64), location: (f64, f64),
id: u64, id: u64,
@ -539,29 +533,23 @@ impl TouchMotionEvent for WinitTouchMovedEvent {
} }
fn x(&self) -> f64 { fn x(&self) -> f64 {
self.location.0 let wsize = self.size.borrow();
self.location.0 * wsize.dpi_factor
} }
fn y(&self) -> f64 { 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 { fn x_transformed(&self, width: u32) -> u32 {
self.location.0 as u32 * width / self let wsize = self.size.borrow();
.window self.location.0 as u32 * width / wsize.logical_size.width as u32
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(width.into(), 0.0))
.width as u32
} }
fn y_transformed(&self, height: u32) -> u32 { fn y_transformed(&self, height: u32) -> u32 {
self.location.1 as u32 * height / self let wsize = self.size.borrow();
.window self.location.1 as u32 * height / wsize.logical_size.height as u32
.window()
.get_inner_size()
.unwrap_or(LogicalSize::new(0.0, height.into()))
.height as u32
} }
} }
@ -696,7 +684,7 @@ impl InputBackend for WinitInputBackend {
let mut handler = self.handler.as_mut(); let mut handler = self.handler.as_mut();
let mut events_handler = self.events_handler.as_mut(); let mut events_handler = self.events_handler.as_mut();
let logger = &self.logger; let logger = &self.logger;
let dpi = &mut self.dpi; let window_size = &self.size;
self.events_loop.poll_events(move |event| { self.events_loop.poll_events(move |event| {
if let Event::WindowEvent { event, .. } = event { if let Event::WindowEvent { event, .. } = event {
@ -707,12 +695,14 @@ impl InputBackend for WinitInputBackend {
(WindowEvent::Resized(size), _, events_handler) => { (WindowEvent::Resized(size), _, events_handler) => {
trace!(logger, "Resizing window to {:?}", size); trace!(logger, "Resizing window to {:?}", size);
window.window().set_inner_size(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 { 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); surface.resize(physical_size.width as i32, physical_size.height as i32, 0, 0);
} }
if let Some(events_handler) = events_handler { 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)) => { (WindowEvent::Moved(position), _, Some(events_handler)) => {
@ -722,9 +712,16 @@ impl InputBackend for WinitInputBackend {
events_handler.focus_changed(focus) events_handler.focus_changed(focus)
} }
(WindowEvent::Refresh, _, Some(events_handler)) => events_handler.refresh(), (WindowEvent::Refresh, _, Some(events_handler)) => events_handler.refresh(),
(WindowEvent::HiDpiFactorChanged(factor), _, Some(events_handler)) => { (WindowEvent::HiDpiFactorChanged(factor), _, events_handler) => {
*dpi = factor; let mut wsize = window_size.borrow_mut();
events_handler.hidpi_changed(factor as f32) 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 { WindowEvent::KeyboardInput {
@ -756,7 +753,7 @@ impl InputBackend for WinitInputBackend {
handler.on_pointer_move_absolute( handler.on_pointer_move_absolute(
seat, seat,
WinitMouseMovedEvent { WinitMouseMovedEvent {
window: window.clone(), size: window_size.clone(),
time, time,
x: position.x, x: position.x,
y: position.y, y: position.y,
@ -786,7 +783,7 @@ impl InputBackend for WinitInputBackend {
handler.on_touch_down( handler.on_touch_down(
seat, seat,
WinitTouchStartedEvent { WinitTouchStartedEvent {
window: window.clone(), size: window_size.clone(),
time, time,
location: location.into(), location: location.into(),
id, id,
@ -807,7 +804,7 @@ impl InputBackend for WinitInputBackend {
handler.on_touch_motion( handler.on_touch_motion(
seat, seat,
WinitTouchMovedEvent { WinitTouchMovedEvent {
window: window.clone(), size: window_size.clone(),
time, time,
location: location.into(), location: location.into(),
id, id,
@ -828,7 +825,7 @@ impl InputBackend for WinitInputBackend {
handler.on_touch_motion( handler.on_touch_motion(
seat, seat,
WinitTouchMovedEvent { WinitTouchMovedEvent {
window: window.clone(), size: window_size.clone(),
time, time,
location: location.into(), location: location.into(),
id, id,