[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