forked from YaLTeR/niri
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xdg-desktop-portal: add basic support for access dialogs
Accessing certain devices like cameras might require permissions. This is handled in xdg-desktop-portal by issuing an access dialog. The backend is expected to expose the org.freedesktop.impl.portal.Access dbus interface.
- Loading branch information
Showing
10 changed files
with
398 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
[preferred] | ||
default=gnome;gtk; | ||
org.freedesktop.impl.portal.Access=niri; | ||
org.freedesktop.impl.portal.Secret=gnome-keyring; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[portal] | ||
DBusName=org.freedesktop.impl.portal.desktop.niri | ||
Interfaces=org.freedesktop.impl.portal.Access; | ||
UseIn=niri |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
use std::ops::Not; | ||
|
||
use zbus::dbus_interface; | ||
|
||
use super::Start; | ||
|
||
pub struct AccessPortalImpl { | ||
to_niri: calloop::channel::Sender<AccessDialogRequest>, | ||
} | ||
|
||
#[dbus_interface(name = "org.freedesktop.impl.portal.Access")] | ||
impl AccessPortalImpl { | ||
/// AccessDialog method | ||
#[allow(clippy::too_many_arguments)] | ||
async fn access_dialog( | ||
&self, | ||
_handle: zbus::zvariant::ObjectPath<'_>, | ||
app_id: &str, | ||
parent_window: &str, | ||
title: &str, | ||
subtitle: &str, | ||
body: &str, | ||
options: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>, | ||
) -> zbus::fdo::Result<( | ||
u32, | ||
std::collections::HashMap<String, zbus::zvariant::OwnedValue>, | ||
)> { | ||
let (response_channel_sender, response_channel_receiver) = async_channel::bounded(1); | ||
|
||
let options = AccessDialogOptions::from_options(options); | ||
let request = AccessDialogRequest { | ||
app_id: app_id.to_string(), | ||
parent_window: parent_window | ||
.is_empty() | ||
.not() | ||
.then(|| parent_window.to_string()), | ||
title: title.to_string(), | ||
subtitle: subtitle.to_string(), | ||
body: body.is_empty().not().then(|| body.to_string()), | ||
options, | ||
|
||
response_channel_sender, | ||
}; | ||
|
||
if let Err(err) = self.to_niri.send(request) { | ||
tracing::warn!(?err, "failed to send access dialog request"); | ||
return Ok((2, Default::default())); | ||
}; | ||
|
||
let result = std::collections::HashMap::<String, zbus::zvariant::OwnedValue>::new(); | ||
let response = match response_channel_receiver.recv().await { | ||
Ok(AccessDialogResponse::Grant) => { | ||
// FIXME: Add selected choices to the result | ||
0 | ||
} | ||
Ok(AccessDialogResponse::Deny) => 1, | ||
Err(err) => { | ||
tracing::warn!(?err, "failed to receive response for access dialog request"); | ||
return Ok((2, Default::default())); | ||
} | ||
}; | ||
|
||
return Ok((response, result)); | ||
} | ||
} | ||
|
||
impl AccessPortalImpl { | ||
pub fn new(to_niri: calloop::channel::Sender<AccessDialogRequest>) -> Self { | ||
Self { to_niri } | ||
} | ||
} | ||
|
||
impl Start for AccessPortalImpl { | ||
fn start(self) -> anyhow::Result<zbus::blocking::Connection> { | ||
let conn = zbus::blocking::ConnectionBuilder::session()? | ||
.name("org.freedesktop.impl.portal.desktop.niri")? | ||
.serve_at("/org/freedesktop/portal/desktop", self)? | ||
.build()?; | ||
Ok(conn) | ||
} | ||
} | ||
|
||
pub struct AccessDialogRequest { | ||
pub app_id: String, | ||
pub parent_window: Option<String>, | ||
pub title: String, | ||
pub subtitle: String, | ||
pub body: Option<String>, | ||
pub options: AccessDialogOptions, | ||
|
||
response_channel_sender: async_channel::Sender<AccessDialogResponse>, | ||
} | ||
|
||
pub struct AccessDialogOptions { | ||
/// Whether to make the dialog modal. Defaults to true. | ||
pub modal: bool, | ||
/// Label for the Deny button. | ||
pub deny_label: Option<String>, | ||
/// Label for the Grant button. | ||
pub grant_label: Option<String>, | ||
/// Icon name for an icon to show in the dialog. This should be a symbolic icon name. | ||
pub icon: Option<String>, | ||
} | ||
|
||
impl AccessDialogOptions { | ||
fn from_options(options: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>) -> Self { | ||
let modal: bool = options | ||
.get("modal") | ||
.and_then(|option| option.downcast_ref()) | ||
.copied() | ||
.unwrap_or(true); | ||
let deny_label: Option<String> = options | ||
.get("deny_label") | ||
.and_then(|option| option.clone().downcast()); | ||
let grant_label: Option<String> = options | ||
.get("grant_label") | ||
.and_then(|option| option.clone().downcast()); | ||
let icon: Option<String> = options | ||
.get("icon") | ||
.and_then(|option| option.clone().downcast()); | ||
|
||
// FIXME: Add support for choices | ||
|
||
Self { | ||
modal, | ||
deny_label, | ||
grant_label, | ||
icon, | ||
} | ||
} | ||
} | ||
|
||
impl AccessDialogRequest { | ||
pub fn grant(self) -> anyhow::Result<()> { | ||
self.response_channel_sender | ||
.send_blocking(AccessDialogResponse::Grant)?; | ||
Ok(()) | ||
} | ||
|
||
pub fn deny(self) -> anyhow::Result<()> { | ||
self.response_channel_sender | ||
.send_blocking(AccessDialogResponse::Deny)?; | ||
Ok(()) | ||
} | ||
} | ||
|
||
pub enum AccessDialogResponse { | ||
Grant, | ||
Deny, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.