forked from AuroraMiddleware/gtk
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
This commit is contained in:
parent
00d45c6743
commit
5507b3f8c1
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user