From 5dff6c38fd185b3ca30c3b99169db7f949426f07 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 24 Apr 2024 13:51:13 +0200 Subject: [PATCH] wayland: implement xdg-dialog-v1 --- docs/features.md | 1 + release-notes.md | 1 + src/globals.rs | 2 + src/ifs.rs | 1 + .../wl_surface/xdg_surface/xdg_toplevel.rs | 10 +- .../xdg_surface/xdg_toplevel/xdg_dialog_v1.rs | 73 ++++++++++++ src/ifs/xdg_wm_dialog_v1.rs | 104 ++++++++++++++++++ wire/xdg_dialog_v1.txt | 11 ++ wire/xdg_wm_dialog_v1.txt | 8 ++ 9 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/ifs/wl_surface/xdg_surface/xdg_toplevel/xdg_dialog_v1.rs create mode 100644 src/ifs/xdg_wm_dialog_v1.rs create mode 100644 wire/xdg_dialog_v1.txt create mode 100644 wire/xdg_wm_dialog_v1.txt diff --git a/docs/features.md b/docs/features.md index 964cb4d0..0f96cdbe 100644 --- a/docs/features.md +++ b/docs/features.md @@ -148,6 +148,7 @@ Jay supports the following wayland protocols: | xdg_activation_v1 | 1 | | | xdg_toplevel_drag_manager_v1 | 1 | | | xdg_wm_base | 6 | | +| xdg_wm_dialog_v1 | 1 | | | zwlr_data_control_manager_v1 | 2 | Yes | | zwlr_layer_shell_v1 | 4[^no_exclusive] | No[^lsaccess] | | zwlr_screencopy_manager_v1 | 3 | Yes | diff --git a/release-notes.md b/release-notes.md index 33a3405f..92b9ae45 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,6 +1,7 @@ # Unreleased - Add support for wp-security-manager-v1. +- Add support for xdg-dialog-v1. # 1.1.0 (2024-04-22) diff --git a/src/globals.rs b/src/globals.rs index df2eb32e..53f50942 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -41,6 +41,7 @@ use { xdg_activation_v1::XdgActivationV1Global, xdg_toplevel_drag_manager_v1::XdgToplevelDragManagerV1Global, xdg_wm_base::XdgWmBaseGlobal, + xdg_wm_dialog_v1::XdgWmDialogV1Global, zwlr_layer_shell_v1::ZwlrLayerShellV1Global, zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1Global, zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global, @@ -186,6 +187,7 @@ impl Globals { add_singleton!(ZwpInputMethodManagerV2Global); add_singleton!(ZwpTextInputManagerV3Global); add_singleton!(WpSecurityContextManagerV1Global); + add_singleton!(XdgWmDialogV1Global); } pub fn add_backend_singletons(&self, backend: &Rc) { diff --git a/src/ifs.rs b/src/ifs.rs index ccd578da..bb9c496b 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -57,6 +57,7 @@ pub mod xdg_positioner; pub mod xdg_toplevel_drag_manager_v1; pub mod xdg_toplevel_drag_v1; pub mod xdg_wm_base; +pub mod xdg_wm_dialog_v1; pub mod zwlr_layer_shell_v1; pub mod zwlr_screencopy_frame_v1; pub mod zwlr_screencopy_manager_v1; diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 48b81111..1922da73 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -1,3 +1,5 @@ +pub mod xdg_dialog_v1; + use { crate::{ bugs, @@ -9,7 +11,10 @@ use { ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, wl_seat::{NodeSeatState, SeatId, WlSeatGlobal}, wl_surface::{ - xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}, + xdg_surface::{ + xdg_toplevel::xdg_dialog_v1::XdgDialogV1, XdgSurface, XdgSurfaceError, + XdgSurfaceExt, + }, WlSurface, }, xdg_toplevel_drag_v1::XdgToplevelDragV1, @@ -99,6 +104,7 @@ pub struct XdgToplevel { toplevel_data: ToplevelData, pub drag: CloneCell>>, is_mapped: Cell, + dialog: CloneCell>>, } impl Debug for XdgToplevel { @@ -137,6 +143,7 @@ impl XdgToplevel { ), drag: Default::default(), is_mapped: Cell::new(false), + dialog: Default::default(), } } @@ -454,6 +461,7 @@ impl Object for XdgToplevel { fn break_loops(&self) { self.tl_destroy(); self.parent.set(None); + self.dialog.set(None); let _children = mem::take(&mut *self.children.borrow_mut()); } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/xdg_dialog_v1.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/xdg_dialog_v1.rs new file mode 100644 index 00000000..c9170ea1 --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/xdg_dialog_v1.rs @@ -0,0 +1,73 @@ +use { + crate::{ + client::{Client, ClientError}, + ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel, + leaks::Tracker, + object::{Object, Version}, + wire::{xdg_dialog_v1::*, XdgDialogV1Id, XdgToplevelId}, + }, + std::{fmt::Debug, rc::Rc}, + thiserror::Error, +}; + +pub struct XdgDialogV1 { + pub id: XdgDialogV1Id, + pub client: Rc, + pub toplevel: Rc, + pub tracker: Tracker, + pub version: Version, +} + +impl XdgDialogV1 { + fn detach(&self) { + self.toplevel.dialog.take(); + } + + pub fn install(self: &Rc) -> Result<(), XdgDialogV1Error> { + if self.toplevel.dialog.is_some() { + return Err(XdgDialogV1Error::AlreadyAttached(self.toplevel.id)); + } + self.toplevel.dialog.set(Some(self.clone())); + Ok(()) + } +} + +impl XdgDialogV1RequestHandler for XdgDialogV1 { + type Error = XdgDialogV1Error; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.detach(); + self.client.remove_obj(self)?; + Ok(()) + } + + fn set_modal(&self, _req: SetModal, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } + + fn unset_modal(&self, _req: UnsetModal, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +object_base! { + self = XdgDialogV1; + version = self.version; +} + +impl Object for XdgDialogV1 { + fn break_loops(&self) { + self.detach(); + } +} + +simple_add_obj!(XdgDialogV1); + +#[derive(Debug, Error)] +pub enum XdgDialogV1Error { + #[error(transparent)] + ClientError(Box), + #[error("Toplevel {0} already has an xdg_dialog_v1")] + AlreadyAttached(XdgToplevelId), +} +efrom!(XdgDialogV1Error, ClientError); diff --git a/src/ifs/xdg_wm_dialog_v1.rs b/src/ifs/xdg_wm_dialog_v1.rs new file mode 100644 index 00000000..75800a38 --- /dev/null +++ b/src/ifs/xdg_wm_dialog_v1.rs @@ -0,0 +1,104 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::wl_surface::xdg_surface::xdg_toplevel::xdg_dialog_v1::{ + XdgDialogV1, XdgDialogV1Error, + }, + leaks::Tracker, + object::{Object, Version}, + wire::{xdg_wm_dialog_v1::*, XdgWmDialogV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct XdgWmDialogV1Global { + name: GlobalName, +} + +impl XdgWmDialogV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: XdgWmDialogV1Id, + client: &Rc, + version: Version, + ) -> Result<(), XdgWmDialogV1Error> { + let obj = Rc::new(XdgWmDialogV1 { + id, + client: client.clone(), + tracker: Default::default(), + version, + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!(XdgWmDialogV1Global, XdgWmDialogV1, XdgWmDialogV1Error); + +impl Global for XdgWmDialogV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(XdgWmDialogV1Global); + +pub struct XdgWmDialogV1 { + pub id: XdgWmDialogV1Id, + pub client: Rc, + pub tracker: Tracker, + pub version: Version, +} + +impl XdgWmDialogV1RequestHandler for XdgWmDialogV1 { + type Error = XdgWmDialogV1Error; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.client.remove_obj(self)?; + Ok(()) + } + + fn get_xdg_dialog(&self, req: GetXdgDialog, _slf: &Rc) -> Result<(), Self::Error> { + let tl = self.client.lookup(req.toplevel)?; + let obj = Rc::new(XdgDialogV1 { + id: req.id, + client: self.client.clone(), + toplevel: tl, + tracker: Default::default(), + version: self.version, + }); + track!(self.client, obj); + self.client.add_client_obj(&obj)?; + obj.install()?; + Ok(()) + } +} + +object_base! { + self = XdgWmDialogV1; + version = self.version; +} + +impl Object for XdgWmDialogV1 {} + +simple_add_obj!(XdgWmDialogV1); + +#[derive(Debug, Error)] +pub enum XdgWmDialogV1Error { + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + XdgDialogV1Error(#[from] XdgDialogV1Error), +} +efrom!(XdgWmDialogV1Error, ClientError); diff --git a/wire/xdg_dialog_v1.txt b/wire/xdg_dialog_v1.txt new file mode 100644 index 00000000..1135d31e --- /dev/null +++ b/wire/xdg_dialog_v1.txt @@ -0,0 +1,11 @@ +request destroy { + +} + +request set_modal { + +} + +request unset_modal { + +} diff --git a/wire/xdg_wm_dialog_v1.txt b/wire/xdg_wm_dialog_v1.txt new file mode 100644 index 00000000..1a6b73aa --- /dev/null +++ b/wire/xdg_wm_dialog_v1.txt @@ -0,0 +1,8 @@ +request destroy { + +} + +request get_xdg_dialog { + id: id(xdg_dialog_v1), + toplevel: id(xdg_toplevel), +}