smithay 0.7.0

Smithay is a library for writing wayland compositors.
Documentation
use std::borrow::Cow;

use wayland_server::protocol::wl_surface::WlSurface;

use crate::{
    backend::renderer::{
        element::{
            surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
            Kind,
        },
        ImportAll, Renderer,
    },
    desktop::{space::SpaceElement, utils::under_from_surface_tree, WindowSurfaceType},
    utils::{Logical, Physical, Point, Rectangle, Scale},
    wayland::seat::WaylandFocus,
    xwayland::X11Surface,
};

use super::{output_update, WindowOutputUserData};

impl WaylandFocus for X11Surface {
    #[inline]
    fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
        self.state.lock().unwrap().wl_surface.clone().map(Cow::Owned)
    }
}

impl SpaceElement for X11Surface {
    fn bbox(&self) -> Rectangle<i32, Logical> {
        let geo = X11Surface::geometry(self);
        Rectangle::from_size(geo.size)
    }

    fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
        let state = self.state.lock().unwrap();
        if let Some(surface) = state.wl_surface.as_ref() {
            under_from_surface_tree(surface, *point, (0, 0), WindowSurfaceType::ALL).is_some()
        } else {
            false
        }
    }

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

    fn output_enter(&self, output: &crate::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()
    }

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

        let state = self.state.lock().unwrap();
        let Some(surface) = state.wl_surface.as_ref() else {
            return;
        };
        output_update(output, None, surface);
    }

    fn refresh(&self) {
        self.user_data().insert_if_missing(WindowOutputUserData::default);
        let wo_state = self.user_data().get::<WindowOutputUserData>().unwrap().borrow();

        let state = self.state.lock().unwrap();
        let Some(surface) = state.wl_surface.as_ref() else {
            return;
        };
        for (weak, overlap) in wo_state.output_overlap.iter() {
            if let Some(output) = weak.upgrade() {
                output_update(&output, Some(*overlap), surface);
            }
        }
    }

    fn z_index(&self) -> u8 {
        if self.is_override_redirect() {
            crate::desktop::space::RenderZindex::Overlay as u8
        } else {
            crate::desktop::space::RenderZindex::Shell as u8
        }
    }
}

impl<R> crate::backend::renderer::element::AsRenderElements<R> for X11Surface
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> {
        let state = self.state.lock().unwrap();
        let Some(surface) = state.wl_surface.as_ref() else {
            return Vec::new();
        };
        render_elements_from_surface_tree(renderer, surface, location, scale, alpha, Kind::Unspecified)
    }
}