From 114fe9d502cd4b37ee332f4165fb92c1056e25d9 Mon Sep 17 00:00:00 2001 From: Matthias Fauconneau Date: Wed, 22 Apr 2020 18:00:41 +0200 Subject: [PATCH] wayland: rework scale factor handling (#1538) - Always send Resized events in case of scale factor change - Properly take into account the resize the user can do using the resize event. --- src/platform_impl/linux/wayland/event_loop.rs | 85 ++++++++++--------- src/platform_impl/linux/wayland/window.rs | 83 +++++++++--------- 2 files changed, 90 insertions(+), 78 deletions(-) diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index 47c5aea6..5a3614c8 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -714,8 +714,43 @@ impl EventLoop { window_target.store.lock().unwrap().for_each(|window| { let window_id = crate::window::WindowId(crate::platform_impl::WindowId::Wayland(window.wid)); - if let Some(frame) = window.frame { - if let Some((w, h)) = window.newsize { + + // Update window logical .size field (for callbacks using .inner_size) + let (old_logical_size, mut logical_size) = { + let mut window_size = window.size.lock().unwrap(); + let old_logical_size = *window_size; + *window_size = window.new_size.unwrap_or(old_logical_size); + (old_logical_size, *window_size) + }; + + if let Some(scale_factor) = window.new_scale_factor { + // Update cursor scale factor + self.cursor_manager + .lock() + .unwrap() + .update_scale_factor(scale_factor as u32); + let new_logical_size = { + let scale_factor = scale_factor as f64; + let mut physical_size = + LogicalSize::::from(logical_size).to_physical(scale_factor); + callback(Event::WindowEvent { + window_id, + event: WindowEvent::ScaleFactorChanged { + scale_factor, + new_inner_size: &mut physical_size, + }, + }); + physical_size.to_logical::(scale_factor).into() + }; + // Update size if changed by callback + if new_logical_size != logical_size { + logical_size = new_logical_size; + *window.size.lock().unwrap() = logical_size.into(); + } + } + + if window.new_size.is_some() || window.new_scale_factor.is_some() { + if let Some(frame) = window.frame { // Update decorations state match window.decorations_action { Some(DecorationsAction::Hide) => frame.set_decorate(false), @@ -726,51 +761,23 @@ impl EventLoop { // mutter (GNOME Wayland) relies on `set_geometry` to reposition window in case // it overlaps mutter's `bounding box`, so we can't avoid this resize call, // which calls `set_geometry` under the hood, for now. + let (w, h) = logical_size; frame.resize(w, h); frame.refresh(); - - // Don't send resize event downstream if the new size is identical to the - // current one. - if (w, h) != *window.size { - let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64); - let physical_size = logical_size - .to_physical(window.new_dpi.unwrap_or(window.prev_dpi) as f64); - - callback(Event::WindowEvent { - window_id, - event: WindowEvent::Resized(physical_size), - }); - *window.size = (w, h); - } } - - if let Some(dpi) = window.new_dpi { - // Update cursor scale factor - { - self.cursor_manager - .lock() - .unwrap() - .update_scale_factor(dpi as u32); - }; - let dpi = dpi as f64; - let logical_size = LogicalSize::::from(*window.size); - let mut new_inner_size = logical_size.to_physical(dpi); - + // Don't send resize event downstream if the new logical size and scale is identical to the + // current one + if logical_size != old_logical_size || window.new_scale_factor.is_some() { + let physical_size = LogicalSize::::from(logical_size).to_physical( + window.new_scale_factor.unwrap_or(window.prev_scale_factor) as f64, + ); callback(Event::WindowEvent { window_id, - event: WindowEvent::ScaleFactorChanged { - scale_factor: dpi, - new_inner_size: &mut new_inner_size, - }, + event: WindowEvent::Resized(physical_size), }); - - let (w, h) = new_inner_size.to_logical::(dpi).into(); - frame.resize(w, h); - // Refresh frame to rescale decorations - frame.refresh(); - *window.size = (w, h); } } + if window.closed { callback(Event::WindowEvent { window_id, diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index 7c30a79b..12ae9ba1 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -59,15 +59,20 @@ impl Window { // Create the surface first to get initial DPI let window_store = evlp.store.clone(); let cursor_manager = evlp.cursor_manager.clone(); - let surface = evlp.env.create_surface(move |dpi, surface| { - window_store.lock().unwrap().dpi_change(&surface, dpi); - surface.set_buffer_scale(dpi); + let surface = evlp.env.create_surface(move |scale_factor, surface| { + window_store + .lock() + .unwrap() + .scale_factor_change(&surface, scale_factor); + surface.set_buffer_scale(scale_factor); }); - let dpi = get_dpi_factor(&surface) as f64; + // Always 1. + let scale_factor = get_dpi_factor(&surface); + let (width, height) = attributes .inner_size - .map(|size| size.to_logical::(dpi).into()) + .map(|size| size.to_logical::(scale_factor as f64).into()) .unwrap_or((800, 600)); // Create the window @@ -91,7 +96,7 @@ impl Window { for window in &mut store.windows { if window.surface.as_ref().equals(&my_surface.as_ref()) { - window.newsize = new_size; + window.new_size = new_size; *(window.need_refresh.lock().unwrap()) = true; { // Get whether we're in fullscreen @@ -173,12 +178,12 @@ impl Window { frame.set_min_size( attributes .min_inner_size - .map(|size| size.to_logical::(dpi).into()), + .map(|size| size.to_logical::(scale_factor as f64).into()), ); frame.set_max_size( attributes .max_inner_size - .map(|size| size.to_logical::(dpi).into()), + .map(|size| size.to_logical::(scale_factor as f64).into()), ); let kill_switch = Arc::new(Mutex::new(false)); @@ -189,7 +194,7 @@ impl Window { evlp.store.lock().unwrap().windows.push(InternalWindow { closed: false, - newsize: None, + new_size: None, size: size.clone(), need_refresh: need_refresh.clone(), fullscreen: fullscreen.clone(), @@ -198,8 +203,8 @@ impl Window { surface: surface.clone(), kill_switch: kill_switch.clone(), frame: Arc::downgrade(&frame), - current_dpi: 1, - new_dpi: None, + current_scale_factor: scale_factor, + new_scale_factor: None, decorated: decorated.clone(), pending_decorations_action: pending_decorations_action.clone(), }); @@ -250,9 +255,9 @@ impl Window { } pub fn inner_size(&self) -> PhysicalSize { - let dpi = self.scale_factor() as f64; + let scale_factor = self.scale_factor() as f64; let size = LogicalSize::::from(*self.size.lock().unwrap()); - size.to_physical(dpi) + size.to_physical(scale_factor) } pub fn request_redraw(&self) { @@ -261,38 +266,38 @@ impl Window { #[inline] pub fn outer_size(&self) -> PhysicalSize { - let dpi = self.scale_factor() as f64; + let scale_factor = self.scale_factor() as f64; let (w, h) = self.size.lock().unwrap().clone(); // let (w, h) = super::wayland_window::add_borders(w as i32, h as i32); let size = LogicalSize::::from((w, h)); - size.to_physical(dpi) + size.to_physical(scale_factor) } #[inline] // NOTE: This will only resize the borders, the contents must be updated by the user pub fn set_inner_size(&self, size: Size) { - let dpi = self.scale_factor() as f64; - let (w, h) = size.to_logical::(dpi).into(); + let scale_factor = self.scale_factor() as f64; + let (w, h) = size.to_logical::(scale_factor).into(); self.frame.lock().unwrap().resize(w, h); *(self.size.lock().unwrap()) = (w, h); } #[inline] pub fn set_min_inner_size(&self, dimensions: Option) { - let dpi = self.scale_factor() as f64; + let scale_factor = self.scale_factor() as f64; self.frame .lock() .unwrap() - .set_min_size(dimensions.map(|dim| dim.to_logical::(dpi).into())); + .set_min_size(dimensions.map(|dim| dim.to_logical::(scale_factor).into())); } #[inline] pub fn set_max_inner_size(&self, dimensions: Option) { - let dpi = self.scale_factor() as f64; + let scale_factor = self.scale_factor() as f64; self.frame .lock() .unwrap() - .set_max_size(dimensions.map(|dim| dim.to_logical::(dpi).into())); + .set_max_size(dimensions.map(|dim| dim.to_logical::(scale_factor).into())); } #[inline] @@ -428,7 +433,7 @@ impl Drop for Window { struct InternalWindow { surface: wl_surface::WlSurface, // TODO: CONVERT TO LogicalSizes - newsize: Option<(u32, u32)>, + new_size: Option<(u32, u32)>, size: Arc>, need_refresh: Arc>, fullscreen: Arc>, @@ -437,8 +442,8 @@ struct InternalWindow { closed: bool, kill_switch: Arc>, frame: Weak>>, - current_dpi: i32, - new_dpi: Option, + current_scale_factor: i32, + new_scale_factor: Option, decorated: Arc>, pending_decorations_action: Arc>>, } @@ -448,10 +453,10 @@ pub struct WindowStore { } pub struct WindowStoreForEach<'a> { - pub newsize: Option<(u32, u32)>, - pub size: &'a mut (u32, u32), - pub prev_dpi: i32, - pub new_dpi: Option, + pub new_size: Option<(u32, u32)>, + pub size: &'a Mutex<(u32, u32)>, + pub prev_scale_factor: i32, + pub new_scale_factor: Option, pub closed: bool, pub grab_cursor: Option, pub surface: &'a wl_surface::WlSurface, @@ -499,10 +504,11 @@ impl WindowStore { } } - fn dpi_change(&mut self, surface: &wl_surface::WlSurface, new: i32) { + fn scale_factor_change(&mut self, surface: &wl_surface::WlSurface, new: i32) { for window in &mut self.windows { if surface.as_ref().equals(&window.surface.as_ref()) { - window.new_dpi = Some(new); + window.new_scale_factor = Some(new); + *(window.need_refresh.lock().unwrap()) = true; } } } @@ -512,15 +518,18 @@ impl WindowStore { F: FnMut(WindowStoreForEach<'_>), { for window in &mut self.windows { + let prev_scale_factor = window.current_scale_factor; + if let Some(scale_factor) = window.new_scale_factor { + window.current_scale_factor = scale_factor; + } let opt_arc = window.frame.upgrade(); let mut opt_mutex_lock = opt_arc.as_ref().map(|m| m.lock().unwrap()); - let mut size = { *window.size.lock().unwrap() }; let decorations_action = { window.pending_decorations_action.lock().unwrap().take() }; f(WindowStoreForEach { - newsize: window.newsize.take(), - size: &mut size, - prev_dpi: window.current_dpi, - new_dpi: window.new_dpi, + new_size: window.new_size.take(), + size: &window.size, + prev_scale_factor, + new_scale_factor: window.new_scale_factor.take(), closed: window.closed, grab_cursor: window.cursor_grab_changed.lock().unwrap().take(), surface: &window.surface, @@ -528,10 +537,6 @@ impl WindowStore { frame: opt_mutex_lock.as_mut().map(|m| &mut **m), decorations_action, }); - *window.size.lock().unwrap() = size; - if let Some(dpi) = window.new_dpi.take() { - window.current_dpi = dpi; - } // avoid re-spamming the event window.closed = false; }