atagen

monolith

public
Star0
Watch0

Commit c7e08bac3e01

tarball

atagen <boss@atagen.co>2026-10-17 02:46 UTC

14 files changed+134-94
monolith: gather subsystems into Services and idle state into Idle

Lock, capture, imports, Xwayland, launch tracking and the IPC server already had types of their own but sat as loose State fields. The idle notifier moves out of the protocol globals, since it is live state next to the inhibitor set it serves.
Modified file: crates/monolith/src/capture.rs+15 additions−9 deletions
@@ -104,12 +104,15 @@ impl ImageCopyCaptureHandler for State {
104104 }
105105
106106 fn new_session(&mut self, session: Session) {
107- self.captures.sessions.push(session);
107+ self.services.captures.sessions.push(session);
108108 }
109109
110110 fn frame(&mut self, session: &SessionRef, frame: Frame) {
111111 if session.user_data().get::<Delivered>().is_some() {
112- self.captures.waiting.push((session.clone(), frame));
112+ self.services
113+ .captures
114+ .waiting
115+ .push((session.clone(), frame));
113116 self.needs_redraw = true;
114117 } else {
115118 self.capture(session, frame);
@@ -117,7 +120,7 @@ impl ImageCopyCaptureHandler for State {
117120 }
118121
119122 fn session_destroyed(&mut self, session: SessionRef) {
120- let c = &mut self.captures;
123+ let c = &mut self.services.captures;
121124 c.sessions.retain(|s| *s != session);
122125 c.waiting.retain(|(s, _)| *s != session);
123126 }
@@ -126,17 +129,17 @@ impl ImageCopyCaptureHandler for State {
126129 impl State {
127130 /// Completes waiting frames whose target showed something new.
128131 pub fn complete_captures(&mut self) {
129- if self.captures.damaged.is_empty() {
132+ if self.services.captures.damaged.is_empty() {
130133 return;
131134 }
132- let damaged = std::mem::take(&mut self.captures.damaged);
133- let (ready, waiting) = std::mem::take(&mut self.captures.waiting)
135+ let damaged = std::mem::take(&mut self.services.captures.damaged);
136+ let (ready, waiting) = std::mem::take(&mut self.services.captures.waiting)
134137 .into_iter()
135138 .partition::<Vec<_>, _>(|(s, _)| {
136139 self.target(&s.source())
137140 .is_some_and(|t| damaged.contains(&t))
138141 });
139- self.captures.waiting = waiting;
142+ self.services.captures.waiting = waiting;
140143 for (session, frame) in ready {
141144 self.capture(&session, frame);
142145 }
@@ -275,7 +278,7 @@ impl State {
275278 ));
276279 }
277280 }
278- match crate::lock::elements(&self.lock, &mut self.renderer, output) {
281+ match crate::lock::elements(&self.services.lock, &mut self.renderer, output) {
279282 Some(locked) => elements.extend(locked),
280283 None => elements.extend(crate::scene::build(
281284 &self.layout,
@@ -287,7 +290,10 @@ impl State {
287290 &self.settings.config.decoration,
288291 &mut self.borders,
289292 Some(output),
290- self.xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
293+ self.services
294+ .xwayland
295+ .as_ref()
296+ .map_or(&[], |x| &x.unmanaged),
291297 )),
292298 }
293299 elements
Modified file: crates/monolith/src/commands.rs+3 additions−3 deletions
@@ -173,14 +173,14 @@ impl State {
173173 cmd.args(args)
174174 .env("WAYLAND_DISPLAY", &self.core.socket_name)
175175 .stdin(Stdio::null());
176- if let Some(sock) = &self.ipc.path {
176+ if let Some(sock) = &self.services.ipc.path {
177177 cmd.env("MONOLITH_SOCKET", sock);
178178 }
179179 if self.drm.is_some() {
180180 cmd.env("XDG_CURRENT_DESKTOP", "monolith")
181181 .env("XDG_SESSION_TYPE", "wayland");
182182 }
183- if let Some(x) = &self.xwayland {
183+ if let Some(x) = &self.services.xwayland {
184184 cmd.env("DISPLAY", format!(":{}", x.display));
185185 }
186186 let token = self.launch_token();
@@ -189,7 +189,7 @@ impl State {
189189 let mut child = cmd.spawn().map_err(|e| format!("{program}: {e}"))?;
190190 tracing::info!(pid = child.id(), ?argv, "spawned");
191191 let (output, tag) = self.launch_context();
192- self.launches.record(child.id(), output, tag);
192+ self.services.launches.record(child.id(), output, tag);
193193 std::thread::spawn(move || child.wait());
194194 Ok(())
195195 }
Modified file: crates/monolith/src/drm.rs+8 additions−3 deletions
@@ -3,6 +3,7 @@
33 //! each rendered when its own vblank lands.
44
55 use crate::scene::Draw;
6+use crate::state::Services;
67 use crate::state::{State, now_ns};
78 use monolith_config::Vrr;
89 use monolith_layout::{OutputId, Rect};
@@ -599,9 +600,13 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
599600 cursor,
600601 cursor_status,
601602 pointer_pos,
602- lock,
603- captures,
604- xwayland,
603+ services:
604+ Services {
605+ lock,
606+ captures,
607+ xwayland,
608+ ..
609+ },
605610 ..
606611 } = state
607612 else {
Modified file: crates/monolith/src/globals.rs+1 additions−9 deletions
@@ -6,14 +6,12 @@ use monolith_protocols::toplevel::ForeignToplevelState;
66 use monolith_protocols::workspace::WorkspaceState;
77 use monolith_render_vk::VulkanRenderer;
88 use smithay::backend::renderer::ImportDma;
9-use smithay::reexports::calloop::LoopHandle;
109 use smithay::reexports::wayland_server::DisplayHandle;
1110 use smithay::wayland::compositor::CompositorState;
1211 use smithay::wayland::cursor_shape::CursorShapeManagerState;
1312 use smithay::wayland::dmabuf::{DmabufGlobal, DmabufState};
1413 use smithay::wayland::foreign_toplevel_list::ForeignToplevelListState;
1514 use smithay::wayland::idle_inhibit::IdleInhibitManagerState;
16-use smithay::wayland::idle_notify::IdleNotifierState;
1715 use smithay::wayland::image_capture_source::{
1816 ImageCaptureSourceState, OutputCaptureSourceState, ToplevelCaptureSourceState,
1917 };
@@ -43,7 +41,6 @@ pub struct Protocols {
4341 pub wlr_data_control_state: WlrDataControlState,
4442 pub ext_data_control_state: ExtDataControlState,
4543 pub session_lock_state: SessionLockManagerState,
46- pub idle_notifier: IdleNotifierState<State>,
4744 pub shm_state: ShmState,
4845 pub dmabuf_state: DmabufState,
4946 pub data_device_state: DataDeviceState,
@@ -60,11 +57,7 @@ pub struct Protocols {
6057 }
6158
6259 impl Protocols {
63- pub fn new(
64- dh: &DisplayHandle,
65- handle: LoopHandle<'static, State>,
66- renderer: &VulkanRenderer,
67- ) -> Self {
60+ pub fn new(dh: &DisplayHandle, renderer: &VulkanRenderer) -> Self {
6861 let mut dmabuf_state = DmabufState::new();
6962 let dmabuf_global = dmabuf_state.create_global::<State>(dh, renderer.dmabuf_formats());
7063 let primary_selection_state = PrimarySelectionState::new::<State>(dh);
@@ -88,7 +81,6 @@ impl Protocols {
8881 ),
8982 primary_selection_state,
9083 session_lock_state: SessionLockManagerState::new::<State, _>(dh, |_| true),
91- idle_notifier: IdleNotifierState::new(dh, handle),
9284 shm_state: ShmState::new::<State>(dh, vec![]),
9385 dmabuf_state,
9486 data_device_state: DataDeviceState::new::<State>(dh),
Modified file: crates/monolith/src/handlers.rs+2 additions−2 deletions
@@ -80,10 +80,10 @@ impl CompositorHandler for State {
8080 {
8181 window.on_commit();
8282 }
83- if self.captures.wants_damage()
83+ if self.services.captures.wants_damage()
8484 && let Some(id) = self.window_id(&root)
8585 {
86- self.captures.window_damaged(id);
86+ self.services.captures.window_damaged(id);
8787 }
8888 }
8989 if let Some(i) = self
Modified file: crates/monolith/src/idle.rs+28 additions−10 deletions
@@ -2,26 +2,44 @@
22 //! when the user went away and video players can keep the screen on.
33
44 use crate::state::State;
5-use smithay::reexports::wayland_server::Resource;
5+use smithay::reexports::calloop::LoopHandle;
66 use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
7+use smithay::reexports::wayland_server::{DisplayHandle, Resource};
78 use smithay::wayland::compositor::get_parent;
89 use smithay::wayland::idle_inhibit::IdleInhibitHandler;
910 use smithay::wayland::idle_notify::{IdleNotifierHandler, IdleNotifierState};
11+use std::collections::HashSet;
12+
13+pub struct Idle {
14+ pub notifier: IdleNotifierState<State>,
15+ pub inhibitors: HashSet<WlSurface>,
16+ pub inhibited: bool,
17+}
18+
19+impl Idle {
20+ pub fn new(dh: &DisplayHandle, handle: LoopHandle<'static, State>) -> Self {
21+ Self {
22+ notifier: IdleNotifierState::new(dh, handle),
23+ inhibitors: HashSet::new(),
24+ inhibited: false,
25+ }
26+ }
27+}
1028
1129 impl IdleNotifierHandler for State {
1230 fn idle_notifier_state(&mut self) -> &mut IdleNotifierState<Self> {
13- &mut self.protocols.idle_notifier
31+ &mut self.services.idle.notifier
1432 }
1533 }
1634
1735 impl IdleInhibitHandler for State {
1836 fn inhibit(&mut self, surface: WlSurface) {
19- self.inhibitors.insert(surface);
37+ self.services.idle.inhibitors.insert(surface);
2038 self.update_inhibit();
2139 }
2240
2341 fn uninhibit(&mut self, surface: WlSurface) {
24- self.inhibitors.remove(&surface);
42+ self.services.idle.inhibitors.remove(&surface);
2543 self.update_inhibit();
2644 }
2745 }
@@ -29,14 +47,14 @@ impl IdleInhibitHandler for State {
2947 impl State {
3048 pub fn activity(&mut self) {
3149 let seat = self.seat.clone();
32- self.protocols.idle_notifier.notify_activity(&seat);
50+ self.services.idle.notifier.notify_activity(&seat);
3351 }
3452
3553 /// An inhibitor only counts while its surface is on screen, as the
3654 /// protocol asks, so a video on a hidden tag lets the screen blank.
3755 pub fn update_inhibit(&mut self) {
38- self.inhibitors.retain(|s| s.is_alive());
39- let shown = self.inhibitors.iter().any(|s| {
56+ self.services.idle.inhibitors.retain(|s| s.is_alive());
57+ let shown = self.services.idle.inhibitors.iter().any(|s| {
4058 let mut root = s.clone();
4159 while let Some(parent) = get_parent(&root) {
4260 root = parent;
@@ -46,9 +64,9 @@ impl State {
4664 .any(|w| crate::state::root(w).as_ref() == Some(&root))
4765 || self.layer_maps_contain(&root)
4866 });
49- if shown != self.inhibited {
50- self.inhibited = shown;
51- self.protocols.idle_notifier.set_is_inhibited(shown);
67+ if shown != self.services.idle.inhibited {
68+ self.services.idle.inhibited = shown;
69+ self.services.idle.notifier.set_is_inhibited(shown);
5270 }
5371 }
5472 }
Modified file: crates/monolith/src/import.rs+3 additions−3 deletions
@@ -88,7 +88,7 @@ impl State {
8888 let _ = notifier.successful::<State>();
8989 return;
9090 }
91- self.imports.start(buffer).notifiers.push(notifier);
91+ self.services.imports.start(buffer).notifiers.push(notifier);
9292 }
9393
9494 /// A blocker for a commit whose dmabuf the renderer has not imported yet.
@@ -96,13 +96,13 @@ impl State {
9696 if self.renderer.has_dmabuf(buffer) {
9797 return None;
9898 }
99- let waiters = self.imports.start(buffer);
99+ let waiters = self.services.imports.start(buffer);
100100 waiters.clients.push(client);
101101 Some(ImportBlocker(waiters.done.clone()))
102102 }
103103
104104 fn imported(&mut self, buffer: Dmabuf, result: Result<VulkanTexture, String>) {
105- let Some(waiters) = self.imports.waiting.remove(&buffer.weak()) else {
105+ let Some(waiters) = self.services.imports.waiting.remove(&buffer.weak()) else {
106106 return;
107107 };
108108 let result = result.and_then(|t| {
Modified file: crates/monolith/src/input.rs+2 additions−2 deletions
@@ -38,7 +38,7 @@ impl State {
3838 if pressed == ButtonState::Released && self.drag.take().is_some() {
3939 return;
4040 }
41- if pressed == ButtonState::Pressed && !self.lock.active() {
41+ if pressed == ButtonState::Pressed && !self.services.lock.active() {
4242 focus_under_pointer(self);
4343 if start_drag(self, button) {
4444 return;
@@ -100,7 +100,7 @@ impl State {
100100 let vt = (sym - xkb::keysyms::KEY_XF86Switch_VT_1 + 1) as i32;
101101 return FilterResult::Intercept(Some(Action::Vt(vt)));
102102 }
103- if state.lock.active() {
103+ if state.services.lock.active() {
104104 return FilterResult::Forward;
105105 }
106106 match state.settings.binds.find(mods, &handle.raw_syms()) {
Modified file: crates/monolith/src/ipc.rs+8 additions−8 deletions
@@ -40,9 +40,9 @@ pub fn init(event_loop: &EventLoop<'static, State>, state: &mut State) -> std::i
4040 let listener = UnixListener::bind(&path)?;
4141 listener.set_nonblocking(true)?;
4242 tracing::info!(path = %path.display(), "control socket");
43- state.ipc.path = Some(path);
43+ state.services.ipc.path = Some(path);
4444 let handle = event_loop.handle();
45- state.ipc.handle = Some(handle.clone());
45+ state.services.ipc.handle = Some(handle.clone());
4646 handle
4747 .insert_source(
4848 Generic::new(listener, Interest::READ, Mode::Level),
@@ -62,7 +62,7 @@ pub fn init(event_loop: &EventLoop<'static, State>, state: &mut State) -> std::i
6262 }
6363
6464 fn add_client(state: &mut State, stream: UnixStream) {
65- let Some(handle) = state.ipc.handle.clone() else {
65+ let Some(handle) = state.services.ipc.handle.clone() else {
6666 return;
6767 };
6868 if stream.set_nonblocking(true).is_err() {
@@ -117,7 +117,7 @@ fn handle_line(state: &mut State, stream: &UnixStream, line: &[u8]) -> Option<En
117117 return Some(Envelope::new(id, Reply::Error("cannot subscribe".into())));
118118 };
119119 send(&sub, &Envelope::new(None, Reply::Event(snapshot(state))));
120- state.ipc.subscribers.push(sub);
120+ state.services.ipc.subscribers.push(sub);
121121 return None;
122122 }
123123 };
@@ -134,16 +134,16 @@ fn send(mut stream: &UnixStream, msg: &Envelope<Reply>) -> bool {
134134
135135 /// Sends subscribers the new state whenever it differs from the last one.
136136 pub fn broadcast(state: &mut State) {
137- if state.ipc.subscribers.is_empty() {
137+ if state.services.ipc.subscribers.is_empty() {
138138 return;
139139 }
140140 let now = snapshot(state);
141- if state.ipc.last.as_ref() == Some(&now) {
141+ if state.services.ipc.last.as_ref() == Some(&now) {
142142 return;
143143 }
144144 let msg = Envelope::new(None, Reply::Event(now.clone()));
145- state.ipc.subscribers.retain(|s| send(s, &msg));
146- state.ipc.last = Some(now);
145+ state.services.ipc.subscribers.retain(|s| send(s, &msg));
146+ state.services.ipc.last = Some(now);
147147 }
148148
149149 fn snapshot(state: &State) -> monolith_ipc::State {
Modified file: crates/monolith/src/lock.rs+15 additions−13 deletions
@@ -55,8 +55,8 @@ impl SessionLockHandler for State {
5555
5656 fn lock(&mut self, confirmation: SessionLocker) {
5757 tracing::info!("session lock requested");
58- self.lock.pending = Some(confirmation);
59- self.lock.blanked.clear();
58+ self.services.lock.pending = Some(confirmation);
59+ self.services.lock.blanked.clear();
6060 self.drag = None;
6161 self.sync_focus();
6262 self.needs_redraw = true;
@@ -64,7 +64,7 @@ impl SessionLockHandler for State {
6464
6565 fn unlock(&mut self) {
6666 tracing::info!("session unlocked");
67- self.lock = Lock::default();
67+ self.services.lock = Lock::default();
6868 self.sync_focus();
6969 self.needs_redraw = true;
7070 }
@@ -74,10 +74,11 @@ impl SessionLockHandler for State {
7474 return;
7575 };
7676 configure(&surface, &output);
77- self.lock
77+ self.services
78+ .lock
7879 .surfaces
7980 .retain(|(o, s)| o != &output && s.alive());
80- self.lock.surfaces.push((output, surface));
81+ self.services.lock.surfaces.push((output, surface));
8182 self.sync_focus();
8283 self.needs_redraw = true;
8384 }
@@ -97,23 +98,23 @@ impl State {
9798 /// windows, so nothing private is left on screen when the locker is told
9899 /// it holds the session.
99100 pub fn confirm_lock(&mut self) {
100- if self.lock.pending.is_none() {
101+ if self.services.lock.pending.is_none() {
101102 return;
102103 }
103104 let all = self
104105 .space
105106 .outputs()
106- .all(|o| self.lock.blanked.contains(&o.name()));
107- if all && let Some(locker) = self.lock.pending.take() {
107+ .all(|o| self.services.lock.blanked.contains(&o.name()));
108+ if all && let Some(locker) = self.services.lock.pending.take() {
108109 locker.lock();
109- self.lock.locked = true;
110+ self.services.lock.locked = true;
110111 tracing::info!("session locked");
111112 }
112113 }
113114
114115 /// Resends sizes after an output changed mode.
115116 pub fn reconfigure_lock(&self) {
116- for (output, surface) in &self.lock.surfaces {
117+ for (output, surface) in &self.services.lock.surfaces {
117118 configure(surface, output);
118119 }
119120 }
@@ -121,9 +122,10 @@ impl State {
121122 pub fn lock_keyboard_focus(&self) -> Option<WlSurface> {
122123 let under = self.space.output_under(self.pointer_pos).next();
123124 under
124- .and_then(|o| self.lock.surface_on(o))
125+ .and_then(|o| self.services.lock.surface_on(o))
125126 .or_else(|| {
126- self.lock
127+ self.services
128+ .lock
127129 .surfaces
128130 .iter()
129131 .map(|(_, s)| s)
@@ -138,7 +140,7 @@ impl State {
138140 ) -> Option<(WlSurface, Point<f64, Logical>)> {
139141 let output = self.space.output_under(pos).next()?;
140142 let origin = self.space.output_geometry(output)?.loc;
141- let surface = self.lock.surface_on(output)?;
143+ let surface = self.services.lock.surface_on(output)?;
142144 under_from_surface_tree(
143145 surface.wl_surface(),
144146 pos - origin.to_f64(),
Modified file: crates/monolith/src/main.rs+1 additions
@@ -164,6 +164,7 @@ fn export_session(state: &State) {
164164 .arg("XDG_SESSION_TYPE=wayland")
165165 .args(
166166 state
167+ .services
167168 .xwayland
168169 .as_ref()
169170 .map(|x| format!("DISPLAY=:{}", x.display)),
Modified file: crates/monolith/src/nested/mod.rs+8 additions−3 deletions
@@ -5,6 +5,7 @@
55
66 mod input;
77
8+use crate::state::Services;
89 use crate::state::State;
910 use calloop_wayland_source::WaylandSource;
1011 use monolith_layout::Rect;
@@ -179,9 +180,13 @@ pub fn render(state: &mut State) {
179180 borders,
180181 settings,
181182 output_id,
182- lock,
183- captures,
184- xwayland,
183+ services:
184+ Services {
185+ lock,
186+ captures,
187+ xwayland,
188+ ..
189+ },
185190 ..
186191 } = state;
187192 let Some(host) = host.as_mut() else { return };
Modified file: crates/monolith/src/state.rs+31 additions−21 deletions
@@ -62,8 +62,7 @@ pub struct State {
6262 pub drag: Option<crate::input::Drag>,
6363 /// Global logical position, shared by every backend.
6464 pub pointer_pos: Point<f64, Logical>,
65- pub ipc: crate::ipc::Server,
66- pub launches: crate::launch::Launches,
65+ pub services: Services,
6766 pub list_handles: crate::toplevels::ListHandles,
6867 pub anim: Animator,
6968 pub borders: crate::scene::Borders,
@@ -75,14 +74,8 @@ pub struct State {
7574 pub placed_by_rule: HashSet<WindowId>,
7675 /// A layer surface given the keyboard by a click, like a launcher.
7776 pub layer_focus: Option<WlSurface>,
78- pub xwayland: Option<crate::xwayland::Xwayland>,
79- pub captures: crate::capture::Captures,
80- pub imports: crate::import::Imports,
8177 /// The render node clients get dmabufs for, known on bare metal.
8278 pub render_node: Option<smithay::backend::drm::DrmNode>,
83- pub lock: crate::lock::Lock,
84- pub inhibitors: HashSet<WlSurface>,
85- pub inhibited: bool,
8679 pub seat_state: SeatState<State>,
8780 pub seat: Seat<State>,
8881 }
@@ -96,6 +89,17 @@ pub struct Core {
9689 pub start: Instant,
9790 }
9891
92+/// Subsystems with state of their own.
93+pub struct Services {
94+ pub lock: crate::lock::Lock,
95+ pub captures: crate::capture::Captures,
96+ pub imports: crate::import::Imports,
97+ pub xwayland: Option<crate::xwayland::Xwayland>,
98+ pub launches: crate::launch::Launches,
99+ pub ipc: crate::ipc::Server,
100+ pub idle: crate::idle::Idle,
101+}
102+
99103 /// The config and what is derived from it, swapped whole on reload.
100104 pub struct Settings {
101105 pub config: Config,
@@ -151,8 +155,9 @@ impl State {
151155 layout.gaps = gaps(&config);
152156 let animation = config.animation.clone();
153157 let imports = crate::import::Imports::new(&handle, renderer.dmabuf_importer())?;
158+ let idle = crate::idle::Idle::new(&dh, handle.clone());
154159 Ok(Self {
155- protocols: Protocols::new(&dh, handle.clone(), &renderer),
160+ protocols: Protocols::new(&dh, &renderer),
156161 core: Core {
157162 display: dh,
158163 handle,
@@ -183,8 +188,15 @@ impl State {
183188 move_inverted: false,
184189 drag: None,
185190 pointer_pos: Point::default(),
186- ipc: crate::ipc::Server::default(),
187- launches: Default::default(),
191+ services: Services {
192+ lock: Default::default(),
193+ captures: Default::default(),
194+ imports,
195+ xwayland: None,
196+ launches: Default::default(),
197+ ipc: Default::default(),
198+ idle,
199+ },
188200 list_handles: Default::default(),
189201 anim: Animator::new(animation),
190202 borders: Default::default(),
@@ -192,13 +204,7 @@ impl State {
192204 awaiting: HashSet::new(),
193205 placed_by_rule: HashSet::new(),
194206 layer_focus: None,
195- xwayland: None,
196- captures: Default::default(),
197- imports,
198207 render_node: None,
199- lock: Default::default(),
200- inhibitors: HashSet::new(),
201- inhibited: false,
202208 seat_state,
203209 seat,
204210 })
@@ -249,7 +255,7 @@ impl State {
249255 .and_then(|c| c.get_credentials(&self.core.display).ok())
250256 .map(|c| c.pid as u32),
251257 };
252- let launch = pid.and_then(|pid| self.launches.find(pid));
258+ let launch = pid.and_then(|pid| self.services.launches.find(pid));
253259 let output = rule
254260 .output
255261 .as_deref()
@@ -517,7 +523,7 @@ impl State {
517523 t.send_pending_configure();
518524 }
519525 }
520- let target: Option<Focus> = if self.lock.active() {
526+ let target: Option<Focus> = if self.services.lock.active() {
521527 self.lock_keyboard_focus().map(Focus::from)
522528 } else {
523529 self.layer_keyboard_focus().map(Focus::from).or_else(|| {
@@ -597,10 +603,14 @@ impl State {
597603 &self,
598604 pos: Point<f64, Logical>,
599605 ) -> Option<(WlSurface, Point<f64, Logical>)> {
600- if self.lock.active() {
606+ if self.services.lock.active() {
601607 return self.lock_surface_under(pos);
602608 }
603- let unmanaged = self.xwayland.iter().flat_map(|x| x.unmanaged.iter().rev());
609+ let unmanaged = self
610+ .services
611+ .xwayland
612+ .iter()
613+ .flat_map(|x| x.unmanaged.iter().rev());
604614 for x in unmanaged {
605615 let geo = x.geometry();
606616 if let Some(s) = x.wl_surface()
Modified file: crates/monolith/src/xwayland.rs+9 additions−8 deletions
@@ -113,7 +113,7 @@ pub fn init(state: &mut State) {
113113 }
114114 }
115115 tracing::info!("X11 clients will start Xwayland on :{number}");
116- state.xwayland = Some(Xwayland {
116+ state.services.xwayland = Some(Xwayland {
117117 display: number,
118118 listeners,
119119 watch,
@@ -125,7 +125,7 @@ pub fn init(state: &mut State) {
125125
126126 /// Waits for the next X client to knock.
127127 fn rearm(state: &mut State) {
128- let Some(x) = state.xwayland.as_mut() else {
128+ let Some(x) = state.services.xwayland.as_mut() else {
129129 return;
130130 };
131131 x.running = false;
@@ -147,7 +147,7 @@ fn set_inherit(listeners: &[UnixListener], inherit: bool) {
147147 }
148148
149149 fn start(state: &mut State, fired: usize) {
150- let Some(x) = state.xwayland.as_mut() else {
150+ let Some(x) = state.services.xwayland.as_mut() else {
151151 return;
152152 };
153153 if x.running {
@@ -195,7 +195,7 @@ fn start(state: &mut State, fired: usize) {
195195 match X11Wm::start_wm(state.core.handle.clone(), &dh, x11_socket, client.clone()) {
196196 Ok(wm) => {
197197 tracing::info!("Xwayland ready");
198- if let Some(x) = state.xwayland.as_mut() {
198+ if let Some(x) = state.services.xwayland.as_mut() {
199199 x.wm = Some(wm);
200200 }
201201 }
@@ -225,7 +225,8 @@ impl XWaylandShellHandler for State {
225225
226226 impl XwmHandler for State {
227227 fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
228- self.xwayland
228+ self.services
229+ .xwayland
229230 .as_mut()
230231 .and_then(|x| x.wm.as_mut())
231232 .expect("X11 events only arrive while the WM runs")
@@ -245,7 +246,7 @@ impl XwmHandler for State {
245246 }
246247
247248 fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
248- if let Some(x) = self.xwayland.as_mut() {
249+ if let Some(x) = self.services.xwayland.as_mut() {
249250 x.unmanaged.retain(|w| w != &window);
250251 x.unmanaged.push(window);
251252 }
@@ -327,7 +328,7 @@ impl XwmHandler for State {
327328 for id in gone {
328329 self.remove_window(id);
329330 }
330- if let Some(x) = self.xwayland.as_mut() {
331+ if let Some(x) = self.services.xwayland.as_mut() {
331332 x.wm = None;
332333 x.unmanaged.clear();
333334 }
@@ -363,7 +364,7 @@ impl State {
363364 }
364365
365366 fn forget_x11(&mut self, window: &X11Surface) {
366- if let Some(x) = self.xwayland.as_mut() {
367+ if let Some(x) = self.services.xwayland.as_mut() {
367368 x.unmanaged.retain(|w| w != window);
368369 }
369370 if let Some(id) = self.x11_window_id(window) {