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::{
|
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,87 +182,88 @@ 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
|
|
||||||
.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
|
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
.rev()
|
.rev()
|
||||||
.filter(|win| win.is_on_active_tag())
|
.filter(|win| win.is_on_active_tag())
|
||||||
.find_map(|win| {
|
.enumerate()
|
||||||
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))
|
|
||||||
})
|
|
||||||
{
|
{
|
||||||
Some((PointerFocusTarget::WlSurface(surface), loc))
|
if win.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||||
} else if let (Some(layer), _) | (None, Some(layer)) = (
|
fullscreen_and_up_split_at = i + 1;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
/// 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},
|
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,67 +311,35 @@ 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 LayerRenderElements {
|
||||||
let is_wayland_actually_fullscreen = {
|
background,
|
||||||
if let Some(toplevel) = win.toplevel() {
|
bottom,
|
||||||
toplevel
|
top,
|
||||||
.current_state()
|
overlay,
|
||||||
.states
|
} = layer_render_elements(output, renderer, scale);
|
||||||
.contains(xdg_toplevel::State::Fullscreen)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
win.with_state(|state| {
|
let (fullscreen_and_up_elements, rest_of_window_elements) =
|
||||||
state.fullscreen_or_maximized.is_fullscreen()
|
window_render_elements::<R>(output, &windows, space, renderer, scale);
|
||||||
&& 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
|
// Elements render from top to bottom
|
||||||
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(
|
output_render_elements.extend(fullscreen_and_up_elements);
|
||||||
window_render_elements
|
|
||||||
.into_iter()
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let LayerRenderElements {
|
|
||||||
background,
|
|
||||||
bottom,
|
|
||||||
top,
|
|
||||||
overlay,
|
|
||||||
} = layer_render_elements(output, renderer, scale);
|
|
||||||
|
|
||||||
let window_render_elements =
|
output_render_elements.extend(
|
||||||
tag_render_elements::<R>(output, &windows, space, renderer, scale);
|
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(
|
output_render_elements.extend(
|
||||||
overlay
|
bottom
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(top)
|
.chain(background)
|
||||||
.map(OutputRenderElements::from),
|
.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
|
output_render_elements
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue