shm: update to wayland-server-0.10

This commit is contained in:
Victor Berger 2017-09-19 17:02:49 +02:00
parent b8f40325aa
commit bb86b1c3ed
3 changed files with 160 additions and 208 deletions

View File

@ -5,7 +5,7 @@ authors = ["Victor Berger <victor.berger@thalesgroup.com>"]
license = "MIT" license = "MIT"
[dependencies] [dependencies]
wayland-server = "0.9.9" wayland-server = "0.10.1"
nix = "0.7.0" nix = "0.7.0"
xkbcommon = "0.2.1" xkbcommon = "0.2.1"
tempfile = "2.1.5" tempfile = "2.1.5"
@ -18,7 +18,7 @@ glium = { version = "0.16.0", optional = true, default-features = false }
input = { version = "0.2.0", optional = true } input = { version = "0.2.0", optional = true }
clippy = { version = "*", optional = true } clippy = { version = "*", optional = true }
rental = "0.4.11" rental = "0.4.11"
wayland-protocols = { version = "0.9.9", features = ["unstable_protocols", "server"] } wayland-protocols = { version = "0.10.1", features = ["unstable_protocols", "server"] }
[build-dependencies] [build-dependencies]
gl_generator = "0.5" gl_generator = "0.5"

View File

@ -12,7 +12,6 @@ extern crate nix;
extern crate rental; extern crate rental;
extern crate tempfile; extern crate tempfile;
extern crate wayland_protocols; extern crate wayland_protocols;
#[macro_use]
extern crate wayland_server; extern crate wayland_server;
extern crate xkbcommon; extern crate xkbcommon;
@ -33,10 +32,10 @@ extern crate slog;
extern crate slog_stdlog; extern crate slog_stdlog;
pub mod backend; pub mod backend;
pub mod compositor; //pub mod compositor;
pub mod shm; pub mod shm;
pub mod keyboard; pub mod keyboard;
pub mod shell; //pub mod shell;
fn slog_or_stdlog<L>(logger: L) -> ::slog::Logger fn slog_or_stdlog<L>(logger: L) -> ::slog::Logger
where where

View File

@ -19,39 +19,39 @@
//! extern crate wayland_server; //! extern crate wayland_server;
//! extern crate smithay; //! extern crate smithay;
//! //!
//! use smithay::shm::ShmGlobal; //! use smithay::shm::init_shm_global;
//! use wayland_server::protocol::wl_shm; //! use wayland_server::protocol::wl_shm::Format;
//! //!
//! # fn main() { //! # fn main() {
//! # let (_, mut event_loop) = wayland_server::create_display(); //! # let (_, mut event_loop) = wayland_server::create_display();
//! //! // Insert the ShmGlobal into your event loop
//! // Insert the ShmGlobal as a handler to your event loop
//! // Here, we specify that Yuyv and C8 format are supported //! // Here, we specify that Yuyv and C8 format are supported
//! // additionnaly to the standart Argb8888 and Xrgb8888. //! // additionnaly to the standart Argb8888 and Xrgb8888.
//! let handler_id = event_loop.add_handler_with_init(ShmGlobal::new( //! let shm_global = init_shm_global(
//! vec![wl_shm::Format::Yuyv, wl_shm::Format::C8], //! &mut event_loop,
//! vec![Format::Yuyv, Format::C8],
//! None // we don't provide a logger here //! None // we don't provide a logger here
//! )); //! );
//! // Register this handler to advertise a wl_shm global of version 1
//! let shm_global = event_loop.register_global::<wl_shm::WlShm,ShmGlobal>(handler_id, 1);
//! // Retrieve the shm token for later use to access the buffers
//! let shm_token = {
//! let state = event_loop.state();
//! state.get_handler::<ShmGlobal>(handler_id).get_token()
//! };
//!
//! # } //! # }
//! ``` //! ```
//! //!
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to //! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
//! do it: //! do it:
//! //!
//! ```ignore //! ```
//! shm_token.with_buffer_contents(&buffer, //! # extern crate wayland_server;
//! |slice: &[u8], buffer_metadata: &BufferData| { //! # extern crate smithay;
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
//! # fn wrap(buffer: &WlBuffer) {
//! use smithay::shm::{with_buffer_contents, BufferData};
//!
//! with_buffer_contents(&buffer,
//! |slice: &[u8], buffer_metadata: BufferData| {
//! // do something to draw it on the screen //! // do something to draw it on the screen
//! } //! }
//! ); //! );
//! # }
//! # fn main() {}
//! ``` //! ```
//! //!
//! **Note** //! **Note**
@ -63,67 +63,50 @@
use self::pool::{Pool, ResizeError}; use self::pool::{Pool, ResizeError};
use std::rc::Rc;
use std::os::unix::io::RawFd;
use std::sync::Arc; use std::sync::Arc;
use wayland_server::{resource_is_registered, Client, EventLoop, EventLoopHandle, Global, Resource};
use wayland_server::{resource_is_registered, Client, Destroy, EventLoopHandle, GlobalHandler, Init, Resource};
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool}; use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
mod pool; mod pool;
/// A global for handling SHM pool and buffers #[derive(Clone)]
/// Internal data storage of ShmGlobal
/// ///
/// You must register it to an event loop using `register_with_init`, or it will /// This type is only visible as type parameter of
/// quickly panic. /// the `Global` handle you are provided.
pub struct ShmGlobal { pub struct ShmGlobalData {
formats: Vec<wl_shm::Format>, formats: Rc<Vec<wl_shm::Format>>,
handler_id: Option<usize>,
log: ::slog::Logger, log: ::slog::Logger,
} }
impl ShmGlobal { /// Create a new SHM global advertizing given supported formats.
/// Create a new SHM global advertizing given supported formats.
///
/// This global will always advertize `ARGB8888` and `XRGB8888` format
/// as they are required by the protocol. Formats given as argument
/// as additionnaly advertized.
pub fn new<L>(mut formats: Vec<wl_shm::Format>, logger: L) -> ShmGlobal
where
L: Into<Option<::slog::Logger>>,
{
let log = ::slog_or_stdlog(logger);
// always add the mandatory formats
formats.push(wl_shm::Format::Argb8888);
formats.push(wl_shm::Format::Xrgb8888);
ShmGlobal {
formats: formats,
handler_id: None,
log: log.new(o!("smithay_module" => "shm_handler")),
}
}
/// Retreive a token from the SHM global.
///
/// This can only be called once the `ShmGlobal` has been added to and event loop
/// and has been initialized. If it is not the case, this method will panic.
///
/// This is needed to retrieve the contents of the shm pools and buffers.
pub fn get_token(&self) -> ShmToken {
ShmToken {
hid: self.handler_id.expect("ShmGlobal was not initialized."),
}
}
}
/// An SHM global token
/// ///
/// It is needed to access the contents of the buffers & pools managed by the /// This global will always advertize `ARGB8888` and `XRGB8888` format
/// associated `ShmGlobal`. /// as they are required by the protocol. Formats given as argument
#[derive(Clone)] /// as additionnaly advertized.
pub struct ShmToken { ///
hid: usize, /// The global is directly registered into the eventloop, and this function
/// returns the global handle, in case you whish to remove this global in
/// the future.
pub fn init_shm_global<L>(evl: &mut EventLoop, mut formats: Vec<wl_shm::Format>, logger: L)
-> Global<wl_shm::WlShm, ShmGlobalData>
where
L: Into<Option<::slog::Logger>>,
{
let log = ::slog_or_stdlog(logger);
// always add the mandatory formats
formats.push(wl_shm::Format::Argb8888);
formats.push(wl_shm::Format::Xrgb8888);
let data = ShmGlobalData {
formats: Rc::new(formats),
log: log.new(o!("smithay_module" => "shm_handler")),
};
let global = evl.register_global::<wl_shm::WlShm, _>(1, shm_global_bind, data);
global
} }
/// Error that can occur when accessing an SHM buffer /// Error that can occur when accessing an SHM buffer
@ -140,109 +123,82 @@ pub enum BufferAccessError {
BadMap, BadMap,
} }
impl ShmToken { /// Call given closure with the contents of the given buffer
/// Call given closure with the contents of the given buffer ///
/// /// If the buffer is managed by the provided ShmGlobal, its contents are
/// If the buffer is managed by the associated ShmGlobal, its contents are /// extracted and the closure is extracted with them:
/// extracted and the closure is extracted with them: ///
/// /// - The first argument is a data slice of the contents of the pool
/// - 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
/// - The second argument is the specification of this buffer is this pool ///
/// /// If the buffer is not managed by the provided ShmGlobal, the closure is not called
/// If the buffer is not managed by the associated ShmGlobal, the closure is not called /// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example). pub fn with_buffer_contents<F>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
pub fn with_buffer_contents<F>(&self, buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError> where
where F: FnOnce(&[u8], BufferData),
F: FnOnce(&[u8], BufferData), {
if !resource_is_registered(buffer, &buffer_implementation()) {
return Err(BufferAccessError::NotManaged);
}
let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };
if data.pool
.with_data_slice(|slice| f(slice, data.data))
.is_err()
{ {
if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) { // SIGBUS error occured
return Err(BufferAccessError::NotManaged); buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
} return Err(BufferAccessError::BadMap);
let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) }; }
Ok(())
}
if data.pool fn shm_global_bind(evlh: &mut EventLoopHandle, data: &mut ShmGlobalData, _: &Client, global: wl_shm::WlShm) {
.with_data_slice(|slice| f(slice, data.data)) // register an handler for this shm
.is_err() evlh.register(&global, shm_implementation(), data.clone(), None);
{ // and then the custom formats
// SIGBUS error occured for f in &data.formats[..] {
buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into()); global.format(*f);
return Err(BufferAccessError::BadMap);
}
Ok(())
} }
} }
impl Init for ShmGlobal { fn shm_implementation() -> wl_shm::Implementation<ShmGlobalData> {
fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) { wl_shm::Implementation {
let id = evqh.add_handler_with_init(ShmHandler { create_pool: |evlh, data, _, shm, pool, fd, size| {
my_id: ::std::usize::MAX, if size <= 0 {
valid_formats: self.formats.clone(),
log: self.log.clone(),
});
self.handler_id = Some(id);
}
}
impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) {
let hid = self.handler_id.expect("ShmGlobal was not initialized.");
// register an handler for this shm
evqh.register::<_, ShmHandler>(&global, hid);
// and then the custom formats
for f in &self.formats {
global.format(*f);
}
}
}
struct ShmHandler {
my_id: usize,
valid_formats: Vec<wl_shm::Format>,
log: ::slog::Logger,
}
impl Init for ShmHandler {
fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) {
self.my_id = index;
debug!(self.log, "Init finished")
}
}
impl wl_shm::Handler for ShmHandler {
fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, shm: &wl_shm::WlShm,
pool: wl_shm_pool::WlShmPool, fd: RawFd, size: i32) {
if size <= 0 {
shm.post_error(
wl_shm::Error::InvalidFd as u32,
"Invalid size for a new wl_shm_pool.".into(),
);
return;
}
let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) {
Ok(p) => p,
Err(()) => {
shm.post_error( shm.post_error(
wl_shm::Error::InvalidFd as u32, wl_shm::Error::InvalidFd as u32,
format!("Failed mmap of fd {}.", fd), "Invalid size for a new wl_shm_pool.".into(),
); );
return; return;
} }
}; let mmap_pool = match Pool::new(fd, size as usize, data.log.clone()) {
let arc_pool = Box::new(Arc::new(mmap_pool)); Ok(p) => p,
evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id); Err(()) => {
pool.set_user_data(Box::into_raw(arc_pool) as *mut ()); shm.post_error(
wl_shm::Error::InvalidFd as u32,
format!("Failed mmap of fd {}.", fd),
);
return;
}
};
let arc_pool = Box::new(Arc::new(mmap_pool));
evlh.register(
&pool,
shm_pool_implementation(),
data.clone(),
Some(destroy_shm_pool),
);
pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
},
} }
} }
impl Destroy<wl_shm_pool::WlShmPool> for ShmHandler { fn destroy_shm_pool(pool: &wl_shm_pool::WlShmPool) {
fn destroy(pool: &wl_shm_pool::WlShmPool) { let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) }; drop(arc_pool)
drop(arc_pool)
}
} }
declare_handler!(ShmHandler, wl_shm::Handler, wl_shm::WlShm);
/// Details of the contents of a buffer relative to its pool /// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct BufferData { pub struct BufferData {
@ -263,56 +219,53 @@ struct InternalBufferData {
data: BufferData, data: BufferData,
} }
impl wl_shm_pool::Handler for ShmHandler { fn shm_pool_implementation() -> wl_shm_pool::Implementation<ShmGlobalData> {
fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client, wl_shm_pool::Implementation {
pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32, width: i32, create_buffer: |evlh, data, _, pool, buffer, offset, width, height, stride, format| {
height: i32, stride: i32, format: wl_shm::Format) { if !data.formats.contains(&format) {
if !self.valid_formats.contains(&format) { buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new()); return;
return;
}
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
let data = Box::into_raw(Box::new(InternalBufferData {
pool: arc_pool.clone(),
data: BufferData {
offset: offset,
width: width,
height: height,
stride: stride,
format: format,
},
}));
evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id);
buffer.set_user_data(data as *mut ());
}
fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client, pool: &wl_shm_pool::WlShmPool,
size: i32) {
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
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) => { let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into()); let data = Box::into_raw(Box::new(InternalBufferData {
pool: arc_pool.clone(),
data: BufferData {
offset: offset,
width: width,
height: height,
stride: stride,
format: format,
},
}));
evlh.register(&buffer, buffer_implementation(), (), Some(destroy_buffer));
buffer.set_user_data(data as *mut ());
},
resize: |_, _, _, pool, size| {
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
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());
}
} }
} },
destroy: |_, _, _, _| {},
} }
} }
impl Destroy<wl_buffer::WlBuffer> for ShmHandler { fn destroy_buffer(buffer: &wl_buffer::WlBuffer) {
fn destroy(buffer: &wl_buffer::WlBuffer) { let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) }; drop(buffer_data)
drop(buffer_data)
}
} }
declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool); fn buffer_implementation() -> wl_buffer::Implementation<()> {
wl_buffer::Implementation {
impl wl_buffer::Handler for ShmHandler {} destroy: |_, _, _, _| {},
}
declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer); }