Compare commits
15 Commits
86118de078
...
ac188788cf
Author | SHA1 | Date |
---|---|---|
Marc-André Lureau | ac188788cf | |
Bilal Elmoussaoui | 7fa131c922 | |
Marc-André Lureau | 0ff232b771 | |
Marc-André Lureau | bbd5494316 | |
mihneabuz | 8c3b5e7cba | |
Marc-André Lureau | a4b0394f27 | |
Marc-André Lureau | 142148e8db | |
Marc-André Lureau | 9da1aa5aeb | |
Marc-André Lureau | 29926a8df0 | |
Marc-André Lureau | 3e2bb7985c | |
Marc-André Lureau | a2185be540 | |
Marc-André Lureau | abca0e48d5 | |
Marc-André Lureau | 67b334e5bb | |
Marc-André Lureau | aa10b12bcb | |
Marc-André Lureau | 24cca85289 |
|
@ -1,5 +1,4 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
.DS_Store
|
||||
.idea
|
||||
*.log
|
||||
|
|
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
|
@ -5,13 +5,17 @@ members = [
|
|||
"qemu-rdw",
|
||||
"qemu-vnc",
|
||||
"qemu-vte",
|
||||
"qemu-rdp",
|
||||
"xtask",
|
||||
]
|
||||
default-members = ["qemu-rdw"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
qemu-display = { path = "qemu-display", version = "0.1" }
|
||||
keycodemap = { path = "keycodemap", version = "0.1" }
|
||||
zbus = { version = "4", features = ["p2p"] }
|
||||
|
||||
[patch.crates-io]
|
||||
zbus = { git = "https://github.com/dbus2/zbus.git" }
|
||||
zvariant = { git = "https://github.com/dbus2/zbus.git" }
|
||||
vnc = { git = "https://github.com/elmarco/rust-vnc", branch = "server" }
|
||||
rdw4 = { path = "../rdw/rdw4" }
|
||||
rdw4 = { git = "https://gitlab.gnome.org/malureau/rdw.git" }
|
||||
|
|
|
@ -13,7 +13,7 @@ qmp = ["dep:qapi", "dep:base64"]
|
|||
cfg-if = "1.0"
|
||||
log = "0.4"
|
||||
derivative = "2.2.0"
|
||||
zbus = "4"
|
||||
zbus.workspace = true
|
||||
zvariant = { version = "4", features = ["serde_bytes"] }
|
||||
libc = "0.2.86"
|
||||
enumflags2 = { version = "0.7", features = ["serde"] }
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::os::unix::net::UnixStream;
|
|||
use uds_windows::UnixStream;
|
||||
#[cfg(unix)]
|
||||
use zbus::zvariant::Fd;
|
||||
use zbus::{dbus_interface, dbus_proxy, Connection};
|
||||
use zbus::Connection;
|
||||
|
||||
use crate::{util, Result};
|
||||
|
||||
|
@ -51,17 +51,17 @@ pub struct Volume {
|
|||
pub volume: Vec<u8>,
|
||||
}
|
||||
|
||||
#[dbus_proxy(
|
||||
#[zbus::proxy(
|
||||
default_service = "org.qemu",
|
||||
default_path = "/org/qemu/Display1/Audio",
|
||||
interface = "org.qemu.Display1.Audio"
|
||||
)]
|
||||
trait Audio {
|
||||
/// RegisterOutListener method
|
||||
fn register_out_listener(&self, listener: Fd) -> zbus::Result<()>;
|
||||
fn register_out_listener(&self, listener: Fd<'_>) -> zbus::Result<()>;
|
||||
|
||||
/// RegisterInListener method
|
||||
fn register_in_listener(&self, listener: Fd) -> zbus::Result<()>;
|
||||
fn register_in_listener(&self, listener: Fd<'_>) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[derive(derivative::Derivative)]
|
||||
|
@ -92,7 +92,7 @@ struct AudioOutListener<H: AudioOutHandler> {
|
|||
handler: H,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.qemu.Display1.AudioOutListener")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.AudioOutListener")]
|
||||
impl<H: AudioOutHandler> AudioOutListener<H> {
|
||||
/// Init method
|
||||
async fn init(
|
||||
|
@ -170,7 +170,7 @@ struct AudioInListener<H: AudioInHandler> {
|
|||
handler: H,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.qemu.Display1.AudioInListener")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.AudioInListener")]
|
||||
impl<H: AudioInHandler> AudioInListener<H> {
|
||||
/// Init method
|
||||
async fn init(
|
||||
|
|
|
@ -3,32 +3,32 @@ use crate::win32::Fd;
|
|||
use std::convert::TryFrom;
|
||||
#[cfg(unix)]
|
||||
use zbus::zvariant::Fd;
|
||||
use zbus::{dbus_proxy, zvariant::ObjectPath};
|
||||
use zbus::zvariant::ObjectPath;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Chardev")]
|
||||
#[zbus::proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Chardev")]
|
||||
pub trait Chardev {
|
||||
/// Register method
|
||||
fn register(&self, stream: Fd) -> zbus::Result<()>;
|
||||
fn register(&self, stream: Fd<'_>) -> zbus::Result<()>;
|
||||
|
||||
/// SendBreak method
|
||||
fn send_break(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Echo property
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn echo(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// FEOpened property
|
||||
#[dbus_proxy(property, name = "FEOpened")]
|
||||
#[zbus(property, name = "FEOpened")]
|
||||
fn fe_opened(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Name property
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn name(&self) -> zbus::Result<String>;
|
||||
|
||||
/// Owner property
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn owner(&self) -> zbus::Result<String>;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use std::convert::TryFrom;
|
||||
use zbus::{
|
||||
dbus_interface, dbus_proxy,
|
||||
zvariant::{ObjectPath, Type},
|
||||
};
|
||||
use zbus::zvariant::{ObjectPath, Type};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
|
@ -15,7 +12,7 @@ pub enum ClipboardSelection {
|
|||
Secondary,
|
||||
}
|
||||
|
||||
#[dbus_proxy(
|
||||
#[zbus::proxy(
|
||||
default_service = "org.qemu",
|
||||
default_path = "/org/qemu/Display1/Clipboard",
|
||||
interface = "org.qemu.Display1.Clipboard"
|
||||
|
@ -58,7 +55,7 @@ pub(crate) struct ClipboardListener<H: ClipboardHandler> {
|
|||
handler: H,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.qemu.Display1.Clipboard")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.Clipboard")]
|
||||
impl<H: ClipboardHandler> ClipboardListener<H> {
|
||||
async fn register(&mut self) {
|
||||
self.handler.register().await;
|
||||
|
|
|
@ -2,27 +2,30 @@
|
|||
use crate::win32::Fd;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::{cell::RefCell, convert::TryFrom};
|
||||
use std::{convert::TryFrom, sync::RwLock};
|
||||
#[cfg(windows)]
|
||||
use uds_windows::UnixStream;
|
||||
#[cfg(unix)]
|
||||
use zbus::zvariant::Fd;
|
||||
use zbus::{dbus_proxy, zvariant::ObjectPath, Connection};
|
||||
use zbus::{zvariant::ObjectPath, Connection};
|
||||
|
||||
use crate::{util, ConsoleListener, ConsoleListenerHandler, KeyboardProxy, MouseProxy, Result};
|
||||
use crate::{
|
||||
util, ConsoleListener, ConsoleListenerHandler, KeyboardProxy, MouseProxy, MultiTouchProxy,
|
||||
Result,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use crate::{
|
||||
ConsoleListenerD3d11, ConsoleListenerD3d11Handler, ConsoleListenerMap,
|
||||
ConsoleListenerMapHandler,
|
||||
};
|
||||
|
||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")]
|
||||
#[zbus::proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")]
|
||||
pub trait Console {
|
||||
/// RegisterListener method
|
||||
fn register_listener(&self, listener: Fd) -> zbus::Result<()>;
|
||||
fn register_listener(&self, listener: Fd<'_>) -> zbus::Result<()>;
|
||||
|
||||
/// SetUIInfo method
|
||||
#[dbus_proxy(name = "SetUIInfo")]
|
||||
#[zbus(name = "SetUIInfo")]
|
||||
fn set_ui_info(
|
||||
&self,
|
||||
width_mm: u16,
|
||||
|
@ -33,19 +36,19 @@ pub trait Console {
|
|||
height: u32,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn label(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn head(&self) -> zbus::Result<u32>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn type_(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn width(&self) -> zbus::Result<u32>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn height(&self) -> zbus::Result<u32>;
|
||||
}
|
||||
|
||||
|
@ -58,7 +61,9 @@ pub struct Console {
|
|||
pub keyboard: KeyboardProxy<'static>,
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub mouse: MouseProxy<'static>,
|
||||
listener: RefCell<Option<Connection>>,
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub multi_touch: MultiTouchProxy<'static>,
|
||||
listener: RwLock<Option<Connection>>,
|
||||
#[cfg(windows)]
|
||||
peer_pid: u32,
|
||||
}
|
||||
|
@ -72,11 +77,16 @@ impl Console {
|
|||
.build()
|
||||
.await?;
|
||||
let mouse = MouseProxy::builder(conn).path(&obj_path)?.build().await?;
|
||||
let multi_touch = MultiTouchProxy::builder(conn)
|
||||
.path(&obj_path)?
|
||||
.build()
|
||||
.await?;
|
||||
Ok(Self {
|
||||
proxy,
|
||||
keyboard,
|
||||
mouse,
|
||||
listener: RefCell::new(None),
|
||||
multi_touch,
|
||||
listener: RwLock::new(None),
|
||||
#[cfg(windows)]
|
||||
peer_pid,
|
||||
})
|
||||
|
@ -107,13 +117,13 @@ impl Console {
|
|||
.serve_at("/org/qemu/Display1/Listener", ConsoleListener::new(handler))?
|
||||
.build()
|
||||
.await?;
|
||||
self.listener.replace(Some(c));
|
||||
*self.listener.write().unwrap() = Some(c);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub async fn set_map_listener<H: ConsoleListenerMapHandler>(&self, handler: H) -> Result<bool> {
|
||||
if let Some(l) = self.listener.borrow_mut().as_mut() {
|
||||
if let Some(l) = &*self.listener.write().unwrap() {
|
||||
return l
|
||||
.object_server()
|
||||
.at(
|
||||
|
@ -132,7 +142,7 @@ impl Console {
|
|||
&self,
|
||||
handler: H,
|
||||
) -> Result<bool> {
|
||||
if let Some(l) = self.listener.borrow_mut().as_mut() {
|
||||
if let Some(l) = &*self.listener.write().unwrap() {
|
||||
return l
|
||||
.object_server()
|
||||
.at(
|
||||
|
@ -146,7 +156,7 @@ impl Console {
|
|||
Err(crate::Error::Failed("Must call register first!".into()))
|
||||
}
|
||||
|
||||
pub fn unregister_listener(&mut self) {
|
||||
self.listener.replace(None);
|
||||
pub fn unregister_listener(&self) {
|
||||
*self.listener.write().unwrap() = None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ use derivative::Derivative;
|
|||
use std::ops::Drop;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use zbus::dbus_interface;
|
||||
#[cfg(unix)]
|
||||
use zbus::zvariant::Fd;
|
||||
|
||||
|
@ -160,7 +159,7 @@ pub(crate) struct ConsoleListener<H: ConsoleListenerHandler> {
|
|||
handler: H,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.qemu.Display1.Listener")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.Listener")]
|
||||
impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
||||
async fn scanout(
|
||||
&mut self,
|
||||
|
@ -205,10 +204,10 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||
#[zbus(name = "ScanoutDMABUF")]
|
||||
async fn scanout_dmabuf(
|
||||
&mut self,
|
||||
_fd: Fd,
|
||||
_fd: Fd<'_>,
|
||||
_width: u32,
|
||||
_height: u32,
|
||||
_stride: u32,
|
||||
|
@ -222,10 +221,10 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||
#[zbus(name = "ScanoutDMABUF")]
|
||||
async fn scanout_dmabuf(
|
||||
&mut self,
|
||||
fd: Fd,
|
||||
fd: Fd<'_>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
|
@ -249,7 +248,7 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[dbus_interface(name = "UpdateDMABUF")]
|
||||
#[zbus(name = "UpdateDMABUF")]
|
||||
async fn update_dmabuf(&mut self, _x: i32, _y: i32, _w: i32, _h: i32) -> zbus::fdo::Result<()> {
|
||||
Err(zbus::fdo::Error::NotSupported(
|
||||
"DMABUF is not support on !unix".into(),
|
||||
|
@ -257,7 +256,7 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[dbus_interface(name = "UpdateDMABUF")]
|
||||
#[zbus(name = "UpdateDMABUF")]
|
||||
async fn update_dmabuf(&mut self, x: i32, y: i32, w: i32, h: i32) -> zbus::fdo::Result<()> {
|
||||
self.handler
|
||||
.update_dmabuf(UpdateDMABUF { x, y, w, h })
|
||||
|
@ -292,7 +291,7 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[dbus_interface(property)]
|
||||
#[zbus(property)]
|
||||
fn interfaces(&self) -> Vec<String> {
|
||||
self.handler.interfaces()
|
||||
}
|
||||
|
@ -325,7 +324,7 @@ pub(crate) struct ConsoleListenerMap<H: ConsoleListenerMapHandler> {
|
|||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[dbus_interface(name = "org.qemu.Display1.Listener.Win32.Map")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.Listener.Win32.Map")]
|
||||
impl<H: ConsoleListenerMapHandler> ConsoleListenerMap<H> {
|
||||
async fn scanout_map(
|
||||
&mut self,
|
||||
|
@ -377,7 +376,7 @@ pub(crate) struct ConsoleListenerD3d11<H: ConsoleListenerD3d11Handler> {
|
|||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[dbus_interface(name = "org.qemu.Display1.Listener.Win32.D3d11")]
|
||||
#[zbus::interface(name = "org.qemu.Display1.Listener.Win32.D3d11")]
|
||||
impl<H: ConsoleListenerD3d11Handler> ConsoleListenerD3d11<H> {
|
||||
async fn scanout_texture2d(
|
||||
&mut self,
|
||||
|
|
|
@ -2,7 +2,7 @@ use futures::stream::{self, StreamExt};
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
convert::{TryFrom, TryInto},
|
||||
sync::Arc,
|
||||
rc::Rc,
|
||||
};
|
||||
use zbus::{
|
||||
fdo,
|
||||
|
@ -31,7 +31,7 @@ struct Inner<'d> {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Display<'d> {
|
||||
inner: Arc<Inner<'d>>,
|
||||
inner: Rc<Inner<'d>>,
|
||||
}
|
||||
|
||||
impl<'d> Display<'d> {
|
||||
|
@ -113,7 +113,7 @@ impl<'d> Display<'d> {
|
|||
};
|
||||
|
||||
Ok(Self {
|
||||
inner: Arc::new(inner),
|
||||
inner: Rc::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,7 @@ impl<'d> Display<'d> {
|
|||
{
|
||||
// FIXME: no ancillary fd API at this point
|
||||
// https://github.com/rust-lang/rust/issues/76915
|
||||
let _ = p0;
|
||||
qmp.execute(&qmp::getfd {
|
||||
fdname: "fdname".into(),
|
||||
})?;
|
||||
|
@ -200,7 +201,7 @@ impl<'d> Display<'d> {
|
|||
}
|
||||
|
||||
pub async fn receive_owner_changed(&self) -> Result<OwnerChangedStream<'_>> {
|
||||
Ok(self.inner.proxy.receive_owner_changed().await?)
|
||||
Ok(self.inner.proxy.inner().receive_owner_changed().await?)
|
||||
}
|
||||
|
||||
pub async fn audio(&self) -> Result<Option<Audio>> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use enumflags2::{bitflags, BitFlags};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zbus::{dbus_proxy, zvariant::Type};
|
||||
use zbus::zvariant::Type;
|
||||
|
||||
#[bitflags]
|
||||
#[repr(u32)]
|
||||
|
@ -11,7 +11,7 @@ pub enum KeyboardModifiers {
|
|||
Caps = 0x4,
|
||||
}
|
||||
|
||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Keyboard")]
|
||||
#[zbus::proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Keyboard")]
|
||||
pub trait Keyboard {
|
||||
/// Press method
|
||||
fn press(&self, keycode: u32) -> zbus::Result<()>;
|
||||
|
@ -19,6 +19,6 @@ pub trait Keyboard {
|
|||
/// Release method
|
||||
fn release(&self, keycode: u32) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn modifiers(&self) -> zbus::Result<BitFlags<KeyboardModifiers>>;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@ pub use mouse::*;
|
|||
mod display;
|
||||
pub use display::*;
|
||||
|
||||
mod multi_touch;
|
||||
pub use multi_touch::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod usbredir;
|
||||
#[cfg(unix)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use zbus::{dbus_proxy, zvariant::Type};
|
||||
use zbus::zvariant::Type;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Deserialize_repr, Serialize_repr, Type, Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
|
@ -13,7 +13,7 @@ pub enum MouseButton {
|
|||
Extra,
|
||||
}
|
||||
|
||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Mouse")]
|
||||
#[zbus::proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Mouse")]
|
||||
pub trait Mouse {
|
||||
/// Press method
|
||||
fn press(&self, button: MouseButton) -> zbus::Result<()>;
|
||||
|
@ -27,6 +27,6 @@ pub trait Mouse {
|
|||
/// RelMotion method
|
||||
fn rel_motion(&self, dx: i32, dy: i32) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn is_absolute(&self) -> zbus::Result<bool>;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use zbus::zvariant::Type;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Type, Debug, PartialEq, Copy, Clone, Eq, Serialize, Deserialize)]
|
||||
pub enum TouchEventKind {
|
||||
Begin = 0,
|
||||
Update = 1,
|
||||
End = 2,
|
||||
Cancel = 3,
|
||||
}
|
||||
|
||||
#[zbus::proxy(
|
||||
default_service = "org.qemu",
|
||||
interface = "org.qemu.Display1.MultiTouch"
|
||||
)]
|
||||
pub trait MultiTouch {
|
||||
fn send_event(&self, kind: TouchEventKind, num_slot: u64, x: f64, y: f64) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn max_slots(&self) -> zbus::Result<i32>;
|
||||
}
|
|
@ -78,7 +78,7 @@ impl DeviceHandler for Handler {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[zbus::dbus_proxy(
|
||||
#[zbus::proxy(
|
||||
interface = "org.freedesktop.usbredir1",
|
||||
default_service = "org.freedesktop.usbredir1",
|
||||
default_path = "/org/freedesktop/usbredir1"
|
||||
|
@ -109,7 +109,7 @@ impl Handler {
|
|||
};
|
||||
|
||||
let (stream, peer) = UnixStream::pair()?;
|
||||
chardev.proxy.register(peer.as_raw_fd().into()).await?;
|
||||
chardev.proxy.register((&peer).into()).await?;
|
||||
|
||||
let c = ctxt.clone();
|
||||
let stream_fd = stream.as_raw_fd();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::Result;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::{io::AsRawFd, net::UnixStream};
|
||||
use std::os::unix::net::UnixStream;
|
||||
#[cfg(windows)]
|
||||
use win32::Fd;
|
||||
#[cfg(unix)]
|
||||
|
@ -21,7 +21,7 @@ use windows::Win32::System::Threading::PROCESS_DUP_HANDLE;
|
|||
pub fn prepare_uds_pass(#[cfg(windows)] peer_pid: u32, us: &UnixStream) -> Result<Fd> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
Ok(us.as_raw_fd().into())
|
||||
Ok(us.into())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
#[zbus::proxy(
|
||||
default_service = "org.qemu",
|
||||
interface = "org.qemu.Display1.VM",
|
||||
default_path = "/org/qemu/Display1/VM"
|
||||
)]
|
||||
pub trait VM {
|
||||
/// Name property
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn name(&self) -> zbus::Result<String>;
|
||||
|
||||
/// UUID property
|
||||
#[dbus_proxy(property)]
|
||||
#[zbus(property)]
|
||||
fn uuid(&self) -> zbus::Result<String>;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use windows::Win32::{
|
|||
#[cfg(feature = "qmp")]
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
pub type Fd = Vec<u8>;
|
||||
pub type Fd<'a> = Vec<u8>;
|
||||
|
||||
// A process handle
|
||||
pub struct ProcessHandle(HANDLE);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "qemu-rdp"
|
||||
version = "0.1.0"
|
||||
authors = ["Mihnea Buzatu <mihneabuzatu88@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
qemu-display = { path = "../qemu-display" }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||
keycodemap = { path = "../keycodemap" }
|
||||
bytes = "1.4"
|
||||
rustls = { version = "0.21" }
|
||||
rustls-pemfile = "1.0"
|
||||
tokio = { version = "1.28", features = ["full"] }
|
||||
tokio-rustls = "0.24"
|
||||
anyhow = "1.0"
|
||||
clap = { version = "4.2", features = ["derive", "cargo"] }
|
||||
async-trait = "0.1"
|
||||
ironrdp = { git = "https://github.com/Devolutions/IronRDP", features = ["server"] }
|
|
@ -0,0 +1,59 @@
|
|||
use clap::clap_derive::ValueEnum;
|
||||
use clap::{crate_name, Parser};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||
pub enum SecurityProtocol {
|
||||
Ssl,
|
||||
Hybrid,
|
||||
HybridEx,
|
||||
}
|
||||
|
||||
impl From<SecurityProtocol> for ironrdp::pdu::nego::SecurityProtocol {
|
||||
fn from(value: SecurityProtocol) -> Self {
|
||||
match value {
|
||||
SecurityProtocol::Ssl => ironrdp::pdu::nego::SecurityProtocol::SSL,
|
||||
SecurityProtocol::Hybrid => ironrdp::pdu::nego::SecurityProtocol::HYBRID,
|
||||
SecurityProtocol::HybridEx => ironrdp::pdu::nego::SecurityProtocol::HYBRID_EX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct ServerArgs {
|
||||
/// IP address
|
||||
#[clap(short, long, default_value = "127.0.0.1")]
|
||||
pub address: std::net::IpAddr,
|
||||
|
||||
/// IP port
|
||||
#[clap(short, long, default_value = "3389")]
|
||||
pub port: u16,
|
||||
|
||||
/// Specify the security protocols to use
|
||||
#[clap(long, value_enum, value_parser, default_value_t = SecurityProtocol::Ssl)]
|
||||
pub security_protocol: SecurityProtocol,
|
||||
|
||||
/// Path to tls certificate
|
||||
#[clap(short, long, value_parser)]
|
||||
pub cert: Option<String>,
|
||||
|
||||
/// Path to private key
|
||||
#[clap(short, long, value_parser)]
|
||||
pub key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct Args {
|
||||
#[clap(short, long, value_parser, default_value_t = format!("{}.log", crate_name!()))]
|
||||
pub log_file: String,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub server: ServerArgs,
|
||||
|
||||
/// DBUS address
|
||||
#[clap(short, long)]
|
||||
pub dbus_address: Option<String>,
|
||||
}
|
||||
|
||||
pub fn parse() -> Args {
|
||||
Args::parse()
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
use anyhow::Context;
|
||||
use qemu_display::zbus;
|
||||
|
||||
mod args;
|
||||
mod server;
|
||||
mod util;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), anyhow::Error> {
|
||||
let mut args = args::parse();
|
||||
|
||||
setup_logging(args.log_file.as_str()).context("unable to initialize logging")?;
|
||||
|
||||
let dbus = match args.dbus_address.take() {
|
||||
None => zbus::Connection::session().await,
|
||||
Some(addr) => {
|
||||
zbus::ConnectionBuilder::address(addr.as_str())?
|
||||
.build()
|
||||
.await
|
||||
}
|
||||
}
|
||||
.expect("Failed to connect to DBus");
|
||||
|
||||
server::Server::new(dbus, args.server).run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_logging(log_file: &str) -> anyhow::Result<()> {
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
use tracing::metadata::LevelFilter;
|
||||
use tracing_subscriber::prelude::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
let file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(log_file)
|
||||
.with_context(|| format!("couldn’t open {log_file}"))?;
|
||||
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.compact()
|
||||
.with_ansi(false)
|
||||
.with_writer(file);
|
||||
|
||||
let env_filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::WARN.into())
|
||||
.with_env_var("QEMURDP_LOG_LEVEL")
|
||||
.from_env_lossy();
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt_layer)
|
||||
.with(env_filter)
|
||||
.try_init()
|
||||
.context("failed to set tracing global subscriber")?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
use anyhow::Result;
|
||||
use ironrdp::{connector::DesktopSize, server::RdpServerDisplayUpdates};
|
||||
use qemu_display::{zbus, Console, ConsoleListenerHandler, Cursor, MouseSet, Scanout, Update};
|
||||
|
||||
use ironrdp::server::{BitmapUpdate, DisplayUpdate, PixelFormat, PixelOrder, RdpServerDisplay};
|
||||
|
||||
use crate::cast;
|
||||
|
||||
pub struct DisplayHandler {
|
||||
console: Console,
|
||||
}
|
||||
|
||||
struct DisplayUpdates {
|
||||
receiver: tokio::sync::mpsc::Receiver<DisplayUpdate>,
|
||||
}
|
||||
|
||||
impl DisplayHandler {
|
||||
pub async fn connect(dbus: zbus::Connection) -> Result<Self> {
|
||||
let console = Console::new(&dbus, 0).await?;
|
||||
|
||||
Ok(Self { console })
|
||||
}
|
||||
|
||||
async fn listen(&self) -> Result<DisplayUpdates> {
|
||||
let (sender, receiver) = tokio::sync::mpsc::channel::<DisplayUpdate>(32);
|
||||
let (width, height) = (
|
||||
self.console.width().await? as _,
|
||||
self.console.height().await? as _,
|
||||
);
|
||||
let desktop_size = DesktopSize { width, height };
|
||||
let listener = Listener::new(sender, desktop_size);
|
||||
self.console.unregister_listener();
|
||||
self.console.register_listener(listener).await?;
|
||||
|
||||
Ok(DisplayUpdates { receiver })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RdpServerDisplayUpdates for DisplayUpdates {
|
||||
async fn next_update(&mut self) -> Option<DisplayUpdate> {
|
||||
self.receiver.recv().await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RdpServerDisplay for DisplayHandler {
|
||||
async fn size(&mut self) -> DesktopSize {
|
||||
let width = self.console.proxy.width().await.unwrap() as u16;
|
||||
let height = self.console.proxy.height().await.unwrap() as u16;
|
||||
DesktopSize { height, width }
|
||||
}
|
||||
|
||||
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
|
||||
Ok(Box::new(self.listen().await?))
|
||||
}
|
||||
}
|
||||
|
||||
struct Listener {
|
||||
sender: tokio::sync::mpsc::Sender<DisplayUpdate>,
|
||||
}
|
||||
|
||||
impl Listener {
|
||||
fn new(sender: tokio::sync::mpsc::Sender<DisplayUpdate>, _desktop_size: DesktopSize) -> Self {
|
||||
Self { sender }
|
||||
}
|
||||
|
||||
async fn send(&mut self, update: DisplayUpdate) {
|
||||
if let Err(e) = self.sender.send(update).await {
|
||||
println!("{:?}", e);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ConsoleListenerHandler for Listener {
|
||||
async fn scanout(&mut self, scanout: Scanout) {
|
||||
let format = match scanout.format {
|
||||
537_004_168 => PixelFormat::BgrA32,
|
||||
_ => PixelFormat::RgbA32,
|
||||
};
|
||||
|
||||
let width: u16 = cast!(scanout.width);
|
||||
let height: u16 = cast!(scanout.height);
|
||||
let bitmap = DisplayUpdate::Bitmap(BitmapUpdate {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: width.try_into().unwrap(),
|
||||
height: height.try_into().unwrap(),
|
||||
format,
|
||||
order: PixelOrder::TopToBottom,
|
||||
data: scanout.data,
|
||||
});
|
||||
|
||||
self.send(bitmap).await;
|
||||
}
|
||||
|
||||
async fn update(&mut self, update: Update) {
|
||||
let format = match update.format {
|
||||
537_004_168 => PixelFormat::BgrA32,
|
||||
_ => PixelFormat::RgbA32,
|
||||
};
|
||||
|
||||
let width: u16 = cast!(update.w);
|
||||
let height: u16 = cast!(update.h);
|
||||
let bitmap = DisplayUpdate::Bitmap(BitmapUpdate {
|
||||
// TODO: fix scary conversion
|
||||
top: cast!(update.y),
|
||||
left: cast!(update.x),
|
||||
width: width.try_into().unwrap(),
|
||||
height: height.try_into().unwrap(),
|
||||
format,
|
||||
order: PixelOrder::TopToBottom,
|
||||
data: update.data,
|
||||
});
|
||||
|
||||
self.send(bitmap).await;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn scanout_dmabuf(&mut self, _scanout: qemu_display::ScanoutDMABUF) {}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn update_dmabuf(&mut self, _update: qemu_display::UpdateDMABUF) {}
|
||||
|
||||
async fn disable(&mut self) {}
|
||||
async fn mouse_set(&mut self, _set: MouseSet) {}
|
||||
async fn cursor_define(&mut self, _cursor: Cursor) {}
|
||||
fn disconnected(&mut self) {}
|
||||
fn interfaces(&self) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
use ironrdp::server::{KeyboardEvent, MouseEvent, RdpServerInputHandler};
|
||||
use qemu_display::{zbus, Console, MouseButton};
|
||||
use tokio::{
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
task,
|
||||
};
|
||||
|
||||
use crate::cast;
|
||||
|
||||
pub struct InputHandler {
|
||||
tx: Sender<InputEvent>,
|
||||
_task: task::JoinHandle<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum InputEvent {
|
||||
Keyboard(KeyboardEvent),
|
||||
Mouse(MouseEvent),
|
||||
}
|
||||
|
||||
impl RdpServerInputHandler for InputHandler {
|
||||
fn keyboard(&mut self, event: KeyboardEvent) {
|
||||
tracing::debug!(?event);
|
||||
if let Err(e) = self.tx.try_send(InputEvent::Keyboard(event)) {
|
||||
eprintln!("keyboard error: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse(&mut self, event: MouseEvent) {
|
||||
tracing::debug!(?event);
|
||||
if let Err(e) = self.tx.try_send(InputEvent::Mouse(event)) {
|
||||
eprintln!("keyboard error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn input_receive_task(mut rx: Receiver<InputEvent>, console: Console) {
|
||||
loop {
|
||||
let res = match rx.recv().await {
|
||||
Some(InputEvent::Keyboard(ev)) => match ev {
|
||||
KeyboardEvent::Pressed { code, .. } => console.keyboard.press(code as u32).await,
|
||||
KeyboardEvent::Released { code, .. } => console.keyboard.release(code as u32).await,
|
||||
other => {
|
||||
eprintln!("unhandled keyboard event: {:?}", other);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Some(InputEvent::Mouse(ev)) => match ev {
|
||||
MouseEvent::Move { x, y } => {
|
||||
tracing::debug!(?x, ?y);
|
||||
console.mouse.set_abs_position(cast!(x), cast!(y)).await
|
||||
}
|
||||
MouseEvent::RightPressed => console.mouse.press(MouseButton::Right).await,
|
||||
MouseEvent::RightReleased => console.mouse.release(MouseButton::Right).await,
|
||||
MouseEvent::LeftPressed => console.mouse.press(MouseButton::Left).await,
|
||||
MouseEvent::LeftReleased => console.mouse.release(MouseButton::Left).await,
|
||||
MouseEvent::VerticalScroll { value } => {
|
||||
let motion = if value > 0 {
|
||||
MouseButton::WheelUp
|
||||
} else {
|
||||
MouseButton::WheelDown
|
||||
};
|
||||
|
||||
console.mouse.press(motion).await
|
||||
}
|
||||
other => {
|
||||
eprintln!("unhandled input event: {:?}", other);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
None => break,
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
eprintln!("input handling error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputHandler {
|
||||
pub async fn connect(dbus: zbus::Connection) -> anyhow::Result<InputHandler> {
|
||||
let console = Console::new(&dbus, 0).await?;
|
||||
let (tx, rx) = tokio::sync::mpsc::channel(30);
|
||||
let _task = task::spawn(async move { input_receive_task(rx, console).await });
|
||||
|
||||
Ok(Self { _task, tx })
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
mod display;
|
||||
mod input;
|
||||
|
||||
use anyhow::Error;
|
||||
use qemu_display::zbus;
|
||||
use rustls::ServerConfig;
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
use std::{fs::File, io::BufReader, sync::Arc};
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
|
||||
use ironrdp::server::RdpServer;
|
||||
|
||||
use crate::args::ServerArgs;
|
||||
|
||||
use display::DisplayHandler;
|
||||
use input::InputHandler;
|
||||
|
||||
pub struct Server {
|
||||
dbus: zbus::Connection,
|
||||
args: ServerArgs,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new(dbus: zbus::Connection, args: ServerArgs) -> Self {
|
||||
Self { dbus, args }
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<(), Error> {
|
||||
let tls = self
|
||||
.args
|
||||
.cert
|
||||
.as_ref()
|
||||
.zip(self.args.key.as_ref())
|
||||
.map(|(cert, key)| acceptor(cert, key).unwrap());
|
||||
|
||||
let handler = InputHandler::connect(self.dbus.clone()).await?;
|
||||
let display = DisplayHandler::connect(self.dbus.clone()).await?;
|
||||
|
||||
let mut server = RdpServer::builder()
|
||||
.with_addr((self.args.address, self.args.port))
|
||||
.with_tls(tls.unwrap())
|
||||
.with_input_handler(handler)
|
||||
.with_display_handler(display)
|
||||
.build();
|
||||
|
||||
server.run().await
|
||||
}
|
||||
}
|
||||
|
||||
fn acceptor(cert_path: &str, key_path: &str) -> Result<TlsAcceptor, Error> {
|
||||
let cert = certs(&mut BufReader::new(File::open(cert_path)?))?[0].clone();
|
||||
let key = pkcs8_private_keys(&mut BufReader::new(File::open(key_path)?))?[0].clone();
|
||||
|
||||
let server_config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(vec![rustls::Certificate(cert)], rustls::PrivateKey(key))
|
||||
.expect("bad certificate/key");
|
||||
|
||||
Ok(TlsAcceptor::from(Arc::new(server_config)))
|
||||
}
|
|
@ -12,9 +12,9 @@ qmp = ["qemu-display/qmp"]
|
|||
log = "0.4"
|
||||
pretty_env_logger = "0.4"
|
||||
once_cell = "1.5"
|
||||
zbus = { version = "4" }
|
||||
qemu-display = { path = "../qemu-display" }
|
||||
keycodemap = { path = "../keycodemap" }
|
||||
zbus.workspace = true
|
||||
qemu-display.workspace = true
|
||||
keycodemap.workspace = true
|
||||
futures-util = "0.3"
|
||||
futures = "0.3"
|
||||
async-trait = "0.1"
|
||||
|
|
|
@ -221,10 +221,7 @@ fn watch_clipboard(
|
|||
}
|
||||
|
||||
fn clipboard_from_selection(selection: ClipboardSelection) -> Option<(gdk::Clipboard, usize)> {
|
||||
let display = match gdk::Display::default() {
|
||||
Some(display) => display,
|
||||
None => return None,
|
||||
};
|
||||
let display = gdk::Display::default()?;
|
||||
|
||||
match selection {
|
||||
ClipboardSelection::Clipboard => Some((display.clipboard(), 0)),
|
||||
|
|
|
@ -4,7 +4,7 @@ use glib::MainContext;
|
|||
use gtk::{gio, glib, prelude::*};
|
||||
use qemu_display::{util, Chardev, Console, Display};
|
||||
use rdw::gtk;
|
||||
use std::{cell::RefCell, convert::TryFrom, sync::Arc};
|
||||
use std::{cell::RefCell, convert::TryFrom, rc::Rc};
|
||||
use zbus::names::BusName;
|
||||
|
||||
mod audio;
|
||||
|
@ -23,7 +23,7 @@ struct Inner {
|
|||
|
||||
#[derive(Clone)]
|
||||
struct App {
|
||||
inner: Arc<Inner>,
|
||||
inner: Rc<Inner>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -36,7 +36,7 @@ struct AppOptions {
|
|||
wait: bool,
|
||||
}
|
||||
|
||||
async fn display_from_opt(opt: Arc<RefCell<AppOptions>>) -> Option<Display<'static>> {
|
||||
async fn display_from_opt(opt: Rc<RefCell<AppOptions>>) -> Option<Display<'static>> {
|
||||
#[cfg(feature = "qmp")]
|
||||
if let Some(qmp_addr) = &opt.borrow().qmp {
|
||||
return Some(Display::new_qmp(qmp_addr).await.unwrap());
|
||||
|
@ -76,6 +76,9 @@ async fn display_from_opt(opt: Arc<RefCell<AppOptions>>) -> Option<Display<'stat
|
|||
.unwrap()
|
||||
.map(Into::into)
|
||||
} else {
|
||||
if opt.borrow().wait {
|
||||
unimplemented!(); // FIXME
|
||||
}
|
||||
BusName::try_from("org.qemu").ok()
|
||||
};
|
||||
|
||||
|
@ -142,7 +145,7 @@ impl App {
|
|||
None,
|
||||
);
|
||||
|
||||
let opt: Arc<RefCell<AppOptions>> = Default::default();
|
||||
let opt: Rc<RefCell<AppOptions>> = Default::default();
|
||||
let opt_clone = opt.clone();
|
||||
app.connect_handle_local_options(move |_, opt| {
|
||||
let mut app_opt = opt_clone.borrow_mut();
|
||||
|
@ -170,7 +173,7 @@ impl App {
|
|||
});
|
||||
|
||||
let app = App {
|
||||
inner: Arc::new(Inner {
|
||||
inner: Rc::new(Inner {
|
||||
app,
|
||||
#[cfg(unix)]
|
||||
usbredir: Default::default(),
|
||||
|
|
|
@ -7,11 +7,11 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
qemu-display = { path = "../qemu-display" }
|
||||
keycodemap = { path ="../keycodemap" }
|
||||
qemu-display.workspace = true
|
||||
keycodemap.workspace = true
|
||||
vnc = "0.4.0"
|
||||
clap = { version = "3.2", features = ["derive"] }
|
||||
zbus = { version = "3.0" }
|
||||
zbus.workspace = true
|
||||
libc = "0.2.86"
|
||||
image = "0.23.14"
|
||||
derivative = "2.2.0"
|
||||
|
|
|
@ -287,6 +287,10 @@ impl ConsoleListenerHandler for ConsoleListener {
|
|||
fn disconnected(&mut self) {
|
||||
dbg!();
|
||||
}
|
||||
|
||||
fn interfaces(&self) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -317,7 +321,7 @@ impl Server {
|
|||
}
|
||||
|
||||
fn stop_console(&self) -> Result<(), Box<dyn Error>> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
let inner = self.inner.lock().unwrap();
|
||||
inner.console.unregister_listener();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ edition = "2018"
|
|||
log = "0.4"
|
||||
pretty_env_logger = "0.4"
|
||||
once_cell = "1.5"
|
||||
zbus = { version = "3.0" }
|
||||
qemu-display = { path = "../qemu-display" }
|
||||
zbus.workspace = true
|
||||
qemu-display.workspace = true
|
||||
futures = "0.3.13"
|
||||
|
||||
[dependencies.vte]
|
||||
|
|
|
@ -37,7 +37,7 @@ fn main() {
|
|||
c.proxy.name().await.expect("Chardev not found");
|
||||
|
||||
let (p0, p1) = UnixStream::pair().unwrap();
|
||||
if c.proxy.register(p1.as_raw_fd().into()).await.is_ok() {
|
||||
if c.proxy.register((&p1).into()).await.is_ok() {
|
||||
let ostream = unsafe { gio::UnixOutputStream::with_fd(p0.as_raw_fd()) };
|
||||
let istream = unsafe { gio::UnixInputStream::take_fd(p0) }
|
||||
.dynamic_cast::<gio::PollableInputStream>()
|
||||
|
|
Loading…
Reference in New Issue