cursor: Move sprite preparation into sprite classes

Make the prepare function a vfunc of MetaCursorSprite, moving the root
cursor prepare function into MetaCursorSpriteXcursor. This should solve
two issues:

- The root cursor prepare function was changed in f77d8e2a12a07ef6abe9
  to solve an issue with fractional scales. The tool cursor prepare
  function was missing this fix.
- The cursors created via the shape protocol had no prepare function at
  all, so were not getting scaled.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3975
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4345>
This commit is contained in:
Jan Alexander Steffens (heftig) 2025-03-18 22:58:37 +01:00 committed by Bruce Leidl
parent bac6e440ae
commit b08cf5c135
7 changed files with 159 additions and 237 deletions

View File

@ -24,6 +24,7 @@
#include "backends/meta-cursor.h"
#include "backends/meta-cursor-renderer.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-logical-monitor.h"
#include "clutter/clutter.h"
#include "cogl/cogl.h"
#include "meta/prefs.h"
@ -461,6 +462,60 @@ meta_cursor_sprite_xcursor_invalidate (MetaCursorSprite *sprite)
sprite_xcursor->invalidated = TRUE;
}
static void
meta_cursor_sprite_xcursor_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,
int y)
{
MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
MetaCursorTracker *cursor_tracker =
meta_cursor_sprite_get_cursor_tracker (sprite);
MetaBackend *backend =
meta_cursor_tracker_get_backend (cursor_tracker);
if (!meta_is_wayland_compositor ())
return;
if (meta_backend_is_stage_views_scaled (backend))
{
if (best_scale != 0.0f)
{
float ceiled_scale;
int cursor_width, cursor_height;
ceiled_scale = ceilf (best_scale);
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) ceiled_scale);
meta_cursor_sprite_realize_texture (sprite);
meta_cursor_sprite_xcursor_get_scaled_image_size (sprite_xcursor,
&cursor_width,
&cursor_height);
meta_cursor_sprite_set_viewport_dst_size (sprite,
cursor_width,
cursor_height);
}
}
else
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
/* Reload the cursor texture if the scale has changed. */
if (logical_monitor)
{
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) logical_monitor->scale);
meta_cursor_sprite_set_texture_scale (sprite, 1.0f);
}
}
}
static ClutterColorState *
ensure_xcursor_color_state (MetaCursorTracker *cursor_tracker)
{
@ -544,4 +599,5 @@ meta_cursor_sprite_xcursor_class_init (MetaCursorSpriteXcursorClass *klass)
cursor_sprite_class->tick_frame = meta_cursor_sprite_xcursor_tick_frame;
cursor_sprite_class->get_current_frame_time =
meta_cursor_sprite_xcursor_get_current_frame_time;
cursor_sprite_class->prepare_at = meta_cursor_sprite_xcursor_prepare_at;
}

View File

@ -65,9 +65,6 @@ typedef struct _MetaCursorSpritePrivate
ClutterColorState *color_state;
MetaCursorPrepareFunc prepare_func;
gpointer prepare_func_data;
MetaCursorTracker *cursor_tracker;
} MetaCursorSpritePrivate;
@ -309,29 +306,16 @@ meta_cursor_sprite_get_viewport_dst_size (MetaCursorSprite *sprite,
return TRUE;
}
void
meta_cursor_sprite_set_prepare_func (MetaCursorSprite *sprite,
MetaCursorPrepareFunc func,
gpointer user_data)
{
MetaCursorSpritePrivate *priv =
meta_cursor_sprite_get_instance_private (sprite);
priv->prepare_func = func;
priv->prepare_func_data = user_data;
}
void
meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,
int y)
{
MetaCursorSpritePrivate *priv =
meta_cursor_sprite_get_instance_private (sprite);
MetaCursorSpriteClass *sprite_class = META_CURSOR_SPRITE_GET_CLASS (sprite);
if (priv->prepare_func)
priv->prepare_func (sprite, best_scale, x, y, priv->prepare_func_data);
if (sprite_class->prepare_at)
sprite_class->prepare_at (sprite, best_scale, x, y);
}
gboolean

View File

@ -42,18 +42,12 @@ struct _MetaCursorSpriteClass
gboolean (* is_animated) (MetaCursorSprite *sprite);
void (* tick_frame) (MetaCursorSprite *sprite);
unsigned int (* get_current_frame_time) (MetaCursorSprite *sprite);
void (* prepare_at) (MetaCursorSprite *sprite,
float best_scale,
int x,
int y);
};
typedef void (* MetaCursorPrepareFunc) (MetaCursorSprite *sprite,
float scale,
int x,
int y,
gpointer user_data);
void meta_cursor_sprite_set_prepare_func (MetaCursorSprite *sprite,
MetaCursorPrepareFunc func,
gpointer user_data);
void meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,

View File

@ -1681,64 +1681,6 @@ meta_display_notify_window_created (MetaDisplay *display,
g_signal_emit (display, display_signals[WINDOW_CREATED], 0, window);
}
static void
root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
float best_scale,
int x,
int y,
MetaDisplay *display)
{
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
MetaBackend *backend = backend_from_display (display);
if (meta_backend_is_stage_views_scaled (backend))
{
if (best_scale != 0.0f)
{
float ceiled_scale;
int cursor_width, cursor_height;
ceiled_scale = ceilf (best_scale);
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) ceiled_scale);
meta_cursor_sprite_realize_texture (cursor_sprite);
meta_cursor_sprite_xcursor_get_scaled_image_size (sprite_xcursor,
&cursor_width,
&cursor_height);
meta_cursor_sprite_set_viewport_dst_size (cursor_sprite,
cursor_width,
cursor_height);
}
}
else
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
/* Reload the cursor texture if the scale has changed. */
if (logical_monitor)
{
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) logical_monitor->scale);
meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0f);
}
}
}
static void
manage_root_cursor_sprite_scale (MetaDisplay *display,
MetaCursorSpriteXcursor *sprite_xcursor)
{
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (sprite_xcursor),
(MetaCursorPrepareFunc) root_cursor_prepare_at,
display);
}
void
meta_display_reload_cursor (MetaDisplay *display)
{
@ -1748,10 +1690,6 @@ meta_display_reload_cursor (MetaDisplay *display)
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
sprite_xcursor = meta_cursor_sprite_xcursor_new (cursor, cursor_tracker);
if (meta_is_wayland_compositor ())
manage_root_cursor_sprite_scale (display, sprite_xcursor);
meta_cursor_tracker_set_root_cursor (cursor_tracker,
META_CURSOR_SPRITE (sprite_xcursor));
g_object_unref (sprite_xcursor);

View File

@ -21,6 +21,12 @@
#include "wayland/meta-cursor-sprite-wayland.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-logical-monitor.h"
#include "wayland/meta-wayland-private.h"
#ifdef HAVE_XWAYLAND
#include "wayland/meta-xwayland.h"
#endif
struct _MetaCursorSpriteWayland
{
@ -65,6 +71,94 @@ meta_cursor_sprite_wayland_invalidate (MetaCursorSprite *sprite)
sprite_wayland->invalidated = TRUE;
}
static void
meta_cursor_sprite_wayland_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,
int y)
{
MetaCursorSpriteWayland *sprite_wayland = META_CURSOR_SPRITE_WAYLAND (sprite);
MetaCursorTracker *cursor_tracker =
meta_cursor_sprite_get_cursor_tracker (sprite);
MetaBackend *backend =
meta_cursor_tracker_get_backend (cursor_tracker);
MetaWaylandSurface *surface = sprite_wayland->surface;
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
if (logical_monitor)
{
int surface_scale;
float texture_scale;
#ifdef HAVE_XWAYLAND
MetaXWaylandManager *xwayland_manager =
&surface->compositor->xwayland_manager;
if (meta_wayland_surface_is_xwayland (surface))
surface_scale = meta_xwayland_get_x11_ui_scaling_factor (xwayland_manager);
else
#endif /* HAVE_XWAYLAND */
surface_scale = surface->applied_state.scale;
if (surface->viewport.has_dst_size)
texture_scale = 1.0f;
else if (meta_backend_is_stage_views_scaled (backend))
texture_scale = 1.0f / surface_scale;
else
texture_scale = (meta_logical_monitor_get_scale (logical_monitor) /
surface_scale);
meta_cursor_sprite_set_texture_scale (sprite, texture_scale);
meta_cursor_sprite_set_texture_transform (sprite,
surface->buffer_transform);
if (surface->viewport.has_src_rect)
{
meta_cursor_sprite_set_viewport_src_rect (sprite,
&surface->viewport.src_rect);
}
else
{
meta_cursor_sprite_reset_viewport_src_rect (sprite);
}
if (surface->viewport.has_dst_size)
{
int dst_width;
int dst_height;
if (meta_backend_is_stage_views_scaled (backend))
{
dst_width = surface->viewport.dst_width;
dst_height = surface->viewport.dst_height;
}
else
{
float monitor_scale =
meta_logical_monitor_get_scale (logical_monitor);
dst_width = (int) (surface->viewport.dst_width * monitor_scale);
dst_height = (int) (surface->viewport.dst_height * monitor_scale);
}
meta_cursor_sprite_set_viewport_dst_size (sprite,
dst_width,
dst_height);
}
else
{
meta_cursor_sprite_reset_viewport_dst_size (sprite);
}
}
meta_wayland_surface_set_main_monitor (surface, logical_monitor);
meta_wayland_surface_update_outputs (surface);
meta_wayland_surface_notify_preferred_scale_monitor (surface);
}
static ClutterColorState *
ensure_default_color_state (MetaCursorTracker *cursor_tracker)
{
@ -135,4 +229,5 @@ meta_cursor_sprite_wayland_class_init (MetaCursorSpriteWaylandClass *klass)
cursor_sprite_class->invalidate =
meta_cursor_sprite_wayland_invalidate;
cursor_sprite_class->is_animated = meta_cursor_sprite_wayland_is_animated;
cursor_sprite_class->prepare_at = meta_cursor_sprite_wayland_prepare_at;
}

View File

@ -30,10 +30,6 @@
#include "wayland/meta-wayland-presentation-time-private.h"
#include "wayland/meta-wayland-private.h"
#ifdef HAVE_XWAYLAND
#include "wayland/meta-xwayland.h"
#endif
typedef struct _MetaWaylandCursorSurfacePrivate MetaWaylandCursorSurfacePrivate;
struct _MetaWaylandCursorSurfacePrivate
@ -104,96 +100,6 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
meta_cursor_renderer_force_update (priv->cursor_renderer);
}
static void
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
float best_scale,
int x,
int y,
MetaWaylandCursorSurface *cursor_surface)
{
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_surface);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
MetaContext *context =
meta_wayland_compositor_get_context (surface->compositor);
MetaBackend *backend = meta_context_get_backend (context);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
if (logical_monitor)
{
int surface_scale;
float texture_scale;
#ifdef HAVE_XWAYLAND
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager =
&wayland_compositor->xwayland_manager;
if (meta_wayland_surface_is_xwayland (surface))
surface_scale = meta_xwayland_get_x11_ui_scaling_factor (xwayland_manager);
else
#endif /* HAVE_XWAYLAND */
surface_scale = surface->applied_state.scale;
if (surface->viewport.has_dst_size)
texture_scale = 1.0f;
else if (meta_backend_is_stage_views_scaled (backend))
texture_scale = 1.0f / surface_scale;
else
texture_scale = (meta_logical_monitor_get_scale (logical_monitor) /
surface_scale);
meta_cursor_sprite_set_texture_scale (cursor_sprite, texture_scale);
meta_cursor_sprite_set_texture_transform (cursor_sprite,
surface->buffer_transform);
if (surface->viewport.has_src_rect)
{
meta_cursor_sprite_set_viewport_src_rect (cursor_sprite,
&surface->viewport.src_rect);
}
else
{
meta_cursor_sprite_reset_viewport_src_rect (cursor_sprite);
}
if (surface->viewport.has_dst_size)
{
int dst_width;
int dst_height;
if (meta_backend_is_stage_views_scaled (backend))
{
dst_width = surface->viewport.dst_width;
dst_height = surface->viewport.dst_height;
}
else
{
float monitor_scale =
meta_logical_monitor_get_scale (logical_monitor);
dst_width = (int) (surface->viewport.dst_width * monitor_scale);
dst_height = (int) (surface->viewport.dst_height * monitor_scale);
}
meta_cursor_sprite_set_viewport_dst_size (cursor_sprite,
dst_width,
dst_height);
}
else
{
meta_cursor_sprite_reset_viewport_dst_size (cursor_sprite);
}
}
meta_wayland_surface_set_main_monitor (surface, logical_monitor);
meta_wayland_surface_update_outputs (surface);
meta_wayland_surface_notify_preferred_scale_monitor (surface);
}
static void
meta_wayland_cursor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
{
@ -362,17 +268,8 @@ meta_wayland_cursor_surface_dispose (GObject *object)
wl_list_for_each_safe (cb, next, &priv->frame_callbacks, link)
wl_resource_destroy (cb->resource);
g_signal_handlers_disconnect_by_func (priv->cursor_sprite,
cursor_sprite_prepare_at, cursor_surface);
g_clear_object (&priv->cursor_renderer);
if (priv->cursor_sprite)
{
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (priv->cursor_sprite),
NULL, NULL);
g_clear_object (&priv->cursor_sprite);
}
g_clear_object (&priv->cursor_sprite);
if (priv->buffer)
{
@ -413,9 +310,6 @@ meta_wayland_cursor_surface_constructed (GObject *object)
priv->cursor_sprite = meta_cursor_sprite_wayland_new (surface,
cursor_tracker);
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (priv->cursor_sprite),
(MetaCursorPrepareFunc) cursor_sprite_prepare_at,
cursor_surface);
}
static void

View File

@ -32,7 +32,6 @@
#include "wayland/meta-wayland-tablet.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-logical-monitor.h"
#include "tablet-unstable-v2-server-protocol.h"
@ -425,39 +424,6 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
}
static void
tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
float best_scale,
int x,
int y,
MetaWaylandTabletTool *tool)
{
MetaBackend *backend = backend_from_tool (tool);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
/* Reload the cursor texture if the scale has changed. */
if (logical_monitor)
{
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
float ceiled_scale;
ceiled_scale = ceilf (logical_monitor->scale);
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) ceiled_scale);
if (meta_backend_is_stage_views_scaled (backend))
meta_cursor_sprite_set_texture_scale (cursor_sprite,
1.0f / ceiled_scale);
else
meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0f);
}
}
MetaWaylandTabletTool *
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDeviceTool *device_tool)
@ -480,9 +446,6 @@ meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
tool->default_sprite = meta_cursor_sprite_xcursor_new (META_CURSOR_DEFAULT,
cursor_tracker);
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
(MetaCursorPrepareFunc) tool_cursor_prepare_at,
tool);
return tool;
}
@ -504,8 +467,6 @@ meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
wl_list_init (wl_resource_get_link (resource));
}
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
NULL, NULL);
g_object_unref (tool->default_sprite);
g_free (tool);