use std::io;
use calloop::{
generic::{Fd, Generic},
EventSource, InsertError, Interest, LoopHandle, Mode, PostAction, RegistrationToken,
TokenFactory,
};
use wayland_client::{EventQueue, ReadEventsGuard};
#[derive(Debug)]
pub struct WaylandSource {
queue: EventQueue,
fd: Generic<Fd>,
read_guard: Option<ReadEventsGuard>,
}
impl WaylandSource {
pub fn new(queue: EventQueue) -> WaylandSource {
let fd = queue.display().get_connection_fd();
WaylandSource {
queue,
fd: Generic::from_fd(fd, Interest::READ, Mode::Level),
read_guard: None,
}
}
pub fn quick_insert<Data: 'static>(
self,
handle: LoopHandle<Data>,
) -> Result<RegistrationToken, InsertError<WaylandSource>> {
handle.insert_source(self, |(), queue, ddata| {
queue.dispatch_pending(ddata, |event, object, _| {
panic!(
"[calloop] Encountered an orphan event: {}@{} : {}",
event.interface,
object.as_ref().id(),
event.name
);
})
})
}
pub fn queue(&mut self) -> &mut EventQueue {
&mut self.queue
}
}
impl EventSource for WaylandSource {
type Event = ();
type Metadata = EventQueue;
type Ret = std::io::Result<u32>;
fn process_events<F>(
&mut self,
readiness: calloop::Readiness,
token: calloop::Token,
mut callback: F,
) -> std::io::Result<PostAction>
where
F: FnMut((), &mut EventQueue) -> std::io::Result<u32>,
{
let queue = &mut self.queue;
let read_guard = &mut self.read_guard;
self.fd.process_events(readiness, token, |_, _| {
if let Some(guard) = read_guard.take() {
if let Err(e) = guard.read_events() {
if e.kind() != io::ErrorKind::WouldBlock {
return Err(e);
}
}
}
loop {
match queue.prepare_read() {
Some(guard) => {
*read_guard = Some(guard);
break;
}
None => {
callback((), queue)?;
}
}
}
if let Err(e) = queue.display().flush() {
if e.kind() != io::ErrorKind::WouldBlock {
return Err(e);
}
}
Ok(PostAction::Continue)
})
}
fn register(
&mut self,
poll: &mut calloop::Poll,
token_factory: &mut TokenFactory,
) -> std::io::Result<()> {
self.fd.register(poll, token_factory)
}
fn reregister(
&mut self,
poll: &mut calloop::Poll,
token_factory: &mut TokenFactory,
) -> std::io::Result<()> {
self.fd.reregister(poll, token_factory)
}
fn unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()> {
self.fd.unregister(poll)
}
fn pre_run<F>(&mut self, mut callback: F) -> std::io::Result<()>
where
F: FnMut((), &mut EventQueue) -> std::io::Result<u32>,
{
debug_assert!(self.read_guard.is_none());
if let Err(e) = self.queue.display().flush() {
if e.kind() != io::ErrorKind::WouldBlock {
log::error!("Error trying to flush the wayland display: {}", e);
return Err(e);
}
}
loop {
match self.queue.prepare_read() {
Some(guard) => {
self.read_guard = Some(guard);
break;
}
None => {
callback((), &mut self.queue)?;
}
}
}
Ok(())
}
fn post_run<F>(&mut self, _: F) -> std::io::Result<()>
where
F: FnMut((), &mut EventQueue) -> std::io::Result<u32>,
{
self.read_guard = None;
Ok(())
}
}