On Wayland, improve initial user size handling
Keep the user provided size in the original values and convert only when we're getting a `configure` event. On some compositors will have a scale available, so it'll work, however with some we'll still have old 'pick 1` as default. Also configure_bounds when compositor tells the user to pick the size, that will ensure that initial `with_inner_size` won't grow beyond the working area. Fixes #3187.
This commit is contained in:
parent
53ca5af48f
commit
12dbbf8012
5 changed files with 92 additions and 26 deletions
|
|
@ -11,7 +11,10 @@ Unreleased` header.
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On Wayland, apply correct scale to `PhysicalSize` passed in `WindowBuilder::with_inner_size` when possible.
|
||||||
- On Wayland, fix `RedrawRequsted` being always sent without decorations and `sctk-adwaita` feature.
|
- On Wayland, fix `RedrawRequsted` being always sent without decorations and `sctk-adwaita` feature.
|
||||||
|
- On Wayland, ignore resize requests when the window is fully tiled.
|
||||||
|
- On Wayland, use `configure_bounds` to constrain `with_inner_size` when compositor wants users to pick size.
|
||||||
- On Windows, fix deadlock when accessing the state during `Cursor{Enter,Leave}`.
|
- On Windows, fix deadlock when accessing the state during `Cursor{Enter,Leave}`.
|
||||||
- On macOS, fix deadlock when entering a nested event loop from an event handler.
|
- On macOS, fix deadlock when entering a nested event loop from an event handler.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
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();
|
||||||
window.resize(new_logical_size);
|
window.request_inner_size(new_logical_size.into());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,9 @@ impl Window {
|
||||||
.map(|activation_state| activation_state.global().clone());
|
.map(|activation_state| activation_state.global().clone());
|
||||||
let display = event_loop_window_target.connection.display();
|
let display = event_loop_window_target.connection.display();
|
||||||
|
|
||||||
// XXX The initial scale factor must be 1, but it might cause sizing issues on HiDPI.
|
let size: Size = attributes
|
||||||
let size: LogicalSize<u32> = attributes
|
|
||||||
.inner_size
|
.inner_size
|
||||||
.map(|size| size.to_logical::<u32>(1.))
|
.unwrap_or(LogicalSize::new(800., 600.).into());
|
||||||
.unwrap_or((800, 600).into());
|
|
||||||
|
|
||||||
// We prefer server side decorations, however to not have decorations we ask for client
|
// We prefer server side decorations, however to not have decorations we ask for client
|
||||||
// side decorations instead.
|
// side decorations instead.
|
||||||
|
|
@ -141,7 +139,8 @@ impl Window {
|
||||||
// Set the window title.
|
// Set the window title.
|
||||||
window_state.set_title(attributes.title);
|
window_state.set_title(attributes.title);
|
||||||
|
|
||||||
// Set the min and max sizes.
|
// Set the min and max sizes. We must set the hints upon creating a window, so
|
||||||
|
// we use the default `1.` scaling...
|
||||||
let min_size = attributes.min_inner_size.map(|size| size.to_logical(1.));
|
let min_size = attributes.min_inner_size.map(|size| size.to_logical(1.));
|
||||||
let max_size = attributes.max_inner_size.map(|size| size.to_logical(1.));
|
let max_size = attributes.max_inner_size.map(|size| size.to_logical(1.));
|
||||||
window_state.set_min_inner_size(min_size);
|
window_state.set_min_inner_size(min_size);
|
||||||
|
|
@ -315,12 +314,9 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
|
pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
|
||||||
let mut window_state = self.window_state.lock().unwrap();
|
let mut window_state = self.window_state.lock().unwrap();
|
||||||
let scale_factor = window_state.scale_factor();
|
let new_size = window_state.request_inner_size(size);
|
||||||
window_state.resize(size.to_logical::<u32>(scale_factor));
|
|
||||||
|
|
||||||
self.request_redraw();
|
self.request_redraw();
|
||||||
|
Some(new_size)
|
||||||
Some(window_state.inner_size().to_physical(scale_factor))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the minimum inner size for the window.
|
/// Set the minimum inner size for the window.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use sctk::shm::Shm;
|
||||||
use sctk::subcompositor::SubcompositorState;
|
use sctk::subcompositor::SubcompositorState;
|
||||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
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;
|
||||||
|
|
@ -133,6 +133,10 @@ pub struct WindowState {
|
||||||
/// sends `None` for the new size in the configure.
|
/// sends `None` for the new size in the configure.
|
||||||
stateless_size: LogicalSize<u32>,
|
stateless_size: LogicalSize<u32>,
|
||||||
|
|
||||||
|
/// Initial window size provided by the user. Removed on the first
|
||||||
|
/// configure.
|
||||||
|
initial_size: Option<Size>,
|
||||||
|
|
||||||
/// The state of the frame callback.
|
/// The state of the frame callback.
|
||||||
frame_callback_state: FrameCallbackState,
|
frame_callback_state: FrameCallbackState,
|
||||||
|
|
||||||
|
|
@ -153,7 +157,7 @@ impl WindowState {
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
queue_handle: &QueueHandle<WinitState>,
|
queue_handle: &QueueHandle<WinitState>,
|
||||||
winit_state: &WinitState,
|
winit_state: &WinitState,
|
||||||
size: LogicalSize<u32>,
|
initial_size: Size,
|
||||||
window: Window,
|
window: Window,
|
||||||
theme: Option<Theme>,
|
theme: Option<Theme>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -194,8 +198,9 @@ impl WindowState {
|
||||||
resizable: true,
|
resizable: true,
|
||||||
scale_factor: 1.,
|
scale_factor: 1.,
|
||||||
shm: winit_state.shm.wl_shm().clone(),
|
shm: winit_state.shm.wl_shm().clone(),
|
||||||
size,
|
size: initial_size.to_logical(1.),
|
||||||
stateless_size: size,
|
stateless_size: initial_size.to_logical(1.),
|
||||||
|
initial_size: Some(initial_size),
|
||||||
text_inputs: Vec::new(),
|
text_inputs: Vec::new(),
|
||||||
theme,
|
theme,
|
||||||
title: String::default(),
|
title: String::default(),
|
||||||
|
|
@ -253,6 +258,14 @@ impl WindowState {
|
||||||
subcompositor: &Arc<SubcompositorState>,
|
subcompositor: &Arc<SubcompositorState>,
|
||||||
event_sink: &mut EventSink,
|
event_sink: &mut EventSink,
|
||||||
) -> LogicalSize<u32> {
|
) -> LogicalSize<u32> {
|
||||||
|
// 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.
|
||||||
|
if let Some(initial_size) = self.initial_size.take() {
|
||||||
|
self.size = initial_size.to_logical(self.scale_factor());
|
||||||
|
self.stateless_size = self.size;
|
||||||
|
}
|
||||||
|
|
||||||
if configure.decoration_mode == DecorationMode::Client
|
if configure.decoration_mode == DecorationMode::Client
|
||||||
&& self.frame.is_none()
|
&& self.frame.is_none()
|
||||||
&& !self.csd_fails
|
&& !self.csd_fails
|
||||||
|
|
@ -297,7 +310,7 @@ impl WindowState {
|
||||||
event_sink.push_window_event(WindowEvent::Occluded(occluded), window_id);
|
event_sink.push_window_event(WindowEvent::Occluded(occluded), window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_size = if let Some(frame) = self.frame.as_mut() {
|
let (mut new_size, constrain) = if let Some(frame) = self.frame.as_mut() {
|
||||||
// Configure the window states.
|
// Configure the window states.
|
||||||
frame.update_state(configure.state);
|
frame.update_state(configure.state);
|
||||||
|
|
||||||
|
|
@ -305,22 +318,38 @@ impl WindowState {
|
||||||
(Some(width), Some(height)) => {
|
(Some(width), Some(height)) => {
|
||||||
let (width, height) = frame.subtract_borders(width, height);
|
let (width, height) = frame.subtract_borders(width, height);
|
||||||
(
|
(
|
||||||
width.map(|w| w.get()).unwrap_or(1),
|
(
|
||||||
height.map(|h| h.get()).unwrap_or(1),
|
width.map(|w| w.get()).unwrap_or(1),
|
||||||
|
height.map(|h| h.get()).unwrap_or(1),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
(_, _) if stateless => self.stateless_size,
|
(_, _) if stateless => (self.stateless_size, true),
|
||||||
_ => self.size,
|
_ => (self.size, true),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match configure.new_size {
|
match configure.new_size {
|
||||||
(Some(width), Some(height)) => (width.get(), height.get()).into(),
|
(Some(width), Some(height)) => ((width.get(), height.get()).into(), false),
|
||||||
_ if stateless => self.stateless_size,
|
_ if stateless => (self.stateless_size, true),
|
||||||
_ => self.size,
|
_ => (self.size, true),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Apply configure bounds only when compositor let the user decide what size to pick.
|
||||||
|
if constrain {
|
||||||
|
let bounds = self.inner_size_bounds(&configure);
|
||||||
|
new_size.width = bounds
|
||||||
|
.0
|
||||||
|
.map(|bound_w| new_size.width.min(bound_w.get()))
|
||||||
|
.unwrap_or(new_size.width);
|
||||||
|
new_size.height = bounds
|
||||||
|
.1
|
||||||
|
.map(|bound_h| new_size.height.min(bound_h.get()))
|
||||||
|
.unwrap_or(new_size.height);
|
||||||
|
}
|
||||||
|
|
||||||
// XXX Set the configure before doing a resize.
|
// XXX Set the configure before doing a resize.
|
||||||
self.last_configure = Some(configure);
|
self.last_configure = Some(configure);
|
||||||
|
|
||||||
|
|
@ -330,6 +359,30 @@ impl WindowState {
|
||||||
new_size
|
new_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the bounds for the inner size of the surface.
|
||||||
|
fn inner_size_bounds(
|
||||||
|
&self,
|
||||||
|
configure: &WindowConfigure,
|
||||||
|
) -> (Option<NonZeroU32>, Option<NonZeroU32>) {
|
||||||
|
let configure_bounds = match configure.suggested_bounds {
|
||||||
|
Some((width, height)) => (NonZeroU32::new(width), NonZeroU32::new(height)),
|
||||||
|
None => (None, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(frame) = self.frame.as_ref() {
|
||||||
|
let (width, height) = frame.subtract_borders(
|
||||||
|
configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()),
|
||||||
|
configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()),
|
||||||
|
);
|
||||||
|
(
|
||||||
|
configure_bounds.0.and(width),
|
||||||
|
configure_bounds.1.and(height),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
configure_bounds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_stateless(configure: &WindowConfigure) -> bool {
|
fn is_stateless(configure: &WindowConfigure) -> bool {
|
||||||
!(configure.is_maximized() || configure.is_fullscreen() || configure.is_tiled())
|
!(configure.is_maximized() || configure.is_fullscreen() || configure.is_tiled())
|
||||||
|
|
@ -568,8 +621,22 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to resize the window when the user can do so.
|
||||||
|
pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize<u32> {
|
||||||
|
if self
|
||||||
|
.last_configure
|
||||||
|
.as_ref()
|
||||||
|
.map(Self::is_stateless)
|
||||||
|
.unwrap_or(true)
|
||||||
|
{
|
||||||
|
self.resize(inner_size.to_logical(self.scale_factor()))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inner_size().to_physical(self.scale_factor())
|
||||||
|
}
|
||||||
|
|
||||||
/// Resize the window to the new inner size.
|
/// Resize the window to the new inner size.
|
||||||
pub fn resize(&mut self, inner_size: LogicalSize<u32>) {
|
fn resize(&mut self, inner_size: LogicalSize<u32>) {
|
||||||
self.size = inner_size;
|
self.size = inner_size;
|
||||||
|
|
||||||
// Update the stateless size.
|
// Update the stateless size.
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ impl XConnection {
|
||||||
return Ok(MonitorHandle::dummy());
|
return Ok(MonitorHandle::dummy());
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = monitors.get(0).unwrap();
|
let default = monitors.first().unwrap();
|
||||||
|
|
||||||
let window_rect = match window_rect {
|
let window_rect = match window_rect {
|
||||||
Some(rect) => rect,
|
Some(rect) => rect,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue