[gtk/wayland-cursor-scale2] wayland: scale cursors to the right size




commit 5507b3f8c1a330a6037df70d47abf1cd54774e5e
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri May 27 10:10:27 2022 -0400

    wayland: scale cursors to the right size
    
    When loading cursors at scale, we expect the
    cursor images to have a size of scale * size.
    If we don't find such images, load them at their
    unscaled size and scale them up ourselves.
    
    Without this, cursors will appear in unexpected
    sizes depending on scales and themes.
    
    Related: #4746

 gdk/wayland/cursor/wayland-cursor.c | 92 ++++++++++++++++++++++---------------
 1 file changed, 54 insertions(+), 38 deletions(-)
---
diff --git a/gdk/wayland/cursor/wayland-cursor.c b/gdk/wayland/cursor/wayland-cursor.c
index 071824d914..4be8f9a4d4 100644
--- a/gdk/wayland/cursor/wayland-cursor.c
+++ b/gdk/wayland/cursor/wayland-cursor.c
@@ -200,27 +200,51 @@ wl_cursor_destroy(struct wl_cursor *cursor)
 }
 
 static struct wl_cursor *
-wl_cursor_create_from_xcursor_images(XcursorImages *images,
-                                    struct wl_cursor_theme *theme,
+wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
                                      const char *name,
                                      unsigned int size,
                                      unsigned int scale)
 {
+        char *path;
+        XcursorImages *images;
        struct cursor *cursor;
        struct cursor_image *image;
        int i, nbytes;
         unsigned int load_size;
-        int width, height;
+        int load_scale = 1;
 
         load_size = size * scale;
+
+        path = g_strconcat (theme->path, "/", name, NULL);
+        images = xcursor_load_images (path, load_size);
+
+        if (!images)
+          {
+            g_free (path);
+            return NULL;
+          }
+
+        if (images->images[0]->width != load_size ||
+            images->images[0]->height != load_size)
+          {
+               xcursor_images_destroy (images);
+                images = xcursor_load_images (path, size);
+                load_scale = scale;
+          }
+
+        g_free (path);
+
        cursor = malloc(sizeof *cursor);
-       if (!cursor)
+       if (!cursor) {
+               xcursor_images_destroy (images);
                return NULL;
+        }
 
        cursor->cursor.images =
                malloc(images->nimage * sizeof cursor->cursor.images[0]);
        if (!cursor->cursor.images) {
                free(cursor);
+               xcursor_images_destroy (images);
                return NULL;
        }
 
@@ -236,19 +260,10 @@ wl_cursor_create_from_xcursor_images(XcursorImages *images,
                image->theme = theme;
                image->buffer = NULL;
 
-                /* ensure that width and height are multiples of scale */
-                width = images->images[i]->width;
-                if ((width % scale) != 0)
-                  width = (width / scale + 1) * scale;
-
-                height = images->images[i]->height;
-                if ((height % scale) != 0)
-                  height = (height / scale + 1) * scale;
-
-               image->image.width = width;
-               image->image.height = height;
-               image->image.hotspot_x = images->images[i]->xhot;
-               image->image.hotspot_y = images->images[i]->yhot;
+               image->image.width = images->images[i]->width * load_scale;
+               image->image.height = images->images[i]->height * load_scale;
+               image->image.hotspot_x = images->images[i]->xhot * load_scale;
+               image->image.hotspot_y = images->images[i]->yhot * load_scale;
                image->image.delay = images->images[i]->delay;
 
                nbytes = image->image.width * image->image.height * 4;
@@ -258,15 +273,24 @@ wl_cursor_create_from_xcursor_images(XcursorImages *images,
                        break;
                }
 
-               /* copy pixels to shm pool */
-                /* pad at the right and bottom with transparent pixels */
-                memset (theme->pool->data + image->offset, 0, nbytes);
-                for (int y = 0; y < height; y++)
-                  {
-                    memcpy(theme->pool->data + image->offset + y * width * 4,
-                           images->images[i]->pixels + y * images->images[i]->width * 4,
-                           images->images[i]->width * 4);
-                  }
+                if (load_scale == 1) {
+                   /* copy pixels to shm pool */
+                    memcpy(theme->pool->data + image->offset,
+                           images->images[i]->pixels, nbytes);
+                }
+                else {
+                    /* scale image up while copying it */
+                    for (int y = 0; y < image->image.height; y++) {
+                        char *p = theme->pool->data + image->offset + y * image->image.width * 4;
+                        char *q = ((char *)images->images[i]->pixels) + (y / load_scale) * 
images->images[i]->width * 4;
+                        for (int x = 0; x < image->image.width; x++) {
+                            p[4 * x] = q[4 * (x/load_scale)];
+                            p[4 * x + 1] = q[4 * (x/load_scale) + 1];
+                            p[4 * x + 2] = q[4 * (x/load_scale) + 2];
+                            p[4 * x + 3] = q[4 * (x/load_scale) + 3];
+                        }
+                    }
+                }
                cursor->total_delay += image->image.delay;
                cursor->cursor.images[i] = (struct wl_cursor_image *) image;
        }
@@ -276,9 +300,12 @@ wl_cursor_create_from_xcursor_images(XcursorImages *images,
                free(cursor->cursor.name);
                free(cursor->cursor.images);
                free(cursor);
+               xcursor_images_destroy (images);
                return NULL;
        }
 
+       xcursor_images_destroy (images);
+
        return &cursor->cursor;
 }
 
@@ -288,18 +315,9 @@ load_cursor(struct wl_cursor_theme *theme,
             unsigned int            size,
             unsigned int            scale)
 {
-        XcursorImages *images;
        struct wl_cursor *cursor;
-        char *path;
 
-        path = g_strconcat (theme->path, "/", name, NULL);
-        images = xcursor_load_images (path, size * scale);
-        g_free (path); 
-
-        if (!images)
-          return;
-
-        cursor = wl_cursor_create_from_xcursor_images(images, theme, name, size, scale);
+        cursor = wl_cursor_create_from_xcursor_images(theme, name, size, scale);
 
        if (cursor) {
                theme->cursor_count++;
@@ -314,8 +332,6 @@ load_cursor(struct wl_cursor_theme *theme,
                        theme->cursors[theme->cursor_count - 1] = cursor;
                }
        }
-
-       xcursor_images_destroy (images);
 }
 
 /** Load a cursor theme to memory shared with the compositor


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]