smithay/wayland/xdg_foreign/
mod.rs

1//! Implementation `xdg_foreign` protocol
2//!
3//! ```rs
4//! # extern crate wayland_server;
5//! #
6//! use wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle};
7//! use smithay::{
8//!     delegate_xdg_foreign,
9//!     wayland::xdg_foreign::{XdgForeignHandler, XdgForeignState}
10//! };
11//!
12//! pub struct State {
13//!     xdg_foreign_state: XdgForeignState,
14//! }
15//!
16//! impl XdgForeignHandler for State {
17//!     fn xdg_foreignHandler_state(&mut self) -> &mut XdgForeignState {
18//!         &mut self.xdg_foreign_state
19//!     }
20//! }
21//!
22//! // Delegate xdg foreign handling for State to XdgForeignState.
23//! delegate_xdg_foreign!(State);
24//!
25//! # let mut display = wayland_server::Display::<State>::new().unwrap();
26//! # let display_handle = display.handle();
27//! let state = State {
28//!     xdg_foreign_state: XdgForeignState::new::<State>(&display_handle),
29//! };
30//! ```
31
32use std::{
33    collections::{HashMap, HashSet},
34    ops::Deref,
35};
36
37use rand::distr::{Alphanumeric, SampleString};
38use wayland_protocols::xdg::foreign::zv2::server::{
39    zxdg_exporter_v2::ZxdgExporterV2, zxdg_imported_v2::ZxdgImportedV2, zxdg_importer_v2::ZxdgImporterV2,
40};
41use wayland_server::{backend::GlobalId, protocol::wl_surface::WlSurface, DisplayHandle, GlobalDispatch};
42
43mod handlers;
44
45/// A trait implemented to be notified of activation requests using the xdg foreign protocol.
46pub trait XdgForeignHandler: 'static {
47    /// Returns the xdg foreign state.
48    fn xdg_foreign_state(&mut self) -> &mut XdgForeignState;
49}
50
51/// The handle contains the unique handle of exported surface.
52/// It may be shared with any client, which then can use it to import the surface by calling xdg_importer.import_toplevel.
53/// A handle may be used to import the surface multiple times.
54#[derive(Debug, Clone, Hash, PartialEq, Eq)]
55struct XdgForeignHandle(String);
56
57impl XdgForeignHandle {
58    fn new() -> Self {
59        Self(Alphanumeric.sample_string(&mut rand::rng(), 32))
60    }
61
62    fn as_str(&self) -> &str {
63        &self.0
64    }
65}
66
67impl Deref for XdgForeignHandle {
68    type Target = str;
69    fn deref(&self) -> &str {
70        &self.0
71    }
72}
73
74/// User data of xdg_exported
75#[derive(Debug)]
76pub struct XdgExportedUserData {
77    handle: XdgForeignHandle,
78}
79
80/// User data of xdg_imported
81#[derive(Debug)]
82pub struct XdgImportedUserData {
83    handle: XdgForeignHandle,
84}
85
86#[derive(Debug)]
87struct ExportedState {
88    exported_surface: WlSurface,
89    requested_child: Option<(WlSurface, ZxdgImportedV2)>,
90    imported_by: HashSet<ZxdgImportedV2>,
91}
92
93/// Tracks the list of exported surfaces
94#[derive(Debug)]
95pub struct XdgForeignState {
96    exported: HashMap<XdgForeignHandle, ExportedState>,
97    exporter: GlobalId,
98    importer: GlobalId,
99}
100
101impl XdgForeignState {
102    /// Creates a new xdg activation global.
103    ///
104    /// In order to use this abstraction, your `D` type needs to implement [`XdgForeignHandler`].
105    pub fn new<D>(display: &DisplayHandle) -> Self
106    where
107        D: XdgForeignHandler,
108        D: GlobalDispatch<ZxdgExporterV2, ()>,
109        D: GlobalDispatch<ZxdgImporterV2, ()>,
110    {
111        let exporter = display.create_global::<D, ZxdgExporterV2, _>(1, ());
112        let importer = display.create_global::<D, ZxdgImporterV2, _>(1, ());
113
114        Self {
115            exported: HashMap::new(),
116            exporter,
117            importer,
118        }
119    }
120
121    /// Returns the xdg_exporter global.
122    pub fn exporter_global(&self) -> GlobalId {
123        self.exporter.clone()
124    }
125
126    /// Returns the xdg_importer global.
127    pub fn importer_global(&self) -> GlobalId {
128        self.importer.clone()
129    }
130}
131
132/// Macro to delegate implementation of the xdg foreign to [`XdgForeignState`].
133///
134/// You must also implement [`XdgForeignHandler`] and
135/// [`XdgShellHandler`](crate::wayland::shell::xdg::XdgShellHandler) to use this.
136#[macro_export]
137macro_rules! delegate_xdg_foreign {
138    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
139        type __ZxdgExporterV2 =
140            $crate::reexports::wayland_protocols::xdg::foreign::zv2::server::zxdg_exporter_v2::ZxdgExporterV2;
141        type __ZxdgImporterV2 =
142            $crate::reexports::wayland_protocols::xdg::foreign::zv2::server::zxdg_importer_v2::ZxdgImporterV2;
143
144        type __ZxdgExportedV2 =
145            $crate::reexports::wayland_protocols::xdg::foreign::zv2::server::zxdg_exported_v2::ZxdgExportedV2;
146        type __ZxdgImportedV2 =
147            $crate::reexports::wayland_protocols::xdg::foreign::zv2::server::zxdg_imported_v2::ZxdgImportedV2;
148
149        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
150            [
151                __ZxdgExporterV2: ()
152            ] => $crate::wayland::xdg_foreign::XdgForeignState
153        );
154        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
155            [
156                __ZxdgImporterV2: ()
157            ] => $crate::wayland::xdg_foreign::XdgForeignState
158        );
159
160        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
161            [
162                __ZxdgExporterV2: ()
163            ] => $crate::wayland::xdg_foreign::XdgForeignState
164        );
165        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
166            [
167                __ZxdgImporterV2: ()
168            ] => $crate::wayland::xdg_foreign::XdgForeignState
169        );
170
171        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
172            [
173                __ZxdgExportedV2: $crate::wayland::xdg_foreign::XdgExportedUserData
174            ] => $crate::wayland::xdg_foreign::XdgForeignState
175        );
176        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
177            [
178                __ZxdgImportedV2: $crate::wayland::xdg_foreign::XdgImportedUserData
179            ] => $crate::wayland::xdg_foreign::XdgForeignState
180        );
181    };
182}