1use std::{collections::HashMap, fmt::Debug, time::Duration};
4
5use futures_util::{Stream, TryFutureExt};
6use serde::{Deserialize, Serialize};
7use zbus::zvariant::{
8 DeserializeDict, ObjectPath, OwnedObjectPath, OwnedValue, SerializeDict, Type,
9};
10
11use super::{session::SessionPortal, HandleToken, Request, Session};
12use crate::{
13 desktop::session::CreateSessionResponse, proxy::Proxy, ActivationToken, Error, WindowIdentifier,
14};
15
16#[derive(Clone, SerializeDict, Type, Debug, Default)]
17#[zvariant(signature = "dict")]
18struct NewShortcutInfo {
19 description: String,
21 preferred_trigger: Option<String>,
24}
25
26#[derive(Clone, Serialize, Type, Debug)]
29pub struct NewShortcut(String, NewShortcutInfo);
30
31impl NewShortcut {
32 pub fn new(id: impl Into<String>, description: impl Into<String>) -> Self {
34 Self(
35 id.into(),
36 NewShortcutInfo {
37 description: description.into(),
38 preferred_trigger: None,
39 },
40 )
41 }
42
43 #[must_use]
46 pub fn preferred_trigger<'a>(mut self, preferred_trigger: impl Into<Option<&'a str>>) -> Self {
47 self.1.preferred_trigger = preferred_trigger.into().map(ToOwned::to_owned);
48 self
49 }
50}
51
52#[derive(Clone, DeserializeDict, Type, Debug, Default)]
53#[zvariant(signature = "dict")]
54struct ShortcutInfo {
55 description: String,
57 trigger_description: String,
60}
61
62#[derive(Clone, Deserialize, Type, Debug)]
67pub struct Shortcut(String, ShortcutInfo);
68
69impl Shortcut {
70 pub fn id(&self) -> &str {
72 &self.0
73 }
74
75 pub fn description(&self) -> &str {
77 &self.1.description
78 }
79
80 pub fn trigger_description(&self) -> &str {
83 &self.1.trigger_description
84 }
85}
86
87#[derive(SerializeDict, Type, Debug, Default)]
89#[zvariant(signature = "dict")]
90struct CreateSessionOptions {
91 handle_token: HandleToken,
93 session_handle_token: HandleToken,
95}
96
97#[derive(SerializeDict, Type, Debug, Default)]
99#[zvariant(signature = "dict")]
100struct BindShortcutsOptions {
101 handle_token: HandleToken,
103}
104
105#[derive(DeserializeDict, Type, Debug)]
107#[zvariant(signature = "dict")]
108pub struct BindShortcuts {
109 shortcuts: Vec<Shortcut>,
110}
111
112impl BindShortcuts {
113 pub fn shortcuts(&self) -> &[Shortcut] {
115 &self.shortcuts
116 }
117}
118
119#[derive(SerializeDict, Type, Debug)]
120#[zvariant(signature = "dict")]
121struct ConfigureShortcutsOptions {
122 activation_token: Option<ActivationToken>,
123}
124
125#[derive(SerializeDict, Type, Debug, Default)]
127#[zvariant(signature = "dict")]
128struct ListShortcutsOptions {
129 handle_token: HandleToken,
131}
132
133#[derive(DeserializeDict, Type, Debug)]
135#[zvariant(signature = "dict")]
136pub struct ListShortcuts {
137 shortcuts: Vec<Shortcut>,
139}
140
141impl ListShortcuts {
142 pub fn shortcuts(&self) -> &[Shortcut] {
144 &self.shortcuts
145 }
146}
147
148#[derive(Debug, Deserialize, Type)]
150pub struct Activated(OwnedObjectPath, String, u64, HashMap<String, OwnedValue>);
151
152impl Activated {
153 pub fn session_handle(&self) -> ObjectPath<'_> {
155 self.0.as_ref()
156 }
157
158 pub fn shortcut_id(&self) -> &str {
160 &self.1
161 }
162
163 pub fn timestamp(&self) -> Duration {
165 Duration::from_millis(self.2)
166 }
167
168 pub fn options(&self) -> &HashMap<String, OwnedValue> {
170 &self.3
171 }
172}
173
174#[derive(Debug, Deserialize, Type)]
176pub struct Deactivated(OwnedObjectPath, String, u64, HashMap<String, OwnedValue>);
177
178impl Deactivated {
179 pub fn session_handle(&self) -> ObjectPath<'_> {
181 self.0.as_ref()
182 }
183
184 pub fn shortcut_id(&self) -> &str {
186 &self.1
187 }
188
189 pub fn timestamp(&self) -> Duration {
191 Duration::from_millis(self.2)
192 }
193
194 pub fn options(&self) -> &HashMap<String, OwnedValue> {
196 &self.3
197 }
198}
199
200#[derive(Debug, Deserialize, Type)]
203pub struct ShortcutsChanged(OwnedObjectPath, Vec<Shortcut>);
204
205impl ShortcutsChanged {
206 pub fn session_handle(&self) -> ObjectPath<'_> {
208 self.0.as_ref()
209 }
210
211 pub fn shortcuts(&self) -> &[Shortcut] {
213 &self.1
214 }
215}
216
217#[derive(Debug)]
219#[doc(alias = "org.freedesktop.portal.GlobalShortcuts")]
220pub struct GlobalShortcuts<'a>(Proxy<'a>);
221
222impl<'a> GlobalShortcuts<'a> {
223 pub async fn new() -> Result<GlobalShortcuts<'a>, Error> {
225 let proxy = Proxy::new_desktop("org.freedesktop.portal.GlobalShortcuts").await?;
226 Ok(Self(proxy))
227 }
228
229 #[doc(alias = "CreateSession")]
235 pub async fn create_session(&self) -> Result<Session<'a, Self>, Error> {
236 let options = CreateSessionOptions::default();
237 let (request, proxy) = futures_util::try_join!(
238 self.0
239 .request::<CreateSessionResponse>(&options.handle_token, "CreateSession", &options)
240 .into_future(),
241 Session::from_unique_name(&options.session_handle_token).into_future(),
242 )?;
243 assert_eq!(proxy.path(), &request.response()?.session_handle.as_ref());
244 Ok(proxy)
245 }
246
247 #[doc(alias = "BindShortcuts")]
253 pub async fn bind_shortcuts(
254 &self,
255 session: &Session<'_, Self>,
256 shortcuts: &[NewShortcut],
257 identifier: Option<&WindowIdentifier>,
258 ) -> Result<Request<BindShortcuts>, Error> {
259 let options = BindShortcutsOptions::default();
260 let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
261 self.0
262 .request(
263 &options.handle_token,
264 "BindShortcuts",
265 &(session, shortcuts, identifier, &options),
266 )
267 .await
268 }
269
270 #[doc(alias = "ListShortcuts")]
276 pub async fn list_shortcuts(
277 &self,
278 session: &Session<'_, Self>,
279 ) -> Result<Request<ListShortcuts>, Error> {
280 let options = ListShortcutsOptions::default();
281 self.0
282 .request(&options.handle_token, "ListShortcuts", &(session, &options))
283 .await
284 }
285
286 #[doc(alias = "ConfigureShortcuts")]
293 pub async fn configure_shortcuts(
294 &self,
295 session: &Session<'_, Self>,
296 identifier: Option<&WindowIdentifier>,
297 activation_token: impl Into<Option<ActivationToken>>,
298 ) -> Result<(), Error> {
299 let options = ConfigureShortcutsOptions {
300 activation_token: activation_token.into(),
301 };
302 let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
303
304 self.0
305 .call_versioned::<()>("ConfigureShortcuts", &(session, identifier, options), 2)
306 .await
307 }
308
309 #[doc(alias = "Activated")]
315 pub async fn receive_activated(&self) -> Result<impl Stream<Item = Activated>, Error> {
316 self.0.signal("Activated").await
317 }
318
319 #[doc(alias = "Deactivated")]
325 pub async fn receive_deactivated(&self) -> Result<impl Stream<Item = Deactivated>, Error> {
326 self.0.signal("Deactivated").await
327 }
328
329 #[doc(alias = "ShortcutsChanged")]
336 pub async fn receive_shortcuts_changed(
337 &self,
338 ) -> Result<impl Stream<Item = ShortcutsChanged>, Error> {
339 self.0.signal("ShortcutsChanged").await
340 }
341}
342
343impl<'a> std::ops::Deref for GlobalShortcuts<'a> {
344 type Target = zbus::Proxy<'a>;
345
346 fn deref(&self) -> &Self::Target {
347 &self.0
348 }
349}
350
351impl crate::Sealed for GlobalShortcuts<'_> {}
352impl SessionPortal for GlobalShortcuts<'_> {}