Merge pull request #35 from vberger/master
Migrate to wayland-server 0.10
This commit is contained in:
commit
24ea2a066a
|
@ -1,3 +1,4 @@
|
||||||
target
|
target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
*.bk
|
*.bk
|
||||||
|
.vscode
|
||||||
|
|
|
@ -5,7 +5,7 @@ authors = ["Victor Berger <victor.berger@thalesgroup.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wayland-server = "0.9.9"
|
wayland-server = "0.10.1"
|
||||||
nix = "0.7.0"
|
nix = "0.7.0"
|
||||||
xkbcommon = "0.2.1"
|
xkbcommon = "0.2.1"
|
||||||
tempfile = "2.1.5"
|
tempfile = "2.1.5"
|
||||||
|
@ -18,7 +18,7 @@ glium = { version = "0.16.0", optional = true, default-features = false }
|
||||||
input = { version = "0.2.0", optional = true }
|
input = { version = "0.2.0", optional = true }
|
||||||
clippy = { version = "*", optional = true }
|
clippy = { version = "*", optional = true }
|
||||||
rental = "0.4.11"
|
rental = "0.4.11"
|
||||||
wayland-protocols = { version = "0.9.9", features = ["unstable_protocols", "server"] }
|
wayland-protocols = { version = "0.10.1", features = ["unstable_protocols", "server"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
gl_generator = "0.5"
|
gl_generator = "0.5"
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
use rand;
|
||||||
|
use smithay::compositor::{CompositorToken, SurfaceUserImplementation};
|
||||||
|
use smithay::shell::{PopupConfigure, ShellSurfaceRole, ShellSurfaceUserImplementation, ToplevelConfigure};
|
||||||
|
use smithay::shm::with_buffer_contents;
|
||||||
|
|
||||||
|
define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SurfaceData {
|
||||||
|
pub buffer: Option<(Vec<u8>, (u32, u32))>,
|
||||||
|
pub location: Option<(i32, i32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn surface_implementation() -> SurfaceUserImplementation<SurfaceData, Roles, ()> {
|
||||||
|
SurfaceUserImplementation {
|
||||||
|
commit: |_, _, surface, token| {
|
||||||
|
// we retrieve the contents of the associated buffer and copy it
|
||||||
|
token.with_surface_data(surface, |attributes| {
|
||||||
|
match attributes.buffer.take() {
|
||||||
|
Some(Some((buffer, (_x, _y)))) => {
|
||||||
|
// we ignore hotspot coordinates in this simple example
|
||||||
|
with_buffer_contents(&buffer, |slice, data| {
|
||||||
|
let offset = data.offset as usize;
|
||||||
|
let stride = data.stride as usize;
|
||||||
|
let width = data.width as usize;
|
||||||
|
let height = data.height as usize;
|
||||||
|
let mut new_vec = Vec::with_capacity(width * height * 4);
|
||||||
|
for i in 0..height {
|
||||||
|
new_vec.extend(
|
||||||
|
&slice[(offset + i * stride)..(offset + i * stride + width * 4)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
attributes.user_data.buffer =
|
||||||
|
Some((new_vec, (data.width as u32, data.height as u32)));
|
||||||
|
}).unwrap();
|
||||||
|
buffer.release();
|
||||||
|
}
|
||||||
|
Some(None) => {
|
||||||
|
// erase the contents
|
||||||
|
attributes.user_data.buffer = None;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
frame: |_, _, _, callback, _| {
|
||||||
|
callback.done(0);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shell_implementation(
|
||||||
|
)
|
||||||
|
-> ShellSurfaceUserImplementation<SurfaceData, Roles, (), CompositorToken<SurfaceData, Roles, ()>, ()>
|
||||||
|
{
|
||||||
|
ShellSurfaceUserImplementation {
|
||||||
|
new_client: |_, _, _| {},
|
||||||
|
client_pong: |_, _, _| {},
|
||||||
|
new_toplevel: |_, token, toplevel| {
|
||||||
|
let wl_surface = toplevel.get_surface().unwrap();
|
||||||
|
token.with_surface_data(wl_surface, |data| {
|
||||||
|
// place the window at a random location in the [0;300]x[0;300] square
|
||||||
|
use rand::distributions::{IndependentSample, Range};
|
||||||
|
let range = Range::new(0, 300);
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let x = range.ind_sample(&mut rng);
|
||||||
|
let y = range.ind_sample(&mut rng);
|
||||||
|
data.user_data.location = Some((x, y))
|
||||||
|
});
|
||||||
|
ToplevelConfigure {
|
||||||
|
size: None,
|
||||||
|
states: vec![],
|
||||||
|
serial: 42,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new_popup: |_, _, _| {
|
||||||
|
PopupConfigure {
|
||||||
|
size: (10, 10),
|
||||||
|
position: (10, 10),
|
||||||
|
serial: 42,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
move_: |_, _, _, _, _| {},
|
||||||
|
resize: |_, _, _, _, _, _| {},
|
||||||
|
grab: |_, _, _, _, _| {},
|
||||||
|
change_display_state: |_, _, _, _, _, _, _| {
|
||||||
|
ToplevelConfigure {
|
||||||
|
size: None,
|
||||||
|
states: vec![],
|
||||||
|
serial: 42,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show_window_menu: |_, _, _, _, _, _, _| {},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
mod glium;
|
mod glium;
|
||||||
|
mod implementations;
|
||||||
|
|
||||||
pub use self::glium::GliumDrawer;
|
pub use self::glium::GliumDrawer;
|
||||||
|
pub use self::implementations::*;
|
||||||
|
|
|
@ -13,151 +13,15 @@ extern crate wayland_server;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
use glium::Surface;
|
use glium::Surface;
|
||||||
|
use helpers::{shell_implementation, surface_implementation, GliumDrawer};
|
||||||
use helpers::GliumDrawer;
|
|
||||||
use slog::{Drain, Logger};
|
use slog::{Drain, Logger};
|
||||||
|
|
||||||
use smithay::backend::graphics::glium::IntoGlium;
|
use smithay::backend::graphics::glium::IntoGlium;
|
||||||
use smithay::backend::input::InputBackend;
|
use smithay::backend::input::InputBackend;
|
||||||
use smithay::backend::winit;
|
use smithay::backend::winit;
|
||||||
use smithay::compositor::{self, CompositorHandler, CompositorToken, SubsurfaceRole, TraversalAction};
|
use smithay::compositor::{compositor_init, SubsurfaceRole, TraversalAction};
|
||||||
use smithay::compositor::roles::Role;
|
use smithay::compositor::roles::Role;
|
||||||
use smithay::shell::{self, PopupConfigure, PopupSurface, ShellClient, ShellHandler, ShellSurfaceRole,
|
use smithay::shell::shell_init;
|
||||||
ToplevelConfigure, ToplevelSurface};
|
use smithay::shm::init_shm_global;
|
||||||
use smithay::shm::{ShmGlobal, ShmToken};
|
|
||||||
|
|
||||||
use wayland_protocols::unstable::xdg_shell::server::{zxdg_shell_v6, zxdg_toplevel_v6};
|
|
||||||
|
|
||||||
use wayland_server::{Client, EventLoopHandle};
|
|
||||||
use wayland_server::protocol::{wl_callback, wl_compositor, wl_output, wl_seat, wl_shell, wl_shm,
|
|
||||||
wl_subcompositor, wl_surface};
|
|
||||||
|
|
||||||
define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );
|
|
||||||
|
|
||||||
struct SurfaceHandler {
|
|
||||||
shm_token: ShmToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct SurfaceData {
|
|
||||||
buffer: Option<(Vec<u8>, (u32, u32))>,
|
|
||||||
location: Option<(i32, i32)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl compositor::Handler<SurfaceData, Roles> for SurfaceHandler {
|
|
||||||
fn commit(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, surface: &wl_surface::WlSurface,
|
|
||||||
token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
|
|
||||||
// we retrieve the contents of the associated buffer and copy it
|
|
||||||
token.with_surface_data(surface, |attributes| {
|
|
||||||
match attributes.buffer.take() {
|
|
||||||
Some(Some((buffer, (_x, _y)))) => {
|
|
||||||
// we ignore hotspot coordinates in this simple example
|
|
||||||
self.shm_token
|
|
||||||
.with_buffer_contents(&buffer, |slice, data| {
|
|
||||||
let offset = data.offset as usize;
|
|
||||||
let stride = data.stride as usize;
|
|
||||||
let width = data.width as usize;
|
|
||||||
let height = data.height as usize;
|
|
||||||
let mut new_vec = Vec::with_capacity(width * height * 4);
|
|
||||||
for i in 0..height {
|
|
||||||
new_vec.extend(
|
|
||||||
&slice[(offset + i * stride)..(offset + i * stride + width * 4)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
attributes.user_data.buffer =
|
|
||||||
Some((new_vec, (data.width as u32, data.height as u32)));
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
buffer.release();
|
|
||||||
}
|
|
||||||
Some(None) => {
|
|
||||||
// erase the contents
|
|
||||||
attributes.user_data.buffer = None;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, surface: &wl_surface::WlSurface,
|
|
||||||
callback: wl_callback::WlCallback, _token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
|
|
||||||
callback.done(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ShellSurfaceHandler {
|
|
||||||
token: CompositorToken<SurfaceData, Roles, SurfaceHandler>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShellSurfaceHandler {
|
|
||||||
fn new(token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) -> ShellSurfaceHandler {
|
|
||||||
ShellSurfaceHandler { token }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl shell::Handler<SurfaceData, Roles, SurfaceHandler, ()> for ShellSurfaceHandler {
|
|
||||||
fn new_client(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
|
|
||||||
fn client_pong(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
|
|
||||||
fn new_toplevel(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>)
|
|
||||||
-> ToplevelConfigure {
|
|
||||||
let wl_surface = surface.get_surface().unwrap();
|
|
||||||
self.token.with_surface_data(wl_surface, |data| {
|
|
||||||
// place the window at a random location in the [0;300]x[0;300] square
|
|
||||||
use rand::distributions::{IndependentSample, Range};
|
|
||||||
let range = Range::new(0, 300);
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let x = range.ind_sample(&mut rng);
|
|
||||||
let y = range.ind_sample(&mut rng);
|
|
||||||
data.user_data.location = Some((x, y))
|
|
||||||
});
|
|
||||||
ToplevelConfigure {
|
|
||||||
size: None,
|
|
||||||
states: vec![],
|
|
||||||
serial: 42,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn new_popup(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>)
|
|
||||||
-> PopupConfigure {
|
|
||||||
PopupConfigure {
|
|
||||||
size: (10, 10),
|
|
||||||
position: (10, 10),
|
|
||||||
serial: 42,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn move_(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
|
|
||||||
_serial: u32) {
|
|
||||||
}
|
|
||||||
fn resize(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
|
|
||||||
_serial: u32, _edges: zxdg_toplevel_v6::ResizeEdge) {
|
|
||||||
}
|
|
||||||
fn grab(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
|
|
||||||
_serial: u32) {
|
|
||||||
}
|
|
||||||
fn change_display_state(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
|
|
||||||
_maximized: Option<bool>, _minimized: Option<bool>, _fullscreen: Option<bool>,
|
|
||||||
_output: Option<&wl_output::WlOutput>)
|
|
||||||
-> ToplevelConfigure {
|
|
||||||
ToplevelConfigure {
|
|
||||||
size: None,
|
|
||||||
states: vec![],
|
|
||||||
serial: 42,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn show_window_menu(&mut self, _evlh: &mut EventLoopHandle,
|
|
||||||
_surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
|
|
||||||
_seat: &wl_seat::WlSeat, _serial: u32, _x: i32, _y: i32) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type MyCompositorHandler = CompositorHandler<SurfaceData, Roles, SurfaceHandler>;
|
|
||||||
type MyShellHandler = ShellHandler<SurfaceData, Roles, SurfaceHandler, ShellSurfaceHandler, ()>;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// A logger facility, here we use the terminal for this example
|
// A logger facility, here we use the terminal for this example
|
||||||
|
@ -172,51 +36,21 @@ fn main() {
|
||||||
let (mut display, mut event_loop) = wayland_server::create_display();
|
let (mut display, mut event_loop) = wayland_server::create_display();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize wl_shm global
|
* Initialize the globals
|
||||||
*/
|
*/
|
||||||
// Insert the ShmGlobal as a handler to your event loop
|
|
||||||
// Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported.
|
|
||||||
let shm_handler_id = event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone()));
|
|
||||||
// Register this handler to advertise a wl_shm global of version 1
|
|
||||||
event_loop.register_global::<wl_shm::WlShm, ShmGlobal>(shm_handler_id, 1);
|
|
||||||
// retreive the token
|
|
||||||
let shm_token = {
|
|
||||||
let state = event_loop.state();
|
|
||||||
state.get_handler::<ShmGlobal>(shm_handler_id).get_token()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
init_shm_global(&mut event_loop, vec![], log.clone());
|
||||||
|
|
||||||
/*
|
let (compositor_token, _, _) =
|
||||||
* Initialize the compositor global
|
compositor_init(&mut event_loop, surface_implementation(), (), log.clone());
|
||||||
*/
|
|
||||||
let compositor_handler_id = event_loop.add_handler_with_init(MyCompositorHandler::new(
|
|
||||||
SurfaceHandler {
|
|
||||||
shm_token: shm_token.clone(),
|
|
||||||
},
|
|
||||||
log.clone(),
|
|
||||||
));
|
|
||||||
// register it to handle wl_compositor and wl_subcompositor
|
|
||||||
event_loop.register_global::<wl_compositor::WlCompositor, MyCompositorHandler>(compositor_handler_id, 4);
|
|
||||||
event_loop
|
|
||||||
.register_global::<wl_subcompositor::WlSubcompositor, MyCompositorHandler>(compositor_handler_id, 1);
|
|
||||||
// retrieve the tokens
|
|
||||||
let compositor_token = {
|
|
||||||
let state = event_loop.state();
|
|
||||||
state
|
|
||||||
.get_handler::<MyCompositorHandler>(compositor_handler_id)
|
|
||||||
.get_token()
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
let (shell_state_token, _, _) = shell_init(
|
||||||
* Initialize the shell global
|
&mut event_loop,
|
||||||
*/
|
compositor_token,
|
||||||
let shell_handler_id = event_loop.add_handler_with_init(MyShellHandler::new(
|
shell_implementation(),
|
||||||
ShellSurfaceHandler::new(compositor_token),
|
|
||||||
compositor_token,
|
compositor_token,
|
||||||
log.clone(),
|
log.clone(),
|
||||||
));
|
);
|
||||||
event_loop.register_global::<wl_shell::WlShell, MyShellHandler>(shell_handler_id, 1);
|
|
||||||
event_loop.register_global::<zxdg_shell_v6::ZxdgShellV6, MyShellHandler>(shell_handler_id, 1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize glium
|
* Initialize glium
|
||||||
|
@ -240,10 +74,7 @@ fn main() {
|
||||||
{
|
{
|
||||||
let screen_dimensions = context.get_framebuffer_dimensions();
|
let screen_dimensions = context.get_framebuffer_dimensions();
|
||||||
let state = event_loop.state();
|
let state = event_loop.state();
|
||||||
for toplevel_surface in state
|
for toplevel_surface in state.get(&shell_state_token).toplevel_surfaces() {
|
||||||
.get_handler::<MyShellHandler>(shell_handler_id)
|
|
||||||
.toplevel_surfaces()
|
|
||||||
{
|
|
||||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||||
// this surface is a root of a subsurface tree that needs to be drawn
|
// this surface is a root of a subsurface tree that needs to be drawn
|
||||||
let initial_place = compositor_token
|
let initial_place = compositor_token
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use super::{CompositorHandler, Handler as UserHandler, Role, RoleType, SubsurfaceRole};
|
|
||||||
|
|
||||||
use wayland_server::{Client, EventLoopHandle, GlobalHandler};
|
|
||||||
use wayland_server::protocol::{wl_compositor, wl_subcompositor};
|
|
||||||
|
|
||||||
impl<U, R, H> GlobalHandler<wl_compositor::WlCompositor> for CompositorHandler<U, R, H>
|
|
||||||
where
|
|
||||||
U: Default + Send + 'static,
|
|
||||||
R: Default + Send + 'static,
|
|
||||||
H: UserHandler<U, R> + Send + 'static,
|
|
||||||
{
|
|
||||||
fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) {
|
|
||||||
debug!(self.log, "New compositor global binded.");
|
|
||||||
evlh.register::<_, CompositorHandler<U, R, H>>(&global, self.my_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<U, R, H> GlobalHandler<wl_subcompositor::WlSubcompositor> for CompositorHandler<U, R, H>
|
|
||||||
where
|
|
||||||
U: Send + 'static,
|
|
||||||
R: RoleType + Role<SubsurfaceRole> + Send + 'static,
|
|
||||||
H: Send + 'static,
|
|
||||||
{
|
|
||||||
fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) {
|
|
||||||
debug!(self.log, "New subcompositor global binded.");
|
|
||||||
evlh.register::<_, CompositorHandler<U, R, H>>(&global, self.my_id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +1,101 @@
|
||||||
use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, RectangleKind, Role, RoleType,
|
use super::{CompositorToken, Damage, Rectangle, RectangleKind, Role, RoleType, SubsurfaceRole,
|
||||||
SubsurfaceRole};
|
SurfaceUserImplementation};
|
||||||
use super::region::RegionData;
|
use super::region::RegionData;
|
||||||
use super::tree::{Location, SurfaceData};
|
use super::tree::{Location, SurfaceData};
|
||||||
use wayland_server::{Client, Destroy, EventLoopHandle, Liveness, Resource};
|
use std::cell::RefCell;
|
||||||
use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region,
|
use std::rc::Rc;
|
||||||
wl_subcompositor, wl_subsurface, wl_surface};
|
use wayland_server::{Client, EventLoopHandle, Liveness, Resource};
|
||||||
|
use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface};
|
||||||
struct CompositorDestructor<U, R> {
|
|
||||||
_t: ::std::marker::PhantomData<U>,
|
|
||||||
_r: ::std::marker::PhantomData<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_compositor
|
* wl_compositor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<U, R, H> wl_compositor::Handler for CompositorHandler<U, R, H>
|
pub(crate) fn compositor_bind<U, R, ID>(evlh: &mut EventLoopHandle, idata: &mut SurfaceIData<U, R, ID>,
|
||||||
|
_: &Client, compositor: wl_compositor::WlCompositor)
|
||||||
where
|
where
|
||||||
U: Default + Send + 'static,
|
U: Default + 'static,
|
||||||
R: Default + Send + 'static,
|
R: Default + 'static,
|
||||||
H: UserHandler<U, R> + Send + 'static,
|
ID: 'static,
|
||||||
{
|
{
|
||||||
fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor,
|
trace!(idata.log, "Binding a new wl_compositor.");
|
||||||
id: wl_surface::WlSurface) {
|
evlh.register(
|
||||||
trace!(self.log, "New surface created.");
|
&compositor,
|
||||||
unsafe { SurfaceData::<U, R>::init(&id) };
|
compositor_implementation::<U, R, ID>(),
|
||||||
evqh.register_with_destructor::<_, CompositorHandler<U, R, H>, CompositorDestructor<U, R>>(
|
idata.clone(),
|
||||||
&id,
|
None,
|
||||||
self.my_id,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn create_region(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor,
|
|
||||||
id: wl_region::WlRegion) {
|
|
||||||
trace!(self.log, "New region created.");
|
|
||||||
unsafe { RegionData::init(&id) };
|
|
||||||
evqh.register_with_destructor::<_, CompositorHandler<U, R, H>, CompositorDestructor<U, R>>(
|
|
||||||
&id,
|
|
||||||
self.my_id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server_declare_handler!(CompositorHandler<U: [Default, Send], R: [Default, Send], H: [UserHandler<U, R>, Send]>, wl_compositor::Handler, wl_compositor::WlCompositor);
|
fn compositor_implementation<U, R, ID>() -> wl_compositor::Implementation<SurfaceIData<U, R, ID>>
|
||||||
|
where
|
||||||
|
U: Default + 'static,
|
||||||
|
R: Default + 'static,
|
||||||
|
ID: 'static,
|
||||||
|
{
|
||||||
|
wl_compositor::Implementation {
|
||||||
|
create_surface: |evlh, idata, _, _, surface| {
|
||||||
|
unsafe { SurfaceData::<U, R>::init(&surface) };
|
||||||
|
evlh.register(
|
||||||
|
&surface,
|
||||||
|
surface_implementation::<U, R, ID>(),
|
||||||
|
idata.clone(),
|
||||||
|
Some(destroy_surface::<U, R>),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
create_region: |evlh, _, _, _, region| {
|
||||||
|
unsafe { RegionData::init(®ion) };
|
||||||
|
evlh.register(®ion, region_implementation(), (), Some(destroy_region));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_surface
|
* wl_surface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<U, R, H: UserHandler<U, R>> wl_surface::Handler for CompositorHandler<U, R, H> {
|
/// Internal implementation data of surfaces
|
||||||
fn attach(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface,
|
///
|
||||||
buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) {
|
/// This type is only visible as type parameter of
|
||||||
trace!(self.log, "Attaching buffer to surface.");
|
/// the `Global` handle you are provided.
|
||||||
unsafe {
|
pub struct SurfaceIData<U, R, ID> {
|
||||||
|
log: ::slog::Logger,
|
||||||
|
implem: SurfaceUserImplementation<U, R, ID>,
|
||||||
|
idata: Rc<RefCell<ID>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U, R, ID> SurfaceIData<U, R, ID> {
|
||||||
|
pub(crate) fn make(log: ::slog::Logger, implem: SurfaceUserImplementation<U, R, ID>, idata: ID)
|
||||||
|
-> SurfaceIData<U, R, ID> {
|
||||||
|
SurfaceIData {
|
||||||
|
log: log,
|
||||||
|
implem: implem,
|
||||||
|
idata: Rc::new(RefCell::new(idata)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U, R, ID> Clone for SurfaceIData<U, R, ID> {
|
||||||
|
fn clone(&self) -> SurfaceIData<U, R, ID> {
|
||||||
|
SurfaceIData {
|
||||||
|
log: self.log.clone(),
|
||||||
|
implem: self.implem.clone(),
|
||||||
|
idata: self.idata.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn surface_implementation<U: 'static, R: 'static, ID: 'static>(
|
||||||
|
)
|
||||||
|
-> wl_surface::Implementation<SurfaceIData<U, R, ID>>
|
||||||
|
{
|
||||||
|
wl_surface::Implementation {
|
||||||
|
attach: |_, _, _, surface, buffer, x, y| unsafe {
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| {
|
SurfaceData::<U, R>::with_data(surface, |d| {
|
||||||
d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y))))
|
d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y))))
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
damage: |_, _, _, surface, x, y, width, height| unsafe {
|
||||||
fn damage(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32,
|
|
||||||
y: i32, width: i32, height: i32) {
|
|
||||||
trace!(self.log, "Registering damage to surface.");
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| {
|
SurfaceData::<U, R>::with_data(surface, |d| {
|
||||||
d.damage = Damage::Surface(Rectangle {
|
d.damage = Damage::Surface(Rectangle {
|
||||||
x,
|
x,
|
||||||
|
@ -69,56 +104,38 @@ impl<U, R, H: UserHandler<U, R>> wl_surface::Handler for CompositorHandler<U, R,
|
||||||
height,
|
height,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
frame: |evlh, idata, _, surface, callback| {
|
||||||
fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface,
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
callback: wl_callback::WlCallback) {
|
trace!(idata.log, "Calling user callback for wl_surface.frame");
|
||||||
trace!(self.log, "Frame surface callback.");
|
(idata.implem.frame)(
|
||||||
let token = self.get_token();
|
evlh,
|
||||||
UserHandler::frame(&mut self.handler, evlh, client, surface, callback, token);
|
&mut *user_idata,
|
||||||
}
|
surface,
|
||||||
fn set_opaque_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface,
|
callback,
|
||||||
region: Option<&wl_region::WlRegion>) {
|
CompositorToken::make(),
|
||||||
trace!(self.log, "Setting surface opaque region.");
|
)
|
||||||
unsafe {
|
},
|
||||||
|
set_opaque_region: |_, _, _, surface, region| unsafe {
|
||||||
let attributes = region.map(|r| RegionData::get_attributes(r));
|
let attributes = region.map(|r| RegionData::get_attributes(r));
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| d.opaque_region = attributes);
|
SurfaceData::<U, R>::with_data(surface, |d| d.opaque_region = attributes);
|
||||||
}
|
},
|
||||||
}
|
set_input_region: |_, _, _, surface, region| unsafe {
|
||||||
fn set_input_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface,
|
|
||||||
region: Option<&wl_region::WlRegion>) {
|
|
||||||
trace!(self.log, "Setting surface input region.");
|
|
||||||
unsafe {
|
|
||||||
let attributes = region.map(|r| RegionData::get_attributes(r));
|
let attributes = region.map(|r| RegionData::get_attributes(r));
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| d.input_region = attributes);
|
SurfaceData::<U, R>::with_data(surface, |d| d.input_region = attributes);
|
||||||
}
|
},
|
||||||
}
|
commit: |evlh, idata, _, surface| {
|
||||||
fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) {
|
let mut user_idata = idata.idata.borrow_mut();
|
||||||
trace!(self.log, "Commit surface callback.");
|
trace!(idata.log, "Calling user callback for wl_surface.commit");
|
||||||
let token = self.get_token();
|
(idata.implem.commit)(evlh, &mut *user_idata, surface, CompositorToken::make())
|
||||||
UserHandler::commit(&mut self.handler, evlh, client, surface, token);
|
},
|
||||||
}
|
set_buffer_transform: |_, _, _, surface, transform| unsafe {
|
||||||
fn set_buffer_transform(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
surface: &wl_surface::WlSurface, transform: wl_output::Transform) {
|
|
||||||
trace!(self.log, "Setting surface's buffer transform.");
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| d.buffer_transform = transform);
|
SurfaceData::<U, R>::with_data(surface, |d| d.buffer_transform = transform);
|
||||||
}
|
},
|
||||||
}
|
set_buffer_scale: |_, _, _, surface, scale| unsafe {
|
||||||
fn set_buffer_scale(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface,
|
|
||||||
scale: i32) {
|
|
||||||
trace!(self.log, "Setting surface's buffer scale.");
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| d.buffer_scale = scale);
|
SurfaceData::<U, R>::with_data(surface, |d| d.buffer_scale = scale);
|
||||||
}
|
},
|
||||||
}
|
damage_buffer: |_, _, _, surface, x, y, width, height| unsafe {
|
||||||
fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface,
|
|
||||||
x: i32, y: i32, width: i32, height: i32) {
|
|
||||||
trace!(
|
|
||||||
self.log,
|
|
||||||
"Registering damage to surface (buffer coordinates)."
|
|
||||||
);
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(surface, |d| {
|
SurfaceData::<U, R>::with_data(surface, |d| {
|
||||||
d.damage = Damage::Buffer(Rectangle {
|
d.damage = Damage::Buffer(Rectangle {
|
||||||
x,
|
x,
|
||||||
|
@ -127,26 +144,22 @@ impl<U, R, H: UserHandler<U, R>> wl_surface::Handler for CompositorHandler<U, R,
|
||||||
height,
|
height,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
destroy: |_, _, _, _| {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(CompositorHandler<U:[], R: [], H: [UserHandler<U, R>]>, wl_surface::Handler, wl_surface::WlSurface);
|
fn destroy_surface<U: 'static, R: 'static>(surface: &wl_surface::WlSurface) {
|
||||||
|
|
||||||
impl<U, R> Destroy<wl_surface::WlSurface> for CompositorDestructor<U, R> {
|
|
||||||
fn destroy(surface: &wl_surface::WlSurface) {
|
|
||||||
unsafe { SurfaceData::<U, R>::cleanup(surface) }
|
unsafe { SurfaceData::<U, R>::cleanup(surface) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_region
|
* wl_region
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<U, R, H> wl_region::Handler for CompositorHandler<U, R, H> {
|
pub(crate) fn region_implementation() -> wl_region::Implementation<()> {
|
||||||
fn add(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32,
|
wl_region::Implementation {
|
||||||
width: i32, height: i32) {
|
add: |_, _, _, region, x, y, width, height| {
|
||||||
trace!(self.log, "Adding rectangle to a region.");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
RegionData::add_rectangle(
|
RegionData::add_rectangle(
|
||||||
region,
|
region,
|
||||||
|
@ -159,10 +172,8 @@ impl<U, R, H> wl_region::Handler for CompositorHandler<U, R, H> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
fn subtract(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32,
|
subtract: |_, _, _, region, x, y, width, height| {
|
||||||
y: i32, width: i32, height: i32) {
|
|
||||||
trace!(self.log, "Subtracting rectangle to a region.");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
RegionData::add_rectangle(
|
RegionData::add_rectangle(
|
||||||
region,
|
region,
|
||||||
|
@ -175,50 +186,61 @@ impl<U, R, H> wl_region::Handler for CompositorHandler<U, R, H> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
destroy: |_, _, _, _| {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(CompositorHandler<U: [], R: [], H: []>, wl_region::Handler, wl_region::WlRegion);
|
fn destroy_region(region: &wl_region::WlRegion) {
|
||||||
|
|
||||||
impl<U, R> Destroy<wl_region::WlRegion> for CompositorDestructor<U, R> {
|
|
||||||
fn destroy(region: &wl_region::WlRegion) {
|
|
||||||
unsafe { RegionData::cleanup(region) };
|
unsafe { RegionData::cleanup(region) };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_subcompositor
|
* wl_subcompositor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<U, R, H> wl_subcompositor::Handler for CompositorHandler<U, R, H>
|
pub(crate) fn subcompositor_bind<U, R>(evlh: &mut EventLoopHandle, _: &mut (), _: &Client,
|
||||||
|
subcompositor: wl_subcompositor::WlSubcompositor)
|
||||||
where
|
where
|
||||||
U: Send + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
R: RoleType + Role<SubsurfaceRole> + Send + 'static,
|
U: 'static,
|
||||||
H: Send + 'static,
|
|
||||||
{
|
{
|
||||||
fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client,
|
evlh.register(
|
||||||
resource: &wl_subcompositor::WlSubcompositor, id: wl_subsurface::WlSubsurface,
|
&subcompositor,
|
||||||
surface: &wl_surface::WlSurface, parent: &wl_surface::WlSurface) {
|
subcompositor_implementation::<U, R>(),
|
||||||
trace!(self.log, "Creating new subsurface.");
|
(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subcompositor_implementation<U, R>() -> wl_subcompositor::Implementation<()>
|
||||||
|
where
|
||||||
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
|
U: 'static,
|
||||||
|
{
|
||||||
|
wl_subcompositor::Implementation {
|
||||||
|
get_subsurface: |evlh, _, _, subcompositor, subsurface, surface, parent| {
|
||||||
if let Err(()) = unsafe { SurfaceData::<U, R>::set_parent(surface, parent) } {
|
if let Err(()) = unsafe { SurfaceData::<U, R>::set_parent(surface, parent) } {
|
||||||
resource.post_error(
|
subcompositor.post_error(
|
||||||
wl_subcompositor::Error::BadSurface as u32,
|
wl_subcompositor::Error::BadSurface as u32,
|
||||||
"Surface already has a role.".into(),
|
"Surface already has a role.".into(),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
id.set_user_data(
|
subsurface.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 _,
|
||||||
);
|
);
|
||||||
evqh.register_with_destructor::<_, CompositorHandler<U, R, H>, CompositorDestructor<U, R>>(
|
evlh.register(
|
||||||
&id,
|
&subsurface,
|
||||||
self.my_id,
|
subsurface_implementation::<U, R>(),
|
||||||
|
(),
|
||||||
|
Some(destroy_subsurface::<U, R>),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
destroy: |_, _, _, _| {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(CompositorHandler<U: [Send], R: [RoleType, Role<SubsurfaceRole>, Send], H: [Send]>, wl_subcompositor::Handler, wl_subcompositor::WlSubcompositor);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_subsurface
|
* wl_subsurface
|
||||||
*/
|
*/
|
||||||
|
@ -226,7 +248,8 @@ server_declare_handler!(CompositorHandler<U: [Send], R: [RoleType, Role<Subsurfa
|
||||||
unsafe fn with_subsurface_attributes<U, R, F>(subsurface: &wl_subsurface::WlSubsurface, f: F)
|
unsafe fn with_subsurface_attributes<U, R, F>(subsurface: &wl_subsurface::WlSubsurface, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut SubsurfaceRole),
|
F: FnOnce(&mut SubsurfaceRole),
|
||||||
R: RoleType + Role<SubsurfaceRole>,
|
U: 'static,
|
||||||
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
{
|
{
|
||||||
let ptr = subsurface.get_user_data();
|
let ptr = subsurface.get_user_data();
|
||||||
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
||||||
|
@ -235,24 +258,19 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H> wl_subsurface::Handler for CompositorHandler<U, R, H>
|
fn subsurface_implementation<U, R>() -> wl_subsurface::Implementation<()>
|
||||||
where
|
where
|
||||||
R: RoleType + Role<SubsurfaceRole>,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
|
U: 'static,
|
||||||
{
|
{
|
||||||
fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client,
|
wl_subsurface::Implementation {
|
||||||
subsurface: &wl_subsurface::WlSubsurface, x: i32, y: i32) {
|
set_position: |_, _, _, subsurface, x, y| unsafe {
|
||||||
trace!(self.log, "Setting subsurface position.");
|
|
||||||
unsafe {
|
|
||||||
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| {
|
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| {
|
||||||
attrs.x = x;
|
attrs.x = x;
|
||||||
attrs.y = y;
|
attrs.y = y;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
place_above: |_, _, _, subsurface, sibling| unsafe {
|
||||||
fn place_above(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) {
|
|
||||||
trace!(self.log, "Setting subsurface above an other.");
|
|
||||||
unsafe {
|
|
||||||
let ptr = subsurface.get_user_data();
|
let ptr = subsurface.get_user_data();
|
||||||
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
||||||
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::After, sibling) {
|
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::After, sibling) {
|
||||||
|
@ -261,12 +279,8 @@ where
|
||||||
"Provided surface is not a sibling or parent.".into(),
|
"Provided surface is not a sibling or parent.".into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
place_below: |_, _, _, subsurface, sibling| unsafe {
|
||||||
fn place_below(&mut self, _: &mut EventLoopHandle, _: &Client,
|
|
||||||
subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) {
|
|
||||||
trace!(self.log, "Setting subsurface below an other.");
|
|
||||||
unsafe {
|
|
||||||
let ptr = subsurface.get_user_data();
|
let ptr = subsurface.get_user_data();
|
||||||
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
let surface = &*(ptr as *mut wl_surface::WlSurface);
|
||||||
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::Before, sibling) {
|
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::Before, sibling) {
|
||||||
|
@ -275,29 +289,26 @@ where
|
||||||
"Provided surface is not a sibling or parent.".into(),
|
"Provided surface is not a sibling or parent.".into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
set_sync: |_, _, _, subsurface| unsafe {
|
||||||
fn set_sync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) {
|
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| {
|
||||||
trace!(self.log, "Setting subsurface sync."; "sync_status" => true);
|
attrs.sync = true;
|
||||||
unsafe {
|
});
|
||||||
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| { attrs.sync = true; });
|
},
|
||||||
}
|
set_desync: |_, _, _, subsurface| unsafe {
|
||||||
}
|
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| {
|
||||||
fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) {
|
attrs.sync = false;
|
||||||
trace!(self.log, "Setting subsurface sync."; "sync_status" => false);
|
});
|
||||||
unsafe {
|
},
|
||||||
with_subsurface_attributes::<U, R, _>(subsurface, |attrs| { attrs.sync = false; });
|
destroy: |_, _, _, _| {},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_declare_handler!(CompositorHandler<U: [], R: [RoleType, Role<SubsurfaceRole>], H: []>, wl_subsurface::Handler, wl_subsurface::WlSubsurface);
|
fn destroy_subsurface<U, R>(subsurface: &wl_subsurface::WlSubsurface)
|
||||||
|
|
||||||
impl<U, R> Destroy<wl_subsurface::WlSubsurface> for CompositorDestructor<U, R>
|
|
||||||
where
|
where
|
||||||
R: RoleType + Role<SubsurfaceRole>,
|
U: 'static,
|
||||||
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
{
|
{
|
||||||
fn destroy(subsurface: &wl_subsurface::WlSubsurface) {
|
|
||||||
let ptr = subsurface.get_user_data();
|
let ptr = subsurface.get_user_data();
|
||||||
subsurface.set_user_data(::std::ptr::null_mut());
|
subsurface.set_user_data(::std::ptr::null_mut());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -307,4 +318,3 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
//! Utilities for handling surfaces, subsurfaces and regions
|
//! Utilities for handling surfaces, subsurfaces and regions
|
||||||
//!
|
//!
|
||||||
//! This module provides the `CompositorHandler<U,H>` type, with implements
|
//! This module provides automatic handling of sufaces, subsurfaces
|
||||||
//! automatic handling of sufaces, subsurfaces and region wayland objects,
|
//! and region wayland objects, by registering an implementation for
|
||||||
//! by being registered as a global handler for `wl_compositor` and
|
//! for the `wl_compositor` and `wl_subcompositor` globals.
|
||||||
//! `wl_subcompositor`.
|
|
||||||
//!
|
//!
|
||||||
//! ## Why use this handler
|
//! ## Why use this implementation
|
||||||
//!
|
//!
|
||||||
//! This handler does a simple job: it stores in a coherent way the state of
|
//! This implementation does a simple job: it stores in a coherent way the state of
|
||||||
//! surface trees with subsurfaces, to provide you a direct access to the tree
|
//! surface trees with subsurfaces, to provide you a direct access to the tree
|
||||||
//! structure and all surface metadata.
|
//! structure and all surface metadata.
|
||||||
//!
|
//!
|
||||||
|
@ -15,7 +14,7 @@
|
||||||
//! you can iterate over the whole tree of subsurfaces to recover all the metadata you
|
//! you can iterate over the whole tree of subsurfaces to recover all the metadata you
|
||||||
//! need to display the subsurface tree.
|
//! need to display the subsurface tree.
|
||||||
//!
|
//!
|
||||||
//! This handler will not do anything more than present you the metadata specified by the
|
//! This implementation will not do anything more than present you the metadata specified by the
|
||||||
//! client in a coherent and practical way. All the logic regarding to drawing itself, and
|
//! client in a coherent and practical way. All the logic regarding to drawing itself, and
|
||||||
//! the positionning of windows (surface trees) one relative to another is out of its scope.
|
//! the positionning of windows (surface trees) one relative to another is out of its scope.
|
||||||
//!
|
//!
|
||||||
|
@ -23,15 +22,16 @@
|
||||||
//!
|
//!
|
||||||
//! ### Initialization
|
//! ### Initialization
|
||||||
//!
|
//!
|
||||||
//! To initialize this handler, simply instanciate it and register it to the event loop
|
//! To initialize this implementation, use the `compositor_init` method provided
|
||||||
//! as a global handler for wl_compositor and wl_subcompositor:
|
//! by this module. It'll require you to first define as few things, as shown in
|
||||||
|
//! this example:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # extern crate wayland_server;
|
//! # extern crate wayland_server;
|
||||||
//! # #[macro_use] extern crate smithay;
|
//! # #[macro_use] extern crate smithay;
|
||||||
//! use wayland_server::protocol::wl_compositor::WlCompositor;
|
//! use wayland_server::protocol::wl_compositor::WlCompositor;
|
||||||
//! use wayland_server::protocol::wl_subcompositor::WlSubcompositor;
|
//! use wayland_server::protocol::wl_subcompositor::WlSubcompositor;
|
||||||
//! use smithay::compositor;
|
//! use smithay::compositor::{compositor_init, SurfaceUserImplementation};
|
||||||
//!
|
//!
|
||||||
//! // Define some user data to be associated with the surfaces.
|
//! // Define some user data to be associated with the surfaces.
|
||||||
//! // It must implement the Default trait, which will represent the state of a surface which
|
//! // It must implement the Default trait, which will represent the state of a surface which
|
||||||
|
@ -44,39 +44,25 @@
|
||||||
//! // Declare the roles enum
|
//! // Declare the roles enum
|
||||||
//! define_roles!(MyRoles);
|
//! define_roles!(MyRoles);
|
||||||
//!
|
//!
|
||||||
//! // Define a sub-handler to take care of the events the CompositorHandler does not rack for you
|
|
||||||
//! struct MyHandler {
|
|
||||||
//! // whatever you need
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // Implement the handler trait for this sub-handler
|
|
||||||
//! impl compositor::Handler<MyData, MyRoles> for MyHandler {
|
|
||||||
//! // See the trait documentation for its implementation
|
|
||||||
//! // A default implementation for each method is provided, that does nothing
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // A type alias to shorten things:
|
|
||||||
//! type MyCompositorHandler = compositor::CompositorHandler<MyData, MyRoles, MyHandler>;
|
|
||||||
//!
|
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
||||||
|
//! // define your implementation for surface
|
||||||
|
//! let my_implementation = SurfaceUserImplementation {
|
||||||
|
//! commit: |evlh, idata, surface, token| { /* ... */ },
|
||||||
|
//! frame: |evlh, idata, surface, callback, token| { /* ... */ }
|
||||||
|
//! };
|
||||||
|
//! // define your implementation data
|
||||||
|
//! let my_implementation_data = ();
|
||||||
//!
|
//!
|
||||||
//! // Instanciate the CompositorHandler and give it to the event loop
|
//! // Call the init function:
|
||||||
//! let compositor_hid = event_loop.add_handler_with_init(
|
//! let (token, _, _) = compositor_init::<MyData, MyRoles, _, _>(
|
||||||
//! MyCompositorHandler::new(MyHandler{ /* ... */ }, None /* put a logger here */)
|
//! &mut event_loop,
|
||||||
|
//! my_implementation, // instance of compositor::SurfaceUserImplementation
|
||||||
|
//! my_implementation_data, // whatever implementation data you need
|
||||||
|
//! None // put a logger here
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
//! // Register it as a handler for wl_compositor
|
//! // this `token` is what you'll use to access the surface associated data
|
||||||
//! event_loop.register_global::<WlCompositor, MyCompositorHandler>(compositor_hid, 4);
|
|
||||||
//!
|
|
||||||
//! // Register it as a handler for wl_subcompositor
|
|
||||||
//! event_loop.register_global::<WlSubcompositor, MyCompositorHandler>(compositor_hid, 1);
|
|
||||||
//!
|
|
||||||
//! // retrieve the token needed to access the surfaces' metadata
|
|
||||||
//! let compositor_token = {
|
|
||||||
//! let state = event_loop.state();
|
|
||||||
//! state.get_handler::<MyCompositorHandler>(compositor_hid).get_token()
|
|
||||||
//! };
|
|
||||||
//!
|
//!
|
||||||
//! // You're now ready to go!
|
//! // You're now ready to go!
|
||||||
//! # }
|
//! # }
|
||||||
|
@ -85,8 +71,9 @@
|
||||||
//! ### Use the surface metadata
|
//! ### Use the surface metadata
|
||||||
//!
|
//!
|
||||||
//! As you can see in the previous example, in the end we are retrieving a token from
|
//! As you can see in the previous example, in the end we are retrieving a token from
|
||||||
//! the `CompositorHandler`. This token is necessary to retrieve the metadata associated with
|
//! the init function. This token is necessary to retrieve the metadata associated with
|
||||||
//! a surface. It can be cloned, and is sendable accross threads. See `CompositorToken` for
|
//! a surface. It can be cloned, and is sendable accross threads (as long as your
|
||||||
|
//! `Mydata` and `MyRoles` are `Send` too). See `CompositorToken` for
|
||||||
//! the details of what it enables you.
|
//! the details of what it enables you.
|
||||||
//!
|
//!
|
||||||
//! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered
|
//! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered
|
||||||
|
@ -97,19 +84,19 @@
|
||||||
//! This `CompositorToken` also provides access to the metadata associated with the role of the
|
//! This `CompositorToken` also provides access to the metadata associated with the role of the
|
||||||
//! surfaces. See the documentation of the `roles` submodule for a detailed explanation.
|
//! surfaces. See the documentation of the `roles` submodule for a detailed explanation.
|
||||||
|
|
||||||
mod global;
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod tree;
|
mod tree;
|
||||||
mod region;
|
mod region;
|
||||||
pub mod roles;
|
pub mod roles;
|
||||||
|
|
||||||
|
pub use self::handlers::SurfaceIData;
|
||||||
use self::region::RegionData;
|
use self::region::RegionData;
|
||||||
use self::roles::{Role, RoleType, WrongRole};
|
use self::roles::{Role, RoleType, WrongRole};
|
||||||
use self::tree::SurfaceData;
|
use self::tree::SurfaceData;
|
||||||
pub use self::tree::TraversalAction;
|
pub use self::tree::TraversalAction;
|
||||||
use wayland_server::{resource_is_registered, Client, EventLoopHandle, Init};
|
use wayland_server::{resource_is_registered, EventLoop, EventLoopHandle, Global};
|
||||||
|
use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region,
|
||||||
use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_region, wl_surface};
|
wl_subcompositor, wl_surface};
|
||||||
|
|
||||||
/// Description of which part of a surface
|
/// Description of which part of a surface
|
||||||
/// should be considered damaged and needs to be redrawn
|
/// should be considered damaged and needs to be redrawn
|
||||||
|
@ -124,6 +111,12 @@ pub enum Damage {
|
||||||
Buffer(Rectangle),
|
Buffer(Rectangle),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
struct Marker<U, R> {
|
||||||
|
_u: ::std::marker::PhantomData<U>,
|
||||||
|
_r: ::std::marker::PhantomData<R>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Data associated with a surface, aggreged by the handlers
|
/// Data associated with a surface, aggreged by the handlers
|
||||||
///
|
///
|
||||||
/// Most of the fields of this struct represent a double-buffered state, which
|
/// Most of the fields of this struct represent a double-buffered state, which
|
||||||
|
@ -261,26 +254,35 @@ impl Default for RegionAttributes {
|
||||||
/// This token can be cloned at will, and is the entry-point to
|
/// This token can be cloned at will, and is the entry-point to
|
||||||
/// access data associated with the wl_surface and wl_region managed
|
/// access data associated with the wl_surface and wl_region managed
|
||||||
/// by the `CompositorGlobal` that provided it.
|
/// by the `CompositorGlobal` that provided it.
|
||||||
pub struct CompositorToken<U, R, H> {
|
pub struct CompositorToken<U, R, ID> {
|
||||||
hid: usize,
|
|
||||||
_data: ::std::marker::PhantomData<*mut U>,
|
_data: ::std::marker::PhantomData<*mut U>,
|
||||||
_role: ::std::marker::PhantomData<*mut R>,
|
_role: ::std::marker::PhantomData<*mut R>,
|
||||||
_handler: ::std::marker::PhantomData<*mut H>,
|
_idata: ::std::marker::PhantomData<*mut ID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<U: Send, R: Send, H: Send> Send for CompositorToken<U, R, H> {}
|
unsafe impl<U: Send, R: Send, ID> Send for CompositorToken<U, R, ID> {}
|
||||||
unsafe impl<U: Send, R: Send, H: Send> Sync for CompositorToken<U, R, H> {}
|
unsafe impl<U: Send, R: Send, ID> Sync for CompositorToken<U, R, ID> {}
|
||||||
|
|
||||||
// we implement them manually because #[derive(..)] would require
|
// we implement them manually because #[derive(..)] would require
|
||||||
// U: Clone and H: Clone ...
|
// U: Clone and R: Clone
|
||||||
impl<U, R, H> Copy for CompositorToken<U, R, H> {}
|
impl<U, R, ID> Copy for CompositorToken<U, R, ID> {}
|
||||||
impl<U, R, H> Clone for CompositorToken<U, R, H> {
|
impl<U, R, ID> Clone for CompositorToken<U, R, ID> {
|
||||||
fn clone(&self) -> CompositorToken<U, R, H> {
|
fn clone(&self) -> CompositorToken<U, R, ID> {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: Send + 'static, R: Send + 'static, H: Handler<U, R> + Send + 'static> CompositorToken<U, R, H> {
|
impl<U, R, ID> CompositorToken<U, R, ID> {
|
||||||
|
pub(crate) fn make() -> CompositorToken<U, R, ID> {
|
||||||
|
CompositorToken {
|
||||||
|
_data: ::std::marker::PhantomData,
|
||||||
|
_role: ::std::marker::PhantomData,
|
||||||
|
_idata: ::std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Send + 'static, R: Send + 'static, ID: 'static> CompositorToken<U, R, ID> {
|
||||||
/// Access the data of a surface
|
/// Access the data of a surface
|
||||||
///
|
///
|
||||||
/// The closure will be called with the contents of the data associated with this surface.
|
/// The closure will be called with the contents of the data associated with this surface.
|
||||||
|
@ -292,18 +294,21 @@ impl<U: Send + 'static, R: Send + 'static, H: Handler<U, R> + Send + 'static> Co
|
||||||
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::with_data(surface, f) }
|
unsafe { SurfaceData::<U, R>::with_data(surface, f) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, H> CompositorToken<U, R, H>
|
impl<U, R, ID> CompositorToken<U, R, ID>
|
||||||
where
|
where
|
||||||
U: Send + 'static,
|
U: 'static,
|
||||||
R: RoleType + Role<SubsurfaceRole> + Send + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
H: Handler<U, R> + Send + 'static,
|
ID: 'static,
|
||||||
{
|
{
|
||||||
/// Access the data of a surface tree
|
/// Access the data of a surface tree
|
||||||
///
|
///
|
||||||
|
@ -327,7 +332,10 @@ where
|
||||||
-> TraversalAction<T>,
|
-> TraversalAction<T>,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -344,7 +352,10 @@ where
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_parent(&self, surface: &wl_surface::WlSurface) -> Option<wl_surface::WlSurface> {
|
pub fn get_parent(&self, surface: &wl_surface::WlSurface) -> Option<wl_surface::WlSurface> {
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::get_parent(surface) }
|
unsafe { SurfaceData::<U, R>::get_parent(surface) }
|
||||||
|
@ -356,22 +367,27 @@ where
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_children(&self, surface: &wl_surface::WlSurface) -> Vec<wl_surface::WlSurface> {
|
pub fn get_children(&self, surface: &wl_surface::WlSurface) -> Vec<wl_surface::WlSurface> {
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::get_children(surface) }
|
unsafe { SurfaceData::<U, R>::get_children(surface) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send + 'static>
|
impl<U: 'static, R: RoleType + 'static, ID: 'static> CompositorToken<U, R, ID> {
|
||||||
CompositorToken<U, R, H> {
|
|
||||||
/// Check wether this surface as a role or not
|
/// Check wether this surface as a role or not
|
||||||
///
|
///
|
||||||
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn has_a_role(&self, surface: &wl_surface::WlSurface) -> bool {
|
pub fn has_a_role(&self, surface: &wl_surface::WlSurface) -> bool {
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::has_a_role(surface) }
|
unsafe { SurfaceData::<U, R>::has_a_role(surface) }
|
||||||
|
@ -386,7 +402,10 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::has_role::<RoleData>(surface) }
|
unsafe { SurfaceData::<U, R>::has_role::<RoleData>(surface) }
|
||||||
|
@ -405,7 +424,10 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
RoleData: Default,
|
RoleData: Default,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::give_role::<RoleData>(surface) }
|
unsafe { SurfaceData::<U, R>::give_role::<RoleData>(surface) }
|
||||||
|
@ -423,7 +445,10 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::give_role_with::<RoleData>(surface, data) }
|
unsafe { SurfaceData::<U, R>::give_role_with::<RoleData>(surface, data) }
|
||||||
|
@ -442,7 +467,10 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
F: FnOnce(&mut RoleData) -> T,
|
F: FnOnce(&mut RoleData) -> T,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::with_role_data::<RoleData, _, _>(surface, f) }
|
unsafe { SurfaceData::<U, R>::with_role_data::<RoleData, _, _>(surface, f) }
|
||||||
|
@ -459,7 +487,10 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(surface, self.hid),
|
resource_is_registered(
|
||||||
|
surface,
|
||||||
|
&self::handlers::surface_implementation::<U, R, ID>()
|
||||||
|
),
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { SurfaceData::<U, R>::remove_role::<RoleData>(surface) }
|
unsafe { SurfaceData::<U, R>::remove_role::<RoleData>(surface) }
|
||||||
|
@ -471,98 +502,93 @@ impl<U: Send + 'static, R: Send + RoleType + 'static, H: Handler<U, R> + Send +
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_region_attributes(&self, region: &wl_region::WlRegion) -> RegionAttributes {
|
pub fn get_region_attributes(&self, region: &wl_region::WlRegion) -> RegionAttributes {
|
||||||
assert!(
|
assert!(
|
||||||
resource_is_registered::<_, CompositorHandler<U, R, H>>(region, self.hid),
|
resource_is_registered(region, &self::handlers::region_implementation()),
|
||||||
"Accessing the data of foreign regions is not supported."
|
"Accessing the data of foreign surfaces is not supported."
|
||||||
);
|
);
|
||||||
unsafe { RegionData::get_attributes(region) }
|
unsafe { RegionData::get_attributes(region) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct handling the `wl_compositor` and `wl_subcompositor` globals
|
/// Create new wl_compositor and wl_subcompositor globals.
|
||||||
///
|
///
|
||||||
/// It allows you to choose a custom `U` type to store data you want
|
/// The globals are directly registered into the eventloop, and this function
|
||||||
/// associated with the surfaces in their metadata, as well a providing
|
/// returns a `CompositorToken` which you'll need access the data associated to
|
||||||
/// a sub-handler to handle the events defined by the `Handler` trait
|
/// the `wl_surface`s.
|
||||||
/// defined in this module.
|
|
||||||
///
|
///
|
||||||
/// See the module-level documentation for instructions and examples of use.
|
/// It also returns the two global handles, in case you whish to remove these
|
||||||
pub struct CompositorHandler<U, R, H> {
|
/// globals from the event loop in the future.
|
||||||
my_id: usize,
|
pub fn compositor_init<U, R, ID, L>(
|
||||||
log: ::slog::Logger,
|
evl: &mut EventLoop, implem: SurfaceUserImplementation<U, R, ID>, idata: ID, logger: L)
|
||||||
handler: H,
|
-> (
|
||||||
_role: ::std::marker::PhantomData<R>,
|
CompositorToken<U, R, ID>,
|
||||||
_data: ::std::marker::PhantomData<U>,
|
Global<wl_compositor::WlCompositor, self::handlers::SurfaceIData<U, R, ID>>,
|
||||||
}
|
Global<wl_subcompositor::WlSubcompositor, ()>,
|
||||||
|
)
|
||||||
impl<U, R, H> Init for CompositorHandler<U, R, H> {
|
|
||||||
fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) {
|
|
||||||
self.my_id = index;
|
|
||||||
debug!(self.log, "Init finished")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<U, R, H> CompositorHandler<U, R, H> {
|
|
||||||
/// Create a new CompositorHandler
|
|
||||||
pub fn new<L>(handler: H, logger: L) -> CompositorHandler<U, R, H>
|
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
U: Default + 'static,
|
||||||
|
R: Default + RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
|
ID: 'static,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
CompositorHandler {
|
let idata = self::handlers::SurfaceIData::make(
|
||||||
my_id: ::std::usize::MAX,
|
log.new(o!("smithay_module" => "compositor_handler")),
|
||||||
log: log.new(o!("smithay_module" => "compositor_handler")),
|
implem,
|
||||||
handler: handler,
|
idata,
|
||||||
_role: ::std::marker::PhantomData,
|
|
||||||
_data: ::std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a token to access the data associated to the objects managed by this handler.
|
|
||||||
pub fn get_token(&self) -> CompositorToken<U, R, H> {
|
|
||||||
assert!(
|
|
||||||
self.my_id != ::std::usize::MAX,
|
|
||||||
"CompositorHandler is not initialized yet."
|
|
||||||
);
|
);
|
||||||
trace!(self.log, "Creating a compositor token.");
|
let compositor_global_token =
|
||||||
CompositorToken {
|
evl.register_global::<wl_compositor::WlCompositor, _>(4, self::handlers::compositor_bind, idata);
|
||||||
hid: self.my_id,
|
let subcompositor_global_token = evl.register_global::<wl_subcompositor::WlSubcompositor, _>(
|
||||||
_data: ::std::marker::PhantomData,
|
1,
|
||||||
_role: ::std::marker::PhantomData,
|
self::handlers::subcompositor_bind::<U, R>,
|
||||||
_handler: ::std::marker::PhantomData,
|
(),
|
||||||
}
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
CompositorToken::make(),
|
||||||
|
compositor_global_token,
|
||||||
|
subcompositor_global_token,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the underlying sub-handler
|
/// Sub-implementation for surface event handling
|
||||||
pub fn get_handler(&mut self) -> &mut H {
|
|
||||||
&mut self.handler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sub-handler trait for surface event handling
|
|
||||||
///
|
///
|
||||||
/// The global provided by Smithay cannot process these events for you, so they
|
/// The global provided by Smithay cannot process these events for you, so they
|
||||||
/// are forwarded directly to a handler implementing this trait that you must provide
|
/// are forwarded directly to this implementation that you must provide
|
||||||
/// at creation of the `CompositorHandler`.
|
/// at creation of the compositor global.
|
||||||
#[allow(unused_variables)]
|
pub struct SurfaceUserImplementation<U, R, ID> {
|
||||||
pub trait Handler<U, R>: Sized {
|
|
||||||
/// The double-buffered state has been validated by the client
|
/// The double-buffered state has been validated by the client
|
||||||
///
|
///
|
||||||
/// At this point, the pending state that has been accumulated in the `SurfaceAttributes` associated
|
/// At this point, the pending state that has been accumulated in the `SurfaceAttributes` associated
|
||||||
/// to this surface should be integrated into the current state of the surface.
|
/// to this surface should be integrated into the current state of the surface.
|
||||||
///
|
///
|
||||||
/// See [`wayland_server::protocol::wl_surface::Handler::commit`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.commit)
|
/// See [`wayland_server::protocol::wl_surface::Implementation::commit`](https://docs.rs/wayland-server/0.10.1/wayland_server/protocol/wl_surface/struct.Implementation.html#structfield.commit)
|
||||||
/// for more details
|
/// for more details
|
||||||
fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface,
|
pub commit: fn(
|
||||||
token: CompositorToken<U, R, Self>) {
|
evlh: &mut EventLoopHandle,
|
||||||
}
|
idata: &mut ID,
|
||||||
|
surface: &wl_surface::WlSurface,
|
||||||
|
token: CompositorToken<U, R, ID>,
|
||||||
|
),
|
||||||
/// The client asks to be notified when would be a good time to update the contents of this surface
|
/// The client asks to be notified when would be a good time to update the contents of this surface
|
||||||
///
|
///
|
||||||
/// You must keep the provided `WlCallback` and trigger it at the appropriate time by calling
|
/// You must keep the provided `WlCallback` and trigger it at the appropriate time by calling
|
||||||
/// its `done()` method.
|
/// its `done()` method.
|
||||||
///
|
///
|
||||||
/// See [`wayland_server::protocol::wl_surface::Handler::frame`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.frame)
|
/// See [`wayland_server::protocol::wl_surface::Implementation::frame`](https://docs.rs/wayland-server/0.10.1/wayland_server/protocol/wl_surface/struct.Implementation.html#structfield.frame)
|
||||||
/// for more details
|
/// for more details
|
||||||
fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface,
|
pub frame: fn(
|
||||||
callback: wl_callback::WlCallback, token: CompositorToken<U, R, Self>) {
|
evlh: &mut EventLoopHandle,
|
||||||
|
idata: &mut ID,
|
||||||
|
surface: &wl_surface::WlSurface,
|
||||||
|
callback: wl_callback::WlCallback,
|
||||||
|
token: CompositorToken<U, R, ID>,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U, R, ID> Copy for SurfaceUserImplementation<U, R, ID> {}
|
||||||
|
impl<U, R, ID> Clone for SurfaceUserImplementation<U, R, ID> {
|
||||||
|
fn clone(&self) -> SurfaceUserImplementation<U, R, ID> {
|
||||||
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use super::{Rectangle, RectangleKind, RegionAttributes};
|
use super::{Rectangle, RectangleKind, RegionAttributes};
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use wayland_server::Resource;
|
use wayland_server::Resource;
|
||||||
|
|
||||||
use wayland_server::protocol::wl_region;
|
use wayland_server::protocol::wl_region;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -13,9 +11,8 @@ pub struct RegionData {
|
||||||
impl RegionData {
|
impl RegionData {
|
||||||
/// Initialize the user_data of a region, must be called right when the surface is created
|
/// Initialize the user_data of a region, must be called right when the surface is created
|
||||||
pub unsafe fn init(region: &wl_region::WlRegion) {
|
pub unsafe fn init(region: &wl_region::WlRegion) {
|
||||||
region.set_user_data(
|
region.set_user_data(Box::into_raw(Box::new(Mutex::new(RegionData::default())))
|
||||||
Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _,
|
as *mut _)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cleans the user_data of that surface, must be called when it is destroyed
|
/// Cleans the user_data of that surface, must be called when it is destroyed
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use super::{SubsurfaceRole, SurfaceAttributes};
|
use super::{SubsurfaceRole, SurfaceAttributes};
|
||||||
use super::roles::*;
|
use super::roles::*;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use wayland_server::{Liveness, Resource};
|
use wayland_server::{Liveness, Resource};
|
||||||
use wayland_server::protocol::wl_surface;
|
use wayland_server::protocol::wl_surface;
|
||||||
|
|
||||||
|
@ -64,7 +63,11 @@ impl<U: Default, R: Default> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R> SurfaceData<U, R> {
|
impl<U, R> SurfaceData<U, R>
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: 'static,
|
||||||
|
{
|
||||||
unsafe fn get_data(surface: &wl_surface::WlSurface) -> &Mutex<SurfaceData<U, R>> {
|
unsafe fn get_data(surface: &wl_surface::WlSurface) -> &Mutex<SurfaceData<U, R>> {
|
||||||
let ptr = surface.get_user_data();
|
let ptr = surface.get_user_data();
|
||||||
&*(ptr as *mut _)
|
&*(ptr as *mut _)
|
||||||
|
@ -97,7 +100,7 @@ impl<U, R> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R: RoleType> SurfaceData<U, R> {
|
impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
||||||
pub unsafe fn has_a_role(surface: &wl_surface::WlSurface) -> bool {
|
pub unsafe fn has_a_role(surface: &wl_surface::WlSurface) -> bool {
|
||||||
debug_assert!(surface.status() == Liveness::Alive);
|
debug_assert!(surface.status() == Liveness::Alive);
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = Self::get_data(surface);
|
||||||
|
@ -171,7 +174,7 @@ impl<U, R: RoleType> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R: RoleType + Role<SubsurfaceRole>> SurfaceData<U, R> {
|
impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R> {
|
||||||
/// Sets the parent of a surface
|
/// Sets the parent of a surface
|
||||||
///
|
///
|
||||||
/// if this surface already has a role, does nothing and fails, otherwise
|
/// if this surface already has a role, does nothing and fails, otherwise
|
||||||
|
@ -291,7 +294,7 @@ impl<U, R: RoleType + Role<SubsurfaceRole>> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R> SurfaceData<U, R> {
|
impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
/// Access the attributes associated with a surface
|
/// Access the attributes associated with a surface
|
||||||
///
|
///
|
||||||
/// Note that an internal lock is taken during access of this data,
|
/// Note that an internal lock is taken during access of this data,
|
||||||
|
@ -319,8 +322,8 @@ impl<U, R> SurfaceData<U, R> {
|
||||||
-> TraversalAction<T>,
|
-> TraversalAction<T>,
|
||||||
{
|
{
|
||||||
// helper function for recursion
|
// helper function for recursion
|
||||||
unsafe fn map<U, R, F, T>(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface,
|
unsafe fn map<U: 'static, R: 'static, F, T>(surface: &wl_surface::WlSurface,
|
||||||
initial: &T, f: &mut F)
|
root: &wl_surface::WlSurface, initial: &T, f: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
where
|
where
|
||||||
F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &mut R, &T)
|
F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &mut R, &T)
|
||||||
|
|
|
@ -12,7 +12,6 @@ extern crate nix;
|
||||||
extern crate rental;
|
extern crate rental;
|
||||||
extern crate tempfile;
|
extern crate tempfile;
|
||||||
extern crate wayland_protocols;
|
extern crate wayland_protocols;
|
||||||
#[macro_use]
|
|
||||||
extern crate wayland_server;
|
extern crate wayland_server;
|
||||||
extern crate xkbcommon;
|
extern crate xkbcommon;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
366
src/shell/mod.rs
366
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.
|
||||||
where
|
///
|
||||||
U: Send + 'static,
|
/// The globals are directly registered into the eventloop, and this function
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
/// returns a `StateToken<_>` which you'll need access the list of shell
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
/// surfaces created by your clients.
|
||||||
{
|
///
|
||||||
/// Create a new CompositorHandler
|
/// It also returns the two global handles, in case you whish to remove these
|
||||||
pub fn new<L>(handler: SH, token: CompositorToken<U, R, H>, logger: L) -> ShellHandler<U, R, H, SH, SD>
|
/// 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: 'static,
|
||||||
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
|
CID: 'static,
|
||||||
|
SID: 'static,
|
||||||
|
SD: Default + 'static,
|
||||||
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);
|
||||||
|
|
||||||
|
let shell_surface_idata = ShellSurfaceIData {
|
||||||
|
log: log.new(o!("smithay_module" => "shell_handler")),
|
||||||
|
compositor_token: token,
|
||||||
|
implementation: implementation,
|
||||||
|
idata: Rc::new(RefCell::new(idata)),
|
||||||
|
state_token: shell_state_token.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: init globals
|
||||||
|
let wl_shell_global = evl.register_global(
|
||||||
|
1,
|
||||||
|
self::wl_handlers::wl_shell_bind::<U, R, CID, SID, SD>,
|
||||||
|
shell_surface_idata.clone(),
|
||||||
|
);
|
||||||
|
let xdg_shell_global = evl.register_global(
|
||||||
|
1,
|
||||||
|
self::xdg_handlers::xdg_shell_bind::<U, R, CID, SID, SD>,
|
||||||
|
shell_surface_idata.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
(shell_state_token, wl_shell_global, xdg_shell_global)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the inner handler of this CompositorHandler
|
/// Shell global state
|
||||||
pub fn get_handler(&mut self) -> &mut SH {
|
///
|
||||||
&mut self.handler
|
/// 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,36 +1,50 @@
|
||||||
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> {
|
||||||
ShellClient {
|
ShellClient {
|
||||||
|
@ -39,62 +53,62 @@ 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
|
||||||
|
@ -102,7 +116,6 @@ impl<SD> Destroy<wl_shell_surface::WlShellSurface> for WlShellDestructor<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(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>,
|
||||||
resource: &wl_shell_surface::WlShellSurface)
|
resource: &wl_shell_surface::WlShellSurface)
|
||||||
|
@ -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,23 +125,18 @@ 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
|
||||||
|
@ -128,42 +144,27 @@ impl<SD> Destroy<zxdg_positioner_v6::ZxdgPositionerV6> 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(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),
|
||||||
|
@ -245,21 +230,24 @@ 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,8 +414,7 @@ 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
|
||||||
|
@ -430,24 +422,22 @@ impl<SD> Destroy<zxdg_toplevel_v6::ZxdgToplevelV6> for XdgShellDestructor<SD> {
|
||||||
// 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
|
||||||
where
|
fn with_surface_toplevel_data<U, R, CID, SID, SD, F>(idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
|
||||||
U: Send + 'static,
|
toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F)
|
||||||
R: Role<ShellSurfaceRole> + Send + 'static,
|
|
||||||
H: CompositorHandler<U, R> + Send + 'static,
|
|
||||||
SH: UserHandler<U, R, H, SD> + Send + 'static,
|
|
||||||
SD: Send + '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
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
|
CID: 'static,
|
||||||
|
SID: 'static,
|
||||||
|
SD: 'static,
|
||||||
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!(),
|
||||||
|
@ -457,27 +447,43 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xdg_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle,
|
fn xdg_handle_display_state_change<U, R, CID, SID, SD>(evlh: &mut EventLoopHandle,
|
||||||
resource: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
idata: &ShellSurfaceIData<U, R, CID, SID, SD>,
|
||||||
|
toplevel: &zxdg_toplevel_v6::ZxdgToplevelV6,
|
||||||
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>)
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<ShellSurfaceRole> + 'static,
|
||||||
|
CID: 'static,
|
||||||
|
SID: 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
|
let handle = make_toplevel_handle(idata.compositor_token, toplevel);
|
||||||
// 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
|
||||||
send_toplevel_configure(self.token, resource, configure);
|
send_toplevel_configure(idata.compositor_token, toplevel, configure);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_toplevel_configure<U, R, H>(token: CompositorToken<U, R, H>,
|
|
||||||
|
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,94 +564,67 @@ 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
|
||||||
|
@ -649,14 +632,14 @@ impl<SD> Destroy<zxdg_popup_v6::ZxdgPopupV6> for XdgShellDestructor<SD> {
|
||||||
// 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
|
|
||||||
);
|
|
||||||
|
|
189
src/shm/mod.rs
189
src/shm/mod.rs
|
@ -19,39 +19,39 @@
|
||||||
//! extern crate wayland_server;
|
//! extern crate wayland_server;
|
||||||
//! extern crate smithay;
|
//! extern crate smithay;
|
||||||
//!
|
//!
|
||||||
//! use smithay::shm::ShmGlobal;
|
//! use smithay::shm::init_shm_global;
|
||||||
//! use wayland_server::protocol::wl_shm;
|
//! use wayland_server::protocol::wl_shm::Format;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (_, mut event_loop) = wayland_server::create_display();
|
//! # let (_, mut event_loop) = wayland_server::create_display();
|
||||||
//!
|
//! // Insert the ShmGlobal into your event loop
|
||||||
//! // Insert the ShmGlobal as a handler to your event loop
|
|
||||||
//! // Here, we specify that Yuyv and C8 format are supported
|
//! // Here, we specify that Yuyv and C8 format are supported
|
||||||
//! // additionnaly to the standart Argb8888 and Xrgb8888.
|
//! // additionnaly to the standart Argb8888 and Xrgb8888.
|
||||||
//! let handler_id = event_loop.add_handler_with_init(ShmGlobal::new(
|
//! let shm_global = init_shm_global(
|
||||||
//! vec![wl_shm::Format::Yuyv, wl_shm::Format::C8],
|
//! &mut event_loop,
|
||||||
|
//! vec![Format::Yuyv, Format::C8],
|
||||||
//! None // we don't provide a logger here
|
//! None // we don't provide a logger here
|
||||||
//! ));
|
//! );
|
||||||
//! // Register this handler to advertise a wl_shm global of version 1
|
|
||||||
//! let shm_global = event_loop.register_global::<wl_shm::WlShm,ShmGlobal>(handler_id, 1);
|
|
||||||
//! // Retrieve the shm token for later use to access the buffers
|
|
||||||
//! let shm_token = {
|
|
||||||
//! let state = event_loop.state();
|
|
||||||
//! state.get_handler::<ShmGlobal>(handler_id).get_token()
|
|
||||||
//! };
|
|
||||||
//!
|
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
|
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
|
||||||
//! do it:
|
//! do it:
|
||||||
//!
|
//!
|
||||||
//! ```ignore
|
//! ```
|
||||||
//! shm_token.with_buffer_contents(&buffer,
|
//! # extern crate wayland_server;
|
||||||
//! |slice: &[u8], buffer_metadata: &BufferData| {
|
//! # extern crate smithay;
|
||||||
|
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
|
||||||
|
//! # fn wrap(buffer: &WlBuffer) {
|
||||||
|
//! use smithay::shm::{with_buffer_contents, BufferData};
|
||||||
|
//!
|
||||||
|
//! with_buffer_contents(&buffer,
|
||||||
|
//! |slice: &[u8], buffer_metadata: BufferData| {
|
||||||
//! // do something to draw it on the screen
|
//! // do something to draw it on the screen
|
||||||
//! }
|
//! }
|
||||||
//! );
|
//! );
|
||||||
|
//! # }
|
||||||
|
//! # fn main() {}
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! **Note**
|
//! **Note**
|
||||||
|
@ -63,32 +63,34 @@
|
||||||
|
|
||||||
|
|
||||||
use self::pool::{Pool, ResizeError};
|
use self::pool::{Pool, ResizeError};
|
||||||
|
use std::rc::Rc;
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use wayland_server::{resource_is_registered, Client, EventLoop, EventLoopHandle, Global, Resource};
|
||||||
use wayland_server::{resource_is_registered, Client, Destroy, EventLoopHandle, GlobalHandler, Init, Resource};
|
|
||||||
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
|
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
|
||||||
|
|
||||||
mod pool;
|
mod pool;
|
||||||
|
|
||||||
/// A global for handling SHM pool and buffers
|
#[derive(Clone)]
|
||||||
|
/// Internal data storage of ShmGlobal
|
||||||
///
|
///
|
||||||
/// You must register it to an event loop using `register_with_init`, or it will
|
/// This type is only visible as type parameter of
|
||||||
/// quickly panic.
|
/// the `Global` handle you are provided.
|
||||||
pub struct ShmGlobal {
|
pub struct ShmGlobalData {
|
||||||
formats: Vec<wl_shm::Format>,
|
formats: Rc<Vec<wl_shm::Format>>,
|
||||||
handler_id: Option<usize>,
|
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShmGlobal {
|
|
||||||
/// Create a new SHM global advertizing given supported formats.
|
/// Create a new SHM global advertizing given supported formats.
|
||||||
///
|
///
|
||||||
/// This global will always advertize `ARGB8888` and `XRGB8888` format
|
/// This global will always advertize `ARGB8888` and `XRGB8888` format
|
||||||
/// as they are required by the protocol. Formats given as argument
|
/// as they are required by the protocol. Formats given as argument
|
||||||
/// as additionnaly advertized.
|
/// as additionnaly advertized.
|
||||||
pub fn new<L>(mut formats: Vec<wl_shm::Format>, logger: L) -> ShmGlobal
|
///
|
||||||
|
/// The global is directly registered into the eventloop, and this function
|
||||||
|
/// returns the global handle, in case you whish to remove this global in
|
||||||
|
/// the future.
|
||||||
|
pub fn init_shm_global<L>(evl: &mut EventLoop, mut formats: Vec<wl_shm::Format>, logger: L)
|
||||||
|
-> Global<wl_shm::WlShm, ShmGlobalData>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -97,33 +99,14 @@ impl ShmGlobal {
|
||||||
// always add the mandatory formats
|
// always add the mandatory formats
|
||||||
formats.push(wl_shm::Format::Argb8888);
|
formats.push(wl_shm::Format::Argb8888);
|
||||||
formats.push(wl_shm::Format::Xrgb8888);
|
formats.push(wl_shm::Format::Xrgb8888);
|
||||||
ShmGlobal {
|
let data = ShmGlobalData {
|
||||||
formats: formats,
|
formats: Rc::new(formats),
|
||||||
handler_id: None,
|
|
||||||
log: log.new(o!("smithay_module" => "shm_handler")),
|
log: log.new(o!("smithay_module" => "shm_handler")),
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Retreive a token from the SHM global.
|
let global = evl.register_global::<wl_shm::WlShm, _>(1, shm_global_bind, data);
|
||||||
///
|
|
||||||
/// This can only be called once the `ShmGlobal` has been added to and event loop
|
|
||||||
/// and has been initialized. If it is not the case, this method will panic.
|
|
||||||
///
|
|
||||||
/// This is needed to retrieve the contents of the shm pools and buffers.
|
|
||||||
pub fn get_token(&self) -> ShmToken {
|
|
||||||
ShmToken {
|
|
||||||
hid: self.handler_id.expect("ShmGlobal was not initialized."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An SHM global token
|
global
|
||||||
///
|
|
||||||
/// It is needed to access the contents of the buffers & pools managed by the
|
|
||||||
/// associated `ShmGlobal`.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ShmToken {
|
|
||||||
hid: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that can occur when accessing an SHM buffer
|
/// Error that can occur when accessing an SHM buffer
|
||||||
|
@ -140,22 +123,21 @@ pub enum BufferAccessError {
|
||||||
BadMap,
|
BadMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShmToken {
|
|
||||||
/// Call given closure with the contents of the given buffer
|
/// Call given closure with the contents of the given buffer
|
||||||
///
|
///
|
||||||
/// If the buffer is managed by the associated ShmGlobal, its contents are
|
/// If the buffer is managed by the provided ShmGlobal, its contents are
|
||||||
/// extracted and the closure is extracted with them:
|
/// extracted and the closure is extracted with them:
|
||||||
///
|
///
|
||||||
/// - The first argument is a data slice of the contents of the pool
|
/// - The first argument is a data slice of the contents of the pool
|
||||||
/// - The second argument is the specification of this buffer is this pool
|
/// - The second argument is the specification of this buffer is this pool
|
||||||
///
|
///
|
||||||
/// If the buffer is not managed by the associated ShmGlobal, the closure is not called
|
/// If the buffer is not managed by the provided ShmGlobal, the closure is not called
|
||||||
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
|
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
|
||||||
pub fn with_buffer_contents<F>(&self, buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
|
pub fn with_buffer_contents<F>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
|
||||||
where
|
where
|
||||||
F: FnOnce(&[u8], BufferData),
|
F: FnOnce(&[u8], BufferData),
|
||||||
{
|
{
|
||||||
if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) {
|
if !resource_is_registered(buffer, &buffer_implementation()) {
|
||||||
return Err(BufferAccessError::NotManaged);
|
return Err(BufferAccessError::NotManaged);
|
||||||
}
|
}
|
||||||
let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };
|
let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };
|
||||||
|
@ -170,47 +152,19 @@ impl ShmToken {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Init for ShmGlobal {
|
fn shm_global_bind(evlh: &mut EventLoopHandle, data: &mut ShmGlobalData, _: &Client, global: wl_shm::WlShm) {
|
||||||
fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) {
|
|
||||||
let id = evqh.add_handler_with_init(ShmHandler {
|
|
||||||
my_id: ::std::usize::MAX,
|
|
||||||
valid_formats: self.formats.clone(),
|
|
||||||
log: self.log.clone(),
|
|
||||||
});
|
|
||||||
self.handler_id = Some(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
|
|
||||||
fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) {
|
|
||||||
let hid = self.handler_id.expect("ShmGlobal was not initialized.");
|
|
||||||
// register an handler for this shm
|
// register an handler for this shm
|
||||||
evqh.register::<_, ShmHandler>(&global, hid);
|
evlh.register(&global, shm_implementation(), data.clone(), None);
|
||||||
// and then the custom formats
|
// and then the custom formats
|
||||||
for f in &self.formats {
|
for f in &data.formats[..] {
|
||||||
global.format(*f);
|
global.format(*f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct ShmHandler {
|
fn shm_implementation() -> wl_shm::Implementation<ShmGlobalData> {
|
||||||
my_id: usize,
|
wl_shm::Implementation {
|
||||||
valid_formats: Vec<wl_shm::Format>,
|
create_pool: |evlh, data, _, shm, pool, fd, size| {
|
||||||
log: ::slog::Logger,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Init for ShmHandler {
|
|
||||||
fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) {
|
|
||||||
self.my_id = index;
|
|
||||||
debug!(self.log, "Init finished")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl wl_shm::Handler for ShmHandler {
|
|
||||||
fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, shm: &wl_shm::WlShm,
|
|
||||||
pool: wl_shm_pool::WlShmPool, fd: RawFd, size: i32) {
|
|
||||||
if size <= 0 {
|
if size <= 0 {
|
||||||
shm.post_error(
|
shm.post_error(
|
||||||
wl_shm::Error::InvalidFd as u32,
|
wl_shm::Error::InvalidFd as u32,
|
||||||
|
@ -218,7 +172,7 @@ impl wl_shm::Handler for ShmHandler {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) {
|
let mmap_pool = match Pool::new(fd, size as usize, data.log.clone()) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
shm.post_error(
|
shm.post_error(
|
||||||
|
@ -229,19 +183,21 @@ impl wl_shm::Handler for ShmHandler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let arc_pool = Box::new(Arc::new(mmap_pool));
|
let arc_pool = Box::new(Arc::new(mmap_pool));
|
||||||
evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id);
|
evlh.register(
|
||||||
|
&pool,
|
||||||
|
shm_pool_implementation(),
|
||||||
|
data.clone(),
|
||||||
|
Some(destroy_shm_pool),
|
||||||
|
);
|
||||||
pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
|
pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Destroy<wl_shm_pool::WlShmPool> for ShmHandler {
|
fn destroy_shm_pool(pool: &wl_shm_pool::WlShmPool) {
|
||||||
fn destroy(pool: &wl_shm_pool::WlShmPool) {
|
|
||||||
let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
|
let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
|
||||||
drop(arc_pool)
|
drop(arc_pool)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
declare_handler!(ShmHandler, wl_shm::Handler, wl_shm::WlShm);
|
|
||||||
|
|
||||||
/// Details of the contents of a buffer relative to its pool
|
/// Details of the contents of a buffer relative to its pool
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -263,11 +219,10 @@ struct InternalBufferData {
|
||||||
data: BufferData,
|
data: BufferData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wl_shm_pool::Handler for ShmHandler {
|
fn shm_pool_implementation() -> wl_shm_pool::Implementation<ShmGlobalData> {
|
||||||
fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client,
|
wl_shm_pool::Implementation {
|
||||||
pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32, width: i32,
|
create_buffer: |evlh, data, _, pool, buffer, offset, width, height, stride, format| {
|
||||||
height: i32, stride: i32, format: wl_shm::Format) {
|
if !data.formats.contains(&format) {
|
||||||
if !self.valid_formats.contains(&format) {
|
|
||||||
buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
|
buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -282,12 +237,10 @@ impl wl_shm_pool::Handler for ShmHandler {
|
||||||
format: format,
|
format: format,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id);
|
evlh.register(&buffer, buffer_implementation(), (), Some(destroy_buffer));
|
||||||
buffer.set_user_data(data as *mut ());
|
buffer.set_user_data(data as *mut ());
|
||||||
}
|
},
|
||||||
|
resize: |_, _, _, pool, size| {
|
||||||
fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client, pool: &wl_shm_pool::WlShmPool,
|
|
||||||
size: i32) {
|
|
||||||
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
|
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
|
||||||
match arc_pool.resize(size) {
|
match arc_pool.resize(size) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
|
@ -301,18 +254,18 @@ impl wl_shm_pool::Handler for ShmHandler {
|
||||||
pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
|
pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
destroy: |_, _, _, _| {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Destroy<wl_buffer::WlBuffer> for ShmHandler {
|
fn destroy_buffer(buffer: &wl_buffer::WlBuffer) {
|
||||||
fn destroy(buffer: &wl_buffer::WlBuffer) {
|
|
||||||
let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
|
let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
|
||||||
drop(buffer_data)
|
drop(buffer_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn buffer_implementation() -> wl_buffer::Implementation<()> {
|
||||||
|
wl_buffer::Implementation {
|
||||||
|
destroy: |_, _, _, _| {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool);
|
|
||||||
|
|
||||||
impl wl_buffer::Handler for ShmHandler {}
|
|
||||||
|
|
||||||
declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer);
|
|
||||||
|
|
Loading…
Reference in New Issue