diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 19fca4b..51c2d0d 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -335,7 +335,7 @@ pub fn init_shell(display: Rc>, log: ::sl ); // init the xdg_shell - let (xdg_shell_state, _, _) = xdg_shell_init( + let (xdg_shell_state, _) = xdg_shell_init( &mut *display.borrow_mut(), move |shell_event, mut ddata| { let state = ddata.get::>().unwrap(); diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index c0bda18..9fc8dee 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -31,7 +31,7 @@ //! use smithay::wayland::shell::xdg::{xdg_shell_init, XdgRequest}; //! //! # let mut display = wayland_server::Display::new(); -//! let (shell_state, _, _) = xdg_shell_init( +//! let (shell_state, _) = xdg_shell_init( //! &mut display, //! // your implementation //! |event: XdgRequest, dispatch_data| { /* handle the shell requests here */ }, @@ -74,12 +74,8 @@ use std::{ sync::{Arc, Mutex}, }; -use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_surface_v6; use wayland_protocols::xdg_shell::server::xdg_surface; -use wayland_protocols::{ - unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_shell_v6, zxdg_toplevel_v6}, - xdg_shell::server::{xdg_popup, xdg_positioner, xdg_toplevel, xdg_wm_base}, -}; +use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_toplevel, xdg_wm_base}; use wayland_server::DispatchData; use wayland_server::{ protocol::{wl_output, wl_seat, wl_surface}, @@ -90,8 +86,6 @@ use super::PingError; // handlers for the xdg_shell protocol pub(super) mod xdg_handlers; -// compatibility handlers for the zxdg_shell_v6 protocol, its earlier version -mod zxdgv6_handlers; /// The role of an XDG toplevel surface. /// @@ -327,7 +321,7 @@ xdg_role!( pub current: PopupState, /// Holds the pending state as set by the server. pub server_pending: Option, - popup_handle: Option + popup_handle: Option }, |attributes,configure| { attributes.last_acked = Some(configure.state); @@ -731,16 +725,12 @@ impl Clone for ShellData { } } -/// Create a new `xdg_shell` globals +/// Create a new `xdg_shell` global pub fn xdg_shell_init( display: &mut Display, implementation: Impl, logger: L, -) -> ( - Arc>, - Global, - Global, -) +) -> (Arc>, Global) where L: Into>, Impl: FnMut(XdgRequest, DispatchData<'_>) + 'static, @@ -757,8 +747,6 @@ where shell_state: shell_state.clone(), }; - let shell_data_z = shell_data.clone(); - let xdg_shell_global = display.create_global( 3, Filter::new(move |(shell, _version), _, dispatch_data| { @@ -766,14 +754,7 @@ where }), ); - let zxdgv6_shell_global = display.create_global( - 1, - Filter::new(move |(shell, _version), _, dispatch_data| { - self::zxdgv6_handlers::implement_shell(shell, &shell_data_z, dispatch_data); - }), - ); - - (shell_state, xdg_shell_global, zxdgv6_shell_global) + (shell_state, xdg_shell_global) } /// Shell global state @@ -805,16 +786,6 @@ impl ShellState { } } -/* - * User interaction - */ - -#[derive(Debug)] -enum ShellClientKind { - Xdg(xdg_wm_base::XdgWmBase), - ZxdgV6(zxdg_shell_v6::ZxdgShellV6), -} - pub(crate) struct ShellClientData { pending_ping: Option, data: UserDataMap, @@ -839,26 +810,19 @@ fn make_shell_client_data() -> ShellClientData { /// client-specific data you wish to associate with it. #[derive(Debug)] pub struct ShellClient { - kind: ShellClientKind, + kind: xdg_wm_base::XdgWmBase, } impl std::cmp::PartialEq for ShellClient { fn eq(&self, other: &Self) -> bool { - match (&self.kind, &other.kind) { - (&ShellClientKind::Xdg(ref s1), &ShellClientKind::Xdg(ref s2)) => s1 == s2, - (&ShellClientKind::ZxdgV6(ref s1), &ShellClientKind::ZxdgV6(ref s2)) => s1 == s2, - _ => false, - } + self.kind == other.kind } } impl ShellClient { /// Is the shell client represented by this handle still connected? pub fn alive(&self) -> bool { - match self.kind { - ShellClientKind::Xdg(ref s) => s.as_ref().is_alive(), - ShellClientKind::ZxdgV6(ref s) => s.as_ref().is_alive(), - } + self.kind.as_ref().is_alive() } /// Send a ping request to this shell client @@ -874,34 +838,19 @@ impl ShellClient { if !self.alive() { return Err(PingError::DeadSurface); } - match self.kind { - ShellClientKind::Xdg(ref shell) => { - let user_data = shell - .as_ref() - .user_data() - .get::() - .unwrap(); - let mut guard = user_data.client_data.lock().unwrap(); - if let Some(pending_ping) = guard.pending_ping { - return Err(PingError::PingAlreadyPending(pending_ping)); - } - guard.pending_ping = Some(serial); - shell.ping(serial.into()); - } - ShellClientKind::ZxdgV6(ref shell) => { - let user_data = shell - .as_ref() - .user_data() - .get::() - .unwrap(); - let mut guard = user_data.client_data.lock().unwrap(); - if let Some(pending_ping) = guard.pending_ping { - return Err(PingError::PingAlreadyPending(pending_ping)); - } - guard.pending_ping = Some(serial); - shell.ping(serial.into()); - } + let user_data = self + .kind + .as_ref() + .user_data() + .get::() + .unwrap(); + let mut guard = user_data.client_data.lock().unwrap(); + if let Some(pending_ping) = guard.pending_ping { + return Err(PingError::PingAlreadyPending(pending_ping)); } + guard.pending_ping = Some(serial); + self.kind.ping(serial.into()); + Ok(()) } @@ -913,40 +862,22 @@ impl ShellClient { if !self.alive() { return Err(crate::utils::DeadResource); } - match self.kind { - ShellClientKind::Xdg(ref shell) => { - let data = shell - .as_ref() - .user_data() - .get::() - .unwrap(); - let mut guard = data.client_data.lock().unwrap(); - Ok(f(&mut guard.data)) - } - ShellClientKind::ZxdgV6(ref shell) => { - let data = shell - .as_ref() - .user_data() - .get::() - .unwrap(); - let mut guard = data.client_data.lock().unwrap(); - Ok(f(&mut guard.data)) - } - } + let data = self + .kind + .as_ref() + .user_data() + .get::() + .unwrap(); + let mut guard = data.client_data.lock().unwrap(); + Ok(f(&mut guard.data)) } } -#[derive(Debug, Clone)] -pub(crate) enum ToplevelKind { - Xdg(xdg_toplevel::XdgToplevel), - ZxdgV6(zxdg_toplevel_v6::ZxdgToplevelV6), -} - /// A handle to a toplevel surface #[derive(Debug, Clone)] pub struct ToplevelSurface { wl_surface: wl_surface::WlSurface, - shell_surface: ToplevelKind, + shell_surface: xdg_toplevel::XdgToplevel, } impl std::cmp::PartialEq for ToplevelSurface { @@ -958,11 +889,7 @@ impl std::cmp::PartialEq for ToplevelSurface { impl ToplevelSurface { /// Is the toplevel surface referred by this handle still alive? pub fn alive(&self) -> bool { - let shell_alive = match self.shell_surface { - ToplevelKind::Xdg(ref s) => s.as_ref().is_alive(), - ToplevelKind::ZxdgV6(ref s) => s.as_ref().is_alive(), - }; - shell_alive && self.wl_surface.as_ref().is_alive() + self.shell_surface.as_ref().is_alive() && self.wl_surface.as_ref().is_alive() } /// Retrieve the shell client owning this toplevel surface @@ -973,23 +900,14 @@ impl ToplevelSurface { return None; } - let shell = match self.shell_surface { - ToplevelKind::Xdg(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - ShellClientKind::Xdg(data.wm_base.clone()) - } - ToplevelKind::ZxdgV6(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - ShellClientKind::ZxdgV6(data.shell.clone()) - } + let shell = { + let data = self + .shell_surface + .as_ref() + .user_data() + .get::() + .unwrap(); + data.wm_base.clone() }; Some(ShellClient { kind: shell }) @@ -1062,12 +980,7 @@ impl ToplevelSurface { }) .unwrap_or(None); if let Some(configure) = configure { - match self.shell_surface { - ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure(s, configure), - ToplevelKind::ZxdgV6(ref s) => { - self::zxdgv6_handlers::send_toplevel_configure(s, configure) - } - } + self::xdg_handlers::send_toplevel_configure(&self.shell_surface, configure) } } } @@ -1114,40 +1027,23 @@ impl ToplevelSurface { }) .unwrap(); if !configured { - match self.shell_surface { - ToplevelKind::Xdg(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - xdg_surface::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - ToplevelKind::ZxdgV6(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - zxdg_surface_v6::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - } + let data = self + .shell_surface + .as_ref() + .user_data() + .get::() + .unwrap(); + data.xdg_surface.as_ref().post_error( + xdg_surface::Error::NotConstructed as u32, + "Surface has not been configured yet.".into(), + ); } configured } /// Send a "close" event to the client pub fn send_close(&self) { - match self.shell_surface { - ToplevelKind::Xdg(ref s) => s.close(), - ToplevelKind::ZxdgV6(ref s) => s.close(), - } + self.shell_surface.close() } /// Access the underlying `wl_surface` of this toplevel surface @@ -1219,10 +1115,7 @@ impl ToplevelSurface { /// Returns the parent of this toplevel surface. pub fn parent(&self) -> Option { - match &self.shell_surface { - ToplevelKind::Xdg(toplevel) => xdg_handlers::get_parent(toplevel), - ToplevelKind::ZxdgV6(toplevel) => zxdgv6_handlers::get_parent(toplevel), - } + xdg_handlers::get_parent(&self.shell_surface) } /// Sets the parent of this toplevel surface and returns whether the parent was successfully set. @@ -1238,10 +1131,7 @@ impl ToplevelSurface { } // Unset the parent - match &self.shell_surface { - ToplevelKind::Xdg(toplevel) => xdg_handlers::set_parent(toplevel, None), - ToplevelKind::ZxdgV6(toplevel) => zxdgv6_handlers::set_parent(toplevel, None), - } + xdg_handlers::set_parent(&self.shell_surface, None); true } @@ -1262,12 +1152,6 @@ pub enum PopupConfigureError { NotReactive, } -#[derive(Debug, Clone)] -pub(crate) enum PopupKind { - Xdg(xdg_popup::XdgPopup), - ZxdgV6(zxdg_popup_v6::ZxdgPopupV6), -} - /// A handle to a popup surface /// /// This is an unified abstraction over the popup surfaces @@ -1275,7 +1159,7 @@ pub(crate) enum PopupKind { #[derive(Debug, Clone)] pub struct PopupSurface { wl_surface: wl_surface::WlSurface, - shell_surface: PopupKind, + shell_surface: xdg_popup::XdgPopup, } impl std::cmp::PartialEq for PopupSurface { @@ -1287,11 +1171,7 @@ impl std::cmp::PartialEq for PopupSurface { impl PopupSurface { /// Is the popup surface referred by this handle still alive? pub fn alive(&self) -> bool { - let shell_alive = match self.shell_surface { - PopupKind::Xdg(ref p) => p.as_ref().is_alive(), - PopupKind::ZxdgV6(ref p) => p.as_ref().is_alive(), - }; - shell_alive && self.wl_surface.as_ref().is_alive() + self.shell_surface.as_ref().is_alive() && self.wl_surface.as_ref().is_alive() } /// Gets a reference of the parent WlSurface of @@ -1322,23 +1202,14 @@ impl PopupSurface { return None; } - let shell = match self.shell_surface { - PopupKind::Xdg(ref p) => { - let data = p - .as_ref() - .user_data() - .get::() - .unwrap(); - ShellClientKind::Xdg(data.wm_base.clone()) - } - PopupKind::ZxdgV6(ref p) => { - let data = p - .as_ref() - .user_data() - .get::() - .unwrap(); - ShellClientKind::ZxdgV6(data.shell.clone()) - } + let shell = { + let data = self + .shell_surface + .as_ref() + .user_data() + .get::() + .unwrap(); + data.wm_base.clone() }; Some(ShellClient { kind: shell }) @@ -1346,10 +1217,7 @@ impl PopupSurface { /// Get the version of the popup resource fn version(&self) -> u32 { - match self.shell_surface { - PopupKind::Xdg(ref xdg) => xdg.as_ref().version(), - PopupKind::ZxdgV6(ref zxdg) => zxdg.as_ref().version(), - } + self.shell_surface.as_ref().version() } /// Internal configure function to re-use the configure @@ -1386,14 +1254,7 @@ impl PopupSurface { }) .unwrap_or(None); if let Some(configure) = next_configure { - match self.shell_surface { - PopupKind::Xdg(ref p) => { - self::xdg_handlers::send_popup_configure(p, configure); - } - PopupKind::ZxdgV6(ref p) => { - self::zxdgv6_handlers::send_popup_configure(p, configure); - } - } + self::xdg_handlers::send_popup_configure(&self.shell_surface, configure); } } } @@ -1470,30 +1331,15 @@ impl PopupSurface { }) .unwrap_or(None); if let Some(handle) = send_error_to { - match handle { - PopupKind::Xdg(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - xdg_surface::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - PopupKind::ZxdgV6(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - zxdg_surface_v6::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - } + let data = handle + .as_ref() + .user_data() + .get::() + .unwrap(); + data.xdg_surface.as_ref().post_error( + xdg_surface::Error::NotConstructed as u32, + "Surface has not been configured yet.".into(), + ); return; } @@ -1539,30 +1385,16 @@ impl PopupSurface { }) .unwrap(); if !configured { - match self.shell_surface { - PopupKind::Xdg(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - xdg_surface::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - PopupKind::ZxdgV6(ref s) => { - let data = s - .as_ref() - .user_data() - .get::() - .unwrap(); - data.xdg_surface.as_ref().post_error( - zxdg_surface_v6::Error::NotConstructed as u32, - "Surface has not been configured yet.".into(), - ); - } - } + let data = self + .shell_surface + .as_ref() + .user_data() + .get::() + .unwrap(); + data.xdg_surface.as_ref().post_error( + xdg_surface::Error::NotConstructed as u32, + "Surface has not been configured yet.".into(), + ); } configured } @@ -1576,10 +1408,7 @@ impl PopupSurface { return; } - match self.shell_surface { - PopupKind::Xdg(ref p) => p.popup_done(), - PopupKind::ZxdgV6(ref p) => p.popup_done(), - } + self.shell_surface.popup_done(); } /// Access the underlying `wl_surface` of this toplevel surface diff --git a/src/wayland/shell/xdg/xdg_handlers.rs b/src/wayland/shell/xdg/xdg_handlers.rs index bef65f0..5ec06e3 100644 --- a/src/wayland/shell/xdg/xdg_handlers.rs +++ b/src/wayland/shell/xdg/xdg_handlers.rs @@ -13,9 +13,9 @@ use wayland_server::{protocol::wl_surface, Filter, Main}; use crate::utils::Rectangle; use super::{ - make_shell_client_data, PopupConfigure, PopupKind, PositionerState, ShellClient, ShellClientData, - ShellData, SurfaceCachedState, ToplevelConfigure, ToplevelKind, XdgPopupSurfaceRoleAttributes, - XdgRequest, XdgToplevelSurfaceRoleAttributes, + make_shell_client_data, PopupConfigure, PositionerState, ShellClient, ShellClientData, ShellData, + SurfaceCachedState, ToplevelConfigure, XdgPopupSurfaceRoleAttributes, XdgRequest, + XdgToplevelSurfaceRoleAttributes, }; pub(crate) fn implement_wm_base( @@ -49,7 +49,7 @@ pub(crate) struct ShellUserData { pub(crate) fn make_shell_client(resource: &xdg_wm_base::XdgWmBase) -> ShellClient { ShellClient { - kind: super::ShellClientKind::Xdg(resource.clone()), + kind: resource.clone(), } } @@ -547,7 +547,7 @@ fn make_toplevel_handle(resource: &xdg_toplevel::XdgToplevel) -> super::Toplevel .unwrap(); super::ToplevelSurface { wl_surface: data.wl_surface.clone(), - shell_surface: ToplevelKind::Xdg(resource.clone()), + shell_surface: resource.clone(), } } @@ -735,7 +735,7 @@ fn make_popup_handle(resource: &xdg_popup::XdgPopup) -> super::PopupSurface { .unwrap(); super::PopupSurface { wl_surface: data.wl_surface.clone(), - shell_surface: PopupKind::Xdg(resource.clone()), + shell_surface: resource.clone(), } } diff --git a/src/wayland/shell/xdg/zxdgv6_handlers.rs b/src/wayland/shell/xdg/zxdgv6_handlers.rs deleted file mode 100644 index b9ca8f2..0000000 --- a/src/wayland/shell/xdg/zxdgv6_handlers.rs +++ /dev/null @@ -1,846 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; -use std::{cell::RefCell, ops::Deref as _, sync::Mutex}; - -use crate::wayland::compositor; -use crate::wayland::shell::xdg::{PopupState, ZXDG_POPUP_ROLE, ZXDG_TOPLEVEL_ROLE}; -use crate::wayland::Serial; -use wayland_protocols::{ - unstable::xdg_shell::v6::server::{ - zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6, - }, - xdg_shell::server::{xdg_positioner, xdg_toplevel}, -}; -use wayland_server::DispatchData; -use wayland_server::{protocol::wl_surface, Filter, Main}; - -use crate::utils::Rectangle; - -use super::{ - make_shell_client_data, PopupConfigure, PopupKind, PositionerState, ShellClient, ShellClientData, - ShellData, SurfaceCachedState, ToplevelConfigure, ToplevelKind, XdgPopupSurfaceRoleAttributes, - XdgRequest, XdgToplevelSurfaceRoleAttributes, -}; - -pub(crate) fn implement_shell( - shell: Main, - shell_data: &ShellData, - dispatch_data: DispatchData<'_>, -) -> zxdg_shell_v6::ZxdgShellV6 { - shell.quick_assign(shell_implementation); - shell.as_ref().user_data().set(|| ShellUserData { - shell_data: shell_data.clone(), - client_data: Mutex::new(make_shell_client_data()), - }); - let mut user_impl = shell_data.user_impl.borrow_mut(); - (&mut *user_impl)( - XdgRequest::NewClient { - client: make_shell_client(&shell), - }, - dispatch_data, - ); - shell.deref().clone() -} - -/* - * xdg_shell - */ - -pub(crate) struct ShellUserData { - shell_data: ShellData, - pub(crate) client_data: Mutex, -} - -pub(crate) fn make_shell_client(resource: &zxdg_shell_v6::ZxdgShellV6) -> ShellClient { - ShellClient { - kind: super::ShellClientKind::ZxdgV6(resource.clone()), - } -} - -fn shell_implementation( - shell: Main, - request: zxdg_shell_v6::Request, - dispatch_data: DispatchData<'_>, -) { - let data = shell.as_ref().user_data().get::().unwrap(); - match request { - zxdg_shell_v6::Request::Destroy => { - // all is handled by destructor - } - zxdg_shell_v6::Request::CreatePositioner { id } => { - implement_positioner(id); - } - zxdg_shell_v6::Request::GetXdgSurface { id, surface } => { - id.quick_assign(xdg_surface_implementation); - id.assign_destructor(Filter::new(|surface, _, _data| destroy_surface(surface))); - id.as_ref().user_data().set(|| XdgSurfaceUserData { - shell_data: data.shell_data.clone(), - wl_surface: surface, - shell: shell.deref().clone(), - has_active_role: AtomicBool::new(false), - }); - } - zxdg_shell_v6::Request::Pong { serial } => { - let serial = Serial::from(serial); - let valid = { - let mut guard = data.client_data.lock().unwrap(); - if guard.pending_ping == Some(serial) { - guard.pending_ping = None; - true - } else { - false - } - }; - if valid { - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)( - XdgRequest::ClientPong { - client: make_shell_client(&shell), - }, - dispatch_data, - ); - } - } - _ => unreachable!(), - } -} - -/* - * xdg_positioner - */ - -fn implement_positioner( - positioner: Main, -) -> zxdg_positioner_v6::ZxdgPositionerV6 { - positioner.quick_assign(|positioner, request, _data| { - let mutex = positioner - .as_ref() - .user_data() - .get::>() - .unwrap(); - let mut state = mutex.borrow_mut(); - match request { - zxdg_positioner_v6::Request::Destroy => { - // handled by destructor - } - zxdg_positioner_v6::Request::SetSize { width, height } => { - if width < 1 || height < 1 { - positioner.as_ref().post_error( - zxdg_positioner_v6::Error::InvalidInput as u32, - "Invalid size for positioner.".into(), - ); - } else { - state.rect_size = (width, height).into(); - } - } - zxdg_positioner_v6::Request::SetAnchorRect { x, y, width, height } => { - if width < 1 || height < 1 { - positioner.as_ref().post_error( - zxdg_positioner_v6::Error::InvalidInput as u32, - "Invalid size for positioner's anchor rectangle.".into(), - ); - } else { - state.anchor_rect = Rectangle::from_loc_and_size((x, y), (width, height)); - } - } - zxdg_positioner_v6::Request::SetAnchor { anchor } => { - if let Some(anchor) = zxdg_anchor_to_xdg(anchor) { - state.anchor_edges = anchor; - } else { - positioner.as_ref().post_error( - zxdg_positioner_v6::Error::InvalidInput as u32, - "Invalid anchor for positioner.".into(), - ); - } - } - zxdg_positioner_v6::Request::SetGravity { gravity } => { - if let Some(gravity) = zxdg_gravity_to_xdg(gravity) { - state.gravity = gravity; - } else { - positioner.as_ref().post_error( - zxdg_positioner_v6::Error::InvalidInput as u32, - "Invalid gravity for positioner.".into(), - ); - } - } - zxdg_positioner_v6::Request::SetConstraintAdjustment { - constraint_adjustment, - } => { - let constraint_adjustment = - zxdg_positioner_v6::ConstraintAdjustment::from_bits_truncate(constraint_adjustment); - state.constraint_adjustment = zxdg_constraints_adg_to_xdg(constraint_adjustment); - } - zxdg_positioner_v6::Request::SetOffset { x, y } => { - state.offset = (x, y).into(); - } - _ => unreachable!(), - } - }); - positioner - .as_ref() - .user_data() - .set(|| RefCell::new(PositionerState::default())); - - positioner.deref().clone() -} - -/* - * xdg_surface - */ - -struct XdgSurfaceUserData { - shell_data: ShellData, - wl_surface: wl_surface::WlSurface, - shell: zxdg_shell_v6::ZxdgShellV6, - has_active_role: AtomicBool, -} - -fn destroy_surface(surface: zxdg_surface_v6::ZxdgSurfaceV6) { - let data = surface.as_ref().user_data().get::().unwrap(); - if !data.wl_surface.as_ref().is_alive() { - // the wl_surface is destroyed, this means the client is not - // trying to change the role but it's a cleanup (possibly a - // disconnecting client), ignore the protocol check. - return; - } - - if compositor::get_role(&data.wl_surface).is_none() { - // No role assigned to the surface, we can exit early. - return; - } - - if data.has_active_role.load(Ordering::Acquire) { - data.shell.as_ref().post_error( - zxdg_shell_v6::Error::Role as u32, - "xdg_surface was destroyed before its role object".into(), - ); - } -} - -fn xdg_surface_implementation( - xdg_surface: Main, - request: zxdg_surface_v6::Request, - dispatch_data: DispatchData<'_>, -) { - let data = xdg_surface - .as_ref() - .user_data() - .get::() - .unwrap(); - match request { - zxdg_surface_v6::Request::Destroy => { - // all is handled by our destructor - } - zxdg_surface_v6::Request::GetToplevel { id } => { - // We now can assign a role to the surface - let surface = &data.wl_surface; - let shell = &data.shell; - - if compositor::give_role(surface, ZXDG_TOPLEVEL_ROLE).is_err() { - shell.as_ref().post_error( - zxdg_shell_v6::Error::Role as u32, - "Surface already has a role.".into(), - ); - return; - } - - data.has_active_role.store(true, Ordering::Release); - - compositor::with_states(surface, |states| { - states - .data_map - .insert_if_missing_threadsafe(|| Mutex::new(XdgToplevelSurfaceRoleAttributes::default())) - }) - .unwrap(); - - compositor::add_commit_hook(surface, super::ToplevelSurface::commit_hook); - - id.quick_assign(toplevel_implementation); - id.assign_destructor(Filter::new(|toplevel, _, _data| destroy_toplevel(toplevel))); - id.as_ref().user_data().set(|| ShellSurfaceUserData { - shell_data: data.shell_data.clone(), - wl_surface: data.wl_surface.clone(), - shell: data.shell.clone(), - xdg_surface: xdg_surface.deref().clone(), - }); - - data.shell_data - .shell_state - .lock() - .unwrap() - .known_toplevels - .push(make_toplevel_handle(&id)); - - let handle = make_toplevel_handle(&id); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)(XdgRequest::NewToplevel { surface: handle }, dispatch_data); - } - zxdg_surface_v6::Request::GetPopup { - id, - parent, - positioner, - } => { - let positioner_data = *positioner - .as_ref() - .user_data() - .get::>() - .unwrap() - .borrow(); - - let parent_surface = { - let parent_data = parent.as_ref().user_data().get::().unwrap(); - parent_data.wl_surface.clone() - }; - - // We now can assign a role to the surface - let surface = &data.wl_surface; - let shell = &data.shell; - - let attributes = XdgPopupSurfaceRoleAttributes { - parent: Some(parent_surface), - server_pending: Some(PopupState { - // Set the positioner data as the popup geometry - geometry: positioner_data.get_geometry(), - positioner: positioner_data, - }), - ..Default::default() - }; - if compositor::give_role(surface, ZXDG_POPUP_ROLE).is_err() { - shell.as_ref().post_error( - zxdg_shell_v6::Error::Role as u32, - "Surface already has a role.".into(), - ); - return; - } - - data.has_active_role.store(true, Ordering::Release); - - compositor::with_states(surface, |states| { - states - .data_map - .insert_if_missing_threadsafe(|| Mutex::new(XdgPopupSurfaceRoleAttributes::default())); - *states - .data_map - .get::>() - .unwrap() - .lock() - .unwrap() = attributes; - }) - .unwrap(); - - compositor::add_commit_hook(surface, super::PopupSurface::commit_hook); - - id.quick_assign(popup_implementation); - id.assign_destructor(Filter::new(|popup, _, _data| destroy_popup(popup))); - id.as_ref().user_data().set(|| ShellSurfaceUserData { - shell_data: data.shell_data.clone(), - wl_surface: data.wl_surface.clone(), - shell: data.shell.clone(), - xdg_surface: xdg_surface.deref().clone(), - }); - - data.shell_data - .shell_state - .lock() - .unwrap() - .known_popups - .push(make_popup_handle(&id)); - - let handle = make_popup_handle(&id); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)( - XdgRequest::NewPopup { - surface: handle, - positioner: positioner_data, - }, - dispatch_data, - ); - } - zxdg_surface_v6::Request::SetWindowGeometry { x, y, width, height } => { - // Check the role of the surface, this can be either xdg_toplevel - // or xdg_popup. If none of the role matches the xdg_surface has no role set - // which is a protocol error. - let surface = &data.wl_surface; - - let role = compositor::get_role(surface); - - if role.is_none() { - xdg_surface.as_ref().post_error( - zxdg_surface_v6::Error::NotConstructed as u32, - "xdg_surface must have a role.".into(), - ); - return; - } - - if role != Some(ZXDG_TOPLEVEL_ROLE) && role != Some(ZXDG_POPUP_ROLE) { - data.shell.as_ref().post_error( - zxdg_shell_v6::Error::Role as u32, - "xdg_surface must have a role of xdg_toplevel or xdg_popup.".into(), - ); - } - - compositor::with_states(surface, |states| { - states.cached_state.pending::().geometry = - Some(Rectangle::from_loc_and_size((x, y), (width, height))); - }) - .unwrap(); - } - zxdg_surface_v6::Request::AckConfigure { serial } => { - let serial = Serial::from(serial); - let surface = &data.wl_surface; - - // Check the role of the surface, this can be either xdg_toplevel - // or xdg_popup. If none of the role matches the xdg_surface has no role set - // which is a protocol error. - if compositor::get_role(surface).is_none() { - data.shell.as_ref().post_error( - zxdg_surface_v6::Error::NotConstructed as u32, - "xdg_surface must have a role.".into(), - ); - return; - } - - // Find the correct configure state for the provided serial - // discard all configure states that are older than the provided - // serial. - // If no matching serial can be found raise a protocol error - // - // Invoke the user impl with the found configuration - // This has to include the serial and the role specific data. - // - For xdg_popup there is no data. - // - For xdg_toplevel send the state data including - // width, height, min/max size, maximized, fullscreen, resizing, activated - // - // This can be used to integrate custom protocol extensions - // - let found_configure = compositor::with_states(surface, |states| { - if states.role == Some(ZXDG_TOPLEVEL_ROLE) { - Ok(states - .data_map - .get::>() - .unwrap() - .lock() - .unwrap() - .ack_configure(serial)) - } else if states.role == Some(ZXDG_POPUP_ROLE) { - Ok(states - .data_map - .get::>() - .unwrap() - .lock() - .unwrap() - .ack_configure(serial)) - } else { - Err(()) - } - }) - .unwrap(); - let configure = match found_configure { - Ok(Some(configure)) => configure, - Ok(None) => { - data.shell.as_ref().post_error( - zxdg_shell_v6::Error::InvalidSurfaceState as u32, - format!("wrong configure serial: {}", ::from(serial)), - ); - return; - } - Err(_) => { - data.shell.as_ref().post_error( - zxdg_shell_v6::Error::Role as u32, - "xdg_surface must have a role of xdg_toplevel or xdg_popup.".into(), - ); - return; - } - }; - - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)( - XdgRequest::AckConfigure { - surface: surface.clone(), - configure, - }, - dispatch_data, - ); - } - _ => unreachable!(), - } -} - -/* - * xdg_toplevel - */ - -pub struct ShellSurfaceUserData { - pub(crate) shell_data: ShellData, - pub(crate) wl_surface: wl_surface::WlSurface, - pub(crate) shell: zxdg_shell_v6::ZxdgShellV6, - pub(crate) xdg_surface: zxdg_surface_v6::ZxdgSurfaceV6, -} - -// Utility functions allowing to factor out a lot of the upcoming logic -fn with_surface_toplevel_role_data(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F) -> T -where - F: FnOnce(&mut XdgToplevelSurfaceRoleAttributes) -> T, -{ - let data = toplevel - .as_ref() - .user_data() - .get::() - .unwrap(); - compositor::with_states(&data.wl_surface, |states| { - f(&mut *states - .data_map - .get::>() - .unwrap() - .lock() - .unwrap()) - }) - .unwrap() -} - -fn with_toplevel_pending_state(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F) -> T -where - F: FnOnce(&mut SurfaceCachedState) -> T, -{ - let data = toplevel - .as_ref() - .user_data() - .get::() - .unwrap(); - compositor::with_states(&data.wl_surface, |states| { - f(&mut *states.cached_state.pending::()) - }) - .unwrap() -} - -pub fn send_toplevel_configure(resource: &zxdg_toplevel_v6::ZxdgToplevelV6, configure: ToplevelConfigure) { - let data = resource - .as_ref() - .user_data() - .get::() - .unwrap(); - - let (width, height) = configure.state.size.unwrap_or_default().into(); - // convert the Vec (which is really a Vec) into Vec - let states = { - let mut states: Vec = configure - .state - .states - .into_filtered_states(resource.as_ref().version()); - let ptr = states.as_mut_ptr(); - let len = states.len(); - let cap = states.capacity(); - ::std::mem::forget(states); - unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } - }; - let serial = configure.serial; - - // Send the toplevel configure - resource.configure(width, height, states); - - // Send the base xdg_surface configure event to mark - // The configure as finished - data.xdg_surface.configure(serial.into()); -} - -fn make_toplevel_handle(resource: &zxdg_toplevel_v6::ZxdgToplevelV6) -> super::ToplevelSurface { - let data = resource - .as_ref() - .user_data() - .get::() - .unwrap(); - super::ToplevelSurface { - wl_surface: data.wl_surface.clone(), - shell_surface: ToplevelKind::ZxdgV6(resource.clone()), - } -} - -fn toplevel_implementation( - toplevel: Main, - request: zxdg_toplevel_v6::Request, - dispatch_data: DispatchData<'_>, -) { - let data = toplevel - .as_ref() - .user_data() - .get::() - .unwrap(); - match request { - zxdg_toplevel_v6::Request::Destroy => { - // all it done by the destructor - } - zxdg_toplevel_v6::Request::SetParent { parent } => { - let parent_surface = parent.map(|toplevel_surface_parent| { - toplevel_surface_parent - .as_ref() - .user_data() - .get::() - .unwrap() - .wl_surface - .clone() - }); - - // Parent is not double buffered, we can set it directly - set_parent(&toplevel, parent_surface); - } - zxdg_toplevel_v6::Request::SetTitle { title } => { - // Title is not double buffered, we can set it directly - with_surface_toplevel_role_data(&toplevel, |data| { - data.title = Some(title); - }); - } - zxdg_toplevel_v6::Request::SetAppId { app_id } => { - // AppId is not double buffered, we can set it directly - with_surface_toplevel_role_data(&toplevel, |role| { - role.app_id = Some(app_id); - }); - } - zxdg_toplevel_v6::Request::ShowWindowMenu { seat, serial, x, y } => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - let serial = Serial::from(serial); - (&mut *user_impl)( - XdgRequest::ShowWindowMenu { - surface: handle, - seat, - serial, - location: (x, y).into(), - }, - dispatch_data, - ); - } - zxdg_toplevel_v6::Request::Move { seat, serial } => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - let serial = Serial::from(serial); - (&mut *user_impl)( - XdgRequest::Move { - surface: handle, - seat, - serial, - }, - dispatch_data, - ); - } - zxdg_toplevel_v6::Request::Resize { seat, serial, edges } => { - let edges = - zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - let serial = Serial::from(serial); - (&mut *user_impl)( - XdgRequest::Resize { - surface: handle, - seat, - serial, - edges: zxdg_edges_to_xdg(edges), - }, - dispatch_data, - ); - } - zxdg_toplevel_v6::Request::SetMaxSize { width, height } => { - with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height).into(); - }); - } - zxdg_toplevel_v6::Request::SetMinSize { width, height } => { - with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.min_size = (width, height).into(); - }); - } - zxdg_toplevel_v6::Request::SetMaximized => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)(XdgRequest::Maximize { surface: handle }, dispatch_data); - } - zxdg_toplevel_v6::Request::UnsetMaximized => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)(XdgRequest::UnMaximize { surface: handle }, dispatch_data); - } - zxdg_toplevel_v6::Request::SetFullscreen { output } => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)( - XdgRequest::Fullscreen { - surface: handle, - output, - }, - dispatch_data, - ); - } - zxdg_toplevel_v6::Request::UnsetFullscreen => { - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)(XdgRequest::UnFullscreen { surface: handle }, dispatch_data); - } - zxdg_toplevel_v6::Request::SetMinimized => { - // This has to be handled by the compositor, may not be - // supported and just ignored - let handle = make_toplevel_handle(&toplevel); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - (&mut *user_impl)(XdgRequest::Minimize { surface: handle }, dispatch_data); - } - _ => unreachable!(), - } -} - -fn destroy_toplevel(toplevel: zxdg_toplevel_v6::ZxdgToplevelV6) { - let data = toplevel - .as_ref() - .user_data() - .get::() - .unwrap(); - if let Some(data) = data.xdg_surface.as_ref().user_data().get::() { - data.has_active_role.store(false, Ordering::Release); - } - // remove this surface from the known ones (as well as any leftover dead surface) - data.shell_data - .shell_state - .lock() - .unwrap() - .known_toplevels - .retain(|other| other.alive()); -} - -/* - * xdg_popup - */ - -pub(crate) fn send_popup_configure(resource: &zxdg_popup_v6::ZxdgPopupV6, configure: PopupConfigure) { - let data = resource - .as_ref() - .user_data() - .get::() - .unwrap(); - - let serial = configure.serial; - let geometry = configure.state.geometry; - - // Send the popup configure - resource.configure(geometry.loc.x, geometry.loc.y, geometry.size.w, geometry.size.h); - - // Send the base xdg_surface configure event to mark - // the configure as finished - data.xdg_surface.configure(serial.into()); -} - -fn make_popup_handle(resource: &zxdg_popup_v6::ZxdgPopupV6) -> super::PopupSurface { - let data = resource - .as_ref() - .user_data() - .get::() - .unwrap(); - super::PopupSurface { - wl_surface: data.wl_surface.clone(), - shell_surface: PopupKind::ZxdgV6(resource.clone()), - } -} - -fn popup_implementation( - popup: Main, - request: zxdg_popup_v6::Request, - dispatch_data: DispatchData<'_>, -) { - let data = popup.as_ref().user_data().get::().unwrap(); - match request { - zxdg_popup_v6::Request::Destroy => { - // all is handled by our destructor - } - zxdg_popup_v6::Request::Grab { seat, serial } => { - let handle = make_popup_handle(&popup); - let mut user_impl = data.shell_data.user_impl.borrow_mut(); - let serial = Serial::from(serial); - (&mut *user_impl)( - XdgRequest::Grab { - surface: handle, - seat, - serial, - }, - dispatch_data, - ); - } - _ => unreachable!(), - } -} - -fn destroy_popup(popup: zxdg_popup_v6::ZxdgPopupV6) { - let data = popup.as_ref().user_data().get::().unwrap(); - if let Some(data) = data.xdg_surface.as_ref().user_data().get::() { - data.has_active_role.store(false, Ordering::Release); - } - // remove this surface from the known ones (as well as any leftover dead surface) - data.shell_data - .shell_state - .lock() - .unwrap() - .known_popups - .retain(|other| other.alive()); -} - -fn zxdg_edges_to_xdg(e: zxdg_toplevel_v6::ResizeEdge) -> xdg_toplevel::ResizeEdge { - match e { - zxdg_toplevel_v6::ResizeEdge::None => xdg_toplevel::ResizeEdge::None, - zxdg_toplevel_v6::ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top, - zxdg_toplevel_v6::ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom, - zxdg_toplevel_v6::ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left, - zxdg_toplevel_v6::ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right, - zxdg_toplevel_v6::ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft, - zxdg_toplevel_v6::ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight, - zxdg_toplevel_v6::ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft, - zxdg_toplevel_v6::ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight, - _ => unreachable!(), - } -} - -fn zxdg_constraints_adg_to_xdg( - c: zxdg_positioner_v6::ConstraintAdjustment, -) -> xdg_positioner::ConstraintAdjustment { - xdg_positioner::ConstraintAdjustment::from_bits_truncate(c.bits()) -} - -fn zxdg_gravity_to_xdg(c: zxdg_positioner_v6::Gravity) -> Option { - match c.bits() { - 0b0000 => Some(xdg_positioner::Gravity::None), - 0b0001 => Some(xdg_positioner::Gravity::Top), - 0b0010 => Some(xdg_positioner::Gravity::Bottom), - 0b0100 => Some(xdg_positioner::Gravity::Left), - 0b0101 => Some(xdg_positioner::Gravity::TopLeft), - 0b0110 => Some(xdg_positioner::Gravity::BottomLeft), - 0b1000 => Some(xdg_positioner::Gravity::Right), - 0b1001 => Some(xdg_positioner::Gravity::TopRight), - 0b1010 => Some(xdg_positioner::Gravity::BottomRight), - _ => None, - } -} - -fn zxdg_anchor_to_xdg(c: zxdg_positioner_v6::Anchor) -> Option { - match c.bits() { - 0b0000 => Some(xdg_positioner::Anchor::None), - 0b0001 => Some(xdg_positioner::Anchor::Top), - 0b0010 => Some(xdg_positioner::Anchor::Bottom), - 0b0100 => Some(xdg_positioner::Anchor::Left), - 0b0101 => Some(xdg_positioner::Anchor::TopLeft), - 0b0110 => Some(xdg_positioner::Anchor::BottomLeft), - 0b1000 => Some(xdg_positioner::Anchor::Right), - 0b1001 => Some(xdg_positioner::Anchor::TopRight), - 0b1010 => Some(xdg_positioner::Anchor::BottomRight), - _ => None, - } -} - -pub(crate) fn get_parent(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6) -> Option { - with_surface_toplevel_role_data(toplevel, |data| data.parent.clone()) -} - -/// Sets the parent of the specified toplevel surface. -/// -/// The parent must be a toplevel surface. -/// -/// The parent of a surface is not double buffered and therefore may be set directly. -/// -/// If the parent is `None`, the parent-child relationship is removed. -pub(crate) fn set_parent(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, parent: Option) { - with_surface_toplevel_role_data(toplevel, |data| { - data.parent = parent; - }); -} diff --git a/src/wayland/xdg_foreign/mod.rs b/src/wayland/xdg_foreign/mod.rs index 63d18b6..14adfb4 100644 --- a/src/wayland/xdg_foreign/mod.rs +++ b/src/wayland/xdg_foreign/mod.rs @@ -20,7 +20,7 @@ //! //! # let mut display = wayland_server::Display::new(); //! // XDG Shell init -//! let (shell_state, _, _) = xdg_shell_init( +//! let (shell_state, _) = xdg_shell_init( //! &mut display, //! |event: XdgRequest, dispatch_data| { /* handle the shell requests here */ }, //! None