Skip to content

Commit b68e941

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 321e969 + 2322f12 commit b68e941

File tree

11 files changed

+387
-302
lines changed

11 files changed

+387
-302
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
allow = Autoriser
2+
cancel = Annuler
3+
capture = Capturer
4+
share = Partager
5+
save-to = Enregistrer dans
6+
.clipboard = { save-to } Presse-papiers
7+
.pictures = { save-to } Images
8+
.documents = { save-to } Documents
9+
choose-folder = Choisir un dossier
10+
11+
share-screen = Partager votre écran
12+
.description = Le système souhaite partager le contenu de votre écran avec "{$app_name}". Sélectionnez un écran ou une fenêtre à partager.
13+
unknown-application = Application inconnue
14+
output = Sortie
15+
window = Fenêtre
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
allow = Ceadaigh
2+
cancel = Cealaigh
3+
capture = Gabh
4+
share = Comhroinn
5+
save-to = Sábháil i
6+
.clipboard = { save-to } Gearrthaisce
7+
.pictures = { save-to } Pictiúir
8+
.documents = { save-to } Cáipéisí
9+
choose-folder = Roghnaigh fillteán
10+
11+
share-screen = Comhroinn do scáileán
12+
.description = Teastaíonn ón gcóras ábhar do scáileáin a chomhroinnt le "{$app_name}". Roghnaigh scáileán nó fuinneog le comhroinnt.
13+
unknown-application = Aip Anaithnid
14+
output = Aschur
15+
window = Fuinneog
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
allow = Permitir
2+
cancel = Cancelar
3+
capture = Capturar
4+
share = Compartilhar
5+
save-to = Guardar em
6+
.clipboard = { save-to } Área de transferências
7+
.pictures = { save-to } Imagens
8+
.documents = { save-to } Documentos
9+
choose-folder = Escolher pasta
10+
11+
share-screen = Compartilhar o ecrã
12+
.description = O sistema quer compartilhar o conteúdo do ecrã com "{$app_name}". Selecione um ecrã ou uma janela para compartilhar.
13+
unknown-application = Aplicação Desconhecida
14+
output = Saída
15+
window = Janela
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
allow = Permite
2+
cancel = Anulează
3+
capture = Capturează
4+
share = Partajează
5+
save-to = Salvează în
6+
.clipboard = { save-to } Clipboard
7+
.pictures = { save-to } Poze
8+
.documents = { save-to } Documente
9+
choose-folder = Alege un folder
10+
11+
share-screen = Partajează-ți ecranul
12+
.description = Sistemul vrea să partajeze conținutul ecranului tău cu „{$app_name}”. Selectează un ecran sau o fereastră pentru a-l partaja.
13+
unknown-application = Aplicație necunoscută
14+
output = Ieșire
15+
window = Fereastră
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
allow = 允许
2+
cancel = 取消
3+
capture = 捕获
4+
share = 分享
5+
save-to = 保存到
6+
.clipboard = { save-to } 剪贴板
7+
.pictures = { save-to } 图片
8+
.documents = { save-to } 文档
9+
choose-folder = 选择文件夹
10+
11+
share-screen = 分享屏幕
12+
.description = 系统想要将你的屏幕内容分享给 "{$app_name}" ,请选择一个屏幕或窗口来分享。
13+
unknown-application = 未知应用程序
14+
output = 输出
15+
window = 窗口

src/app.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::{access, config, file_chooser, fl, screencast_dialog, screenshot, subscription};
1+
use crate::{access, config, file_chooser, screencast_dialog, screenshot, subscription};
22
use cosmic::iced_core::event::wayland::OutputEvent;
3-
use cosmic::widget::{self, dropdown};
3+
use cosmic::widget;
44
use cosmic::Task;
55
use cosmic::{
66
app, cosmic_config,
@@ -100,25 +100,6 @@ impl cosmic::Application for CosmicPortal {
100100
config,
101101
}: Self::Flags,
102102
) -> (Self, cosmic::iced::Task<cosmic::Action<Self::Message>>) {
103-
let mut model = cosmic::widget::dropdown::multi::model();
104-
model.insert(dropdown::multi::list(
105-
Some(fl!("save-to")),
106-
vec![
107-
(
108-
fl!("save-to", "clipboard"),
109-
config::screenshot::ImageSaveLocation::Clipboard,
110-
),
111-
(
112-
fl!("save-to", "pictures"),
113-
config::screenshot::ImageSaveLocation::Pictures,
114-
),
115-
(
116-
fl!("save-to", "documents"),
117-
config::screenshot::ImageSaveLocation::Documents,
118-
),
119-
],
120-
));
121-
model.selected = Some(config.screenshot.save_location);
122103
let wayland_conn = crate::wayland::connect_to_wayland();
123104
let wayland_helper = crate::wayland::WaylandHelper::new(wayland_conn);
124105
(

src/screencast.rs

Lines changed: 132 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{collections::HashMap, mem};
66
use tokio::sync::mpsc::Sender;
77
use zbus::zvariant;
88

9-
use crate::screencast_dialog;
9+
use crate::screencast_dialog::{self, CaptureSources};
1010
use crate::screencast_thread::ScreencastThread;
1111
use crate::subscription;
1212
use 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}")]
31116
struct 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 {
44129
struct 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

Comments
 (0)