diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index d2971177..46c76b9c 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -814,24 +814,6 @@ where })); } - if let Some(xwm) = state - .shell - .xwayland_state - .as_mut() - .and_then(|state| state.xwm.as_mut()) - { - // we don't include the popup elements, which contain the OR windows, because we are not supposed to restack them - if let Err(err) = - xwm.update_stacking_order_upwards(window_elements.iter().rev().map(|e| e.id())) - { - warn!( - wm_id = ?xwm.id(), - ?err, - "Failed to update Xwm stacking order.", - ); - } - } - elements.extend(window_elements); Ok(elements) diff --git a/src/main.rs b/src/main.rs index 33424e68..c6580331 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,6 +110,7 @@ fn main() -> Result<()> { } state.common.shell.refresh(); state::Common::refresh_focus(state); + state.common.update_x11_stacking_order(); if state.common.shell.animations_going() { for output in state diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index ca5b121d..c15d35c0 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -30,9 +30,8 @@ use smithay::{ renderer::{ element::{ memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement, - AsRenderElements, Element, Id as ElementId, Kind, RenderElement, + AsRenderElements, }, - utils::CommitCounter, ImportAll, ImportMem, Renderer, }, }, @@ -49,7 +48,7 @@ use smithay::{ }, output::Output, render_elements, - utils::{Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform}, + utils::{Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size}, wayland::seat::WaylandFocus, }; use std::{ @@ -560,30 +559,10 @@ impl CosmicStack { let windows = p.windows.lock().unwrap(); let active = p.active.load(Ordering::SeqCst); - let (mut window_elements, popup_elements) = windows[active] + let (window_elements, popup_elements) = windows[active] .split_render_elements::>( renderer, window_loc, scale, alpha, ); - // preparing the other windows will fix their x11 stacking order. - // they won't actually be drawn due to the placeholder element. - for window in windows - .iter() - .enumerate() - .filter(|(i, _)| *i != active) - .map(|(_, w)| w) - { - let location = - window_loc + offset - window.geometry().loc.to_physical_precise_round(scale); - let (elements, _) = window - .split_render_elements::>( - renderer, location, scale, alpha, - ); - window_elements.extend( - elements - .into_iter() - .map(|e| PlaceholderElement(e.id().clone()).into()), - ); - } (window_elements, popup_elements) }); @@ -1623,69 +1602,8 @@ impl PointerTarget for CosmicStack { } } -pub struct PlaceholderElement(ElementId); - -impl Element for PlaceholderElement { - fn id(&self) -> &ElementId { - &self.0 - } - - fn current_commit(&self) -> CommitCounter { - 0.into() - } - - fn src(&self) -> Rectangle { - Rectangle::from_loc_and_size((0., 0.), (0., 0.)) - } - - fn geometry(&self, _: Scale) -> Rectangle { - Rectangle::from_loc_and_size((0, 0), (0, 0)) - } - - fn location(&self, _: Scale) -> Point { - (0, 0).into() - } - - fn transform(&self) -> Transform { - Transform::Normal - } - - fn damage_since( - &self, - _: Scale, - _: Option, - ) -> Vec> { - vec![] - } - - fn opaque_regions(&self, _scale: Scale) -> Vec> { - vec![] - } - - fn alpha(&self) -> f32 { - 1.0 - } - - fn kind(&self) -> Kind { - Kind::default() - } -} - -impl RenderElement for PlaceholderElement { - fn draw( - &self, - _: &mut ::Frame<'_>, - _: Rectangle, - _: Rectangle, - _: &[Rectangle], - ) -> Result<(), ::Error> { - Ok(()) - } -} - render_elements! { pub CosmicStackRenderElement where R: ImportAll + ImportMem; Header = MemoryRenderBufferRenderElement, Window = WaylandSurfaceRenderElement, - Placeholder = PlaceholderElement, } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 7ed464dc..3e909be6 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1178,39 +1178,6 @@ impl Shell { set.workspaces[set.active].tiling_layer.cleanup_drag(); } set.activate(idx, workspace_delta, &mut self.workspace_state.update())?; - if let Some(xwm) = self - .xwayland_state - .as_mut() - .and_then(|state| state.xwm.as_mut()) - { - { - for window in set.workspaces[set.active] - .tiling_layer - .mapped() - .map(|(w, _)| w) - .chain(set.workspaces[set.active].floating_layer.space.elements()) - { - if let Some(surf) = window.active_window().x11_surface() { - let _ = xwm.raise_window(surf); - } - } - for window in set.sticky_layer.space.elements() { - if let Some(surf) = window.active_window().x11_surface() { - let _ = xwm.raise_window(surf); - } - } - if let Some(surf) = set.workspaces[set.active] - .fullscreen - .as_ref() - .and_then(|f| f.surface.x11_surface()) - { - let _ = xwm.raise_window(surf); - } - } - for surface in &self.override_redirect_windows { - let _ = xwm.raise_window(surface); - } - } let output_geo = output.geometry(); Ok(Some( diff --git a/src/xwayland.rs b/src/xwayland.rs index 4cefe351..77309129 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -136,6 +136,104 @@ impl State { } } +impl Common { + fn is_x_focused(&self, xwm: XwmId) -> bool { + if let Some(keyboard) = self.last_active_seat().get_keyboard() { + if let Some(KeyboardFocusTarget::Element(mapped)) = keyboard.current_focus() { + if let Some(surface) = mapped.active_window().x11_surface() { + return surface.xwm_id().unwrap() == xwm; + } + } + } + + false + } + + pub fn update_x11_stacking_order(&mut self) { + let active_output = self.last_active_seat().active_output(); + if let Some(xwm) = self + .shell + .xwayland_state + .as_mut() + .and_then(|state| state.xwm.as_mut()) + { + // front to back, given that is how the workspace enumerates + let order = self + .shell + .workspaces + .sets + .iter() + .filter(|(output, _)| *output == &active_output) + .chain( + self.shell + .workspaces + .sets + .iter() + .filter(|(output, _)| *output != &active_output), + ) + .flat_map(|(_, set)| { + set.sticky_layer + .mapped() + .flat_map(|mapped| { + let active = mapped.active_window(); + std::iter::once(active.clone()).chain( + mapped + .is_stack() + .then(move || { + mapped + .windows() + .map(|(s, _)| s) + .filter(move |s| s != &active) + }) + .into_iter() + .flatten(), + ) + }) + .chain( + set.workspaces + .iter() + .enumerate() + .filter(|(i, _)| *i == set.active) + .chain( + set.workspaces + .iter() + .enumerate() + .filter(|(i, _)| *i != set.active), + ) + .flat_map(|(_, workspace)| { + workspace.get_fullscreen().cloned().into_iter().chain( + workspace.mapped().flat_map(|mapped| { + let active = mapped.active_window(); + std::iter::once(active.clone()).chain( + mapped + .is_stack() + .then(move || { + mapped + .windows() + .map(|(s, _)| s) + .filter(move |s| s != &active) + }) + .into_iter() + .flatten(), + ) + }), + ) + }), + ) + }) + .collect::>(); + + // we don't include the popup elements, which contain the OR windows, because we are not supposed to restack them. + // Which is also why we match upwards, to not disturb elements at the top. + // + // But this also means we need to match across all outputs and workspaces at once, to be sure nothing that shouldn't be on top of us is. + if let Err(err) = xwm.update_stacking_order_upwards(order.iter().rev()) { + warn!(wm_id = ?xwm.id(), ?err, "Failed to update Xwm stacking order."); + } + } + } +} + impl XwmHandler for State { fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm { self.common @@ -583,17 +681,3 @@ impl XwmHandler for State { } } } - -impl Common { - fn is_x_focused(&self, xwm: XwmId) -> bool { - if let Some(keyboard) = self.last_active_seat().get_keyboard() { - if let Some(KeyboardFocusTarget::Element(mapped)) = keyboard.current_focus() { - if let Some(surface) = mapped.active_window().x11_surface() { - return surface.xwm_id().unwrap() == xwm; - } - } - } - - false - } -}