Skip to content

Commit

Permalink
Add activation_token
Browse files Browse the repository at this point in the history
Fixes: #55
  • Loading branch information
A6GibKm committed Jan 4, 2023
1 parent 1849b0a commit 4a772b4
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 11 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ gdk3x11 = {package = "gdkx11", version = "0.16", optional = true}
gdk3wayland = {package = "gdkwayland", version = "0.16", optional = true}
gtk3 = {package = "gtk", version = "0.16", optional = true}

gdk4wayland = {package = "gdk4-wayland", version = "0.5", optional = true}
gdk4wayland = {package = "gdk4-wayland", version = "0.5", optional = true, features = ["wayland_crate"]}
gdk4x11 = {package = "gdk4-x11", version = "0.5", optional = true}
gtk4 = {version = "0.5", optional = true}

Expand All @@ -44,7 +44,7 @@ tracing = {version = "0.1", optional = true}
libc = {version = "0.2", optional = true}
raw-window-handle = {version = "0.5", optional = true}
wayland-client = {version = "0.30", optional = true}
wayland-protocols = {version = "0.30", optional = true, features = ["unstable", "client"]}
wayland-protocols = {version = "0.30", optional = true, features = ["unstable", "client", "staging"]}
wayland-backend = {version = "0.1", optional = true, features = ["client_system"]}
async-std = {version = "1.12", optional = true}
tokio = {version = "1.21", features = ["fs", "io-util"], optional = true, default-features = false}
Expand Down
9 changes: 7 additions & 2 deletions ashpd-demo/src/portals/desktop/open_uri.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use ashpd::{desktop::open_uri, WindowIdentifier};
use ashpd::{desktop::open_uri, ActivationToken, WindowIdentifier};
use gtk::{glib, prelude::*, subclass::prelude::*};

use crate::widgets::{NotificationKind, PortalPage, PortalPageExt, PortalPageImpl};
use crate::{
config::APP_ID,
widgets::{NotificationKind, PortalPage, PortalPageExt, PortalPageImpl},
};

mod imp {
use adw::subclass::prelude::*;
Expand Down Expand Up @@ -59,11 +62,13 @@ impl OpenUriPage {
let ask = imp.ask_switch.is_active();
let root = self.native().unwrap();
let identifier = WindowIdentifier::from_native(&root).await;
let activation_token = ActivationToken::from_native(APP_ID, &root).await;
match url::Url::parse(&imp.uri_entry.text()) {
Ok(uri) => {
let request = open_uri::OpenFileRequest::default()
.ask(ask)
.writeable(writeable)
.activation_token(activation_token)
.identifier(identifier);
match request.build_uri(&uri).await {
Ok(_) => {
Expand Down
17 changes: 17 additions & 0 deletions src/activation_token/gtk3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use gtk3::prelude::*;
use gtk3::{gdk, glib};

#[derive(Debug)]
pub struct Gtk3ActivationToken {
pub(crate) token: String,
}

impl Gtk3ActivationToken {
pub fn from_window(window: &impl glib::IsA<gdk::Window>) -> Option<Self> {
let display = window.as_ref().display();
match display.backend() {
gdk::Backend::Wayland => todo!(),
_ => None,
}
}
}
40 changes: 40 additions & 0 deletions src/activation_token/gtk4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#[cfg(feature = "wayland")]
use super::wayland::WaylandActivationToken;
use gdk4wayland::prelude::WaylandSurfaceExtManual;
use gtk4::{gdk, glib, prelude::*};

#[derive(Debug)]
pub struct Gtk4ActivationToken {
pub(crate) wl_token: WaylandActivationToken,
}

#[cfg(all(feature = "gtk4_wayland", feature = "wayland"))]
impl Gtk4ActivationToken {
pub async fn from_native<N: glib::IsA<gtk4::Native>>(app_id: &str, native: &N) -> Option<Self> {
let surface = native.surface();
match surface.display().backend() {
gdk::Backend::Wayland => {
let surface = surface
.downcast_ref::<gdk4wayland::WaylandSurface>()
.unwrap();
if let Some(wl_surface) = surface.wl_surface() {
let wl_token = WaylandActivationToken::from_surface(app_id, &wl_surface)
.await
.unwrap();

Some(Self { wl_token })
} else {
None
}
}
_ => None,
}
}
}

#[cfg(feature = "wayland")]
impl From<WaylandActivationToken> for Gtk4ActivationToken {
fn from(wl_token: WaylandActivationToken) -> Self {
Self { wl_token }
}
}
149 changes: 149 additions & 0 deletions src/activation_token/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#[cfg(all(feature = "gtk3", feature = "wayland"))]
mod gtk3;
#[cfg(all(feature = "gtk3", feature = "wayland"))]
pub use self::gtk3::Gtk3ActivationToken;

#[cfg(feature = "gtk4_wayland")]
mod gtk4;
#[cfg(feature = "gtk4_wayland")]
pub use self::gtk4::Gtk4ActivationToken;

#[cfg(any(feature = "wayland"))]
mod wayland;
#[cfg(feature = "wayland")]
pub use wayland::WaylandActivationToken;

use serde::{ser::Serializer, Serialize};
use zbus::zvariant::Type;

// TODO
/// See https://wayland.app/protocols/xdg-activation-v1
#[derive(Debug, Type)]
#[zvariant(signature = "s")]
pub enum ActivationToken {
#[cfg(feature = "wayland")]
#[doc(hidden)]
Wayland(WaylandActivationToken),
#[cfg(feature = "gtk4_wayland")]
#[doc(hidden)]
Gtk4(Gtk4ActivationToken),
#[cfg(all(feature = "gtk3", feature = "wayland"))]
#[doc(hidden)]
Gtk3(Gtk3ActivationToken),
#[doc(hidden)]
Raw(String),
#[doc(hidden)]
None,
}

impl Serialize for ActivationToken {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}

impl Default for ActivationToken {
fn default() -> Self {
Self::None
}
}

impl ActivationToken {
#[cfg(feature = "wayland")]
/// Create an instance of [`ActivationToken`] from a Wayland surface and the
/// application's id.
pub async fn from_wayland_surface(
app_id: &str,
surface: &wayland_client::protocol::wl_surface::WlSurface,
) -> Self {
if let Some(token) = WaylandActivationToken::from_surface(app_id, surface).await {
Self::Wayland(token)
} else {
Self::default()
}
}

#[cfg(feature = "wayland")]
/// Create an instance of [`ActivationToken`] from a raw Wayland surface and
/// the application's id.
///
/// # Safety
///
/// Both pointers have to be valid surface and display pointers. You must
/// ensure the `display_ptr` lives longer than the returned
/// `ActivationToken`.
pub async unsafe fn from_wayland_raw(
app_id: &str,
surface_ptr: *mut std::ffi::c_void,
display_ptr: *mut std::ffi::c_void,
) -> Self {
if let Some(token) =
WaylandActivationToken::from_raw(app_id, surface_ptr, display_ptr).await
{
Self::Wayland(token)
} else {
Self::default()
}
}

#[cfg(feature = "gtk4_wayland")]
// TODO Maybe name from_display.
/// Creates a [`ActivationToken`] from a [`gtk4::Native`](https://docs.gtk.org/gtk4/class.Native.html).
pub async fn from_native<N: ::gtk4::glib::IsA<::gtk4::Native>>(
app_id: &str,
native: &N,
) -> Self {
if let Some(token) = Gtk4ActivationToken::from_native(app_id, native).await {
Self::Gtk4(token)
} else {
Self::default()
}
}

#[cfg(all(feature = "gtk3", feature = "wayland"))]
/// Creates a [`ActivationToken`] from a [`IsA<gdk3::Window>`](https://gtk-rs.org/gtk3-rs/stable/latest/docs/gdk/struct.Window.html).
pub fn from_window(window: &impl ::gtk3::glib::IsA<::gtk3::gdk::Window>) -> Self {
if let Some(token) = Gtk3ActivationToken::from_window(window) {
Self::Gtk3(token)
} else {
Self::default()
}
}

pub fn is_some(&self) -> bool {
!self.is_none()
}

pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}

pub(crate) fn as_str(&self) -> &str {
match self {
#[cfg(feature = "wayland")]
Self::Wayland(activation_token) => activation_token.token.as_str(),
#[cfg(feature = "gtk4_wayland")]
Self::Gtk4(activation_token) => activation_token.wl_token.token.as_str(),
#[cfg(all(feature = "gtk3", feature = "wayland"))]
Self::Gtk3(activation_token) => activation_token.token.as_str(),
Self::Raw(string) => string.as_str(),
Self::None => "",
}
}

pub(crate) fn into_string(self) -> String {
match self {
#[cfg(feature = "wayland")]
Self::Wayland(activation_token) => activation_token.token,
#[cfg(feature = "gtk4_wayland")]
Self::Gtk4(activation_token) => activation_token.wl_token.token,
#[cfg(all(feature = "gtk3", feature = "wayland"))]
Self::Gtk3(activation_token) => activation_token.token,
Self::Raw(string) => string,
Self::None => "".into(),
}
}
}
Loading

0 comments on commit 4a772b4

Please sign in to comment.