From 048dda59e3ef835723883679f7a5f598e96a8ba4 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Mon, 23 Apr 2018 11:40:41 +0200 Subject: [PATCH] wayland.shell: legacy module for wl_shell --- examples/drm.rs | 2 +- examples/helpers/implementations.rs | 63 ++++- examples/helpers/mod.rs | 2 +- examples/helpers/window_map.rs | 55 +++- examples/udev.rs | 2 +- examples/winit.rs | 2 +- src/wayland/shell/legacy/mod.rs | 354 ++++++++++++++++++++++++ src/wayland/shell/legacy/wl_handlers.rs | 232 ++++++++++++++++ src/wayland/shell/xdg/mod.rs | 4 +- 9 files changed, 684 insertions(+), 32 deletions(-) diff --git a/examples/drm.rs b/examples/drm.rs index 5db2ada..7993c72 100644 --- a/examples/drm.rs +++ b/examples/drm.rs @@ -125,7 +125,7 @@ fn main() { init_shm_global(&mut display, event_loop.token(), vec![], log.clone()); - let (compositor_token, _shell_state_token, window_map) = + let (compositor_token, _, _, window_map) = init_shell(&mut display, event_loop.token(), log.clone(), egl_display); /* diff --git a/examples/helpers/implementations.rs b/examples/helpers/implementations.rs index 10ef7bd..4d78bc9 100644 --- a/examples/helpers/implementations.rs +++ b/examples/helpers/implementations.rs @@ -1,19 +1,21 @@ -use super::WindowMap; +use super::{SurfaceKind, WindowMap}; use glium::texture::Texture2d; use rand; use smithay::backend::graphics::egl::wayland::{BufferAccessError, Format}; use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLImages}; use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent}; -use smithay::wayland::shell::xdg::{xdg_shell_init, PopupConfigure, ShellState, ToplevelConfigure, - XdgRequest, XdgSurfaceRole}; +use smithay::wayland::shell::xdg::{xdg_shell_init, PopupConfigure, ShellState as XdgShellState, + ToplevelConfigure, XdgRequest, XdgSurfaceRole}; +use smithay::wayland::shell::legacy::{wl_shell_init, ShellRequest, ShellState as WlShellState, + ShellSurfaceKind, ShellSurfaceRole}; use smithay::wayland::shm::with_buffer_contents as shm_buffer_contents; use std::cell::RefCell; use std::rc::Rc; use std::sync::{Arc, Mutex}; use wayland_server::{Display, LoopToken, Resource}; -use wayland_server::protocol::{wl_buffer, wl_callback, wl_surface}; +use wayland_server::protocol::{wl_buffer, wl_callback, wl_shell_surface, wl_surface}; -define_roles!(Roles => [ ShellSurface, XdgSurfaceRole ] ); +define_roles!(Roles => [ XdgSurface, XdgSurfaceRole ] [ ShellSurface, ShellSurfaceRole<()>] ); #[derive(Default)] pub struct SurfaceData { @@ -97,7 +99,7 @@ fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { } pub type MyWindowMap = - WindowMap) -> Option<(i32, i32)>>; + WindowMap) -> Option<(i32, i32)>>; pub fn init_shell( display: &mut Display, @@ -106,7 +108,8 @@ pub fn init_shell( egl_display: Rc>>, ) -> ( CompositorToken, - Arc>>, + Arc>>, + Arc>>, Rc>, ) { // Create the compositor @@ -125,16 +128,16 @@ pub fn init_shell( ); // Init a window map, to track the location of our windows - let window_map = Rc::new(RefCell::new(WindowMap::<_, _, (), _>::new( + let window_map = Rc::new(RefCell::new(WindowMap::<_, _, (), (), _>::new( compositor_token, get_size as _, ))); // init the xdg_shell - let shell_window_map = window_map.clone(); - let (shell_state, _, _) = xdg_shell_init( + let xdg_window_map = window_map.clone(); + let (xdg_shell_state, _, _) = xdg_shell_init( display, - looptoken, + looptoken.clone(), compositor_token.clone(), move |shell_event, ()| match shell_event { XdgRequest::NewToplevel { surface } => { @@ -149,7 +152,9 @@ pub fn init_shell( states: vec![], serial: 42, }); - shell_window_map.borrow_mut().insert(surface, (x, y)); + xdg_window_map + .borrow_mut() + .insert(SurfaceKind::Xdg(surface), (x, y)); } XdgRequest::NewPopup { surface } => surface.send_configure(PopupConfigure { size: (10, 10), @@ -161,5 +166,37 @@ pub fn init_shell( log.clone(), ); - (compositor_token, shell_state, window_map) + // init the wl_shell + let shell_window_map = window_map.clone(); + let (wl_shell_state, _) = wl_shell_init( + display, + looptoken, + compositor_token.clone(), + move |req: ShellRequest<_, _, ()>, ()| match req { + ShellRequest::SetKind { + surface, + kind: ShellSurfaceKind::Toplevel, + } => { + // 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); + surface.send_configure((0, 0), wl_shell_surface::Resize::None); + shell_window_map + .borrow_mut() + .insert(SurfaceKind::Wl(surface), (x, y)); + } + _ => (), + }, + log.clone(), + ); + + ( + compositor_token, + xdg_shell_state, + wl_shell_state, + window_map, + ) } diff --git a/examples/helpers/mod.rs b/examples/helpers/mod.rs index 6659931..2747f60 100644 --- a/examples/helpers/mod.rs +++ b/examples/helpers/mod.rs @@ -4,4 +4,4 @@ mod window_map; pub use self::glium::GliumDrawer; pub use self::implementations::*; -pub use self::window_map::WindowMap; +pub use self::window_map::{Kind as SurfaceKind, WindowMap}; diff --git a/examples/helpers/window_map.rs b/examples/helpers/window_map.rs index b48a6e1..af79ca3 100644 --- a/examples/helpers/window_map.rs +++ b/examples/helpers/window_map.rs @@ -2,20 +2,48 @@ use smithay::utils::Rectangle; use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction}; use smithay::wayland::compositor::roles::Role; use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole}; +use smithay::wayland::shell::legacy::{ShellSurface, ShellSurfaceRole}; use wayland_server::Resource; use wayland_server::protocol::wl_surface; -struct Window { - location: (i32, i32), - surface: Rectangle, - toplevel: ToplevelSurface, +pub enum Kind { + Xdg(ToplevelSurface), + Wl(ShellSurface), } -impl Window +impl Kind where U: 'static, - R: Role + Role + 'static, + R: Role + Role + Role> + 'static, SD: 'static, + D: 'static, +{ + pub fn alive(&self) -> bool { + match *self { + Kind::Xdg(ref t) => t.alive(), + Kind::Wl(ref t) => t.alive(), + } + } + pub fn get_surface(&self) -> Option<&Resource> { + match *self { + Kind::Xdg(ref t) => t.get_surface(), + Kind::Wl(ref t) => t.get_surface(), + } + } +} + +struct Window { + location: (i32, i32), + surface: Rectangle, + toplevel: Kind, +} + +impl Window +where + U: 'static, + R: Role + Role + Role> + 'static, + SD: 'static, + D: 'static, { // Find the topmost surface under this point if any and the location of this point in the surface fn matching( @@ -111,20 +139,21 @@ where } } -pub struct WindowMap { +pub struct WindowMap { ctoken: CompositorToken, - windows: Vec>, + windows: Vec>, get_size: F, } -impl WindowMap +impl WindowMap where F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, U: 'static, - R: Role + Role + 'static, + R: Role + Role + Role> + 'static, SD: 'static, + D: 'static, { - pub fn new(ctoken: CompositorToken, get_size: F) -> WindowMap { + pub fn new(ctoken: CompositorToken, get_size: F) -> WindowMap { WindowMap { ctoken: ctoken, windows: Vec::new(), @@ -132,7 +161,7 @@ where } } - pub fn insert(&mut self, toplevel: ToplevelSurface, location: (i32, i32)) { + pub fn insert(&mut self, toplevel: Kind, location: (i32, i32)) { let mut window = Window { location: location, surface: Rectangle { @@ -181,7 +210,7 @@ where pub fn with_windows_from_bottom_to_top(&self, mut f: Func) where - Func: FnMut(&ToplevelSurface, (i32, i32)), + Func: FnMut(&Kind, (i32, i32)), { for w in self.windows.iter().rev() { f(&w.toplevel, w.location) diff --git a/examples/udev.rs b/examples/udev.rs index 862e6be..f89c9ed 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -286,7 +286,7 @@ fn main() { log.clone(), ); - let (compositor_token, _shell_state_token, window_map) = init_shell( + let (compositor_token, _, _, window_map) = init_shell( &mut display.borrow_mut(), event_loop.token(), log.clone(), diff --git a/examples/winit.rs b/examples/winit.rs index e388c1d..a680b8d 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -195,7 +195,7 @@ fn main() { init_shm_global(&mut display, event_loop.token(), vec![], log.clone()); - let (compositor_token, _shell_state_token, window_map) = + let (compositor_token, _, _, window_map) = init_shell(&mut display, event_loop.token(), log.clone(), egl_display); let (mut seat, _) = Seat::new( diff --git a/src/wayland/shell/legacy/mod.rs b/src/wayland/shell/legacy/mod.rs index 031280d..d9936ab 100644 --- a/src/wayland/shell/legacy/mod.rs +++ b/src/wayland/shell/legacy/mod.rs @@ -1 +1,355 @@ +//! Utilities for handling shell surfaces with the `wl_shell` protocol +//! +//! This module provides automatic handling of shell surfaces objects, by being registered +//! as a global handler for `wl_shell`. This protocol is deprecated in favor of `xdg_shell`, +//! thus this module is provided as a compatibility layer with older clients. As a consequence, +//! you can as a compositor-writer decide to only support its fonctionnality in a best-effort +//! maneer: as this global is part of the core protocol, you are still required to provide +//! some support for it. +//! +//! ## Why use this implementation +//! +//! This implementation can track for you the various shell surfaces defined by the +//! clients by handling the `wl_shell` protocol. +//! +//! 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. +//! +//! This handler only handles the protocol exchanges with the client to present you the +//! information in a coherent and relatively easy to use maneer. All the actual drawing +//! and positioning logic of windows is out of its scope. +//! +//! ## How to use it +//! +//! ### Initialization +//! +//! To initialize this handler, simple use the `wl_shell_init` function provided in this +//! module. You will need to provide it the `CompositorToken` you retrieved from an +//! instanciation of the compositor handler provided by smithay. +//! +//! ```no_run +//! # extern crate wayland_server; +//! # #[macro_use] extern crate smithay; +//! # extern crate wayland_protocols; +//! # +//! use smithay::wayland::compositor::roles::*; +//! use smithay::wayland::compositor::CompositorToken; +//! use smithay::wayland::shell::legacy::{wl_shell_init, ShellSurfaceRole, ShellRequest}; +//! use wayland_server::{EventLoop, LoopToken}; +//! # use wayland_server::protocol::{wl_seat, wl_output}; +//! # #[derive(Default)] struct MySurfaceData; +//! +//! // define the metadata you want associated with the shell surfaces +//! #[derive(Default)] +//! pub struct MyShellSurfaceData { +//! /* ... */ +//! } +//! +//! // define the roles type. You need to integrate the XdgSurface role: +//! define_roles!(MyRoles => +//! [ShellSurface, ShellSurfaceRole] +//! ); +//! +//! # fn main() { +//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>( +//! # &mut display, +//! # event_loop.token(), +//! # |_, _| {}, +//! # None +//! # ); +//! let (shell_state, _) = wl_shell_init( +//! &mut display, +//! event_loop.token(), +//! // token from the compositor implementation +//! compositor_token, +//! // your implementation, can also be a strucy implementing the +//! // appropriate Implementation<(), ShellRequest<_, _, _>> trait +//! |event: ShellRequest<_, _, MyShellSurfaceData>, ()| { /* ... */ }, +//! None // put a logger if you want +//! ); +//! +//! // You're now ready to go! +//! # } +//! ``` + +use std::rc::Rc; +use std::cell::RefCell; +use std::sync::{Arc, Mutex}; + +use wayland::compositor::CompositorToken; +use wayland::compositor::roles::Role; + +use wayland_server::{Display, Global, LoopToken, Resource}; +use wayland_server::commons::Implementation; +use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; + mod wl_handlers; + +/// Metadata associated with the `xdg_surface` role +pub struct ShellSurfaceRole { + /// Title of the surface + pub title: String, + /// Class of the surface + pub class: String, + pending_ping: u32, + /// Some user data you may want to associate with the surface + pub user_data: D, +} + +/// A handle to a shell surface +pub struct ShellSurface { + wl_surface: Resource, + shell_surface: Resource, + token: CompositorToken, + _d: ::std::marker::PhantomData, +} + +impl ShellSurface +where + U: 'static, + R: Role> + 'static, + D: 'static, +{ + /// Is the shell surface refered by this handle still alive? + pub fn alive(&self) -> bool { + self.shell_surface.is_alive() && self.wl_surface.is_alive() + } + + /// Do this handle and the other one actually refer to the same shell surface? + pub fn equals(&self, other: &Self) -> bool { + self.shell_surface.equals(&other.shell_surface) + } + + /// Access the underlying `wl_surface` of this toplevel surface + /// + /// Returns `None` if the toplevel surface actually no longer exists. + pub fn get_surface(&self) -> Option<&Resource> { + if self.alive() { + Some(&self.wl_surface) + } else { + None + } + } + + /// Send a ping request to this shell surface + /// + /// You'll receive the reply as a `ShellRequest::Pong` request + /// + /// A typical use is to start a timer at the same time you send this ping + /// request, and cancel it when you receive the pong. If the timer runs + /// down to 0 before a pong is received, mark the client as unresponsive. + /// + /// Fails if this shell client already has a pending ping or is already dead. + pub fn send_ping(&self, serial: u32) -> Result<(), ()> { + if !self.alive() { + return Err(()); + } + let ret = self.token.with_role_data(&self.wl_surface, |data| { + if data.pending_ping == 0 { + data.pending_ping = serial; + true + } else { + false + } + }); + if let Ok(true) = ret { + self.shell_surface + .send(wl_shell_surface::Event::Ping { serial }); + Ok(()) + } else { + Err(()) + } + } + + /// Send a configure event to this toplevel surface to suggest it a new configuration + pub fn send_configure(&self, size: (u32, u32), edges: wl_shell_surface::Resize) { + self.shell_surface.send(wl_shell_surface::Event::Configure { + edges, + width: size.0 as i32, + height: size.1 as i32, + }) + } + + /// Signal a popup surface that it has lost focus + pub fn send_popup_done(&self) { + self.shell_surface.send(wl_shell_surface::Event::PopupDone) + } + + /// Access the user data you associated to this surface + pub fn with_user_data(&self, f: F) -> Result + where + F: FnOnce(&mut D) -> T, + { + self.token + .with_role_data(&self.wl_surface, |data| f(&mut data.user_data)) + .map_err(|_| ()) + } +} + +/// Possible kinds of shell surface of the `wl_shell` protocol +pub enum ShellSurfaceKind { + /// Toplevel, a regular window displayed somewhere in the compositor space + Toplevel, + /// Transient, this surface has a parent surface + /// + /// These are sub-windows of an application (for example a configuration window), + /// and as such should only be visible in their parent window is, and on top of it. + Transient { + /// The surface considered as parent + parent: Resource, + /// Location relative to the parent + location: (i32, i32), + /// Wether this window should be marked as inactive + inactive: bool, + }, + /// Fullscreen surface, covering an entire output + Fullscreen { + /// Method used for fullscreen + method: wl_shell_surface::FullscreenMethod, + /// Framerate (relevant only for driver fullscreen) + framerate: u32, + /// Requested output if any + output: Option>, + }, + /// A popup surface + /// + /// Short-lived surface, typically refrered as "tooltips" in many + /// contexts. + Popup { + /// The parent surface of this popup + parent: Resource, + /// The serial of the input event triggering the creation of this + /// popup + serial: u32, + /// Wether this popup should be marked as inactive + inactive: bool, + /// Location of the popup relative to its parent + location: (i32, i32), + /// Seat associated this the input that triggered the creation of the + /// popup. Used to define when the "popup done" event is sent. + seat: Resource, + }, + /// A maximized surface + /// + /// Like a toplevel surface, but as big as possible on a single output + /// while keeping any relevant desktop-environment interface visible. + Maximized { + /// Requested output for maximization + output: Option>, + }, +} + +/// A request triggered by a wl_shell_surface +pub enum ShellRequest { + /// A new shell surface was created + /// + /// by default it has no kind and this should not be displayed + NewShellSurface { + /// The created surface + surface: ShellSurface, + }, + /// A pong event + /// + /// The surface responded to its pending ping. If you receive this + /// event, smithay has already checked that the responded serial was valid. + Pong { + /// The surface that sent the pong + surface: ShellSurface, + }, + /// Start of an interactive move + /// + /// The surface requests that an interactive move is started on it + Move { + /// The surface requesting the move + surface: ShellSurface, + /// Serial of the implicit grab that initiated the move + serial: u32, + /// Seat associated with the move + seat: Resource, + }, + /// Start of an interactive resize + /// + /// The surface requests that an interactive resize is started on it + Resize { + /// The surface requesting the resize + surface: ShellSurface, + /// Serial of the implicit grab that initiated the resize + serial: u32, + /// Seat associated with the resize + seat: Resource, + /// Direction of the resize + edges: wl_shell_surface::Resize, + }, + /// The surface changed its kind + SetKind { + /// The surface + surface: ShellSurface, + /// Its new kind + kind: ShellSurfaceKind, + }, +} + +/// Shell global state +/// +/// This state allows you to retrieve a list of surfaces +/// currently known to the shell global. +pub struct ShellState { + known_surfaces: Vec>, +} + +impl ShellState +where + U: 'static, + R: Role> + 'static, + D: 'static, +{ + /// Cleans the internal surface storage by removing all dead surfaces + pub(crate) fn cleanup_surfaces(&mut self) { + self.known_surfaces.retain(|s| s.alive()); + } + + /// Access all the shell surfaces known by this handler + pub fn surfaces(&self) -> &[ShellSurface] { + &self.known_surfaces[..] + } +} + +/// Create a new `wl_shell` global +pub fn wl_shell_init( + display: &mut Display, + ltoken: LoopToken, + ctoken: CompositorToken, + implementation: Impl, + logger: L, +) -> (Arc>>, Global) +where + U: 'static, + D: Default + 'static, + R: Role> + 'static, + L: Into>, + Impl: Implementation<(), ShellRequest>, +{ + let _log = ::slog_or_stdlog(logger); + + let implementation = Rc::new(RefCell::new(implementation)); + + let ltoken2 = ltoken.clone(); + + let state = Arc::new(Mutex::new(ShellState { + known_surfaces: Vec::new(), + })); + let state2 = state.clone(); + + let global = display.create_global(<oken2, 1, move |_version, shell| { + self::wl_handlers::implement_shell( + shell, + ltoken.clone(), + ctoken.clone(), + implementation.clone(), + state2.clone(), + ); + }); + + (state, global) +} diff --git a/src/wayland/shell/legacy/wl_handlers.rs b/src/wayland/shell/legacy/wl_handlers.rs index 8b13789..3dbc0e6 100644 --- a/src/wayland/shell/legacy/wl_handlers.rs +++ b/src/wayland/shell/legacy/wl_handlers.rs @@ -1 +1,233 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::{Arc, Mutex}; +use wayland_server::{LoopToken, NewResource, Resource}; +use wayland_server::commons::Implementation; +use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface}; + +use wayland::compositor::CompositorToken; +use wayland::compositor::roles::Role; + +use super::{ShellRequest, ShellState, ShellSurface, ShellSurfaceKind, ShellSurfaceRole}; + +pub(crate) fn implement_shell( + shell: NewResource, + ltoken: LoopToken, + ctoken: CompositorToken, + implementation: Rc>, + state: Arc>>, +) where + U: 'static, + D: Default + 'static, + R: Role> + 'static, + Impl: Implementation<(), ShellRequest> + 'static, +{ + let ltoken2 = ltoken.clone(); + shell.implement_nonsend( + move |req, shell: Resource<_>| { + let wl_shell::Request::GetShellSurface { id, surface } = req; + let role_data = ShellSurfaceRole { + title: "".into(), + class: "".into(), + pending_ping: 0, + user_data: Default::default(), + }; + if ctoken.give_role_with(&surface, role_data).is_err() { + shell.post_error( + wl_shell::Error::Role as u32, + "Surface already has a role.".into(), + ); + return; + } + let shell_surface = implement_shell_surface( + id, + surface, + implementation.clone(), + ltoken.clone(), + ctoken.clone(), + state.clone(), + ); + state + .lock() + .unwrap() + .known_surfaces + .push(make_handle(&shell_surface, ctoken.clone())); + implementation.borrow_mut().receive( + ShellRequest::NewShellSurface { + surface: make_handle(&shell_surface, ctoken.clone()), + }, + (), + ); + }, + None::, + <oken2, + ); +} + +fn make_handle( + shell_surface: &Resource, + token: CompositorToken, +) -> ShellSurface { + let data = unsafe { &*(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; + ShellSurface { + wl_surface: data.surface.clone(), + shell_surface: shell_surface.clone(), + token, + _d: ::std::marker::PhantomData, + } +} + +pub(crate) struct ShellSurfaceUserData { + surface: Resource, + state: Arc>>, +} + +fn implement_shell_surface( + shell_surface: NewResource, + surface: Resource, + implementation: Rc>, + ltoken: LoopToken, + ctoken: CompositorToken, + state: Arc>>, +) -> Resource +where + U: 'static, + D: 'static, + R: Role> + 'static, + Impl: Implementation<(), ShellRequest> + 'static, +{ + use self::wl_shell_surface::Request; + let shell_surface = shell_surface.implement_nonsend( + move |req, shell_surface: Resource<_>| { + let data = unsafe { &mut *(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; + let mut user_impl = implementation.borrow_mut(); + match req { + Request::Pong { serial } => { + let valid = ctoken + .with_role_data(&data.surface, |data| { + if data.pending_ping == serial { + data.pending_ping = 0; + true + } else { + false + } + }) + .expect("wl_shell_surface exists but surface has not the right role?"); + if valid { + user_impl.receive( + ShellRequest::Pong { + surface: make_handle(&shell_surface, ctoken.clone()), + }, + (), + ); + } + } + Request::Move { seat, serial } => user_impl.receive( + ShellRequest::Move { + surface: make_handle(&shell_surface, ctoken.clone()), + serial, + seat, + }, + (), + ), + Request::Resize { + seat, + serial, + edges, + } => user_impl.receive( + ShellRequest::Resize { + surface: make_handle(&shell_surface, ctoken.clone()), + serial, + seat, + edges, + }, + (), + ), + Request::SetToplevel => user_impl.receive( + ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken.clone()), + kind: ShellSurfaceKind::Toplevel, + }, + (), + ), + Request::SetTransient { + parent, + x, + y, + flags, + } => user_impl.receive( + ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken.clone()), + kind: ShellSurfaceKind::Transient { + parent, + location: (x, y), + inactive: flags.contains(wl_shell_surface::Transient::Inactive), + }, + }, + (), + ), + Request::SetFullscreen { + method, + framerate, + output, + } => user_impl.receive( + ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken.clone()), + kind: ShellSurfaceKind::Fullscreen { + method, + framerate, + output, + }, + }, + (), + ), + Request::SetPopup { + seat, + serial, + parent, + x, + y, + flags, + } => user_impl.receive( + ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken.clone()), + kind: ShellSurfaceKind::Popup { + parent, + serial, + seat, + location: (x, y), + inactive: flags.contains(wl_shell_surface::Transient::Inactive), + }, + }, + (), + ), + Request::SetMaximized { output } => user_impl.receive( + ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken.clone()), + kind: ShellSurfaceKind::Maximized { output }, + }, + (), + ), + Request::SetTitle { title } => { + ctoken + .with_role_data(&data.surface, |data| data.title = title) + .expect("wl_shell_surface exists but surface has not shell_surface role?!"); + } + Request::SetClass { class_ } => { + ctoken + .with_role_data(&data.surface, |data| data.class = class_) + .expect("wl_shell_surface exists but surface has not shell_surface role?!"); + } + } + }, + Some(|shell_surface: Resource<_>, _| { + let data = + unsafe { Box::from_raw(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; + data.state.lock().unwrap().cleanup_surfaces(); + }), + <oken, + ); + shell_surface.set_user_data(Box::into_raw(Box::new(ShellSurfaceUserData { surface, state })) as *mut ()); + shell_surface +} diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index c091f73..b4b281c 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -21,9 +21,9 @@ //! //! ### Initialization //! -//! To initialize this handler, simple use the `shell_init` function provided in this +//! To initialize this handler, simple use the `xdg_shell_init` function provided in this //! module. You will need to provide it the `CompositorToken` you retrieved from an -//! instanciation of the `CompositorHandler` provided by smithay. +//! instanciation of the compositor global provided by smithay. //! //! ```no_run //! # extern crate wayland_server;