From e0c89f6c858696a9039f7fe5c44c9baca110cd19 Mon Sep 17 00:00:00 2001 From: PolyMeilex Date: Sun, 14 Dec 2025 18:24:52 +0100 Subject: [PATCH] xdg_portal: Drop wayland-rs --- .github/workflows/rust.yml | 3 - CHANGELOG.md | 1 + Cargo.lock | 312 ++-------------- Cargo.toml | 13 +- examples/simple.rs | 2 + src/backend/xdg_desktop_portal.rs | 6 +- .../window_identifier/mod.rs | 26 +- .../window_identifier/wayland.rs | 151 +------- .../window_identifier/wayland/ffi.rs | 334 ++++++++++++++++++ .../window_identifier/wayland/raw.rs | 228 ++++++++++++ 10 files changed, 609 insertions(+), 467 deletions(-) create mode 100644 src/backend/xdg_desktop_portal/window_identifier/wayland/ffi.rs create mode 100644 src/backend/xdg_desktop_portal/window_identifier/wayland/raw.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bead4de..d41cf1d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -44,9 +44,6 @@ jobs: - name: "[Ubuntu GTK] install dependencies" if: matrix.name == 'Ubuntu GTK' run: sudo apt update && sudo apt install libgtk-3-dev - - name: "[Ubuntu XDG] install dependencies" - if: matrix.name == 'Ubuntu XDG' - run: sudo apt update && sudo apt install libwayland-dev - name: "[WASM] rustup" if: matrix.name == 'WASM32' run: rustup target add wasm32-unknown-unknown diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f7422..ff87999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- `wayland` feature removed - `tokio` and `async-std` features removed ## 0.16.0 diff --git a/Cargo.lock b/Cargo.lock index a2d23a6..6e1c58b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,15 +51,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "cc" -version = "1.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-expr" version = "0.15.8" @@ -89,19 +80,23 @@ dependencies = [ ] [[package]] -name = "dlib" -version = "0.5.2" +name = "env_filter" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ - "libloading", + "log", ] [[package]] -name = "downcast-rs" -version = "1.2.1" +name = "env_logger" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "env_filter", + "log", +] [[package]] name = "equivalent" @@ -109,16 +104,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "errno" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "futures" version = "0.3.31" @@ -328,22 +313,6 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.3", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "log" version = "0.4.27" @@ -456,15 +425,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.40" @@ -486,6 +446,7 @@ version = "0.16.0" dependencies = [ "block2", "dispatch2", + "env_logger", "futures", "glib-sys", "gobject-sys", @@ -501,24 +462,8 @@ dependencies = [ "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", - "wayland-backend", - "wayland-client", - "wayland-protocols", "web-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -528,25 +473,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] [[package]] -name = "serde" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -562,12 +510,6 @@ dependencies = [ "serde", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "slab" version = "0.4.9" @@ -730,66 +672,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wayland-backend" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" -dependencies = [ - "bitflags", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" -dependencies = [ - "bitflags", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" -dependencies = [ - "proc-macro2", - "quick-xml", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -822,165 +704,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.7.10" diff --git a/Cargo.toml b/Cargo.toml index 65a5b29..559bb01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,14 @@ repository = "https://github.com/PolyMeilex/rfd" documentation = "https://docs.rs/rfd" [features] -default = ["xdg-portal", "wayland"] +default = ["xdg-portal"] file-handle-inner = [] gtk3 = ["gtk-sys", "glib-sys", "gobject-sys"] xdg-portal = ["pollster"] -# Enable wayland support for xdg-portal -wayland = ["wayland-backend", "wayland-client", "wayland-protocols"] common-controls-v6 = ["windows-sys/Win32_UI_Controls"] [dev-dependencies] +env_logger = { version = "0.11.8", default-features = false } futures = "0.3.12" [dependencies] @@ -75,14 +74,6 @@ windows-sys = { version = "0.61", features = [ libc = "0.2" # XDG Desktop Portal pollster = { version = "0.4", optional = true } -wayland-backend = { version = "0.3", features = [ - "client_system", -], optional = true } -wayland-client = { version = "0.31", optional = true } -wayland-protocols = { version = "0.32", features = [ - "unstable", - "client", -], optional = true } # GTK gtk-sys = { version = "0.18.0", features = ["v3_24"], optional = true } glib-sys = { version = "0.18.0", optional = true } diff --git a/examples/simple.rs b/examples/simple.rs index 2c7710c..a368a99 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,5 +1,7 @@ #[cfg(not(target_arch = "wasm32"))] fn main() { + env_logger::init(); + let path = std::env::current_dir().unwrap(); let res = rfd::FileDialog::new() diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 1df6635..75f1e0d 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -37,11 +37,7 @@ fn to_window_identifier( window: Option, display: Option, ) -> Option { - window.map(|window| { - block_on(Box::pin(async move { - WindowIdentifier::from_raw_handle(&window, display.as_ref()).await - })) - })? + window.and_then(|window| WindowIdentifier::from_raw_handle(&window, display.as_ref())) } impl From<&Filter> for portal::FileFilter { diff --git a/src/backend/xdg_desktop_portal/window_identifier/mod.rs b/src/backend/xdg_desktop_portal/window_identifier/mod.rs index 6aa296c..22e7570 100644 --- a/src/backend/xdg_desktop_portal/window_identifier/mod.rs +++ b/src/backend/xdg_desktop_portal/window_identifier/mod.rs @@ -2,10 +2,12 @@ use std::fmt; use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; +mod wayland; +pub use wayland::WaylandWindowIdentifier; + #[derive(Debug)] -#[non_exhaustive] +#[allow(clippy::large_enum_variant)] pub enum WindowIdentifier { - #[cfg(feature = "wayland")] Wayland(WaylandWindowIdentifier), X11(WindowIdentifierType), } @@ -13,7 +15,6 @@ pub enum WindowIdentifier { impl std::fmt::Display for WindowIdentifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - #[cfg(feature = "wayland")] Self::Wayland(identifier) => identifier.fmt(f), Self::X11(identifier) => identifier.fmt(f), } @@ -21,20 +22,18 @@ impl std::fmt::Display for WindowIdentifier { } impl WindowIdentifier { - pub async fn from_raw_handle( + pub fn from_raw_handle( window_handle: &RawWindowHandle, display_handle: Option<&RawDisplayHandle>, ) -> Option { use raw_window_handle::RawWindowHandle::{Xcb, Xlib}; - #[cfg(feature = "wayland")] + use raw_window_handle::{ RawDisplayHandle::Wayland as DisplayHandle, RawWindowHandle::Wayland, }; match (window_handle, display_handle) { - #[cfg(feature = "wayland")] (Wayland(wl_handle), Some(DisplayHandle(wl_display))) => unsafe { Self::from_wayland_raw(wl_handle.surface.as_ptr(), wl_display.display.as_ptr()) - .await }, (Xlib(x_handle), _) => Some(Self::from_xid(x_handle.window)), (Xcb(x_handle), _) => Some(Self::from_xid(x_handle.window.get().into())), @@ -46,14 +45,11 @@ impl WindowIdentifier { Self::X11(WindowIdentifierType::X11(xid)) } - #[cfg(feature = "wayland")] - pub async unsafe fn from_wayland_raw( + pub unsafe fn from_wayland_raw( surface_ptr: *mut std::ffi::c_void, display_ptr: *mut std::ffi::c_void, ) -> Option { - WaylandWindowIdentifier::from_raw(surface_ptr, display_ptr) - .await - .map(Self::Wayland) + WaylandWindowIdentifier::from_raw(surface_ptr, display_ptr).map(Self::Wayland) } } @@ -81,9 +77,3 @@ impl fmt::Display for WindowIdentifierType { } } } - -#[cfg(feature = "wayland")] -mod wayland; - -#[cfg(feature = "wayland")] -pub use self::wayland::WaylandWindowIdentifier; diff --git a/src/backend/xdg_desktop_portal/window_identifier/wayland.rs b/src/backend/xdg_desktop_portal/window_identifier/wayland.rs index e3c44f1..034e073 100644 --- a/src/backend/xdg_desktop_portal/window_identifier/wayland.rs +++ b/src/backend/xdg_desktop_portal/window_identifier/wayland.rs @@ -1,28 +1,15 @@ use std::fmt; -use wayland_backend::sys::client::Backend; -use wayland_client::{ - protocol::{wl_registry, wl_surface::WlSurface}, - Proxy, QueueHandle, -}; -use wayland_protocols::xdg::foreign::zv2::client::{ - zxdg_exported_v2::{self, ZxdgExportedV2}, - zxdg_exporter_v2::ZxdgExporterV2, -}; - -use super::WindowIdentifierType; - -// Supported versions. -const ZXDG_EXPORTER_V2: u32 = 1; +mod ffi; +mod raw; #[derive(Debug)] pub struct WaylandWindowIdentifier { - exported: ZxdgExportedV2, - type_: WindowIdentifierType, + handle: raw::XdgForeignHandle, } impl WaylandWindowIdentifier { - pub async unsafe fn from_raw( + pub unsafe fn from_raw( surface_ptr: *mut std::ffi::c_void, display_ptr: *mut std::ffi::c_void, ) -> Option { @@ -30,136 +17,14 @@ impl WaylandWindowIdentifier { return None; } - let backend = Backend::from_foreign_display(display_ptr as *mut _); - let conn = wayland_client::Connection::from_backend(backend); - let obj_id = wayland_backend::sys::client::ObjectId::from_ptr( - WlSurface::interface(), - surface_ptr as *mut _, - ) - .ok()?; - - let surface = WlSurface::from_id(&conn, obj_id).ok()?; - - Self::new_inner(conn, &surface).await - } - - async fn new_inner(conn: wayland_client::Connection, surface: &WlSurface) -> Option { - let (sender, receiver) = crate::oneshot::channel::>(); - - let surface = surface.clone(); - std::thread::spawn(move || match wayland_export_handle(conn, &surface) { - Some(window_handle) => sender.send(Some(window_handle)).unwrap(), - None => { - sender.send(None).unwrap(); - } - }); - - receiver.await.unwrap() + Some(Self { + handle: raw::run(display_ptr, surface_ptr)?, + }) } } impl fmt::Display for WaylandWindowIdentifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.type_.fmt(f) - } -} - -impl Drop for WaylandWindowIdentifier { - fn drop(&mut self) { - self.exported.destroy(); - } -} - -#[derive(Default, Debug)] -struct State { - handle: String, - exporter: Option, -} - -impl wayland_client::Dispatch for State { - fn event( - state: &mut Self, - _proxy: &ZxdgExportedV2, - event: ::Event, - _data: &(), - _connhandle: &wayland_client::Connection, - _qhandle: &QueueHandle, - ) { - if let zxdg_exported_v2::Event::Handle { handle } = event { - state.handle = handle; - } - } -} - -impl wayland_client::Dispatch for State { - fn event( - _state: &mut Self, - _proxy: &ZxdgExporterV2, - _event: ::Event, - _data: &(), - _connhandle: &wayland_client::Connection, - _qhandle: &QueueHandle, - ) { - } -} - -impl wayland_client::Dispatch for State { - fn event( - state: &mut Self, - registry: &wl_registry::WlRegistry, - event: wl_registry::Event, - _: &(), - _: &wayland_client::Connection, - qhandle: &QueueHandle, - ) { - if let wl_registry::Event::Global { - name, - interface, - version, - } = event - { - if interface.as_str() == "zxdg_exporter_v2" { - let exporter = registry.bind::( - name, - version.min(ZXDG_EXPORTER_V2), - qhandle, - (), - ); - state.exporter = Some(exporter); - } - } - } -} - -fn wayland_export_handle( - conn: wayland_client::Connection, - surface: &WlSurface, -) -> Option { - let display = conn.display(); - let mut event_queue = conn.new_event_queue(); - let qhandle = event_queue.handle(); - let mut state = State::default(); - display.get_registry(&qhandle, ()); - event_queue.roundtrip(&mut state).ok()?; - - let exported = match state.exporter.take() { - Some(exporter) => { - let exp = exporter.export_toplevel(surface, &qhandle, ()); - event_queue.roundtrip(&mut state).ok()?; - exporter.destroy(); - - Some(exp) - } - None => None, - }; - - if let Some(exported) = exported { - Some(WaylandWindowIdentifier { - exported, - type_: WindowIdentifierType::Wayland(state.handle), - }) - } else { - log::warn!("Wayland compositor did not reposne with xdg foreign token"); - None + self.handle.fmt(f) } } diff --git a/src/backend/xdg_desktop_portal/window_identifier/wayland/ffi.rs b/src/backend/xdg_desktop_portal/window_identifier/wayland/ffi.rs new file mode 100644 index 0000000..7c2919f --- /dev/null +++ b/src/backend/xdg_desktop_portal/window_identifier/wayland/ffi.rs @@ -0,0 +1,334 @@ +#![allow(non_camel_case_types)] + +use std::{ + ffi::{c_char, c_int, c_void, CStr}, + fmt, + rc::Rc, +}; + +pub enum wl_proxy {} +pub enum wl_display {} +pub enum wl_event_queue {} + +#[repr(C)] +pub struct wl_message { + pub name: *const c_char, + pub signature: *const c_char, + pub types: *const *const wl_interface, +} + +unsafe impl Send for wl_message {} +unsafe impl Sync for wl_message {} + +#[repr(C)] +pub struct wl_interface { + pub name: *const c_char, + pub version: c_int, + pub request_count: c_int, + pub requests: *const wl_message, + pub event_count: c_int, + pub events: *const wl_message, +} + +impl fmt::Debug for wl_interface { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "wl_interface@{:p}", self) + } +} + +unsafe impl Send for wl_interface {} +unsafe impl Sync for wl_interface {} + +#[derive(Debug)] +pub struct WlEventQueueHandle { + wl_event_queue: *mut wl_event_queue, + lib: LibWayland, +} + +impl WlEventQueueHandle { + pub fn new(lib: &LibWayland, wl_display: *mut wl_display) -> Self { + let wl_event_queue = (lib.wl_display_create_queue_with_name)(wl_display, c"rfd".as_ptr()); + assert!(!wl_event_queue.is_null()); + + Self { + wl_event_queue, + lib: lib.clone(), + } + } + + pub fn as_ptr(&self) -> *mut wl_event_queue { + self.wl_event_queue + } +} + +impl Drop for WlEventQueueHandle { + fn drop(&mut self) { + (self.lib.wl_event_queue_destroy)(self.wl_event_queue); + } +} + +#[derive(Debug)] +pub struct WlProxyHandle { + wl_proxy: *mut wl_proxy, + lib: LibWayland, +} + +impl WlProxyHandle { + pub fn new(wl_proxy: *mut wl_proxy, lib: LibWayland) -> Self { + Self { wl_proxy, lib } + } + + pub fn as_ptr(&self) -> *mut wl_proxy { + self.wl_proxy + } +} + +impl Drop for WlProxyHandle { + fn drop(&mut self) { + (self.lib.wl_proxy_destroy)(self.wl_proxy); + } +} + +struct DlHandle(*mut c_void); + +impl Drop for DlHandle { + fn drop(&mut self) { + unsafe { libc::dlclose(self.0) }; + } +} + +#[derive(Clone)] +pub struct LibWayland { + pub wl_display_create_queue_with_name: + extern "C" fn(display: *mut wl_display, name: *const c_char) -> *mut wl_event_queue, + pub wl_display_roundtrip_queue: extern "C" fn(*mut wl_display, *mut wl_event_queue) -> c_int, + + pub wl_event_queue_destroy: extern "C" fn(*mut wl_event_queue), + + #[allow(unused)] + pub wl_proxy_marshal_flags: extern "C" fn( + proxy: *mut wl_proxy, + opcode: u32, + interface: *const wl_interface, + version: u32, + flags: u32, + ... + ) -> *mut wl_proxy, + + pub wl_proxy_marshal_constructor: + extern "C" fn(*mut wl_proxy, u32, *const wl_interface, ...) -> *mut wl_proxy, + pub wl_proxy_marshal_constructor_versioned: + extern "C" fn(*mut wl_proxy, u32, *const wl_interface, u32, ...) -> *mut wl_proxy, + + pub wl_proxy_add_listener: + extern "C" fn(*mut wl_proxy, *mut extern "C" fn(), *mut c_void) -> c_int, + + pub wl_proxy_set_queue: extern "C" fn(*mut wl_proxy, *mut wl_event_queue), + pub wl_proxy_set_user_data: extern "C" fn(*mut wl_proxy, *mut c_void) -> (), + + pub wl_proxy_create_wrapper: extern "C" fn(*mut wl_proxy) -> *mut wl_proxy, + pub wl_proxy_wrapper_destroy: extern "C" fn(*mut wl_proxy), + pub wl_proxy_destroy: extern "C" fn(*mut wl_proxy), + + _lib: Rc, +} + +impl fmt::Debug for LibWayland { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LibWayland").finish_non_exhaustive() + } +} + +impl LibWayland { + pub fn new() -> Option { + unsafe { + let lib = Rc::new(DlHandle(libc::dlopen( + c"libwayland-client.so.0".as_ptr(), + libc::RTLD_LAZY | libc::RTLD_LOCAL, + ))); + + macro_rules! load_symbols { + ($handle:expr, [ $($name:ident),* $(,)? ]) => { + Self { + $( + $name: { + let name = concat!(stringify!($name), "\0"); + let sym = libc::dlsym( + $handle.0, + CStr::from_bytes_with_nul_unchecked(name.as_bytes()).as_ptr() + ); + + if sym.is_null() { + log::error!("Symbol '{name}' not found"); + return None; + } + + #[allow(clippy::missing_transmute_annotations)] + std::mem::transmute(sym) + }, + )* + _lib: $handle, + } + }; + } + + let lib = load_symbols!( + lib, + [ + wl_display_create_queue_with_name, + wl_display_roundtrip_queue, + wl_event_queue_destroy, + wl_proxy_marshal_flags, + wl_proxy_marshal_constructor, + wl_proxy_marshal_constructor_versioned, + wl_proxy_add_listener, + wl_proxy_set_queue, + wl_proxy_set_user_data, + wl_proxy_create_wrapper, + wl_proxy_wrapper_destroy, + wl_proxy_destroy, + ] + ); + + Some(lib) + } + } +} + +pub struct SyncWrapper(pub T); +unsafe impl Sync for SyncWrapper {} + +pub mod display { + #[allow(unused)] + pub const WL_DISPLAY_SYNC: u32 = 0; + pub const WL_DISPLAY_GET_REGISTRY: u32 = 1; +} + +pub mod registry { + use super::{wl_interface, wl_message}; + + pub const WL_REGISTRY_BIND: u32 = 0; + + pub static INTERFACE: wl_interface = wl_interface { + name: c"wl_registry".as_ptr(), + version: 1, + request_count: 1, + requests: { + static MESSAGES: [wl_message; 1] = [wl_message { + name: c"bind".as_ptr(), + signature: c"usun".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 4] = [None, None, None, None]; + TYPES.as_ptr().cast() + }, + }]; + MESSAGES.as_ptr() + }, + event_count: 2, + events: { + static MESSAGES: [wl_message; 2] = [ + wl_message { + name: c"global".as_ptr(), + signature: c"usu".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 3] = [None, None, None]; + TYPES.as_ptr().cast() + }, + }, + wl_message { + name: c"global_remove".as_ptr(), + signature: c"u".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 1] = [None]; + TYPES.as_ptr().cast() + }, + }, + ]; + MESSAGES.as_ptr() + }, + }; +} + +pub mod xdg_exporter { + use std::ptr::{self, null}; + + use super::{wl_interface, wl_message}; + + #[allow(unused)] + pub const ZXDG_EXPORTER_V2_DESTROY: u32 = 0; + pub const ZXDG_EXPORTER_V2_EXPORT_TOPLEVEL: u32 = 1; + + pub static INTERFACE: wl_interface = wl_interface { + name: c"zxdg_exporter_v2".as_ptr(), + version: 1, + request_count: 2, + requests: { + static MESSAGES: [wl_message; 2] = [ + wl_message { + name: c"destroy".as_ptr(), + signature: c"".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 1] = [None]; + TYPES.as_ptr().cast() + }, + }, + wl_message { + name: c"export_toplevel".as_ptr(), + signature: c"no".as_ptr(), + types: { + static WL_SURFACE_INTERFACE: wl_interface = wl_interface { + name: c"wl_surface".as_ptr(), + version: 6, + request_count: 0, + requests: ptr::null(), + event_count: 0, + events: ptr::null(), + }; + static MESSAGES: [Option<&'static wl_interface>; 2] = [ + Some(&super::xdg_exported::INTERFACE), + Some(&WL_SURFACE_INTERFACE), + ]; + MESSAGES.as_ptr().cast() + }, + }, + ]; + MESSAGES.as_ptr() + }, + event_count: 0, + events: null::(), + }; +} + +pub mod xdg_exported { + + use super::{wl_interface, wl_message}; + + pub static INTERFACE: wl_interface = wl_interface { + name: c"zxdg_exported_v2".as_ptr(), + version: 1, + request_count: 1, + requests: { + static MESSAGES: [wl_message; 1] = [wl_message { + name: c"destroy".as_ptr(), + signature: c"".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 1] = [None]; + TYPES.as_ptr().cast() + }, + }]; + MESSAGES.as_ptr() + }, + event_count: 1, + events: { + static MESSAGES: [wl_message; 1] = [wl_message { + name: c"handle".as_ptr(), + signature: c"s".as_ptr(), + types: { + static TYPES: [Option<&'static wl_interface>; 1] = [None]; + TYPES.as_ptr().cast() + }, + }]; + MESSAGES.as_ptr() + }, + }; +} diff --git a/src/backend/xdg_desktop_portal/window_identifier/wayland/raw.rs b/src/backend/xdg_desktop_portal/window_identifier/wayland/raw.rs new file mode 100644 index 0000000..8588911 --- /dev/null +++ b/src/backend/xdg_desktop_portal/window_identifier/wayland/raw.rs @@ -0,0 +1,228 @@ +use std::{ + cell::UnsafeCell, + ffi::{c_char, c_void, CStr, CString}, + fmt, ptr, +}; + +use super::super::super::window_identifier::WindowIdentifierType; +use super::ffi; + +use ffi::{wl_display, wl_proxy, LibWayland, SyncWrapper, WlEventQueueHandle, WlProxyHandle}; + +impl LibWayland { + fn wl_display_get_registry( + &self, + display: *mut wl_display, + queue: &WlEventQueueHandle, + ) -> WlProxyHandle { + let wrapped_display = (self.wl_proxy_create_wrapper)(display.cast()); + assert!(!wrapped_display.is_null()); + + (self.wl_proxy_set_queue)(wrapped_display, queue.as_ptr()); + + let wl_registry = (self.wl_proxy_marshal_constructor)( + wrapped_display, + ffi::display::WL_DISPLAY_GET_REGISTRY, + &ffi::registry::INTERFACE, + ); + assert!(!wl_registry.is_null()); + + (self.wl_proxy_wrapper_destroy)(wrapped_display); + + WlProxyHandle::new(wl_registry, self.clone()) + } + + fn wl_registry_bind_exporter( + &self, + registry: WlProxyHandle, + xdg_exporter_name: u32, + ) -> WlProxyHandle { + let registry = registry.as_ptr(); + let xdg_exporter = (self.wl_proxy_marshal_constructor)( + registry, + ffi::registry::WL_REGISTRY_BIND, + &ffi::xdg_exporter::INTERFACE, + xdg_exporter_name, + ffi::xdg_exporter::INTERFACE.name, + 1, + ); + assert!(!xdg_exporter.is_null()); + + WlProxyHandle::new(xdg_exporter, self.clone()) + } + + fn xdg_exporter_export_toplevel( + &self, + xdg_exporter: WlProxyHandle, + wl_surface: *mut wl_proxy, + ) -> WlProxyHandle { + let xdg_exporter = xdg_exporter.as_ptr(); + let xdg_exported = (self.wl_proxy_marshal_constructor_versioned)( + xdg_exporter, + ffi::xdg_exporter::ZXDG_EXPORTER_V2_EXPORT_TOPLEVEL, + &ffi::xdg_exported::INTERFACE, + 1, + 0, + wl_surface, + ); + assert!(!xdg_exported.is_null()); + WlProxyHandle::new(xdg_exported, self.clone()) + } + + fn roundtrip_with_listener( + &self, + display: *mut wl_display, + queue: &WlEventQueueHandle, + proxy: &WlProxyHandle, + cb: &SyncWrapper>, + user_data: &mut U, + ) { + (self.wl_proxy_add_listener)( + proxy.as_ptr(), + cb.0.get().cast(), + user_data as *mut _ as *mut _, + ); + (self.wl_display_roundtrip_queue)(display, queue.as_ptr()); + (self.wl_proxy_set_user_data)(proxy.as_ptr(), ptr::null_mut::()); + } + + fn fetch_xdg_exporter_from_registry( + &self, + display: *mut wl_display, + queue: &WlEventQueueHandle, + ) -> Option { + let registry = self.wl_display_get_registry(display.cast(), queue); + + let xdg_exporter_name = { + #[derive(Default)] + struct UserData(Option); + + extern "C" fn registry_global( + data: *mut c_void, + _registry: *mut wl_proxy, + name: u32, + interface: *const c_char, + _version: u32, + ) { + unsafe { + let data: *mut UserData = data.cast(); + if data.is_null() { + return; + } + + if CStr::from_ptr(interface) == c"zxdg_exporter_v2" { + (*data).0 = Some(name); + } + } + } + + extern "C" fn registry_global_remove( + _data: *mut c_void, + _registry: *mut wl_proxy, + _name: u32, + ) { + } + + static REGISTRY_IMPL: SyncWrapper> = + SyncWrapper(UnsafeCell::new([ + registry_global as *const c_void, + registry_global_remove as *const c_void, + ])); + + let mut xdg_exported = UserData::default(); + + self.roundtrip_with_listener( + display, + queue, + ®istry, + ®ISTRY_IMPL, + &mut xdg_exported, + ); + + xdg_exported.0 + }; + + Some(self.wl_registry_bind_exporter(registry, xdg_exporter_name?)) + } + + fn fetch_xdg_exported_handle( + &self, + xdg_exported: &WlProxyHandle, + display: *mut wl_display, + queue: &WlEventQueueHandle, + ) -> Option { + #[derive(Default)] + struct UserData(Option); + + extern "C" fn xdg_exported_handle( + data: *mut c_void, + _exported: *mut c_void, + handle: *const c_char, + ) { + unsafe { + let data: *mut UserData = data.cast(); + if data.is_null() { + return; + } + let handle = CStr::from_ptr(handle).to_owned(); + (*data).0 = Some(handle); + } + } + + static XDG_EXPORTED_IMPL: SyncWrapper> = + SyncWrapper(UnsafeCell::new([xdg_exported_handle as *const c_void])); + + let mut user_data = UserData::default(); + + self.roundtrip_with_listener( + display, + queue, + xdg_exported, + &XDG_EXPORTED_IMPL, + &mut user_data, + ); + + user_data.0 + } +} + +#[derive(Debug)] +pub struct XdgForeignHandle { + pub token: WindowIdentifierType, + _xdg_exported: WlProxyHandle, + _queue: WlEventQueueHandle, + _lib: LibWayland, +} + +impl fmt::Display for XdgForeignHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.token.fmt(f) + } +} + +impl XdgForeignHandle {} + +pub fn run(display_ptr: *mut c_void, surface_ptr: *mut c_void) -> Option { + let display = display_ptr as *mut wl_display; + let wl_surface = surface_ptr as *mut wl_proxy; + + assert!(!display.is_null()); + assert!(!wl_surface.is_null()); + + let lib = LibWayland::new()?; + + let queue = WlEventQueueHandle::new(&lib, display); + + let xdg_exporter = lib.fetch_xdg_exporter_from_registry(display, &queue)?; + let xdg_exported = lib.xdg_exporter_export_toplevel(xdg_exporter, wl_surface); + + let token = lib.fetch_xdg_exported_handle(&xdg_exported, display, &queue)?; + let token = token.to_str().ok()?.to_string(); + + Some(XdgForeignHandle { + token: WindowIdentifierType::Wayland(token), + _xdg_exported: xdg_exported, + _queue: queue, + _lib: lib, + }) +}