From 07aec59278ae91913ee3801ead02836051615f6b Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 25 Apr 2017 23:14:45 +1000 Subject: [PATCH] Begin integrating xdg_shell This commit mostly attempts to replace wl_shell with xdg_shell to make integration simpler, however the plan is to re-integrate support for wl_shell and move all xdg_shell functionality behind a (defaulted) feature gate in a future commit to allow for backward-compatibility with wl_shell. Several xdg_surface methods have not yet been exposed in the `DecoratedSurface` API. This commit also fixes a spelling mistake: substract -> subtract. --- Cargo.toml | 5 + examples/simple_window.rs | 21 ++-- src/decorated_surface.rs | 203 +++++++++++++++++++++++++++----------- src/lib.rs | 7 +- 4 files changed, 167 insertions(+), 69 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6668f4..478ee6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,11 @@ travis-ci = { repository = "vberger/wayland-window" } byteorder = "1.0" tempfile = "2.0" wayland-client = { version = ">=0.8.0, <0.10", features = ["cursor"] } +wayland-protocols = { optional = true, version = "0.9.4", features = ["client", "nightly", "unstable_protocols"] } [dev-dependencies] wayland-client = { version = ">=0.8.0, <0.10", features = ["cursor", "dlopen"] } + +[features] +xdg_shell = ["wayland-protocols"] +default = ["xdg_shell"] diff --git a/examples/simple_window.rs b/examples/simple_window.rs index ebf431c..08e8a82 100644 --- a/examples/simple_window.rs +++ b/examples/simple_window.rs @@ -2,6 +2,7 @@ extern crate byteorder; extern crate tempfile; #[macro_use] extern crate wayland_client; +extern crate wayland_protocols; extern crate wayland_window; use byteorder::{WriteBytesExt, NativeEndian}; @@ -13,8 +14,8 @@ use std::os::unix::io::AsRawFd; use tempfile::tempfile; use wayland_client::{EventQueueHandle, EnvHandler}; -use wayland_client::protocol::{wl_surface, wl_shm_pool, wl_buffer, wl_compositor, wl_shell, - wl_subcompositor, wl_shm, wl_shell_surface}; +use wayland_client::protocol::{wl_surface, wl_shm_pool, wl_buffer, wl_compositor, wl_subcompositor, wl_shm}; +use wayland_protocols::unstable::xdg_shell; use wayland_window::DecoratedSurface; @@ -22,7 +23,7 @@ wayland_env!(WaylandEnv, compositor: wl_compositor::WlCompositor, subcompositor: wl_subcompositor::WlSubcompositor, shm: wl_shm::WlShm, - shell: wl_shell::WlShell + shell: xdg_shell::client::zxdg_shell_v6::ZxdgShellV6 ); struct Window { @@ -35,8 +36,15 @@ struct Window { } impl wayland_window::Handler for Window { - fn configure(&mut self, _: &mut EventQueueHandle, _: wl_shell_surface::Resize, width: i32, height: i32) { - self.newsize = Some((width, height)) + fn configure(&mut self, _: &mut EventQueueHandle, width: i32, height: i32) { + let w = std::cmp::max(width, 100); + let h = std::cmp::max(height, 100); + if width <= 0 || height <= 0 { + println!("WARNING: wayland_window::Handler::configure: Received invalid dimensions: \ + {:?}. Using {:?} instead.", (width, height), (w, h)); + } + println!("\tconfigure: resizing to {:?}", (w, h)); + self.newsize = Some((w, h)) } } @@ -95,9 +103,6 @@ fn main() { } } - surface.attach(Some(&buffer), 0, 0); - surface.commit(); - let window = Window { s: surface, tmp: tmp, diff --git a/src/decorated_surface.rs b/src/decorated_surface.rs index 6583b30..d689f03 100644 --- a/src/decorated_surface.rs +++ b/src/decorated_surface.rs @@ -7,11 +7,11 @@ use byteorder::{WriteBytesExt, NativeEndian}; use tempfile::tempfile; -use wayland_client::{Proxy, EventQueueHandle, Init}; -use wayland_client::protocol::{wl_surface, wl_shell, wl_compositor, wl_buffer, wl_subsurface, - wl_seat, wl_shm, wl_pointer, wl_shell_surface, - wl_subcompositor, wl_shm_pool, wl_output}; - +use wayland_client::{self, Proxy, EventQueueHandle, Init}; +use wayland_client::protocol::{wl_surface, wl_compositor, wl_buffer, wl_subsurface, wl_seat, + wl_shm, wl_pointer, wl_shell_surface, wl_subcompositor, wl_shm_pool, + wl_output}; +use wayland_protocols::unstable::xdg_shell; use super::themed_pointer::ThemedPointer; // The surfaces handling the borders, 8 total, are organised this way: @@ -122,6 +122,7 @@ impl PointerState { } } + /// A wrapper for a decorated surface. /// /// This is the main object of this crate. It wraps a user provided @@ -132,7 +133,7 @@ impl PointerState { /// resizing and moving of the window. See the root documentation of /// this crate for explanations about how to use it. pub struct DecoratedSurface { - shell_surface: wl_shell_surface::WlShellSurface, + xdg: Xdg, border_subsurfaces: Vec, buffers: Vec, tempfile: File, @@ -146,6 +147,12 @@ pub struct DecoratedSurface { decorate: bool } +struct Xdg { + toplevel: xdg_shell::client::zxdg_toplevel_v6::ZxdgToplevelV6, + surface: xdg_shell::client::zxdg_surface_v6::ZxdgSurfaceV6, +} + + impl DecoratedSurface { /// Resizes the borders to given width and height. /// @@ -248,7 +255,7 @@ impl DecoratedSurface { compositor: &wl_compositor::WlCompositor, subcompositor: &wl_subcompositor::WlSubcompositor, shm: &wl_shm::WlShm, - shell: &wl_shell::WlShell, + shell: &xdg_shell::client::zxdg_shell_v6::ZxdgShellV6, seat: Option, decorate: bool) -> Result, ()> @@ -273,15 +280,15 @@ impl DecoratedSurface { // create surfaces let border_surfaces: Vec<_> = (0..4).map(|_| compositor.create_surface()) .collect(); - let border_subsurfaces: Vec<_> = border_surfaces.iter() - .map(|s| subcompositor.get_subsurface(&s, surface) - .expect("Subcompositor cannot be destroyed") - ) - .collect(); + let border_subsurfaces: Vec<_> = border_surfaces.iter().map(|s| { + subcompositor.get_subsurface(&s, surface).expect("Subcompositor cannot be destroyed") + }).collect(); for s in &border_subsurfaces { s.set_desync(); } - let shell_surface = shell.get_shell_surface(surface); - shell_surface.set_toplevel(); + // Create the `xdg_surface` and assign the `toplevel` role. + let xdg_surface = shell.get_xdg_surface(surface).expect("shell cannot be destroyed"); + let toplevel = xdg_surface.get_toplevel().expect("xdg_surface cannot be destroyed"); + surface.commit(); // Pointer let pointer_state = { @@ -305,7 +312,10 @@ impl DecoratedSurface { }; let mut me = DecoratedSurface { - shell_surface: shell_surface, + xdg: Xdg { + toplevel: toplevel, + surface: xdg_surface, + }, border_subsurfaces: border_subsurfaces, buffers: Vec::new(), tempfile: tempfile, @@ -329,23 +339,22 @@ impl DecoratedSurface { /// This string may be used to identify the surface in a task bar, window list, or other user /// interface elements provided by the compositor. pub fn set_title(&self, title: String) { - self.shell_surface.set_title(title); + self.xdg.toplevel.set_title(title); } - /// Set a class for the surface. - /// - /// The surface class identifies the general class of applications to which the surface - /// belongs. A common convention is to use the file name (or the full path if it is a - /// non-standard location) of the application's .desktop file as the class. - pub fn set_class(&self, class: String) { - self.shell_surface.set_class(class); - } + // /// Set a class for the surface. + // /// + // /// The surface class identifies the general class of applications to which the surface + // /// belongs. A common convention is to use the file name (or the full path if it is a + // /// non-standard location) of the application's .desktop file as the class. + // pub fn set_class(&self, class: String) { + // self.shell_surface.set_class(class); + // } /// Turn on or off decoration of this surface /// /// Automatically disables fullscreen mode if it was set. pub fn set_decorate(&mut self, decorate: bool) { - self.shell_surface.set_toplevel(); self.decorate = decorate; // trigger redraw let (w, h) = (self.width, self.height); @@ -355,11 +364,8 @@ impl DecoratedSurface { /// Sets this surface as fullscreen (see `wl_shell_surface` for details) /// /// Automatically disables decorations. - pub fn set_fullscreen(&mut self, - method: wl_shell_surface::FullscreenMethod, - framerate: u32, - output: Option<&wl_output::WlOutput>) { - self.shell_surface.set_fullscreen(method, framerate, output); + pub fn set_fullscreen(&mut self, output: Option<&wl_output::WlOutput>) { + self.xdg.toplevel.set_fullscreen(output); self.decorate = false; // trigger redraw let (w, h) = (self.width, self.height); @@ -373,7 +379,8 @@ impl DecoratedSurface { impl Init for DecoratedSurface { fn init(&mut self, evqh: &mut EventQueueHandle, my_index: usize) { - evqh.register::<_, DecoratedSurface>(&self.shell_surface, my_index); + evqh.register::<_, DecoratedSurface>(&self.xdg.toplevel, my_index); + evqh.register::<_, DecoratedSurface>(&self.xdg.surface, my_index); match self.pointer_state.pointer { Pointer::Plain(ref pointer) => { evqh.register::<_, DecoratedSurface>(pointer, my_index); }, Pointer::Themed(ref pointer) => { evqh.register::<_, DecoratedSurface>(&**pointer, my_index); }, @@ -437,54 +444,134 @@ impl wl_pointer::Handler for DecoratedSurface { }; if let Some(ref seat) = self.seat { if resize { - self.shell_surface.resize(&seat, serial, direction); + self.xdg.toplevel.resize(&seat, serial, direction.to_raw()); } else { - self.shell_surface._move(&seat, serial); + self.xdg.toplevel._move(&seat, serial); } } } } -unsafe impl ::wayland_client::Handler for DecoratedSurface { - unsafe fn message(&mut self, evq: &mut EventQueueHandle, proxy: &wl_pointer::WlPointer, opcode: u32, args: *const ::wayland_client::sys::wl_argument) -> Result<(),()> { - as ::wayland_client::protocol::wl_pointer::Handler>::__message(self, evq, proxy, opcode, args) +unsafe impl wayland_client::Handler for DecoratedSurface { + unsafe fn message(&mut self, evq: &mut EventQueueHandle, proxy: &wl_pointer::WlPointer, opcode: u32, args: *const wayland_client::sys::wl_argument) -> Result<(),()> { + as wayland_client::protocol::wl_pointer::Handler>::__message(self, evq, proxy, opcode, args) } } + +/// Subtracts the border dimensions from the given dimensions. +pub fn subtract_borders(width: i32, height: i32) -> (i32, i32) { + ( + width - 2*(DECORATION_SIZE as i32), + height - DECORATION_SIZE as i32 - DECORATION_TOP_SIZE as i32 + ) +} + +/// Adds the border dimensions to the given dimensions. +pub fn add_borders(width: i32, height: i32) -> (i32, i32) { + ( + width + 2*(DECORATION_SIZE as i32), + height + DECORATION_SIZE as i32 + DECORATION_TOP_SIZE as i32 + ) +} + + +///////////////////////////////////////// +// xdg_shell `Handler` implementations // +///////////////////////////////////////// + + +#[cfg(feature = "xdg_shell")] pub trait Handler { - fn configure(&mut self, evqh: &mut EventQueueHandle, edges: wl_shell_surface::Resize, width: i32, height: i32); + fn configure(&mut self, evqh: &mut EventQueueHandle, width: i32, height: i32); } -impl wl_shell_surface::Handler for DecoratedSurface { - fn ping(&mut self, _: &mut EventQueueHandle, me: &wl_shell_surface::WlShellSurface, serial: u32) { - me.pong(serial); +#[cfg(feature = "xdg_shell")] +unsafe impl wayland_client::Handler for DecoratedSurface { + unsafe fn message(&mut self, + evq: &mut EventQueueHandle, + proxy: &xdg_shell::client::zxdg_toplevel_v6::ZxdgToplevelV6, + opcode: u32, + args: *const wayland_client::sys::wl_argument) -> Result<(),()> + { + as xdg_shell::client::zxdg_toplevel_v6::Handler>::__message(self, evq, proxy, opcode, args) + } +} + +#[cfg(feature = "xdg_shell")] +unsafe impl wayland_client::Handler for DecoratedSurface { + unsafe fn message(&mut self, + evq: &mut EventQueueHandle, + proxy: &xdg_shell::client::zxdg_surface_v6::ZxdgSurfaceV6, + opcode: u32, + args: *const wayland_client::sys::wl_argument) -> Result<(),()> + { + as xdg_shell::client::zxdg_surface_v6::Handler>::__message(self, evq, proxy, opcode, args) } - fn configure(&mut self, evqh: &mut EventQueueHandle, _: &wl_shell_surface::WlShellSurface, edges: wl_shell_surface::Resize, width: i32, height: i32) { +} + +#[cfg(feature = "xdg_shell")] +impl xdg_shell::client::zxdg_toplevel_v6::Handler for DecoratedSurface { + + fn configure(&mut self, + evqh: &mut EventQueueHandle, + _proxy: &xdg_shell::client::zxdg_toplevel_v6::ZxdgToplevelV6, + width: i32, height: i32, + _states: Vec) + { + // NOTE: Not sure if/how `_states` should be handled here. if let Some(ref mut handler) = self.handler { - let (w, h) = substract_borders(width, height); - handler.configure(evqh, edges, w, h) + let (w, h) = subtract_borders(width, height); + handler.configure(evqh, max(w, 1), max(h, 1)); } } + + fn close(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &xdg_shell::client::zxdg_toplevel_v6::ZxdgToplevelV6) + { + // NOTE: Should there be a method on `Handler` for this? + } } -unsafe impl ::wayland_client::Handler for DecoratedSurface { - unsafe fn message(&mut self, evq: &mut EventQueueHandle, proxy: &wl_shell_surface::WlShellSurface, opcode: u32, args: *const ::wayland_client::sys::wl_argument) -> Result<(),()> { - as ::wayland_client::protocol::wl_shell_surface::Handler>::__message(self, evq, proxy, opcode, args) +#[cfg(feature = "xdg_shell")] +impl xdg_shell::client::zxdg_surface_v6::Handler for DecoratedSurface { + + fn configure(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &xdg_shell::client::zxdg_surface_v6::ZxdgSurfaceV6, + serial: u32) + { + self.xdg.surface.ack_configure(serial).expect("surface cannot be destroyed"); } + } -/// Substracts the border dimensions from the given dimensions. -pub fn substract_borders(width: i32, height: i32) -> (i32, i32) { - ( - width - 2*(DECORATION_SIZE as i32), - height - DECORATION_SIZE as i32 - DECORATION_TOP_SIZE as i32 - ) + +//////////////////////////////////////// +// wl_shell `Handler` implementations // +//////////////////////////////////////// + + +#[cfg(not(feature = "xdg_shell"))] +pub trait Handler { + fn configure(&mut self, evqh: &mut EventQueueHandle, edges: wl_shell_surface::Resize, width: i32, height: i32); } -/// Adds the border dimensions to the given dimensions. -pub fn add_borders(width: i32, height: i32) -> (i32, i32) { - ( - width + 2*(DECORATION_SIZE as i32), - height + DECORATION_SIZE as i32 + DECORATION_TOP_SIZE as i32 - ) +impl wl_shell_surface::Handler for DecoratedSurface { + fn ping(&mut self, _: &mut EventQueueHandle, me: &wl_shell_surface::WlShellSurface, serial: u32) { + me.pong(serial); + } + fn configure(&mut self, evqh: &mut EventQueueHandle, _: &wl_shell_surface::WlShellSurface, _edges: wl_shell_surface::Resize, width: i32, height: i32) { + if let Some(ref mut handler) = self.handler { + let (w, h) = subtract_borders(width, height); + handler.configure(evqh, w, h) + } + } +} + +unsafe impl wayland_client::Handler for DecoratedSurface { + unsafe fn message(&mut self, evq: &mut EventQueueHandle, proxy: &wl_shell_surface::WlShellSurface, opcode: u32, args: *const wayland_client::sys::wl_argument) -> Result<(),()> { + as wayland_client::protocol::wl_shell_surface::Handler>::__message(self, evq, proxy, opcode, args) + } } diff --git a/src/lib.rs b/src/lib.rs index f34214e..c2c76d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ //! newsize = Some((x, y)) //! } //! if let Some((x, y)) = newsize { -//! let (x, y) = substract_borders(x, y); +//! let (x, y) = subtract_borders(x, y); //! window.resize(x, y); //! } //! ``` @@ -74,14 +74,15 @@ //! window to its current size (update the buffer to the compositor), as the compositer //! might have resized your window without telling you. //! - The size hint provided by the compositor counts the borders size, to get the real -//! size hint for your interior surface, use the function `substract_borders(..)` provided +//! size hint for your interior surface, use the function `subtract_borders(..)` provided //! by this library. extern crate byteorder; extern crate tempfile; extern crate wayland_client; +#[cfg(feature = "xdg_shell")] extern crate wayland_protocols; mod decorated_surface; mod themed_pointer; -pub use decorated_surface::{DecoratedSurface, substract_borders, add_borders, Handler}; +pub use decorated_surface::{DecoratedSurface, subtract_borders, add_borders, Handler};