wayland: Redo cursor loading

Stop using a viewporter to scale cursors. Instead, just pass
the surface scale to the cursor loading code, and take the
buffer dimensions and hotspot that it returns, unchanged.

This avoids problems with cursor themes like Breeze, where
buffer dimensions are different from the nominal cursor size.

Make the cursor loading code take a floating point scale,
and return the closest sized cursor that it can find.
This commit is contained in:
Matthias Clasen
2024-09-27 11:52:47 -04:00
parent c358606a46
commit 403da9a2d5
7 changed files with 29 additions and 109 deletions

View File

@@ -208,21 +208,16 @@ wl_cursor_destroy(struct wl_cursor *cursor)
static struct wl_cursor *
wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
const char *name,
unsigned int size,
unsigned int scale)
unsigned int size)
{
char *path;
XcursorImages *images;
struct wl_cursor *cursor;
struct cursor_image *image;
int i, nbytes;
unsigned int load_size;
int load_scale = 1;
load_size = size * scale;
path = g_strconcat (theme->path, "/", name, NULL);
images = xcursor_load_images (path, load_size);
images = xcursor_load_images (path, size);
if (!images)
{
@@ -230,14 +225,6 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
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);
@@ -255,7 +242,7 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
}
cursor->name = strdup(name);
cursor->size = load_size;
cursor->size = images->images[0]->size;
for (i = 0; i < images->nimage; i++) {
image = malloc(sizeof *image);
@@ -265,10 +252,10 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
image->theme = theme;
image->buffer = NULL;
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.width = images->images[i]->width;
image->image.height = images->images[i]->height;
image->image.hotspot_x = images->images[i]->xhot;
image->image.hotspot_y = images->images[i]->yhot;
image->image.delay = images->images[i]->delay;
nbytes = image->image.width * image->image.height * 4;
@@ -278,24 +265,9 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
break;
}
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];
}
}
}
/* copy pixels to shm pool */
memcpy(theme->pool->data + image->offset,
images->images[i]->pixels, nbytes);
cursor->images[i] = (struct wl_cursor_image *) image;
}
cursor->image_count = i;
@@ -316,12 +288,11 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
static void
load_cursor(struct wl_cursor_theme *theme,
const char *name,
unsigned int size,
unsigned int scale)
unsigned int size)
{
struct wl_cursor *cursor;
cursor = wl_cursor_create_from_xcursor_images(theme, name, size, scale);
cursor = wl_cursor_create_from_xcursor_images(theme, name, size);
if (cursor) {
theme->cursor_count++;
@@ -405,12 +376,12 @@ wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
struct wl_cursor *
wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
const char *name,
unsigned int scale)
float scale)
{
unsigned int i;
unsigned int size;
size = theme->size * scale;
size = ceil (theme->size * scale);
for (i = 0; i < theme->cursor_count; i++) {
if (size == theme->cursors[i]->size &&
@@ -418,11 +389,10 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
return theme->cursors[i];
}
load_cursor (theme, name, theme->size, scale);
load_cursor (theme, name, size);
if (i < theme->cursor_count) {
if (size == theme->cursors[i]->size &&
strcmp (name, theme->cursors[theme->cursor_count - 1]->name) == 0)
if (strcmp (name, theme->cursors[theme->cursor_count - 1]->name) == 0)
return theme->cursors[theme->cursor_count - 1];
}

View File

@@ -59,7 +59,7 @@ wl_cursor_theme_destroy(struct wl_cursor_theme *theme);
struct wl_cursor *
wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
const char *name,
unsigned int scale);
float scale);
struct wl_buffer *
wl_cursor_image_get_buffer(struct wl_cursor_image *image);

View File

@@ -119,7 +119,7 @@ name_fallback (const char *name)
static struct wl_cursor *
gdk_wayland_cursor_load_for_name (GdkWaylandDisplay *display_wayland,
struct wl_cursor_theme *theme,
int scale,
float scale,
const char *name)
{
struct wl_cursor *c;
@@ -156,35 +156,30 @@ struct wl_buffer *
_gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display,
GdkCursor *cursor,
double desired_scale,
gboolean use_viewporter,
guint image_index,
int *hotspot_x,
int *hotspot_y,
int *width,
int *height,
double *scale)
int *height)
{
GdkTexture *texture;
if (gdk_cursor_get_name (cursor))
{
struct wl_cursor *c;
int scale_factor;
if (g_str_equal (gdk_cursor_get_name (cursor), "none"))
{
*hotspot_x = *hotspot_y = 0;
*width = *height = 0;
*scale = 1;
return NULL;
}
scale_factor = (int) ceil (desired_scale);
c = gdk_wayland_cursor_load_for_name (display,
display->cursor_theme,
scale_factor,
desired_scale,
gdk_cursor_get_name (cursor));
if (c && c->image_count > 0)
{
struct wl_cursor_image *image;
@@ -199,22 +194,10 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display,
image = c->images[image_index];
*width = display->cursor_theme_size;
*height = display->cursor_theme_size;
*scale = image->width / (double) *width;
*hotspot_x = image->hotspot_x / scale_factor;
*hotspot_y = image->hotspot_y / scale_factor;
if (*scale != scale_factor && !use_viewporter)
{
g_warning (G_STRLOC " cursor image size (%d) not an integer "
"multiple of theme size (%d)", image->width, *width);
*width = image->width;
*height = image->height;
*hotspot_x = image->hotspot_x;
*hotspot_y = image->hotspot_y;
*scale = 1;
}
*width = image->width;
*height = image->height;
*hotspot_x = image->hotspot_x;
*hotspot_y = image->hotspot_y;
return wl_cursor_image_get_buffer (image);
}
@@ -248,7 +231,6 @@ from_texture:
*hotspot_y = gdk_cursor_get_hotspot_y (cursor);
*width = gdk_texture_get_width (texture);
*height = gdk_texture_get_height (texture);
*scale = 1;
cairo_surface_reference (surface);
buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface);
@@ -260,14 +242,9 @@ from_texture:
}
else
{
if (!use_viewporter)
*scale = ceil (desired_scale);
else
*scale = desired_scale;
texture = gdk_cursor_get_texture_for_size (cursor,
display->cursor_theme_size,
*scale,
desired_scale,
width,
height,
hotspot_x,
@@ -302,11 +279,9 @@ from_texture:
return _gdk_wayland_cursor_get_buffer (display,
gdk_cursor_get_fallback (cursor),
desired_scale,
use_viewporter,
image_index,
hotspot_x, hotspot_y,
width, height,
scale);
width, height);
}
else
{

View File

@@ -62,7 +62,6 @@ struct _GdkWaylandPointerData {
uint32_t grab_time;
struct wl_surface *pointer_surface;
struct wp_viewport *pointer_surface_viewport;
guint cursor_is_default: 1;
GdkCursor *cursor;
guint cursor_timeout_id;

View File

@@ -261,26 +261,19 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device)
gdk_wayland_device_get_pointer (wayland_device);
struct wl_buffer *buffer;
int x, y, w, h;
double scale;
guint next_image_index, next_image_delay;
gboolean retval = G_SOURCE_REMOVE;
GdkWaylandTabletData *tablet;
gboolean use_viewport = FALSE;
tablet = gdk_wayland_seat_find_tablet (seat, device);
if (pointer->pointer_surface_viewport &&
g_getenv ("USE_POINTER_VIEWPORT"))
use_viewport = TRUE;
if (pointer->cursor)
{
buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display),
pointer->cursor,
pointer->current_output_scale,
use_viewport,
pointer->cursor_image_index,
&x, &y, &w, &h, &scale);
&x, &y, &w, &h);
}
else
{
@@ -317,17 +310,6 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device)
if (buffer)
{
wl_surface_attach (pointer->pointer_surface, buffer, 0, 0);
if (use_viewport)
{
wp_viewport_set_source (pointer->pointer_surface_viewport,
wl_fixed_from_int (0),
wl_fixed_from_int (0),
wl_fixed_from_double (w * scale),
wl_fixed_from_double (h * scale));
wp_viewport_set_destination (pointer->pointer_surface_viewport, w, h);
}
else if (wl_surface_get_version (pointer->pointer_surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
wl_surface_set_buffer_scale (pointer->pointer_surface, scale);
wl_surface_damage (pointer->pointer_surface, 0, 0, w, h);
wl_surface_commit (pointer->pointer_surface);
}

View File

@@ -117,13 +117,11 @@ void gdk_wayland_display_system_bell (GdkDisplay *display,
struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display,
GdkCursor *cursor,
double desired_scale,
gboolean use_viewporter,
guint image_index,
int *hotspot_x,
int *hotspot_y,
int *w,
int *h,
double *scale);
int *h);
guint _gdk_wayland_cursor_get_next_image_index (GdkWaylandDisplay *display,
GdkCursor *cursor,
guint scale,

View File

@@ -3894,7 +3894,6 @@ gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer)
g_clear_object (&pointer->cursor);
wl_surface_destroy (pointer->pointer_surface);
g_slist_free (pointer->pointer_surface_outputs);
g_clear_pointer (&pointer->pointer_surface_viewport, wp_viewport_destroy);
}
static void
@@ -4261,9 +4260,6 @@ init_pointer_data (GdkWaylandPointerData *pointer_data,
wl_surface_add_listener (pointer_data->pointer_surface,
&pointer_surface_listener,
logical_device);
if (display_wayland->viewporter)
pointer_data->pointer_surface_viewport = wp_viewporter_get_viewport (display_wayland->viewporter, pointer_data->pointer_surface);
}
void