use calloop::{
generic::{Fd, Generic},
Dispatcher, EventSource, Interest, Mode,
};
use std::{cell::RefCell, io, rc::Rc};
use wayland_client::EventQueue;
use super::{application, window};
pub(crate) struct WaylandSource {
appdata: std::sync::Arc<application::Data>,
queue: Rc<RefCell<EventQueue>>,
fd: Generic<Fd>,
}
impl WaylandSource {
pub fn new(appdata: std::sync::Arc<application::Data>) -> WaylandSource {
let queue = appdata.wayland.queue.clone();
let fd = queue.borrow().display().get_connection_fd();
WaylandSource {
appdata,
queue,
fd: Generic::from_fd(fd, Interest::READ, Mode::Level),
}
}
pub fn into_dispatcher(
self,
) -> Dispatcher<
Self,
impl FnMut(
window::WindowHandle,
&mut Rc<RefCell<EventQueue>>,
&mut std::sync::Arc<application::Data>,
) -> io::Result<u32>,
> {
Dispatcher::new(self, |_winhandle, queue, appdata| {
queue
.borrow_mut()
.dispatch_pending(appdata, |event, object, _| {
tracing::error!(
"[druid-shell] Encountered an orphan event: {}@{} : {}",
event.interface,
object.as_ref().id(),
event.name
);
tracing::error!("all events should be handled: please raise an issue");
})
})
}
}
impl EventSource for WaylandSource {
type Event = window::WindowHandle;
type Metadata = Rc<RefCell<EventQueue>>;
type Ret = io::Result<u32>;
fn process_events<F>(
&mut self,
ready: calloop::Readiness,
token: calloop::Token,
mut callback: F,
) -> std::io::Result<()>
where
F: FnMut(window::WindowHandle, &mut Rc<RefCell<EventQueue>>) -> Self::Ret,
{
tracing::trace!("processing events invoked {:?} {:?}", ready, token);
self.appdata.display_flushed.replace(false);
let winhandle = match self.appdata.acquire_current_window() {
Some(winhandle) => winhandle,
None => {
tracing::error!("unable to acquire current window");
return Ok(());
}
};
loop {
if let Some(guard) = self.queue.borrow().prepare_read() {
if let Err(e) = guard.read_events() {
if e.kind() != io::ErrorKind::WouldBlock {
return Err(e);
}
}
}
tracing::trace!("processing events initiated");
let ret = callback(winhandle.clone(), &mut self.queue);
tracing::trace!("processing events completed {:?}", ret);
match ret {
Ok(0) => {
break;
}
Ok(_) => {}
Err(e) => {
return Err(e);
}
}
}
tracing::trace!("dispatching completed, flushing");
if let Err(e) = self.queue.borrow().display().flush() {
if e.kind() != io::ErrorKind::WouldBlock {
return Err(e);
}
tracing::warn!("unable to flush display: {:?}", e);
} else {
self.appdata.display_flushed.replace(true);
}
tracing::trace!("event queue completed");
Ok(())
}
fn register(&mut self, poll: &mut calloop::Poll, token: calloop::Token) -> std::io::Result<()> {
self.fd.register(poll, token)
}
fn reregister(
&mut self,
poll: &mut calloop::Poll,
token: calloop::Token,
) -> std::io::Result<()> {
self.fd.reregister(poll, token)
}
fn unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()> {
self.fd.unregister(poll)
}
}