gtk: draw client cursor

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-03-30 16:01:44 +04:00
parent ced718c264
commit 609a0732b4
5 changed files with 86 additions and 13 deletions

View File

@ -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<E: 'static + EventSender<Event = ConsoleEvent>> ConsoleListener<E> {
}
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<u8>) {

View File

@ -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<bool>;
}

View File

@ -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)
}),

View File

@ -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<GLuint>,
pub scanout: Cell<Option<ScanoutDMABUF>>,
pub scanout_size: Cell<(u32, u32)>,
pub cursor_abs: Cell<bool>,
pub cursor: RefCell<Option<gdk::Cursor>>,
pub mouse: Cell<Option<MouseSet>>,
}
#[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: &gtk::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 {

View File

@ -316,7 +316,7 @@ impl Server {
inner.tx.send(Event::ConsoleUpdate(rect)).unwrap();
}
ConsoleEvent::CursorDefine { .. } => {}
ConsoleEvent::MouseSet { .. } => {}
ConsoleEvent::MouseSet(_) => {}
e => {
dbg!(e);
}