Render everything when there's a fullscreen window

And properly handle input and layering this time
This commit is contained in:
Ottatop 2024-04-07 01:56:36 -05:00
parent 485dba69d6
commit 76fc825b51
3 changed files with 130 additions and 142 deletions

View file

@ -7,6 +7,7 @@ use std::{collections::HashMap, mem::Discriminant, time::Duration};
use crate::{ use crate::{
focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget}, focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget},
state::WithState, state::WithState,
window::WindowElement,
}; };
use pinnacle_api_defs::pinnacle::input::v0alpha1::{ use pinnacle_api_defs::pinnacle::input::v0alpha1::{
set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse, set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse,
@ -181,38 +182,28 @@ impl State {
.output_geometry(output) .output_geometry(output)
.expect("called output_geometry on unmapped output"); .expect("called output_geometry on unmapped output");
let layers = layer_map_for_output(output); let mut fullscreen_and_up_split_at = 0;
let top_fullscreen_window = output for (i, win) in self
.with_state(|state| state.focus_stack.stack.clone())
.into_iter()
.rev()
.find(|win| {
win.with_state(|state| {
state.fullscreen_or_maximized.is_fullscreen()
&& output.with_state(|op_state| {
op_state
.focused_tags()
.any(|op_tag| state.tags.contains(op_tag))
})
})
});
if let Some(window) = top_fullscreen_window {
let loc = self
.space .space
.element_location(&window) .elements()
.expect("called elem loc on unmapped win") .rev()
- window.geometry().loc; .filter(|win| win.is_on_active_tag())
.enumerate()
{
if win.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
fullscreen_and_up_split_at = i + 1;
}
}
window let layer_under =
.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL) |layers: &[wlr_layer::Layer]| -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
.map(|(surf, surf_loc)| (PointerFocusTarget::WlSurface(surf), surf_loc + loc)) let layer_map = layer_map_for_output(output);
} else if let (Some(layer), _) | (None, Some(layer)) = ( let layer = layers
layers.layer_under(wlr_layer::Layer::Overlay, point), .iter()
layers.layer_under(wlr_layer::Layer::Top, point), .find_map(|layer| layer_map.layer_under(*layer, point))?;
) {
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc; let layer_loc = layer_map.layer_geometry(layer)?.loc;
layer layer
.surface_under( .surface_under(
@ -225,12 +216,11 @@ impl State {
surf_loc + layer_loc + output_geo.loc, surf_loc + layer_loc + output_geo.loc,
) )
}) })
} else if let Some((surface, loc)) = self };
.space
.elements() let window_under =
.rev() |windows: &[WindowElement]| -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
.filter(|win| win.is_on_active_tag()) windows.iter().find_map(|win| {
.find_map(|win| {
let loc = self let loc = self
.space .space
.element_location(win) .element_location(win)
@ -238,30 +228,42 @@ impl State {
- win.geometry().loc; - win.geometry().loc;
win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL) win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
.map(|(surf, surf_loc)| (surf, surf_loc + loc))
})
{
Some((PointerFocusTarget::WlSurface(surface), loc))
} else if let (Some(layer), _) | (None, Some(layer)) = (
layers.layer_under(wlr_layer::Layer::Overlay, point),
layers.layer_under(wlr_layer::Layer::Top, point),
) {
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
layer
.surface_under(
point - layer_loc.to_f64() - output_geo.loc.to_f64(),
WindowSurfaceType::ALL,
)
.map(|(surf, surf_loc)| { .map(|(surf, surf_loc)| {
( (PointerFocusTarget::WlSurface(surf), surf_loc + loc)
PointerFocusTarget::WlSurface(surf), })
surf_loc + layer_loc + output_geo.loc, })
};
// Input and rendering go, from top to bottom,
// - All windows down to the bottom-most fullscreen window (this mimics Awesome)
// - Overlay and Top layer surfaces
// - The rest of the windows
// - Bottom and background layer surfaces
window_under(
&self
.space
.elements()
.rev()
.filter(|win| win.is_on_active_tag())
.take(fullscreen_and_up_split_at)
.cloned()
.collect::<Vec<_>>(),
)
.or_else(|| layer_under(&[wlr_layer::Layer::Overlay, wlr_layer::Layer::Top]))
.or_else(|| {
window_under(
&self
.space
.elements()
.rev()
.filter(|win| win.is_on_active_tag())
.skip(fullscreen_and_up_split_at)
.cloned()
.collect::<Vec<_>>(),
) )
}) })
} else { .or_else(|| layer_under(&[wlr_layer::Layer::Bottom, wlr_layer::Layer::Background]))
None
}
} }
/// Update the pointer focus if it's different from the previous one. /// Update the pointer focus if it's different from the previous one.

View file

@ -22,10 +22,7 @@ use smithay::{
}, },
input::pointer::{CursorImageAttributes, CursorImageStatus}, input::pointer::{CursorImageAttributes, CursorImageStatus},
output::Output, output::Output,
reexports::{ reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland_protocols::xdg::shell::server::xdg_toplevel,
wayland_server::protocol::wl_surface::WlSurface,
},
render_elements, render_elements,
utils::{Logical, Physical, Point, Scale}, utils::{Logical, Physical, Point, Scale},
wayland::{compositor, shell::wlr_layer}, wayland::{compositor, shell::wlr_layer},
@ -129,22 +126,38 @@ where
} }
/// Get render elements for windows on active tags. /// Get render elements for windows on active tags.
fn tag_render_elements<R>( ///
/// ret.1 contains render elements for the windows at and above the first fullscreen window.
/// ret.2 contains the rest.
#[allow(clippy::type_complexity)]
fn window_render_elements<R>(
output: &Output, output: &Output,
windows: &[WindowElement], windows: &[WindowElement],
space: &Space<WindowElement>, space: &Space<WindowElement>,
renderer: &mut R, renderer: &mut R,
scale: Scale<f64>, scale: Scale<f64>,
) -> Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>> ) -> (
Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>,
Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>,
)
where where
R: Renderer + ImportAll + ImportMem, R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: 'static, <R as Renderer>::TextureId: 'static,
{ {
let elements = windows // bot wwwwwFFww top
// rev wwFFwwwww
let mut last_fullscreen_split_at = 0;
let mut elements = windows
.iter() .iter()
.rev() // rev because I treat the focus stack backwards vs how the renderer orders it .rev() // rev because I treat the focus stack backwards vs how the renderer orders it
.filter(|win| win.is_on_active_tag()) .filter(|win| win.is_on_active_tag())
.map(|win| { .enumerate()
.map(|(i, win)| {
if win.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
last_fullscreen_split_at = i + 1;
}
// subtract win.geometry().loc to align decorations correctly // subtract win.geometry().loc to align decorations correctly
let loc = ( let loc = (
space.element_location(win) .unwrap_or((0, 0).into()) space.element_location(win) .unwrap_or((0, 0).into())
@ -159,7 +172,7 @@ where
}); });
(win.render_elements::<WaylandSurfaceRenderElement<R>>(renderer, loc, scale, 1.0), elem_geo) (win.render_elements::<WaylandSurfaceRenderElement<R>>(renderer, loc, scale, 1.0), elem_geo)
}).flat_map(|(elems, rect)| { }).map(|(elems, rect)| {
// We're cropping everything down to its expected size to stop any sussy windows that // We're cropping everything down to its expected size to stop any sussy windows that
// don't want to cooperate. Unfortunately this also truncates shadows and other // don't want to cooperate. Unfortunately this also truncates shadows and other
// external decorations. // external decorations.
@ -171,10 +184,15 @@ where
}, },
None => elems.into_iter().map(OutputRenderElements::from).collect(), None => elems.into_iter().map(OutputRenderElements::from).collect(),
} }
}) }).collect::<Vec<_>>();
.collect::<Vec<_>>();
elements let rest = elements.split_off(last_fullscreen_split_at);
// PERF: bunch of allocations here
(
elements.into_iter().flatten().collect(),
rest.into_iter().flatten().collect(),
)
} }
pub fn pointer_render_elements<R>( pub fn pointer_render_elements<R>(
@ -293,39 +311,6 @@ where
// | base it on if it's a descendant or not // | base it on if it's a descendant or not
output_render_elements.extend(o_r_elements.map(OutputRenderElements::from)); output_render_elements.extend(o_r_elements.map(OutputRenderElements::from));
let top_fullscreen_window = windows.iter().rev().find(|win| {
let is_wayland_actually_fullscreen = {
if let Some(toplevel) = win.toplevel() {
toplevel
.current_state()
.states
.contains(xdg_toplevel::State::Fullscreen)
} else {
true
}
};
win.with_state(|state| {
state.fullscreen_or_maximized.is_fullscreen()
&& output.with_state(|op_state| {
op_state
.focused_tags()
.any(|op_tag| state.tags.contains(op_tag))
})
}) && is_wayland_actually_fullscreen
});
// If fullscreen windows exist, render only the topmost one
if let Some(window) = top_fullscreen_window {
let window_render_elements: Vec<WaylandSurfaceRenderElement<_>> =
window.render_elements(renderer, (0, 0).into(), scale, 1.0);
output_render_elements.extend(
window_render_elements
.into_iter()
.map(OutputRenderElements::from),
);
} else {
let LayerRenderElements { let LayerRenderElements {
background, background,
bottom, bottom,
@ -333,11 +318,13 @@ where
overlay, overlay,
} = layer_render_elements(output, renderer, scale); } = layer_render_elements(output, renderer, scale);
let window_render_elements = let (fullscreen_and_up_elements, rest_of_window_elements) =
tag_render_elements::<R>(output, &windows, space, renderer, scale); window_render_elements::<R>(output, &windows, space, renderer, scale);
// Elements render from top to bottom // Elements render from top to bottom
output_render_elements.extend(fullscreen_and_up_elements);
output_render_elements.extend( output_render_elements.extend(
overlay overlay
.into_iter() .into_iter()
@ -345,7 +332,7 @@ where
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
output_render_elements.extend(window_render_elements); output_render_elements.extend(rest_of_window_elements);
output_render_elements.extend( output_render_elements.extend(
bottom bottom
@ -353,7 +340,6 @@ where
.chain(background) .chain(background)
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
}
output_render_elements output_render_elements
} }

View file

@ -18,7 +18,7 @@ use self::window_state::WindowElementState;
pub mod window_state; pub mod window_state;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WindowElement(Window); pub struct WindowElement(Window);
impl Deref for WindowElement { impl Deref for WindowElement {