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:
parent
7c7cf91c32
commit
79c86ae890
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user