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
// Copyright 2022 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 {
    fuchsia_async as fasync,
    fuchsia_zircon::{self as zx, HandleBased},
    futures::{channel::mpsc as async_mpsc, StreamExt},
    std::sync::mpsc as sync_mpsc,
    wayland_bridge::dispatcher::WaylandDispatcher,
};

pub enum WaylandCommand {
    PushClient(zx::Channel),
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct wayland_server_handle_t {
    pub sender: async_mpsc::UnboundedSender<WaylandCommand>,
}

fn start_wayland_server() -> Result<(fasync::LocalExecutor, WaylandDispatcher), zx::Status> {
    let mut executor = fasync::LocalExecutor::new();
    let mut dispatcher = WaylandDispatcher::new().map_err(|e| {
        tracing::error!("Failed to create wayland dispatcher: {}", e);
        zx::Status::INTERNAL
    })?;
    // Try to get display properties before serving.
    let scenic = dispatcher.display.scenic().clone();
    match executor.run_singlethreaded(async { scenic.get_display_info().await }) {
        Ok(display_info) => dispatcher.display.set_display_info(&display_info),
        Err(e) => eprintln!("get_display_info error: {:?}", e),
    }
    Ok((executor, dispatcher))
}

#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn wayland_server_create(
    out: *mut *mut wayland_server_handle_t,
) -> zx::sys::zx_status_t {
    let (sender, mut receiver) = async_mpsc::unbounded::<WaylandCommand>();
    let (result_sender, result_receiver) = sync_mpsc::sync_channel::<zx::sys::zx_status_t>(0);
    std::thread::spawn(move || {
        let (mut executor, dispatcher) = match start_wayland_server() {
            Ok(result) => {
                result_sender.send(zx::sys::ZX_OK).unwrap();
                result
            }
            Err(status) => {
                result_sender.send(status.into_raw()).unwrap();
                return;
            }
        };

        executor.run_singlethreaded(async move {
            while let Some(WaylandCommand::PushClient(channel)) = receiver.next().await {
                dispatcher
                    .display
                    .clone()
                    .spawn_new_client(fasync::Channel::from_channel(channel), false);
            }
        });
    });

    let result = match result_receiver.recv() {
        Ok(status) => status,
        Err(_) => zx::sys::ZX_ERR_INTERNAL,
    };

    if result == zx::sys::ZX_OK {
        // Allocate the type we provide to the caller on the heap. This will be owned by the client
        // so we leak the pointer here.
        let ptr = Box::leak(Box::new(wayland_server_handle_t { sender }));

        unsafe { *out = ptr };
    }
    result
}

#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn wayland_server_push_client(
    server_handle: *mut wayland_server_handle_t,
    channel: zx::sys::zx_handle_t,
) {
    let handle = unsafe { zx::Handle::from_raw(channel) };
    // Unwrap here since this will only fail if we're provided with a null pointer, which is not
    // something we support.
    let server = unsafe { server_handle.as_mut().unwrap() };
    // Unwrap here since the only failure mode is if this is called after `wayland_server_destroy`,
    // which is not supported.
    server
        .sender
        .unbounded_send(WaylandCommand::PushClient(zx::Channel::from_handle(handle)))
        .unwrap();
}

#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn wayland_server_destroy(server_handle: *mut wayland_server_handle_t) {
    unsafe {
        // Drop the boxed pointer.
        let _ = Box::from_raw(server_handle);
    }
}