mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-01 07:57:59 +01:00
Render everything when there's a fullscreen window
And properly handle input and layering this time
This commit is contained in:
parent
485dba69d6
commit
76fc825b51
3 changed files with 130 additions and 142 deletions
150
src/input.rs
150
src/input.rs
|
@ -7,6 +7,7 @@ use std::{collections::HashMap, mem::Discriminant, time::Duration};
|
|||
use crate::{
|
||||
focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget},
|
||||
state::WithState,
|
||||
window::WindowElement,
|
||||
};
|
||||
use pinnacle_api_defs::pinnacle::input::v0alpha1::{
|
||||
set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse,
|
||||
|
@ -181,87 +182,88 @@ impl State {
|
|||
.output_geometry(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
|
||||
.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
|
||||
.element_location(&window)
|
||||
.expect("called elem loc on unmapped win")
|
||||
- window.geometry().loc;
|
||||
|
||||
window
|
||||
.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
|
||||
.map(|(surf, surf_loc)| (PointerFocusTarget::WlSurface(surf), surf_loc + 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)| {
|
||||
(
|
||||
PointerFocusTarget::WlSurface(surf),
|
||||
surf_loc + layer_loc + output_geo.loc,
|
||||
)
|
||||
})
|
||||
} else if let Some((surface, loc)) = self
|
||||
for (i, win) in self
|
||||
.space
|
||||
.elements()
|
||||
.rev()
|
||||
.filter(|win| win.is_on_active_tag())
|
||||
.find_map(|win| {
|
||||
let loc = self
|
||||
.space
|
||||
.element_location(win)
|
||||
.expect("called elem loc on unmapped win")
|
||||
- win.geometry().loc;
|
||||
|
||||
win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
|
||||
.map(|(surf, surf_loc)| (surf, surf_loc + loc))
|
||||
})
|
||||
.enumerate()
|
||||
{
|
||||
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)| {
|
||||
(
|
||||
PointerFocusTarget::WlSurface(surf),
|
||||
surf_loc + layer_loc + output_geo.loc,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
if win.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||
fullscreen_and_up_split_at = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
let layer_under =
|
||||
|layers: &[wlr_layer::Layer]| -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
|
||||
let layer_map = layer_map_for_output(output);
|
||||
let layer = layers
|
||||
.iter()
|
||||
.find_map(|layer| layer_map.layer_under(*layer, point))?;
|
||||
|
||||
let layer_loc = layer_map.layer_geometry(layer)?.loc;
|
||||
|
||||
layer
|
||||
.surface_under(
|
||||
point - layer_loc.to_f64() - output_geo.loc.to_f64(),
|
||||
WindowSurfaceType::ALL,
|
||||
)
|
||||
.map(|(surf, surf_loc)| {
|
||||
(
|
||||
PointerFocusTarget::WlSurface(surf),
|
||||
surf_loc + layer_loc + output_geo.loc,
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
let window_under =
|
||||
|windows: &[WindowElement]| -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
|
||||
windows.iter().find_map(|win| {
|
||||
let loc = self
|
||||
.space
|
||||
.element_location(win)
|
||||
.expect("called elem loc on unmapped win")
|
||||
- win.geometry().loc;
|
||||
|
||||
win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
|
||||
.map(|(surf, surf_loc)| {
|
||||
(PointerFocusTarget::WlSurface(surf), surf_loc + 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<_>>(),
|
||||
)
|
||||
})
|
||||
.or_else(|| layer_under(&[wlr_layer::Layer::Bottom, wlr_layer::Layer::Background]))
|
||||
}
|
||||
|
||||
/// Update the pointer focus if it's different from the previous one.
|
||||
|
|
120
src/render.rs
120
src/render.rs
|
@ -22,10 +22,7 @@ use smithay::{
|
|||
},
|
||||
input::pointer::{CursorImageAttributes, CursorImageStatus},
|
||||
output::Output,
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
wayland_server::protocol::wl_surface::WlSurface,
|
||||
},
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
render_elements,
|
||||
utils::{Logical, Physical, Point, Scale},
|
||||
wayland::{compositor, shell::wlr_layer},
|
||||
|
@ -129,22 +126,38 @@ where
|
|||
}
|
||||
|
||||
/// 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,
|
||||
windows: &[WindowElement],
|
||||
space: &Space<WindowElement>,
|
||||
renderer: &mut R,
|
||||
scale: Scale<f64>,
|
||||
) -> Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>
|
||||
) -> (
|
||||
Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>,
|
||||
Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>,
|
||||
)
|
||||
where
|
||||
R: Renderer + ImportAll + ImportMem,
|
||||
<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()
|
||||
.rev() // rev because I treat the focus stack backwards vs how the renderer orders it
|
||||
.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
|
||||
let loc = (
|
||||
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)
|
||||
}).flat_map(|(elems, rect)| {
|
||||
}).map(|(elems, rect)| {
|
||||
// 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
|
||||
// external decorations.
|
||||
|
@ -171,10 +184,15 @@ where
|
|||
},
|
||||
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>(
|
||||
|
@ -293,67 +311,35 @@ where
|
|||
// | base it on if it's a descendant or not
|
||||
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
|
||||
}
|
||||
};
|
||||
let LayerRenderElements {
|
||||
background,
|
||||
bottom,
|
||||
top,
|
||||
overlay,
|
||||
} = layer_render_elements(output, renderer, scale);
|
||||
|
||||
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
|
||||
});
|
||||
let (fullscreen_and_up_elements, rest_of_window_elements) =
|
||||
window_render_elements::<R>(output, &windows, space, renderer, scale);
|
||||
|
||||
// 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);
|
||||
// Elements render from top to bottom
|
||||
|
||||
output_render_elements.extend(
|
||||
window_render_elements
|
||||
.into_iter()
|
||||
.map(OutputRenderElements::from),
|
||||
);
|
||||
} else {
|
||||
let LayerRenderElements {
|
||||
background,
|
||||
bottom,
|
||||
top,
|
||||
overlay,
|
||||
} = layer_render_elements(output, renderer, scale);
|
||||
output_render_elements.extend(fullscreen_and_up_elements);
|
||||
|
||||
let window_render_elements =
|
||||
tag_render_elements::<R>(output, &windows, space, renderer, scale);
|
||||
output_render_elements.extend(
|
||||
overlay
|
||||
.into_iter()
|
||||
.chain(top)
|
||||
.map(OutputRenderElements::from),
|
||||
);
|
||||
|
||||
// Elements render from top to bottom
|
||||
output_render_elements.extend(rest_of_window_elements);
|
||||
|
||||
output_render_elements.extend(
|
||||
overlay
|
||||
.into_iter()
|
||||
.chain(top)
|
||||
.map(OutputRenderElements::from),
|
||||
);
|
||||
|
||||
output_render_elements.extend(window_render_elements);
|
||||
|
||||
output_render_elements.extend(
|
||||
bottom
|
||||
.into_iter()
|
||||
.chain(background)
|
||||
.map(OutputRenderElements::from),
|
||||
);
|
||||
}
|
||||
output_render_elements.extend(
|
||||
bottom
|
||||
.into_iter()
|
||||
.chain(background)
|
||||
.map(OutputRenderElements::from),
|
||||
);
|
||||
|
||||
output_render_elements
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use self::window_state::WindowElementState;
|
|||
|
||||
pub mod window_state;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct WindowElement(Window);
|
||||
|
||||
impl Deref for WindowElement {
|
||||
|
|
Loading…
Add table
Reference in a new issue