backend: Store XcursorImages for theme cursors

There's a chance the icon will be animated, so store the XcursorImages
instead of the individual XcursorImage, and handle that as a nimages=1
special case.

API to "tick" a cursor animation, and retrieve current frame timing
information has been added.

https://bugzilla.gnome.org/show_bug.cgi?id=752342
This commit is contained in:
Carlos Garnacho 2015-07-13 20:32:42 +02:00
parent e648f2c244
commit 141760057b
2 changed files with 61 additions and 8 deletions

View File

@ -24,6 +24,7 @@
#include "meta-cursor.h"
#include <X11/Xcursor/Xcursor.h>
#include <cogl/cogl.h>
#ifdef HAVE_NATIVE_BACKEND
@ -42,6 +43,8 @@ typedef struct {
struct _MetaCursorReference {
int ref_count;
int current_frame;
XcursorImages *xcursor_images;
MetaCursor cursor;
MetaCursorImage image;
};
@ -56,4 +59,8 @@ struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_y);
#endif
gboolean meta_cursor_reference_is_animated (MetaCursorReference *self);
void meta_cursor_reference_tick_frame (MetaCursorReference *self);
guint meta_cursor_reference_get_current_frame_time (MetaCursorReference *self);
#endif /* META_CURSOR_PRIVATE_H */

View File

@ -67,6 +67,8 @@ meta_cursor_image_free (MetaCursorImage *image)
static void
meta_cursor_reference_free (MetaCursorReference *self)
{
if (self->xcursor_images)
XcursorImagesDestroy (self->xcursor_images);
meta_cursor_image_free (&self->image);
g_slice_free (MetaCursorReference, self);
}
@ -135,12 +137,12 @@ meta_cursor_create_x_cursor (Display *xdisplay,
return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
}
static XcursorImage *
static XcursorImages *
load_cursor_on_client (MetaCursor cursor)
{
return XcursorLibraryLoadImage (translate_meta_cursor (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size ());
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size ());
}
#ifdef HAVE_NATIVE_BACKEND
@ -256,6 +258,46 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
#endif
}
static XcursorImage *
meta_cursor_reference_get_current_frame_image (MetaCursorReference *self)
{
return self->xcursor_images->images[self->current_frame];
}
void
meta_cursor_reference_tick_frame (MetaCursorReference *self)
{
XcursorImage *image;
if (!meta_cursor_reference_is_animated (self))
return;
self->current_frame++;
if (self->current_frame >= self->xcursor_images->nimage)
self->current_frame = 0;
meta_cursor_image_free (&self->image);
image = meta_cursor_reference_get_current_frame_image (self);
meta_cursor_image_load_from_xcursor_image (&self->image, image);
}
guint
meta_cursor_reference_get_current_frame_time (MetaCursorReference *self)
{
if (!meta_cursor_reference_is_animated (self))
return 0;
return self->xcursor_images->images[self->current_frame]->delay;
}
gboolean
meta_cursor_reference_is_animated (MetaCursorReference *self)
{
return (self->xcursor_images &&
self->xcursor_images->nimage > 1);
}
static void
load_cursor_image (MetaCursorReference *cursor)
{
@ -266,12 +308,16 @@ load_cursor_image (MetaCursorReference *cursor)
* load this directly. */
g_assert (cursor->cursor != META_CURSOR_NONE);
image = load_cursor_on_client (cursor->cursor);
if (!image)
return;
if (!cursor->xcursor_images)
{
cursor->current_frame = 0;
cursor->xcursor_images = load_cursor_on_client (cursor->cursor);
if (!cursor->xcursor_images)
return;
}
image = meta_cursor_reference_get_current_frame_image (cursor);
meta_cursor_image_load_from_xcursor_image (&cursor->image, image);
XcursorImageDestroy (image);
}
MetaCursorReference *