shell: update to new wayland-server
This commit is contained in:
parent
33f80a622f
commit
32e60de4f3
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
372
src/shell/mod.rs
372
src/shell/mod.rs
|
@ -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(),
|
||||||
|
state_token: self.state_token.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> ShellHandler<U, R, H, SH, SD>
|
/// Create new xdg_shell and wl_shell globals.
|
||||||
|
///
|
||||||
|
/// 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
|
where
|
||||||
U: Send + 'static,
|
U: 'static,
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
CID: 'static,
|
||||||
{
|
SID: 'static,
|
||||||
/// Create a new CompositorHandler
|
SD: Default + 'static,
|
||||||
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>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
ShellHandler {
|
let shell_state = ShellState {
|
||||||
my_id: ::std::usize::MAX,
|
|
||||||
log: log.new(o!("smithay_module" => "shell_handler")),
|
|
||||||
token: token,
|
|
||||||
handler: handler,
|
|
||||||
known_toplevels: Vec::new(),
|
known_toplevels: Vec::new(),
|
||||||
known_popups: Vec::new(),
|
known_popups: Vec::new(),
|
||||||
_shell_data: ::std::marker::PhantomData,
|
};
|
||||||
}
|
let shell_state_token = evl.state().insert(shell_state);
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the inner handler of this CompositorHandler
|
let shell_surface_idata = ShellSurfaceIData {
|
||||||
pub fn get_handler(&mut self) -> &mut SH {
|
log: log.new(o!("smithay_module" => "shell_handler")),
|
||||||
&mut self.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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(_) = self.token.give_role_with(surface, role_data) {
|
if let Err(_) = idata.compositor_token.give_role_with(surface, role_data) {
|
||||||
resource.post_error(
|
shell.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;
|
return;
|
||||||
}
|
}
|
||||||
id.set_user_data(
|
shell_surface.set_user_data(
|
||||||
Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _,
|
Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _,
|
||||||
);
|
);
|
||||||
evlh.register_with_destructor::<_, Self, WlShellDestructor<SD>>(&id, self.my_id);
|
evlh.register(
|
||||||
|
&shell_surface,
|
||||||
|
shell_surface_implementation(),
|
||||||
|
idata.clone(),
|
||||||
|
Some(destroy_shell_surface),
|
||||||
|
);
|
||||||
|
|
||||||
// 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,34 +153,66 @@ 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,
|
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
|
||||||
SH: UserHandler<U, R, H, SD> + Send + 'static,
|
|
||||||
SD: Send + 'static,
|
|
||||||
{
|
|
||||||
fn wl_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle,
|
|
||||||
resource: &wl_shell_surface::WlShellSurface,
|
|
||||||
maximized: Option<bool>, minimized: Option<bool>,
|
maximized: Option<bool>, minimized: Option<bool>,
|
||||||
fullscreen: Option<bool>, output: Option<&wl_output::WlOutput>) {
|
fullscreen: Option<bool>,
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
output: Option<&wl_output::WlOutput>) {
|
||||||
|
let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
|
||||||
// handler callback
|
// handler callback
|
||||||
let configure =
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
self.handler
|
let configure = (idata.implementation.change_display_state)(
|
||||||
.change_display_state(evlh, handle, maximized, minimized, fullscreen, output);
|
evlh,
|
||||||
|
&mut *user_idata,
|
||||||
|
handle,
|
||||||
|
maximized,
|
||||||
|
minimized,
|
||||||
|
fullscreen,
|
||||||
|
output,
|
||||||
|
);
|
||||||
// send the configure response to client
|
// send the configure response to client
|
||||||
let (w, h) = configure.size.unwrap_or((0, 0));
|
let (w, h) = configure.size.unwrap_or((0, 0));
|
||||||
resource.configure(wl_shell_surface::None, w, h);
|
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>)
|
||||||
|
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) };
|
||||||
|
idata
|
||||||
|
.compositor_token
|
||||||
|
.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) };
|
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
// copy token to make borrow checker happy
|
// copy token to make borrow checker happy
|
||||||
let token = self.token;
|
let token = idata.compositor_token;
|
||||||
let need_send = token
|
let need_send = token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| {
|
||||||
match data.pending_state {
|
match data.pending_state {
|
||||||
|
@ -176,7 +221,10 @@ where
|
||||||
}
|
}
|
||||||
ShellSurfacePendingState::Popup(_) => {
|
ShellSurfacePendingState::Popup(_) => {
|
||||||
// this is no longer a popup, deregister it
|
// this is no longer a popup, deregister it
|
||||||
self.known_popups.retain(|other| {
|
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))
|
||||||
|
@ -200,24 +248,30 @@ where
|
||||||
);
|
);
|
||||||
// we need to notify about this new toplevel surface
|
// we need to notify about this new toplevel surface
|
||||||
if need_send {
|
if need_send {
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
evlh.state()
|
||||||
let configure = self.handler.new_toplevel(evlh, handle);
|
.get_mut(&idata.state_token)
|
||||||
send_toplevel_configure(resource, configure);
|
.known_toplevels
|
||||||
}
|
.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();
|
||||||
|
let configure = (idata.implementation.new_toplevel)(evlh, &mut *user_idata, handle);
|
||||||
|
send_toplevel_configure(shell_surface, configure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> wl_shell_surface::Handler for ShellHandler<U, R, H, SH, SD>
|
fn shell_surface_implementation<U, R, CID, SID, SD>(
|
||||||
|
)
|
||||||
|
-> wl_shell_surface::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 pong(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
wl_shell_surface::Implementation {
|
||||||
resource: &wl_shell_surface::WlShellSurface, serial: u32) {
|
pong: |evlh, idata, _, shell_surface, serial| {
|
||||||
let &(_, ref shell) = unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
let &(_, ref shell) = unsafe { &*(shell_surface.get_user_data() as *mut ShellSurfaceUserData) };
|
||||||
let valid = {
|
let valid = {
|
||||||
let mutex = unsafe { &*(shell.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();
|
||||||
|
@ -229,77 +283,89 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if valid {
|
if valid {
|
||||||
self.handler.client_pong(evlh, make_shell_client(shell));
|
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| {
|
||||||
fn move_(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
|
||||||
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32) {
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
(idata.implementation.move_)(evlh, &mut *user_idata, handle, seat, serial);
|
||||||
self.handler.move_(evlh, handle, seat, serial);
|
},
|
||||||
}
|
resize: |evlh, idata, _, shell_surface, seat, serial, edges| {
|
||||||
|
|
||||||
fn resize(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32,
|
|
||||||
edges: wl_shell_surface::Resize) {
|
|
||||||
let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges.bits())
|
let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges.bits())
|
||||||
.unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
|
.unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
let handle = make_toplevel_handle(idata.compositor_token, shell_surface);
|
||||||
self.handler.resize(evlh, handle, seat, serial, edges);
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
}
|
(idata.implementation.resize)(evlh, &mut *user_idata, handle, seat, serial, edges);
|
||||||
|
},
|
||||||
fn set_toplevel(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
set_toplevel: |evlh, idata, _, shell_surface| {
|
||||||
resource: &wl_shell_surface::WlShellSurface) {
|
wl_ensure_toplevel(evlh, idata, shell_surface);
|
||||||
self.wl_ensure_toplevel(evlh, resource);
|
wl_set_parent(idata, shell_surface, None);
|
||||||
self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None)
|
wl_handle_display_state_change(
|
||||||
}
|
evlh,
|
||||||
|
idata,
|
||||||
fn set_transient(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
shell_surface,
|
||||||
resource: &wl_shell_surface::WlShellSurface, parent: &wl_surface::WlSurface, _x: i32,
|
Some(false),
|
||||||
_y: i32, _flags: wl_shell_surface::Transient) {
|
Some(false),
|
||||||
self.wl_ensure_toplevel(evlh, resource);
|
Some(false),
|
||||||
// set the parent
|
None,
|
||||||
let ptr = resource.get_user_data();
|
)
|
||||||
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
},
|
||||||
self.token
|
set_transient: |evlh, idata, _, shell_surface, parent, _, _, _| {
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(wl_surface, |data| match data.pending_state {
|
wl_ensure_toplevel(evlh, idata, shell_surface);
|
||||||
ShellSurfacePendingState::Toplevel(ref mut state) => {
|
wl_set_parent(
|
||||||
state.parent = Some(unsafe { parent.clone_unchecked() });
|
idata,
|
||||||
}
|
shell_surface,
|
||||||
_ => unreachable!(),
|
Some(unsafe { parent.clone_unchecked() }),
|
||||||
})
|
);
|
||||||
.unwrap();
|
wl_handle_display_state_change(
|
||||||
// set as regular surface
|
evlh,
|
||||||
self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None)
|
idata,
|
||||||
}
|
shell_surface,
|
||||||
|
Some(false),
|
||||||
fn set_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
Some(false),
|
||||||
resource: &wl_shell_surface::WlShellSurface,
|
Some(false),
|
||||||
_method: wl_shell_surface::FullscreenMethod, _framerate: u32,
|
None,
|
||||||
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)
|
set_fullscreen: |evlh, idata, _, shell_surface, _, _, output| {
|
||||||
}
|
wl_ensure_toplevel(evlh, idata, shell_surface);
|
||||||
|
wl_set_parent(idata, shell_surface, None);
|
||||||
fn set_popup(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
wl_handle_display_state_change(
|
||||||
resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32,
|
evlh,
|
||||||
parent: &wl_surface::WlSurface, x: i32, y: i32, _: wl_shell_surface::Transient) {
|
idata,
|
||||||
let ptr = resource.get_user_data();
|
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) };
|
let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
// we are reseting the popup state, so remove this surface from everywhere
|
// we are reseting the popup state, so remove this surface from everywhere
|
||||||
self.known_toplevels.retain(|other| {
|
evlh.state()
|
||||||
|
.get_mut(&idata.state_token)
|
||||||
|
.known_toplevels
|
||||||
|
.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)
|
||||||
});
|
});
|
||||||
self.known_popups.retain(|other| {
|
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)
|
||||||
});
|
});
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data(wl_surface, |data| {
|
.with_role_data(wl_surface, |data| {
|
||||||
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
||||||
parent: unsafe { parent.clone_unchecked() },
|
parent: unsafe { parent.clone_unchecked() },
|
||||||
|
@ -321,24 +387,40 @@ where
|
||||||
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
||||||
|
|
||||||
// notify the handler about this new popup
|
// notify the handler about this new popup
|
||||||
let handle = make_popup_handle(self.token, resource);
|
evlh.state()
|
||||||
let configure = self.handler.new_popup(evlh, handle);
|
.get_mut(&idata.state_token)
|
||||||
send_popup_configure(resource, configure);
|
.known_popups
|
||||||
self.handler
|
.push(make_popup_handle(idata.compositor_token, shell_surface));
|
||||||
.grab(evlh, make_popup_handle(self.token, resource), seat, serial);
|
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);
|
||||||
fn set_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
send_popup_configure(shell_surface, configure);
|
||||||
resource: &wl_shell_surface::WlShellSurface, output: Option<&wl_output::WlOutput>) {
|
(idata.implementation.grab)(
|
||||||
self.wl_ensure_toplevel(evlh, resource);
|
evlh,
|
||||||
self.wl_handle_display_state_change(evlh, resource, Some(true), Some(false), Some(false), output)
|
&mut *user_idata,
|
||||||
}
|
make_popup_handle(idata.compositor_token, shell_surface),
|
||||||
|
seat,
|
||||||
fn set_title(&mut self, _: &mut EventLoopHandle, _: &Client,
|
serial,
|
||||||
resource: &wl_shell_surface::WlShellSurface, title: String) {
|
);
|
||||||
let ptr = resource.get_user_data();
|
},
|
||||||
|
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) };
|
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data(surface, |data| match data.pending_state {
|
.with_role_data(surface, |data| match data.pending_state {
|
||||||
ShellSurfacePendingState::Toplevel(ref mut state) => {
|
ShellSurfacePendingState::Toplevel(ref mut state) => {
|
||||||
state.title = title;
|
state.title = title;
|
||||||
|
@ -346,25 +428,19 @@ where
|
||||||
_ => {}
|
_ => {}
|
||||||
})
|
})
|
||||||
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
||||||
}
|
},
|
||||||
|
set_class: |_, idata, _, shell_surface, class| {
|
||||||
fn set_class(&mut self, _: &mut EventLoopHandle, _: &Client,
|
let ptr = shell_surface.get_user_data();
|
||||||
resource: &wl_shell_surface::WlShellSurface, class_: String) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data(surface, |data| match data.pending_state {
|
.with_role_data(surface, |data| match data.pending_state {
|
||||||
ShellSurfacePendingState::Toplevel(ref mut state) => {
|
ShellSurfacePendingState::Toplevel(ref mut state) => {
|
||||||
state.app_id = class_;
|
state.app_id = class;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
})
|
})
|
||||||
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
.expect("wl_shell_surface exists but wl_surface has wrong role?!");
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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_surface::Handler,
|
|
||||||
wl_shell_surface::WlShellSurface
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,57 +1,72 @@
|
||||||
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_popup_v6, zxdg_positioner_v6, zxdg_shell_v6,
|
use wayland_protocols::unstable::xdg_shell::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6,
|
||||||
zxdg_surface_v6, zxdg_toplevel_v6};
|
zxdg_surface_v6, zxdg_toplevel_v6};
|
||||||
use wayland_server::{Client, Destroy, EventLoopHandle, Resource};
|
use wayland_server::{Client, EventLoopHandle, Resource};
|
||||||
use wayland_server::protocol::{wl_output, wl_seat, wl_surface};
|
use wayland_server::protocol::{wl_output, wl_surface};
|
||||||
|
|
||||||
pub struct XdgShellDestructor<SD> {
|
pub(crate) fn xdg_shell_bind<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
|
||||||
_data: ::std::marker::PhantomData<SD>,
|
idata: &mut ShellSurfaceIData<U, R, CID, SID, SD>,
|
||||||
|
_: &Client, shell: zxdg_shell_v6::ZxdgShellV6)
|
||||||
|
where
|
||||||
|
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>()))) 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_shell
|
* xdg_shell
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub type ShellUserData<SD> = Mutex<ShellClientData<SD>>;
|
pub(crate) type ShellUserData<SD> = Mutex<ShellClientData<SD>>;
|
||||||
|
|
||||||
impl<SD> Destroy<zxdg_shell_v6::ZxdgShellV6> for XdgShellDestructor<SD> {
|
fn destroy_shell<SD>(shell: &zxdg_shell_v6::ZxdgShellV6) {
|
||||||
fn destroy(shell: &zxdg_shell_v6::ZxdgShellV6) {
|
|
||||||
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>) };
|
||||||
// explicit call to drop to not forget what we're doing here
|
// explicit call to drop to not forget what we're doing here
|
||||||
::std::mem::drop(data);
|
::std::mem::drop(data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_shell_client<SD>(resource: &zxdg_shell_v6::ZxdgShellV6) -> ShellClient<SD> {
|
pub(crate) fn make_shell_client<SD>(resource: &zxdg_shell_v6::ZxdgShellV6) -> ShellClient<SD> {
|
||||||
ShellClient {
|
ShellClient {
|
||||||
kind: super::ShellClientKind::Xdg(unsafe { resource.clone_unchecked() }),
|
kind: super::ShellClientKind::Xdg(unsafe { resource.clone_unchecked() }),
|
||||||
_data: ::std::marker::PhantomData,
|
_data: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> zxdg_shell_v6::Handler for ShellHandler<U, R, H, SH, SD>
|
fn shell_implementation<U, R, CID, SID, SD>(
|
||||||
|
)
|
||||||
|
-> zxdg_shell_v6::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 destroy(&mut self, _: &mut EventLoopHandle, _: &Client, _: &zxdg_shell_v6::ZxdgShellV6) {}
|
zxdg_shell_v6::Implementation {
|
||||||
fn create_positioner(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
destroy: |_, _, _, _| {},
|
||||||
_: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_positioner_v6::ZxdgPositionerV6) {
|
create_positioner: |evlh, _, _, _, positioner| {
|
||||||
trace!(self.log, "Creating new xdg_positioner.");
|
let data = PositionerState {
|
||||||
id.set_user_data(Box::into_raw(Box::new(PositionerState {
|
|
||||||
rect_size: (0, 0),
|
rect_size: (0, 0),
|
||||||
anchor_rect: Rectangle {
|
anchor_rect: Rectangle {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -63,38 +78,44 @@ where
|
||||||
gravity: zxdg_positioner_v6::Gravity::empty(),
|
gravity: zxdg_positioner_v6::Gravity::empty(),
|
||||||
constraint_adjustment: zxdg_positioner_v6::ConstraintAdjustment::empty(),
|
constraint_adjustment: zxdg_positioner_v6::ConstraintAdjustment::empty(),
|
||||||
offset: (0, 0),
|
offset: (0, 0),
|
||||||
})) as *mut _);
|
};
|
||||||
evlh.register_with_destructor::<_, Self, XdgShellDestructor<SD>>(&id, self.my_id);
|
positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _);
|
||||||
}
|
evlh.register(
|
||||||
fn get_xdg_surface(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
&positioner,
|
||||||
resource: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_surface_v6::ZxdgSurfaceV6,
|
positioner_implementation(),
|
||||||
surface: &wl_surface::WlSurface) {
|
(),
|
||||||
trace!(self.log, "Creating new wl_shell_surface.");
|
Some(destroy_positioner),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
get_xdg_surface: |evlh, idata, _, shell, xdg_surface, wl_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: false,
|
configured: false,
|
||||||
};
|
};
|
||||||
if let Err(_) = self.token.give_role_with(surface, role_data) {
|
if let Err(_) = idata.compositor_token.give_role_with(wl_surface, role_data) {
|
||||||
resource.post_error(
|
shell.post_error(
|
||||||
zxdg_shell_v6::Error::Role as u32,
|
zxdg_shell_v6::Error::Role as u32,
|
||||||
"Surface already has a role.".into(),
|
"Surface already has a role.".into(),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
id.set_user_data(
|
xdg_surface.set_user_data(
|
||||||
Box::into_raw(Box::new((unsafe { surface.clone_unchecked() }, unsafe {
|
Box::into_raw(Box::new((unsafe { wl_surface.clone_unchecked() }, unsafe {
|
||||||
resource.clone_unchecked()
|
shell.clone_unchecked()
|
||||||
}))) as *mut _,
|
}))) as *mut _,
|
||||||
);
|
);
|
||||||
evlh.register_with_destructor::<_, Self, XdgShellDestructor<SD>>(&id, self.my_id);
|
evlh.register(
|
||||||
}
|
&xdg_surface,
|
||||||
|
surface_implementation(),
|
||||||
fn pong(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_shell_v6::ZxdgShellV6,
|
idata.clone(),
|
||||||
serial: u32) {
|
Some(destroy_surface),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
pong: |evlh, idata, _, shell, serial| {
|
||||||
let valid = {
|
let valid = {
|
||||||
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.pending_ping == serial {
|
if guard.pending_ping == serial {
|
||||||
guard.pending_ping = 0;
|
guard.pending_ping = 0;
|
||||||
|
@ -104,66 +125,46 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if valid {
|
if valid {
|
||||||
self.handler.client_pong(evlh, make_shell_client(resource));
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
|
(idata.implementation.client_pong)(evlh, &mut *user_idata, make_shell_client(shell));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(
|
|
||||||
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>,
|
|
||||||
zxdg_shell_v6::Handler,
|
|
||||||
zxdg_shell_v6::ZxdgShellV6
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_positioner
|
* xdg_positioner
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<SD> Destroy<zxdg_positioner_v6::ZxdgPositionerV6> for XdgShellDestructor<SD> {
|
fn destroy_positioner(positioner: &zxdg_positioner_v6::ZxdgPositionerV6) {
|
||||||
fn destroy(positioner: &zxdg_positioner_v6::ZxdgPositionerV6) {
|
|
||||||
let ptr = positioner.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
positioner.set_user_data(::std::ptr::null_mut());
|
positioner.set_user_data(::std::ptr::null_mut());
|
||||||
// drop the PositionerState
|
// drop the PositionerState
|
||||||
let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) };
|
let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) };
|
||||||
// explicit call to drop to not forget what we're doing here
|
// explicit call to drop to not forget what we're doing here
|
||||||
::std::mem::drop(surface);
|
::std::mem::drop(surface);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> zxdg_positioner_v6::Handler for ShellHandler<U, R, H, SH, SD>
|
fn positioner_implementation() -> zxdg_positioner_v6::Implementation<()> {
|
||||||
where
|
zxdg_positioner_v6::Implementation {
|
||||||
U: Send + 'static,
|
destroy: |_, _, _, _| {},
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
set_size: |_, _, _, positioner, width, height| if width < 1 || height < 1 {
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
positioner.post_error(
|
||||||
SH: UserHandler<U, R, H, SD> + Send + 'static,
|
|
||||||
SD: Send + 'static,
|
|
||||||
{
|
|
||||||
fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, _: &zxdg_positioner_v6::ZxdgPositionerV6) {}
|
|
||||||
|
|
||||||
fn set_size(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6, width: i32, height: i32) {
|
|
||||||
if width < 1 || height < 1 {
|
|
||||||
resource.post_error(
|
|
||||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||||
"Invalid size for positioner.".into(),
|
"Invalid size for positioner.".into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let ptr = resource.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.rect_size = (width, height);
|
state.rect_size = (width, height);
|
||||||
}
|
},
|
||||||
}
|
set_anchor_rect: |_, _, _, positioner, x, y, width, height| if width < 1 || height < 1 {
|
||||||
|
positioner.post_error(
|
||||||
fn set_anchor_rect(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6, x: i32, y: i32, width: i32,
|
|
||||||
height: i32) {
|
|
||||||
if width < 1 || height < 1 {
|
|
||||||
resource.post_error(
|
|
||||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||||
"Invalid size for positioner's anchor rectangle.".into(),
|
"Invalid size for positioner's anchor rectangle.".into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let ptr = resource.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.anchor_rect = Rectangle {
|
state.anchor_rect = Rectangle {
|
||||||
x,
|
x,
|
||||||
|
@ -171,72 +172,56 @@ where
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
set_anchor: |_, _, _, positioner, anchor| {
|
||||||
|
|
||||||
fn set_anchor(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6, anchor: zxdg_positioner_v6::Anchor) {
|
|
||||||
use self::zxdg_positioner_v6::{AnchorBottom, AnchorLeft, AnchorRight, AnchorTop};
|
use self::zxdg_positioner_v6::{AnchorBottom, AnchorLeft, AnchorRight, AnchorTop};
|
||||||
if anchor.contains(AnchorLeft | AnchorRight) || anchor.contains(AnchorTop | AnchorBottom) {
|
if anchor.contains(AnchorLeft | AnchorRight) || anchor.contains(AnchorTop | AnchorBottom) {
|
||||||
resource.post_error(
|
positioner.post_error(
|
||||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||||
"Invalid anchor for positioner.".into(),
|
"Invalid anchor for positioner.".into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let ptr = resource.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.anchor_edges = anchor;
|
state.anchor_edges = anchor;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
set_gravity: |_, _, _, positioner, gravity| {
|
||||||
fn set_gravity(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6, gravity: zxdg_positioner_v6::Gravity) {
|
|
||||||
use self::zxdg_positioner_v6::{GravityBottom, GravityLeft, GravityRight, GravityTop};
|
use self::zxdg_positioner_v6::{GravityBottom, GravityLeft, GravityRight, GravityTop};
|
||||||
if gravity.contains(GravityLeft | GravityRight) || gravity.contains(GravityTop | GravityBottom) {
|
if gravity.contains(GravityLeft | GravityRight) || gravity.contains(GravityTop | GravityBottom) {
|
||||||
resource.post_error(
|
positioner.post_error(
|
||||||
zxdg_positioner_v6::Error::InvalidInput as u32,
|
zxdg_positioner_v6::Error::InvalidInput as u32,
|
||||||
"Invalid gravity for positioner.".into(),
|
"Invalid gravity for positioner.".into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let ptr = resource.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.gravity = gravity;
|
state.gravity = gravity;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
set_constraint_adjustment: |_, _, _, positioner, constraint_adjustment| {
|
||||||
fn set_constraint_adjustment(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6,
|
|
||||||
constraint_adjustment: u32) {
|
|
||||||
let constraint_adjustment =
|
let constraint_adjustment =
|
||||||
zxdg_positioner_v6::ConstraintAdjustment::from_bits_truncate(constraint_adjustment);
|
zxdg_positioner_v6::ConstraintAdjustment::from_bits_truncate(constraint_adjustment);
|
||||||
let ptr = resource.get_user_data();
|
let ptr = positioner.get_user_data();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.constraint_adjustment = constraint_adjustment;
|
state.constraint_adjustment = constraint_adjustment;
|
||||||
}
|
},
|
||||||
|
set_offset: |_, _, _, positioner, x, y| {
|
||||||
fn set_offset(&mut self, _: &mut EventLoopHandle, _: &Client,
|
let ptr = positioner.get_user_data();
|
||||||
resource: &zxdg_positioner_v6::ZxdgPositionerV6, x: i32, y: i32) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
||||||
state.offset = (x, y);
|
state.offset = (x, y);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(
|
|
||||||
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>,
|
|
||||||
zxdg_positioner_v6::Handler,
|
|
||||||
zxdg_positioner_v6::ZxdgPositionerV6
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_surface
|
* xdg_surface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<SD> Destroy<zxdg_surface_v6::ZxdgSurfaceV6> for XdgShellDestructor<SD> {
|
fn destroy_surface(surface: &zxdg_surface_v6::ZxdgSurfaceV6) {
|
||||||
fn destroy(surface: &zxdg_surface_v6::ZxdgSurfaceV6) {
|
|
||||||
let ptr = surface.get_user_data();
|
let ptr = surface.get_user_data();
|
||||||
surface.set_user_data(::std::ptr::null_mut());
|
surface.set_user_data(::std::ptr::null_mut());
|
||||||
// drop the PositionerState
|
// drop the state
|
||||||
let data = unsafe {
|
let data = unsafe {
|
||||||
Box::from_raw(
|
Box::from_raw(
|
||||||
ptr as *mut (zxdg_surface_v6::ZxdgSurfaceV6, zxdg_shell_v6::ZxdgShellV6),
|
ptr as *mut (zxdg_surface_v6::ZxdgSurfaceV6, zxdg_shell_v6::ZxdgShellV6),
|
||||||
|
@ -244,22 +229,25 @@ impl<SD> Destroy<zxdg_surface_v6::ZxdgSurfaceV6> for XdgShellDestructor<SD> {
|
||||||
};
|
};
|
||||||
// explicit call to drop to not forget what we're doing here
|
// explicit call to drop to not forget what we're doing here
|
||||||
::std::mem::drop(data);
|
::std::mem::drop(data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> zxdg_surface_v6::Handler for ShellHandler<U, R, H, SH, SD>
|
fn surface_implementation<U, R, CID, SID, SD>(
|
||||||
|
)
|
||||||
|
-> zxdg_surface_v6::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 destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6) {
|
zxdg_surface_v6::Implementation {
|
||||||
let ptr = resource.get_user_data();
|
destroy: |_, idata, _, xdg_surface| {
|
||||||
|
let ptr = xdg_surface.get_user_data();
|
||||||
let &(ref surface, ref shell) =
|
let &(ref surface, ref shell) =
|
||||||
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
if let ShellSurfacePendingState::None = data.pending_state {
|
if let ShellSurfacePendingState::None = data.pending_state {
|
||||||
// all is good
|
// all is good
|
||||||
|
@ -273,14 +261,13 @@ where
|
||||||
.expect(
|
.expect(
|
||||||
"xdg_surface exists but surface has not shell_surface role?!",
|
"xdg_surface exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
get_toplevel: |evlh, idata, _, xdg_surface, toplevel| {
|
||||||
fn get_toplevel(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
let ptr = xdg_surface.get_user_data();
|
||||||
resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_toplevel_v6::ZxdgToplevelV6) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let &(ref surface, ref shell) =
|
let &(ref surface, ref shell) =
|
||||||
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
|
data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState {
|
||||||
parent: None,
|
parent: None,
|
||||||
|
@ -294,30 +281,34 @@ where
|
||||||
"xdg_surface exists but surface has not shell_surface role?!",
|
"xdg_surface exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
|
|
||||||
id.set_user_data(Box::into_raw(Box::new(unsafe {
|
toplevel.set_user_data(Box::into_raw(Box::new(unsafe {
|
||||||
(
|
(
|
||||||
surface.clone_unchecked(),
|
surface.clone_unchecked(),
|
||||||
shell.clone_unchecked(),
|
shell.clone_unchecked(),
|
||||||
resource.clone_unchecked(),
|
xdg_surface.clone_unchecked(),
|
||||||
)
|
)
|
||||||
})) as *mut _);
|
})) as *mut _);
|
||||||
evlh.register_with_destructor::<_, Self, XdgShellDestructor<SD>>(&id, self.my_id);
|
evlh.register(
|
||||||
|
&toplevel,
|
||||||
|
toplevel_implementation(),
|
||||||
|
idata.clone(),
|
||||||
|
Some(destroy_toplevel),
|
||||||
|
);
|
||||||
|
|
||||||
// register to self
|
// register to self
|
||||||
self.known_toplevels
|
evlh.state()
|
||||||
.push(make_toplevel_handle(self.token, &id));
|
.get_mut(&idata.state_token)
|
||||||
|
.known_toplevels
|
||||||
|
.push(make_toplevel_handle(idata.compositor_token, &toplevel));
|
||||||
|
|
||||||
// intial configure event
|
// intial configure event
|
||||||
let handle = make_toplevel_handle(self.token, &id);
|
let handle = make_toplevel_handle(idata.compositor_token, &toplevel);
|
||||||
let configure = self.handler.new_toplevel(evlh, handle);
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
send_toplevel_configure(self.token, &id, configure);
|
let configure = (idata.implementation.new_toplevel)(evlh, &mut *user_idata, handle);
|
||||||
}
|
send_toplevel_configure(idata.compositor_token, &toplevel, configure);
|
||||||
|
},
|
||||||
fn get_popup(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
get_popup: |evlh, idata, _, xdg_surface, popup, parent, positioner| {
|
||||||
resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_popup_v6::ZxdgPopupV6,
|
let ptr = xdg_surface.get_user_data();
|
||||||
parent: &zxdg_surface_v6::ZxdgSurfaceV6,
|
|
||||||
positioner: &zxdg_positioner_v6::ZxdgPositionerV6) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let &(ref surface, ref shell) =
|
let &(ref surface, ref shell) =
|
||||||
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
|
|
||||||
|
@ -327,7 +318,8 @@ where
|
||||||
let &(ref parent_surface, _) =
|
let &(ref parent_surface, _) =
|
||||||
unsafe { &*(parent_ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(parent_ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
|
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
data.pending_state = ShellSurfacePendingState::Popup(PopupState {
|
||||||
parent: unsafe { parent_surface.clone_unchecked() },
|
parent: unsafe { parent_surface.clone_unchecked() },
|
||||||
|
@ -338,31 +330,38 @@ where
|
||||||
"xdg_surface exists but surface has not shell_surface role?!",
|
"xdg_surface exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
|
|
||||||
id.set_user_data(Box::into_raw(Box::new(unsafe {
|
popup.set_user_data(Box::into_raw(Box::new(unsafe {
|
||||||
(
|
(
|
||||||
surface.clone_unchecked(),
|
surface.clone_unchecked(),
|
||||||
shell.clone_unchecked(),
|
shell.clone_unchecked(),
|
||||||
resource.clone_unchecked(),
|
xdg_surface.clone_unchecked(),
|
||||||
)
|
)
|
||||||
})) as *mut _);
|
})) as *mut _);
|
||||||
evlh.register_with_destructor::<_, Self, XdgShellDestructor<SD>>(&id, self.my_id);
|
evlh.register(
|
||||||
|
&popup,
|
||||||
|
popup_implementation(),
|
||||||
|
idata.clone(),
|
||||||
|
Some(destroy_popup),
|
||||||
|
);
|
||||||
|
|
||||||
// register to self
|
// register to self
|
||||||
self.known_popups.push(make_popup_handle(self.token, &id));
|
evlh.state()
|
||||||
|
.get_mut(&idata.state_token)
|
||||||
|
.known_popups
|
||||||
|
.push(make_popup_handle(idata.compositor_token, &popup));
|
||||||
|
|
||||||
// intial configure event
|
// intial configure event
|
||||||
let handle = make_popup_handle(self.token, &id);
|
let handle = make_popup_handle(idata.compositor_token, &popup);
|
||||||
let configure = self.handler.new_popup(evlh, handle);
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
send_popup_configure(self.token, &id, configure);
|
let configure = (idata.implementation.new_popup)(evlh, &mut *user_idata, handle);
|
||||||
}
|
send_popup_configure(idata.compositor_token, &popup, configure);
|
||||||
|
},
|
||||||
fn set_window_geometry(&mut self, _: &mut EventLoopHandle, _: &Client,
|
set_window_geometry: |_, idata, _, surface, x, y, width, height| {
|
||||||
resource: &zxdg_surface_v6::ZxdgSurfaceV6, x: i32, y: i32, width: i32,
|
let ptr = surface.get_user_data();
|
||||||
height: i32) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let &(ref surface, _) =
|
let &(ref surface, _) =
|
||||||
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
data.window_geometry = Some(Rectangle {
|
data.window_geometry = Some(Rectangle {
|
||||||
x,
|
x,
|
||||||
|
@ -374,14 +373,13 @@ where
|
||||||
.expect(
|
.expect(
|
||||||
"xdg_surface exists but surface has not shell_surface role?!",
|
"xdg_surface exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
ack_configure: |_, idata, _, surface, serial| {
|
||||||
fn ack_configure(&mut self, _: &mut EventLoopHandle, _: &Client,
|
let ptr = surface.get_user_data();
|
||||||
resource: &zxdg_surface_v6::ZxdgSurfaceV6, serial: u32) {
|
|
||||||
let ptr = resource.get_user_data();
|
|
||||||
let &(ref surface, ref shell) =
|
let &(ref surface, ref shell) =
|
||||||
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
data.pending_configures.retain(|&s| {
|
data.pending_configures.retain(|&s| {
|
||||||
|
@ -402,15 +400,10 @@ where
|
||||||
.expect(
|
.expect(
|
||||||
"xdg_surface exists but surface has not shell_surface role?!",
|
"xdg_surface exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(
|
|
||||||
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>,
|
|
||||||
zxdg_surface_v6::Handler,
|
|
||||||
zxdg_surface_v6::ZxdgSurfaceV6
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_toplevel
|
* xdg_toplevel
|
||||||
*/
|
*/
|
||||||
|
@ -421,33 +414,30 @@ pub type ShellSurfaceUserData = (
|
||||||
zxdg_surface_v6::ZxdgSurfaceV6,
|
zxdg_surface_v6::ZxdgSurfaceV6,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<SD> Destroy<zxdg_toplevel_v6::ZxdgToplevelV6> for XdgShellDestructor<SD> {
|
fn destroy_toplevel(surface: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
||||||
fn destroy(surface: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
|
||||||
let ptr = surface.get_user_data();
|
let ptr = surface.get_user_data();
|
||||||
surface.set_user_data(::std::ptr::null_mut());
|
surface.set_user_data(::std::ptr::null_mut());
|
||||||
// drop the PositionerState
|
// drop the PositionerState
|
||||||
let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
||||||
// explicit call to drop to not forget what we're doing there
|
// explicit call to drop to not forget what we're doing there
|
||||||
::std::mem::drop(data);
|
::std::mem::drop(data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> ShellHandler<U, R, H, SH, SD>
|
// Utility functions allowing to factor out a lot of the upcoming logic
|
||||||
|
fn with_surface_toplevel_data<U, R, CID, SID, SD, F>(idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
|
||||||
|
toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F)
|
||||||
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,
|
||||||
{
|
|
||||||
// Utility function allowing to factor out a lot of the upcoming logic
|
|
||||||
fn with_surface_toplevel_data<F>(&self, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F)
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut ToplevelState),
|
F: FnOnce(&mut ToplevelState),
|
||||||
{
|
{
|
||||||
let ptr = resource.get_user_data();
|
let ptr = toplevel.get_user_data();
|
||||||
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| match data.pending_state {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| match data.pending_state {
|
||||||
ShellSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data),
|
ShellSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -455,29 +445,45 @@ where
|
||||||
.expect(
|
.expect(
|
||||||
"xdg_toplevel exists but surface has not shell_surface role?!",
|
"xdg_toplevel exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
fn xdg_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle,
|
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
|
||||||
maximized: Option<bool>, minimized: Option<bool>,
|
|
||||||
fullscreen: Option<bool>, output: Option<&wl_output::WlOutput>) {
|
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
|
||||||
// handler callback
|
|
||||||
let configure =
|
|
||||||
self.handler
|
|
||||||
.change_display_state(evlh, handle, maximized, minimized, fullscreen, output);
|
|
||||||
// send the configure response to client
|
|
||||||
send_toplevel_configure(self.token, resource, configure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_toplevel_configure<U, R, H>(token: CompositorToken<U, R, H>,
|
fn xdg_handle_display_state_change<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
|
||||||
|
idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
|
||||||
|
toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
||||||
|
maximized: Option<bool>, minimized: Option<bool>,
|
||||||
|
fullscreen: Option<bool>,
|
||||||
|
output: Option<&wl_output::WlOutput>)
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
|
CID: 'static,
|
||||||
|
SID: 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
|
let handle = make_toplevel_handle(idata.compositor_token, toplevel);
|
||||||
|
// handler callback
|
||||||
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
|
let configure = (idata.implementation.change_display_state)(
|
||||||
|
evlh,
|
||||||
|
&mut *user_idata,
|
||||||
|
handle,
|
||||||
|
maximized,
|
||||||
|
minimized,
|
||||||
|
fullscreen,
|
||||||
|
output,
|
||||||
|
);
|
||||||
|
// send the configure response to client
|
||||||
|
send_toplevel_configure(idata.compositor_token, toplevel, configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn send_toplevel_configure<U, R, ID>(token: CompositorToken<U, R, ID>,
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
resource: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
||||||
configure: ToplevelConfigure)
|
configure: ToplevelConfigure)
|
||||||
where
|
where
|
||||||
U: Send + 'static,
|
U: 'static,
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
ID: 'static,
|
||||||
{
|
{
|
||||||
let &(ref surface, _, ref shell_surface) =
|
let &(ref surface, _, ref shell_surface) =
|
||||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
||||||
|
@ -515,18 +521,22 @@ fn make_toplevel_handle<U, R, H, SD>(token: CompositorToken<U, R, H>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> zxdg_toplevel_v6::Handler for ShellHandler<U, R, H, SH, SD>
|
fn toplevel_implementation<U, R, CID, SID, SD>(
|
||||||
|
)
|
||||||
|
-> zxdg_toplevel_v6::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 destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
zxdg_toplevel_v6::Implementation {
|
||||||
let ptr = resource.get_user_data();
|
destroy: |evlh, idata, _, toplevel| {
|
||||||
|
let ptr = toplevel.get_user_data();
|
||||||
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
data.pending_state = ShellSurfacePendingState::None;
|
data.pending_state = ShellSurfacePendingState::None;
|
||||||
data.configured = false;
|
data.configured = false;
|
||||||
|
@ -535,18 +545,18 @@ where
|
||||||
"xdg_toplevel exists but surface has not shell_surface role?!",
|
"xdg_toplevel exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||||
self.known_toplevels.retain(|other| {
|
evlh.state()
|
||||||
|
.get_mut(&idata.state_token)
|
||||||
|
.known_toplevels
|
||||||
|
.retain(|other| {
|
||||||
other
|
other
|
||||||
.get_surface()
|
.get_surface()
|
||||||
.map(|s| !s.equals(surface))
|
.map(|s| !s.equals(surface))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
set_parent: |_, idata, _, toplevel, parent| {
|
||||||
fn set_parent(&mut self, _: &mut EventLoopHandle, _: &Client,
|
with_surface_toplevel_data(idata, toplevel, |toplevel_data| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
|
||||||
parent: Option<&zxdg_toplevel_v6::ZxdgToplevelV6>) {
|
|
||||||
self.with_surface_toplevel_data(resource, |toplevel_data| {
|
|
||||||
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
||||||
let parent_ptr = toplevel_surface_parent.get_user_data();
|
let parent_ptr = toplevel_surface_parent.get_user_data();
|
||||||
let &(ref parent_surface, _) =
|
let &(ref parent_surface, _) =
|
||||||
|
@ -554,109 +564,82 @@ where
|
||||||
unsafe { parent_surface.clone_unchecked() }
|
unsafe { parent_surface.clone_unchecked() }
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
set_title: |_, idata, _, toplevel, title| {
|
||||||
fn set_title(&mut self, _: &mut EventLoopHandle, _: &Client,
|
with_surface_toplevel_data(idata, toplevel, |toplevel_data| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, title: String) {
|
toplevel_data.title = title;
|
||||||
self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.title = title; });
|
});
|
||||||
}
|
},
|
||||||
|
set_app_id: |_, idata, _, toplevel, app_id| {
|
||||||
fn set_app_id(&mut self, _: &mut EventLoopHandle, _: &Client,
|
with_surface_toplevel_data(idata, toplevel, |toplevel_data| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, app_id: String) {
|
toplevel_data.app_id = app_id;
|
||||||
self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.app_id = app_id; });
|
});
|
||||||
}
|
},
|
||||||
|
show_window_menu: |evlh, idata, _, toplevel, seat, serial, x, y| {
|
||||||
fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
let handle = make_toplevel_handle(idata.compositor_token, toplevel);
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32,
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
x: i32, y: i32) {
|
(idata.implementation.show_window_menu)(evlh, &mut *user_idata, handle, seat, serial, x, y)
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
},
|
||||||
self.handler
|
move_: |evlh, idata, _, toplevel, seat, serial| {
|
||||||
.show_window_menu(evlh, handle, seat, serial, x, y);
|
let handle = make_toplevel_handle(idata.compositor_token, toplevel);
|
||||||
}
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
|
(idata.implementation.move_)(evlh, &mut *user_idata, handle, seat, serial)
|
||||||
fn move_(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
},
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32) {
|
resize: |evlh, idata, _, toplevel, seat, serial, edges| {
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
|
||||||
self.handler.move_(evlh, handle, seat, serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32, edges: u32) {
|
|
||||||
let edges =
|
let edges =
|
||||||
zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
|
zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None);
|
||||||
let handle = make_toplevel_handle(self.token, resource);
|
let handle = make_toplevel_handle(idata.compositor_token, toplevel);
|
||||||
self.handler.resize(evlh, handle, seat, serial, edges);
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
}
|
(idata.implementation.resize)(evlh, &mut *user_idata, handle, seat, serial, edges)
|
||||||
|
},
|
||||||
fn set_max_size(&mut self, _: &mut EventLoopHandle, _: &Client,
|
set_max_size: |_, idata, _, toplevel, width, height| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) {
|
with_surface_toplevel_data(idata, toplevel, |toplevel_data| {
|
||||||
self.with_surface_toplevel_data(resource, |toplevel_data| {
|
|
||||||
toplevel_data.max_size = (width, height);
|
toplevel_data.max_size = (width, height);
|
||||||
});
|
})
|
||||||
}
|
},
|
||||||
|
set_min_size: |_, idata, _, toplevel, width, height| {
|
||||||
fn set_min_size(&mut self, _: &mut EventLoopHandle, _: &Client,
|
with_surface_toplevel_data(idata, toplevel, |toplevel_data| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) {
|
|
||||||
self.with_surface_toplevel_data(resource, |toplevel_data| {
|
|
||||||
toplevel_data.min_size = (width, height);
|
toplevel_data.min_size = (width, height);
|
||||||
});
|
})
|
||||||
}
|
},
|
||||||
|
set_maximized: |evlh, idata, _, toplevel| {
|
||||||
fn set_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
xdg_handle_display_state_change(evlh, idata, toplevel, Some(true), None, None, None);
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
},
|
||||||
self.xdg_handle_display_state_change(evlh, resource, Some(true), None, None, None);
|
unset_maximized: |evlh, idata, _, toplevel| {
|
||||||
}
|
xdg_handle_display_state_change(evlh, idata, toplevel, Some(false), None, None, None);
|
||||||
|
},
|
||||||
fn unset_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
set_fullscreen: |evlh, idata, _, toplevel, seat| {
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
xdg_handle_display_state_change(evlh, idata, toplevel, None, None, Some(true), seat);
|
||||||
self.xdg_handle_display_state_change(evlh, resource, Some(false), None, None, None);
|
},
|
||||||
}
|
unset_fullscreen: |evlh, idata, _, toplevel| {
|
||||||
|
xdg_handle_display_state_change(evlh, idata, toplevel, None, None, Some(false), None);
|
||||||
fn set_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
},
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6, output: Option<&wl_output::WlOutput>) {
|
set_minimized: |evlh, idata, _, toplevel| {
|
||||||
self.xdg_handle_display_state_change(evlh, resource, None, None, Some(true), output);
|
xdg_handle_display_state_change(evlh, idata, toplevel, None, Some(true), None, None);
|
||||||
}
|
},
|
||||||
|
|
||||||
fn unset_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
|
||||||
self.xdg_handle_display_state_change(evlh, resource, None, None, Some(false), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_minimized(&mut self, evlh: &mut EventLoopHandle, _: &Client,
|
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6) {
|
|
||||||
self.xdg_handle_display_state_change(evlh, resource, None, Some(true), None, None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(
|
|
||||||
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>,
|
|
||||||
zxdg_toplevel_v6::Handler,
|
|
||||||
zxdg_toplevel_v6::ZxdgToplevelV6
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_popup
|
* xdg_popup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
fn destroy_popup(surface: &zxdg_popup_v6::ZxdgPopupV6) {
|
||||||
|
|
||||||
impl<SD> Destroy<zxdg_popup_v6::ZxdgPopupV6> for XdgShellDestructor<SD> {
|
|
||||||
fn destroy(surface: &zxdg_popup_v6::ZxdgPopupV6) {
|
|
||||||
let ptr = surface.get_user_data();
|
let ptr = surface.get_user_data();
|
||||||
surface.set_user_data(::std::ptr::null_mut());
|
surface.set_user_data(::std::ptr::null_mut());
|
||||||
// drop the PositionerState
|
// drop the PositionerState
|
||||||
let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
||||||
// explicit call to drop to not forget what we're doing
|
// explicit call to drop to not forget what we're doing
|
||||||
::std::mem::drop(data);
|
::std::mem::drop(data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_popup_configure<U, R, H>(token: CompositorToken<U, R, H>, resource: &zxdg_popup_v6::ZxdgPopupV6,
|
pub(crate) fn send_popup_configure<U, R, ID>(token: CompositorToken<U, R, ID>,
|
||||||
|
resource: &zxdg_popup_v6::ZxdgPopupV6,
|
||||||
configure: PopupConfigure)
|
configure: PopupConfigure)
|
||||||
where
|
where
|
||||||
U: Send + 'static,
|
U: 'static,
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
ID: 'static,
|
||||||
{
|
{
|
||||||
let &(ref surface, _, ref shell_surface) =
|
let &(ref surface, _, ref shell_surface) =
|
||||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
||||||
|
@ -685,25 +668,29 @@ fn make_popup_handle<U, R, H, SD>(token: CompositorToken<U, R, H>, resource: &zx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H, SH, SD> zxdg_popup_v6::Handler for ShellHandler<U, R, H, SH, SD>
|
fn popup_implementation<U, R, CID, SID, SD>(
|
||||||
|
)
|
||||||
|
-> zxdg_popup_v6::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 destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6) {
|
zxdg_popup_v6::Implementation {
|
||||||
let ptr = resource.get_user_data();
|
destroy: |evlh, idata, _, popup| {
|
||||||
|
let ptr = popup.get_user_data();
|
||||||
let &(ref surface, _, _) = unsafe {
|
let &(ref surface, _, _) = unsafe {
|
||||||
&*(ptr as
|
&*(ptr
|
||||||
*mut (
|
as *mut (
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
zxdg_shell_v6::ZxdgShellV6,
|
zxdg_shell_v6::ZxdgShellV6,
|
||||||
zxdg_surface_v6::ZxdgSurfaceV6,
|
zxdg_surface_v6::ZxdgSurfaceV6,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
self.token
|
idata
|
||||||
|
.compositor_token
|
||||||
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
.with_role_data::<ShellSurfaceRole, _, _>(surface, |data| {
|
||||||
data.pending_state = ShellSurfacePendingState::None;
|
data.pending_state = ShellSurfacePendingState::None;
|
||||||
data.configured = false;
|
data.configured = false;
|
||||||
|
@ -712,23 +699,20 @@ where
|
||||||
"xdg_toplevel exists but surface has not shell_surface role?!",
|
"xdg_toplevel exists but surface has not shell_surface role?!",
|
||||||
);
|
);
|
||||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||||
self.known_popups.retain(|other| {
|
evlh.state()
|
||||||
|
.get_mut(&idata.state_token)
|
||||||
|
.known_popups
|
||||||
|
.retain(|other| {
|
||||||
other
|
other
|
||||||
.get_surface()
|
.get_surface()
|
||||||
.map(|s| !s.equals(surface))
|
.map(|s| !s.equals(surface))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
grab: |evlh, idata, _, popup, seat, serial| {
|
||||||
fn grab(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6,
|
let handle = make_popup_handle(idata.compositor_token, popup);
|
||||||
seat: &wl_seat::WlSeat, serial: u32) {
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
let handle = make_popup_handle(self.token, resource);
|
(idata.implementation.grab)(evlh, &mut *user_idata, handle, seat, serial)
|
||||||
self.handler.grab(evlh, handle, seat, serial);
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(
|
|
||||||
ShellHandler<U: [Send], R: [Role<ShellSurfaceRole>, Send], H:[CompositorHandler<U, R>, Send], SH: [UserHandler<U,R,H,SD>, Send], SD: [Send]>,
|
|
||||||
zxdg_popup_v6::Handler,
|
|
||||||
zxdg_popup_v6::ZxdgPopupV6
|
|
||||||
);
|
|
||||||
|
|
Loading…
Reference in New Issue