From 609a0732b4724d96c74b6885574952643e9a428a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 30 Mar 2021 16:01:44 +0400 Subject: [PATCH] gtk: draw client cursor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- qemu-display-listener/src/console_listener.rs | 15 +++-- qemu-display-listener/src/mouse.rs | 3 + qemu-gtk4/src/console.rs | 20 ++++++- qemu-gtk4/src/console_area.rs | 59 ++++++++++++++++++- qemu-vnc/src/main.rs | 2 +- 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/qemu-display-listener/src/console_listener.rs b/qemu-display-listener/src/console_listener.rs index c75f60e..22b484c 100644 --- a/qemu-display-listener/src/console_listener.rs +++ b/qemu-display-listener/src/console_listener.rs @@ -54,6 +54,13 @@ impl Drop for ScanoutDMABUF { } } +#[derive(Debug, Copy, Clone)] +pub struct MouseSet { + pub x: i32, + pub y: i32, + pub on: i32, +} + // TODO: replace events mpsc with async traits #[derive(Debug)] pub enum ConsoleEvent { @@ -66,11 +73,7 @@ pub enum ConsoleEvent { w: i32, h: i32, }, - MouseSet { - x: i32, - y: i32, - on: i32, - }, + MouseSet(MouseSet), CursorDefine { width: i32, height: i32, @@ -160,7 +163,7 @@ impl> ConsoleListener { } fn mouse_set(&mut self, x: i32, y: i32, on: i32) { - self.send(ConsoleEvent::MouseSet { x, y, on }) + self.send(ConsoleEvent::MouseSet(MouseSet { x, y, on })) } fn cursor_define(&mut self, width: i32, height: i32, hot_x: i32, hot_y: i32, data: Vec) { diff --git a/qemu-display-listener/src/mouse.rs b/qemu-display-listener/src/mouse.rs index cc7334b..8c1a88b 100644 --- a/qemu-display-listener/src/mouse.rs +++ b/qemu-display-listener/src/mouse.rs @@ -24,4 +24,7 @@ pub trait Mouse { /// SetAbsPosition method fn set_abs_position(&self, x: u32, y: u32) -> zbus::Result<()>; + + #[dbus_proxy(property)] + fn is_absolute(&self) -> zbus::Result; } diff --git a/qemu-gtk4/src/console.rs b/qemu-gtk4/src/console.rs index 9d56642..4b32a16 100644 --- a/qemu-gtk4/src/console.rs +++ b/qemu-gtk4/src/console.rs @@ -75,7 +75,14 @@ mod imp { self.area.add_controller(&ec); ec.connect_motion(clone!(@weak obj => move |_, x, y| { let priv_ = imp::QemuConsole::from_instance(&obj); - priv_.motion(x, y); + let c = obj.qemu_console(); + if let Ok(abs) = c.mouse.is_absolute() { + if abs { + priv_.motion(x, y); + } else { + dbg!() + } + } })); let ec = gtk::GestureClick::new(); @@ -284,9 +291,16 @@ mod imp { let pb = pb.scale_simple(width * scale, height * scale, gdk::gdk_pixbuf::InterpType::Bilinear).unwrap(); let tex = gdk::Texture::new_for_pixbuf(&pb); let cur = gdk::Cursor::from_texture(&tex, hot_x * scale, hot_y * scale, None); - priv_.area.set_cursor(Some(&cur)); + priv_.area.cursor_define(cur); + } + Event::MouseSet(m) => { + priv_.area.mouse_set(m); + let c = obj.qemu_console(); + if let Ok(abs) = c.mouse.is_absolute() { + priv_.area.set_cursor_abs(abs); + } + priv_.area.queue_render(); } - _t => { } } Continue(true) }), diff --git a/qemu-gtk4/src/console_area.rs b/qemu-gtk4/src/console_area.rs index db3afcb..3937dde 100644 --- a/qemu-gtk4/src/console_area.rs +++ b/qemu-gtk4/src/console_area.rs @@ -2,14 +2,14 @@ use glib::subclass::prelude::*; use glib::translate::*; use gtk::prelude::*; use gtk::subclass::widget::WidgetImplExt; -use gtk::{gdk, glib}; -use std::cell::Cell; +use gtk::{gdk, glib, graphene}; +use std::cell::{Cell, RefCell}; use std::ffi::{CStr, CString}; use crate::egl; use crate::error::*; use gl::{self, types::*}; -use qemu_display_listener::{Scanout, ScanoutDMABUF, Update}; +use qemu_display_listener::{MouseSet, Scanout, ScanoutDMABUF, Update}; mod imp { use super::*; @@ -23,6 +23,9 @@ mod imp { pub texture_blit_flip_prog: Cell, pub scanout: Cell>, pub scanout_size: Cell<(u32, u32)>, + pub cursor_abs: Cell, + pub cursor: RefCell>, + pub mouse: Cell>, } #[glib::object_subclass] @@ -91,6 +94,31 @@ mod imp { self.parent_size_allocate(widget, width, height, baseline); widget.notify("resize-hack"); } + + fn snapshot(&self, widget: &Self::Type, snapshot: >k::Snapshot) { + self.parent_snapshot(widget, snapshot); + + if !self.cursor_abs.get() { + if let Some(mouse) = self.mouse.get() { + if mouse.on != 0 { + if let Some(cursor) = self.cursor.borrow().clone() { + if let Some(texture) = cursor.get_texture() { + let sf = widget.get_scale_factor(); + snapshot.append_texture( + &texture, + &graphene::Rect::new( + (mouse.x - cursor.get_hotspot_x() / sf) as f32, + (mouse.y - cursor.get_hotspot_y() / sf) as f32, + (texture.get_width() / sf) as f32, + (texture.get_height() / sf) as f32, + ), + ) + } + } + } + } + } + } } impl GLAreaImpl for QemuConsoleArea { @@ -104,6 +132,7 @@ mod imp { gl::Viewport(vp.x, vp.y, vp.width, vp.height); self.texture_blit(false); } + // parent will return to update call false } @@ -383,6 +412,30 @@ impl QemuConsoleArea { let y = (y - vp.y) as f64 * (sh as f64 / vp.height as f64); Some((x as u32, y as u32)) } + + pub fn set_cursor_abs(&self, abs: bool) { + let priv_ = imp::QemuConsoleArea::from_instance(self); + + priv_.cursor_abs.set(abs); + if abs { + if let Some(cursor) = priv_.cursor.borrow().clone() { + self.set_cursor(Some(&cursor)); + } + } else { + self.set_cursor_from_name(Some("none")) + } + self.queue_render(); + } + + pub fn cursor_define(&self, cursor: gdk::Cursor) { + let priv_ = imp::QemuConsoleArea::from_instance(self); + priv_.cursor.replace(Some(cursor)); + } + + pub fn mouse_set(&self, mouse: MouseSet) { + let priv_ = imp::QemuConsoleArea::from_instance(self); + priv_.mouse.set(Some(mouse)); + } } unsafe fn compile_shader(type_: GLenum, src: &CStr) -> GLuint { diff --git a/qemu-vnc/src/main.rs b/qemu-vnc/src/main.rs index 7d61a3f..14c71cf 100644 --- a/qemu-vnc/src/main.rs +++ b/qemu-vnc/src/main.rs @@ -316,7 +316,7 @@ impl Server { inner.tx.send(Event::ConsoleUpdate(rect)).unwrap(); } ConsoleEvent::CursorDefine { .. } => {} - ConsoleEvent::MouseSet { .. } => {} + ConsoleEvent::MouseSet(_) => {} e => { dbg!(e); }