MetaCursorTracker: add support for loading cursors from the theme

Not only this way we get the right Adwaita cursor as the default
(instead of shipping our own in png format), but we also add
support for all MetaCursors as root cursor (which most important
should allow us to have I-beams in shell entries)

https://bugzilla.gnome.org/show_bug.cgi?id=707573
This commit is contained in:
Giovanni Campagna 2013-09-06 10:37:03 +02:00
parent a3e44d13d1
commit 7baf687499
6 changed files with 116 additions and 117 deletions

View File

@ -1,5 +1,5 @@
SUBDIRS=src protocol data po doc SUBDIRS=src protocol po doc
EXTRA_DIST = HACKING MAINTAINERS rationales.txt EXTRA_DIST = HACKING MAINTAINERS rationales.txt

View File

@ -209,19 +209,7 @@ if test x$found_introspection != xno; then
AC_SUBST(META_GIR) AC_SUBST(META_GIR)
fi fi
AC_MSG_CHECKING([Xcursor]) MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
if $PKG_CONFIG xcursor; then
have_xcursor=yes
else
have_xcursor=no
fi
AC_MSG_RESULT($have_xcursor)
if test x$have_xcursor = xyes; then
echo "Building with Xcursor"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
fi
# We always build with wayland enabled # We always build with wayland enabled
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support]) AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
@ -473,7 +461,6 @@ src/Makefile
src/libmutter-wayland.pc src/libmutter-wayland.pc
src/compositor/plugins/Makefile src/compositor/plugins/Makefile
protocol/Makefile protocol/Makefile
data/Makefile
po/Makefile.in po/Makefile.in
]) ])

View File

@ -1,3 +0,0 @@
defaultcursordir = $(pkgdatadir)/cursors
dist_defaultcursor_DATA = left_ptr.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 736 B

View File

@ -64,9 +64,7 @@
#ifdef HAVE_XKB #ifdef HAVE_XKB
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#endif #endif
#ifdef HAVE_XCURSOR
#include <X11/Xcursor/Xcursor.h> #include <X11/Xcursor/Xcursor.h>
#endif
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
#include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h> #include <X11/extensions/Xdamage.h>
@ -828,14 +826,10 @@ meta_display_open (void)
meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n");
} }
#ifdef HAVE_XCURSOR
{ {
XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ()); XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ());
XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ()); XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ());
} }
#else /* HAVE_XCURSOR */
meta_verbose ("Not compiled with Xcursor support\n");
#endif /* !HAVE_XCURSOR */
/* Create the leader window here. Set its properties and /* Create the leader window here. Set its properties and
* use the timestamp from one of the PropertyNotify events * use the timestamp from one of the PropertyNotify events
@ -4726,7 +4720,6 @@ void
meta_display_set_cursor_theme (const char *theme, meta_display_set_cursor_theme (const char *theme,
int size) int size)
{ {
#ifdef HAVE_XCURSOR
GSList *tmp; GSList *tmp;
MetaDisplay *display = meta_get_display (); MetaDisplay *display = meta_get_display ();
@ -4743,8 +4736,6 @@ meta_display_set_cursor_theme (const char *theme,
tmp = tmp->next; tmp = tmp->next;
} }
#endif
} }
/* /*

View File

@ -43,6 +43,7 @@
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <X11/extensions/Xfixes.h> #include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#include "meta-cursor-tracker-private.h" #include "meta-cursor-tracker-private.h"
#include "screen-private.h" #include "screen-private.h"
@ -71,7 +72,7 @@ struct _MetaCursorTracker {
MetaCursorReference *sprite; MetaCursorReference *sprite;
MetaCursorReference *root_cursor; MetaCursorReference *root_cursor;
MetaCursorReference *default_cursor; MetaCursorReference *default_cursors[META_CURSOR_LAST];
int current_x, current_y; int current_x, current_y;
MetaRectangle current_rect; MetaRectangle current_rect;
@ -127,49 +128,107 @@ meta_cursor_reference_unref (MetaCursorReference *self)
} }
} }
static MetaCursorReference * static const char *
meta_cursor_reference_from_file (MetaCursorTracker *tracker, get_cursor_filename (MetaCursor cursor)
const char *filename,
GError **error)
{ {
GdkPixbuf *pixbuf; switch (cursor)
{
case META_CURSOR_DEFAULT:
return "left_ptr";
break;
case META_CURSOR_NORTH_RESIZE:
return "top_side";
break;
case META_CURSOR_SOUTH_RESIZE:
return "bottom_side";
break;
case META_CURSOR_WEST_RESIZE:
return "left_side";
break;
case META_CURSOR_EAST_RESIZE:
return "right_side";
break;
case META_CURSOR_SE_RESIZE:
return "bottom_right_corner";
break;
case META_CURSOR_SW_RESIZE:
return "bottom_left_corner";
break;
case META_CURSOR_NE_RESIZE:
return "top_right_corner";
break;
case META_CURSOR_NW_RESIZE:
return "top_left_corner";
break;
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
return "fleur";
break;
case META_CURSOR_BUSY:
return "busy";
break;
case META_CURSOR_DND_IN_DRAG:
return "dnd-in-drag";
break;
case META_CURSOR_DND_MOVE:
return "dnd-copy";
break;
case META_CURSOR_DND_UNSUPPORTED_TARGET:
return "dnd-none";
break;
case META_CURSOR_POINTING_HAND:
return "hand";
break;
case META_CURSOR_CROSSHAIR:
return "crosshair";
break;
case META_CURSOR_IBEAM:
return "xterm";
break;
default:
g_assert_not_reached ();
return NULL;
}
}
static MetaCursorReference *
meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
MetaCursor cursor)
{
const char *theme;
const char *filename;
int size;
XcursorImage *image;
int width, height, rowstride; int width, height, rowstride;
int bits_per_sample;
int n_channels;
gboolean has_alpha;
CoglPixelFormat cogl_format; CoglPixelFormat cogl_format;
uint32_t gbm_format; uint32_t gbm_format;
ClutterBackend *clutter_backend; ClutterBackend *clutter_backend;
CoglContext *cogl_context; CoglContext *cogl_context;
MetaCursorReference *self; MetaCursorReference *self;
pixbuf = gdk_pixbuf_new_from_file (filename, error); filename = get_cursor_filename (cursor);
if (!pixbuf) theme = XcursorGetTheme (tracker->screen->display->xdisplay);
size = XcursorGetDefaultSize (tracker->screen->display->xdisplay);
image = XcursorLibraryLoadImage (filename, theme, size);
if (!image)
return NULL; return NULL;
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); width = image->width;
width = gdk_pixbuf_get_width (pixbuf); height = image->height;
height = gdk_pixbuf_get_height (pixbuf); rowstride = width * 4;
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
g_assert (bits_per_sample == 8); gbm_format = GBM_FORMAT_ARGB8888;
if (has_alpha) #if G_BYTE_ORDER == G_LITTLE_ENDIAN
{ cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
g_assert (n_channels == 4); #else
cogl_format = COGL_PIXEL_FORMAT_RGBA_8888; cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
gbm_format = GBM_FORMAT_ARGB8888; #endif
}
else
{
g_assert (n_channels == 3);
cogl_format = COGL_PIXEL_FORMAT_RGB_888;
gbm_format = GBM_FORMAT_XRGB8888;
}
self = g_slice_new0 (MetaCursorReference); self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1; self->ref_count = 1;
self->hot_x = image->xhot;
self->hot_y = image->yhot;
clutter_backend = clutter_get_default_backend (); clutter_backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (clutter_backend); cogl_context = clutter_backend_get_cogl_context (clutter_backend);
@ -178,54 +237,29 @@ meta_cursor_reference_from_file (MetaCursorTracker *tracker,
cogl_format, cogl_format,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
rowstride, rowstride,
gdk_pixbuf_get_pixels (pixbuf), (uint8_t*)image->pixels,
NULL); NULL);
if (tracker->gbm) if (tracker->gbm)
{ {
if (width > 64 || height > 64) if (width > 64 || height > 64)
{ {
meta_warning ("Invalid default cursor size (must be at most 64x64)\n"); meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
goto out; goto out;
} }
if (gbm_device_is_format_supported (tracker->gbm, gbm_format, if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE)) GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
{ {
uint8_t *data; uint32_t buf[64 * 64];
uint8_t buf[4 * 64 * 64]; int i;
int i, j;
self->bo = gbm_bo_create (tracker->gbm, 64, 64, self->bo = gbm_bo_create (tracker->gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
data = gdk_pixbuf_get_pixels (pixbuf);
memset (buf, 0, sizeof(buf)); memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++) for (i = 0; i < height; i++)
{ memcpy (buf + i * 64, image->pixels + i * width, width * 4);
for (j = 0; j < width; j++)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
/* The byte order is B G R (A) */
buf[i * 4 * 64 + j * 4 + 0] = data[i * rowstride + j * n_channels + 2];
buf[i * 4 * 64 + j * 4 + 1] = data[i * rowstride + j * n_channels + 1];
buf[i * 4 * 64 + j * 4 + 2] = data[i * rowstride + j * n_channels + 0];
if (has_alpha)
buf[i * 4 * 64 + j * 4 + 3] = data[i * rowstride + j * n_channels + 3];
else
buf[i * 4 * 64 + j * 4 + 3] = 0;
#else
/* The byte order is (A) R G B */
buf[i * 4 * 64 + j * 4 + 3] = data[i * rowstride + j * n_channels + 2];
buf[i * 4 * 64 + j * 4 + 2] = data[i * rowstride + j * n_channels + 1];
buf[i * 4 * 64 + j * 4 + 1] = data[i * rowstride + j * n_channels + 0];
if (has_alpha)
buf[i * 4 * 64 + j * 4 + 0] = data[i * rowstride + j * n_channels + 3];
else
buf[i * 4 * 64 + j * 4 + 0] = 0;
#endif
}
}
gbm_bo_write (self->bo, buf, 64 * 64 * 4); gbm_bo_write (self->bo, buf, 64 * 64 * 4);
} }
@ -234,7 +268,7 @@ meta_cursor_reference_from_file (MetaCursorTracker *tracker,
} }
out: out:
g_object_unref (pixbuf); XcursorImageDestroy (image);
return self; return self;
} }
@ -431,13 +465,17 @@ static void
meta_cursor_tracker_finalize (GObject *object) meta_cursor_tracker_finalize (GObject *object)
{ {
MetaCursorTracker *self = META_CURSOR_TRACKER (object); MetaCursorTracker *self = META_CURSOR_TRACKER (object);
int i;
if (self->sprite) if (self->sprite)
meta_cursor_reference_unref (self->sprite); meta_cursor_reference_unref (self->sprite);
if (self->root_cursor) if (self->root_cursor)
meta_cursor_reference_unref (self->root_cursor); meta_cursor_reference_unref (self->root_cursor);
if (self->default_cursor)
meta_cursor_reference_unref (self->default_cursor); for (i = 0; i < META_CURSOR_LAST; i++)
if (self->default_cursors[i])
meta_cursor_reference_unref (self->default_cursors[i]);
if (self->pipeline) if (self->pipeline)
cogl_object_unref (self->pipeline); cogl_object_unref (self->pipeline);
if (self->gbm) if (self->gbm)
@ -693,33 +731,18 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
} }
} }
static void static MetaCursorReference *
ensure_wayland_cursor (MetaCursorTracker *tracker) ensure_wayland_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{ {
char *filename; if (tracker->default_cursors[cursor])
GError *error; return tracker->default_cursors[cursor];
if (tracker->default_cursor) tracker->default_cursors[cursor] = meta_cursor_reference_from_theme (tracker, cursor);
return; if (!tracker->default_cursors[cursor])
meta_warning ("Failed to load cursor from theme\n");
filename = g_build_filename (MUTTER_PKGDATADIR, return tracker->default_cursors[cursor];
"cursors/left_ptr.png",
NULL);
error = NULL;
tracker->default_cursor = meta_cursor_reference_from_file (tracker, filename, &error);
if (!tracker->default_cursor)
{
if (error)
g_error ("Failed to load default cursor: %s", error->message);
else
g_error ("Failed to load default cursor");
}
tracker->default_cursor->hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
tracker->default_cursor->hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
g_free (filename);
} }
void void
@ -739,11 +762,12 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
/* Now update the real root cursor */ /* Now update the real root cursor */
if (meta_is_wayland_compositor ()) if (meta_is_wayland_compositor ())
{ {
/* FIXME! We need to load all the other cursors too */ MetaCursorReference *ref;
ensure_wayland_cursor (tracker);
ref = ensure_wayland_cursor (tracker, cursor);
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref); g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
tracker->root_cursor = meta_cursor_reference_ref (tracker->default_cursor); tracker->root_cursor = meta_cursor_reference_ref (ref);
} }
} }