Allow toplevels to reconfigure themselves

This commit is contained in:
Shawn Wallace 2025-05-11 11:46:29 -04:00
parent 378421d356
commit 51300780f8
4 changed files with 36 additions and 26 deletions

View file

@ -125,7 +125,7 @@ impl SurfaceData {
output_name output_name
} }
fn update_viewport(&self, dims: WindowDims, size_hints: Option<WmNormalHints>) { pub(super) fn update_viewport(&self, dims: WindowDims, size_hints: Option<WmNormalHints>) {
let width = (dims.width as f64 / self.scale_factor) as i32; let width = (dims.width as f64 / self.scale_factor) as i32;
let height = (dims.height as f64 / self.scale_factor) as i32; let height = (dims.height as f64 / self.scale_factor) as i32;
if width > 0 && height > 0 { if width > 0 && height > 0 {

View file

@ -798,8 +798,8 @@ impl<C: XConnection> ServerState<C> {
win.surface_serial = Some(serial); win.surface_serial = Some(serial);
} }
pub fn can_reconfigure_window(&mut self, window: x::Window) -> bool { pub fn can_change_position(&self, window: x::Window) -> bool {
let Some(win) = self.windows.get_mut(&window) else { let Some(win) = self.windows.get(&window) else {
return true; return true;
}; };
@ -851,6 +851,11 @@ impl<C: XConnection> ServerState<C> {
); );
popup.popup.reposition(&popup.positioner, 0); popup.popup.reposition(&popup.positioner, 0);
} }
Some(SurfaceRole::Toplevel(Some(_))) => {
win.attrs.dims.width = dims.width;
win.attrs.dims.height = dims.height;
data.update_viewport(win.attrs.dims, win.attrs.size_hints);
}
other => warn!("Non popup ({other:?}) being reconfigured, behavior may be off."), other => warn!("Non popup ({other:?}) being reconfigured, behavior may be off."),
} }
} }

View file

@ -1574,17 +1574,27 @@ fn reposition_popup() {
} }
#[test] #[test]
fn ignore_toplevel_reconfigure() { fn toplevel_reconfigure() {
let (mut f, comp) = TestFixture::new_with_compositor(); let (mut f, comp) = TestFixture::new_with_compositor();
let toplevel = unsafe { Window::new(1) }; let toplevel = unsafe { Window::new(1) };
let _ = f.create_toplevel(&comp, toplevel); let (_, surface) = f.create_toplevel(&comp, toplevel);
{
let data = f
.testwl
.get_surface_data(surface)
.expect("Missing surface data");
let viewport = data.viewport.as_ref().expect("Missing viewport");
assert_eq!(viewport.width, 100);
assert_eq!(viewport.height, 100);
}
f.satellite.reconfigure_window(x::ConfigureNotifyEvent::new( f.satellite.reconfigure_window(x::ConfigureNotifyEvent::new(
toplevel, toplevel,
toplevel, toplevel,
x::WINDOW_NONE, x::WINDOW_NONE,
40, // x 0, // x
60, // y 0, // y
80, // width 80, // width
100, // height 100, // height
0, 0,
@ -1592,16 +1602,13 @@ fn ignore_toplevel_reconfigure() {
)); ));
f.run(); f.run();
let win_data = &f.connection().windows[&toplevel]; let data = f
assert_eq!( .testwl
win_data.dims, .get_surface_data(surface)
WindowDims { .expect("Missing surface data");
x: 0, let viewport = data.viewport.as_ref().expect("Missing viewport");
y: 0, assert_eq!(viewport.width, 80);
width: 100, assert_eq!(viewport.height, 100);
height: 100
}
);
} }
type EventMatcher<'a, Event> = Box<dyn FnMut(&Event) -> bool + 'a>; type EventMatcher<'a, Event> = Box<dyn FnMut(&Event) -> bool + 'a>;

View file

@ -407,20 +407,18 @@ impl XState {
self.handle_property_change(e, server_state); self.handle_property_change(e, server_state);
} }
xcb::Event::X(x::Event::ConfigureRequest(e)) => { xcb::Event::X(x::Event::ConfigureRequest(e)) => {
if !server_state.can_reconfigure_window(e.window()) {
debug!("ignoring reconfigure request for {:?}", e.window());
continue;
}
debug!("{:?} request: {:?}", e.window(), e.value_mask()); debug!("{:?} request: {:?}", e.window(), e.value_mask());
let mut list = Vec::new(); let mut list = Vec::new();
let mask = e.value_mask(); let mask = e.value_mask();
if mask.contains(x::ConfigWindowMask::X) { if server_state.can_change_position(e.window()) {
list.push(x::ConfigWindow::X(e.x().into())); if mask.contains(x::ConfigWindowMask::X) {
} list.push(x::ConfigWindow::X(e.x().into()));
if mask.contains(x::ConfigWindowMask::Y) { }
list.push(x::ConfigWindow::Y(e.y().into())); if mask.contains(x::ConfigWindowMask::Y) {
list.push(x::ConfigWindow::Y(e.y().into()));
}
} }
if mask.contains(x::ConfigWindowMask::WIDTH) { if mask.contains(x::ConfigWindowMask::WIDTH) {
list.push(x::ConfigWindow::Width(e.width().into())); list.push(x::ConfigWindow::Width(e.width().into()));