Support scaling of cursor sprites given what output they are on

This commits refactors cursor handling code and plugs in logic so that
cursor sprites changes appearance as it moves across the screen.
Renderers are adapted to handle the necessary functionality.

The logic for changing the cursor sprite appearance is done outside of
MetaCursorSprite, and actually where depends on what type of cursor it
is. In mutter we now have two types of cursors that may have their
appearance changed:

 - Themed cursors (aka root cursors)
 - wl_surface cursors

Themed cursors are created by MetaScreen and when created, when
applicable(*), it will extend the cursor via connecting to a signal
which is emitted everytime the cursor is moved. The signal handler will
calculate the expected scale given the monitor it is on and reload the
theme in a correct size when needed.

wl_surface cursors are created when a wl_surface is assigned the
"cursor" role, i.e. when a client calls wl_pointer.set_cursor. A
cursor role object is created which is connected to the cursor object
by the position signal, and will set a correct texture scale given what
monitor the cursor is on and what scale the wl_surface's active buffer
is in. It will also push new buffers to the same to the cursor object
when new ones are committed to the surface.

This commit also makes texture loading lazy, since the renderer doesn't
calculate a rectangle when the cursor position changes.

The native backend is refactored to be triple-buffered; see the comment
in meta-cursor-renderer-native.c for further explanations.

* when we are running as a Wayland compositor

https://bugzilla.gnome.org/show_bug.cgi?id=744932
This commit is contained in:
Jonas Ådahl 2015-07-17 23:16:39 +08:00
parent 7c7cf91c32
commit 79c86ae890
13 changed files with 634 additions and 249 deletions

View File

@ -37,7 +37,6 @@
struct _MetaCursorRendererPrivate
{
int current_x, current_y;
MetaRectangle current_rect;
MetaCursorSprite *displayed_cursor;
gboolean handled_by_backend;
@ -47,28 +46,33 @@ typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
static void
queue_redraw (MetaCursorRenderer *renderer)
queue_redraw (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
CoglTexture *texture;
MetaRectangle rect = { 0 };
if (cursor_sprite)
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
/* During early initialization, we can have no stage */
if (!stage)
return;
if (priv->displayed_cursor && !priv->handled_by_backend)
texture = meta_cursor_sprite_get_cogl_texture (priv->displayed_cursor,
NULL, NULL);
if (cursor_sprite && !priv->handled_by_backend)
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
else
texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
meta_stage_set_cursor (META_STAGE (stage), texture, &rect);
}
static gboolean
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer)
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
return FALSE;
}
@ -84,35 +88,50 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
{
}
MetaRectangle
meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
CoglTexture *texture;
int hot_x, hot_y;
int width, height;
float texture_scale;
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
if (!texture)
return (MetaRectangle) { 0 };
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
width = cogl_texture_get_width (texture);
height = cogl_texture_get_height (texture);
return (MetaRectangle) {
.x = (int)roundf (priv->current_x - (hot_x * texture_scale)),
.y = (int)roundf (priv->current_y - (hot_y * texture_scale)),
.width = (int)roundf (width * texture_scale),
.height = (int)roundf (height * texture_scale),
};
}
static void
update_cursor (MetaCursorRenderer *renderer)
update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend;
gboolean should_redraw = FALSE;
if (priv->displayed_cursor)
{
CoglTexture *texture;
int hot_x, hot_y;
if (cursor_sprite)
meta_cursor_sprite_prepare_at (cursor_sprite,
priv->current_x,
priv->current_y);
texture = meta_cursor_sprite_get_cogl_texture (priv->displayed_cursor,
&hot_x, &hot_y);
priv->current_rect.x = priv->current_x - hot_x;
priv->current_rect.y = priv->current_y - hot_y;
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
}
else
{
priv->current_rect.x = 0;
priv->current_rect.y = 0;
priv->current_rect.width = 0;
priv->current_rect.height = 0;
}
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
handled_by_backend =
META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer,
cursor_sprite);
if (handled_by_backend != priv->handled_by_backend)
{
priv->handled_by_backend = handled_by_backend;
@ -123,7 +142,7 @@ update_cursor (MetaCursorRenderer *renderer)
should_redraw = TRUE;
if (should_redraw)
queue_redraw (renderer);
queue_redraw (renderer, cursor_sprite);
}
MetaCursorRenderer *
@ -140,16 +159,18 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
if (priv->displayed_cursor == cursor_sprite)
return;
priv->displayed_cursor = cursor_sprite;
update_cursor (renderer);
update_cursor (renderer, cursor_sprite);
}
void
meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
{
update_cursor (renderer);
queue_redraw (renderer);
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
update_cursor (renderer, priv->displayed_cursor);
}
void
@ -163,7 +184,7 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
priv->current_x = x;
priv->current_y = y;
update_cursor (renderer);
update_cursor (renderer, priv->displayed_cursor);
}
MetaCursorSprite *
@ -174,14 +195,6 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
return priv->displayed_cursor;
}
const MetaRectangle *
meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return &priv->current_rect;
}
#ifdef HAVE_WAYLAND
void
meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,

View File

@ -42,7 +42,8 @@ struct _MetaCursorRendererClass
{
GObjectClass parent_class;
gboolean (* update_cursor) (MetaCursorRenderer *renderer);
gboolean (* update_cursor) (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
#ifdef HAVE_WAYLAND
void (* realize_cursor_from_wl_buffer) (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
@ -65,7 +66,9 @@ void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
MetaRectangle meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
#ifdef HAVE_WAYLAND
void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,

View File

@ -246,10 +246,11 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
if (sprite != NULL)
{
MetaCursorSprite *cursor_sprite =
meta_cursor_sprite_from_texture (sprite,
cursor_image->xhot,
cursor_image->yhot);
MetaCursorSprite *cursor_sprite = meta_cursor_sprite_new ();
meta_cursor_sprite_set_texture (cursor_sprite,
sprite,
cursor_image->xhot,
cursor_image->yhot);
cogl_object_unref (sprite);
tracker->xfixes_cursor = cursor_sprite;
}
@ -279,7 +280,7 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
}
if (cursor_sprite)
return meta_cursor_sprite_get_cogl_texture (cursor_sprite, NULL, NULL);
return meta_cursor_sprite_get_cogl_texture (cursor_sprite);
else
return NULL;
}
@ -311,7 +312,7 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
}
if (cursor_sprite)
meta_cursor_sprite_get_cogl_texture (cursor_sprite, x, y);
meta_cursor_sprite_get_hotspot (cursor_sprite, x, y);
else
{
if (x)

View File

@ -35,9 +35,13 @@
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#ifdef HAVE_WAYLAND
#include <cogl/cogl-wayland-server.h>
#endif
enum {
PREPARE_AT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
struct _MetaCursorSprite
{
@ -46,10 +50,14 @@ struct _MetaCursorSprite
MetaCursor cursor;
CoglTexture2D *texture;
float texture_scale;
int hot_x, hot_y;
int current_frame;
XcursorImages *xcursor_images;
int theme_scale;
gboolean theme_dirty;
};
GType meta_cursor_sprite_get_type (void) G_GNUC_CONST;
@ -112,11 +120,11 @@ meta_cursor_create_x_cursor (Display *xdisplay,
}
static XcursorImages *
load_cursor_on_client (MetaCursor cursor)
load_cursor_on_client (MetaCursor cursor, int scale)
{
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size ());
meta_prefs_get_cursor_size () * scale);
}
static void
@ -129,6 +137,7 @@ meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
CoglPixelFormat cogl_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
CoglTexture *texture;
g_assert (self->texture == NULL);
@ -144,14 +153,15 @@ meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
clutter_backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
self->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
(uint8_t *) xc_image->pixels,
NULL);
self->hot_x = xc_image->xhot;
self->hot_y = xc_image->yhot;
texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
(uint8_t *) xc_image->pixels,
NULL);
meta_cursor_sprite_set_texture (self, texture,
xc_image->xhot, xc_image->yhot);
cogl_object_unref (texture);
meta_cursor_renderer_realize_cursor_from_xcursor (renderer, self, xc_image);
}
@ -198,92 +208,82 @@ meta_cursor_sprite_is_animated (MetaCursorSprite *self)
}
MetaCursorSprite *
meta_cursor_sprite_from_theme (MetaCursor cursor)
meta_cursor_sprite_new (void)
{
return g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
}
static void
meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
{
MetaCursorSprite *self;
XcursorImage *image;
self = g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
g_assert (self->cursor != META_CURSOR_NONE);
/* We might be reloading with a different scale. If so clear the old data. */
if (self->xcursor_images)
{
g_clear_pointer (&self->texture, cogl_object_unref);
XcursorImagesDestroy (self->xcursor_images);
}
self->cursor = cursor;
self->current_frame = 0;
self->xcursor_images = load_cursor_on_client (self->cursor);
self->xcursor_images = load_cursor_on_client (self->cursor,
self->theme_scale);
if (!self->xcursor_images)
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
image = meta_cursor_sprite_get_current_frame_image (self);
meta_cursor_sprite_load_from_xcursor_image (self, image);
return self;
self->theme_dirty = FALSE;
}
MetaCursorSprite *
meta_cursor_sprite_from_texture (CoglTexture2D *texture,
int hot_x,
int hot_y)
meta_cursor_sprite_from_theme (MetaCursor cursor)
{
MetaCursorSprite *self;
self = g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
self = meta_cursor_sprite_new ();
cogl_object_ref (texture);
self->texture = texture;
self->hot_x = hot_x;
self->hot_y = hot_y;
self->cursor = cursor;
self->theme_dirty = TRUE;
return self;
}
#ifdef HAVE_WAYLAND
static void
meta_cursor_sprite_load_from_buffer (MetaCursorSprite *self,
struct wl_resource *buffer,
int hot_x,
int hot_y)
void
meta_cursor_sprite_set_texture (MetaCursorSprite *self,
CoglTexture *texture,
int hot_x,
int hot_y)
{
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer =
meta_backend_get_cursor_renderer (meta_backend);
ClutterBackend *backend;
CoglContext *cogl_context;
g_clear_pointer (&self->texture, cogl_object_unref);
if (texture)
self->texture = cogl_object_ref (texture);
self->hot_x = hot_x;
self->hot_y = hot_y;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
meta_cursor_renderer_realize_cursor_from_wl_buffer (renderer, self, buffer);
}
MetaCursorSprite *
meta_cursor_sprite_from_buffer (struct wl_resource *buffer,
int hot_x,
int hot_y)
void
meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
float scale)
{
MetaCursorSprite *self;
self = g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
meta_cursor_sprite_load_from_buffer (self, buffer, hot_x, hot_y);
return self;
self->texture_scale = scale;
}
void
meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
int theme_scale)
{
if (self->theme_scale != theme_scale)
self->theme_dirty = TRUE;
self->theme_scale = theme_scale;
}
#endif
CoglTexture *
meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self,
int *hot_x,
int *hot_y)
meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self)
{
if (hot_x)
*hot_x = self->hot_x;
if (hot_y)
*hot_y = self->hot_y;
return COGL_TEXTURE (self->texture);
}
@ -302,21 +302,31 @@ meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
*hot_y = self->hot_y;
}
guint
meta_cursor_sprite_get_width (MetaCursorSprite *self)
float
meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self)
{
return cogl_texture_get_width (COGL_TEXTURE (self->texture));
return self->texture_scale;
}
guint
meta_cursor_sprite_get_height (MetaCursorSprite *self)
void
meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
int x,
int y)
{
return cogl_texture_get_height (COGL_TEXTURE (self->texture));
g_signal_emit (self, signals[PREPARE_AT], 0, x, y);
}
void
meta_cursor_sprite_realize_texture (MetaCursorSprite *self)
{
if (self->theme_dirty)
meta_cursor_sprite_load_from_theme (self);
}
static void
meta_cursor_sprite_init (MetaCursorSprite *self)
{
self->texture_scale = 1.0f;
}
static void
@ -338,4 +348,13 @@ meta_cursor_sprite_class_init (MetaCursorSpriteClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_cursor_sprite_finalize;
signals[PREPARE_AT] = g_signal_new ("prepare-at",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2,
G_TYPE_INT,
G_TYPE_INT);
}

View File

@ -23,6 +23,7 @@
#define META_CURSOR_H
#include <meta/common.h>
#include <meta/boxes.h>
typedef struct _MetaCursorSprite MetaCursorSprite;
@ -32,35 +33,40 @@ G_DECLARE_FINAL_TYPE (MetaCursorSprite,
META, CURSOR_SPRITE,
GObject);
MetaCursorSprite * meta_cursor_sprite_from_theme (MetaCursor cursor);
MetaCursorSprite * meta_cursor_sprite_new (void);
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
MetaCursorSprite * meta_cursor_sprite_from_buffer (struct wl_resource *buffer,
int hot_x,
int hot_y);
#endif
MetaCursorSprite * meta_cursor_sprite_from_theme (MetaCursor cursor);
void meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
int scale);
MetaCursor meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self);
MetaCursorSprite * meta_cursor_sprite_from_texture (CoglTexture2D *texture,
int hot_x,
int hot_y);
Cursor meta_cursor_create_x_cursor (Display *xdisplay,
MetaCursor cursor);
CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self,
int *hot_x,
int *hot_y);
void meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
int x,
int y);
void meta_cursor_sprite_realize_texture (MetaCursorSprite *self);
void meta_cursor_sprite_set_texture (MetaCursorSprite *self,
CoglTexture *texture,
int hot_x,
int hot_y);
void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
float scale);
CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self);
void meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
int *hot_x,
int *hot_y);
guint meta_cursor_sprite_get_width (MetaCursorSprite *self);
guint meta_cursor_sprite_get_height (MetaCursorSprite *self);
float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self);
gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *self);
void meta_cursor_sprite_tick_frame (MetaCursorSprite *self);

View File

@ -174,7 +174,8 @@ struct _MetaCRTC
/* Used when changing configuration */
gboolean is_dirty;
MetaCursorSprite *cursor;
/* Used by cursor renderer backend */
void *cursor_renderer_private;
gpointer driver_private;
GDestroyNotify driver_notify;

View File

@ -29,9 +29,13 @@
#include <string.h>
#include <gbm.h>
#include <xf86drm.h>
#include <errno.h>
#include <meta/util.h>
#include <meta/meta-backend.h>
#include "meta-monitor-manager-private.h"
#include "meta/boxes.h"
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
@ -40,6 +44,19 @@
#define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
/* When animating a cursor, we usually call drmModeSetCursor2 once per frame.
* Though, testing shows that we need to triple buffer the cursor buffer in
* order to avoid glitches when animating the cursor, at least when running on
* Intel. The reason for this might be (but is not confirmed to be) due to
* the user space gbm_bo cache, making us reuse and overwrite the kernel side
* buffer content before it was scanned out. To avoid this, we keep a user space
* reference to each buffer we set until at least one frame after it was drawn.
* In effect, this means we three active cursor gbm_bo's: one that that just has
* been set, one that was previously set and may or may not have been scanned
* out, and one pending that will be replaced if the cursor sprite changes.
*/
#define HW_CURSOR_BUFFER_COUNT 3
static GQuark quark_cursor_sprite = 0;
struct _MetaCursorRendererNativePrivate
@ -57,8 +74,25 @@ struct _MetaCursorRendererNativePrivate
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
typedef enum _MetaCursorGbmBoState
{
META_CURSOR_GBM_BO_STATE_NONE,
META_CURSOR_GBM_BO_STATE_SET,
META_CURSOR_GBM_BO_STATE_INVALIDATED,
} MetaCursorGbmBoState;
typedef struct _MetaCursorNativePrivate
{
guint active_bo;
MetaCursorGbmBoState pending_bo_state;
struct gbm_bo *bos[HW_CURSOR_BUFFER_COUNT];
} MetaCursorNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
static MetaCursorNativePrivate *
ensure_cursor_priv (MetaCursorSprite *cursor_sprite);
static void
meta_cursor_renderer_native_finalize (GObject *object)
{
@ -74,26 +108,53 @@ meta_cursor_renderer_native_finalize (GObject *object)
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
}
static guint
get_pending_cursor_sprite_gbm_bo_index (MetaCursorSprite *cursor_sprite)
{
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
return (cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
}
static struct gbm_bo *
get_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
get_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
{
return g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
guint pending_bo;
if (!cursor_priv)
return NULL;
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
return cursor_priv->bos[pending_bo];
}
static struct gbm_bo *
get_active_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
{
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
if (!cursor_priv)
return NULL;
return cursor_priv->bos[cursor_priv->active_bo];
}
static void
cursor_gbm_bo_free (gpointer data)
set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
struct gbm_bo *bo)
{
if (!data)
return;
MetaCursorNativePrivate *cursor_priv;
guint pending_bo;
gbm_bo_destroy ((struct gbm_bo *)data);
}
cursor_priv = ensure_cursor_priv (cursor_sprite);
static void
set_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite, struct gbm_bo *bo)
{
g_object_set_qdata_full (G_OBJECT (cursor_sprite), quark_cursor_sprite,
bo, cursor_gbm_bo_free);
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
cursor_priv->bos[pending_bo] = bo;
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_SET;
}
static void
@ -104,55 +165,78 @@ set_crtc_cursor (MetaCursorRendererNative *native,
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
if (crtc->cursor == cursor_sprite && !force)
return;
crtc->cursor = cursor_sprite;
if (cursor_sprite)
{
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
struct gbm_bo *bo;
union gbm_bo_handle handle;
int hot_x, hot_y;
bo = get_cursor_sprite_gbm_bo (cursor_sprite);
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
bo = get_pending_cursor_sprite_gbm_bo (cursor_sprite);
else
bo = get_active_cursor_sprite_gbm_bo (cursor_sprite);
if (!force && bo == crtc->cursor_renderer_private)
return;
crtc->cursor_renderer_private = bo;
handle = gbm_bo_get_handle (bo);
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
{
cursor_priv->active_bo =
(cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_NONE;
}
}
else
{
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
if (force || crtc->cursor_renderer_private != NULL)
{
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
crtc->cursor_renderer_private = NULL;
}
}
}
static void
update_hw_cursor (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite,
gboolean force)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
const MetaRectangle *cursor_rect = meta_cursor_renderer_get_rect (renderer);
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
MetaRectangle rect;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
if (cursor_sprite)
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
else
rect = (MetaRectangle) { 0 };
for (i = 0; i < n_crtcs; i++)
{
gboolean crtc_should_have_cursor;
gboolean crtc_should_use_cursor;
MetaCursorSprite *crtc_cursor;
MetaRectangle *crtc_rect;
crtc_rect = &crtcs[i].rect;
crtc_should_have_cursor = (priv->has_hw_cursor && meta_rectangle_overlap (cursor_rect, crtc_rect));
if (crtc_should_have_cursor)
crtc_should_use_cursor = (priv->has_hw_cursor &&
meta_rectangle_overlap (&rect, crtc_rect));
if (crtc_should_use_cursor)
crtc_cursor = cursor_sprite;
else
crtc_cursor = NULL;
@ -162,49 +246,78 @@ update_hw_cursor (MetaCursorRendererNative *native,
if (crtc_cursor)
{
drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
cursor_rect->x - crtc_rect->x,
cursor_rect->y - crtc_rect->y);
rect.x - crtc_rect->x,
rect.y - crtc_rect->y);
}
}
}
static gboolean
should_have_hw_cursor (MetaCursorRenderer *renderer)
has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
{
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
if (cursor_sprite)
return (get_cursor_sprite_gbm_bo (cursor_sprite) != NULL);
else
switch (cursor_priv->pending_bo_state)
{
case META_CURSOR_GBM_BO_STATE_NONE:
return get_active_cursor_sprite_gbm_bo (cursor_sprite) != NULL;
case META_CURSOR_GBM_BO_STATE_SET:
return TRUE;
case META_CURSOR_GBM_BO_STATE_INVALIDATED:
return FALSE;
}
g_assert_not_reached ();
return FALSE;
}
static gboolean
should_have_hw_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
CoglTexture *texture;
if (!cursor_sprite)
return FALSE;
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
if (!texture)
return FALSE;
if (meta_cursor_sprite_get_texture_scale (cursor_sprite) != 1)
return FALSE;
if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite))
return FALSE;
return TRUE;
}
static gboolean
meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorSprite *cursor_sprite;
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
priv->animation_timeout_id = 0;
cursor_sprite =
meta_cursor_renderer_get_cursor (META_CURSOR_RENDERER (native));
meta_cursor_sprite_tick_frame (cursor_sprite);
meta_cursor_renderer_force_update (META_CURSOR_RENDERER (native));
meta_cursor_renderer_force_update (renderer);
meta_cursor_renderer_native_force_update (native);
return G_SOURCE_REMOVE;
}
static void
meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native)
meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorSprite *cursor_sprite;
gboolean cursor_change;
guint delay;
cursor_sprite =
meta_cursor_renderer_get_cursor (META_CURSOR_RENDERER (native));
cursor_change = cursor_sprite != priv->last_cursor;
priv->last_cursor = cursor_sprite;
@ -234,15 +347,19 @@ meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native)
}
static gboolean
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer)
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
meta_cursor_renderer_native_trigger_frame (native);
if (cursor_sprite)
meta_cursor_sprite_realize_texture (cursor_sprite);
priv->has_hw_cursor = should_have_hw_cursor (renderer);
update_hw_cursor (native, FALSE);
meta_cursor_renderer_native_trigger_frame (native, cursor_sprite);
priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite);
update_hw_cursor (native, cursor_sprite, FALSE);
return priv->has_hw_cursor;
}
@ -257,6 +374,38 @@ get_hardware_cursor_size (MetaCursorRendererNative *native,
*height = priv->cursor_height;
}
static void
cursor_priv_free (gpointer data)
{
MetaCursorNativePrivate *cursor_priv = data;
guint i;
if (!data)
return;
for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++)
g_clear_pointer (&cursor_priv->bos[0], (GDestroyNotify) gbm_bo_destroy);
g_slice_free (MetaCursorNativePrivate, cursor_priv);
}
static MetaCursorNativePrivate *
ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
{
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
if (!cursor_priv)
{
cursor_priv = g_slice_new0 (MetaCursorNativePrivate);
g_object_set_qdata_full (G_OBJECT (cursor_sprite),
quark_cursor_sprite,
cursor_priv,
cursor_priv_free);
}
return cursor_priv;
}
static void
load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite,
@ -288,17 +437,45 @@ load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
bo = gbm_bo_create (priv->gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo)
{
meta_warning ("Failed to allocate HW cursor buffer\n");
return;
}
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
if (gbm_bo_write (bo, buf, cursor_width * cursor_height * 4) != 0)
{
meta_warning ("Failed to write cursors buffer data: %s",
g_strerror (errno));
gbm_bo_destroy (bo);
return;
}
gbm_bo_write (bo, buf, cursor_width * cursor_height * 4);
set_cursor_sprite_gbm_bo (cursor_sprite, bo);
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
{
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
}
static void
invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
{
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
guint pending_bo;
if (!cursor_priv)
return;
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
g_clear_pointer (&cursor_priv->bos[pending_bo],
(GDestroyNotify) gbm_bo_destroy);
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
}
#ifdef HAVE_WAYLAND
@ -312,10 +489,17 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
meta_cursor_renderer_native_get_instance_private (native);
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
CoglTexture *texture;
uint width, height;
width = meta_cursor_sprite_get_width (cursor_sprite);
height = meta_cursor_sprite_get_height (cursor_sprite);
/* Destroy any previous pending cursor buffer; we'll always either fail (which
* should unset, or succeed, which will set new buffer.
*/
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite);
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
width = cogl_texture_get_width (texture);
height = cogl_texture_get_height (texture);
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
@ -384,7 +568,7 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
return;
}
set_cursor_sprite_gbm_bo (cursor_sprite, bo);
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo);
}
}
#endif
@ -396,6 +580,8 @@ meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *ren
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite);
load_cursor_sprite_gbm_buffer (native,
cursor_sprite,
(uint8_t *) xc_image->pixels,
@ -423,12 +609,20 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
}
static void
force_update_hw_cursor (MetaCursorRendererNative *native)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
update_hw_cursor (native, meta_cursor_renderer_get_cursor (renderer), TRUE);
}
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaCursorRendererNative *native)
{
/* Our tracking is all messed up, so force an update. */
update_hw_cursor (native, TRUE);
force_update_hw_cursor (native);
}
static void
@ -476,5 +670,5 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{
update_hw_cursor (native, TRUE);
force_update_hw_cursor (native);
}

View File

@ -40,25 +40,29 @@ typedef struct _MetaCursorRendererX11Private MetaCursorRendererX11Private;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererX11, meta_cursor_renderer_x11, META_TYPE_CURSOR_RENDERER);
static gboolean
meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer)
meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer);
MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11);
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
Window xwindow = meta_backend_x11_get_xwindow (backend);
if (xwindow == None)
return FALSE;
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
if (xwindow == None)
{
if (cursor_sprite)
meta_cursor_sprite_realize_texture (cursor_sprite);
return FALSE;
}
gboolean has_server_cursor = FALSE;
if (cursor_sprite)
{
MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite);
if (cursor != META_CURSOR_NONE)
{
Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
@ -80,6 +84,9 @@ meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer)
priv->server_cursor_visible = has_server_cursor;
}
if (!priv->server_cursor_visible && cursor_sprite)
meta_cursor_sprite_realize_texture (cursor_sprite);
return priv->server_cursor_visible;
}

View File

@ -39,8 +39,11 @@ G_DEFINE_TYPE (MetaCursorRendererX11Nested, meta_cursor_renderer_x11_nested,
META_TYPE_CURSOR_RENDERER);
static gboolean
meta_cursor_renderer_x11_nested_update_cursor (MetaCursorRenderer *renderer)
meta_cursor_renderer_x11_nested_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
if (cursor_sprite)
meta_cursor_sprite_realize_texture (cursor_sprite);
return FALSE;
}

View File

@ -152,6 +152,10 @@ const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen
const MetaMonitorInfo* meta_screen_calculate_monitor_for_window (MetaScreen *screen,
MetaWindow *window);
const MetaMonitorInfo* meta_screen_get_monitor_for_point (MetaScreen *screen,
int x,
int y);
const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen,
int which_monitor,

View File

@ -43,6 +43,7 @@
#include <meta/meta-enum-types.h>
#include "core.h"
#include "meta-cursor-tracker-private.h"
#include "boxes-private.h"
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xcomposite.h>
@ -1255,6 +1256,31 @@ update_num_workspaces (MetaScreen *screen,
g_object_notify (G_OBJECT (screen), "n-workspaces");
}
static void
root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
int x,
int y,
MetaScreen *screen)
{
const MetaMonitorInfo *monitor;
monitor = meta_screen_get_monitor_for_point (screen, x, y);
/* Reload the cursor texture if the scale has changed. */
meta_cursor_sprite_set_theme_scale (cursor_sprite, monitor->scale);
}
static void
manage_root_cursor_sprite_scale (MetaScreen *screen,
MetaCursorSprite *cursor_sprite)
{
g_signal_connect_object (cursor_sprite,
"prepare-at",
G_CALLBACK (root_cursor_prepare_at),
screen,
0);
}
void
meta_screen_update_cursor (MetaScreen *screen)
{
@ -1265,6 +1291,10 @@ meta_screen_update_cursor (MetaScreen *screen)
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (screen);
cursor_sprite = meta_cursor_sprite_from_theme (cursor);
if (meta_is_wayland_compositor ())
manage_root_cursor_sprite_scale (screen, cursor_sprite);
meta_cursor_tracker_set_root_cursor (tracker, cursor_sprite);
g_object_unref (cursor_sprite);
@ -1454,6 +1484,25 @@ meta_screen_get_monitor_index_for_rect (MetaScreen *screen,
return monitor->number;
}
const MetaMonitorInfo *
meta_screen_get_monitor_for_point (MetaScreen *screen,
int x,
int y)
{
int i;
if (screen->n_monitor_infos == 1)
return &screen->monitor_infos[0];
for (i = 0; i < screen->n_monitor_infos; i++)
{
if (POINT_IN_RECT (x, y, screen->monitor_infos[i].rect))
return &screen->monitor_infos[i];
}
return NULL;
}
const MetaMonitorInfo*
meta_screen_get_monitor_neighbor (MetaScreen *screen,
int which_monitor,

View File

@ -44,15 +44,22 @@
#include "config.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include <linux/input.h>
#include "meta-wayland-pointer.h"
#include "meta-wayland-popup.h"
#include "meta-wayland-private.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-buffer.h"
#include "meta-cursor.h"
#include "meta-cursor-tracker-private.h"
#include "meta-surface-actor-wayland.h"
#include "meta/meta-cursor-tracker.h"
#include "backends/meta-backend-private.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-cursor-renderer.h"
#include <string.h>
@ -61,6 +68,10 @@
struct _MetaWaylandSurfaceRoleCursor
{
MetaWaylandSurfaceRole parent;
int hot_x;
int hot_y;
MetaCursorSprite *cursor_sprite;
};
GType meta_wayland_surface_role_cursor_get_type (void) G_GNUC_CONST;
@ -215,32 +226,6 @@ sync_focus_surface (MetaWaylandPointer *pointer)
}
static void
set_cursor_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
if (pointer->cursor_surface == surface)
return;
if (pointer->cursor_surface)
wl_list_remove (&pointer->cursor_surface_destroy_listener.link);
pointer->cursor_surface = surface;
if (pointer->cursor_surface)
wl_resource_add_destroy_listener (pointer->cursor_surface->resource,
&pointer->cursor_surface_destroy_listener);
}
static void
pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, cursor_surface_destroy_listener);
set_cursor_surface (pointer, NULL);
meta_wayland_pointer_update_cursor_surface (pointer);
}
static void
pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
@ -376,7 +361,6 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
pointer->cursor_surface = NULL;
pointer->cursor_surface_destroy_listener.notify = pointer_handle_cursor_surface_destroy;
pointer->default_grab.interface = &default_pointer_grab_interface;
pointer->default_grab.pointer = pointer;
@ -390,10 +374,10 @@ void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
meta_wayland_pointer_set_focus (pointer, NULL);
set_cursor_surface (pointer, NULL);
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
pointer->display = NULL;
pointer->cursor_surface = NULL;
}
static int
@ -742,22 +726,17 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
if (pointer->current)
{
MetaCursorSprite *cursor_sprite;
MetaCursorSprite *cursor_sprite = NULL;
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
if (pointer->cursor_surface)
{
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
cursor_sprite = meta_cursor_sprite_from_buffer (buffer,
pointer->hotspot_x,
pointer->hotspot_y);
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (pointer->cursor_surface->role);
cursor_sprite = cursor_role->cursor_sprite;
}
else
cursor_sprite = NULL;
meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite);
if (cursor_sprite)
g_object_unref (cursor_sprite);
}
else
{
@ -765,12 +744,76 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
}
}
static void
update_cursor_sprite_texture (MetaWaylandSurface *surface)
{
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (meta_get_backend ());
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaCursorSprite *cursor_sprite = cursor_role->cursor_sprite;
ClutterBackend *clutter_backend = clutter_get_default_backend ();
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
CoglTexture *texture;
if (surface->buffer)
{
struct wl_resource *buffer;
buffer = surface->buffer->resource;
texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context,
buffer,
NULL);
meta_cursor_sprite_set_texture (cursor_sprite,
texture,
cursor_role->hot_x * surface->scale,
cursor_role->hot_y * surface->scale);
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_renderer,
cursor_sprite,
buffer);
cogl_object_unref (texture);
}
else
{
meta_cursor_sprite_set_texture (cursor_sprite, NULL, 0, 0);
}
meta_cursor_renderer_force_update (cursor_renderer);
}
static void
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
int x,
int y,
MetaWaylandSurfaceRoleCursor *cursor_role)
{
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_role);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
MetaDisplay *display = meta_get_display ();
MetaScreen *screen = display->screen;
const MetaMonitorInfo *monitor;
monitor = meta_screen_get_monitor_for_point (screen, x, y);
meta_cursor_sprite_set_texture_scale (cursor_sprite,
(float)monitor->scale / surface->scale);
}
static void
meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *cursor_surface)
{
pointer->cursor_surface = cursor_surface;
meta_wayland_pointer_update_cursor_surface (pointer);
}
static void
pointer_set_cursor (struct wl_client *client,
struct wl_resource *resource,
uint32_t serial,
struct wl_resource *surface_resource,
int32_t x, int32_t y)
int32_t hot_x, int32_t hot_y)
{
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
@ -794,10 +837,28 @@ pointer_set_cursor (struct wl_client *client,
return;
}
pointer->hotspot_x = x;
pointer->hotspot_y = y;
set_cursor_surface (pointer, surface);
meta_wayland_pointer_update_cursor_surface (pointer);
if (surface)
{
MetaWaylandSurfaceRoleCursor *cursor_role;
cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
if (!cursor_role->cursor_sprite)
{
cursor_role->cursor_sprite = meta_cursor_sprite_new ();
g_signal_connect_object (cursor_role->cursor_sprite,
"prepare-at",
G_CALLBACK (cursor_sprite_prepare_at),
cursor_role,
0);
}
cursor_role->hot_x = hot_x;
cursor_role->hot_y = hot_y;
update_cursor_sprite_texture (surface);
}
meta_wayland_pointer_set_cursor_surface (pointer, surface);
}
static void
@ -877,12 +938,35 @@ cursor_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
{
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandPointer *pointer = &surface->compositor->seat->pointer;
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
if (pending->newly_attached)
meta_wayland_pointer_update_cursor_surface (pointer);
update_cursor_sprite_texture (surface);
}
static void
cursor_surface_role_dispose (GObject *object)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (object);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandPointer *pointer = &compositor->seat->pointer;
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
g_signal_handlers_disconnect_by_func (cursor_tracker,
(gpointer) cursor_sprite_prepare_at,
cursor_role);
if (pointer->cursor_surface == surface)
pointer->cursor_surface = NULL;
meta_wayland_pointer_update_cursor_surface (pointer);
g_clear_object (&cursor_role->cursor_sprite);
G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (object);
}
static void
@ -895,7 +979,10 @@ meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *
{
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
surface_role_class->assigned = cursor_surface_role_assigned;
surface_role_class->commit = cursor_surface_role_commit;
object_class->dispose = cursor_surface_role_dispose;
}

View File

@ -73,8 +73,6 @@ struct _MetaWaylandPointer
guint32 click_serial;
MetaWaylandSurface *cursor_surface;
struct wl_listener cursor_surface_destroy_listener;
int hotspot_x, hotspot_y;
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;