smithay 0.7.0

Smithay is a library for writing wayland compositors.
Documentation
use crate::{
    backend::renderer::{
        element::{
            surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
            AsRenderElements, Kind,
        },
        ImportAll, Renderer,
    },
    desktop::{space::SpaceElement, PopupManager, Window, WindowSurface, WindowSurfaceType},
    output::Output,
    utils::{Logical, Physical, Point, Rectangle, Scale},
    wayland::seat::WaylandFocus,
};

use super::{output_update, WindowOutputUserData};

impl SpaceElement for Window {
    fn geometry(&self) -> Rectangle<i32, Logical> {
        self.geometry()
    }

    fn bbox(&self) -> Rectangle<i32, Logical> {
        self.bbox_with_popups()
    }

    fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
        self.surface_under(*point, WindowSurfaceType::ALL).is_some()
    }

    fn z_index(&self) -> u8 {
        self.0.z_index.load(std::sync::atomic::Ordering::SeqCst)
    }

    fn set_activate(&self, activated: bool) {
        self.set_activated(activated);
    }

    #[profiling::function]
    fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
        self.user_data().insert_if_missing(WindowOutputUserData::default);
        {
            let mut state = self
                .user_data()
                .get::<WindowOutputUserData>()
                .unwrap()
                .borrow_mut();
            state.output_overlap.insert(output.downgrade(), overlap);
            state.output_overlap.retain(|weak, _| weak.is_alive());
        }
        self.refresh()
    }

    #[profiling::function]
    fn output_leave(&self, output: &Output) {
        if let Some(state) = self.user_data().get::<WindowOutputUserData>() {
            state.borrow_mut().output_overlap.retain(|weak, _| weak != output);
        }

        if let Some(surface) = self.wl_surface() {
            output_update(output, None, &surface);
            for (popup, _) in PopupManager::popups_for_surface(&surface) {
                output_update(output, None, popup.wl_surface());
            }
        }
    }

    #[profiling::function]
    fn refresh(&self) {
        self.user_data().insert_if_missing(WindowOutputUserData::default);
        let state = self.user_data().get::<WindowOutputUserData>().unwrap().borrow();

        if let Some(surface) = self.wl_surface() {
            for (weak, overlap) in state.output_overlap.iter() {
                if let Some(output) = weak.upgrade() {
                    output_update(&output, Some(*overlap), &surface);
                    for (popup, location) in PopupManager::popups_for_surface(&surface) {
                        let mut overlap = *overlap;
                        overlap.loc -= location;
                        output_update(&output, Some(overlap), popup.wl_surface());
                    }
                }
            }
        }
    }
}

impl<R> AsRenderElements<R> for Window
where
    R: Renderer + ImportAll,
    R::TextureId: Clone + 'static,
{
    type RenderElement = WaylandSurfaceRenderElement<R>;

    #[profiling::function]
    fn render_elements<C: From<WaylandSurfaceRenderElement<R>>>(
        &self,
        renderer: &mut R,
        location: Point<i32, Physical>,
        scale: Scale<f64>,
        alpha: f32,
    ) -> Vec<C> {
        match self.underlying_surface() {
            WindowSurface::Wayland(s) => {
                let mut render_elements: Vec<C> = Vec::new();
                let surface = s.wl_surface();
                let popup_render_elements =
                    PopupManager::popups_for_surface(surface).flat_map(|(popup, popup_offset)| {
                        let offset = (self.geometry().loc + popup_offset - popup.geometry().loc)
                            .to_physical_precise_round(scale);

                        render_elements_from_surface_tree(
                            renderer,
                            popup.wl_surface(),
                            location + offset,
                            scale,
                            alpha,
                            Kind::Unspecified,
                        )
                    });

                render_elements.extend(popup_render_elements);

                render_elements.extend(render_elements_from_surface_tree(
                    renderer,
                    surface,
                    location,
                    scale,
                    alpha,
                    Kind::Unspecified,
                ));

                render_elements
            }
            #[cfg(feature = "xwayland")]
            WindowSurface::X11(s) => AsRenderElements::render_elements(s, renderer, location, scale, alpha),
        }
    }
}