atagen

monolith

public
Star0
Watch0

Commit 410c558612d5

tarball

atagen <boss@atagen.co>2026-10-19 10:50 UTC

1 file changed+18-3
windows: place transients with their parent

map_window used launch_of(pid), whose owner lookup takes the first window of the process in slot order, so a dialog could land on a hidden tag or another output while drawn over its parent. A scratchpad or sticky parent has no tag to follow, so those use the output's launch tag.
Modified file: crates/monolith/src/windows.rs+18 additions−3 deletions
@@ -2,7 +2,7 @@ use crate::anim::Ghost;
22 use crate::state::{State, now_ns};
33 use crate::wm::{Kind, LastFrame, identity, root};
44 use monolith_config::At;
5-use monolith_layout::{OutputId, Rect, WindowId};
5+use monolith_layout::{OutputId, Rect, TagId, WindowId};
66 use monolith_render_vk::VulkanTexture;
77 use smithay::backend::renderer::Renderer;
88 use smithay::backend::renderer::utils::{import_surface_tree, with_renderer_surface_state};
@@ -23,7 +23,10 @@ impl State {
2323 let (app_id, title) = identity(&window);
2424 let facts = self.facts(&window, None);
2525 let rule = self.settings.config.placement(&facts.subject());
26- let launch = self.launch_of(self.window_pid(&window));
26+ let parent = self.parent_of(&window);
27+ let launch = self
28+ .parent_context(parent)
29+ .unwrap_or_else(|| self.launch_of(self.window_pid(&window)));
2730 let (asked, fullscreen_output) = requested_fullscreen(&window);
2831 let fullscreen = rule.fullscreen.unwrap_or(asked);
2932 let output = rule
@@ -50,7 +53,6 @@ impl State {
5053 .wm
5154 .layout
5255 .add_window(output, tag, float.filter(|_| floating));
53- let parent = self.parent_of(&window);
5456 self.wm.layout.set_parent(id, parent);
5557 self.wm.layout.set_modal(id, is_modal(&window));
5658 if floating != self.wm.layout.window(id).is_some_and(|w| w.floating) {
@@ -83,6 +85,19 @@ impl State {
8385 self.apply_layout();
8486 }
8587
88+ /// Where a transient of `parent` belongs, which is where its parent is.
89+ /// A scratchpad or sticky parent has no tag of its own to follow.
90+ fn parent_context(&self, parent: Option<WindowId>) -> Option<(Option<OutputId>, TagId)> {
91+ let win = self.wm.layout.window(parent?)?;
92+ let output = win.output?;
93+ let tag = if win.scratchpad.is_some() || win.sticky {
94+ self.wm.layout.launch_tag(output)
95+ } else {
96+ win.tag
97+ };
98+ Some((Some(output), tag))
99+ }
100+
86101 /// The mapped window `window` is a dialog or other transient of.
87102 pub(crate) fn parent_of(&self, window: &Window) -> Option<WindowId> {
88103 if let Some(x) = window.x11_surface() {