carnelian/app/strategies/
framebuffer.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::app::strategies::base::AppStrategy;
6use crate::app::{Config, InternalSender, MessageInternal};
7use crate::drawing::DisplayRotation;
8use crate::geometry::IntSize;
9use crate::input::report::InputReportHandler;
10use crate::input::{self, listen_for_user_input, DeviceId};
11use crate::view::strategies::base::{DisplayDirectParams, ViewStrategyParams, ViewStrategyPtr};
12use crate::view::strategies::display_direct::DisplayDirectViewStrategy;
13use crate::view::ViewKey;
14use anyhow::{bail, Context, Error};
15use async_trait::async_trait;
16use euclid::size2;
17use fidl::endpoints::{self};
18use fidl_fuchsia_hardware_display::{
19    CoordinatorListenerMarker, CoordinatorListenerRequest, CoordinatorMarker, CoordinatorProxy,
20    ProviderMarker, ProviderOpenCoordinatorWithListenerForPrimaryRequest,
21    ProviderOpenCoordinatorWithListenerForVirtconRequest, VirtconMode,
22};
23use fidl_fuchsia_input_report as hid_input_report;
24use fuchsia_async::{self as fasync};
25use futures::channel::mpsc::UnboundedSender;
26use futures::{StreamExt, TryFutureExt, TryStreamExt};
27use keymaps::Keymap;
28use std::collections::HashMap;
29use std::fmt::Debug;
30use std::fs;
31use std::path::{Path, PathBuf};
32use std::rc::Rc;
33use zx::Status;
34
35async fn watch_directory_async(
36    dir: PathBuf,
37    app_sender: UnboundedSender<MessageInternal>,
38) -> Result<(), Error> {
39    let dir_proxy = fuchsia_fs::directory::open_in_namespace(
40        dir.to_str().expect("to_str"),
41        fuchsia_fs::Flags::empty(),
42    )?;
43    let mut watcher = fuchsia_fs::directory::Watcher::new(&dir_proxy).await?;
44    fasync::Task::local(async move {
45        while let Some(msg) = (watcher.try_next()).await.expect("msg") {
46            match msg.event {
47                fuchsia_fs::directory::WatchEvent::ADD_FILE
48                | fuchsia_fs::directory::WatchEvent::EXISTING => {
49                    if msg.filename == Path::new(".") {
50                        continue;
51                    }
52                    let device_path = dir.join(msg.filename);
53                    app_sender
54                        .unbounded_send(MessageInternal::NewDisplayCoordinator(device_path))
55                        .expect("unbounded_send");
56                }
57                _ => (),
58            }
59        }
60    })
61    .detach();
62    Ok(())
63}
64
65pub(crate) struct AutoRepeatContext {
66    app_sender: UnboundedSender<MessageInternal>,
67    #[allow(unused)]
68    keyboard_autorepeat_task: Option<fasync::Task<()>>,
69    repeat_interval: std::time::Duration,
70}
71
72pub(crate) trait AutoRepeatTimer {
73    fn schedule_autorepeat_timer(&mut self, device_id: &DeviceId);
74    fn continue_autorepeat_timer(&mut self, device_id: &DeviceId);
75    fn cancel_autorepeat_timer(&mut self) {}
76}
77
78impl AutoRepeatContext {
79    pub(crate) fn new(app_sender: &UnboundedSender<MessageInternal>) -> Self {
80        Self {
81            app_sender: app_sender.clone(),
82            keyboard_autorepeat_task: None,
83            repeat_interval: Config::get().keyboard_autorepeat_slow_interval,
84        }
85    }
86
87    fn schedule(&mut self, device_id: &DeviceId) {
88        let timer =
89            fasync::Timer::new(fuchsia_async::MonotonicInstant::after(self.repeat_interval.into()));
90        let app_sender = self.app_sender.clone();
91        let device_id = device_id.clone();
92        let task = fasync::Task::local(async move {
93            timer.await;
94            app_sender
95                .unbounded_send(MessageInternal::KeyboardAutoRepeat(device_id))
96                .expect("unbounded_send");
97        });
98        self.keyboard_autorepeat_task = Some(task);
99    }
100}
101
102impl AutoRepeatTimer for AutoRepeatContext {
103    fn schedule_autorepeat_timer(&mut self, device_id: &DeviceId) {
104        self.repeat_interval = Config::get().keyboard_autorepeat_slow_interval;
105        self.schedule(device_id);
106    }
107
108    fn continue_autorepeat_timer(&mut self, device_id: &DeviceId) {
109        self.repeat_interval =
110            (self.repeat_interval * 3 / 4).max(Config::get().keyboard_autorepeat_fast_interval);
111        self.schedule(device_id);
112    }
113
114    fn cancel_autorepeat_timer(&mut self) {
115        self.keyboard_autorepeat_task = None;
116    }
117}
118
119const DISPLAY_COORDINATOR_PATH: &'static str = "/dev/class/display-coordinator";
120
121pub type CoordinatorProxyPtr = Rc<CoordinatorProxy>;
122
123pub fn first_display_device_path() -> Option<PathBuf> {
124    let mut entries = fs::read_dir(DISPLAY_COORDINATOR_PATH).ok()?;
125    entries.next()?.ok().map(|entry| entry.path())
126}
127
128pub struct DisplayCoordinator {
129    pub coordinator: CoordinatorProxyPtr,
130}
131
132impl DisplayCoordinator {
133    pub(crate) async fn open(
134        path: &str,
135        virtcon_mode: &Option<VirtconMode>,
136        app_sender: &UnboundedSender<MessageInternal>,
137    ) -> Result<Self, Error> {
138        let provider =
139            fuchsia_component::client::connect_to_protocol_at_path::<ProviderMarker>(path)
140                .context("while opening device file")?;
141        let (coordinator, coordinator_server) = endpoints::create_proxy::<CoordinatorMarker>();
142        let (listener_client, mut listener_requests) =
143            endpoints::create_request_stream::<CoordinatorListenerMarker>();
144        let () = if virtcon_mode.is_some() {
145            provider
146                .open_coordinator_with_listener_for_virtcon(
147                    ProviderOpenCoordinatorWithListenerForVirtconRequest {
148                        coordinator: Some(coordinator_server),
149                        coordinator_listener: Some(listener_client),
150                        __source_breaking: fidl::marker::SourceBreaking,
151                    },
152                )
153                .await
154        } else {
155            provider
156                .open_coordinator_with_listener_for_primary(
157                    ProviderOpenCoordinatorWithListenerForPrimaryRequest {
158                        coordinator: Some(coordinator_server),
159                        coordinator_listener: Some(listener_client),
160                        __source_breaking: fidl::marker::SourceBreaking,
161                    },
162                )
163                .await
164        }
165        .context("failed to perform FIDL call")?
166        .map_err(Status::from_raw)
167        .context("failed to open display coordinator")?;
168
169        if let Some(virtcon_mode) = virtcon_mode {
170            coordinator.set_virtcon_mode(*virtcon_mode)?;
171        }
172
173        let app_sender = app_sender.clone();
174        let f = async move {
175            loop {
176                if let Some(listener_request) = listener_requests.next().await {
177                    if let Ok(listener_request) = listener_request {
178                        app_sender
179                            .unbounded_send(MessageInternal::DisplayCoordinatorListenerRequest(
180                                listener_request,
181                            ))
182                            .expect("unbounded_send");
183                    }
184                }
185            }
186        };
187        fasync::Task::local(f).detach();
188        coordinator.set_vsync_event_delivery(true).context("enable_vsync failed")?;
189
190        Ok(Self { coordinator: Rc::new(coordinator) })
191    }
192
193    pub(crate) async fn watch_displays(app_sender: UnboundedSender<MessageInternal>) {
194        watch_directory_async(PathBuf::from(DISPLAY_COORDINATOR_PATH), app_sender)
195            .await
196            .expect("watch_directory_async");
197    }
198}
199
200pub type DisplayId = display_utils::DisplayId;
201
202#[derive(Debug)]
203pub struct DisplayInfo {
204    preferred_size: IntSize,
205    info: fidl_fuchsia_hardware_display::Info,
206}
207
208pub(crate) struct DisplayDirectAppStrategy<'a> {
209    pub display_coordinator: Option<DisplayCoordinator>,
210    pub display_rotation: DisplayRotation,
211    pub keymap: &'a Keymap<'a>,
212    pub input_report_handlers: HashMap<DeviceId, InputReportHandler<'a>>,
213    pub context: AutoRepeatContext,
214    pub app_sender: UnboundedSender<MessageInternal>,
215    pub owned: bool,
216    pub primary_display: Option<DisplayInfo>,
217    views: HashMap<DisplayId, Vec<ViewKey>>,
218}
219
220impl<'a> DisplayDirectAppStrategy<'a> {
221    pub fn new(
222        display_coordinator: Option<DisplayCoordinator>,
223        keymap: &'a Keymap<'a>,
224        app_sender: UnboundedSender<MessageInternal>,
225        app_config: &Config,
226    ) -> DisplayDirectAppStrategy<'a> {
227        DisplayDirectAppStrategy {
228            display_coordinator: display_coordinator,
229            display_rotation: app_config.display_rotation,
230            keymap,
231            input_report_handlers: HashMap::new(),
232            context: AutoRepeatContext::new(&app_sender),
233            app_sender,
234            owned: false,
235            primary_display: None,
236            views: Default::default(),
237        }
238    }
239
240    async fn handle_displays_changed(
241        &mut self,
242        added: Vec<fidl_fuchsia_hardware_display::Info>,
243        removed: Vec<fidl_fuchsia_hardware_display_types::DisplayId>,
244    ) -> Result<(), Error> {
245        let display_coordinator = self.display_coordinator.as_ref().expect("display_coordinator");
246        for display_id in removed {
247            self.views.remove(&display_id.into());
248            self.app_sender
249                .unbounded_send(MessageInternal::CloseViewsOnDisplay(display_id.into()))
250                .expect("unbounded");
251        }
252
253        for info in added {
254            // We use the preferred mode of the first display as the preferred size.
255            // This makes it more likely that input events will translate across
256            // different displays.
257            let preferred_size = self
258                .primary_display
259                .get_or_insert_with(|| {
260                    let mode = &info.modes[0];
261                    DisplayInfo {
262                        preferred_size: size2(mode.active_area.width, mode.active_area.height)
263                            .to_i32(),
264                        info: info.clone(),
265                    }
266                })
267                .preferred_size;
268            self.app_sender
269                .unbounded_send(MessageInternal::CreateView(ViewStrategyParams::DisplayDirect(
270                    DisplayDirectParams {
271                        view_key: None,
272                        coordinator: display_coordinator.coordinator.clone(),
273                        info,
274                        preferred_size,
275                    },
276                )))
277                .expect("send");
278        }
279
280        Ok(())
281    }
282}
283
284#[async_trait(?Send)]
285impl<'a> AppStrategy for DisplayDirectAppStrategy<'a> {
286    async fn create_view_strategy(
287        &mut self,
288        key: ViewKey,
289        app_sender: UnboundedSender<MessageInternal>,
290        strategy_params: ViewStrategyParams,
291    ) -> Result<ViewStrategyPtr, Error> {
292        let strategy_params = match strategy_params {
293            ViewStrategyParams::DisplayDirect(params) => params,
294            _ => bail!(
295                "Incorrect ViewStrategyParams passed to create_view_strategy for frame buffer"
296            ),
297        };
298        let views_on_display = self.views.entry(strategy_params.info.id.into()).or_default();
299        views_on_display.push(key);
300        Ok(DisplayDirectViewStrategy::new(
301            key,
302            strategy_params.coordinator,
303            app_sender.clone(),
304            strategy_params.info,
305            strategy_params.preferred_size,
306        )
307        .await?)
308    }
309
310    fn create_view_strategy_params_for_additional_view(
311        &mut self,
312        view_key: ViewKey,
313    ) -> ViewStrategyParams {
314        let primary_display = self.primary_display.as_ref().expect("primary_display");
315        ViewStrategyParams::DisplayDirect(DisplayDirectParams {
316            view_key: Some(view_key),
317            coordinator: self
318                .display_coordinator
319                .as_ref()
320                .expect("display_coordinator")
321                .coordinator
322                .clone(),
323            info: primary_display.info.clone(),
324            preferred_size: primary_display.preferred_size,
325        })
326    }
327
328    fn supports_scenic(&self) -> bool {
329        return false;
330    }
331
332    async fn post_setup(&mut self, internal_sender: &InternalSender) -> Result<(), Error> {
333        let input_report_sender = internal_sender.clone();
334        fasync::Task::local(
335            listen_for_user_input(input_report_sender)
336                .unwrap_or_else(|e: anyhow::Error| eprintln!("error: listening for input {:?}", e)),
337        )
338        .detach();
339        Ok(())
340    }
341
342    fn handle_input_report(
343        &mut self,
344        device_id: &input::DeviceId,
345        input_report: &hid_input_report::InputReport,
346    ) -> Vec<input::Event> {
347        let handler = self.input_report_handlers.get_mut(device_id).expect("input_report_handler");
348        handler.handle_input_report(device_id, input_report, &mut self.context)
349    }
350
351    fn handle_register_input_device(
352        &mut self,
353        device_id: &input::DeviceId,
354        device_descriptor: &hid_input_report::DeviceDescriptor,
355    ) {
356        let frame_buffer_size =
357            self.primary_display.as_ref().expect("primary_display").preferred_size;
358        self.input_report_handlers.insert(
359            device_id.clone(),
360            InputReportHandler::new(
361                device_id.clone(),
362                frame_buffer_size,
363                self.display_rotation,
364                device_descriptor,
365                self.keymap,
366            ),
367        );
368    }
369
370    fn handle_keyboard_autorepeat(&mut self, device_id: &input::DeviceId) -> Vec<input::Event> {
371        let handler = self.input_report_handlers.get_mut(device_id).expect("input_report_handler");
372        handler.handle_keyboard_autorepeat(device_id, &mut self.context)
373    }
374
375    async fn handle_new_display_coordinator(&mut self, display_path: PathBuf) {
376        if self.display_coordinator.is_none() {
377            let display_coordinator = DisplayCoordinator::open(
378                display_path.to_str().unwrap(),
379                &Config::get().virtcon_mode,
380                &self.app_sender,
381            )
382            .await
383            .expect("DisplayCoordinator::open");
384            self.display_coordinator = Some(display_coordinator);
385        }
386    }
387
388    async fn handle_display_coordinator_event(&mut self, event: CoordinatorListenerRequest) {
389        match event {
390            CoordinatorListenerRequest::OnDisplaysChanged { added, removed, control_handle: _ } => {
391                self.handle_displays_changed(added, removed)
392                    .await
393                    .expect("handle_displays_changed");
394            }
395            CoordinatorListenerRequest::OnClientOwnershipChange {
396                has_ownership,
397                control_handle: _,
398            } => {
399                self.owned = has_ownership;
400                self.app_sender
401                    .unbounded_send(MessageInternal::OwnershipChanged(has_ownership))
402                    .expect("unbounded_send");
403            }
404            CoordinatorListenerRequest::OnVsync { .. } => {
405                panic!("App strategy should not see vsync events");
406            }
407            CoordinatorListenerRequest::_UnknownMethod { ordinal, .. } => {
408                panic!("Unknown method #{:}", ordinal);
409            }
410        }
411    }
412
413    fn set_virtcon_mode(&mut self, virtcon_mode: VirtconMode) {
414        self.display_coordinator
415            .as_ref()
416            .expect("display_coordinator")
417            .coordinator
418            .set_virtcon_mode(virtcon_mode)
419            .expect("set_virtcon_mode");
420    }
421
422    fn get_focused_view_key(&self) -> Option<ViewKey> {
423        self.views.keys().next().and_then(|first_display| {
424            self.views.get(first_display).expect("first_display").last().cloned()
425        })
426    }
427
428    fn get_visible_view_key_for_display(&self, display_id: DisplayId) -> Option<ViewKey> {
429        self.views
430            .get(&display_id)
431            .and_then(|views_on_first_display| views_on_first_display.last().cloned())
432    }
433
434    fn handle_view_closed(&mut self, view_key: ViewKey) {
435        for views_on_display in self.views.values_mut() {
436            views_on_display.retain(|a_view_key| view_key != *a_view_key);
437        }
438    }
439}