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`.
|
- On Web, add the ability to toggle calling `Event.preventDefault()` on `Window`.
|
||||||
- **Breaking:** Remove `WindowAttributes::fullscreen()` and expose as field directly.
|
- **Breaking:** Remove `WindowAttributes::fullscreen()` and expose as field directly.
|
||||||
- **Breaking:** Rename `VideoMode` to `VideoModeHandle` to represent that it doesn't hold static data.
|
- **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
|
# 0.29.7
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use sctk::reexports::calloop_wayland_source::WaylandSource;
|
||||||
use sctk::reexports::client::globals;
|
use sctk::reexports::client::globals;
|
||||||
use sctk::reexports::client::{Connection, QueueHandle};
|
use sctk::reexports::client::{Connection, QueueHandle};
|
||||||
|
|
||||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
use crate::dpi::LogicalSize;
|
||||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||||
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
|
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
|
||||||
use crate::event_loop::{
|
use crate::event_loop::{
|
||||||
|
|
@ -34,7 +34,7 @@ use sink::EventSink;
|
||||||
|
|
||||||
use super::state::{WindowCompositorUpdate, WinitState};
|
use super::state::{WindowCompositorUpdate, WinitState};
|
||||||
use super::window::state::FrameCallbackState;
|
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>;
|
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(..) {
|
for mut compositor_update in compositor_updates.drain(..) {
|
||||||
let window_id = compositor_update.window_id;
|
let window_id = compositor_update.window_id;
|
||||||
if let Some(scale_factor) = compositor_update.scale_factor {
|
if compositor_update.scale_changed {
|
||||||
let physical_size = self.with_state(|state| {
|
let (physical_size, scale_factor) = self.with_state(|state| {
|
||||||
let windows = state.windows.get_mut();
|
let windows = state.windows.get_mut();
|
||||||
let mut window = windows.get(&window_id).unwrap().lock().unwrap();
|
let window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||||
|
let scale_factor = window.scale_factor();
|
||||||
// Set the new scale factor.
|
let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
|
||||||
window.set_scale_factor(scale_factor);
|
(size, scale_factor)
|
||||||
let window_size = compositor_update.size.unwrap_or(window.inner_size());
|
|
||||||
logical_to_physical_rounded(window_size, scale_factor)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stash the old window size.
|
// Stash the old window size.
|
||||||
|
|
@ -386,30 +384,30 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
let physical_size = *new_inner_size.lock().unwrap();
|
let physical_size = *new_inner_size.lock().unwrap();
|
||||||
drop(new_inner_size);
|
drop(new_inner_size);
|
||||||
let new_logical_size = physical_size.to_logical(scale_factor);
|
|
||||||
|
|
||||||
// Resize the window when user altered the size.
|
// Resize the window when user altered the size.
|
||||||
if old_physical_size != physical_size {
|
if old_physical_size != physical_size {
|
||||||
self.with_state(|state| {
|
self.with_state(|state| {
|
||||||
let windows = state.windows.get_mut();
|
let windows = state.windows.get_mut();
|
||||||
let mut window = windows.get(&window_id).unwrap().lock().unwrap();
|
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());
|
window.request_inner_size(new_logical_size.into());
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Make it queue resize.
|
// Make it queue resize.
|
||||||
compositor_update.size = Some(new_logical_size);
|
compositor_update.resized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(size) = compositor_update.size.take() {
|
if compositor_update.resized {
|
||||||
let physical_size = self.with_state(|state| {
|
let physical_size = self.with_state(|state| {
|
||||||
let windows = state.windows.get_mut();
|
let windows = state.windows.get_mut();
|
||||||
let window = windows.get(&window_id).unwrap().lock().unwrap();
|
let window = windows.get(&window_id).unwrap().lock().unwrap();
|
||||||
|
|
||||||
let scale_factor = window.scale_factor();
|
let scale_factor = window.scale_factor();
|
||||||
let physical_size = logical_to_physical_rounded(size, scale_factor);
|
let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
|
||||||
|
|
||||||
// TODO could probably bring back size reporting optimization.
|
|
||||||
|
|
||||||
// Mark the window as needed a redraw.
|
// Mark the window as needed a redraw.
|
||||||
state
|
state
|
||||||
|
|
@ -420,7 +418,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
.redraw_requested
|
.redraw_requested
|
||||||
.store(true, Ordering::Relaxed);
|
.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
physical_size
|
size
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
|
|
@ -684,10 +682,3 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
.into())
|
.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::protocol::wl_surface::WlSurface;
|
||||||
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
||||||
|
|
||||||
|
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||||
pub use crate::platform_impl::platform::{OsError, WindowId};
|
pub use crate::platform_impl::platform::{OsError, WindowId};
|
||||||
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||||
pub use output::{MonitorHandle, VideoModeHandle};
|
pub use output::{MonitorHandle, VideoModeHandle};
|
||||||
|
|
@ -76,3 +77,10 @@ impl DeviceId {
|
||||||
fn make_wid(surface: &WlSurface) -> WindowId {
|
fn make_wid(surface: &WlSurface) -> WindowId {
|
||||||
WindowId(surface.id().as_ptr() as u64)
|
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::shm::{Shm, ShmHandler};
|
||||||
use sctk::subcompositor::SubcompositorState;
|
use sctk::subcompositor::SubcompositorState;
|
||||||
|
|
||||||
use crate::dpi::LogicalSize;
|
use crate::platform_impl::wayland::event_loop::sink::EventSink;
|
||||||
use crate::platform_impl::OsError;
|
use crate::platform_impl::wayland::output::MonitorHandle;
|
||||||
|
use crate::platform_impl::wayland::seat::{
|
||||||
use super::event_loop::sink::EventSink;
|
|
||||||
use super::output::MonitorHandle;
|
|
||||||
use super::seat::{
|
|
||||||
PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
|
PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
|
||||||
WinitPointerDataExt, WinitSeatState,
|
WinitPointerDataExt, WinitSeatState,
|
||||||
};
|
};
|
||||||
use super::types::kwin_blur::KWinBlurManager;
|
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||||
use super::types::wp_fractional_scaling::FractionalScalingManager;
|
use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager;
|
||||||
use super::types::wp_viewporter::ViewporterState;
|
use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState;
|
||||||
use super::types::xdg_activation::XdgActivationState;
|
use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState;
|
||||||
use super::window::{WindowRequests, WindowState};
|
use crate::platform_impl::wayland::window::{WindowRequests, WindowState};
|
||||||
use super::{WaylandError, WindowId};
|
use crate::platform_impl::wayland::{WaylandError, WindowId};
|
||||||
|
use crate::platform_impl::OsError;
|
||||||
|
|
||||||
/// Winit's Wayland state.
|
/// Winit's Wayland state.
|
||||||
pub struct WinitState {
|
pub struct WinitState {
|
||||||
|
|
@ -227,7 +225,7 @@ impl WinitState {
|
||||||
|
|
||||||
// Update the scale factor right away.
|
// Update the scale factor right away.
|
||||||
window.lock().unwrap().set_scale_factor(scale_factor);
|
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()) {
|
} else if let Some(pointer) = self.pointer_surfaces.get(&surface.id()) {
|
||||||
// Get the window, where the pointer resides right now.
|
// Get the window, where the pointer resides right now.
|
||||||
let focused_window = match pointer.pointer().winit_data().focused_window() {
|
let focused_window = match pointer.pointer().winit_data().focused_window() {
|
||||||
|
|
@ -291,9 +289,7 @@ impl WindowHandler for WinitState {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Populate the configure to the window.
|
// Populate the configure to the window.
|
||||||
//
|
self.window_compositor_updates[pos].resized |= self
|
||||||
// XXX the size on the window will be updated right before dispatching the size to the user.
|
|
||||||
let new_size = self
|
|
||||||
.windows
|
.windows
|
||||||
.get_mut()
|
.get_mut()
|
||||||
.get_mut(&window_id)
|
.get_mut(&window_id)
|
||||||
|
|
@ -306,12 +302,6 @@ impl WindowHandler for WinitState {
|
||||||
&self.subcompositor_state,
|
&self.subcompositor_state,
|
||||||
&mut self.events_sink,
|
&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,
|
pub window_id: WindowId,
|
||||||
|
|
||||||
/// New window size.
|
/// New window size.
|
||||||
pub size: Option<LogicalSize<u32>>,
|
pub resized: bool,
|
||||||
|
|
||||||
/// New scale factor.
|
/// New scale factor.
|
||||||
pub scale_factor: Option<f64>,
|
pub scale_changed: bool,
|
||||||
|
|
||||||
/// Close the window.
|
/// Close the window.
|
||||||
pub close_window: bool,
|
pub close_window: bool,
|
||||||
|
|
@ -418,8 +408,8 @@ impl WindowCompositorUpdate {
|
||||||
fn new(window_id: WindowId) -> Self {
|
fn new(window_id: WindowId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
window_id,
|
window_id,
|
||||||
size: None,
|
resized: false,
|
||||||
scale_factor: None,
|
scale_changed: false,
|
||||||
close_window: false,
|
close_window: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,7 @@ impl Window {
|
||||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||||
let window_state = self.window_state.lock().unwrap();
|
let window_state = self.window_state.lock().unwrap();
|
||||||
let scale_factor = window_state.scale_factor();
|
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]
|
#[inline]
|
||||||
|
|
@ -315,7 +315,7 @@ impl Window {
|
||||||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||||
let window_state = self.window_state.lock().unwrap();
|
let window_state = self.window_state.lock().unwrap();
|
||||||
let scale_factor = window_state.scale_factor();
|
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]
|
#[inline]
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
|
||||||
use crate::error::{ExternalError, NotSupportedError};
|
use crate::error::{ExternalError, NotSupportedError};
|
||||||
use crate::event::WindowEvent;
|
use crate::event::WindowEvent;
|
||||||
use crate::platform_impl::wayland::event_loop::sink::EventSink;
|
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::cursor::{CustomCursor, SelectedCursor};
|
||||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
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::platform_impl::WindowId;
|
||||||
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
||||||
|
|
||||||
|
|
@ -262,7 +262,7 @@ impl WindowState {
|
||||||
shm: &Shm,
|
shm: &Shm,
|
||||||
subcompositor: &Option<Arc<SubcompositorState>>,
|
subcompositor: &Option<Arc<SubcompositorState>>,
|
||||||
event_sink: &mut EventSink,
|
event_sink: &mut EventSink,
|
||||||
) -> Option<LogicalSize<u32>> {
|
) -> bool {
|
||||||
// NOTE: when using fractional scaling or wl_compositor@v6 the scaling
|
// NOTE: when using fractional scaling or wl_compositor@v6 the scaling
|
||||||
// should be delivered before the first configure, thus apply it to
|
// should be delivered before the first configure, thus apply it to
|
||||||
// properly scale the physical sizes provided by the users.
|
// 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() {
|
if state_change_requires_resize || new_size != self.inner_size() {
|
||||||
self.resize(new_size);
|
self.resize(new_size);
|
||||||
Some(new_size)
|
true
|
||||||
} else {
|
} else {
|
||||||
None
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -656,7 +656,7 @@ impl WindowState {
|
||||||
self.resize(inner_size.to_logical(self.scale_factor()))
|
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.
|
/// Resize the window to the new inner size.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue