use std::cell::RefCell; use std::os::unix::net::UnixStream; use std::rc::Rc; use std::sync::mpsc::{self, Receiver}; use std::{os::unix::io::AsRawFd, thread}; use zbus::{dbus_proxy, export::zvariant::Fd}; use crate::Result; use crate::{Event, Listener}; #[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")] pub trait Console { /// RegisterListener method fn register_listener(&self, listener: Fd) -> zbus::Result<()>; #[dbus_proxy(property)] fn label(&self) -> zbus::Result; #[dbus_proxy(property)] fn head(&self) -> zbus::Result; #[dbus_proxy(property)] fn type_(&self) -> zbus::Result; #[dbus_proxy(property)] fn width(&self) -> zbus::Result; #[dbus_proxy(property)] fn height(&self) -> zbus::Result; } #[derive(derivative::Derivative)] #[derivative(Debug)] pub struct Console<'c> { #[derivative(Debug = "ignore")] proxy: ConsoleProxy<'c>, } impl<'c> Console<'c> { pub fn new(conn: &zbus::Connection, idx: u32) -> Result { let proxy = ConsoleProxy::new_for_owned_path( conn.clone(), format!("/org/qemu/Display1/Console_{}", idx), )?; Ok(Self { proxy }) } pub fn label(&self) -> Result { Ok(self.proxy.label()?) } pub fn width(&self) -> Result { Ok(self.proxy.width()?) } pub fn height(&self) -> Result { Ok(self.proxy.height()?) } pub fn listen(&self) -> Result> { let (p0, p1) = UnixStream::pair()?; let (tx, rx) = mpsc::channel(); self.proxy.register_listener(p0.as_raw_fd().into())?; 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)); s.at( &zvariant::ObjectPath::from_str_unchecked("/org/qemu/Display1/Listener"), Listener::new(tx, err.clone()), ) .unwrap(); loop { if let Err(e) = s.try_handle_next() { eprintln!("Listener DBus error: {}", e); return; } if let Some(e) = &*err.borrow() { eprintln!("Listener channel error: {}", e); return; } } }); Ok(rx) } } #[cfg(feature = "glib")] impl<'c> Console<'c> { pub fn glib_listen(&self) -> Result> { 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 _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)); s.at( &zvariant::ObjectPath::from_str_unchecked("/org/qemu/Display1/Listener"), Listener::new(tx, err.clone()), ) .unwrap(); loop { if let Err(e) = s.try_handle_next() { eprintln!("Listener DBus error: {}", e); return; } if let Some(e) = &*err.borrow() { eprintln!("Listener channel error: {}", e); return; } } }); Ok(rx) } }