diff --git a/src/lib.rs b/src/lib.rs index 69568d1..8f679f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ use xcb::x; pub trait XConnection: Sized + 'static { type X11Selection: X11Selection; - fn set_window_dims(&mut self, window: x::Window, dims: PendingSurfaceState); + fn set_window_dims(&mut self, window: x::Window, dims: PendingSurfaceState) -> bool; fn set_fullscreen(&mut self, window: x::Window, fullscreen: bool); fn focus_window(&mut self, window: x::Window, output_name: Option); fn close_window(&mut self, window: x::Window); @@ -134,8 +134,7 @@ pub fn main(mut data: impl RunData) -> Option<()> { } }; - let mut server_state = EarlyServerState::new(dh, data.server()); - server_state.connect(connection); + let mut server_state = EarlyServerState::new(dh, data.server(), connection); server_state.run(); // Remove the lifetimes on our fds to avoid borrowing issues, since we know they will exist for @@ -177,8 +176,7 @@ pub fn main(mut data: impl RunData) -> Option<()> { display.flush_clients().unwrap(); } - let mut xstate: Option = None; - let xstate = xstate.insert(XState::new(xsock_wl.as_fd())); + let mut xstate = XState::new(xsock_wl.as_fd()); let mut reader = BufReader::new(&ready_rx); { let mut display = String::new(); diff --git a/src/server/event.rs b/src/server/event.rs index 7f21309..946ca9e 100644 --- a/src/server/event.rs +++ b/src/server/event.rs @@ -157,9 +157,8 @@ impl SurfaceEvents { ); if state.last_focused_toplevel == Some(*window) { let output = get_output_name(Some(&on_output), &state.world); - let conn = connection.as_mut().unwrap(); debug!("focused window changed outputs - resetting primary output"); - conn.focus_window(*window, output); + connection.focus_window(*window, output); } if state.fractional_scale.is_none() { @@ -205,7 +204,7 @@ impl SurfaceEvents { target: Entity, state: &mut ServerState, ) { - let connection = state.connection.as_mut().unwrap(); + let connection = &mut state.connection; let state = &mut state.inner; let xdg_surface::Event::Configure { serial } = event else { unreachable!(); @@ -308,7 +307,7 @@ impl SurfaceEvents { toplevel.fullscreen = states.contains(&(u32::from(xdg_toplevel::State::Fullscreen) as u8)); if toplevel.fullscreen != prev_fs { - state.connection.as_mut().unwrap().set_fullscreen( + state.connection.set_fullscreen( *data.get::<&x::Window>().unwrap(), toplevel.fullscreen, ); @@ -364,8 +363,6 @@ impl SurfaceEvents { xdg_popup::Event::PopupDone => { state .connection - .as_mut() - .unwrap() .unmap_window(*data.get::<&x::Window>().unwrap()); } other => todo!("{other:?}"), @@ -482,7 +479,7 @@ impl Event for client::wl_pointer::Event { let mut do_enter = || { debug!("pointer entering {} ({serial} {})", surface.id(), scale.0); server.enter(serial, surface, surface_x * scale.0, surface_y * scale.0); - state.connection.as_mut().unwrap().raise_to_top(*window); + state.connection.raise_to_top(*window); if !surface_is_popup { state.inner.last_hovered = Some(*window); } @@ -916,7 +913,7 @@ fn update_window_output_offsets( output: Entity, global_output_offset: &GlobalOutputOffset, world: &World, - connection: &mut Option, + connection: &mut impl XConnection, ) { let dimensions = world.get::<&OutputDimensions>(output).unwrap(); let mut query = world.query::<(&x::Window, &mut WindowData, &OnOutput)>(); @@ -940,7 +937,7 @@ pub(super) fn update_global_output_offset( output: Entity, global_output_offset: &GlobalOutputOffset, world: &World, - connection: &mut Option, + connection: &mut impl XConnection, ) { let entity = world.entity(output).unwrap(); let mut query = entity.query::<(&OutputDimensions, &WlOutput)>(); @@ -1459,8 +1456,6 @@ where let entity = state.world.reserve_entity(); let server = state .client - .as_ref() - .unwrap() .create_resource::<_, _, InnerServerState>(&state.dh, 1, entity) .unwrap(); let obj_key: &LateInitObjectKey = client.data().unwrap(); diff --git a/src/server/mod.rs b/src/server/mod.rs index 542368e..18613a9 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 Option, + connection: &mut C, ) { log::trace!("offset: {offset:?}"); if offset == self.output_offset { @@ -150,19 +150,17 @@ impl WindowData { dims.y += (offset.y - self.output_offset.y) as i16; self.output_offset = offset; - 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 _, - }, - ); + if 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); } - - debug!("set {:?} offset to {:?}", window, self.output_offset); } } @@ -415,14 +413,15 @@ impl XConnection for EarlyConnection { fn set_fullscreen(&mut self, _: x::Window, _: bool) { debug!("could not toggle fullscreen without XWayland initialized"); } - fn set_window_dims(&mut self, _: x::Window, _: crate::server::PendingSurfaceState) { + fn set_window_dims(&mut self, _: x::Window, _: crate::server::PendingSurfaceState) -> bool { debug!("could not set window dimensions without XWayland initialized"); + false } } pub struct ServerState { inner: InnerServerState, - pub connection: Option, + pub connection: C, } pub struct InnerServerState { @@ -433,7 +432,7 @@ pub struct InnerServerState { world: MyWorld, queue: EventQueue, qh: QueueHandle, - client: Option, + client: Client, to_focus: Option, unfocus: bool, last_focused_toplevel: Option, @@ -453,7 +452,11 @@ pub struct InnerServerState { } impl ServerState> { - pub fn new(dh: DisplayHandle, server_connection: Option) -> Self { + pub fn new( + mut dh: DisplayHandle, + server_connection: Option, + client: UnixStream, + ) -> Self { let connection = if let Some(stream) = server_connection { Connection::from_socket(stream).unwrap() } else { @@ -508,10 +511,12 @@ impl ServerState> { .contents() .with_list(|globals| handle_globals::(&dh, globals)); + let client = dh.insert_client(client, std::sync::Arc::new(())).unwrap(); + let inner = InnerServerState { windows: HashMap::new(), pids: HashSet::new(), - client: None, + client, queue, qh, dh, @@ -543,9 +548,9 @@ impl ServerState> { }; Self { inner, - connection: Some(EarlyConnection { + connection: EarlyConnection { _p: std::marker::PhantomData, - }), + }, } } @@ -555,7 +560,7 @@ impl ServerState> { { ServerState { inner: self.inner, - connection: Some(connection), + connection, } } } @@ -569,18 +574,10 @@ impl ServerState { self.inner.clientside_fd() } - pub fn connect(&mut self, connection: UnixStream) { - self.inner.connect(connection) - } - fn handle_new_globals(&mut self) { self.inner.handle_new_globals() } - pub fn set_x_connection(&mut self, connection: C) { - self.connection = Some(connection); - } - pub fn new_window( &mut self, window: x::Window, @@ -761,13 +758,11 @@ impl ServerState { output_name, }) = self.inner.to_focus.take() { - let conn = self.connection.as_mut().unwrap(); debug!("focusing window {window:?}"); - conn.focus_window(window, output_name); + self.connection.focus_window(window, output_name); self.inner.last_focused_toplevel = Some(window); } else if self.inner.unfocus { - let conn = self.connection.as_mut().unwrap(); - conn.focus_window(x::WINDOW_NONE, None); + self.connection.focus_window(x::WINDOW_NONE, None); } self.inner.unfocus = false; } @@ -806,7 +801,7 @@ impl ServerState { fn close_x_window(&mut self, window: x::Window) { debug!("sending close request to {window:?}"); - self.connection.as_mut().unwrap().close_window(window); + self.connection.close_window(window); if self.inner.last_focused_toplevel == Some(window) { self.inner.last_focused_toplevel.take(); } @@ -821,14 +816,6 @@ impl InnerServerState { self.queue.as_fd() } - fn connect(&mut self, connection: UnixStream) { - self.client = Some( - self.dh - .insert_client(connection, std::sync::Arc::new(())) - .unwrap(), - ); - } - fn handle_new_globals(&mut self) { let globals = std::mem::take(&mut self.world.new_globals); handle_globals::(&self.dh, globals.iter()); diff --git a/src/server/tests.rs b/src/server/tests.rs index 212fdd3..c164a92 100644 --- a/src/server/tests.rs +++ b/src/server/tests.rs @@ -209,13 +209,14 @@ impl super::XConnection for FakeXConnection { } #[track_caller] - fn set_window_dims(&mut self, window: Window, state: super::PendingSurfaceState) { + fn set_window_dims(&mut self, window: Window, state: super::PendingSurfaceState) -> bool { self.window_mut(window).dims = WindowDims { x: state.x as _, y: state.y as _, width: state.width as _, height: state.height as _, }; + true } #[track_caller] @@ -367,9 +368,8 @@ impl EarlyTestFixture { }); let (fake_client, xwls_server) = UnixStream::pair().unwrap(); - let mut satellite = EarlyServerState::new(display.handle(), Some(client_s)); + let satellite = EarlyServerState::new(display.handle(), Some(client_s), xwls_server); let testwl = thread.join().unwrap(); - satellite.connect(xwls_server); let xwls_connection = Connection::from_socket(fake_client).unwrap(); let registry = TestObject::::from_request( @@ -549,7 +549,7 @@ impl TestFixture { } fn connection(&self) -> &FakeXConnection { - self.satellite.connection.as_ref().unwrap() + &self.satellite.connection } fn object_data

(&self, obj: &P) -> Arc> @@ -612,12 +612,7 @@ impl TestFixture { } fn register_window(&mut self, window: Window, data: WindowData) { - self.satellite - .connection - .as_mut() - .unwrap() - .windows - .insert(window, data); + self.satellite.connection.windows.insert(window, data); } fn new_window(&mut self, window: Window, override_redirect: bool, data: WindowData) { @@ -940,7 +935,7 @@ fn toplevel_flow() { f.testwl.close_toplevel(testwl_id); f.run(); - assert!(!f.satellite.connection.as_ref().unwrap().windows[&window].mapped); + assert!(!f.satellite.connection.windows[&window].mapped); assert!( f.testwl.get_surface_data(testwl_id).is_some(), diff --git a/src/xstate/mod.rs b/src/xstate/mod.rs index 41c4f94..c795005 100644 --- a/src/xstate/mod.rs +++ b/src/xstate/mod.rs @@ -44,19 +44,24 @@ impl From for MaybeBadWindow { type XResult = Result; macro_rules! unwrap_or_skip_bad_window { - ($err:expr) => { + ($err:expr, $skip:expr) => { match $err { Ok(v) => v, Err(e) => { let err = MaybeBadWindow::from(e); match err { - MaybeBadWindow::BadWindow => return, + MaybeBadWindow::BadWindow => $skip, MaybeBadWindow::Other(other) => panic!("X11 protocol error: {other:?}"), } } } }; } +macro_rules! unwrap_or_skip_bad_window_ret { + ($err:expr) => { + unwrap_or_skip_bad_window!($err, return) + }; +} /// Essentially a trait alias. trait PropertyResolver { @@ -310,16 +315,7 @@ impl XState { pub fn handle_events(&mut self, server_state: &mut super::RealServerState) { macro_rules! unwrap_or_skip_bad_window_cont { ($err:expr) => { - match $err { - Ok(v) => v, - Err(e) => { - let err = MaybeBadWindow::from(e); - match err { - MaybeBadWindow::BadWindow => continue, - MaybeBadWindow::Other(other) => panic!("X11 protocol error: {other:?}"), - } - } - } + unwrap_or_skip_bad_window!($err, continue) }; } @@ -412,8 +408,6 @@ impl XState { // The connection on the server state stores state. server_state .connection - .as_mut() - .unwrap() .focus_window(x::Window::none(), None); } @@ -506,11 +500,7 @@ impl XState { xcb::Event::RandR(xcb::randr::Event::Notify(e)) if matches!(e.u(), xcb::randr::NotifyData::Rc(_)) => { - server_state - .connection - .as_mut() - .unwrap() - .update_outputs(self.root); + server_state.connection.update_outputs(self.root); } other => { warn!("unhandled event: {other:?}"); @@ -850,31 +840,34 @@ impl XState { match event.atom() { x if x == x::ATOM_WM_HINTS => { let hints = - unwrap_or_skip_bad_window!(self.get_wm_hints(window).resolve()).unwrap(); + unwrap_or_skip_bad_window_ret!(self.get_wm_hints(window).resolve()).unwrap(); server_state.set_win_hints(window, hints); } x if x == x::ATOM_WM_NORMAL_HINTS => { let hints = - unwrap_or_skip_bad_window!(self.get_wm_size_hints(window).resolve()).unwrap(); + unwrap_or_skip_bad_window_ret!(self.get_wm_size_hints(window).resolve()) + .unwrap(); server_state.set_size_hints(window, hints); } x if x == x::ATOM_WM_NAME => { - let name = unwrap_or_skip_bad_window!(self.get_wm_name(window).resolve()).unwrap(); + let name = + unwrap_or_skip_bad_window_ret!(self.get_wm_name(window).resolve()).unwrap(); server_state.set_win_title(window, name); } x if x == self.atoms.net_wm_name => { let name = - unwrap_or_skip_bad_window!(self.get_net_wm_name(window).resolve()).unwrap(); + unwrap_or_skip_bad_window_ret!(self.get_net_wm_name(window).resolve()).unwrap(); server_state.set_win_title(window, name); } x if x == x::ATOM_WM_CLASS => { let class = - unwrap_or_skip_bad_window!(self.get_wm_class(window).resolve()).unwrap(); + unwrap_or_skip_bad_window_ret!(self.get_wm_class(window).resolve()).unwrap(); server_state.set_win_class(window, class); } x if x == self.atoms.motif_wm_hints => { let motif_hints = - unwrap_or_skip_bad_window!(self.get_motif_wm_hints(window).resolve()).unwrap(); + unwrap_or_skip_bad_window_ret!(self.get_motif_wm_hints(window).resolve()) + .unwrap(); if let Some(decorations) = motif_hints.decorations { server_state.set_win_decorations(window, decorations); } @@ -1197,17 +1190,25 @@ impl RealConnection { impl XConnection for RealConnection { type X11Selection = Selection; - fn set_window_dims(&mut self, window: x::Window, dims: crate::server::PendingSurfaceState) { + fn set_window_dims( + &mut self, + window: x::Window, + dims: crate::server::PendingSurfaceState, + ) -> bool { trace!("set window dimensions {window:?} {dims:?}"); - unwrap_or_skip_bad_window!(self.connection.send_and_check_request(&x::ConfigureWindow { - window, - value_list: &[ - x::ConfigWindow::X(dims.x), - x::ConfigWindow::Y(dims.y), - x::ConfigWindow::Width(dims.width as _), - x::ConfigWindow::Height(dims.height as _), - ] - })); + unwrap_or_skip_bad_window!( + self.connection.send_and_check_request(&x::ConfigureWindow { + window, + value_list: &[ + x::ConfigWindow::X(dims.x), + x::ConfigWindow::Y(dims.y), + x::ConfigWindow::Width(dims.width as _), + x::ConfigWindow::Height(dims.height as _), + ] + }), + return false + ); + true } fn set_fullscreen(&mut self, window: x::Window, fullscreen: bool) { @@ -1299,7 +1300,7 @@ impl XConnection for RealConnection { long_offset: 0, long_length: 10, }); - let reply = unwrap_or_skip_bad_window!(self.connection.wait_for_reply(cookie)); + let reply = unwrap_or_skip_bad_window_ret!(self.connection.wait_for_reply(cookie)); if reply .value::() @@ -1312,30 +1313,32 @@ impl XConnection for RealConnection { x::ClientMessageData::Data32(data), ); - unwrap_or_skip_bad_window!(self.connection.send_and_check_request(&x::SendEvent { + unwrap_or_skip_bad_window_ret!(self.connection.send_and_check_request(&x::SendEvent { destination: x::SendEventDest::Window(window), propagate: false, event_mask: x::EventMask::empty(), event, })); } else { - unwrap_or_skip_bad_window!(self.connection.send_and_check_request(&x::KillClient { + unwrap_or_skip_bad_window_ret!(self.connection.send_and_check_request(&x::KillClient { resource: window.resource_id() })) } } fn unmap_window(&mut self, window: x::Window) { - unwrap_or_skip_bad_window!(self + unwrap_or_skip_bad_window_ret!(self .connection .send_and_check_request(&x::UnmapWindow { window })); } fn raise_to_top(&mut self, window: x::Window) { - unwrap_or_skip_bad_window!(self.connection.send_and_check_request(&x::ConfigureWindow { - window, - value_list: &[x::ConfigWindow::StackMode(x::StackMode::Above)], - })); + unwrap_or_skip_bad_window_ret!(self.connection.send_and_check_request( + &x::ConfigureWindow { + window, + value_list: &[x::ConfigWindow::StackMode(x::StackMode::Above)], + } + )); } }