diff --git a/qemu-display-listener/src/console.rs b/qemu-display-listener/src/console.rs index 5339531..86345ba 100644 --- a/qemu-display-listener/src/console.rs +++ b/qemu-display-listener/src/console.rs @@ -1,7 +1,5 @@ -use std::cell::RefCell; use std::os::unix::net::UnixStream; -use std::rc::Rc; -use std::sync::mpsc::{self, Receiver}; +use std::sync::mpsc::{self, Receiver, Sender}; use std::{os::unix::io::AsRawFd, thread}; use zbus::{dbus_proxy, export::zvariant::Fd}; @@ -66,18 +64,20 @@ impl Console { Ok(self.proxy.height()?) } - pub fn listen(&self) -> Result> { + pub fn listen(&self) -> Result<(Receiver, Sender<()>)> { let (p0, p1) = UnixStream::pair()?; let (tx, rx) = mpsc::channel(); self.proxy.register_listener(p0.as_raw_fd().into())?; + let (wait_tx, wait_rx) = mpsc::channel(); let _thread = thread::spawn(move || { let c = zbus::Connection::new_unix_client(p1, false).unwrap(); let mut s = zbus::ObjectServer::new(&c); - let err = Rc::new(RefCell::new(None)); + let listener = Listener::new(tx, wait_rx); + let err = listener.err(); s.at( "/org/qemu/Display1/Listener", - Listener::new(tx, err.clone()), + listener ) .unwrap(); loop { @@ -92,24 +92,26 @@ impl Console { } }); - Ok(rx) + Ok((rx, wait_tx)) } } #[cfg(feature = "glib")] impl Console { - pub fn glib_listen(&self) -> Result> { + pub fn glib_listen(&self) -> Result<(glib::Receiver, Sender<()>)> { let (p0, p1) = UnixStream::pair()?; let (tx, rx) = glib::MainContext::channel(glib::source::Priority::default()); self.proxy.register_listener(p0.as_raw_fd().into())?; + let (wait_tx, wait_rx) = mpsc::channel(); let _thread = thread::spawn(move || { let c = zbus::Connection::new_unix_client(p1, false).unwrap(); let mut s = zbus::ObjectServer::new(&c); - let err = Rc::new(RefCell::new(None)); + let listener = Listener::new(tx, wait_rx); + let err = listener.err(); s.at( "/org/qemu/Display1/Listener", - Listener::new(tx, err.clone()), + listener ) .unwrap(); loop { @@ -124,6 +126,6 @@ impl Console { } }); - Ok(rx) + Ok((rx, wait_tx)) } } diff --git a/qemu-display-listener/src/listener.rs b/qemu-display-listener/src/listener.rs index e1973e6..d265884 100644 --- a/qemu-display-listener/src/listener.rs +++ b/qemu-display-listener/src/listener.rs @@ -1,8 +1,8 @@ use std::cell::RefCell; use std::ops::Drop; use std::os::unix::io::{AsRawFd, RawFd}; -use std::rc::Rc; -use std::sync::mpsc::{SendError, Sender}; +use std::sync::Arc; +use std::sync::mpsc::{RecvError, SendError, Sender, Receiver}; use zbus::{dbus_interface, export::zvariant::Fd}; @@ -76,7 +76,8 @@ impl EventSender for glib::Sender { #[derive(Debug)] pub(crate) struct Listener { tx: E, - err: Rc>>>, + wait_rx: Receiver<()>, + err: Arc>>>, } #[dbus_interface(name = "org.qemu.Display1.Listener")] @@ -86,7 +87,10 @@ impl Listener { } fn update(&mut self, x: i32, y: i32, w: i32, h: i32) { - self.send(Event::Update { x, y, w, h }) + self.send(Event::Update { x, y, w, h }); + if let Err(e) = self.wait() { + eprintln!("update returned error: {}", e) + } } fn scanout( @@ -127,8 +131,9 @@ impl Listener { } impl Listener { - pub(crate) fn new(tx: E, err: Rc>>>) -> Self { - Listener { tx, err } + pub(crate) fn new(tx: E, wait_rx: Receiver<()>) -> Self { + let err = Arc::new(RefCell::new(None)); + Listener { tx, wait_rx, err } } fn send(&mut self, event: Event) { @@ -136,6 +141,14 @@ impl Listener { *self.err.borrow_mut() = Some(e); } } + + fn wait(&mut self) -> Result<(), RecvError> { + self.wait_rx.recv() + } + + pub fn err(&self) -> Arc>>> { + self.err.clone() + } } impl Drop for Listener { diff --git a/qemu-gtk4/src/console.rs b/qemu-gtk4/src/console.rs index 73dff44..df0d74d 100644 --- a/qemu-gtk4/src/console.rs +++ b/qemu-gtk4/src/console.rs @@ -4,6 +4,7 @@ use gtk::prelude::*; use gtk::subclass::widget::WidgetImplExt; use gtk::{glib, CompositeTemplate}; use once_cell::sync::OnceCell; +use std::cell::Cell; use keycodemap::*; use qemu_display_listener::{Console, Event, MouseButton}; @@ -21,6 +22,7 @@ mod imp { #[template_child] pub label: TemplateChild, pub console: OnceCell, + pub wait_rendering: Cell, } impl ObjectSubclass for QemuConsole { @@ -137,23 +139,37 @@ glib::wrapper! { impl QemuConsole { pub fn set_qemu_console(&self, console: Console) { let priv_ = imp::QemuConsole::from_instance(self); - let rx = console + let (rx, wait_tx) = console .glib_listen() .expect("Failed to listen to the console"); + priv_ + .area + .connect_render(clone!(@weak self as obj => move |_, _| { + let priv_ = imp::QemuConsole::from_instance(&obj); + let wait_rendering = priv_.wait_rendering.get(); + if wait_rendering > 0 { + if let Err(e) = wait_tx.send(()) { + eprintln!("Failed to ack rendering: {}", e); + } + priv_.wait_rendering.set(wait_rendering - 1); + } + glib::signal::Inhibit(false) + })); rx.attach( None, clone!(@weak self as con => move |t| { - let con = imp::QemuConsole::from_instance(&con); + let priv_ = imp::QemuConsole::from_instance(&con); match t { Event::Update { .. } => { - con.area.queue_render(); + priv_.wait_rendering.set(priv_.wait_rendering.get() + 1); + priv_.area.queue_render(); } Event::Scanout(s) => { - con.label.set_label(&format!("{:?}", s)); - con.area.set_scanout(s); + priv_.label.set_label(&format!("{:?}", s)); + priv_.area.set_scanout(s); } Event::Disconnected => { - con.label.set_label("Console disconnected!"); + priv_.label.set_label("Console disconnected!"); } _ => () } diff --git a/qemu-gtk4/src/console_area.rs b/qemu-gtk4/src/console_area.rs index 9642a69..26f26e7 100644 --- a/qemu-gtk4/src/console_area.rs +++ b/qemu-gtk4/src/console_area.rs @@ -75,7 +75,7 @@ mod imp { widget.make_current(); if let Err(e) = unsafe { self.realize_gl() } { - let e = glib::Error::new(AppError::GL, &format!("{}", e)); + let e = glib::Error::new(AppError::GL, &e.to_string()); widget.set_error(Some(&e)); } } @@ -92,7 +92,8 @@ mod imp { gl::Viewport(vp.x, vp.y, vp.width, vp.height); self.texture_blit(false); } - return true; /* FIXME: Inibit */ + // parent will return to update call + false } } @@ -308,11 +309,11 @@ impl QemuConsoleArea { } } -unsafe fn compile_shader(type_: GLenum, src: &CStr) -> Result { +unsafe fn compile_shader(type_: GLenum, src: &CStr) -> GLuint { let shader = gl::CreateShader(type_); gl::ShaderSource(shader, 1, &src.as_ptr(), std::ptr::null()); gl::CompileShader(shader); - Ok(shader) + shader } fn cstring_new_len(len: usize) -> CString { @@ -321,8 +322,8 @@ fn cstring_new_len(len: usize) -> CString { } unsafe fn compile_prog(vs: &CStr, fs: &CStr) -> Result { - let vs = compile_shader(gl::VERTEX_SHADER, vs)?; - let fs = compile_shader(gl::FRAGMENT_SHADER, fs)?; + let vs = compile_shader(gl::VERTEX_SHADER, vs); + let fs = compile_shader(gl::FRAGMENT_SHADER, fs); let prog = gl::CreateProgram(); gl::AttachShader(prog, vs);