From ee4eee5ab9dc4e0fb108947f6d07f2af6803b071 Mon Sep 17 00:00:00 2001 From: Timidger Date: Sun, 27 May 2018 17:21:30 -0700 Subject: [PATCH 01/15] Added wlroots protocols to build.rs --- wlroots-sys/build.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/wlroots-sys/build.rs b/wlroots-sys/build.rs index 7cbe2131..4f328519 100644 --- a/wlroots-sys/build.rs +++ b/wlroots-sys/build.rs @@ -127,7 +127,7 @@ fn meson() { } /// Gets the unstable and stable protocols in /usr/share-wayland-protocols and -/// generates server headers for them. +/// in wlroots/protocol. /// /// The path to the folder with the generated headers is returned. It will /// have two directories, `stable`, and `unstable`. @@ -157,6 +157,26 @@ fn generate_protocol_headers() -> io::Result { .unwrap(); } } + for entry in fs::read_dir("./wlroots/protocol")? { + let entry = entry?; + let path = entry.path(); + let mut filename = entry.file_name().into_string().unwrap(); + if filename.ends_with(".xml") { + let new_length = filename.len() - 4; + filename.truncate(new_length); + } else { + continue + } + filename.push_str("-protocol"); + Command::new("wayland-scanner").arg("server-header") + .arg(path.clone()) + .arg(format!("{}/{}.h", + out_path.to_str().unwrap(), + filename)) + .status() + .unwrap(); + } + Ok(out_path) } From de194cbf3f2c6b45fe7195f7560c198eee6dd272 Mon Sep 17 00:00:00 2001 From: Timidger Date: Sun, 27 May 2018 17:21:39 -0700 Subject: [PATCH 02/15] Added wlr layer shell header --- wlroots-sys/src/wlroots.h | 1 + 1 file changed, 1 insertion(+) diff --git a/wlroots-sys/src/wlroots.h b/wlroots-sys/src/wlroots.h index 01f08b16..3ae033f8 100644 --- a/wlroots-sys/src/wlroots.h +++ b/wlroots-sys/src/wlroots.h @@ -41,6 +41,7 @@ #include #include #include +#include #include /// Util includes From d0c81892abcb09d1a4ccafc72e4ef2a8e797d812 Mon Sep 17 00:00:00 2001 From: Timidger Date: Sun, 27 May 2018 17:33:25 -0700 Subject: [PATCH 03/15] Fixed panic comment in shells --- src/types/shell/xdg_shell_v6.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/types/shell/xdg_shell_v6.rs b/src/types/shell/xdg_shell_v6.rs index 0dd11b4c..4bf952b2 100644 --- a/src/types/shell/xdg_shell_v6.rs +++ b/src/types/shell/xdg_shell_v6.rs @@ -195,10 +195,6 @@ impl XdgV6ShellSurface { } /// Creates a weak reference to an `XdgV6ShellSurface`. - /// - /// # Panics - /// If this `XdgV6ShellSurface` is a previously upgraded `XdgV6ShellSurfaceHandle`, - /// then this function will panic. pub fn weak_reference(&self) -> XdgV6ShellSurfaceHandle { XdgV6ShellSurfaceHandle { handle: Rc::downgrade(&self.liveliness), state: match self.state { From f9afe4e095dbb76e369355b2eae53fcb9a1346ca Mon Sep 17 00:00:00 2001 From: Timidger Date: Wed, 30 May 2018 20:46:36 -0700 Subject: [PATCH 04/15] Document xdg shell v6 for each function --- src/types/shell/xdg_shell_v6.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/types/shell/xdg_shell_v6.rs b/src/types/shell/xdg_shell_v6.rs index 4bf952b2..cfe8f876 100644 --- a/src/types/shell/xdg_shell_v6.rs +++ b/src/types/shell/xdg_shell_v6.rs @@ -182,6 +182,10 @@ impl XdgV6ShellSurface { } } + /// Call `iterator` on each surface in the xdg-surface tree, with the surface's + /// position relative to the root xdg-surface. + /// + /// The function is called from root to leaves (in rendering order). pub fn for_each_surface(&self, mut iterator: &mut FnMut(SurfaceHandle, i32, i32)) { unsafe { unsafe extern "C" fn c_iterator(wlr_surface: *mut wlr_surface, sx: i32, sy: i32, data: *mut c_void) { From 7df1de8f864b11007c6d2fde4ba481a73d2d4c82 Mon Sep 17 00:00:00 2001 From: Timidger Date: Wed, 30 May 2018 20:51:43 -0700 Subject: [PATCH 05/15] Added Surface::is_layer_surface --- src/types/surface/surface.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/types/surface/surface.rs b/src/types/surface/surface.rs index 0d53bd2e..eb150f25 100644 --- a/src/types/surface/surface.rs +++ b/src/types/surface/surface.rs @@ -8,7 +8,7 @@ use wayland_sys::server::signal::wl_signal_add; use wlroots_sys::{timespec, wlr_subsurface, wlr_surface, wlr_surface_get_root_surface, wlr_surface_has_buffer, wlr_surface_point_accepts_input, wlr_surface_send_enter, wlr_surface_send_frame_done, wlr_surface_send_leave, wlr_surface_surface_at, - wlr_surface_is_xdg_surface}; + wlr_surface_is_layer_surface, wlr_surface_is_xdg_surface}; use super::{Subsurface, SubsurfaceHandle, SubsurfaceHandler, SubsurfaceManager, SurfaceState, InternalSubsurface}; @@ -300,6 +300,13 @@ impl Surface { unsafe { (*self.surface).surface_to_buffer_matrix } } + /// Determines if this surface is a layer surface. + pub fn is_layer_surface(&self) -> bool { + unsafe { + wlr_surface_is_layer_surface(self.surface) + } + } + /// Creates a weak reference to a `Surface`. /// /// # Panics From 7ffd1a5845d0eb8ef6c9dddda97c033f434ecf34 Mon Sep 17 00:00:00 2001 From: Timidger Date: Wed, 30 May 2018 21:46:16 -0700 Subject: [PATCH 06/15] Added layer shell --- src/lib.rs | 6 +- src/manager/layer_shell_handler.rs | 82 ++++++ src/manager/layer_shell_manager.rs | 76 ++++++ src/manager/mod.rs | 4 + src/types/shell/layer_shell.rs | 399 +++++++++++++++++++++++++++++ src/types/shell/mod.rs | 2 + 6 files changed, 567 insertions(+), 2 deletions(-) create mode 100644 src/manager/layer_shell_handler.rs create mode 100644 src/manager/layer_shell_manager.rs create mode 100644 src/types/shell/layer_shell.rs diff --git a/src/lib.rs b/src/lib.rs index a70bbe74..ecbce4ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,8 +36,10 @@ pub use self::events::{key_events, seat_events, tablet_pad_events, tablet_tool_e xdg_shell_v6_events, xdg_shell_events}; pub use self::manager::{InputManagerHandler, KeyboardHandler, OutputBuilder, OutputBuilderResult, OutputHandler, OutputManagerHandler, PointerHandler, TabletPadHandler, - TabletToolHandler, TouchHandler, XdgV6ShellHandler, XdgV6ShellManagerHandler, - XdgShellHandler, XdgShellManagerHandler}; + TabletToolHandler, TouchHandler, + XdgV6ShellHandler, XdgV6ShellManagerHandler, + XdgShellHandler, XdgShellManagerHandler, + LayerShellManagerHandler, LayerShellHandler}; pub use self::types::area::*; pub use self::types::cursor::*; pub use self::types::data_device::*; diff --git a/src/manager/layer_shell_handler.rs b/src/manager/layer_shell_handler.rs new file mode 100644 index 00000000..d3cafd27 --- /dev/null +++ b/src/manager/layer_shell_handler.rs @@ -0,0 +1,82 @@ +//! Handler for layer shell client. + +use libc; + +use wlroots_sys::{wlr_layer_surface, wlr_xdg_popup}; + +use {Surface, SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, + XdgPopup, XdgShellState}; +use compositor::{compositor_handle, CompositorHandle}; + + +/// Handles events from the client layer shells. +pub trait LayerShellHandler { + /// Called when the surface is ready to be mapped. It should be added to the list of views + /// at this time. + fn on_map(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} + + /// Called when the surface should be unmapped. + /// + /// It should be removed from the list of views at this time, + /// but may be remapped at a later time. + fn on_unmap(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} + + /// Called when there is a new popup. + fn new_popup(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle, XdgShellSurfaceHandle) {} +} + +wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ + on_map_listener => on_map_notify: |this: &mut LayerShell, _data: *mut libc::c_void,| unsafe { + let (ref shell_surface, ref surface, ref mut manager) = this.data; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + manager.on_map(compositor, + surface.weak_reference(), + shell_surface.weak_reference()); + }; + on_unmap_listener => on_unmap_notify: |this: &mut LayerShell, _data: *mut libc::c_void,| + unsafe { + let (ref shell_surface, ref surface, ref mut manager) = this.data; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + + manager.on_unmap(compositor, + surface.weak_reference(), + shell_surface.weak_reference()); + }; + new_popup_listener => new_popup_notify: |this: &mut LayerShell, data: *mut libc::c_void,| + unsafe { + let (ref shell_surface, ref surface, ref mut manager) = this.data; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + let popup_ptr = data as *mut wlr_xdg_popup; + // TODO This seems really incorrect. + // Is base right? + // Shouldn't we store this somewhere now? + // ugh + let xdg_surface = (*popup_ptr).base; + let popup = XdgPopup::from_shell(xdg_surface, popup_ptr); + let xdg_surface = XdgShellSurface::new(xdg_surface, XdgShellState::Popup(popup)); + + manager.new_popup(compositor, + surface.weak_reference(), + shell_surface.weak_reference(), + xdg_surface.weak_reference()); + }; +]); + +impl LayerShell { + pub(crate) unsafe fn surface_ptr(&self) -> *mut wlr_layer_surface { + self.data.0.as_ptr() + } + + pub(crate) fn surface_mut(&mut self) -> LayerSurfaceHandle { + self.data.0.weak_reference() + } +} diff --git a/src/manager/layer_shell_manager.rs b/src/manager/layer_shell_manager.rs new file mode 100644 index 00000000..2ce31bcc --- /dev/null +++ b/src/manager/layer_shell_manager.rs @@ -0,0 +1,76 @@ +//! Manager for layer shell clients. + +use libc; +use wayland_sys::server::WAYLAND_SERVER_HANDLE; +use wayland_sys::server::signal::wl_signal_add; +use wlroots_sys::wlr_layer_surface; + +use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface}; +use super::layer_shell_handler::LayerShell; +use compositor::{compositor_handle, CompositorHandle}; + +pub trait LayerShellManagerHandler { + /// Callback that is triggered when a new layer shell surface appears. + fn new_surface(&mut self, + CompositorHandle, + LayerSurfaceHandle) + -> Option>; + + /// Callback that is triggered when a layer shell surface is destroyed. + fn surface_destroyed(&mut self, CompositorHandle, LayerSurfaceHandle); +} + +wayland_listener!(LayerShellManager, (Vec>, Box), [ + add_listener => add_notify: |this: &mut LayerShellManager, data: *mut libc::c_void,| unsafe { + let remove_listener = this.remove_listener() as *mut _ as _; + let (ref mut shells, ref mut manager) = this.data; + let data = data as *mut wlr_layer_surface; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + wlr_log!(L_DEBUG, "New layer shell surface request {:p}", data); + let surface = Surface::new((*data).surface); + let layer_surface = LayerSurface::new(data); + let new_surface_res = manager.new_surface(compositor, layer_surface.weak_reference()); + if let Some(layer_surface_handler) = new_surface_res { + let mut layer_surface = LayerShell::new((layer_surface, + surface, + layer_surface_handler)); + // Hook the destroy event into this manager. + wl_signal_add(&mut (*data).events.destroy as *mut _ as _, + remove_listener); + + // Hook the other events into the shell surface. + wl_signal_add(&mut (*data).events.map as *mut _ as _, + layer_surface.on_map_listener() as _); + wl_signal_add(&mut (*data).events.unmap as *mut _ as _, + layer_surface.on_unmap_listener() as _); + wl_signal_add(&mut (*data).events.new_popup as *mut _ as _, + layer_surface.new_popup_listener() as _); + shells.push(layer_surface); + } + }; + remove_listener => remove_notify: |this: &mut LayerShellManager, data: *mut libc::c_void,| + unsafe { + let (ref mut shells, ref mut manager) = this.data; + let data = data as *mut wlr_layer_surface; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + if let Some(index) = shells.iter().position(|shell| shell.surface_ptr() == data) { + let mut removed_shell = shells.remove(index); + manager.surface_destroyed(compositor, removed_shell.surface_mut()); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*removed_shell.on_map_listener()).link as *mut _ as _); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*removed_shell.on_unmap_listener()).link as *mut _ as _); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*removed_shell.new_popup_listener()).link as *mut _ as _); + } + }; +]); diff --git a/src/manager/mod.rs b/src/manager/mod.rs index d2566cd1..0b27aaf9 100644 --- a/src/manager/mod.rs +++ b/src/manager/mod.rs @@ -8,6 +8,8 @@ mod xdg_shell_v6_manager; mod xdg_shell_v6_handler; mod xdg_shell_manager; mod xdg_shell_handler; +mod layer_shell_manager; +mod layer_shell_handler; mod tablet_pad_handler; mod tablet_tool_handler; @@ -24,3 +26,5 @@ pub use self::xdg_shell_v6_handler::*; pub use self::xdg_shell_v6_manager::*; pub use self::xdg_shell_handler::*; pub use self::xdg_shell_manager::*; +pub use self::layer_shell_handler::*; +pub use self::layer_shell_manager::*; diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs new file mode 100644 index 00000000..f5a74e27 --- /dev/null +++ b/src/types/shell/layer_shell.rs @@ -0,0 +1,399 @@ +//! wlr_layer_shell allows clients to arrange themselves in "layers" on the +//! desktop in accordance with the wlr-layer-shell protocol. +//! +//! When a client is added, the new_surface signal will be raised and passed +//! a reference to our wlr_layer_surface. At this time, the client will have +//! configured the surface as it desires, including information like +//! desired anchors and margins. +//! +//! The compositor should use this information to decide how to arrange the layer +//! on-screen, then determine the dimensions of the layer and call +//! wlr_layer_surface_configure. +//! +//! The client will then attach a buffer and commit +//! the surface, at which point the wlr_layer_surface map signal is raised and +//! the compositor should begin rendering the surface. + +use std::{panic, ptr, cell::Cell, rc::{Rc, Weak}, marker::PhantomData}; + +use libc::{c_double, c_void}; +use wlroots_sys::{wlr_layer_surface_state, wlr_layer_surface, + wlr_layer_surface_configure, wlr_layer_surface_close, + wlr_layer_surface_for_each_surface, wlr_surface, + wlr_layer_surface_surface_at, zwlr_layer_shell_v1_layer}; + +use utils::c_to_rust_string; +use errors::{HandleErr, HandleResult}; + +use {SurfaceHandle, OutputHandle}; + +/// Used to reconstruct `LayerSurfaceHandle`s from raw pointers. +struct InternalLayerSurfaceState { + handle: Weak> +} + +#[derive(Debug)] +pub struct LayerSurface { + liveliness: Rc>, + layer_surface: *mut wlr_layer_surface +} + +#[derive(Debug, Clone)] +/// A handle to a layer surface that can be upgraded when there are no +/// other references active to it. +pub struct LayerSurfaceHandle { + handle: Weak>, + layer_surface: *mut wlr_layer_surface +} + +/// The meta information about a layer surface. +pub struct LayerSurfaceState<'surface> { + state: *const wlr_layer_surface_state, + phantom: PhantomData<&'surface LayerSurface> +} + +/// The configuration sent with a change in state. +pub struct LayerSurfaceConfigure<'surface> { + configure: *const wlr_layer_surface_configure, + phantom: PhantomData<&'surface LayerSurface> +} + +impl <'surface> LayerSurfaceState<'surface> { + unsafe fn new<'unbound>(state: *const wlr_layer_surface_state) -> Self { + LayerSurfaceState { state, phantom: PhantomData } + } + + pub fn anchor(&self) -> u32 { + unsafe { (*self.state).anchor } + } + + pub fn exclusive_zone(&self) -> i32 { + unsafe { (*self.state).exclusive_zone } + } + + /// Get the margin in this format: (top, right, bottom, left). + pub fn margin(&self) -> (u32, u32, u32, u32) { + unsafe { + ((*self.state).margin.top, + (*self.state).margin.right, + (*self.state).margin.bottom, + (*self.state).margin.left) + } + } + + pub fn keyboard_interactive(&self) -> bool { + unsafe { (*self.state).keyboard_interactive } + } + + /// Get the desired size of the surface in (width, height) format. + pub fn desired_size(&self) -> (u32, u32) { + unsafe { ((*self.state).desired_width, (*self.state).desired_height) } + } + + /// Get the desired size of the surface in (width, height) format. + pub fn actual_size(&self) -> (u32, u32) { + unsafe { ((*self.state).actual_width, (*self.state).actual_height) } + } +} + +impl <'surface> LayerSurfaceConfigure<'surface> { + unsafe fn new<'unbound>(configure: *const wlr_layer_surface_configure) -> Self { + LayerSurfaceConfigure { configure, phantom: PhantomData } + } + + pub fn serial(&self) -> u32 { + unsafe { (*self.configure).serial } + } + + pub fn state(&'surface self) -> LayerSurfaceState<'surface> { + unsafe { LayerSurfaceState::new(&(*self.configure).state) } + } +} + +impl LayerSurface { + pub(crate) unsafe fn new(layer_surface: *mut wlr_layer_surface) -> Self { + if (*layer_surface).output.is_null() { + // TODO Don't do this, instead gotta return a builder + panic!("Layer surface had a null output") + } + let liveliness = Rc::new(Cell::new(false)); + let state = Box::new(InternalLayerSurfaceState { handle: Rc::downgrade(&liveliness) }); + (*layer_surface).data = Box::into_raw(state) as *mut _; + LayerSurface { liveliness, + layer_surface } + } + + pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_layer_surface { + self.layer_surface + } + + unsafe fn from_handle(handle: &LayerSurfaceHandle) -> HandleResult { + let liveliness = handle.handle + .upgrade() + .ok_or_else(|| HandleErr::AlreadyDropped)?; + Ok(LayerSurface { liveliness, layer_surface: handle.as_ptr() }) + } + + /// Creates a weak reference to a `LayerSurface`. + pub fn weak_reference(&self) -> LayerSurfaceHandle { + LayerSurfaceHandle { handle: Rc::downgrade(&self.liveliness), + layer_surface: self.layer_surface } + } + + /// Gets the surface used by this Layer shell. + pub fn surface(&self) -> SurfaceHandle { + unsafe { + let surface = (*self.layer_surface).surface; + if surface.is_null() { + panic!("Layer surface had a null surface!") + } + SurfaceHandle::from_ptr(surface) + } + } + + pub fn output(&self) -> OutputHandle { + unsafe { + let output = (*self.layer_surface).output; + if output.is_null() { + panic!("Layer surface had a null output!") + } + OutputHandle::from_ptr(output) + } + } + + // TODO Implement when xdg shell stable is implemented + //pub fn popups(&self) -> Vec<> + + /// Get the namespace this surface resides in. + pub fn namespace(&self) -> Option { + unsafe { c_to_rust_string((*self.layer_surface).namespace) } + } + + pub fn layer(&self) -> zwlr_layer_shell_v1_layer { + unsafe { (*self.layer_surface).layer } + } + + pub fn added(&self) -> bool { + unsafe { (*self.layer_surface).added } + } + + pub fn configured(&self) -> bool { + unsafe { (*self.layer_surface).configured } + } + + pub fn mapped(&self) -> bool { + unsafe { (*self.layer_surface).mapped } + } + + pub fn closed(&self) -> bool { + unsafe { (*self.layer_surface).closed} + } + + pub fn configure_serial(&self) -> u32 { + unsafe { (*self.layer_surface).configure_serial } + } + + pub fn configure_next_serial(&self) -> u32 { + unsafe { (*self.layer_surface).configure_next_serial } + } + + pub fn configure_list<'surface>(&'surface self) -> Vec> { + let mut result = Vec::new(); + unsafe { + wl_list_for_each!((*self.layer_surface).configure_list, + link, + (configure: wlr_layer_surface_configure) => { + result.push(LayerSurfaceConfigure::new(configure)) + }); + } + result + } + + pub fn acked_configure<'surface>(&'surface self) -> Option> { + unsafe { + let acked_configure = (*self.layer_surface).acked_configure; + if acked_configure.is_null() { + None + } else { + Some(LayerSurfaceConfigure::new(acked_configure)) + } + } + } + + pub fn client_pending<'surface>(&'surface self) -> LayerSurfaceState<'surface> { + unsafe { + LayerSurfaceState::new(&(*self.layer_surface).client_pending) + } + } + + pub fn server_pending<'surface>(&'surface self) -> LayerSurfaceState<'surface> { + unsafe { + LayerSurfaceState::new(&(*self.layer_surface).server_pending) + } + } + + pub fn current<'surface>(&'surface self) -> LayerSurfaceState<'surface> { + unsafe { + LayerSurfaceState::new(&(*self.layer_surface).current) + } + } + + /// Unmaps this layer surface and notifies the client that it has been closed. + pub fn close(&mut self) { + unsafe { + wlr_layer_surface_close(self.layer_surface) + } + } + + /// Find a surface within this layer-surface tree at the given surface-local + /// coordinates. + /// + //// Returns the surface and coordinates in the leaf surface + /// coordinate system or None if no surface is found at that location. + /// + /// Return coordinates are in (x, y) format + pub fn surface_at(&self, sx: c_double, sy: c_double) -> Option<(SurfaceHandle, c_double, c_double)> { + unsafe { + let (mut sub_x, mut sub_y) = (0.0, 0.0); + let surface_ptr = wlr_layer_surface_surface_at(self.layer_surface, sx, sy, &mut sub_x, &mut sub_y); + if surface_ptr.is_null() { + None + } else { + Some((SurfaceHandle::from_ptr(surface_ptr), sub_x, sub_y)) + } + } + } + + /// Calls the iterator function for each sub-surface and popup of this surface + pub fn for_each_surface(&self, mut iterator: &mut FnMut(SurfaceHandle, i32, i32)) { + unsafe extern "C" fn c_iterator(wlr_surface: *mut wlr_surface, sx: i32, sy: i32, data: *mut c_void) { + let iterator = &mut *(data as *mut &mut FnMut(SurfaceHandle, i32, i32)); + let surface = SurfaceHandle::from_ptr(wlr_surface); + iterator(surface, sx, sy); + } + unsafe { + let iterator_ptr: *mut c_void = &mut iterator as *mut _ as *mut c_void; + wlr_layer_surface_for_each_surface(self.layer_surface, Some(c_iterator), iterator_ptr); + } + } +} + +impl Drop for LayerSurface { + fn drop(&mut self) { + if Rc::strong_count(&self.liveliness) == 1 { + wlr_log!(L_DEBUG, "Dropped Layer Shell Surface {:p}", self.layer_surface); + unsafe { + let _ = Box::from_raw((*self.layer_surface).data as *mut InternalLayerSurfaceState); + } + let weak_count = Rc::weak_count(&self.liveliness); + if weak_count > 0 { + wlr_log!(L_DEBUG, + "Still {} weak pointers to Layer Shell Surface {:p}", + weak_count, self.layer_surface); + } + } + } +} + +impl LayerSurfaceHandle { + /// Constructs a new LayerSurfaceHandle that is always invalid. Calling `run` on this + /// will always fail. + /// + /// This is useful for pre-filling a value before it's provided by the server, or + /// for mocking/testing. + pub fn new() -> Self { + unsafe { + LayerSurfaceHandle { handle: Weak::new(), + layer_surface: ptr::null_mut() } + } + } + + /// Creates a LayerSurfaceHandle from the raw pointer, using the saved + /// user data to recreate the memory model. + pub(crate) unsafe fn from_ptr(layer_surface: *mut wlr_layer_surface) -> Self { + let data = (*layer_surface).data as *mut InternalLayerSurfaceState; + if data.is_null() { + panic!("Layer surface has not been setup properly!"); + } + let handle = (*data).handle.clone(); + LayerSurfaceHandle { handle, layer_surface } + } + + /// Upgrades the wayland shell handle to a reference to the backing `LayerSurface`. + /// + /// # Unsafety + /// This function is unsafe, because it creates an unbound `LayerSurface` + /// which may live forever.. + /// But no surface lives forever and might be disconnected at any time. + pub(crate) unsafe fn upgrade(&self) -> HandleResult { + self.handle.upgrade() + .ok_or(HandleErr::AlreadyDropped) + // NOTE + // We drop the Rc here because having two would allow a dangling + // pointer to exist! + .and_then(|check| { + let shell_surface = LayerSurface::from_handle(self)?; + if check.get() { + return Err(HandleErr::AlreadyBorrowed) + } + check.set(true); + Ok(shell_surface) + }) + } + + /// Run a function on the referenced LayerSurface, if it still exists + /// + /// Returns the result of the function, if successful + /// + /// # Safety + /// By enforcing a rather harsh limit on the lifetime of the output + /// to a short lived scope of an anonymous function, + /// this function ensures the LayerSurface does not live longer + /// than it exists. + /// + /// # Panics + /// This function will panic if multiple mutable borrows are detected. + /// This will happen if you call `upgrade` directly within this callback, + /// or if you run this function within the another run to the same `LayerSurface`. + /// + /// So don't nest `run` calls and everything will be ok :). + pub fn run(&mut self, runner: F) -> HandleResult + where F: FnOnce(&mut LayerSurface) -> R + { + let mut layer_surface = unsafe { self.upgrade()? }; + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut layer_surface))); + self.handle.upgrade().map(|check| { + // Sanity check that it hasn't been tampered with. + if !check.get() { + wlr_log!(L_ERROR, + "After running LayerSurface callback, \ + mutable lock was false for: {:?}", + layer_surface); + panic!("Lock in incorrect state!"); + } + check.set(false); + }); + match res { + Ok(res) => Ok(res), + Err(err) => panic::resume_unwind(err) + } + } + + unsafe fn as_ptr(&self) -> *mut wlr_layer_surface { + self.layer_surface + } +} + +impl Default for LayerSurfaceHandle { + fn default() -> Self { + LayerSurfaceHandle::new() + } +} + +impl PartialEq for LayerSurfaceHandle { + fn eq(&self, other: &LayerSurfaceHandle) -> bool { + self.layer_surface == other.layer_surface + } +} + +impl Eq for LayerSurfaceHandle {} diff --git a/src/types/shell/mod.rs b/src/types/shell/mod.rs index 77e342f8..3af7274d 100644 --- a/src/types/shell/mod.rs +++ b/src/types/shell/mod.rs @@ -1,5 +1,7 @@ mod xdg_shell_v6; mod xdg_shell; +mod layer_shell; pub use self::xdg_shell_v6::*; pub use self::xdg_shell::*; +pub use self::layer_shell::*; From 959e9cc9c2ee79b510a2e75f0ca8f3530e192e18 Mon Sep 17 00:00:00 2001 From: Timidger Date: Wed, 30 May 2018 22:03:38 -0700 Subject: [PATCH 07/15] Added layer shell to compositor builder --- src/compositor.rs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/compositor.rs b/src/compositor.rs index 70ec31a4..960382b2 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -9,15 +9,15 @@ use errors::{HandleErr, HandleResult}; use types::surface::{InternalSurface, InternalSurfaceState}; use extensions::server_decoration::ServerDecorationManager; use manager::{InputManager, InputManagerHandler, OutputManager, OutputManagerHandler, - XdgShellManager, - XdgShellManagerHandler, XdgV6ShellManager, XdgV6ShellManagerHandler}; + XdgShellManager, XdgShellManagerHandler, XdgV6ShellManager, + XdgV6ShellManagerHandler, LayerShellManagerHandler, LayerShellManager}; use render::GenericRenderer; use wayland_sys::server::{wl_display, wl_event_loop, signal::wl_signal_add, WAYLAND_SERVER_HANDLE}; use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start, - wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, + wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, wlr_wl_shell, wlr_xdg_shell_v6, wlr_xdg_shell_v6_create, - wlr_xdg_shell, wlr_xdg_shell_create}; + wlr_xdg_shell, wlr_xdg_shell_create, wlr_layer_shell_create, wlr_layer_shell}; use wlroots_sys::wayland_server::sys::wl_display_init_shm; /// Global compositor pointer, used to refer to the compositor state unsafely. @@ -80,12 +80,17 @@ pub struct Compositor { xdg_shell_manager: Option>, /// Manager for XDG shells v6. xdg_v6_shell_manager: Option>, + /// Manager for layer shells. + layer_shell_manager: Option>, /// Pointer to the xdg_shell global. /// If xdg_shell_manager is `None`, this value will be `NULL`. xdg_shell_global: *mut wlr_xdg_shell, /// Pointer to the xdg_shell_v6 global. /// If xdg_v6_shell_manager is `None`, this value will be `NULL`. xdg_v6_shell_global: *mut wlr_xdg_shell_v6, + /// Pointer to the layer_shell global. + /// If layer_shell_manager is `None`, this value will be `NULL`. + layer_shell_global: *mut wlr_layer_shell, /// Pointer to the wlr_compositor. compositor: *mut wlr_compositor, /// Pointer to the wlroots backend in use. @@ -122,6 +127,7 @@ pub struct CompositorBuilder { output_manager_handler: Option>, xdg_shell_manager_handler: Option>, xdg_v6_shell_manager_handler: Option>, + layer_shell_manager_handler: Option>, gles2: bool, server_decoration_manager: bool, data_device_manager: bool, @@ -142,6 +148,7 @@ impl CompositorBuilder { output_manager_handler: None, xdg_shell_manager_handler: None, xdg_v6_shell_manager_handler: None, + layer_shell_manager_handler: None, xwayland: None, user_terminate: None } } @@ -179,6 +186,14 @@ impl CompositorBuilder { self } + /// Set the handler for the layer shells. + pub fn layer_shell_manager(mut self, + layer_shell_manager_handler: Box) + -> Self { + self.layer_shell_manager_handler = Some(layer_shell_manager_handler); + self + } + /// Decide whether or not to enable the data device manager. /// /// This is used to do DnD, or "drag 'n drop" copy paste. @@ -311,6 +326,17 @@ impl CompositorBuilder { xdg_v6_shell_manager }); + // Set up the layer shell handler and associated Wayland global, + // if user provided a manager for it. + let mut layer_shell_global = ptr::null_mut(); + let layer_shell_manager = self.layer_shell_manager_handler.map(|handler| { + layer_shell_global = wlr_layer_shell_create(display as *mut _); + let mut layer_shell_manager = LayerShellManager::new((vec![], handler)); + wl_signal_add(&mut (*layer_shell_global).events.new_surface as *mut _ as _, + layer_shell_manager.add_listener() as *mut _ as _); + layer_shell_manager + }); + // Set up the XWayland server, if the user wants it. let xwayland = self.xwayland.and_then(|manager| { Some(XWaylandServer::new(display as _, @@ -344,6 +370,8 @@ impl CompositorBuilder { xdg_shell_global, xdg_v6_shell_manager, xdg_v6_shell_global, + layer_shell_manager, + layer_shell_global, data_device_manager, compositor, backend, From 3c5c5a47f3eb1a4c74fb10a62669a1087e90fa85 Mon Sep 17 00:00:00 2001 From: Timidger Date: Wed, 30 May 2018 22:04:24 -0700 Subject: [PATCH 08/15] Removed InternalLayerSurfaceState --- src/types/shell/layer_shell.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs index f5a74e27..a6119282 100644 --- a/src/types/shell/layer_shell.rs +++ b/src/types/shell/layer_shell.rs @@ -27,11 +27,6 @@ use errors::{HandleErr, HandleResult}; use {SurfaceHandle, OutputHandle}; -/// Used to reconstruct `LayerSurfaceHandle`s from raw pointers. -struct InternalLayerSurfaceState { - handle: Weak> -} - #[derive(Debug)] pub struct LayerSurface { liveliness: Rc>, @@ -117,8 +112,6 @@ impl LayerSurface { panic!("Layer surface had a null output") } let liveliness = Rc::new(Cell::new(false)); - let state = Box::new(InternalLayerSurfaceState { handle: Rc::downgrade(&liveliness) }); - (*layer_surface).data = Box::into_raw(state) as *mut _; LayerSurface { liveliness, layer_surface } } @@ -282,9 +275,6 @@ impl Drop for LayerSurface { fn drop(&mut self) { if Rc::strong_count(&self.liveliness) == 1 { wlr_log!(L_DEBUG, "Dropped Layer Shell Surface {:p}", self.layer_surface); - unsafe { - let _ = Box::from_raw((*self.layer_surface).data as *mut InternalLayerSurfaceState); - } let weak_count = Rc::weak_count(&self.liveliness); if weak_count > 0 { wlr_log!(L_DEBUG, @@ -308,17 +298,6 @@ impl LayerSurfaceHandle { } } - /// Creates a LayerSurfaceHandle from the raw pointer, using the saved - /// user data to recreate the memory model. - pub(crate) unsafe fn from_ptr(layer_surface: *mut wlr_layer_surface) -> Self { - let data = (*layer_surface).data as *mut InternalLayerSurfaceState; - if data.is_null() { - panic!("Layer surface has not been setup properly!"); - } - let handle = (*data).handle.clone(); - LayerSurfaceHandle { handle, layer_surface } - } - /// Upgrades the wayland shell handle to a reference to the backing `LayerSurface`. /// /// # Unsafety From b49074b69062c1dbdb5113afda72af73e04a73ff Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 4 Jun 2018 19:47:11 -0700 Subject: [PATCH 09/15] Made layer shell act like the other shells E.g there is no longer a vec of shells in the manager --- src/compositor.rs | 4 +-- src/manager/layer_shell_handler.rs | 40 ++++++++++++++++------ src/manager/layer_shell_manager.rs | 54 +++++++----------------------- src/types/shell/layer_shell.rs | 4 --- 4 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/compositor.rs b/src/compositor.rs index 960382b2..ba77f312 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -15,7 +15,7 @@ use render::GenericRenderer; use wayland_sys::server::{wl_display, wl_event_loop, signal::wl_signal_add, WAYLAND_SERVER_HANDLE}; use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start, - wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, wlr_wl_shell, + wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, wlr_xdg_shell_v6, wlr_xdg_shell_v6_create, wlr_xdg_shell, wlr_xdg_shell_create, wlr_layer_shell_create, wlr_layer_shell}; use wlroots_sys::wayland_server::sys::wl_display_init_shm; @@ -331,7 +331,7 @@ impl CompositorBuilder { let mut layer_shell_global = ptr::null_mut(); let layer_shell_manager = self.layer_shell_manager_handler.map(|handler| { layer_shell_global = wlr_layer_shell_create(display as *mut _); - let mut layer_shell_manager = LayerShellManager::new((vec![], handler)); + let mut layer_shell_manager = LayerShellManager::new(handler); wl_signal_add(&mut (*layer_shell_global).events.new_surface as *mut _ as _, layer_shell_manager.add_listener() as *mut _ as _); layer_shell_manager diff --git a/src/manager/layer_shell_handler.rs b/src/manager/layer_shell_handler.rs index d3cafd27..5902dd13 100644 --- a/src/manager/layer_shell_handler.rs +++ b/src/manager/layer_shell_handler.rs @@ -2,6 +2,7 @@ use libc; +use wayland_sys::server::WAYLAND_SERVER_HANDLE; use wlroots_sys::{wlr_layer_surface, wlr_xdg_popup}; use {Surface, SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, @@ -23,9 +24,38 @@ pub trait LayerShellHandler { /// Called when there is a new popup. fn new_popup(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle, XdgShellSurfaceHandle) {} + + /// Called when the Layer Shell is destroyed. + fn destroyed(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} } wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ + destroy_listener => destroy_notify: |this: &mut LayerShell, data: *mut libc::c_void,| unsafe { + let layer_surface_ptr = data as *mut wlr_layer_surface; + { + let (ref shell_surface, ref surface, ref mut manager) = this.data; + let compositor = match compositor_handle() { + Some(handle) => handle, + None => return + }; + manager.destroyed(compositor, + surface.weak_reference(), + shell_surface.weak_reference()); + } + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*this.destroy_listener()).link as *mut _ as _); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*this.on_map_listener()).link as *mut _ as _); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*this.on_unmap_listener()).link as *mut _ as _); + ffi_dispatch!(WAYLAND_SERVER_HANDLE, + wl_list_remove, + &mut (*this.new_popup_listener()).link as *mut _ as _); + Box::from_raw((*layer_surface_ptr).data as *mut LayerShell); + }; on_map_listener => on_map_notify: |this: &mut LayerShell, _data: *mut libc::c_void,| unsafe { let (ref shell_surface, ref surface, ref mut manager) = this.data; let compositor = match compositor_handle() { @@ -70,13 +100,3 @@ wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ xdg_surface.weak_reference()); }; ]); - -impl LayerShell { - pub(crate) unsafe fn surface_ptr(&self) -> *mut wlr_layer_surface { - self.data.0.as_ptr() - } - - pub(crate) fn surface_mut(&mut self) -> LayerSurfaceHandle { - self.data.0.weak_reference() - } -} diff --git a/src/manager/layer_shell_manager.rs b/src/manager/layer_shell_manager.rs index 2ce31bcc..54f14104 100644 --- a/src/manager/layer_shell_manager.rs +++ b/src/manager/layer_shell_manager.rs @@ -1,7 +1,6 @@ //! Manager for layer shell clients. use libc; -use wayland_sys::server::WAYLAND_SERVER_HANDLE; use wayland_sys::server::signal::wl_signal_add; use wlroots_sys::wlr_layer_surface; @@ -15,62 +14,33 @@ pub trait LayerShellManagerHandler { CompositorHandle, LayerSurfaceHandle) -> Option>; - - /// Callback that is triggered when a layer shell surface is destroyed. - fn surface_destroyed(&mut self, CompositorHandle, LayerSurfaceHandle); } -wayland_listener!(LayerShellManager, (Vec>, Box), [ +wayland_listener!(LayerShellManager, Box, [ add_listener => add_notify: |this: &mut LayerShellManager, data: *mut libc::c_void,| unsafe { - let remove_listener = this.remove_listener() as *mut _ as _; - let (ref mut shells, ref mut manager) = this.data; - let data = data as *mut wlr_layer_surface; + let ref mut manager = this.data; + let layer_surface_ptr = data as *mut wlr_layer_surface; let compositor = match compositor_handle() { Some(handle) => handle, None => return }; - wlr_log!(L_DEBUG, "New layer shell surface request {:p}", data); - let surface = Surface::new((*data).surface); - let layer_surface = LayerSurface::new(data); + wlr_log!(L_DEBUG, "New layer shell surface request {:p}", layer_surface_ptr); + let surface = Surface::new((*layer_surface_ptr).surface); + let layer_surface = LayerSurface::new(layer_surface_ptr); let new_surface_res = manager.new_surface(compositor, layer_surface.weak_reference()); if let Some(layer_surface_handler) = new_surface_res { let mut layer_surface = LayerShell::new((layer_surface, surface, layer_surface_handler)); - // Hook the destroy event into this manager. - wl_signal_add(&mut (*data).events.destroy as *mut _ as _, - remove_listener); - - // Hook the other events into the shell surface. - wl_signal_add(&mut (*data).events.map as *mut _ as _, + wl_signal_add(&mut (*layer_surface_ptr).events.destroy as *mut _ as _, + layer_surface.destroy_listener() as _); + wl_signal_add(&mut (*layer_surface_ptr).events.map as *mut _ as _, layer_surface.on_map_listener() as _); - wl_signal_add(&mut (*data).events.unmap as *mut _ as _, + wl_signal_add(&mut (*layer_surface_ptr).events.unmap as *mut _ as _, layer_surface.on_unmap_listener() as _); - wl_signal_add(&mut (*data).events.new_popup as *mut _ as _, + wl_signal_add(&mut (*layer_surface_ptr).events.new_popup as *mut _ as _, layer_surface.new_popup_listener() as _); - shells.push(layer_surface); - } - }; - remove_listener => remove_notify: |this: &mut LayerShellManager, data: *mut libc::c_void,| - unsafe { - let (ref mut shells, ref mut manager) = this.data; - let data = data as *mut wlr_layer_surface; - let compositor = match compositor_handle() { - Some(handle) => handle, - None => return - }; - if let Some(index) = shells.iter().position(|shell| shell.surface_ptr() == data) { - let mut removed_shell = shells.remove(index); - manager.surface_destroyed(compositor, removed_shell.surface_mut()); - ffi_dispatch!(WAYLAND_SERVER_HANDLE, - wl_list_remove, - &mut (*removed_shell.on_map_listener()).link as *mut _ as _); - ffi_dispatch!(WAYLAND_SERVER_HANDLE, - wl_list_remove, - &mut (*removed_shell.on_unmap_listener()).link as *mut _ as _); - ffi_dispatch!(WAYLAND_SERVER_HANDLE, - wl_list_remove, - &mut (*removed_shell.new_popup_listener()).link as *mut _ as _); + (*layer_surface_ptr).data = Box::into_raw(layer_surface) as *mut _; } }; ]); diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs index a6119282..ee71c8c1 100644 --- a/src/types/shell/layer_shell.rs +++ b/src/types/shell/layer_shell.rs @@ -116,10 +116,6 @@ impl LayerSurface { layer_surface } } - pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_layer_surface { - self.layer_surface - } - unsafe fn from_handle(handle: &LayerSurfaceHandle) -> HandleResult { let liveliness = handle.handle .upgrade() From 4a4dba304fbaf420a9b729e3be9e165fcbcd2b28 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 19:47:43 -0700 Subject: [PATCH 10/15] implement popups --- src/types/shell/layer_shell.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs index ee71c8c1..be79dff5 100644 --- a/src/types/shell/layer_shell.rs +++ b/src/types/shell/layer_shell.rs @@ -20,12 +20,12 @@ use libc::{c_double, c_void}; use wlroots_sys::{wlr_layer_surface_state, wlr_layer_surface, wlr_layer_surface_configure, wlr_layer_surface_close, wlr_layer_surface_for_each_surface, wlr_surface, - wlr_layer_surface_surface_at, zwlr_layer_shell_v1_layer}; + wlr_layer_surface_surface_at, zwlr_layer_shell_v1_layer, wlr_xdg_popup}; use utils::c_to_rust_string; use errors::{HandleErr, HandleResult}; -use {SurfaceHandle, OutputHandle}; +use {SurfaceHandle, OutputHandle, XdgShellSurfaceHandle}; #[derive(Debug)] pub struct LayerSurface { @@ -150,8 +150,18 @@ impl LayerSurface { } } - // TODO Implement when xdg shell stable is implemented - //pub fn popups(&self) -> Vec<> + /// Get a list of all the popups for this layer surface. + pub fn popups(&self) -> Vec { + unsafe { + let mut result = vec![]; + wl_list_for_each!((*self.layer_surface).popups, + link, + (popup: wlr_xdg_popup) => { + result.push(XdgShellSurfaceHandle::from_ptr((*popup).base)) + }); + result + } + } /// Get the namespace this surface resides in. pub fn namespace(&self) -> Option { From e5721b7ae95c879cc8747d59c51c1d58890913db Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 20:01:04 -0700 Subject: [PATCH 11/15] Fixed new_popup to set up an xdg surface properly --- src/manager/layer_shell_handler.rs | 33 +++++++------ src/manager/xdg_shell_manager.rs | 78 ++++++++++++++++-------------- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/manager/layer_shell_handler.rs b/src/manager/layer_shell_handler.rs index 5902dd13..b2962d4a 100644 --- a/src/manager/layer_shell_handler.rs +++ b/src/manager/layer_shell_handler.rs @@ -5,9 +5,10 @@ use libc; use wayland_sys::server::WAYLAND_SERVER_HANDLE; use wlroots_sys::{wlr_layer_surface, wlr_xdg_popup}; -use {Surface, SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, - XdgPopup, XdgShellState}; use compositor::{compositor_handle, CompositorHandle}; +use manager::construct_xdg_shell; +use {Surface, SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, + XdgPopup, XdgShellState, XdgShellHandler, SurfaceHandler}; /// Handles events from the client layer shells. @@ -23,7 +24,9 @@ pub trait LayerShellHandler { fn on_unmap(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} /// Called when there is a new popup. - fn new_popup(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle, XdgShellSurfaceHandle) {} + fn new_popup(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle, XdgShellSurfaceHandle) + -> (Option>, Option>) + { (None, None) } /// Called when the Layer Shell is destroyed. fn destroyed(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} @@ -86,17 +89,19 @@ wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ None => return }; let popup_ptr = data as *mut wlr_xdg_popup; - // TODO This seems really incorrect. - // Is base right? - // Shouldn't we store this somewhere now? - // ugh - let xdg_surface = (*popup_ptr).base; - let popup = XdgPopup::from_shell(xdg_surface, popup_ptr); - let xdg_surface = XdgShellSurface::new(xdg_surface, XdgShellState::Popup(popup)); + let xdg_surface_ptr = (*popup_ptr).base; + let popup = XdgPopup::from_shell(xdg_surface_ptr, popup_ptr); + let xdg_surface = XdgShellSurface::new(xdg_surface_ptr, XdgShellState::Popup(popup)); - manager.new_popup(compositor, - surface.weak_reference(), - shell_surface.weak_reference(), - xdg_surface.weak_reference()); + let res = manager.new_popup(compositor, + surface.weak_reference(), + shell_surface.weak_reference(), + xdg_surface.weak_reference()); + if let (Some(shell_surface_handler), surface_handler) = res { + construct_xdg_shell(xdg_surface, + shell_surface_handler, + surface_handler, + xdg_surface_ptr); + } }; ]); diff --git a/src/manager/xdg_shell_manager.rs b/src/manager/xdg_shell_manager.rs index 51cfb255..0ade0498 100644 --- a/src/manager/xdg_shell_manager.rs +++ b/src/manager/xdg_shell_manager.rs @@ -47,43 +47,49 @@ wayland_listener!(XdgShellManager, Box, [ shell_surface.weak_reference()); if let (Some(shell_surface_handler), surface_handler) = new_surface_res { + construct_xdg_shell(shell_surface, shell_surface_handler, surface_handler, data); - let mut shell_surface = XdgShell::new((shell_surface, shell_surface_handler)); - let surface_state = (*(*data).surface).data as *mut InternalSurfaceState; - if let Some(surface_handler) = surface_handler { - (*(*surface_state).surface).data().1 = surface_handler; - } - - wl_signal_add(&mut (*data).events.destroy as *mut _ as _, - shell_surface.destroy_listener() as _); - wl_signal_add(&mut (*(*data).surface).events.commit as *mut _ as _, - shell_surface.commit_listener() as _); - wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _, - shell_surface.ping_timeout_listener() as _); - wl_signal_add(&mut (*data).events.new_popup as *mut _ as _, - shell_surface.new_popup_listener() as _); - let events = with_handles!([(shell_surface: {shell_surface.surface_mut()})] => { - match shell_surface.state() { - None | Some(&mut Popup(_)) => None, - Some(&mut TopLevel(ref mut toplevel)) => Some((*toplevel.as_ptr()).events) - } - }).expect("Cannot borrow xdg shell surface"); - if let Some(mut events) = events { - wl_signal_add(&mut events.request_maximize as *mut _ as _, - shell_surface.maximize_listener() as _); - wl_signal_add(&mut events.request_fullscreen as *mut _ as _, - shell_surface.fullscreen_listener() as _); - wl_signal_add(&mut events.request_minimize as *mut _ as _, - shell_surface.minimize_listener() as _); - wl_signal_add(&mut events.request_move as *mut _ as _, - shell_surface.move_listener() as _); - wl_signal_add(&mut events.request_resize as *mut _ as _, - shell_surface.resize_listener() as _); - wl_signal_add(&mut events.request_show_window_menu as *mut _ as _, - shell_surface.show_window_menu_listener() as _); - } - let shell_data = (*data).data as *mut XdgShellSurfaceState; - (*shell_data).shell = Box::into_raw(shell_surface); } }; ]); +pub(crate) unsafe fn construct_xdg_shell(shell_surface: XdgShellSurface, + shell_surface_handler: Box, + surface_handler: Option>, + data: *mut wlr_xdg_surface) { + let mut shell_surface = XdgShell::new((shell_surface, shell_surface_handler)); + let surface_state = (*(*data).surface).data as *mut InternalSurfaceState; + if let Some(surface_handler) = surface_handler { + (*(*surface_state).surface).data().1 = surface_handler; + } + + wl_signal_add(&mut (*data).events.destroy as *mut _ as _, + shell_surface.destroy_listener() as _); + wl_signal_add(&mut (*(*data).surface).events.commit as *mut _ as _, + shell_surface.commit_listener() as _); + wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _, + shell_surface.ping_timeout_listener() as _); + wl_signal_add(&mut (*data).events.new_popup as *mut _ as _, + shell_surface.new_popup_listener() as _); + let events = with_handles!([(shell_surface: {shell_surface.surface_mut()})] => { + match shell_surface.state() { + None | Some(&mut Popup(_)) => None, + Some(&mut TopLevel(ref mut toplevel)) => Some((*toplevel.as_ptr()).events) + } + }).expect("Cannot borrow xdg shell surface"); + if let Some(mut events) = events { + wl_signal_add(&mut events.request_maximize as *mut _ as _, + shell_surface.maximize_listener() as _); + wl_signal_add(&mut events.request_fullscreen as *mut _ as _, + shell_surface.fullscreen_listener() as _); + wl_signal_add(&mut events.request_minimize as *mut _ as _, + shell_surface.minimize_listener() as _); + wl_signal_add(&mut events.request_move as *mut _ as _, + shell_surface.move_listener() as _); + wl_signal_add(&mut events.request_resize as *mut _ as _, + shell_surface.resize_listener() as _); + wl_signal_add(&mut events.request_show_window_menu as *mut _ as _, + shell_surface.show_window_menu_listener() as _); + } + let shell_data = (*data).data as *mut XdgShellSurfaceState; + (*shell_data).shell = Box::into_raw(shell_surface); +} From faca96f0d50def62201872939c39f6500eeb348c Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 20:16:40 -0700 Subject: [PATCH 12/15] Force the user to specify the layer shell output If they don't close the connection to the client. --- src/manager/layer_shell_manager.rs | 22 ++++++++++++++++++---- src/types/shell/layer_shell.rs | 4 ---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/manager/layer_shell_manager.rs b/src/manager/layer_shell_manager.rs index 54f14104..6a963974 100644 --- a/src/manager/layer_shell_manager.rs +++ b/src/manager/layer_shell_manager.rs @@ -4,15 +4,20 @@ use libc; use wayland_sys::server::signal::wl_signal_add; use wlroots_sys::wlr_layer_surface; -use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface}; +use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface, OutputHandle}; use super::layer_shell_handler::LayerShell; use compositor::{compositor_handle, CompositorHandle}; pub trait LayerShellManagerHandler { /// Callback that is triggered when a new layer shell surface appears. + /// + /// The output is the output that was specified by the client. + /// If it was `None` then none was specified and you *must* specify it. + /// Do so by setting the value in the `Option`. fn new_surface(&mut self, CompositorHandle, - LayerSurfaceHandle) + LayerSurfaceHandle, + &mut Option) -> Option>; } @@ -26,8 +31,17 @@ wayland_listener!(LayerShellManager, Box, [ }; wlr_log!(L_DEBUG, "New layer shell surface request {:p}", layer_surface_ptr); let surface = Surface::new((*layer_surface_ptr).surface); - let layer_surface = LayerSurface::new(layer_surface_ptr); - let new_surface_res = manager.new_surface(compositor, layer_surface.weak_reference()); + let mut layer_surface = LayerSurface::new(layer_surface_ptr); + let mut output = if (*layer_surface_ptr).output.is_null() { + None + } else { + Some(OutputHandle::from_ptr((*layer_surface_ptr).output)) + }; + let new_surface_res = manager.new_surface(compositor, layer_surface.weak_reference(), &mut output); + if output.is_none() { + layer_surface.close(); + return + } if let Some(layer_surface_handler) = new_surface_res { let mut layer_surface = LayerShell::new((layer_surface, surface, diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs index be79dff5..4c87d246 100644 --- a/src/types/shell/layer_shell.rs +++ b/src/types/shell/layer_shell.rs @@ -107,10 +107,6 @@ impl <'surface> LayerSurfaceConfigure<'surface> { impl LayerSurface { pub(crate) unsafe fn new(layer_surface: *mut wlr_layer_surface) -> Self { - if (*layer_surface).output.is_null() { - // TODO Don't do this, instead gotta return a builder - panic!("Layer surface had a null output") - } let liveliness = Rc::new(Cell::new(false)); LayerSurface { liveliness, layer_surface } From ebc8350944c0192d1044ae833c5654c9a771f7a8 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 20:49:15 -0700 Subject: [PATCH 13/15] Made layer shell run &self --- src/types/shell/layer_shell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/shell/layer_shell.rs b/src/types/shell/layer_shell.rs index 4c87d246..a0654294 100644 --- a/src/types/shell/layer_shell.rs +++ b/src/types/shell/layer_shell.rs @@ -338,7 +338,7 @@ impl LayerSurfaceHandle { /// or if you run this function within the another run to the same `LayerSurface`. /// /// So don't nest `run` calls and everything will be ok :). - pub fn run(&mut self, runner: F) -> HandleResult + pub fn run(&self, runner: F) -> HandleResult where F: FnOnce(&mut LayerSurface) -> R { let mut layer_surface = unsafe { self.upgrade()? }; From a6af67023008f7bc692a8432630c54054e6d1364 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 21:07:22 -0700 Subject: [PATCH 14/15] Layer shell doesn't own the Surface any more Like the other shells. --- src/manager/layer_shell_handler.rs | 22 +++++++++++++--------- src/manager/layer_shell_manager.rs | 8 +++----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/manager/layer_shell_handler.rs b/src/manager/layer_shell_handler.rs index b2962d4a..5ed0ef58 100644 --- a/src/manager/layer_shell_handler.rs +++ b/src/manager/layer_shell_handler.rs @@ -32,17 +32,18 @@ pub trait LayerShellHandler { fn destroyed(&mut self, CompositorHandle, SurfaceHandle, LayerSurfaceHandle) {} } -wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ +wayland_listener!(LayerShell, (LayerSurface, Box), [ destroy_listener => destroy_notify: |this: &mut LayerShell, data: *mut libc::c_void,| unsafe { let layer_surface_ptr = data as *mut wlr_layer_surface; { - let (ref shell_surface, ref surface, ref mut manager) = this.data; + let (ref shell_surface, ref mut manager) = this.data; + let surface = shell_surface.surface(); let compositor = match compositor_handle() { Some(handle) => handle, None => return }; manager.destroyed(compositor, - surface.weak_reference(), + surface, shell_surface.weak_reference()); } ffi_dispatch!(WAYLAND_SERVER_HANDLE, @@ -60,30 +61,33 @@ wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ Box::from_raw((*layer_surface_ptr).data as *mut LayerShell); }; on_map_listener => on_map_notify: |this: &mut LayerShell, _data: *mut libc::c_void,| unsafe { - let (ref shell_surface, ref surface, ref mut manager) = this.data; + let (ref shell_surface, ref mut manager) = this.data; + let surface = shell_surface.surface(); let compositor = match compositor_handle() { Some(handle) => handle, None => return }; manager.on_map(compositor, - surface.weak_reference(), + surface, shell_surface.weak_reference()); }; on_unmap_listener => on_unmap_notify: |this: &mut LayerShell, _data: *mut libc::c_void,| unsafe { - let (ref shell_surface, ref surface, ref mut manager) = this.data; + let (ref shell_surface, ref mut manager) = this.data; + let surface = shell_surface.surface(); let compositor = match compositor_handle() { Some(handle) => handle, None => return }; manager.on_unmap(compositor, - surface.weak_reference(), + surface, shell_surface.weak_reference()); }; new_popup_listener => new_popup_notify: |this: &mut LayerShell, data: *mut libc::c_void,| unsafe { - let (ref shell_surface, ref surface, ref mut manager) = this.data; + let (ref shell_surface, ref mut manager) = this.data; + let surface = shell_surface.surface(); let compositor = match compositor_handle() { Some(handle) => handle, None => return @@ -94,7 +98,7 @@ wayland_listener!(LayerShell, (LayerSurface, Surface, Box), [ let xdg_surface = XdgShellSurface::new(xdg_surface_ptr, XdgShellState::Popup(popup)); let res = manager.new_popup(compositor, - surface.weak_reference(), + surface, shell_surface.weak_reference(), xdg_surface.weak_reference()); if let (Some(shell_surface_handler), surface_handler) = res { diff --git a/src/manager/layer_shell_manager.rs b/src/manager/layer_shell_manager.rs index 6a963974..297de98e 100644 --- a/src/manager/layer_shell_manager.rs +++ b/src/manager/layer_shell_manager.rs @@ -4,7 +4,7 @@ use libc; use wayland_sys::server::signal::wl_signal_add; use wlroots_sys::wlr_layer_surface; -use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface, OutputHandle}; +use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface, SurfaceHandle, OutputHandle}; use super::layer_shell_handler::LayerShell; use compositor::{compositor_handle, CompositorHandle}; @@ -30,7 +30,7 @@ wayland_listener!(LayerShellManager, Box, [ None => return }; wlr_log!(L_DEBUG, "New layer shell surface request {:p}", layer_surface_ptr); - let surface = Surface::new((*layer_surface_ptr).surface); + let surface = SurfaceHandle::from_ptr((*layer_surface_ptr).surface); let mut layer_surface = LayerSurface::new(layer_surface_ptr); let mut output = if (*layer_surface_ptr).output.is_null() { None @@ -43,9 +43,7 @@ wayland_listener!(LayerShellManager, Box, [ return } if let Some(layer_surface_handler) = new_surface_res { - let mut layer_surface = LayerShell::new((layer_surface, - surface, - layer_surface_handler)); + let mut layer_surface = LayerShell::new((layer_surface, layer_surface_handler)); wl_signal_add(&mut (*layer_surface_ptr).events.destroy as *mut _ as _, layer_surface.destroy_listener() as _); wl_signal_add(&mut (*layer_surface_ptr).events.map as *mut _ as _, From 80e67f9cd96e16725b2026f2a099b6b84735c021 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 7 Jun 2018 21:09:39 -0700 Subject: [PATCH 15/15] Set the output pointer after getting it from user --- src/manager/layer_shell_handler.rs | 2 +- src/manager/layer_shell_manager.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/manager/layer_shell_handler.rs b/src/manager/layer_shell_handler.rs index 5ed0ef58..23559ce9 100644 --- a/src/manager/layer_shell_handler.rs +++ b/src/manager/layer_shell_handler.rs @@ -7,7 +7,7 @@ use wlroots_sys::{wlr_layer_surface, wlr_xdg_popup}; use compositor::{compositor_handle, CompositorHandle}; use manager::construct_xdg_shell; -use {Surface, SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, +use {SurfaceHandle, LayerSurface, LayerSurfaceHandle, XdgShellSurface, XdgShellSurfaceHandle, XdgPopup, XdgShellState, XdgShellHandler, SurfaceHandler}; diff --git a/src/manager/layer_shell_manager.rs b/src/manager/layer_shell_manager.rs index 297de98e..ef06d7ca 100644 --- a/src/manager/layer_shell_manager.rs +++ b/src/manager/layer_shell_manager.rs @@ -4,7 +4,7 @@ use libc; use wayland_sys::server::signal::wl_signal_add; use wlroots_sys::wlr_layer_surface; -use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, Surface, SurfaceHandle, OutputHandle}; +use {LayerSurface, LayerSurfaceHandle, LayerShellHandler, OutputHandle}; use super::layer_shell_handler::LayerShell; use compositor::{compositor_handle, CompositorHandle}; @@ -30,7 +30,6 @@ wayland_listener!(LayerShellManager, Box, [ None => return }; wlr_log!(L_DEBUG, "New layer shell surface request {:p}", layer_surface_ptr); - let surface = SurfaceHandle::from_ptr((*layer_surface_ptr).surface); let mut layer_surface = LayerSurface::new(layer_surface_ptr); let mut output = if (*layer_surface_ptr).output.is_null() { None @@ -38,7 +37,9 @@ wayland_listener!(LayerShellManager, Box, [ Some(OutputHandle::from_ptr((*layer_surface_ptr).output)) }; let new_surface_res = manager.new_surface(compositor, layer_surface.weak_reference(), &mut output); - if output.is_none() { + if let Some(output) = output { + (*layer_surface_ptr).output = output.as_ptr(); + } else { layer_surface.close(); return }