[PATCH 4/4] compositor: implement new pointer surfaces protocol
Ander Conselvan de Oliveira
ander.conselvan.de.oliveira at intel.com
Tue Apr 3 05:44:18 PDT 2012
---
clients/window.c | 10 ++-
src/compositor-wayland.c | 7 +-
src/compositor.c | 267 ++++++++++++++++++++++++++++++++++++++--------
src/compositor.h | 7 +-
4 files changed, 245 insertions(+), 46 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index 74ddedd..7a759df 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -166,6 +166,8 @@ struct input {
struct wl_input_device *input_device;
struct window *pointer_focus;
struct window *keyboard_focus;
+ struct wl_surface *ps_surface;
+ struct wl_pointer_surface *ps;
int current_pointer_image;
uint32_t modifiers;
int32_t sx, sy;
@@ -1886,9 +1888,11 @@ input_set_pointer_image(struct input *input, uint32_t time, int pointer)
return;
buffer = display_get_buffer_for_surface(display, surface);
- wl_input_device_attach(input->input_device, time, buffer,
+ wl_pointer_surface_set_hotspot(input->ps,
pointer_images[pointer].hotspot_x,
pointer_images[pointer].hotspot_y);
+ wl_surface_attach(input->ps_surface, buffer, 0, 0);
+ wl_surface_damage(input->ps_surface, 0, 0, 32, 32);
}
struct wl_data_device *
@@ -2662,6 +2666,10 @@ display_add_input(struct display *d, uint32_t id)
input->input_device);
wl_data_device_add_listener(input->data_device,
&data_device_listener, input);
+
+ input->ps_surface = wl_compositor_create_surface(d->compositor);
+ input->ps = wl_input_device_set_pointer_surface(input->input_device,
+ input->ps_surface);
}
static void
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 593e272..828d4e1 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -87,6 +87,8 @@ struct wayland_input {
struct wayland_compositor *compositor;
struct wl_input_device *input_device;
struct wl_list link;
+ struct wl_surface *ps_surface;
+ struct wl_pointer_surface *ps;
};
@@ -557,7 +559,6 @@ input_handle_pointer_enter(void *data,
output = wl_surface_get_user_data(surface);
notify_pointer_focus(c->base.input_device,
time, &output->base, sx, sy);
- wl_input_device_attach(input->input_device, time, NULL, 0, 0);
}
static void
@@ -628,6 +629,10 @@ display_add_input(struct wayland_compositor *c, uint32_t id)
wl_input_device_add_listener(input->input_device,
&input_device_listener, input);
wl_input_device_set_user_data(input->input_device, input);
+
+ input->ps_surface = wl_compositor_create_surface(c->parent.compositor);
+ input->ps = wl_input_device_set_pointer_surface(input->input_device,
+ input->ps_surface);
}
static void
diff --git a/src/compositor.c b/src/compositor.c
index 0ed57de..a555e77 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1499,8 +1499,12 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
interface->motion(device->pointer_grab, time,
device->pointer_grab->x, device->pointer_grab->y);
- if (wd->sprite)
- weston_compositor_schedule_repaint(ec);
+ /* The pointer may have moved to a surface belonging to a different
+ * client than the previous one. In this case, the pointer surface
+ * needs to be updated but that can only be done during repaint
+ * because it needs an up-to-date surface list. Schedule a repaint
+ * here to make sure that happens. */
+ weston_compositor_schedule_repaint(ec);
}
WL_EXPORT void
@@ -1847,51 +1851,167 @@ notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
}
}
+struct wl_pointer_surface {
+ struct wl_resource resource;
+ struct weston_surface *surface;
+ int hotspot_x, hotspot_y;
+ struct wl_list link;
+ struct wl_listener surface_destroy_listener;
+};
+
+static void
+pointer_surface_set_hotspot(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x, int32_t y)
+{
+ struct wl_pointer_surface *ps = resource->data;
+ struct weston_surface *es = ps->surface;
+
+ ps->hotspot_x = x;
+ ps->hotspot_y = y;
+
+ if (weston_surface_is_mapped(es))
+ weston_compositor_schedule_repaint(es->compositor);
+}
+
+static struct wl_pointer_surface_interface pointer_surface_interface = {
+ pointer_surface_set_hotspot,
+};
+
+static void
+pointer_surface_destroy(struct wl_resource *resource)
+{
+ struct wl_pointer_surface *ps;
+
+ ps = container_of(resource, struct wl_pointer_surface, resource);
+
+ if (weston_surface_is_mapped(ps->surface))
+ weston_surface_unmap(ps->surface);
+
+ ps->surface->configure = NULL;
+ undef_region(&ps->surface->input);
+ wl_list_remove(&ps->link);
+ wl_list_remove(&ps->surface_destroy_listener.link);
+ free(ps);
+}
+
static void
-input_device_attach(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t time,
- struct wl_resource *buffer_resource, int32_t x, int32_t y)
+destroy_pointer_surface_surface(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct wl_pointer_surface *ps;
+
+ ps = container_of(listener, struct wl_pointer_surface,
+ surface_destroy_listener);
+
+ wl_resource_destroy(&ps->resource, 0);
+}
+
+static struct wl_pointer_surface *
+surface_get_pointer_surface(struct weston_surface *es)
+{
+ struct wl_list *list = &es->surface.resource.destroy_listener_list;
+ struct wl_listener *listener;
+
+ wl_list_for_each(listener, list, link) {
+ if (listener->func == destroy_pointer_surface_surface)
+ return container_of(listener,
+ struct wl_pointer_surface,
+ surface_destroy_listener);
+ }
+
+ return NULL;
+}
+
+static void
+pointer_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+ struct wl_pointer_surface *ps = surface_get_pointer_surface(es);
+
+ weston_surface_configure(es, es->geometry.x + sx, es->geometry.y + sy,
+ es->buffer->width, es->buffer->height);
+
+ empty_region(&es->input);
+
+ ps->hotspot_x += sx;
+ ps->hotspot_y += sy;
+}
+
+static struct wl_pointer_surface *
+device_get_client_pointer_surface(struct weston_input_device *device,
+ struct wl_client *client)
+{
+ struct wl_pointer_surface *ps;
+
+ wl_list_for_each(ps, &device->pointer_surfaces, link)
+ if (ps->resource.client == client)
+ return ps;
+
+ return NULL;
+}
+
+static void
+input_device_set_pointer_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *surface_resource,
+ uint32_t id)
{
struct weston_input_device *device = resource->data;
- struct weston_compositor *compositor = device->compositor;
- struct wl_buffer *buffer = NULL;
+ struct wl_pointer_surface *ps;
+ struct weston_surface *es;
- if (time < device->input_device.pointer_focus_time)
- return;
- if (device->input_device.pointer_focus == NULL)
- return;
- if (device->input_device.pointer_focus->resource.client != client)
+ if (!surface_resource) {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface cannot be nil");
return;
+ }
- if (buffer_resource)
- buffer = buffer_resource->data;
-
- weston_surface_attach(&device->sprite->surface, buffer);
+ es = surface_resource->data;
- if (!buffer)
+ if (es->configure) {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
return;
+ }
+
+ ps = device_get_client_pointer_surface(device, client);
+ if (ps)
+ wl_resource_destroy(&ps->resource, 0);
- if (!weston_surface_is_mapped(device->sprite)) {
- wl_list_insert(&compositor->cursor_layer.surface_list,
- &device->sprite->layer_link);
- weston_surface_assign_output(device->sprite);
+ ps = malloc(sizeof *ps);
+ if (!ps) {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_NO_MEMORY,
+ "no memory");
+ return;
}
+ es->configure = pointer_surface_configure;
+ empty_region(&es->input);
- device->hotspot_x = x;
- device->hotspot_y = y;
- weston_surface_configure(device->sprite,
- device->input_device.x - device->hotspot_x,
- device->input_device.y - device->hotspot_y,
- buffer->width, buffer->height);
+ ps->hotspot_x = 0;
+ ps->hotspot_y = 0;
- surface_damage(NULL, &device->sprite->surface.resource,
- 0, 0, buffer->width, buffer->height);
+ ps->surface = es;
+ ps->surface_destroy_listener.func = destroy_pointer_surface_surface;
+ wl_list_insert(es->surface.resource.destroy_listener_list.prev,
+ &ps->surface_destroy_listener.link);
+
+ ps->resource.data = ps;
+ ps->resource.object.id = id;
+ ps->resource.object.interface = &wl_pointer_surface_interface;
+ ps->resource.object.implementation = (void (**)(void))
+ &pointer_surface_interface;
+ ps->resource.destroy = pointer_surface_destroy;
+
+ wl_client_add_resource(client, &ps->resource);
+ wl_list_insert(&device->pointer_surfaces, &ps->link);
}
static const struct wl_input_device_interface input_device_interface = {
- input_device_attach,
+ input_device_set_pointer_surface,
};
static void
@@ -1949,12 +2069,11 @@ weston_input_device_init(struct weston_input_device *device,
wl_display_add_global(ec->wl_display, &wl_input_device_interface,
device, bind_input_device);
- device->sprite = weston_surface_create(ec);
- device->sprite->surface.resource.data = device->sprite;
+ device->sprite = NULL;
+ device->ps = NULL;
+ wl_list_init(&device->pointer_surfaces);
device->compositor = ec;
- device->hotspot_x = 16;
- device->hotspot_y = 16;
device->modifier_state = 0;
device->num_tp = 0;
@@ -1970,25 +2089,81 @@ weston_input_device_init(struct weston_input_device *device,
WL_EXPORT void
weston_input_device_release(struct weston_input_device *device)
{
+ struct wl_pointer_surface *ps, *tmp;
+
wl_list_remove(&device->link);
/* The global object is destroyed at wl_display_destroy() time. */
- if (device->sprite)
- destroy_surface(&device->sprite->surface.resource);
+ wl_list_for_each_safe(ps, tmp, &device->pointer_surfaces, link)
+ wl_resource_destroy(&ps->resource, 0);
wl_input_device_release(&device->input_device);
}
static void
+device_destroy_ps(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct weston_input_device *device;
+
+ device = container_of(listener, struct weston_input_device,
+ ps_destroy_listener);
+
+ device->sprite = NULL;
+ device->ps = NULL;
+}
+
+static void
+device_set_pointer_surface(struct weston_input_device *device,
+ struct wl_client *client)
+{
+ struct wl_pointer_surface *ps;
+
+ ps = device_get_client_pointer_surface(device, client);
+
+ if (ps && ps != device->ps) {
+ if (device->ps) {
+ weston_surface_unmap(device->ps->surface);
+ wl_list_remove(&device->ps_destroy_listener.link);
+ }
+
+ device->ps = ps;
+ device->sprite = ps->surface;
+
+ device->ps_destroy_listener.func = device_destroy_ps;
+ wl_list_insert(ps->resource.destroy_listener_list.prev,
+ &device->ps_destroy_listener.link);
+ }
+}
+
+static void
device_update_cursor_sprite(struct weston_input_device *device)
{
+ struct weston_compositor *ec = device->compositor;
+ struct weston_surface *focus = (struct weston_surface *)
+ device->input_device.pointer_focus;
+ struct weston_surface *es;
int x, y;
- x = device->input_device.x - device->hotspot_x;
- y = device->input_device.y - device->hotspot_y;
+ if (focus) {
+ struct wl_client *client = focus->surface.resource.client;
+ device_set_pointer_surface(device, client);
+ }
+
+ if (device->ps) {
+ es = device->ps->surface;
+
+ x = device->input_device.x - device->ps->hotspot_x;
+ y = device->input_device.y - device->ps->hotspot_y;
+
+ weston_surface_set_position(es, x, y);
- if (device->sprite)
- weston_surface_set_position(device->sprite, x, y);
+ if (es->buffer && !weston_surface_is_mapped(es)) {
+ wl_list_insert(&ec->cursor_layer.surface_list,
+ &es->layer_link);
+ weston_surface_assign_output(es);
+ }
+ }
}
WL_EXPORT void
@@ -2054,12 +2229,18 @@ device_release_drag_surface(struct weston_input_device *device)
static void
device_map_drag_surface(struct weston_input_device *device)
{
+ struct wl_list *link;
+
if (weston_surface_is_mapped(device->drag_surface) ||
!device->drag_surface->buffer)
return;
- wl_list_insert(&device->sprite->layer_link,
- &device->drag_surface->layer_link);
+ if (device->ps)
+ link = &device->ps->surface->layer_link;
+ else
+ link = &device->compositor->cursor_layer.surface_list;
+
+ wl_list_insert(link, &device->drag_surface->layer_link);
weston_surface_assign_output(device->drag_surface);
empty_region(&device->drag_surface->input);
}
diff --git a/src/compositor.h b/src/compositor.h
index adfae41..ba22b7c 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -106,11 +106,16 @@ struct weston_output {
struct weston_input_device {
struct wl_input_device input_device;
struct weston_compositor *compositor;
+
struct weston_surface *sprite;
- int32_t hotspot_x, hotspot_y;
+ struct wl_pointer_surface *ps;
+ struct wl_listener ps_destroy_listener;
+ struct wl_list pointer_surfaces;
+
struct weston_surface *drag_surface;
struct wl_listener drag_surface_destroy_listener;
int32_t drag_surf_x, drag_surf_y;
+
struct wl_list link;
uint32_t modifier_state;
int hw_cursor;
--
1.7.4.1
More information about the wayland-devel
mailing list