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| {
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::<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 {
// Update decorations state
match window.decorations_action {
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
// 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::<f64>::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::<f64>::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::<u32>(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,

View file

@ -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::<f64>(dpi).into())
.map(|size| size.to_logical::<f64>(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::<f64>(dpi).into()),
.map(|size| size.to_logical::<f64>(scale_factor as f64).into()),
);
frame.set_max_size(
attributes
.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));
@ -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<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());
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<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) = super::wayland_window::add_borders(w as i32, h as i32);
let size = LogicalSize::<f64>::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::<u32>(dpi).into();
let scale_factor = self.scale_factor() as f64;
let (w, h) = size.to_logical::<u32>(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<Size>) {
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::<f64>(dpi).into()));
.set_min_size(dimensions.map(|dim| dim.to_logical::<f64>(scale_factor).into()));
}
#[inline]
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
.lock()
.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]
@ -428,7 +433,7 @@ impl Drop for Window {
struct InternalWindow {
surface: wl_surface::WlSurface,
// TODO: CONVERT TO LogicalSize<u32>s
newsize: Option<(u32, u32)>,
new_size: Option<(u32, u32)>,
size: Arc<Mutex<(u32, u32)>>,
need_refresh: Arc<Mutex<bool>>,
fullscreen: Arc<Mutex<bool>>,
@ -437,8 +442,8 @@ struct InternalWindow {
closed: bool,
kill_switch: Arc<Mutex<bool>>,
frame: Weak<Mutex<SWindow<ConceptFrame>>>,
current_dpi: i32,
new_dpi: Option<i32>,
current_scale_factor: i32,
new_scale_factor: Option<i32>,
decorated: Arc<Mutex<bool>>,
pending_decorations_action: Arc<Mutex<Option<DecorationsAction>>>,
}
@ -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<i32>,
pub new_size: Option<(u32, u32)>,
pub size: &'a Mutex<(u32, u32)>,
pub prev_scale_factor: i32,
pub new_scale_factor: Option<i32>,
pub closed: bool,
pub grab_cursor: Option<bool>,
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;
}