summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2010-08-16 10:38:29 -0400
committerKristian Høgsberg <krh@bitplanet.net>2010-08-16 10:38:29 -0400
commit77fb1679566566d881f16d2547d8b00857dc55bc (patch)
tree92e1dd134b8a930454db706f22053a98b027b211
parentb036ad4a9ac53def327b80203ab3aaebe709744c (diff)
Add protocol for setting the pointer image
-rw-r--r--TODO11
-rw-r--r--compositor.c155
-rw-r--r--compositor.h2
-rw-r--r--protocol.xml6
-rw-r--r--spec/main.tex18
5 files changed, 110 insertions, 82 deletions
diff --git a/TODO b/TODO
index 77a7bdd..820288a 100644
--- a/TODO
+++ b/TODO
@@ -13,17 +13,6 @@ Core wayland protocol
or do X style (content mime-type negotiation, but data goes away
when client quits).
- - protocol for setting the cursor image
-
- - should we have a mechanism to attach surface to cursor for
- guaranteed non-laggy drag?
-
- - drawing cursors, moving them, cursor themes, attaching surfaces
- to cursors. How do you change cursors when you mouse over a
- text field if you don't have subwindows? This is what we do: a
- client can set a cursor for a surface and wayland will set that
- on enter and revert to default on leave
-
- Discard buffer, as in "wayland discarded your buffer, it's no
longer visible, you can stop updating it now.", reattach, as in "oh
hey, I'm about to show your buffer that I threw away, what was it
diff --git a/compositor.c b/compositor.c
index 454d81e..0ecbb7d 100644
--- a/compositor.c
+++ b/compositor.c
@@ -125,12 +125,24 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v)
*v = t;
}
-static void
-wlsc_surface_init(struct wlsc_surface *surface,
- struct wlsc_compositor *compositor, struct wl_visual *visual,
- int32_t x, int32_t y, int32_t width, int32_t height)
+static struct wlsc_surface *
+wlsc_surface_create(struct wlsc_compositor *compositor,
+ struct wl_visual *visual,
+ int32_t x, int32_t y, int32_t width, int32_t height)
{
+ struct wlsc_surface *surface;
+
+ surface = malloc(sizeof *surface);
+ if (surface == NULL)
+ return NULL;
+
glGenTextures(1, &surface->texture);
+ glBindTexture(GL_TEXTURE_2D, surface->texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
surface->compositor = compositor;
surface->visual = visual;
wlsc_matrix_init(&surface->matrix);
@@ -140,35 +152,8 @@ wlsc_surface_init(struct wlsc_surface *surface,
wlsc_matrix_init(&surface->matrix_inv);
wlsc_matrix_translate(&surface->matrix_inv, -x, -y, 0);
wlsc_matrix_scale(&surface->matrix_inv, 1.0 / width, 1.0 / height, 1);
-}
-
-static struct wlsc_surface *
-wlsc_surface_create_from_cairo_surface(struct wlsc_compositor *ec,
- cairo_surface_t *surface,
- int x, int y, int width, int height)
-{
- struct wlsc_surface *es;
- int stride;
- void *data;
-
- stride = cairo_image_surface_get_stride(surface);
- data = cairo_image_surface_get_data(surface);
-
- es = malloc(sizeof *es);
- if (es == NULL)
- return NULL;
-
- wlsc_surface_init(es, ec, &ec->premultiplied_argb_visual,
- x, y, width, height);
- glBindTexture(GL_TEXTURE_2D, es->texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, data);
- return es;
+ return surface;
}
static void
@@ -213,6 +198,16 @@ pointer_create(struct wlsc_compositor *ec, int x, int y, int width, int height)
const int hotspot_x = 16, hotspot_y = 16;
cairo_surface_t *surface;
cairo_t *cr;
+ int stride;
+ void *data;
+
+ EGLint image_attribs[] = {
+ EGL_WIDTH, 0,
+ EGL_HEIGHT, 0,
+ EGL_IMAGE_FORMAT_MESA, EGL_IMAGE_FORMAT_ARGB8888_MESA,
+ EGL_IMAGE_USE_MESA, EGL_IMAGE_USE_SCANOUT_MESA,
+ EGL_NONE
+ };
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
width, height);
@@ -231,17 +226,37 @@ pointer_create(struct wlsc_compositor *ec, int x, int y, int width, int height)
cairo_fill(cr);
cairo_destroy(cr);
- es = wlsc_surface_create_from_cairo_surface(ec,
- surface,
- x - hotspot_x,
- y - hotspot_y,
- width, height);
-
+ es = wlsc_surface_create(ec, &ec->premultiplied_argb_visual,
+ x, y, width, height);
+
+ stride = cairo_image_surface_get_stride(surface);
+ data = cairo_image_surface_get_data(surface);
+
+ image_attribs[1] = width;
+ image_attribs[3] = height;
+ ec->default_pointer_image =
+ eglCreateDRMImageMESA(ec->display, image_attribs);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ec->default_pointer_image);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+
cairo_surface_destroy(surface);
return es;
}
+static void
+wlsc_input_device_set_default_pointer_image(struct wlsc_input_device *device)
+{
+ struct wlsc_compositor *ec = device->ec;
+
+ glBindTexture(GL_TEXTURE_2D, device->sprite->texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ec->default_pointer_image);
+ device->sprite->visual = &ec->premultiplied_argb_visual;
+ device->hotspot_x = 16;
+ device->hotspot_y = 16;
+}
+
static struct wlsc_surface *
background_create(struct wlsc_output *output, const char *filename)
{
@@ -251,11 +266,12 @@ background_create(struct wlsc_output *output, const char *filename)
void *data;
GLenum format;
- background = malloc(sizeof *background);
+ background = wlsc_surface_create(output->compositor,
+ &output->compositor->rgb_visual,
+ output->x, output->y,
+ output->width, output->height);
if (background == NULL)
return NULL;
-
- g_type_init();
pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
output->width,
@@ -268,17 +284,7 @@ background_create(struct wlsc_output *output, const char *filename)
data = gdk_pixbuf_get_pixels(pixbuf);
- wlsc_surface_init(background, output->compositor,
- &output->compositor->rgb_visual,
- output->x, output->y, output->width, output->height);
-
- glBindTexture(GL_TEXTURE_2D, background->texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- if (gdk_pixbuf_get_has_alpha(pixbuf))
+ if (gdk_pixbuf_get_has_alpha(pixbuf))
format = GL_RGBA;
else
format = GL_RGB;
@@ -432,10 +438,6 @@ surface_attach(struct wl_client *client,
struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base;
glBindTexture(GL_TEXTURE_2D, es->texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
es->visual = buffer->visual;
}
@@ -520,7 +522,7 @@ compositor_create_surface(struct wl_client *client,
struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor;
struct wlsc_surface *surface;
- surface = malloc(sizeof *surface);
+ surface = wlsc_surface_create(ec, NULL, 0, 0, 0, 0);
if (surface == NULL) {
wl_client_post_event(client,
(struct wl_object *) ec->wl_display,
@@ -528,8 +530,6 @@ compositor_create_surface(struct wl_client *client,
return;
}
- wlsc_surface_init(surface, ec, NULL, 0, 0, 0, 0);
-
wl_list_insert(ec->surface_list.prev, &surface->link);
surface->base.base.destroy = destroy_surface;
wl_client_add_surface(client, &surface->base,
@@ -609,6 +609,9 @@ wlsc_input_device_set_pointer_focus(struct wlsc_input_device *device,
time, &surface->base,
x, y, sx, sy);
+ if (!surface)
+ wlsc_input_device_set_default_pointer_image(device);
+
device->pointer_focus = surface;
}
@@ -640,7 +643,6 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
struct wlsc_surface *es;
struct wlsc_compositor *ec = device->ec;
struct wlsc_output *output;
- const int hotspot_x = 16, hotspot_y = 16;
int32_t sx, sy, width, height;
/* FIXME: We need some multi head love here. */
@@ -727,7 +729,7 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
wlsc_matrix_init(&device->sprite->matrix);
wlsc_matrix_scale(&device->sprite->matrix, 64, 64, 1);
wlsc_matrix_translate(&device->sprite->matrix,
- x - hotspot_x, y - hotspot_y, 0);
+ x - device->hotspot_x, y - device->hotspot_y, 0);
wlsc_compositor_schedule_repaint(device->ec);
}
@@ -829,6 +831,30 @@ notify_key(struct wlsc_input_device *device,
WL_INPUT_DEVICE_KEY, time, key, state);
}
+static void
+input_device_attach(struct wl_client *client,
+ struct wl_input_device *device_base,
+ struct wl_buffer *buffer_base, int32_t x, int32_t y)
+{
+ struct wlsc_input_device *device =
+ (struct wlsc_input_device *) device_base;
+ struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base;
+
+ if (device->pointer_focus == NULL ||
+ device->pointer_focus->base.client != client)
+ return;
+
+ glBindTexture(GL_TEXTURE_2D, device->sprite->texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
+ device->sprite->visual = buffer->visual;
+ device->hotspot_x = x;
+ device->hotspot_y = y;
+}
+
+const static struct wl_input_device_interface input_device_interface = {
+ input_device_attach,
+};
+
static uint32_t
get_time(void)
{
@@ -866,7 +892,8 @@ wlsc_input_device_init(struct wlsc_input_device *device,
struct wlsc_compositor *ec)
{
device->base.interface = &wl_input_device_interface;
- device->base.implementation = NULL;
+ device->base.implementation =
+ (void (**)(void)) &input_device_interface;
wl_display_add_object(ec->wl_display, &device->base);
wl_display_add_global(ec->wl_display, &device->base, NULL);
@@ -874,6 +901,8 @@ wlsc_input_device_init(struct wlsc_input_device *device,
device->y = 100;
device->ec = ec;
device->sprite = pointer_create(ec, device->x, device->y, 64, 64);
+ device->hotspot_x = 16;
+ device->hotspot_y = 16;
device->listener.func = handle_surface_destroy;
wl_list_insert(ec->surface_destroy_listener_list.prev,
@@ -1092,6 +1121,8 @@ int main(int argc, char *argv[])
GError *error = NULL;
GOptionContext *context;
+ g_type_init(); /* GdkPixbuf needs this, it seems. */
+
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, option_entries, "Wayland");
if (!g_option_context_parse(context, &argc, &argv, &error)) {
diff --git a/compositor.h b/compositor.h
index 1237fbc..ac812dc 100644
--- a/compositor.h
+++ b/compositor.h
@@ -81,6 +81,7 @@ struct wlsc_input_device {
int32_t x, y;
struct wlsc_compositor *ec;
struct wlsc_surface *sprite;
+ int32_t hotspot_x, hotspot_y;
struct wl_list link;
struct wlsc_surface *pointer_focus;
@@ -118,6 +119,7 @@ struct wlsc_compositor {
EGLContext context;
GLuint fbo, vbo;
GLuint proj_uniform, tex_uniform;
+ EGLImageKHR default_pointer_image;
struct wl_display *wl_display;
/* We implement the shell interface. */
diff --git a/protocol.xml b/protocol.xml
index be2e79b..d8c644c 100644
--- a/protocol.xml
+++ b/protocol.xml
@@ -119,6 +119,12 @@
</interface>
<interface name="input_device" version="1">
+ <request name="attach">
+ <arg name="buffer" type="object" interface="buffer"/>
+ <arg name="hotspot_x" type="int"/>
+ <arg name="hotspot_y" type="int"/>
+ </request>
+
<event name="motion">
<arg name="time" type="uint"/>
<arg name="x" type="int"/>
diff --git a/spec/main.tex b/spec/main.tex
index 330d672..41e0367 100644
--- a/spec/main.tex
+++ b/spec/main.tex
@@ -159,7 +159,7 @@ delivered in both screen coordinates and surface local coordinates.
\hline
Interface \texttt{cache} \\ \hline
Requests \\ \hline
- no requests \\ \hline
+ \texttt{attach(buffer, x, y)} \\
Events \\ \hline
\texttt{motion(x, y, sx, sy)} \\
\texttt{button(button, state, x, y, sx, sy)} \\
@@ -179,14 +179,14 @@ Talk about:
A surface can change the pointer image when the surface is the pointer
focus of the input device. Wayland doesn't automatically change the
pointer image when a pointer enters a surface, but expects the
-application to set the cursor it wants in response the the motion
-event. The rationale is that a client has to manage changing pointer
-images for UI elements within the surface in response to motion events
-anyway, so we'll make that the only mechanism for setting changing the
-pointer image. If the server receives a request to set the pointer
-image after the surface loses pointer focus, the request is ignored.
-To the client this will look like it successfully set the pointer
-image.
+application to set the cursor it wants in response the the pointer
+focus and motion events. The rationale is that a client has to manage
+changing pointer images for UI elements within the surface in response
+to motion events anyway, so we'll make that the only mechanism for
+setting changing the pointer image. If the server receives a request
+to set the pointer image after the surface loses pointer focus, the
+request is ignored. To the client this will look like it successfully
+set the pointer image.
The compositor will revert the pointer image back to a default image
when no surface has the pointer focus for that device. Clients can