From 70f7b1994066a5058479d7327b13011f1bf40a1e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 12:05:42 +0200 Subject: [PATCH 01/13] compositor: add missing token method --- src/compositor/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index a1529bb..f9fdb0c 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -434,6 +434,23 @@ impl + Send + unsafe { SurfaceData::::give_role_with::(surface, data) } } + /// Access the role data of a surface + /// + /// Fails and don't call the closure if the surface doesn't have this role + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn with_role_data(&self, surface: &wl_surface::WlSurface, f: F) -> Result + where + R: Role, + F: FnOnce(&mut RoleData) -> T + { + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); + unsafe { SurfaceData::::with_role_data::(surface, f) } + } /// Register that this surface does not have a role any longer and retrieve the data /// From 3128585fc971fc6404f52d03f47c9a14f9048d32 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 19:50:22 +0200 Subject: [PATCH 02/13] shell: shell backend first draft --- Cargo.toml | 1 + src/lib.rs | 25 +- src/shell/global.rs | 54 +++ src/shell/mod.rs | 503 ++++++++++++++++++++++++++ src/shell/wl_handlers.rs | 365 +++++++++++++++++++ src/shell/xdg_handlers.rs | 731 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1667 insertions(+), 12 deletions(-) create mode 100644 src/shell/global.rs create mode 100644 src/shell/mod.rs create mode 100644 src/shell/wl_handlers.rs create mode 100644 src/shell/xdg_handlers.rs diff --git a/Cargo.toml b/Cargo.toml index 855f6a8..57fa1e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ glium = { version = "0.16.0", optional = true, default-features = false } input = { version = "0.2.0", optional = true } clippy = { version = "*", optional = true } rental = "0.4.11" +wayland-protocols = { version = "0.9.9", features = ["unstable_protocols", "server"] } [build-dependencies] gl_generator = "0.5" diff --git a/src/lib.rs b/src/lib.rs index d706968..d6c17a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,24 +4,24 @@ //! Most entry points in the modules can take an optionnal `slog::Logger` as argument //! that will be used as a drain for logging. If `None` is provided, they'll log to `slog-stdlog`. - #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] -#[macro_use] -extern crate wayland_server; extern crate nix; -extern crate xkbcommon; -extern crate tempfile; #[macro_use] extern crate rental; +extern crate tempfile; +extern crate wayland_protocols; +#[macro_use] +extern crate wayland_server; +extern crate xkbcommon; -#[cfg(feature = "backend_winit")] -extern crate winit; -#[cfg(feature = "backend_winit")] -extern crate wayland_client; #[cfg(feature = "backend_libinput")] extern crate input; +#[cfg(feature = "backend_winit")] +extern crate wayland_client; +#[cfg(feature = "backend_winit")] +extern crate winit; extern crate libloading; @@ -36,13 +36,14 @@ pub mod backend; pub mod compositor; pub mod shm; pub mod keyboard; +pub mod shell; fn slog_or_stdlog(logger: L) -> ::slog::Logger where L: Into>, { use slog::Drain; - logger.into().unwrap_or_else(|| { - ::slog::Logger::root(::slog_stdlog::StdLog.fuse(), o!()) - }) + logger + .into() + .unwrap_or_else(|| ::slog::Logger::root(::slog_stdlog::StdLog.fuse(), o!())) } diff --git a/src/shell/global.rs b/src/shell/global.rs new file mode 100644 index 0000000..07e13a3 --- /dev/null +++ b/src/shell/global.rs @@ -0,0 +1,54 @@ +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() -> ShellClientData { + ShellClientData { + pending_ping: 0, + data: Default::default(), + } +} + +impl GlobalHandler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + 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::(), + Vec::::new(), + )))) as *mut _); + evlh.register_with_destructor::<_, Self, WlShellDestructor>(&global, self.my_id); + } +} + +impl GlobalHandler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + 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::()))) as *mut _, + ); + evlh.register_with_destructor::<_, Self, XdgShellDestructor>(&global, self.my_id); + } +} diff --git a/src/shell/mod.rs b/src/shell/mod.rs new file mode 100644 index 0000000..00cbc5c --- /dev/null +++ b/src/shell/mod.rs @@ -0,0 +1,503 @@ +use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle}; +use compositor::roles::Role; + +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}; + +use wayland_server::{EventLoopHandle, EventResult, Init, Liveness, Resource}; +use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; + +mod global; +mod wl_handlers; +mod xdg_handlers; + +pub struct ShellSurfaceRole { + pub pending_state: ShellSurfacePendingState, + pub window_geometry: Option, + pub pending_configures: Vec, + pub configured: bool, +} + +#[derive(Copy, Clone, Debug)] +pub struct PositionerState { + pub rect_size: (i32, i32), + pub anchor_rect: Rectangle, + pub anchor_edges: xdg_positioner::Anchor, + pub gravity: xdg_positioner::Gravity, + pub constraint_adjustment: xdg_positioner::ConstraintAdjustment, + pub offset: (i32, i32), +} + +pub enum ShellSurfacePendingState { + /// This a regular, toplevel surface + /// + /// This corresponds to either the `xdg_toplevel` role from the + /// `xdg_shell` protocol, or the result of `set_toplevel` using the + /// `wl_shell` protocol. + Toplevel(ToplevelState), + /// This is a popup surface + /// + /// This corresponds to either the `xdg_popup` role from the + /// `xdg_shell` protocol, or the result of `set_popup` using the + /// `wl_shell` protocole + Popup(PopupState), + /// This surface was not yet assigned a kind + None, +} + +pub struct ToplevelState { + pub parent: Option, + pub title: String, + pub app_id: String, + pub min_size: (i32, i32), + pub max_size: (i32, i32), +} + +impl ToplevelState { + pub fn clone(&self) -> ToplevelState { + ToplevelState { + parent: self.parent.as_ref().and_then(|p| p.clone()), + title: self.title.clone(), + app_id: self.app_id.clone(), + min_size: self.min_size, + max_size: self.max_size, + } + } +} + +pub struct PopupState { + pub parent: wl_surface::WlSurface, + pub positioner: PositionerState, +} + +impl PopupState { + pub fn clone(&self) -> Option { + if let Some(p) = self.parent.clone() { + Some(PopupState { + parent: p, + positioner: self.positioner.clone(), + }) + } else { + // the parent surface does no exist any longer, + // this popup does not make any sense now + None + } + } +} + +impl Default for ShellSurfacePendingState { + fn default() -> ShellSurfacePendingState { + ShellSurfacePendingState::None + } +} + +pub struct ShellHandler { + my_id: usize, + log: ::slog::Logger, + token: CompositorToken, + handler: SH, + known_toplevels: Vec>, + known_popups: Vec>, + _shell_data: ::std::marker::PhantomData, +} + +impl Init for ShellHandler { + fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { + self.my_id = index; + debug!(self.log, "Init finished") + } +} + +impl ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, +{ + /// Create a new CompositorHandler + pub fn new(handler: SH, token: CompositorToken, logger: L) -> ShellHandler + where + L: Into>, + { + let log = ::slog_or_stdlog(logger); + ShellHandler { + my_id: ::std::usize::MAX, + log: log.new(o!("smithay_module" => "shell_handler")), + token: token, + handler: handler, + known_toplevels: Vec::new(), + known_popups: Vec::new(), + _shell_data: ::std::marker::PhantomData, + } + } + + /// Access the inner handler of this CompositorHandler + pub fn get_handler(&mut self) -> &mut SH { + &mut self.handler + } + + /// Cleans the internal surface storage by removing all dead surfaces + pub fn cleanup_surfaces(&mut self) { + self.known_toplevels.retain(|s| s.alive()); + self.known_popups.retain(|s| s.alive()); + } + + /// Access all the shell surfaces known by this handler + pub fn toplevel_surfaces(&self) -> &[ToplevelSurface] { + &self.known_toplevels[..] + } + + /// Access all the popup surfaces known by this handler + pub fn popup_surfaces(&self) -> &[PopupSurface] { + &self.known_popups[..] + } +} + +/* + * User interaction + */ + +enum ShellClientKind { + Wl(wl_shell::WlShell), + Xdg(zxdg_shell_v6::ZxdgShellV6), +} + +struct ShellClientData { + pending_ping: u32, + data: SD, +} + +pub struct ShellClient { + kind: ShellClientKind, + _data: ::std::marker::PhantomData<*mut SD>, +} + +impl ShellClient { + pub fn alive(&self) -> bool { + match self.kind { + ShellClientKind::Wl(ref s) => s.status() == Liveness::Alive, + ShellClientKind::Xdg(ref s) => s.status() == Liveness::Alive, + } + } + + pub fn equals(&self, other: &Self) -> bool { + match (&self.kind, &other.kind) { + (&ShellClientKind::Wl(ref s1), &ShellClientKind::Wl(ref s2)) => s1.equals(s2), + (&ShellClientKind::Xdg(ref s1), &ShellClientKind::Xdg(ref s2)) => s1.equals(s2), + _ => false, + } + } + + /// Send a ping request to this shell client + /// + /// You'll receive the reply in the `Handler::cient_pong()` method. + /// + /// 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(()); + } + match self.kind { + ShellClientKind::Wl(ref shell) => { + let mutex = unsafe { &*(shell.get_user_data() as *mut self::wl_handlers::ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + if guard.0.pending_ping == 0 { + return Err(()); + } + guard.0.pending_ping = serial; + if let Some(surface) = guard.1.first() { + // there is at least one surface, send the ping + // if there is no surface, the ping will remain pending + // and will be sent when the client creates a surface + surface.ping(serial); + } + } + ShellClientKind::Xdg(ref shell) => { + let mutex = + unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + if guard.pending_ping == 0 { + return Err(()); + } + guard.pending_ping = serial; + shell.ping(serial); + } + } + Ok(()) + } + + pub fn with_data(&self, f: F) -> Result + where + F: FnOnce(&mut SD) -> T, + { + if !self.alive() { + return Err(()); + } + match self.kind { + ShellClientKind::Wl(ref shell) => { + let mutex = unsafe { &*(shell.get_user_data() as *mut self::wl_handlers::ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + Ok(f(&mut guard.0.data)) + } + ShellClientKind::Xdg(ref shell) => { + let mutex = + unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + Ok(f(&mut guard.data)) + } + } + } +} + +enum SurfaceKind { + Wl(wl_shell_surface::WlShellSurface), + XdgToplevel(zxdg_toplevel_v6::ZxdgToplevelV6), + XdgPopup(zxdg_popup_v6::ZxdgPopupV6), +} + +pub struct ToplevelSurface { + wl_surface: wl_surface::WlSurface, + shell_surface: SurfaceKind, + token: CompositorToken, + _shell_data: ::std::marker::PhantomData, +} + +impl ToplevelSurface +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, +{ + pub fn alive(&self) -> bool { + let shell_surface_alive = match self.shell_surface { + SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, + SurfaceKind::XdgToplevel(ref s) => s.status() == Liveness::Alive, + SurfaceKind::XdgPopup(_) => unreachable!(), + }; + shell_surface_alive && self.wl_surface.status() == Liveness::Alive + } + + pub fn equals(&self, other: &Self) -> bool { + self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) + } + + pub fn client(&self) -> ShellClient { + match self.shell_surface { + SurfaceKind::Wl(ref s) => { + let &(_, ref shell) = + unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; + ShellClient { + kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } + } + SurfaceKind::XdgToplevel(ref s) => { + let &(_, ref shell, _) = + unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; + ShellClient { + kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } + } + SurfaceKind::XdgPopup(_) => unreachable!(), + } + } + + pub fn send_configure(&self, cfg: ToplevelConfigure) -> EventResult<()> { + if !self.alive() { + return EventResult::Destroyed; + } + match self.shell_surface { + SurfaceKind::Wl(ref s) => self::wl_handlers::send_toplevel_configure(s, cfg), + SurfaceKind::XdgToplevel(ref s) => { + self::xdg_handlers::send_toplevel_configure(self.token, s, cfg) + } + SurfaceKind::XdgPopup(_) => unreachable!(), + } + EventResult::Sent(()) + } + + /// Make sure this surface was configured + /// + /// Returns `true` if it was, if not, returns `false` and raise + /// a protocol error to the associated client. Also returns `false` + /// if the surface is already destroyed. + /// + /// xdg_shell mandates that a client acks a configure before commiting + /// anything. + pub fn ensure_configured(&self) -> bool { + if !self.alive() { + return false; + } + let configured = self.token + .with_role_data::(&self.wl_surface, |data| data.configured) + .expect( + "A shell surface object exists but the surface does not have the shell_surface role ?!", + ); + if !configured { + if let SurfaceKind::XdgToplevel(ref s) = self.shell_surface { + let ptr = s.get_user_data(); + let &(_, _, ref xdg_surface) = + unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) }; + xdg_surface.post_error( + zxdg_surface_v6::Error::NotConstructed as u32, + "Surface has not been confgured yet.".into(), + ); + } else { + unreachable!(); + } + } + configured + } + + pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { + if self.alive() { + Some(&self.wl_surface) + } else { + None + } + } + + pub fn get_pending_state(&self) -> Option { + if !self.alive() { + return None; + } + self.token + .with_role_data::(&self.wl_surface, |data| match data.pending_state { + ShellSurfacePendingState::Toplevel(ref state) => Some(state.clone()), + _ => None, + }) + .ok() + .and_then(|x| x) + } +} + +pub struct PopupSurface { + wl_surface: wl_surface::WlSurface, + shell_surface: SurfaceKind, + token: CompositorToken, + _shell_data: ::std::marker::PhantomData, +} + +impl PopupSurface +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, +{ + pub fn alive(&self) -> bool { + let shell_surface_alive = match self.shell_surface { + SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, + SurfaceKind::XdgPopup(ref s) => s.status() == Liveness::Alive, + SurfaceKind::XdgToplevel(_) => unreachable!(), + }; + shell_surface_alive && self.wl_surface.status() == Liveness::Alive + } + + pub fn equals(&self, other: &Self) -> bool { + self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) + } + + pub fn client(&self) -> ShellClient { + match self.shell_surface { + SurfaceKind::Wl(ref s) => { + let &(_, ref shell) = + unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; + ShellClient { + kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } + } + SurfaceKind::XdgPopup(ref s) => { + let &(_, ref shell, _) = + unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; + ShellClient { + kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } + } + SurfaceKind::XdgToplevel(_) => unreachable!(), + } + } + + pub fn send_configure(&self, cfg: PopupConfigure) -> EventResult<()> { + if !self.alive() { + return EventResult::Destroyed; + } + match self.shell_surface { + SurfaceKind::Wl(ref s) => self::wl_handlers::send_popup_configure(s, cfg), + SurfaceKind::XdgPopup(ref s) => self::xdg_handlers::send_popup_configure(self.token, s, cfg), + SurfaceKind::XdgToplevel(_) => unreachable!(), + } + EventResult::Sent(()) + } + + pub fn send_popup_done(&self) -> EventResult<()> { + if !self.alive() { + return EventResult::Destroyed; + } + match self.shell_surface { + SurfaceKind::Wl(ref s) => s.popup_done(), + SurfaceKind::XdgPopup(ref s) => s.popup_done(), + SurfaceKind::XdgToplevel(_) => unreachable!(), + } + } + + pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { + if self.alive() { + Some(&self.wl_surface) + } else { + None + } + } + + pub fn get_pending_state(&self) -> Option { + if !self.alive() { + return None; + } + self.token + .with_role_data::(&self.wl_surface, |data| match data.pending_state { + ShellSurfacePendingState::Popup(ref state) => state.clone(), + _ => None, + }) + .ok() + .and_then(|x| x) + } +} + +pub struct ToplevelConfigure { + pub size: Option<(i32, i32)>, + pub states: Vec, + pub serial: u32, +} + +pub struct PopupConfigure { + pub position: (i32, i32), + pub size: (i32, i32), + pub serial: u32, +} + +pub trait Handler { + 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) + -> ToplevelConfigure; + fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface) + -> PopupConfigure; + fn move_(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, + seat: &wl_seat::WlSeat, serial: u32); + fn resize(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, + seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge); + fn grab(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface, + seat: &wl_seat::WlSeat, serial: u32); + fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, + maximized: Option, minimized: Option, fullscreen: Option, + output: Option<&wl_output::WlOutput>) + -> ToplevelConfigure; + fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, + seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32); +} diff --git a/src/shell/wl_handlers.rs b/src/shell/wl_handlers.rs new file mode 100644 index 0000000..89edb94 --- /dev/null +++ b/src/shell/wl_handlers.rs @@ -0,0 +1,365 @@ +use super::{Handler as UserHandler, PopupConfigure, PopupState, PositionerState, ShellClient, + ShellClientData, ShellHandler, ShellSurfacePendingState, ShellSurfaceRole, ToplevelConfigure, + ToplevelState}; + +use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle}; +use compositor::roles::*; + +use std::sync::Mutex; + +use wayland_protocols::unstable::xdg_shell::server::{zxdg_positioner_v6 as xdg_positioner, zxdg_toplevel_v6}; + +use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; + +pub struct WlShellDestructor { + _data: ::std::marker::PhantomData, +} + +/* + * wl_shell + */ + +pub type ShellUserData = Mutex<(ShellClientData, Vec)>; + +impl Destroy for WlShellDestructor { + fn destroy(shell: &wl_shell::WlShell) { + let ptr = shell.get_user_data(); + shell.set_user_data(::std::ptr::null_mut()); + let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; + } +} + +pub fn make_shell_client(resource: &wl_shell::WlShell) -> ShellClient { + ShellClient { + kind: super::ShellClientKind::Wl(unsafe { resource.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } +} + +impl wl_shell::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell::WlShell, id: wl_shell_surface::WlShellSurface, + surface: &wl_surface::WlSurface) { + trace!(self.log, "Creating new wl_shell_surface."); + let role_data = ShellSurfaceRole { + pending_state: ShellSurfacePendingState::None, + window_geometry: None, + pending_configures: Vec::new(), + configured: true, + }; + if let Err(_) = self.token.give_role_with(surface, role_data) { + resource.post_error( + wl_shell::Error::Role as u32, + "Surface already has a role.".into(), + ); + return; + } + id.set_user_data( + Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _, + ); + evqh.register_with_destructor::<_, Self, WlShellDestructor>(&id, self.my_id); + + // register ourselves to the wl_shell for ping handling + let mutex = unsafe { &*(resource.get_user_data() as *mut ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + if guard.1.len() == 0 && guard.0.pending_ping != 0 { + // 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 + // destroyed, because wl_shell_surface has no destructor! + id.ping(guard.0.pending_ping); + } + guard.1.push(id); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH:[UserHandler, Send], SD: [Send]>, + wl_shell::Handler, + wl_shell::WlShell +); + +/* + * wl_shell_surface + */ + +pub type ShellSurfaceUserData = (wl_surface::WlSurface, wl_shell::WlShell); + +impl Destroy for WlShellDestructor { + fn destroy(shell_surface: &wl_shell_surface::WlShellSurface) { + let ptr = shell_surface.get_user_data(); + shell_surface.set_user_data(::std::ptr::null_mut()); + // drop the WlSurface object + let surface = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + } +} + +fn make_toplevel_handle(token: CompositorToken, + resource: &wl_shell_surface::WlShellSurface) + -> super::ToplevelSurface { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + super::ToplevelSurface { + wl_surface: unsafe { wl_surface.clone_unchecked() }, + shell_surface: super::SurfaceKind::Wl(unsafe { resource.clone_unchecked() }), + token: token, + _shell_data: ::std::marker::PhantomData, + } +} + +fn make_popup_handle(token: CompositorToken, + resource: &wl_shell_surface::WlShellSurface) + -> super::PopupSurface { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + super::PopupSurface { + wl_surface: unsafe { wl_surface.clone_unchecked() }, + shell_surface: super::SurfaceKind::Wl(unsafe { resource.clone_unchecked() }), + token: token, + _shell_data: ::std::marker::PhantomData, + } +} + +pub fn send_toplevel_configure(resource: &wl_shell_surface::WlShellSurface, configure: ToplevelConfigure) { + let (w, h) = configure.size.unwrap_or((0, 0)); + resource.configure(wl_shell_surface::Resize::empty(), w, h); +} + +pub fn send_popup_configure(resource: &wl_shell_surface::WlShellSurface, configure: PopupConfigure) { + let (w, h) = configure.size; + resource.configure(wl_shell_surface::Resize::empty(), w, h); +} + +impl ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn wl_handle_display_state_change(&mut self, evqh: &mut EventLoopHandle, + resource: &wl_shell_surface::WlShellSurface, + maximized: Option, minimized: Option, + fullscreen: Option, output: Option<&wl_output::WlOutput>) { + let handle = make_toplevel_handle(self.token, resource); + // handler callback + let configure = + self.handler + .change_display_state(evqh, handle, maximized, minimized, fullscreen, output); + // send the configure response to client + let (w, h) = configure.size.unwrap_or((0, 0)); + resource.configure(wl_shell_surface::None, w, h); + } + + fn wl_ensure_toplevel(&mut self, evqh: &mut EventLoopHandle, + resource: &wl_shell_surface::WlShellSurface) { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + // copy token to make borrow checker happy + let token = self.token; + let need_send = token + .with_role_data::(wl_surface, |data| { + match data.pending_state { + ShellSurfacePendingState::Toplevel(_) => { + return false; + } + ShellSurfacePendingState::Popup(_) => { + // this is no longer a popup, deregister it + self.known_popups.retain(|other| { + other + .get_surface() + .map(|s| !s.equals(wl_surface)) + .unwrap_or(false) + }); + } + ShellSurfacePendingState::None => {} + } + // This was not previously toplevel, need to make it toplevel + data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState { + parent: None, + title: String::new(), + app_id: String::new(), + min_size: (0, 0), + max_size: (0, 0), + }); + return true; + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + // we need to notify about this new toplevel surface + if need_send { + let handle = make_toplevel_handle(self.token, resource); + let configure = self.handler.new_toplevel(evqh, handle); + send_toplevel_configure(resource, configure); + } + } +} + +impl wl_shell_surface::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn pong(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, serial: u32) { + let &(_, ref shell) = unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let valid = { + let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + if guard.0.pending_ping == serial { + guard.0.pending_ping = 0; + true + } else { + false + } + }; + if valid { + self.handler.client_pong(evqh, make_shell_client(shell)); + } + } + + fn move_(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32) { + let handle = make_toplevel_handle(self.token, resource); + self.handler.move_(evqh, handle, seat, serial); + } + + fn resize(&mut self, evqh: &mut EventLoopHandle, client: &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()) + .unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); + let handle = make_toplevel_handle(self.token, resource); + self.handler.resize(evqh, handle, seat, serial, edges); + } + + fn set_toplevel(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface) { + self.wl_ensure_toplevel(evqh, resource); + self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(false), None) + } + + fn set_transient(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, parent: &wl_surface::WlSurface, x: i32, + y: i32, flags: wl_shell_surface::Transient) { + self.wl_ensure_toplevel(evqh, resource); + // set the parent + let ptr = resource.get_user_data(); + let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + self.token + .with_role_data::(wl_surface, |data| match data.pending_state { + ShellSurfacePendingState::Toplevel(ref mut state) => { + state.parent = Some(unsafe { parent.clone_unchecked() }); + } + _ => unreachable!(), + }) + .unwrap(); + // set as regular surface + self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(false), None) + } + + fn set_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, + method: wl_shell_surface::FullscreenMethod, framerate: u32, + output: Option<&wl_output::WlOutput>) { + self.wl_ensure_toplevel(evqh, resource); + self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(true), output) + } + + fn set_popup(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32, + parent: &wl_surface::WlSurface, x: i32, y: i32, flags: wl_shell_surface::Transient) { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + // we are reseting the popup state, so remove this surface from everywhere + self.known_toplevels.retain(|other| { + other + .get_surface() + .map(|s| !s.equals(wl_surface)) + .unwrap_or(false) + }); + self.known_popups.retain(|other| { + other + .get_surface() + .map(|s| !s.equals(wl_surface)) + .unwrap_or(false) + }); + self.token + .with_role_data(wl_surface, |data| { + data.pending_state = ShellSurfacePendingState::Popup(PopupState { + parent: unsafe { parent.clone_unchecked() }, + positioner: PositionerState { + rect_size: (1, 1), + anchor_rect: Rectangle { + x, + y, + width: 1, + height: 1, + }, + anchor_edges: xdg_positioner::Anchor::empty(), + gravity: xdg_positioner::Gravity::empty(), + constraint_adjustment: xdg_positioner::ConstraintAdjustment::empty(), + offset: (0, 0), + }, + }); + }) + .expect("wl_shell_surface exists but wl_surface has wrong role?!"); + + // notify the handler about this new popup + let handle = make_popup_handle(self.token, resource); + let configure = self.handler.new_popup(evqh, handle); + send_popup_configure(resource, configure); + } + + fn set_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, output: Option<&wl_output::WlOutput>) { + self.wl_ensure_toplevel(evqh, resource); + self.wl_handle_display_state_change(evqh, resource, Some(true), Some(false), Some(false), output) + } + + fn set_title(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, title: String) { + let ptr = resource.get_user_data(); + let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + self.token + .with_role_data(surface, |data| match data.pending_state { + ShellSurfacePendingState::Toplevel(ref mut state) => { + state.title = title; + } + _ => {} + }) + .expect("wl_shell_surface exists but wl_surface has wrong role?!"); + } + + fn set_class(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, class_: String) { + let ptr = resource.get_user_data(); + let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + self.token + .with_role_data(surface, |data| match data.pending_state { + ShellSurfacePendingState::Toplevel(ref mut state) => { + state.app_id = class_; + } + _ => {} + }) + .expect("wl_shell_surface exists but wl_surface has wrong role?!"); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + wl_shell_surface::Handler, + wl_shell_surface::WlShellSurface +); diff --git a/src/shell/xdg_handlers.rs b/src/shell/xdg_handlers.rs new file mode 100644 index 0000000..50c92a7 --- /dev/null +++ b/src/shell/xdg_handlers.rs @@ -0,0 +1,731 @@ +use super::{Handler as UserHandler, PopupConfigure, PopupState, PositionerState, ShellClient, + ShellClientData, ShellHandler, ShellSurfacePendingState, ShellSurfaceRole, ToplevelConfigure, + ToplevelState}; + +use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle}; +use compositor::roles::*; + +use std::sync::Mutex; + +use wayland_protocols::unstable::xdg_shell::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6, + zxdg_surface_v6, zxdg_toplevel_v6}; +use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +use wayland_server::protocol::{wl_output, wl_seat, wl_surface}; + +pub struct XdgShellDestructor { + _data: ::std::marker::PhantomData, +} + +/* + * xdg_shell + */ + +pub type ShellUserData = Mutex>; + +impl Destroy for XdgShellDestructor { + fn destroy(shell: &zxdg_shell_v6::ZxdgShellV6) { + let ptr = shell.get_user_data(); + shell.set_user_data(::std::ptr::null_mut()); + let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; + } +} + +pub fn make_shell_client(resource: &zxdg_shell_v6::ZxdgShellV6) -> ShellClient { + ShellClient { + kind: super::ShellClientKind::Xdg(unsafe { resource.clone_unchecked() }), + _data: ::std::marker::PhantomData, + } +} + +impl zxdg_shell_v6::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_shell_v6::ZxdgShellV6) { + } + fn create_positioner(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_positioner_v6::ZxdgPositionerV6) { + trace!(self.log, "Creating new xdg_positioner."); + id.set_user_data(Box::into_raw(Box::new(PositionerState { + rect_size: (0, 0), + anchor_rect: Rectangle { + x: 0, + y: 0, + width: 0, + height: 0, + }, + anchor_edges: zxdg_positioner_v6::Anchor::empty(), + gravity: zxdg_positioner_v6::Gravity::empty(), + constraint_adjustment: zxdg_positioner_v6::ConstraintAdjustment::empty(), + offset: (0, 0), + })) as *mut _); + evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + } + fn get_xdg_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_surface_v6::ZxdgSurfaceV6, + surface: &wl_surface::WlSurface) { + trace!(self.log, "Creating new wl_shell_surface."); + let role_data = ShellSurfaceRole { + pending_state: ShellSurfacePendingState::None, + window_geometry: None, + pending_configures: Vec::new(), + configured: false, + }; + if let Err(_) = self.token.give_role_with(surface, role_data) { + resource.post_error( + zxdg_shell_v6::Error::Role as u32, + "Surface already has a role.".into(), + ); + return; + } + id.set_user_data( + Box::into_raw(Box::new((unsafe { surface.clone_unchecked() }, unsafe { + resource.clone_unchecked() + }))) as *mut _, + ); + evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + } + + fn pong(&mut self, evqh: &mut EventLoopHandle, client: &Client, resource: &zxdg_shell_v6::ZxdgShellV6, + serial: u32) { + let valid = { + let mutex = unsafe { &*(resource.get_user_data() as *mut ShellUserData) }; + let mut guard = mutex.lock().unwrap(); + if guard.pending_ping == serial { + guard.pending_ping = 0; + true + } else { + false + } + }; + if valid { + self.handler.client_pong(evqh, make_shell_client(resource)); + } + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + zxdg_shell_v6::Handler, + zxdg_shell_v6::ZxdgShellV6 +); + +/* + * xdg_positioner + */ + +impl Destroy for XdgShellDestructor { + fn destroy(positioner: &zxdg_positioner_v6::ZxdgPositionerV6) { + let ptr = positioner.get_user_data(); + positioner.set_user_data(::std::ptr::null_mut()); + // drop the PositionerState + let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) }; + } +} + +impl zxdg_positioner_v6::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_positioner_v6::ZxdgPositionerV6) { + } + + fn set_size(&mut self, evqh: &mut EventLoopHandle, client: &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, + "Invalid size for positioner.".into(), + ); + } else { + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.rect_size = (width, height); + } + } + + fn set_anchor_rect(&mut self, evqh: &mut EventLoopHandle, client: &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, + "Invalid size for positioner's anchor rectangle.".into(), + ); + } else { + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.anchor_rect = Rectangle { + x, + y, + width, + height, + }; + } + } + + fn set_anchor(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_positioner_v6::ZxdgPositionerV6, anchor: zxdg_positioner_v6::Anchor) { + use self::zxdg_positioner_v6::{AnchorBottom, AnchorLeft, AnchorRight, AnchorTop}; + if anchor.contains(AnchorLeft | AnchorRight) || anchor.contains(AnchorTop | AnchorBottom) { + resource.post_error( + zxdg_positioner_v6::Error::InvalidInput as u32, + "Invalid anchor for positioner.".into(), + ); + } else { + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.anchor_edges = anchor; + } + } + + fn set_gravity(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_positioner_v6::ZxdgPositionerV6, gravity: zxdg_positioner_v6::Gravity) { + use self::zxdg_positioner_v6::{GravityBottom, GravityLeft, GravityRight, GravityTop}; + if gravity.contains(GravityLeft | GravityRight) || gravity.contains(GravityTop | GravityBottom) { + resource.post_error( + zxdg_positioner_v6::Error::InvalidInput as u32, + "Invalid gravity for positioner.".into(), + ); + } else { + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.gravity = gravity; + } + } + + fn set_constraint_adjustment(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_positioner_v6::ZxdgPositionerV6, + constraint_adjustment: u32) { + let constraint_adjustment = + zxdg_positioner_v6::ConstraintAdjustment::from_bits_truncate(constraint_adjustment); + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.constraint_adjustment = constraint_adjustment; + } + + fn set_offset(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_positioner_v6::ZxdgPositionerV6, x: i32, y: i32) { + let ptr = resource.get_user_data(); + let state = unsafe { &mut *(ptr as *mut PositionerState) }; + state.offset = (x, y); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + zxdg_positioner_v6::Handler, + zxdg_positioner_v6::ZxdgPositionerV6 +); + +/* + * xdg_surface + */ + +impl Destroy for XdgShellDestructor { + fn destroy(surface: &zxdg_surface_v6::ZxdgSurfaceV6) { + let ptr = surface.get_user_data(); + surface.set_user_data(::std::ptr::null_mut()); + // drop the PositionerState + let data = unsafe { + Box::from_raw( + ptr as *mut (zxdg_surface_v6::ZxdgSurfaceV6, zxdg_shell_v6::ZxdgShellV6), + ) + }; + } +} + +impl zxdg_surface_v6::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_surface_v6::ZxdgSurfaceV6) { + let ptr = resource.get_user_data(); + let &(ref surface, ref shell) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + self.token + .with_role_data::(surface, |data| { + if let ShellSurfacePendingState::None = data.pending_state { + // all is good + } else { + shell.post_error( + zxdg_shell_v6::Error::Role as u32, + "xdg_surface was destroyed before its role object".into(), + ); + } + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + } + + fn get_toplevel(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_toplevel_v6::ZxdgToplevelV6) { + let ptr = resource.get_user_data(); + let &(ref surface, ref shell) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + self.token + .with_role_data::(surface, |data| { + data.pending_state = ShellSurfacePendingState::Toplevel(ToplevelState { + parent: None, + title: String::new(), + app_id: String::new(), + min_size: (0, 0), + max_size: (0, 0), + }); + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + + id.set_user_data(Box::into_raw(Box::new(unsafe { + ( + surface.clone_unchecked(), + shell.clone_unchecked(), + resource.clone_unchecked(), + ) + })) as *mut _); + evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + + // register to self + self.known_toplevels + .push(make_toplevel_handle(self.token, &id)); + + // intial configure event + let handle = make_toplevel_handle(self.token, &id); + let configure = self.handler.new_toplevel(evqh, handle); + send_toplevel_configure(self.token, &id, configure); + } + + fn get_popup(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_popup_v6::ZxdgPopupV6, + parent: &zxdg_surface_v6::ZxdgSurfaceV6, + positioner: &zxdg_positioner_v6::ZxdgPositionerV6) { + let ptr = resource.get_user_data(); + let &(ref surface, ref shell) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + + let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) }; + + let parent_ptr = parent.get_user_data(); + let &(ref parent_surface, _) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + + self.token + .with_role_data::(surface, |data| { + data.pending_state = ShellSurfacePendingState::Popup(PopupState { + parent: unsafe { parent_surface.clone_unchecked() }, + positioner: positioner_data.clone(), + }); + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + + id.set_user_data(Box::into_raw(Box::new(unsafe { + ( + surface.clone_unchecked(), + shell.clone_unchecked(), + resource.clone_unchecked(), + ) + })) as *mut _); + evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + + // register to self + self.known_popups.push(make_popup_handle(self.token, &id)); + + // intial configure event + let handle = make_popup_handle(self.token, &id); + let configure = self.handler.new_popup(evqh, handle); + send_popup_configure(self.token, &id, configure); + } + + fn set_window_geometry(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_surface_v6::ZxdgSurfaceV6, x: i32, y: i32, width: i32, + height: i32) { + let ptr = resource.get_user_data(); + let &(ref surface, _) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + self.token + .with_role_data::(surface, |data| { + data.window_geometry = Some(Rectangle { + x, + y, + width, + height, + }); + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + } + + fn ack_configure(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_surface_v6::ZxdgSurfaceV6, serial: u32) { + let ptr = resource.get_user_data(); + let &(ref surface, ref shell) = + unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + self.token + .with_role_data::(surface, |data| { + let mut found = false; + data.pending_configures.retain(|&s| { + if s == serial { + found = true; + } + s > serial + }); + if !found { + // client responded to a non-existing configure + shell.post_error( + zxdg_shell_v6::Error::InvalidSurfaceState as u32, + format!("Wrong configure serial: {}", serial), + ); + } + data.configured = true; + }) + .expect( + "xdg_surface exists but surface has not shell_surface role?!", + ); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + zxdg_surface_v6::Handler, + zxdg_surface_v6::ZxdgSurfaceV6 +); + +/* + * xdg_toplevel + */ + +pub type ShellSurfaceUserData = ( + wl_surface::WlSurface, + zxdg_shell_v6::ZxdgShellV6, + zxdg_surface_v6::ZxdgSurfaceV6, +); + +impl Destroy for XdgShellDestructor { + fn destroy(surface: &zxdg_toplevel_v6::ZxdgToplevelV6) { + let ptr = surface.get_user_data(); + surface.set_user_data(::std::ptr::null_mut()); + // drop the PositionerState + let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + } +} + +impl ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + // Utility function allowing to factor out a lot of the upcoming logic + fn with_surface_toplevel_data(&self, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, f: F) + where + F: FnOnce(&mut ToplevelState), + { + let ptr = resource.get_user_data(); + let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + self.token + .with_role_data::(surface, |data| match data.pending_state { + ShellSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data), + _ => unreachable!(), + }) + .expect( + "xdg_toplevel exists but surface has not shell_surface role?!", + ); + } + + fn xdg_handle_display_state_change(&mut self, evqh: &mut EventLoopHandle, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, + maximized: Option, minimized: Option, + fullscreen: Option, output: Option<&wl_output::WlOutput>) { + let handle = make_toplevel_handle(self.token, resource); + // handler callback + let configure = + self.handler + .change_display_state(evqh, handle, maximized, minimized, fullscreen, output); + // send the configure response to client + send_toplevel_configure(self.token, resource, configure); + } +} + +pub fn send_toplevel_configure(token: CompositorToken, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, + configure: ToplevelConfigure) +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, +{ + let &(ref surface, _, ref shell_surface) = + unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let (w, h) = configure.size.unwrap_or((0, 0)); + // convert the Vec (which is really a Vec) into Vec + let states = { + let mut states = configure.states; + let ptr = states.as_mut_ptr(); + let len = states.len(); + let cap = states.capacity(); + ::std::mem::forget(states); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + let serial = configure.serial; + resource.configure(w, h, states); + shell_surface.configure(serial); + // Add the configure as pending + token + .with_role_data::(surface, |data| data.pending_configures.push(serial)) + .expect( + "xdg_toplevel exists but surface has not shell_surface role?!", + ); +} + +fn make_toplevel_handle(token: CompositorToken, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) + -> super::ToplevelSurface { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + super::ToplevelSurface { + wl_surface: unsafe { wl_surface.clone_unchecked() }, + shell_surface: super::SurfaceKind::XdgToplevel(unsafe { resource.clone_unchecked() }), + token: token, + _shell_data: ::std::marker::PhantomData, + } +} + +impl zxdg_toplevel_v6::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + let ptr = resource.get_user_data(); + let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + self.token + .with_role_data::(surface, |data| { + data.pending_state = ShellSurfacePendingState::None; + data.configured = false; + }) + .expect( + "xdg_toplevel exists but surface has not shell_surface role?!", + ); + // remove this surface from the known ones (as well as any leftover dead surface) + self.known_toplevels.retain(|other| { + other + .get_surface() + .map(|s| !s.equals(surface)) + .unwrap_or(false) + }); + } + + fn set_parent(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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| { + let parent_ptr = toplevel_surface_parent.get_user_data(); + let &(ref parent_surface, _) = + unsafe { &*(parent_ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + unsafe { parent_surface.clone_unchecked() } + }) + }); + } + + fn set_title(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, title: String) { + self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.title = title; }); + } + + fn set_app_id(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, app_id: String) { + self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.app_id = app_id; }); + } + + fn show_window_menu(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32, + x: i32, y: i32) { + let handle = make_toplevel_handle(self.token, resource); + self.handler + .show_window_menu(evqh, handle, seat, serial, x, y); + } + + fn move_(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32) { + let handle = make_toplevel_handle(self.token, resource); + self.handler.move_(evqh, handle, seat, serial); + } + + fn resize(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32, edges: u32) { + let edges = + zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); + let handle = make_toplevel_handle(self.token, resource); + self.handler.resize(evqh, handle, seat, serial, edges); + } + + fn set_max_size(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) { + self.with_surface_toplevel_data(resource, |toplevel_data| { + toplevel_data.max_size = (width, height); + }); + } + + fn set_min_size(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) { + self.with_surface_toplevel_data(resource, |toplevel_data| { + toplevel_data.min_size = (width, height); + }); + } + + fn set_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + self.xdg_handle_display_state_change(evqh, resource, Some(true), None, None, None); + } + + fn unset_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + self.xdg_handle_display_state_change(evqh, resource, Some(false), None, None, None); + } + + fn set_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6, output: Option<&wl_output::WlOutput>) { + self.xdg_handle_display_state_change(evqh, resource, None, None, Some(true), output); + } + + fn unset_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + self.xdg_handle_display_state_change(evqh, resource, None, None, Some(false), None); + } + + fn set_minimized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + self.xdg_handle_display_state_change(evqh, resource, None, Some(true), None, None); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + zxdg_toplevel_v6::Handler, + zxdg_toplevel_v6::ZxdgToplevelV6 +); + +/* + * xdg_popup + */ + + + +impl Destroy for XdgShellDestructor { + fn destroy(surface: &zxdg_popup_v6::ZxdgPopupV6) { + let ptr = surface.get_user_data(); + surface.set_user_data(::std::ptr::null_mut()); + // drop the PositionerState + let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + } +} + +pub fn send_popup_configure(token: CompositorToken, resource: &zxdg_popup_v6::ZxdgPopupV6, + configure: PopupConfigure) +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, +{ + let &(ref surface, _, ref shell_surface) = + unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let (x, y) = configure.position; + let (w, h) = configure.size; + let serial = configure.serial; + resource.configure(x, y, w, h); + shell_surface.configure(serial); + // Add the configure as pending + token + .with_role_data::(surface, |data| data.pending_configures.push(serial)) + .expect( + "xdg_toplevel exists but surface has not shell_surface role?!", + ); +} + +fn make_popup_handle(token: CompositorToken, resource: &zxdg_popup_v6::ZxdgPopupV6) + -> super::PopupSurface { + let ptr = resource.get_user_data(); + let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + super::PopupSurface { + wl_surface: unsafe { wl_surface.clone_unchecked() }, + shell_surface: super::SurfaceKind::XdgPopup(unsafe { resource.clone_unchecked() }), + token: token, + _shell_data: ::std::marker::PhantomData, + } +} + +impl zxdg_popup_v6::Handler for ShellHandler +where + U: Send + 'static, + R: Role + Send + 'static, + H: CompositorHandler + Send + 'static, + SH: UserHandler + Send + 'static, + SD: Send + 'static, +{ + fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &zxdg_popup_v6::ZxdgPopupV6) { + let ptr = resource.get_user_data(); + let &(ref surface, _, _) = unsafe { + &*(ptr as + *mut ( + wl_surface::WlSurface, + zxdg_shell_v6::ZxdgShellV6, + zxdg_surface_v6::ZxdgSurfaceV6, + )) + }; + self.token + .with_role_data::(surface, |data| { + data.pending_state = ShellSurfacePendingState::None; + data.configured = false; + }) + .expect( + "xdg_toplevel exists but surface has not shell_surface role?!", + ); + // remove this surface from the known ones (as well as any leftover dead surface) + self.known_popups.retain(|other| { + other + .get_surface() + .map(|s| !s.equals(surface)) + .unwrap_or(false) + }); + } + + fn grab(&mut self, evqh: &mut EventLoopHandle, client: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6, + seat: &wl_seat::WlSeat, serial: u32) { + let handle = make_popup_handle(self.token, resource); + self.handler.grab(evqh, handle, seat, serial); + } +} + +server_declare_handler!( + ShellHandler, Send], H:[CompositorHandler, Send], SH: [UserHandler, Send], SD: [Send]>, + zxdg_popup_v6::Handler, + zxdg_popup_v6::ZxdgPopupV6 +); From 00c9a0c6950cdd535468fbb89606f0efa93629f7 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 19:50:41 +0200 Subject: [PATCH 03/13] travis: use rustfmt-nightly --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 65c23e2..57cf7e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,15 +30,15 @@ branches: before_script: - export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH - - which rustfmt || cargo install rustfmt + - pip install 'travis-cargo<0.2' --user + - which rustfmt || travis-cargo --only nightly install rustfmt-nightly - which cargo-install-update || cargo install cargo-update - cargo install-update -a - - pip install 'travis-cargo<0.2' --user - mkdir $(pwd)/socket - export XDG_RUNTIME_DIR="$(pwd)/socket" script: - - cargo fmt -- --write-mode=diff + - travis-cargo --only nightly fmt -- --write-mode=diff - travis-cargo --skip nightly build - travis-cargo --only nightly build -- --features "clippy" - travis-cargo --only stable doc -- --no-deps From 88773cf1b326e798df5e7b850a0e1f0d42992b49 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 19:51:05 +0200 Subject: [PATCH 04/13] cargo fmt --- examples/helpers/glium.rs | 6 +- examples/helpers/shell.rs | 23 ++---- examples/simple.rs | 53 ++++++------ src/backend/graphics/egl.rs | 61 +++++++------- src/backend/libinput.rs | 71 ++++++++-------- src/backend/winit.rs | 159 ++++++++++++++++++++---------------- src/compositor/global.rs | 12 +-- src/compositor/handlers.rs | 24 +++--- src/compositor/mod.rs | 14 ++-- src/compositor/region.rs | 6 +- src/compositor/tree.rs | 20 ++--- src/keyboard/mod.rs | 17 ++-- src/shm/mod.rs | 13 ++- src/shm/pool.rs | 2 +- 14 files changed, 235 insertions(+), 246 deletions(-) diff --git a/examples/helpers/glium.rs b/examples/helpers/glium.rs index 23a8278..d407b46 100644 --- a/examples/helpers/glium.rs +++ b/examples/helpers/glium.rs @@ -19,7 +19,6 @@ pub struct GliumDrawer<'a, F: 'a> { impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { pub fn new(display: &'a F) -> GliumDrawer<'a, F> { - // building the vertex buffer, which contains all the vertices that we will draw let vertex_buffer = glium::VertexBuffer::new( display, @@ -87,7 +86,6 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { pub fn draw(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32), surface_location: (i32, i32), screen_size: (u32, u32)) { - let image = glium::texture::RawImage2d { data: contents.into(), width: surface_dimensions.0, @@ -102,8 +100,7 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { let x = 2.0 * (surface_location.0 as f32) / (screen_size.0 as f32) - 1.0; let y = 1.0 - 2.0 * (surface_location.1 as f32) / (screen_size.1 as f32); - let uniforms = - uniform! { + let uniforms = uniform! { matrix: [ [xscale, 0.0 , 0.0, 0.0], [ 0.0 , yscale , 0.0, 0.0], @@ -122,6 +119,5 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { &Default::default(), ) .unwrap(); - } } diff --git a/examples/helpers/shell.rs b/examples/helpers/shell.rs index e640b0d..e3d9b14 100644 --- a/examples/helpers/shell.rs +++ b/examples/helpers/shell.rs @@ -44,20 +44,14 @@ impl Init for WlShellStubHandler { impl GlobalHandler for WlShellStubHandler where U: Send + 'static, - R: RoleType - + Role - + Send - + 'static, - H: CompositorHandler - + Send - + 'static, + R: RoleType + Role + Send + 'static, + H: CompositorHandler + Send + 'static, { fn bind(&mut self, evqh: &mut EventLoopHandle, client: &Client, global: wl_shell::WlShell) { evqh.register::<_, Self>( &global, - self.my_id.expect( - "WlShellStubHandler was not properly initialized.", - ), + self.my_id + .expect("WlShellStubHandler was not properly initialized."), ); } } @@ -65,10 +59,7 @@ where impl wl_shell::Handler for WlShellStubHandler where U: Send + 'static, - R: RoleType - + Role - + Send - + 'static, + R: RoleType + Role + Send + 'static, H: CompositorHandler + Send + 'static, { fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, @@ -95,9 +86,7 @@ server_declare_handler!(WlShellStubHandler wl_shell_surface::Handler for WlShellStubHandler where U: Send + 'static, - H: CompositorHandler - + Send - + 'static, + H: CompositorHandler + Send + 'static, { } diff --git a/examples/simple.rs b/examples/simple.rs index ea8723a..8635357 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,9 +1,9 @@ -#[macro_use(server_declare_handler)] -extern crate wayland_server; -#[macro_use(define_roles)] -extern crate smithay; #[macro_use] extern crate glium; +#[macro_use(define_roles)] +extern crate smithay; +#[macro_use(server_declare_handler)] +extern crate wayland_server; #[macro_use] extern crate slog; @@ -59,7 +59,6 @@ impl compositor::Handler for SurfaceHandler { attributes.user_data.buffer = Some((new_vec, (data.width as u32, data.height as u32))); }); - } Some(None) => { // erase the contents @@ -104,7 +103,9 @@ fn main() { * Initialize the compositor global */ let compositor_handler_id = event_loop.add_handler_with_init(MyCompositorHandler::new( - SurfaceHandler { shm_token: shm_token.clone() }, + SurfaceHandler { + shm_token: shm_token.clone(), + }, log.clone(), )); // register it to handle wl_compositor and wl_subcompositor @@ -151,32 +152,32 @@ fn main() { { let screen_dimensions = context.get_framebuffer_dimensions(); let state = event_loop.state(); - for &(_, ref surface) in - state - .get_handler::>(shell_handler_id) - .surfaces() + for &(_, ref surface) in state + .get_handler::>(shell_handler_id) + .surfaces() { if surface.status() != Liveness::Alive { continue; } // this surface is a root of a subsurface tree that needs to be drawn - compositor_token.with_surface_tree(surface, (100, 100), |surface, - attributes, - role, - &(mut x, mut y)| { - if let Some((ref contents, (w, h))) = attributes.user_data.buffer { - // there is actually something to draw ! - if let Ok(subdata) = Role::::data(role) { - x += subdata.x; - y += subdata.y; + compositor_token.with_surface_tree( + surface, + (100, 100), + |surface, attributes, role, &(mut x, mut y)| { + if let Some((ref contents, (w, h))) = attributes.user_data.buffer { + // there is actually something to draw ! + if let Ok(subdata) = Role::::data(role) { + x += subdata.x; + y += subdata.y; + } + drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + TraversalAction::DoChildren((x, y)) + } else { + // we are not display, so our children are neither + TraversalAction::SkipChildren } - drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); - TraversalAction::DoChildren((x, y)) - } else { - // we are not display, so our children are neither - TraversalAction::SkipChildren - } - }); + }, + ); } } frame.finish().unwrap(); diff --git a/src/backend/graphics/egl.rs b/src/backend/graphics/egl.rs index bfd33ad..b6c5e51 100644 --- a/src/backend/graphics/egl.rs +++ b/src/backend/graphics/egl.rs @@ -116,11 +116,11 @@ impl error::Error for CreationError { CreationError::OsError(ref text) => text, CreationError::OpenGlVersionNotSupported => { "The requested OpenGL version is not \ - supported." + supported." } CreationError::NoAvailablePixelFormat => { "Couldn't find any pixel format that matches \ - the criterias." + the criterias." } CreationError::NonMatchingSurfaceType => "Surface type does not match the context type.", CreationError::NotSupported => "Context creation is not supported on the current window system", @@ -244,31 +244,36 @@ impl EGLContext { let display = match native { NativeDisplay::X11(display) - if has_dp_extension("EGL_KHR_platform_x11") && egl.GetPlatformDisplay.is_loaded() => { + if has_dp_extension("EGL_KHR_platform_x11") && egl.GetPlatformDisplay.is_loaded() => + { trace!(log, "EGL Display Initialization via EGL_KHR_platform_x11"); egl.GetPlatformDisplay(ffi::egl::PLATFORM_X11_KHR, display as *mut _, ptr::null()) } NativeDisplay::X11(display) - if has_dp_extension("EGL_EXT_platform_x11") && egl.GetPlatformDisplayEXT.is_loaded() => { + if has_dp_extension("EGL_EXT_platform_x11") && egl.GetPlatformDisplayEXT.is_loaded() => + { trace!(log, "EGL Display Initialization via EGL_EXT_platform_x11"); egl.GetPlatformDisplayEXT(ffi::egl::PLATFORM_X11_EXT, display as *mut _, ptr::null()) } NativeDisplay::Gbm(display) - if has_dp_extension("EGL_KHR_platform_gbm") && egl.GetPlatformDisplay.is_loaded() => { + if has_dp_extension("EGL_KHR_platform_gbm") && egl.GetPlatformDisplay.is_loaded() => + { trace!(log, "EGL Display Initialization via EGL_KHR_platform_gbm"); egl.GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null()) } NativeDisplay::Gbm(display) - if has_dp_extension("EGL_MESA_platform_gbm") && egl.GetPlatformDisplayEXT.is_loaded() => { + if has_dp_extension("EGL_MESA_platform_gbm") && egl.GetPlatformDisplayEXT.is_loaded() => + { trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); egl.GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null()) } NativeDisplay::Wayland(display) - if has_dp_extension("EGL_KHR_platform_wayland") && egl.GetPlatformDisplay.is_loaded() => { + if has_dp_extension("EGL_KHR_platform_wayland") && egl.GetPlatformDisplay.is_loaded() => + { trace!( log, "EGL Display Initialization via EGL_KHR_platform_wayland" @@ -281,7 +286,8 @@ impl EGLContext { } NativeDisplay::Wayland(display) - if has_dp_extension("EGL_EXT_platform_wayland") && egl.GetPlatformDisplayEXT.is_loaded() => { + if has_dp_extension("EGL_EXT_platform_wayland") && egl.GetPlatformDisplayEXT.is_loaded() => + { trace!( log, "EGL Display Initialization via EGL_EXT_platform_wayland" @@ -293,9 +299,7 @@ impl EGLContext { ) } - NativeDisplay::X11(display) | - NativeDisplay::Gbm(display) | - NativeDisplay::Wayland(display) => { + NativeDisplay::X11(display) | NativeDisplay::Gbm(display) | NativeDisplay::Wayland(display) => { trace!(log, "Default EGL Display Initialization via GetDisplay"); egl.GetDisplay(display as *mut _) } @@ -522,7 +526,6 @@ impl EGLContext { context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32); context_attributes.push(0); - } else if egl_version >= (1, 3) { trace!(log, "Setting CONTEXT_CLIENT_VERSION to {}", version.0); context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); @@ -602,14 +605,12 @@ impl EGLContext { let surface = match (native, self.backend_type) { (NativeSurface::X11(window), NativeType::X11) | (NativeSurface::Wayland(window), NativeType::Wayland) | - (NativeSurface::Gbm(window), NativeType::Gbm) => { - self.egl.CreateWindowSurface( - self.display, - self.config_id, - window, - self.surface_attributes.as_ptr(), - ) - } + (NativeSurface::Gbm(window), NativeType::Gbm) => self.egl.CreateWindowSurface( + self.display, + self.config_id, + window, + self.surface_attributes.as_ptr(), + ), _ => return Err(CreationError::NonMatchingSurfaceType), }; @@ -654,10 +655,9 @@ impl<'a> EGLSurface<'a> { /// Swaps buffers at the end of a frame. pub fn swap_buffers(&self) -> Result<(), SwapBuffersError> { let ret = unsafe { - self.context.egl.SwapBuffers( - self.context.display as *const _, - self.surface as *const _, - ) + self.context + .egl + .SwapBuffers(self.context.display as *const _, self.surface as *const _) }; if ret == 0 { @@ -705,10 +705,8 @@ impl Drop for EGLContext { unsafe { // we don't call MakeCurrent(0, 0) because we are not sure that the context // is still the current one - self.egl.DestroyContext( - self.display as *const _, - self.context as *const _, - ); + self.egl + .DestroyContext(self.display as *const _, self.context as *const _); self.egl.Terminate(self.display as *const _); } } @@ -717,10 +715,9 @@ impl Drop for EGLContext { impl<'a> Drop for EGLSurface<'a> { fn drop(&mut self) { unsafe { - self.context.egl.DestroySurface( - self.context.display as *const _, - self.surface as *const _, - ); + self.context + .egl + .DestroySurface(self.context.display as *const _, self.surface as *const _); } } } diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 65ceb4e..4cbad35 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -87,10 +87,10 @@ impl<'a> backend::PointerAxisEvent for PointerAxisEvent { fn amount(&self) -> f64 { match self.source() { - backend::AxisSource::Finger | - backend::AxisSource::Continuous => self.event.axis_value(self.axis), - backend::AxisSource::Wheel | - backend::AxisSource::WheelTilt => self.event.axis_value_discrete(self.axis).unwrap(), + backend::AxisSource::Finger | backend::AxisSource::Continuous => self.event.axis_value(self.axis), + backend::AxisSource::Wheel | backend::AxisSource::WheelTilt => { + self.event.axis_value_discrete(self.axis).unwrap() + } } } } @@ -271,9 +271,9 @@ impl backend::InputBackend for LibinputInputBackend { } fn get_handler(&mut self) -> Option<&mut backend::InputHandler> { - self.handler.as_mut().map(|handler| { - handler as &mut backend::InputHandler - }) + self.handler + .as_mut() + .map(|handler| handler as &mut backend::InputHandler) } fn clear_handler(&mut self) { @@ -349,21 +349,18 @@ impl backend::InputBackend for LibinputInputBackend { // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`. if let Some(seat) = self.seats.get_mut(&device_seat) { let caps = seat.capabilities_mut(); - caps.pointer = - self.devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Pointer)); - caps.keyboard = - self.devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Keyboard)); - caps.touch = - self.devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); + caps.pointer = self.devices + .iter() + .filter(|x| x.seat() == device_seat) + .any(|x| x.has_capability(libinput::DeviceCapability::Pointer)); + caps.keyboard = self.devices + .iter() + .filter(|x| x.seat() == device_seat) + .any(|x| x.has_capability(libinput::DeviceCapability::Keyboard)); + caps.touch = self.devices + .iter() + .filter(|x| x.seat() == device_seat) + .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); } else { panic!("Seat changed that was never created") } @@ -395,9 +392,9 @@ impl backend::InputBackend for LibinputInputBackend { use input::event::touch::*; if let Some(ref mut handler) = self.handler { let device_seat = touch_event.device().seat(); - let seat = &self.seats.get(&device_seat).expect( - "Recieved touch event of non existing Seat", - ); + let seat = &self.seats + .get(&device_seat) + .expect("Recieved touch event of non existing Seat"); match touch_event { TouchEvent::Down(down_event) => { trace!(self.logger, "Calling on_touch_down with {:?}", down_event); @@ -433,25 +430,23 @@ impl backend::InputBackend for LibinputInputBackend { libinput::Event::Keyboard(keyboard_event) => { use input::event::keyboard::*; match keyboard_event { - KeyboardEvent::Key(key_event) => { - if let Some(ref mut handler) = self.handler { - let device_seat = key_event.device().seat(); - let seat = &self.seats.get(&device_seat).expect( - "Recieved key event of non existing Seat", - ); - trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); - handler.on_keyboard_key(seat, key_event); - } - } + KeyboardEvent::Key(key_event) => if let Some(ref mut handler) = self.handler { + let device_seat = key_event.device().seat(); + let seat = &self.seats + .get(&device_seat) + .expect("Recieved key event of non existing Seat"); + trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); + handler.on_keyboard_key(seat, key_event); + }, } } libinput::Event::Pointer(pointer_event) => { use input::event::pointer::*; if let Some(ref mut handler) = self.handler { let device_seat = pointer_event.device().seat(); - let seat = &self.seats.get(&device_seat).expect( - "Recieved pointer event of non existing Seat", - ); + let seat = &self.seats + .get(&device_seat) + .expect("Recieved pointer event of non existing Seat"); match pointer_event { PointerEvent::Motion(motion_event) => { trace!( diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 5fdb921..3cf23d2 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -214,9 +214,9 @@ impl EGLGraphicsBackend for WinitGraphicsBackend { } fn get_framebuffer_dimensions(&self) -> (u32, u32) { - self.window.get_inner_size_pixels().expect( - "Window does not exist anymore", - ) + self.window + .get_inner_size_pixels() + .expect("Window does not exist anymore") } fn is_current(&self) -> bool { @@ -310,14 +310,16 @@ impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { fn x_transformed(&self, width: u32) -> u32 { cmp::min( - (self.x * width as f64 / self.window.get_inner_size_points().unwrap_or((width, 0)).0 as f64) as u32, + (self.x * width as f64 / self.window.get_inner_size_points().unwrap_or((width, 0)).0 as f64) as + u32, 0, ) } fn y_transformed(&self, height: u32) -> u32 { cmp::min( - (self.y * height as f64 / self.window.get_inner_size_points().unwrap_or((0, height)).1 as f64) as u32, + (self.y * height as f64 / self.window.get_inner_size_points().unwrap_or((0, height)).1 as f64) as + u32, 0, ) } @@ -529,9 +531,9 @@ impl InputBackend for WinitInputBackend { } fn get_handler(&mut self) -> Option<&mut InputHandler> { - self.handler.as_mut().map(|handler| { - handler as &mut InputHandler - }) + self.handler + .as_mut() + .map(|handler| handler as &mut InputHandler) } fn clear_handler(&mut self) { @@ -590,10 +592,15 @@ impl InputBackend for WinitInputBackend { wl_egl_surface.resize(x as i32, y as i32, 0, 0); } } - (WindowEvent::KeyboardInput { - input: KeyboardInput { scancode, state, .. }, .. - }, - Some(handler)) => { + ( + WindowEvent::KeyboardInput { + input: KeyboardInput { + scancode, state, .. + }, + .. + }, + Some(handler), + ) => { match state { ElementState::Pressed => *key_counter += 1, ElementState::Released => { @@ -615,7 +622,12 @@ impl InputBackend for WinitInputBackend { }, ) } - (WindowEvent::MouseMoved { position: (x, y), .. }, Some(handler)) => { + ( + WindowEvent::MouseMoved { + position: (x, y), .. + }, + Some(handler), + ) => { trace!(logger, "Calling on_pointer_move_absolute with {:?}", (x, y)); handler.on_pointer_move_absolute( seat, @@ -627,39 +639,36 @@ impl InputBackend for WinitInputBackend { }, ) } - (WindowEvent::MouseWheel { delta, .. }, Some(handler)) => { - match delta { - MouseScrollDelta::LineDelta(x, y) | - MouseScrollDelta::PixelDelta(x, y) => { - if x != 0.0 { - let event = WinitMouseWheelEvent { - axis: Axis::Horizontal, - time: *time_counter, - delta: delta, - }; - trace!( - logger, - "Calling on_pointer_axis for Axis::Horizontal with {:?}", - x - ); - handler.on_pointer_axis(seat, event); - } - if y != 0.0 { - let event = WinitMouseWheelEvent { - axis: Axis::Vertical, - time: *time_counter, - delta: delta, - }; - trace!( - logger, - "Calling on_pointer_axis for Axis::Vertical with {:?}", - y - ); - handler.on_pointer_axis(seat, event); - } + (WindowEvent::MouseWheel { delta, .. }, Some(handler)) => match delta { + MouseScrollDelta::LineDelta(x, y) | MouseScrollDelta::PixelDelta(x, y) => { + if x != 0.0 { + let event = WinitMouseWheelEvent { + axis: Axis::Horizontal, + time: *time_counter, + delta: delta, + }; + trace!( + logger, + "Calling on_pointer_axis for Axis::Horizontal with {:?}", + x + ); + handler.on_pointer_axis(seat, event); + } + if y != 0.0 { + let event = WinitMouseWheelEvent { + axis: Axis::Vertical, + time: *time_counter, + delta: delta, + }; + trace!( + logger, + "Calling on_pointer_axis for Axis::Vertical with {:?}", + y + ); + handler.on_pointer_axis(seat, event); } } - } + }, (WindowEvent::MouseInput { state, button, .. }, Some(handler)) => { trace!( logger, @@ -675,13 +684,15 @@ impl InputBackend for WinitInputBackend { }, ) } - (WindowEvent::Touch(Touch { - phase: TouchPhase::Started, - location: (x, y), - id, - .. - }), - Some(handler)) => { + ( + WindowEvent::Touch(Touch { + phase: TouchPhase::Started, + location: (x, y), + id, + .. + }), + Some(handler), + ) => { trace!(logger, "Calling on_touch_down at {:?}", (x, y)); handler.on_touch_down( seat, @@ -693,13 +704,15 @@ impl InputBackend for WinitInputBackend { }, ) } - (WindowEvent::Touch(Touch { - phase: TouchPhase::Moved, - location: (x, y), - id, - .. - }), - Some(handler)) => { + ( + WindowEvent::Touch(Touch { + phase: TouchPhase::Moved, + location: (x, y), + id, + .. + }), + Some(handler), + ) => { trace!(logger, "Calling on_touch_motion at {:?}", (x, y)); handler.on_touch_motion( seat, @@ -711,13 +724,15 @@ impl InputBackend for WinitInputBackend { }, ) } - (WindowEvent::Touch(Touch { - phase: TouchPhase::Ended, - location: (x, y), - id, - .. - }), - Some(handler)) => { + ( + WindowEvent::Touch(Touch { + phase: TouchPhase::Ended, + location: (x, y), + id, + .. + }), + Some(handler), + ) => { trace!(logger, "Calling on_touch_motion at {:?}", (x, y)); handler.on_touch_motion( seat, @@ -737,12 +752,14 @@ impl InputBackend for WinitInputBackend { }, ); } - (WindowEvent::Touch(Touch { - phase: TouchPhase::Cancelled, - id, - .. - }), - Some(handler)) => { + ( + WindowEvent::Touch(Touch { + phase: TouchPhase::Cancelled, + id, + .. + }), + Some(handler), + ) => { trace!(logger, "Calling on_touch_cancel"); handler.on_touch_cancel( seat, diff --git a/src/compositor/global.rs b/src/compositor/global.rs index 80609e2..db03be3 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -5,15 +5,9 @@ use wayland_server::protocol::{wl_compositor, wl_subcompositor}; impl GlobalHandler for CompositorHandler where - U: Default - + Send - + 'static, - R: Default - + Send - + 'static, - H: UserHandler - + Send - + 'static, + U: Default + Send + 'static, + R: Default + Send + 'static, + H: UserHandler + Send + 'static, { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) { debug!(self.log, "New compositor global binded."); diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 9a4add9..b8acb67 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -193,10 +193,7 @@ impl Destroy for CompositorDestructor { impl wl_subcompositor::Handler for CompositorHandler where U: Send + 'static, - R: RoleType - + Role - + Send - + 'static, + R: RoleType + Role + Send + 'static, H: Send + 'static, { fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client, @@ -210,9 +207,9 @@ where ); return; } - id.set_user_data(Box::into_raw( - Box::new(unsafe { surface.clone_unchecked() }), - ) as *mut _); + id.set_user_data( + Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _, + ); evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>( &id, self.my_id, @@ -259,7 +256,10 @@ where let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); if let Err(()) = SurfaceData::::reorder(surface, Location::After, sibling) { - subsurface.post_error(wl_subsurface::Error::BadSurface as u32, "Provided surface is not a sibling or parent.".into()); + subsurface.post_error( + wl_subsurface::Error::BadSurface as u32, + "Provided surface is not a sibling or parent.".into(), + ); } } } @@ -270,7 +270,10 @@ where let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); if let Err(()) = SurfaceData::::reorder(surface, Location::Before, sibling) { - subsurface.post_error(wl_subsurface::Error::BadSurface as u32, "Provided surface is not a sibling or parent.".into()); + subsurface.post_error( + wl_subsurface::Error::BadSurface as u32, + "Provided surface is not a sibling or parent.".into(), + ); } } } @@ -291,7 +294,8 @@ where server_declare_handler!(CompositorHandler], H: []>, wl_subsurface::Handler, wl_subsurface::WlSubsurface); impl Destroy for CompositorDestructor - where R: RoleType + Role +where + R: RoleType + Role, { fn destroy(subsurface: &wl_subsurface::WlSubsurface) { let ptr = subsurface.get_user_data(); diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index f9fdb0c..af9582b 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -107,7 +107,7 @@ use self::region::RegionData; use self::roles::{Role, RoleType, WrongRole}; use self::tree::SurfaceData; pub use self::tree::TraversalAction; -use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered}; +use wayland_server::{resource_is_registered, Client, EventLoopHandle, Init}; use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_region, wl_surface}; @@ -321,14 +321,11 @@ where /// - a custom value that is passer in a fold-like maneer, but only from the output of a parent /// to its children. See `TraversalAction` for details. /// - /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// If the surface not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, initial: T, f: F) -> Result<(), ()> where - F: FnMut(&wl_surface::WlSurface, - &mut SurfaceAttributes, - &mut R, - &T) + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { assert!( @@ -440,10 +437,11 @@ impl + Send + /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). - pub fn with_role_data(&self, surface: &wl_surface::WlSurface, f: F) -> Result + pub fn with_role_data(&self, surface: &wl_surface::WlSurface, f: F) + -> Result where R: Role, - F: FnOnce(&mut RoleData) -> T + F: FnOnce(&mut RoleData) -> T, { assert!( resource_is_registered::<_, CompositorHandler>(surface, self.hid), diff --git a/src/compositor/region.rs b/src/compositor/region.rs index 7f56d1c..d6a7a22 100644 --- a/src/compositor/region.rs +++ b/src/compositor/region.rs @@ -13,9 +13,9 @@ pub struct RegionData { impl RegionData { /// Initialize the user_data of a region, must be called right when the surface is created pub unsafe fn init(region: &wl_region::WlRegion) { - region.set_user_data(Box::into_raw( - Box::new(Mutex::new(RegionData::default())), - ) as *mut _) + region.set_user_data( + Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _, + ) } /// Cleans the user_data of that surface, must be called when it is destroyed diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index c3c1e9b..ccd0de4 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -58,9 +58,9 @@ impl SurfaceData { /// Initialize the user_data of a surface, must be called right when the surface is created pub unsafe fn init(surface: &wl_surface::WlSurface) { - surface.set_user_data(Box::into_raw( - Box::new(Mutex::new(SurfaceData::::new())), - ) as *mut _) + surface.set_user_data( + Box::into_raw(Box::new(Mutex::new(SurfaceData::::new()))) as *mut _, + ) } } @@ -315,21 +315,15 @@ impl SurfaceData { /// false will cause an early-stopping. pub unsafe fn map_tree(root: &wl_surface::WlSurface, initial: T, mut f: F) where - F: FnMut(&wl_surface::WlSurface, - &mut SurfaceAttributes, - &mut R, - &T) + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { // helper function for recursion - unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, initial: &T, - f: &mut F) + unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, + initial: &T, f: &mut F) -> bool where - F: FnMut(&wl_surface::WlSurface, - &mut SurfaceAttributes, - &mut R, - &T) + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { // stop if we met the root, so to not deadlock/inifinte loop diff --git a/src/keyboard/mod.rs b/src/keyboard/mod.rs index cf957a9..0b444de 100644 --- a/src/keyboard/mod.rs +++ b/src/keyboard/mod.rs @@ -29,7 +29,7 @@ use wayland_server::protocol::{wl_keyboard, wl_surface}; use xkbcommon::xkb; -pub use xkbcommon::xkb::{Keysym, keysyms}; +pub use xkbcommon::xkb::{keysyms, Keysym}; /// Represents the current state of the keyboard modifiers /// @@ -178,19 +178,18 @@ where "rules" => rules, "model" => model, "layout" => layout, "variant" => variant, "options" => &options ); - let internal = KbdInternal::new(rules, model, layout, variant, options) - .map_err(|_| { - debug!(log, "Loading keymap failed"); - Error::BadKeymap - })?; + let internal = KbdInternal::new(rules, model, layout, variant, options).map_err(|_| { + debug!(log, "Loading keymap failed"); + Error::BadKeymap + })?; // prepare a tempfile with the keymap, to send it to clients let mut keymap_file = tempfile().map_err(Error::IoError)?; let keymap_data = internal.keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1); - keymap_file.write_all(keymap_data.as_bytes()).map_err( - Error::IoError, - )?; + keymap_file + .write_all(keymap_data.as_bytes()) + .map_err(Error::IoError)?; keymap_file.flush().map_err(Error::IoError)?; trace!(log, "Keymap loaded and copied to tempfile."; diff --git a/src/shm/mod.rs b/src/shm/mod.rs index 9dba511..d3dd27b 100644 --- a/src/shm/mod.rs +++ b/src/shm/mod.rs @@ -67,7 +67,7 @@ use self::pool::{Pool, ResizeError}; use std::os::unix::io::RawFd; use std::sync::Arc; -use wayland_server::{Client, Destroy, EventLoopHandle, GlobalHandler, Init, Resource, resource_is_registered}; +use wayland_server::{resource_is_registered, Client, Destroy, EventLoopHandle, GlobalHandler, Init, Resource}; use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool}; mod pool; @@ -111,7 +111,9 @@ impl ShmGlobal { /// /// 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.") } + ShmToken { + hid: self.handler_id.expect("ShmGlobal was not initialized."), + } } } @@ -218,8 +220,11 @@ impl wl_shm::Handler for ShmHandler { let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) { Ok(p) => p, Err(()) => { - shm.post_error(wl_shm::Error::InvalidFd as u32, format!("Failed mmap of fd {}.", fd)); - return + shm.post_error( + wl_shm::Error::InvalidFd as u32, + format!("Failed mmap of fd {}.", fd), + ); + return; } }; let arc_pool = Box::new(Arc::new(mmap_pool)); diff --git a/src/shm/pool.rs b/src/shm/pool.rs index 4a814f0..227f669 100644 --- a/src/shm/pool.rs +++ b/src/shm/pool.rs @@ -6,7 +6,7 @@ use nix::sys::signal::{self, SigAction, SigHandler, Signal}; use std::cell::Cell; use std::os::unix::io::RawFd; use std::ptr; -use std::sync::{ONCE_INIT, Once, RwLock}; +use std::sync::{Once, RwLock, ONCE_INIT}; thread_local!(static SIGBUS_GUARD: Cell<(*const MemMap, bool)> = Cell::new((ptr::null_mut(), false))); From a86b3d6d678455ceb42f5f9620715bb6d06379a4 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 20:11:26 +0200 Subject: [PATCH 05/13] travis: fix argument nesting --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 57cf7e9..70fc95b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - export XDG_RUNTIME_DIR="$(pwd)/socket" script: - - travis-cargo --only nightly fmt -- --write-mode=diff + - travis-cargo --only nightly fmt -- -- --write-mode=diff - travis-cargo --skip nightly build - travis-cargo --only nightly build -- --features "clippy" - travis-cargo --only stable doc -- --no-deps From aab56047f030482df6697929e3787c802a847474 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 21:09:50 +0200 Subject: [PATCH 06/13] Update example to use shell global --- examples/helpers/mod.rs | 2 - examples/helpers/shell.rs | 93 --------------------------- examples/simple.rs | 129 ++++++++++++++++++++++++++++---------- src/shell/mod.rs | 2 +- 4 files changed, 96 insertions(+), 130 deletions(-) delete mode 100644 examples/helpers/shell.rs diff --git a/examples/helpers/mod.rs b/examples/helpers/mod.rs index 6964d2b..407fec4 100644 --- a/examples/helpers/mod.rs +++ b/examples/helpers/mod.rs @@ -1,5 +1,3 @@ -mod shell; mod glium; pub use self::glium::GliumDrawer; -pub use self::shell::{ShellSurfaceRole, WlShellStubHandler}; diff --git a/examples/helpers/shell.rs b/examples/helpers/shell.rs deleted file mode 100644 index e3d9b14..0000000 --- a/examples/helpers/shell.rs +++ /dev/null @@ -1,93 +0,0 @@ - - -use smithay::compositor::{CompositorToken, Handler as CompositorHandler}; -use smithay::compositor::roles::{Role, RoleType}; -use wayland_server::{Client, EventLoopHandle, GlobalHandler, Init, Resource}; -use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface}; - -/// A very basic handler for wl_shell -/// -/// All it does is track which wl_shell_surface exist and which do not, -/// as well as the roles associated to them. -/// -/// That's it. -pub struct WlShellStubHandler { - my_id: Option, - token: CompositorToken, - surfaces: Vec<(wl_shell_surface::WlShellSurface, wl_surface::WlSurface)>, -} - -#[derive(Default)] -pub struct ShellSurfaceRole; - -impl WlShellStubHandler { - pub fn new(compositor_token: CompositorToken) -> WlShellStubHandler { - WlShellStubHandler { - my_id: None, - token: compositor_token, - surfaces: Vec::new(), - } - } - - pub fn surfaces(&self) -> &[(wl_shell_surface::WlShellSurface, wl_surface::WlSurface)] { - &self.surfaces - } -} - -impl Init for WlShellStubHandler { - fn init(&mut self, evqh: &mut EventLoopHandle, index: usize) { - self.my_id = Some(index) - } -} - - -impl GlobalHandler for WlShellStubHandler -where - U: Send + 'static, - R: RoleType + Role + Send + 'static, - H: CompositorHandler + Send + 'static, -{ - fn bind(&mut self, evqh: &mut EventLoopHandle, client: &Client, global: wl_shell::WlShell) { - evqh.register::<_, Self>( - &global, - self.my_id - .expect("WlShellStubHandler was not properly initialized."), - ); - } -} - -impl wl_shell::Handler for WlShellStubHandler -where - U: Send + 'static, - R: RoleType + Role + Send + 'static, - H: CompositorHandler + Send + 'static, -{ - fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &wl_shell::WlShell, id: wl_shell_surface::WlShellSurface, - surface: &wl_surface::WlSurface) { - let surface = surface.clone().expect( - "WlShellStubHandler can only manage surfaces managed by Smithay's CompositorHandler.", - ); - if self.token.give_role::(&surface).is_err() { - // This surface already has a role, and thus cannot be given one! - resource.post_error( - wl_shell::Error::Role as u32, - "Surface already has a role.".into(), - ); - return; - } - evqh.register::<_, Self>(&id, self.my_id.unwrap()); - self.surfaces.push((id, surface)) - } -} - -server_declare_handler!(WlShellStubHandler, Send], H: [CompositorHandler, Send]>, wl_shell::Handler, wl_shell::WlShell); - -impl wl_shell_surface::Handler for WlShellStubHandler -where - U: Send + 'static, - H: CompositorHandler + Send + 'static, -{ -} - -server_declare_handler!(WlShellStubHandler, Send]>, wl_shell_surface::Handler, wl_shell_surface::WlShellSurface); diff --git a/examples/simple.rs b/examples/simple.rs index 8635357..2abf90a 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -2,6 +2,7 @@ extern crate glium; #[macro_use(define_roles)] extern crate smithay; +extern crate wayland_protocols; #[macro_use(server_declare_handler)] extern crate wayland_server; @@ -14,7 +15,7 @@ mod helpers; use glium::Surface; -use helpers::{GliumDrawer, ShellSurfaceRole, WlShellStubHandler}; +use helpers::GliumDrawer; use slog::{Drain, Logger}; use smithay::backend::graphics::glium::IntoGlium; @@ -22,10 +23,15 @@ use smithay::backend::input::InputBackend; use smithay::backend::winit; use smithay::compositor::{self, CompositorHandler, CompositorToken, SubsurfaceRole, TraversalAction}; use smithay::compositor::roles::Role; +use smithay::shell::{self, PopupConfigure, PopupSurface, ShellClient, ShellHandler, ShellSurfaceRole, + ToplevelConfigure, ToplevelSurface}; use smithay::shm::{BufferData, ShmGlobal, ShmToken}; -use wayland_server::{Client, EventLoopHandle, Liveness, Resource}; -use wayland_server::protocol::{wl_compositor, wl_shell, wl_shm, wl_subcompositor, wl_surface}; +use wayland_protocols::unstable::xdg_shell::server::{zxdg_shell_v6, zxdg_toplevel_v6}; + +use wayland_server::{Client, EventLoopHandle, Liveness, Resource}; +use wayland_server::protocol::{wl_compositor, wl_output, wl_seat, wl_shell, wl_shm, wl_subcompositor, + wl_surface}; define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] ); @@ -36,6 +42,7 @@ struct SurfaceHandler { #[derive(Default)] struct SurfaceData { buffer: Option<(Vec, (u32, u32))>, + location: Option<(u32, u32)>, } impl compositor::Handler for SurfaceHandler { @@ -70,7 +77,61 @@ impl compositor::Handler for SurfaceHandler { } } +struct ShellSurfaceHandler; + +impl shell::Handler 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) + -> ToplevelConfigure { + ToplevelConfigure { + size: None, + states: vec![], + serial: 42, + } + } + fn new_popup(&mut self, evlh: &mut EventLoopHandle, + surface: PopupSurface) + -> PopupConfigure { + PopupConfigure { + size: (10, 10), + position: (10, 10), + serial: 42, + } + } + fn move_(&mut self, evlh: &mut EventLoopHandle, + surface: ToplevelSurface, seat: &wl_seat::WlSeat, + serial: u32) { + } + fn resize(&mut self, evlh: &mut EventLoopHandle, + surface: ToplevelSurface, seat: &wl_seat::WlSeat, + serial: u32, edges: zxdg_toplevel_v6::ResizeEdge) { + } + fn grab(&mut self, evlh: &mut EventLoopHandle, + surface: PopupSurface, seat: &wl_seat::WlSeat, + serial: u32) { + } + fn change_display_state(&mut self, evlh: &mut EventLoopHandle, + surface: ToplevelSurface, + maximized: Option, minimized: Option, fullscreen: Option, + output: Option<&wl_output::WlOutput>) + -> ToplevelConfigure { + ToplevelConfigure { + size: None, + states: vec![], + serial: 42, + } + } + fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, + surface: ToplevelSurface, + seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32) { + } +} + + type MyCompositorHandler = CompositorHandler; +type MyShellHandler = ShellHandler; fn main() { // A logger facility, here we use the terminal for this example @@ -121,14 +182,15 @@ fn main() { }; /* - * Initialize the shell stub global + * Initialize the shell global */ - let shell_handler_id = - event_loop.add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); - event_loop.register_global::>( - shell_handler_id, - 1, - ); + let shell_handler_id = event_loop.add_handler_with_init(MyShellHandler::new( + ShellSurfaceHandler, + compositor_token.clone(), + log.clone(), + )); + event_loop.register_global::(shell_handler_id, 1); + event_loop.register_global::(shell_handler_id, 1); /* * Initialize glium @@ -152,32 +214,31 @@ fn main() { { let screen_dimensions = context.get_framebuffer_dimensions(); let state = event_loop.state(); - for &(_, ref surface) in state - .get_handler::>(shell_handler_id) - .surfaces() + for toplevel_surface in state + .get_handler::(shell_handler_id) + .toplevel_surfaces() { - if surface.status() != Liveness::Alive { - continue; - } - // this surface is a root of a subsurface tree that needs to be drawn - compositor_token.with_surface_tree( - surface, - (100, 100), - |surface, attributes, role, &(mut x, mut y)| { - if let Some((ref contents, (w, h))) = attributes.user_data.buffer { - // there is actually something to draw ! - if let Ok(subdata) = Role::::data(role) { - x += subdata.x; - y += subdata.y; + if let Some(wl_surface) = toplevel_surface.get_surface() { + // this surface is a root of a subsurface tree that needs to be drawn + compositor_token.with_surface_tree( + wl_surface, + (100, 100), + |surface, attributes, role, &(mut x, mut y)| { + if let Some((ref contents, (w, h))) = attributes.user_data.buffer { + // there is actually something to draw ! + if let Ok(subdata) = Role::::data(role) { + x += subdata.x; + y += subdata.y; + } + drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + TraversalAction::DoChildren((x, y)) + } else { + // we are not display, so our children are neither + TraversalAction::SkipChildren } - drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); - TraversalAction::DoChildren((x, y)) - } else { - // we are not display, so our children are neither - TraversalAction::SkipChildren - } - }, - ); + }, + ); + } } } frame.finish().unwrap(); diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 00cbc5c..1777b7d 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -115,7 +115,7 @@ where H: CompositorHandler + Send + 'static, { /// Create a new CompositorHandler - pub fn new(handler: SH, token: CompositorToken, logger: L) -> ShellHandler + pub fn new(handler: SH, token: CompositorToken, logger: L) -> ShellHandler where L: Into>, { From db6bad16761d6e92da1e8c6e782d108251d49de9 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 21:23:17 +0200 Subject: [PATCH 07/13] compositor: return value from Token::with_surface_data --- src/compositor/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index af9582b..77d11b0 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -287,17 +287,15 @@ impl + Send + 'static> Co /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). - pub fn with_surface_data(&self, surface: &wl_surface::WlSurface, f: F) + pub fn with_surface_data(&self, surface: &wl_surface::WlSurface, f: F) -> T where - F: FnOnce(&mut SurfaceAttributes), + F: FnOnce(&mut SurfaceAttributes) -> T, { assert!( resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported." ); - unsafe { - SurfaceData::::with_data(surface, f); - } + unsafe { SurfaceData::::with_data(surface, f) } } } From 30c062895951e9639443e8fd264993ba2edd4cc7 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 5 Sep 2017 21:23:40 +0200 Subject: [PATCH 08/13] examples: randomise window location in simple.rs --- Cargo.toml | 1 + examples/simple.rs | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 57fa1e3..35127d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ gl_generator = "0.5" [dev-dependencies] slog-term = "2.0" slog-async = "2.0" +rand = "0.3" [features] default = ["backend_winit", "backend_libinput", "renderer_glium"] diff --git a/examples/simple.rs b/examples/simple.rs index 2abf90a..76f39db 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,16 +1,16 @@ #[macro_use] extern crate glium; +extern crate rand; +#[macro_use] +extern crate slog; +extern crate slog_async; +extern crate slog_term; #[macro_use(define_roles)] extern crate smithay; extern crate wayland_protocols; #[macro_use(server_declare_handler)] extern crate wayland_server; -#[macro_use] -extern crate slog; -extern crate slog_async; -extern crate slog_term; - mod helpers; use glium::Surface; @@ -42,7 +42,7 @@ struct SurfaceHandler { #[derive(Default)] struct SurfaceData { buffer: Option<(Vec, (u32, u32))>, - location: Option<(u32, u32)>, + location: Option<(i32, i32)>, } impl compositor::Handler for SurfaceHandler { @@ -77,7 +77,15 @@ impl compositor::Handler for SurfaceHandler { } } -struct ShellSurfaceHandler; +struct ShellSurfaceHandler { + token: CompositorToken, +} + +impl ShellSurfaceHandler { + fn new(token: CompositorToken) -> ShellSurfaceHandler { + ShellSurfaceHandler { token } + } +} impl shell::Handler for ShellSurfaceHandler { fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient<()>) {} @@ -85,6 +93,16 @@ impl shell::Handler for ShellSurfaceHand fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface) -> 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![], @@ -185,8 +203,8 @@ fn main() { * Initialize the shell global */ let shell_handler_id = event_loop.add_handler_with_init(MyShellHandler::new( - ShellSurfaceHandler, - compositor_token.clone(), + ShellSurfaceHandler::new(compositor_token), + compositor_token, log.clone(), )); event_loop.register_global::(shell_handler_id, 1); @@ -220,9 +238,11 @@ fn main() { { if let Some(wl_surface) = toplevel_surface.get_surface() { // this surface is a root of a subsurface tree that needs to be drawn + let initial_place = compositor_token + .with_surface_data(wl_surface, |data| data.user_data.location.unwrap_or((0, 0))); compositor_token.with_surface_tree( wl_surface, - (100, 100), + initial_place, |surface, attributes, role, &(mut x, mut y)| { if let Some((ref contents, (w, h))) = attributes.user_data.buffer { // there is actually something to draw ! From 6dec2cb5da61c3eaeab7f09024e77ed3c9a5de7b Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 6 Sep 2017 14:41:59 +0200 Subject: [PATCH 09/13] shell: types documentation --- src/shell/mod.rs | 248 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 237 insertions(+), 11 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 1777b7d..bbb655c 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -11,49 +11,109 @@ mod global; mod wl_handlers; mod xdg_handlers; +/// Metadata associated with the `shell_surface` role pub struct ShellSurfaceRole { + /// Pending state as requested by the client + /// + /// The data in this field are double-buffered, you should + /// apply them on a surface commit. pub pending_state: ShellSurfacePendingState, + /// Geometry of the surface + /// + /// Defines, in surface relative coordinates, what should + /// be considered as "the surface itself", regarding focus, + /// window alignment, etc... + /// + /// By default, you should consider the full contents of the + /// buffers of this surface and its subsurfaces. pub window_geometry: Option, + /// List of non-acked configures pending + /// + /// Whenever a configure is acked by the client, all configure + /// older than it are discarded as well. As such, this vec contains + /// the serials of all the configure send to this surface that are + /// newer than the last ack received. pub pending_configures: Vec, + /// Has this surface acked at least one configure? + /// + /// xdg_shell defines it as illegal to commit on a surface that has + /// not yet acked a configure. pub configured: bool, } #[derive(Copy, Clone, Debug)] +/// The state of a positioner, as set by the client pub struct PositionerState { + /// Size of the rectangle that needs to be positioned pub rect_size: (i32, i32), + /// Anchor rectangle in the parent surface coordinates + /// relative to which the surface must be positioned pub anchor_rect: Rectangle, + /// Edges defining the anchor point pub anchor_edges: xdg_positioner::Anchor, + /// Gravity direction for positioning the child surface + /// relative to its anchor point pub gravity: xdg_positioner::Gravity, + /// Adjustments to do if previous criterias constraint the + /// surface pub constraint_adjustment: xdg_positioner::ConstraintAdjustment, + /// Offset placement relative to the anchor point pub offset: (i32, i32), } +/// Contents of the pending state of a shell surface, depending on its role pub enum ShellSurfacePendingState { /// This a regular, toplevel surface /// /// This corresponds to either the `xdg_toplevel` role from the /// `xdg_shell` protocol, or the result of `set_toplevel` using the /// `wl_shell` protocol. + /// + /// This is what you'll generaly interpret as "a window". Toplevel(ToplevelState), /// This is a popup surface /// /// This corresponds to either the `xdg_popup` role from the /// `xdg_shell` protocol, or the result of `set_popup` using the - /// `wl_shell` protocole + /// `wl_shell` protocol. + /// + /// This are mostly for small tooltips and similar short-lived + /// surfaces. Popup(PopupState), /// This surface was not yet assigned a kind None, } +/// State of a regular toplevel surface pub struct ToplevelState { + /// Parent of this surface + /// + /// If this surface has a parent, it should be hidden + /// or displayed, brought up at the same time as it. pub parent: Option, + /// Title of this shell surface pub title: String, + /// App id for this shell surface + /// + /// This identifier can be used to group surface together + /// as being several instance of the same app. This can + /// also be used as the D-Bus name for the app. pub app_id: String, + /// Minimum size requested for this surface + /// + /// A value of 0 on an axis means this axis is not constrained pub min_size: (i32, i32), + /// Maximum size requested for this surface + /// + /// A value of 0 on an axis means this axis is not constrained pub max_size: (i32, i32), } impl ToplevelState { + /// Clone this ToplevelState + /// + /// If the parent surface refers to a surface that no longer + /// exists, it is replaced by `None` in the process. pub fn clone(&self) -> ToplevelState { ToplevelState { parent: self.parent.as_ref().and_then(|p| p.clone()), @@ -65,12 +125,21 @@ impl ToplevelState { } } +/// The pending state of a popup surface pub struct PopupState { + /// Parent of this popup surface pub parent: wl_surface::WlSurface, + /// The positioner specifying how this tooltip should + /// be placed relative to its parent. pub positioner: PositionerState, } impl PopupState { + /// Clone this PopupState + /// + /// If the parent surface refers to a surface that no longer + /// exists, this will return `None`, as the popup can no + /// longer be meaningfully displayed. pub fn clone(&self) -> Option { if let Some(p) = self.parent.clone() { Some(PopupState { @@ -91,6 +160,9 @@ impl Default for ShellSurfacePendingState { } } +/// The handler for the shell globals +/// +/// See module-level documentation for its use. pub struct ShellHandler { my_id: usize, log: ::slog::Logger, @@ -167,12 +239,23 @@ struct ShellClientData { data: SD, } +/// A shell client +/// +/// This represents an instanciation of a shell +/// global (be it `wl_shell` or `xdg_shell`). +/// +/// Most of the time, you can consider that a +/// wayland client will be a single shell client. +/// +/// You can use this handle to access a storage for any +/// client-specific data you wish to associate with it. pub struct ShellClient { kind: ShellClientKind, _data: ::std::marker::PhantomData<*mut SD>, } impl ShellClient { + /// Is the shell client represented by this handle still connected? pub fn alive(&self) -> bool { match self.kind { ShellClientKind::Wl(ref s) => s.status() == Liveness::Alive, @@ -180,6 +263,8 @@ impl ShellClient { } } + /// Checks if this handle and the other one actually refer to the + /// same shell client pub fn equals(&self, other: &Self) -> bool { match (&self.kind, &other.kind) { (&ShellClientKind::Wl(ref s1), &ShellClientKind::Wl(ref s2)) => s1.equals(s2), @@ -230,6 +315,7 @@ impl ShellClient { Ok(()) } + /// Access the user data associated with this shell client pub fn with_data(&self, f: F) -> Result where F: FnOnce(&mut SD) -> T, @@ -259,6 +345,10 @@ enum SurfaceKind { XdgPopup(zxdg_popup_v6::ZxdgPopupV6), } +/// A handle to a toplevel surface +/// +/// This is an unified abstraction over the toplevel surfaces +/// of both `wl_shell` and `xdg_shell`. pub struct ToplevelSurface { wl_surface: wl_surface::WlSurface, shell_surface: SurfaceKind, @@ -272,6 +362,7 @@ where R: Role + Send + 'static, H: CompositorHandler + Send + 'static, { + /// Is the toplevel surface refered by this handle still alive? pub fn alive(&self) -> bool { let shell_surface_alive = match self.shell_surface { SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, @@ -281,32 +372,40 @@ where shell_surface_alive && self.wl_surface.status() == Liveness::Alive } + /// Do this handle and the other one actually refer to the same toplevel surface? pub fn equals(&self, other: &Self) -> bool { self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) } - pub fn client(&self) -> ShellClient { + /// Retrieve the shell client owning this toplevel surface + /// + /// Returns `None` if the surface does actually no longer exist. + pub fn client(&self) -> Option> { + if !self.alive() { return None } match self.shell_surface { SurfaceKind::Wl(ref s) => { let &(_, ref shell) = unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; - ShellClient { + Some(ShellClient { kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), _data: ::std::marker::PhantomData, - } + }) } SurfaceKind::XdgToplevel(ref s) => { let &(_, ref shell, _) = unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; - ShellClient { + Some(ShellClient { kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), _data: ::std::marker::PhantomData, - } + }) } SurfaceKind::XdgPopup(_) => unreachable!(), } } + /// Send a configure event to this toplevel surface to suggest it a new configuration + /// + /// The serial of this configure will be tracked waiting for the client to ACK it. pub fn send_configure(&self, cfg: ToplevelConfigure) -> EventResult<()> { if !self.alive() { return EventResult::Destroyed; @@ -354,6 +453,9 @@ where configured } + /// Access the underlying `wl_surface` of this toplevel surface + /// + /// Returns `None` if the toplevel surface actually no longer exists. pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { if self.alive() { Some(&self.wl_surface) @@ -362,6 +464,9 @@ where } } + /// Retrieve a copy of the pending state of this toplevel surface + /// + /// Returns `None` of the toplevel surface actually no longer exists. pub fn get_pending_state(&self) -> Option { if !self.alive() { return None; @@ -376,6 +481,10 @@ where } } +/// A handle to a popup surface +/// +/// This is an unified abstraction over the popup surfaces +/// of both `wl_shell` and `xdg_shell`. pub struct PopupSurface { wl_surface: wl_surface::WlSurface, shell_surface: SurfaceKind, @@ -389,6 +498,7 @@ where R: Role + Send + 'static, H: CompositorHandler + Send + 'static, { + /// Is the popup surface refered by this handle still alive? pub fn alive(&self) -> bool { let shell_surface_alive = match self.shell_surface { SurfaceKind::Wl(ref s) => s.status() == Liveness::Alive, @@ -398,32 +508,40 @@ where shell_surface_alive && self.wl_surface.status() == Liveness::Alive } + /// Do this handle and the other one actually refer to the same popup surface? pub fn equals(&self, other: &Self) -> bool { self.alive() && other.alive() && self.wl_surface.equals(&other.wl_surface) } - pub fn client(&self) -> ShellClient { + /// Retrieve the shell client owning this popup surface + /// + /// Returns `None` if the surface does actually no longer exist. + pub fn client(&self) -> Option> { + if !self.alive() { return None } match self.shell_surface { SurfaceKind::Wl(ref s) => { let &(_, ref shell) = unsafe { &*(s.get_user_data() as *mut self::wl_handlers::ShellSurfaceUserData) }; - ShellClient { + Some(ShellClient { kind: ShellClientKind::Wl(unsafe { shell.clone_unchecked() }), _data: ::std::marker::PhantomData, - } + }) } SurfaceKind::XdgPopup(ref s) => { let &(_, ref shell, _) = unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; - ShellClient { + Some(ShellClient { kind: ShellClientKind::Xdg(unsafe { shell.clone_unchecked() }), _data: ::std::marker::PhantomData, - } + }) } SurfaceKind::XdgToplevel(_) => unreachable!(), } } + /// Send a configure event to this toplevel surface to suggest it a new configuration + /// + /// The serial of this configure will be tracked waiting for the client to ACK it. pub fn send_configure(&self, cfg: PopupConfigure) -> EventResult<()> { if !self.alive() { return EventResult::Destroyed; @@ -436,6 +554,43 @@ where EventResult::Sent(()) } + /// Make sure this surface was configured + /// + /// Returns `true` if it was, if not, returns `false` and raise + /// a protocol error to the associated client. Also returns `false` + /// if the surface is already destroyed. + /// + /// xdg_shell mandates that a client acks a configure before commiting + /// anything. + pub fn ensure_configured(&self) -> bool { + if !self.alive() { + return false; + } + let configured = self.token + .with_role_data::(&self.wl_surface, |data| data.configured) + .expect( + "A shell surface object exists but the surface does not have the shell_surface role ?!", + ); + if !configured { + if let SurfaceKind::XdgPopup(ref s) = self.shell_surface { + let ptr = s.get_user_data(); + let &(_, _, ref xdg_surface) = + unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) }; + xdg_surface.post_error( + zxdg_surface_v6::Error::NotConstructed as u32, + "Surface has not been confgured yet.".into(), + ); + } else { + unreachable!(); + } + } + configured + } + + /// Send a 'popup_done' event to the popup surface + /// + /// It means that the use has dismissed the popup surface, or that + /// the pointer has left the area of popup grab if there was a grab. pub fn send_popup_done(&self) -> EventResult<()> { if !self.alive() { return EventResult::Destroyed; @@ -447,6 +602,9 @@ where } } + /// Access the underlying `wl_surface` of this toplevel surface + /// + /// Returns `None` if the toplevel surface actually no longer exists. pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { if self.alive() { Some(&self.wl_surface) @@ -455,6 +613,9 @@ where } } + /// Retrieve a copy of the pending state of this popup surface + /// + /// Returns `None` of the popup surface actually no longer exists. pub fn get_pending_state(&self) -> Option { if !self.alive() { return None; @@ -469,35 +630,100 @@ where } } +/// A configure message for toplevel surfaces pub struct ToplevelConfigure { + /// A suggestion for a new size for the surface pub size: Option<(i32, i32)>, + /// A notification of what are the current states of this surface + /// + /// A surface can be any combination of these possible states + /// at the same time. pub states: Vec, + /// A serial number to track ACK from the client + /// + /// This should be an ever increasing number, as the ACK-ing + /// from a client for a serial will validate all pending lower + /// serials. pub serial: u32, } +/// A configure message for popup surface pub struct PopupConfigure { + /// The position chosen for this popup relative to + /// its parent pub position: (i32, i32), + /// A suggested size for the popup pub size: (i32, i32), + /// A serial number to track ACK from the client + /// + /// This should be an ever increasing number, as the ACK-ing + /// from a client for a serial will validate all pending lower + /// serials. pub serial: u32, } +/// A trait for the sub-handler provided to the ShellHandler +/// +/// You need to implement this trait to handle events that the ShellHandler +/// cannot process for you directly. +/// +/// Depending on what you want to do, you might implement some of these methods +/// as doing nothing. pub trait Handler { + /// A new shell client was instanciated fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient); + /// The pong for a pending ping of this shell client was received + /// + /// The SHellHandler already checked for you that the serial matches the one + /// from the pending ping. fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient); + /// A new toplevel surface was created + /// + /// You need to return a `ToplevelConfigure` from this method, which will be sent + /// to the client to configure this surface fn new_toplevel(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface) -> ToplevelConfigure; + /// A new popup surface was created + /// + /// You need to return a `PopupConfigure` from this method, which will be sent + /// to the client to configure this surface fn new_popup(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface) -> PopupConfigure; + /// The client requested the start of an interactive move for this surface fn move_(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, seat: &wl_seat::WlSeat, serial: u32); + /// The client requested the start of an interactive resize for this surface + /// + /// The `edges` argument specifies which part of the window's border is being dragged. fn resize(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, seat: &wl_seat::WlSeat, serial: u32, edges: zxdg_toplevel_v6::ResizeEdge); + /// This popup requests a grab of the pointer + /// + /// This means it requests to be sent a `popup_done` event when the pointer leaves + /// the grab area. fn grab(&mut self, evlh: &mut EventLoopHandle, surface: PopupSurface, seat: &wl_seat::WlSeat, serial: u32); + /// A toplevel surface requested its display state to be changed + /// + /// Each field represents the request of the client for a specific property: + /// + /// - `None`: no request is made to change this property + /// - `Some(true)`: this property should be enabled + /// - `Some(false)`: this property should be disabled + /// + /// For fullscreen/maximization, the client can also optionnaly request a specific + /// output. + /// + /// You are to answer with a `ToplevelConfigure` that will be sent to the client in + /// response. fn change_display_state(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, maximized: Option, minimized: Option, fullscreen: Option, output: Option<&wl_output::WlOutput>) -> ToplevelConfigure; + /// The client requests the window menu to be displayed on this surface at this location + /// + /// This menu belongs to the compositor. It is typically expected to contain options for + /// control of the window (maximize/minimize/close/move/etc...). fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, surface: ToplevelSurface, seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32); } From 3171160cff9cc23c4420ce104377ec5d38876e65 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 6 Sep 2017 15:21:12 +0200 Subject: [PATCH 10/13] shell: fix warnings --- src/shell/mod.rs | 10 +++- src/shell/wl_handlers.rs | 75 ++++++++++++----------- src/shell/xdg_handlers.rs | 123 +++++++++++++++++++------------------- 3 files changed, 110 insertions(+), 98 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index bbb655c..65c4eea 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -381,7 +381,9 @@ where /// /// Returns `None` if the surface does actually no longer exist. pub fn client(&self) -> Option> { - if !self.alive() { return None } + if !self.alive() { + return None; + } match self.shell_surface { SurfaceKind::Wl(ref s) => { let &(_, ref shell) = @@ -517,7 +519,9 @@ where /// /// Returns `None` if the surface does actually no longer exist. pub fn client(&self) -> Option> { - if !self.alive() { return None } + if !self.alive() { + return None; + } match self.shell_surface { SurfaceKind::Wl(ref s) => { let &(_, ref shell) = @@ -658,7 +662,7 @@ pub struct PopupConfigure { /// /// This should be an ever increasing number, as the ACK-ing /// from a client for a serial will validate all pending lower - /// serials. + /// serials. pub serial: u32, } diff --git a/src/shell/wl_handlers.rs b/src/shell/wl_handlers.rs index 89edb94..e536a51 100644 --- a/src/shell/wl_handlers.rs +++ b/src/shell/wl_handlers.rs @@ -9,7 +9,7 @@ use std::sync::Mutex; use wayland_protocols::unstable::xdg_shell::server::{zxdg_positioner_v6 as xdg_positioner, zxdg_toplevel_v6}; -use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +use wayland_server::{Client, Destroy, EventLoopHandle, Resource}; use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; pub struct WlShellDestructor { @@ -27,6 +27,8 @@ impl Destroy for WlShellDestructor { let ptr = shell.get_user_data(); shell.set_user_data(::std::ptr::null_mut()); let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; + // explicitly call drop to not forget what we're doing here + ::std::mem::drop(data); } } @@ -45,9 +47,8 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &wl_shell::WlShell, id: wl_shell_surface::WlShellSurface, - surface: &wl_surface::WlSurface) { + fn get_shell_surface(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell::WlShell, + id: wl_shell_surface::WlShellSurface, surface: &wl_surface::WlSurface) { trace!(self.log, "Creating new wl_shell_surface."); let role_data = ShellSurfaceRole { pending_state: ShellSurfacePendingState::None, @@ -65,7 +66,7 @@ where id.set_user_data( Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _, ); - evqh.register_with_destructor::<_, Self, WlShellDestructor>(&id, self.my_id); + evlh.register_with_destructor::<_, Self, WlShellDestructor>(&id, self.my_id); // register ourselves to the wl_shell for ping handling let mutex = unsafe { &*(resource.get_user_data() as *mut ShellUserData) }; @@ -98,6 +99,8 @@ impl Destroy for WlShellDestructor { shell_surface.set_user_data(::std::ptr::null_mut()); // drop the WlSurface object let surface = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + // explicitly call drop to not forget what we're doing here + ::std::mem::drop(surface); } } @@ -145,7 +148,7 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn wl_handle_display_state_change(&mut self, evqh: &mut EventLoopHandle, + fn wl_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle, resource: &wl_shell_surface::WlShellSurface, maximized: Option, minimized: Option, fullscreen: Option, output: Option<&wl_output::WlOutput>) { @@ -153,13 +156,13 @@ where // handler callback let configure = self.handler - .change_display_state(evqh, handle, maximized, minimized, fullscreen, output); + .change_display_state(evlh, handle, maximized, minimized, fullscreen, output); // send the configure response to client let (w, h) = configure.size.unwrap_or((0, 0)); resource.configure(wl_shell_surface::None, w, h); } - fn wl_ensure_toplevel(&mut self, evqh: &mut EventLoopHandle, + fn wl_ensure_toplevel(&mut self, evlh: &mut EventLoopHandle, resource: &wl_shell_surface::WlShellSurface) { let ptr = resource.get_user_data(); let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; @@ -198,7 +201,7 @@ where // we need to notify about this new toplevel surface if need_send { let handle = make_toplevel_handle(self.token, resource); - let configure = self.handler.new_toplevel(evqh, handle); + let configure = self.handler.new_toplevel(evlh, handle); send_toplevel_configure(resource, configure); } } @@ -212,7 +215,7 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn pong(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn pong(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, serial: u32) { let &(_, ref shell) = unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; let valid = { @@ -226,35 +229,35 @@ where } }; if valid { - self.handler.client_pong(evqh, make_shell_client(shell)); + self.handler.client_pong(evlh, make_shell_client(shell)); } } - fn move_(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn move_(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32) { let handle = make_toplevel_handle(self.token, resource); - self.handler.move_(evqh, handle, seat, serial); + self.handler.move_(evlh, handle, seat, serial); } - fn resize(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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()) .unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); let handle = make_toplevel_handle(self.token, resource); - self.handler.resize(evqh, handle, seat, serial, edges); + self.handler.resize(evlh, handle, seat, serial, edges); } - fn set_toplevel(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_toplevel(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface) { - self.wl_ensure_toplevel(evqh, resource); - self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(false), None) + self.wl_ensure_toplevel(evlh, resource); + self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None) } - fn set_transient(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &wl_shell_surface::WlShellSurface, parent: &wl_surface::WlSurface, x: i32, - y: i32, flags: wl_shell_surface::Transient) { - self.wl_ensure_toplevel(evqh, resource); + fn set_transient(&mut self, evlh: &mut EventLoopHandle, _: &Client, + resource: &wl_shell_surface::WlShellSurface, parent: &wl_surface::WlSurface, _x: i32, + _y: i32, _flags: wl_shell_surface::Transient) { + self.wl_ensure_toplevel(evlh, resource); // set the parent let ptr = resource.get_user_data(); let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; @@ -267,20 +270,20 @@ where }) .unwrap(); // set as regular surface - self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(false), None) + self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(false), None) } - fn set_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, - method: wl_shell_surface::FullscreenMethod, framerate: u32, + _method: wl_shell_surface::FullscreenMethod, _framerate: u32, output: Option<&wl_output::WlOutput>) { - self.wl_ensure_toplevel(evqh, resource); - self.wl_handle_display_state_change(evqh, resource, Some(false), Some(false), Some(true), output) + self.wl_ensure_toplevel(evlh, resource); + self.wl_handle_display_state_change(evlh, resource, Some(false), Some(false), Some(true), output) } - fn set_popup(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_popup(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, seat: &wl_seat::WlSeat, serial: u32, - parent: &wl_surface::WlSurface, x: i32, y: i32, flags: wl_shell_surface::Transient) { + parent: &wl_surface::WlSurface, x: i32, y: i32, _: wl_shell_surface::Transient) { let ptr = resource.get_user_data(); let &(ref wl_surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; // we are reseting the popup state, so remove this surface from everywhere @@ -319,17 +322,19 @@ where // notify the handler about this new popup let handle = make_popup_handle(self.token, resource); - let configure = self.handler.new_popup(evqh, handle); + let configure = self.handler.new_popup(evlh, handle); send_popup_configure(resource, configure); + self.handler + .grab(evlh, make_popup_handle(self.token, resource), seat, serial); } - fn set_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, output: Option<&wl_output::WlOutput>) { - self.wl_ensure_toplevel(evqh, resource); - self.wl_handle_display_state_change(evqh, resource, Some(true), Some(false), Some(false), output) + self.wl_ensure_toplevel(evlh, resource); + self.wl_handle_display_state_change(evlh, resource, Some(true), Some(false), Some(false), output) } - fn set_title(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_title(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, title: String) { let ptr = resource.get_user_data(); let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; @@ -343,7 +348,7 @@ where .expect("wl_shell_surface exists but wl_surface has wrong role?!"); } - fn set_class(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_class(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_shell_surface::WlShellSurface, class_: String) { let ptr = resource.get_user_data(); let &(ref surface, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; diff --git a/src/shell/xdg_handlers.rs b/src/shell/xdg_handlers.rs index 50c92a7..5b7fe53 100644 --- a/src/shell/xdg_handlers.rs +++ b/src/shell/xdg_handlers.rs @@ -9,7 +9,7 @@ use std::sync::Mutex; use wayland_protocols::unstable::xdg_shell::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6}; -use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +use wayland_server::{Client, Destroy, EventLoopHandle, Resource}; use wayland_server::protocol::{wl_output, wl_seat, wl_surface}; pub struct XdgShellDestructor { @@ -27,6 +27,8 @@ impl Destroy for XdgShellDestructor { let ptr = shell.get_user_data(); shell.set_user_data(::std::ptr::null_mut()); let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; + // explicit call to drop to not forget what we're doing here + ::std::mem::drop(data); } } @@ -45,11 +47,9 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_shell_v6::ZxdgShellV6) { - } - fn create_positioner(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_positioner_v6::ZxdgPositionerV6) { + fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, _: &zxdg_shell_v6::ZxdgShellV6) {} + fn create_positioner(&mut self, evlh: &mut EventLoopHandle, _: &Client, + _: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_positioner_v6::ZxdgPositionerV6) { trace!(self.log, "Creating new xdg_positioner."); id.set_user_data(Box::into_raw(Box::new(PositionerState { rect_size: (0, 0), @@ -64,9 +64,9 @@ where constraint_adjustment: zxdg_positioner_v6::ConstraintAdjustment::empty(), offset: (0, 0), })) as *mut _); - evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + evlh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); } - fn get_xdg_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn get_xdg_surface(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_shell_v6::ZxdgShellV6, id: zxdg_surface_v6::ZxdgSurfaceV6, surface: &wl_surface::WlSurface) { trace!(self.log, "Creating new wl_shell_surface."); @@ -88,10 +88,10 @@ where resource.clone_unchecked() }))) as *mut _, ); - evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + evlh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); } - fn pong(&mut self, evqh: &mut EventLoopHandle, client: &Client, resource: &zxdg_shell_v6::ZxdgShellV6, + fn pong(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_shell_v6::ZxdgShellV6, serial: u32) { let valid = { let mutex = unsafe { &*(resource.get_user_data() as *mut ShellUserData) }; @@ -104,7 +104,7 @@ where } }; if valid { - self.handler.client_pong(evqh, make_shell_client(resource)); + self.handler.client_pong(evlh, make_shell_client(resource)); } } } @@ -125,6 +125,8 @@ impl Destroy for XdgShellDestructor + Send + 'static, SD: Send + 'static, { - fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_positioner_v6::ZxdgPositionerV6) { - } + fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, _: &zxdg_positioner_v6::ZxdgPositionerV6) {} - fn set_size(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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( @@ -154,7 +154,7 @@ where } } - fn set_anchor_rect(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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 { @@ -174,7 +174,7 @@ where } } - fn set_anchor(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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}; if anchor.contains(AnchorLeft | AnchorRight) || anchor.contains(AnchorTop | AnchorBottom) { @@ -189,7 +189,7 @@ where } } - fn set_gravity(&mut self, evqh: &mut EventLoopHandle, client: &Client, + 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}; if gravity.contains(GravityLeft | GravityRight) || gravity.contains(GravityTop | GravityBottom) { @@ -204,7 +204,7 @@ where } } - fn set_constraint_adjustment(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_constraint_adjustment(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_positioner_v6::ZxdgPositionerV6, constraint_adjustment: u32) { let constraint_adjustment = @@ -214,7 +214,7 @@ where state.constraint_adjustment = constraint_adjustment; } - fn set_offset(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_offset(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_positioner_v6::ZxdgPositionerV6, x: i32, y: i32) { let ptr = resource.get_user_data(); let state = unsafe { &mut *(ptr as *mut PositionerState) }; @@ -242,6 +242,8 @@ impl Destroy for XdgShellDestructor { ptr as *mut (zxdg_surface_v6::ZxdgSurfaceV6, zxdg_shell_v6::ZxdgShellV6), ) }; + // explicit call to drop to not forget what we're doing here + ::std::mem::drop(data); } } @@ -253,8 +255,7 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_surface_v6::ZxdgSurfaceV6) { + fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6) { let ptr = resource.get_user_data(); let &(ref surface, ref shell) = unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; @@ -274,7 +275,7 @@ where ); } - fn get_toplevel(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn get_toplevel(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_toplevel_v6::ZxdgToplevelV6) { let ptr = resource.get_user_data(); let &(ref surface, ref shell) = @@ -300,7 +301,7 @@ where resource.clone_unchecked(), ) })) as *mut _); - evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + evlh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); // register to self self.known_toplevels @@ -308,11 +309,11 @@ where // intial configure event let handle = make_toplevel_handle(self.token, &id); - let configure = self.handler.new_toplevel(evqh, handle); + let configure = self.handler.new_toplevel(evlh, handle); send_toplevel_configure(self.token, &id, configure); } - fn get_popup(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn get_popup(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6, id: zxdg_popup_v6::ZxdgPopupV6, parent: &zxdg_surface_v6::ZxdgSurfaceV6, positioner: &zxdg_positioner_v6::ZxdgPositionerV6) { @@ -324,7 +325,7 @@ where let parent_ptr = parent.get_user_data(); let &(ref parent_surface, _) = - unsafe { &*(ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; + unsafe { &*(parent_ptr as *mut (wl_surface::WlSurface, zxdg_shell_v6::ZxdgShellV6)) }; self.token .with_role_data::(surface, |data| { @@ -344,18 +345,18 @@ where resource.clone_unchecked(), ) })) as *mut _); - evqh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); + evlh.register_with_destructor::<_, Self, XdgShellDestructor>(&id, self.my_id); // register to self self.known_popups.push(make_popup_handle(self.token, &id)); // intial configure event let handle = make_popup_handle(self.token, &id); - let configure = self.handler.new_popup(evqh, handle); + let configure = self.handler.new_popup(evlh, handle); send_popup_configure(self.token, &id, configure); } - fn set_window_geometry(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_window_geometry(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6, x: i32, y: i32, width: i32, height: i32) { let ptr = resource.get_user_data(); @@ -375,7 +376,7 @@ where ); } - fn ack_configure(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn ack_configure(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_surface_v6::ZxdgSurfaceV6, serial: u32) { let ptr = resource.get_user_data(); let &(ref surface, ref shell) = @@ -426,6 +427,8 @@ impl Destroy for XdgShellDestructor { surface.set_user_data(::std::ptr::null_mut()); // drop the PositionerState let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + // explicit call to drop to not forget what we're doing there + ::std::mem::drop(data); } } @@ -454,7 +457,7 @@ where ); } - fn xdg_handle_display_state_change(&mut self, evqh: &mut EventLoopHandle, + fn xdg_handle_display_state_change(&mut self, evlh: &mut EventLoopHandle, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, maximized: Option, minimized: Option, fullscreen: Option, output: Option<&wl_output::WlOutput>) { @@ -462,7 +465,7 @@ where // handler callback let configure = self.handler - .change_display_state(evqh, handle, maximized, minimized, fullscreen, output); + .change_display_state(evlh, handle, maximized, minimized, fullscreen, output); // send the configure response to client send_toplevel_configure(self.token, resource, configure); } @@ -520,8 +523,7 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { + fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { let ptr = resource.get_user_data(); let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; self.token @@ -541,7 +543,7 @@ where }); } - fn set_parent(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_parent(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, parent: Option<&zxdg_toplevel_v6::ZxdgToplevelV6>) { self.with_surface_toplevel_data(resource, |toplevel_data| { @@ -554,75 +556,75 @@ where }); } - fn set_title(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_title(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, title: String) { self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.title = title; }); } - fn set_app_id(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_app_id(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, app_id: String) { self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.app_id = app_id; }); } - fn show_window_menu(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32) { let handle = make_toplevel_handle(self.token, resource); self.handler - .show_window_menu(evqh, handle, seat, serial, x, y); + .show_window_menu(evlh, handle, seat, serial, x, y); } - fn move_(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn move_(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32) { let handle = make_toplevel_handle(self.token, resource); - self.handler.move_(evqh, handle, seat, serial); + self.handler.move_(evlh, handle, seat, serial); } - fn resize(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn resize(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, seat: &wl_seat::WlSeat, serial: u32, edges: u32) { let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); let handle = make_toplevel_handle(self.token, resource); - self.handler.resize(evqh, handle, seat, serial, edges); + self.handler.resize(evlh, handle, seat, serial, edges); } - fn set_max_size(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_max_size(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) { self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.max_size = (width, height); }); } - fn set_min_size(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_min_size(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, width: i32, height: i32) { self.with_surface_toplevel_data(resource, |toplevel_data| { toplevel_data.min_size = (width, height); }); } - fn set_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { - self.xdg_handle_display_state_change(evqh, resource, Some(true), None, None, None); + self.xdg_handle_display_state_change(evlh, resource, Some(true), None, None, None); } - fn unset_maximized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn unset_maximized(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { - self.xdg_handle_display_state_change(evqh, resource, Some(false), None, None, None); + self.xdg_handle_display_state_change(evlh, resource, Some(false), None, None, None); } - fn set_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6, output: Option<&wl_output::WlOutput>) { - self.xdg_handle_display_state_change(evqh, resource, None, None, Some(true), output); + self.xdg_handle_display_state_change(evlh, resource, None, None, Some(true), output); } - fn unset_fullscreen(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn unset_fullscreen(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { - self.xdg_handle_display_state_change(evqh, resource, None, None, Some(false), None); + self.xdg_handle_display_state_change(evlh, resource, None, None, Some(false), None); } - fn set_minimized(&mut self, evqh: &mut EventLoopHandle, client: &Client, + fn set_minimized(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_toplevel_v6::ZxdgToplevelV6) { - self.xdg_handle_display_state_change(evqh, resource, None, Some(true), None, None); + self.xdg_handle_display_state_change(evlh, resource, None, Some(true), None, None); } } @@ -644,6 +646,8 @@ impl Destroy for XdgShellDestructor { surface.set_user_data(::std::ptr::null_mut()); // drop the PositionerState let data = unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; + // explicit call to drop to not forget what we're doing + ::std::mem::drop(data); } } @@ -689,8 +693,7 @@ where SH: UserHandler + Send + 'static, SD: Send + 'static, { - fn destroy(&mut self, evqh: &mut EventLoopHandle, client: &Client, - resource: &zxdg_popup_v6::ZxdgPopupV6) { + fn destroy(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6) { let ptr = resource.get_user_data(); let &(ref surface, _, _) = unsafe { &*(ptr as @@ -717,10 +720,10 @@ where }); } - fn grab(&mut self, evqh: &mut EventLoopHandle, client: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6, + fn grab(&mut self, evlh: &mut EventLoopHandle, _: &Client, resource: &zxdg_popup_v6::ZxdgPopupV6, seat: &wl_seat::WlSeat, serial: u32) { let handle = make_popup_handle(self.token, resource); - self.handler.grab(evqh, handle, seat, serial); + self.handler.grab(evlh, handle, seat, serial); } } From eeb6373dedced83001d9aa6acd418bd6d3e5bff8 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 6 Sep 2017 16:33:35 +0200 Subject: [PATCH 11/13] Silence example warnings. --- examples/simple.rs | 118 +++++++++++++++++++++++---------------------- src/shm/mod.rs | 1 + 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 76f39db..b3dd58a 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -8,7 +8,6 @@ extern crate slog_term; #[macro_use(define_roles)] extern crate smithay; extern crate wayland_protocols; -#[macro_use(server_declare_handler)] extern crate wayland_server; mod helpers; @@ -25,11 +24,11 @@ use smithay::compositor::{self, CompositorHandler, CompositorToken, SubsurfaceRo use smithay::compositor::roles::Role; use smithay::shell::{self, PopupConfigure, PopupSurface, ShellClient, ShellHandler, ShellSurfaceRole, ToplevelConfigure, ToplevelSurface}; -use smithay::shm::{BufferData, ShmGlobal, ShmToken}; +use smithay::shm::{ShmGlobal, ShmToken}; use wayland_protocols::unstable::xdg_shell::server::{zxdg_shell_v6, zxdg_toplevel_v6}; -use wayland_server::{Client, EventLoopHandle, Liveness, Resource}; +use wayland_server::{Client, EventLoopHandle}; use wayland_server::protocol::{wl_compositor, wl_output, wl_seat, wl_shell, wl_shm, wl_subcompositor, wl_surface}; @@ -46,26 +45,29 @@ struct SurfaceData { } impl compositor::Handler for SurfaceHandler { - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, + fn commit(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, surface: &wl_surface::WlSurface, token: CompositorToken) { // 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)))) => { - 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))); - }); + 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(); } Some(None) => { // erase the contents @@ -88,9 +90,9 @@ impl ShellSurfaceHandler { } impl shell::Handler 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, + 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) -> ToplevelConfigure { let wl_surface = surface.get_surface().unwrap(); @@ -109,8 +111,8 @@ impl shell::Handler for ShellSurfaceHand serial: 42, } } - fn new_popup(&mut self, evlh: &mut EventLoopHandle, - surface: PopupSurface) + fn new_popup(&mut self, _evlh: &mut EventLoopHandle, + _surface: PopupSurface) -> PopupConfigure { PopupConfigure { size: (10, 10), @@ -118,22 +120,22 @@ impl shell::Handler for ShellSurfaceHand serial: 42, } } - fn move_(&mut self, evlh: &mut EventLoopHandle, - surface: ToplevelSurface, seat: &wl_seat::WlSeat, - serial: u32) { + fn move_(&mut self, _evlh: &mut EventLoopHandle, + _surface: ToplevelSurface, _seat: &wl_seat::WlSeat, + _serial: u32) { } - fn resize(&mut self, evlh: &mut EventLoopHandle, - surface: ToplevelSurface, seat: &wl_seat::WlSeat, - serial: u32, edges: zxdg_toplevel_v6::ResizeEdge) { + fn resize(&mut self, _evlh: &mut EventLoopHandle, + _surface: ToplevelSurface, _seat: &wl_seat::WlSeat, + _serial: u32, _edges: zxdg_toplevel_v6::ResizeEdge) { } - fn grab(&mut self, evlh: &mut EventLoopHandle, - surface: PopupSurface, seat: &wl_seat::WlSeat, - serial: u32) { + fn grab(&mut self, _evlh: &mut EventLoopHandle, + _surface: PopupSurface, _seat: &wl_seat::WlSeat, + _serial: u32) { } - fn change_display_state(&mut self, evlh: &mut EventLoopHandle, - surface: ToplevelSurface, - maximized: Option, minimized: Option, fullscreen: Option, - output: Option<&wl_output::WlOutput>) + fn change_display_state(&mut self, _evlh: &mut EventLoopHandle, + _surface: ToplevelSurface, + _maximized: Option, _minimized: Option, _fullscreen: Option, + _output: Option<&wl_output::WlOutput>) -> ToplevelConfigure { ToplevelConfigure { size: None, @@ -141,9 +143,9 @@ impl shell::Handler for ShellSurfaceHand serial: 42, } } - fn show_window_menu(&mut self, evlh: &mut EventLoopHandle, - surface: ToplevelSurface, - seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32) { + fn show_window_menu(&mut self, _evlh: &mut EventLoopHandle, + _surface: ToplevelSurface, + _seat: &wl_seat::WlSeat, _serial: u32, _x: i32, _y: i32) { } } @@ -240,24 +242,26 @@ fn main() { // this surface is a root of a subsurface tree that needs to be drawn let initial_place = compositor_token .with_surface_data(wl_surface, |data| data.user_data.location.unwrap_or((0, 0))); - compositor_token.with_surface_tree( - wl_surface, - initial_place, - |surface, attributes, role, &(mut x, mut y)| { - if let Some((ref contents, (w, h))) = attributes.user_data.buffer { - // there is actually something to draw ! - if let Ok(subdata) = Role::::data(role) { - x += subdata.x; - y += subdata.y; + compositor_token + .with_surface_tree( + wl_surface, + initial_place, + |_surface, attributes, role, &(mut x, mut y)| { + if let Some((ref contents, (w, h))) = attributes.user_data.buffer { + // there is actually something to draw ! + if let Ok(subdata) = Role::::data(role) { + x += subdata.x; + y += subdata.y; + } + drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + TraversalAction::DoChildren((x, y)) + } else { + // we are not display, so our children are neither + TraversalAction::SkipChildren } - drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); - TraversalAction::DoChildren((x, y)) - } else { - // we are not display, so our children are neither - TraversalAction::SkipChildren - } - }, - ); + }, + ) + .unwrap(); } } } diff --git a/src/shm/mod.rs b/src/shm/mod.rs index d3dd27b..c0e05d5 100644 --- a/src/shm/mod.rs +++ b/src/shm/mod.rs @@ -127,6 +127,7 @@ pub struct ShmToken { } /// Error that can occur when accessing an SHM buffer +#[derive(Debug)] pub enum BufferAccessError { /// This buffer is not managed by the SHM handler NotManaged, From 08e6187e474082ba740e3a7390cc9e6f3869cbbc Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 6 Sep 2017 16:35:49 +0200 Subject: [PATCH 12/13] shell: module-level documentation --- src/shell/mod.rs | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 65c4eea..eaf761c 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,3 +1,144 @@ +//! Utilities for handling shell surfaces, toplevel and popups +//! +//! This module provides the `ShellHandler` type, which implements automatic handling of +//! shell surfaces objects, by being registered as a global handler for `wl_shell` and +//! `xdg_shell`. +//! +//! ## Why use this handler +//! +//! This handler can track for you the various shell surfaces defined by the clients by +//! handling the `xdg_shell` protocol. It also includes a compatibility layer for the +//! deprecated `wl_shell` global. +//! +//! 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, simply instanciate it and register it to the event loop +//! as a global handler for xdg_shell and wl_shell. You will need to provide it the +//! `CompositorToken` you retrieved from an instanciation of the `CompositorHandler` +//! provided y smithay. +//! +//! ``` +//! # extern crate wayland_server; +//! # #[macro_use] extern crate smithay; +//! # extern crate wayland_protocols; +//! # +//! use smithay::compositor::roles::*; +//! use smithay::compositor::CompositorToken; +//! use smithay::shell::{ShellHandler, Handler as ShellHandlerTrait, ShellSurfaceRole}; +//! use wayland_server::protocol::wl_shell::WlShell; +//! use wayland_protocols::unstable::xdg_shell::server::zxdg_shell_v6::ZxdgShellV6; +//! use wayland_server::{EventLoop, EventLoopHandle}; +//! # use smithay::shell::*; +//! # use wayland_server::protocol::{wl_seat, wl_output}; +//! # use wayland_protocols::unstable::xdg_shell::server::zxdg_toplevel_v6; +//! # #[derive(Default)] struct MySurfaceData; +//! # struct MyHandlerForCompositor; +//! # impl ::smithay::compositor::Handler for MyHandlerForCompositor {} +//! +//! // define the roles type. You need to integrate the ShellSurface role: +//! define_roles!(MyRoles => +//! [ShellSurface, ShellSurfaceRole] +//! ); +//! +//! // define the metadata you want associated with the shell clients +//! #[derive(Default)] +//! struct MyShellData { +//! /* ... */ +//! } +//! +//! // define a sub-handler for the shell::Handler trait +//! struct MyHandlerForShell { +//! /* ... */ +//! } +//! +//! # type MyToplevelSurface = ToplevelSurface; +//! # type MyPopupSurface = PopupSurface; +//! +//! impl ShellHandlerTrait for MyHandlerForShell { +//! /* ... a few methods to implement, see shell::Handler +//! documentation for details ... */ +//! # fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient) { unimplemented!() } +//! # fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient) { 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, minimized: Option, fullscreen: Option, +//! # 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; +//! // 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() { +//! # let (_display, mut event_loop) = wayland_server::create_display(); +//! # let compositor_hid = event_loop.add_handler_with_init( +//! # MyCompositorHandler::new(MyHandlerForCompositor{ /* ... */ }, None /* put a logger here */) +//! # ); +//! # let compositor_token = { +//! # let state = event_loop.state(); +//! # state.get_handler::(compositor_hid).get_token() +//! # }; +//! +//! let shell_hid = event_loop.add_handler_with_init( +//! MyShellHandler::new( +//! MyHandlerForShell{ /* ... */ }, +//! compositor_token, // the composior token you retrieved from the CompositorHandler +//! None /* put a logger here */ +//! ) +//! ); +//! +//! event_loop.register_global::(shell_hid, 1); +//! event_loop.register_global::(shell_hid, 1); +//! +//! // You're now ready to go! +//! # } +//! ``` +//! +//! ### Access to shell surface and clients data +//! +//! There are mainly 3 kind of objects that you'll manipulate from this handler: +//! +//! - `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 +//! the example above). +//! - `ToplevelSurface`: This is a handle representing a toplevel surface, you can +//! retrive a list of all currently alive toplevel surface from the `Shellhandler`. +//! - `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'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 +//! access from the `state()` of the event loop. + use compositor::{CompositorToken, Handler as CompositorHandler, Rectangle}; use compositor::roles::Role; From 22a2f4649fe090baaec5bd999384516c90450b48 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 8 Sep 2017 13:13:07 +0200 Subject: [PATCH 13/13] shell: fix doc typos --- src/shell/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index eaf761c..7d58480 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -24,7 +24,7 @@ //! To initialize this handler, simply instanciate it and register it to the event loop //! as a global handler for xdg_shell and wl_shell. You will need to provide it the //! `CompositorToken` you retrieved from an instanciation of the `CompositorHandler` -//! provided y smithay. +//! provided by smithay. //! //! ``` //! # extern crate wayland_server; @@ -819,7 +819,7 @@ pub trait Handler { fn new_client(&mut self, evlh: &mut EventLoopHandle, client: ShellClient); /// 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. fn client_pong(&mut self, evlh: &mut EventLoopHandle, client: ShellClient); /// A new toplevel surface was created