pub struct EventQueue<State> { /* private fields */ }
Expand description

An event queue

This is an abstraction for handling event dispatching, that allows you to ensure access to some common state &mut State to your event handlers.

Event queues are created through Connection::new_event_queue().

Upon creation, a wayland object is assigned to an event queue by passing the associated QueueHandle as argument to the method creating it. All events received by that object will be processed by that event queue, when dispatch_pending() or blocking_dispatch() is invoked.

Usage

Single queue app

If your app is simple enough that the only source of event to process is the Wayland socket and you only need a single event queue, your main loop can be as simple as this:

use wayland_client::Connection;

let connection = Connection::connect_to_env().unwrap();
let mut event_queue = connection.new_event_queue();

/*
 * Here your initial setup
 */

// And the main loop:
while !state.exit {
    event_queue.blocking_dispatch(&mut state).unwrap();
}

The blocking_dispatch() will wait (by putting the thread to sleep) until there are some events from the server that can be processed, and all your actual app logic can be done in the callbacks of the Dispatch implementations, and in the main loop after the blocking_dispatch() call.

Multi-thread multi-queue app

In a case where you app is multithreaded and you want to process events in multiple thread, a simple pattern is to have one EventQueue per thread processing Wayland events.

With this pattern, each thread can use EventQueue::blocking_dispatch()(EventQueue::blocking_dispatch on its own event loop, and everything will “Just Work”.

Single-queue guest library

If your code is some library code that will act on a Wayland connection shared by the main program, it is likely you should not trigger socket reads yourself and instead let the main app take care of it. In this case, to ensure your EventQueue still makes progress, you should regularly invoke EventQueue::dispatch_pending() which will process the events that were enqueued in the inner buffer of your EventQueue by the main app reading the socket.

Integrating the event queue with other sources of events

If your program needs to monitor other sources of events alongside the Wayland socket using a monitoring system like epoll, you can integrate the Wayland socket into this system. This is done with the help of the EventQueue::prepare_read() method. You event loop will be a bit more explicit:


loop {
    // flush the outgoing buffers to ensure that the server does receive the messages
    // you've sent
    event_queue.flush().unwrap();

    // (this step is only relevant if other threads might be reading the socket as well)
    // make sure you don't have any pending events if the event queue that might have been
    // enqueued by other threads reading the socket
    event_queue.dispatch_pending(&mut state).unwrap();

    // This puts in place some internal synchronization to prepare for the fact that
    // you're going to wait for events on the socket and read them, in case other threads
    // are doing the same thing
    let read_guard = event_queue.prepare_read().unwrap();

    /*
     * At this point you can invoke epoll(..) to wait for readiness on the multiple FD you
     * are working with, and read_guard.connection_fd() will give you the FD to wait on for
     * the Wayland connection
     */

    if wayland_socket_ready {
        // If epoll notified readiness of the Wayland socket, you can now proceed to the read
        read_guard.read().unwrap();
        // And now, you must invoke dispatch_pending() to actually process the events
        event_queue.dispatch_pending(&mut state).unwrap();
    } else {
        // otherwise, some of your other FD are ready, but you didn't receive Wayland events,
        // you can drop the guard to cancel the read preparation
        std::mem::drop(read_guard);
    }

    /*
     * There you process all relevant events from your other event sources
     */
}

Implementations§

source§

impl<State> EventQueue<State>

source

pub fn handle(&self) -> QueueHandle<State>

Get a QueueHandle for this event queue

source

pub fn dispatch_pending( &mut self, data: &mut State ) -> Result<usize, DispatchError>

Dispatch pending events

Events are accumulated in the event queue internal buffer when the Wayland socket is read using the read APIs on Connection, or when reading is done from an other thread. This method will dispatch all such pending events by sequentially invoking their associated handlers: the Dispatch implementations on the provided &mut D.

Note: this may block if another thread has frozen the queue.

source

pub fn blocking_dispatch( &mut self, data: &mut State ) -> Result<usize, DispatchError>

Block waiting for events and dispatch them

This method is similar to dispatch_pending, but if there are no pending events it will also flush the connection and block waiting for the Wayland server to send an event.

A simple app event loop can consist of invoking this method in a loop.

source

pub fn roundtrip(&mut self, data: &mut State) -> Result<usize, DispatchError>

Synchronous roundtrip

This function will cause a synchronous round trip with the wayland server. This function will block until all requests in the queue are sent and processed by the server.

This function may be useful during initial setup of your app. This function may also be useful where you need to guarantee all requests prior to calling this function are completed.

source

pub fn prepare_read(&self) -> Result<ReadEventsGuard, WaylandError>

Start a synchronized read from the socket

This is needed if you plan to wait on readiness of the Wayland socket using an event loop. See the EventQueue and ReadEventsGuard docs for details. Once the events are received, you’ll then need to dispatch them from the event queue using EventQueue::dispatch_pending().

If you don’t need to manage multiple event sources, see blocking_dispatch() for a simpler mechanism.

This method is identical to Connection::prepare_read().

source

pub fn flush(&self) -> Result<(), WaylandError>

Flush pending outgoing events to the server

This needs to be done regularly to ensure the server receives all your requests. /// This method is identical to Connection::flush().

source

pub fn poll_dispatch_pending( &mut self, cx: &mut Context<'_>, data: &mut State ) -> Poll<Result<Infallible, DispatchError>>

Attempt to dispatch events from this queue, registering the current task for wakeup if no events are pending.

This method is similar to dispatch_pending; it will not perform reads on the Wayland socket. Reads on the socket by other tasks or threads will cause the current task to wake up if events are pending on this queue.

use futures_channel::mpsc::Receiver;
use futures_util::future::{poll_fn,select};
use futures_util::stream::StreamExt;
use wayland_client::EventQueue;

struct Data;

enum AppEvent {
    SomethingHappened(u32),
}

impl Data {
    fn handle(&mut self, event: AppEvent) {
        // actual event handling goes here
    }
}

// An async task that is spawned on an executor in order to handle events that need access
// to a specific data object.
async fn run(data: &mut Data, mut wl_queue: EventQueue<Data>, mut app_queue: Receiver<AppEvent>)
    -> Result<(), Box<dyn std::error::Error>>
{
    use futures_util::future::Either;
    loop {
        match select(
            poll_fn(|cx| wl_queue.poll_dispatch_pending(cx, data)),
            app_queue.next(),
        ).await {
            Either::Left((res, _)) => match res? {},
            Either::Right((Some(event), _)) => {
                data.handle(event);
            }
            Either::Right((None, _)) => return Ok(()),
        }
    }
}

Trait Implementations§

source§

impl<State> Debug for EventQueue<State>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<State> RefUnwindSafe for EventQueue<State>

§

impl<State> Send for EventQueue<State>

§

impl<State> Sync for EventQueue<State>

§

impl<State> Unpin for EventQueue<State>

§

impl<State> UnwindSafe for EventQueue<State>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast for Twhere T: Any,

§

fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for Twhere T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync + 'static>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.