Remove XDG Shell V6
This commit is contained in:
parent
a9f1188fea
commit
8114bac8fd
|
@ -335,7 +335,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, 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::<AnvilState<BackendData>>().unwrap();
|
||||
|
|
|
@ -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<PopupState>,
|
||||
popup_handle: Option<PopupKind>
|
||||
popup_handle: Option<xdg_popup::XdgPopup>
|
||||
},
|
||||
|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<L, Impl>(
|
||||
display: &mut Display,
|
||||
implementation: Impl,
|
||||
logger: L,
|
||||
) -> (
|
||||
Arc<Mutex<ShellState>>,
|
||||
Global<xdg_wm_base::XdgWmBase>,
|
||||
Global<zxdg_shell_v6::ZxdgShellV6>,
|
||||
)
|
||||
) -> (Arc<Mutex<ShellState>>, Global<xdg_wm_base::XdgWmBase>)
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
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<Serial>,
|
||||
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,9 +838,8 @@ impl ShellClient {
|
|||
if !self.alive() {
|
||||
return Err(PingError::DeadSurface);
|
||||
}
|
||||
match self.kind {
|
||||
ShellClientKind::Xdg(ref shell) => {
|
||||
let user_data = shell
|
||||
let user_data = self
|
||||
.kind
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellUserData>()
|
||||
|
@ -886,22 +849,8 @@ impl ShellClient {
|
|||
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::<self::zxdgv6_handlers::ShellUserData>()
|
||||
.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());
|
||||
}
|
||||
}
|
||||
self.kind.ping(serial.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -913,9 +862,8 @@ impl ShellClient {
|
|||
if !self.alive() {
|
||||
return Err(crate::utils::DeadResource);
|
||||
}
|
||||
match self.kind {
|
||||
ShellClientKind::Xdg(ref shell) => {
|
||||
let data = shell
|
||||
let data = self
|
||||
.kind
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellUserData>()
|
||||
|
@ -923,30 +871,13 @@ impl ShellClient {
|
|||
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::<self::zxdgv6_handlers::ShellUserData>()
|
||||
.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
|
||||
let shell = {
|
||||
let data = self
|
||||
.shell_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
ShellClientKind::Xdg(data.wm_base.clone())
|
||||
}
|
||||
ToplevelKind::ZxdgV6(ref s) => {
|
||||
let data = s
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::zxdgv6_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
ShellClientKind::ZxdgV6(data.shell.clone())
|
||||
}
|
||||
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,9 +1027,8 @@ impl ToplevelSurface {
|
|||
})
|
||||
.unwrap();
|
||||
if !configured {
|
||||
match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => {
|
||||
let data = s
|
||||
let data = self
|
||||
.shell_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellSurfaceUserData>()
|
||||
|
@ -1126,28 +1038,12 @@ impl ToplevelSurface {
|
|||
"Surface has not been configured yet.".into(),
|
||||
);
|
||||
}
|
||||
ToplevelKind::ZxdgV6(ref s) => {
|
||||
let data = s
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::zxdgv6_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
data.xdg_surface.as_ref().post_error(
|
||||
zxdg_surface_v6::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<wl_surface::WlSurface> {
|
||||
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
|
||||
let shell = {
|
||||
let data = self
|
||||
.shell_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
ShellClientKind::Xdg(data.wm_base.clone())
|
||||
}
|
||||
PopupKind::ZxdgV6(ref p) => {
|
||||
let data = p
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::zxdgv6_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
ShellClientKind::ZxdgV6(data.shell.clone())
|
||||
}
|
||||
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,9 +1331,7 @@ impl PopupSurface {
|
|||
})
|
||||
.unwrap_or(None);
|
||||
if let Some(handle) = send_error_to {
|
||||
match handle {
|
||||
PopupKind::Xdg(ref s) => {
|
||||
let data = s
|
||||
let data = handle
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellSurfaceUserData>()
|
||||
|
@ -1481,19 +1340,6 @@ impl PopupSurface {
|
|||
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::<self::zxdgv6_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
data.xdg_surface.as_ref().post_error(
|
||||
zxdg_surface_v6::Error::NotConstructed as u32,
|
||||
"Surface has not been configured yet.".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1539,9 +1385,8 @@ impl PopupSurface {
|
|||
})
|
||||
.unwrap();
|
||||
if !configured {
|
||||
match self.shell_surface {
|
||||
PopupKind::Xdg(ref s) => {
|
||||
let data = s
|
||||
let data = self
|
||||
.shell_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::xdg_handlers::ShellSurfaceUserData>()
|
||||
|
@ -1551,19 +1396,6 @@ impl PopupSurface {
|
|||
"Surface has not been configured yet.".into(),
|
||||
);
|
||||
}
|
||||
PopupKind::ZxdgV6(ref s) => {
|
||||
let data = s
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<self::zxdgv6_handlers::ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
data.xdg_surface.as_ref().post_error(
|
||||
zxdg_surface_v6::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
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<zxdg_shell_v6::ZxdgShellV6>,
|
||||
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<ShellClientData>,
|
||||
}
|
||||
|
||||
pub(crate) fn make_shell_client(resource: &zxdg_shell_v6::ZxdgShellV6) -> ShellClient {
|
||||
ShellClient {
|
||||
kind: super::ShellClientKind::ZxdgV6(resource.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn shell_implementation(
|
||||
shell: Main<zxdg_shell_v6::ZxdgShellV6>,
|
||||
request: zxdg_shell_v6::Request,
|
||||
dispatch_data: DispatchData<'_>,
|
||||
) {
|
||||
let data = shell.as_ref().user_data().get::<ShellUserData>().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>,
|
||||
) -> zxdg_positioner_v6::ZxdgPositionerV6 {
|
||||
positioner.quick_assign(|positioner, request, _data| {
|
||||
let mutex = positioner
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<RefCell<PositionerState>>()
|
||||
.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::<XdgSurfaceUserData>().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<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
request: zxdg_surface_v6::Request,
|
||||
dispatch_data: DispatchData<'_>,
|
||||
) {
|
||||
let data = xdg_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<XdgSurfaceUserData>()
|
||||
.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::<RefCell<PositionerState>>()
|
||||
.unwrap()
|
||||
.borrow();
|
||||
|
||||
let parent_surface = {
|
||||
let parent_data = parent.as_ref().user_data().get::<XdgSurfaceUserData>().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::<Mutex<XdgPopupSurfaceRoleAttributes>>()
|
||||
.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::<SurfaceCachedState>().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::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.ack_configure(serial))
|
||||
} else if states.role == Some(ZXDG_POPUP_ROLE) {
|
||||
Ok(states
|
||||
.data_map
|
||||
.get::<Mutex<XdgPopupSurfaceRoleAttributes>>()
|
||||
.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: {}", <u32>::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<F, T>(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut XdgToplevelSurfaceRoleAttributes) -> T,
|
||||
{
|
||||
let data = toplevel
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
compositor::with_states(&data.wl_surface, |states| {
|
||||
f(&mut *states
|
||||
.data_map
|
||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap())
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn with_toplevel_pending_state<F, T>(toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut SurfaceCachedState) -> T,
|
||||
{
|
||||
let data = toplevel
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
compositor::with_states(&data.wl_surface, |states| {
|
||||
f(&mut *states.cached_state.pending::<SurfaceCachedState>())
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn send_toplevel_configure(resource: &zxdg_toplevel_v6::ZxdgToplevelV6, configure: ToplevelConfigure) {
|
||||
let data = resource
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
|
||||
let (width, height) = configure.state.size.unwrap_or_default().into();
|
||||
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
|
||||
let states = {
|
||||
let mut states: Vec<xdg_toplevel::State> = 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::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
super::ToplevelSurface {
|
||||
wl_surface: data.wl_surface.clone(),
|
||||
shell_surface: ToplevelKind::ZxdgV6(resource.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn toplevel_implementation(
|
||||
toplevel: Main<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
request: zxdg_toplevel_v6::Request,
|
||||
dispatch_data: DispatchData<'_>,
|
||||
) {
|
||||
let data = toplevel
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<ShellSurfaceUserData>()
|
||||
.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::<ShellSurfaceUserData>()
|
||||
.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::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
if let Some(data) = data.xdg_surface.as_ref().user_data().get::<XdgSurfaceUserData>() {
|
||||
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::<ShellSurfaceUserData>()
|
||||
.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::<ShellSurfaceUserData>()
|
||||
.unwrap();
|
||||
super::PopupSurface {
|
||||
wl_surface: data.wl_surface.clone(),
|
||||
shell_surface: PopupKind::ZxdgV6(resource.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn popup_implementation(
|
||||
popup: Main<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
request: zxdg_popup_v6::Request,
|
||||
dispatch_data: DispatchData<'_>,
|
||||
) {
|
||||
let data = popup.as_ref().user_data().get::<ShellSurfaceUserData>().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::<ShellSurfaceUserData>().unwrap();
|
||||
if let Some(data) = data.xdg_surface.as_ref().user_data().get::<XdgSurfaceUserData>() {
|
||||
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<xdg_positioner::Gravity> {
|
||||
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<xdg_positioner::Anchor> {
|
||||
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<wl_surface::WlSurface> {
|
||||
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<wl_surface::WlSurface>) {
|
||||
with_surface_toplevel_role_data(toplevel, |data| {
|
||||
data.parent = parent;
|
||||
});
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue