Fix issues where screen and window sizes contained Pixels, but were declared as DevicePixels (#12991)

On most platforms, things were working correctly, but had the wrong
type. On X11, there were some problems with window and display size
calculations.

Release Notes:

- Fixed issues with window positioning on X11

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-06-13 10:48:37 -07:00 committed by GitHub
parent 22dc88ed3d
commit da281d6d8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 331 additions and 367 deletions

View file

@ -1,6 +1,5 @@
use std::cell::{Ref, RefCell, RefMut};
use std::ffi::c_void;
use std::num::NonZeroU32;
use std::ptr::NonNull;
use std::rc::Rc;
use std::sync::Arc;
@ -26,9 +25,9 @@ use crate::platform::linux::wayland::serial::SerialKind;
use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
use crate::scene::Scene;
use crate::{
px, size, AnyWindowHandle, Bounds, DevicePixels, Globals, Modifiers, Output, Pixels,
PlatformDisplay, PlatformInput, Point, PromptLevel, Size, WaylandClientStatePtr,
WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowParams,
px, size, AnyWindowHandle, Bounds, Globals, Modifiers, Output, Pixels, PlatformDisplay,
PlatformInput, Point, PromptLevel, Size, WaylandClientStatePtr, WindowAppearance,
WindowBackgroundAppearance, WindowBounds, WindowParams,
};
#[derive(Default)]
@ -76,13 +75,13 @@ pub struct WaylandWindowState {
display: Option<(ObjectId, Output)>,
globals: Globals,
renderer: BladeRenderer,
bounds: Bounds<u32>,
bounds: Bounds<Pixels>,
scale: f32,
input_handler: Option<PlatformInputHandler>,
decoration_state: WaylandDecorationState,
fullscreen: bool,
maximized: bool,
windowed_bounds: Bounds<DevicePixels>,
windowed_bounds: Bounds<Pixels>,
client: WaylandClientStatePtr,
handle: AnyWindowHandle,
active: bool,
@ -108,8 +107,6 @@ impl WaylandWindowState {
globals: Globals,
options: WindowParams,
) -> anyhow::Result<Self> {
let bounds = options.bounds.map(|p| p.0 as u32);
let raw = RawWindow {
window: surface.id().as_ptr().cast::<c_void>(),
display: surface
@ -134,8 +131,8 @@ impl WaylandWindowState {
);
let config = BladeSurfaceConfig {
size: gpu::Extent {
width: bounds.size.width,
height: bounds.size.height,
width: options.bounds.size.width.0 as u32,
height: options.bounds.size.height.0 as u32,
depth: 1,
},
transparent: options.window_background != WindowBackgroundAppearance::Opaque,
@ -153,7 +150,7 @@ impl WaylandWindowState {
outputs: HashMap::default(),
display: None,
renderer: BladeRenderer::new(gpu, config),
bounds,
bounds: options.bounds,
scale: 1.0,
input_handler: None,
decoration_state: WaylandDecorationState::Client,
@ -349,10 +346,16 @@ impl WaylandWindowStatePtr {
pub fn handle_toplevel_event(&self, event: xdg_toplevel::Event) -> bool {
match event {
xdg_toplevel::Event::Configure {
mut width,
mut height,
width,
height,
states,
} => {
let mut size = if width == 0 || height == 0 {
None
} else {
Some(size(px(width as f32), px(height as f32)))
};
let fullscreen = states.contains(&(xdg_toplevel::State::Fullscreen as u8));
let maximized = states.contains(&(xdg_toplevel::State::Maximized as u8));
@ -362,19 +365,20 @@ impl WaylandWindowStatePtr {
state.maximized = maximized;
if got_unmaximized {
width = state.windowed_bounds.size.width.0;
height = state.windowed_bounds.size.height.0;
} else if width != 0 && height != 0 && !fullscreen && !maximized {
state.windowed_bounds = Bounds {
origin: Point::default(),
size: size(width.into(), height.into()),
};
size = Some(state.windowed_bounds.size);
} else if !fullscreen && !maximized {
if let Some(size) = size {
state.windowed_bounds = Bounds {
origin: Point::default(),
size,
};
}
}
let width = NonZeroU32::new(width as u32);
let height = NonZeroU32::new(height as u32);
drop(state);
self.resize(width, height);
if let Some(size) = size {
self.resize(size);
}
false
}
@ -483,63 +487,43 @@ impl WaylandWindowStatePtr {
bounds
}
pub fn set_size_and_scale(
&self,
width: Option<NonZeroU32>,
height: Option<NonZeroU32>,
scale: Option<f32>,
) {
let (width, height, scale) = {
pub fn set_size_and_scale(&self, size: Option<Size<Pixels>>, scale: Option<f32>) {
let (size, scale) = {
let mut state = self.state.borrow_mut();
if width.map_or(true, |width| width.get() == state.bounds.size.width)
&& height.map_or(true, |height| height.get() == state.bounds.size.height)
if size.map_or(true, |size| size == state.bounds.size)
&& scale.map_or(true, |scale| scale == state.scale)
{
return;
}
if let Some(width) = width {
state.bounds.size.width = width.get();
}
if let Some(height) = height {
state.bounds.size.height = height.get();
if let Some(size) = size {
state.bounds.size = size;
}
if let Some(scale) = scale {
state.scale = scale;
}
let width = state.bounds.size.width;
let height = state.bounds.size.height;
let scale = state.scale;
state.renderer.update_drawable_size(size(
width as f64 * scale as f64,
height as f64 * scale as f64,
));
(width, height, scale)
let device_bounds = state.bounds.to_device_pixels(state.scale);
state.renderer.update_drawable_size(device_bounds.size);
(state.bounds.size, state.scale)
};
if let Some(ref mut fun) = self.callbacks.borrow_mut().resize {
fun(
Size {
width: px(width as f32),
height: px(height as f32),
},
scale,
);
fun(size, scale);
}
{
let state = self.state.borrow();
if let Some(viewport) = &state.viewport {
viewport.set_destination(width as i32, height as i32);
viewport.set_destination(size.width.0 as i32, size.height.0 as i32);
}
}
}
pub fn resize(&self, width: Option<NonZeroU32>, height: Option<NonZeroU32>) {
self.set_size_and_scale(width, height, None);
pub fn resize(&self, size: Size<Pixels>) {
self.set_size_and_scale(Some(size), None);
}
pub fn rescale(&self, scale: f32) {
self.set_size_and_scale(None, None, Some(scale));
self.set_size_and_scale(None, Some(scale));
}
/// Notifies the window of the state of the decorations.
@ -625,8 +609,8 @@ impl rwh::HasDisplayHandle for WaylandWindow {
}
impl PlatformWindow for WaylandWindow {
fn bounds(&self) -> Bounds<DevicePixels> {
self.borrow().bounds.map(|p| DevicePixels(p as i32))
fn bounds(&self) -> Bounds<Pixels> {
self.borrow().bounds
}
fn is_maximized(&self) -> bool {
@ -640,16 +624,13 @@ impl PlatformWindow for WaylandWindow {
} else if state.maximized {
WindowBounds::Maximized(state.windowed_bounds)
} else {
WindowBounds::Windowed(state.bounds.map(|p| DevicePixels(p as i32)))
drop(state);
WindowBounds::Windowed(self.bounds())
}
}
fn content_size(&self) -> Size<Pixels> {
let state = self.borrow();
Size {
width: Pixels(state.bounds.size.width as f32),
height: Pixels(state.bounds.size.height as f32),
}
self.borrow().bounds.size
}
fn scale_factor(&self) -> f32 {
@ -661,11 +642,12 @@ impl PlatformWindow for WaylandWindow {
}
fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
self.borrow().display.as_ref().map(|(id, display)| {
let state = self.borrow();
state.display.as_ref().map(|(id, display)| {
Rc::new(WaylandDisplay {
id: id.clone(),
name: display.name.clone(),
bounds: display.bounds,
bounds: display.bounds.to_pixels(state.scale),
}) as Rc<dyn PlatformDisplay>
})
}