diff --git a/CHANGELOG.md b/CHANGELOG.md index f50757fd5b..bc5ba4abe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Unreleased` header. # Unreleased - On X11, reduce the amount of time spent fetching screen resources. +- 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 diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 2ba3bb07dc..b9fbf2c091 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -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>; @@ -356,15 +356,13 @@ impl EventLoop { 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 EventLoop { 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 = + 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 EventLoop { .redraw_requested .store(true, Ordering::Relaxed); - physical_size + size }); callback( @@ -684,10 +682,3 @@ impl EventLoopWindowTarget { .into()) } } - -// The default routine does floor, but we need round on Wayland. -fn logical_to_physical_rounded(size: LogicalSize, scale_factor: f64) -> PhysicalSize { - let width = size.width as f64 * scale_factor; - let height = size.height as f64 * scale_factor; - (width.round(), height.round()).into() -} diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 6d232b0d8a..44c6d2e3f4 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -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, VideoMode}; @@ -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, scale_factor: f64) -> PhysicalSize { + let width = size.width as f64 * scale_factor; + let height = size.height as f64 * scale_factor; + (width.round(), height.round()).into() +} diff --git a/src/platform_impl/linux/wayland/state.rs b/src/platform_impl/linux/wayland/state.rs index 8e81c59a1a..1d38a570a4 100644 --- a/src/platform_impl/linux/wayland/state.rs +++ b/src/platform_impl/linux/wayland/state.rs @@ -22,21 +22,19 @@ use sctk::shell::WaylandSurface; 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 { @@ -219,7 +217,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() { @@ -283,9 +281,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) @@ -298,12 +294,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; - } } } @@ -397,10 +387,10 @@ pub struct WindowCompositorUpdate { pub window_id: WindowId, /// New window size. - pub size: Option>, + pub resized: bool, /// New scale factor. - pub scale_factor: Option, + pub scale_changed: bool, /// Close the window. pub close_window: bool, @@ -410,8 +400,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, } } diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index ae6558a810..2ca949a7cf 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -280,7 +280,7 @@ impl Window { pub fn inner_size(&self) -> PhysicalSize { 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] @@ -308,7 +308,7 @@ impl Window { pub fn outer_size(&self) -> PhysicalSize { 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] diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index cfa6cc66a6..dd48bd91fe 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -31,8 +31,8 @@ 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::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}; @@ -256,7 +256,7 @@ impl WindowState { shm: &Shm, subcompositor: &Option>, event_sink: &mut EventSink, - ) -> Option> { + ) -> 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. @@ -368,9 +368,9 @@ impl WindowState { if state_change_requires_resize || new_size != self.inner_size() { self.resize(new_size); - Some(new_size) + true } else { - None + false } } @@ -647,7 +647,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.