carnelian/app/strategies/
framebuffer.rs1use 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 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}