wayland.shell: integrate the stable xdg_shell
This commit is contained in:
parent
b8d4b17a8a
commit
d97fde32e9
|
@ -1,4 +1,4 @@
|
|||
//! Utilities for handling shell surfaces, toplevel and popups using the `xdg_shell` protocol
|
||||
//! Utilities for handling shell surfaces with the `xdg_shell` protocol
|
||||
//!
|
||||
//! This module provides automatic handling of shell surfaces objects, by being registered
|
||||
//! as a global handler for `xdg_shell`.
|
||||
|
@ -6,7 +6,9 @@
|
|||
//! ## Why use this implementation
|
||||
//!
|
||||
//! This implementation can track for you the various shell surfaces defined by the
|
||||
//! clients by handling the `xdg_shell` protocol.
|
||||
//! clients by handling the `xdg_shell` protocol. It also contains a compatibility
|
||||
//! layer handling its precursor, the unstable `zxdg_shell_v6` protocol, which is
|
||||
//! mostly identical.
|
||||
//!
|
||||
//! It allows you to easily access a list of all shell surfaces defined by your clients
|
||||
//! access their associated metadata and underlying `wl_surface`s.
|
||||
|
@ -30,12 +32,10 @@
|
|||
//! #
|
||||
//! use smithay::wayland::compositor::roles::*;
|
||||
//! use smithay::wayland::compositor::CompositorToken;
|
||||
//! use smithay::wayland::shell::{shell_init, ShellSurfaceRole, ShellSurfaceUserImplementation};
|
||||
//! use wayland_server::protocol::wl_shell::WlShell;
|
||||
//! use smithay::wayland::shell::xdg::{xdg_shell_init, ShellSurfaceRole, ShellEvent};
|
||||
//! use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_shell_v6::ZxdgShellV6;
|
||||
//! use wayland_server::{EventLoop, EventLoopHandle};
|
||||
//! use wayland_server::{EventLoop, LoopToken};
|
||||
//! # use wayland_server::protocol::{wl_seat, wl_output};
|
||||
//! # use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_toplevel_v6;
|
||||
//! # #[derive(Default)] struct MySurfaceData;
|
||||
//!
|
||||
//! // define the roles type. You need to integrate the ShellSurface role:
|
||||
|
@ -50,36 +50,21 @@
|
|||
//! }
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
||||
//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>(
|
||||
//! # &mut event_loop,
|
||||
//! # unimplemented!(),
|
||||
//! # (),
|
||||
//! # &mut display,
|
||||
//! # event_loop.token(),
|
||||
//! # |_, _| {},
|
||||
//! # None
|
||||
//! # );
|
||||
//! // define your implementation for shell
|
||||
//! let my_shell_implementation = ShellSurfaceUserImplementation {
|
||||
//! new_client: |evlh, idata, client| { unimplemented!() },
|
||||
//! client_pong: |evlh, idata, client| { unimplemented!() },
|
||||
//! new_toplevel: |evlh, idata, toplevel| { unimplemented!() },
|
||||
//! new_popup: |evlh, idata, popup| { unimplemented!() },
|
||||
//! move_: |evlh, idata, toplevel, seat, serial| { unimplemented!() },
|
||||
//! resize: |evlh, idata, toplevel, seat, serial, edges| { unimplemented!() },
|
||||
//! grab: |evlh, idata, popup, seat, serial| { unimplemented!() },
|
||||
//! change_display_state: |evlh, idata, toplevel, maximized, minimized, fullscreen, output| {
|
||||
//! unimplemented!()
|
||||
//! },
|
||||
//! show_window_menu: |evlh, idata, toplevel, seat, serial, x, y| { unimplemented!() },
|
||||
//! };
|
||||
//!
|
||||
//! // define your implementation data
|
||||
//! let my_shell_implementation_data = ();
|
||||
//!
|
||||
//! let (shell_state_token, _, _) = shell_init::<_, _, _, _, MyShellData, _>(
|
||||
//! &mut event_loop,
|
||||
//! compositor_token, // token from the compositor implementation
|
||||
//! my_shell_implementation, // instance of shell::ShellSurfaceUserImplementation
|
||||
//! my_shell_implementation_data, // whatever data you need here
|
||||
//! let (shell_state, _, _) = xdg_shell_init(
|
||||
//! &mut display,
|
||||
//! event_loop.token(),
|
||||
//! // token from the compositor implementation
|
||||
//! compositor_token,
|
||||
//! // your implementation, can also be a strucy implementing the
|
||||
//! // appropriate Implementation<(), ShellEvent<_, _, _>> trait
|
||||
//! |event: ShellEvent<_, _, MyShellData>, ()| { /* ... */ },
|
||||
//! None // put a logger if you want
|
||||
//! );
|
||||
//!
|
||||
|
@ -100,9 +85,8 @@
|
|||
//! you can get a list of all currently alive popup surface from the `ShellState`.
|
||||
//!
|
||||
//! You'll obtain these objects though two means: either via the callback methods of
|
||||
//! the subhandler you provided, or via methods on the `ShellState` that you can
|
||||
//! access from the `state()` of the event loop and the token returned by the init
|
||||
//! function.
|
||||
//! the subhandler you provided, or via methods on the `ShellState` that you are given
|
||||
//! (in an `Arc<Mutex<_>>`) as return value of the init function.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
@ -110,14 +94,17 @@ use std::sync::{Arc, Mutex};
|
|||
use utils::Rectangle;
|
||||
use wayland::compositor::CompositorToken;
|
||||
use wayland::compositor::roles::Role;
|
||||
use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6,
|
||||
zxdg_positioner_v6 as xdg_positioner,
|
||||
zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6};
|
||||
use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base};
|
||||
use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6,
|
||||
zxdg_toplevel_v6};
|
||||
use wayland_server::{Display, Global, LoopToken, Resource};
|
||||
use wayland_server::commons::Implementation;
|
||||
use wayland_server::protocol::{wl_output, wl_seat, wl_surface};
|
||||
|
||||
// handlers for the xdg_shell protocol
|
||||
mod xdg_handlers;
|
||||
// compatibility handlers for the zxdg_shell_v6 protocol, its earlier version
|
||||
mod zxdgv6_handlers;
|
||||
|
||||
/// Metadata associated with the `shell_surface` role
|
||||
pub struct ShellSurfaceRole {
|
||||
|
@ -149,7 +136,7 @@ pub struct ShellSurfaceRole {
|
|||
pub configured: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
/// The state of a positioner, as set by the client
|
||||
pub struct PositionerState {
|
||||
/// Size of the rectangle that needs to be positioned
|
||||
|
@ -169,6 +156,24 @@ pub struct PositionerState {
|
|||
pub offset: (i32, i32),
|
||||
}
|
||||
|
||||
impl PositionerState {
|
||||
pub(crate) fn new() -> PositionerState {
|
||||
PositionerState {
|
||||
rect_size: (0, 0),
|
||||
anchor_rect: Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
anchor_edges: xdg_positioner::Anchor::None,
|
||||
gravity: xdg_positioner::Gravity::None,
|
||||
constraint_adjustment: xdg_positioner::ConstraintAdjustment::None,
|
||||
offset: (0, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contents of the pending state of a shell surface, depending on its role
|
||||
pub enum ShellSurfacePendingState {
|
||||
/// This a regular, toplevel surface
|
||||
|
@ -228,7 +233,7 @@ impl Clone for ToplevelState {
|
|||
/// The pending state of a popup surface
|
||||
pub struct PopupState {
|
||||
/// Parent of this popup surface
|
||||
pub parent: Resource<wl_surface::WlSurface>,
|
||||
pub parent: Option<Resource<wl_surface::WlSurface>>,
|
||||
/// The positioner specifying how this tooltip should
|
||||
/// be placed relative to its parent.
|
||||
pub positioner: PositionerState,
|
||||
|
@ -237,8 +242,8 @@ pub struct PopupState {
|
|||
impl Clone for PopupState {
|
||||
fn clone(&self) -> PopupState {
|
||||
PopupState {
|
||||
parent: self.parent.clone(),
|
||||
positioner: self.positioner,
|
||||
parent: self.parent.as_ref().map(|p| p.clone()),
|
||||
positioner: self.positioner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +275,7 @@ impl<U, R, SD> Clone for ShellImplementation<U, R, SD> {
|
|||
}
|
||||
|
||||
/// Create a new `xdg_shell` globals
|
||||
pub fn shell_init<U, R, SD, L, Impl>(
|
||||
pub fn xdg_shell_init<U, R, SD, L, Impl>(
|
||||
display: &mut Display,
|
||||
ltoken: LoopToken,
|
||||
ctoken: CompositorToken<U, R>,
|
||||
|
@ -278,6 +283,7 @@ pub fn shell_init<U, R, SD, L, Impl>(
|
|||
logger: L,
|
||||
) -> (
|
||||
Arc<Mutex<ShellState<U, R, SD>>>,
|
||||
Global<xdg_wm_base::XdgWmBase>,
|
||||
Global<zxdg_shell_v6::ZxdgShellV6>,
|
||||
)
|
||||
where
|
||||
|
@ -301,11 +307,17 @@ where
|
|||
shell_state: shell_state.clone(),
|
||||
};
|
||||
|
||||
let shell_impl_z = shell_impl.clone();
|
||||
|
||||
let xdg_shell_global = display.create_global(<oken, 1, move |_version, shell| {
|
||||
self::xdg_handlers::implement_shell(shell, &shell_impl);
|
||||
self::xdg_handlers::implement_wm_base(shell, &shell_impl);
|
||||
});
|
||||
|
||||
(shell_state, xdg_shell_global)
|
||||
let zxdgv6_shell_global = display.create_global(<oken, 1, move |_version, shell| {
|
||||
self::zxdgv6_handlers::implement_shell(shell, &shell_impl_z);
|
||||
});
|
||||
|
||||
(shell_state, xdg_shell_global, zxdgv6_shell_global)
|
||||
}
|
||||
|
||||
/// Shell global state
|
||||
|
@ -345,7 +357,8 @@ where
|
|||
*/
|
||||
|
||||
enum ShellClientKind {
|
||||
Xdg(Resource<zxdg_shell_v6::ZxdgShellV6>),
|
||||
Xdg(Resource<xdg_wm_base::XdgWmBase>),
|
||||
ZxdgV6(Resource<zxdg_shell_v6::ZxdgShellV6>),
|
||||
}
|
||||
|
||||
pub(crate) struct ShellClientData<SD> {
|
||||
|
@ -380,6 +393,7 @@ impl<SD> ShellClient<SD> {
|
|||
pub fn alive(&self) -> bool {
|
||||
match self.kind {
|
||||
ShellClientKind::Xdg(ref s) => s.is_alive(),
|
||||
ShellClientKind::ZxdgV6(ref s) => s.is_alive(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +402,8 @@ impl<SD> ShellClient<SD> {
|
|||
pub fn equals(&self, other: &Self) -> bool {
|
||||
match (&self.kind, &other.kind) {
|
||||
(&ShellClientKind::Xdg(ref s1), &ShellClientKind::Xdg(ref s2)) => s1.equals(s2),
|
||||
(&ShellClientKind::ZxdgV6(ref s1), &ShellClientKind::ZxdgV6(ref s2)) => s1.equals(s2),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,6 +429,16 @@ impl<SD> ShellClient<SD> {
|
|||
return Err(());
|
||||
}
|
||||
guard.pending_ping = serial;
|
||||
shell.send(xdg_wm_base::Event::Ping { serial });
|
||||
}
|
||||
ShellClientKind::ZxdgV6(ref shell) => {
|
||||
let mutex =
|
||||
unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData<SD>) };
|
||||
let mut guard = mutex.lock().unwrap();
|
||||
if guard.pending_ping == 0 {
|
||||
return Err(());
|
||||
}
|
||||
guard.pending_ping = serial;
|
||||
shell.send(zxdg_shell_v6::Event::Ping { serial });
|
||||
}
|
||||
}
|
||||
|
@ -434,14 +460,25 @@ impl<SD> ShellClient<SD> {
|
|||
let mut guard = mutex.lock().unwrap();
|
||||
Ok(f(&mut guard.data))
|
||||
}
|
||||
ShellClientKind::ZxdgV6(ref shell) => {
|
||||
let mutex =
|
||||
unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData<SD>) };
|
||||
let mut guard = mutex.lock().unwrap();
|
||||
Ok(f(&mut guard.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum ToplevelKind {
|
||||
Xdg(Resource<xdg_toplevel::XdgToplevel>),
|
||||
ZxdgV6(Resource<zxdg_toplevel_v6::ZxdgToplevelV6>),
|
||||
}
|
||||
|
||||
/// A handle to a toplevel surface
|
||||
pub struct ToplevelSurface<U, R, SD> {
|
||||
wl_surface: Resource<wl_surface::WlSurface>,
|
||||
shell_surface: Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
shell_surface: ToplevelKind,
|
||||
token: CompositorToken<U, R>,
|
||||
_shell_data: ::std::marker::PhantomData<SD>,
|
||||
}
|
||||
|
@ -454,7 +491,11 @@ where
|
|||
{
|
||||
/// Is the toplevel surface refered by this handle still alive?
|
||||
pub fn alive(&self) -> bool {
|
||||
self.shell_surface.is_alive() && self.wl_surface.is_alive()
|
||||
let shell_alive = match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => s.is_alive(),
|
||||
ToplevelKind::ZxdgV6(ref s) => s.is_alive(),
|
||||
};
|
||||
shell_alive && self.wl_surface.is_alive()
|
||||
}
|
||||
|
||||
/// Do this handle and the other one actually refer to the same toplevel surface?
|
||||
|
@ -469,11 +510,22 @@ where
|
|||
if !self.alive() {
|
||||
return None;
|
||||
}
|
||||
let &(_, ref shell, _) = unsafe {
|
||||
&*(self.shell_surface.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData)
|
||||
|
||||
let shell = match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => {
|
||||
let &(_, ref shell, _) =
|
||||
unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
||||
ShellClientKind::Xdg(shell.clone())
|
||||
}
|
||||
ToplevelKind::ZxdgV6(ref s) => {
|
||||
let &(_, ref shell, _) =
|
||||
unsafe { &*(s.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
||||
ShellClientKind::ZxdgV6(shell.clone())
|
||||
}
|
||||
};
|
||||
|
||||
Some(ShellClient {
|
||||
kind: ShellClientKind::Xdg(shell.clone()),
|
||||
kind: shell,
|
||||
_data: ::std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
@ -485,7 +537,10 @@ where
|
|||
if !self.alive() {
|
||||
return;
|
||||
}
|
||||
self::xdg_handlers::send_toplevel_configure(self.token, &self.shell_surface, cfg);
|
||||
match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure(self.token, s, cfg),
|
||||
ToplevelKind::ZxdgV6(ref s) => self::zxdgv6_handlers::send_toplevel_configure(self.token, s, cfg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure this surface was configured
|
||||
|
@ -504,20 +559,36 @@ where
|
|||
.with_role_data::<ShellSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
||||
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
||||
if !configured {
|
||||
let ptr = self.shell_surface.get_user_data();
|
||||
match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => {
|
||||
let ptr = s.get_user_data();
|
||||
let &(_, _, ref xdg_surface) =
|
||||
unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
||||
xdg_surface.post_error(
|
||||
zxdg_surface_v6::Error::NotConstructed as u32,
|
||||
"Surface has not been confgured yet.".into(),
|
||||
xdg_surface::Error::NotConstructed as u32,
|
||||
"Surface has not been configured yet.".into(),
|
||||
);
|
||||
}
|
||||
ToplevelKind::ZxdgV6(ref s) => {
|
||||
let ptr = s.get_user_data();
|
||||
let &(_, _, ref xdg_surface) =
|
||||
unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
||||
xdg_surface.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) {
|
||||
self.shell_surface.send(zxdg_toplevel_v6::Event::Close);
|
||||
match self.shell_surface {
|
||||
ToplevelKind::Xdg(ref s) => s.send(xdg_toplevel::Event::Close),
|
||||
ToplevelKind::ZxdgV6(ref s) => s.send(zxdg_toplevel_v6::Event::Close),
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the underlying `wl_surface` of this toplevel surface
|
||||
|
@ -548,13 +619,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) enum PopupKind {
|
||||
Xdg(Resource<xdg_popup::XdgPopup>),
|
||||
ZxdgV6(Resource<zxdg_popup_v6::ZxdgPopupV6>),
|
||||
}
|
||||
|
||||
/// A handle to a popup surface
|
||||
///
|
||||
/// This is an unified abstraction over the popup surfaces
|
||||
/// of both `wl_shell` and `xdg_shell`.
|
||||
pub struct PopupSurface<U, R, SD> {
|
||||
wl_surface: Resource<wl_surface::WlSurface>,
|
||||
shell_surface: Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
shell_surface: PopupKind,
|
||||
token: CompositorToken<U, R>,
|
||||
_shell_data: ::std::marker::PhantomData<SD>,
|
||||
}
|
||||
|
@ -567,7 +643,11 @@ where
|
|||
{
|
||||
/// Is the popup surface refered by this handle still alive?
|
||||
pub fn alive(&self) -> bool {
|
||||
self.shell_surface.is_alive() && self.wl_surface.is_alive()
|
||||
let shell_alive = match self.shell_surface {
|
||||
PopupKind::Xdg(ref p) => p.is_alive(),
|
||||
PopupKind::ZxdgV6(ref p) => p.is_alive(),
|
||||
};
|
||||
shell_alive && self.wl_surface.is_alive()
|
||||
}
|
||||
|
||||
/// Do this handle and the other one actually refer to the same popup surface?
|
||||
|
@ -582,11 +662,22 @@ where
|
|||
if !self.alive() {
|
||||
return None;
|
||||
}
|
||||
let &(_, ref shell, _) = unsafe {
|
||||
&*(self.shell_surface.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData)
|
||||
|
||||
let shell = match self.shell_surface {
|
||||
PopupKind::Xdg(ref p) => {
|
||||
let &(_, ref shell, _) =
|
||||
unsafe { &*(p.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
||||
ShellClientKind::Xdg(shell.clone())
|
||||
}
|
||||
PopupKind::ZxdgV6(ref p) => {
|
||||
let &(_, ref shell, _) =
|
||||
unsafe { &*(p.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
||||
ShellClientKind::ZxdgV6(shell.clone())
|
||||
}
|
||||
};
|
||||
|
||||
Some(ShellClient {
|
||||
kind: ShellClientKind::Xdg(shell.clone()),
|
||||
kind: shell,
|
||||
_data: ::std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
@ -598,7 +689,14 @@ where
|
|||
if !self.alive() {
|
||||
return;
|
||||
}
|
||||
self::xdg_handlers::send_popup_configure(self.token, &self.shell_surface, cfg);
|
||||
match self.shell_surface {
|
||||
PopupKind::Xdg(ref p) => {
|
||||
self::xdg_handlers::send_popup_configure(self.token, p, cfg);
|
||||
}
|
||||
PopupKind::ZxdgV6(ref p) => {
|
||||
self::zxdgv6_handlers::send_popup_configure(self.token, p, cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure this surface was configured
|
||||
|
@ -617,14 +715,27 @@ where
|
|||
.with_role_data::<ShellSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
||||
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
||||
if !configured {
|
||||
let ptr = self.shell_surface.get_user_data();
|
||||
match self.shell_surface {
|
||||
PopupKind::Xdg(ref s) => {
|
||||
let ptr = s.get_user_data();
|
||||
let &(_, _, ref xdg_surface) =
|
||||
unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
||||
xdg_surface.post_error(
|
||||
xdg_surface::Error::NotConstructed as u32,
|
||||
"Surface has not been confgured yet.".into(),
|
||||
);
|
||||
}
|
||||
PopupKind::ZxdgV6(ref s) => {
|
||||
let ptr = s.get_user_data();
|
||||
let &(_, _, ref xdg_surface) =
|
||||
unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
||||
xdg_surface.post_error(
|
||||
zxdg_surface_v6::Error::NotConstructed as u32,
|
||||
"Surface has not been confgured yet.".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
configured
|
||||
}
|
||||
|
||||
|
@ -633,7 +744,10 @@ where
|
|||
/// It means that the use has dismissed the popup surface, or that
|
||||
/// the pointer has left the area of popup grab if there was a grab.
|
||||
pub fn send_popup_done(&self) {
|
||||
self.shell_surface.send(zxdg_popup_v6::Event::PopupDone);
|
||||
match self.shell_surface {
|
||||
PopupKind::Xdg(ref p) => p.send(xdg_popup::Event::PopupDone),
|
||||
PopupKind::ZxdgV6(ref p) => p.send(zxdg_popup_v6::Event::PopupDone),
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the underlying `wl_surface` of this toplevel surface
|
||||
|
@ -672,7 +786,7 @@ pub struct ToplevelConfigure {
|
|||
///
|
||||
/// A surface can be any combination of these possible states
|
||||
/// at the same time.
|
||||
pub states: Vec<zxdg_toplevel_v6::State>,
|
||||
pub states: Vec<xdg_toplevel::State>,
|
||||
/// A serial number to track ACK from the client
|
||||
///
|
||||
/// This should be an ever increasing number, as the ACK-ing
|
||||
|
@ -750,7 +864,7 @@ pub enum ShellEvent<U, R, SD> {
|
|||
/// The grab serial
|
||||
serial: u32,
|
||||
/// Specification of which part of the window's border is being dragged
|
||||
edges: zxdg_toplevel_v6::ResizeEdge,
|
||||
edges: xdg_toplevel::ResizeEdge,
|
||||
},
|
||||
/// This popup requests a grab of the pointer
|
||||
///
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
use super::{make_shell_client_data, PopupConfigure, PopupState, PositionerState, ShellClient,
|
||||
use super::{make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient,
|
||||
ShellClientData, ShellEvent, ShellImplementation, ShellSurfacePendingState, ShellSurfaceRole,
|
||||
ToplevelConfigure, ToplevelState};
|
||||
ToplevelConfigure, ToplevelKind, ToplevelState};
|
||||
use std::sync::Mutex;
|
||||
use utils::Rectangle;
|
||||
use wayland::compositor::CompositorToken;
|
||||
use wayland::compositor::roles::*;
|
||||
use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6,
|
||||
zxdg_surface_v6, zxdg_toplevel_v6};
|
||||
use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base};
|
||||
use wayland_server::{LoopToken, NewResource, Resource};
|
||||
use wayland_server::commons::{downcast_impl, Implementation};
|
||||
use wayland_server::protocol::wl_surface;
|
||||
|
||||
pub(crate) fn implement_shell<U, R, SD>(
|
||||
shell: NewResource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
pub(crate) fn implement_wm_base<U, R, SD>(
|
||||
shell: NewResource<xdg_wm_base::XdgWmBase>,
|
||||
implem: &ShellImplementation<U, R, SD>,
|
||||
) -> Resource<zxdg_shell_v6::ZxdgShellV6>
|
||||
) -> Resource<xdg_wm_base::XdgWmBase>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
|
@ -42,7 +41,7 @@ where
|
|||
|
||||
pub(crate) type ShellUserData<SD> = Mutex<ShellClientData<SD>>;
|
||||
|
||||
fn destroy_shell<SD>(shell: &Resource<zxdg_shell_v6::ZxdgShellV6>) {
|
||||
fn destroy_shell<SD>(shell: &Resource<xdg_wm_base::XdgWmBase>) {
|
||||
let ptr = shell.get_user_data();
|
||||
shell.set_user_data(::std::ptr::null_mut());
|
||||
let data = unsafe { Box::from_raw(ptr as *mut ShellUserData<SD>) };
|
||||
|
@ -50,29 +49,29 @@ fn destroy_shell<SD>(shell: &Resource<zxdg_shell_v6::ZxdgShellV6>) {
|
|||
::std::mem::drop(data);
|
||||
}
|
||||
|
||||
pub(crate) fn make_shell_client<SD>(resource: &Resource<zxdg_shell_v6::ZxdgShellV6>) -> ShellClient<SD> {
|
||||
pub(crate) fn make_shell_client<SD>(resource: &Resource<xdg_wm_base::XdgWmBase>) -> ShellClient<SD> {
|
||||
ShellClient {
|
||||
kind: super::ShellClientKind::Xdg(resource.clone()),
|
||||
_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_shell_v6::ZxdgShellV6>, zxdg_shell_v6::Request>
|
||||
impl<U, R, SD> Implementation<Resource<xdg_wm_base::XdgWmBase>, xdg_wm_base::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(&mut self, request: zxdg_shell_v6::Request, shell: Resource<zxdg_shell_v6::ZxdgShellV6>) {
|
||||
fn receive(&mut self, request: xdg_wm_base::Request, shell: Resource<xdg_wm_base::XdgWmBase>) {
|
||||
match request {
|
||||
zxdg_shell_v6::Request::Destroy => {
|
||||
xdg_wm_base::Request::Destroy => {
|
||||
// all is handled by destructor
|
||||
}
|
||||
zxdg_shell_v6::Request::CreatePositioner { id } => {
|
||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||
implement_positioner(id, &self.loop_token);
|
||||
}
|
||||
zxdg_shell_v6::Request::GetXdgSurface { id, surface } => {
|
||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||
let role_data = ShellSurfaceRole {
|
||||
pending_state: ShellSurfacePendingState::None,
|
||||
window_geometry: None,
|
||||
|
@ -84,7 +83,7 @@ where
|
|||
.is_err()
|
||||
{
|
||||
shell.post_error(
|
||||
zxdg_shell_v6::Error::Role as u32,
|
||||
xdg_wm_base::Error::Role as u32,
|
||||
"Surface already has a role.".into(),
|
||||
);
|
||||
return;
|
||||
|
@ -97,7 +96,7 @@ where
|
|||
xdg_surface
|
||||
.set_user_data(Box::into_raw(Box::new((surface.clone(), shell.clone()))) as *mut _);
|
||||
}
|
||||
zxdg_shell_v6::Request::Pong { serial } => {
|
||||
xdg_wm_base::Request::Pong { serial } => {
|
||||
let valid = {
|
||||
let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
|
||||
let mut guard = mutex.lock().unwrap();
|
||||
|
@ -126,7 +125,7 @@ where
|
|||
* xdg_positioner
|
||||
*/
|
||||
|
||||
fn destroy_positioner(positioner: &Resource<zxdg_positioner_v6::ZxdgPositionerV6>) {
|
||||
fn destroy_positioner(positioner: &Resource<xdg_positioner::XdgPositioner>) {
|
||||
let ptr = positioner.get_user_data();
|
||||
positioner.set_user_data(::std::ptr::null_mut());
|
||||
// drop the PositionerState
|
||||
|
@ -136,28 +135,28 @@ fn destroy_positioner(positioner: &Resource<zxdg_positioner_v6::ZxdgPositionerV6
|
|||
}
|
||||
|
||||
fn implement_positioner(
|
||||
positioner: NewResource<zxdg_positioner_v6::ZxdgPositionerV6>,
|
||||
positioner: NewResource<xdg_positioner::XdgPositioner>,
|
||||
token: &LoopToken,
|
||||
) -> Resource<zxdg_positioner_v6::ZxdgPositionerV6> {
|
||||
) -> Resource<xdg_positioner::XdgPositioner> {
|
||||
let positioner = positioner.implement_nonsend(
|
||||
|request, positioner: Resource<_>| {
|
||||
let ptr = positioner.get_user_data();
|
||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||
match request {
|
||||
zxdg_positioner_v6::Request::Destroy => {
|
||||
xdg_positioner::Request::Destroy => {
|
||||
// handled by destructor
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetSize { width, height } => {
|
||||
xdg_positioner::Request::SetSize { width, height } => {
|
||||
if width < 1 || height < 1 {
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
xdg_positioner::Error::InvalidInput as u32,
|
||||
"Invalid size for positioner.".into(),
|
||||
);
|
||||
} else {
|
||||
state.rect_size = (width, height);
|
||||
}
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetAnchorRect {
|
||||
xdg_positioner::Request::SetAnchorRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
|
@ -165,7 +164,7 @@ fn implement_positioner(
|
|||
} => {
|
||||
if width < 1 || height < 1 {
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
xdg_positioner::Error::InvalidInput as u32,
|
||||
"Invalid size for positioner's anchor rectangle.".into(),
|
||||
);
|
||||
} else {
|
||||
|
@ -177,40 +176,20 @@ fn implement_positioner(
|
|||
};
|
||||
}
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetAnchor { anchor } => {
|
||||
use self::zxdg_positioner_v6::Anchor;
|
||||
if anchor.contains(Anchor::Left | Anchor::Right)
|
||||
|| anchor.contains(Anchor::Top | Anchor::Bottom)
|
||||
{
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
"Invalid anchor for positioner.".into(),
|
||||
);
|
||||
} else {
|
||||
xdg_positioner::Request::SetAnchor { anchor } => {
|
||||
state.anchor_edges = anchor;
|
||||
}
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetGravity { gravity } => {
|
||||
use self::zxdg_positioner_v6::Gravity;
|
||||
if gravity.contains(Gravity::Left | Gravity::Right)
|
||||
|| gravity.contains(Gravity::Top | Gravity::Bottom)
|
||||
{
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
"Invalid gravity for positioner.".into(),
|
||||
);
|
||||
} else {
|
||||
xdg_positioner::Request::SetGravity { gravity } => {
|
||||
state.gravity = gravity;
|
||||
}
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetConstraintAdjustment {
|
||||
xdg_positioner::Request::SetConstraintAdjustment {
|
||||
constraint_adjustment,
|
||||
} => {
|
||||
let constraint_adjustment =
|
||||
zxdg_positioner_v6::ConstraintAdjustment::from_bits_truncate(constraint_adjustment);
|
||||
xdg_positioner::ConstraintAdjustment::from_bits_truncate(constraint_adjustment);
|
||||
state.constraint_adjustment = constraint_adjustment;
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetOffset { x, y } => {
|
||||
xdg_positioner::Request::SetOffset { x, y } => {
|
||||
state.offset = (x, y);
|
||||
}
|
||||
}
|
||||
|
@ -218,19 +197,7 @@ fn implement_positioner(
|
|||
Some(|positioner, _| destroy_positioner(&positioner)),
|
||||
token,
|
||||
);
|
||||
let data = PositionerState {
|
||||
rect_size: (0, 0),
|
||||
anchor_rect: Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
anchor_edges: zxdg_positioner_v6::Anchor::empty(),
|
||||
gravity: zxdg_positioner_v6::Gravity::empty(),
|
||||
constraint_adjustment: zxdg_positioner_v6::ConstraintAdjustment::empty(),
|
||||
offset: (0, 0),
|
||||
};
|
||||
let data = PositionerState::new();
|
||||
positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _);
|
||||
positioner
|
||||
}
|
||||
|
@ -241,12 +208,12 @@ fn implement_positioner(
|
|||
|
||||
type XdgSurfaceUserData = (
|
||||
Resource<wl_surface::WlSurface>,
|
||||
Resource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
Resource<xdg_wm_base::XdgWmBase>,
|
||||
);
|
||||
|
||||
fn destroy_surface<U, R, SD>(
|
||||
surface: Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_surface_v6::ZxdgSurfaceV6>, zxdg_surface_v6::Request>>,
|
||||
surface: Resource<xdg_surface::XdgSurface>,
|
||||
implem: Box<Implementation<Resource<xdg_surface::XdgSurface>, xdg_surface::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
|
@ -264,7 +231,7 @@ fn destroy_surface<U, R, SD>(
|
|||
// all is good
|
||||
} else {
|
||||
data.1.post_error(
|
||||
zxdg_shell_v6::Error::Role as u32,
|
||||
xdg_wm_base::Error::Role as u32,
|
||||
"xdg_surface was destroyed before its role object".into(),
|
||||
);
|
||||
}
|
||||
|
@ -272,25 +239,21 @@ fn destroy_surface<U, R, SD>(
|
|||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_surface_v6::ZxdgSurfaceV6>, zxdg_surface_v6::Request>
|
||||
impl<U, R, SD> Implementation<Resource<xdg_surface::XdgSurface>, xdg_surface::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(
|
||||
&mut self,
|
||||
request: zxdg_surface_v6::Request,
|
||||
xdg_surface: Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
) {
|
||||
fn receive(&mut self, request: xdg_surface::Request, xdg_surface: Resource<xdg_surface::XdgSurface>) {
|
||||
let ptr = xdg_surface.get_user_data();
|
||||
let &(ref surface, ref shell) = unsafe { &*(ptr as *mut XdgSurfaceUserData) };
|
||||
match request {
|
||||
zxdg_surface_v6::Request::Destroy => {
|
||||
xdg_surface::Request::Destroy => {
|
||||
// all is handled by our destructor
|
||||
}
|
||||
zxdg_surface_v6::Request::GetToplevel { id } => {
|
||||
xdg_surface::Request::GetToplevel { id } => {
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
|
||||
|
@ -323,20 +286,23 @@ where
|
|||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::NewToplevel { surface: handle }, ());
|
||||
}
|
||||
zxdg_surface_v6::Request::GetPopup {
|
||||
xdg_surface::Request::GetPopup {
|
||||
id,
|
||||
parent,
|
||||
positioner,
|
||||
} => {
|
||||
let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) };
|
||||
|
||||
let parent_surface = parent.map(|parent| {
|
||||
let parent_ptr = parent.get_user_data();
|
||||
let &(ref parent_surface, _) = unsafe { &*(parent_ptr as *mut XdgSurfaceUserData) };
|
||||
parent_surface.clone()
|
||||
});
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
||||
parent: parent_surface.clone(),
|
||||
positioner: *positioner_data,
|
||||
parent: parent_surface,
|
||||
positioner: positioner_data.clone(),
|
||||
});
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
|
@ -361,7 +327,7 @@ where
|
|||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::NewPopup { surface: handle }, ());
|
||||
}
|
||||
zxdg_surface_v6::Request::SetWindowGeometry {
|
||||
xdg_surface::Request::SetWindowGeometry {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
|
@ -378,7 +344,7 @@ where
|
|||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
}
|
||||
zxdg_surface_v6::Request::AckConfigure { serial } => {
|
||||
xdg_surface::Request::AckConfigure { serial } => {
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
let mut found = false;
|
||||
|
@ -391,7 +357,7 @@ where
|
|||
if !found {
|
||||
// client responded to a non-existing configure
|
||||
shell.post_error(
|
||||
zxdg_shell_v6::Error::InvalidSurfaceState as u32,
|
||||
xdg_wm_base::Error::InvalidSurfaceState as u32,
|
||||
format!("Wrong configure serial: {}", serial),
|
||||
);
|
||||
}
|
||||
|
@ -409,14 +375,14 @@ where
|
|||
|
||||
pub type ShellSurfaceUserData = (
|
||||
Resource<wl_surface::WlSurface>,
|
||||
Resource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
Resource<xdg_wm_base::XdgWmBase>,
|
||||
Resource<xdg_surface::XdgSurface>,
|
||||
);
|
||||
|
||||
// Utility functions allowing to factor out a lot of the upcoming logic
|
||||
fn with_surface_toplevel_data<U, R, SD, F>(
|
||||
implem: &ShellImplementation<U, R, SD>,
|
||||
toplevel: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
toplevel: &Resource<xdg_toplevel::XdgToplevel>,
|
||||
f: F,
|
||||
) where
|
||||
U: 'static,
|
||||
|
@ -437,7 +403,7 @@ fn with_surface_toplevel_data<U, R, SD, F>(
|
|||
|
||||
pub fn send_toplevel_configure<U, R>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
||||
configure: ToplevelConfigure,
|
||||
) where
|
||||
U: 'static,
|
||||
|
@ -456,12 +422,12 @@ pub fn send_toplevel_configure<U, R>(
|
|||
unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) }
|
||||
};
|
||||
let serial = configure.serial;
|
||||
resource.send(zxdg_toplevel_v6::Event::Configure {
|
||||
resource.send(xdg_toplevel::Event::Configure {
|
||||
width,
|
||||
height,
|
||||
states,
|
||||
});
|
||||
shell_surface.send(zxdg_surface_v6::Event::Configure { serial });
|
||||
shell_surface.send(xdg_surface::Event::Configure { serial });
|
||||
// Add the configure as pending
|
||||
token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
||||
|
@ -470,35 +436,31 @@ pub fn send_toplevel_configure<U, R>(
|
|||
|
||||
fn make_toplevel_handle<U, R, SD>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
||||
) -> super::ToplevelSurface<U, R, SD> {
|
||||
let ptr = resource.get_user_data();
|
||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||
super::ToplevelSurface {
|
||||
wl_surface: wl_surface.clone(),
|
||||
shell_surface: resource.clone(),
|
||||
shell_surface: ToplevelKind::Xdg(resource.clone()),
|
||||
token: token,
|
||||
_shell_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_toplevel_v6::ZxdgToplevelV6>, zxdg_toplevel_v6::Request>
|
||||
impl<U, R, SD> Implementation<Resource<xdg_toplevel::XdgToplevel>, xdg_toplevel::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(
|
||||
&mut self,
|
||||
request: zxdg_toplevel_v6::Request,
|
||||
toplevel: Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
) {
|
||||
fn receive(&mut self, request: xdg_toplevel::Request, toplevel: Resource<xdg_toplevel::XdgToplevel>) {
|
||||
match request {
|
||||
zxdg_toplevel_v6::Request::Destroy => {
|
||||
xdg_toplevel::Request::Destroy => {
|
||||
// all it done by the destructor
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetParent { parent } => {
|
||||
xdg_toplevel::Request::SetParent { parent } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
||||
let parent_ptr = toplevel_surface_parent.get_user_data();
|
||||
|
@ -508,17 +470,17 @@ where
|
|||
})
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetTitle { title } => {
|
||||
xdg_toplevel::Request::SetTitle { title } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.title = title;
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetAppId { app_id } => {
|
||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.app_id = app_id;
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
|
@ -531,7 +493,7 @@ where
|
|||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::Move { seat, serial } => {
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
|
@ -543,13 +505,13 @@ where
|
|||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::Resize {
|
||||
xdg_toplevel::Request::Resize {
|
||||
seat,
|
||||
serial,
|
||||
edges,
|
||||
} => {
|
||||
let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges)
|
||||
.unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
|
||||
let edges =
|
||||
xdg_toplevel::ResizeEdge::from_raw(edges).unwrap_or(xdg_toplevel::ResizeEdge::None);
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
|
@ -562,27 +524,27 @@ where
|
|||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMaxSize { width, height } => {
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.max_size = (width, height);
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMinSize { width, height } => {
|
||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.max_size = (width, height);
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMaximized => {
|
||||
xdg_toplevel::Request::SetMaximized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::Maximize { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::UnsetMaximized => {
|
||||
xdg_toplevel::Request::UnsetMaximized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::UnMaximize { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetFullscreen { output } => {
|
||||
xdg_toplevel::Request::SetFullscreen { output } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
|
@ -593,12 +555,12 @@ where
|
|||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::UnsetFullscreen => {
|
||||
xdg_toplevel::Request::UnsetFullscreen => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::UnFullscreen { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMinimized => {
|
||||
xdg_toplevel::Request::SetMinimized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::Minimize { surface: handle }, ());
|
||||
|
@ -608,8 +570,8 @@ where
|
|||
}
|
||||
|
||||
fn destroy_toplevel<U, R, SD>(
|
||||
toplevel: Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_toplevel_v6::ZxdgToplevelV6>, zxdg_toplevel_v6::Request>>,
|
||||
toplevel: Resource<xdg_toplevel::XdgToplevel>,
|
||||
implem: Box<Implementation<Resource<xdg_toplevel::XdgToplevel>, xdg_toplevel::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
|
@ -647,7 +609,7 @@ fn destroy_toplevel<U, R, SD>(
|
|||
|
||||
pub(crate) fn send_popup_configure<U, R>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
resource: &Resource<xdg_popup::XdgPopup>,
|
||||
configure: PopupConfigure,
|
||||
) where
|
||||
U: 'static,
|
||||
|
@ -658,13 +620,13 @@ pub(crate) fn send_popup_configure<U, R>(
|
|||
let (x, y) = configure.position;
|
||||
let (width, height) = configure.size;
|
||||
let serial = configure.serial;
|
||||
resource.send(zxdg_popup_v6::Event::Configure {
|
||||
resource.send(xdg_popup::Event::Configure {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
shell_surface.send(zxdg_surface_v6::Event::Configure { serial });
|
||||
shell_surface.send(xdg_surface::Event::Configure { serial });
|
||||
// Add the configure as pending
|
||||
token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
||||
|
@ -673,31 +635,31 @@ pub(crate) fn send_popup_configure<U, R>(
|
|||
|
||||
fn make_popup_handle<U, R, SD>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
resource: &Resource<xdg_popup::XdgPopup>,
|
||||
) -> super::PopupSurface<U, R, SD> {
|
||||
let ptr = resource.get_user_data();
|
||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||
super::PopupSurface {
|
||||
wl_surface: wl_surface.clone(),
|
||||
shell_surface: resource.clone(),
|
||||
shell_surface: PopupKind::Xdg(resource.clone()),
|
||||
token: token,
|
||||
_shell_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_popup_v6::ZxdgPopupV6>, zxdg_popup_v6::Request>
|
||||
impl<U, R, SD> Implementation<Resource<xdg_popup::XdgPopup>, xdg_popup::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(&mut self, request: zxdg_popup_v6::Request, popup: Resource<zxdg_popup_v6::ZxdgPopupV6>) {
|
||||
fn receive(&mut self, request: xdg_popup::Request, popup: Resource<xdg_popup::XdgPopup>) {
|
||||
match request {
|
||||
zxdg_popup_v6::Request::Destroy => {
|
||||
xdg_popup::Request::Destroy => {
|
||||
// all is handled by our destructor
|
||||
}
|
||||
zxdg_popup_v6::Request::Grab { seat, serial } => {
|
||||
xdg_popup::Request::Grab { seat, serial } => {
|
||||
let handle = make_popup_handle(self.compositor_token, &popup);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
|
@ -714,8 +676,8 @@ where
|
|||
}
|
||||
|
||||
fn destroy_popup<U, R, SD>(
|
||||
popup: Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_popup_v6::ZxdgPopupV6>, zxdg_popup_v6::Request>>,
|
||||
popup: Resource<xdg_popup::XdgPopup>,
|
||||
implem: Box<Implementation<Resource<xdg_popup::XdgPopup>, xdg_popup::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
|
|
|
@ -0,0 +1,781 @@
|
|||
use super::{make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient,
|
||||
ShellClientData, ShellEvent, ShellImplementation, ShellSurfacePendingState, ShellSurfaceRole,
|
||||
ToplevelConfigure, ToplevelKind, ToplevelState};
|
||||
use std::sync::Mutex;
|
||||
use utils::Rectangle;
|
||||
use wayland::compositor::CompositorToken;
|
||||
use wayland::compositor::roles::*;
|
||||
use wayland_protocols::xdg_shell::server::{xdg_positioner, xdg_toplevel};
|
||||
use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6,
|
||||
zxdg_surface_v6, zxdg_toplevel_v6};
|
||||
use wayland_server::{LoopToken, NewResource, Resource};
|
||||
use wayland_server::commons::{downcast_impl, Implementation};
|
||||
use wayland_server::protocol::wl_surface;
|
||||
|
||||
pub(crate) fn implement_shell<U, R, SD>(
|
||||
shell: NewResource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
implem: &ShellImplementation<U, R, SD>,
|
||||
) -> Resource<zxdg_shell_v6::ZxdgShellV6>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: Default + 'static,
|
||||
{
|
||||
let shell = shell.implement_nonsend(
|
||||
implem.clone(),
|
||||
Some(|shell, _| destroy_shell::<SD>(&shell)),
|
||||
&implem.loop_token,
|
||||
);
|
||||
shell.set_user_data(Box::into_raw(Box::new(Mutex::new(make_shell_client_data::<SD>()))) as *mut _);
|
||||
let mut user_impl = implem.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::NewClient {
|
||||
client: make_shell_client(&shell),
|
||||
},
|
||||
(),
|
||||
);
|
||||
shell
|
||||
}
|
||||
|
||||
/*
|
||||
* xdg_shell
|
||||
*/
|
||||
|
||||
pub(crate) type ShellUserData<SD> = Mutex<ShellClientData<SD>>;
|
||||
|
||||
fn destroy_shell<SD>(shell: &Resource<zxdg_shell_v6::ZxdgShellV6>) {
|
||||
let ptr = shell.get_user_data();
|
||||
shell.set_user_data(::std::ptr::null_mut());
|
||||
let data = unsafe { Box::from_raw(ptr as *mut ShellUserData<SD>) };
|
||||
// explicit call to drop to not forget what we're doing here
|
||||
::std::mem::drop(data);
|
||||
}
|
||||
|
||||
pub(crate) fn make_shell_client<SD>(resource: &Resource<zxdg_shell_v6::ZxdgShellV6>) -> ShellClient<SD> {
|
||||
ShellClient {
|
||||
kind: super::ShellClientKind::ZxdgV6(resource.clone()),
|
||||
_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_shell_v6::ZxdgShellV6>, zxdg_shell_v6::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(&mut self, request: zxdg_shell_v6::Request, shell: Resource<zxdg_shell_v6::ZxdgShellV6>) {
|
||||
match request {
|
||||
zxdg_shell_v6::Request::Destroy => {
|
||||
// all is handled by destructor
|
||||
}
|
||||
zxdg_shell_v6::Request::CreatePositioner { id } => {
|
||||
implement_positioner(id, &self.loop_token);
|
||||
}
|
||||
zxdg_shell_v6::Request::GetXdgSurface { id, surface } => {
|
||||
let role_data = ShellSurfaceRole {
|
||||
pending_state: ShellSurfacePendingState::None,
|
||||
window_geometry: None,
|
||||
pending_configures: Vec::new(),
|
||||
configured: false,
|
||||
};
|
||||
if self.compositor_token
|
||||
.give_role_with(&surface, role_data)
|
||||
.is_err()
|
||||
{
|
||||
shell.post_error(
|
||||
zxdg_shell_v6::Error::Role as u32,
|
||||
"Surface already has a role.".into(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
let xdg_surface = id.implement_nonsend(
|
||||
self.clone(),
|
||||
Some(destroy_surface::<U, R, SD>),
|
||||
&self.loop_token,
|
||||
);
|
||||
xdg_surface
|
||||
.set_user_data(Box::into_raw(Box::new((surface.clone(), shell.clone()))) as *mut _);
|
||||
}
|
||||
zxdg_shell_v6::Request::Pong { serial } => {
|
||||
let valid = {
|
||||
let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
|
||||
let mut guard = mutex.lock().unwrap();
|
||||
if guard.pending_ping == serial {
|
||||
guard.pending_ping = 0;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if valid {
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::ClientPong {
|
||||
client: make_shell_client(&shell),
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xdg_positioner
|
||||
*/
|
||||
|
||||
fn destroy_positioner(positioner: &Resource<zxdg_positioner_v6::ZxdgPositionerV6>) {
|
||||
let ptr = positioner.get_user_data();
|
||||
positioner.set_user_data(::std::ptr::null_mut());
|
||||
// drop the PositionerState
|
||||
let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) };
|
||||
// explicit call to drop to not forget what we're doing here
|
||||
::std::mem::drop(surface);
|
||||
}
|
||||
|
||||
fn implement_positioner(
|
||||
positioner: NewResource<zxdg_positioner_v6::ZxdgPositionerV6>,
|
||||
token: &LoopToken,
|
||||
) -> Resource<zxdg_positioner_v6::ZxdgPositionerV6> {
|
||||
let positioner = positioner.implement_nonsend(
|
||||
|request, positioner: Resource<_>| {
|
||||
let ptr = positioner.get_user_data();
|
||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||
match request {
|
||||
zxdg_positioner_v6::Request::Destroy => {
|
||||
// handled by destructor
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetSize { width, height } => {
|
||||
if width < 1 || height < 1 {
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
"Invalid size for positioner.".into(),
|
||||
);
|
||||
} else {
|
||||
state.rect_size = (width, height);
|
||||
}
|
||||
}
|
||||
zxdg_positioner_v6::Request::SetAnchorRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
if width < 1 || height < 1 {
|
||||
positioner.post_error(
|
||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||
"Invalid size for positioner's anchor rectangle.".into(),
|
||||
);
|
||||
} else {
|
||||
state.anchor_rect = Rectangle {
|
||||
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.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.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);
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(|positioner, _| destroy_positioner(&positioner)),
|
||||
token,
|
||||
);
|
||||
let data = PositionerState::new();
|
||||
positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _);
|
||||
positioner
|
||||
}
|
||||
|
||||
/*
|
||||
* xdg_surface
|
||||
*/
|
||||
|
||||
type XdgSurfaceUserData = (
|
||||
Resource<wl_surface::WlSurface>,
|
||||
Resource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
);
|
||||
|
||||
fn destroy_surface<U, R, SD>(
|
||||
surface: Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_surface_v6::ZxdgSurfaceV6>, zxdg_surface_v6::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
||||
let ptr = surface.get_user_data();
|
||||
surface.set_user_data(::std::ptr::null_mut());
|
||||
// take back ownership of the userdata
|
||||
let data = unsafe { Box::from_raw(ptr as *mut XdgSurfaceUserData) };
|
||||
implem
|
||||
.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(&data.0, |rdata| {
|
||||
if let ShellSurfacePendingState::None = rdata.pending_state {
|
||||
// all is good
|
||||
} else {
|
||||
data.1.post_error(
|
||||
zxdg_shell_v6::Error::Role as u32,
|
||||
"xdg_surface was destroyed before its role object".into(),
|
||||
);
|
||||
}
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_surface_v6::ZxdgSurfaceV6>, zxdg_surface_v6::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(
|
||||
&mut self,
|
||||
request: zxdg_surface_v6::Request,
|
||||
xdg_surface: Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
) {
|
||||
let ptr = xdg_surface.get_user_data();
|
||||
let &(ref surface, ref shell) = unsafe { &*(ptr as *mut XdgSurfaceUserData) };
|
||||
match request {
|
||||
zxdg_surface_v6::Request::Destroy => {
|
||||
// all is handled by our destructor
|
||||
}
|
||||
zxdg_surface_v6::Request::GetToplevel { id } => {
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
|
||||
parent: None,
|
||||
title: String::new(),
|
||||
app_id: String::new(),
|
||||
min_size: (0, 0),
|
||||
max_size: (0, 0),
|
||||
});
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
let toplevel = id.implement_nonsend(
|
||||
self.clone(),
|
||||
Some(destroy_toplevel::<U, R, SD>),
|
||||
&self.loop_token,
|
||||
);
|
||||
toplevel.set_user_data(Box::into_raw(Box::new((
|
||||
surface.clone(),
|
||||
shell.clone(),
|
||||
xdg_surface.clone(),
|
||||
))) as *mut _);
|
||||
|
||||
self.shell_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.known_toplevels
|
||||
.push(make_toplevel_handle(self.compositor_token, &toplevel));
|
||||
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::NewToplevel { surface: handle }, ());
|
||||
}
|
||||
zxdg_surface_v6::Request::GetPopup {
|
||||
id,
|
||||
parent,
|
||||
positioner,
|
||||
} => {
|
||||
let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) };
|
||||
|
||||
let parent_ptr = parent.get_user_data();
|
||||
let &(ref parent_surface, _) = unsafe { &*(parent_ptr as *mut XdgSurfaceUserData) };
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
||||
parent: Some(parent_surface.clone()),
|
||||
positioner: positioner_data.clone(),
|
||||
});
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
let popup = id.implement_nonsend(
|
||||
self.clone(),
|
||||
Some(destroy_popup::<U, R, SD>),
|
||||
&self.loop_token,
|
||||
);
|
||||
popup.set_user_data(Box::into_raw(Box::new((
|
||||
surface.clone(),
|
||||
shell.clone(),
|
||||
xdg_surface.clone(),
|
||||
))) as *mut _);
|
||||
|
||||
self.shell_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.known_popups
|
||||
.push(make_popup_handle(self.compositor_token, &popup));
|
||||
|
||||
let handle = make_popup_handle(self.compositor_token, &popup);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::NewPopup { surface: handle }, ());
|
||||
}
|
||||
zxdg_surface_v6::Request::SetWindowGeometry {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
data.window_geometry = Some(Rectangle {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
}
|
||||
zxdg_surface_v6::Request::AckConfigure { serial } => {
|
||||
self.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||
let mut found = false;
|
||||
data.pending_configures.retain(|&s| {
|
||||
if s == serial {
|
||||
found = true;
|
||||
}
|
||||
s > serial
|
||||
});
|
||||
if !found {
|
||||
// client responded to a non-existing configure
|
||||
shell.post_error(
|
||||
zxdg_shell_v6::Error::InvalidSurfaceState as u32,
|
||||
format!("Wrong configure serial: {}", serial),
|
||||
);
|
||||
}
|
||||
data.configured = true;
|
||||
})
|
||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xdg_toplevel
|
||||
*/
|
||||
|
||||
pub type ShellSurfaceUserData = (
|
||||
Resource<wl_surface::WlSurface>,
|
||||
Resource<zxdg_shell_v6::ZxdgShellV6>,
|
||||
Resource<zxdg_surface_v6::ZxdgSurfaceV6>,
|
||||
);
|
||||
|
||||
// Utility functions allowing to factor out a lot of the upcoming logic
|
||||
fn with_surface_toplevel_data<U, R, SD, F>(
|
||||
implem: &ShellImplementation<U, R, SD>,
|
||||
toplevel: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
f: F,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
F: FnOnce(&mut ToplevelState),
|
||||
{
|
||||
let ptr = toplevel.get_user_data();
|
||||
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||
implem
|
||||
.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| match data.pending_state {
|
||||
ShellSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||
}
|
||||
|
||||
pub fn send_toplevel_configure<U, R>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
configure: ToplevelConfigure,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
{
|
||||
let &(ref surface, _, ref shell_surface) =
|
||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
||||
let (width, height) = configure.size.unwrap_or((0, 0));
|
||||
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
|
||||
let states = {
|
||||
let mut states = configure.states;
|
||||
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;
|
||||
resource.send(zxdg_toplevel_v6::Event::Configure {
|
||||
width,
|
||||
height,
|
||||
states,
|
||||
});
|
||||
shell_surface.send(zxdg_surface_v6::Event::Configure { serial });
|
||||
// Add the configure as pending
|
||||
token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||
}
|
||||
|
||||
fn make_toplevel_handle<U, R, SD>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
) -> super::ToplevelSurface<U, R, SD> {
|
||||
let ptr = resource.get_user_data();
|
||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||
super::ToplevelSurface {
|
||||
wl_surface: wl_surface.clone(),
|
||||
shell_surface: ToplevelKind::ZxdgV6(resource.clone()),
|
||||
token: token,
|
||||
_shell_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_toplevel_v6::ZxdgToplevelV6>, zxdg_toplevel_v6::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(
|
||||
&mut self,
|
||||
request: zxdg_toplevel_v6::Request,
|
||||
toplevel: Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
) {
|
||||
match request {
|
||||
zxdg_toplevel_v6::Request::Destroy => {
|
||||
// all it done by the destructor
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetParent { parent } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
||||
let parent_ptr = toplevel_surface_parent.get_user_data();
|
||||
let &(ref parent_surface, _, _) =
|
||||
unsafe { &*(parent_ptr as *mut ShellSurfaceUserData) };
|
||||
parent_surface.clone()
|
||||
})
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetTitle { title } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.title = title;
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetAppId { app_id } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.app_id = app_id;
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::ShowWindowMenu {
|
||||
surface: handle,
|
||||
seat,
|
||||
serial,
|
||||
location: (x, y),
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::Move { seat, serial } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::Move {
|
||||
surface: handle,
|
||||
seat,
|
||||
serial,
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
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(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::Resize {
|
||||
surface: handle,
|
||||
seat,
|
||||
serial,
|
||||
edges: zxdg_edges_to_xdg(edges),
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMaxSize { width, height } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.max_size = (width, height);
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMinSize { width, height } => {
|
||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
||||
toplevel_data.max_size = (width, height);
|
||||
});
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMaximized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::Maximize { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::UnsetMaximized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::UnMaximize { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetFullscreen { output } => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::Fullscreen {
|
||||
surface: handle,
|
||||
output,
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
zxdg_toplevel_v6::Request::UnsetFullscreen => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::UnFullscreen { surface: handle }, ());
|
||||
}
|
||||
zxdg_toplevel_v6::Request::SetMinimized => {
|
||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(ShellEvent::Minimize { surface: handle }, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy_toplevel<U, R, SD>(
|
||||
toplevel: Resource<zxdg_toplevel_v6::ZxdgToplevelV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_toplevel_v6::ZxdgToplevelV6>, zxdg_toplevel_v6::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
||||
let ptr = toplevel.get_user_data();
|
||||
toplevel.set_user_data(::std::ptr::null_mut());
|
||||
// take back ownership of the userdata
|
||||
let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
||||
implem
|
||||
.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(&data.0, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::None;
|
||||
data.configured = false;
|
||||
})
|
||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||
implem
|
||||
.shell_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.known_toplevels
|
||||
.retain(|other| {
|
||||
other
|
||||
.get_surface()
|
||||
.map(|s| !s.equals(&data.0))
|
||||
.unwrap_or(false)
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* xdg_popup
|
||||
*/
|
||||
|
||||
pub(crate) fn send_popup_configure<U, R>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
configure: PopupConfigure,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
{
|
||||
let &(ref surface, _, ref shell_surface) =
|
||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
||||
let (x, y) = configure.position;
|
||||
let (width, height) = configure.size;
|
||||
let serial = configure.serial;
|
||||
resource.send(zxdg_popup_v6::Event::Configure {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
shell_surface.send(zxdg_surface_v6::Event::Configure { serial });
|
||||
// Add the configure as pending
|
||||
token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||
}
|
||||
|
||||
fn make_popup_handle<U, R, SD>(
|
||||
token: CompositorToken<U, R>,
|
||||
resource: &Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
) -> super::PopupSurface<U, R, SD> {
|
||||
let ptr = resource.get_user_data();
|
||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||
super::PopupSurface {
|
||||
wl_surface: wl_surface.clone(),
|
||||
shell_surface: PopupKind::ZxdgV6(resource.clone()),
|
||||
token: token,
|
||||
_shell_data: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, R, SD> Implementation<Resource<zxdg_popup_v6::ZxdgPopupV6>, zxdg_popup_v6::Request>
|
||||
for ShellImplementation<U, R, SD>
|
||||
where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
fn receive(&mut self, request: zxdg_popup_v6::Request, popup: Resource<zxdg_popup_v6::ZxdgPopupV6>) {
|
||||
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(self.compositor_token, &popup);
|
||||
let mut user_impl = self.user_impl.borrow_mut();
|
||||
user_impl.receive(
|
||||
ShellEvent::Grab {
|
||||
surface: handle,
|
||||
seat,
|
||||
serial,
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy_popup<U, R, SD>(
|
||||
popup: Resource<zxdg_popup_v6::ZxdgPopupV6>,
|
||||
implem: Box<Implementation<Resource<zxdg_popup_v6::ZxdgPopupV6>, zxdg_popup_v6::Request>>,
|
||||
) where
|
||||
U: 'static,
|
||||
R: Role<ShellSurfaceRole> + 'static,
|
||||
SD: 'static,
|
||||
{
|
||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
||||
let ptr = popup.get_user_data();
|
||||
popup.set_user_data(::std::ptr::null_mut());
|
||||
// take back ownership of the userdata
|
||||
let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
||||
implem
|
||||
.compositor_token
|
||||
.with_role_data::<ShellSurfaceRole, _, _>(&data.0, |data| {
|
||||
data.pending_state = ShellSurfacePendingState::None;
|
||||
data.configured = false;
|
||||
})
|
||||
.expect("xdg_popup exists but surface has not shell_surface role?!");
|
||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||
implem
|
||||
.shell_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.known_popups
|
||||
.retain(|other| {
|
||||
other
|
||||
.get_surface()
|
||||
.map(|s| !s.equals(&data.0))
|
||||
.unwrap_or(false)
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue