On Wayland, fix Window::request_inner_size during resize
The user may change the size during the on-going resize, meaning that the size will desync with winit's internal loop which breaks viewporter setup with fractional scaling. Links: https://github.com/alacritty/alacritty/issues/7474
This commit is contained in:
parent
ad1843aea6
commit
8f6de4ef4b
6 changed files with 50 additions and 59 deletions
|
|
@ -27,6 +27,8 @@ Unreleased` header.
|
|||
- On Web, add the ability to toggle calling `Event.preventDefault()` on `Window`.
|
||||
- **Breaking:** Remove `WindowAttributes::fullscreen()` and expose as field directly.
|
||||
- **Breaking:** Rename `VideoMode` to `VideoModeHandle` to represent that it doesn't hold static data.
|
||||
- On Wayland, fix `Window::request_inner_size` being overwritten by resize.
|
||||
- On Wayland, fix `Window::inner_size` not using the correct rounding.
|
||||
|
||||
# 0.29.7
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use sctk::reexports::calloop_wayland_source::WaylandSource;
|
|||
use sctk::reexports::client::globals;
|
||||
use sctk::reexports::client::{Connection, QueueHandle};
|
||||
|
||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
|
|
@ -34,7 +34,7 @@ use sink::EventSink;
|
|||
|
||||
use super::state::{WindowCompositorUpdate, WinitState};
|
||||
use super::window::state::FrameCallbackState;
|
||||
use super::{DeviceId, WaylandError, WindowId};
|
||||
use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId};
|
||||
|
||||
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
|
||||
|
||||
|
|
@ -356,15 +356,13 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
for mut compositor_update in compositor_updates.drain(..) {
|
||||
let window_id = compositor_update.window_id;
|
||||
if let Some(scale_factor) = compositor_update.scale_factor {
|
||||
let physical_size = self.with_state(|state| {
|
||||
if compositor_update.scale_changed {
|
||||
let (physical_size, scale_factor) = self.with_state(|state| {
|
||||
let windows = state.windows.get_mut();
|
||||
let mut window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||
|
||||
// Set the new scale factor.
|
||||
window.set_scale_factor(scale_factor);
|
||||
let window_size = compositor_update.size.unwrap_or(window.inner_size());
|
||||
logical_to_physical_rounded(window_size, scale_factor)
|
||||
let window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||
let scale_factor = window.scale_factor();
|
||||
let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
|
||||
(size, scale_factor)
|
||||
});
|
||||
|
||||
// Stash the old window size.
|
||||
|
|
@ -386,30 +384,30 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let physical_size = *new_inner_size.lock().unwrap();
|
||||
drop(new_inner_size);
|
||||
let new_logical_size = physical_size.to_logical(scale_factor);
|
||||
|
||||
// Resize the window when user altered the size.
|
||||
if old_physical_size != physical_size {
|
||||
self.with_state(|state| {
|
||||
let windows = state.windows.get_mut();
|
||||
let mut window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||
|
||||
let new_logical_size: LogicalSize<f64> =
|
||||
physical_size.to_logical(scale_factor);
|
||||
window.request_inner_size(new_logical_size.into());
|
||||
});
|
||||
}
|
||||
|
||||
// Make it queue resize.
|
||||
compositor_update.size = Some(new_logical_size);
|
||||
// Make it queue resize.
|
||||
compositor_update.resized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(size) = compositor_update.size.take() {
|
||||
if compositor_update.resized {
|
||||
let physical_size = self.with_state(|state| {
|
||||
let windows = state.windows.get_mut();
|
||||
let window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||
|
||||
let scale_factor = window.scale_factor();
|
||||
let physical_size = logical_to_physical_rounded(size, scale_factor);
|
||||
|
||||
// TODO could probably bring back size reporting optimization.
|
||||
let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
|
||||
|
||||
// Mark the window as needed a redraw.
|
||||
state
|
||||
|
|
@ -420,7 +418,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
.redraw_requested
|
||||
.store(true, Ordering::Relaxed);
|
||||
|
||||
physical_size
|
||||
size
|
||||
});
|
||||
|
||||
callback(
|
||||
|
|
@ -684,10 +682,3 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
// The default routine does floor, but we need round on Wayland.
|
||||
fn logical_to_physical_rounded(size: LogicalSize<u32>, scale_factor: f64) -> PhysicalSize<u32> {
|
||||
let width = size.width as f64 * scale_factor;
|
||||
let height = size.height as f64 * scale_factor;
|
||||
(width.round(), height.round()).into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use sctk::reexports::client::globals::{BindError, GlobalError};
|
|||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
||||
|
||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||
pub use crate::platform_impl::platform::{OsError, WindowId};
|
||||
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||
pub use output::{MonitorHandle, VideoModeHandle};
|
||||
|
|
@ -76,3 +77,10 @@ impl DeviceId {
|
|||
fn make_wid(surface: &WlSurface) -> WindowId {
|
||||
WindowId(surface.id().as_ptr() as u64)
|
||||
}
|
||||
|
||||
/// The default routine does floor, but we need round on Wayland.
|
||||
fn logical_to_physical_rounded(size: LogicalSize<u32>, scale_factor: f64) -> PhysicalSize<u32> {
|
||||
let width = size.width as f64 * scale_factor;
|
||||
let height = size.height as f64 * scale_factor;
|
||||
(width.round(), height.round()).into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,21 +23,19 @@ use sctk::shm::slot::SlotPool;
|
|||
use sctk::shm::{Shm, ShmHandler};
|
||||
use sctk::subcompositor::SubcompositorState;
|
||||
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::platform_impl::OsError;
|
||||
|
||||
use super::event_loop::sink::EventSink;
|
||||
use super::output::MonitorHandle;
|
||||
use super::seat::{
|
||||
use crate::platform_impl::wayland::event_loop::sink::EventSink;
|
||||
use crate::platform_impl::wayland::output::MonitorHandle;
|
||||
use crate::platform_impl::wayland::seat::{
|
||||
PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
|
||||
WinitPointerDataExt, WinitSeatState,
|
||||
};
|
||||
use super::types::kwin_blur::KWinBlurManager;
|
||||
use super::types::wp_fractional_scaling::FractionalScalingManager;
|
||||
use super::types::wp_viewporter::ViewporterState;
|
||||
use super::types::xdg_activation::XdgActivationState;
|
||||
use super::window::{WindowRequests, WindowState};
|
||||
use super::{WaylandError, WindowId};
|
||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||
use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager;
|
||||
use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState;
|
||||
use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState;
|
||||
use crate::platform_impl::wayland::window::{WindowRequests, WindowState};
|
||||
use crate::platform_impl::wayland::{WaylandError, WindowId};
|
||||
use crate::platform_impl::OsError;
|
||||
|
||||
/// Winit's Wayland state.
|
||||
pub struct WinitState {
|
||||
|
|
@ -227,7 +225,7 @@ impl WinitState {
|
|||
|
||||
// Update the scale factor right away.
|
||||
window.lock().unwrap().set_scale_factor(scale_factor);
|
||||
self.window_compositor_updates[pos].scale_factor = Some(scale_factor);
|
||||
self.window_compositor_updates[pos].scale_changed = true;
|
||||
} else if let Some(pointer) = self.pointer_surfaces.get(&surface.id()) {
|
||||
// Get the window, where the pointer resides right now.
|
||||
let focused_window = match pointer.pointer().winit_data().focused_window() {
|
||||
|
|
@ -291,9 +289,7 @@ impl WindowHandler for WinitState {
|
|||
};
|
||||
|
||||
// Populate the configure to the window.
|
||||
//
|
||||
// XXX the size on the window will be updated right before dispatching the size to the user.
|
||||
let new_size = self
|
||||
self.window_compositor_updates[pos].resized |= self
|
||||
.windows
|
||||
.get_mut()
|
||||
.get_mut(&window_id)
|
||||
|
|
@ -306,12 +302,6 @@ impl WindowHandler for WinitState {
|
|||
&self.subcompositor_state,
|
||||
&mut self.events_sink,
|
||||
);
|
||||
|
||||
// NOTE: Only update when the value is `Some` to not override consequent configures with
|
||||
// the same sizes.
|
||||
if new_size.is_some() {
|
||||
self.window_compositor_updates[pos].size = new_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -405,10 +395,10 @@ pub struct WindowCompositorUpdate {
|
|||
pub window_id: WindowId,
|
||||
|
||||
/// New window size.
|
||||
pub size: Option<LogicalSize<u32>>,
|
||||
pub resized: bool,
|
||||
|
||||
/// New scale factor.
|
||||
pub scale_factor: Option<f64>,
|
||||
pub scale_changed: bool,
|
||||
|
||||
/// Close the window.
|
||||
pub close_window: bool,
|
||||
|
|
@ -418,8 +408,8 @@ impl WindowCompositorUpdate {
|
|||
fn new(window_id: WindowId) -> Self {
|
||||
Self {
|
||||
window_id,
|
||||
size: None,
|
||||
scale_factor: None,
|
||||
resized: false,
|
||||
scale_changed: false,
|
||||
close_window: false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ impl Window {
|
|||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||
let window_state = self.window_state.lock().unwrap();
|
||||
let scale_factor = window_state.scale_factor();
|
||||
window_state.inner_size().to_physical(scale_factor)
|
||||
super::logical_to_physical_rounded(window_state.inner_size(), scale_factor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -315,7 +315,7 @@ impl Window {
|
|||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||
let window_state = self.window_state.lock().unwrap();
|
||||
let scale_factor = window_state.scale_factor();
|
||||
window_state.outer_size().to_physical(scale_factor)
|
||||
super::logical_to_physical_rounded(window_state.outer_size(), scale_factor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
|
|||
use crate::error::{ExternalError, NotSupportedError};
|
||||
use crate::event::WindowEvent;
|
||||
use crate::platform_impl::wayland::event_loop::sink::EventSink;
|
||||
use crate::platform_impl::wayland::make_wid;
|
||||
use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor};
|
||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||
use crate::platform_impl::wayland::{logical_to_physical_rounded, make_wid};
|
||||
use crate::platform_impl::WindowId;
|
||||
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
||||
|
||||
|
|
@ -262,7 +262,7 @@ impl WindowState {
|
|||
shm: &Shm,
|
||||
subcompositor: &Option<Arc<SubcompositorState>>,
|
||||
event_sink: &mut EventSink,
|
||||
) -> Option<LogicalSize<u32>> {
|
||||
) -> bool {
|
||||
// NOTE: when using fractional scaling or wl_compositor@v6 the scaling
|
||||
// should be delivered before the first configure, thus apply it to
|
||||
// properly scale the physical sizes provided by the users.
|
||||
|
|
@ -374,9 +374,9 @@ impl WindowState {
|
|||
|
||||
if state_change_requires_resize || new_size != self.inner_size() {
|
||||
self.resize(new_size);
|
||||
Some(new_size)
|
||||
true
|
||||
} else {
|
||||
None
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -656,7 +656,7 @@ impl WindowState {
|
|||
self.resize(inner_size.to_logical(self.scale_factor()))
|
||||
}
|
||||
|
||||
self.inner_size().to_physical(self.scale_factor())
|
||||
logical_to_physical_rounded(self.inner_size(), self.scale_factor())
|
||||
}
|
||||
|
||||
/// Resize the window to the new inner size.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue