shell: types documentation

This commit is contained in:
Victor Berger 2017-09-06 14:41:59 +02:00
parent 30c0628959
commit 6dec2cb5da
1 changed files with 237 additions and 11 deletions

View File

@ -11,49 +11,109 @@ mod global;
mod wl_handlers; mod wl_handlers;
mod xdg_handlers; mod xdg_handlers;
/// Metadata associated with the `shell_surface` role
pub struct ShellSurfaceRole { pub struct ShellSurfaceRole {
/// Pending state as requested by the client
///
/// The data in this field are double-buffered, you should
/// apply them on a surface commit.
pub pending_state: ShellSurfacePendingState, pub pending_state: ShellSurfacePendingState,
/// Geometry of the surface
///
/// Defines, in surface relative coordinates, what should
/// be considered as "the surface itself", regarding focus,
/// window alignment, etc...
///
/// By default, you should consider the full contents of the
/// buffers of this surface and its subsurfaces.
pub window_geometry: Option<Rectangle>, pub window_geometry: Option<Rectangle>,
/// List of non-acked configures pending
///
/// Whenever a configure is acked by the client, all configure
/// older than it are discarded as well. As such, this vec contains
/// the serials of all the configure send to this surface that are
/// newer than the last ack received.
pub pending_configures: Vec<u32>, pub pending_configures: Vec<u32>,
/// Has this surface acked at least one configure?
///
/// xdg_shell defines it as illegal to commit on a surface that has
/// not yet acked a configure.
pub configured: bool, pub configured: bool,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
/// The state of a positioner, as set by the client
pub struct PositionerState { pub struct PositionerState {
/// Size of the rectangle that needs to be positioned
pub rect_size: (i32, i32), pub rect_size: (i32, i32),
/// Anchor rectangle in the parent surface coordinates
/// relative to which the surface must be positioned
pub anchor_rect: Rectangle, pub anchor_rect: Rectangle,
/// Edges defining the anchor point
pub anchor_edges: xdg_positioner::Anchor, pub anchor_edges: xdg_positioner::Anchor,
/// Gravity direction for positioning the child surface
/// relative to its anchor point
pub gravity: xdg_positioner::Gravity, pub gravity: xdg_positioner::Gravity,
/// Adjustments to do if previous criterias constraint the
/// surface
pub constraint_adjustment: xdg_positioner::ConstraintAdjustment, pub constraint_adjustment: xdg_positioner::ConstraintAdjustment,
/// Offset placement relative to the anchor point
pub offset: (i32, i32), pub offset: (i32, i32),
} }
/// Contents of the pending state of a shell surface, depending on its role
pub enum ShellSurfacePendingState { pub enum ShellSurfacePendingState {
/// This a regular, toplevel surface /// This a regular, toplevel surface
/// ///
/// This corresponds to either the `xdg_toplevel` role from the /// This corresponds to either the `xdg_toplevel` role from the
/// `xdg_shell` protocol, or the result of `set_toplevel` using the /// `xdg_shell` protocol, or the result of `set_toplevel` using the
/// `wl_shell` protocol. /// `wl_shell` protocol.
///
/// This is what you'll generaly interpret as "a window".
Toplevel(ToplevelState), Toplevel(ToplevelState),
/// This is a popup surface /// This is a popup surface
/// ///
/// This corresponds to either the `xdg_popup` role from the /// This corresponds to either the `xdg_popup` role from the
/// `xdg_shell` protocol, or the result of `set_popup` using the /// `xdg_shell` protocol, or the result of `set_popup` using the
/// `wl_shell` protocole /// `wl_shell` protocol.
///
/// This are mostly for small tooltips and similar short-lived
/// surfaces.
Popup(PopupState), Popup(PopupState),
/// This surface was not yet assigned a kind /// This surface was not yet assigned a kind
None, None,
} }
/// State of a regular toplevel surface
pub struct ToplevelState { pub struct ToplevelState {
/// Parent of this surface
///
/// If this surface has a parent, it should be hidden
/// or displayed, brought up at the same time as it.
pub parent: Option<wl_surface::WlSurface>, pub parent: Option<wl_surface::WlSurface>,
/// Title of this shell surface
pub title: String, pub title: String,
/// App id for this shell surface
///
/// This identifier can be used to group surface together
/// as being several instance of the same app. This can
/// also be used as the D-Bus name for the app.
pub app_id: String, pub app_id: String,
/// Minimum size requested for this surface
///
/// A value of 0 on an axis means this axis is not constrained
pub min_size: (i32, i32), pub min_size: (i32, i32),
/// Maximum size requested for this surface
///
/// A value of 0 on an axis means this axis is not constrained
pub max_size: (i32, i32), pub max_size: (i32, i32),
} }
impl ToplevelState { impl ToplevelState {
/// Clone this ToplevelState
///
/// If the parent surface refers to a surface that no longer
/// exists, it is replaced by `None` in the process.
pub fn clone(&self) -> ToplevelState { pub fn clone(&self) -> ToplevelState {
ToplevelState { ToplevelState {
parent: self.parent.as_ref().and_then(|p| p.clone()), parent: self.parent.as_ref().and_then(|p| p.clone()),
@ -65,12 +125,21 @@ impl ToplevelState {
} }
} }
/// The pending state of a popup surface
pub struct PopupState { pub struct PopupState {
/// Parent of this popup surface
pub parent: wl_surface::WlSurface, pub parent: wl_surface::WlSurface,
/// The positioner specifying how this tooltip should
/// be placed relative to its parent.
pub positioner: PositionerState, pub positioner: PositionerState,
} }
impl PopupState { impl PopupState {
/// Clone this PopupState
///
/// If the parent surface refers to a surface that no longer
/// exists, this will return `None`, as the popup can no
/// longer be meaningfully displayed.
pub fn clone(&self) -> Option<PopupState> { pub fn clone(&self) -> Option<PopupState> {
if let Some(p) = self.parent.clone() { if let Some(p) = self.parent.clone() {
Some(PopupState { Some(PopupState {
@ -91,6 +160,9 @@ impl Default for ShellSurfacePendingState {
} }
} }
/// The handler for the shell globals
///
/// See module-level documentation for its use.
pub struct ShellHandler<U, R, H, SH, SD> { pub struct ShellHandler<U, R, H, SH, SD> {
my_id: usize, my_id: usize,
log: ::slog::Logger, log: ::slog::Logger,
@ -167,12 +239,23 @@ struct ShellClientData<SD> {
data: SD, data: SD,
} }
/// A shell client
///
/// This represents an instanciation of a shell
/// global (be it `wl_shell` or `xdg_shell`).
///
/// Most of the time, you can consider that a
/// wayland client will be a single shell client.
///
/// You can use this handle to access a storage for any
/// client-specific data you wish to associate with it.
pub struct ShellClient<SD> { pub struct ShellClient<SD> {
kind: ShellClientKind, kind: ShellClientKind,
_data: ::std::marker::PhantomData<*mut SD>, _data: ::std::marker::PhantomData<*mut SD>,
} }
impl<SD> ShellClient<SD> { impl<SD> ShellClient<SD> {
/// Is the shell client represented by this handle still connected?
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
match self.kind { match self.kind {
ShellClientKind::Wl(ref s) => s.status() == Liveness::Alive, ShellClientKind::Wl(ref s) => s.status() == Liveness::Alive,
@ -180,6 +263,8 @@ impl<SD> ShellClient<SD> {
} }
} }
/// Checks if this handle and the other one actually refer to the
/// same shell client
pub fn equals(&self, other: &Self) -> bool { pub fn equals(&self, other: &Self) -> bool {
match (&self.kind, &other.kind) { match (&self.kind, &other.kind) {
(&ShellClientKind::Wl(ref s1), &ShellClientKind::Wl(ref s2)) => s1.equals(s2), (&ShellClientKind::Wl(ref s1), &ShellClientKind::Wl(ref s2)) => s1.equals(s2),
@ -230,6 +315,7 @@ impl<SD> ShellClient<SD> {
Ok(()) Ok(())
} }
/// Access the user data associated with this shell client
pub fn with_data<F, T>(&self, f: F) -> Result<T, ()> pub fn with_data<F, T>(&self, f: F) -> Result<T, ()>
where where
F: FnOnce(&mut SD) -> T, F: FnOnce(&mut SD) -> T,
@ -259,6 +345,10 @@ enum SurfaceKind {
XdgPopup(zxdg_popup_v6::ZxdgPopupV6), XdgPopup(zxdg_popup_v6::ZxdgPopupV6),
} }
/// A handle to a toplevel surface
///
/// This is an unified abstraction over the toplevel surfaces
/// of both `wl_shell` and `xdg_shell`.
pub struct ToplevelSurface<U, R, H, SD> { pub struct ToplevelSurface<U, R, H, SD> {
wl_surface: wl_surface::WlSurface, wl_surface: wl_surface::WlSurface,
shell_surface: SurfaceKind, shell_surface: SurfaceKind,
@ -272,6 +362,7 @@ where
R: Role<ShellSurfaceRole> + Send + 'static, R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static, H: CompositorHandler<U, R> + Send + 'static,
{ {
/// Is the toplevel surface refered by this handle still alive?
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
let shell_surface_alive = match self.shell_surface { let shell_surface_alive = match self.shell_surface {
SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive,
@ -281,32 +372,40 @@ where
shell_surface_alive && self.wl_surface.status() == Liveness::Alive shell_surface_alive && self.wl_surface.status() == Liveness::Alive
} }
/// Do this handle and the other one actually refer to the same toplevel surface?
pub fn equals(&self, other: &Self) -> bool { pub fn equals(&self, other: &Self) -> bool {
self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface)
} }
pub fn client(&self) -> ShellClient<SD> { /// Retrieve the shell client owning this toplevel surface
///
/// Returns `None` if the surface does actually no longer exist.
pub fn client(&self) -> Option<ShellClient<SD>> {
if !self.alive() { return None }
match self.shell_surface { match self.shell_surface {
SurfaceKind::Wl(ref s) => { SurfaceKind::Wl(ref s) => {
let &(_, ref shell) = let &(_, ref shell) =
unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) };
ShellClient { Some(ShellClient {
kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }),
_data: ::std::marker::PhantomData, _data: ::std::marker::PhantomData,
} })
} }
SurfaceKind::XdgToplevel(ref s) => { SurfaceKind::XdgToplevel(ref s) => {
let &(_, ref shell, _) = let &(_, ref shell, _) =
unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
ShellClient { Some(ShellClient {
kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }),
_data: ::std::marker::PhantomData, _data: ::std::marker::PhantomData,
} })
} }
SurfaceKind::XdgPopup(_) => unreachable!(), SurfaceKind::XdgPopup(_) => unreachable!(),
} }
} }
/// Send a configure event to this toplevel surface to suggest it a new configuration
///
/// The serial of this configure will be tracked waiting for the client to ACK it.
pub fn send_configure(&self, cfg: ToplevelConfigure) -> EventResult<()> { pub fn send_configure(&self, cfg: ToplevelConfigure) -> EventResult<()> {
if !self.alive() { if !self.alive() {
return EventResult::Destroyed; return EventResult::Destroyed;
@ -354,6 +453,9 @@ where
configured configured
} }
/// Access the underlying `wl_surface` of this toplevel surface
///
/// Returns `None` if the toplevel surface actually no longer exists.
pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
if self.alive() { if self.alive() {
Some(&self.wl_surface) Some(&self.wl_surface)
@ -362,6 +464,9 @@ where
} }
} }
/// Retrieve a copy of the pending state of this toplevel surface
///
/// Returns `None` of the toplevel surface actually no longer exists.
pub fn get_pending_state(&self) -> Option<ToplevelState> { pub fn get_pending_state(&self) -> Option<ToplevelState> {
if !self.alive() { if !self.alive() {
return None; return None;
@ -376,6 +481,10 @@ where
} }
} }
/// 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, H, SD> { pub struct PopupSurface<U, R, H, SD> {
wl_surface: wl_surface::WlSurface, wl_surface: wl_surface::WlSurface,
shell_surface: SurfaceKind, shell_surface: SurfaceKind,
@ -389,6 +498,7 @@ where
R: Role<ShellSurfaceRole> + Send + 'static, R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static, H: CompositorHandler<U, R> + Send + 'static,
{ {
/// Is the popup surface refered by this handle still alive?
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
let shell_surface_alive = match self.shell_surface { let shell_surface_alive = match self.shell_surface {
SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive,
@ -398,32 +508,40 @@ where
shell_surface_alive && self.wl_surface.status() == Liveness::Alive shell_surface_alive && self.wl_surface.status() == Liveness::Alive
} }
/// Do this handle and the other one actually refer to the same popup surface?
pub fn equals(&self, other: &Self) -> bool { pub fn equals(&self, other: &Self) -> bool {
self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface)
} }
pub fn client(&self) -> ShellClient<SD> { /// Retrieve the shell client owning this popup surface
///
/// Returns `None` if the surface does actually no longer exist.
pub fn client(&self) -> Option<ShellClient<SD>> {
if !self.alive() { return None }
match self.shell_surface { match self.shell_surface {
SurfaceKind::Wl(ref s) => { SurfaceKind::Wl(ref s) => {
let &(_, ref shell) = let &(_, ref shell) =
unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) };
ShellClient { Some(ShellClient {
kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }),
_data: ::std::marker::PhantomData, _data: ::std::marker::PhantomData,
} })
} }
SurfaceKind::XdgPopup(ref s) => { SurfaceKind::XdgPopup(ref s) => {
let &(_, ref shell, _) = let &(_, ref shell, _) =
unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
ShellClient { Some(ShellClient {
kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }),
_data: ::std::marker::PhantomData, _data: ::std::marker::PhantomData,
} })
} }
SurfaceKind::XdgToplevel(_) => unreachable!(), SurfaceKind::XdgToplevel(_) => unreachable!(),
} }
} }
/// Send a configure event to this toplevel surface to suggest it a new configuration
///
/// The serial of this configure will be tracked waiting for the client to ACK it.
pub fn send_configure(&self, cfg: PopupConfigure) -> EventResult<()> { pub fn send_configure(&self, cfg: PopupConfigure) -> EventResult<()> {
if !self.alive() { if !self.alive() {
return EventResult::Destroyed; return EventResult::Destroyed;
@ -436,6 +554,43 @@ where
EventResult::Sent(()) EventResult::Sent(())
} }
/// Make sure this surface was configured
///
/// Returns `true` if it was, if not, returns `false` and raise
/// a protocol error to the associated client. Also returns `false`
/// if the surface is already destroyed.
///
/// xdg_shell mandates that a client acks a configure before commiting
/// anything.
pub fn ensure_configured(&self) -> bool {
if !self.alive() {
return false;
}
let configured = self.token
.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 {
if let SurfaceKind::XdgPopup(ref s) = self.shell_surface {
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(),
);
} else {
unreachable!();
}
}
configured
}
/// Send a 'popup_done' event to the popup surface
///
/// 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) -> EventResult<()> { pub fn send_popup_done(&self) -> EventResult<()> {
if !self.alive() { if !self.alive() {
return EventResult::Destroyed; return EventResult::Destroyed;
@ -447,6 +602,9 @@ where
} }
} }
/// Access the underlying `wl_surface` of this toplevel surface
///
/// Returns `None` if the toplevel surface actually no longer exists.
pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
if self.alive() { if self.alive() {
Some(&self.wl_surface) Some(&self.wl_surface)
@ -455,6 +613,9 @@ where
} }
} }
/// Retrieve a copy of the pending state of this popup surface
///
/// Returns `None` of the popup surface actually no longer exists.
pub fn get_pending_state(&self) -> Option<PopupState> { pub fn get_pending_state(&self) -> Option<PopupState> {
if !self.alive() { if !self.alive() {
return None; return None;
@ -469,35 +630,100 @@ where
} }
} }
/// A configure message for toplevel surfaces
pub struct ToplevelConfigure { pub struct ToplevelConfigure {
/// A suggestion for a new size for the surface
pub size: Option<(i32, i32)>, pub size: Option<(i32, i32)>,
/// A notification of what are the current states of this surface
///
/// A surface can be any combination of these possible states
/// at the same time.
pub states: Vec<zxdg_toplevel_v6::State>, pub states: Vec<zxdg_toplevel_v6::State>,
/// A serial number to track ACK from the client
///
/// This should be an ever increasing number, as the ACK-ing
/// from a client for a serial will validate all pending lower
/// serials.
pub serial: u32, pub serial: u32,
} }
/// A configure message for popup surface
pub struct PopupConfigure { pub struct PopupConfigure {
/// The position chosen for this popup relative to
/// its parent
pub position: (i32, i32), pub position: (i32, i32),
/// A suggested size for the popup
pub size: (i32, i32), pub size: (i32, i32),
/// A serial number to track ACK from the client
///
/// This should be an ever increasing number, as the ACK-ing
/// from a client for a serial will validate all pending lower
/// serials.
pub serial: u32, pub serial: u32,
} }
/// A trait for the sub-handler provided to the ShellHandler
///
/// You need to implement this trait to handle events that the ShellHandler
/// cannot process for you directly.
///
/// Depending on what you want to do, you might implement some of these methods
/// as doing nothing.
pub trait Handler<U, R, H, SD> { pub trait Handler<U, R, H, SD> {
/// A new shell client was instanciated
fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>); fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>);
/// The pong for a pending ping of this shell client was received
///
/// The SHellHandler already checked for you that the serial matches the one
/// from the pending ping.
fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>); fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>);
/// A new toplevel surface was created
///
/// You need to return a `ToplevelConfigure` from this method, which will be sent
/// to the client to configure this surface
fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>) fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>)
-> ToplevelConfigure; -> ToplevelConfigure;
/// A new popup surface was created
///
/// You need to return a `PopupConfigure` from this method, which will be sent
/// to the client to configure this surface
fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>) fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>)
-> PopupConfigure; -> PopupConfigure;
/// The client requested the start of an interactive move for this surface
fn move_(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, fn move_(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>,
seat: &wl_seat::WlSeat, serial: u32); seat: &wl_seat::WlSeat, serial: u32);
/// The client requested the start of an interactive resize for this surface
///
/// The `edges` argument specifies which part of the window's border is being dragged.
fn resize(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, fn resize(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>,
seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge); seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge);
/// This popup requests a grab of the pointer
///
/// This means it requests to be sent a `popup_done` event when the pointer leaves
/// the grab area.
fn grab(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>, fn grab(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>,
seat: &wl_seat::WlSeat, serial: u32); seat: &wl_seat::WlSeat, serial: u32);
/// A toplevel surface requested its display state to be changed
///
/// Each field represents the request of the client for a specific property:
///
/// - `None`: no request is made to change this property
/// - `Some(true)`: this property should be enabled
/// - `Some(false)`: this property should be disabled
///
/// For fullscreen/maximization, the client can also optionnaly request a specific
/// output.
///
/// You are to answer with a `ToplevelConfigure` that will be sent to the client in
/// response.
fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>,
maximized: Option<bool>, minimized: Option<bool>, fullscreen: Option<bool>, maximized: Option<bool>, minimized: Option<bool>, fullscreen: Option<bool>,
output: Option<&wl_output::WlOutput>) output: Option<&wl_output::WlOutput>)
-> ToplevelConfigure; -> ToplevelConfigure;
/// The client requests the window menu to be displayed on this surface at this location
///
/// This menu belongs to the compositor. It is typically expected to contain options for
/// control of the window (maximize/minimize/close/move/etc...).
fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>,
seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32); seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32);
} }