Struct wayland_client::event_queue::EventQueue
source · pub struct EventQueue<State> {
handle: QueueHandle<State>,
conn: Connection,
}
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()
call 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()
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
*/
}
Fields§
§handle: QueueHandle<State>
§conn: Connection
Implementations§
source§impl<State> EventQueue<State>
impl<State> EventQueue<State>
pub(crate) fn new(conn: Connection) -> Self
sourcepub fn handle(&self) -> QueueHandle<State>
pub fn handle(&self) -> QueueHandle<State>
Get a QueueHandle
for this event queue
sourcepub fn dispatch_pending(
&mut self,
data: &mut State,
) -> Result<usize, DispatchError>
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.
sourcepub fn blocking_dispatch(
&mut self,
data: &mut State,
) -> Result<usize, DispatchError>
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.
sourcepub fn roundtrip(&mut self, data: &mut State) -> Result<usize, DispatchError>
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.
sourcepub fn prepare_read(&self) -> Option<ReadEventsGuard>
pub fn prepare_read(&self) -> Option<ReadEventsGuard>
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 this method returns None
, you should invoke ’dispatch_pending()`
before trying to invoke it again.
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()
.
sourcepub fn flush(&self) -> Result<(), WaylandError>
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()
.
fn dispatching_impl( backend: &Connection, qhandle: &QueueHandle<State>, data: &mut State, ) -> Result<usize, DispatchError>
fn try_next(inner: &Mutex<EventQueueInner<State>>) -> Option<QueueEvent<State>>
sourcepub fn poll_dispatch_pending(
&mut self,
cx: &mut Context<'_>,
data: &mut State,
) -> Poll<Result<Infallible, DispatchError>>
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> AsFd for EventQueue<State>
impl<State> AsFd for EventQueue<State>
source§fn as_fd(&self) -> BorrowedFd<'_>
fn as_fd(&self) -> BorrowedFd<'_>
Provides fd from Backend::poll_fd
for polling.
Auto Trait Implementations§
impl<State> Freeze for EventQueue<State>
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.