@@ -6,7 +6,7 @@ use std::{collections::HashMap, mem};
66use tokio:: sync:: mpsc:: Sender ;
77use zbus:: zvariant;
88
9- use crate :: screencast_dialog;
9+ use crate :: screencast_dialog:: { self , CaptureSources } ;
1010use crate :: screencast_thread:: ScreencastThread ;
1111use crate :: subscription;
1212use crate :: wayland:: { CaptureSource , WaylandHelper } ;
@@ -26,6 +26,91 @@ struct CreateSessionResult {
2626 session_id : String ,
2727}
2828
29+ #[ derive( Clone ) ]
30+ struct PersistedCaptureSources {
31+ pub outputs : Vec < String > ,
32+ pub toplevels : Vec < String > ,
33+ }
34+
35+ impl PersistedCaptureSources {
36+ fn from_capture_sources (
37+ wayland_helper : & WaylandHelper ,
38+ sources : & CaptureSources ,
39+ ) -> Option < Self > {
40+ let mut outputs = Vec :: new ( ) ;
41+ for handle in & sources. outputs {
42+ let info = wayland_helper. output_info ( handle) ?;
43+ outputs. push ( info. name . clone ( ) ?) ;
44+ }
45+
46+ let mut toplevels = Vec :: new ( ) ;
47+ let toplevel_infos = wayland_helper. toplevels ( ) ;
48+ for handle in & sources. toplevels {
49+ let info = toplevel_infos
50+ . iter ( )
51+ . find ( |t| t. foreign_toplevel == * handle) ?;
52+ toplevels. push ( info. identifier . clone ( ) ) ;
53+ }
54+
55+ Some ( Self { outputs, toplevels } )
56+ }
57+
58+ fn to_capture_sources ( & self , wayland_helper : & WaylandHelper ) -> Option < CaptureSources > {
59+ let mut outputs = Vec :: new ( ) ;
60+ for name in & self . outputs {
61+ outputs. push ( wayland_helper. output_for_name ( name) ?) ;
62+ }
63+
64+ let mut toplevels = Vec :: new ( ) ;
65+ let toplevel_infos = wayland_helper. toplevels ( ) ;
66+ for identifier in & self . toplevels {
67+ let info = toplevel_infos
68+ . iter ( )
69+ . find ( |t| t. identifier == * identifier) ?;
70+ toplevels. push ( info. foreign_toplevel . clone ( ) ) ;
71+ }
72+
73+ Some ( CaptureSources { outputs, toplevels } )
74+ }
75+ }
76+
77+ #[ derive( Debug , serde:: Serialize , serde:: Deserialize , zvariant:: Type ) ]
78+ #[ zvariant( signature = "(suv)" ) ]
79+ struct RestoreData {
80+ vendor : String ,
81+ version : u32 ,
82+ data : zvariant:: OwnedValue ,
83+ }
84+
85+ impl From < PersistedCaptureSources > for RestoreData {
86+ fn from ( sources : PersistedCaptureSources ) -> RestoreData {
87+ RestoreData {
88+ vendor : "COSMIC" . to_string ( ) ,
89+ version : 1 ,
90+ data : zvariant:: Value :: from ( zvariant:: Structure :: from ( (
91+ sources. outputs ,
92+ sources. toplevels ,
93+ ) ) )
94+ . try_to_owned ( )
95+ . unwrap ( ) ,
96+ }
97+ }
98+ }
99+
100+ impl TryFrom < & RestoreData > for PersistedCaptureSources {
101+ type Error = ( ) ;
102+ fn try_from ( restore_data : & RestoreData ) -> Result < Self , ( ) > {
103+ if ( & * restore_data. vendor , restore_data. version ) != ( "COSMIC" , 1 ) {
104+ return Err ( ( ) ) ;
105+ }
106+ let structure = zvariant:: Structure :: try_from ( & * restore_data. data ) . map_err ( |_| ( ) ) ?;
107+ let ( outputs, toplevels) = structure. try_into ( ) . map_err ( |_| ( ) ) ?;
108+ Ok ( PersistedCaptureSources { outputs, toplevels } )
109+ }
110+ }
111+
112+ // TODO TryFrom
113+
29114#[ derive( zvariant:: DeserializeDict , zvariant:: Type ) ]
30115#[ zvariant( signature = "a{sv}" ) ]
31116struct SelectSourcesOptions {
@@ -34,7 +119,7 @@ struct SelectSourcesOptions {
34119 // Default: false
35120 multiple : Option < bool > ,
36121 cursor_mode : Option < u32 > ,
37- restore_data : Option < ( String , u32 , zvariant :: OwnedValue ) > ,
122+ restore_data : Option < RestoreData > ,
38123 // Default: 0
39124 persist_mode : Option < u32 > ,
40125}
@@ -44,7 +129,7 @@ struct SelectSourcesOptions {
44129struct StartResult {
45130 streams : Vec < ( u32 , HashMap < String , zvariant:: OwnedValue > ) > ,
46131 persist_mode : Option < u32 > ,
47- restore_data : Option < ( String , u32 , zvariant :: OwnedValue ) > ,
132+ restore_data : Option < RestoreData > ,
48133}
49134
50135#[ derive( Default ) ]
@@ -53,6 +138,7 @@ struct SessionData {
53138 cursor_mode : Option < u32 > ,
54139 multiple : bool ,
55140 source_types : BitFlags < SourceType > ,
141+ persisted_capture_sources : Option < PersistedCaptureSources > ,
56142 closed : bool ,
57143}
58144
@@ -120,6 +206,13 @@ impl ScreenCast {
120206 if session_data. source_types . is_empty ( ) {
121207 session_data. source_types = SourceType :: Monitor . into ( ) ;
122208 }
209+ if let Some ( restore_data) = & options. restore_data {
210+ if let Ok ( persisted_capture_sources) = restore_data. try_into ( ) {
211+ session_data. persisted_capture_sources = Some ( persisted_capture_sources) ;
212+ } else {
213+ log:: warn!( "unrecognized screencopy restore data: {:?}" , restore_data) ;
214+ }
215+ }
123216 PortalResponse :: Success ( HashMap :: new ( ) )
124217 }
125218 None => PortalResponse :: Other ,
@@ -143,12 +236,18 @@ impl ScreenCast {
143236 return PortalResponse :: Other ;
144237 } ;
145238
146- let ( cursor_mode, multiple, source_types) = {
239+ let ( cursor_mode, multiple, source_types, persisted_capture_sources ) = {
147240 let session_data = interface. get_mut ( ) . await ;
148241 let cursor_mode = session_data. cursor_mode . unwrap_or ( CURSOR_MODE_HIDDEN ) ;
149242 let multiple = session_data. multiple ;
150243 let source_types = session_data. source_types ;
151- ( cursor_mode, multiple, source_types)
244+ let persisted_capture_sources = session_data. persisted_capture_sources . clone ( ) ;
245+ (
246+ cursor_mode,
247+ multiple,
248+ source_types,
249+ persisted_capture_sources,
250+ )
152251 } ;
153252
154253 // XXX
@@ -158,31 +257,38 @@ impl ScreenCast {
158257 return PortalResponse :: Other ;
159258 }
160259
161- // Show dialog to prompt for what to capture
162- let resp = screencast_dialog:: show_screencast_prompt (
163- & self . tx ,
164- & session_handle,
165- app_id,
166- multiple,
167- source_types,
168- & self . wayland_helper ,
169- )
170- . await ;
171- let Some ( capture_sources) = resp else {
172- return PortalResponse :: Cancelled ;
260+ let capture_sources = if let Some ( capture_sources) =
261+ persisted_capture_sources. and_then ( |x| x. to_capture_sources ( & self . wayland_helper ) )
262+ {
263+ capture_sources
264+ } else {
265+ // Show dialog to prompt for what to capture
266+ let resp = screencast_dialog:: show_screencast_prompt (
267+ & self . tx ,
268+ & session_handle,
269+ app_id,
270+ multiple,
271+ source_types,
272+ & self . wayland_helper ,
273+ )
274+ . await ;
275+ let Some ( capture_sources) = resp else {
276+ return PortalResponse :: Cancelled ;
277+ } ;
278+ capture_sources
173279 } ;
174280
175281 let overlay_cursor = cursor_mode == CURSOR_MODE_EMBEDDED ;
176282 // Use `FuturesOrdered` so streams are in consistent order
177283 let mut res_futures = FuturesOrdered :: new ( ) ;
178- for output in capture_sources. outputs {
284+ for output in & capture_sources. outputs {
179285 res_futures. push_back ( ScreencastThread :: new (
180286 self . wayland_helper . clone ( ) ,
181- CaptureSource :: Output ( output) ,
287+ CaptureSource :: Output ( output. clone ( ) ) ,
182288 overlay_cursor,
183289 ) ) ;
184290 }
185- for foreign_toplevel in capture_sources. toplevels {
291+ for foreign_toplevel in & capture_sources. toplevels {
186292 res_futures. push_back ( ScreencastThread :: new (
187293 self . wayland_helper . clone ( ) ,
188294 CaptureSource :: Toplevel ( foreign_toplevel. clone ( ) ) ,
@@ -224,11 +330,15 @@ impl ScreenCast {
224330 . collect ( ) ;
225331 interface. get_mut ( ) . await . screencast_threads = screencast_threads;
226332
333+ let persisted_capture_sources = PersistedCaptureSources :: from_capture_sources (
334+ & self . wayland_helper ,
335+ & capture_sources,
336+ ) ;
337+
227338 PortalResponse :: Success ( StartResult {
228- // XXX
229339 streams,
230340 persist_mode : None ,
231- restore_data : None ,
341+ restore_data : persisted_capture_sources . map ( |x| x . into ( ) ) ,
232342 } )
233343 } )
234344 . await
0 commit comments