diff --git a/src/server/event.rs b/src/server/event.rs index 3107aa5..537e3e7 100644 --- a/src/server/event.rs +++ b/src/server/event.rs @@ -151,7 +151,7 @@ impl SurfaceEvents { x: dimensions.x - state.global_output_offset.x.value, y: dimensions.y - state.global_output_offset.y.value, }, - state.connection.as_mut().unwrap(), + &mut state.connection, ); if state.last_focused_toplevel == Some(*window) { let output = get_output_name(Some(&on_output), &state.world); @@ -889,21 +889,19 @@ fn update_output_offset( ); } - if let Some(connection) = state.connection.as_mut() { - update_window_output_offsets( - output, - &state.global_output_offset, - &state.world, - connection, - ); - } + update_window_output_offsets( + output, + &state.global_output_offset, + &state.world, + &mut state.connection, + ); } fn update_window_output_offsets( output: Entity, global_output_offset: &GlobalOutputOffset, world: &World, - connection: &mut impl XConnection, + connection: &mut Option, ) { let dimensions = world.get::<&OutputDimensions>(output).unwrap(); let mut query = world.query::<(&x::Window, &mut WindowData, &OnOutput)>(); @@ -927,7 +925,7 @@ pub(super) fn update_global_output_offset( output: Entity, global_output_offset: &GlobalOutputOffset, world: &World, - connection: &mut impl XConnection, + connection: &mut Option, ) { let entity = world.entity(output).unwrap(); let mut query = entity.query::<(&OutputDimensions, &WlOutput)>(); diff --git a/src/server/mod.rs b/src/server/mod.rs index 28174c7..4680ab5 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -138,7 +138,7 @@ impl WindowData { &mut self, window: x::Window, offset: WindowOutputOffset, - connection: &mut C, + connection: &mut Option, ) { log::trace!("offset: {offset:?}"); if offset == self.output_offset { @@ -150,15 +150,17 @@ impl WindowData { dims.y += (offset.y - self.output_offset.y) as i16; self.output_offset = offset; - connection.set_window_dims( - window, - PendingSurfaceState { - x: dims.x as i32, - y: dims.y as i32, - width: self.attrs.dims.width as _, - height: self.attrs.dims.height as _, - }, - ); + if let Some(connection) = connection.as_mut() { + connection.set_window_dims( + window, + PendingSurfaceState { + x: dims.x as i32, + y: dims.y as i32, + width: self.attrs.dims.width as _, + height: self.attrs.dims.height as _, + }, + ); + } debug!("set {:?} offset to {:?}", window, self.output_offset); } @@ -989,7 +991,7 @@ impl ServerState { e, &self.global_output_offset, &self.world, - self.connection.as_mut().unwrap(), + &mut self.connection, ); } self.global_offset_updated = false; diff --git a/src/server/tests.rs b/src/server/tests.rs index 45e7b78..0bdde9b 100644 --- a/src/server/tests.rs +++ b/src/server/tests.rs @@ -321,8 +321,50 @@ impl PopupBuilder { } } +trait PreConnectFn: Sized { + fn call(self, _: &mut testwl::Server) {} +} +impl PreConnectFn for F { + fn call(self, server: &mut testwl::Server) { + self(server); + } +} +impl PreConnectFn for () {} + +struct SetupOptions { + pre_connect: Option, + connect_x: bool, +} + +impl SetupOptions<()> { + fn dont_connect_x() -> Self { + Self { + pre_connect: None, + connect_x: false, + } + } +} + +impl SetupOptions { + fn pre_connect(pre_connect: F) -> Self { + Self { + pre_connect: Some(pre_connect), + connect_x: true, + } + } +} + +impl Default for SetupOptions<()> { + fn default() -> Self { + Self { + pre_connect: None, + connect_x: true, + } + } +} + impl TestFixture { - fn new_pre_connect(pre_connect: impl FnOnce(&mut testwl::Server)) -> Self { + fn new_with_options(options: SetupOptions) -> Self { INIT.call_once(|| { env_logger::builder() .is_test(true) @@ -332,7 +374,9 @@ impl TestFixture { let (client_s, server_s) = UnixStream::pair().unwrap(); let mut testwl = testwl::Server::new(true); - pre_connect(&mut testwl); + if let Some(pre_connect) = options.pre_connect { + pre_connect.call(&mut testwl); + } let display = Display::::new().unwrap(); testwl.connect(server_s); // Handle initial globals roundtrip setup requirement @@ -350,7 +394,9 @@ impl TestFixture { let (fake_client, xwls_server) = UnixStream::pair().unwrap(); satellite.connect(xwls_server); - satellite.set_x_connection(FakeXConnection::default()); + if options.connect_x { + satellite.set_x_connection(FakeXConnection::default()); + } let xwls_connection = Connection::from_socket(fake_client).unwrap(); let registry = TestObject::::from_request( @@ -371,7 +417,11 @@ impl TestFixture { } fn new() -> Self { - Self::new_pre_connect(|_| {}) + Self::new_with_options(SetupOptions::default()) + } + + fn new_pre_connect(pre_connect: impl FnOnce(&mut testwl::Server)) -> Self { + Self::new_with_options(SetupOptions::pre_connect(pre_connect)) } fn new_with_compositor() -> (Self, Compositor) { @@ -514,6 +564,7 @@ impl TestFixture { }, ); self.run(); + self.run(); (output, self.testwl.last_created_output()) } @@ -2359,6 +2410,23 @@ fn tablet_tool_fractional_scale() { assert_eq!(y, 40.0 * 1.5); } +#[test] +fn output_updated_before_x_connection() { + let mut f = TestFixture::new_with_options(SetupOptions::dont_connect_x()); + let comp = f.compositor(); + let (_, output) = f.new_output(-20, -20); + + f.satellite.set_x_connection(FakeXConnection::default()); + + let window = unsafe { Window::new(1) }; + let (_, surface_id) = f.create_toplevel(&comp, window); + f.testwl.move_surface_to_output(surface_id, &output); + f.run(); + f.run(); + let data = &f.connection().windows[&window]; + assert_eq!(data.dims.x, 0); + assert_eq!(data.dims.y, 0); +} /// See Pointer::handle_event for an explanation. #[test] fn popup_pointer_motion_workaround() {}