summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-05-27 10:10:27 -0400
committerMatthias Clasen <mclasen@redhat.com>2022-05-27 12:26:45 -0400
commit5507b3f8c1a330a6037df70d47abf1cd54774e5e (patch)
treeb9ddc18dafe24046fcd091ba7f6d1f18ac097d69
parent00d45c67433b97db91ac4edb34d02c25cf3db39a (diff)
downloadgtk+-5507b3f8c1a330a6037df70d47abf1cd54774e5e.tar.gz
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
-rw-r--r--gdk/wayland/cursor/wayland-cursor.c92
1 files 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