Fix clone!() macro

This commit is contained in:
Marc-André Lureau 2024-07-22 20:05:35 +04:00
parent 15f63a920e
commit 56b38e54d7
4 changed files with 420 additions and 254 deletions

View File

@ -62,8 +62,10 @@ impl ClipboardHandler for InnerHandler {
let p = p.clone(); let p = p.clone();
let mime = mime.to_string(); let mime = mime.to_string();
Some(Box::pin( Some(Box::pin(clone!(
clone!(@strong stream => @default-return panic!(), async move { #[strong]
stream,
async move {
match p.request(selection, &[&mime]).await { match p.request(selection, &[&mime]).await {
Ok((_, data)) => { Ok((_, data)) => {
let bytes = glib::Bytes::from(&data); let bytes = glib::Bytes::from(&data);
@ -75,8 +77,8 @@ impl ClipboardHandler for InnerHandler {
Err(glib::Error::new(gio::IOErrorEnum::Failed, &err)) Err(glib::Error::new(gio::IOErrorEnum::Failed, &err))
} }
} }
}), }
)) )))
}); });
if let Err(e) = clipboard.set_content(Some(&content)) { if let Err(e) = clipboard.set_content(Some(&content)) {

View File

@ -99,64 +99,122 @@ mod imp {
self.obj().set_mouse_absolute(false); self.obj().set_mouse_absolute(false);
self.obj().connect_key_event( self.obj().connect_key_event(clone!(
clone!(@weak self as this => move |_, keyval, keycode, event| { #[weak(rename_to = this)]
let mapped = this.keymap.get().and_then(|m| m.get(keycode as usize)).map(|x| *x as u32); self,
move |_, keyval, keycode, event| {
let mapped = this
.keymap
.get()
.and_then(|m| m.get(keycode as usize))
.map(|x| *x as u32);
log::debug!("key-{event:?}: {keyval} {keycode} -> {mapped:?}"); log::debug!("key-{event:?}: {keyval} {keycode} -> {mapped:?}");
if let Some(qnum) = mapped { if let Some(qnum) = mapped {
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
if event.contains(rdw::KeyEvent::PRESS) { #[weak]
let _ = this.obj().console().keyboard.press(qnum).await; this,
async move {
if event.contains(rdw::KeyEvent::PRESS) {
let _ = this.obj().console().keyboard.press(qnum).await;
}
if event.contains(rdw::KeyEvent::RELEASE) {
let _ = this.obj().console().keyboard.release(qnum).await;
}
} }
if event.contains(rdw::KeyEvent::RELEASE) { ));
let _ = this.obj().console().keyboard.release(qnum).await;
}
}));
} }
}), }
); ));
self.obj() self.obj().connect_motion(clone!(
.connect_motion(clone!(@weak self as this => move |_, x, y| { #[weak(rename_to = this)]
self,
move |_, x, y| {
log::trace!("motion: {:?}", (x, y)); log::trace!("motion: {:?}", (x, y));
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
if !this.obj().console().mouse.is_absolute().await.unwrap_or(false) { #[weak]
return; this,
async move {
if !this
.obj()
.console()
.mouse
.is_absolute()
.await
.unwrap_or(false)
{
return;
}
if let Err(e) = this
.obj()
.console()
.mouse
.set_abs_position(x as _, y as _)
.await
{
log::warn!("{e}");
}
} }
if let Err(e) = this.obj().console().mouse.set_abs_position(x as _, y as _).await { ));
log::warn!("{e}"); }
} ));
}));
}));
self.obj() self.obj().connect_motion_relative(clone!(
.connect_motion_relative(clone!(@weak self as this => move |_, dx, dy| { #[weak(rename_to = this)]
self,
move |_, dx, dy| {
log::trace!("motion-relative: {:?}", (dx, dy)); log::trace!("motion-relative: {:?}", (dx, dy));
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
let _ = this.obj().console().mouse.rel_motion(dx.round() as _, dy.round() as _).await; #[weak]
})); this,
})); async move {
let _ = this
.obj()
.console()
.mouse
.rel_motion(dx.round() as _, dy.round() as _)
.await;
}
));
}
));
self.obj() self.obj().connect_mouse_press(clone!(
.connect_mouse_press(clone!(@weak self as this => move |_, button| { #[weak(rename_to = this)]
self,
move |_, button| {
log::debug!("mouse-press: {:?}", button); log::debug!("mouse-press: {:?}", button);
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
let button = from_gdk_button(button); #[weak]
let _ = this.obj().console().mouse.press(button).await; this,
})); async move {
})); let button = from_gdk_button(button);
let _ = this.obj().console().mouse.press(button).await;
}
));
}
));
self.obj() self.obj().connect_mouse_release(clone!(
.connect_mouse_release(clone!(@weak self as this => move |_, button| { #[weak(rename_to = this)]
self,
move |_, button| {
log::debug!("mouse-release: {:?}", button); log::debug!("mouse-release: {:?}", button);
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
let button = from_gdk_button(button); #[weak]
let _ = this.obj().console().mouse.release(button).await; this,
})); async move {
})); let button = from_gdk_button(button);
let _ = this.obj().console().mouse.release(button).await;
}
));
}
));
self.obj() self.obj().connect_scroll_discrete(clone!(
.connect_scroll_discrete(clone!(@weak self as this => move |_, scroll| { #[weak(rename_to = this)]
self,
move |_, scroll| {
use qemu_display::MouseButton; use qemu_display::MouseButton;
log::debug!("scroll-discrete: {:?}", scroll); log::debug!("scroll-discrete: {:?}", scroll);
@ -169,18 +227,36 @@ mod imp {
return; return;
} }
}; };
MainContext::default().spawn_local(clone!(@weak this => async move { MainContext::default().spawn_local(clone!(
let _ = this.obj().console().mouse.press(button).await; #[weak]
let _ = this.obj().console().mouse.release(button).await; this,
})); async move {
})); let _ = this.obj().console().mouse.press(button).await;
let _ = this.obj().console().mouse.release(button).await;
}
));
}
));
self.obj().connect_resize_request(clone!(@weak self as this => move |_, width, height, wmm, hmm| { self.obj().connect_resize_request(clone!(
log::debug!("resize-request: {:?}", (width, height, wmm, hmm)); #[weak(rename_to = this)]
MainContext::default().spawn_local(clone!(@weak this => async move { self,
let _ = this.obj().console().proxy.set_ui_info(wmm as _, hmm as _, 0, 0, width, height).await; move |_, width, height, wmm, hmm| {
})); log::debug!("resize-request: {:?}", (width, height, wmm, hmm));
})); MainContext::default().spawn_local(clone!(
#[weak]
this,
async move {
let _ = this
.obj()
.console()
.proxy
.set_ui_info(wmm as _, hmm as _, 0, 0, width, height)
.await;
}
));
}
));
} }
} }
@ -190,152 +266,216 @@ mod imp {
self.keymap.set(rdw::keymap_qnum()); self.keymap.set(rdw::keymap_qnum());
MainContext::default().spawn_local(clone!(@weak self as this => async move { MainContext::default().spawn_local(clone!(
let console = this.console.get().unwrap(); #[weak(rename_to = this)]
// we have to use a channel, because widget is not Send.. self,
let (sender, mut receiver) = futures::channel::mpsc::unbounded(); async move {
let handler = ConsoleHandler { sender }; let console = this.console.get().unwrap();
console.register_listener(handler.clone()).await.unwrap(); // we have to use a channel, because widget is not Send..
#[cfg(windows)] let (sender, mut receiver) = futures::channel::mpsc::unbounded();
{ let handler = ConsoleHandler { sender };
console.set_map_listener(handler.clone()).await.unwrap(); console.register_listener(handler.clone()).await.unwrap();
console.set_d3d11_listener(handler.clone()).await.unwrap(); #[cfg(windows)]
{
console.set_map_listener(handler.clone()).await.unwrap();
console.set_d3d11_listener(handler.clone()).await.unwrap();
}
MainContext::default().spawn_local(clone!(
#[weak]
this,
async move {
while let Some(e) = receiver.next().await {
use ConsoleEvent::*;
match e {
Scanout(s) => {
if s.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", s.format);
continue;
}
this.obj()
.set_display_size(Some((s.width as _, s.height as _)));
this.obj().update_area(
0,
0,
s.width as _,
s.height as _,
s.stride as _,
Some(&s.data),
);
}
Update(u) => {
if u.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", u.format);
continue;
}
this.obj().update_area(
u.x as _,
u.y as _,
u.w as _,
u.h as _,
u.stride as _,
Some(&u.data),
);
}
#[cfg(windows)]
ScanoutMap(s) => {
use windows::Win32::System::Memory::{
MapViewOfFile, FILE_MAP_READ,
};
log::debug!("{s:?}");
if s.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", s.format);
continue;
}
let handle = HANDLE(s.handle as _);
let size = s.height as usize * s.stride as usize;
let offset = s.offset as isize;
let ptr = unsafe {
MapViewOfFile(
handle,
FILE_MAP_READ,
0,
0,
s.offset as usize + size,
)
};
if ptr.is_null() {
log::warn!("Failed to map scanout!");
continue;
}
let map = MemoryMap {
ptr,
handle,
offset,
size,
};
this.obj()
.set_display_size(Some((s.width as _, s.height as _)));
this.obj().update_area(
0,
0,
s.width as _,
s.height as _,
s.stride as _,
Some(map.as_bytes()),
);
this.scanout_map.replace(Some((map, s.stride)));
}
#[cfg(windows)]
UpdateMap(u) => {
log::debug!("{u:?}");
let scanout_map = this.scanout_map.borrow();
let Some((map, stride)) = scanout_map.as_ref() else {
log::warn!("No mapped scanout!");
continue;
};
let stride = *stride;
let bytes = map.as_bytes();
this.obj().update_area(
u.x as _,
u.y as _,
u.w as _,
u.h as _,
stride as _,
Some(
&bytes[u.y as usize * stride as usize
+ u.x as usize * 4..],
),
);
}
#[cfg(windows)]
ScanoutD3dTexture2d(s) => {
log::debug!("{s:?}");
this.obj().set_display_size(Some((s.w as _, s.h as _)));
this.obj().set_d3d11_texture2d_scanout(Some(
rdw::RdwD3d11Texture2dScanout {
handle: s.handle as _,
tex_width: s.tex_width,
tex_height: s.tex_height,
y0_top: s.y0_top,
x: s.x,
y: s.y,
w: s.w,
h: s.h,
},
));
}
#[cfg(windows)]
UpdateD3dTexture2d { wait_tx, update } => {
this.obj().set_d3d11_texture2d_can_acquire(true);
this.obj().update_area(
update.x, update.y, update.w, update.h, 0, None,
);
this.obj().set_d3d11_texture2d_can_acquire(false);
let _ = wait_tx.send(());
}
#[cfg(unix)]
ScanoutDMABUF(s) => {
log::trace!("{s:?}");
this.obj()
.set_display_size(Some((s.width as _, s.height as _)));
this.obj().set_dmabuf_scanout(rdw::RdwDmabufScanout {
width: s.width,
height: s.height,
stride: s.stride,
fourcc: s.fourcc,
y0_top: s.y0_top,
modifier: s.modifier,
fd: s.into_raw_fd(),
});
}
#[cfg(unix)]
UpdateDMABUF { wait_tx, update } => {
this.obj().update_area(
update.x, update.y, update.w, update.h, 0, None,
);
let _ = wait_tx.send(());
}
Disable => {
log::warn!("Display disabled");
}
Disconnected => {
log::warn!("Console disconnected");
}
CursorDefine(c) => {
log::debug!("{c:?}");
let cursor = rdw::Display::make_cursor(
&c.data, c.width, c.height, c.hot_x, c.hot_y, 1,
);
this.obj().define_cursor(Some(cursor));
}
MouseSet(m) => {
if m.on != 0 {
this.obj()
.set_cursor_position(Some((m.x as _, m.y as _)));
} else {
this.obj().set_cursor_position(None);
}
}
}
}
}
));
let mut abs_changed = console.mouse.receive_is_absolute_changed().await;
this.obj()
.set_mouse_absolute(console.mouse.is_absolute().await.unwrap_or(false));
MainContext::default().spawn_local(clone!(
#[weak]
this,
async move {
while let Some(abs) = abs_changed.next().await {
if let Ok(abs) = abs.get().await {
this.obj().set_mouse_absolute(abs);
}
}
}
));
} }
));
MainContext::default().spawn_local(clone!(@weak this => async move {
while let Some(e) = receiver.next().await {
use ConsoleEvent::*;
match e {
Scanout(s) => {
if s.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", s.format);
continue;
}
this.obj().set_display_size(Some((s.width as _, s.height as _)));
this.obj().update_area(0, 0, s.width as _, s.height as _, s.stride as _, Some(&s.data));
}
Update(u) => {
if u.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", u.format);
continue;
}
this.obj().update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, Some(&u.data));
}
#[cfg(windows)]
ScanoutMap(s) => {
use windows::Win32::System::Memory::{FILE_MAP_READ, MapViewOfFile};
log::debug!("{s:?}");
if s.format != 0x20020888 {
log::warn!("Format not yet supported: {:X}", s.format);
continue;
}
let handle = HANDLE(s.handle as _);
let size = s.height as usize * s.stride as usize;
let offset = s.offset as isize;
let ptr = unsafe { MapViewOfFile(handle, FILE_MAP_READ, 0, 0, s.offset as usize + size) };
if ptr.is_null() {
log::warn!("Failed to map scanout!");
continue;
}
let map = MemoryMap { ptr, handle, offset, size };
this.obj().set_display_size(Some((s.width as _, s.height as _)));
this.obj().update_area(0, 0, s.width as _, s.height as _, s.stride as _, Some(map.as_bytes()));
this.scanout_map.replace(Some((map, s.stride)));
}
#[cfg(windows)]
UpdateMap(u) => {
log::debug!("{u:?}");
let scanout_map = this.scanout_map.borrow();
let Some((map, stride)) = scanout_map.as_ref() else {
log::warn!("No mapped scanout!");
continue;
};
let stride = *stride;
let bytes = map.as_bytes();
this.obj().update_area(u.x as _, u.y as _, u.w as _, u.h as _, stride as _, Some(&bytes[u.y as usize * stride as usize + u.x as usize * 4..]));
}
#[cfg(windows)]
ScanoutD3dTexture2d(s) => {
log::debug!("{s:?}");
this.obj().set_display_size(Some((s.w as _, s.h as _)));
this.obj().set_d3d11_texture2d_scanout(Some(rdw::RdwD3d11Texture2dScanout {
handle: s.handle as _,
tex_width: s.tex_width,
tex_height: s.tex_height,
y0_top: s.y0_top,
x: s.x,
y: s.y,
w: s.w,
h: s.h,
}));
}
#[cfg(windows)]
UpdateD3dTexture2d { wait_tx, update } => {
this.obj().set_d3d11_texture2d_can_acquire(true);
this.obj().update_area(update.x, update.y, update.w, update.h, 0, None);
this.obj().set_d3d11_texture2d_can_acquire(false);
let _ = wait_tx.send(());
}
#[cfg(unix)]
ScanoutDMABUF(s) => {
log::trace!("{s:?}");
this.obj().set_display_size(Some((s.width as _, s.height as _)));
this.obj().set_dmabuf_scanout(rdw::RdwDmabufScanout {
width: s.width,
height: s.height,
stride: s.stride,
fourcc: s.fourcc,
y0_top: s.y0_top,
modifier: s.modifier,
fd: s.into_raw_fd(),
});
}
#[cfg(unix)]
UpdateDMABUF { wait_tx, update } => {
this.obj().update_area(update.x, update.y, update.w, update.h, 0, None);
let _ = wait_tx.send(());
}
Disable => {
log::warn!("Display disabled");
}
Disconnected => {
log::warn!("Console disconnected");
}
CursorDefine(c) => {
log::debug!("{c:?}");
let cursor = rdw::Display::make_cursor(
&c.data,
c.width,
c.height,
c.hot_x,
c.hot_y,
1,
);
this.obj().define_cursor(Some(cursor));
}
MouseSet(m) => {
if m.on != 0 {
this.obj().set_cursor_position(Some((m.x as _, m.y as _)));
} else {
this.obj().set_cursor_position(None);
}
}
}
}
}));
let mut abs_changed = console.mouse.receive_is_absolute_changed().await;
this.obj().set_mouse_absolute(console.mouse.is_absolute().await.unwrap_or(false));
MainContext::default().spawn_local(clone!(@weak this => async move {
while let Some(abs) = abs_changed.next().await {
if let Ok(abs) = abs.get().await {
this.obj().set_mouse_absolute(abs);
}
}
}));
}));
} }
} }

View File

@ -19,16 +19,25 @@ impl Handler {
let usbredir = self.usbredir.clone(); let usbredir = self.usbredir.clone();
widget widget
.model() .model()
.connect_items_changed(clone!(@weak widget => move |model, pos, _rm, add| { .connect_items_changed(clone!(move |model, pos, _rm, add| {
let usbredir = usbredir.clone(); let usbredir = usbredir.clone();
MainContext::default().spawn_local(clone!(@weak model => async move { MainContext::default().spawn_local(clone!(
for pos in pos..pos + add { #[weak]
let item = model.item(pos).unwrap(); model,
if let Some(dev) = item.downcast_ref::<rdw::UsbDevice>().unwrap().device() { async move {
item.set_property("active", usbredir.is_device_connected(&dev).await); for pos in pos..pos + add {
let item = model.item(pos).unwrap();
if let Some(dev) =
item.downcast_ref::<rdw::UsbDevice>().unwrap().device()
{
item.set_property(
"active",
usbredir.is_device_connected(&dev).await,
);
}
} }
} }
})); ));
})); }));
let usbredir = self.usbredir.clone(); let usbredir = self.usbredir.clone();
@ -39,29 +48,38 @@ impl Handler {
}; };
let usbredir = usbredir.clone(); let usbredir = usbredir.clone();
MainContext::default().spawn_local(clone!(@weak item, @weak widget => async move { MainContext::default().spawn_local(clone!(
match usbredir.set_device_state(&device, state).await { #[weak]
Ok(active) => item.set_property("active", active), item,
Err(e) => { #[weak]
if state { widget,
item.set_property("active", false); async move {
match usbredir.set_device_state(&device, state).await {
Ok(active) => item.set_property("active", active),
Err(e) => {
if state {
item.set_property("active", false);
}
widget.emit_by_name::<bool>("show-error", &[&e.to_string()]);
} }
widget.emit_by_name::<bool>("show-error", &[&e.to_string()]); }
},
} }
})); ));
}); });
let usbredir = self.usbredir.clone(); let usbredir = self.usbredir.clone();
MainContext::default().spawn_local(clone!(@weak widget => async move { MainContext::default().spawn_local(clone!(
use futures::stream::StreamExt; // for `next` #[weak]
widget widget,
.set_property("free-channels", usbredir.n_free_channels().await); async move {
let mut n = usbredir.receive_n_free_channels().await; use futures::stream::StreamExt; // for `next`
while let Some(n) = n.next().await { widget.set_property("free-channels", usbredir.n_free_channels().await);
widget.set_property("free-channels", n); let mut n = usbredir.receive_n_free_channels().await;
while let Some(n) = n.next().await {
widget.set_property("free-channels", n);
}
} }
})); ));
widget widget
} }

View File

@ -29,40 +29,46 @@ fn main() {
window.set_child(Some(&term)); window.set_child(Some(&term));
let id = chardev_id.clone(); let id = chardev_id.clone();
MainContext::default().spawn_local(clone!(@strong window => async move { MainContext::default().spawn_local(clone!(
let conn = Connection::session().await #[strong]
.expect("Failed to connect to session D-Bus"); window,
async move {
let conn = Connection::session()
.await
.expect("Failed to connect to session D-Bus");
let c = Chardev::new(&conn, &id).await.unwrap(); let c = Chardev::new(&conn, &id).await.unwrap();
c.proxy.name().await.expect("Chardev not found"); c.proxy.name().await.expect("Chardev not found");
let (p0, p1) = UnixStream::pair().unwrap(); let (p0, p1) = UnixStream::pair().unwrap();
if c.proxy.register((&p1).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 ostream = unsafe { gio::UnixOutputStream::with_fd(p0.as_raw_fd()) };
let istream = unsafe { gio::UnixInputStream::take_fd(p0) } let istream = unsafe { gio::UnixInputStream::take_fd(p0) }
.dynamic_cast::<gio::PollableInputStream>() .dynamic_cast::<gio::PollableInputStream>()
.unwrap(); .unwrap();
let mut read = istream.into_async_read().unwrap(); let mut read = istream.into_async_read().unwrap();
term.connect_commit(move |_, text, _| { term.connect_commit(move |_, text, _| {
let _res = ostream.write(text.as_bytes(), gio::Cancellable::NONE); // TODO cancellable and error let _res = ostream.write(text.as_bytes(), gio::Cancellable::NONE);
}); // TODO cancellable and error
});
loop { loop {
let mut buffer = [0u8; 8192]; let mut buffer = [0u8; 8192];
match read.read(&mut buffer[..]).await { match read.read(&mut buffer[..]).await {
Ok(0) => break, Ok(0) => break,
Ok(len) => { Ok(len) => {
term.feed(&buffer[..len]); term.feed(&buffer[..len]);
} }
Err(e) => { Err(e) => {
log::warn!("{}", e); log::warn!("{}", e);
break; break;
}
} }
} }
} }
} }
})); ));
window.show(); window.show();
}); });