wayland: Load a buffer from well known location for the cursor

Semantic changes to Wayland means that we cannot rely on the compositor
setting a pointer buffer for us if set it to nil. The first part of fixing
this is to create an shm buffer containing the bytes for our cursor.

The best way to do this currently is to load the cursor from the well known
location where weston instals its cursor images. The code to implemente this
was derivedlifted from the Wayland backend in GTK+.
This commit is contained in:
Rob Bradford 2012-01-10 16:40:59 +00:00
parent 3c99fd2ddb
commit e1434cebdb
2 changed files with 182 additions and 0 deletions

View File

@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
@ -48,12 +49,15 @@
#include <wayland-client.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <cogl/cogl.h>
#define clutter_backend_wayland_get_type _clutter_backend_wayland_get_type
G_DEFINE_TYPE (ClutterBackendWayland, clutter_backend_wayland, CLUTTER_TYPE_BACKEND);
static void clutter_backend_wayland_load_cursor (ClutterBackendWayland *backend_wayland);
static void
clutter_backend_wayland_dispose (GObject *gobject)
{
@ -65,6 +69,12 @@ clutter_backend_wayland_dispose (GObject *gobject)
backend_wayland->device_manager = NULL;
}
if (backend_wayland->cursor_buffer)
{
wl_buffer_destroy (backend_wayland->cursor_buffer);
backend_wayland->cursor_buffer = NULL;
}
G_OBJECT_CLASS (clutter_backend_wayland_parent_class)->dispose (gobject);
}
@ -142,6 +152,9 @@ clutter_backend_wayland_post_parse (ClutterBackend *backend,
backend_wayland->wayland_shell))
wl_display_roundtrip (backend_wayland->wayland_display);
/* We need the shm object before we can create the cursor */
clutter_backend_wayland_load_cursor (backend_wayland);
return TRUE;
}
@ -212,6 +225,172 @@ clutter_backend_wayland_class_init (ClutterBackendWaylandClass *klass)
backend_class->get_display = clutter_backend_wayland_get_display;
}
/*
* clutter_backend_wayland_load_cursor and the two functions below were copied
* from GTK+ and adapted for clutter
*/
static void
set_pixbuf (GdkPixbuf *pixbuf,
unsigned char *map,
int width,
int height)
{
int stride, i, n_channels;
unsigned char *pixels, *end, *argb_pixels, *s, *d;
stride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
argb_pixels = map;
#define MULT(_d,c,a,t) \
do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0)
if (n_channels == 4)
{
for (i = 0; i < height; i++)
{
s = pixels + i * stride;
end = s + width * 4;
d = argb_pixels + i * width * 4;
while (s < end)
{
unsigned int t;
MULT(d[0], s[2], s[3], t);
MULT(d[1], s[1], s[3], t);
MULT(d[2], s[0], s[3], t);
d[3] = s[3];
s += 4;
d += 4;
}
}
}
else if (n_channels == 3)
{
for (i = 0; i < height; i++)
{
s = pixels + i * stride;
end = s + width * 3;
d = argb_pixels + i * width * 4;
while (s < end)
{
d[0] = s[2];
d[1] = s[1];
d[2] = s[0];
d[3] = 0xff;
s += 3;
d += 4;
}
}
}
}
static struct wl_buffer *
create_cursor (ClutterBackendWayland *backend_wayland,
GdkPixbuf *pixbuf)
{
int stride, fd;
char *filename;
GError *error = NULL;
struct wl_buffer *buffer;
gint width, height;
gsize size;
unsigned char *map;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
stride = width * 4;
size = stride * height;
fd = g_file_open_tmp ("wayland-shm-XXXXXX", &filename, &error);
if (fd < 0)
{
g_critical (G_STRLOC ": Opening temporary file failed: %s", error->message);
g_error_free (error);
return NULL;
}
unlink (filename);
g_free (filename);
if (ftruncate (fd, size) < 0)
{
g_critical (G_STRLOC ": Setting the size of temporary file failed: %s", g_strerror (errno));
close (fd);
return NULL;
}
map = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
g_critical (G_STRLOC ": Memory mapping file failed: %s", g_strerror (errno));
close (fd);
return NULL;
}
set_pixbuf (pixbuf, map, width, height);
buffer = wl_shm_create_buffer (backend_wayland->wayland_shm,
fd,
width,
height,
stride,
WL_SHM_FORMAT_ARGB32);
close(fd);
munmap (map, size);
return buffer;
}
static void
clutter_backend_wayland_load_cursor (ClutterBackendWayland *backend_wayland)
{
const gchar * const *directories;
gint j;
GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
directories = g_get_system_data_dirs();
for (j = 0; directories[j] != NULL; j++)
{
gchar *filename;
filename = g_build_filename (directories[j],
"weston",
"left_ptr.png",
NULL);
if (g_file_test (filename, G_FILE_TEST_EXISTS))
{
pixbuf = gdk_pixbuf_new_from_file (filename, &error);
if (error != NULL)
{
g_warning ("Failed to load cursor: %s: %s",
filename, error->message);
g_error_free (error);
return;
}
break;
}
}
if (!pixbuf)
return;
backend_wayland->cursor_buffer = create_cursor (backend_wayland, pixbuf);
if (backend_wayland->cursor_buffer)
{
backend_wayland->cursor_x = 15;
backend_wayland->cursor_y = 15;
}
g_object_unref (pixbuf);
}
static void
clutter_backend_wayland_init (ClutterBackendWayland *backend_wayland)
{

View File

@ -56,6 +56,9 @@ struct _ClutterBackendWayland
struct wl_compositor *wayland_compositor;
struct wl_shell *wayland_shell;
struct wl_shm *wayland_shm;
struct wl_buffer *cursor_buffer;
gint cursor_x, cursor_y;
GSource *wayland_source;
/* event timer */