listener: make it all async

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-04-17 02:18:19 +04:00
parent 697fb50c0f
commit c77fbad908
3 changed files with 127 additions and 114 deletions

View File

@ -5,7 +5,7 @@ use std::{os::unix::io::AsRawFd, thread};
use zbus::{dbus_proxy, export::zvariant::Fd}; use zbus::{dbus_proxy, export::zvariant::Fd};
use crate::Result; use crate::Result;
use crate::{ConsoleEvent, ConsoleListener, KeyboardProxy, MouseProxy}; use crate::{ConsoleEvent, ConsoleListener, AsyncKeyboardProxy, AsyncMouseProxy};
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")] #[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")]
pub trait Console { pub trait Console {
@ -44,19 +44,19 @@ pub trait Console {
#[derivative(Debug)] #[derivative(Debug)]
pub struct Console { pub struct Console {
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
pub proxy: ConsoleProxy<'static>, pub proxy: AsyncConsoleProxy<'static>,
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
pub keyboard: KeyboardProxy<'static>, pub keyboard: AsyncKeyboardProxy<'static>,
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
pub mouse: MouseProxy<'static>, pub mouse: AsyncMouseProxy<'static>,
} }
impl Console { impl Console {
pub fn new(conn: &zbus::Connection, idx: u32) -> Result<Self> { pub async fn new(conn: &zbus::azync::Connection, idx: u32) -> Result<Self> {
let obj_path = format!("/org/qemu/Display1/Console_{}", idx); let obj_path = format!("/org/qemu/Display1/Console_{}", idx);
let proxy = ConsoleProxy::new_for_owned_path(conn.clone(), obj_path.clone())?; let proxy = AsyncConsoleProxy::new_for_owned_path(conn.clone(), obj_path.clone())?;
let keyboard = KeyboardProxy::new_for_owned_path(conn.clone(), obj_path.clone())?; let keyboard = AsyncKeyboardProxy::new_for_owned_path(conn.clone(), obj_path.clone())?;
let mouse = MouseProxy::new_for_owned_path(conn.clone(), obj_path)?; let mouse = AsyncMouseProxy::new_for_owned_path(conn.clone(), obj_path)?;
Ok(Self { Ok(Self {
proxy, proxy,
keyboard, keyboard,
@ -64,22 +64,22 @@ impl Console {
}) })
} }
pub fn label(&self) -> Result<String> { pub async fn label(&self) -> Result<String> {
Ok(self.proxy.label()?) Ok(self.proxy.label().await?)
} }
pub fn width(&self) -> Result<u32> { pub async fn width(&self) -> Result<u32> {
Ok(self.proxy.width()?) Ok(self.proxy.width().await?)
} }
pub fn height(&self) -> Result<u32> { pub async fn height(&self) -> Result<u32> {
Ok(self.proxy.height()?) Ok(self.proxy.height().await?)
} }
pub fn listen(&self) -> Result<(Receiver<ConsoleEvent>, Sender<()>)> { pub async fn listen(&self) -> Result<(Receiver<ConsoleEvent>, Sender<()>)> {
let (p0, p1) = UnixStream::pair()?; let (p0, p1) = UnixStream::pair()?;
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
self.proxy.register_listener(p0.as_raw_fd().into())?; self.proxy.register_listener(p0.as_raw_fd().into()).await?;
let (wait_tx, wait_rx) = mpsc::channel(); let (wait_tx, wait_rx) = mpsc::channel();
let _thread = thread::spawn(move || { let _thread = thread::spawn(move || {
@ -106,10 +106,10 @@ impl Console {
#[cfg(feature = "glib")] #[cfg(feature = "glib")]
impl Console { impl Console {
pub fn glib_listen(&self) -> Result<(glib::Receiver<ConsoleEvent>, Sender<()>)> { pub async fn glib_listen(&self) -> Result<(glib::Receiver<ConsoleEvent>, Sender<()>)> {
let (p0, p1) = UnixStream::pair()?; let (p0, p1) = UnixStream::pair()?;
let (tx, rx) = glib::MainContext::channel(glib::source::Priority::default()); let (tx, rx) = glib::MainContext::channel(glib::source::Priority::default());
self.proxy.register_listener(p0.as_raw_fd().into())?; self.proxy.register_listener(p0.as_raw_fd().into()).await?;
let (wait_tx, wait_rx) = mpsc::channel(); let (wait_tx, wait_rx) = mpsc::channel();
let _thread = thread::spawn(move || { let _thread = thread::spawn(move || {

View File

@ -1,4 +1,4 @@
use glib::{clone, subclass::prelude::*, translate::*}; use glib::{clone, subclass::prelude::*, translate::*, MainContext};
use gtk::{glib, prelude::*}; use gtk::{glib, prelude::*};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@ -58,59 +58,57 @@ mod imp {
obj.set_mouse_absolute(true); obj.set_mouse_absolute(true);
obj.connect_key_press(clone!(@weak obj => move |_, keyval, keycode| { obj.connect_key_press(clone!(@weak obj => move |_, keyval, keycode| {
let self_ = Self::from_instance(&obj);
log::debug!("key-press: {:?}", (keyval, keycode)); log::debug!("key-press: {:?}", (keyval, keycode));
let console = self_.console.get().unwrap();
if let Some(qnum) = KEYMAP_XORGEVDEV2QNUM.get(keycode as usize) { if let Some(qnum) = KEYMAP_XORGEVDEV2QNUM.get(keycode as usize) {
let _ = console.keyboard.press(*qnum as u32); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = obj.console().keyboard.press(*qnum as u32).await;
}));
} }
})); }));
obj.connect_key_release(clone!(@weak obj => move |_, keyval, keycode| { obj.connect_key_release(clone!(@weak obj => move |_, keyval, keycode| {
let self_ = Self::from_instance(&obj);
log::debug!("key-release: {:?}", (keyval, keycode)); log::debug!("key-release: {:?}", (keyval, keycode));
let console = self_.console.get().unwrap();
if let Some(qnum) = KEYMAP_XORGEVDEV2QNUM.get(keycode as usize) { if let Some(qnum) = KEYMAP_XORGEVDEV2QNUM.get(keycode as usize) {
let _ = console.keyboard.release(*qnum as u32); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = obj.console().keyboard.release(*qnum as u32).await;
}));
} }
})); }));
obj.connect_motion(clone!(@weak obj => move |_, x, y| { obj.connect_motion(clone!(@weak obj => move |_, x, y| {
let self_ = Self::from_instance(&obj);
log::debug!("motion: {:?}", (x, y)); log::debug!("motion: {:?}", (x, y));
let console = self_.console.get().unwrap(); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = console.mouse.set_abs_position(x as _, y as _); let _ = obj.console().mouse.set_abs_position(x as _, y as _).await;
}));
})); }));
obj.connect_motion_relative(clone!(@weak obj => move |_, dx, dy| { obj.connect_motion_relative(clone!(@weak obj => move |_, dx, dy| {
let self_ = Self::from_instance(&obj);
log::debug!("motion-relative: {:?}", (dx, dy)); log::debug!("motion-relative: {:?}", (dx, dy));
let console = self_.console.get().unwrap(); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = console.mouse.rel_motion(dx as _, dy as _); let _ = obj.console().mouse.rel_motion(dx as _, dy as _).await;
}));
})); }));
obj.connect_mouse_press(clone!(@weak obj => move |_, button| { obj.connect_mouse_press(clone!(@weak obj => move |_, button| {
let self_ = Self::from_instance(&obj);
log::debug!("mouse-press: {:?}", button); log::debug!("mouse-press: {:?}", button);
let button = from_gdk_button(button); MainContext::default().spawn_local(clone!(@weak obj => async move {
let console = self_.console.get().unwrap(); let button = from_gdk_button(button);
let _ = console.mouse.press(button); let _ = obj.console().mouse.press(button).await;
}));
})); }));
obj.connect_mouse_release(clone!(@weak obj => move |_, button| { obj.connect_mouse_release(clone!(@weak obj => move |_, button| {
let self_ = Self::from_instance(&obj);
log::debug!("mouse-release: {:?}", button); log::debug!("mouse-release: {:?}", button);
let button = from_gdk_button(button); MainContext::default().spawn_local(clone!(@weak obj => async move {
let console = self_.console.get().unwrap(); let button = from_gdk_button(button);
let _ = console.mouse.release(button); let _ = obj.console().mouse.release(button).await;
}));
})); }));
obj.connect_scroll_discrete(clone!(@weak obj => move |_, scroll| { obj.connect_scroll_discrete(clone!(@weak obj => move |_, scroll| {
use qemu_display_listener::MouseButton; use qemu_display_listener::MouseButton;
let self_ = Self::from_instance(&obj);
log::debug!("scroll-discrete: {:?}", scroll); log::debug!("scroll-discrete: {:?}", scroll);
let console = self_.console.get().unwrap();
let button = match scroll { let button = match scroll {
rdw::Scroll::Up => MouseButton::WheelUp, rdw::Scroll::Up => MouseButton::WheelUp,
@ -120,15 +118,17 @@ mod imp {
return; return;
} }
}; };
let _ = console.mouse.press(button); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = console.mouse.release(button); let _ = obj.console().mouse.press(button).await;
let _ = obj.console().mouse.release(button).await;
}));
})); }));
obj.connect_resize_request(clone!(@weak obj => move |_, width, height, wmm, hmm| { obj.connect_resize_request(clone!(@weak obj => move |_, width, height, wmm, hmm| {
let self_ = Self::from_instance(&obj);
log::debug!("resize-request: {:?}", (width, height, wmm, hmm)); log::debug!("resize-request: {:?}", (width, height, wmm, hmm));
let console = self_.console.get().unwrap(); MainContext::default().spawn_local(clone!(@weak obj => async move {
let _ = console.proxy.set_ui_info(wmm as _, hmm as _, 0, 0, width, height); let _ = obj.console().proxy.set_ui_info(wmm as _, hmm as _, 0, 0, width, height).await;
}));
})); }));
} }
} }
@ -137,73 +137,76 @@ mod imp {
fn realize(&self, widget: &Self::Type) { fn realize(&self, widget: &Self::Type) {
self.parent_realize(widget); self.parent_realize(widget);
let console = self.console.get().unwrap(); MainContext::default().spawn_local(clone!(@weak widget => async move {
let (rx, wait_tx) = console let self_ = Self::from_instance(&widget);
.glib_listen() let console = self_.console.get().unwrap();
.expect("Failed to listen to the console"); let (rx, wait_tx) = console
rx.attach( .glib_listen()
None, .await
clone!(@weak widget => @default-panic, move |evt| { .expect("Failed to listen to the console");
use qemu_display_listener::ConsoleEvent::*; rx.attach(
None,
clone!(@weak widget => @default-panic, move |evt| {
use qemu_display_listener::ConsoleEvent::*;
let self_ = Self::from_instance(&widget); log::debug!("Console event: {:?}", evt);
log::debug!("Console event: {:?}", evt); match evt {
match evt { Scanout(s) => {
Scanout(s) => { if s.format != 0x20020888 {
if s.format != 0x20020888 { log::warn!("Format not yet supported: {:X}", s.format);
log::warn!("Format not yet supported: {:X}", s.format); return Continue(true);
return Continue(true); }
widget.set_display_size(Some((s.width as _, s.height as _)));
widget.update_area(0, 0, s.width as _, s.height as _, s.stride as _, &s.data);
} }
widget.set_display_size(Some((s.width as _, s.height as _))); Update(u) => {
widget.update_area(0, 0, s.width as _, s.height as _, s.stride as _, &s.data); if u.format != 0x20020888 {
} log::warn!("Format not yet supported: {:X}", u.format);
Update(u) => { return Continue(true);
if u.format != 0x20020888 { }
log::warn!("Format not yet supported: {:X}", u.format); widget.update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, &u.data);
return Continue(true);
} }
widget.update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, &u.data); ScanoutDMABUF(s) => {
} widget.set_display_size(Some((s.width as _, s.height as _)));
ScanoutDMABUF(s) => { widget.set_dmabuf_scanout(rdw::DmabufScanout {
widget.set_display_size(Some((s.width as _, s.height as _))); width: s.width,
widget.set_dmabuf_scanout(rdw::DmabufScanout { height: s.height,
width: s.width, stride: s.stride,
height: s.height, fourcc: s.fourcc,
stride: s.stride, y0_top: s.y0_top,
fourcc: s.fourcc, modifier: s.modifier,
y0_top: s.y0_top, fd: s.into_raw_fd(),
modifier: s.modifier, });
fd: s.into_raw_fd(), }
}); UpdateDMABUF { .. } => {
} widget.render();
UpdateDMABUF { .. } => { let _ = wait_tx.send(());
widget.render(); }
let _ = wait_tx.send(()); Disconnected => {
} }
Disconnected => { CursorDefine { width, height, hot_x, hot_y, data }=> {
} let cursor = rdw::Display::make_cursor(
CursorDefine { width, height, hot_x, hot_y, data }=> { &data,
let cursor = rdw::Display::make_cursor( width,
&data, height,
width, hot_x,
height, hot_y,
hot_x, 1,
hot_y, );
1, widget.define_cursor(Some(cursor));
); }
widget.define_cursor(Some(cursor)); MouseSet(m) => {
} if m.on != 0 {
MouseSet(m) => { widget.set_cursor_position(Some((m.x as _, m.y as _)));
if m.on != 0 { } else {
widget.set_cursor_position(Some((m.x as _, m.y as _))); widget.set_cursor_position(None);
} else { }
widget.set_cursor_position(None);
} }
} }
} Continue(true)
Continue(true) })
}), );
); }));
} }
} }
@ -227,6 +230,11 @@ impl DisplayQemu {
self_.set_console(console); self_.set_console(console);
obj obj
} }
pub(crate) fn console(&self) -> &Console {
let self_ = imp::DisplayQemu::from_instance(self);
self_.console.get().unwrap()
}
} }
fn from_gdk_button(button: u32) -> qemu_display_listener::MouseButton { fn from_gdk_button(button: u32) -> qemu_display_listener::MouseButton {

View File

@ -1,5 +1,7 @@
use std::error::Error;
use gio::ApplicationFlags; use gio::ApplicationFlags;
use gtk::{gio, prelude::*}; use glib::{clone, MainContext};
use gtk::{gio, glib, prelude::*};
use qemu_display_listener::Console; use qemu_display_listener::Console;
use zbus::Connection; use zbus::Connection;
@ -10,7 +12,7 @@ fn main() {
let app = gtk::Application::new(Some("org.qemu.rdw.demo"), ApplicationFlags::NON_UNIQUE); let app = gtk::Application::new(Some("org.qemu.rdw.demo"), ApplicationFlags::NON_UNIQUE);
let conn = Connection::new_session().expect("Failed to connect to DBus"); let conn: zbus::azync::Connection = Connection::new_session().expect("Failed to connect to DBus").into();
app.connect_activate(move |app| { app.connect_activate(move |app| {
let window = gtk::ApplicationWindow::new(app); let window = gtk::ApplicationWindow::new(app);
@ -18,11 +20,14 @@ fn main() {
window.set_title(Some("rdw demo")); window.set_title(Some("rdw demo"));
window.set_default_size(1024, 768); window.set_default_size(1024, 768);
let console = Console::new(&conn, 0).expect("Failed to get the QEMU console"); let conn = conn.clone();
let display = display_qemu::DisplayQemu::new(console); MainContext::default().spawn_local(clone!(@strong window => async move {
window.set_child(Some(&display)); let console = Console::new(&conn, 0).await.expect("Failed to get the QEMU console");
let display = display_qemu::DisplayQemu::new(console);
window.set_child(Some(&display));
window.show(); window.show();
}));
}); });
app.run(); app.run();