ashpd/window_identifier/
mod.rs1use std::{fmt, str::FromStr};
2
3#[cfg(all(feature = "raw_handle", feature = "gtk4"))]
4use raw_window_handle::{
5 DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
6};
7#[cfg(feature = "raw_handle")]
8use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
9use serde::{ser::Serializer, Deserialize, Serialize};
10use zbus::zvariant::Type;
11#[derive(Type)]
87#[zvariant(signature = "s")]
88#[doc(alias = "XdpParent")]
89#[non_exhaustive]
90pub enum WindowIdentifier {
91 #[cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))]
93 #[doc(hidden)]
94 Gtk4(Gtk4WindowIdentifier),
95 #[cfg(feature = "wayland")]
96 #[doc(hidden)]
97 Wayland(WaylandWindowIdentifier),
98 #[doc(hidden)]
99 X11(WindowIdentifierType),
100}
101
102unsafe impl Send for WindowIdentifier {}
103unsafe impl Sync for WindowIdentifier {}
104
105impl Serialize for WindowIdentifier {
106 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107 where
108 S: Serializer,
109 {
110 serializer.serialize_str(&self.to_string())
111 }
112}
113
114impl std::fmt::Display for WindowIdentifier {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 match self {
117 #[cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))]
118 Self::Gtk4(identifier) => f.write_str(&format!("{identifier}")),
119 #[cfg(feature = "wayland")]
120 Self::Wayland(identifier) => f.write_str(&format!("{identifier}")),
121 Self::X11(identifier) => f.write_str(&format!("{identifier}")),
122 }
123 }
124}
125
126impl std::fmt::Debug for WindowIdentifier {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 f.debug_tuple("WindowIdentifier")
129 .field(&format!("{self}"))
130 .finish()
131 }
132}
133
134impl WindowIdentifier {
135 #[cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))]
136 #[cfg_attr(docsrs, doc(cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))))]
137 #[doc(alias = "xdp_parent_new_gtk")]
144 pub async fn from_native(native: &impl ::gtk4::prelude::IsA<::gtk4::Native>) -> Option<Self> {
145 Gtk4WindowIdentifier::new(native).await.map(Self::Gtk4)
146 }
147
148 #[cfg(feature = "raw_handle")]
149 #[cfg_attr(docsrs, doc(cfg(feature = "raw_handle")))]
150 pub async fn from_raw_handle(
158 window_handle: &RawWindowHandle,
159 display_handle: Option<&RawDisplayHandle>,
160 ) -> Option<Self> {
161 use raw_window_handle::RawWindowHandle::{Xcb, Xlib};
162 #[cfg(feature = "wayland")]
163 use raw_window_handle::{
164 RawDisplayHandle::Wayland as DisplayHandle, RawWindowHandle::Wayland,
165 };
166 match (window_handle, display_handle) {
167 #[cfg(feature = "wayland")]
168 (Wayland(wl_handle), Some(DisplayHandle(wl_display))) => unsafe {
169 Self::from_wayland_raw(wl_handle.surface.as_ptr(), wl_display.display.as_ptr())
170 .await
171 },
172 (Xlib(x_handle), _) => Some(Self::from_xid(x_handle.window)),
173 (Xcb(x_handle), _) => Some(Self::from_xid(x_handle.window.get().into())),
174 _ => None,
175 }
176 }
177
178 pub fn from_xid(xid: std::os::raw::c_ulong) -> Self {
180 Self::X11(WindowIdentifierType::X11(xid))
181 }
182
183 #[cfg(feature = "wayland")]
184 #[cfg_attr(docsrs, doc(cfg(feature = "wayland")))]
185 pub async unsafe fn from_wayland_raw(
193 surface_ptr: *mut std::ffi::c_void,
194 display_ptr: *mut std::ffi::c_void,
195 ) -> Option<Self> {
196 WaylandWindowIdentifier::from_raw(surface_ptr, display_ptr)
197 .await
198 .map(Self::Wayland)
199 }
200
201 #[cfg(feature = "wayland")]
202 #[cfg_attr(docsrs, doc(cfg(feature = "wayland")))]
203 pub async fn from_wayland(
205 surface: &wayland_client::protocol::wl_surface::WlSurface,
206 ) -> Option<Self> {
207 WaylandWindowIdentifier::new(surface)
208 .await
209 .map(Self::Wayland)
210 }
211}
212
213#[cfg(all(feature = "raw_handle", feature = "gtk4"))]
214impl HasDisplayHandle for WindowIdentifier {
215 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
224 match self {
225 #[cfg(feature = "gtk4")]
226 Self::Gtk4(identifier) => Ok(identifier.as_raw_display_handle()),
227 _ => unreachable!(),
228 }
229 }
230}
231
232#[cfg(all(feature = "raw_handle", feature = "gtk4"))]
233impl HasWindowHandle for WindowIdentifier {
234 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
243 match self {
244 #[cfg(feature = "gtk4")]
245 Self::Gtk4(identifier) => Ok(identifier.as_raw_window_handle()),
246 _ => unreachable!(),
247 }
248 }
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Type)]
253#[zvariant(signature = "s")]
254pub enum WindowIdentifierType {
255 X11(std::os::raw::c_ulong),
257 #[allow(dead_code)]
258 Wayland(String),
260}
261
262impl fmt::Display for WindowIdentifierType {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 match self {
265 Self::X11(xid) => f.write_str(&format!("x11:0x{xid:x}")),
266 Self::Wayland(handle) => f.write_str(&format!("wayland:{handle}")),
267 }
268 }
269}
270
271impl FromStr for WindowIdentifierType {
272 type Err = PortalError;
273 fn from_str(s: &str) -> Result<Self, Self::Err> {
274 let (kind, handle) = s
275 .split_once(':')
276 .ok_or_else(|| PortalError::InvalidArgument("Invalid Window Identifier".to_owned()))?;
277 match kind {
278 "x11" => {
279 let handle = handle.trim_start_matches("0x");
280 Ok(Self::X11(
281 std::os::raw::c_ulong::from_str_radix(handle, 16)
282 .map_err(|_| PortalError::InvalidArgument(format!("Wrong XID {handle}")))?,
283 ))
284 }
285 "wayland" => Ok(Self::Wayland(handle.to_owned())),
286 t => Err(PortalError::InvalidArgument(format!(
287 "Invalid Window Identifier type {t}",
288 ))),
289 }
290 }
291}
292
293impl<'de> Deserialize<'de> for WindowIdentifierType {
294 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
295 where
296 D: serde::Deserializer<'de>,
297 {
298 let handle = String::deserialize(deserializer)?;
299 Self::from_str(&handle)
300 .map_err(|e| serde::de::Error::custom(format!("Invalid Window identifier {e}")))
301 }
302}
303
304impl Serialize for WindowIdentifierType {
305 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
306 where
307 S: Serializer,
308 {
309 self.to_string().serialize(serializer)
310 }
311}
312
313#[cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))]
314mod gtk4;
315
316#[cfg(any(feature = "gtk4_wayland", feature = "gtk4_x11"))]
317pub use self::gtk4::Gtk4WindowIdentifier;
318use crate::PortalError;
319
320#[cfg(feature = "wayland")]
321mod wayland;
322
323#[cfg(feature = "wayland")]
324pub use self::wayland::WaylandWindowIdentifier;
325
326#[cfg(test)]
327mod tests {
328 use std::str::FromStr;
329
330 use super::WindowIdentifier;
331 use crate::window_identifier::WindowIdentifierType;
332
333 #[test]
334 fn test_serialize() {
335 let x11 = WindowIdentifier::from_xid(1024);
336 assert_eq!(x11.to_string(), "x11:0x400");
337
338 assert_eq!(
339 WindowIdentifierType::from_str("x11:0x11432").unwrap(),
340 WindowIdentifierType::X11(70706)
341 );
342
343 assert_eq!(
344 WindowIdentifierType::from_str("wayland:Somerandomchars").unwrap(),
345 WindowIdentifierType::Wayland("Somerandomchars".to_owned())
346 );
347 assert!(WindowIdentifierType::from_str("some_handle").is_err());
348 assert!(WindowIdentifierType::from_str("some_type:some_handle").is_err());
349 }
350}