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