atagen

monolith

public
Star0
Watch0

Commit 480ead9a41f5

tarball

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

8 files changed+101-97
monolith: move window helpers from state.rs into wm.rs

configure, root and identity, with the placement Kind, are about windows, and the window model is where callers now look for them.
Modified file: crates/monolith/src/handlers.rs+1 additions−1 deletions
@@ -77,7 +77,7 @@ impl CompositorHandler for State {
7777 self.wm
7878 .unmapped
7979 .iter()
80- .find(|w| crate::state::root(w).as_ref() == Some(&root))
80+ .find(|w| crate::wm::root(w).as_ref() == Some(&root))
8181 });
8282 if let Some(window) = window {
8383 window.on_commit();
Modified file: crates/monolith/src/idle.rs+1 additions−1 deletions
@@ -62,7 +62,7 @@ impl State {
6262 self.wm
6363 .space
6464 .elements()
65- .any(|w| crate::state::root(w).as_ref() == Some(&root))
65+ .any(|w| crate::wm::root(w).as_ref() == Some(&root))
6666 || self.layer_maps_contain(&root)
6767 });
6868 if shown != self.services.idle.inhibited {
Modified file: crates/monolith/src/input.rs+1 additions−1 deletions
@@ -154,7 +154,7 @@ fn focus_under_pointer(state: &mut State) {
154154 .wm
155155 .space
156156 .element_under(pos)
157- .and_then(|(w, _)| crate::state::root(w))
157+ .and_then(|(w, _)| crate::wm::root(w))
158158 .and_then(|s| state.window_id(&s));
159159 if let Some(id) = id
160160 && state.wm.layout.focused() != Some(id)
Modified file: crates/monolith/src/ipc.rs+2 additions−1 deletions
@@ -1,7 +1,8 @@
11 //! The JSONL control socket, and the `msg`, `get` and `subscribe` client
22 //! subcommands that talk to it.
33
4-use crate::state::{State, identity};
4+use crate::state::State;
5+use crate::wm::identity;
56 use monolith_ipc::{Answer, Envelope, Query, Reply, Request, VERSION};
67 use smithay::reexports::calloop::generic::Generic;
78 use smithay::reexports::calloop::{EventLoop, Interest, LoopHandle, Mode, PostAction};
Modified file: crates/monolith/src/scene.rs+2 additions−2 deletions
@@ -191,7 +191,7 @@ fn window_elements(
191191 .filter_map(|e| CropRenderElement::from_element(e, 1.0, crop))
192192 .map(Draw::Cropped),
193193 );
194- let Some(root) = crate::state::root(window) else {
194+ let Some(root) = crate::wm::root(window) else {
195195 return;
196196 };
197197 let context = renderer.context_id();
@@ -305,7 +305,7 @@ fn effect_elements(
305305 (at, size): ((i32, i32), (i32, i32)),
306306 effect: Effect,
307307 ) {
308- let Some(root) = crate::state::root(window) else {
308+ let Some(root) = crate::wm::root(window) else {
309309 return;
310310 };
311311 let root_id = Id::from_wayland_resource(&root);
Modified file: crates/monolith/src/state.rs+2 additions−89 deletions
@@ -2,7 +2,7 @@ use crate::anim::{Animator, Ghost};
22 use crate::commands::Binds;
33 use crate::focus::Focus;
44 use crate::globals::Protocols;
5-use crate::wm::Wm;
5+use crate::wm::{Kind, Wm, configure, identity, root};
66 use monolith_config::Config;
77 use monolith_layout::{Layout, OutputId, Rect, WindowId};
88 use monolith_protocols::workspace::{Group, Snapshot, Workspace};
@@ -19,15 +19,12 @@ use smithay::reexports::calloop::LoopHandle;
1919 use smithay::reexports::calloop::generic::Generic;
2020 use smithay::reexports::calloop::timer::{TimeoutAction, Timer};
2121 use smithay::reexports::calloop::{EventLoop, Interest, LoopSignal, Mode, PostAction};
22-use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState;
2322 use smithay::reexports::wayland_server::backend::{ClientData, ClientId, DisconnectReason};
2423 use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
2524 use smithay::reexports::wayland_server::{Display, DisplayHandle, Resource};
2625 use smithay::utils::{Clock, Logical, Monotonic, Point, Rectangle, SERIAL_COUNTER, Size};
27-use smithay::wayland::compositor::{CompositorClientState, with_states};
28-use smithay::wayland::seat::WaylandFocus;
26+use smithay::wayland::compositor::CompositorClientState;
2927 use smithay::wayland::shell::wlr_layer::Layer;
30-use smithay::wayland::shell::xdg::XdgToplevelSurfaceData;
3128 use smithay::wayland::socket::ListeningSocketSource;
3229 use std::collections::{HashMap, HashSet};
3330 use std::ffi::OsString;
@@ -622,94 +619,10 @@ impl State {
622619 }
623620 }
624621
625-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
626-pub enum Kind {
627- Tiled,
628- Floating,
629- Fullscreen,
630-}
631-
632-/// Sets a window's pending size and states. Returns false for windows
633-/// squeezed to a line by an expanded sibling, which are not shown.
634-fn configure(window: &Window, rect: Rect, kind: Kind, maximized: bool) -> bool {
635- let (x, y) = (rect.x.round(), rect.y.round());
636- let w = (rect.right().round() - x) as i32;
637- let h = (rect.bottom().round() - y) as i32;
638- if w < 1 || h < 1 {
639- return false;
640- }
641- let (x0, y0) = (x as i32, y as i32);
642- if let Some(x) = window.x11_surface() {
643- let _ = x.configure(Rectangle::new((x0, y0).into(), (w, h).into()));
644- let _ = x.set_fullscreen(kind == Kind::Fullscreen);
645- let _ = x.set_maximized(maximized && kind == Kind::Tiled);
646- }
647- if let Some(t) = window.toplevel() {
648- t.with_pending_state(|s| {
649- s.size = Some((w, h).into());
650- let tiled = [
651- XdgState::TiledLeft,
652- XdgState::TiledRight,
653- XdgState::TiledTop,
654- XdgState::TiledBottom,
655- ];
656- for st in tiled {
657- if kind == Kind::Tiled {
658- s.states.set(st);
659- } else {
660- s.states.unset(st);
661- }
662- }
663- if kind == Kind::Fullscreen {
664- s.states.set(XdgState::Fullscreen);
665- } else {
666- s.states.unset(XdgState::Fullscreen);
667- }
668- if maximized && kind == Kind::Tiled {
669- s.states.set(XdgState::Maximized);
670- } else {
671- s.states.unset(XdgState::Maximized);
672- }
673- });
674- if t.is_initial_configure_sent() {
675- t.send_pending_configure();
676- }
677- }
678- true
679-}
680-
681622 pub fn now_ns() -> u64 {
682623 Duration::from(Clock::<Monotonic>::new().now()).as_nanos() as u64
683624 }
684625
685-/// A window's surface, for xdg toplevels and X11 windows alike.
686-pub fn root(window: &Window) -> Option<WlSurface> {
687- window.wl_surface().map(|s| s.into_owned())
688-}
689-
690-/// A window's app id and title. X11 windows give their class.
691-pub fn identity(window: &Window) -> (String, String) {
692- if let Some(x) = window.x11_surface() {
693- return (x.class(), x.title());
694- }
695- let Some(t) = window.toplevel() else {
696- return Default::default();
697- };
698- with_states(t.wl_surface(), |s| {
699- let data = s
700- .data_map
701- .get::<XdgToplevelSurfaceData>()
702- .and_then(|d| d.lock().ok());
703- data.map(|d| {
704- (
705- d.app_id.clone().unwrap_or_default(),
706- d.title.clone().unwrap_or_default(),
707- )
708- })
709- .unwrap_or_default()
710- })
711-}
712-
713626 pub fn gaps(config: &Config) -> monolith_layout::Gaps {
714627 monolith_layout::Gaps {
715628 inner: config.general.gaps.inner,
Modified file: crates/monolith/src/toplevels.rs+2 additions−1 deletions
@@ -1,7 +1,8 @@
11 //! Window lists for other clients: ext-foreign-toplevel-list for listing,
22 //! and wlr-foreign-toplevel-management for taskbars that also act on them.
33
4-use crate::state::{State, identity};
4+use crate::state::State;
5+use crate::wm::identity;
56 use monolith_layout::WindowId;
67 use monolith_protocols::toplevel::{
78 Action, ForeignToplevelHandler, ForeignToplevelState, Snapshot, Toplevel,
Modified file: crates/monolith/src/wm.rs+90 additions−1 deletions
@@ -2,13 +2,18 @@
22 //! monolith keeps beside it.
33
44 use crate::anim::Animator;
5-use crate::state::{Kind, root};
5+
66 use monolith_layout::{Layout, OutputId, Rect, WindowId};
77 use slotmap::SecondaryMap;
88 use smithay::backend::renderer::element::solid::SolidColorBuffer;
99 use smithay::desktop::{PopupManager, Space, Window};
10+use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState;
1011 use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
12+use smithay::utils::Rectangle;
13+use smithay::wayland::compositor::with_states;
1114 use smithay::wayland::foreign_toplevel_list::ForeignToplevelHandle;
15+use smithay::wayland::seat::WaylandFocus;
16+use smithay::wayland::shell::xdg::XdgToplevelSurfaceData;
1217 use std::collections::HashMap;
1318
1419 pub struct Wm {
@@ -133,3 +138,87 @@ impl Wm {
133138 self.windows.values().any(|w| w.awaiting_buffer)
134139 }
135140 }
141+
142+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143+pub enum Kind {
144+ Tiled,
145+ Floating,
146+ Fullscreen,
147+}
148+
149+/// Sets a window's pending size and states. Returns false for windows
150+/// squeezed to a line by an expanded sibling, which are not shown.
151+pub fn configure(window: &Window, rect: Rect, kind: Kind, maximized: bool) -> bool {
152+ let (x, y) = (rect.x.round(), rect.y.round());
153+ let w = (rect.right().round() - x) as i32;
154+ let h = (rect.bottom().round() - y) as i32;
155+ if w < 1 || h < 1 {
156+ return false;
157+ }
158+ let (x0, y0) = (x as i32, y as i32);
159+ if let Some(x) = window.x11_surface() {
160+ let _ = x.configure(Rectangle::new((x0, y0).into(), (w, h).into()));
161+ let _ = x.set_fullscreen(kind == Kind::Fullscreen);
162+ let _ = x.set_maximized(maximized && kind == Kind::Tiled);
163+ }
164+ if let Some(t) = window.toplevel() {
165+ t.with_pending_state(|s| {
166+ s.size = Some((w, h).into());
167+ let tiled = [
168+ XdgState::TiledLeft,
169+ XdgState::TiledRight,
170+ XdgState::TiledTop,
171+ XdgState::TiledBottom,
172+ ];
173+ for st in tiled {
174+ if kind == Kind::Tiled {
175+ s.states.set(st);
176+ } else {
177+ s.states.unset(st);
178+ }
179+ }
180+ if kind == Kind::Fullscreen {
181+ s.states.set(XdgState::Fullscreen);
182+ } else {
183+ s.states.unset(XdgState::Fullscreen);
184+ }
185+ if maximized && kind == Kind::Tiled {
186+ s.states.set(XdgState::Maximized);
187+ } else {
188+ s.states.unset(XdgState::Maximized);
189+ }
190+ });
191+ if t.is_initial_configure_sent() {
192+ t.send_pending_configure();
193+ }
194+ }
195+ true
196+}
197+
198+/// A window's surface, for xdg toplevels and X11 windows alike.
199+pub fn root(window: &Window) -> Option<WlSurface> {
200+ window.wl_surface().map(|s| s.into_owned())
201+}
202+
203+/// A window's app id and title. X11 windows give their class.
204+pub fn identity(window: &Window) -> (String, String) {
205+ if let Some(x) = window.x11_surface() {
206+ return (x.class(), x.title());
207+ }
208+ let Some(t) = window.toplevel() else {
209+ return Default::default();
210+ };
211+ with_states(t.wl_surface(), |s| {
212+ let data = s
213+ .data_map
214+ .get::<XdgToplevelSurfaceData>()
215+ .and_then(|d| d.lock().ok());
216+ data.map(|d| {
217+ (
218+ d.app_id.clone().unwrap_or_default(),
219+ d.title.clone().unwrap_or_default(),
220+ )
221+ })
222+ .unwrap_or_default()
223+ })
224+}