shared_screen.rs

  1use crate::{
  2    item::{Item, ItemEvent},
  3    ItemNavHistory, Pane, WorkspaceId,
  4};
  5use anyhow::Result;
  6use call::participant::{Frame, RemoteVideoTrack};
  7use client::{proto::PeerId, User};
  8use futures::StreamExt;
  9use gpui::{
 10    elements::*,
 11    geometry::{rect::RectF, vector::vec2f},
 12    platform::MouseButton,
 13    AppContext, Entity, Task, View, ViewContext,
 14};
 15use settings::Settings;
 16use smallvec::SmallVec;
 17use std::sync::{Arc, Weak};
 18
 19pub enum Event {
 20    Close,
 21}
 22
 23pub struct SharedScreen {
 24    track: Weak<RemoteVideoTrack>,
 25    frame: Option<Frame>,
 26    pub peer_id: PeerId,
 27    user: Arc<User>,
 28    nav_history: Option<ItemNavHistory>,
 29    _maintain_frame: Task<Result<()>>,
 30}
 31
 32impl SharedScreen {
 33    pub fn new(
 34        track: &Arc<RemoteVideoTrack>,
 35        peer_id: PeerId,
 36        user: Arc<User>,
 37        cx: &mut ViewContext<Self>,
 38    ) -> Self {
 39        let mut frames = track.frames();
 40        Self {
 41            track: Arc::downgrade(track),
 42            frame: None,
 43            peer_id,
 44            user,
 45            nav_history: Default::default(),
 46            _maintain_frame: cx.spawn(|this, mut cx| async move {
 47                while let Some(frame) = frames.next().await {
 48                    this.update(&mut cx, |this, cx| {
 49                        this.frame = Some(frame);
 50                        cx.notify();
 51                    })?;
 52                }
 53                this.update(&mut cx, |_, cx| cx.emit(Event::Close))?;
 54                Ok(())
 55            }),
 56        }
 57    }
 58}
 59
 60impl Entity for SharedScreen {
 61    type Event = Event;
 62}
 63
 64impl View for SharedScreen {
 65    fn ui_name() -> &'static str {
 66        "SharedScreen"
 67    }
 68
 69    fn render(&mut self, cx: &mut ViewContext<Self>) -> Element<Self> {
 70        enum Focus {}
 71
 72        let frame = self.frame.clone();
 73        MouseEventHandler::<Focus, _>::new(0, cx, |_, cx| {
 74            Canvas::new(move |scene, bounds, _, _, _| {
 75                if let Some(frame) = frame.clone() {
 76                    let size = constrain_size_preserving_aspect_ratio(
 77                        bounds.size(),
 78                        vec2f(frame.width() as f32, frame.height() as f32),
 79                    );
 80                    let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
 81                    scene.push_surface(gpui::platform::mac::Surface {
 82                        bounds: RectF::new(origin, size),
 83                        image_buffer: frame.image(),
 84                    });
 85                }
 86            })
 87            .contained()
 88            .with_style(cx.global::<Settings>().theme.shared_screen)
 89            .boxed()
 90        })
 91        .on_down(MouseButton::Left, |_, _, cx| cx.focus_parent_view())
 92        .boxed()
 93    }
 94}
 95
 96impl Item for SharedScreen {
 97    fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
 98        if let Some(nav_history) = self.nav_history.as_ref() {
 99            nav_history.push::<()>(None, cx);
100        }
101    }
102
103    fn tab_content(
104        &self,
105        _: Option<usize>,
106        style: &theme::Tab,
107        _: &AppContext,
108    ) -> gpui::Element<Pane> {
109        Flex::row()
110            .with_child(
111                Svg::new("icons/disable_screen_sharing_12.svg")
112                    .with_color(style.label.text.color)
113                    .constrained()
114                    .with_width(style.type_icon_width)
115                    .aligned()
116                    .contained()
117                    .with_margin_right(style.spacing)
118                    .boxed(),
119            )
120            .with_child(
121                Label::new(
122                    format!("{}'s screen", self.user.github_login),
123                    style.label.clone(),
124                )
125                .aligned()
126                .boxed(),
127            )
128            .boxed()
129    }
130
131    fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
132        self.nav_history = Some(history);
133    }
134
135    fn clone_on_split(
136        &self,
137        _workspace_id: WorkspaceId,
138        cx: &mut ViewContext<Self>,
139    ) -> Option<Self> {
140        let track = self.track.upgrade()?;
141        Some(Self::new(&track, self.peer_id, self.user.clone(), cx))
142    }
143
144    fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
145        match event {
146            Event::Close => smallvec::smallvec!(ItemEvent::CloseItem),
147        }
148    }
149}