Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ pub struct WaylandSource<D> {
queue: EventQueue<D>,
connection_source: Generic<Connection>,
read_guard: Option<ReadEventsGuard>,
/// Number of messages read from the socket in before_handle_events. We use
/// this to skip dipatching events in cases where the socket becomes
/// readable but no messages are available.
messages_read: usize,
/// Calloop's before_will_sleep method allows
/// skipping the sleeping by returning a `Token`.
/// We cannot produce this on the fly, so store it here instead
Expand All @@ -86,6 +90,7 @@ impl<D> WaylandSource<D> {
queue,
connection_source,
read_guard: None,
messages_read: 0,
fake_token: None,
stored_error: Ok(()),
}
Expand Down Expand Up @@ -150,8 +155,14 @@ impl<D> EventSource for WaylandSource<D> {
// no-op, so we just handle the event ourselves.

let queue = &mut self.queue;
// Dispatch any pending events in the queue
Self::loop_callback_pending(queue, &mut callback)?;

// Only dispatch if we actually read messages from the socket. Sometimes the
// socket becomes readable but there are no messages to read. In such
// case, read() returns Ok(0) and we can skip the dispatch entirely.
if self.messages_read > 0 {
// Dispatch any pending events in the queue
Self::loop_callback_pending(queue, &mut callback)?;
}

// Once dispatching is finished, flush the responses to the compositor
flush_queue(queue)?;
Expand Down Expand Up @@ -203,17 +214,31 @@ impl<D> EventSource for WaylandSource<D> {
// socket For example, creating a Vulkan surface needs access to the
// connection
let guard = self.read_guard.take();
self.messages_read = 0;

if events.count() > 0 {
// Read events from the socket if any are available
if let Some(Err(WaylandError::Io(err))) = guard.map(ReadEventsGuard::read) {
// If some other thread read events before us, concurrently, that's an expected
// case, so this error isn't an issue. Other error kinds do need to be returned,
// however
if err.kind() != io::ErrorKind::WouldBlock {
match guard.map(ReadEventsGuard::read) {
Some(Ok(n)) => {
self.messages_read = n;
},
Some(Err(WaylandError::Io(err))) => {
// If some other thread read events before us, concurrently, that's an expected
// case, so this error isn't an issue. Other error kinds do need to be returned,
// however
if err.kind() != io::ErrorKind::WouldBlock {
// before_handle_events doesn't allow returning errors
// For now, cache it in self until process_events is called
self.stored_error = Err(err);
}
},
Some(Err(WaylandError::Protocol(err))) => {
log_error!("Protocol error received on display: {}", err);
// before_handle_events doesn't allow returning errors
// For now, cache it in self until process_events is called
self.stored_error = Err(err);
}
Comment on lines -208 to -216
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that this if let is not exhaustive. I can split this into a separate commit if you prefer. Or we can discard it completely if it does not make sense

self.stored_error = Err(Errno::PROTO.into());
},
None => {},
}
}
}
Expand Down