Make LayoutElement more visual-geometry-based

This commit is contained in:
Ivan Molodetskikh
2023-12-26 17:38:40 +04:00
parent 77b4715e0b
commit bfc2418267
2 changed files with 91 additions and 44 deletions
+76 -9
View File
@@ -33,19 +33,23 @@ use std::mem;
use std::rc::Rc;
use std::time::Duration;
use smithay::backend::renderer::element::AsRenderElements;
use smithay::backend::renderer::{ImportAll, Renderer};
use smithay::desktop::space::SpaceElement;
use smithay::desktop::Window;
use smithay::output::Output;
use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::utils::{Logical, Point, Rectangle, Size, Transform};
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
use smithay::wayland::compositor::{send_surface_state, with_states};
use smithay::wayland::shell::xdg::SurfaceCachedState;
pub use self::monitor::MonitorRenderElement;
use self::monitor::{Monitor, WorkspaceSwitch, WorkspaceSwitchGesture};
use self::workspace::{compute_working_area, ColumnWidth, OutputId, Workspace};
use self::workspace::{
compute_working_area, ColumnWidth, OutputId, Workspace, WorkspaceRenderElement,
};
use crate::animation::Animation;
use crate::config::{self, Config, SizeChange, Struts};
use crate::utils::output_size;
@@ -55,8 +59,35 @@ mod monitor;
mod workspace;
pub trait LayoutElement: PartialEq {
fn geometry(&self) -> Rectangle<i32, Logical>;
/// Visual size of the element.
///
/// This is what the user would consider the size, i.e. excluding CSD shadows and whatnot.
/// Corresponds to the Wayland window geometry size.
fn size(&self) -> Size<i32, Logical>;
/// Returns the location of the element's buffer relative to the element's visual geometry.
///
/// I.e. if the element has CSD shadows, its buffer location will have negative coordinates.
fn buf_loc(&self) -> Point<i32, Logical>;
/// Checks whether a point is in the element's input region.
///
/// The point is relative to the element's visual geometry.
fn is_in_input_region(&self, point: Point<f64, Logical>) -> bool;
/// Renders the element at the given visual location.
///
/// The element should be rendered in such a way that its visual geometry ends up at the given
/// location.
fn render<R: Renderer + ImportAll>(
&self,
renderer: &mut R,
location: Point<i32, Logical>,
scale: Scale<f64>,
) -> Vec<WorkspaceRenderElement<R>>
where
<R as Renderer>::TextureId: 'static;
fn request_size(&self, size: Size<i32, Logical>);
fn request_fullscreen(&self, size: Size<i32, Logical>);
fn min_size(&self) -> Size<i32, Logical>;
@@ -156,12 +187,35 @@ impl Options {
}
impl LayoutElement for Window {
fn geometry(&self) -> Rectangle<i32, Logical> {
SpaceElement::geometry(self)
fn size(&self) -> Size<i32, Logical> {
self.geometry().size
}
fn buf_loc(&self) -> Point<i32, Logical> {
Point::from((0, 0)) - self.geometry().loc
}
fn is_in_input_region(&self, point: Point<f64, Logical>) -> bool {
SpaceElement::is_in_input_region(self, &point)
let surace_local = point + self.geometry().loc.to_f64();
SpaceElement::is_in_input_region(self, &surace_local)
}
fn render<R: Renderer + ImportAll>(
&self,
renderer: &mut R,
location: Point<i32, Logical>,
scale: Scale<f64>,
) -> Vec<WorkspaceRenderElement<R>>
where
<R as Renderer>::TextureId: 'static,
{
let buf_pos = location - self.geometry().loc;
self.render_elements(
renderer,
buf_pos.to_physical_precise_round(scale),
scale,
1.,
)
}
fn request_size(&self, size: Size<i32, Logical>) {
@@ -394,7 +448,7 @@ impl<W: LayoutElement> Layout<W> {
) -> Option<&Output> {
let width = width
.or(self.options.default_width)
.unwrap_or_else(|| ColumnWidth::Fixed(window.geometry().size.w));
.unwrap_or_else(|| ColumnWidth::Fixed(window.size().w));
match &mut self.monitor_set {
MonitorSet::Normal {
@@ -1356,14 +1410,27 @@ mod tests {
}
impl LayoutElement for TestWindow {
fn geometry(&self) -> Rectangle<i32, Logical> {
self.0.bbox.get()
fn size(&self) -> Size<i32, Logical> {
self.0.bbox.get().size
}
fn buf_loc(&self) -> Point<i32, Logical> {
(0, 0).into()
}
fn is_in_input_region(&self, _point: Point<f64, Logical>) -> bool {
false
}
fn render<R: Renderer + ImportAll>(
&self,
_renderer: &mut R,
_location: Point<i32, Logical>,
_scale: Scale<f64>,
) -> Vec<WorkspaceRenderElement<R>> {
vec![]
}
fn request_size(&self, size: Size<i32, Logical>) {
self.0.requested_size.set(Some(size));
}
+15 -35
View File
@@ -4,7 +4,6 @@ use std::rc::Rc;
use std::time::Duration;
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
use smithay::backend::renderer::element::AsRenderElements;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::ImportAll;
use smithay::desktop::space::SpaceElement;
@@ -236,7 +235,7 @@ impl<W: LayoutElement> Workspace<W> {
if !self.columns.is_empty() {
let col = &self.columns[self.active_column_idx];
let active_win = &col.windows[col.active_window_idx];
let geom = active_win.geometry();
let size = active_win.size();
let has_ssd = active_win.has_ssd();
let win_pos = Point::from((
@@ -244,7 +243,7 @@ impl<W: LayoutElement> Workspace<W> {
col.window_y(col.active_window_idx),
));
self.focus_ring.update(win_pos, geom.size, has_ssd);
self.focus_ring.update(win_pos, size, has_ssd);
self.focus_ring.set_active(is_active);
}
}
@@ -742,13 +741,12 @@ impl<W: LayoutElement> Workspace<W> {
// Prefer the active window since it's drawn on top.
let col = &self.columns[self.active_column_idx];
let active_win = &col.windows[col.active_window_idx];
let geom = active_win.geometry();
let buf_pos = Point::from((
let win_pos = Point::from((
self.column_x(self.active_column_idx) - view_pos,
col.window_y(col.active_window_idx),
)) - geom.loc;
if active_win.is_in_input_region(pos - buf_pos.to_f64()) {
return Some((active_win, buf_pos));
));
if active_win.is_in_input_region(pos - win_pos.to_f64()) {
return Some((active_win, win_pos + active_win.buf_loc()));
}
let mut x = -view_pos;
@@ -759,10 +757,9 @@ impl<W: LayoutElement> Workspace<W> {
continue;
}
let geom = win.geometry();
let buf_pos = Point::from((x, y)) - geom.loc;
if win.is_in_input_region(pos - buf_pos.to_f64()) {
return Some((win, buf_pos));
let win_pos = Point::from((x, y));
if win.is_in_input_region(pos - win_pos.to_f64()) {
return Some((win, win_pos + win.buf_loc()));
}
}
@@ -917,14 +914,7 @@ impl Workspace<Window> {
));
// Draw the window itself.
let geom = active_win.geometry();
let buf_pos = win_pos - geom.loc;
rv.extend(active_win.render_elements(
renderer,
buf_pos.to_physical_precise_round(output_scale),
output_scale,
1.,
));
rv.extend(active_win.render(renderer, win_pos, output_scale));
// Draw the focus ring.
rv.extend(self.focus_ring.render(output_scale).map(Into::into));
@@ -937,14 +927,8 @@ impl Workspace<Window> {
continue;
}
let geom = win.geometry();
let buf_pos = Point::from((x, y)) - geom.loc;
rv.extend(win.render_elements(
renderer,
buf_pos.to_physical_precise_round(output_scale),
output_scale,
1.,
));
let win_pos = Point::from((x, y));
rv.extend(win.render(renderer, win_pos, output_scale));
}
x += col.width() + self.options.gaps;
@@ -1189,11 +1173,7 @@ impl<W: LayoutElement> Column<W> {
}
fn width(&self) -> i32 {
self.windows
.iter()
.map(|win| win.geometry().size.w)
.max()
.unwrap()
self.windows.iter().map(|win| win.size().w).max().unwrap()
}
fn focus_up(&mut self) {
@@ -1312,7 +1292,7 @@ impl<W: LayoutElement> Column<W> {
fn set_window_height(&mut self, change: SizeChange) {
let current = self.heights[self.active_window_idx];
let current_px = match current {
WindowHeight::Auto => self.windows[self.active_window_idx].geometry().size.h,
WindowHeight::Auto => self.windows[self.active_window_idx].size().h,
WindowHeight::Fixed(height) => height,
};
let current_prop = (current_px + self.options.gaps) as f64
@@ -1372,7 +1352,7 @@ impl<W: LayoutElement> Column<W> {
self.windows.iter().map(move |win| {
let pos = y;
y += win.geometry().size.h + self.options.gaps;
y += win.size().h + self.options.gaps;
pos
})
}