wayland_bridge/
xdg_shell.rs

1// Copyright 2018 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::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
48// This must start at 1 to satisfy the ViewProducer protocol.
49static NEXT_VIEW_ID: AtomicUsize = AtomicUsize::new(1);
50
51// Annotations namespace for title.
52static TITLE_ANNOTATION_NS: &'static str = "ermine";
53
54// Title annotation value.
55static TITLE_ANNOTATION_VALUE: &'static str = "name";
56
57///
58/// Popup, dialog, and multiple toplevel window status:
59///
60/// The view system on Fuchsia is lacking support for these
61/// type of window management features today so we emulate them
62/// using child views.
63///
64/// Here are the child surface features currently implemented:
65///
66/// - XDG shell popups with static placement. Configured to only
67///   occupy the the desired area.
68/// - XDG shell toplevels without a parent. Configured to occupy
69///   the fullscreen area.
70/// - XDG shell toplevels with parent and dynamic offset set
71///   using the aura shell interface. Configured to only occupy
72///   the the desired area. This is used to implement X11
73///   override-redirect windows for tooltips and menus.
74/// - XDG shell toplevels without a parent but created after
75///   a view provider has already been created. These toplevels
76///   are created as child views of the root XDG surface.
77/// - Window controls are missing but XDG surfaces can be closed
78///   by pressing Escape key three times quickly.
79///
80
81/// `XdgShell` is an implementation of the xdg_wm_base global.
82///
83/// `XdgShell` is used to create traditional desktop-style applications. The
84/// `XdgShell` can be used to create `XdgSurface` objects. Similar to `Surface`,
85/// an `XdgSurface` doesn't do much good on it's own until it's assigned a
86/// sub-role (ex: `XdgToplevel`, `XdgPopup`).
87pub struct XdgShell;
88
89impl XdgShell {
90    /// Creates a new `XdgShell` global.
91    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
250/// An `XdgSurface` is the common base to the different surfaces in the
251/// `XdgShell` (ex: `XdgToplevel`, `XdgPopup`).
252pub struct XdgSurface {
253    /// A reference to the underlying `Surface` for this `XdgSurface`.
254    surface_ref: ObjectRef<Surface>,
255    /// A reference to the root `Surface` for this `XdgSurface`. The root surface
256    /// is the surface that can receive keyboard focus.
257    root_surface_ref: ObjectRef<Surface>,
258    /// The sub-role assigned to this `XdgSurface`. This is needed because the
259    /// `XdgSurface` is not a role itself, but a base for the concrete XDG
260    /// surface roles.
261    xdg_role: Option<XdgSurfaceRole>,
262    /// The associated scenic view for this `XdgSurface`. This will be
263    /// populated in response to requests to the public `ViewProvider` service,
264    /// or by creating an internal child view.
265    view: Option<XdgSurfaceViewPtr>,
266}
267
268impl XdgSurface {
269    /// Creates a new `XdgSurface`.
270    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    /// Returns a reference to the underlying `Surface` for this `XdgSurface`.
280    pub fn surface_ref(&self) -> ObjectRef<Surface> {
281        self.surface_ref
282    }
283
284    /// Returns a reference to the root `Surface` for this `XdgSurface`.
285    pub fn root_surface_ref(&self) -> ObjectRef<Surface> {
286        self.root_surface_ref
287    }
288
289    /// Sets the concrete role for this `XdgSurface`.
290    ///
291    /// Similar to `Surface`, an `XdgSurface` isn't of much use until a role
292    /// has been assigned.
293    pub fn set_xdg_role(&mut self, xdg_role: XdgSurfaceRole) -> Result<(), Error> {
294        ftrace::duration!(c"wayland", c"XdgSurface::set_xdg_role");
295        // The role is valid unless a different role has been assigned before.
296        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    /// Sets the backing view for this `XdgSurface`.
320    fn set_view(&mut self, view: XdgSurfaceViewPtr) {
321        // We shut down the ViewProvider after creating the first view, so this
322        // should never happen.
323        assert!(self.view.is_none());
324        self.view = Some(view);
325    }
326
327    /// Sets the root surface for this `XdgSurface`.
328    fn set_root_surface(&mut self, root_surface_ref: ObjectRef<Surface>) {
329        self.root_surface_ref = root_surface_ref;
330    }
331
332    /// Performs a surface configuration sequence.
333    ///
334    /// Each concrete `XdgSurface` role configuration sequence is concluded and
335    /// committed by a xdg_surface::configure event.
336    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    /// Handle a commit request to this `XdgSurface`.
355    ///
356    /// This will be triggered by a wl_surface::commit request to the backing
357    /// wl_surface object for this xdg_surface, and simply delegates the request
358    /// to the concrete surface.
359    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    /// Adds a child view to this `XdgSurface`.
407    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                                        // If our focus has changed we need to reconfigure so that the
791                                        // Activated flag can be set or cleared.
792                                        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/// Models the different roles that can be assigned to an `XdgSurface`.
905#[derive(Copy, Clone, Debug)]
906pub enum XdgSurfaceRole {
907    Popup(ObjectRef<XdgPopup>),
908    Toplevel(ObjectRef<XdgToplevel>),
909}
910
911pub struct XdgPopup {
912    /// A reference to the underlying wl_surface for this toplevel.
913    surface_ref: ObjectRef<Surface>,
914    /// A reference to the underlying xdg_surface for this toplevel.
915    xdg_surface_ref: ObjectRef<XdgSurface>,
916    /// This will be used to support reactive changes to positioner.
917    #[allow(dead_code)]
918    positioner_ref: ObjectRef<XdgPositioner>,
919    /// Popup geometry.
920    geometry: Rect,
921}
922
923impl XdgPopup {
924    /// Performs a configure sequence for the XdgPopup object referenced by
925    /// `this`.
926    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    /// Creates a new `XdgPopup` surface.
946    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                // We need to present here to commit the removal of our
975                // popup. This will inform our parent that our view has
976                // been destroyed.
977                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
989/// `XdgToplevel` is a surface that should appear as a top-level window.
990///
991/// `XdgToplevel` will be implemented as a scenic `View`/`ViewProvider` that
992/// hosts the surface contents. The actual presentation of the `View` will be
993/// deferred to whatever user shell is used.
994pub struct XdgToplevel {
995    /// A reference to the underlying wl_surface for this toplevel.
996    surface_ref: ObjectRef<Surface>,
997    /// A reference to the underlying xdg_surface for this toplevel.
998    xdg_surface_ref: ObjectRef<XdgSurface>,
999    /// This handle can be used to terminate the |ViewProvider| FIDL service
1000    /// associated with this toplevel.
1001    view_provider_controller: Option<ViewProviderControlHandle>,
1002    /// This proxy can be used to dismiss the |View| associated with this
1003    /// toplevel.
1004    view_controller_proxy: Option<ViewControllerProxy>,
1005    /// Identifier for the view.
1006    view_id: u32,
1007    /// This will be set to false after we received an initial commit.
1008    waiting_for_initial_commit: bool,
1009    /// A reference to an optional parent `XdgToplevel`.
1010    parent_ref: Option<ObjectRef<XdgToplevel>>,
1011    /// Optional title for `XdgToplevel`.
1012    title: Option<String>,
1013    /// Maximum size for `XdgToplevel`. A value of zero means no maximum
1014    /// size in the given dimension.
1015    max_size: Size,
1016}
1017
1018impl XdgToplevel {
1019    /// Performs a configure sequence for the XdgToplevel object referenced by
1020    /// `this`.
1021    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 the client determine the size if it has a parent.
1032            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 the surface doesn't have a parent, set the maximized state
1069        // to hint to the client it really should obey the geometry we're
1070        // asking for. From the xdg_shell spec:
1071        //
1072        // maximized:
1073        //    The surface is maximized. The window geometry specified in the
1074        //    configure event must be obeyed by the client.
1075        if maximized {
1076            states.push(xdg_toplevel::State::Maximized)?;
1077        }
1078        if client.input_dispatcher.has_focus(surface_ref) {
1079            // If the window has focus, we set the activated state. This is
1080            // just a hint to pass along to the client so it can draw itself
1081            // differently with and without focus.
1082            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    /// Sets the parent for this `XdgToplevel`.
1092    pub fn set_parent(&mut self, parent: Option<ObjectRef<XdgToplevel>>) {
1093        self.parent_ref = parent;
1094    }
1095
1096    /// Sets the title for this `XdgToplevel`.
1097    fn set_title(&mut self, title: Option<String>) {
1098        self.title = title;
1099    }
1100
1101    /// Sets the maximum size for this `XdgToplevel`.
1102    ///
1103    /// Returns true iff the new size is different from the previous value.
1104    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    /// Creates a new `XdgToplevel` surface.
1118    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        // Create a new ViewProvider service, hand off the client endpoint to
1145        // our ViewSink to be presented.
1146        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        // Spawn the view provider server for this surface.
1151        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                // This only supports a single view, so this is an "if" instead of a "while".  For
1159                // example, we move `flatland` into the XdgSurfaceView we create below, so it
1160                // wouldn't be available for a subsequent iteration of the loop.  This would need to
1161                // be restructured to handle subsequent requests.
1162                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                // See previous comment about only supporting a single view.  Here, we ensure that
1235                // our client never asks us to create a second view.
1236                if let Some(request) = stream.try_next().await.unwrap() {
1237                    panic!("unsupported view provider request: {:?}", request)
1238                }
1239
1240                task_queue.post(|_client| {
1241                    // Returning an error causes the client connection to be
1242                    // closed (and that typically closes the application).
1243                    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                // Wait for stream to close.
1338                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        // Initial commit requires that we spawn a view and send a configure event.
1355        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            // Spawn a child view if `XdgToplevel` has a parent or there's an existing
1365            // `XdgSurface` that can be used as parent.
1366            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            // Initial commit requires that we send a configure event.
1396            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            // Maybe move keyboard focus to this XDG surface.
1401            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                    // Move keyboard focus to new event target.
1450                    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                // We need to present here to commit the removal of our
1460                // toplevel. This will inform our parent that our view has
1461                // been destroyed.
1462                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
1499/// A scenic view implementation to back an |XdgSurface| resource.
1500///
1501/// An `XdgSurfaceView` will be created by the `ViewProvider` for an
1502/// `XdgSurface`.
1503struct 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 we have both a size and a pixel scale, we're ready to send the
1533        // configure event to the client. We need both because we send expose
1534        // physical pixels to the client.
1535        if self.logical_size.width != 0.0 && self.logical_size.height != 0.0 {
1536            // Post the xdg_toplevel::configure event to inform the client about
1537            // the change.
1538            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        // Use local offset if we have a parent view.
1550        parent.as_ref().map_or_else(
1551            ||
1552            // Center in available space if geometry is non-zero.
1553            (
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                // Center in available space by default and relative to parent if
1567                // local offset is set.
1568                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        // Get initial size from parent if available.
1621        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        // Perform an update if we have an initial size.
1659        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            // TODO(https://fxbug.dev/42172143): Add background color if there's no parent.
1701            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}