[Spice-commits] 14 commits - src/map-file src/spice-glib-sym-file src/spice-widget.c src/spice-widget-cairo.c src/spice-widget-egl.c src/spice-widget.h src/spice-widget-priv.h tools/spicy.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Aug 19 09:46:50 UTC 2020


 src/map-file             |    1 
 src/spice-glib-sym-file  |    1 
 src/spice-widget-cairo.c |   22 ++++--
 src/spice-widget-egl.c   |    2 
 src/spice-widget-priv.h  |    1 
 src/spice-widget.c       |  167 +++++++++++++++++++++++++++++++++++++----------
 src/spice-widget.h       |    1 
 tools/spicy.c            |    3 
 8 files changed, 157 insertions(+), 41 deletions(-)

New commits:
commit 515a84ba125c72a9b64431cb62b91ce96caa6790
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Aug 8 18:10:38 2020 +0200

    spice-widget: prevent mouse cursor from being too small
    
    Caps the minimum scale of the mouse cursor to 50% so that it is still
    visible even if the window is too small.
    
    This also workarounds a GDK warning when SpiceDisplay is used in
    remote-viewer. Upon its initialization there is a possible race
    condition, where update_mouse_cursor is called but the widget still has
    a size of 1x1. In such case, the calculated scale is very small and the
    mouse surface width and height are both zero, causing a warning:
    
    gdk_cursor_new_from_surface: assertion '0 <= x && x < cairo_image_surface_get_width (surface)' failed
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 4f2bb65..6e0fa54 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -3018,6 +3018,8 @@ static void update_mouse_cursor(SpiceDisplay *display)
     spice_display_get_scaling(display, &scale, NULL, NULL, NULL, NULL);
     scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
 
+    scale = MAX(0.5, scale);
+
     cairo_surface_destroy(d->cursor_surface);
 
     /* scale mouse cursor surface */
commit cbdda3334724f5bb7afe9e21ce0e972e53e71fdc
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 11 01:46:49 2020 +0200

    spice-widget: ensure a 640x480 initial size on HiDPI
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 8574779..4f2bb65 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -209,19 +209,16 @@ static void update_size_request(SpiceDisplay *display)
     gint reqwidth, reqheight;
     gint scale_factor;
 
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+
     if (d->resize_guest_enable || d->allow_scaling) {
-        reqwidth = 640;
-        reqheight = 480;
+        reqwidth = 640 / scale_factor;
+        reqheight = 480 / scale_factor;
     } else {
-        reqwidth = d->area.width;
-        reqheight = d->area.height;
+        reqwidth = d->area.width / scale_factor;
+        reqheight = d->area.height / scale_factor;
     }
 
-    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
-
-    reqwidth /= scale_factor;
-    reqheight /= scale_factor;
-
     gtk_widget_set_size_request(GTK_WIDGET(display), reqwidth, reqheight);
     recalc_geometry(GTK_WIDGET(display));
     update_mouse_cursor(display);
commit d589fdafe35d78608820843b0932ff1377f5e016
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 25 00:15:53 2020 +0200

    spice-widget-egl: make mouse cursor scale with window size
    
    This is the corresponding fix for EGL server mouse.
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget-egl.c b/src/spice-widget-egl.c
index 3bffd05..e31e322 100644
--- a/src/spice-widget-egl.c
+++ b/src/spice-widget-egl.c
@@ -593,6 +593,8 @@ void spice_egl_update_display(SpiceDisplay *display)
         GdkPixbuf *image = d->mouse_pixbuf;
         int width = gdk_pixbuf_get_width(image);
         int height = gdk_pixbuf_get_height(image);
+        width = ceil(width * s);
+        height = ceil(height * s);
 
         glBindTexture(GL_TEXTURE_2D, d->egl.tex_pointer_id);
         glEnable(GL_BLEND);
commit 5e0a461bec4fbd4d4573938b49bcde23409ec55c
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 11 01:41:10 2020 +0200

    spice-widget: make mouse cursor scale with window size
    
    Make mouse cursor size scale with the window size on Cairo/EGL client
    mouse and Cairo server mouse. The cursor size should always be the same
    as how big it really is inside the virtual machine.
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 4ab0e6a..8574779 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -127,6 +127,7 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *di
 static void channel_destroy(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *display);
 static void cursor_invalidate(SpiceDisplay *display);
 static bool egl_enabled(SpiceDisplayPrivate *d);
+static void update_mouse_cursor(SpiceDisplay *display);
 static void update_area(SpiceDisplay *display, gint x, gint y, gint width, gint height);
 static void release_keys(SpiceDisplay *display);
 static void size_allocate(GtkWidget *widget, GtkAllocation *conf, gpointer data);
@@ -196,6 +197,7 @@ static void scaling_updated(SpiceDisplay *display)
 
     recalc_geometry(GTK_WIDGET(display));
     if (d->canvas.surface && window) { /* if not yet shown */
+        update_mouse_cursor(display);
         gtk_widget_queue_draw(GTK_WIDGET(display));
     }
     update_size_request(display);
@@ -222,6 +224,7 @@ static void update_size_request(SpiceDisplay *display)
 
     gtk_widget_set_size_request(GTK_WIDGET(display), reqwidth, reqheight);
     recalc_geometry(GTK_WIDGET(display));
+    update_mouse_cursor(display);
 }
 
 static void update_keyboard_focus(SpiceDisplay *display, gboolean state)
@@ -2276,6 +2279,8 @@ static void size_allocate(GtkWidget *widget, GtkAllocation *conf, gpointer data)
     d->mx = conf->x;
     d->my = conf->y;
 
+    update_mouse_cursor(display);
+
 #ifdef G_OS_WIN32
     if (d->mouse_grab_active) {
         try_mouse_ungrab(display);
@@ -2970,9 +2975,7 @@ static void cursor_set(SpiceCursorChannel *channel,
 {
     SpiceDisplay *display = data;
     SpiceDisplayPrivate *d = display->priv;
-    GdkCursor *cursor = NULL;
     SpiceCursorShape *cursor_shape;
-    gint hotspot_x, hotspot_y;
 
     g_object_get(G_OBJECT(channel), "cursor", &cursor_shape, NULL);
     if (G_UNLIKELY(cursor_shape == NULL || cursor_shape->data == NULL)) {
@@ -2984,7 +2987,6 @@ static void cursor_set(SpiceCursorChannel *channel,
 
     cursor_invalidate(display);
     g_clear_object(&d->mouse_pixbuf);
-    cairo_surface_destroy(d->cursor_surface);
     d->mouse_pixbuf = gdk_pixbuf_new_from_data(cursor_shape->data,
                                                GDK_COLORSPACE_RGB,
                                                TRUE, 8,
@@ -2992,15 +2994,59 @@ static void cursor_set(SpiceCursorChannel *channel,
                                                cursor_shape->height,
                                                cursor_shape->width * 4,
                                                cursor_shape_destroy, cursor_shape);
-    d->cursor_surface = gdk_cairo_surface_create_from_pixbuf(d->mouse_pixbuf, 0,
-                                                             gtk_widget_get_window(GTK_WIDGET(display)));
-    hotspot_x = d->mouse_hotspot.x = cursor_shape->hot_spot_x;
-    hotspot_y = d->mouse_hotspot.y = cursor_shape->hot_spot_y;
+    d->mouse_hotspot.x = cursor_shape->hot_spot_x;
+    d->mouse_hotspot.y = cursor_shape->hot_spot_y;
+
+    update_mouse_cursor(display);
+}
+
+static void update_mouse_cursor(SpiceDisplay *display)
+{
+    SpiceDisplayPrivate *d = display->priv;
+    GdkCursor *cursor = NULL;
+    cairo_t *cursor_ctx;
+    cairo_surface_t *surface, *target;
+    double scale;
+    gint scale_factor;
+    gint hotspot_x, hotspot_y;
+
+    if (G_UNLIKELY(!d->mouse_pixbuf)) {
+        return;
+    }
+
+    if (!d->ready || !d->monitor_ready) {
+        return;
+    }
+
+    spice_display_get_scaling(display, &scale, NULL, NULL, NULL, NULL);
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+
+    cairo_surface_destroy(d->cursor_surface);
+
+    /* scale mouse cursor surface */
+    surface = gdk_cairo_surface_create_from_pixbuf(d->mouse_pixbuf, 0, gtk_widget_get_window(GTK_WIDGET(display)));
+    target = cairo_image_surface_create(cairo_image_surface_get_format(surface),
+                                        scale * gdk_pixbuf_get_width(d->mouse_pixbuf),
+                                        scale * gdk_pixbuf_get_height(d->mouse_pixbuf));
+
+    cairo_surface_set_device_scale(target, scale_factor, scale_factor);
+    cursor_ctx = cairo_create(target);
+    cairo_scale(cursor_ctx, scale, scale);
+    cairo_set_source_surface(cursor_ctx, surface, 0, 0);
+    cairo_paint(cursor_ctx);
+
+    d->cursor_surface = cairo_surface_reference(cairo_get_target(cursor_ctx));
+
+    cairo_surface_destroy(target);
+    cairo_surface_destroy(surface);
+    cairo_destroy(cursor_ctx);
+
+    hotspot_x = d->mouse_hotspot.x * scale;
+    hotspot_y = d->mouse_hotspot.y * scale;
 
 #ifdef GDK_WINDOWING_X11
     /* undo hotspot scaling in gdkcursor */
     if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(GTK_WIDGET(display)))) {
-        gint scale_factor = gdk_window_get_scale_factor(gtk_widget_get_window(GTK_WIDGET(display)));
         hotspot_x /= scale_factor;
         hotspot_y /= scale_factor;
     }
commit a15ba78aff6550dc1204783e4322b3a79694b9c9
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 11 01:04:37 2020 +0200

    spice-widget: correctly position mouse on ungrab
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index d1f9ee6..4ab0e6a 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -1309,6 +1309,7 @@ static void try_mouse_ungrab(SpiceDisplay *display)
     SpiceDisplayPrivate *d = display->priv;
     double s;
     int x, y;
+    gint scale_factor;
     GdkWindow *window;
 
     if (!d->mouse_grab_active)
@@ -1323,12 +1324,13 @@ static void try_mouse_ungrab(SpiceDisplay *display)
 
     d->mouse_grab_active = false;
 
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
     spice_display_get_scaling(display, &s, &x, &y, NULL, NULL);
 
     window = gtk_widget_get_window(GTK_WIDGET(display));
     gdk_window_get_root_coords(window,
-                               x + d->mouse_guest_x * s,
-                               y + d->mouse_guest_y * s,
+                               (x + d->mouse_guest_x * s) / scale_factor,
+                               (y + d->mouse_guest_y * s) / scale_factor,
                                &x, &y);
 
     gdk_device_warp(spice_gdk_window_get_pointing_device(window),
commit 63644cdb2c78f70259b7c4b603625085fc86f264
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 11 00:59:39 2020 +0200

    spice-widget: treat cairo/egl equally on HiDPI
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 968a836..d1f9ee6 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -205,7 +205,7 @@ static void update_size_request(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
     gint reqwidth, reqheight;
-    gint scale_factor = 1;
+    gint scale_factor;
 
     if (d->resize_guest_enable || d->allow_scaling) {
         reqwidth = 640;
@@ -215,9 +215,7 @@ static void update_size_request(SpiceDisplay *display)
         reqheight = d->area.height;
     }
 
-    if (egl_enabled(d)) {
-        scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
-    }
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
 
     reqwidth /= scale_factor;
     reqheight /= scale_factor;
@@ -1358,14 +1356,12 @@ static void recalc_geometry(GtkWidget *widget)
     SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = display->priv;
     gdouble zoom = 1.0;
-    gint scale_factor = 1;
+    gint scale_factor;
 
     if (spice_cairo_is_scaled(display))
         zoom = (gdouble)d->zoom_level / 100;
 
-    if (egl_enabled(d)) {
-        scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
-    }
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
 
     DISPLAY_DEBUG(display,
                   "recalc geom monitor: %d:%d, guest +%d+%d:%dx%d, window %dx%d, zoom %g, scale %d",
@@ -2056,14 +2052,12 @@ static void transform_input(SpiceDisplay *display,
     SpiceDisplayPrivate *d = display->priv;
     int display_x, display_y, display_w, display_h;
     double is;
-    gint scale_factor = 1;
+    gint scale_factor;
 
     spice_display_get_scaling(display, NULL,
                               &display_x, &display_y,
                               &display_w, &display_h);
-    if (egl_enabled(d)) {
-        scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
-    }
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
     /* For input we need a different scaling factor in order to
        be able to reach the full width of a display. For instance, consider
        a display of 100 pixels showing in a window 10 pixels wide. The normal
@@ -2906,6 +2900,7 @@ static void invalidate(SpiceChannel *channel,
     int display_x, display_y;
     int x1, y1, x2, y2;
     double s;
+    gint scale_factor;
     GdkRectangle rect = {
         .x = x,
         .y = y,
@@ -2926,11 +2921,13 @@ static void invalidate(SpiceChannel *channel,
     if (d->canvas.convert)
         do_color_convert(display, &rect);
 
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
     spice_display_get_scaling(display, &s,
                               &display_x, &display_y,
                               NULL, NULL);
+    display_x /= scale_factor;
+    display_y /= scale_factor;
 
-    gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
     if (s * scale_factor > 1) {
         rect.x -= 1;
         rect.y -= 1;
@@ -2938,10 +2935,10 @@ static void invalidate(SpiceChannel *channel,
         rect.height += 2;
     }
 
-    x1 = floor ((rect.x - d->area.x) * s);
-    y1 = floor ((rect.y - d->area.y) * s);
-    x2 = ceil ((rect.x - d->area.x + rect.width) * s);
-    y2 = ceil ((rect.y - d->area.y + rect.height) * s);
+    x1 = floor ((rect.x - d->area.x) * s) / scale_factor;
+    y1 = floor ((rect.y - d->area.y) * s) / scale_factor;
+    x2 = ceil ((rect.x - d->area.x + rect.width) * s) / scale_factor;
+    y2 = ceil ((rect.y - d->area.y + rect.height) * s) / scale_factor;
 
     queue_draw_area(display,
                     display_x + x1, display_y + y1,
@@ -3049,6 +3046,7 @@ static void cursor_hide(SpiceCursorChannel *channel, gpointer data)
     update_mouse_pointer(display);
 }
 
+/* Output is always in physical device pixel, not logical pixel, regardless of EGL */
 G_GNUC_INTERNAL
 void spice_display_get_scaling(SpiceDisplay *display,
                                double *s_out,
@@ -3060,12 +3058,9 @@ void spice_display_get_scaling(SpiceDisplay *display,
     int ww, wh;
     int x, y, w, h;
     double s;
-    gint scale_factor = 1;
 
     if (gtk_widget_get_realized (GTK_WIDGET(display))) {
-        if (egl_enabled(d)) {
-            scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
-        }
+        gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
         ww = gtk_widget_get_allocated_width(GTK_WIDGET(display)) * scale_factor;
         wh = gtk_widget_get_allocated_height(GTK_WIDGET(display)) * scale_factor;
     } else {
@@ -3115,6 +3110,8 @@ static void cursor_invalidate(SpiceDisplay *display)
     SpiceDisplayPrivate *d = display->priv;
     double s;
     int x, y;
+    gint redraw_x, redraw_y;
+    gint scale_factor;
 
     if (!gtk_widget_get_realized (GTK_WIDGET(display)))
         return;
@@ -3126,10 +3123,15 @@ static void cursor_invalidate(SpiceDisplay *display)
         return;
 
     spice_display_get_scaling(display, &s, &x, &y, NULL, NULL);
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+
+    redraw_x = floor((d->mouse_guest_x - d->mouse_hotspot.x - d->area.x) * s) + x;
+    redraw_y = floor((d->mouse_guest_y - d->mouse_hotspot.y - d->area.y) * s) + y;
+    redraw_x /= scale_factor;
+    redraw_y /= scale_factor;
 
     queue_draw_area(display,
-                    floor ((d->mouse_guest_x - d->mouse_hotspot.x - d->area.x) * s) + x,
-                    floor ((d->mouse_guest_y - d->mouse_hotspot.y - d->area.y) * s) + y,
+                    redraw_x, redraw_y,
                     ceil (gdk_pixbuf_get_width(d->mouse_pixbuf) * s),
                     ceil (gdk_pixbuf_get_height(d->mouse_pixbuf) * s));
 }
commit c905e80e59f517ad1a04947f25dad47263443094
Author: Haochen Tong <i at hexchain.org>
Date:   Sat Jul 11 00:57:26 2020 +0200

    spice-widget-cairo: respect device scale factor
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget-cairo.c b/src/spice-widget-cairo.c
index 89b2154..4d25c08 100644
--- a/src/spice-widget-cairo.c
+++ b/src/spice-widget-cairo.c
@@ -25,6 +25,7 @@ G_GNUC_INTERNAL
 int spice_cairo_image_create(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
+    gint scale_factor;
 
     if (d->canvas.surface != NULL)
         return 0;
@@ -46,6 +47,9 @@ int spice_cairo_image_create(SpiceDisplay *display)
              d->canvas.width, d->canvas.height, d->canvas.stride);
     }
 
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+    cairo_surface_set_device_scale(d->canvas.surface, scale_factor, scale_factor);
+
     return 0;
 }
 
@@ -70,9 +74,17 @@ void spice_cairo_draw_event(SpiceDisplay *display, cairo_t *cr)
     int x, y;
     int ww, wh;
     int w, h;
+    gint scale_factor;
 
+    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
     spice_display_get_scaling(display, &s, &x, &y, &w, &h);
 
+    /* convert physical pixel to logical */
+    x /= scale_factor;
+    y /= scale_factor;
+    w /= scale_factor;
+    h /= scale_factor;
+
     ww = gtk_widget_get_allocated_width(GTK_WIDGET(display));
     wh = gtk_widget_get_allocated_height(GTK_WIDGET(display));
 
@@ -117,11 +129,11 @@ void spice_cairo_draw_event(SpiceDisplay *display, cairo_t *cr)
             d->mouse_guest_x != -1 && d->mouse_guest_y != -1 &&
             !d->show_cursor &&
             spice_gtk_session_get_pointer_grabbed(d->gtk_session)) {
-            GdkPixbuf *image = d->mouse_pixbuf;
-            if (image != NULL) {
-                gdk_cairo_set_source_pixbuf(cr, image,
-                                            d->mouse_guest_x - d->mouse_hotspot.x,
-                                            d->mouse_guest_y - d->mouse_hotspot.y);
+            cairo_surface_t *surface = d->cursor_surface;
+            if (surface != NULL) {
+                cairo_set_source_surface(cr, surface,
+                                         (double)(d->mouse_guest_x - d->mouse_hotspot.x) / scale_factor,
+                                         (double)(d->mouse_guest_y - d->mouse_hotspot.y) / scale_factor);
                 cairo_paint(cr);
             }
         }
commit 9db4ae96a2118ceb7ca682a00d971352c231c085
Author: Haochen Tong <i at hexchain.org>
Date:   Fri Jul 10 22:51:55 2020 +0200

    spice-widget: fix typo (wrap -> warp)
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 629ff5d..968a836 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -1209,7 +1209,7 @@ static void try_mouse_grab(SpiceDisplay *display)
     d->mouse_last_y = -1;
 }
 
-static void mouse_wrap(SpiceDisplay *display, GdkEventMotion *motion)
+static void mouse_warp(SpiceDisplay *display, GdkEventMotion *motion)
 {
     SpiceDisplayPrivate *d = display->priv;
     gint xr, yr;
@@ -1219,7 +1219,7 @@ static void mouse_wrap(SpiceDisplay *display, GdkEventMotion *motion)
     g_return_if_fail(GetClipCursor(&clip));
     xr = clip.left + (clip.right - clip.left) / 2;
     yr = clip.top + (clip.bottom - clip.top) / 2;
-    /* the clip rectangle has no offset, so we can't use gdk_wrap_pointer */
+    /* the clip rectangle has no offset, so we can't use gdk_display_warp_pointer */
     SetCursorPos(xr, yr);
     d->mouse_last_x = -1;
     d->mouse_last_y = -1;
@@ -2128,7 +2128,7 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
             d->mouse_last_x = x;
             d->mouse_last_y = y;
             if (dx != 0 || dy != 0)
-                mouse_wrap(display, motion);
+                mouse_warp(display, motion);
         }
         break;
     default:
@@ -3538,4 +3538,4 @@ void spice_display_get_preferred_size(SpiceDisplay *display, int *width, int *he
 
     if (height)
         *height = d->area.height;
-}
\ No newline at end of file
+}
commit 18dfbb9e7974d153a1758aef58208591111de80e
Author: Haochen Tong <i at hexchain.org>
Date:   Fri Jul 10 22:11:35 2020 +0200

    spice-widget: add an API to get guest display size
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/map-file b/src/map-file
index d46f2bc..acdd38f 100644
--- a/src/map-file
+++ b/src/map-file
@@ -33,6 +33,7 @@ spice_display_channel_gl_draw_done;
 spice_display_get_gl_scanout;
 spice_display_get_grab_keys;
 spice_display_get_pixbuf;
+spice_display_get_preferred_size;
 spice_display_get_primary;
 spice_display_get_type;
 spice_display_gl_draw_done;
diff --git a/src/spice-glib-sym-file b/src/spice-glib-sym-file
index c3b2561..72e6ef0 100644
--- a/src/spice-glib-sym-file
+++ b/src/spice-glib-sym-file
@@ -29,6 +29,7 @@ spice_display_channel_get_primary
 spice_display_channel_get_type
 spice_display_channel_gl_draw_done
 spice_display_get_gl_scanout
+spice_display_get_preferred_size
 spice_display_get_primary
 spice_display_gl_draw_done
 spice_file_transfer_task_cancel
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 50775e2..629ff5d 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -3520,3 +3520,22 @@ GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay *display)
 
     return pixbuf;
 }
+
+/**
+ * spice_display_get_preferred_size:
+ * @display: a #SpiceDisplay
+ * @width: the preferred width of the display, in physical pixel
+ * @height: the preferred height of the display, in physical pixel
+ *
+ * Get the preferred width and height of the display.
+ **/
+void spice_display_get_preferred_size(SpiceDisplay *display, int *width, int *height)
+{
+    SpiceDisplayPrivate *d = display->priv;
+
+    if (width)
+        *width = d->area.width;
+
+    if (height)
+        *height = d->area.height;
+}
\ No newline at end of file
diff --git a/src/spice-widget.h b/src/spice-widget.h
index e0b1fb3..ead5d7c 100644
--- a/src/spice-widget.h
+++ b/src/spice-widget.h
@@ -79,6 +79,7 @@ SpiceGrabSequence *spice_display_get_grab_keys(SpiceDisplay *display);
 void spice_display_send_keys(SpiceDisplay *display, const guint *keyvals,
                              int nkeyvals, SpiceDisplayKeyEvent kind);
 GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay *display);
+void spice_display_get_preferred_size(SpiceDisplay *display, int *width, int *height);
 
 G_END_DECLS
 
diff --git a/tools/spicy.c b/tools/spicy.c
index 8ca62f9..437a298 100644
--- a/tools/spicy.c
+++ b/tools/spicy.c
@@ -587,8 +587,7 @@ static void menu_cb_resize_to(GtkAction *action G_GNUC_UNUSED,
     spin_x = gtk_spin_button_new_with_range(0, G_MAXINT, 10);
     spin_y = gtk_spin_button_new_with_range(0, G_MAXINT, 10);
 
-    gtk_widget_get_preferred_width(win->spice, NULL, &width);
-    gtk_widget_get_preferred_height(win->spice, NULL, &height);
+    spice_display_get_preferred_size(SPICE_DISPLAY(win->spice), &width, &height);
 
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_width), width);
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_height), height);
commit b30598293b1c48b9dc0eddfde5a9fc996a83939c
Author: Haochen Tong <i at hexchain.org>
Date:   Fri Jul 10 11:23:44 2020 +0200

    spice-widget: fix widget size request on HiDPI when scaling is disabled
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index b7938c1..50775e2 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -126,6 +126,7 @@ static void recalc_geometry(GtkWidget *widget);
 static void channel_new(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *display);
 static void channel_destroy(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *display);
 static void cursor_invalidate(SpiceDisplay *display);
+static bool egl_enabled(SpiceDisplayPrivate *d);
 static void update_area(SpiceDisplay *display, gint x, gint y, gint width, gint height);
 static void release_keys(SpiceDisplay *display);
 static void size_allocate(GtkWidget *widget, GtkAllocation *conf, gpointer data);
@@ -204,6 +205,7 @@ static void update_size_request(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
     gint reqwidth, reqheight;
+    gint scale_factor = 1;
 
     if (d->resize_guest_enable || d->allow_scaling) {
         reqwidth = 640;
@@ -213,6 +215,13 @@ static void update_size_request(SpiceDisplay *display)
         reqheight = d->area.height;
     }
 
+    if (egl_enabled(d)) {
+        scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+    }
+
+    reqwidth /= scale_factor;
+    reqheight /= scale_factor;
+
     gtk_widget_set_size_request(GTK_WIDGET(display), reqwidth, reqheight);
     recalc_geometry(GTK_WIDGET(display));
 }
commit a945a3c24b11de017a3b22acb5085fec59efa662
Author: Haochen Tong <i at hexchain.org>
Date:   Wed Jul 8 21:53:08 2020 +0200

    spice-widget: fix hotspot position on X11/HiDPI
    
    GDK scales hotspot coordinates using screen scale factor on X11. We need
    to undo this to get the correct hotspot behavior, otherwise mouse
    selection becomes very inaccurate and difficult in the guest.
    
    See [1].
    
    [1] https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.21/gdk/x11/gdkcursor-x11.c#L556-557
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index a620084..b7938c1 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2964,6 +2964,7 @@ static void cursor_set(SpiceCursorChannel *channel,
     SpiceDisplayPrivate *d = display->priv;
     GdkCursor *cursor = NULL;
     SpiceCursorShape *cursor_shape;
+    gint hotspot_x, hotspot_y;
 
     g_object_get(G_OBJECT(channel), "cursor", &cursor_shape, NULL);
     if (G_UNLIKELY(cursor_shape == NULL || cursor_shape->data == NULL)) {
@@ -2985,12 +2986,22 @@ static void cursor_set(SpiceCursorChannel *channel,
                                                cursor_shape_destroy, cursor_shape);
     d->cursor_surface = gdk_cairo_surface_create_from_pixbuf(d->mouse_pixbuf, 0,
                                                              gtk_widget_get_window(GTK_WIDGET(display)));
-    d->mouse_hotspot.x = cursor_shape->hot_spot_x;
-    d->mouse_hotspot.y = cursor_shape->hot_spot_y;
+    hotspot_x = d->mouse_hotspot.x = cursor_shape->hot_spot_x;
+    hotspot_y = d->mouse_hotspot.y = cursor_shape->hot_spot_y;
+
+#ifdef GDK_WINDOWING_X11
+    /* undo hotspot scaling in gdkcursor */
+    if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(GTK_WIDGET(display)))) {
+        gint scale_factor = gdk_window_get_scale_factor(gtk_widget_get_window(GTK_WIDGET(display)));
+        hotspot_x /= scale_factor;
+        hotspot_y /= scale_factor;
+    }
+#endif
+
     cursor = gdk_cursor_new_from_surface(gtk_widget_get_display(GTK_WIDGET(display)),
                                          d->cursor_surface,
-                                         d->mouse_hotspot.x,
-                                         d->mouse_hotspot.y);
+                                         hotspot_x,
+                                         hotspot_y);
 
 #if HAVE_EGL
     if (egl_enabled(d))
commit 3c9efe24bdfb1bdbcdd5f734b22f49b521fdad77
Author: Haochen Tong <i at hexchain.org>
Date:   Wed Jul 8 19:30:21 2020 +0200

    spice-widget: fix EGL input coordinate on HiDPI
    
    Fixes #127.
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 6407990..a620084 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2072,8 +2072,8 @@ static void transform_input(SpiceDisplay *display,
     */
     is = ((double)(d->area.width-1) / (double)(display_w-1)) * scale_factor;
 
-    window_x -= display_x;
-    window_y -= display_y;
+    window_x -= display_x / scale_factor;
+    window_y -= display_y / scale_factor;
 
     *input_x = floor (window_x * is);
     *input_y = floor (window_y * is);
commit dddd48ad3dc2dcafed96a3e9542c72e1e00ee9fe
Author: Haochen Tong <i at hexchain.org>
Date:   Wed Jul 8 16:05:04 2020 +0200

    spice-widget: correctly scale mouse pointer on HiDPI
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget-priv.h b/src/spice-widget-priv.h
index 99b3da6..a9883d6 100644
--- a/src/spice-widget-priv.h
+++ b/src/spice-widget-priv.h
@@ -106,6 +106,7 @@ struct _SpiceDisplayPrivate {
     int                     mouse_last_y;
     int                     mouse_guest_x;
     int                     mouse_guest_y;
+    cairo_surface_t         *cursor_surface;
 
     bool                    keyboard_grab_active;
     bool                    keyboard_have_focus;
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 273167c..6407990 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -474,6 +474,7 @@ static void spice_display_finalize(GObject *obj)
     g_clear_object(&d->show_cursor);
     g_clear_object(&d->mouse_cursor);
     g_clear_object(&d->mouse_pixbuf);
+    cairo_surface_destroy(d->cursor_surface);
 
     G_OBJECT_CLASS(spice_display_parent_class)->finalize(obj);
 }
@@ -2974,6 +2975,7 @@ static void cursor_set(SpiceCursorChannel *channel,
 
     cursor_invalidate(display);
     g_clear_object(&d->mouse_pixbuf);
+    cairo_surface_destroy(d->cursor_surface);
     d->mouse_pixbuf = gdk_pixbuf_new_from_data(cursor_shape->data,
                                                GDK_COLORSPACE_RGB,
                                                TRUE, 8,
@@ -2981,12 +2983,14 @@ static void cursor_set(SpiceCursorChannel *channel,
                                                cursor_shape->height,
                                                cursor_shape->width * 4,
                                                cursor_shape_destroy, cursor_shape);
+    d->cursor_surface = gdk_cairo_surface_create_from_pixbuf(d->mouse_pixbuf, 0,
+                                                             gtk_widget_get_window(GTK_WIDGET(display)));
     d->mouse_hotspot.x = cursor_shape->hot_spot_x;
     d->mouse_hotspot.y = cursor_shape->hot_spot_y;
-    cursor = gdk_cursor_new_from_pixbuf(gtk_widget_get_display(GTK_WIDGET(display)),
-                                        d->mouse_pixbuf,
-                                        d->mouse_hotspot.x,
-                                        d->mouse_hotspot.y);
+    cursor = gdk_cursor_new_from_surface(gtk_widget_get_display(GTK_WIDGET(display)),
+                                         d->cursor_surface,
+                                         d->mouse_hotspot.x,
+                                         d->mouse_hotspot.y);
 
 #if HAVE_EGL
     if (egl_enabled(d))
commit 5e8a597f1ccf98c3fae358769f3f35e66d51c460
Author: Haochen Tong <i at hexchain.org>
Date:   Wed Jul 8 16:01:25 2020 +0200

    spice-widget: use pixel size for monitor geometry on scaled display
    
    On HiDPI displays, guest screen used to be blurry because the screen
    size is smaller than the widget size, and is scaled up. This patch fixes
    that by considering scale factor when calculating geometry.
    
    Signed-off-by: Haochen Tong <i at hexchain.org>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 5cef966..273167c 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -1348,19 +1348,26 @@ static void recalc_geometry(GtkWidget *widget)
     SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = display->priv;
     gdouble zoom = 1.0;
+    gint scale_factor = 1;
 
     if (spice_cairo_is_scaled(display))
         zoom = (gdouble)d->zoom_level / 100;
 
+    if (egl_enabled(d)) {
+        scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
+    }
+
     DISPLAY_DEBUG(display,
-                  "recalc geom monitor: %d:%d, guest +%d+%d:%dx%d, window %dx%d, zoom %g",
+                  "recalc geom monitor: %d:%d, guest +%d+%d:%dx%d, window %dx%d, zoom %g, scale %d",
                   d->channel_id, d->monitor_id, d->area.x, d->area.y,
                   d->area.width, d->area.height,
-                  d->ww, d->wh, zoom);
+                  d->ww, d->wh, zoom, scale_factor);
 
     if (d->resize_guest_enable)
         spice_main_channel_update_display(d->main, get_display_id(display),
-                                          d->area.x, d->area.y, d->ww / zoom, d->wh / zoom, TRUE);
+                                          d->area.x, d->area.y,
+                                          d->ww * scale_factor / zoom,
+                                          d->wh * scale_factor / zoom, TRUE);
 }
 
 /* ---------------------------------------------------------------- */


More information about the Spice-commits mailing list