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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
use std::{ffi::CString, sync::Arc};

use crate::{
    core_interfaces::{WL_DISPLAY_INTERFACE, WL_REGISTRY_INTERFACE},
    protocol::{same_interface, Argument, Interface, Message, ObjectInfo, ANONYMOUS_INTERFACE},
    types::server::{DisconnectReason, GlobalInfo, InvalidId},
};
use smallvec::SmallVec;

use super::{
    client::ClientStore, registry::Registry, ClientData, ClientId, Credentials, Data,
    GlobalHandler, GlobalId, ObjectData, ObjectId,
};
use crate::rs::map::Object;

/// Main handle of a backend to the Wayland protocol
///
/// This type hosts most of the protocol-related functionality of the backend, and is the
/// main entry point for manipulating Wayland objects. It can be retrieved both from
/// the backend via [`Backend::handle()`](super::Backend::handle), and is given to you as argument
/// in most event callbacks.
#[derive(Debug)]
pub struct Handle<D> {
    pub(crate) clients: ClientStore<D>,
    pub(crate) registry: Registry<D>,
}

enum DispatchAction<D> {
    Request {
        object: Object<Data<D>>,
        object_id: ObjectId,
        opcode: u16,
        arguments: SmallVec<[Argument<ObjectId>; 4]>,
        is_destructor: bool,
        created_id: Option<ObjectId>,
    },
    Bind {
        object: ObjectId,
        client: ClientId,
        global: GlobalId,
        handler: Arc<dyn GlobalHandler<D>>,
    },
}

impl<D> Handle<D> {
    pub(crate) fn new() -> Self {
        let debug =
            matches!(std::env::var_os("WAYLAND_DEBUG"), Some(str) if str == "1" || str == "server");
        Handle { clients: ClientStore::new(debug), registry: Registry::new() }
    }

    pub(crate) fn cleanup(&mut self) {
        let dead_clients = self.clients.cleanup();
        self.registry.cleanup(&dead_clients);
    }

    pub(crate) fn dispatch_events_for(
        &mut self,
        data: &mut D,
        client_id: ClientId,
    ) -> std::io::Result<usize> {
        let mut dispatched = 0;
        loop {
            let action = if let Ok(client) = self.clients.get_client_mut(client_id.clone()) {
                let (message, object) = match client.next_request() {
                    Ok(v) => v,
                    Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
                        if dispatched > 0 {
                            break;
                        } else {
                            return Err(e);
                        }
                    }
                    Err(e) => return Err(e),
                };
                dispatched += 1;
                if same_interface(object.interface, &WL_DISPLAY_INTERFACE) {
                    client.handle_display_request(message, &mut self.registry);
                    continue;
                } else if same_interface(object.interface, &WL_REGISTRY_INTERFACE) {
                    if let Some((client, global, object, handler)) =
                        client.handle_registry_request(message, &mut self.registry)
                    {
                        DispatchAction::Bind { client, global, object, handler }
                    } else {
                        continue;
                    }
                } else {
                    let object_id = ObjectId {
                        id: message.sender_id,
                        serial: object.data.serial,
                        interface: object.interface,
                        client_id: client.id.clone(),
                    };
                    let opcode = message.opcode;
                    let (arguments, is_destructor, created_id) =
                        match client.process_request(&object, message) {
                            Some(args) => args,
                            None => continue,
                        };
                    // Return the whole set to invoke the callback while handle is not borrower via client
                    DispatchAction::Request {
                        object,
                        object_id,
                        opcode,
                        arguments,
                        is_destructor,
                        created_id,
                    }
                }
            } else {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidInput,
                    "Invalid client ID",
                ));
            };
            match action {
                DispatchAction::Request {
                    object,
                    object_id,
                    opcode,
                    arguments,
                    is_destructor,
                    created_id,
                } => {
                    let ret = object.data.user_data.clone().request(
                        self,
                        data,
                        client_id.clone(),
                        Message { sender_id: object_id.clone(), opcode, args: arguments },
                    );
                    if is_destructor {
                        object.data.user_data.destroyed(client_id.clone(), object_id.clone());
                        if let Ok(client) = self.clients.get_client_mut(client_id.clone()) {
                            client.send_delete_id(object_id);
                        }
                    }
                    match (created_id, ret) {
                        (Some(child_id), Some(child_data)) => {
                            if let Ok(client) = self.clients.get_client_mut(client_id.clone()) {
                                client
                                    .map
                                    .with(child_id.id, |obj| obj.data.user_data = child_data)
                                    .unwrap();
                            }
                        }
                        (None, None) => {}
                        (Some(child_id), None) => {
                            panic!(
                                "Callback creating object {} did not provide any object data.",
                                child_id
                            );
                        }
                        (None, Some(_)) => {
                            panic!("An object data was returned from a callback not creating any object");
                        }
                    }
                }
                DispatchAction::Bind { object, client, global, handler } => {
                    let child_data =
                        handler.bind(self, data, client.clone(), global, object.clone());
                    if let Ok(client) = self.clients.get_client_mut(client.clone()) {
                        client.map.with(object.id, |obj| obj.data.user_data = child_data).unwrap();
                    }
                }
            }
        }
        Ok(dispatched)
    }

    pub(crate) fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
        if let Some(client) = client {
            match self.clients.get_client_mut(client) {
                Ok(client) => client.flush(),
                Err(InvalidId) => Ok(()),
            }
        } else {
            for client in self.clients.clients_mut() {
                let _ = client.flush();
            }
            Ok(())
        }
    }
}

impl<D> Handle<D> {
    /// Returns information about some object.
    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
        self.clients.get_client(id.client_id.clone())?.object_info(id)
    }

    /// Returns the id of the client which owns the object.
    pub fn get_client(&self, id: ObjectId) -> Result<ClientId, InvalidId> {
        if self.clients.get_client(id.client_id.clone()).is_ok() {
            Ok(id.client_id)
        } else {
            Err(InvalidId)
        }
    }

    /// Returns the data associated with a client.
    pub fn get_client_data(&self, id: ClientId) -> Result<Arc<dyn ClientData<D>>, InvalidId> {
        let client = self.clients.get_client(id)?;
        Ok(client.data.clone())
    }

    /// Retrive the [`Credentials`] of a client
    pub fn get_client_credentials(&self, id: ClientId) -> Result<Credentials, InvalidId> {
        let client = self.clients.get_client(id)?;
        Ok(client.get_credentials())
    }

    /// Returns an iterator over all clients connected to the server.
    pub fn all_clients<'a>(&'a self) -> Box<dyn Iterator<Item = ClientId> + 'a> {
        Box::new(self.clients.all_clients_id())
    }

    /// Returns an iterator over all objects owned by a client.
    pub fn all_objects_for<'a>(
        &'a self,
        client_id: ClientId,
    ) -> Result<Box<dyn Iterator<Item = ObjectId> + 'a>, InvalidId> {
        let client = self.clients.get_client(client_id)?;
        Ok(Box::new(client.all_objects()))
    }

    /// Retrieve the `ObjectId` for a wayland object given its protocol numerical ID
    pub fn object_for_protocol_id(
        &self,
        client_id: ClientId,
        interface: &'static Interface,
        protocol_id: u32,
    ) -> Result<ObjectId, InvalidId> {
        let client = self.clients.get_client(client_id)?;
        let object = client.object_for_protocol_id(protocol_id)?;
        if same_interface(interface, object.interface) {
            Ok(object)
        } else {
            Err(InvalidId)
        }
    }

    /// Create a new object for given client
    ///
    /// To ensure state coherence of the protocol, the created object should be immediately
    /// sent as a "New ID" argument in an event to the client.
    pub fn create_object(
        &mut self,
        client_id: ClientId,
        interface: &'static Interface,
        version: u32,
        data: Arc<dyn ObjectData<D>>,
    ) -> Result<ObjectId, InvalidId> {
        let client = self.clients.get_client_mut(client_id)?;
        Ok(client.create_object(interface, version, data))
    }

    /// Returns an object id that represents a null object.
    pub fn null_id(&mut self) -> ObjectId {
        ObjectId {
            id: 0,
            serial: 0,
            client_id: ClientId { id: 0, serial: 0 },
            interface: &ANONYMOUS_INTERFACE,
        }
    }

    /// Send an event to the client
    ///
    /// Returns an error if the sender ID of the provided message is no longer valid.
    ///
    /// **Panic:**
    ///
    /// Checks against the protocol specification are done, and this method will panic if they do
    /// not pass:
    ///
    /// - the message opcode must be valid for the sender interface
    /// - the argument list must match the prototype for the message associated with this opcode
    pub fn send_event(&mut self, msg: Message<ObjectId>) -> Result<(), InvalidId> {
        self.clients.get_client_mut(msg.sender_id.client_id.clone())?.send_event(msg)
    }

    /// Returns the data associated with an object.
    pub fn get_object_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData<D>>, InvalidId> {
        self.clients.get_client(id.client_id.clone())?.get_object_data(id)
    }

    /// Sets the data associated with some object.
    pub fn set_object_data(
        &mut self,
        id: ObjectId,
        data: Arc<dyn ObjectData<D>>,
    ) -> Result<(), InvalidId> {
        self.clients.get_client_mut(id.client_id.clone())?.set_object_data(id, data)
    }

    /// Posts an error on an object. This will also disconnect the client which created the object.
    pub fn post_error(&mut self, object_id: ObjectId, error_code: u32, message: CString) {
        if let Ok(client) = self.clients.get_client_mut(object_id.client_id.clone()) {
            client.post_error(object_id, error_code, message)
        }
    }

    /// Kills the connection to a client.
    ///
    /// The disconnection reason determines the error message that is sent to the client (if any).
    pub fn kill_client(&mut self, client_id: ClientId, reason: DisconnectReason) {
        if let Ok(client) = self.clients.get_client_mut(client_id) {
            client.kill(reason)
        }
    }

    /// Creates a global of the specified interface and version and then advertises it to clients.
    ///
    /// The clients which the global is advertised to is determined by the implementation of the [`GlobalHandler`].
    pub fn create_global(
        &mut self,
        interface: &'static Interface,
        version: u32,
        handler: Arc<dyn GlobalHandler<D>>,
    ) -> GlobalId {
        self.registry.create_global(interface, version, handler, &mut self.clients)
    }

    /// Disables a global object that is currently active.
    ///
    /// The global removal will be signaled to all currently connected clients. New clients will not know of the global,
    /// but the associated state and callbacks will not be freed. As such, clients that still try to bind the global
    /// afterwards (because they have not yet realized it was removed) will succeed.
    pub fn disable_global(&mut self, id: GlobalId) {
        self.registry.disable_global(id, &mut self.clients)
    }

    /// Removes a global object and free its ressources.
    ///
    /// The global object will no longer be considered valid by the server, clients trying to bind it will be killed,
    /// and the global ID is freed for re-use.
    ///
    /// It is advised to first disable a global and wait some amount of time before removing it, to ensure all clients
    /// are correctly aware of its removal. Note that clients will generally not expect globals that represent a capability
    /// of the server to be removed, as opposed to globals representing peripherals (like `wl_output` or `wl_seat`).
    pub fn remove_global(&mut self, id: GlobalId) {
        self.registry.remove_global(id, &mut self.clients)
    }

    /// Returns information about a global.
    pub fn global_info(&self, id: GlobalId) -> Result<GlobalInfo, InvalidId> {
        self.registry.get_info(id)
    }

    /// Returns the handler which manages the visibility and notifies when a client has bound the global.
    pub fn get_global_handler(&self, id: GlobalId) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
        self.registry.get_handler(id)
    }
}