[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 3/6] ui/gtk: Handle relative mode events correctly with Waylan
From: |
Vivek Kasireddy |
Subject: |
[PATCH v2 3/6] ui/gtk: Handle relative mode events correctly with Wayland compositors |
Date: |
Thu, 17 Nov 2022 17:44:23 -0800 |
gdk_device_warp() is a no-op when running in a Host environment that is
Wayland based as the Wayland protocol does not allow clients to move
the cursor to a specific location. This presents a problem when Qemu is
running with GTK UI + relative mouse mode, as we would no longer be able
to warp the cursor to the Guest's location like it is done when running
in Xorg-based environments. To solve this problem, we just store the
Guest's cursor location and add/subtract the difference compared to the
Host's cursor location when injecting the next motion event.
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Dongwon Kim <dongwon.kim@intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
include/ui/gtk.h | 2 ++
ui/gtk.c | 71 ++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index ae0f53740d..f8df042f95 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -130,6 +130,8 @@ struct GtkDisplayState {
gboolean last_set;
int last_x;
int last_y;
+ int guest_x;
+ int guest_y;
int grab_x_root;
int grab_y_root;
VirtualConsole *kbd_owner;
diff --git a/ui/gtk.c b/ui/gtk.c
index 9d0c27c9e7..8ccc948813 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -447,22 +447,44 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
int x, int y, int visible)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
- GdkDisplay *dpy;
+ GtkDisplayState *s = vc->s;
+ GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area);
gint x_root, y_root;
if (qemu_input_is_absolute()) {
return;
}
+ /*
+ * When the mouse cursor moves from one vc (or connector in guest
+ * terminology) to another, some guest compositors (e.g. Weston)
+ * set x and y to 0 on the old vc. We check for this condition
+ * and return right away as we do not want to move the cursor
+ * back to the old vc (at 0, 0).
+ */
+ if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
+ if (s->ptr_owner != vc || (x == 0 && y == 0)) {
+ return;
+ }
+ }
+ /*
+ * Since Wayland compositors do not support clients warping/moving
+ * the cursor, we just store the Guest's cursor location here and
+ * add or subtract the difference when injecting the next motion event.
+ */
+ if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
+ s->guest_x = x;
+ s->guest_y = y;
+ return;
+ }
- dpy = gtk_widget_get_display(vc->gfx.drawing_area);
gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area),
x * vc->gfx.scale_x, y * vc->gfx.scale_y,
&x_root, &y_root);
gdk_device_warp(gd_get_pointer(dpy),
gtk_widget_get_screen(vc->gfx.drawing_area),
x_root, y_root);
- vc->s->last_x = x;
- vc->s->last_y = y;
+ s->last_x = x;
+ s->last_y = y;
}
static void gd_cursor_define(DisplayChangeListener *dcl,
@@ -869,6 +891,7 @@ static gboolean gd_motion_event(GtkWidget *widget,
GdkEventMotion *motion,
{
VirtualConsole *vc = opaque;
GtkDisplayState *s = vc->s;
+ GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area);
GdkWindow *window;
int x, y;
int mx, my;
@@ -915,14 +938,41 @@ static gboolean gd_motion_event(GtkWidget *widget,
GdkEventMotion *motion,
0, surface_height(vc->gfx.ds));
qemu_input_event_sync();
} else if (s->last_set && s->ptr_owner == vc) {
- qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x);
- qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y);
+ int dx = x - s->last_x;
+ int dy = y - s->last_y;
+
+ /*
+ * To converge/sync the Guest's and Host's cursor locations more
+ * accurately, we can avoid doing the / 2 below but it appears
+ * some Guest compositors (e.g. Weston) do not like large jumps;
+ * so we just do / 2 which seems to work reasonably well.
+ */
+ if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
+ dx += s->guest_x ? (x - s->guest_x) / 2 : 0;
+ dy += s->guest_y ? (y - s->guest_y) / 2 : 0;
+ s->guest_x = 0;
+ s->guest_y = 0;
+ }
+ qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, dx);
+ qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, dy);
qemu_input_event_sync();
}
s->last_x = x;
s->last_y = y;
s->last_set = TRUE;
+ /*
+ * When running in Wayland environment, we don't grab the cursor; so,
+ * we want to return right away as it would not make sense to warp it
+ * (below).
+ */
+ if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
+ if (s->ptr_owner != vc) {
+ s->ptr_owner = vc;
+ }
+ return TRUE;
+ }
+
if (!qemu_input_is_absolute() && s->ptr_owner == vc) {
GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area);
GdkDisplay *dpy = gtk_widget_get_display(widget);
@@ -961,11 +1011,16 @@ static gboolean gd_button_event(GtkWidget *widget,
GdkEventButton *button,
{
VirtualConsole *vc = opaque;
GtkDisplayState *s = vc->s;
+ GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area);
InputButton btn;
- /* implicitly grab the input at the first click in the relative mode */
+ /* Implicitly grab the input at the first click in the relative mode.
+ * However, when running in Wayland environment, some limited testing
+ * indicates that grabs are not very reliable.
+ */
if (button->button == 1 && button->type == GDK_BUTTON_PRESS &&
- !qemu_input_is_absolute() && s->ptr_owner != vc) {
+ !qemu_input_is_absolute() && s->ptr_owner != vc &&
+ !GDK_IS_WAYLAND_DISPLAY(dpy)) {
if (!vc->window) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
TRUE);
--
2.37.2
- [PATCH v2 0/6] ui/gtk: Add a new parameter to assign connectors/monitors (v2), Vivek Kasireddy, 2022/11/17
- [PATCH v2 1/6] ui/gtk: Consider the scaling factor when getting the root coordinates, Vivek Kasireddy, 2022/11/17
- [PATCH v2 2/6] ui/gtk-gl-area: Don't forget to calculate the scaling factors in draw, Vivek Kasireddy, 2022/11/17
- [PATCH v2 4/6] ui/gtk: Disable the scanout when a detached tab is closed, Vivek Kasireddy, 2022/11/17
- [PATCH v2 3/6] ui/gtk: Handle relative mode events correctly with Wayland compositors,
Vivek Kasireddy <=
- [PATCH v2 5/6] ui/gtk: Factor out tab window creation into a separate function, Vivek Kasireddy, 2022/11/17
- [PATCH v2 6/6] ui/gtk: Add a new parameter to assign connectors/monitors to GFX VCs (v2), Vivek Kasireddy, 2022/11/17