<NME> mod.rs
<BEF> //! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! SHM (Shared Memory) is the most basic way wayland clients can send content to
//! the compositor: by sending a file descriptor to some (likely RAM-backed) storage
//! containing the actual data. This helper handles for you most of the logic for
//! handling these file descriptor and accessing their contents as simple `&[u8]` slices.
//!
//! This module is heavily inspired from
//! [the similar helpers](https://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-shm.c)
//! of the wayland C libraries.
//!
//! To use it, first add a `ShmGlobal` to your display, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol).
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::wayland::buffer::BufferHandler;
//! use smithay::wayland::shm::{ShmState, ShmHandler};
//! use smithay::delegate_shm;
//! use wayland_server::protocol::wl_shm::Format;
//!
//! # struct State { shm_state: ShmState };
//! # let mut display = wayland_server::Display::<State>::new().unwrap();
//! // Create the ShmState.
//! // Here, we specify that Yuyv and C8 format are supported
//! // additionally to the standard Argb8888 and Xrgb8888.
//! let state = ShmState::new::<State, _>(
//!     &display.handle(),
//!     vec![Format::Yuyv, Format::C8],
//!     None // we don't provide a logger here
//! );
//!
//! // insert the shmstate into your compositor state.
//! // ..
//!
//! // provide the necessary trait implementations
//! impl BufferHandler for State {
//!     fn buffer_destroyed(&mut self, buffer: &wayland_server::protocol::wl_buffer::WlBuffer) {
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
//! # use wayland_server::Resource;
//! # fn wrap(buffer: &Resource<WlBuffer>) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
//!
//! let content = with_buffer_contents(&buffer,
//!     }
//! }
//! delegate_shm!(State);
//! ```
//!
//! Then, when you have a [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)
//! and need to retrieve its contents, use the
//! [`with_buffer_contents`] function to do it:
//!
//! ```
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # fn wrap(buffer: &wayland_server::protocol::wl_buffer::WlBuffer) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
//!
//! let content = with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: BufferData| {
//!         // do something to extract the contents of the buffer
//!     }
//! );
//!
//! match content {
//!     Ok(something) =>  {
//!         /* `something` is the value you returned from the closure */
//!     },
//!     Err(BufferAccessError::NotManaged) => {
//!         /* This buffer is not managed by the SHM global, but by something else */
//!     },
//!     Err(BufferAccessError::BadMap) => {
//!         /* The client supplied invalid content specification for this buffer,
use std::{rc::Rc, sync::Arc};
use wayland_server::{
    protocol::{wl_buffer, wl_shm, wl_shm_pool},
    Display, DisplayToken, Global, NewResource, Resource,
};

mod pool;
//! }
//! # }
//! ```
//!
//! **Note**
//!
pub struct ShmGlobalData {
    formats: Rc<Vec<wl_shm::Format>>,
    log: ::slog::Logger,
    token: DisplayToken,
}

/// Create a new SHM global advertizing given supported formats.

use wayland_server::{
    backend::GlobalId,
    protocol::{
        wl_buffer,
        wl_shm::{self, WlShm},
        wl_shm_pool::WlShmPool,
    },
    Dispatch, DisplayHandle, GlobalDispatch, Resource,
};

mod handlers;
mod pool;

use crate::utils::UnmanagedResource;

use self::pool::Pool;

use super::buffer::BufferHandler;

/// State of SHM module
    let data = ShmGlobalData {
        formats: Rc::new(formats),
        log: log.new(o!("smithay_module" => "shm_handler")),
        token: display.get_token(),
    };

    display.create_global::<wl_shm::WlShm, _>(1, move |shm_new: NewResource<_>, _version| {
        let shm = shm_new.implement_nonsend(
            {
                let mut data = data.clone();
                move |req, shm| data.receive_shm_message(req, shm)
            },
            None::<fn(_)>,
            (),
            &data.token,
        );
        // send the formats
        for f in &data.formats[..] {
            shm.send(wl_shm::Event::Format { format: *f });
        }
    })
}
            + Dispatch<WlShmPool, ShmPoolUserData>
            + BufferHandler
            + ShmHandler
            + 'static,
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);

        // Mandatory formats
        formats.push(wl_shm::Format::Argb8888);
        formats.push(wl_shm::Format::Xrgb8888);

        let shm = display.create_global::<D, WlShm, _>(1, ());

        ShmState {
            formats,
            shm,
            log: log.new(slog::o!("smithay_module" => "shm_handler")),
        }
    }

    /// Returns the id of the [`WlShm`] global.
///
/// If the buffer is not managed by the provided `ShmGlobal`, the closure is not called
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
pub fn with_buffer_contents<F, T>(
    buffer: &Resource<wl_buffer::WlBuffer>,
    f: F,
) -> Result<T, BufferAccessError>
where
    F: FnOnce(&[u8], BufferData) -> T,
{
    let data = match buffer.user_data::<InternalBufferData>() {
        Some(d) => d,
        None => return Err(BufferAccessError::NotManaged),
    };
/// Error that can occur when accessing an SHM buffer
#[derive(Debug, thiserror::Error)]
        Ok(t) => Ok(t),
        Err(()) => {
            // SIGBUS error occurred
            buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
            Err(BufferAccessError::BadMap)
        }
    }
}

impl ShmGlobalData {
    fn receive_shm_message(&mut self, request: wl_shm::Request, shm: Resource<wl_shm::WlShm>) {
        use self::wl_shm::{Error, Request};

        let Request::CreatePool { id: pool, fd, size } = request;
        if size <= 0 {
            shm.post_error(
                Error::InvalidFd as u32,
                "Invalid size for a new wl_shm_pool.".into(),
            );
    fn from(_: UnmanagedResource) -> Self {
        Self::NotManaged
        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),
                );
///
            }
        };
        let arc_pool = Arc::new(mmap_pool);
        pool.implement_nonsend(
            {
                let mut data = self.clone();
                move |req, pool| data.receive_pool_message(req, pool)
            },
            None::<fn(_)>,
            arc_pool,
            &self.token,
        );
    }
}

    match data.pool.with_data_slice(|slice| f(slice, data.data)) {
        Ok(t) => Ok(t),
        Err(()) => {
            // SIGBUS error occurred
            buffer.post_error(wl_shm::Error::InvalidFd, "Bad pool size.");
            Err(BufferAccessError::BadMap)
        }
    }
}

/// Call given closure with the contents of the given buffer for mutable access
///
/// If the buffer is managed by the provided `ShmGlobal`, its contents are
/// extracted and the closure is extracted with them:
///
/// - The first argument is a data slice of the contents of the pool
/// - The second argument is the specification of this buffer is this pool
///
}

impl ShmGlobalData {
    fn receive_pool_message(
        &mut self,
        request: wl_shm_pool::Request,
        pool: Resource<wl_shm_pool::WlShmPool>,
    ) {
        use self::wl_shm_pool::Request;

        let arc_pool = pool.user_data::<Arc<Pool>>().unwrap();

        match request {
            Request::CreateBuffer {

    match data.pool.with_data_slice_mut(|slice| f(slice, data.data)) {
        Ok(t) => Ok(t),
        Err(()) => {
            // SIGBUS error occurred
                format,
            } => {
                if !self.formats.contains(&format) {
                    pool.post_error(
                        wl_shm::Error::InvalidFormat as u32,
                        format!("SHM format {:?} is not supported.", format),
                    );
///
/// Note: This is a best-effort, but it will never return
/// `false` for formats having an alpha channel
pub fn has_alpha(format: wl_shm::Format) -> bool {
    !matches!(
        format,
        wl_shm::Format::Xrgb8888
            | wl_shm::Format::C8
            | wl_shm::Format::Rgb332
                        format,
                    },
                };
                buffer.implement_nonsend(
                    |req, _| {
                        // this will break if a variant is added to wl_buffer::Request
                        let wl_buffer::Request::Destroy = req;
                    },
                    None::<fn(_)>,
                    data,
                    &self.token,
                );
            }
            Request::Resize { size } => match arc_pool.resize(size) {
                Ok(()) => {}
                Err(ResizeError::InvalidSize) => {
                    pool.post_error(
                        wl_shm::Error::InvalidFd as u32,
                        "Invalid new size for a wl_shm_pool.".into(),
                    );
                }
                Err(ResizeError::MremapFailed) => {
                    pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
                }
            },
            Request::Destroy => {}
        }
    }
}
            | wl_shm::Format::Vyuy
            | wl_shm::Format::Ayuv
            | wl_shm::Format::Nv12
            | wl_shm::Format::Nv21
            | wl_shm::Format::Nv16
            | wl_shm::Format::Nv61
            | wl_shm::Format::Yuv410
            | wl_shm::Format::Yvu410
            | wl_shm::Format::Yuv411
            | wl_shm::Format::Yvu411
            | wl_shm::Format::Yuv420
            | wl_shm::Format::Yvu420
            | wl_shm::Format::Yuv422
            | wl_shm::Format::Yvu422
            | wl_shm::Format::Yuv444
            | wl_shm::Format::Yvu444
            | wl_shm::Format::R8
            | wl_shm::Format::R16
            | wl_shm::Format::Rg88
            | wl_shm::Format::Gr88
            | wl_shm::Format::Rg1616
            | wl_shm::Format::Gr1616
            | wl_shm::Format::Xrgb16161616f
            | wl_shm::Format::Xbgr16161616f
            | wl_shm::Format::Xyuv8888
            | wl_shm::Format::Vuy888
            | wl_shm::Format::Vuy101010
            | wl_shm::Format::Y210
            | wl_shm::Format::Y212
            | wl_shm::Format::Y216
            | wl_shm::Format::Y410
            | wl_shm::Format::Y412
            | wl_shm::Format::Y416
            | wl_shm::Format::Xvyu2101010
            | wl_shm::Format::Xvyu1216161616
            | wl_shm::Format::Xvyu16161616
            | wl_shm::Format::Y0l0
            | wl_shm::Format::X0l0
            | wl_shm::Format::Y0l2
            | wl_shm::Format::X0l2
            | wl_shm::Format::Yuv4208bit
            | wl_shm::Format::Yuv42010bit
            | wl_shm::Format::Xrgb8888A8
            | wl_shm::Format::Xbgr8888A8
            | wl_shm::Format::Rgbx8888A8
            | wl_shm::Format::Bgrx8888A8
            | wl_shm::Format::Rgb888A8
            | wl_shm::Format::Bgr888A8
            | wl_shm::Format::Rgb565A8
            | wl_shm::Format::Bgr565A8
            | wl_shm::Format::Nv24
            | wl_shm::Format::Nv42
            | wl_shm::Format::P210
            | wl_shm::Format::P010
            | wl_shm::Format::P012
            | wl_shm::Format::P016
            | wl_shm::Format::Nv15
            | wl_shm::Format::Q410
            | wl_shm::Format::Q401
            | wl_shm::Format::Xrgb16161616
            | wl_shm::Format::Xbgr16161616
    )
}

/// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Width of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format,
}

/// User data of WlShmPool
#[derive(Debug)]
pub struct ShmPoolUserData {
    inner: Arc<Pool>,
}

/// User data of shm WlBuffer
#[derive(Debug)]
pub struct ShmBufferUserData {
    pub(crate) pool: Arc<Pool>,
    pub(crate) data: BufferData,
}

#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_shm {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm_pool::WlShmPool: $crate::wayland::shm::ShmPoolUserData
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_buffer::WlBuffer: $crate::wayland::shm::ShmBufferUserData
        ] => $crate::wayland::shm::ShmState);
    };
}

<MSG> Update smithay to wayland-server 0.23

<DFF> @@ -44,8 +44,7 @@
 //! # extern crate wayland_server;
 //! # extern crate smithay;
 //! # use wayland_server::protocol::wl_buffer::WlBuffer;
-//! # use wayland_server::Resource;
-//! # fn wrap(buffer: &Resource<WlBuffer>) {
+//! # fn wrap(buffer: &WlBuffer) {
 //! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
 //!
 //! let content = with_buffer_contents(&buffer,
@@ -82,7 +81,7 @@ use self::pool::{Pool, ResizeError};
 use std::{rc::Rc, sync::Arc};
 use wayland_server::{
     protocol::{wl_buffer, wl_shm, wl_shm_pool},
-    Display, DisplayToken, Global, NewResource, Resource,
+    Display, Global, NewResource, Resource,
 };
 
 mod pool;
@@ -95,7 +94,6 @@ mod pool;
 pub struct ShmGlobalData {
     formats: Rc<Vec<wl_shm::Format>>,
     log: ::slog::Logger,
-    token: DisplayToken,
 }
 
 /// Create a new SHM global advertizing given supported formats.
@@ -123,22 +121,20 @@ where
     let data = ShmGlobalData {
         formats: Rc::new(formats),
         log: log.new(o!("smithay_module" => "shm_handler")),
-        token: display.get_token(),
     };
 
     display.create_global::<wl_shm::WlShm, _>(1, move |shm_new: NewResource<_>, _version| {
-        let shm = shm_new.implement_nonsend(
+        let shm = shm_new.implement_closure(
             {
                 let mut data = data.clone();
                 move |req, shm| data.receive_shm_message(req, shm)
             },
             None::<fn(_)>,
             (),
-            &data.token,
         );
         // send the formats
-        for f in &data.formats[..] {
-            shm.send(wl_shm::Event::Format { format: *f });
+        for &f in &data.formats[..] {
+            shm.format(f);
         }
     })
 }
@@ -167,14 +163,11 @@ pub enum BufferAccessError {
 ///
 /// If the buffer is not managed by the provided `ShmGlobal`, the closure is not called
 /// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
-pub fn with_buffer_contents<F, T>(
-    buffer: &Resource<wl_buffer::WlBuffer>,
-    f: F,
-) -> Result<T, BufferAccessError>
+pub fn with_buffer_contents<F, T>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<T, BufferAccessError>
 where
     F: FnOnce(&[u8], BufferData) -> T,
 {
-    let data = match buffer.user_data::<InternalBufferData>() {
+    let data = match buffer.as_ref().user_data::<InternalBufferData>() {
         Some(d) => d,
         None => return Err(BufferAccessError::NotManaged),
     };
@@ -183,19 +176,24 @@ where
         Ok(t) => Ok(t),
         Err(()) => {
             // SIGBUS error occurred
-            buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
+            buffer
+                .as_ref()
+                .post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
             Err(BufferAccessError::BadMap)
         }
     }
 }
 
 impl ShmGlobalData {
-    fn receive_shm_message(&mut self, request: wl_shm::Request, shm: Resource<wl_shm::WlShm>) {
+    fn receive_shm_message(&mut self, request: wl_shm::Request, shm: wl_shm::WlShm) {
         use self::wl_shm::{Error, Request};
 
-        let Request::CreatePool { id: pool, fd, size } = request;
+        let (pool, fd, size) = match request {
+            Request::CreatePool { id: pool, fd, size } => (pool, fd, size),
+            _ => unreachable!(),
+        };
         if size <= 0 {
-            shm.post_error(
+            shm.as_ref().post_error(
                 Error::InvalidFd as u32,
                 "Invalid size for a new wl_shm_pool.".into(),
             );
@@ -204,7 +202,7 @@ impl ShmGlobalData {
         let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) {
             Ok(p) => p,
             Err(()) => {
-                shm.post_error(
+                shm.as_ref().post_error(
                     wl_shm::Error::InvalidFd as u32,
                     format!("Failed mmap of fd {}.", fd),
                 );
@@ -212,14 +210,13 @@ impl ShmGlobalData {
             }
         };
         let arc_pool = Arc::new(mmap_pool);
-        pool.implement_nonsend(
+        pool.implement_closure(
             {
                 let mut data = self.clone();
                 move |req, pool| data.receive_pool_message(req, pool)
             },
             None::<fn(_)>,
             arc_pool,
-            &self.token,
         );
     }
 }
@@ -245,14 +242,10 @@ struct InternalBufferData {
 }
 
 impl ShmGlobalData {
-    fn receive_pool_message(
-        &mut self,
-        request: wl_shm_pool::Request,
-        pool: Resource<wl_shm_pool::WlShmPool>,
-    ) {
+    fn receive_pool_message(&mut self, request: wl_shm_pool::Request, pool: wl_shm_pool::WlShmPool) {
         use self::wl_shm_pool::Request;
 
-        let arc_pool = pool.user_data::<Arc<Pool>>().unwrap();
+        let arc_pool = pool.as_ref().user_data::<Arc<Pool>>().unwrap();
 
         match request {
             Request::CreateBuffer {
@@ -264,7 +257,7 @@ impl ShmGlobalData {
                 format,
             } => {
                 if !self.formats.contains(&format) {
-                    pool.post_error(
+                    pool.as_ref().post_error(
                         wl_shm::Error::InvalidFormat as u32,
                         format!("SHM format {:?} is not supported.", format),
                     );
@@ -280,29 +273,23 @@ impl ShmGlobalData {
                         format,
                     },
                 };
-                buffer.implement_nonsend(
-                    |req, _| {
-                        // this will break if a variant is added to wl_buffer::Request
-                        let wl_buffer::Request::Destroy = req;
-                    },
-                    None::<fn(_)>,
-                    data,
-                    &self.token,
-                );
+                buffer.implement_closure(|_, _| {}, None::<fn(_)>, data);
             }
             Request::Resize { size } => match arc_pool.resize(size) {
                 Ok(()) => {}
                 Err(ResizeError::InvalidSize) => {
-                    pool.post_error(
+                    pool.as_ref().post_error(
                         wl_shm::Error::InvalidFd as u32,
                         "Invalid new size for a wl_shm_pool.".into(),
                     );
                 }
                 Err(ResizeError::MremapFailed) => {
-                    pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
+                    pool.as_ref()
+                        .post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
                 }
             },
             Request::Destroy => {}
+            _ => unreachable!(),
         }
     }
 }

Update smithay to wayland-server 0.23