| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use std::sync::Arc; |
| |
| use failure::{format_err, Error}; |
| use fuchsia_async as fasync; |
| use parking_lot::Mutex; |
| use wayland::*; |
| |
| use crate::client::Client; |
| use crate::object::{NewObjectExt, ObjectRef, RequestReceiver}; |
| use crate::registry::Registry; |
| |
| /// When the connection is created it is initialized with a 'wl_display' object |
| /// that the client can immediately interact with. |
| pub const DISPLAY_SINGLETON_OBJECT_ID: u32 = 1; |
| |
| /// |Display| is the global object used to manage a wayland server. |
| /// |
| /// The |Display| has a |Registry| that will hold the set of global |
| /// interfaces that will be advertised to clients. |
| #[derive(Clone)] |
| pub struct Display { |
| registry: Arc<Mutex<Registry>>, |
| } |
| |
| impl Display { |
| pub fn new(registry: Registry) -> Self { |
| Display { |
| registry: Arc::new(Mutex::new(registry)), |
| } |
| } |
| |
| pub fn spawn_new_client(&self, chan: fasync::Channel) { |
| let mut client = Client::new(chan, self.registry.clone()); |
| client.set_protocol_logging(true); |
| |
| // Add the global wl_display object. We unwrap here since the object map |
| // is empty so failure should not be possible. |
| client |
| .add_object(DISPLAY_SINGLETON_OBJECT_ID, DisplayReceiver) |
| .unwrap(); |
| |
| // Start polling the channel for messages. |
| client.start(); |
| } |
| } |
| |
| /// An implementation of wl_display. |
| struct DisplayReceiver; |
| |
| impl RequestReceiver<WlDisplay> for DisplayReceiver { |
| fn receive( |
| this: ObjectRef<Self>, request: WlDisplayRequest, client: &mut Client, |
| ) -> Result<(), Error> { |
| match request { |
| WlDisplayRequest::GetRegistry { registry } => { |
| let registry = registry.implement(client, RegistryReceiver)?; |
| RegistryReceiver::report_globals(registry, client)?; |
| Ok(()) |
| } |
| WlDisplayRequest::Sync { callback } => { |
| // Since we callback immediately we'll skip actually adding this |
| // object, but we need to send the wl_display::delete_id event |
| // explicitly, which is otherwise done for us in |
| // Client:delete_id, |
| client.post(callback.id(), WlCallbackEvent::Done { callback_data: 0 })?; |
| client.post(this.id(), WlDisplayEvent::DeleteId { id: callback.id() })?; |
| Ok(()) |
| } |
| } |
| } |
| } |
| |
| /// An implementation of wl_registry. |
| struct RegistryReceiver; |
| |
| impl RegistryReceiver { |
| /// Sends a wl_registry::global event for each entry in the |Registry|. |
| pub fn report_globals(this: ObjectRef<Self>, client: &Client) -> Result<(), Error> { |
| let registry = client.registry(); |
| for (name, global) in registry.lock().globals().iter().enumerate() { |
| client.post( |
| this.id(), |
| WlRegistryEvent::Global { |
| name: name as u32, |
| interface: global.interface().into(), |
| version: global.version(), |
| }, |
| )?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl RequestReceiver<WlRegistry> for RegistryReceiver { |
| fn receive( |
| _this: ObjectRef<Self>, request: WlRegistryRequest, client: &mut Client, |
| ) -> Result<(), Error> { |
| let WlRegistryRequest::Bind { name, id, .. } = request; |
| let registry = client.registry(); |
| let (spec, receiver) = { |
| let mut lock = registry.lock(); |
| if let Some(global) = lock.globals().get_mut(name as usize) { |
| (global.request_spec(), global.bind(id, client)?) |
| } else { |
| return Err(format_err!("Invalid global name {}", name)); |
| } |
| }; |
| client.add_object_raw(id, receiver, spec)?; |
| Ok(()) |
| } |
| } |
| |
| /// An implementation of wl_callback. |
| pub struct Callback; |
| |
| impl Callback { |
| /// Posts the `done` event for this callback. |
| #[allow(dead_code)] |
| pub fn done( |
| this: ObjectRef<Self>, client: &mut Client, callback_data: u32, |
| ) -> Result<(), Error> { |
| client.post(this.id(), WlCallbackEvent::Done { callback_data }) |
| } |
| } |
| |
| impl RequestReceiver<WlCallback> for Callback { |
| fn receive( |
| _this: ObjectRef<Self>, request: WlCallbackRequest, _client: &mut Client, |
| ) -> Result<(), Error> { |
| match request {} |
| } |
| } |