1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::reexports::client::globals::{BindError, GlobalList};
use crate::reexports::client::protocol::wl_compositor::WlCompositor;
use crate::reexports::client::protocol::wl_subcompositor::WlSubcompositor;
use crate::reexports::client::protocol::wl_subsurface::WlSubsurface;
use crate::reexports::client::protocol::wl_surface::WlSurface;
use crate::reexports::client::{Connection, Dispatch, Proxy, QueueHandle};

use crate::compositor::SurfaceData;
use crate::globals::GlobalData;

#[derive(Debug)]
pub struct SubcompositorState {
    compositor: WlCompositor,
    subcompositor: WlSubcompositor,
}

impl SubcompositorState {
    pub fn bind<State>(
        compositor: WlCompositor,
        globals: &GlobalList,
        queue_handle: &QueueHandle<State>,
    ) -> Result<Self, BindError>
    where
        State: Dispatch<WlSubcompositor, GlobalData, State> + 'static,
    {
        let subcompositor = globals.bind(queue_handle, 1..=1, GlobalData)?;
        Ok(SubcompositorState { compositor, subcompositor })
    }

    pub fn create_subsurface<State>(
        &self,
        parent: WlSurface,
        queue_handle: &QueueHandle<State>,
    ) -> (WlSubsurface, WlSurface)
    where
        State: Dispatch<WlSurface, SurfaceData> + Dispatch<WlSubsurface, SubsurfaceData> + 'static,
    {
        let surface_data = SurfaceData::new(Some(parent.clone()), 1);
        let surface = self.compositor.create_surface(queue_handle, surface_data);
        let subsurface_data = SubsurfaceData::new(surface.clone());
        let subsurface =
            self.subcompositor.get_subsurface(&surface, &parent, queue_handle, subsurface_data);
        (subsurface, surface)
    }
}

impl<D> Dispatch<WlSubsurface, SubsurfaceData, D> for SubcompositorState
where
    D: Dispatch<WlSubsurface, SubsurfaceData>,
{
    fn event(
        _: &mut D,
        _: &WlSubsurface,
        _: <WlSubsurface as Proxy>::Event,
        _: &SubsurfaceData,
        _: &Connection,
        _: &QueueHandle<D>,
    ) {
        unreachable!("wl_subsurface has no events")
    }
}

impl<D> Dispatch<WlSubcompositor, GlobalData, D> for SubcompositorState
where
    D: Dispatch<WlSubcompositor, GlobalData>,
{
    fn event(
        _: &mut D,
        _: &WlSubcompositor,
        _: <WlSubcompositor as Proxy>::Event,
        _: &GlobalData,
        _: &Connection,
        _: &QueueHandle<D>,
    ) {
        unreachable!("wl_subcompositor has no events")
    }
}

/// The data assoctiated with the subsurface.
#[derive(Debug)]
pub struct SubsurfaceData {
    /// The surface used when creating this subsurface.
    surface: WlSurface,
}

impl SubsurfaceData {
    pub(crate) fn new(surface: WlSurface) -> Self {
        Self { surface }
    }

    /// Get the surface used when creating the given subsurface.
    pub fn surface(&self) -> &WlSurface {
        &self.surface
    }
}

#[macro_export]
macro_rules! delegate_subcompositor {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::delegate_subcompositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; subsurface: []);
        $crate::delegate_subcompositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; subsurface-only: $crate::subcompositor::SubsurfaceData);
    };
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, subsurface: [$($subsurface: ty),*$(,)?]) => {
        $crate::delegate_subcompositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; subsurface: [ $($subsurface),* ]);
    };
    (@{$($ty:tt)*}; subsurface: []) => {
        $crate::reexports::client::delegate_dispatch!($($ty)*:
            [
                $crate::reexports::client::protocol::wl_subcompositor::WlSubcompositor: $crate::globals::GlobalData
            ] => $crate::subcompositor::SubcompositorState
        );
    };
    (@{$($ty:tt)*}; subsurface-only: $subsurface:ty) => {
        $crate::reexports::client::delegate_dispatch!($($ty)*:
            [
                    $crate::reexports::client::protocol::wl_subsurface::WlSubsurface: $subsurface
            ] => $crate::subcompositor::SubcompositorState
        );
    };
    (@$ty:tt; subsurface: [ $($subsurface:ty),+ ]) => {
        $crate::delegate_subcompositor!(@$ty; subsurface: []);
        $( $crate::delegate_subcompositor!(@$ty; subsurface-only: $subsurface); )*
    };
}