From 56d5cce2d026c27ecffa9ef4e890835617c0a27a Mon Sep 17 00:00:00 2001 From: En-En <39373446+En-En-Code@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:56:42 +0000 Subject: [PATCH] server: split XConnection from rest of State refactor --- src/lib.rs | 4 +- src/server/dispatch.rs | 100 ++++----- src/server/event.rs | 108 +++++++--- src/server/mod.rs | 458 ++++++++++++++++++++++++++--------------- src/server/tests.rs | 17 +- 5 files changed, 432 insertions(+), 255 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab38c3a..92f6235 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ pub fn main(mut data: impl RunData) -> Option<()> { info!("Starting xwayland-satellite version {version}"); let socket = ListeningSocket::bind_auto("xwls", 1..=128).unwrap(); - let mut display = Display::::new().unwrap(); + let mut display = Display::new().unwrap(); let dh = display.handle(); data.created_server(); @@ -203,7 +203,7 @@ pub fn main(mut data: impl RunData) -> Option<()> { xstate.handle_events(&mut server_state); } - display.dispatch_clients(&mut server_state).unwrap(); + display.dispatch_clients(server_state.inner_mut()).unwrap(); server_state.run(); display.flush_clients().unwrap(); diff --git a/src/server/dispatch.rs b/src/server/dispatch.rs index 4eacc87..31d66a8 100644 --- a/src/server/dispatch.rs +++ b/src/server/dispatch.rs @@ -65,7 +65,7 @@ use wayland_server::{ }; // noop -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( _: &mut Self, _: &wayland_server::Client, @@ -79,7 +79,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -182,7 +182,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( _: &mut Self, _: &wayland_server::Client, @@ -202,9 +202,9 @@ impl Dispatch for ServerS } } -impl +impl Dispatch> - for ServerState + for InnerServerState { fn request( state: &mut Self, @@ -251,7 +251,7 @@ impl } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -272,7 +272,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -316,8 +316,8 @@ impl Dispatch for Ser } } -impl Dispatch> - for ServerState +impl Dispatch> + for InnerServerState { fn request( state: &mut Self, @@ -340,7 +340,7 @@ impl Dispatch> } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -383,7 +383,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -407,7 +407,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -431,7 +431,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -484,7 +484,7 @@ impl Dispatch for ServerState { macro_rules! only_destroy_request_impl { ($server:ty, $client:ty) => { - impl Dispatch<$server, Entity> for ServerState { + impl Dispatch<$server, Entity> for InnerServerState { fn request( state: &mut Self, _: &Client, @@ -512,9 +512,9 @@ macro_rules! only_destroy_request_impl { only_destroy_request_impl!(RelativePointerServer, RelativePointerClient); -impl +impl Dispatch> - for ServerState + for InnerServerState { fn request( state: &mut Self, @@ -545,7 +545,7 @@ impl } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -569,9 +569,9 @@ impl Dispatch for ServerState { } } -impl +impl Dispatch - for ServerState + for InnerServerState { fn request( state: &mut Self, @@ -599,11 +599,11 @@ impl } } -impl +impl Dispatch< s_dmabuf::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, c_dmabuf::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, - > for ServerState + > for InnerServerState { fn request( state: &mut Self, @@ -662,11 +662,11 @@ impl } } -impl +impl Dispatch< s_dmabuf::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, ClientGlobalWrapper, - > for ServerState + > for InnerServerState { fn request( state: &mut Self, @@ -711,7 +711,7 @@ impl } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -827,7 +827,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -849,8 +849,8 @@ impl Dispatch for ServerState { } } -impl Dispatch> - for ServerState +impl Dispatch> + for InnerServerState { fn request( state: &mut Self, @@ -880,7 +880,7 @@ impl Dispatch Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -902,7 +902,7 @@ impl Dispatch for ServerState } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, @@ -941,9 +941,9 @@ impl Dispatch for ServerState { } } -impl +impl Dispatch> - for ServerState + for InnerServerState { fn request( state: &mut Self, @@ -1039,11 +1039,11 @@ impl } } -impl +impl Dispatch< s_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2, ClientGlobalWrapper, - > for ServerState + > for InnerServerState { fn request( state: &mut Self, @@ -1091,8 +1091,8 @@ only_destroy_request_impl!( c_tablet::zwp_tablet_pad_group_v2::ZwpTabletPadGroupV2 ); -impl Dispatch - for ServerState +impl Dispatch + for InnerServerState { fn request( state: &mut Self, @@ -1125,8 +1125,8 @@ impl Dispatch Dispatch - for ServerState +impl Dispatch + for InnerServerState { fn request( state: &mut Self, @@ -1167,8 +1167,8 @@ impl Dispatch Dispatch - for ServerState +impl Dispatch + for InnerServerState { fn request( state: &mut Self, @@ -1200,8 +1200,8 @@ impl Dispatch Dispatch - for ServerState +impl Dispatch + for InnerServerState { fn request( state: &mut Self, @@ -1251,9 +1251,9 @@ impl Default for ClientGlobalWrapper { macro_rules! global_dispatch_no_events { ($server:ty, $client:ty) => { - impl GlobalDispatch<$server, Global> for ServerState + impl GlobalDispatch<$server, Global> for InnerServerState where - ServerState: Dispatch<$server, ClientGlobalWrapper<$client>>, + InnerServerState: Dispatch<$server, ClientGlobalWrapper<$client>>, MyWorld: wayland_client::Dispatch<$client, ()>, { fn bind( @@ -1282,11 +1282,11 @@ macro_rules! global_dispatch_no_events { macro_rules! global_dispatch_with_events { ($server:ty, $client:ty) => { - impl GlobalDispatch<$server, Global> for ServerState + impl GlobalDispatch<$server, Global> for InnerServerState where $server: Resource, $client: Proxy, - ServerState: Dispatch<$server, Entity>, + InnerServerState: Dispatch<$server, Entity>, MyWorld: wayland_client::Dispatch<$client, Entity>, { fn bind( @@ -1325,7 +1325,7 @@ global_dispatch_no_events!( c_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2 ); -impl GlobalDispatch for ServerState { +impl GlobalDispatch for InnerServerState { fn bind( state: &mut Self, _: &DisplayHandle, @@ -1348,7 +1348,7 @@ impl GlobalDispatch for ServerState { } } -impl GlobalDispatch for ServerState { +impl GlobalDispatch for InnerServerState { fn bind( state: &mut Self, _: &DisplayHandle, @@ -1383,7 +1383,7 @@ impl GlobalDispatch for ServerState { } global_dispatch_with_events!(WlDrmServer, WlDrmClient); -impl GlobalDispatch for ServerState { +impl GlobalDispatch for InnerServerState { fn bind( _: &mut Self, _: &DisplayHandle, @@ -1396,7 +1396,7 @@ impl GlobalDispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, client: &wayland_server::Client, @@ -1432,7 +1432,7 @@ impl Dispatch for ServerState { } } -impl Dispatch for ServerState { +impl Dispatch for InnerServerState { fn request( state: &mut Self, _: &wayland_server::Client, diff --git a/src/server/event.rs b/src/server/event.rs index 537e3e7..7f21309 100644 --- a/src/server/event.rs +++ b/src/server/event.rs @@ -88,7 +88,7 @@ impl Event for SurfaceEvents { SurfaceEvents::Popup(event) => Self::popup_event(event, target, state), SurfaceEvents::FractionalScale(event) => match event { wp_fractional_scale_v1::Event::PreferredScale { scale } => { - let entity = state.world.entity(target).unwrap(); + let entity = state.inner.world.entity(target).unwrap(); let factor = scale as f64 / 120.0; debug!( "{} scale factor: {}", @@ -100,14 +100,14 @@ impl Event for SurfaceEvents { if let Some(OnOutput(output)) = entity.get::<&OnOutput>().as_deref().copied() { if update_output_scale( - state.world.query_one(output).unwrap(), + state.inner.world.query_one(output).unwrap(), OutputScaleFactor::Fractional(factor), ) { - state.updated_outputs.push(output); + state.inner.updated_outputs.push(output); } } if entity.has::() { - update_surface_viewport(state.world.query_one(target).unwrap()); + update_surface_viewport(state.inner.world.query_one(target).unwrap()); } } _ => unreachable!(), @@ -123,6 +123,8 @@ impl SurfaceEvents { state: &mut ServerState, ) { use client::wl_surface::Event; + let connection = &mut state.connection; + let state = &mut state.inner; let data = state.world.entity(target).unwrap(); let surface = data.get::<&WlSurface>().unwrap(); @@ -151,11 +153,11 @@ impl SurfaceEvents { x: dimensions.x - state.global_output_offset.x.value, y: dimensions.y - state.global_output_offset.y.value, }, - &mut state.connection, + connection, ); if state.last_focused_toplevel == Some(*window) { let output = get_output_name(Some(&on_output), &state.world); - let conn = state.connection.as_mut().unwrap(); + let conn = connection.as_mut().unwrap(); debug!("focused window changed outputs - resetting primary output"); conn.focus_window(*window, output); } @@ -204,6 +206,7 @@ impl SurfaceEvents { state: &mut ServerState, ) { let connection = state.connection.as_mut().unwrap(); + let state = &mut state.inner; let xdg_surface::Event::Configure { serial } = event else { unreachable!(); }; @@ -287,7 +290,7 @@ impl SurfaceEvents { target: Entity, state: &mut ServerState, ) { - let data = state.world.entity(target).unwrap(); + let data = state.inner.world.entity(target).unwrap(); match event { xdg_toplevel::Event::Configure { width, @@ -334,7 +337,7 @@ impl SurfaceEvents { target: Entity, state: &mut ServerState, ) { - let data = state.world.entity(target).unwrap(); + let data = state.inner.world.entity(target).unwrap(); match event { xdg_popup::Event::Configure { x, @@ -416,13 +419,18 @@ pub(super) fn update_surface_viewport( impl Event for client::wl_buffer::Event { fn handle(self, target: Entity, state: &mut ServerState) { // The only event from a buffer would be the release. - state.world.get::<&WlBuffer>(target).unwrap().release(); + state + .inner + .world + .get::<&WlBuffer>(target) + .unwrap() + .release(); } } impl Event for client::wl_seat::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let server = state.world.get::<&WlSeat>(target).unwrap(); + let server = state.inner.world.get::<&WlSeat>(target).unwrap(); simple_event_shunt! { server, self => [ Capabilities { |capabilities| convert_wenum(capabilities) }, @@ -453,10 +461,11 @@ impl Event for client::wl_pointer::Event { surface_y, } => { let mut cmd = CommandBuffer::new(); - let pending_enter = state.world.remove_one::(target).ok(); - let server = state.world.get::<&WlPointer>(target).unwrap(); + let pending_enter = state.inner.world.remove_one::(target).ok(); + let server = state.inner.world.get::<&WlPointer>(target).unwrap(); let mut query = surface.data().copied().and_then(|e| { state + .inner .world .query_one::<(&WlSurface, &SurfaceRole, &SurfaceScaleFactor, &x::Window)>(e) .ok() @@ -475,7 +484,7 @@ impl Event for client::wl_pointer::Event { server.enter(serial, surface, surface_x * scale.0, surface_y * scale.0); state.connection.as_mut().unwrap().raise_to_top(*window); if !surface_is_popup { - state.last_hovered = Some(*window); + state.inner.last_hovered = Some(*window); } }; @@ -504,21 +513,22 @@ impl Event for client::wl_pointer::Event { } drop(query); drop(server); - cmd.run_on(&mut state.world); + cmd.run_on(&mut state.inner.world); } client::wl_pointer::Event::Leave { serial, surface } => { - let _ = state.world.remove_one::(target); + let _ = state.inner.world.remove_one::(target); if !surface.is_alive() { return; } debug!("leaving surface ({serial})"); - let _ = state.world.remove_one::(target); + let _ = state.inner.world.remove_one::(target); if let Some(surface) = surface .data() .copied() - .and_then(|key| state.world.get::<&WlSurface>(key).ok()) + .and_then(|key| state.inner.world.get::<&WlSurface>(key).ok()) { state + .inner .world .get::<&WlPointer>(target) .unwrap() @@ -532,7 +542,7 @@ impl Event for client::wl_pointer::Event { surface_x, surface_y, } => { - let pending_enter = state.world.get::<&PendingEnter>(target).ok(); + let pending_enter = state.inner.world.get::<&PendingEnter>(target).ok(); match pending_enter.as_deref() { Some(p) => { let PendingEnter(client::wl_pointer::Event::Enter { @@ -547,7 +557,7 @@ impl Event for client::wl_pointer::Event { if surface .data() .copied() - .is_some_and(|key| state.world.contains(key)) + .is_some_and(|key| state.inner.world.contains(key)) { trace!("resending enter ({serial}) before motion"); let enter_event = client::wl_pointer::Event::Enter { @@ -567,6 +577,7 @@ impl Event for client::wl_pointer::Event { None => { drop(pending_enter); let (server, scale) = state + .inner .world .query_one_mut::<(&WlPointer, &SurfaceScaleFactor)>(target) .unwrap(); @@ -581,7 +592,7 @@ impl Event for client::wl_pointer::Event { } } _ => { - let server = state.world.get::<&WlPointer>(target).unwrap(); + let server = state.inner.world.get::<&WlPointer>(target).unwrap(); simple_event_shunt! { server, self => [ Frame, @@ -624,6 +635,7 @@ impl Event for client::wl_pointer::Event { impl Event for client::wl_keyboard::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let data = state.world.entity(target).unwrap(); let keyboard = data.get::<&WlKeyboard>().unwrap(); match self { @@ -714,6 +726,7 @@ impl Event for client::wl_keyboard::Event { impl Event for client::wl_touch::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); match self { Self::Down { serial, @@ -855,6 +868,8 @@ fn update_output_offset( y: i32, state: &mut ServerState, ) { + let connection = &mut state.connection; + let state = &mut state.inner; { let mut dimensions = state.world.get::<&mut OutputDimensions>(output).unwrap(); if matches!(source, OutputDimensionsSource::Wl { .. }) @@ -893,7 +908,7 @@ fn update_output_offset( output, &state.global_output_offset, &state.world, - &mut state.connection, + connection, ); } @@ -1027,6 +1042,7 @@ impl OutputEvent { y, state, ); + let state = state.inner_mut(); let (output, dimensions, xdg) = state .world @@ -1068,6 +1084,7 @@ impl OutputEvent { height, refresh, } => { + let state = state.inner_mut(); let (output, dimensions) = state .world .query_one_mut::<(&WlOutput, &mut OutputDimensions)>(target) @@ -1084,6 +1101,7 @@ impl OutputEvent { output.mode(convert_wenum(flags), width, height, refresh); } Event::Scale { factor } => { + let state = state.inner_mut(); debug!( "{} scale: {factor}", state.world.get::<&WlOutput>(target).unwrap().id() @@ -1099,6 +1117,7 @@ impl OutputEvent { } } Event::Name { name } => { + let state = state.inner_mut(); state .world .get::<&WlOutput>(target) @@ -1107,7 +1126,7 @@ impl OutputEvent { state.world.insert(target, (OutputName(name),)).unwrap(); } _ => simple_event_shunt! { - state.world.get::<&WlOutput>(target).unwrap(), + state.inner.world.get::<&WlOutput>(target).unwrap(), event: client::wl_output::Event => [ Description { description }, Done @@ -1126,6 +1145,7 @@ impl OutputEvent { match event { Event::LogicalPosition { x, y } => { update_output_offset(target, OutputDimensionsSource::Xdg, x, y, state); + let state = state.inner_mut(); state .world .get::<&XdgOutputServer>(target) @@ -1136,6 +1156,7 @@ impl OutputEvent { ); } Event::LogicalSize { .. } => { + let state = state.inner_mut(); let (xdg, dimensions) = state .world .query_one_mut::<(&XdgOutputServer, &OutputDimensions)>(target) @@ -1147,7 +1168,7 @@ impl OutputEvent { } } _ => simple_event_shunt! { - state.world.get::<&XdgOutputServer>(target).unwrap(), + state.inner.world.get::<&XdgOutputServer>(target).unwrap(), event: zxdg_output_v1::Event => [ Done, Name { name }, @@ -1160,7 +1181,7 @@ impl OutputEvent { impl Event for wl_drm::client::wl_drm::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let server = state.world.get::<&WlDrmServer>(target).unwrap(); + let server = state.inner.world.get::<&WlDrmServer>(target).unwrap(); simple_event_shunt! { server, self => [ Device { name }, @@ -1175,6 +1196,7 @@ impl Event for wl_drm::client::wl_drm::Event { impl Event for c_dmabuf::zwp_linux_dmabuf_feedback_v1::Event { fn handle(self, target: Entity, state: &mut ServerState) { let server = state + .inner .world .get::<&s_dmabuf::zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1>(target) .unwrap(); @@ -1194,7 +1216,11 @@ impl Event for c_dmabuf::zwp_linux_dmabuf_feedback_v1::Event { impl Event for zwp_relative_pointer_v1::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let server = state.world.get::<&RelativePointerServer>(target).unwrap(); + let server = state + .inner + .world + .get::<&RelativePointerServer>(target) + .unwrap(); simple_event_shunt! { server, self => [ RelativeMotion { @@ -1212,7 +1238,11 @@ impl Event for zwp_relative_pointer_v1::Event { impl Event for zwp_locked_pointer_v1::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let server = state.world.get::<&LockedPointerServer>(target).unwrap(); + let server = state + .inner + .world + .get::<&LockedPointerServer>(target) + .unwrap(); simple_event_shunt! { server, self => [ Locked, @@ -1224,7 +1254,11 @@ impl Event for zwp_locked_pointer_v1::Event { impl Event for zwp_confined_pointer_v1::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let server = state.world.get::<&ConfinedPointerServer>(target).unwrap(); + let server = state + .inner + .world + .get::<&ConfinedPointerServer>(target) + .unwrap(); simple_event_shunt! { server, self => [ Confined, @@ -1236,6 +1270,7 @@ impl Event for zwp_confined_pointer_v1::Event { impl Event for zwp_tablet_seat_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let seat = state.world.get::<&TabletSeatServer>(target).unwrap(); match self { Self::TabletAdded { id } => { @@ -1263,7 +1298,7 @@ impl Event for zwp_tablet_seat_v2::Event { impl Event for zwp_tablet_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let tab = state.world.get::<&TabletServer>(target).unwrap(); + let tab = state.inner.world.get::<&TabletServer>(target).unwrap(); simple_event_shunt! { tab, self => [ Name { name }, @@ -1278,6 +1313,7 @@ impl Event for zwp_tablet_v2::Event { impl Event for zwp_tablet_pad_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let pad = state.world.get::<&TabletPadServer>(target).unwrap(); let s_surf; match self { @@ -1331,6 +1367,7 @@ impl Event for zwp_tablet_pad_v2::Event { impl Event for zwp_tablet_tool_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); match self { Self::ProximityIn { serial, @@ -1407,20 +1444,24 @@ impl Event for zwp_tablet_tool_v2::Event { } #[must_use] -fn from_client( +fn from_client< + Server: Resource + 'static, + Client: Proxy + Send + Sync + 'static, + S: X11Selection + 'static, +>( client: &Client, - state: &ServerState, + state: &InnerServerState, ) -> (Entity, Server) where Client::Event: Send + Into, - ServerState: wayland_server::Dispatch, + InnerServerState: wayland_server::Dispatch, { let entity = state.world.reserve_entity(); let server = state .client .as_ref() .unwrap() - .create_resource::<_, _, ServerState>(&state.dh, 1, entity) + .create_resource::<_, _, InnerServerState>(&state.dh, 1, entity) .unwrap(); let obj_key: &LateInitObjectKey = client.data().unwrap(); obj_key.init(entity); @@ -1429,6 +1470,7 @@ where impl Event for zwp_tablet_pad_group_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let group = state.world.get::<&TabletPadGroupServer>(target).unwrap(); match self { Self::Buttons { buttons } => group.buttons(buttons), @@ -1457,6 +1499,7 @@ impl Event for zwp_tablet_pad_group_v2::Event { impl Event for zwp_tablet_pad_ring_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let ring = state.world.get::<&TabletPadRingServer>(target).unwrap(); simple_event_shunt! { ring, self => [ @@ -1471,6 +1514,7 @@ impl Event for zwp_tablet_pad_ring_v2::Event { impl Event for zwp_tablet_pad_strip_v2::Event { fn handle(self, target: Entity, state: &mut ServerState) { + let state = state.inner_mut(); let strip = state.world.get::<&TabletPadStripServer>(target).unwrap(); simple_event_shunt! { strip, self => [ diff --git a/src/server/mod.rs b/src/server/mod.rs index 47e1146..902fe2b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -342,7 +342,7 @@ enum ObjectEvent { } } -fn handle_globals<'a, C: XConnection>( +fn handle_globals<'a, S: X11Selection + 'static>( dh: &DisplayHandle, globals: impl IntoIterator, ) { @@ -353,7 +353,7 @@ fn handle_globals<'a, C: XConnection>( $( ref x if x == <$global>::interface().name => { let version = u32::min(global.version, <$global>::interface().version); - dh.create_global::, $global, Global>(version, global.clone()); + dh.create_global::, $global, Global>(version, global.clone()); } )+ _ => {} @@ -394,6 +394,11 @@ struct GlobalOutputOffset { } pub struct ServerState { + inner: InnerServerState, + pub connection: Option, +} + +pub struct InnerServerState { dh: DisplayHandle, windows: HashMap, pids: HashSet, @@ -406,13 +411,12 @@ pub struct ServerState { unfocus: bool, last_focused_toplevel: Option, last_hovered: Option, - pub connection: Option, xdg_wm_base: XdgWmBase, viewporter: WpViewporter, fractional_scale: Option, decoration_manager: Option, - clipboard_data: Option>, + clipboard_data: Option>, last_kb_serial: Option<(client::wl_seat::WlSeat, u32)>, activation_state: Option, global_output_offset: GlobalOutputOffset, @@ -472,12 +476,12 @@ impl ServerState { }) .ok(); - dh.create_global::(1, ()); + dh.create_global::, XwaylandShellV1, _>(1, ()); global_list .contents() - .with_list(|globals| handle_globals::(&dh, globals)); + .with_list(|globals| handle_globals::(&dh, globals)); - Self { + let inner = InnerServerState { windows: HashMap::new(), pids: HashSet::new(), client: None, @@ -488,7 +492,6 @@ impl ServerState { unfocus: false, last_focused_toplevel: None, last_hovered: None, - connection: None, xdg_wm_base, viewporter, fractional_scale, @@ -510,14 +513,276 @@ impl ServerState { new_scale: None, decoration_manager, world: MyWorld::new(global_list), + }; + Self { + inner, + connection: None, } } +} + +impl ServerState { + pub fn inner_mut(&mut self) -> &mut InnerServerState { + &mut self.inner + } pub fn clientside_fd(&self) -> BorrowedFd<'_> { - self.queue.as_fd() + 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, + override_redirect: bool, + dims: WindowDims, + pid: Option, + ) { + self.inner.new_window(window, override_redirect, dims, pid) + } + + pub fn set_popup(&mut self, window: x::Window, is_popup: bool) { + self.inner.set_popup(window, is_popup) + } + + pub fn set_win_title(&mut self, window: x::Window, name: WmName) { + self.inner.set_win_title(window, name); + } + + pub fn set_win_class(&mut self, window: x::Window, class: String) { + self.inner.set_win_class(window, class) + } + + pub fn set_win_hints(&mut self, window: x::Window, hints: WmHints) { + self.inner.set_win_hints(window, hints) + } + + pub fn set_size_hints(&mut self, window: x::Window, hints: WmNormalHints) { + self.inner.set_size_hints(window, hints) + } + + pub fn set_win_decorations(&mut self, window: x::Window, decorations: Decorations) { + self.inner.set_win_decorations(window, decorations) + } + + pub fn set_window_serial(&mut self, window: x::Window, serial: [u32; 2]) { + self.inner.set_window_serial(window, serial) + } + + pub fn can_change_position(&self, window: x::Window) -> bool { + self.inner.can_change_position(window) + } + + pub fn reconfigure_window(&mut self, event: x::ConfigureNotifyEvent) { + self.inner.reconfigure_window(event) + } + + pub fn map_window(&mut self, window: x::Window) { + self.inner.map_window(window) + } + + pub fn unmap_window(&mut self, window: x::Window) { + self.inner.unmap_window(window) + } + + pub fn set_fullscreen(&mut self, window: x::Window, state: super::xstate::SetState) { + self.inner.set_fullscreen(window, state) + } + + pub fn set_transient_for(&mut self, window: x::Window, parent: x::Window) { + self.inner.set_transient_for(window, parent) + } + + pub fn activate_window(&mut self, window: x::Window) { + self.inner.activate_window(window) + } + + pub fn destroy_window(&mut self, window: x::Window) { + self.inner.destroy_window(window) + } + + pub(crate) fn set_copy_paste_source(&mut self, selection: &Rc) { + self.inner.set_copy_paste_source(selection) + } + + pub fn run(&mut self) { + if let Some(r) = self.inner.queue.prepare_read() { + let fd = r.connection_fd(); + let pollfd = PollFd::new(&fd, PollFlags::IN); + if poll(&mut [pollfd], 0).unwrap() > 0 { + let _ = r.read(); + } + } + self.inner + .queue + .dispatch_pending(&mut self.inner.world) + .expect("Failed dispatching client side Wayland events"); + self.handle_clientside_events(); + } + + pub fn handle_clientside_events(&mut self) { + self.handle_new_globals(); + + for (target, event) in self.inner.world.read_events() { + if !self.inner.world.contains(target) { + warn!("could not handle clientside event: stale object"); + continue; + } + event.handle(target, self); + } + + if self.inner.global_offset_updated { + if self.inner.global_output_offset.x.owner.is_none() + || self.inner.global_output_offset.y.owner.is_none() + { + self.calc_global_output_offset(); + } + + debug!( + "updated global output offset: {}x{}", + self.inner.global_output_offset.x.value, self.inner.global_output_offset.y.value + ); + for (e, _) in self.inner.world.query::<&WlOutput>().iter() { + event::update_global_output_offset( + e, + &self.inner.global_output_offset, + &self.inner.world, + &mut self.connection, + ); + } + self.inner.global_offset_updated = false; + } + + if !self.inner.updated_outputs.is_empty() { + for output in self.inner.updated_outputs.drain(..) { + let output_scale = self.inner.world.get::<&OutputScaleFactor>(output).unwrap(); + if matches!(*output_scale, OutputScaleFactor::Output(..)) { + let mut surface_query = self + .inner + .world + .query::<(&OnOutput, &mut SurfaceScaleFactor)>() + .with::<(&WindowData, &WlSurface)>(); + + let mut surfaces = vec![]; + for (surface, (OnOutput(s_output), surface_scale)) in surface_query.iter() { + if *s_output == output { + surface_scale.0 = output_scale.get(); + surfaces.push(surface); + } + } + + drop(surface_query); + for surface in surfaces { + update_surface_viewport(self.inner.world.query_one(surface).unwrap()); + } + } + } + + let mut mixed_scale = false; + let mut scale; + + let mut outputs = self + .inner + .world + .query_mut::<&OutputScaleFactor>() + .into_iter(); + let (_, output_scale) = outputs.next().unwrap(); + + scale = output_scale.get(); + + for (_, output_scale) in outputs { + if output_scale.get() != scale { + mixed_scale = true; + scale = scale.min(output_scale.get()); + } + } + + if mixed_scale { + warn!("Mixed output scales detected, choosing to give apps the smallest detected scale ({scale}x)"); + } + + debug!("Using new scale {scale}"); + self.inner.new_scale = Some(scale); + } + + { + if let Some(FocusData { + window, + 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.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.inner.unfocus = false; + } + + self.handle_clipboard_events(); + self.handle_activations(); + self.inner + .queue + .flush() + .expect("Failed flushing clientside events"); + } + + pub fn new_global_scale(&mut self) -> Option { + self.inner.new_global_scale() + } + + pub fn new_selection(&mut self) -> Option { + self.inner.new_selection() + } + + fn handle_clipboard_events(&mut self) { + self.inner.handle_clipboard_events() + } + + fn handle_activations(&mut self) { + self.inner.handle_activations() + } + + fn calc_global_output_offset(&mut self) { + self.inner.calc_global_output_offset() + } + + // create_role_window is only called in a Dispatch impl, a trait impl necessarily moved to be + // on the ineer value. create_toplevel and create_popup are only called by that create_role_window + // call, so none of them need wrapper functions. + + fn close_x_window(&mut self, window: x::Window) { + debug!("sending close request to {window:?}"); + self.connection.as_mut().unwrap().close_window(window); + if self.inner.last_focused_toplevel == Some(window) { + self.inner.last_focused_toplevel.take(); + } + if self.inner.last_hovered == Some(window) { + self.inner.last_hovered.take(); + } + } +} + +impl InnerServerState { + fn clientside_fd(&self) -> BorrowedFd<'_> { + self.queue.as_fd() + } + + fn connect(&mut self, connection: UnixStream) { self.client = Some( self.dh .insert_client(connection, std::sync::Arc::new(())) @@ -525,16 +790,12 @@ impl ServerState { ); } - pub fn set_x_connection(&mut self, connection: C) { - self.connection = Some(connection); - } - fn handle_new_globals(&mut self) { let globals = std::mem::take(&mut self.world.new_globals); - handle_globals::(&self.dh, globals.iter()); + handle_globals::(&self.dh, globals.iter()); } - pub fn new_window( + fn new_window( &mut self, window: x::Window, override_redirect: bool, @@ -559,7 +820,7 @@ impl ServerState { self.windows.insert(window, id); } - pub fn set_popup(&mut self, window: x::Window, is_popup: bool) { + fn set_popup(&mut self, window: x::Window, is_popup: bool) { let Some(id) = self.windows.get(&window).copied() else { debug!("not setting popup for unknown window {window:?}"); return; @@ -572,7 +833,7 @@ impl ServerState { .is_popup = is_popup; } - pub fn set_win_title(&mut self, window: x::Window, name: WmName) { + fn set_win_title(&mut self, window: x::Window, name: WmName) { let Some(data) = self .windows .get(&window) @@ -610,7 +871,7 @@ impl ServerState { } } - pub fn set_win_class(&mut self, window: x::Window, class: String) { + fn set_win_class(&mut self, window: x::Window, class: String) { let Some(data) = self .windows .get(&window) @@ -631,7 +892,7 @@ impl ServerState { } } - pub fn set_win_hints(&mut self, window: x::Window, hints: WmHints) { + fn set_win_hints(&mut self, window: x::Window, hints: WmHints) { let Some(id) = self.windows.get(&window).copied() else { debug!("not setting hints for unknown window {window:?}"); return; @@ -640,7 +901,7 @@ impl ServerState { self.world.get::<&mut WindowData>(id).unwrap().attrs.group = hints.window_group; } - pub fn set_size_hints(&mut self, window: x::Window, hints: WmNormalHints) { + fn set_size_hints(&mut self, window: x::Window, hints: WmNormalHints) { let Some(data) = self .windows .get(&window) @@ -674,7 +935,7 @@ impl ServerState { } } - pub fn set_win_decorations(&mut self, window: x::Window, decorations: Decorations) { + fn set_win_decorations(&mut self, window: x::Window, decorations: Decorations) { if self.decoration_manager.is_none() { return; }; @@ -705,7 +966,7 @@ impl ServerState { } } - pub fn set_window_serial(&mut self, window: x::Window, serial: [u32; 2]) { + fn set_window_serial(&mut self, window: x::Window, serial: [u32; 2]) { let Some(id) = self.windows.get(&window).copied() else { warn!("Tried to set serial for unknown window {window:?}"); return; @@ -714,7 +975,7 @@ impl ServerState { self.world.insert(id, (SurfaceSerial(serial),)).unwrap(); } - pub fn can_change_position(&self, window: x::Window) -> bool { + fn can_change_position(&self, window: x::Window) -> bool { let Some(win) = self .windows .get(&window) @@ -728,7 +989,7 @@ impl ServerState { !win.mapped || win.attrs.is_popup } - pub fn reconfigure_window(&mut self, event: x::ConfigureNotifyEvent) { + fn reconfigure_window(&mut self, event: x::ConfigureNotifyEvent) { let Some((mut win, data)) = self .windows .get(&event.window()) @@ -787,7 +1048,7 @@ impl ServerState { } } - pub fn map_window(&mut self, window: x::Window) { + fn map_window(&mut self, window: x::Window) { debug!("mapping {window:?}"); let Some(mut win) = self @@ -804,7 +1065,7 @@ impl ServerState { win.mapped = true; } - pub fn unmap_window(&mut self, window: x::Window) { + fn unmap_window(&mut self, window: x::Window) { let entity = self.windows.get(&window).copied(); { @@ -832,7 +1093,7 @@ impl ServerState { } } - pub fn set_fullscreen(&mut self, window: x::Window, state: super::xstate::SetState) { + fn set_fullscreen(&mut self, window: x::Window, state: super::xstate::SetState) { let Some(data) = self .windows .get(&window) @@ -867,7 +1128,7 @@ impl ServerState { } } - pub fn set_transient_for(&mut self, window: x::Window, parent: x::Window) { + fn set_transient_for(&mut self, window: x::Window, parent: x::Window) { let Some(mut win) = self .windows .get(&window) @@ -881,7 +1142,7 @@ impl ServerState { win.attrs.transient_for = Some(parent); } - pub fn activate_window(&mut self, window: x::Window) { + fn activate_window(&mut self, window: x::Window) { let Some(activation_state) = self.activation_state.as_ref() else { return; }; @@ -918,7 +1179,7 @@ impl ServerState { ); } - pub fn destroy_window(&mut self, window: x::Window) { + fn destroy_window(&mut self, window: x::Window) { if let Some(id) = self.windows.remove(&window) { self.world.remove::<(x::Window, WindowData)>(id).unwrap(); if self.world.entity(id).unwrap().is_empty() { @@ -927,7 +1188,7 @@ impl ServerState { } } - pub(crate) fn set_copy_paste_source(&mut self, selection: &Rc) { + fn set_copy_paste_source(&mut self, selection: &Rc) { if let Some(d) = &mut self.clipboard_data { let src = d .manager @@ -950,129 +1211,11 @@ impl ServerState { } } - pub fn run(&mut self) { - if let Some(r) = self.queue.prepare_read() { - let fd = r.connection_fd(); - let pollfd = PollFd::new(&fd, PollFlags::IN); - if poll(&mut [pollfd], 0).unwrap() > 0 { - let _ = r.read(); - } - } - self.queue - .dispatch_pending(&mut self.world) - .expect("Failed dispatching client side Wayland events"); - self.handle_clientside_events(); - } - - pub fn handle_clientside_events(&mut self) { - self.handle_new_globals(); - - for (target, event) in self.world.read_events() { - if !self.world.contains(target) { - warn!("could not handle clientside event: stale object"); - continue; - } - event.handle(target, self); - } - - if self.global_offset_updated { - if self.global_output_offset.x.owner.is_none() - || self.global_output_offset.y.owner.is_none() - { - self.calc_global_output_offset(); - } - - debug!( - "updated global output offset: {}x{}", - self.global_output_offset.x.value, self.global_output_offset.y.value - ); - for (e, _) in self.world.query::<&WlOutput>().iter() { - event::update_global_output_offset( - e, - &self.global_output_offset, - &self.world, - &mut self.connection, - ); - } - self.global_offset_updated = false; - } - - if !self.updated_outputs.is_empty() { - for output in self.updated_outputs.drain(..) { - let output_scale = self.world.get::<&OutputScaleFactor>(output).unwrap(); - if matches!(*output_scale, OutputScaleFactor::Output(..)) { - let mut surface_query = self - .world - .query::<(&OnOutput, &mut SurfaceScaleFactor)>() - .with::<(&WindowData, &WlSurface)>(); - - let mut surfaces = vec![]; - for (surface, (OnOutput(s_output), surface_scale)) in surface_query.iter() { - if *s_output == output { - surface_scale.0 = output_scale.get(); - surfaces.push(surface); - } - } - - drop(surface_query); - for surface in surfaces { - update_surface_viewport(self.world.query_one(surface).unwrap()); - } - } - } - - let mut mixed_scale = false; - let mut scale; - - let mut outputs = self.world.query_mut::<&OutputScaleFactor>().into_iter(); - let (_, output_scale) = outputs.next().unwrap(); - - scale = output_scale.get(); - - for (_, output_scale) in outputs { - if output_scale.get() != scale { - mixed_scale = true; - scale = scale.min(output_scale.get()); - } - } - - if mixed_scale { - warn!("Mixed output scales detected, choosing to give apps the smallest detected scale ({scale}x)"); - } - - debug!("Using new scale {scale}"); - self.new_scale = Some(scale); - } - - { - if let Some(FocusData { - window, - output_name, - }) = self.to_focus.take() - { - let conn = self.connection.as_mut().unwrap(); - debug!("focusing window {window:?}"); - conn.focus_window(window, output_name); - self.last_focused_toplevel = Some(window); - } else if self.unfocus { - let conn = self.connection.as_mut().unwrap(); - conn.focus_window(x::WINDOW_NONE, None); - } - self.unfocus = false; - } - - self.handle_clipboard_events(); - self.handle_activations(); - self.queue - .flush() - .expect("Failed flushing clientside events"); - } - - pub fn new_global_scale(&mut self) -> Option { + fn new_global_scale(&mut self) -> Option { self.new_scale.take() } - pub fn new_selection(&mut self) -> Option { + fn new_selection(&mut self) -> Option { self.clipboard_data.as_mut().and_then(|c| { c.source.take().and_then(|s| match s { CopyPasteData::Foreign(f) => Some(f), @@ -1367,17 +1510,6 @@ 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); - if self.last_focused_toplevel == Some(window) { - self.last_focused_toplevel.take(); - } - if self.last_hovered == Some(window) { - self.last_hovered.take(); - } - } } #[derive(Default, Debug)] @@ -1406,7 +1538,7 @@ impl ForeignSelection { state: &ServerState, ) -> Vec { let mut pipe = self.inner.receive(mime_type).unwrap(); - state.queue.flush().unwrap(); + state.inner.queue.flush().unwrap(); let mut data = Vec::new(); pipe.read_to_end(&mut data).unwrap(); data diff --git a/src/server/tests.rs b/src/server/tests.rs index 2908c9b..6ee35d6 100644 --- a/src/server/tests.rs +++ b/src/server/tests.rs @@ -1,4 +1,4 @@ -use super::{ServerState, WindowDims}; +use super::{InnerServerState, ServerState, WindowDims}; use crate::xstate::{SetState, WinSize, WmName}; use rustix::event::{poll, PollFd, PollFlags}; use std::collections::HashMap; @@ -184,6 +184,7 @@ impl Default for FakeXConnection { } } +type FakeX11Selection = Vec; impl crate::X11Selection for Vec { fn mime_types(&self) -> Vec<&str> { self.iter().map(|data| data.mime_type.as_str()).collect() @@ -204,7 +205,7 @@ impl crate::X11Selection for Vec { } impl super::XConnection for FakeXConnection { - type X11Selection = Vec; + type X11Selection = FakeX11Selection; fn root_window(&self) -> Window { self.root } @@ -259,7 +260,7 @@ struct TestFixture { /// Our connection to satellite - i.e., where Xwayland sends requests to xwls_connection: Arc, /// Satellite's display - must dispatch this for our server state to advance - xwls_display: Display, + xwls_display: Display>, surface_serial: u64, registry: TestObject, } @@ -379,7 +380,7 @@ impl TestFixture { if let Some(pre_connect) = options.pre_connect { pre_connect.call(&mut testwl); } - let display = Display::::new().unwrap(); + let display = Display::new().unwrap(); testwl.connect(server_s); // Handle initial globals roundtrip setup requirement let thread = std::thread::spawn(move || { @@ -513,7 +514,7 @@ impl TestFixture { // Have satellite dispatch our requests self.xwls_display - .dispatch_clients(&mut self.satellite) + .dispatch_clients(self.satellite.inner_mut()) .unwrap(); self.xwls_display.flush_clients().unwrap(); @@ -1428,12 +1429,12 @@ fn raise_window_on_pointer_event() { f.testwl.move_pointer_to(id2, 0.0, 0.0); f.run(); assert_eq!(f.connection().focused_window, Some(win2)); - assert_eq!(f.satellite.last_hovered, Some(win2)); + assert_eq!(f.satellite.inner.last_hovered, Some(win2)); f.testwl.move_pointer_to(id1, 0.0, 0.0); f.run(); assert_eq!(f.connection().focused_window, Some(win2)); - assert_eq!(f.satellite.last_hovered, Some(win1)); + assert_eq!(f.satellite.inner.last_hovered, Some(win1)); } #[test] @@ -1450,7 +1451,7 @@ fn override_redirect_choose_hover_window() { f.testwl.move_pointer_to(id1, 0.0, 0.0); f.run(); - assert_eq!(f.satellite.last_hovered, Some(win1)); + assert_eq!(f.satellite.inner.last_hovered, Some(win1)); let win3 = unsafe { Window::new(3) }; let (buffer, surface) = comp.create_surface();