<NME> shell.rs
<BEF> use std::cell::RefCell;

use smithay::{
    backend::renderer::utils::on_commit_buffer_handler,
    desktop::{
        find_popup_root_surface, layer_map_for_output, Kind as SurfaceKind, LayerSurface, PopupKeyboardGrab,
        PopupKind, PopupManager, PopupPointerGrab, PopupUngrabStrategy, Space, Window, WindowSurfaceType,
    },
    input::{
        pointer::{
            AxisFrame, ButtonEvent, Focus, GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab,
            PointerInnerHandle,
        },
        Seat,
    },
    output::Output,
    },
    utils::Rectangle,
    wayland::{
        compositor::{compositor_init, BufferAssignment, CompositorToken, RegionAttributes, SurfaceEvent},
        data_device::DnDIconRole,
        seat::{AxisFrame, CursorImageRole, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
        shell::{
        compositor::{
            get_parent, is_sync_subsurface, with_states, with_surface_tree_upward, CompositorHandler,
            CompositorState, TraversalAction,
        },
        seat::WaylandFocus,
                XdgSurfacePendingState, XdgSurfaceRole,
            },
        },
        SERIAL_COUNTER as SCOUNTER,
    },
};

                Configure, PopupSurface, PositionerState, SurfaceCachedState, ToplevelSurface,
                XdgPopupSurfaceData, XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
            },
        },
    },
};

use crate::{
    focus::FocusTarget,
    state::{AnvilState, Backend},
};

struct MoveSurfaceGrab<B: 'static> {
    start_data: PointerGrabStartData<AnvilState<B>>,
    window: Window,
    initial_window_location: Point<i32, Logical>,
}

impl<BackendData> PointerGrab<AnvilState<BackendData>> for MoveSurfaceGrab<BackendData> {
    fn motion(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        _focus: Option<(FocusTarget, Point<i32, Logical>)>,
        event: &MotionEvent,
    ) {
        // While the grab is active, no client has pointer focus
        handle.motion(data, None, event);

        let delta = event.location - self.start_data.location;
        let new_location = self.initial_window_location.to_f64() + delta;

        data.space
            .map_element(self.window.clone(), new_location.to_i32_round(), true);
    }

    fn button(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        event: &ButtonEvent,
    ) {
        handle.button(data, event);
        if handle.current_pressed().is_empty() {
            // No more buttons are pressed, release the grab.
            handle.unset_grab(data, event.serial, event.time);
        }
    }

    fn axis(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        details: AxisFrame,
    ) {
        handle.axis(data, details)
    }

    fn start_data(&self) -> &PointerGrabStartData<AnvilState<BackendData>> {
        &self.start_data
    }
}

bitflags::bitflags! {
    struct ResizeEdge: u32 {
        const NONE = 0;
        const TOP = 1;
        const BOTTOM = 2;
        const LEFT = 4;
        const TOP_LEFT = 5;
        const BOTTOM_LEFT = 6;
        const RIGHT = 8;
        const TOP_RIGHT = 9;
        const BOTTOM_RIGHT = 10;
    }
}

impl From<xdg_toplevel::ResizeEdge> for ResizeEdge {
    #[inline]
    fn from(x: xdg_toplevel::ResizeEdge) -> Self {
        Self::from_bits(x as u32).unwrap()
    }
}

impl From<ResizeEdge> for xdg_toplevel::ResizeEdge {
    #[inline]
    fn from(x: ResizeEdge) -> Self {
        use std::convert::TryFrom;

        Self::try_from(x.bits()).unwrap()
    }
}

struct ResizeSurfaceGrab<B: 'static> {
    start_data: PointerGrabStartData<AnvilState<B>>,
    window: Window,
    edges: ResizeEdge,
    initial_window_location: Point<i32, Logical>,
    initial_window_size: Size<i32, Logical>,
    last_window_size: Size<i32, Logical>,
}

impl<BackendData> PointerGrab<AnvilState<BackendData>> for ResizeSurfaceGrab<BackendData> {
    fn motion(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        _focus: Option<(FocusTarget, Point<i32, Logical>)>,
        event: &MotionEvent,
    ) {
        // While the grab is active, no client has pointer focus
        handle.motion(data, None, event);

        // It is impossible to get `min_size` and `max_size` of dead toplevel, so we return early.
        if !self.window.toplevel().alive() {
            handle.unset_grab(data, event.serial, event.time);
            return;
        }

        let (mut dx, mut dy) = (event.location - self.start_data.location).into();

        let mut new_window_width = self.initial_window_size.w;
        let mut new_window_height = self.initial_window_size.h;

        let left_right = ResizeEdge::LEFT | ResizeEdge::RIGHT;
        let top_bottom = ResizeEdge::TOP | ResizeEdge::BOTTOM;

        if self.edges.intersects(left_right) {
            if self.edges.intersects(ResizeEdge::LEFT) {
                dx = -dx;
            }

            new_window_width = (self.initial_window_size.w as f64 + dx) as i32;
        }

        if self.edges.intersects(top_bottom) {
            if self.edges.intersects(ResizeEdge::TOP) {
                dy = -dy;
            }

            new_window_height = (self.initial_window_size.h as f64 + dy) as i32;
        }

        let (min_size, max_size) = with_states(self.window.toplevel().wl_surface(), |states| {
            let data = states.cached_state.current::<SurfaceCachedState>();
            (data.min_size, data.max_size)
        });

        let min_width = min_size.w.max(1);
        let min_height = min_size.h.max(1);
        let max_width = if max_size.w == 0 {
            i32::max_value()
        } else {
            max_size.w
        };
        let max_height = if max_size.h == 0 {
            i32::max_value()
        } else {
            max_size.h
        };

        new_window_width = new_window_width.max(min_width).min(max_width);
        new_window_height = new_window_height.max(min_height).min(max_height);

        self.last_window_size = (new_window_width, new_window_height).into();

        match &self.window.toplevel() {
            SurfaceKind::Xdg(xdg) => {
                xdg.with_pending_state(|state| {
                    state.states.set(xdg_toplevel::State::Resizing);
                    state.size = Some(self.last_window_size);
                });
                xdg.send_configure();
            }
            #[cfg(feature = "xwayland")]
            SurfaceKind::X11(_) => {
                // TODO: What to do here? Send the update via X11?
            }
        }
    }

    fn button(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        event: &ButtonEvent,
    ) {
        handle.button(data, event);
        if handle.current_pressed().is_empty() {
            // No more buttons are pressed, release the grab.
            handle.unset_grab(data, event.serial, event.time);

            // If toplevel is dead, we can't resize it, so we return early.
            if !self.window.toplevel().alive() {
                return;
            }

            #[cfg_attr(not(feature = "xwayland"), allow(irrefutable_let_patterns))]
            if let SurfaceKind::Xdg(xdg) = &self.window.toplevel() {
                xdg.with_pending_state(|state| {
                    state.states.unset(xdg_toplevel::State::Resizing);
                    state.size = Some(self.last_window_size);
                });
                xdg.send_configure();
                if self.edges.intersects(ResizeEdge::TOP_LEFT) {
                    let geometry = self.window.geometry();
                    let mut location = data.space.element_location(&self.window).unwrap();

                    if self.edges.intersects(ResizeEdge::LEFT) {
                        location.x =
                            self.initial_window_location.x + (self.initial_window_size.w - geometry.size.w);
                    }
                    if self.edges.intersects(ResizeEdge::TOP) {
                        location.y =
                            self.initial_window_location.y + (self.initial_window_size.h - geometry.size.h);
                    }

                    data.space.map_element(self.window.clone(), location, true);
                }

                with_states(self.window.toplevel().wl_surface(), |states| {
                    let mut data = states
                        .data_map
                        .get::<RefCell<SurfaceData>>()
                        .unwrap()
                        .borrow_mut();
                    if let ResizeState::Resizing(resize_data) = data.resize_state {
                        data.resize_state = ResizeState::WaitingForFinalAck(resize_data, event.serial);
                    } else {
                        panic!("invalid resize state: {:?}", data.resize_state);
                    }
                });
            } else {
                with_states(self.window.toplevel().wl_surface(), |states| {
                    let mut data = states
                        .data_map
                        .get::<RefCell<SurfaceData>>()
                        .unwrap()
                        .borrow_mut();
                    if let ResizeState::Resizing(resize_data) = data.resize_state {
                        data.resize_state = ResizeState::WaitingForCommit(resize_data);
                    } else {
                        panic!("invalid resize state: {:?}", data.resize_state);
                    }
                });
            }
        }
    }

    fn axis(
        &mut self,
        data: &mut AnvilState<BackendData>,
        handle: &mut PointerInnerHandle<'_, AnvilState<BackendData>>,
        details: AxisFrame,
    ) {
        handle.axis(data, details)
    }

    fn start_data(&self) -> &PointerGrabStartData<AnvilState<BackendData>> {
        &self.start_data
    }
}

fn fullscreen_output_geometry(
    wl_surface: &WlSurface,
    wl_output: Option<&wl_output::WlOutput>,
    space: &mut Space<Window>,
) -> Option<Rectangle<i32, Logical>> {
    // First test if a specific output has been requested
    // if the requested output is not found ignore the request
    wl_output
        .and_then(Output::from_resource)
        .or_else(|| {
            let w = space
                .elements()
                .find(|window| window.toplevel().wl_surface() == wl_surface)
                .cloned();
            w.and_then(|w| space.outputs_for_element(&w).get(0).cloned())
        })
        .and_then(|o| space.output_geometry(&o))
}

#[derive(Default)]
pub struct FullscreenSurface(RefCell<Option<Window>>);

impl FullscreenSurface {
    pub fn set(&self, window: Window) {
        *self.0.borrow_mut() = Some(window);
    }

    pub fn get(&self) -> Option<Window> {
        self.0.borrow().clone()
    }

    pub fn clear(&self) -> Option<Window> {
        self.0.borrow_mut().take()
    }
}

impl<BackendData> BufferHandler for AnvilState<BackendData> {
    fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {}
}

impl<BackendData: Backend> CompositorHandler for AnvilState<BackendData> {
    fn compositor_state(&mut self) -> &mut CompositorState {
        &mut self.compositor_state
    }
    fn commit(&mut self, surface: &WlSurface) {
        on_commit_buffer_handler(surface);
        self.backend_data.early_import(surface);

        #[cfg(feature = "xwayland")]
        if let Some(x11) = self.x11_state.as_mut() {
            super::xwayland::commit_hook(surface, &self.display_handle, x11, &mut self.space);
        }

        if !is_sync_subsurface(surface) {
            let mut root = surface.clone();
            while let Some(parent) = get_parent(&root) {
                root = parent;
            }
            if let Some(window) = self.window_for_surface(&root) {
                window.on_commit();
            }
        }
        self.popups.commit(surface);

        ensure_initial_configure(surface, &self.space, &mut self.popups)
    }
}

impl<BackendData: Backend> XdgShellHandler for AnvilState<BackendData> {
    fn xdg_shell_state(&mut self) -> &mut XdgShellState {
        &mut self.xdg_shell_state
    }

    fn new_toplevel(&mut self, surface: ToplevelSurface) {
        // Do not send a configure here, the initial configure
        // of a xdg_surface has to be sent during the commit if
        // the surface is not already configured
        let window = Window::new(SurfaceKind::Xdg(surface));
        place_new_window(&mut self.space, &window, true);
    }

    fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {
        // Do not send a configure here, the initial configure
        // of a xdg_surface has to be sent during the commit if
        // the surface is not already configured

        // TODO: properly recompute the geometry with the whole of positioner state
        surface.with_pending_state(|state| {
            // NOTE: This is not really necessary as the default geometry
            // is already set the same way, but for demonstrating how
            // to set the initial popup geometry this code is left as
            // an example
            state.geometry = positioner.get_geometry();
        });
        if let Err(err) = self.popups.track_popup(PopupKind::from(surface)) {
            slog::warn!(self.log, "Failed to track popup: {}", err);
        }
    }

    fn reposition_request(&mut self, surface: PopupSurface, positioner: PositionerState, token: u32) {
        surface.with_pending_state(|state| {
            // NOTE: This is again a simplification, a proper compositor would
            // calculate the geometry of the popup here. For simplicity we just
            // use the default implementation here that does not take the
            // window position and output constraints into account.
            let geometry = positioner.get_geometry();
            state.geometry = geometry;
            state.positioner = positioner;
        });
        surface.send_repositioned(token);
    }

    fn move_request(&mut self, surface: ToplevelSurface, seat: wl_seat::WlSeat, serial: Serial) {
        let seat: Seat<AnvilState<BackendData>> = Seat::from_resource(&seat).unwrap();
        // TODO: touch move.
        let pointer = seat.get_pointer().unwrap();

        // Check that this surface has a click grab.
        if !pointer.has_grab(serial) {
            return;
        }

        let start_data = pointer.grab_start_data().unwrap();

        let window = self.window_for_surface(surface.wl_surface()).unwrap();

        // If the focus was for a different surface, ignore the request.
        if start_data.focus.is_none()
            || !start_data
                .focus
                .as_ref()
                .unwrap()
                .0
                .same_client_as(&surface.wl_surface().id())
        {
            return;
        }

        let mut initial_window_location = self.space.element_location(&window).unwrap();

        // If surface is maximized then unmaximize it
        let current_state = surface.current_state();
        if current_state.states.contains(xdg_toplevel::State::Maximized) {
            surface.with_pending_state(|state| {
                state.states.unset(xdg_toplevel::State::Maximized);
                state.size = None;
            });

            surface.send_configure();

            // NOTE: In real compositor mouse location should be mapped to a new window size
            // For example, you could:
            // 1) transform mouse pointer position from compositor space to window space (location relative)
            // 2) divide the x coordinate by width of the window to get the percentage
            //   - 0.0 would be on the far left of the window
            //   - 0.5 would be in middle of the window
            //   - 1.0 would be on the far right of the window
            // 3) multiply the percentage by new window width
            // 4) by doing that, drag will look a lot more natural
            //
            // but for anvil needs setting location to pointer location is fine
            let pos = pointer.current_location();
            initial_window_location = (pos.x as i32, pos.y as i32).into();
        }

        let grab = MoveSurfaceGrab {
            start_data,
            window,
            initial_window_location,
        };

        pointer.set_grab(self, grab, serial, Focus::Clear);
    }

    fn resize_request(
        &mut self,
        surface: ToplevelSurface,
        seat: wl_seat::WlSeat,
        serial: Serial,
        edges: xdg_toplevel::ResizeEdge,
    ) {
        let seat: Seat<AnvilState<BackendData>> = Seat::from_resource(&seat).unwrap();
        // TODO: touch resize.
        let pointer = seat.get_pointer().unwrap();

        // Check that this surface has a click grab.
        if !pointer.has_grab(serial) {
            return;
        }

        let start_data = pointer.grab_start_data().unwrap();

        let window = self.window_for_surface(surface.wl_surface()).unwrap();

        // If the focus was for a different surface, ignore the request.
        if start_data.focus.is_none()
            || !start_data
                .focus
                .as_ref()
                .unwrap()
                .0
                .same_client_as(&surface.wl_surface().id())
        {
            return;
        }

        let geometry = window.geometry();
        let loc = self.space.element_location(&window).unwrap();
        let (initial_window_location, initial_window_size) = (loc, geometry.size);

        with_states(surface.wl_surface(), move |states| {
            states
                .data_map
                .get::<RefCell<SurfaceData>>()
                .unwrap()
                .borrow_mut()
                .resize_state = ResizeState::Resizing(ResizeData {
                edges: edges.into(),
                initial_window_location,
                initial_window_size,
            });
        });

        let grab = ResizeSurfaceGrab {
            start_data,
            window,
            edges: edges.into(),
            initial_window_location,
            initial_window_size,
            last_window_size: initial_window_size,
        };

        pointer.set_grab(self, grab, serial, Focus::Clear);
    }

    fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
        if let Configure::Toplevel(configure) = configure {
            if let Some(serial) = with_states(&surface, |states| {
                if let Some(data) = states.data_map.get::<RefCell<SurfaceData>>() {
                    if let ResizeState::WaitingForFinalAck(_, serial) = data.borrow().resize_state {
                        return Some(serial);
                    }
                }

                None
            }) {
                // When the resize grab is released the surface
                // resize state will be set to WaitingForFinalAck
                // and the client will receive a configure request
                // without the resize state to inform the client
                // resizing has finished. Here we will wait for
                // the client to acknowledge the end of the
                // resizing. To check if the surface was resizing
                // before sending the configure we need to use
                // the current state as the received acknowledge
                // will no longer have the resize state set
                let is_resizing = with_states(&surface, |states| {
                    states
                        .data_map
                        .get::<XdgToplevelSurfaceData>()
                        .unwrap()
                        .lock()
                        .unwrap()
                        .current
                        .states
                        .contains(xdg_toplevel::State::Resizing)
                });

                if configure.serial >= serial && is_resizing {
                    with_states(&surface, |states| {
                        let mut data = states
                            .data_map
                            .get::<RefCell<SurfaceData>>()
                            .unwrap()
                            .borrow_mut();
                        if let ResizeState::WaitingForFinalAck(resize_data, _) = data.resize_state {
                            data.resize_state = ResizeState::WaitingForCommit(resize_data);
                        } else {
                            unreachable!()
                        }
                    });
                }
            }
        }
    }

    fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option<wl_output::WlOutput>) {
        // NOTE: This is only one part of the solution. We can set the
        // location and configure size here, but the surface should be rendered fullscreen
        // independently from its buffer size
        let wl_surface = surface.wl_surface();

        let output_geometry = fullscreen_output_geometry(wl_surface, wl_output.as_ref(), &mut self.space);

        if let Some(geometry) = output_geometry {
            let output = wl_output
                .as_ref()
                .and_then(Output::from_resource)
                .unwrap_or_else(|| self.space.outputs().next().unwrap().clone());
            let client = self.display_handle.get_client(wl_surface.id()).unwrap();
            for output in output.client_outputs(&client) {
                wl_output = Some(output);
            }

            surface.with_pending_state(|state| {
                state.states.set(xdg_toplevel::State::Fullscreen);
                state.size = Some(geometry.size);
                state.fullscreen_output = wl_output;
            });

            let window = self
                .space
                .elements()
                .find(|window| window.toplevel().wl_surface() == wl_surface)
                .unwrap();
            window.configure();
            output.user_data().insert_if_missing(FullscreenSurface::default);
            output
                .user_data()
                .get::<FullscreenSurface>()
                .unwrap()
                .set(window.clone());
            slog::trace!(self.log, "Fullscreening: {:?}", window);
        }
    }

    fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
        let ret = surface.with_pending_state(|state| {
            state.states.unset(xdg_toplevel::State::Fullscreen);
            state.size = None;
            state.fullscreen_output.take()
        });
        if let Some(output) = ret {
            let output = Output::from_resource(&output).unwrap();
            if let Some(fullscreen) = output.user_data().get::<FullscreenSurface>() {
                slog::trace!(self.log, "Unfullscreening: {:?}", fullscreen.get());
                fullscreen.clear();
                self.backend_data.reset_buffers(&output);
            }

            surface.send_configure();
    }
}

#[derive(Default)]
pub struct SurfaceData {
    pub buffer: Option<wl_buffer::WlBuffer>,
    pub texture: Option<crate::glium_drawer::TextureMetadata>,
    pub dimensions: Option<(i32, i32)>,
    pub geometry: Option<Rectangle>,
    pub input_region: Option<RegionAttributes>,
    pub resize_state: ResizeState,
    /// Minimum width and height, as requested by the surface.
    ///
        });
        window.configure();
        self.space.map_element(window, geometry.loc, true);
    ///
    /// `0` means unlimited.
    pub max_size: (i32, i32),
    pub frame_callback: Option<wl_callback::WlCallback>,
}

impl SurfaceData {
    /// Returns the size of the surface.
    pub fn size(&self) -> Option<(i32, i32)> {
        self.dimensions
    }

    /// Checks if the surface's input region contains the point.
    fn new_layer_surface(
        &mut self,
        surface: WlrLayerSurface,
        wl_output: Option<wl_output::WlOutput>,
        _layer: Layer,
        namespace: String,
    ) {
        let output = wl_output
            .as_ref()
            .and_then(Output::from_resource)
            .unwrap_or_else(|| self.space.outputs().next().unwrap().clone());
        let mut map = layer_map_for_output(&output);
        map.map_layer(&LayerSurface::new(surface, namespace)).unwrap();
    }
}

impl<BackendData> AnvilState<BackendData> {
    fn window_for_surface(&self, surface: &WlSurface) -> Option<Window> {
        self.space
        }

        // If there's no input region, we're done.
        if self.input_region.is_none() {
            return true;
        }

        self.input_region.as_ref().unwrap().contains(point)
    }

    /// Send the frame callback if it had been requested
    pub fn send_frame(&mut self, serial: u32) {
        if let Some(callback) = self.frame_callback.take() {
            callback.done(serial);
        }
    }

/// State of the resize operation.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ResizeState {
    /// The surface is not being resized.
    NotResizing,
    /// The surface is currently being resized.
    Resizing(ResizeData),
    /// The resize has finished, and the surface needs to ack the final configure.
    WaitingForFinalAck(ResizeData, Serial),
    /// The resize has finished, and the surface needs to commit its final state.
    WaitingForCommit(ResizeData),
}

impl Default for ResizeState {
    fn default() -> Self {
        ResizeState::NotResizing
        geometry = role.window_geometry;
    });

    let refresh = token.with_surface_data(surface, |attributes| {
        attributes
            .user_data
            .insert_if_missing(|| RefCell::new(SurfaceData::default()));
        |_, _, _| TraversalAction::DoChildren(()),
        |_, states, _| {
            states
            .unwrap()
            .borrow_mut();

        data.geometry = geometry;
        data.input_region = attributes.input_region.clone();
        data.min_size = min_size;
        data.max_size = max_size;

                    .unwrap()
        match attributes.buffer.take() {
            Some(BufferAssignment::NewBuffer { buffer, .. }) => {
                // new contents
                // TODO: handle hotspot coordinates
                if let Some(old_buffer) = data.buffer.replace(buffer) {
                    old_buffer.release();
                }
                data.texture = None;
                // If this fails, the buffer will be discarded later by the drawing code.
                data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap());
            }
            Some(BufferAssignment::Removed) => {
                // erase the contents
                if let Some(old_buffer) = data.buffer.take() {
                    old_buffer.release();
                }
                data.texture = None;
                data.dimensions = None;
            }
            None => {}
        }

        // process the frame callback if any
        if let Some(callback) = attributes.frame_callback.take() {
            if let Some(old_callback) = data.frame_callback.take() {
                // fire the old unfired callback to clean it up
                old_callback.done(SCOUNTER.next_serial());
            }
            data.frame_callback = Some(callback);
        }

        window_map.borrow().find(surface)
    });

    if let Some(toplevel) = refresh {
        let mut window_map = window_map.borrow_mut();
        window_map.refresh_toplevel(&toplevel);
    };
}

fn place_new_window(space: &mut Space<Window>, window: &Window, activate: bool) {
    // place the window at a random location on the primary output
    // or if there is not output in a [0;800]x[0;800] square
    use rand::distributions::{Distribution, Uniform};

    let output = space.outputs().next().cloned();
    let output_geometry = output
        .and_then(|o| {
            let geo = space.output_geometry(&o)?;
            let map = layer_map_for_output(&o);
            let zone = map.non_exclusive_zone();
            Some(Rectangle::from_loc_and_size(geo.loc + zone.loc, zone.size))
        })
        .unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800)));

    let max_x = output_geometry.loc.x + (((output_geometry.size.w as f32) / 3.0) * 2.0) as i32;
    let max_y = output_geometry.loc.y + (((output_geometry.size.h as f32) / 3.0) * 2.0) as i32;
    let x_range = Uniform::new(output_geometry.loc.x, max_x);
    let y_range = Uniform::new(output_geometry.loc.y, max_y);
    let mut rng = rand::thread_rng();
    let x = x_range.sample(&mut rng);
    let y = y_range.sample(&mut rng);

    space.map_element(window.clone(), (x, y), activate);
}

pub fn fixup_positions(space: &mut Space<Window>) {
    // fixup outputs
    let mut offset = Point::<i32, Logical>::from((0, 0));
    for output in space.outputs().cloned().collect::<Vec<_>>().into_iter() {
        let size = space
            .output_geometry(&output)
            .map(|geo| geo.size)
            .unwrap_or_else(|| Size::from((0, 0)));
        space.map_output(&output, offset);
        layer_map_for_output(&output).arrange();
        offset.x += size.w;
    }

    // fixup windows
    let mut orphaned_windows = Vec::new();
    let outputs = space
        .outputs()
        .flat_map(|o| {
            let geo = space.output_geometry(o)?;
            let map = layer_map_for_output(o);
            let zone = map.non_exclusive_zone();
            Some(Rectangle::from_loc_and_size(geo.loc + zone.loc, zone.size))
        })
        .collect::<Vec<_>>();
    for window in space.elements() {
        let window_location = match space.element_location(window) {
            Some(loc) => loc,
            None => continue,
        };
        let geo_loc = window.bbox().loc + window_location;

        if !outputs.iter().any(|o_geo| o_geo.contains(geo_loc)) {
            orphaned_windows.push(window.clone());
        }
    }
    for window in orphaned_windows.into_iter() {
        place_new_window(space, &window, false);
    }
}

<MSG> anvil: Implement subsurface state caching

<DFF> @@ -17,7 +17,10 @@ use smithay::{
     },
     utils::Rectangle,
     wayland::{
-        compositor::{compositor_init, BufferAssignment, CompositorToken, RegionAttributes, SurfaceEvent},
+        compositor::{
+            compositor_init, roles::Role, BufferAssignment, CompositorToken, RegionAttributes,
+            SubsurfaceRole, SurfaceEvent, TraversalAction,
+        },
         data_device::DnDIconRole,
         seat::{AxisFrame, CursorImageRole, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
         shell::{
@@ -29,7 +32,6 @@ use smithay::{
                 XdgSurfacePendingState, XdgSurfaceRole,
             },
         },
-        SERIAL_COUNTER as SCOUNTER,
     },
 };
 
@@ -640,13 +642,19 @@ impl Default for ResizeState {
     }
 }
 
+#[derive(Default, Clone)]
+pub struct CommitedState {
+    pub buffer: Option<wl_buffer::WlBuffer>,
+    pub input_region: Option<RegionAttributes>,
+    pub dimensions: Option<(i32, i32)>,
+    pub frame_callback: Option<wl_callback::WlCallback>,
+    pub sub_location: (i32, i32),
+}
+
 #[derive(Default)]
 pub struct SurfaceData {
-    pub buffer: Option<wl_buffer::WlBuffer>,
     pub texture: Option<crate::glium_drawer::TextureMetadata>,
-    pub dimensions: Option<(i32, i32)>,
     pub geometry: Option<Rectangle>,
-    pub input_region: Option<RegionAttributes>,
     pub resize_state: ResizeState,
     /// Minimum width and height, as requested by the surface.
     ///
@@ -656,13 +664,63 @@ pub struct SurfaceData {
     ///
     /// `0` means unlimited.
     pub max_size: (i32, i32),
-    pub frame_callback: Option<wl_callback::WlCallback>,
+    pub current_state: CommitedState,
+    pub cached_state: Option<CommitedState>,
+}
+
+impl SurfaceData {
+    /// Apply a next state into the surface current state
+    pub fn apply_state(&mut self, next_state: CommitedState) {
+        if Self::merge_state(&mut self.current_state, next_state) {
+            self.texture = None;
+        }
+    }
+
+    /// Apply a next state into the cached state
+    pub fn apply_cache(&mut self, next_state: CommitedState) {
+        match self.cached_state {
+            Some(ref mut cached) => {
+                Self::merge_state(cached, next_state);
+            }
+            None => self.cached_state = Some(next_state),
+        }
+    }
+
+    /// Apply the current cached state if any
+    pub fn apply_from_cache(&mut self) {
+        if let Some(cached) = self.cached_state.take() {
+            self.apply_state(cached);
+        }
+    }
+
+    // merge the "next" state into the "into" state
+    //
+    // returns true if the texture cache should be invalidated
+    fn merge_state(into: &mut CommitedState, next: CommitedState) -> bool {
+        let mut new_buffer = false;
+        // release the previous buffer if relevant
+        if into.buffer != next.buffer {
+            if let Some(buffer) = into.buffer.take() {
+                buffer.release();
+            }
+            new_buffer = true;
+        }
+        // ping the previous callback if relevant
+        if into.frame_callback != next.frame_callback {
+            if let Some(callback) = into.frame_callback.take() {
+                callback.done(0);
+            }
+        }
+
+        *into = next;
+        new_buffer
+    }
 }
 
 impl SurfaceData {
     /// Returns the size of the surface.
     pub fn size(&self) -> Option<(i32, i32)> {
-        self.dimensions
+        self.current_state.dimensions
     }
 
     /// Checks if the surface's input region contains the point.
@@ -688,16 +746,16 @@ impl SurfaceData {
         }
 
         // If there's no input region, we're done.
-        if self.input_region.is_none() {
+        if self.current_state.input_region.is_none() {
             return true;
         }
 
-        self.input_region.as_ref().unwrap().contains(point)
+        self.current_state.input_region.as_ref().unwrap().contains(point)
     }
 
     /// Send the frame callback if it had been requested
     pub fn send_frame(&mut self, serial: u32) {
-        if let Some(callback) = self.frame_callback.take() {
+        if let Some(callback) = self.current_state.frame_callback.take() {
             callback.done(serial);
         }
     }
@@ -721,7 +779,13 @@ fn surface_commit(
         geometry = role.window_geometry;
     });
 
-    let refresh = token.with_surface_data(surface, |attributes| {
+    let sub_data = token
+        .with_role_data(surface, |role: &mut SubsurfaceRole| role.clone())
+        .ok();
+
+    let mut next_state = CommitedState::default();
+
+    let (refresh, apply_children) = token.with_surface_data(surface, |attributes| {
         attributes
             .user_data
             .insert_if_missing(|| RefCell::new(SurfaceData::default()));
@@ -731,8 +795,20 @@ fn surface_commit(
             .unwrap()
             .borrow_mut();
 
+        if let Some(ref cached_state) = data.cached_state {
+            // There is a pending state, accumulate into it
+            next_state = cached_state.clone();
+        } else {
+            // start from the current state
+            next_state = data.current_state.clone();
+        }
+
+        if let Some(ref data) = sub_data {
+            next_state.sub_location = data.location;
+        }
+
         data.geometry = geometry;
-        data.input_region = attributes.input_region.clone();
+        next_state.input_region = attributes.input_region.clone();
         data.min_size = min_size;
         data.max_size = max_size;
 
@@ -740,37 +816,72 @@ fn surface_commit(
         match attributes.buffer.take() {
             Some(BufferAssignment::NewBuffer { buffer, .. }) => {
                 // new contents
-                // TODO: handle hotspot coordinates
-                if let Some(old_buffer) = data.buffer.replace(buffer) {
-                    old_buffer.release();
-                }
-                data.texture = None;
-                // If this fails, the buffer will be discarded later by the drawing code.
-                data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap());
+                next_state.dimensions = buffer_utils.dimensions(&buffer);
+                next_state.buffer = Some(buffer);
             }
             Some(BufferAssignment::Removed) => {
-                // erase the contents
-                if let Some(old_buffer) = data.buffer.take() {
-                    old_buffer.release();
-                }
-                data.texture = None;
-                data.dimensions = None;
+                // remove the contents
+                next_state.buffer = None;
+                next_state.dimensions = None;
             }
             None => {}
         }
 
-        // process the frame callback if any
-        if let Some(callback) = attributes.frame_callback.take() {
-            if let Some(old_callback) = data.frame_callback.take() {
-                // fire the old unfired callback to clean it up
-                old_callback.done(SCOUNTER.next_serial());
+        if let Some(frame_cb) = attributes.frame_callback.take() {
+            if let Some(old_cb) = next_state.frame_callback.take() {
+                old_cb.done(0);
             }
-            data.frame_callback = Some(callback);
+            next_state.frame_callback = Some(frame_cb);
         }
 
-        window_map.borrow().find(surface)
+        data.apply_cache(next_state);
+
+        let apply_children = if let Some(SubsurfaceRole { sync: true, .. }) = sub_data {
+            false
+        } else {
+            data.apply_from_cache();
+            true
+        };
+
+        (window_map.borrow().find(surface), apply_children)
     });
 
+    // Apply the cached state of all sync children
+    if apply_children {
+        token.with_surface_tree_upward(
+            surface,
+            true,
+            |_, _, role, &is_root| {
+                // only process children if the surface is sync or we are the root
+                if is_root {
+                    // we are the root
+                    TraversalAction::DoChildren(false)
+                } else if let Ok(sub_data) = Role::<SubsurfaceRole>::data(role) {
+                    if sub_data.sync || is_root {
+                        TraversalAction::DoChildren(false)
+                    } else {
+                        // if we are not sync, we won't apply from cache and don't process
+                        // the children
+                        TraversalAction::SkipChildren
+                    }
+                } else {
+                    unreachable!();
+                }
+            },
+            |_, attributes, role, _| {
+                // only apply from cache if we are a sync subsurface
+                if let Ok(sub_data) = Role::<SubsurfaceRole>::data(role) {
+                    if sub_data.sync {
+                        if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
+                            data.borrow_mut().apply_from_cache();
+                        }
+                    }
+                }
+            },
+            |_, _, _, _| true,
+        )
+    }
+
     if let Some(toplevel) = refresh {
         let mut window_map = window_map.borrow_mut();
         window_map.refresh_toplevel(&toplevel);

anvil: Implement subsurface state caching