mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2025-02-07 02:59:28 +00:00
Wait for rendering after Update
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
2a26d33561
commit
35758dacb0
@ -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<Receiver<Event>> {
|
||||
pub fn listen(&self) -> Result<(Receiver<Event>, 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<glib::Receiver<Event>> {
|
||||
pub fn glib_listen(&self) -> Result<(glib::Receiver<Event>, 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))
|
||||
}
|
||||
}
|
||||
|
@ -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<Event> {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Listener<E: EventSender> {
|
||||
tx: E,
|
||||
err: Rc<RefCell<Option<SendError<Event>>>>,
|
||||
wait_rx: Receiver<()>,
|
||||
err: Arc<RefCell<Option<SendError<Event>>>>,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.qemu.Display1.Listener")]
|
||||
@ -86,7 +87,10 @@ impl<E: 'static + EventSender> Listener<E> {
|
||||
}
|
||||
|
||||
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<E: 'static + EventSender> Listener<E> {
|
||||
}
|
||||
|
||||
impl<E: EventSender> Listener<E> {
|
||||
pub(crate) fn new(tx: E, err: Rc<RefCell<Option<SendError<Event>>>>) -> 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<E: EventSender> Listener<E> {
|
||||
*self.err.borrow_mut() = Some(e);
|
||||
}
|
||||
}
|
||||
|
||||
fn wait(&mut self) -> Result<(), RecvError> {
|
||||
self.wait_rx.recv()
|
||||
}
|
||||
|
||||
pub fn err(&self) -> Arc<RefCell<Option<SendError<Event>>>> {
|
||||
self.err.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EventSender> Drop for Listener<E> {
|
||||
|
@ -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<gtk::Label>,
|
||||
pub console: OnceCell<Console>,
|
||||
pub wait_rendering: Cell<usize>,
|
||||
}
|
||||
|
||||
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!");
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
@ -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<GLuint, String> {
|
||||
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<GLuint, String> {
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user