1use crate::client::{Client, TaskQueue};
6use crate::compositor::{Surface, SurfaceCommand, SurfaceRole};
7use crate::display::Callback;
8use crate::object::{NewObjectExt, ObjectRef, RequestReceiver};
9use crate::scenic::{Flatland, FlatlandPtr};
10use anyhow::{format_err, Error, Result};
11use async_utils::hanging_get::client::HangingGetStream;
12use fidl::endpoints::{create_endpoints, create_proxy, ServerEnd};
13use fidl::prelude::*;
14use fidl_fuchsia_element::{
15 Annotation, AnnotationKey, AnnotationValue, ViewControllerMarker, ViewControllerProxy, ViewSpec,
16};
17use fidl_fuchsia_math::{Rect, Size, SizeF, SizeU, Vec_};
18use fidl_fuchsia_ui_app::{ViewProviderControlHandle, ViewProviderMarker, ViewProviderRequest};
19use fidl_fuchsia_ui_composition::{
20 ChildViewWatcherMarker, ChildViewWatcherProxy, ContentId, FlatlandEvent, FlatlandEventStream,
21 FlatlandMarker, ParentViewportWatcherMarker, ParentViewportWatcherProxy, TransformId,
22 ViewportProperties,
23};
24use fidl_fuchsia_ui_pointer::{
25 MousePointerSample, MouseSourceMarker, MouseSourceProxy, TouchPointerSample, TouchSourceMarker,
26 TouchSourceProxy,
27};
28use fidl_fuchsia_ui_views::{
29 ViewIdentityOnCreation, ViewRefFocusedMarker, ViewRefFocusedProxy, ViewportCreationToken,
30};
31use fuchsia_component::client::connect_to_protocol;
32use fuchsia_scenic::flatland::{ViewBoundProtocols, ViewCreationTokenPair};
33use fuchsia_scenic::ViewRefPair;
34use fuchsia_sync::Mutex;
35use fuchsia_wayland_core::Enum;
36use futures::prelude::*;
37use std::collections::BTreeSet;
38use std::sync::atomic::{AtomicUsize, Ordering};
39use std::sync::Arc;
40use xdg_shell_server_protocol::xdg_positioner::{Anchor, Gravity};
41use xdg_shell_server_protocol::{
42 self as xdg_shell, xdg_toplevel, XdgPopupEvent, XdgPopupRequest, XdgPositionerRequest,
43 XdgSurfaceEvent, XdgSurfaceRequest, XdgToplevelEvent, XdgToplevelRequest, XdgWmBase,
44 XdgWmBaseRequest,
45};
46use {fuchsia_async as fasync, fuchsia_trace as ftrace, fuchsia_wayland_core as wl};
47
48static NEXT_VIEW_ID: AtomicUsize = AtomicUsize::new(1);
50
51static TITLE_ANNOTATION_NS: &'static str = "ermine";
53
54static TITLE_ANNOTATION_VALUE: &'static str = "name";
56
57pub struct XdgShell;
88
89impl XdgShell {
90 pub fn new() -> Self {
92 Self
93 }
94}
95
96impl RequestReceiver<XdgWmBase> for XdgShell {
97 fn receive(
98 this: ObjectRef<Self>,
99 request: XdgWmBaseRequest,
100 client: &mut Client,
101 ) -> Result<(), Error> {
102 match request {
103 XdgWmBaseRequest::Destroy => {
104 client.delete_id(this.id())?;
105 }
106 XdgWmBaseRequest::GetXdgSurface { id, surface } => {
107 let xdg_surface = XdgSurface::new(surface);
108 let surface_ref = xdg_surface.surface_ref;
109 let xdg_surface_ref = id.implement(client, xdg_surface)?;
110 surface_ref.get_mut(client)?.set_role(SurfaceRole::XdgSurface(xdg_surface_ref))?;
111 }
112 XdgWmBaseRequest::CreatePositioner { id } => {
113 id.implement(client, XdgPositioner::new())?;
114 }
115 XdgWmBaseRequest::Pong { .. } => {}
116 }
117 Ok(())
118 }
119}
120
121pub struct XdgPositioner {
122 size: Size,
123 anchor_rect: Rect,
124 anchor: Enum<Anchor>,
125 gravity: Enum<Gravity>,
126 offset: (i32, i32),
127}
128
129impl XdgPositioner {
130 pub fn new() -> Self {
131 Self {
132 size: Size { width: 0, height: 0 },
133 anchor_rect: Rect { x: 0, y: 0, width: 0, height: 0 },
134 anchor: Enum::Recognized(Anchor::None),
135 gravity: Enum::Recognized(Gravity::None),
136 offset: (0, 0),
137 }
138 }
139
140 pub fn get_geometry(&self) -> Result<Rect, Error> {
141 let mut geometry = Rect {
142 x: self.offset.0,
143 y: self.offset.1,
144 width: self.size.width,
145 height: self.size.height,
146 };
147
148 let anchor = self.anchor.as_enum()?;
149 geometry.x += match anchor {
150 Anchor::Left | Anchor::BottomLeft | Anchor::TopLeft => self.anchor_rect.x,
151 Anchor::Right | Anchor::BottomRight | Anchor::TopRight => {
152 self.anchor_rect.x + self.anchor_rect.width
153 }
154 _ => self.anchor_rect.x + self.anchor_rect.width / 2,
155 };
156
157 geometry.y += match anchor {
158 Anchor::Top | Anchor::TopLeft | Anchor::TopRight => self.anchor_rect.y,
159 Anchor::Bottom | Anchor::BottomLeft | Anchor::BottomRight => {
160 self.anchor_rect.y + self.anchor_rect.height
161 }
162 _ => self.anchor_rect.y + self.anchor_rect.height / 2,
163 };
164
165 let gravity = self.gravity.as_enum()?;
166 geometry.x -= match gravity {
167 Gravity::Left | Gravity::BottomLeft | Gravity::TopLeft => geometry.width,
168 Gravity::Right | Gravity::BottomRight | Gravity::TopRight => 0,
169 _ => geometry.width / 2,
170 };
171
172 geometry.y -= match gravity {
173 Gravity::Top | Gravity::TopLeft | Gravity::TopRight => geometry.height,
174 Gravity::Bottom | Gravity::BottomLeft | Gravity::BottomRight => 0,
175 _ => geometry.height / 2,
176 };
177
178 Ok(geometry)
179 }
180
181 fn set_size(&mut self, width: i32, height: i32) {
182 self.size = Size { width, height };
183 }
184
185 fn set_anchor_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
186 self.anchor_rect = Rect { x, y, width, height };
187 }
188
189 fn set_anchor(&mut self, anchor: Enum<Anchor>) {
190 self.anchor = anchor;
191 }
192
193 fn set_gravity(&mut self, gravity: Enum<Gravity>) {
194 self.gravity = gravity;
195 }
196
197 fn set_offset(&mut self, x: i32, y: i32) {
198 self.offset = (x, y);
199 }
200}
201
202impl RequestReceiver<xdg_shell::XdgPositioner> for XdgPositioner {
203 fn receive(
204 this: ObjectRef<Self>,
205 request: XdgPositionerRequest,
206 client: &mut Client,
207 ) -> Result<(), Error> {
208 match request {
209 XdgPositionerRequest::Destroy => {
210 client.delete_id(this.id())?;
211 }
212 XdgPositionerRequest::SetSize { width, height } => {
213 if width <= 0 || height <= 0 {
214 return Err(format_err!(
215 "invalid_input error width={:?} height={:?}",
216 width,
217 height
218 ));
219 }
220 this.get_mut(client)?.set_size(width, height);
221 }
222 XdgPositionerRequest::SetAnchorRect { x, y, width, height } => {
223 if width <= 0 || height <= 0 {
224 return Err(format_err!(
225 "invalid_input error width={:?} height={:?}",
226 width,
227 height
228 ));
229 }
230 this.get_mut(client)?.set_anchor_rect(x, y, width, height);
231 }
232 XdgPositionerRequest::SetAnchor { anchor } => {
233 this.get_mut(client)?.set_anchor(anchor);
234 }
235 XdgPositionerRequest::SetGravity { gravity } => {
236 this.get_mut(client)?.set_gravity(gravity);
237 }
238 XdgPositionerRequest::SetConstraintAdjustment { .. } => {}
239 XdgPositionerRequest::SetOffset { x, y } => {
240 this.get_mut(client)?.set_offset(x, y);
241 }
242 XdgPositionerRequest::SetReactive { .. } => {}
243 XdgPositionerRequest::SetParentSize { .. } => {}
244 XdgPositionerRequest::SetParentConfigure { .. } => {}
245 }
246 Ok(())
247 }
248}
249
250pub struct XdgSurface {
253 surface_ref: ObjectRef<Surface>,
255 root_surface_ref: ObjectRef<Surface>,
258 xdg_role: Option<XdgSurfaceRole>,
262 view: Option<XdgSurfaceViewPtr>,
266}
267
268impl XdgSurface {
269 pub fn new(id: wl::ObjectId) -> Self {
271 XdgSurface {
272 surface_ref: id.into(),
273 root_surface_ref: id.into(),
274 xdg_role: None,
275 view: None,
276 }
277 }
278
279 pub fn surface_ref(&self) -> ObjectRef<Surface> {
281 self.surface_ref
282 }
283
284 pub fn root_surface_ref(&self) -> ObjectRef<Surface> {
286 self.root_surface_ref
287 }
288
289 pub fn set_xdg_role(&mut self, xdg_role: XdgSurfaceRole) -> Result<(), Error> {
294 ftrace::duration!(c"wayland", c"XdgSurface::set_xdg_role");
295 let valid_role = match &self.xdg_role {
297 Some(XdgSurfaceRole::Popup(_)) => match xdg_role {
298 XdgSurfaceRole::Popup(_) => true,
299 _ => false,
300 },
301 Some(XdgSurfaceRole::Toplevel(_)) => match xdg_role {
302 XdgSurfaceRole::Toplevel(_) => true,
303 _ => false,
304 },
305 _ => true,
306 };
307 if valid_role {
308 self.xdg_role = Some(xdg_role);
309 Ok(())
310 } else {
311 Err(format_err!(
312 "Attemping to re-assign xdg_surface role from {:?} to {:?}",
313 self.xdg_role,
314 xdg_role
315 ))
316 }
317 }
318
319 fn set_view(&mut self, view: XdgSurfaceViewPtr) {
321 assert!(self.view.is_none());
324 self.view = Some(view);
325 }
326
327 fn set_root_surface(&mut self, root_surface_ref: ObjectRef<Surface>) {
329 self.root_surface_ref = root_surface_ref;
330 }
331
332 pub fn configure(this: ObjectRef<Self>, client: &mut Client) -> Result<(), Error> {
337 ftrace::duration!(c"wayland", c"XdgSurface::configure");
338 if let Some(xdg_surface) = this.try_get(client) {
339 match xdg_surface.xdg_role {
340 Some(XdgSurfaceRole::Popup(popup)) => {
341 XdgPopup::configure(popup, client)?;
342 }
343 Some(XdgSurfaceRole::Toplevel(toplevel)) => {
344 XdgToplevel::configure(toplevel, client)?;
345 }
346 _ => {}
347 }
348 let serial = client.event_queue().next_serial();
349 client.event_queue().post(this.id(), XdgSurfaceEvent::Configure { serial })?;
350 }
351 Ok(())
352 }
353
354 pub fn finalize_commit(this: ObjectRef<Self>, client: &mut Client) -> Result<bool, Error> {
360 ftrace::duration!(c"wayland", c"XdgSurface::finalize_commit");
361 if let Some(xdg_surface) = this.try_get(client) {
362 match xdg_surface.xdg_role {
363 Some(XdgSurfaceRole::Popup(_)) => Ok(true),
364 Some(XdgSurfaceRole::Toplevel(toplevel)) => {
365 XdgToplevel::finalize_commit(toplevel, client)
366 }
367 _ => Ok(false),
368 }
369 } else {
370 Ok(false)
371 }
372 }
373
374 pub fn shutdown(&self, client: &Client) {
375 ftrace::duration!(c"wayland", c"XdgSurface::shutdown");
376 self.view.as_ref().map(|v| v.lock().shutdown());
377 match self.xdg_role {
378 Some(XdgSurfaceRole::Popup(popup)) => {
379 if let Some(popup) = popup.try_get(client) {
380 popup.shutdown();
381 }
382 }
383 Some(XdgSurfaceRole::Toplevel(toplevel)) => {
384 if let Some(toplevel) = toplevel.try_get(client) {
385 toplevel.shutdown(client);
386 }
387 }
388 _ => {}
389 }
390 }
391
392 fn get_event_target(
393 root_surface_ref: ObjectRef<Surface>,
394 client: &Client,
395 ) -> Option<ObjectRef<Self>> {
396 for xdg_surface_ref in client.xdg_surfaces.iter().rev() {
397 if let Some(xdg_surface) = xdg_surface_ref.try_get(client) {
398 if xdg_surface.root_surface_ref == root_surface_ref {
399 return Some(*xdg_surface_ref);
400 }
401 }
402 }
403 None
404 }
405
406 fn add_child_view(
408 this: ObjectRef<Self>,
409 client: &mut Client,
410 viewport_creation_token: ViewportCreationToken,
411 ) -> Result<(), Error> {
412 ftrace::duration!(c"wayland", c"XdgSurface::add_child_view");
413 let xdg_surface = this.get(client)?;
414 let surface = xdg_surface.surface_ref().get(client)?;
415 let flatland = surface.flatland().ok_or_else(|| {
416 format_err!("Unable to create a child view without a flatland instance.")
417 })?;
418 let transform = flatland.borrow_mut().alloc_transform_id();
419 let task_queue = client.task_queue();
420 let (child_view_watcher, server_end) = create_proxy::<ChildViewWatcherMarker>();
421 XdgSurface::spawn_child_view_listener(
422 this,
423 child_view_watcher,
424 task_queue,
425 transform.value,
426 );
427 if let Some(view) = this.get_mut(client)?.view.clone() {
428 view.lock().add_child_view(transform.value, viewport_creation_token, server_end);
429 }
430 Ok(())
431 }
432
433 fn spawn_child_view(
434 this: ObjectRef<Self>,
435 client: &mut Client,
436 flatland: FlatlandPtr,
437 parent_ref: ObjectRef<Self>,
438 local_offset: Option<(i32, i32)>,
439 geometry: Rect,
440 ) -> Result<(), Error> {
441 ftrace::duration!(c"wayland", c"XdgSurface::spawn_child_view");
442 let creation_tokens =
443 ViewCreationTokenPair::new().expect("failed to create ViewCreationTokenPair");
444 let parent = parent_ref.get(client)?;
445 let parent_view = parent.view.clone();
446 let root_surface_ref = parent.root_surface_ref();
447 Self::add_child_view(parent_ref, client, creation_tokens.viewport_creation_token)?;
448 let xdg_surface = this.get(client)?;
449 let surface_ref = xdg_surface.surface_ref();
450 let task_queue = client.task_queue();
451 let (parent_viewport_watcher, server_end) = create_proxy::<ParentViewportWatcherMarker>();
452 flatland
453 .borrow()
454 .proxy()
455 .create_view(creation_tokens.view_creation_token, server_end)
456 .expect("fidl error");
457 XdgSurface::spawn_parent_viewport_listener(
458 this,
459 parent_viewport_watcher,
460 task_queue.clone(),
461 );
462 let view_ptr = XdgSurfaceView::new(
463 flatland,
464 task_queue,
465 this,
466 surface_ref,
467 parent_view,
468 local_offset,
469 geometry,
470 )?;
471 XdgSurfaceView::finish_setup_scene(&view_ptr, client)?;
472 let xdg_surface = this.get_mut(client)?;
473 xdg_surface.set_view(view_ptr.clone());
474 xdg_surface.set_root_surface(root_surface_ref);
475 client.xdg_surfaces.push(this);
476 Ok(())
477 }
478
479 fn spawn_flatland_listener(
480 this: ObjectRef<Self>,
481 client: &mut Client,
482 stream: FlatlandEventStream,
483 ) -> Result<(), Error> {
484 let task_queue = client.task_queue();
485 let surface_ref = this.get(client)?.surface_ref;
486 fasync::Task::local(
487 stream
488 .try_for_each(move |event| {
489 match event {
490 FlatlandEvent::OnNextFrameBegin { values } => {
491 task_queue.post(move |client| {
492 let infos = values
493 .future_presentation_infos
494 .as_ref()
495 .expect("no future presentation infos");
496 let info =
497 infos.iter().next().expect("no future presentation info");
498 let time_in_ms =
499 (info.presentation_time.expect("no presentation time")
500 / 1_000_000) as u32;
501 if let Some(surface) = surface_ref.try_get_mut(client) {
502 let callbacks = surface.take_on_next_frame_begin_callbacks();
503 callbacks.iter().try_for_each(|callback| {
504 Callback::done(*callback, client, time_in_ms)?;
505 client.delete_id(callback.id())
506 })?;
507 }
508 Surface::add_present_credits(
509 surface_ref,
510 client,
511 values.additional_present_credits.unwrap_or(0),
512 );
513 Ok(())
514 });
515 }
516 FlatlandEvent::OnFramePresented { frame_presented_info: _ } => {}
517 FlatlandEvent::OnError { error } => {
518 println!("FlatlandEvent::OnError: {:?}", error);
519 }
520 };
521 future::ok(())
522 })
523 .unwrap_or_else(|e| eprintln!("error listening for Flatland Events: {:?}", e)),
524 )
525 .detach();
526 Ok(())
527 }
528
529 fn spawn_parent_viewport_listener(
530 this: ObjectRef<Self>,
531 parent_viewport_watcher: ParentViewportWatcherProxy,
532 task_queue: TaskQueue,
533 ) {
534 let mut layout_info_stream =
535 HangingGetStream::new(parent_viewport_watcher, ParentViewportWatcherProxy::get_layout);
536
537 fasync::Task::local(async move {
538 while let Some(result) = layout_info_stream.next().await {
539 match result {
540 Ok(layout_info) => {
541 if let Some(logical_size) = layout_info.logical_size.map(|size| SizeF {
542 width: size.width as f32,
543 height: size.height as f32,
544 }) {
545 task_queue.post(move |client| {
546 if let Some(view) = this.get(client)?.view.clone() {
547 view.lock().handle_layout_changed(&logical_size);
548 }
549 Ok(())
550 });
551 }
552 }
553 Err(fidl::Error::ClientChannelClosed { .. }) => {
554 return;
555 }
556 Err(fidl_error) => {
557 println!("parent viewport GetLayout() error: {:?}", fidl_error);
558 return;
559 }
560 }
561 }
562 })
563 .detach();
564 }
565
566 fn spawn_touch_listener(
567 this: ObjectRef<Self>,
568 touch_source: TouchSourceProxy,
569 task_queue: TaskQueue,
570 ) {
571 fasync::Task::local(async move {
572 let mut responses: Vec<fidl_fuchsia_ui_pointer::TouchResponse> = Vec::new();
573 loop {
574 let result = touch_source.watch(&responses).await;
575 match result {
576 Ok(returned_events) => {
577 responses = returned_events
578 .iter()
579 .map(|event| fidl_fuchsia_ui_pointer::TouchResponse {
580 response_type: event.pointer_sample.as_ref().and_then(|_| {
581 Some(fidl_fuchsia_ui_pointer::TouchResponseType::Yes)
582 }),
583 ..Default::default()
584 })
585 .collect();
586 let events = returned_events.clone();
587 task_queue.post(move |client| {
588 if let Some(xdg_surface) = this.try_get(client) {
589 let root_surface_ref = xdg_surface.root_surface_ref;
590 for event in &events {
591 if let Some(TouchPointerSample {
592 interaction: Some(interaction),
593 phase: Some(phase),
594 position_in_viewport: Some(position_in_viewport),
595 ..
596 }) = event.pointer_sample.as_ref()
597 {
598 let x = position_in_viewport[0];
599 let y = position_in_viewport[1];
600 let xdg_surface_ref =
601 XdgSurface::get_event_target(root_surface_ref, client)
602 .unwrap_or(this);
603 let target =
604 XdgSurface::hit_test(xdg_surface_ref, x, y, client);
605 if let Some((_, surface_ref, offset)) = target {
606 if let Some(surface) = surface_ref.try_get(client) {
607 let position = {
608 let geometry = surface.window_geometry();
609 [
610 x + geometry.x as f32 - offset.0 as f32,
611 y + geometry.y as f32 - offset.1 as f32,
612 ]
613 };
614
615 let timestamp = event.timestamp.expect("timestamp");
616 client
617 .input_dispatcher
618 .handle_touch_event(
619 surface_ref,
620 timestamp,
621 interaction
622 .interaction_id
623 .try_into()
624 .unwrap(),
625 &position,
626 *phase,
627 )
628 .expect("handle_touch_event");
629 }
630 }
631 }
632 }
633 }
634 Ok(())
635 });
636 }
637 Err(fidl::Error::ClientChannelClosed { .. }) => {
638 return;
639 }
640 Err(fidl_error) => {
641 println!("touch source Watch() error: {:?}", fidl_error);
642 return;
643 }
644 }
645 }
646 })
647 .detach();
648 }
649
650 fn spawn_mouse_listener(
651 this: ObjectRef<Self>,
652 mouse_source: MouseSourceProxy,
653 task_queue: TaskQueue,
654 ) {
655 fasync::Task::local(async move {
656 loop {
657 let result = mouse_source.watch().await;
658 match result {
659 Ok(returned_events) => {
660 let events = returned_events.clone();
661 task_queue.post(move |client| {
662 if let Some(xdg_surface) = this.try_get(client) {
663 let root_surface_ref = xdg_surface.root_surface_ref;
664 for event in &events {
665 if let Some(MousePointerSample {
666 device_id: _,
667 position_in_viewport: Some(position_in_viewport),
668 relative_motion,
669 scroll_v,
670 scroll_h,
671 pressed_buttons,
672 ..
673 }) = event.pointer_sample.as_ref()
674 {
675 let x = position_in_viewport[0];
676 let y = position_in_viewport[1];
677 let xdg_surface_ref =
678 XdgSurface::get_event_target(root_surface_ref, client)
679 .unwrap_or(this);
680 let target =
681 XdgSurface::hit_test(xdg_surface_ref, x, y, client);
682 if let Some((_, surface_ref, offset)) = target {
683 if let Some(surface) = surface_ref.try_get(client) {
684 let position = {
685 let geometry = surface.window_geometry();
686 [
687 x + geometry.x as f32 - offset.0 as f32,
688 y + geometry.y as f32 - offset.1 as f32,
689 ]
690 };
691
692 let timestamp = event.timestamp.expect("timestamp");
693 client
694 .input_dispatcher
695 .handle_pointer_event(
696 surface_ref,
697 timestamp,
698 &position,
699 pressed_buttons,
700 relative_motion,
701 scroll_v,
702 scroll_h,
703 )
704 .expect("handle_mouse_event");
705 }
706 }
707 }
708 }
709 }
710 Ok(())
711 });
712 }
713 Err(fidl::Error::ClientChannelClosed { .. }) => {
714 return;
715 }
716 Err(fidl_error) => {
717 println!("mouse source Watch() error: {:?}", fidl_error);
718 return;
719 }
720 }
721 }
722 })
723 .detach();
724 }
725
726 fn spawn_child_view_listener(
727 this: ObjectRef<Self>,
728 child_view_watcher: ChildViewWatcherProxy,
729 task_queue: TaskQueue,
730 id: u64,
731 ) {
732 let mut status_stream =
733 HangingGetStream::new(child_view_watcher, ChildViewWatcherProxy::get_status);
734
735 fasync::Task::local(async move {
736 while let Some(result) = status_stream.next().await {
737 match result {
738 Ok(_status) => {}
739 Err(fidl::Error::ClientChannelClosed { .. }) => {
740 let xdg_surface_ref = this;
741 task_queue.post(move |client| {
742 if let Some(xdg_surface) = xdg_surface_ref.try_get(client) {
743 if let Some(view) = xdg_surface.view.as_ref() {
744 view.lock().handle_view_disconnected(id);
745 }
746 }
747 Ok(())
748 });
749 return;
750 }
751 Err(fidl_error) => {
752 println!("child view GetStatus() error: {:?}", fidl_error);
753 return;
754 }
755 }
756 }
757 })
758 .detach();
759 }
760
761 fn spawn_view_ref_focused_listener(
762 this: ObjectRef<Self>,
763 source_surface_ref: ObjectRef<Surface>,
764 view_ref_focused: ViewRefFocusedProxy,
765 task_queue: TaskQueue,
766 ) {
767 let mut focus_state_stream =
768 HangingGetStream::new(view_ref_focused, ViewRefFocusedProxy::watch);
769
770 fasync::Task::local(async move {
771 while let Some(result) = focus_state_stream.next().await {
772 match result {
773 Ok(focus_state) => {
774 task_queue.post(move |client| {
775 if let Some(xdg_surface) = this.try_get(client) {
776 let root_surface_ref = xdg_surface.root_surface_ref;
777 let xdg_surface_ref =
778 XdgSurface::get_event_target(root_surface_ref, client)
779 .unwrap_or(this);
780 let surface_ref = xdg_surface_ref.get(client)?.surface_ref;
781 if surface_ref.try_get(client).is_some() {
782 let had_focus = client.input_dispatcher.has_focus(surface_ref);
783 client.input_dispatcher.handle_keyboard_focus(
784 source_surface_ref,
785 surface_ref,
786 focus_state.focused.unwrap(),
787 )?;
788 let has_focus = client.input_dispatcher.has_focus(surface_ref);
789 if had_focus != has_focus {
790 Self::configure(xdg_surface_ref, client)?;
793 }
794 }
795 }
796 Ok(())
797 });
798 }
799 Err(fidl::Error::ClientChannelClosed { .. }) => {
800 return;
801 }
802 Err(fidl_error) => {
803 println!("ViewRefFocused Watch() error: {:?}", fidl_error);
804 return;
805 }
806 }
807 }
808 })
809 .detach();
810 }
811
812 fn hit_test(
813 this: ObjectRef<Self>,
814 location_x: f32,
815 location_y: f32,
816 client: &Client,
817 ) -> Option<(ObjectRef<Self>, ObjectRef<Surface>, (i32, i32))> {
818 let mut maybe_xdg_surface_ref = Some(this);
819 while let Some(xdg_surface_ref) = maybe_xdg_surface_ref.take() {
820 if let Some(xdg_surface) = xdg_surface_ref.try_get(client) {
821 if let Some((parent_view, view_offset)) = xdg_surface.view.as_ref().map(|v| {
822 let view = v.lock();
823 (view.parent(), view.absolute_offset())
824 }) {
825 let surface_ref = xdg_surface.surface_ref;
826 if let Some(surface) = surface_ref.try_get(client) {
827 let x = location_x - view_offset.0 as f32;
828 let y = location_y - view_offset.1 as f32;
829 if let Some((surface_ref, offset)) = surface.hit_test(x, y, client) {
830 let offset_x = offset.0 + view_offset.0;
831 let offset_y = offset.1 + view_offset.1;
832 return Some((xdg_surface_ref, surface_ref, (offset_x, offset_y)));
833 }
834 }
835 maybe_xdg_surface_ref = parent_view.as_ref().map(|v| v.lock().xdg_surface());
836 }
837 }
838 }
839 None
840 }
841}
842
843impl RequestReceiver<xdg_shell::XdgSurface> for XdgSurface {
844 fn receive(
845 this: ObjectRef<Self>,
846 request: XdgSurfaceRequest,
847 client: &mut Client,
848 ) -> Result<(), Error> {
849 match request {
850 XdgSurfaceRequest::Destroy => {
851 client.delete_id(this.id())?;
852 }
853 XdgSurfaceRequest::GetToplevel { id } => {
854 let proxy =
855 connect_to_protocol::<FlatlandMarker>().expect("error connecting to Flatland");
856 let flatland = Flatland::new(proxy);
857 let toplevel = XdgToplevel::new(this, client, flatland.clone())?;
858 let toplevel_ref = id.implement(client, toplevel)?;
859 this.get_mut(client)?.set_xdg_role(XdgSurfaceRole::Toplevel(toplevel_ref))?;
860 XdgSurface::spawn_flatland_listener(
861 this,
862 client,
863 flatland.borrow().proxy().take_event_stream(),
864 )?;
865 }
866 XdgSurfaceRequest::GetPopup { id, parent, positioner } => {
867 let proxy =
868 connect_to_protocol::<FlatlandMarker>().expect("error connecting to Flatland");
869 let flatland = Flatland::new(proxy);
870 let popup = XdgPopup::new(this, client, flatland.clone(), positioner.into())?;
871 let geometry = popup.geometry();
872 let popup_ref = id.implement(client, popup)?;
873 let xdg_surface = this.get_mut(client)?;
874 xdg_surface.set_xdg_role(XdgSurfaceRole::Popup(popup_ref))?;
875 XdgSurface::spawn_child_view(
876 this,
877 client,
878 flatland.clone(),
879 parent.into(),
880 Some((geometry.x, geometry.y)),
881 geometry,
882 )?;
883 XdgSurface::spawn_flatland_listener(
884 this,
885 client,
886 flatland.borrow().proxy().take_event_stream(),
887 )?;
888 }
889 XdgSurfaceRequest::SetWindowGeometry { x, y, width, height } => {
890 let surface_ref = this.get(client)?.surface_ref;
891 surface_ref.get_mut(client)?.enqueue(SurfaceCommand::SetWindowGeometry(Rect {
892 x,
893 y,
894 width,
895 height,
896 }));
897 }
898 XdgSurfaceRequest::AckConfigure { .. } => {}
899 }
900 Ok(())
901 }
902}
903
904#[derive(Copy, Clone, Debug)]
906pub enum XdgSurfaceRole {
907 Popup(ObjectRef<XdgPopup>),
908 Toplevel(ObjectRef<XdgToplevel>),
909}
910
911pub struct XdgPopup {
912 surface_ref: ObjectRef<Surface>,
914 xdg_surface_ref: ObjectRef<XdgSurface>,
916 #[allow(dead_code)]
918 positioner_ref: ObjectRef<XdgPositioner>,
919 geometry: Rect,
921}
922
923impl XdgPopup {
924 pub fn configure(this: ObjectRef<Self>, client: &mut Client) -> Result<(), Error> {
927 ftrace::duration!(c"wayland", c"XdgPopup::configure");
928 let geometry = this.get(client)?.geometry;
929 client.event_queue().post(
930 this.id(),
931 XdgPopupEvent::Configure {
932 x: geometry.x,
933 y: geometry.y,
934 width: geometry.width,
935 height: geometry.height,
936 },
937 )?;
938 Ok(())
939 }
940
941 fn geometry(&self) -> Rect {
942 self.geometry
943 }
944
945 pub fn new(
947 xdg_surface_ref: ObjectRef<XdgSurface>,
948 client: &mut Client,
949 flatland: FlatlandPtr,
950 positioner_ref: ObjectRef<XdgPositioner>,
951 ) -> Result<Self, Error> {
952 let geometry = positioner_ref.get(client)?.get_geometry()?;
953 let surface_ref = xdg_surface_ref.get(client)?.surface_ref();
954 surface_ref.get_mut(client)?.set_flatland(flatland)?;
955 Ok(XdgPopup { surface_ref, xdg_surface_ref, positioner_ref, geometry })
956 }
957
958 pub fn shutdown(&self) {}
959}
960
961impl RequestReceiver<xdg_shell::XdgPopup> for XdgPopup {
962 fn receive(
963 this: ObjectRef<Self>,
964 request: XdgPopupRequest,
965 client: &mut Client,
966 ) -> Result<(), Error> {
967 match request {
968 XdgPopupRequest::Destroy => {
969 let (surface_ref, xdg_surface_ref) = {
970 let popup = this.get(client)?;
971 (popup.surface_ref, popup.xdg_surface_ref)
972 };
973 xdg_surface_ref.get(client)?.shutdown(client);
974 Surface::present_internal(surface_ref, client);
978
979 surface_ref.get_mut(client)?.clear_flatland();
980 client.delete_id(this.id())?;
981 }
982 XdgPopupRequest::Grab { .. } => {}
983 XdgPopupRequest::Reposition { .. } => {}
984 }
985 Ok(())
986 }
987}
988
989pub struct XdgToplevel {
995 surface_ref: ObjectRef<Surface>,
997 xdg_surface_ref: ObjectRef<XdgSurface>,
999 view_provider_controller: Option<ViewProviderControlHandle>,
1002 view_controller_proxy: Option<ViewControllerProxy>,
1005 view_id: u32,
1007 waiting_for_initial_commit: bool,
1009 parent_ref: Option<ObjectRef<XdgToplevel>>,
1011 title: Option<String>,
1013 max_size: Size,
1016}
1017
1018impl XdgToplevel {
1019 pub fn configure(this: ObjectRef<Self>, client: &mut Client) -> Result<(), Error> {
1022 ftrace::duration!(c"wayland", c"XdgToplevel::configure");
1023 let (width, height, maximized, surface_ref) = {
1024 let (view, max_size, surface_ref, maybe_parent_ref) = {
1025 let toplevel = this.get(client)?;
1026 let max_size = toplevel.max_size;
1027 let xdg_surface_ref = toplevel.xdg_surface_ref;
1028 let xdg_surface = xdg_surface_ref.get(client)?;
1029 (xdg_surface.view.clone(), max_size, toplevel.surface_ref, toplevel.parent_ref)
1030 };
1031 let (width, height, maximized) = if maybe_parent_ref.is_some() {
1033 surface_ref
1034 .try_get(client)
1035 .map(|surface| {
1036 let geometry = surface.window_geometry();
1037 (geometry.width, geometry.height, false)
1038 })
1039 .unwrap_or((0, 0, false))
1040 } else {
1041 let display_info = client.display().display_info();
1042 let physical_size = view
1043 .as_ref()
1044 .map(|view| view.lock().physical_size())
1045 .filter(|size| size.width != 0 && size.height != 0)
1046 .unwrap_or(Size {
1047 width: display_info.width_in_px as i32,
1048 height: display_info.height_in_px as i32,
1049 });
1050 (
1051 if max_size.width > 0 {
1052 physical_size.width.min(max_size.width)
1053 } else {
1054 physical_size.width
1055 },
1056 if max_size.height > 0 {
1057 physical_size.height.min(max_size.height)
1058 } else {
1059 physical_size.height
1060 },
1061 true,
1062 )
1063 };
1064 (width, height, maximized, surface_ref)
1065 };
1066
1067 let mut states = wl::Array::new();
1068 if maximized {
1076 states.push(xdg_toplevel::State::Maximized)?;
1077 }
1078 if client.input_dispatcher.has_focus(surface_ref) {
1079 states.push(xdg_toplevel::State::Activated)?;
1083 }
1084 client
1085 .event_queue()
1086 .post(this.id(), XdgToplevelEvent::Configure { width, height, states })?;
1087
1088 Ok(())
1089 }
1090
1091 pub fn set_parent(&mut self, parent: Option<ObjectRef<XdgToplevel>>) {
1093 self.parent_ref = parent;
1094 }
1095
1096 fn set_title(&mut self, title: Option<String>) {
1098 self.title = title;
1099 }
1100
1101 fn set_max_size(&mut self, max_size: Size) -> bool {
1105 if max_size != self.max_size {
1106 self.max_size = max_size;
1107 return true;
1108 }
1109 false
1110 }
1111
1112 fn close(this: ObjectRef<Self>, client: &mut Client) -> Result<(), Error> {
1113 ftrace::duration!(c"wayland", c"XdgToplevel::close");
1114 client.event_queue().post(this.id(), XdgToplevelEvent::Close)
1115 }
1116
1117 pub fn new(
1119 xdg_surface_ref: ObjectRef<XdgSurface>,
1120 client: &mut Client,
1121 flatland: FlatlandPtr,
1122 ) -> Result<Self, Error> {
1123 let surface_ref = xdg_surface_ref.get(client)?.surface_ref();
1124 surface_ref.get_mut(client)?.set_flatland(flatland)?;
1125 Ok(XdgToplevel {
1126 surface_ref,
1127 xdg_surface_ref,
1128 view_provider_controller: None,
1129 view_controller_proxy: None,
1130 view_id: NEXT_VIEW_ID.fetch_add(1, Ordering::SeqCst) as u32,
1131 waiting_for_initial_commit: true,
1132 parent_ref: None,
1133 title: None,
1134 max_size: Size { width: 0, height: 0 },
1135 })
1136 }
1137
1138 fn spawn_view_provider(
1139 this: ObjectRef<Self>,
1140 client: &mut Client,
1141 flatland: FlatlandPtr,
1142 ) -> Result<ViewProviderControlHandle, Error> {
1143 ftrace::duration!(c"wayland", c"XdgToplevel::spawn_view_provider");
1144 let (client_end, server_end) = create_endpoints::<ViewProviderMarker>();
1147 let view_id = this.get(client)?.view_id;
1148 client.display().new_view_provider(client_end, view_id);
1149
1150 let surface_ref = this.get(client)?.surface_ref;
1152 let xdg_surface_ref = this.get(client)?.xdg_surface_ref;
1153 let task_queue = client.task_queue();
1154 let mut stream = server_end.into_stream();
1155 let control_handle = stream.control_handle();
1156 fasync::Task::local(
1157 async move {
1158 if let Some(request) = stream.try_next().await.unwrap() {
1163 match request {
1164 ViewProviderRequest::CreateView2 { args, .. } => {
1165 let view_creation_token = args.view_creation_token.unwrap();
1166 let viewref_pair = ViewRefPair::new()?;
1167 let view_identity = ViewIdentityOnCreation::from(viewref_pair);
1168 let (parent_viewport_watcher, parent_viewport_watcher_request) =
1169 create_proxy::<ParentViewportWatcherMarker>();
1170 let (view_ref_focused, view_ref_focused_request) =
1171 create_proxy::<ViewRefFocusedMarker>();
1172 let (touch_source, touch_source_request) =
1173 create_proxy::<TouchSourceMarker>();
1174 let (mouse_source, mouse_source_request) =
1175 create_proxy::<MouseSourceMarker>();
1176 let view_bound_protocols = ViewBoundProtocols {
1177 view_ref_focused: Some(view_ref_focused_request),
1178 touch_source: Some(touch_source_request),
1179 mouse_source: Some(mouse_source_request),
1180 ..Default::default()
1181 };
1182 flatland
1183 .borrow()
1184 .proxy()
1185 .create_view2(
1186 view_creation_token,
1187 view_identity,
1188 view_bound_protocols,
1189 parent_viewport_watcher_request,
1190 )
1191 .expect("fidl error");
1192 XdgSurface::spawn_view_ref_focused_listener(
1193 xdg_surface_ref,
1194 surface_ref,
1195 view_ref_focused,
1196 task_queue.clone(),
1197 );
1198 XdgSurface::spawn_parent_viewport_listener(
1199 xdg_surface_ref,
1200 parent_viewport_watcher,
1201 task_queue.clone(),
1202 );
1203 XdgSurface::spawn_touch_listener(
1204 xdg_surface_ref,
1205 touch_source,
1206 task_queue.clone(),
1207 );
1208 XdgSurface::spawn_mouse_listener(
1209 xdg_surface_ref,
1210 mouse_source,
1211 task_queue.clone(),
1212 );
1213 let view_ptr = XdgSurfaceView::new(
1214 flatland,
1215 task_queue.clone(),
1216 xdg_surface_ref,
1217 surface_ref,
1218 None,
1219 Some((0, 0)),
1220 Rect { x: 0, y: 0, width: 0, height: 0 },
1221 )?;
1222 task_queue.post(move |client| {
1223 XdgSurfaceView::finish_setup_scene(&view_ptr, client)?;
1224 xdg_surface_ref.get_mut(client)?.set_view(view_ptr.clone());
1225 Ok(())
1226 });
1227 }
1228 _ => {
1229 panic!("unsupported view provider request: {:?}", request)
1230 }
1231 }
1232 }
1233
1234 if let Some(request) = stream.try_next().await.unwrap() {
1237 panic!("unsupported view provider request: {:?}", request)
1238 }
1239
1240 task_queue.post(|_client| {
1241 Err(format_err!("View provider channel closed "))
1244 });
1245 Ok(())
1246 }
1247 .unwrap_or_else(|e: Error| println!("{:?}", e)),
1248 )
1249 .detach();
1250 Ok(control_handle)
1251 }
1252
1253 fn spawn_view(
1254 this: ObjectRef<Self>,
1255 client: &mut Client,
1256 flatland: FlatlandPtr,
1257 ) -> Result<ViewControllerProxy, Error> {
1258 ftrace::duration!(c"wayland", c"XdgToplevel::spawn_view");
1259 let (proxy, server_end) = create_proxy::<ViewControllerMarker>();
1260 let stream = proxy.take_event_stream();
1261 let creation_tokens = ViewCreationTokenPair::new().expect("failed to create token pair");
1262 let viewref_pair = ViewRefPair::new()?;
1263 let view_ref_dup = fuchsia_scenic::duplicate_view_ref(&viewref_pair.view_ref)?;
1264 let view_identity = ViewIdentityOnCreation::from(viewref_pair);
1265 let toplevel = this.get(client)?;
1266 let annotations = toplevel.title.as_ref().map(|title| {
1267 let title_key = AnnotationKey {
1268 namespace: TITLE_ANNOTATION_NS.to_string(),
1269 value: TITLE_ANNOTATION_VALUE.to_string(),
1270 };
1271 vec![Annotation { key: title_key, value: AnnotationValue::Text(title.clone()) }]
1272 });
1273 let view_spec = ViewSpec {
1274 viewport_creation_token: Some(creation_tokens.viewport_creation_token),
1275 view_ref: Some(view_ref_dup),
1276 annotations,
1277 ..Default::default()
1278 };
1279 let (parent_viewport_watcher, parent_viewport_watcher_request) =
1280 create_proxy::<ParentViewportWatcherMarker>();
1281 let (view_ref_focused, view_ref_focused_request) = create_proxy::<ViewRefFocusedMarker>();
1282 let (touch_source, touch_source_request) = create_proxy::<TouchSourceMarker>();
1283 let (mouse_source, mouse_source_request) = create_proxy::<MouseSourceMarker>();
1284 let view_bound_protocols = ViewBoundProtocols {
1285 view_ref_focused: Some(view_ref_focused_request),
1286 touch_source: Some(touch_source_request),
1287 mouse_source: Some(mouse_source_request),
1288 ..Default::default()
1289 };
1290 flatland
1291 .borrow()
1292 .proxy()
1293 .create_view2(
1294 creation_tokens.view_creation_token,
1295 view_identity,
1296 view_bound_protocols,
1297 parent_viewport_watcher_request,
1298 )
1299 .expect("fidl error");
1300 let xdg_surface_ref = toplevel.xdg_surface_ref;
1301 let surface_ref = toplevel.surface_ref;
1302 let max_size = toplevel.max_size;
1303 let task_queue = client.task_queue();
1304 XdgSurface::spawn_view_ref_focused_listener(
1305 xdg_surface_ref,
1306 surface_ref,
1307 view_ref_focused,
1308 task_queue.clone(),
1309 );
1310 XdgSurface::spawn_parent_viewport_listener(
1311 xdg_surface_ref,
1312 parent_viewport_watcher,
1313 task_queue.clone(),
1314 );
1315 XdgSurface::spawn_touch_listener(xdg_surface_ref, touch_source, task_queue.clone());
1316 XdgSurface::spawn_mouse_listener(xdg_surface_ref, mouse_source, task_queue.clone());
1317 let view_ptr = XdgSurfaceView::new(
1318 flatland,
1319 task_queue.clone(),
1320 xdg_surface_ref,
1321 surface_ref,
1322 None,
1323 Some((0, 0)),
1324 Rect { x: 0, y: 0, width: max_size.width, height: max_size.height },
1325 )?;
1326 XdgSurfaceView::finish_setup_scene(&view_ptr, client)?;
1327 xdg_surface_ref.get_mut(client)?.set_view(view_ptr.clone());
1328 let graphical_presenter = client.display().graphical_presenter().clone();
1329 fasync::Task::local(
1330 async move {
1331 graphical_presenter
1332 .present_view(view_spec, None, Some(server_end))
1333 .await
1334 .expect("failed to present view")
1335 .unwrap_or_else(|e| println!("{:?}", e));
1336
1337 let _ = stream.collect::<Vec<_>>().await;
1339 task_queue.post(move |client| {
1340 XdgToplevel::close(this, client)?;
1341 Ok(())
1342 });
1343 Ok(())
1344 }
1345 .unwrap_or_else(|e: Error| println!("{:?}", e)),
1346 )
1347 .detach();
1348 Ok(proxy)
1349 }
1350
1351 pub fn finalize_commit(this: ObjectRef<Self>, client: &mut Client) -> Result<bool, Error> {
1352 ftrace::duration!(c"wayland", c"XdgToplevel::finalize_commit");
1353 let top_level = this.get(client)?;
1354 if top_level.waiting_for_initial_commit {
1356 let xdg_surface_ref = top_level.xdg_surface_ref;
1357 let xdg_surface = xdg_surface_ref.get(client)?;
1358 let surface_ref = xdg_surface.surface_ref();
1359 let surface = surface_ref.get(client)?;
1360 let flatland = surface
1361 .flatland()
1362 .ok_or_else(|| format_err!("Unable to spawn view without a flatland instance"))?;
1363
1364 let maybe_parent_ref = if let Some(parent_ref) = top_level.parent_ref {
1367 let parent = parent_ref.get(client)?;
1368 Some(parent.xdg_surface_ref)
1369 } else {
1370 None
1371 };
1372
1373 let (maybe_view_provider_control_handle, maybe_view_controller_proxy) = {
1374 if let Some(parent_ref) = maybe_parent_ref {
1375 let offset = surface.offset();
1376 let geometry = surface.window_geometry();
1377 XdgSurface::spawn_child_view(
1378 xdg_surface_ref,
1379 client,
1380 flatland,
1381 parent_ref,
1382 offset,
1383 geometry,
1384 )?;
1385 (None, None)
1386 } else if client.take_view_provider_request() {
1387 let control_handle = XdgToplevel::spawn_view_provider(this, client, flatland)?;
1388 (Some(control_handle), None)
1389 } else {
1390 let view_controller_proxy = XdgToplevel::spawn_view(this, client, flatland)?;
1391 (None, Some(view_controller_proxy))
1392 }
1393 };
1394
1395 let top_level = this.get_mut(client)?;
1397 top_level.waiting_for_initial_commit = false;
1398 top_level.view_provider_controller = maybe_view_provider_control_handle;
1399 top_level.view_controller_proxy = maybe_view_controller_proxy;
1400 if let Some(parent_ref) = maybe_parent_ref {
1402 let root_surface_ref = parent_ref.get(client)?.root_surface_ref();
1403 client
1404 .input_dispatcher
1405 .maybe_update_keyboard_focus(root_surface_ref, surface_ref)?;
1406 }
1407 XdgSurface::configure(xdg_surface_ref, client)?;
1408 client.xdg_surfaces.push(xdg_surface_ref);
1409 } else {
1410 let xdg_surface_ref = top_level.xdg_surface_ref;
1411 let xdg_surface = xdg_surface_ref.get(client)?;
1412 let surface = xdg_surface.surface_ref().get(client)?;
1413 let geometry = surface.window_geometry();
1414 let local_offset = surface.offset();
1415 if let Some(view) = xdg_surface.view.clone() {
1416 view.lock().set_geometry_and_local_offset(&geometry, &local_offset);
1417 }
1418 }
1419 Ok(true)
1420 }
1421
1422 pub fn shutdown(&self, client: &Client) {
1423 if let Some(view_provider_controller) = self.view_provider_controller.as_ref() {
1424 view_provider_controller.shutdown();
1425 client.display().delete_view_provider(self.view_id);
1426 }
1427 if let Some(view_controller_proxy) = self.view_controller_proxy.as_ref() {
1428 view_controller_proxy.dismiss().unwrap_or_else(|e| println!("{:?}", e));
1429 }
1430 }
1431}
1432
1433impl RequestReceiver<xdg_shell::XdgToplevel> for XdgToplevel {
1434 fn receive(
1435 this: ObjectRef<Self>,
1436 request: XdgToplevelRequest,
1437 client: &mut Client,
1438 ) -> Result<(), Error> {
1439 match request {
1440 XdgToplevelRequest::Destroy => {
1441 let (surface_ref, xdg_surface_ref) = {
1442 let toplevel = this.get(client)?;
1443 (toplevel.surface_ref, toplevel.xdg_surface_ref)
1444 };
1445 client.xdg_surfaces.retain(|&x| x != xdg_surface_ref);
1446 let xdg_surface = xdg_surface_ref.get(client)?;
1447 xdg_surface.shutdown(client);
1448 if client.input_dispatcher.has_focus(surface_ref) {
1449 let source_surface_ref = xdg_surface.root_surface_ref();
1451 let maybe_target = XdgSurface::get_event_target(source_surface_ref, client);
1452 if let Some(target_xdg_surface_ref) = maybe_target {
1453 let target_surface_ref = target_xdg_surface_ref.get(client)?.surface_ref;
1454 client
1455 .input_dispatcher
1456 .maybe_update_keyboard_focus(source_surface_ref, target_surface_ref)?;
1457 }
1458 }
1459 Surface::present_internal(surface_ref, client);
1463
1464 surface_ref.get_mut(client)?.clear_flatland();
1465 client.delete_id(this.id())?;
1466 }
1467 XdgToplevelRequest::SetParent { parent } => {
1468 let toplevel = this.get_mut(client)?;
1469 let maybe_parent = if parent != 0 { Some(parent.into()) } else { None };
1470 toplevel.set_parent(maybe_parent);
1471 }
1472 XdgToplevelRequest::SetTitle { title } => {
1473 let toplevel = this.get_mut(client)?;
1474 toplevel.set_title(Some(title));
1475 }
1476 XdgToplevelRequest::SetAppId { .. } => {}
1477 XdgToplevelRequest::ShowWindowMenu { .. } => {}
1478 XdgToplevelRequest::Move { .. } => {}
1479 XdgToplevelRequest::Resize { .. } => {}
1480 XdgToplevelRequest::SetMaxSize { width, height } => {
1481 let toplevel = this.get_mut(client)?;
1482 if toplevel.set_max_size(Size { width, height })
1483 && !toplevel.waiting_for_initial_commit
1484 {
1485 XdgSurface::configure(toplevel.xdg_surface_ref, client)?;
1486 }
1487 }
1488 XdgToplevelRequest::SetMinSize { .. } => {}
1489 XdgToplevelRequest::SetMaximized => {}
1490 XdgToplevelRequest::UnsetMaximized => {}
1491 XdgToplevelRequest::SetFullscreen { .. } => {}
1492 XdgToplevelRequest::UnsetFullscreen => {}
1493 XdgToplevelRequest::SetMinimized => {}
1494 }
1495 Ok(())
1496 }
1497}
1498
1499struct XdgSurfaceView {
1504 flatland: FlatlandPtr,
1505 root_transform: Option<TransformId>,
1506 container_transform: TransformId,
1507 logical_size: SizeF,
1508 local_offset: Option<(i32, i32)>,
1509 absolute_offset: (i32, i32),
1510 task_queue: TaskQueue,
1511 xdg_surface: ObjectRef<XdgSurface>,
1512 surface: ObjectRef<Surface>,
1513 geometry: Rect,
1514 parent: Option<XdgSurfaceViewPtr>,
1515 children: BTreeSet<u64>,
1516}
1517
1518type XdgSurfaceViewPtr = Arc<Mutex<XdgSurfaceView>>;
1519
1520impl XdgSurfaceView {
1521 fn present_internal(&mut self) {
1522 let surface_ref = self.surface;
1523 self.task_queue.post(move |client| Ok(Surface::present_internal(surface_ref, client)));
1524 }
1525
1526 fn update_and_present(&mut self) {
1527 self.update();
1528 self.present_internal();
1529 }
1530
1531 fn reconfigure(&self) {
1532 if self.logical_size.width != 0.0 && self.logical_size.height != 0.0 {
1536 let xdg_surface = self.xdg_surface;
1539 self.task_queue.post(move |client| XdgSurface::configure(xdg_surface, client))
1540 }
1541 }
1542
1543 fn compute_absolute_offset(
1544 parent: &Option<XdgSurfaceViewPtr>,
1545 physical_size: &Size,
1546 local_offset: &Option<(i32, i32)>,
1547 geometry: &Rect,
1548 ) -> (i32, i32) {
1549 parent.as_ref().map_or_else(
1551 ||
1552 (
1554 if geometry.width != 0 {
1555 (physical_size.width as i32 - geometry.width) / 2
1556 } else {
1557 0
1558 },
1559 if geometry.height != 0 {
1560 (physical_size.height as i32 - geometry.height) / 2
1561 } else {
1562 0
1563 }
1564 ),
1565 |parent| {
1566 local_offset.map_or_else(
1569 || {
1570 if physical_size.width != 0 && physical_size.height != 0 {
1571 (
1572 (physical_size.width as i32 - geometry.width) / 2,
1573 (physical_size.height as i32 - geometry.height) / 2,
1574 )
1575 } else {
1576 (0, 0)
1577 }
1578 },
1579 |(x, y)| {
1580 let parent_offset = parent.lock().absolute_offset();
1581 (parent_offset.0 + x, parent_offset.1 + y)
1582 },
1583 )
1584 },
1585 )
1586 }
1587
1588 fn update_absolute_offset(&mut self) {
1589 self.absolute_offset = Self::compute_absolute_offset(
1590 &self.parent,
1591 &self.physical_size(),
1592 &self.local_offset,
1593 &self.geometry,
1594 );
1595 }
1596
1597 fn absolute_offset(&self) -> (i32, i32) {
1598 self.absolute_offset
1599 }
1600
1601 fn parent(&self) -> Option<XdgSurfaceViewPtr> {
1602 self.parent.clone()
1603 }
1604
1605 fn xdg_surface(&self) -> ObjectRef<XdgSurface> {
1606 self.xdg_surface
1607 }
1608}
1609
1610impl XdgSurfaceView {
1611 pub fn new(
1612 flatland: FlatlandPtr,
1613 task_queue: TaskQueue,
1614 xdg_surface: ObjectRef<XdgSurface>,
1615 surface: ObjectRef<Surface>,
1616 parent: Option<XdgSurfaceViewPtr>,
1617 local_offset: Option<(i32, i32)>,
1618 geometry: Rect,
1619 ) -> Result<XdgSurfaceViewPtr, Error> {
1620 let logical_size = parent
1622 .as_ref()
1623 .map_or(SizeF { width: 0.0, height: 0.0 }, |parent| parent.lock().logical_size);
1624 let physical_size = Self::physical_size_internal(&logical_size);
1625 let absolute_offset =
1626 Self::compute_absolute_offset(&parent, &physical_size, &local_offset, &geometry);
1627 let root_transform = flatland.borrow_mut().alloc_transform_id();
1628 let container_transform = flatland.borrow_mut().alloc_transform_id();
1629 flatland.borrow().proxy().create_transform(&root_transform).expect("fidl error");
1630 flatland.borrow().proxy().create_transform(&container_transform).expect("fidl error");
1631 let view_controller = XdgSurfaceView {
1632 flatland,
1633 root_transform: Some(root_transform),
1634 container_transform,
1635 logical_size,
1636 local_offset,
1637 absolute_offset,
1638 task_queue,
1639 xdg_surface,
1640 surface,
1641 geometry,
1642 parent,
1643 children: BTreeSet::new(),
1644 };
1645 let view_controller = Arc::new(Mutex::new(view_controller));
1646 Ok(view_controller)
1647 }
1648
1649 pub fn finish_setup_scene(
1650 view_controller: &XdgSurfaceViewPtr,
1651 client: &mut Client,
1652 ) -> Result<(), Error> {
1653 ftrace::duration!(c"wayland", c"XdgSurfaceView::finish_setup_scene");
1654 let mut vc = view_controller.lock();
1655 vc.setup_scene();
1656 vc.attach(vc.surface, client)?;
1657
1658 if vc.logical_size.width != 0.0 && vc.logical_size.height != 0.0 {
1660 vc.update();
1661 vc.reconfigure();
1662 }
1663 vc.present_internal();
1664 Ok(())
1665 }
1666
1667 pub fn shutdown(&mut self) {
1668 self.root_transform.take().map(|_| {
1669 self.flatland.borrow().proxy().release_view().expect("fidl error");
1670 });
1671 }
1672
1673 fn physical_size_internal(logical_size: &SizeF) -> Size {
1674 Size {
1675 width: logical_size.width.round() as i32,
1676 height: logical_size.height.round() as i32,
1677 }
1678 }
1679
1680 pub fn physical_size(&self) -> Size {
1681 Self::physical_size_internal(&self.logical_size)
1682 }
1683
1684 fn attach(&self, surface: ObjectRef<Surface>, client: &Client) -> Result<(), Error> {
1685 ftrace::duration!(c"wayland", c"XdgSurfaceView::attach");
1686 let surface = surface.get(client)?;
1687 let surface_transform = surface.transform().expect("surface is missing a transform");
1688 self.flatland
1689 .borrow()
1690 .proxy()
1691 .add_child(&self.container_transform, &surface_transform)
1692 .expect("fidl error");
1693 Ok(())
1694 }
1695
1696 fn setup_scene(&self) {
1697 ftrace::duration!(c"wayland", c"XdgSurfaceView::setup_scene");
1698 self.root_transform.as_ref().map(|root_transform| {
1699 self.flatland.borrow().proxy().set_root_transform(&root_transform).expect("fidl error");
1700 self.flatland
1702 .borrow()
1703 .proxy()
1704 .add_child(&root_transform, &self.container_transform)
1705 .expect("fidl error");
1706 });
1707 }
1708
1709 fn update(&mut self) {
1710 ftrace::duration!(c"wayland", c"XdgSurfaceView::update");
1711 let translation = Vec_ { x: self.absolute_offset.0, y: self.absolute_offset.1 };
1712 self.flatland
1713 .borrow()
1714 .proxy()
1715 .set_translation(&self.container_transform, &translation)
1716 .expect("fidl error");
1717 }
1718
1719 pub fn handle_layout_changed(&mut self, logical_size: &SizeF) {
1720 ftrace::duration!(c"wayland", c"XdgSurfaceView::handle_layout_changed");
1721 if *logical_size != self.logical_size {
1722 self.logical_size = *logical_size;
1723 for id in &self.children {
1724 self.set_viewport_properties(*id);
1725 }
1726 self.update_absolute_offset();
1727 self.update_and_present();
1728 self.reconfigure();
1729 }
1730 }
1731
1732 pub fn set_geometry_and_local_offset(
1733 &mut self,
1734 geometry: &Rect,
1735 local_offset: &Option<(i32, i32)>,
1736 ) {
1737 ftrace::duration!(c"wayland", c"XdgSurfaceView::set_geometry_and_local_offset");
1738 self.geometry = *geometry;
1739 self.local_offset = *local_offset;
1740 let absolute_offset = Self::compute_absolute_offset(
1741 &self.parent,
1742 &self.physical_size(),
1743 &self.local_offset,
1744 &self.geometry,
1745 );
1746 if absolute_offset != self.absolute_offset {
1747 self.absolute_offset = absolute_offset;
1748 self.update_and_present();
1749 }
1750 }
1751
1752 pub fn add_child_view(
1753 &mut self,
1754 id: u64,
1755 viewport_creation_token: ViewportCreationToken,
1756 server_end: ServerEnd<ChildViewWatcherMarker>,
1757 ) {
1758 ftrace::duration!(c"wayland", c"XdgSurfaceView::add_child_view");
1759 let viewport_properties = ViewportProperties {
1760 logical_size: Some(SizeU {
1761 width: self.logical_size.width.round() as u32,
1762 height: self.logical_size.height.round() as u32,
1763 }),
1764 ..Default::default()
1765 };
1766 let child_transform = TransformId { value: id.into() };
1767 let link = ContentId { value: id.into() };
1768 self.flatland.borrow().proxy().create_transform(&child_transform).expect("fidl error");
1769 self.flatland
1770 .borrow()
1771 .proxy()
1772 .create_viewport(&link, viewport_creation_token, &viewport_properties, server_end)
1773 .expect("fidl error");
1774 self.flatland.borrow().proxy().set_content(&child_transform, &link).expect("fidl error");
1775 self.root_transform.as_ref().map(|root_transform| {
1776 self.flatland
1777 .borrow()
1778 .proxy()
1779 .add_child(&root_transform.clone(), &child_transform)
1780 .expect("fidl error");
1781 });
1782 self.children.insert(id);
1783 self.update_and_present();
1784 }
1785
1786 pub fn handle_view_disconnected(&mut self, id: u64) {
1787 ftrace::duration!(c"wayland", c"XdgSurfaceView::handle_view_disconnected");
1788 if self.children.remove(&id) {
1789 self.root_transform.as_ref().map(|root_transform| {
1790 let child_transform = TransformId { value: id.into() };
1791 self.flatland
1792 .borrow()
1793 .proxy()
1794 .remove_child(&root_transform, &child_transform)
1795 .expect("fidl error");
1796 self.flatland
1797 .borrow()
1798 .proxy()
1799 .release_transform(&child_transform)
1800 .expect("fidl error");
1801 let link = ContentId { value: id.into() };
1802 let _ = self.flatland.borrow().proxy().release_viewport(&link);
1803 });
1804 }
1805 self.update_and_present();
1806 }
1807
1808 fn set_viewport_properties(&self, id: u64) {
1809 let viewport_properties = ViewportProperties {
1810 logical_size: Some(SizeU {
1811 width: self.logical_size.width.round() as u32,
1812 height: self.logical_size.height.round() as u32,
1813 }),
1814 ..Default::default()
1815 };
1816 let link = ContentId { value: id.into() };
1817 self.flatland
1818 .borrow()
1819 .proxy()
1820 .set_viewport_properties(&link, &viewport_properties)
1821 .expect("fidl error");
1822 }
1823}
1824
1825#[cfg(test)]
1826mod tests {
1827 use super::*;
1828
1829 #[test]
1830 fn positioner_default() -> Result<(), Error> {
1831 let positioner = XdgPositioner::new();
1832 assert_eq!(Rect { x: 0, y: 0, width: 0, height: 0 }, positioner.get_geometry()?);
1833 Ok(())
1834 }
1835
1836 #[test]
1837 fn positioner_set_offset_and_size() -> Result<(), Error> {
1838 let mut positioner = XdgPositioner::new();
1839 positioner.set_offset(250, 550);
1840 positioner.set_size(100, 200);
1841 assert_eq!(Rect { x: 200, y: 450, width: 100, height: 200 }, positioner.get_geometry()?);
1842 Ok(())
1843 }
1844
1845 #[test]
1846 fn positioner_set_anchor_rect() -> Result<(), Error> {
1847 let mut positioner = XdgPositioner::new();
1848 positioner.set_offset(0, 0);
1849 positioner.set_size(168, 286);
1850 positioner.set_anchor_rect(486, 0, 44, 28);
1851 positioner.set_anchor(Enum::Recognized(Anchor::BottomLeft));
1852 positioner.set_gravity(Enum::Recognized(Gravity::BottomRight));
1853 assert_eq!(Rect { x: 486, y: 28, width: 168, height: 286 }, positioner.get_geometry()?);
1854 Ok(())
1855 }
1856}