From 3963f537a4182dbcd8e1e2f262ee105473facc56 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Tue, 19 Mar 2024 14:41:17 +0400 Subject: Wrap mapped windows in a Mapped --- src/window/mapped.rs | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/window/mod.rs | 3 + 2 files changed, 162 insertions(+) create mode 100644 src/window/mapped.rs (limited to 'src/window') diff --git a/src/window/mapped.rs b/src/window/mapped.rs new file mode 100644 index 00000000..4476dede --- /dev/null +++ b/src/window/mapped.rs @@ -0,0 +1,159 @@ +use smithay::backend::renderer::element::{AsRenderElements as _, Id}; +use smithay::desktop::space::SpaceElement as _; +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, Scale, Size, Transform}; +use smithay::wayland::compositor::{send_surface_state, with_states}; +use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; + +use super::ResolvedWindowRules; +use crate::layout::{LayoutElement, LayoutElementRenderElement}; +use crate::niri::WindowOffscreenId; +use crate::render_helpers::renderer::NiriRenderer; + +#[derive(Debug)] +pub struct Mapped { + pub window: Window, + + /// Up-to-date rules. + pub rules: ResolvedWindowRules, +} + +impl Mapped { + pub fn new(window: Window, rules: ResolvedWindowRules) -> Self { + Self { window, rules } + } + + pub fn toplevel(&self) -> &ToplevelSurface { + self.window.toplevel().expect("no X11 support") + } +} + +impl LayoutElement for Mapped { + type Id = Window; + + fn id(&self) -> &Self::Id { + &self.window + } + + fn size(&self) -> Size { + self.window.geometry().size + } + + fn buf_loc(&self) -> Point { + Point::from((0, 0)) - self.window.geometry().loc + } + + fn is_in_input_region(&self, point: Point) -> bool { + let surface_local = point + self.window.geometry().loc.to_f64(); + self.window.is_in_input_region(&surface_local) + } + + fn render( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + ) -> Vec> { + let buf_pos = location - self.window.geometry().loc; + self.window.render_elements( + renderer, + buf_pos.to_physical_precise_round(scale), + scale, + 1., + ) + } + + fn request_size(&self, size: Size) { + self.toplevel().with_pending_state(|state| { + state.size = Some(size); + state.states.unset(xdg_toplevel::State::Fullscreen); + }); + } + + fn request_fullscreen(&self, size: Size) { + self.toplevel().with_pending_state(|state| { + state.size = Some(size); + state.states.set(xdg_toplevel::State::Fullscreen); + }); + } + + fn min_size(&self) -> Size { + with_states(self.toplevel().wl_surface(), |state| { + let curr = state.cached_state.current::(); + curr.min_size + }) + } + + fn max_size(&self) -> Size { + with_states(self.toplevel().wl_surface(), |state| { + let curr = state.cached_state.current::(); + curr.max_size + }) + } + + fn is_wl_surface(&self, wl_surface: &WlSurface) -> bool { + self.toplevel().wl_surface() == wl_surface + } + + fn set_preferred_scale_transform(&self, scale: i32, transform: Transform) { + self.window.with_surfaces(|surface, data| { + send_surface_state(surface, data, scale, transform); + }); + } + + fn has_ssd(&self) -> bool { + self.toplevel().current_state().decoration_mode + == Some(zxdg_toplevel_decoration_v1::Mode::ServerSide) + } + + fn output_enter(&self, output: &Output) { + let overlap = Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX)); + self.window.output_enter(output, overlap) + } + + fn output_leave(&self, output: &Output) { + self.window.output_leave(output) + } + + fn set_offscreen_element_id(&self, id: Option) { + let data = self + .window + .user_data() + .get_or_insert(WindowOffscreenId::default); + data.0.replace(id); + } + + fn set_activated(&self, active: bool) { + self.window.set_activated(active); + } + + fn set_bounds(&self, bounds: Size) { + self.toplevel().with_pending_state(|state| { + state.bounds = Some(bounds); + }); + } + + fn send_pending_configure(&self) { + self.toplevel().send_pending_configure(); + } + + fn is_fullscreen(&self) -> bool { + self.toplevel() + .current_state() + .states + .contains(xdg_toplevel::State::Fullscreen) + } + + fn is_pending_fullscreen(&self) -> bool { + self.toplevel() + .with_pending_state(|state| state.states.contains(xdg_toplevel::State::Fullscreen)) + } + + fn refresh(&self) { + self.window.refresh(); + } +} diff --git a/src/window/mod.rs b/src/window/mod.rs index fd494b42..124a62f3 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -1,5 +1,8 @@ use crate::layout::workspace::ColumnWidth; +pub mod mapped; +pub use mapped::Mapped; + pub mod unmapped; pub use unmapped::{InitialConfigureState, Unmapped}; -- cgit