[Spice-commits] 2 commits - gtk/spice-widget-cairo.c gtk/spice-widget-priv.h gtk/spice-widget-x11.c gtk/spice-widget.c

Alexander Larsson alexl at kemper.freedesktop.org
Thu Aug 30 13:08:56 PDT 2012


 gtk/spice-widget-cairo.c |   97 ++++++---------------
 gtk/spice-widget-priv.h  |    4 
 gtk/spice-widget-x11.c   |   39 +++-----
 gtk/spice-widget.c       |  217 ++++++++++++++++++++++++++++++-----------------
 4 files changed, 187 insertions(+), 170 deletions(-)

New commits:
commit 4153421381a0c1307b18188166aaff62cae3543f
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Aug 30 19:29:46 2012 +0200

    Add only_downscale property
    
    When this is enabled we never scale displays larger
    than their actual size.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=54277

diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
index 7d59359..4ed5fbc 100644
--- a/gtk/spice-widget-priv.h
+++ b/gtk/spice-widget-priv.h
@@ -67,6 +67,7 @@ struct _SpiceDisplayPrivate {
     bool                    convert;
     bool                    have_mitshm;
     gboolean                allow_scaling;
+    gboolean                only_downscale;
     gboolean                disable_inputs;
 
     /* TODO: make a display object instead? */
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index fa890a7..5045fb0 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -100,6 +100,7 @@ enum {
     PROP_RESIZE_GUEST,
     PROP_AUTO_CLIPBOARD,
     PROP_SCALING,
+    PROP_ONLY_DOWNSCALE,
     PROP_DISABLE_INPUTS,
     PROP_ZOOM_LEVEL,
     PROP_MONITOR_ID,
@@ -170,10 +171,13 @@ static void spice_display_get_property(GObject    *object,
         break;
     case PROP_SCALING:
         g_value_set_boolean(value, d->allow_scaling);
-	break;
+        break;
+    case PROP_ONLY_DOWNSCALE:
+        g_value_set_boolean(value, d->only_downscale);
+        break;
     case PROP_DISABLE_INPUTS:
         g_value_set_boolean(value, d->disable_inputs);
-	break;
+        break;
     case PROP_ZOOM_LEVEL:
         g_value_set_int(value, d->zoom_level);
         break;
@@ -335,6 +339,10 @@ static void spice_display_set_property(GObject      *object,
         d->allow_scaling = g_value_get_boolean(value);
         scaling_updated(display);
         break;
+    case PROP_ONLY_DOWNSCALE:
+        d->only_downscale = g_value_get_boolean(value);
+        scaling_updated(display);
+        break;
     case PROP_AUTO_CLIPBOARD:
         g_object_set(d->gtk_session, "auto-clipboard",
                      g_value_get_boolean(value), NULL);
@@ -1627,6 +1635,15 @@ static void spice_display_class_init(SpiceDisplayClass *klass)
         (gobject_class, PROP_SCALING,
          g_param_spec_boolean("scaling", "Scaling",
                               "Whether we should use scaling",
+                              TRUE,
+                              G_PARAM_READWRITE |
+                              G_PARAM_CONSTRUCT |
+                              G_PARAM_STATIC_STRINGS));
+
+    g_object_class_install_property
+        (gobject_class, PROP_ONLY_DOWNSCALE,
+         g_param_spec_boolean("only-downscale", "Only Downscale",
+                              "If scaling, only scale down, never up. Since: 0.14",
                               FALSE,
                               G_PARAM_READWRITE |
                               G_PARAM_CONSTRUCT |
@@ -1994,6 +2011,9 @@ void spice_display_get_scaling(SpiceDisplay *display,
     } else {
         s = MIN ((double)ww / (double)fbw, (double)wh / (double)fbh);
 
+        if (d->only_downscale && s >= 1.0)
+            s = 1.0;
+
         /* Round to int size */
         w = floor (fbw * s + 0.5);
         h = floor (fbh * s + 0.5);
commit d0bc4f9194c0b8d6a001883344ab2689ea13c6b4
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Aug 30 19:27:28 2012 +0200

    Centralize scaling handling
    
    This moves all the handling of scaling calculations and
    positioning of the display inside the widget into one place.
    
    This makes it easier to later change how scaling works.
    
    Also, the new scaling only support aspect-ratio-keeping
    scaling.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=54277

diff --git a/gtk/spice-widget-cairo.c b/gtk/spice-widget-cairo.c
index 1144308..069410a 100644
--- a/gtk/spice-widget-cairo.c
+++ b/gtk/spice-widget-cairo.c
@@ -77,44 +77,42 @@ G_GNUC_INTERNAL
 void spicex_draw_event(SpiceDisplay *display, cairo_t *cr)
 {
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+    double s;
+    int x, y;
     int ww, wh;
+    int w, h;
+
+    spice_display_get_scaling(display, &s, &x, &y, &w, &h);
 
     gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(display)), &ww, &wh);
 
-    /* If we don't have a pixmap, or we're not scaling, then
-       we need to fill with background color */
-    if (!d->ximage ||
-        !d->allow_scaling) {
-        cairo_rectangle(cr, 0, 0, ww, wh);
-        /* Optionally cut out the inner area where the pixmap
-           will be drawn. This avoids 'flashing' since we're
-           not double-buffering. Note we're using the undocumented
-           behaviour of drawing the rectangle from right to left
-           to cut out the whole */
-        if (d->ximage)
-            cairo_rectangle(cr, d->mx + d->area.width, d->my,
-                            -d->area.width, d->area.height);
-        cairo_fill(cr);
-    }
+    /* We need to paint the bg color around the image */
+    cairo_rectangle(cr, 0, 0, ww, wh);
+
+    /* Optionally cut out the inner area where the pixmap
+       will be drawn. This avoids 'flashing' since we're
+       not double-buffering. Note we're using the undocumented
+       behaviour of drawing the rectangle from right to left
+       to cut out the whole */
+    if (d->ximage)
+        cairo_rectangle(cr, x + w, y,
+                        -w, h);
+
+    /* Need to set a real solid color, because the default is usually
+       transparent these days, and non-double buffered windows can't
+       render transparently */
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_fill(cr);
 
     /* Draw the display */
     if (d->ximage) {
-        if (d->allow_scaling) {
-            double sx, sy;
-            spice_display_get_scaling(display, &sx, &sy);
-            cairo_scale(cr, sx, sy);
-            if (!d->convert)
-                cairo_translate(cr, -d->area.x, -d->area.y);
-            cairo_set_source_surface(cr, d->ximage, 0, 0);
-        } else {
-            cairo_translate(cr, d->mx, d->my);
-            cairo_rectangle(cr, 0, 0, d->area.width, d->area.height);
-            cairo_clip(cr);
-            if (!d->convert)
-                cairo_translate(cr, -d->area.x, -d->area.y);
-            cairo_set_source_surface(cr, d->ximage, 0, 0);
-        }
-        cairo_paint(cr);
+        cairo_translate(cr, x, y);
+        cairo_rectangle(cr, 0, 0, w, h);
+        cairo_scale(cr, s, s);
+        if (!d->convert)
+            cairo_translate(cr, -d->area.x, -d->area.y);
+        cairo_set_source_surface(cr, d->ximage, 0, 0);
+        cairo_fill(cr);
 
         if (d->mouse_mode == SPICE_MOUSE_MODE_SERVER &&
             !d->show_cursor) {
@@ -150,43 +148,6 @@ void spicex_expose_event(SpiceDisplay *display, GdkEventExpose *expose)
 #endif
 
 G_GNUC_INTERNAL
-void spicex_image_invalidate(SpiceDisplay *display,
-                             gint *x, gint *y, gint *w, gint *h)
-{
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
-    int ww, wh;
-
-    gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(display)), &ww, &wh);
-
-    if (d->allow_scaling) {
-        double sx, sy;
-
-        /* Scale the exposed region */
-        sx = (double)ww / (double)d->area.width;
-        sy = (double)wh / (double)d->area.height;
-
-        *x *= sx;
-        *y *= sy;
-        *w *= sx;
-        *h *= sy;
-
-        /* FIXME: same hack as gtk-vnc */
-        /* Without this, we get horizontal & vertical line artifacts
-         * when drawing. This "fix" is somewhat dubious though. The
-         * true mistake & fix almost certainly lies elsewhere.
-         */
-        *x -= 2;
-        *y -= 2;
-        *w += 4;
-        *h += 4;
-    } else {
-        /* Offset the Spice region to produce expose region */
-        *x += d->mx;
-        *y += d->my;
-    }
-}
-
-G_GNUC_INTERNAL
 gboolean spicex_is_scaled(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
index 87d1de9..7d59359 100644
--- a/gtk/spice-widget-priv.h
+++ b/gtk/spice-widget-priv.h
@@ -120,14 +120,13 @@ struct _SpiceDisplayPrivate {
 
 int      spicex_image_create                 (SpiceDisplay *display);
 void     spicex_image_destroy                (SpiceDisplay *display);
-void     spicex_image_invalidate             (SpiceDisplay *display, gint *x, gint *y, gint *w, gint *h);
 #if GTK_CHECK_VERSION (2, 91, 0)
 void     spicex_draw_event                   (SpiceDisplay *display, cairo_t *cr);
 #else
 void     spicex_expose_event                 (SpiceDisplay *display, GdkEventExpose *ev);
 #endif
 gboolean spicex_is_scaled                    (SpiceDisplay *display);
-void     spice_display_get_scaling           (SpiceDisplay *display, double *sx, double *sy);
+void     spice_display_get_scaling           (SpiceDisplay *display, double *s, int *x, int *y, int *w, int *h);
 
 G_END_DECLS
 
diff --git a/gtk/spice-widget-x11.c b/gtk/spice-widget-x11.c
index 7fc99ff..178dc98 100644
--- a/gtk/spice-widget-x11.c
+++ b/gtk/spice-widget-x11.c
@@ -219,33 +219,36 @@ void spicex_expose_event(SpiceDisplay *display, GdkEventExpose *expose)
 {
     GdkDrawable *window = gtk_widget_get_window(GTK_WIDGET(display));
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+    int x, y, w, h;
 
-    if (expose->area.x >= d->mx &&
-        expose->area.y >= d->my &&
-        expose->area.x + expose->area.width  <= d->mx + d->area.width &&
-        expose->area.y + expose->area.height <= d->my + d->area.height) {
+    spice_display_get_scaling(display, NULL, &x, &y, &w, &h);
+
+    if (expose->area.x >= x &&
+        expose->area.y >= y &&
+        expose->area.x + expose->area.width  <= x + w &&
+        expose->area.y + expose->area.height <= y + h) {
         /* area is completely inside the guest screen -- blit it */
         if (d->have_mitshm && d->shminfo) {
             XShmPutImage(d->dpy, gdk_x11_drawable_get_xid(window),
                          d->gc, d->ximage,
-                         d->area.x + expose->area.x - d->mx, d->area.y + expose->area.y - d->my,
+                         d->area.x + expose->area.x - x, d->area.y + expose->area.y - y,
                          expose->area.x, expose->area.y,
                          expose->area.width, expose->area.height,
                          true);
         } else {
             XPutImage(d->dpy, gdk_x11_drawable_get_xid(window),
                       d->gc, d->ximage,
-                      d->area.x + expose->area.x - d->mx, d->area.y + expose->area.y - d->my,
-                      expose->area.x expose->area.y,
+                      d->area.x + expose->area.x - x, d->area.y + expose->area.y - y,
+                      expose->area.x, expose->area.y,
                       expose->area.width, expose->area.height);
         }
     } else {
         /* complete window update */
         if (d->ww > d->area.width || d->wh > d->area.height) {
-            int x1 = d->mx;
-            int x2 = d->mx + d->area.width;
-            int y1 = d->my;
-            int y2 = d->my + d->area.height;
+            int x1 = x;
+            int x2 = x + w;
+            int y1 = y;
+            int y2 = y + h;
             XFillRectangle(d->dpy, gdk_x11_drawable_get_xid(window),
                            d->gc, 0, 0, x1, d->wh);
             XFillRectangle(d->dpy, gdk_x11_drawable_get_xid(window),
@@ -258,27 +261,17 @@ void spicex_expose_event(SpiceDisplay *display, GdkEventExpose *expose)
         if (d->have_mitshm && d->shminfo) {
             XShmPutImage(d->dpy, gdk_x11_drawable_get_xid(window),
                          d->gc, d->ximage,
-                         d->area.x, d->area.y, d->mx, d->my, d->area.width, d->area.height,
+                         d->area.x, d->area.y, x, y, w, h,
                          true);
         } else {
             XPutImage(d->dpy, gdk_x11_drawable_get_xid(window),
                       d->gc, d->ximage,
-                      d->area.x, d->area.y, d->mx, d->my, d->area.width, d->area.height);
+                      d->area.x, d->area.y, x, y, w, h);
         }
     }
 }
 
 G_GNUC_INTERNAL
-void spicex_image_invalidate (SpiceDisplay *display,
-                              gint *x, gint *y, gint *w, gint *h)
-{
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
-    /* Offset the Spice region to produce expose region */
-    *x += d->mx;
-    *y += d->my;
-}
-
-G_GNUC_INTERNAL
 gboolean spicex_is_scaled(SpiceDisplay *display)
 {
     return FALSE; /* backend doesn't support scaling yet */
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index 5fe36de..fa890a7 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -196,9 +196,7 @@ static void scaling_updated(SpiceDisplay *display)
 
     recalc_geometry(GTK_WIDGET(display));
     if (d->ximage && window) { /* if not yet shown */
-        int ww, wh;
-        gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(display)), &ww, &wh);
-        gtk_widget_queue_draw_area(GTK_WIDGET(display), 0, 0, ww, wh);
+        gtk_widget_queue_draw(GTK_WIDGET(display));
     }
 }
 
@@ -884,19 +882,12 @@ static void recalc_geometry(GtkWidget *widget)
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
     gdouble zoom = 1.0;
 
-    d->mx = 0;
-    d->my = 0;
-    if (!spicex_is_scaled(display)) {
-        if (d->ww > d->area.width)
-            d->mx = (d->ww - d->area.width) / 2;
-        if (d->wh > d->area.height)
-            d->my = (d->wh - d->area.height) / 2;
-    } else
+    if (spicex_is_scaled(display))
         zoom = (gdouble)d->zoom_level / 100;
 
-    SPICE_DEBUG("recalc geom monitor: %d:%d, guest +%d+%d:%dx%d, window %dx%d, zoom %g, offset +%d+%d",
+    SPICE_DEBUG("recalc geom monitor: %d:%d, guest +%d+%d:%dx%d, window %dx%d, zoom %g",
                 d->channel_id, d->monitor_id, d->area.x, d->area.y, d->area.width, d->area.height,
-                d->ww, d->wh, zoom, d->mx, d->my);
+                d->ww, d->wh, zoom);
 
     if (d->resize_guest_enable)
         spice_main_set_display(d->main, get_display_id(display),
@@ -1320,63 +1311,76 @@ static int button_mask_gdk_to_spice(int gdk)
     return spice;
 }
 
+G_GNUC_INTERNAL
+void spicex_transform_input (SpiceDisplay *display,
+                             double window_x, double window_y,
+                             int *input_x, int *input_y)
+{
+    SpiceDisplayPrivate *d = display->priv;
+    int display_x, display_y, display_w, display_h;
+    double is;
+
+    spice_display_get_scaling(display, NULL,
+                              &display_x, &display_y,
+                              &display_w, &display_h);
+
+    /* 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
+       scaling factor here would be 100/10==10, but if you then take the largest
+       possible window coordinate, i.e. 9 and multiply by 10 you get 90, not 99,
+       which is the max display coord.
+
+       If you want to be able to reach the last pixel in the window you need
+       max_window_x * input_scale == max_display_x, which is
+       (window_width - 1) * input_scale == (display_width - 1)
+
+       Note, this is the inverse of s (i.e. s ~= 1/is) as we're converting the
+       coordinates in the inverse direction (window -> display) as the fb size
+       (display -> window).
+    */
+    is = (double)(d->area.width-1) / (double)(display_w-1);
+
+    window_x -= display_x;
+    window_y -= display_y;
+
+    *input_x = floor (window_x * is);
+    *input_y = floor (window_y * is);
+}
+
 static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 {
     SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
-    int ww, wh;
+    int x, y;
 
     if (!d->inputs)
         return true;
     if (d->disable_inputs)
         return true;
 
-    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
-    if (spicex_is_scaled(display) && (d->area.width != ww || d->area.height != wh)) {
-        double sx, sy;
-        sx = (double)d->area.width / (double)ww;
-        sy = (double)d->area.height / (double)wh;
-
-        /* Scaling the desktop, so scale the mouse coords by the same.
-         * Ratio for the rounding used:
-         * 1) We should be able to send mouse coords for all 4 corner pixels
-         * 2) The GdkMotion events are double's, so we've X.Xfrac and Y.Yfrac
-         * 3) The X and Y integer values always go from 0 - (ww/wh - 1)
-         * 4) Note that even if Xfrac = .99999, X will still go from 0 - (ww-1)
-         *    so x will go from 0.99999 - (ww-1).99999
-         * 5) Given 4, the only way to be sure we can always generate 0
-         *    coordinates is to first floor the input coordinates
-         * 6) To avoid rounding errors causing us to be unable to generate
-         *    coordinates for the bottom row / left column of pixels we ceil
-         *    the end result
-         */
-        motion->x = ceil(floor(motion->x) * sx);
-        motion->y = ceil(floor(motion->y) * sy);
-    } else {
-        motion->x -= d->mx;
-        motion->y -= d->my;
-    }
+    spicex_transform_input (display, motion->x, motion->y, &x, &y);
 
     switch (d->mouse_mode) {
     case SPICE_MOUSE_MODE_CLIENT:
-        if (motion->x >= 0 && motion->x < d->area.width &&
-            motion->y >= 0 && motion->y < d->area.height) {
+        if (x >= 0 && x < d->area.width &&
+            y >= 0 && y < d->area.height) {
             spice_inputs_position(d->inputs,
-                                  motion->x + d->area.x, motion->y + d->area.y,
+                                  x + d->area.x, y + d->area.y,
                                   d->channel_id,
                                   button_mask_gdk_to_spice(motion->state));
         }
         break;
     case SPICE_MOUSE_MODE_SERVER:
         if (d->mouse_grab_active) {
-            gint dx = d->mouse_last_x != -1 ? motion->x - d->mouse_last_x : 0;
-            gint dy = d->mouse_last_y != -1 ? motion->y - d->mouse_last_y : 0;
+            gint dx = d->mouse_last_x != -1 ? x - d->mouse_last_x : 0;
+            gint dy = d->mouse_last_y != -1 ? y - d->mouse_last_y : 0;
 
             spice_inputs_motion(d->inputs, dx, dy,
                                 button_mask_gdk_to_spice(motion->state));
 
-            d->mouse_last_x = motion->x;
-            d->mouse_last_y = motion->y;
+            d->mouse_last_x = x;
+            d->mouse_last_y = y;
             mouse_wrap(display, motion);
         }
         break;
@@ -1420,6 +1424,7 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
 {
     SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+    int x, y;
 
     SPICE_DEBUG("%s %s: button %d, state 0x%x", __FUNCTION__,
             button->type == GDK_BUTTON_PRESS ? "press" : "release",
@@ -1428,16 +1433,12 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
     if (d->disable_inputs)
         return true;
 
-    if (!spicex_is_scaled(display)
-        && d->mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
-        gint x, y;
-
+    spicex_transform_input (display, button->x, button->y, &x, &y);
+    if ((x < 0 || x >= d->area.width ||
+         y < 0 || y >= d->area.height) &&
+        d->mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
         /* rule out clicks in outside region */
-        gtk_widget_get_pointer (widget, &x, &y);
-        x -= d->mx;
-        y -= d->my;
-        if (!(x >= 0 && x < d->area.width && y >= 0 && y < d->area.height))
-            return true;
+        return true;
     }
 
     gtk_widget_grab_focus(widget);
@@ -1856,6 +1857,9 @@ static void invalidate(SpiceChannel *channel,
 {
     SpiceDisplay *display = data;
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+    int display_x, display_y;
+    int x1, y1, x2, y2;
+    double s;
     GdkRectangle rect = {
         .x = x,
         .y = y,
@@ -1872,14 +1876,18 @@ static void invalidate(SpiceChannel *channel,
     if (d->convert)
         do_color_convert(display, &rect);
 
-    x = rect.x - d->area.x;
-    y = rect.y - d->area.y;
-    w = rect.width;
-    h = rect.height;
+    spice_display_get_scaling(display, &s,
+                              &display_x, &display_y,
+                              NULL, NULL);
+
+    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);
 
-    spicex_image_invalidate(display, &x, &y, &w, &h);
     gtk_widget_queue_draw_area(GTK_WIDGET(display),
-                               x, y, w, h);
+                               display_x + x1, display_y + y1,
+                               x2 - x1, y2-y1);
 }
 
 static void mark(SpiceDisplay *display, gint mark)
@@ -1955,39 +1963,74 @@ static void cursor_hide(SpiceCursorChannel *channel, gpointer data)
 }
 
 G_GNUC_INTERNAL
-void spice_display_get_scaling(SpiceDisplay *display, double *sx, double *sy)
+void spice_display_get_scaling(SpiceDisplay *display,
+                               double *s_out,
+                               int *x_out, int *y_out,
+                               int *w_out, int *h_out)
 {
     SpiceDisplayPrivate *d = display->priv;
     int fbw = d->area.width, fbh = d->area.height;
     int ww, wh;
+    int x, y, w, h;
+    double s;
 
-    if (!spicex_is_scaled(display) || !gtk_widget_get_window(GTK_WIDGET(display))) {
-        *sx = 1.0;
-        *sy = 1.0;
-        return;
+    if (gtk_widget_get_realized (GTK_WIDGET(display)))
+        gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(display)), &ww, &wh);
+    else {
+        ww = fbw;
+        wh = fbh;
     }
 
-    gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(display)), &ww, &wh);
+    if (!spicex_is_scaled(display)) {
+        s = 1.0;
+        x = 0;
+        y = 0;
+        if (ww > d->area.width)
+            x = (ww - d->area.width) / 2;
+        if (wh > d->area.height)
+            y = (wh - d->area.height) / 2;
+        w = fbw;
+        h = fbh;
+    } else {
+        s = MIN ((double)ww / (double)fbw, (double)wh / (double)fbh);
+
+        /* Round to int size */
+        w = floor (fbw * s + 0.5);
+        h = floor (fbh * s + 0.5);
+
+        /* Center the display */
+        x = (ww - w) / 2;
+        y = (wh - h) / 2;
+    }
 
-    *sx = (double)ww / (double)fbw;
-    *sy = (double)wh / (double)fbh;
+    if (s_out)
+        *s_out = s;
+    if (w_out)
+        *w_out = w;
+    if (h_out)
+        *h_out = h;
+    if (x_out)
+        *x_out = x;
+    if (y_out)
+        *y_out = y;
 }
 
 static void cursor_invalidate(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
-    double sx, sy;
+    double s;
+    int x, y;
 
     if (d->mouse_pixbuf == NULL)
         return;
 
-    spice_display_get_scaling(display, &sx, &sy);
+    spice_display_get_scaling(display, &s, &x, &y, NULL, NULL);
 
     gtk_widget_queue_draw_area(GTK_WIDGET(display),
-                               (d->mouse_guest_x + d->mx - d->mouse_hotspot.x - d->area.x) * sx,
-                               (d->mouse_guest_y + d->my - d->mouse_hotspot.y - d->area.y) * sy,
-                               gdk_pixbuf_get_width(d->mouse_pixbuf) * sx,
-                               gdk_pixbuf_get_height(d->mouse_pixbuf) * sy);
+                               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,
+                               ceil (gdk_pixbuf_get_width(d->mouse_pixbuf) * s),
+                               ceil (gdk_pixbuf_get_height(d->mouse_pixbuf) * s));
 }
 
 static void cursor_move(SpiceCursorChannel *channel, gint x, gint y, gpointer data)


More information about the Spice-commits mailing list