Skip to content

Commit

Permalink
client: API docs
Browse files Browse the repository at this point in the history
  • Loading branch information
elinorbgr committed Apr 4, 2018
1 parent acb0643 commit b091117
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 3 deletions.
49 changes: 49 additions & 0 deletions wayland-client/src/display.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(feature = "native_lib")]
use std::ffi::{CString, OsString};
use std::io;
#[cfg(feature = "native_lib")]
use std::os::unix::ffi::OsStringExt;
use std::sync::Arc;
Expand All @@ -22,6 +23,7 @@ pub enum ConnectError {
///
/// Most of the time, this means that the program was not started from a wayland session.
NoCompositorListening,
/// The provided socket name is invalid
InvalidName,
}

Expand Down Expand Up @@ -55,6 +57,13 @@ impl Drop for DisplayInner {
}
}

/// A connection to a wayland server
///
/// This object both represent the connection to the server, and as such
/// must be kept alive as long as you are connected, and contains the
/// primary `WlDisplay` wayland object, from which you can create all
/// your need objects. The inner `Proxy<WlDisplay>` can be accessed via
/// `Deref`.
pub struct Display {
inner: Arc<DisplayInner>,
}
Expand All @@ -77,6 +86,15 @@ impl Display {
Ok((display, evq))
}

/// Attempt to connect to a wayland server using the contents of the environment variables
///
/// If the `WAYLAND_DISPLAY` variable is set, it will try to connect to the socket it points
/// to. Otherwise, it will default to `wayland-0`.
///
/// 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_env() -> Result<(Display, EventQueue), ConnectError> {
#[cfg(not(feature = "native_lib"))]
{
Expand All @@ -96,6 +114,12 @@ impl Display {
}
}

/// 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, EventQueue), ConnectError> {
#[cfg(not(feature = "native_lib"))]
{
Expand All @@ -117,6 +141,31 @@ impl Display {
}
}

/// 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 coul be written, will return an io error `WouldBlock`.
///
/// On success returns the number of written requests.
pub fn flush(&self) -> io::Result<i32> {
let ret = unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_flush,
self.inner.ptr()
)
};
if ret >= 0 {
Ok(ret)
} else {
Err(io::Error::last_os_error())
}
}

/// Create a new event queue associated with this wayland connection
pub fn create_event_queue(&self) -> EventQueue {
#[cfg(not(feature = "native_lib"))]
{
Expand Down
37 changes: 37 additions & 0 deletions wayland-client/src/event_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,45 @@ struct EventQueueInner {
inner: Arc<DisplayInner>,
}

/// An event queue for protocol messages
///
/// Event dispatching in wayland is made on a queue basis, allowing you
/// to organise your objects into different queues that can be dispatched
/// independently, for example from different threads.
///
/// And `EventQueue` is not `Send`, and thus must stay on the thread on which
/// they were created. However the `Display` object is `Send + Sync`, allowing
/// you to create the queues directly in the threads that host them.
///
/// When a queue is dispatched (via the `dispatch()` or `dispatch_pending()` methods)
/// all the incoming messages from the server destinated 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.
///
/// Thus, a typical single-queue event loop for a simple wayland app can be:
///
/// ```no_run
/// # extern crate wayland_client;
/// # use wayland_client::{Display};
/// # fn main() {
/// # let (display, mut event_queue) = Display::connect_to_env().unwrap();
/// loop {
/// display.flush().unwrap();
/// event_queue.dispatch().expect("An error occured during event dispatching!");
/// }
/// # }
/// ```
pub struct EventQueue {
// EventQueue is *not* Send
inner: Rc<EventQueueInner>,
}

/// 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::make_wrapper` and `NewProxy::implement_nonsend`.
pub struct QueueToken {
inner: Rc<EventQueueInner>,
}
Expand Down Expand Up @@ -148,6 +182,9 @@ impl EventQueue {
}
}

/// Create a new token associated with this event queue
///
/// See `QueueToken` documentation for its use.
pub fn get_token(&self) -> QueueToken {
QueueToken {
inner: self.inner.clone(),
Expand Down
22 changes: 20 additions & 2 deletions wayland-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![warn(missing_docs)]

#[macro_use]
extern crate bitflags;
extern crate libc;
Expand All @@ -14,12 +16,28 @@ mod proxy;
pub use proxy::{NewProxy, Proxy};
pub use display::Display;
pub use event_queue::{EventQueue, QueueToken};
#[cfg(feature = "native_lib")]
pub use generated::c_api as protocol;

/// Re-export of wayland-commons
///
/// Common traits and functions to work with wayland objects
pub mod commons {
pub use wayland_commons::*;
}

#[cfg(feature = "native_lib")]
/// C-associated types
///
/// Required for plugging wayland-server generated protocols
/// or interfacing with C code using wayland objects.
pub mod sys {
pub use super::generated::c_interfaces as protocol_interfaces;
pub use wayland_sys::{common,client};
}

/// Generated interfaces for the core wayland protocol
pub mod protocol {
#[cfg(feature = "native_lib")]
pub use generated::c_api::*;
}

mod generated {
Expand Down
114 changes: 113 additions & 1 deletion wayland-client/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ impl ProxyInternal {
}
}

/// An handle to a wayland proxy
///
/// This represents a wayland object instanciated 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
/// you need to import the associated `RequestsTrait` trait from the module
/// of this interface.
pub struct Proxy<I: Interface> {
_i: ::std::marker::PhantomData<*const I>,
#[cfg(not(feature = "native_lib"))] internal: Arc<ProxyInternal>,
Expand All @@ -34,6 +46,16 @@ unsafe impl<I: Interface> Send for Proxy<I> {}
unsafe impl<I: Interface> Sync for Proxy<I> {}

impl<I: Interface> Proxy<I> {
/// Send a request through this object
///
/// This is the generic method to send requests.
///
/// Several requests require the creation of new objects using
/// the `child()` method, which if done wrong can cause protocol
/// errors (in which case the server will terminate your connexion).
/// Thus unless your know exactly what you are doing, you should use
/// the helper methods provided by the various `RequestsTrait` for
/// each interface, which handle this correctly for you.
pub fn send(&self, msg: I::Requests) {
#[cfg(not(feature = "native_lib"))]
{
Expand Down Expand Up @@ -64,7 +86,12 @@ impl<I: Interface> Proxy<I> {
}
}

// returns false is external
/// Check if the object associated with this proxy is still alive
///
/// Will return `false` if either:
///
/// - The object has been destroyed
/// - The object is not managed by this library (see the `from_c_ptr` method)
pub fn is_alive(&self) -> bool {
#[cfg(not(feature = "native_lib"))]
{
Expand All @@ -79,6 +106,15 @@ impl<I: Interface> Proxy<I> {
}
}

/// Associate an arbitrary payload to this object
///
/// The pointer you associate here can be retrieved from any
/// other proxy to the same wayland object.
///
/// Setting or getting user data is done as an atomic operation.
/// You are responsible for the correct initialization of this
/// pointer, synchronisation of access, and destruction of the
/// contents at the appropriate time.
pub fn set_user_data(&self, ptr: *mut ()) {
#[cfg(not(feature = "native_lib"))]
{
Expand All @@ -92,6 +128,9 @@ impl<I: Interface> Proxy<I> {
}
}

/// Retrieve the arbitrary payload associated to this object
///
/// See `set_user_data` for explanations.
pub fn get_user_data(&self) -> *mut () {
#[cfg(not(feature = "native_lib"))]
{
Expand All @@ -108,10 +147,17 @@ impl<I: Interface> Proxy<I> {
}

#[cfg(feature = "native_lib")]
/// Check whether this proxy is managed by the library or not
///
/// See `from_c_ptr` for details.
pub fn is_external(&self) -> bool {
self.internal.is_none()
}

/// Clone this proxy
///
/// It only creates a new handle to the same wayland
/// object, and does not create a new one.
pub fn clone(&self) -> Proxy<I> {
Proxy {
_i: ::std::marker::PhantomData,
Expand All @@ -124,11 +170,32 @@ impl<I: Interface> Proxy<I> {
}

#[cfg(feature = "native_lib")]
/// 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).
pub fn c_ptr(&self) -> *mut wl_proxy {
self.ptr
}

#[cfg(feature = "native_lib")]
/// 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 `false` 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 pointer to this object.
pub unsafe fn from_c_ptr(ptr: *mut wl_proxy) -> Self {
use wayland_sys::client::*;

Expand Down Expand Up @@ -163,6 +230,16 @@ impl<I: Interface> Proxy<I> {
}

#[cfg(feature = "native_lib")]
/// Create a wrapper for this object for queue management
///
/// As assigning a proxy to an event queue can be a racy operation
/// in contextes involving multiple thread, this provides a facility
/// to do this safely.
///
/// The wrapper object created behaves like a regular `Proxy`, except that
/// all objects created as the result of its requests will be assigned to
/// the queue associated to the provided token, rather than the queue of
/// their parent. This does not change the queue of the proxy itself.
pub fn make_wrapper(&self, queue: &QueueToken) -> Result<Proxy<I>, ()> {
if !self.is_external() && !self.is_alive() {
return Err(());
Expand All @@ -182,6 +259,16 @@ impl<I: Interface> Proxy<I> {
})
}

/// Create a new child object
///
/// This creates a new wayland object, considered as a
/// child of this object. It will notably inherit its interface
/// version.
///
/// The created object should immediatly be implemented and sent
/// in a request to the server, to keep the object list properly
/// synchronized. Failure to do so will likely cause a protocol
/// error.
pub fn child<C: Interface>(&self) -> NewProxy<C> {
#[cfg(not(feature = "native_lib"))]
{
Expand Down Expand Up @@ -230,6 +317,17 @@ impl<I: Interface> Drop for Proxy<I> {
}
}

/// A newly-created proxy that needs implementation
///
/// Whenever a new wayland object is created, you will
/// receive it as a `NewProxy`. You then have to provide an
/// implementation for it, in order to process the incoming
/// events it may receive. Once this done you will be able
/// to use it as a regular `Proxy`.
///
/// Implementations are structs implementing the appropriate
/// variant of the `Implementation` trait. They can also be
/// closures.
pub struct NewProxy<I: Interface> {
_i: ::std::marker::PhantomData<*const I>,
#[cfg(feature = "native_lib")] ptr: *mut wl_proxy,
Expand Down Expand Up @@ -304,11 +402,25 @@ impl<I: Interface + 'static> NewProxy<I> {
}

#[cfg(feature = "native_lib")]
/// 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).
///
/// Use this if you need to pass an unimplemented object to the C library
/// you are interfacing with.
pub fn c_ptr(&self) -> *mut wl_proxy {
self.ptr
}

#[cfg(feature = "native_lib")]
/// Create a `NewProxy` instance from a C pointer.
///
/// By doing so, you assert that this wayland object was newly created and
/// can be safely implemented. As implementing it will overwrite any previously
/// associated data or implementation, this can cause weird errors akin to
/// memory corruption if it was not the case.
pub unsafe fn from_c_ptr(ptr: *mut wl_proxy) -> Self {
NewProxy {
_i: ::std::marker::PhantomData,
Expand Down

0 comments on commit b091117

Please sign in to comment.