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.
This commit is contained in:
Matthias Fauconneau 2020-04-22 18:00:41 +02:00 committed by GitHub
parent 54bc41f68b
commit 114fe9d502
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 78 deletions

View file

@ -714,8 +714,43 @@ impl<T> EventLoop<T> {
window_target.store.lock().unwrap().for_each(|window| { window_target.store.lock().unwrap().for_each(|window| {
let window_id = let window_id =
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(window.wid)); crate::window::WindowId(crate::platform_impl::WindowId::Wayland(window.wid));
// 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::<f64>::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::<u32>(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 { if let Some(frame) = window.frame {
if let Some((w, h)) = window.newsize {
// Update decorations state // Update decorations state
match window.decorations_action { match window.decorations_action {
Some(DecorationsAction::Hide) => frame.set_decorate(false), Some(DecorationsAction::Hide) => frame.set_decorate(false),
@ -726,51 +761,23 @@ impl<T> EventLoop<T> {
// mutter (GNOME Wayland) relies on `set_geometry` to reposition window in case // 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, // it overlaps mutter's `bounding box`, so we can't avoid this resize call,
// which calls `set_geometry` under the hood, for now. // which calls `set_geometry` under the hood, for now.
let (w, h) = logical_size;
frame.resize(w, h); frame.resize(w, h);
frame.refresh(); frame.refresh();
}
// Don't send resize event downstream if the new size is identical to the // Don't send resize event downstream if the new logical size and scale is identical to the
// current one. // current one
if (w, h) != *window.size { if logical_size != old_logical_size || window.new_scale_factor.is_some() {
let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64); let physical_size = LogicalSize::<f64>::from(logical_size).to_physical(
let physical_size = logical_size window.new_scale_factor.unwrap_or(window.prev_scale_factor) as f64,
.to_physical(window.new_dpi.unwrap_or(window.prev_dpi) as f64); );
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: WindowEvent::Resized(physical_size), 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::<f64>::from(*window.size);
let mut new_inner_size = logical_size.to_physical(dpi);
callback(Event::WindowEvent {
window_id,
event: WindowEvent::ScaleFactorChanged {
scale_factor: dpi,
new_inner_size: &mut new_inner_size,
},
});
let (w, h) = new_inner_size.to_logical::<u32>(dpi).into();
frame.resize(w, h);
// Refresh frame to rescale decorations
frame.refresh();
*window.size = (w, h);
}
}
if window.closed { if window.closed {
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,

View file

@ -59,15 +59,20 @@ impl Window {
// Create the surface first to get initial DPI // Create the surface first to get initial DPI
let window_store = evlp.store.clone(); let window_store = evlp.store.clone();
let cursor_manager = evlp.cursor_manager.clone(); let cursor_manager = evlp.cursor_manager.clone();
let surface = evlp.env.create_surface(move |dpi, surface| { let surface = evlp.env.create_surface(move |scale_factor, surface| {
window_store.lock().unwrap().dpi_change(&surface, dpi); window_store
surface.set_buffer_scale(dpi); .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 let (width, height) = attributes
.inner_size .inner_size
.map(|size| size.to_logical::<f64>(dpi).into()) .map(|size| size.to_logical::<f64>(scale_factor as f64).into())
.unwrap_or((800, 600)); .unwrap_or((800, 600));
// Create the window // Create the window
@ -91,7 +96,7 @@ impl Window {
for window in &mut store.windows { for window in &mut store.windows {
if window.surface.as_ref().equals(&my_surface.as_ref()) { 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; *(window.need_refresh.lock().unwrap()) = true;
{ {
// Get whether we're in fullscreen // Get whether we're in fullscreen
@ -173,12 +178,12 @@ impl Window {
frame.set_min_size( frame.set_min_size(
attributes attributes
.min_inner_size .min_inner_size
.map(|size| size.to_logical::<f64>(dpi).into()), .map(|size| size.to_logical::<f64>(scale_factor as f64).into()),
); );
frame.set_max_size( frame.set_max_size(
attributes attributes
.max_inner_size .max_inner_size
.map(|size| size.to_logical::<f64>(dpi).into()), .map(|size| size.to_logical::<f64>(scale_factor as f64).into()),
); );
let kill_switch = Arc::new(Mutex::new(false)); let kill_switch = Arc::new(Mutex::new(false));
@ -189,7 +194,7 @@ impl Window {
evlp.store.lock().unwrap().windows.push(InternalWindow { evlp.store.lock().unwrap().windows.push(InternalWindow {
closed: false, closed: false,
newsize: None, new_size: None,
size: size.clone(), size: size.clone(),
need_refresh: need_refresh.clone(), need_refresh: need_refresh.clone(),
fullscreen: fullscreen.clone(), fullscreen: fullscreen.clone(),
@ -198,8 +203,8 @@ impl Window {
surface: surface.clone(), surface: surface.clone(),
kill_switch: kill_switch.clone(), kill_switch: kill_switch.clone(),
frame: Arc::downgrade(&frame), frame: Arc::downgrade(&frame),
current_dpi: 1, current_scale_factor: scale_factor,
new_dpi: None, new_scale_factor: None,
decorated: decorated.clone(), decorated: decorated.clone(),
pending_decorations_action: pending_decorations_action.clone(), pending_decorations_action: pending_decorations_action.clone(),
}); });
@ -250,9 +255,9 @@ impl Window {
} }
pub fn inner_size(&self) -> PhysicalSize<u32> { pub fn inner_size(&self) -> PhysicalSize<u32> {
let dpi = self.scale_factor() as f64; let scale_factor = self.scale_factor() as f64;
let size = LogicalSize::<f64>::from(*self.size.lock().unwrap()); let size = LogicalSize::<f64>::from(*self.size.lock().unwrap());
size.to_physical(dpi) size.to_physical(scale_factor)
} }
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
@ -261,38 +266,38 @@ impl Window {
#[inline] #[inline]
pub fn outer_size(&self) -> PhysicalSize<u32> { pub fn outer_size(&self) -> PhysicalSize<u32> {
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) = self.size.lock().unwrap().clone();
// let (w, h) = super::wayland_window::add_borders(w as i32, h as i32); // let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
let size = LogicalSize::<f64>::from((w, h)); let size = LogicalSize::<f64>::from((w, h));
size.to_physical(dpi) size.to_physical(scale_factor)
} }
#[inline] #[inline]
// NOTE: This will only resize the borders, the contents must be updated by the user // NOTE: This will only resize the borders, the contents must be updated by the user
pub fn set_inner_size(&self, size: Size) { pub fn set_inner_size(&self, size: Size) {
let dpi = self.scale_factor() as f64; let scale_factor = self.scale_factor() as f64;
let (w, h) = size.to_logical::<u32>(dpi).into(); let (w, h) = size.to_logical::<u32>(scale_factor).into();
self.frame.lock().unwrap().resize(w, h); self.frame.lock().unwrap().resize(w, h);
*(self.size.lock().unwrap()) = (w, h); *(self.size.lock().unwrap()) = (w, h);
} }
#[inline] #[inline]
pub fn set_min_inner_size(&self, dimensions: Option<Size>) { pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
let dpi = self.scale_factor() as f64; let scale_factor = self.scale_factor() as f64;
self.frame self.frame
.lock() .lock()
.unwrap() .unwrap()
.set_min_size(dimensions.map(|dim| dim.to_logical::<f64>(dpi).into())); .set_min_size(dimensions.map(|dim| dim.to_logical::<f64>(scale_factor).into()));
} }
#[inline] #[inline]
pub fn set_max_inner_size(&self, dimensions: Option<Size>) { pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
let dpi = self.scale_factor() as f64; let scale_factor = self.scale_factor() as f64;
self.frame self.frame
.lock() .lock()
.unwrap() .unwrap()
.set_max_size(dimensions.map(|dim| dim.to_logical::<f64>(dpi).into())); .set_max_size(dimensions.map(|dim| dim.to_logical::<f64>(scale_factor).into()));
} }
#[inline] #[inline]
@ -428,7 +433,7 @@ impl Drop for Window {
struct InternalWindow { struct InternalWindow {
surface: wl_surface::WlSurface, surface: wl_surface::WlSurface,
// TODO: CONVERT TO LogicalSize<u32>s // TODO: CONVERT TO LogicalSize<u32>s
newsize: Option<(u32, u32)>, new_size: Option<(u32, u32)>,
size: Arc<Mutex<(u32, u32)>>, size: Arc<Mutex<(u32, u32)>>,
need_refresh: Arc<Mutex<bool>>, need_refresh: Arc<Mutex<bool>>,
fullscreen: Arc<Mutex<bool>>, fullscreen: Arc<Mutex<bool>>,
@ -437,8 +442,8 @@ struct InternalWindow {
closed: bool, closed: bool,
kill_switch: Arc<Mutex<bool>>, kill_switch: Arc<Mutex<bool>>,
frame: Weak<Mutex<SWindow<ConceptFrame>>>, frame: Weak<Mutex<SWindow<ConceptFrame>>>,
current_dpi: i32, current_scale_factor: i32,
new_dpi: Option<i32>, new_scale_factor: Option<i32>,
decorated: Arc<Mutex<bool>>, decorated: Arc<Mutex<bool>>,
pending_decorations_action: Arc<Mutex<Option<DecorationsAction>>>, pending_decorations_action: Arc<Mutex<Option<DecorationsAction>>>,
} }
@ -448,10 +453,10 @@ pub struct WindowStore {
} }
pub struct WindowStoreForEach<'a> { pub struct WindowStoreForEach<'a> {
pub newsize: Option<(u32, u32)>, pub new_size: Option<(u32, u32)>,
pub size: &'a mut (u32, u32), pub size: &'a Mutex<(u32, u32)>,
pub prev_dpi: i32, pub prev_scale_factor: i32,
pub new_dpi: Option<i32>, pub new_scale_factor: Option<i32>,
pub closed: bool, pub closed: bool,
pub grab_cursor: Option<bool>, pub grab_cursor: Option<bool>,
pub surface: &'a wl_surface::WlSurface, 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 { for window in &mut self.windows {
if surface.as_ref().equals(&window.surface.as_ref()) { 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<'_>), F: FnMut(WindowStoreForEach<'_>),
{ {
for window in &mut self.windows { 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 opt_arc = window.frame.upgrade();
let mut opt_mutex_lock = opt_arc.as_ref().map(|m| m.lock().unwrap()); 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() }; let decorations_action = { window.pending_decorations_action.lock().unwrap().take() };
f(WindowStoreForEach { f(WindowStoreForEach {
newsize: window.newsize.take(), new_size: window.new_size.take(),
size: &mut size, size: &window.size,
prev_dpi: window.current_dpi, prev_scale_factor,
new_dpi: window.new_dpi, new_scale_factor: window.new_scale_factor.take(),
closed: window.closed, closed: window.closed,
grab_cursor: window.cursor_grab_changed.lock().unwrap().take(), grab_cursor: window.cursor_grab_changed.lock().unwrap().take(),
surface: &window.surface, surface: &window.surface,
@ -528,10 +537,6 @@ impl WindowStore {
frame: opt_mutex_lock.as_mut().map(|m| &mut **m), frame: opt_mutex_lock.as_mut().map(|m| &mut **m),
decorations_action, decorations_action,
}); });
*window.size.lock().unwrap() = size;
if let Some(dpi) = window.new_dpi.take() {
window.current_dpi = dpi;
}
// avoid re-spamming the event // avoid re-spamming the event
window.closed = false; window.closed = false;
} }