shell: update to new wayland-server

This commit is contained in:
Victor Berger 2017-09-20 15:03:39 +02:00
parent 33f80a622f
commit 32e60de4f3
5 changed files with 1136 additions and 1072 deletions

View File

@ -35,7 +35,7 @@ pub mod backend;
pub mod compositor; pub mod compositor;
pub mod shm; pub mod shm;
pub mod keyboard; pub mod keyboard;
//pub mod shell; pub mod shell;
fn slog_or_stdlog<L>(logger: L) -> ::slog::Logger fn slog_or_stdlog<L>(logger: L) -> ::slog::Logger
where where

View File

@ -1,54 +0,0 @@
use super::{Handler as UserHandler, ShellClientData, ShellHandler, ShellSurfaceRole};
use super::wl_handlers::WlShellDestructor;
use super::xdg_handlers::XdgShellDestructor;
use compositor::Handler as CompositorHandler;
use compositor::roles::*;
use std::sync::Mutex;
use wayland_protocols::unstable::xdg_shell::server::zxdg_shell_v6;
use wayland_server::{Client, EventLoopHandle, GlobalHandler, Resource};
use wayland_server::protocol::{wl_shell, wl_shell_surface};
fn shell_client_data<SD: Default>() -> ShellClientData<SD> {
ShellClientData {
pending_ping: 0,
data: Default::default(),
}
}
impl<U, R, H, SH, SD> GlobalHandler<wl_shell::WlShell> for ShellHandler<U, R, H, SH, SD>
where
U: Send + 'static,
R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static,
SH: UserHandler<U, R, H, SD> + Send + 'static,
SD: Default + Send + 'static,
{
fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_shell::WlShell) {
debug!(self.log, "New wl_shell global binded.");
global.set_user_data(Box::into_raw(Box::new(Mutex::new((
shell_client_data::<SD>(),
Vec::<wl_shell_surface::WlShellSurface>::new(),
)))) as *mut _);
evlh.register_with_destructor::<_, Self, WlShellDestructor<SD>>(&global, self.my_id);
}
}
impl<U, R, H, SH, SD> GlobalHandler<zxdg_shell_v6::ZxdgShellV6> for ShellHandler<U, R, H, SH, SD>
where
U: Send + 'static,
R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static,
SH: UserHandler<U, R, H, SD> + Send + 'static,
SD: Default + Send + 'static,
{
fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: zxdg_shell_v6::ZxdgShellV6) {
debug!(self.log, "New xdg_shell global binded.");
global.set_user_data(
Box::into_raw(Box::new(Mutex::new(shell_client_data::<SD>()))) as *mut _,
);
evlh.register_with_destructor::<_, Self, XdgShellDestructor<SD>>(&global, self.my_id);
}
}

View File

@ -1,14 +1,13 @@
//! Utilities for handling shell surfaces, toplevel and popups //! Utilities for handling shell surfaces, toplevel and popups
//! //!
//! This module provides the `ShellHandler` type, which implements automatic handling of //! This module provides automatic handling of shell surfaces objects, by being registered
//! shell surfaces objects, by being registered as a global handler for `wl_shell` and //! as a global handler for `wl_shell` and `xdg_shell`.
//! `xdg_shell`.
//! //!
//! ## Why use this handler //! ## Why use this implementation
//! //!
//! This handler can track for you the various shell surfaces defined by the clients by //! This implementation can track for you the various shell surfaces defined by the
//! handling the `xdg_shell` protocol. It also includes a compatibility layer for the //! clients by handling the `xdg_shell` protocol. It also includes a compatibility
//! deprecated `wl_shell` global. //! layer for the deprecated `wl_shell` global.
//! //!
//! It allows you to easily access a list of all shell surfaces defined by your clients //! 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. //! access their associated metadata and underlying `wl_surface`s.
@ -21,28 +20,24 @@
//! //!
//! ### Initialization //! ### Initialization
//! //!
//! To initialize this handler, simply instanciate it and register it to the event loop //! To initialize this handler, simple use the `shell_init` function provided in this
//! as a global handler for xdg_shell and wl_shell. You will need to provide it the //! module. You will need to provide it the `CompositorToken` you retrieved from an
//! `CompositorToken` you retrieved from an instanciation of the `CompositorHandler` //! instanciation of the `CompositorHandler` provided by smithay.
//! provided by smithay.
//! //!
//! ``` //! ```no_run
//! # extern crate wayland_server; //! # extern crate wayland_server;
//! # #[macro_use] extern crate smithay; //! # #[macro_use] extern crate smithay;
//! # extern crate wayland_protocols; //! # extern crate wayland_protocols;
//! # //! #
//! use smithay::compositor::roles::*; //! use smithay::compositor::roles::*;
//! use smithay::compositor::CompositorToken; //! use smithay::compositor::CompositorToken;
//! use smithay::shell::{ShellHandler, Handler as ShellHandlerTrait, ShellSurfaceRole}; //! use smithay::shell::{shell_init, ShellSurfaceRole, ShellSurfaceUserImplementation};
//! use wayland_server::protocol::wl_shell::WlShell; //! use wayland_server::protocol::wl_shell::WlShell;
//! use wayland_protocols::unstable::xdg_shell::server::zxdg_shell_v6::ZxdgShellV6; //! use wayland_protocols::unstable::xdg_shell::server::zxdg_shell_v6::ZxdgShellV6;
//! use wayland_server::{EventLoop, EventLoopHandle}; //! use wayland_server::{EventLoop, EventLoopHandle};
//! # use smithay::shell::*;
//! # use wayland_server::protocol::{wl_seat, wl_output}; //! # use wayland_server::protocol::{wl_seat, wl_output};
//! # use wayland_protocols::unstable::xdg_shell::server::zxdg_toplevel_v6; //! # use wayland_protocols::unstable::xdg_shell::server::zxdg_toplevel_v6;
//! # #[derive(Default)] struct MySurfaceData; //! # #[derive(Default)] struct MySurfaceData;
//! # struct MyHandlerForCompositor;
//! # impl ::smithay::compositor::Handler<MySurfaceData, MyRoles> for MyHandlerForCompositor {}
//! //!
//! // define the roles type. You need to integrate the ShellSurface role: //! // define the roles type. You need to integrate the ShellSurface role:
//! define_roles!(MyRoles => //! define_roles!(MyRoles =>
@ -55,100 +50,70 @@
//! /* ... */ //! /* ... */
//! } //! }
//! //!
//! // define a sub-handler for the shell::Handler trait
//! struct MyHandlerForShell {
//! /* ... */
//! }
//!
//! # type MyToplevelSurface = ToplevelSurface<MySurfaceData, MyRoles, MyHandlerForCompositor,
//! # MyShellData>;
//! # type MyPopupSurface = PopupSurface<MySurfaceData, MyRoles, MyHandlerForCompositor,
//! # MyShellData>;
//!
//! impl ShellHandlerTrait<MySurfaceData, MyRoles, MyHandlerForCompositor, MyShellData> for MyHandlerForShell {
//! /* ... a few methods to implement, see shell::Handler
//! documentation for details ... */
//! # fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<MyShellData>) { unimplemented!() }
//! # fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<MyShellData>) { unimplemented!() }
//! # fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: MyToplevelSurface)
//! # -> ToplevelConfigure { unimplemented!() }
//! # fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: MyPopupSurface)
//! # -> PopupConfigure { unimplemented!() }
//! # fn move_(&mut self, evlh: &mut EventLoopHandle, surface: MyToplevelSurface,
//! # seat: &wl_seat::WlSeat, serial: u32) { unimplemented!() }
//! # fn resize(&mut self, evlh: &mut EventLoopHandle, surface: MyToplevelSurface,
//! # seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge) { unimplemented!() }
//! # fn grab(&mut self, evlh: &mut EventLoopHandle, surface: MyPopupSurface,
//! # seat: &wl_seat::WlSeat, serial: u32) { unimplemented!() }
//! # fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: MyToplevelSurface,
//! # maximized: Option<bool>, minimized: Option<bool>, fullscreen: Option<bool>,
//! # output: Option<&wl_output::WlOutput>)
//! # -> ToplevelConfigure { unimplemented!() }
//! # fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: MyToplevelSurface,
//! # seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32) { unimplemented!() }
//! }
//!
//! # type MyCompositorHandler = smithay::compositor::CompositorHandler<MySurfaceData, MyRoles,
//! # MyHandlerForCompositor>;
//! // A type alias for brevety. ShellHandler has many type parameters:
//! type MyShellHandler = ShellHandler<
//! MySurfaceData, // the surface data you defined for the CompositorHandler
//! MyRoles, // the roles type
//! MyHandlerForCompositor, // the sub-handler type you defined for the CompositorHandler
//! MyHandlerForShell, // the sub-handler type you defined for this ShellHandler
//! MyShellData // the client data you defined for this ShellHandler
//! >;
//! # fn main() { //! # fn main() {
//! # let (_display, mut event_loop) = wayland_server::create_display(); //! # let (_display, mut event_loop) = wayland_server::create_display();
//! # let compositor_hid = event_loop.add_handler_with_init( //! # let (compositor_token, _, _) = smithay::compositor::compositor_init::<(), MyRoles, _, _>(
//! # MyCompositorHandler::new(MyHandlerForCompositor{ /* ... */ }, None /* put a logger here */) //! # &mut event_loop,
//! # unimplemented!(),
//! # (),
//! # None
//! # ); //! # );
//! # let compositor_token = { //! // define your implementation for shell
//! # let state = event_loop.state(); //! let my_shell_implementation = ShellSurfaceUserImplementation {
//! # state.get_handler::<MyCompositorHandler>(compositor_hid).get_token() //! 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!() },
//! };
//! //!
//! let shell_hid = event_loop.add_handler_with_init( //! // define your implementation data
//! MyShellHandler::new( //! let my_shell_implementation_data = ();
//! MyHandlerForShell{ /* ... */ }, //!
//! compositor_token, // the composior token you retrieved from the CompositorHandler //! let (shell_state_token, _, _) = shell_init::<_, _, _, _, MyShellData, _>(
//! None /* put a logger here */ //! &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
//! None // put a logger if you want
//! ); //! );
//! //!
//! event_loop.register_global::<WlShell, MyShellHandler>(shell_hid, 1);
//! event_loop.register_global::<ZxdgShellV6, MyShellHandler>(shell_hid, 1);
//!
//! // You're now ready to go! //! // You're now ready to go!
//! # } //! # }
//! ``` //! ```
//! //!
//! ### Access to shell surface and clients data //! ### Access to shell surface and clients data
//! //!
//! There are mainly 3 kind of objects that you'll manipulate from this handler: //! There are mainly 3 kind of objects that you'll manipulate from this implementation:
//! //!
//! - `ShellClient`: This is a handle representing an isntanciation of a shell global //! - `ShellClient`: This is a handle representing an isntanciation of a shell global
//! you can associate client-wise metadata to it (this is the `MyShellData` type in //! you can associate client-wise metadata to it (this is the `MyShellData` type in
//! the example above). //! the example above).
//! - `ToplevelSurface`: This is a handle representing a toplevel surface, you can //! - `ToplevelSurface`: This is a handle representing a toplevel surface, you can
//! retrive a list of all currently alive toplevel surface from the `Shellhandler`. //! retrive a list of all currently alive toplevel surface from the `ShellState`.
//! - `PopupSurface`: This is a handle representing a popup/tooltip surface. Similarly, //! - `PopupSurface`: This is a handle representing a popup/tooltip surface. Similarly,
//! you can get a list of all currently alive popup surface from the `ShellHandler`. //! 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 //! You'll obtain these objects though two means: either via the callback methods of
//! the subhandler you provided, or via methods on the `ShellHandler` that you can //! the subhandler you provided, or via methods on the `ShellState` that you can
//! access from the `state()` of the event loop. //! access from the `state()` of the event loop and the token returned by the init
//! function.
use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle}; use compositor::{CompositorToken, Rectangle};
use compositor::roles::Role; use compositor::roles::Role;
use std::cell::RefCell;
use std::rc::Rc;
use wayland_protocols::unstable::xdg_shell::server::{zxdg_popup_v6, zxdg_positioner_v6 as xdg_positioner, use wayland_protocols::unstable::xdg_shell::server::{zxdg_popup_v6, zxdg_positioner_v6 as xdg_positioner,
zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6}; zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6};
use wayland_server::{EventLoop, EventLoopHandle, EventResult, Global, Liveness, Resource, StateToken};
use wayland_server::{EventLoopHandle, EventResult, Init, Liveness, Resource};
use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface};
mod global;
mod wl_handlers; mod wl_handlers;
mod xdg_handlers; mod xdg_handlers;
@ -301,54 +266,100 @@ impl Default for ShellSurfacePendingState {
} }
} }
/// The handler for the shell globals /// Internal implementation data of shell surfaces
/// ///
/// See module-level documentation for its use. /// This type is only visible as type parameter of
pub struct ShellHandler<U, R, H, SH, SD> { /// the `Global` handle you are provided.
my_id: usize, pub struct ShellSurfaceIData<U, R, CID, SID, SD> {
log: ::slog::Logger, log: ::slog::Logger,
token: CompositorToken<U, R, H>, compositor_token: CompositorToken<U, R, CID>,
handler: SH, implementation: ShellSurfaceUserImplementation<U, R, CID, SID, SD>,
known_toplevels: Vec<ToplevelSurface<U, R, H, SD>>, idata: Rc<RefCell<SID>>,
known_popups: Vec<PopupSurface<U, R, H, SD>>, state_token: StateToken<ShellState<U, R, CID, SD>>,
_shell_data: ::std::marker::PhantomData<SD>,
} }
impl<U, R, H, SH, SD> Init for ShellHandler<U, R, H, SH, SD> { impl<U, R, CID, SID, SD> Clone for ShellSurfaceIData<U, R, CID, SID, SD> {
fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { fn clone(&self) -> ShellSurfaceIData<U, R, CID, SID, SD> {
self.my_id = index; ShellSurfaceIData {
debug!(self.log, "Init finished") log: self.log.clone(),
} compositor_token: self.compositor_token.clone(),
} implementation: self.implementation.clone(),
idata: self.idata.clone(),
impl<U, R, H, SH, SD> ShellHandler<U, R, H, SH, SD> state_token: self.state_token.clone(),
where
U: Send + 'static,
R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static,
{
/// Create a new CompositorHandler
pub fn new<L>(handler: SH, token: CompositorToken<U, R, H>, logger: L) -> ShellHandler<U, R, H, SH, SD>
where
L: Into<Option<::slog::Logger>>,
{
let log = ::slog_or_stdlog(logger);
ShellHandler {
my_id: ::std::usize::MAX,
log: log.new(o!("smithay_module" => "shell_handler")),
token: token,
handler: handler,
known_toplevels: Vec::new(),
known_popups: Vec::new(),
_shell_data: ::std::marker::PhantomData,
} }
} }
}
/// Access the inner handler of this CompositorHandler /// Create new xdg_shell and wl_shell globals.
pub fn get_handler(&mut self) -> &mut SH { ///
&mut self.handler /// The globals are directly registered into the eventloop, and this function
} /// returns a `StateToken<_>` which you'll need access the list of shell
/// surfaces created by your clients.
///
/// It also returns the two global handles, in case you whish to remove these
/// globals from the event loop in the future.
pub fn shell_init<U, R, CID, SID, SD, L>(
evl: &mut EventLoop, token: CompositorToken<U, R, CID>,
implementation: ShellSurfaceUserImplementation<U, R, CID, SID, SD>, idata: SID, logger: L)
-> (
StateToken<ShellState<U, R, CID, SD>>,
Global<wl_shell::WlShell, ShellSurfaceIData<U, R, CID, SID, SD>>,
Global<zxdg_shell_v6::ZxdgShellV6, ShellSurfaceIData<U, R, CID, SID, SD>>,
)
where
U: 'static,
R: Role<ShellSurfaceRole> + 'static,
CID: 'static,
SID: 'static,
SD: Default + 'static,
L: Into<Option<::slog::Logger>>,
{
let log = ::slog_or_stdlog(logger);
let shell_state = ShellState {
known_toplevels: Vec::new(),
known_popups: Vec::new(),
};
let shell_state_token = evl.state().insert(shell_state);
let shell_surface_idata = ShellSurfaceIData {
log: log.new(o!("smithay_module" => "shell_handler")),
compositor_token: token,
implementation: implementation,
idata: Rc::new(RefCell::new(idata)),
state_token: shell_state_token.clone(),
};
// TODO: init globals
let wl_shell_global = evl.register_global(
1,
self::wl_handlers::wl_shell_bind::<U, R, CID, SID, SD>,
shell_surface_idata.clone(),
);
let xdg_shell_global = evl.register_global(
1,
self::xdg_handlers::xdg_shell_bind::<U, R, CID, SID, SD>,
shell_surface_idata.clone(),
);
(shell_state_token, wl_shell_global, xdg_shell_global)
}
/// Shell global state
///
/// This state allows you to retrieve a list of surfaces
/// currently known to the shell global.
pub struct ShellState<U, R, CID, SD> {
known_toplevels: Vec<ToplevelSurface<U, R, CID, SD>>,
known_popups: Vec<PopupSurface<U, R, CID, SD>>,
}
impl<U, R, CID, SD> ShellState<U, R, CID, SD>
where
U: 'static,
R: Role<ShellSurfaceRole> + 'static,
CID: 'static,
SD: 'static,
{
/// Cleans the internal surface storage by removing all dead surfaces /// Cleans the internal surface storage by removing all dead surfaces
pub fn cleanup_surfaces(&mut self) { pub fn cleanup_surfaces(&mut self) {
self.known_toplevels.retain(|s| s.alive()); self.known_toplevels.retain(|s| s.alive());
@ -356,12 +367,12 @@ where
} }
/// Access all the shell surfaces known by this handler /// Access all the shell surfaces known by this handler
pub fn toplevel_surfaces(&self) -> &[ToplevelSurface<U, R, H, SD>] { pub fn toplevel_surfaces(&self) -> &[ToplevelSurface<U, R, CID, SD>] {
&self.known_toplevels[..] &self.known_toplevels[..]
} }
/// Access all the popup surfaces known by this handler /// Access all the popup surfaces known by this handler
pub fn popup_surfaces(&self) -> &[PopupSurface<U, R, H, SD>] { pub fn popup_surfaces(&self) -> &[PopupSurface<U, R, CID, SD>] {
&self.known_popups[..] &self.known_popups[..]
} }
} }
@ -375,11 +386,18 @@ enum ShellClientKind {
Xdg(zxdg_shell_v6::ZxdgShellV6), Xdg(zxdg_shell_v6::ZxdgShellV6),
} }
struct ShellClientData<SD> { pub(crate) struct ShellClientData<SD> {
pending_ping: u32, pending_ping: u32,
data: SD, data: SD,
} }
fn make_shell_client_data<SD: Default>() -> ShellClientData<SD> {
ShellClientData {
pending_ping: 0,
data: Default::default(),
}
}
/// A shell client /// A shell client
/// ///
/// This represents an instanciation of a shell /// This represents an instanciation of a shell
@ -490,18 +508,19 @@ enum SurfaceKind {
/// ///
/// This is an unified abstraction over the toplevel surfaces /// This is an unified abstraction over the toplevel surfaces
/// of both `wl_shell` and `xdg_shell`. /// of both `wl_shell` and `xdg_shell`.
pub struct ToplevelSurface<U, R, H, SD> { pub struct ToplevelSurface<U, R, CID, SD> {
wl_surface: wl_surface::WlSurface, wl_surface: wl_surface::WlSurface,
shell_surface: SurfaceKind, shell_surface: SurfaceKind,
token: CompositorToken<U, R, H>, token: CompositorToken<U, R, CID>,
_shell_data: ::std::marker::PhantomData<SD>, _shell_data: ::std::marker::PhantomData<SD>,
} }
impl<U, R, H, SD> ToplevelSurface<U, R, H, SD> impl<U, R, CID, SD> ToplevelSurface<U, R, CID, SD>
where where
U: Send + 'static, U: 'static,
R: Role<ShellSurfaceRole> + Send + 'static, R: Role<ShellSurfaceRole> + 'static,
H: CompositorHandler<U, R> + Send + 'static, CID: 'static,
SD: 'static,
{ {
/// Is the toplevel surface refered by this handle still alive? /// Is the toplevel surface refered by this handle still alive?
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
@ -628,18 +647,19 @@ where
/// ///
/// This is an unified abstraction over the popup surfaces /// This is an unified abstraction over the popup surfaces
/// of both `wl_shell` and `xdg_shell`. /// of both `wl_shell` and `xdg_shell`.
pub struct PopupSurface<U, R, H, SD> { pub struct PopupSurface<U, R, CID, SD> {
wl_surface: wl_surface::WlSurface, wl_surface: wl_surface::WlSurface,
shell_surface: SurfaceKind, shell_surface: SurfaceKind,
token: CompositorToken<U, R, H>, token: CompositorToken<U, R, CID>,
_shell_data: ::std::marker::PhantomData<SD>, _shell_data: ::std::marker::PhantomData<SD>,
} }
impl<U, R, H, SD> PopupSurface<U, R, H, SD> impl<U, R, CID, SD> PopupSurface<U, R, CID, SD>
where where
U: Send + 'static, U: 'static,
R: Role<ShellSurfaceRole> + Send + 'static, R: Role<ShellSurfaceRole> + 'static,
H: CompositorHandler<U, R> + Send + 'static, CID: 'static,
SD: 'static,
{ {
/// Is the popup surface refered by this handle still alive? /// Is the popup surface refered by this handle still alive?
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
@ -807,47 +827,66 @@ pub struct PopupConfigure {
pub serial: u32, pub serial: u32,
} }
/// A trait for the sub-handler provided to the ShellHandler /// A sub-implementation for the shell
/// ///
/// You need to implement this trait to handle events that the ShellHandler /// You need to provide this to handle events that the provided implementation
/// cannot process for you directly. /// cannot process for you directly.
/// ///
/// Depending on what you want to do, you might implement some of these methods /// Depending on what you want to do, you might implement some of these functions
/// as doing nothing. /// as doing nothing.
pub trait Handler<U, R, H, SD> { pub struct ShellSurfaceUserImplementation<U, R, CID, SID, SD> {
/// A new shell client was instanciated /// A new shell client was instanciated
fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>); pub new_client: fn(evlh: &mut EventLoopHandle, idata: &mut SID, client: ShellClient<SD>),
/// The pong for a pending ping of this shell client was received /// The pong for a pending ping of this shell client was received
/// ///
/// The ShellHandler already checked for you that the serial matches the one /// The ShellHandler already checked for you that the serial matches the one
/// from the pending ping. /// from the pending ping.
fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<SD>); pub client_pong: fn(evlh: &mut EventLoopHandle, idata: &mut SID, client: ShellClient<SD>),
/// A new toplevel surface was created /// A new toplevel surface was created
/// ///
/// You need to return a `ToplevelConfigure` from this method, which will be sent /// You need to return a `ToplevelConfigure` from this function, which will be sent
/// to the client to configure this surface /// to the client to configure this surface
fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>) pub new_toplevel: fn(
-> ToplevelConfigure; evlh: &mut EventLoopHandle,
idata: &mut SID,
surface: ToplevelSurface<U, R, CID, SD>,
) -> ToplevelConfigure,
/// A new popup surface was created /// A new popup surface was created
/// ///
/// You need to return a `PopupConfigure` from this method, which will be sent /// You need to return a `PopupConfigure` from this function, which will be sent
/// to the client to configure this surface /// to the client to configure this surface
fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>) pub new_popup: fn(evlh: &mut EventLoopHandle, idata: &mut SID, surface: PopupSurface<U, R, CID, SD>)
-> PopupConfigure; -> PopupConfigure,
/// The client requested the start of an interactive move for this surface /// 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>, pub move_: fn(
seat: &wl_seat::WlSeat, serial: u32); evlh: &mut EventLoopHandle,
idata: &mut SID,
surface: ToplevelSurface<U, R, CID, SD>,
seat: &wl_seat::WlSeat,
serial: u32,
),
/// The client requested the start of an interactive resize for this surface /// 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. /// 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>, pub resize: fn(
seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge); evlh: &mut EventLoopHandle,
idata: &mut SID,
surface: ToplevelSurface<U, R, CID, SD>,
seat: &wl_seat::WlSeat,
serial: u32,
edges: zxdg_toplevel_v6::ResizeEdge,
),
/// This popup requests a grab of the pointer /// This popup requests a grab of the pointer
/// ///
/// This means it requests to be sent a `popup_done` event when the pointer leaves /// This means it requests to be sent a `popup_done` event when the pointer leaves
/// the grab area. /// the grab area.
fn grab(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface<U, R, H, SD>, pub grab: fn(
seat: &wl_seat::WlSeat, serial: u32); evlh: &mut EventLoopHandle,
idata: &mut SID,
surface: PopupSurface<U, R, CID, SD>,
seat: &wl_seat::WlSeat,
serial: u32,
),
/// A toplevel surface requested its display state to be changed /// A toplevel surface requested its display state to be changed
/// ///
/// Each field represents the request of the client for a specific property: /// Each field represents the request of the client for a specific property:
@ -861,14 +900,33 @@ pub trait Handler<U, R, H, SD> {
/// ///
/// You are to answer with a `ToplevelConfigure` that will be sent to the client in /// You are to answer with a `ToplevelConfigure` that will be sent to the client in
/// response. /// response.
fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, pub change_display_state: fn(
maximized: Option<bool>, minimized: Option<bool>, fullscreen: Option<bool>, evlh: &mut EventLoopHandle,
output: Option<&wl_output::WlOutput>) idata: &mut SID,
-> ToplevelConfigure; surface: ToplevelSurface<U, R, CID, SD>,
maximized: Option<bool>,
minimized: Option<bool>,
fullscreen: Option<bool>,
output: Option<&wl_output::WlOutput>,
) -> ToplevelConfigure,
/// The client requests the window menu to be displayed on this surface at this location /// 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 /// This menu belongs to the compositor. It is typically expected to contain options for
/// control of the window (maximize/minimize/close/move/etc...). /// control of the window (maximize/minimize/close/move/etc...).
fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface<U, R, H, SD>, pub show_window_menu: fn(
seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32); evlh: &mut EventLoopHandle,
idata: &mut SID,
surface: ToplevelSurface<U, R, CID, SD>,
seat: &wl_seat::WlSeat,
serial: u32,
x: i32,
y: i32,
),
}
impl<U, R, CID, SID, SD> Copy for ShellSurfaceUserImplementation<U, R, CID, SID, SD> {}
impl<U, R, CID, SID, SD> Clone for ShellSurfaceUserImplementation<U, R, CID, SID, SD> {
fn clone(&self) -> ShellSurfaceUserImplementation<U, R, CID, SID, SD> {
*self
}
} }

View File

@ -1,35 +1,49 @@
use super::{Handler as UserHandler, PopupConfigure, PopupState, PositionerState, ShellClient, use super::{make_shell_client_data, PopupConfigure, PopupState, PositionerState, ShellClient,
ShellClientData, ShellHandler, ShellSurfacePendingState, ShellSurfaceRole, ToplevelConfigure, ShellClientData, ShellSurfaceIData, ShellSurfacePendingState, ShellSurfaceRole,
ToplevelState}; ToplevelConfigure, ToplevelState};
use compositor::{CompositorToken, Rectangle};
use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle};
use compositor::roles::*; use compositor::roles::*;
use std::sync::Mutex; use std::sync::Mutex;
use wayland_protocols::unstable::xdg_shell::server::{zxdg_positioner_v6 as xdg_positioner, zxdg_toplevel_v6}; use wayland_protocols::unstable::xdg_shell::server::{zxdg_positioner_v6 as xdg_positioner, zxdg_toplevel_v6};
use wayland_server::{Client, EventLoopHandle, Resource};
use wayland_server::protocol::{wl_output, wl_shell, wl_shell_surface, wl_surface};
use wayland_server::{Client, Destroy, EventLoopHandle, Resource}; pub(crate) fn wl_shell_bind<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; idata: &mut ShellSurfaceIData<U, R, CID, SID, SD>,
_: &Client, shell: wl_shell::WlShell)
pub struct WlShellDestructor<SD> { where
_data: ::std::marker::PhantomData<SD>, U: 'static,
R: Role<ShellSurfaceRole> + 'static,
CID: 'static,
SID: 'static,
SD: Default + 'static,
{
shell.set_user_data(Box::into_raw(Box::new(Mutex::new((
make_shell_client_data::<SD>(),
Vec::<wl_shell_surface::WlShellSurface>::new(),
)))) as *mut _);
evlh.register(
&shell,
shell_implementation(),
idata.clone(),
Some(destroy_shell::<SD>),
);
let mut user_idata = idata.idata.borrow_mut();
(idata.implementation.new_client)(evlh, &mut *user_idata, make_shell_client(&shell));
} }
/* /*
* wl_shell * wl_shell
*/ */
pub type ShellUserData<SD> = Mutex<(ShellClientData<SD>, Vec<wl_shell_surface::WlShellSurface>)>; pub(crate) type ShellUserData<SD> = Mutex<(ShellClientData<SD>, Vec<wl_shell_surface::WlShellSurface>)>;
impl<SD> Destroy<wl_shell::WlShell> for WlShellDestructor<SD> { fn destroy_shell<SD>(shell: &wl_shell::WlShell) {
fn destroy(shell: &wl_shell::WlShell) { let ptr = shell.get_user_data();
let ptr = shell.get_user_data(); shell.set_user_data(::std::ptr::null_mut());
shell.set_user_data(::std::ptr::null_mut()); let data = unsafe { Box::from_raw(ptr as *mut ShellUserData<SD>) };
let data = unsafe { Box::from_raw(ptr as *mut ShellUserData<SD>) }; // explicitly call drop to not forget what we're doing here
// explicitly call drop to not forget what we're doing here ::std::mem::drop(data);
::std::mem::drop(data);
}
} }
pub fn make_shell_client<SD>(resource: &wl_shell::WlShell) -> ShellClient<SD> { pub fn make_shell_client<SD>(resource: &wl_shell::WlShell) -> ShellClient<SD> {
@ -39,69 +53,68 @@ pub fn make_shell_client<SD>(resource: &wl_shell::WlShell) -> ShellClient<SD> {
} }
} }
impl<U, R, H, SH, SD> wl_shell::Handler for ShellHandler<U, R, H, SH, SD> fn shell_implementation<U, R, CID, SID, SD>(
)
-> wl_shell::Implementation<ShellSurfaceIData<U, R, CID, SID, SD>>
where where
U: Send + 'static, U: 'static,
R: Role<ShellSurfaceRole> + Send + 'static, R: Role<ShellSurfaceRole> + 'static,
H: CompositorHandler<U, R> + Send + 'static, CID: 'static,
SH: UserHandler<U, R, H, SD> + Send + 'static, SID: 'static,
SD: Send + 'static, SD: 'static,
{ {
fn get_shell_surface(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell::WlShell, wl_shell::Implementation {
id: wl_shell_surface::WlShellSurface, surface: &wl_surface::WlSurface) { get_shell_surface: |evlh, idata, _, shell, shell_surface, surface| {
trace!(self.log, "Creating new wl_shell_surface."); let role_data = ShellSurfaceRole {
let role_data = ShellSurfaceRole { pending_state: ShellSurfacePendingState::None,
pending_state: ShellSurfacePendingState::None, window_geometry: None,
window_geometry: None, pending_configures: Vec::new(),
pending_configures: Vec::new(), configured: true,
configured: true, };
}; if let Err(_) = idata.compositor_token.give_role_with(surface, role_data) {
if let Err(_) = self.token.give_role_with(surface, role_data) { shell.post_error(
resource.post_error( wl_shell::Error::Role as u32,
wl_shell::Error::Role as u32, "Surface already has a role.".into(),
"Surface already has a role.".into(), );
return;
}
shell_surface.set_user_data(
Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _,
);
evlh.register(
&shell_surface,
shell_surface_implementation(),
idata.clone(),
Some(destroy_shell_surface),
); );
return;
}
id.set_user_data(
Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _,
);
evlh.register_with_destructor::<_, Self, WlShellDestructor<SD>>(&id, self.my_id);
// register ourselves to the wl_shell for ping handling // register ourselves to the wl_shell for ping handling
let mutex = unsafe { &*(resource.get_user_data() as *mut ShellUserData<SD>) }; let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
let mut guard = mutex.lock().unwrap(); let mut guard = mutex.lock().unwrap();
if guard.1.len() == 0 && guard.0.pending_ping != 0 { if guard.1.len() == 0 && guard.0.pending_ping != 0 {
// there is a pending ping that no surface could receive yet, send it // there is a pending ping that no surface could receive yet, send it
// note this is not possible that it was received and then a wl_shell_surface was // note this is not possible that it was received and then a wl_shell_surface was
// destroyed, because wl_shell_surface has no destructor! // destroyed, because wl_shell_surface has no destructor!
id.ping(guard.0.pending_ping); shell_surface.ping(guard.0.pending_ping);
} }
guard.1.push(id); guard.1.push(shell_surface);
},
} }
} }
server_declare_handler!(
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH:[UserHandler<U,R,H,SD>, Send], SD: [Send]>,
wl_shell::Handler,
wl_shell::WlShell
);
/* /*
* wl_shell_surface * wl_shell_surface
*/ */
pub type ShellSurfaceUserData = (wl_surface::WlSurface, wl_shell::WlShell); pub type ShellSurfaceUserData = (wl_surface::WlSurface, wl_shell::WlShell);
impl<SD> Destroy<wl_shell_surface::WlShellSurface> for WlShellDestructor<SD> { fn destroy_shell_surface(shell_surface: &wl_shell_surface::WlShellSurface) {
fn destroy(shell_surface: &wl_shell_surface::WlShellSurface) { let ptr = shell_surface.get_user_data();
let ptr = shell_surface.get_user_data(); shell_surface.set_user_data(::std::ptr::null_mut());
shell_surface.set_user_data(::std::ptr::null_mut()); // drop the WlSurface object
// drop the WlSurface object let surface = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
let surface = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; // explicitly call drop to not forget what we're doing here
// explicitly call drop to not forget what we're doing here ::std::mem::drop(surface);
::std::mem::drop(surface);
}
} }
fn make_toplevel_handle<U, R, H, SD>(token: CompositorToken<U, R, H>, fn make_toplevel_handle<U, R, H, SD>(token: CompositorToken<U, R, H>,
@ -140,231 +153,294 @@ pub fn send_popup_configure(resource: &wl_shell_surface::WlShellSurface, configu
resource.configure(wl_shell_surface::Resize::empty(), w, h); resource.configure(wl_shell_surface::Resize::empty(), w, h);
} }
impl<U, R, H, SH, SD> ShellHandler<U, R, H, SH, SD> fn wl_handle_display_state_change<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
where idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
U: Send + 'static, shell_surface: &wl_shell_surface::WlShellSurface,
R: Role<ShellSurfaceRole> + Send + 'static, maximized: Option<bool>, minimized: Option<bool>,
H: CompositorHandler<U, R> + Send + 'static, fullscreen: Option<bool>,
SH: UserHandler<U, R, H, SD> + Send + 'static, output: Option<&wl_output::WlOutput>) {
SD: Send + 'static, let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
{ // handler callback
fn wl_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle, let mut user_idata = idata.idata.borrow_mut();
resource: &wl_shell_surface::WlShellSurface, let configure = (idata.implementation.change_display_state)(
maximized: Option<bool>, minimized: Option<bool>, evlh,
fullscreen: Option<bool>, output: Option<&wl_output::WlOutput>) { &mut *user_idata,
let handle = make_toplevel_handle(self.token, resource); handle,
// handler callback maximized,
let configure = minimized,
self.handler fullscreen,
.change_display_state(evlh, handle, maximized, minimized, fullscreen, output); output,
// send the configure response to client );
let (w, h) = configure.size.unwrap_or((0, 0)); // send the configure response to client
resource.configure(wl_shell_surface::None, w, h); let (w, h) = configure.size.unwrap_or((0, 0));
} shell_surface.configure(wl_shell_surface::None, w, h);
}
fn wl_ensure_toplevel(&mut self, evlh: &mut EventLoopHandle, fn wl_set_parent<U, R, CID, SID, SD>(idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
resource: &wl_shell_surface::WlShellSurface) { shell_surface: &wl_shell_surface::WlShellSurface,
let ptr = resource.get_user_data(); parent: Option<wl_surface::WlSurface>)
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; where
// copy token to make borrow checker happy U: 'static,
let token = self.token; R: Role<ShellSurfaceRole> + 'static,
let need_send = token CID: 'static,
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| { SID: 'static,
match data.pending_state { SD: 'static,
ShellSurfacePendingState::Toplevel(_) => { {
return false; let ptr = shell_surface.get_user_data();
} let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
ShellSurfacePendingState::Popup(_) => { idata
// this is no longer a popup, deregister it .compositor_token
self.known_popups.retain(|other| { .with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.parent = parent;
}
_ => unreachable!(),
})
.unwrap();
}
fn wl_ensure_toplevel<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
shell_surface: &wl_shell_surface::WlShellSurface)
where
U: 'static,
R: Role<ShellSurfaceRole> + 'static,
CID: 'static,
SID: 'static,
SD: 'static,
{
let ptr = shell_surface.get_user_data();
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
// copy token to make borrow checker happy
let token = idata.compositor_token;
let need_send = token
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| {
match data.pending_state {
ShellSurfacePendingState::Toplevel(_) => {
return false;
}
ShellSurfacePendingState::Popup(_) => {
// this is no longer a popup, deregister it
evlh.state()
.get_mut(&idata.state_token)
.known_popups
.retain(|other| {
other other
.get_surface() .get_surface()
.map(|s| !s.equals(wl_surface)) .map(|s| !s.equals(wl_surface))
.unwrap_or(false) .unwrap_or(false)
}); });
}
ShellSurfacePendingState::None => {}
} }
// This was not previously toplevel, need to make it toplevel ShellSurfacePendingState::None => {}
data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
parent: None,
title: String::new(),
app_id: String::new(),
min_size: (0, 0),
max_size: (0, 0),
});
return true;
})
.expect(
"xdg_surface exists but surface has not shell_surface role?!",
);
// we need to notify about this new toplevel surface
if need_send {
let handle = make_toplevel_handle(self.token, resource);
let configure = self.handler.new_toplevel(evlh, handle);
send_toplevel_configure(resource, configure);
}
}
}
impl<U, R, H, SH, SD> wl_shell_surface::Handler for ShellHandler<U, R, H, SH, SD>
where
U: Send + 'static,
R: Role<ShellSurfaceRole> + Send + 'static,
H: CompositorHandler<U, R> + Send + 'static,
SH: UserHandler<U, R, H, SD> + Send + 'static,
SD: Send + 'static,
{
fn pong(&mut self, evlh: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, serial: u32) {
let &(_, ref shell) = unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
let valid = {
let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
let mut guard = mutex.lock().unwrap();
if guard.0.pending_ping == serial {
guard.0.pending_ping = 0;
true
} else {
false
} }
}; // This was not previously toplevel, need to make it toplevel
if valid { data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
self.handler.client_pong(evlh, make_shell_client(shell)); parent: None,
} title: String::new(),
} app_id: String::new(),
min_size: (0, 0),
fn move_(&mut self, evlh: &mut EventLoopHandle, _: &Client, max_size: (0, 0),
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32) { });
let handle = make_toplevel_handle(self.token, resource); return true;
self.handler.move_(evlh, handle, seat, serial); })
} .expect(
"xdg_surface exists but surface has not shell_surface role?!",
fn resize(&mut self, evlh: &mut EventLoopHandle, _: &Client, );
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32, // we need to notify about this new toplevel surface
edges: wl_shell_surface::Resize) { if need_send {
let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges.bits()) evlh.state()
.unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); .get_mut(&idata.state_token)
let handle = make_toplevel_handle(self.token, resource); .known_toplevels
self.handler.resize(evlh, handle, seat, serial, edges); .push(make_toplevel_handle(idata.compositor_token, shell_surface));
} let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
let mut user_idata = idata.idata.borrow_mut();
fn set_toplevel(&mut self, evlh: &mut EventLoopHandle, _: &Client, let configure = (idata.implementation.new_toplevel)(evlh, &mut *user_idata, handle);
resource: &wl_shell_surface::WlShellSurface) { send_toplevel_configure(shell_surface, configure);
self.wl_ensure_toplevel(evlh, resource);
self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None)
}
fn set_transient(&mut self, evlh: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, parent: &wl_surface::WlSurface, _x: i32,
_y: i32, _flags: wl_shell_surface::Transient) {
self.wl_ensure_toplevel(evlh, resource);
// set the parent
let ptr = resource.get_user_data();
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
self.token
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.parent = Some(unsafe { parent.clone_unchecked() });
}
_ => unreachable!(),
})
.unwrap();
// set as regular surface
self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None)
}
fn set_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface,
_method: wl_shell_surface::FullscreenMethod, _framerate: u32,
output: Option<&wl_output::WlOutput>) {
self.wl_ensure_toplevel(evlh, resource);
self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(true), output)
}
fn set_popup(&mut self, evlh: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32,
parent: &wl_surface::WlSurface, x: i32, y: i32, _: wl_shell_surface::Transient) {
let ptr = resource.get_user_data();
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
// we are reseting the popup state, so remove this surface from everywhere
self.known_toplevels.retain(|other| {
other
.get_surface()
.map(|s| !s.equals(wl_surface))
.unwrap_or(false)
});
self.known_popups.retain(|other| {
other
.get_surface()
.map(|s| !s.equals(wl_surface))
.unwrap_or(false)
});
self.token
.with_role_data(wl_surface, |data| {
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
parent: unsafe { parent.clone_unchecked() },
positioner: PositionerState {
rect_size: (1, 1),
anchor_rect: Rectangle {
x,
y,
width: 1,
height: 1,
},
anchor_edges: xdg_positioner::Anchor::empty(),
gravity: xdg_positioner::Gravity::empty(),
constraint_adjustment: xdg_positioner::ConstraintAdjustment::empty(),
offset: (0, 0),
},
});
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
// notify the handler about this new popup
let handle = make_popup_handle(self.token, resource);
let configure = self.handler.new_popup(evlh, handle);
send_popup_configure(resource, configure);
self.handler
.grab(evlh, make_popup_handle(self.token, resource), seat, serial);
}
fn set_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, output: Option<&wl_output::WlOutput>) {
self.wl_ensure_toplevel(evlh, resource);
self.wl_handle_display_state_change(evlh, resource, Some(true), Some(false), Some(false), output)
}
fn set_title(&mut self, _: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, title: String) {
let ptr = resource.get_user_data();
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
self.token
.with_role_data(surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.title = title;
}
_ => {}
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
}
fn set_class(&mut self, _: &mut EventLoopHandle, _: &Client,
resource: &wl_shell_surface::WlShellSurface, class_: String) {
let ptr = resource.get_user_data();
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
self.token
.with_role_data(surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.app_id = class_;
}
_ => {}
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
} }
} }
server_declare_handler!( fn shell_surface_implementation<U, R, CID, SID, SD>(
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>, )
wl_shell_surface::Handler, -> wl_shell_surface::Implementation<ShellSurfaceIData<U, R, CID, SID, SD>>
wl_shell_surface::WlShellSurface where
); U: 'static,
R: Role<ShellSurfaceRole> + 'static,
CID: 'static,
SID: 'static,
SD: 'static,
{
wl_shell_surface::Implementation {
pong: |evlh, idata, _, shell_surface, serial| {
let &(_, ref shell) = unsafe { &*(shell_surface.get_user_data() as *mut ShellSurfaceUserData) };
let valid = {
let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
let mut guard = mutex.lock().unwrap();
if guard.0.pending_ping == serial {
guard.0.pending_ping = 0;
true
} else {
false
}
};
if valid {
let mut user_idata = idata.idata.borrow_mut();
(idata.implementation.client_pong)(evlh, &mut *user_idata, make_shell_client(shell));
}
},
move_: |evlh, idata, _, shell_surface, seat, serial| {
let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
let mut user_idata = idata.idata.borrow_mut();
(idata.implementation.move_)(evlh, &mut *user_idata, handle, seat, serial);
},
resize: |evlh, idata, _, shell_surface, seat, serial, edges| {
let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges.bits())
.unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
let mut user_idata = idata.idata.borrow_mut();
(idata.implementation.resize)(evlh, &mut *user_idata, handle, seat, serial, edges);
},
set_toplevel: |evlh, idata, _, shell_surface| {
wl_ensure_toplevel(evlh, idata, shell_surface);
wl_set_parent(idata, shell_surface, None);
wl_handle_display_state_change(
evlh,
idata,
shell_surface,
Some(false),
Some(false),
Some(false),
None,
)
},
set_transient: |evlh, idata, _, shell_surface, parent, _, _, _| {
wl_ensure_toplevel(evlh, idata, shell_surface);
wl_set_parent(
idata,
shell_surface,
Some(unsafe { parent.clone_unchecked() }),
);
wl_handle_display_state_change(
evlh,
idata,
shell_surface,
Some(false),
Some(false),
Some(false),
None,
)
},
set_fullscreen: |evlh, idata, _, shell_surface, _, _, output| {
wl_ensure_toplevel(evlh, idata, shell_surface);
wl_set_parent(idata, shell_surface, None);
wl_handle_display_state_change(
evlh,
idata,
shell_surface,
Some(false),
Some(false),
Some(true),
output,
)
},
set_popup: |evlh, idata, _, shell_surface, seat, serial, parent, x, y, _| {
let ptr = shell_surface.get_user_data();
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
// we are reseting the popup state, so remove this surface from everywhere
evlh.state()
.get_mut(&idata.state_token)
.known_toplevels
.retain(|other| {
other
.get_surface()
.map(|s| !s.equals(wl_surface))
.unwrap_or(false)
});
evlh.state()
.get_mut(&idata.state_token)
.known_popups
.retain(|other| {
other
.get_surface()
.map(|s| !s.equals(wl_surface))
.unwrap_or(false)
});
idata
.compositor_token
.with_role_data(wl_surface, |data| {
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
parent: unsafe { parent.clone_unchecked() },
positioner: PositionerState {
rect_size: (1, 1),
anchor_rect: Rectangle {
x,
y,
width: 1,
height: 1,
},
anchor_edges: xdg_positioner::Anchor::empty(),
gravity: xdg_positioner::Gravity::empty(),
constraint_adjustment: xdg_positioner::ConstraintAdjustment::empty(),
offset: (0, 0),
},
});
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
// notify the handler about this new popup
evlh.state()
.get_mut(&idata.state_token)
.known_popups
.push(make_popup_handle(idata.compositor_token, shell_surface));
let handle = make_popup_handle(idata.compositor_token, shell_surface);
let mut user_idata = idata.idata.borrow_mut();
let configure = (idata.implementation.new_popup)(evlh, &mut *user_idata, handle);
send_popup_configure(shell_surface, configure);
(idata.implementation.grab)(
evlh,
&mut *user_idata,
make_popup_handle(idata.compositor_token, shell_surface),
seat,
serial,
);
},
set_maximized: |evlh, idata, _, shell_surface, output| {
wl_ensure_toplevel(evlh, idata, shell_surface);
wl_set_parent(idata, shell_surface, None);
wl_handle_display_state_change(
evlh,
idata,
shell_surface,
Some(true),
Some(false),
Some(false),
output,
)
},
set_title: |_, idata, _, shell_surface, title| {
let ptr = shell_surface.get_user_data();
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
idata
.compositor_token
.with_role_data(surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.title = title;
}
_ => {}
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
},
set_class: |_, idata, _, shell_surface, class| {
let ptr = shell_surface.get_user_data();
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
idata
.compositor_token
.with_role_data(surface, |data| match data.pending_state {
ShellSurfacePendingState::Toplevel(ref mut state) => {
state.app_id = class;
}
_ => {}
})
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
},
}
}

File diff suppressed because it is too large Load Diff