Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1,261 @@
use std::env;
use std::ffi::OsString;
use std::io;
use std::ops::Deref;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::sync::Arc;
use nix::fcntl;
use crate::{EventQueue, Proxy};
use crate::imp::DisplayInner;
#[cfg(feature = "use_system_lib")]
use wayland_sys::client::wl_display;
/// Enum representing the possible reasons why connecting to the wayland server failed
#[derive(Debug)]
pub enum ConnectError {
/// The library was compiled with the `dlopen` feature, and the `libwayland-client.so`
/// library could not be found at runtime
NoWaylandLib,
/// The `XDG_RUNTIME_DIR` variable is not set while it should be
XdgRuntimeDirNotSet,
/// Any needed library was found, but the listening socket of the server was not.
///
/// Most of the time, this means that the program was not started from a wayland session.
NoCompositorListening,
/// The provided socket name is invalid
InvalidName,
/// The FD provided in `WAYLAND_SOCKET` was invalid
InvalidFd,
}
impl ::std::error::Error for ConnectError {}
impl ::std::fmt::Display for ConnectError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
ConnectError::NoWaylandLib => f.write_str("Could not find libwayland-client.so."),
ConnectError::XdgRuntimeDirNotSet => f.write_str("XDG_RUNTIME_DIR is not set."),
ConnectError::NoCompositorListening => {
f.write_str("Could not find a listening wayland compositor.")
}
ConnectError::InvalidName => f.write_str("The wayland socket name is invalid."),
ConnectError::InvalidFd => f.write_str("The FD provided in WAYLAND_SOCKET is invalid."),
}
}
}
/// A protocol error
///
/// This kind of error is generated by the server if your client didn't respect
/// the protocol, after which the server will kill your connection.
///
/// If the dispatching methods of `EventQueues` start to fail, you may want to
/// check `Display::protocol_error()` to see if a protocol error was generated.
#[derive(Clone, Debug)]
pub struct ProtocolError {
/// The error code associated with the error
///
/// It should be interpreted as an instance of the `Error` enum of the
/// associated interface.
pub code: u32,
/// The id of the object that caused the error
pub object_id: u32,
/// The interface of the object that caused the error
pub object_interface: &'static str,
/// The message sent by the server describing the error
pub message: String,
}
impl ::std::error::Error for ProtocolError {
fn description(&self) -> &str {
"Wayland protocol error"
}
}
impl ::std::fmt::Display for ProtocolError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(
f,
"Protocol error {} on object {}@{}: {}",
self.code, self.object_interface, self.object_id, self.message
)
}
}
/// A connection to a wayland server
///
/// This object both represent the connection to the server and contains the
/// primary `WlDisplay` wayland object. As such, it must be kept alive as long
/// as you are connected. You can access the contained `WlDisplay` via `Deref`
/// to create all the objects you need.
///
/// **Safety note:** If you activate the `use_system_lib` cargo feature and provide pointers
/// to wayland objects to other libraries, you **must** ensure that these libraries clean up
/// their state before the last clone of this `Display` is dropped, otherwise these libraries
/// will access freed memory when doing their cleanup.
#[derive(Clone)]
pub struct Display {
pub(crate) inner: Arc<DisplayInner>,
}
impl std::fmt::Debug for Display {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Display { ... }")
}
}
impl Display {
/// Attempt to connect to a wayland server using the contents of the environment variables
///
/// First of all, if the `WAYLAND_SOCKET` environment variable is set, it'll try to interpret
/// it as a FD number to use.
///
/// Otherwise, it will try to connect to the socket name defined in the `WAYLAND_DISPLAY`
/// environment variable, and error if it is not set.
///
/// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
pub fn connect_to_env() -> Result<Display, ConnectError> {
if let Ok(txt) = env::var("WAYLAND_SOCKET") {
// We should connect to the provided WAYLAND_SOCKET
let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
// remove the variable so any child processes don't see it
env::remove_var("WAYLAND_SOCKET");
// set the CLOEXEC flag on this FD
let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
let result = flags
.map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
.and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
match result {
Ok(_) => {
// setting the O_CLOEXEC worked
unsafe { Display::from_fd(fd) }
}
Err(_) => {
// something went wrong in F_GETFD or F_SETFD
let _ = ::nix::unistd::close(fd);
Err(ConnectError::InvalidFd)
}
}
} else {
let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
.map(Into::<PathBuf>::into)
.ok_or(ConnectError::XdgRuntimeDirNotSet)?;
socket_path
.push(env::var_os("WAYLAND_DISPLAY").ok_or(ConnectError::NoCompositorListening)?);
let socket = UnixStream::connect(socket_path)
.map_err(|_| ConnectError::NoCompositorListening)?;
unsafe { Display::from_fd(socket.into_raw_fd()) }
}
}
/// Attempt to connect to a wayland server socket with given name
///
/// On success, you are given the `Display` object as well as the main `EventQueue` hosting
/// the `WlDisplay` wayland object.
///
/// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
pub fn connect_to_name<S: Into<OsString>>(name: S) -> Result<Display, ConnectError> {
let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
.map(Into::<PathBuf>::into)
.ok_or(ConnectError::XdgRuntimeDirNotSet)?;
socket_path.push(name.into());
let socket =
UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositorListening)?;
unsafe { Display::from_fd(socket.into_raw_fd()) }
}
/// Attempt to use an already connected unix socket on given FD to start a wayland connection
///
/// On success, you are given the `Display` object.
///
/// Will take ownership of the FD.
///
/// # Safety
///
/// The file descriptor must be associated to a connected unix socket.
pub unsafe fn from_fd(fd: RawFd) -> Result<Display, ConnectError> {
Ok(Display { inner: DisplayInner::from_fd(fd)? })
}
/// Non-blocking write to the server
///
/// Outgoing messages to the server are buffered by the library for efficiency. This method
/// flushes the internal buffer to the server socket.
///
/// Will write as many pending requests as possible to the server socket. Never blocks: if not all
/// requests could be written, will return an io error `WouldBlock`.
pub fn flush(&self) -> io::Result<()> {
self.inner.flush()
}
/// Create a new event queue associated with this wayland connection
pub fn create_event_queue(&self) -> EventQueue {
let evq_inner = DisplayInner::create_event_queue(&self.inner);
EventQueue::new(evq_inner, self.clone())
}
/// Retrieve the last protocol error if any occured
///
/// If your client does not respect some part of a protocol it is using, the server
/// will send a special "protocol error" event and kill your connection. This method
/// allows you to retrieve the contents of this event if it occured.
///
/// If the dispatch methods of the `EventQueue` return an error, this is an indication
/// that a protocol error may have occured. Such errors are not recoverable, but this
/// method allows you to gracefully display them to the user, along with indications for
/// submitting a bug-report for example.
pub fn protocol_error(&self) -> Option<ProtocolError> {
self.inner.protocol_error()
}
/// Retrieve the file descriptor associated with the wayland socket
///
/// This FD should only be used to integrate into a polling mechanism, and should
/// never be directly read from or written to.
pub fn get_connection_fd(&self) -> ::std::os::unix::io::RawFd {
self.inner.get_connection_fd()
}
#[cfg(feature = "use_system_lib")]
/// Create a Display and from an external display
///
/// This allows you to interface with an already-existing wayland connection,
/// for example provided by a GUI toolkit.
///
/// Note that if you need to retrieve the actual `wl_display` pointer back (rather than
/// its wrapper), you must use the `get_display_ptr()` method.
///
/// # Safety
///
/// The provided pointer must point to a valid `wl_display` from `libwayland-client`
pub unsafe fn from_external_display(display_ptr: *mut wl_display) -> Display {
Display { inner: DisplayInner::from_external(display_ptr) }
}
#[cfg(feature = "use_system_lib")]
/// Retrieve the `wl_display` pointer
///
/// If this `Display` was created from an external `wl_display`, its `c_ptr()` method will
/// return a wrapper to the actual display. While this is perfectly good as a `wl_proxy`
/// pointer, to send requests, this is not the actual `wl_display` and cannot be used as such.
///
/// This method will give you the `wl_display`.
pub fn get_display_ptr(&self) -> *mut wl_display {
self.inner.ptr()
}
}
impl Deref for Display {
type Target = Proxy<crate::protocol::wl_display::WlDisplay>;
fn deref(&self) -> &Proxy<crate::protocol::wl_display::WlDisplay> {
self.inner.get_proxy()
}
}

View file

@ -0,0 +1,283 @@
use std::{io, rc::Rc};
use crate::imp::EventQueueInner;
use crate::{AnonymousObject, DispatchData, Display, Main, RawEvent};
/// An event queue for protocol messages
///
/// Event dispatching in wayland is made on a queue basis, allowing you
/// to organize your objects into different queues that can be dispatched
/// independently, for example from different threads.
///
/// An `EventQueue` is not `Send`, and thus must stay on the thread on which
/// it was created. However the `Display` object is `Send + Sync`, allowing
/// you to create the queues directly on the threads that host them.
///
/// When a queue is dispatched (via the `dispatch(..)` or `dispatch_pending(..)` methods)
/// all the incoming messages from the server designated to objects associated with
/// the queue are processed sequentially, and the appropriate implementation for each
/// is invoked. When all messages have been processed these methods return.
///
/// There are two main ways to driving an event queue forward. The first way is the
/// simplest and generally sufficient for single-threaded apps that only process events
/// from wayland. It consists of using the `EventQueue::dispatch(..)` method, which will
/// take care of sending pending requests to the server, block until some events are
/// available, read them, and call the associated handlers:
///
/// ```no_run
/// # extern crate wayland_client;
/// # use wayland_client::{Display};
/// # let display = Display::connect_to_env().unwrap();
/// # let mut event_queue = display.create_event_queue();
/// loop {
/// // The dispatch() method returns once it has received some events to dispatch
/// // and have emptied the wayland socket from its pending messages, so it needs
/// // to be called in a loop. If this method returns an error, your connection to
/// // the wayland server is very likely dead. See its documentation for more details.
/// event_queue.dispatch(&mut (), |_,_,_| {
/// /* This closure will be called for every event received by an object not
/// assigned to any Filter. If you plan to assign all your objects to Filter,
/// the simplest thing to do is to assert this is never called. */
/// unreachable!();
/// }).expect("An error occurred during event dispatching!");
/// }
/// ```
///
/// The second way is more appropriate for apps that are either multithreaded (and need to process
/// wayland events from different threads conccurently) or need to react to events from different
/// sources and can't affort to just block on the wayland socket. It centers around three methods:
/// `Display::flush()`, `EventQueue::read_events()` and `EventQueue::dispatch_pending()`:
///
/// ```no_run
/// # extern crate wayland_client;
/// # use wayland_client::Display;
/// # let display = Display::connect_to_env().unwrap();
/// # let mut event_queue = display.create_event_queue();
/// loop {
/// // The first method, called on the Display, is flush(). It writes all pending
/// // requests to the socket. Calling it ensures that the server will indeed
/// // receive your requests (so it can react to them).
/// if let Err(e) = display.flush() {
/// if e.kind() != ::std::io::ErrorKind::WouldBlock {
/// // if you are sending a realy large number of request, it might fill
/// // the internal buffers of the socket, in which case you should just
/// // retry flushing later. Other errors are a problem though.
/// eprintln!("Error while trying to flush the wayland socket: {:?}", e);
/// }
/// }
///
/// // The second method will try to read events from the socket. It is done in two
/// // steps, first the read is prepared, and then it is actually executed. This allows
/// // lower contention when different threads are trying to trigger a read of events
/// // concurently
/// if let Some(guard) = event_queue.prepare_read() {
/// // prepare_read() returns None if there are already events pending in this
/// // event queue, in which case there is no need to try to read from the socket
/// if let Err(e) = guard.read_events() {
/// if e.kind() != ::std::io::ErrorKind::WouldBlock {
/// // if read_events() returns Err(WouldBlock), this just means that no new
/// // messages are available to be read
/// eprintln!("Error while trying to read from the wayland socket: {:?}", e);
/// }
/// }
/// }
///
/// // Then, once events have been read from the socket and stored in the internal
/// // queues, they need to be dispatched to their handler. Note that while flush()
/// // and read_events() are global and will affect the whole connection, this last
/// // method will only affect the event queue it is being called on. This method
/// // cannot error unless there is a bug in the server or a previous read of events
/// // already errored.
/// event_queue.dispatch_pending(&mut (), |_,_,_| {}).expect("Failed to dispatch all messages.");
///
/// // Note that none of these methods are blocking, as such they should not be used
/// // as a loop as-is if there are no other sources of events your program is waiting on.
///
/// // The wayland socket can also be integrated in a poll-like mechanism by using
/// // the file descriptor provided by the `get_connection_fd()` method.
/// }
/// ```
pub struct EventQueue {
// EventQueue is *not* Send
pub(crate) inner: Rc<EventQueueInner>,
display: Display,
}
impl std::fmt::Debug for EventQueue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("EventQueue { ... }")
}
}
/// A token representing this event queue
///
/// This token can be cloned and is meant to allow easier
/// interaction with other functions in the library that
/// require the specification of an event queue, like
/// `Proxy::assign`.
#[derive(Clone)]
pub struct QueueToken {
pub(crate) inner: Rc<EventQueueInner>,
}
impl std::fmt::Debug for QueueToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("QueueToken { ... }")
}
}
impl EventQueue {
pub(crate) fn new(inner: EventQueueInner, display: Display) -> EventQueue {
EventQueue { inner: Rc::new(inner), display }
}
/// Dispatches events from the internal buffer.
///
/// Dispatches all events to their appropriate filters.
/// If no events were in the internal buffer, will block until
/// some events are read and dispatch them.
/// This process can insert events in the internal buffers of
/// other event queues.
///
/// The provided `data` will be mutably accessible from all the callbacks, via the
/// [`DispatchData`](struct.DispatchData.html) mechanism. If you don't need global data, you
/// can just provide a `&mut ()` there.
///
/// If an error is returned, your connection with the wayland compositor is probably lost.
/// You may want to check `Display::protocol_error()` to see if it was caused by a protocol error.
pub fn dispatch<T: std::any::Any, F>(&mut self, data: &mut T, fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
let mut data = DispatchData::wrap(data);
self.inner.dispatch(data.reborrow(), fallback)
}
/// Dispatches pending events from the internal buffer.
///
/// Dispatches all events to their appropriate callbacks.
/// Never blocks, if no events were pending, simply returns
/// `Ok(0)`.
///
/// The provided `data` will be mutably accessible from all the callbacks, via the
/// [`DispatchData`](struct.DispatchData.html) mechanism. If you don't need global data, you
/// can just provide a `&mut ()` there.
///
/// If an error is returned, your connection with the wayland compositor is probably lost.
/// You may want to check `Display::protocol_error()` to see if it was caused by a protocol error.
pub fn dispatch_pending<T: std::any::Any, F>(
&mut self,
data: &mut T,
fallback: F,
) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
let mut data = DispatchData::wrap(data);
self.inner.dispatch_pending(data.reborrow(), fallback)
}
/// Synchronous roundtrip
///
/// This call will cause a synchronous roundtrip with the wayland server. It will block until all
/// pending requests of this queue are sent to the server and it has processed all of them and
/// send the appropriate events.
///
/// Handlers are called as a consequence.
///
/// The provided `data` will be mutably accessible from all the callbacks, via the
/// [`DispatchData`](struct.DispatchData.html) mechanism. If you don't need global data, you
/// can just provide a `&mut ()` there.
///
/// On success returns the number of dispatched events.
/// If an error is returned, your connection with the wayland compositor is probably lost.
/// You may want to check `Display::protocol_error()` to see if it was caused by a protocol error.
pub fn sync_roundtrip<T: std::any::Any, F>(
&mut self,
data: &mut T,
fallback: F,
) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
let mut data = DispatchData::wrap(data);
self.inner.sync_roundtrip(data.reborrow(), fallback)
}
/// Create a new token associated with this event queue
///
/// See `QueueToken` documentation for its use.
pub fn token(&self) -> QueueToken {
QueueToken { inner: self.inner.clone() }
}
/// Prepare an concurrent read
///
/// Will declare your intention to read events from the server socket.
///
/// Will return `None` if there are still some events awaiting dispatch on this EventIterator.
/// In this case, you need to call `dispatch_pending()` before calling this method again.
///
/// The guard can then be used by two means:
///
/// - Calling its `cancel()` method (or letting it go out of scope): the read intention will
/// be cancelled
/// - Calling its `read_events()` method: will block until all existing guards are destroyed
/// by one of these methods, then events will be read and all blocked `read_events()` calls
/// will return.
///
/// This call will otherwise not block on the server socket if it is empty, and return
/// an io error `WouldBlock` in such cases.
pub fn prepare_read(&self) -> Option<ReadEventsGuard> {
match self.inner.prepare_read() {
Ok(()) => Some(ReadEventsGuard { inner: self.inner.clone(), done: false }),
Err(()) => None,
}
}
/// Access the `Display` of the connection
pub fn display(&self) -> &Display {
&self.display
}
}
/// A guard over a read intention.
///
/// See `EventQueue::prepare_read()` for details about its use.
pub struct ReadEventsGuard {
inner: Rc<EventQueueInner>,
done: bool,
}
impl std::fmt::Debug for ReadEventsGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ReadEventsGuard { ... }")
}
}
impl ReadEventsGuard {
/// Read events
///
/// Reads events from the server socket. If other `ReadEventsGuard` exists, will block
/// until they are all consumed or destroyed.
pub fn read_events(mut self) -> io::Result<()> {
self.done = true;
self.inner.read_events()
}
/// Cancel the read
///
/// Will cancel the read intention associated with this guard. Never blocks.
///
/// Has the same effect as letting the guard go out of scope.
pub fn cancel(self) {
// just run the destructor
}
}
impl Drop for ReadEventsGuard {
fn drop(&mut self) {
if !self.done {
self.inner.cancel_read();
}
}
}

View file

@ -0,0 +1,343 @@
use std::sync::{Arc, Mutex};
use crate::protocol::wl_display;
use crate::protocol::wl_registry;
use crate::{Attached, DispatchData, Interface, Main, Proxy};
#[derive(Debug)]
struct Inner {
list: Vec<(u32, String, u32)>,
}
/// An utility to manage global objects
///
/// This utility provides an implemenation for the registry
/// that track the list of globals for you, as well as utilities
/// to bind them.
#[derive(Clone, Debug)]
pub struct GlobalManager {
inner: Arc<Mutex<Inner>>,
registry: Main<wl_registry::WlRegistry>,
}
/// An error that occurred trying to bind a global
#[derive(Debug, PartialEq)]
pub enum GlobalError {
/// The requested global was missing
Missing,
/// The global advertised by the server has a lower version number
/// than the one requested
VersionTooLow(u32),
}
impl ::std::error::Error for GlobalError {}
impl ::std::fmt::Display for GlobalError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
GlobalError::Missing => f.write_str("The requested global was missing."),
GlobalError::VersionTooLow(_) => {
f.write_str("The requested global's version is too low.")
}
}
}
}
/// Event provided to the user callback of GlobalManager
#[derive(Debug)]
pub enum GlobalEvent {
/// A new global was created
New {
/// Id of the new global
id: u32,
/// Interface of the new global
interface: String,
/// Maximum supported version of the new global
version: u32,
},
/// A global was removed
Removed {
/// Id of the removed global
id: u32,
/// Interface of the removed global
interface: String,
},
}
impl GlobalManager {
/// Create a global manager handling a registry
///
/// You need to provide an attached handle of the Waland display, and the
/// global manager will be managed by the associated event queue.
pub fn new(display: &Attached<wl_display::WlDisplay>) -> GlobalManager {
let inner = Arc::new(Mutex::new(Inner { list: Vec::new() }));
let inner_clone = inner.clone();
let registry = display
.as_ref()
.send::<wl_registry::WlRegistry>(wl_display::Request::GetRegistry {}, None)
.unwrap();
registry.quick_assign(move |_proxy, msg, _data| {
let mut inner = inner.lock().unwrap();
match msg {
wl_registry::Event::Global { name, interface, version } => {
inner.list.push((name, interface, version));
}
wl_registry::Event::GlobalRemove { name } => {
inner.list.retain(|&(n, _, _)| n != name);
}
}
});
GlobalManager { inner: inner_clone, registry }
}
/// Create a global manager handling a registry with a callback
///
/// This global manager will track globals as a simple one, but will
/// also forward the registry events to your callback.
///
/// This can be used if you want to handle specially certain globals, but want
/// to use the default mechanism for the rest.
///
/// You need to provide an attached handle of the Waland display, and the
/// global manager will be managed by the associated event queue.
pub fn new_with_cb<F>(
display: &Attached<wl_display::WlDisplay>,
mut callback: F,
) -> GlobalManager
where
F: FnMut(GlobalEvent, Attached<wl_registry::WlRegistry>, DispatchData) + 'static,
{
let inner = Arc::new(Mutex::new(Inner { list: Vec::new() }));
let inner_clone = inner.clone();
let registry = display
.as_ref()
.send::<wl_registry::WlRegistry>(wl_display::Request::GetRegistry {}, None)
.unwrap();
registry.quick_assign(move |proxy, msg, data| {
let mut inner = inner.lock().unwrap();
let inner = &mut *inner;
match msg {
wl_registry::Event::Global {
name,
interface,
version,
} => {
inner.list.push((name, interface.clone(), version));
callback(
GlobalEvent::New {
id: name,
interface,
version,
},
(*proxy).clone(),
data,
);
}
wl_registry::Event::GlobalRemove { name } => {
if let Some((i, _)) = inner.list.iter().enumerate().find(|&(_, &(n, _, _))| n == name) {
let (id, interface, _) = inner.list.swap_remove(i);
callback(GlobalEvent::Removed { id, interface }, (*proxy).clone(), data);
} else {
panic!(
"Wayland protocol error: the server removed non-existing global \"{}\".",
name
);
}
}
}
});
GlobalManager { inner: inner_clone, registry }
}
/// Instantiate a global with a specific version
///
/// Meaning of requests and events can change depending on the object version you use,
/// as such unless you specifically want to support several versions of a protocol, it is
/// recommended to use this method with an hardcoded value for the version (the one you'll
/// use a as reference for your implementation). Notably you should *not* use `I::VERSION`
/// as a version, as this value can change when the protocol files are updated.
///
/// This method is only appropriate for globals that are expected to
/// not exist with multiplicity (such as `wl_compositor` or `wl_shm`),
/// as it will always bind the first one that was advertized.
pub fn instantiate_exact<I>(&self, version: u32) -> Result<Main<I>, GlobalError>
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>,
{
let inner = self.inner.lock().unwrap();
for &(id, ref interface, server_version) in &inner.list {
if interface == I::NAME {
if version > server_version {
return Err(GlobalError::VersionTooLow(server_version));
} else {
return Ok(self.registry.bind::<I>(version, id));
}
}
}
Err(GlobalError::Missing)
}
/// Instantiate a global from a version range
///
/// If you want to support several versions of a particular global, this method allows you to
/// specify a range of versions that you accept. It'll bind the highest possible version that
/// is between `min_version` and `max_version` inclusive, and return an error if the highest
/// version supported by the compositor is lower than `min_version`. As for
/// `instantiate_exact`, you should not use `I::VERSION` here: the versions your code support
/// do not change when the protocol files are updated.
///
/// When trying to support several versions of a protocol, you can check which version has
/// actually been used on any object using the `Proxy::version()` method.
///
/// As `instantiate_exact`, it should only be used for singleton globals, for the same reasons.
pub fn instantiate_range<I>(
&self,
min_version: u32,
max_version: u32,
) -> Result<Main<I>, GlobalError>
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>,
{
let inner = self.inner.lock().unwrap();
for &(id, ref interface, version) in &inner.list {
if interface == I::NAME {
if version >= min_version {
let version = ::std::cmp::min(version, max_version);
return Ok(self.registry.bind::<I>(version, id));
} else {
return Err(GlobalError::VersionTooLow(version));
}
}
}
Err(GlobalError::Missing)
}
/// Retrieve the list of currently known globals
pub fn list(&self) -> Vec<(u32, String, u32)> {
self.inner.lock().unwrap().list.clone()
}
}
/// A trait for implementation of the global advertisement
///
/// It is automatically implemented for `FnMut(Main<I>, DispatchData)` closures,
/// in which case the `error` messages are ignored.
pub trait GlobalImplementor<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>> {
/// A new global of given interface has been instantiated and you can assign
/// a filter to it.
fn new_global(&mut self, global: Main<I>, data: DispatchData);
/// A global was advertised but its version was lower than the minimal version
/// you requested.
///
/// The advertised version is provided as argument.
fn error(&mut self, _version: u32, _data: DispatchData) {}
}
impl<F, I: Interface> GlobalImplementor<I> for F
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>,
F: FnMut(Main<I>, DispatchData),
{
fn new_global(&mut self, global: Main<I>, data: DispatchData) {
(*self)(global, data)
}
}
/// Convenience macro to create a `GlobalManager` callback
///
/// This macro aims to simplify the specific but common case of
/// providing a callback to the `GlobalManager` that needs to
/// auto-bind all advertised instances of some specific globals
/// whenever they happen. Typically, your application will likely
/// want to keep track of all `wl_seat` and `wl_output` globals
/// to be able to correctly react to user input and their different
/// monitors.
///
/// The output of this macro is a closure, that can be given to
/// `GlobalManager::new_with_cb` as the callback argument.
///
/// Example use is typically:
///
/// ```no_run
/// # #[macro_use] extern crate wayland_client;
/// use wayland_client::GlobalManager;
/// # use wayland_client::{Display, Main, DispatchData};
/// use wayland_client::protocol::{wl_output, wl_seat};
///
/// # fn main() {
/// # let display = Display::connect_to_env().unwrap();
/// # let mut event_queue = display.create_event_queue();
/// # let seat_implementor: fn(Main<_>, DispatchData) = unimplemented!();
/// # let output_implementor: fn(Main<_>, DispatchData) = unimplemented!();
/// let globals = GlobalManager::new_with_cb(
/// &display.attach(event_queue.token()),
/// global_filter!(
/// // Bind all wl_seat with version 4
/// [wl_seat::WlSeat, 4, seat_implementor],
/// // Bind all wl_output with version 1
/// [wl_output::WlOutput, 1, output_implementor]
/// )
/// );
/// # }
/// ```
///
/// The supplied callbacks for each global kind must be an instance of a type
/// implementing the `GlobalImplementor<I>` trait. The argument provided to your
/// callback is a `Main` handle of the newly instantiated global, and you should assign it
/// to a filter in this callback if you plan to do so.. The error case happens if the server
/// advertised a lower version of the global than the one you requested, in which case you
/// are given the version it advertised in the error method, if you want to handle it graciously.
///
/// You can also provide closures for the various callbacks, in this case the errors will
/// be ignored. However, due to a lack of capability of rustc's inference, you'll likely need
/// to add some type annotation to your closure, typically something like this:
///
/// ```ignore
/// global_filter!(
/// [Interface, version, |proxy: Main<_>, dispatch_data| {
/// /* Setup the global as required */
/// }]
/// );
/// ```
#[macro_export]
macro_rules! global_filter {
($([$interface:ty, $version:expr, $callback:expr]),*) => {
{
use $crate::protocol::wl_registry;
use $crate::{GlobalEvent, Interface, Attached, GlobalImplementor, DispatchData};
type Callback = Box<dyn FnMut(u32, u32, Attached<wl_registry::WlRegistry>, DispatchData<'_>)>;
let mut callbacks: Vec<(&'static str, Callback)> = Vec::new();
// Create the callback list
$({
let mut cb = { $callback };
callbacks.push((
<$interface as Interface>::NAME,
Box::new(move |id, version, registry: Attached<wl_registry::WlRegistry>, ddata: DispatchData| {
if version < $version {
GlobalImplementor::<$interface>::error(&mut cb, version, ddata);
} else {
let proxy = registry.bind::<$interface>(version, id);
GlobalImplementor::<$interface>::new_global(&mut cb, proxy, ddata);
}
}) as Box<_>
));
})*
// return the global closure
move |event: GlobalEvent, registry: Attached<wl_registry::WlRegistry>, ddata| {
if let GlobalEvent::New { id, interface, version } = event {
for &mut (iface, ref mut cb) in &mut callbacks {
if iface == interface {
cb(id, version, registry, ddata);
break;
}
}
}
}
}
}
}

View file

@ -0,0 +1,321 @@
//! Client-side Wayland connector
//!
//! ## Overview
//!
//! This crate provides the interfaces and machinery to safely create
//! client applications for the Wayland protocol. It can be used as a rust
//! implementation of the protocol or as a wrapper around the system-wide
//! `libwayland-client.so` if you enable the `use_system_lib` cargo feature.
//!
//! The Wayland protocol revolves around the creation of various objects
//! and the exchange of messages associated to these objects. The initial
//! object is always the `Display`, that you get at initialization of the
//! connection, exposed by this crate as `Display::connect_to_env()`.
//!
//! ## Protocol and messages handling model
//!
//! The protocol being bi-directional, you can send and receive messages.
//! Sending messages is done via methods of Rust objects corresponding to the wayland protocol
//! objects, receiving and handling them is done by providing callbacks.
//!
//! ### Proxies
//!
//! Wayland objects are represented by proxies, which are handles to them.
//! You can interact with them in 4 states:
//!
//! - As the interface object directly `I`. This representation is the most immediate
//! one. It allows you to send requests though this object and can be send accross threads.
//! - As a `Proxy<I>`. This representation is suitable if you want to access the proxy as
//! a proxy, rather than a wayland object. You can convert between `I` and `Proxy<I>` via
//! the `From` and `Into` traits, and get a `&Proxy<I>` from an `I` via the `AsRef` trait.
//! - As a `Main<I>`. This represents a main handle to this proxy, and allows you greater
//! control of the object, but cannot be shared accros threads. This handle allows you to
//! assign filters to the object, and send requests that create new objects.
//! - As an `Attached<I>`. If you use more than one event queue (see below), this allows you
//! to control on which event queue the children object are created.
//!
//! There is not a 1 to 1 mapping between Rust object instances and protocol
//! objects. Rather, you can think of the Rust objects as `Rc`-like handles to a
//! Wayland object. Multiple instances of a Rust object can exist referring to the same
//! protocol object.
//!
//! Similarly, the lifetimes of the protocol objects and the Rust objects are
//! not tightly tied. As protocol objects are created and destroyed by protocol
//! messages, it can happen that an object gets destroyed while one or more
//! Rust objects still refer to it. In such case, these Rust objects will be disabled
//! and the `alive()` method on the underlying `Proxy<I>` will start to return `false`.
//!
//! Sending requests on dead objects will be silently ignored. And if these requests
//! would create new objects, these objects will be created dead.
//!
//! ### Filters
//!
//! Your wayland objects can receive events from the server, which need to be processed.
//! To do so, you can assign `Filter`s to your object. These are specially wrapped closure
//! so that several objects can be assigned to the same `Filter`, to ease state sharing
//! between the code handling different objects.
//!
//! If an object is not assigned to any `Filter`, its events will instead be delivered to the
//! fallback closure given to its event queue when dispatching it.
//!
//! ## Event Queues
//!
//! The Wayland client machinery provides the possibility to have one or more event queues
//! handling the processing of received messages. All Wayland objects are associated to an
//! event queue, which controls when its events are dispatched.
//!
//! Events received from the server are stored in an internal buffer, and processed (by calling
//! the appropriate callbacks) when the associated event queue is dispatched.
//!
//! When you send a request creating a new object, this new object will be assigned to an event
//! queue depending on the parent object that created it.
//!
//! - If the request was sent from a `Main<I>` handle, the child object will be assigned to the
//! same event queue as its parent.
//! - If the request was sent from an `Attached<I>` handle, the child object will be assigned to
//! the event queue its parent has been attached to.
//!
//! At the beginning you'll need to create an event queue and assign the initial `Proxy<WlDisplay>`
//! to it.
//!
//! ## Dynamic linking with `libwayland-client.so`
//!
//! If you need to gracefully handle the case of a system on which Wayland is not installed (by
//! fallbacking to X11 for example), you can do so by activating the `dlopen` cargo feature.
//!
//! When this is done, the library will be loaded a runtime rather than directly linked. And trying
//! to create a `Display` on a system that does not have this library will return a `NoWaylandLib`
//! error.
#![warn(missing_docs, missing_debug_implementations)]
#[macro_use]
extern crate bitflags;
#[cfg(not(feature = "use_system_lib"))]
#[macro_use]
extern crate downcast_rs as downcast;
#[cfg_attr(feature = "use_system_lib", macro_use)]
extern crate wayland_sys;
mod display;
mod event_queue;
mod globals;
mod proxy;
pub use anonymous_object::AnonymousObject;
pub use display::{ConnectError, Display, ProtocolError};
pub use event_queue::{EventQueue, QueueToken, ReadEventsGuard};
pub use globals::{GlobalError, GlobalEvent, GlobalImplementor, GlobalManager};
pub use imp::ProxyMap;
pub use proxy::{Attached, Main, Proxy};
pub use wayland_commons::{
filter::{DispatchData, Filter},
user_data::UserData,
Interface, MessageGroup, NoMessage,
};
// rust implementation
#[cfg(not(feature = "use_system_lib"))]
#[path = "rust_imp/mod.rs"]
mod imp;
// C-lib based implementation
#[cfg(feature = "use_system_lib")]
#[path = "native_lib/mod.rs"]
mod imp;
/// C-associated types
///
/// Required for plugging wayland-scanner generated protocols
/// or interfacing with C code using wayland objects.
pub mod sys {
pub use wayland_sys::{client, common};
}
pub mod protocol {
#![allow(dead_code, non_camel_case_types, unused_unsafe, unused_variables)]
#![allow(non_upper_case_globals, non_snake_case, unused_imports)]
#![allow(missing_docs, clippy::all)]
pub(crate) use crate::{AnonymousObject, Attached, Main, Proxy, ProxyMap};
pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
pub(crate) use wayland_commons::smallvec;
pub(crate) use wayland_commons::wire::{Argument, ArgumentType, Message, MessageDesc};
pub(crate) use wayland_commons::{Interface, MessageGroup};
pub(crate) use wayland_sys as sys;
include!(concat!(env!("OUT_DIR"), "/wayland_api.rs"));
}
mod anonymous_object {
use super::{Interface, NoMessage, Proxy};
use std::fmt::{self, Debug, Formatter};
/// Anonymous interface
///
/// A special Interface implementation representing an
/// handle to an object for which the interface is not known.
#[derive(Clone, Eq, PartialEq)]
pub struct AnonymousObject(pub(crate) Proxy<AnonymousObject>);
impl Interface for AnonymousObject {
type Request = NoMessage;
type Event = NoMessage;
const NAME: &'static str = "<anonymous>";
const VERSION: u32 = 0;
fn c_interface() -> *const crate::sys::common::wl_interface {
std::ptr::null()
}
}
impl AsRef<Proxy<AnonymousObject>> for AnonymousObject {
#[inline]
fn as_ref(&self) -> &Proxy<Self> {
&self.0
}
}
impl From<Proxy<AnonymousObject>> for AnonymousObject {
#[inline]
fn from(proxy: Proxy<Self>) -> Self {
AnonymousObject(proxy)
}
}
impl From<AnonymousObject> for Proxy<AnonymousObject> {
#[inline]
fn from(value: AnonymousObject) -> Self {
value.0
}
}
impl Debug for AnonymousObject {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{:?}", self.0))
}
}
}
/// Enum of possible argument in an event
#[derive(Debug)]
pub enum Argument {
/// i32
Int(i32),
/// u32
Uint(u32),
/// float
Float(f32),
/// CString
Str(Option<String>),
/// id of a wayland object
Object(Option<Proxy<AnonymousObject>>),
/// id of a newly created wayland object
NewId(Option<Main<AnonymousObject>>),
/// Vec<u8>
Array(Option<Vec<u8>>),
/// RawFd
Fd(std::os::unix::io::RawFd),
}
/// An generic event
#[derive(Debug)]
pub struct RawEvent {
/// Interface of the associated object
pub interface: &'static str,
/// Opcode of the event
pub opcode: u16,
/// Name of the event
pub name: &'static str,
/// Arguments of the message
pub args: Vec<Argument>,
}
/// Generate an enum joining several objects events
///
/// This macro allows you to easily create a enum type for use with your message Filters. It is
/// used like so:
///
/// ```no_run
/// # use wayland_client::protocol::{wl_pointer::WlPointer, wl_keyboard::WlKeyboard, wl_surface::WlSurface};
/// # use wayland_client::event_enum;
/// event_enum!(
/// MyEnum |
/// Pointer => WlPointer,
/// Keyboard => WlKeyboard,
/// Surface => WlSurface
/// );
/// ```
///
/// This will generate the following enum, unifying the events from each of the provided interface:
///
/// ```ignore
/// pub enum MyEnum {
/// Pointer { event: WlPointer::Event, object: Main<WlPointer> },
/// Keyboard { event: WlKeyboard::Event, object: Main<WlKeyboard> },
/// Surface { event: WlSurface::Event, object: Main<WlSurface> }
/// }
/// ```
///
/// It will also generate the appropriate `From<_>` implementation so that a `Filter<MyEnum>` can be
/// used as an implementation for `WlPointer`, `WlKeyboard` and `WlSurface`.
///
/// If you want to add custom messages to the enum, the macro also supports it:
///
/// ```no_run
/// # use wayland_client::protocol::{wl_pointer::WlPointer, wl_keyboard::WlKeyboard, wl_surface::WlSurface};
/// # use wayland_client::event_enum;
/// # struct SomeType;
/// # struct OtherType;
/// event_enum!(
/// MyEnum |
/// Pointer => WlPointer,
/// Keyboard => WlKeyboard,
/// Surface => WlSurface |
/// MyMessage => SomeType,
/// OtherMessage => OtherType
/// );
/// ```
///
/// will generate the following enum:
///
/// ```ignore
/// pub enum MyEnum {
/// Pointer { event: WlPointer::Event, object: Main<WlPointer> },
/// Keyboard { event: WlKeyboard::Event, object: Main<WlKeyboard> },
/// Surface { event: WlSurface::Event, object: Main<WlSurface> },
/// MyMessage(SomeType),
/// OtherMessage(OtherType)
/// }
/// ```
///
/// as well as implementations of `From<SomeType>` and `From<OtherType>`, so that these types can
/// directly be provided into a `Filter<MyEnum>`.
#[macro_export]
macro_rules! event_enum(
($(#[$attrs:meta])* $enu:ident | $($evt_name:ident => $iface:ty),*) => {
$crate::event_enum!($(#[$attrs])* $enu | $($evt_name => $iface),* | );
};
($(#[$attrs:meta])* $enu:ident | $($evt_name:ident => $iface:ty),* | $($name:ident => $value:ty),*) => {
$(#[$attrs])*
pub enum $enu {
$(
$evt_name { event: <$iface as $crate::Interface>::Event, object: $crate::Main<$iface> },
)*
$(
$name($value),
)*
}
$(
impl From<($crate::Main<$iface>, <$iface as $crate::Interface>::Event)> for $enu {
fn from((object, event): ($crate::Main<$iface>, <$iface as $crate::Interface>::Event)) -> $enu {
$enu::$evt_name { event, object }
}
}
)*
$(
impl From<$value> for $enu {
fn from(value: $value) -> $enu {
$enu::$name(value)
}
}
)*
};
);

View file

@ -0,0 +1,128 @@
use std::io;
use std::os::unix::io::RawFd;
use std::sync::Arc;
use crate::protocol::wl_display::WlDisplay;
use wayland_sys::client::*;
use crate::{ConnectError, Proxy};
use super::{EventQueueInner, ProxyInner};
pub(crate) struct DisplayInner {
proxy: Proxy<WlDisplay>,
display: Arc<DisplayGuard>,
}
pub(crate) struct DisplayGuard {
ptr: *mut wl_display,
external: bool,
}
unsafe impl Send for DisplayInner {}
unsafe impl Sync for DisplayInner {}
unsafe fn make_display(ptr: *mut wl_display) -> Result<Arc<DisplayInner>, ConnectError> {
if ptr.is_null() {
return Err(ConnectError::NoCompositorListening);
}
let mut inner = DisplayInner {
proxy: Proxy::from_c_ptr(ptr as *mut _),
display: Arc::new(DisplayGuard { ptr, external: false }),
};
inner.proxy.inner.display = Some(Arc::downgrade(&inner.display));
Ok(Arc::new(inner))
}
impl DisplayInner {
pub unsafe fn from_fd(fd: RawFd) -> Result<Arc<DisplayInner>, ConnectError> {
if !::wayland_sys::client::is_lib_available() {
return Err(ConnectError::NoWaylandLib);
}
let display_ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_connect_to_fd, fd);
make_display(display_ptr)
}
pub(crate) fn get_connection_fd(&self) -> ::std::os::unix::io::RawFd {
unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_get_fd, self.ptr()) }
}
pub(crate) fn ptr(&self) -> *mut wl_display {
self.display.ptr
}
pub(crate) fn flush(&self) -> io::Result<()> {
let ret = unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_flush, self.ptr()) };
if ret >= 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub(crate) fn create_event_queue(me: &Arc<DisplayInner>) -> EventQueueInner {
unsafe {
let ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_create_queue, me.ptr());
EventQueueInner::new(me.clone(), ptr)
}
}
pub(crate) fn get_proxy(&self) -> &Proxy<WlDisplay> {
&self.proxy
}
pub(crate) fn protocol_error(&self) -> Option<crate::ProtocolError> {
let ret = unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_get_error, self.ptr()) };
if ret == ::nix::errno::Errno::EPROTO as i32 {
let mut interface = ::std::ptr::null_mut();
let mut id = 0;
let code = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_get_protocol_error,
self.ptr(),
&mut interface,
&mut id
)
};
let interface_name = if !interface.is_null() {
unsafe { ::std::ffi::CStr::from_ptr((*interface).name) }
.to_str()
.unwrap_or("<unknown>")
} else {
"<unknown>"
};
Some(crate::ProtocolError {
code,
object_id: id,
object_interface: interface_name,
message: String::new(),
})
} else {
None
}
}
pub(crate) unsafe fn from_external(display_ptr: *mut wl_display) -> Arc<DisplayInner> {
Arc::new(DisplayInner {
proxy: Proxy::wrap(ProxyInner::from_external_display(display_ptr as *mut _)),
display: Arc::new(DisplayGuard { ptr: display_ptr, external: true }),
})
}
}
impl Drop for DisplayGuard {
fn drop(&mut self) {
if !self.external {
// disconnect only if we are owning this display
unsafe {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_disconnect, self.ptr);
}
}
}
}

View file

@ -0,0 +1,142 @@
use std::cell::RefCell;
use std::io;
use std::sync::Arc;
use crate::{AnonymousObject, DispatchData, Main, RawEvent};
use wayland_sys::client::*;
use super::DisplayInner;
scoped_tls::scoped_thread_local! {
pub(crate) static DISPATCH_METADATA: RefCell<(&mut dyn FnMut(RawEvent, Main<AnonymousObject>, DispatchData), DispatchData)>
}
#[allow(clippy::transmute_ptr_to_ptr)]
fn with_dispatch_meta<T, FB, F>(mut fb: FB, data: DispatchData, f: F) -> T
where
FB: FnMut(RawEvent, Main<AnonymousObject>, DispatchData),
F: FnOnce() -> T,
{
// We erase the lifetime of the callback to be able to store it in the tls,
// it's safe as it'll only last until the end of this function call anyway
let fb = unsafe { std::mem::transmute(&mut fb as &mut dyn FnMut(_, _, _)) };
let data = unsafe { std::mem::transmute(data) };
DISPATCH_METADATA.set(&RefCell::new((fb, data)), f)
}
pub(crate) struct EventQueueInner {
wlevq: *mut wl_event_queue,
inner: Arc<super::DisplayInner>,
}
impl EventQueueInner {
pub(crate) fn new(inner: Arc<DisplayInner>, wlevq: *mut wl_event_queue) -> EventQueueInner {
EventQueueInner { wlevq, inner }
}
pub(crate) fn dispatch<F>(&self, data: DispatchData, fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
with_dispatch_meta(fallback, data, || {
let ret = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_dispatch_queue,
self.inner.ptr(),
self.wlevq
)
};
if ret >= 0 {
Ok(ret as u32)
} else {
Err(io::Error::last_os_error())
}
})
}
pub(crate) fn dispatch_pending<F>(&self, data: DispatchData, fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
with_dispatch_meta(fallback, data, || {
let ret = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_dispatch_queue_pending,
self.inner.ptr(),
self.wlevq
)
};
if ret >= 0 {
Ok(ret as u32)
} else {
Err(io::Error::last_os_error())
}
})
}
pub(crate) fn sync_roundtrip<F>(&self, data: DispatchData, fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
with_dispatch_meta(fallback, data, || {
let ret = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_roundtrip_queue,
self.inner.ptr(),
self.wlevq
)
};
if ret >= 0 {
Ok(ret as u32)
} else {
Err(io::Error::last_os_error())
}
})
}
pub(crate) fn prepare_read(&self) -> Result<(), ()> {
let ret = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_prepare_read_queue,
self.inner.ptr(),
self.wlevq
)
};
if ret >= 0 {
Ok(())
} else {
Err(())
}
}
pub(crate) fn read_events(&self) -> io::Result<()> {
let ret = unsafe {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_read_events, self.inner.ptr())
};
if ret >= 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub(crate) fn cancel_read(&self) {
unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_cancel_read, self.inner.ptr()) }
}
pub(crate) unsafe fn assign_proxy(&self, proxy: *mut wl_proxy) {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_set_queue, proxy, self.wlevq)
}
}
impl Drop for EventQueueInner {
fn drop(&mut self) {
unsafe {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_event_queue_destroy, self.wlevq);
}
}
}

View file

@ -0,0 +1,36 @@
mod display;
mod event_queue;
mod proxy;
pub(crate) use self::display::DisplayInner;
pub(crate) use self::event_queue::EventQueueInner;
pub(crate) use self::proxy::ProxyInner;
use crate::{Interface, Main, Proxy};
/// This type only exists for type-level compatibility
/// with the rust implementation.
///
/// It is an empty enum that cannot be instantiated
#[derive(Debug)]
pub enum ProxyMap {}
impl ProxyMap {
/// Unusable method only existing for type-level compatibility
pub fn get<I: Interface>(&mut self, _: u32) -> Option<Proxy<I>> {
match *self {}
}
/// Unusable method only existing for type-level compatibility
pub fn get_or_dead<I: Interface>(&mut self, _: u32) -> Proxy<I> {
match *self {}
}
/// Unusable method only existing for type-level compatibility
pub fn get_new<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
&mut self,
_: u32,
) -> Option<Main<I>> {
match *self {}
}
}

View file

@ -0,0 +1,519 @@
use std::cell::RefCell;
use std::os::raw::{c_int, c_void};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Weak};
use crate::{Interface, Main, Proxy, RawEvent};
use wayland_commons::filter::Filter;
use wayland_commons::user_data::UserData;
use wayland_commons::wire::ArgumentType;
use wayland_commons::MessageGroup;
use super::EventQueueInner;
use wayland_sys::client::*;
use wayland_sys::common::*;
pub struct ProxyInternal {
alive: AtomicBool,
user_data: UserData,
}
impl ProxyInternal {
pub fn new(user_data: UserData) -> ProxyInternal {
ProxyInternal { alive: AtomicBool::new(true), user_data }
}
}
pub(crate) struct ProxyInner {
internal: Option<Arc<ProxyInternal>>,
ptr: *mut wl_proxy,
wrapping: Option<*mut wl_proxy>,
pub(crate) display: Option<Weak<super::display::DisplayGuard>>,
}
unsafe impl Send for ProxyInner {}
unsafe impl Sync for ProxyInner {}
impl ProxyInner {
pub(crate) fn is_alive(&self) -> bool {
if let Some(ref weak) = self.display {
if Weak::strong_count(weak) == 0 {
// the connection is dead
return false;
}
}
self.internal.as_ref().map(|i| i.alive.load(Ordering::Acquire)).unwrap_or(true)
}
pub(crate) fn is_external(&self) -> bool {
self.internal.is_none()
}
pub(crate) fn version(&self) -> u32 {
if !self.is_alive() {
return 0;
}
let version =
unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_version, self.ptr) as u32 };
if version == 0 {
// For backcompat reasons the C libs return 0 as a version for the wl_display
// So override it
return 1;
}
version
}
pub(crate) fn is_interface<I: Interface>(&self) -> bool {
if !self.is_alive() {
return false;
}
unsafe {
let c_class_ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_class, self.ptr);
let class = std::ffi::CStr::from_ptr(c_class_ptr);
let i_class = std::ffi::CStr::from_ptr((*I::c_interface()).name);
class == i_class
}
}
pub(crate) fn id(&self) -> u32 {
if !self.is_alive() {
return 0;
}
unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, self.ptr) }
}
pub(crate) fn user_data(&self) -> &UserData {
static INVALID_USERDATA: UserData = UserData::new();
if let Some(ref inner) = self.internal {
&inner.user_data
} else {
INVALID_USERDATA.set_threadsafe(|| ());
&INVALID_USERDATA
}
}
pub(crate) fn send<I, J>(&self, msg: I::Request, version: Option<u32>) -> Option<ProxyInner>
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>,
J: Interface + AsRef<Proxy<J>> + From<Proxy<J>>,
{
let destructor = msg.is_destructor();
let opcode = msg.opcode();
// figure out if the call creates an object
let nid_idx = I::Request::MESSAGES[opcode as usize]
.signature
.iter()
.position(|&t| t == ArgumentType::NewId);
let alive = self.is_alive();
let ret = if let Some(mut nid_idx) = nid_idx {
if let Some(o) = I::Request::child(opcode, 1, &()) {
if !o.is_interface::<J>() {
panic!("Trying to use 'send_constructor' with the wrong return type. Required interface {} but the message creates interface {}", J::NAME, o.interface)
}
} else {
// there is no target interface in the protocol, this is a generic object-creating
// function (likely wl_registry.bind), the newid arg will thus expand to (str, u32, obj)
nid_idx += 2;
}
let version = version.unwrap_or_else(|| self.version());
if alive {
if self.wrapping.is_none() {
panic!("Attemping to create an object from a non-attached proxy.");
}
unsafe {
let ptr = msg.as_raw_c_in(|opcode, args| {
assert!(
args[nid_idx].o.is_null(),
"Trying to use 'send_constructor' with a non-placeholder object."
);
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_marshal_array_constructor_versioned,
self.wrapping.unwrap_or(self.ptr),
opcode,
args.as_mut_ptr(),
J::c_interface(),
version
)
});
let mut new_proxy = ProxyInner::init_from_c_ptr::<J>(ptr);
new_proxy.display = self.display.clone();
Some(new_proxy)
}
} else {
// Create a dead proxy ex-nihilo
Some(ProxyInner::dead())
}
} else {
// not a constructor, nothing much to do
if alive {
msg.as_raw_c_in(|opcode, args| unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_marshal_array,
self.wrapping.unwrap_or(self.ptr),
opcode,
args.as_ptr() as *mut _
);
});
}
None
};
if destructor && alive {
// we need to destroy the proxy now
if let Some(ref internal) = self.internal {
internal.alive.store(false, Ordering::Release);
unsafe {
let user_data =
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, self.ptr);
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_set_user_data,
self.ptr,
std::ptr::null_mut()
);
let _ = Box::from_raw(user_data as *mut ProxyUserData<I>);
}
}
unsafe {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_destroy, self.ptr);
}
}
ret
}
pub(crate) fn equals(&self, other: &ProxyInner) -> bool {
if !self.is_alive() {
return false;
}
match (&self.internal, &other.internal) {
(&Some(ref my_inner), &Some(ref other_inner)) => Arc::ptr_eq(my_inner, other_inner),
(&None, &None) => self.ptr == other.ptr,
_ => false,
}
}
pub(crate) fn detach(&mut self) {
if !self.is_external() && !self.is_alive() {
return;
}
if let Some(ptr) = self.wrapping.take() {
// self.ptr == self.wrapping means we are a Main<_>
if ptr != self.ptr {
unsafe {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_wrapper_destroy, ptr);
}
}
}
}
pub(crate) fn attach(&mut self, queue: &EventQueueInner) {
if !self.is_external() && !self.is_alive() {
return;
}
let wrapper_ptr;
unsafe {
wrapper_ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_create_wrapper, self.ptr);
queue.assign_proxy(wrapper_ptr);
}
self.wrapping = Some(wrapper_ptr);
}
pub(crate) fn c_ptr(&self) -> *mut wl_proxy {
self.wrapping.unwrap_or(self.ptr)
}
pub fn assign<I, E>(&self, filter: Filter<E>)
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
E: From<(Main<I>, I::Event)> + 'static,
I::Event: MessageGroup<Map = super::ProxyMap>,
{
if self.is_external() {
panic!("Cannot assign an external proxy to a filter.");
}
if !self.is_alive() {
return;
}
unsafe {
let user_data = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, self.ptr)
as *mut ProxyUserData<I>;
if let Ok(ref mut guard) = (*user_data).implem.try_borrow_mut() {
**guard =
Some(Box::new(move |evt, obj, data| filter.send((obj, evt).into(), data)));
} else {
panic!("Re-assigning an object from within its own callback is not supported.");
}
}
}
pub(crate) unsafe fn init_from_c_ptr<I: Interface + From<Proxy<I>> + AsRef<Proxy<I>>>(
ptr: *mut wl_proxy,
) -> Self {
let new_user_data = Box::new(ProxyUserData::<I>::new(UserData::new()));
let internal = new_user_data.internal.clone();
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_add_dispatcher,
ptr,
proxy_dispatcher::<I>,
&::wayland_sys::RUST_MANAGED as *const _ as *const _,
Box::into_raw(new_user_data) as *mut _
);
// We are a Main<_>, so ptr == wrapping
ProxyInner { internal: Some(internal), ptr, wrapping: Some(ptr), display: None }
}
fn dead() -> Self {
ProxyInner {
internal: Some(Arc::new(ProxyInternal {
alive: AtomicBool::new(false),
user_data: UserData::new(),
})),
ptr: std::ptr::null_mut(),
wrapping: None,
display: None,
}
}
pub(crate) unsafe fn from_c_ptr<I: Interface + From<Proxy<I>> + AsRef<Proxy<I>>>(
ptr: *mut wl_proxy,
) -> Self {
if ptr.is_null() {
return Self::dead();
}
let is_managed = {
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_listener, ptr)
== &::wayland_sys::RUST_MANAGED as *const u8 as *const _
};
let internal = if is_managed {
let user_data = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
as *mut ProxyUserData<I>;
Some((*user_data).internal.clone())
} else {
None
};
ProxyInner { internal, ptr, wrapping: None, display: None }
}
pub(crate) unsafe fn from_external_display(d: *mut wl_proxy) -> ProxyInner {
ProxyInner { internal: None, ptr: d, wrapping: None, display: None }
}
}
impl Clone for ProxyInner {
fn clone(&self) -> ProxyInner {
let mut new = ProxyInner {
internal: self.internal.clone(),
ptr: self.ptr,
wrapping: None,
display: self.display.clone(),
};
if !self.is_external() && !self.is_alive() {
return new;
}
if let Some(ptr) = self.wrapping {
if ptr != self.ptr {
// create a new wrapper to keep correct track of them
let wrapper_ptr;
unsafe {
wrapper_ptr =
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_create_wrapper, ptr);
}
new.wrapping = Some(wrapper_ptr);
} else {
// self.wrapping == self.ptr means we are a Main<_>, not a wrapper
new.wrapping = Some(self.ptr);
}
}
new
}
}
impl Drop for ProxyInner {
fn drop(&mut self) {
// always detach on drop to avoid leaking wrappers
self.detach();
}
}
type BoxedCallback<I> = Box<dyn Fn(<I as Interface>::Event, Main<I>, crate::DispatchData<'_>)>;
struct ProxyUserData<I: Interface + From<Proxy<I>> + AsRef<Proxy<I>>> {
internal: Arc<ProxyInternal>,
implem: RefCell<Option<BoxedCallback<I>>>,
}
impl<I: Interface + From<Proxy<I>> + AsRef<Proxy<I>>> ProxyUserData<I> {
fn new(user_data: UserData) -> ProxyUserData<I> {
ProxyUserData {
internal: Arc::new(ProxyInternal::new(user_data)),
implem: RefCell::new(None),
}
}
}
unsafe extern "C" fn proxy_dispatcher<I: Interface>(
_implem: *const c_void,
proxy: *mut c_void,
opcode: u32,
_msg: *const wl_message,
args: *const wl_argument,
) -> c_int
where
I: Interface + From<Proxy<I>> + AsRef<Proxy<I>>,
{
let proxy = proxy as *mut wl_proxy;
// We don't need to worry about panic-safeness, because if there is a panic,
// we'll abort the process, so no access to corrupted data is possible.
let ret = ::std::panic::catch_unwind(move || {
let must_destroy = I::Event::MESSAGES[opcode as usize].destructor;
// retrieve the impl
let user_data = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, proxy);
{
// a scope to ensure the &mut reference to the user data no longer exists when
// the callback is invoked
let (implem, internal) = {
let user_data = &mut *(user_data as *mut ProxyUserData<I>);
if must_destroy {
user_data.internal.alive.store(false, Ordering::Release);
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_destroy, proxy);
}
// remove the implem from the user data, so that it remains valid even if the
// object is destroyed from within the callback
(user_data.implem.borrow_mut().take(), user_data.internal.clone())
};
// if there is an implem, call it, otherwise call the fallback
match implem {
Some(ref implem) => {
// parse the message:
let msg = I::Event::from_raw_c(proxy as *mut _, opcode, args)?;
// create the proxy object
let mut proxy_inner = ProxyInner::from_c_ptr::<I>(proxy);
// This proxy must be a Main, so it as attached wrapping itself
proxy_inner.wrapping = Some(proxy_inner.ptr);
let proxy_obj = crate::Main::wrap(proxy_inner);
super::event_queue::DISPATCH_METADATA.with(|meta| {
let mut meta = meta.borrow_mut();
let (_, ref mut dispatch_data) = *meta;
implem(msg, proxy_obj, dispatch_data.reborrow());
})
}
None => {
// parse the message:
let msg = parse_raw_event::<I>(opcode, args);
// create the proxy object
let proxy_obj = crate::Main::wrap(ProxyInner::from_c_ptr::<I>(proxy));
super::event_queue::DISPATCH_METADATA.with(|meta| {
let mut meta = meta.borrow_mut();
let (ref mut fallback, ref mut dispatch_data) = *meta;
(&mut *fallback)(msg, proxy_obj, dispatch_data.reborrow());
})
}
}
// if the proxy is still alive, put the implem back in place
if internal.alive.load(Ordering::Acquire) {
let user_data = &mut *(user_data as *mut ProxyUserData<I>);
let mut implem_place = user_data.implem.borrow_mut();
// only place the implem back if it has not been replaced with an other
if implem_place.is_none() {
*implem_place = implem;
}
}
}
if must_destroy {
// final cleanup
let _ = Box::from_raw(user_data as *mut ProxyUserData<I>);
}
Ok(())
});
// check the return status
match ret {
Ok(Ok(())) => 0,
Ok(Err(())) => {
eprintln!(
"[wayland-client error] Attempted to dispatch unknown opcode {} for {}, aborting.",
opcode,
I::NAME
);
libc::abort();
}
Err(_) => {
eprintln!("[wayland-client error] A handler for {} panicked.", I::NAME);
libc::abort()
}
}
}
unsafe fn parse_raw_event<I: Interface>(opcode: u32, args: *const wl_argument) -> RawEvent {
let desc = &I::Event::MESSAGES[opcode as usize];
let c_args = std::slice::from_raw_parts(args, desc.signature.len());
let mut args = Vec::with_capacity(c_args.len());
// parse the arguments one by one
for (t, a) in desc.signature.iter().zip(c_args.iter()) {
args.push(match t {
ArgumentType::Int => crate::Argument::Int(a.i),
ArgumentType::Uint => crate::Argument::Uint(a.u),
ArgumentType::Fixed => crate::Argument::Float((a.f as f32) / 256.),
ArgumentType::Array => {
if a.a.is_null() {
crate::Argument::Array(None)
} else {
let array = &*a.a;
crate::Argument::Array(Some(
::std::slice::from_raw_parts(array.data as *const u8, array.size)
.to_owned(),
))
}
}
ArgumentType::Str => {
if a.s.is_null() {
crate::Argument::Str(None)
} else {
crate::Argument::Str(Some(
::std::ffi::CStr::from_ptr(a.s).to_string_lossy().into_owned(),
))
}
}
ArgumentType::Fd => crate::Argument::Fd(a.h),
ArgumentType::Object => {
if a.o.is_null() {
crate::Argument::Object(None)
} else {
crate::Argument::Object(Some(Proxy::from_c_ptr(a.o as *mut _)))
}
}
ArgumentType::NewId => {
if a.o.is_null() {
crate::Argument::NewId(None)
} else {
crate::Argument::NewId(Some(Main::from_c_ptr(a.o as *mut _)))
}
}
});
}
RawEvent { interface: I::NAME, opcode: opcode as u16, name: desc.name, args }
}

View file

@ -0,0 +1,441 @@
use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use super::AnonymousObject;
use wayland_commons::user_data::UserData;
use wayland_commons::Interface;
use wayland_sys::client::*;
use crate::event_queue::QueueToken;
use crate::imp::ProxyInner;
use wayland_commons::{filter::Filter, MessageGroup};
/// An handle to a wayland proxy
///
/// This represents a wayland object instantiated in your client
/// session. Several handles to the same object can exist at a given
/// time, and cloning them won't create a new protocol object, only
/// clone the handle. The lifetime of the protocol object is **not**
/// tied to the lifetime of these handles, but rather to sending or
/// receiving destroying messages.
///
/// These handles are notably used to send requests to the server. To do this
/// you need to convert them to the corresponding Rust object (using `.into()`)
/// and use methods on the Rust object.
///
/// This handle is the most conservative one: it can be sent between threads,
/// but you cannot send any message that would create a new object using it.
/// You must attach it to a event queue, that will host the newly created objects.
pub struct Proxy<I: Interface> {
_i: ::std::marker::PhantomData<&'static I>,
pub(crate) inner: ProxyInner,
}
impl<I: Interface> Clone for Proxy<I> {
fn clone(&self) -> Proxy<I> {
let mut cloned = self.inner.clone();
// an owned Proxy must always be detached
cloned.detach();
Proxy { _i: ::std::marker::PhantomData, inner: cloned }
}
}
impl<I: Interface> PartialEq for Proxy<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn eq(&self, other: &Proxy<I>) -> bool {
self.equals(other)
}
}
impl<I: Interface> Debug for Proxy<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}@{}", I::NAME, self.inner.id())
}
}
impl<I: Interface> Eq for Proxy<I> where I: AsRef<Proxy<I>> + From<Proxy<I>> {}
impl<I: Interface> Proxy<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
#[allow(dead_code)]
pub(crate) fn wrap(inner: ProxyInner) -> Proxy<I> {
Proxy { _i: ::std::marker::PhantomData, inner }
}
/// Send a request creating an object through this object
///
/// **Warning:** This method is mostly intended to be used by code generated
/// by `wayland-scanner`, and you should probably never need to use it directly,
/// but rather use the appropriate methods on the Rust object.
///
/// This is the generic method to send requests.
pub fn send<J>(&self, msg: I::Request, version: Option<u32>) -> Option<Main<J>>
where
J: Interface + AsRef<Proxy<J>> + From<Proxy<J>>,
{
if msg.since() > self.version() && self.version() > 0 {
let opcode = msg.opcode() as usize;
panic!(
"Cannot send request {} which requires version >= {} on proxy {}@{} which is version {}.",
I::Request::MESSAGES[opcode].name,
msg.since(),
I::NAME,
self.id(),
self.version()
);
}
self.inner.send::<I, J>(msg, version).map(Main::wrap)
}
/// Check if the object associated with this proxy is still alive
///
/// Will return `false` if the object has been destroyed.
///
/// If the object is not managed by this library (if it was created from a raw
/// pointer from some other library your program interfaces with), this will always
/// returns `true`.
pub fn is_alive(&self) -> bool {
self.inner.is_alive()
}
/// Retrieve the interface version of this wayland object instance
///
/// Returns 0 on dead objects
pub fn version(&self) -> u32 {
self.inner.version()
}
/// Retrieve the object id of this wayland object
pub fn id(&self) -> u32 {
self.inner.id()
}
/// Access the UserData associated to this object
///
/// Each wayland object has an associated UserData, that can store
/// a payload of arbitrary type and is shared by all proxies of this
/// object.
///
/// See [`UserData`](struct.UserData.html) documentation for more details.
pub fn user_data(&self) -> &UserData {
self.inner.user_data()
}
/// Check if the other proxy refers to the same underlying wayland object
///
/// You can also use the `PartialEq` implementation.
pub fn equals(&self, other: &Proxy<I>) -> bool {
self.inner.equals(&other.inner)
}
/// Attach this proxy to the event queue represented by this token
///
/// Once a proxy is attached, you can use it to send requests that
/// create new objects. These new objects will be handled by the
/// event queue represented by the provided token.
///
/// This does not impact the events received by this object, which
/// are still handled by their original event queue.
pub fn attach(&self, token: QueueToken) -> Attached<I> {
let mut other = self.clone();
other.inner.attach(&token.inner);
Attached { inner: other.into(), _s: std::marker::PhantomData }
}
/// Erase the actual type of this proxy
pub fn anonymize(self) -> Proxy<AnonymousObject> {
Proxy { _i: ::std::marker::PhantomData, inner: self.inner }
}
}
impl Proxy<AnonymousObject> {
/// Attempt to recover the typed variant of an anonymous proxy
pub fn deanonymize<I: Interface>(self) -> Result<Proxy<I>, Self> {
if self.inner.is_interface::<I>() {
Ok(Proxy { inner: self.inner, _i: ::std::marker::PhantomData })
} else {
Err(self)
}
}
}
impl<I: Interface + Debug> Debug for Attached<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}[ATTACHED]", self.inner)
}
}
/// A handle to a proxy that has been attached to an event queue
///
/// As opposed to `Proxy`, you can use it to send requests
/// that create new objects. The created objects will be handled
/// by the event queue this proxy has been attached to.
#[derive(PartialEq)]
pub struct Attached<I: Interface> {
// AttachedProxy is *not* send/sync
_s: ::std::marker::PhantomData<*mut ()>,
inner: I,
}
impl<I: Interface> Attached<I>
where
I: Into<Proxy<I>> + From<Proxy<I>> + AsRef<Proxy<I>>,
{
/// Create a non-attached handle from this one
pub fn detach(&self) -> I {
self.inner.as_ref().clone().into()
}
}
impl<I: Interface> Deref for Attached<I> {
type Target = I;
fn deref(&self) -> &I {
&self.inner
}
}
impl<I: Interface> Clone for Attached<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn clone(&self) -> Attached<I> {
let cloned = self.inner.as_ref().inner.clone();
Attached {
inner: Proxy { _i: std::marker::PhantomData, inner: cloned }.into(),
_s: std::marker::PhantomData,
}
}
}
/// A main handle to a proxy
///
/// This handle allows the same control as an `Attached` handle,
/// but additionnaly can be used to assign the proxy to a `Filter`,
/// in order to process its events.
#[derive(Clone, PartialEq)]
pub struct Main<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>> {
inner: Attached<I>,
}
impl<I: Interface> Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
pub(crate) fn wrap(inner: ProxyInner) -> Main<I> {
Main {
inner: Attached {
inner: Proxy { _i: std::marker::PhantomData, inner }.into(),
_s: std::marker::PhantomData,
},
}
}
/// Assign this object to given filter
///
/// All future event received by this object will be delivered to this
/// filter.
///
/// An object that is not assigned to any filter will see its events
/// delivered to the fallback callback of its event queue.
///
/// Event message type of the filter should verify
/// `E: From<(Main<I>, I::Event)>`. See the `event_enum!` macro provided
/// in this library to easily generate appropriate types.
pub fn assign<E>(&self, filter: Filter<E>)
where
I: Sync,
E: From<(Main<I>, I::Event)> + 'static,
I::Event: MessageGroup<Map = crate::ProxyMap>,
{
self.inner.inner.as_ref().inner.assign(filter);
}
/// Shorthand for assigning a closure to an object
///
/// Behaves similarly as `assign(..)`, but is a shorthand if
/// you want to assign this object to its own filter. In which
/// case you just need to provide the appropriate closure, of
/// type `FnMut(Main<I>, I::Event)`.
pub fn quick_assign<F>(&self, mut f: F)
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
F: FnMut(Main<I>, I::Event, crate::DispatchData) + 'static,
I::Event: MessageGroup<Map = crate::ProxyMap>,
{
self.assign(Filter::new(move |(proxy, event), _, data| f(proxy, event, data)))
}
}
impl Main<AnonymousObject> {
/// Attempt to recover the typed variant of an anonymous proxy
pub fn deanonymize<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
self,
) -> Result<Main<I>, Self> {
if self.inner.as_ref().inner.is_interface::<I>() {
Ok(Main {
inner: Attached {
inner: Proxy { _i: std::marker::PhantomData, inner: self.inner.inner.0.inner }
.into(),
_s: std::marker::PhantomData,
},
})
} else {
Err(self)
}
}
}
impl<I: Interface> Deref for Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
type Target = Attached<I>;
fn deref(&self) -> &Attached<I> {
&self.inner
}
}
impl<I: Interface> From<Main<I>> for Attached<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn from(main: Main<I>) -> Attached<I> {
main.inner
}
}
impl<I: Interface> Debug for Main<I>
where
I: Debug + AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}[MAIN]", self.inner.inner)
}
}
/*
* C-interfacing stuff
*/
impl<I: Interface> Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
/// Create a `Main` instance from a C pointer
///
/// Create a `Main` from a raw pointer to a wayland object from the
/// C library.
///
/// In order to handle protocol races, invoking it with a NULL pointer will
/// create an already-dead object.
///
/// NOTE: This method will panic if called while the `use_system_lib` feature is
/// not activated.
///
/// # Safety
///
/// This will take control of the underlying proxy & manage it. To be safe
/// you must ensure that:
///
/// - The provided proxy has not already been used in any way (it was just created)
/// - This is called from the same thread as the one hosting the event queue
/// handling this proxy
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Main<I> {
#[cfg(feature = "use_system_lib")]
{
Main::wrap(ProxyInner::init_from_c_ptr::<I>(_ptr))
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
}
impl<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>> Proxy<I> {
/// Check whether this proxy is managed by the library or not
///
/// See `from_c_ptr` for details.
///
/// NOTE: This method will panic if called while the `use_system_lib` feature is
/// not activated.
pub fn is_external(&self) -> bool {
#[cfg(feature = "use_system_lib")]
{
self.inner.is_external()
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
/// Get a raw pointer to the underlying wayland object
///
/// Retrieve a pointer to the object from the `libwayland-client.so` library.
/// You will mostly need it to interface with C libraries needing access
/// to wayland objects (to initialize an opengl context for example).
///
/// NOTE: This method will panic if called while the `use_system_lib` feature is
/// not activated.
pub fn c_ptr(&self) -> *mut wl_proxy {
#[cfg(feature = "use_system_lib")]
{
self.inner.c_ptr()
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
/// Create a `Proxy` instance from a C pointer
///
/// Create a `Proxy` from a raw pointer to a wayland object from the
/// C library.
///
/// If the pointer was previously obtained by the `c_ptr()` method, this
/// constructs a new proxy for the same object just like the `clone()`
/// method would have.
///
/// If the object was created by some other C library you are interfacing
/// with, it will be created in an "unmanaged" state: wayland-client will
/// treat it as foreign, and as such most of the safeties will be absent.
/// Notably the lifetime of the object can't be tracked, so the `alive()`
/// method will always return `true` and you are responsible of not using
/// an object past its destruction (as this would cause a protocol error).
/// You will also be unable to associate any user data value to this object.
///
/// In order to handle protocol races, invoking it with a NULL pointer will
/// create an already-dead object.
///
/// NOTE: This method will panic if called while the `use_system_lib` feature is
/// not activated.
///
/// # Safety
///
/// The provided pointer must point to a valid wayland object from `libwayland-client`
/// with the correct interface.
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Proxy<I>
where
I: From<Proxy<I>>,
{
#[cfg(feature = "use_system_lib")]
{
Proxy { _i: ::std::marker::PhantomData, inner: ProxyInner::from_c_ptr::<I>(_ptr) }
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
}

View file

@ -0,0 +1,181 @@
use std::cell::RefCell;
use std::os::unix::io::{FromRawFd, RawFd};
use std::sync::{Arc, Mutex};
use nix::Result as NixResult;
use wayland_commons::map::{Object, ObjectMap, SERVER_ID_LIMIT};
use wayland_commons::socket::{BufferedSocket, Socket};
use wayland_commons::wire::{Argument, ArgumentType, Message, MessageParseError};
use super::proxy::ObjectMeta;
use super::queues::QueueBuffer;
use crate::ProtocolError;
#[derive(Clone, Debug)]
pub(crate) enum Error {
Protocol(ProtocolError),
Parse(MessageParseError),
Nix(::nix::Error),
}
pub(crate) struct Connection {
pub(crate) socket: BufferedSocket,
pub(crate) map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
pub(crate) last_error: Arc<Mutex<Option<Error>>>,
pub(crate) display_buffer: QueueBuffer,
}
impl Connection {
pub(crate) unsafe fn new(fd: RawFd, display_object: Object<ObjectMeta>) -> Connection {
let socket = BufferedSocket::new(Socket::from_raw_fd(fd));
let mut map = ObjectMap::new();
// Insert first pre-existing object
let display_buffer = display_object.meta.buffer.clone();
map.insert_at(1, display_object).unwrap();
Connection {
socket,
map: Arc::new(Mutex::new(map)),
last_error: Arc::new(Mutex::new(None)),
display_buffer,
}
}
pub(crate) fn write_message(&mut self, msg: &Message) -> NixResult<()> {
self.socket.write_message(msg)
}
pub(crate) fn flush(&mut self) -> NixResult<()> {
self.socket.flush()
}
pub(crate) fn read_events(&mut self) -> Result<usize, Error> {
if let Some(ref err) = *self.last_error.lock().unwrap() {
return Err(err.clone());
}
// acquire the map lock, this means no objects can be created nor destroyed while we
// are reading events
let mut map = self.map.lock().unwrap();
// wrap it in a RefCell for cheap sharing in the two closures below
let map = RefCell::new(&mut *map);
let mut last_error = self.last_error.lock().unwrap();
// read messages
let ret = self.socket.read_messages(
|id, opcode| {
map.borrow()
.find(id)
.and_then(|o| o.events.get(opcode as usize))
.map(|desc| desc.signature)
},
|msg| {
// Early exit on protocol error
if msg.sender_id == 1 && msg.opcode == 0 {
if let [Argument::Object(faulty_id), Argument::Uint(error_code), Argument::Str(ref error_msg)] = &msg.args[..] {
let error_msg = error_msg.to_string_lossy().into_owned();
let faulty_interface = map.borrow().find(*faulty_id).map(|obj| obj.interface).unwrap_or("unknown");
// abort parsing, this is an unrecoverable error
*last_error = Some(Error::Protocol(ProtocolError {
code: *error_code,
object_id: *faulty_id,
object_interface: faulty_interface,
message: error_msg
}));
} else {
unreachable!();
}
return false;
}
// dispatch the message to the proper object
let mut map = map.borrow_mut();
let object = map.find(msg.sender_id);
// create a new object if applicable
if let Some((mut child, dead_parent)) = object
.as_ref()
.and_then(|o| o.event_child(msg.opcode).map(|c| (c, o.meta.client_destroyed)))
{
let new_id = msg
.args
.iter()
.flat_map(|a| if let Argument::NewId(nid) = *a { Some(nid) } else { None })
.next()
.unwrap();
let child_interface = child.interface;
// if this ID belonged to a now destroyed server object, we can replace it
if new_id >= SERVER_ID_LIMIT
&& map.with(new_id, |obj| obj.meta.client_destroyed).unwrap_or(false)
{
map.remove(new_id)
}
// if the parent object is already destroyed, the user will never see this
// object, so we set it as client_destroyed to ignore all future messages to it
if dead_parent {
child.meta.client_destroyed = true;
}
if let Err(()) = map.insert_at(new_id, child) {
// abort parsing, this is an unrecoverable error
*last_error = Some(Error::Protocol(ProtocolError {
code: 0,
object_id: 0,
object_interface: "",
message: format!(
"Protocol error: server tried to create \
an object \"{}\" with invalid id \"{}\".",
child_interface, new_id
),
}));
return false;
}
} else {
// debug assert: if this opcode does not define a child, then there should be no
// NewId argument
debug_assert!(!msg.args.iter().any(|a| a.get_type() == ArgumentType::NewId));
}
// send the message to the appropriate pending queue
match object {
Some(Object { meta: ObjectMeta { client_destroyed: true, .. }, .. }) | None => {
// this is a message sent to a destroyed object
// to avoid dying because of races, we just consume it into void
// closing any associated FDs
for a in msg.args {
if let Argument::Fd(fd) = a {
let _ = ::nix::unistd::close(fd);
}
}
}
Some(obj) => {
obj.meta.buffer.lock().unwrap().push_back(msg);
}
};
// continue parsing
true
},
);
if let Some(ref e) = *last_error {
// a protocol error was generated, don't lose it, it is the source of any subsequent error
return Err(e.clone());
}
match ret {
Ok(Ok(n)) => Ok(n),
Ok(Err(e)) => {
*last_error = Some(Error::Parse(e.clone()));
Err(Error::Parse(e))
}
// non-fatal error
Err(e @ nix::Error::EAGAIN) => Err(Error::Nix(e)),
// fatal errors
Err(e) => {
*last_error = Some(Error::Nix(e));
Err(Error::Nix(e))
}
}
}
}

View file

@ -0,0 +1,152 @@
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use wayland_commons::debug;
use wayland_commons::map::{Object, ObjectMap};
use wayland_commons::wire::Message;
use wayland_commons::MessageGroup;
use crate::protocol::wl_display::{self, WlDisplay};
use crate::{ConnectError, ProtocolError, Proxy};
use super::connection::{Connection, Error as CxError};
use super::proxy::{ObjectMeta, ProxyInner};
use super::{Dispatched, EventQueueInner, ProxyMap, WAYLAND_DEBUG};
pub(crate) struct DisplayInner {
connection: Arc<Mutex<Connection>>,
proxy: Proxy<WlDisplay>,
}
impl DisplayInner {
pub unsafe fn from_fd(fd: RawFd) -> Result<Arc<DisplayInner>, ConnectError> {
if let Some(value) = std::env::var_os("WAYLAND_DEBUG") {
// Follow libwayland-client and enable debug log only on `1` and `client` values.
if value == "1" || value == "client" {
// Toggle debug log.
WAYLAND_DEBUG.store(true, Ordering::Relaxed);
}
}
// The special buffer for display events
let buffer = super::queues::create_queue_buffer();
let display_object = Object::from_interface::<WlDisplay>(1, ObjectMeta::new(buffer));
let (connection, map) = {
let c = Connection::new(fd, display_object);
let m = c.map.clone();
(Arc::new(Mutex::new(c)), m)
};
// Setup the display dispatcher
map.lock()
.unwrap()
.with(1, |obj| {
obj.meta.dispatcher = Arc::new(Mutex::new(DisplayDispatcher {
map: map.clone(),
last_error: connection.lock().unwrap().last_error.clone(),
}));
})
.unwrap();
let display_proxy = ProxyInner::from_id(1, map, connection.clone()).unwrap();
let display = DisplayInner { proxy: Proxy::wrap(display_proxy), connection };
Ok(Arc::new(display))
}
pub(crate) fn flush(&self) -> io::Result<()> {
match self.connection.lock().unwrap().flush() {
Ok(()) => Ok(()),
Err(errno) => Err(errno.into()),
}
}
pub(crate) fn create_event_queue(me: &Arc<DisplayInner>) -> EventQueueInner {
EventQueueInner::new(me.connection.clone(), None)
}
pub(crate) fn get_proxy(&self) -> &Proxy<WlDisplay> {
&self.proxy
}
pub(crate) fn protocol_error(&self) -> Option<ProtocolError> {
let cx = self.connection.lock().unwrap();
let last_error = cx.last_error.lock().unwrap();
if let Some(CxError::Protocol(ref e)) = *last_error {
Some(e.clone())
} else {
None
}
}
pub(crate) fn get_connection_fd(&self) -> ::std::os::unix::io::RawFd {
self.connection.lock().unwrap().socket.get_socket().as_raw_fd()
}
}
// WlDisplay needs its own dispatcher, as it can be dispatched from multiple threads
struct DisplayDispatcher {
map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
last_error: Arc<Mutex<Option<CxError>>>,
}
impl super::Dispatcher for DisplayDispatcher {
fn dispatch(
&mut self,
msg: Message,
proxy: ProxyInner,
map: &mut ProxyMap,
_data: crate::DispatchData,
) -> Dispatched {
if WAYLAND_DEBUG.load(Ordering::Relaxed) {
debug::print_dispatched_message(
proxy.object.interface,
proxy.id,
proxy.object.events[msg.opcode as usize].name,
&msg.args,
);
}
let event = match wl_display::Event::from_raw(msg, map) {
Ok(v) => v,
Err(()) => return Dispatched::BadMsg,
};
match event {
wl_display::Event::Error { object_id, code, message } => {
eprintln!(
"[wayland-client] Protocol error {} on object {}@{}: {}",
code,
object_id.as_ref().inner.object.interface,
object_id.as_ref().id(),
message
);
*self.last_error.lock().unwrap() = Some(CxError::Protocol(ProtocolError {
code,
object_id: object_id.as_ref().id(),
object_interface: object_id.as_ref().inner.object.interface,
message,
}));
}
wl_display::Event::DeleteId { id } => {
// cleanup the map as appropriate
let mut map = self.map.lock().unwrap();
let client_destroyed = map
.with(id, |obj| {
obj.meta.server_destroyed = true;
obj.meta.client_destroyed
})
.unwrap_or(false);
if client_destroyed {
map.remove(id);
}
}
}
Dispatched::Yes
}
}

View file

@ -0,0 +1,213 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use downcast::Downcast;
use wayland_commons::debug;
use wayland_commons::filter::Filter;
use wayland_commons::map::ObjectMap;
use wayland_commons::wire::Message;
use wayland_commons::{MessageGroup, ThreadGuard};
use crate::{Interface, Main, Proxy};
mod connection;
mod display;
mod proxy;
mod queues;
pub(crate) use self::display::DisplayInner;
pub(crate) use self::proxy::ProxyInner;
pub(crate) use self::queues::EventQueueInner;
/// Flag to toggle debug output.
static WAYLAND_DEBUG: AtomicBool = AtomicBool::new(false);
/// A handle to the object map internal to the library state.
///
/// This type is only used by code generated by `wayland-scanner`, and can not
/// be instantiated directly.
pub struct ProxyMap {
map: Arc<Mutex<ObjectMap<self::proxy::ObjectMeta>>>,
connection: Arc<Mutex<self::connection::Connection>>,
}
impl std::fmt::Debug for ProxyMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ProxyMap { ... }")
}
}
impl ProxyMap {
pub(crate) fn make(
map: Arc<Mutex<ObjectMap<self::proxy::ObjectMeta>>>,
connection: Arc<Mutex<self::connection::Connection>>,
) -> ProxyMap {
ProxyMap { map, connection }
}
/// Returns the Proxy corresponding to a given id
pub fn get<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
&mut self,
id: u32,
) -> Option<Proxy<I>> {
ProxyInner::from_id(id, self.map.clone(), self.connection.clone()).map(|object| {
debug_assert!(I::NAME == "<anonymous>" || object.is_interface::<I>());
Proxy::wrap(object)
})
}
/// Returns the Proxy corresponding to a given id, and create a dead one if none is found
pub fn get_or_dead<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
&mut self,
id: u32,
) -> Proxy<I> {
self.get(id).unwrap_or_else(|| {
Proxy::wrap(ProxyInner::dead::<I>(id, self.map.clone(), self.connection.clone()))
})
}
/// Creates a new proxy for given id
pub fn get_new<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
&mut self,
id: u32,
) -> Option<Main<I>> {
debug_assert!(self
.map
.lock()
.unwrap()
.find(id)
.map(|obj| obj.is_interface::<I>())
.unwrap_or(true));
ProxyInner::from_id(id, self.map.clone(), self.connection.clone()).map(Main::wrap)
}
}
/*
* Dispatching logic
*/
#[allow(clippy::large_enum_variant)]
pub(crate) enum Dispatched {
Yes,
NoDispatch(Message, ProxyInner),
BadMsg,
}
pub(crate) trait Dispatcher: Downcast + Send {
fn dispatch(
&mut self,
msg: Message,
proxy: ProxyInner,
map: &mut ProxyMap,
data: crate::DispatchData,
) -> Dispatched;
}
mod dispatcher_impl {
// this mod has the sole purpose of silencing these `dead_code` warnings...
#![allow(dead_code)]
use super::Dispatcher;
impl_downcast!(Dispatcher);
}
pub(crate) struct ImplDispatcher<
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>,
F: FnMut(I::Event, Main<I>, crate::DispatchData<'_>) + 'static,
> {
_i: ::std::marker::PhantomData<&'static I>,
implementation: F,
}
impl<I, F> Dispatcher for ImplDispatcher<I, F>
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
F: FnMut(I::Event, Main<I>, crate::DispatchData<'_>) + 'static + Send,
I::Event: MessageGroup<Map = ProxyMap>,
{
fn dispatch(
&mut self,
msg: Message,
proxy: ProxyInner,
map: &mut ProxyMap,
data: crate::DispatchData,
) -> Dispatched {
let opcode = msg.opcode as usize;
if WAYLAND_DEBUG.load(Ordering::Relaxed) {
debug::print_dispatched_message(
proxy.object.interface,
proxy.id,
proxy.object.events[opcode].name,
&msg.args,
);
}
let message = match I::Event::from_raw(msg, map) {
Ok(v) => v,
Err(()) => return Dispatched::BadMsg,
};
if message.since() > proxy.version() {
eprintln!(
"Received an event {} requiring version >= {} while proxy {}@{} is version {}.",
proxy.object.events[opcode].name,
message.since(),
proxy.object.interface,
proxy.id,
proxy.version()
);
return Dispatched::BadMsg;
}
if message.is_destructor() {
proxy.object.meta.alive.store(false, Ordering::Release);
{
// cleanup the map as appropriate
let mut map = proxy.map.lock().unwrap();
let server_destroyed = map
.with(proxy.id, |obj| {
obj.meta.client_destroyed = true;
obj.meta.server_destroyed
})
.unwrap_or(false);
if server_destroyed {
map.remove(proxy.id);
}
}
}
(self.implementation)(message, Main::<I>::wrap(proxy), data);
Dispatched::Yes
}
}
pub(crate) fn make_dispatcher<I, E>(filter: Filter<E>) -> Arc<Mutex<dyn Dispatcher + Send>>
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
E: From<(Main<I>, I::Event)> + 'static,
I::Event: MessageGroup<Map = ProxyMap>,
{
let guard = ThreadGuard::new(filter);
Arc::new(Mutex::new(ImplDispatcher {
_i: ::std::marker::PhantomData,
implementation: move |evt, proxy, data| guard.get().send((proxy, evt).into(), data),
}))
}
pub(crate) fn default_dispatcher() -> Arc<Mutex<dyn Dispatcher + Send>> {
struct DefaultDisp;
impl Dispatcher for DefaultDisp {
fn dispatch(
&mut self,
msg: Message,
proxy: ProxyInner,
_map: &mut ProxyMap,
_data: crate::DispatchData,
) -> Dispatched {
Dispatched::NoDispatch(msg, proxy)
}
}
Arc::new(Mutex::new(DefaultDisp))
}

View file

@ -0,0 +1,248 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use wayland_commons::debug;
use wayland_commons::filter::Filter;
use wayland_commons::map::{Object, ObjectMap, ObjectMetadata};
use wayland_commons::user_data::UserData;
use wayland_commons::wire::{Argument, ArgumentType};
use wayland_commons::MessageGroup;
use super::connection::Connection;
use super::queues::QueueBuffer;
use super::{Dispatcher, EventQueueInner, WAYLAND_DEBUG};
use crate::{Interface, Main, Proxy};
#[derive(Clone)]
pub(crate) struct ObjectMeta {
pub(crate) buffer: QueueBuffer,
pub(crate) alive: Arc<AtomicBool>,
user_data: Arc<UserData>,
pub(crate) dispatcher: Arc<Mutex<dyn Dispatcher>>,
pub(crate) server_destroyed: bool,
pub(crate) client_destroyed: bool,
}
impl ObjectMetadata for ObjectMeta {
fn child(&self) -> ObjectMeta {
ObjectMeta {
buffer: self.buffer.clone(),
alive: Arc::new(AtomicBool::new(true)),
user_data: Arc::new(UserData::new()),
dispatcher: super::default_dispatcher(),
server_destroyed: false,
client_destroyed: false,
}
}
}
impl ObjectMeta {
pub(crate) fn new(buffer: QueueBuffer) -> ObjectMeta {
ObjectMeta {
buffer,
alive: Arc::new(AtomicBool::new(true)),
user_data: Arc::new(UserData::new()),
dispatcher: super::default_dispatcher(),
server_destroyed: false,
client_destroyed: false,
}
}
fn dead() -> ObjectMeta {
ObjectMeta {
buffer: super::queues::create_queue_buffer(),
alive: Arc::new(AtomicBool::new(false)),
user_data: Arc::new(UserData::new()),
dispatcher: super::default_dispatcher(),
server_destroyed: true,
client_destroyed: true,
}
}
}
#[derive(Clone)]
pub(crate) struct ProxyInner {
pub(crate) map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
pub(crate) connection: Arc<Mutex<Connection>>,
pub(crate) object: Object<ObjectMeta>,
pub(crate) id: u32,
pub(crate) queue: Option<QueueBuffer>,
}
impl ProxyInner {
pub(crate) fn from_id(
id: u32,
map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
connection: Arc<Mutex<Connection>>,
) -> Option<ProxyInner> {
let me = map.lock().unwrap().find(id);
me.map(|obj| ProxyInner {
map,
connection,
id,
queue: Some(obj.meta.buffer.clone()),
object: obj,
})
}
pub(crate) fn dead<I: Interface>(
id: u32,
map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
connection: Arc<Mutex<Connection>>,
) -> ProxyInner {
ProxyInner {
map,
connection,
id,
queue: None,
object: Object::from_interface::<I>(1, ObjectMeta::dead()),
}
}
pub(crate) fn is_interface<I: Interface>(&self) -> bool {
self.object.is_interface::<I>()
}
pub(crate) fn is_alive(&self) -> bool {
self.object.meta.alive.load(Ordering::Acquire)
}
pub fn version(&self) -> u32 {
self.object.version
}
pub(crate) fn id(&self) -> u32 {
if self.is_alive() {
self.id
} else {
0
}
}
pub(crate) fn user_data(&self) -> &UserData {
&*self.object.meta.user_data
}
pub(crate) fn detach(&mut self) {
self.queue = None;
}
pub(crate) fn attach(&mut self, queue: &EventQueueInner) {
self.queue = Some(queue.buffer.clone())
}
pub(crate) fn send<I, J>(&self, msg: I::Request, version: Option<u32>) -> Option<ProxyInner>
where
I: Interface,
J: Interface,
{
// grab the connection lock before anything else
// this avoids the risk or races during object creation
let mut conn_lock = self.connection.lock().unwrap();
let destructor = msg.is_destructor();
let mut msg = msg.into_raw(self.id);
let opcode = msg.opcode;
// figure out if the call creates an object
let nid_idx = I::Request::MESSAGES[opcode as usize]
.signature
.iter()
.position(|&t| t == ArgumentType::NewId);
let alive = self.is_alive();
let ret = if let Some(mut nid_idx) = nid_idx {
let target_queue = self
.queue
.clone()
.expect("Attemping to create an object from a non-attached proxy.");
if let Some(o) = I::Request::child(opcode, 1, &()) {
if !o.is_interface::<J>() {
panic!(
"Trying to use 'send_constructor' with the wrong return type. \
Required interface {} but the message creates interface {}",
J::NAME,
o.interface
)
}
} else {
// There is no target interface in the protocol, this is a generic object-creating
// function (likely wl_registry.bind), the newid arg will thus expand to
// (str, u32, obj).
nid_idx += 2;
}
// insert the newly created object in the message
let new_object = Object::from_interface::<J>(
version.unwrap_or(self.object.version),
if alive { ObjectMeta::new(target_queue.clone()) } else { ObjectMeta::dead() },
);
let mut new_id = 0;
if alive {
new_id = self.map.lock().unwrap().client_insert_new(new_object.clone());
msg.args[nid_idx] = Argument::NewId(new_id);
}
Some(ProxyInner {
map: self.map.clone(),
connection: self.connection.clone(),
id: new_id,
object: new_object,
queue: Some(target_queue),
})
} else {
None
};
if WAYLAND_DEBUG.load(Ordering::Relaxed) {
debug::print_send_message(
I::NAME,
self.id,
alive,
self.object.requests[msg.opcode as usize].name,
&msg.args,
);
}
// Only actually send the message (& process destructor) if the object is alive.
if !alive {
return ret;
}
conn_lock.write_message(&msg).expect("Sending a message failed.");
if destructor {
self.object.meta.alive.store(false, Ordering::Release);
// Cleanup the map as appropriate.
let mut map = conn_lock.map.lock().unwrap();
let server_destroyed = map
.with(self.id, |obj| {
obj.meta.client_destroyed = true;
obj.meta.server_destroyed
})
.unwrap_or(false);
if server_destroyed {
map.remove(self.id);
}
}
ret
}
pub(crate) fn equals(&self, other: &ProxyInner) -> bool {
self.is_alive() && Arc::ptr_eq(&self.object.meta.alive, &other.object.meta.alive)
}
pub fn assign<I, E>(&self, filter: Filter<E>)
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
E: From<(Main<I>, I::Event)> + 'static,
I::Event: MessageGroup<Map = super::ProxyMap>,
{
// ignore failure if target object is dead
let _ = self.map.lock().unwrap().with(self.id, |obj| {
obj.meta.dispatcher = super::make_dispatcher(filter);
});
}
}

View file

@ -0,0 +1,300 @@
use std::cell::Cell;
use std::collections::VecDeque;
use std::io;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use nix::poll::{poll, PollFd, PollFlags};
use wayland_commons::map::ObjectMap;
use wayland_commons::wire::{Argument, Message};
use super::connection::{Connection, Error as CError};
use super::proxy::{ObjectMeta, ProxyInner};
use super::Dispatched;
use crate::{AnonymousObject, DispatchData, Filter, Main, RawEvent};
pub(crate) type QueueBuffer = Arc<Mutex<VecDeque<Message>>>;
pub(crate) fn create_queue_buffer() -> QueueBuffer {
Arc::new(Mutex::new(VecDeque::new()))
}
pub(crate) struct EventQueueInner {
pub(crate) connection: Arc<Mutex<Connection>>,
pub(crate) map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
pub(crate) buffer: QueueBuffer,
display_buffer: QueueBuffer,
}
impl EventQueueInner {
pub(crate) fn new(
connection: Arc<Mutex<Connection>>,
buffer: Option<QueueBuffer>,
) -> EventQueueInner {
let (map, display_buffer) = {
let cx = connection.lock().unwrap();
(cx.map.clone(), cx.display_buffer.clone())
};
EventQueueInner {
connection,
map,
buffer: buffer.unwrap_or_else(create_queue_buffer),
display_buffer,
}
}
pub(crate) fn dispatch<F>(&self, mut data: DispatchData, mut fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
// don't read events if there are some pending
if let Err(()) = self.prepare_read() {
return self.dispatch_pending(data.reborrow(), &mut fallback);
}
// temporarily retrieve the socket Fd, only using it for POLL-ing!
let socket_fd;
{
// Flush the outgoing socket
let mut conn_lock = self.connection.lock().unwrap();
socket_fd = conn_lock.socket.get_socket().as_raw_fd();
loop {
match conn_lock.flush() {
Ok(_) => break,
Err(nix::Error::EAGAIN) => {
// EAGAIN, we need to wait before writing, so we poll the socket
let poll_ret = poll(&mut [PollFd::new(socket_fd, PollFlags::POLLOUT)], -1);
match poll_ret {
Ok(_) => continue,
Err(e) => {
self.cancel_read();
return Err(e.into());
}
}
}
Err(e) => {
if e != nix::Error::EPIPE {
// don't abort on EPIPE, so we can continue reading
// to get the protocol error
self.cancel_read();
return Err(e.into());
}
}
}
}
}
// wait for incoming messages to arrive
match poll(&mut [PollFd::new(socket_fd, PollFlags::POLLIN)], -1) {
Ok(_) => (),
Err(e) => {
self.cancel_read();
return Err(e.into());
}
}
let read_ret = self.read_events();
// even if read_events returned an error, it may have queued messages the need dispatching
// so we dispatch them
let dispatch_ret = self.dispatch_pending(data.reborrow(), &mut fallback);
match read_ret {
Ok(()) => (),
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
// we waited for read readiness be then received a WouldBlock error
// this means that an other thread was also reading events and read them
// under our nose
// this is alright, continue
}
Err(e) => return Err(e),
}
dispatch_ret
}
fn dispatch_buffer<F>(
&self,
buffer: &Mutex<VecDeque<Message>>,
mut data: DispatchData,
mut fallback: F,
) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
let mut count = 0;
let mut proxymap = super::ProxyMap::make(self.map.clone(), self.connection.clone());
loop {
let msg = { buffer.lock().unwrap().pop_front() };
let msg = match msg {
Some(m) => m,
None => break,
};
let id = msg.sender_id;
if let Some(proxy) = ProxyInner::from_id(id, self.map.clone(), self.connection.clone())
{
let object = proxy.object.clone();
if object.meta.client_destroyed {
// This is a potential race, if we reach here it means that the proxy was
// destroyed by the user between this message was queued and now. To handle it
// correctly, we must close any FDs it contains, mark any child object as
// destroyed (but the server will never know about it, so the ids will be
// leaked) and discard the event.
for arg in msg.args {
match arg {
Argument::Fd(fd) => {
let _ = ::nix::unistd::close(fd);
}
Argument::NewId(id) => {
let mut map = self.map.lock().unwrap();
map.with(id, |obj| {
obj.meta.client_destroyed = true;
})
.unwrap();
}
_ => {}
}
}
continue;
}
let mut dispatcher = object.meta.dispatcher.lock().unwrap();
match dispatcher.dispatch(msg, proxy, &mut proxymap, data.reborrow()) {
Dispatched::Yes => {
count += 1;
}
Dispatched::NoDispatch(msg, proxy) => {
let raw_event = message_to_rawevent(msg, &proxy, &mut proxymap);
fallback(raw_event, Main::wrap(proxy), data.reborrow());
count += 1;
}
Dispatched::BadMsg => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Dispatch for object {}@{} errored.", object.interface, id),
))
}
}
} else {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Received an event for unknown object {}.", id),
));
}
}
Ok(count)
}
pub(crate) fn dispatch_pending<F>(&self, mut data: DispatchData, fallback: F) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
// First always dispatch the display buffer
let display_dispatched =
self.dispatch_buffer(&self.display_buffer, data.reborrow(), |_, _, _| unreachable!())?;
// Then our actual buffer
let self_dispatched = self.dispatch_buffer(&self.buffer, data.reborrow(), fallback)?;
Ok(display_dispatched + self_dispatched)
}
pub(crate) fn sync_roundtrip<F>(
&self,
mut data: DispatchData,
mut fallback: F,
) -> io::Result<u32>
where
F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
{
use crate::protocol::wl_callback::{Event as CbEvent, WlCallback};
use crate::protocol::wl_display::{Request as DRequest, WlDisplay};
// first retrieve the display and make a wrapper for it in this event queue
let mut display =
ProxyInner::from_id(1, self.map.clone(), self.connection.clone()).unwrap();
display.attach(self);
let done = Rc::new(Cell::new(false));
let cb = display.send::<WlDisplay, WlCallback>(DRequest::Sync {}, Some(1)).unwrap();
let done2 = done.clone();
cb.assign::<WlCallback, _>(Filter::new(move |(_, CbEvent::Done { .. }), _, _| {
done2.set(true);
}));
let mut dispatched = 0;
loop {
dispatched += self.dispatch(data.reborrow(), &mut fallback)?;
if done.get() {
return Ok(dispatched);
}
}
}
pub(crate) fn prepare_read(&self) -> Result<(), ()> {
if !self.buffer.lock().unwrap().is_empty() {
return Err(());
}
// TODO: un-mock
Ok(())
}
pub(crate) fn read_events(&self) -> io::Result<()> {
// TODO: integrate more properly with prepare read with a fence
match self.connection.lock().unwrap().read_events() {
Ok(_) => Ok(()),
Err(CError::Protocol(e)) => {
eprintln!("[wayland-client] Protocol error while reading events: {}", e);
Err(::nix::errno::Errno::EPROTO.into())
}
Err(CError::Parse(e)) => {
eprintln!("[wayland-client] Parse error while reading events: {}", e);
Err(::nix::errno::Errno::EPROTO.into())
}
Err(CError::Nix(errno)) => Err(errno.into()),
}
}
pub(crate) fn cancel_read(&self) {
// TODO: un-mock
}
}
fn message_to_rawevent(msg: Message, proxy: &ProxyInner, map: &mut super::ProxyMap) -> RawEvent {
let Message { opcode, args, .. } = msg;
let args = args
.into_iter()
.map(|a| match a {
Argument::Int(i) => crate::Argument::Int(i),
Argument::Uint(u) => crate::Argument::Uint(u),
Argument::Array(v) => {
crate::Argument::Array(if v.is_empty() { None } else { Some(*v) })
}
Argument::Fixed(f) => crate::Argument::Float((f as f32) / 256.),
Argument::Fd(f) => crate::Argument::Fd(f),
Argument::Str(cs) => crate::Argument::Str({
let bytes = cs.into_bytes();
if bytes.is_empty() {
None
} else {
Some(
String::from_utf8(bytes)
.unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into()),
)
}
}),
Argument::Object(id) => crate::Argument::Object(map.get(id)),
Argument::NewId(id) => crate::Argument::NewId(map.get_new(id)),
})
.collect();
RawEvent {
interface: proxy.object.interface,
opcode,
name: proxy.object.events[opcode as usize].name,
args,
}
}