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
// Copyright 2021 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 {
    crate::{
        alpha_compositing::*, aura_shell::*, compositor::*, data_device_manager::*, display::*,
        linux_dmabuf::*, object::*, output::*, pointer_constraints::*, registry::*,
        relative_pointer::*, seat::*, secure_output::*, shm::*, subcompositor::*, viewporter::*,
        xdg_shell::*,
    },
    anyhow::{Error, Result},
    fuchsia_sync::Mutex,
    fuchsia_zircon as zx,
    std::io::Read,
    std::sync::Arc,
    wayland_server_protocol::{
        WlCompositor, WlDataDeviceManager, WlOutput, WlSeat, WlShm, WlSubcompositor,
    },
    wp_viewporter_server_protocol::WpViewporter,
    xdg_shell_server_protocol::XdgWmBase,
    zaura_shell_server_protocol::ZauraShell,
    zcr_alpha_compositing_v1_server_protocol::ZcrAlphaCompositingV1,
    zcr_secure_output_v1_server_protocol::ZcrSecureOutputV1,
    zwp_linux_dmabuf_v1_server_protocol::ZwpLinuxDmabufV1,
    zwp_pointer_constraints_v1_server_protocol::ZwpPointerConstraintsV1,
    zwp_relative_pointer_v1_server_protocol::ZwpRelativePointerManagerV1,
};

/// Produces a VMO out of the contents of the file with the given filename.
fn read_file_into_vmo(filename: &str) -> Result<zx::Vmo> {
    let mut file = std::fs::File::open(filename)?;
    let keymap_len = file.metadata()?.len();

    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    let vmo = zx::Vmo::create(keymap_len)?;
    vmo.write(&buffer, 0)?;
    Ok(vmo)
}

/// The main FIDL server that listens for incoming client connection
/// requests.
pub struct WaylandDispatcher {
    /// The display handles the creation of new clients. Must be
    /// Arc/Mutex since this is shared with the future run on the executor.
    pub display: Display,
}

impl WaylandDispatcher {
    pub fn new_local(client: Arc<Mutex<Box<dyn LocalViewProducerClient>>>) -> Result<Self, Error> {
        let registry = WaylandDispatcher::new_registry()?;
        let display = Display::new_local(registry, client)?;
        Ok(WaylandDispatcher { display })
    }

    pub fn new() -> Result<Self, Error> {
        let registry = WaylandDispatcher::new_registry()?;
        let display = Display::new(registry)?;
        Ok(WaylandDispatcher { display })
    }

    fn new_registry() -> Result<Registry, Error> {
        let mut registry = RegistryBuilder::new();
        registry.add_global(WlCompositor, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(Compositor::new())))
        });
        registry.add_global(WlSubcompositor, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(Subcompositor::new())))
        });
        registry.add_global(WlOutput, move |id, _, client| {
            let output = Output::new();
            let display_info = client.display().display_info();
            // Send display info.
            Output::post_output_info(id, client, &display_info)?;
            Output::post_output_done(id, client)?;
            Ok(Box::new(RequestDispatcher::new(output)))
        });
        {
            registry.add_global(WlSeat, move |id, version, client| {
                let vmo = read_file_into_vmo("/pkg/data/keymap.xkb")?;
                let seat = Seat::new(version, vmo);
                seat.post_seat_info(id, version, client)?;
                Ok(Box::new(RequestDispatcher::new(seat)))
            });
        }
        registry.add_global(WlShm, move |id, _, client| {
            let shm = Shm::new();
            // announce the set of supported shm pixel formats.
            shm.post_formats(id, client)?;
            Ok(Box::new(RequestDispatcher::new(shm)))
        });
        registry.add_global(WlDataDeviceManager, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(DataDeviceManager::new())))
        });
        registry.add_global(XdgWmBase, move |_, _, _| {
            let xdg_shell = XdgShell::new();
            Ok(Box::new(RequestDispatcher::new(xdg_shell)))
        });
        registry.add_global(ZwpLinuxDmabufV1, move |id, version, client| {
            let linux_dmabuf = LinuxDmabuf::new(version);
            // announce the set of supported pixel formats.
            linux_dmabuf.post_formats(id, client)?;
            Ok(Box::new(RequestDispatcher::new(linux_dmabuf)))
        });
        registry.add_global(ZcrAlphaCompositingV1, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(AlphaCompositing::new())))
        });
        registry.add_global(ZcrSecureOutputV1, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(SecureOutput::new())))
        });
        registry.add_global(WpViewporter, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(Viewporter::new())))
        });
        registry.add_global(ZauraShell, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(AuraShell::new())))
        });
        registry.add_global(ZwpRelativePointerManagerV1, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(RelativePointerManager)))
        });
        registry.add_global(ZwpPointerConstraintsV1, move |_, _, _| {
            Ok(Box::new(RequestDispatcher::new(PointerConstraints)))
        });

        Ok(registry.build())
    }
}