[PATCH 4/4] compositor: implement new pointer surface protocol

Ander Conselvan de Oliveira conselvan2 at gmail.com
Thu Feb 23 03:42:50 PST 2012


---
 clients/window.c |   25 +++++++-
 src/compositor.c |  180 ++++++++++++++++++++++++++++++++++++++++++++----------
 src/compositor.h |   10 +++
 3 files changed, 179 insertions(+), 36 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index ac26f52..e503182 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -159,6 +159,7 @@ struct input {
 	struct wl_input_device *input_device;
 	struct window *pointer_focus;
 	struct window *keyboard_focus;
+	struct wl_surface *pointer_surface;
 	uint32_t current_pointer_image;
 	uint32_t modifiers;
 	int32_t sx, sy;
@@ -1875,10 +1876,12 @@ input_set_pointer_image(struct input *input, uint32_t time, int pointer)
 	struct display *display = input->display;
 	struct wl_buffer *buffer;
 	cairo_surface_t *surface;
+	int old_pointer;
 
 	if (pointer == input->current_pointer_image)
 		return;
 
+	old_pointer = input->current_pointer_image;
 	input->current_pointer_image = pointer;
 	surface = display->pointer_surfaces[pointer];
 
@@ -1886,9 +1889,20 @@ 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,
-			       pointer_images[pointer].hotspot_x,
-			       pointer_images[pointer].hotspot_y);
+	if (old_pointer == POINTER_UNSET) {
+		wl_input_device_set_hotspot(input->input_device,
+					    pointer_images[pointer].hotspot_x,
+					    pointer_images[pointer].hotspot_y);
+		wl_surface_attach(input->pointer_surface, buffer, 0, 0);
+	}
+	else {
+		int dx = pointer_images[old_pointer].hotspot_x -
+			pointer_images[pointer].hotspot_x;
+		int dy = pointer_images[old_pointer].hotspot_y -
+			pointer_images[pointer].hotspot_y;
+
+		wl_surface_attach(input->pointer_surface, buffer, dx, dy);
+	}
 }
 
 struct wl_data_device *
@@ -2650,6 +2664,11 @@ 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->current_pointer_image = POINTER_UNSET;
+	input->pointer_surface = wl_compositor_create_surface(d->compositor);
+	wl_input_device_set_pointer_surface(input->input_device,
+					    input->pointer_surface);
 }
 
 static void
diff --git a/src/compositor.c b/src/compositor.c
index 97f7c3e..a84f52f 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -929,6 +929,7 @@ weston_output_repaint(struct weston_output *output, int msecs)
 		overlap, surface_overlap;
 	int32_t width, height;
 
+	weston_compositor_update_cursor_sprites(ec);
 	weston_compositor_update_drag_surfaces(ec);
 
 	width = output->current->width +
@@ -1107,15 +1108,23 @@ weston_surface_assign_output(struct weston_surface *es)
 	}
 }
 
+static struct weston_pointer_surface *
+device_client_pointer_surface(struct weston_input_device *device,
+			      struct wl_client *client);
+
 static void
 surface_attach(struct wl_client *client,
 	       struct wl_resource *resource,
 	       struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
 {
 	struct weston_surface *es = resource->data;
+	struct weston_input_device *device = (struct weston_input_device *)
+		es->compositor->input_device;
 	struct weston_shell *shell = es->compositor->shell;
 	struct wl_buffer *buffer;
 
+	struct weston_pointer_surface *ps;
+
 	if (!buffer_resource && !es->output)
 		return;
 
@@ -1152,6 +1161,17 @@ surface_attach(struct wl_client *client,
 				 buffer->width, buffer->height);
 	}
 
+	ps = device_client_pointer_surface(device, client);
+	if (ps && es == ps->surface) {
+		ps->hotspot_x -= sx;
+		ps->hotspot_y -= sy;
+
+		if (ps->surface == device->sprite) {
+			device->hotspot_x = ps->hotspot_x;
+			device->hotspot_y = ps->hotspot_y;
+		}
+	}
+
 	weston_buffer_attach(buffer, &es->surface);
 }
 
@@ -1666,47 +1686,74 @@ notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
 }
 
 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)
+pointer_surface_destroy(struct weston_pointer_surface *ps)
+{
+	if (!ps)
+		return;
+
+	if (ps->surface->output)
+		weston_surface_unmap(ps->surface);
+
+	ps->surface->pickable = 1;
+	wl_list_remove(&ps->link);
+	free(ps);
+}
+
+static void
+input_device_set_pointer_surface(struct wl_client *client,
+				 struct wl_resource *resource,
+				 struct wl_resource *surface_resource)
 {
 	struct weston_input_device *device = resource->data;
-	struct weston_compositor *compositor = device->compositor;
-	struct wl_buffer *buffer;
+	struct weston_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)
-		return;
+	/* find if client has a previous pointer surface for this device */
+	ps = device_client_pointer_surface(device, client);
+	pointer_surface_destroy(ps);
 
-	if (!buffer_resource && device->sprite->output) {
-		wl_list_remove(&device->sprite->link);
-		device->sprite->output = NULL;
-		return;
-	}
+	if (surface_resource) {
+		es = surface_resource->data;
+
+		ps = malloc(sizeof *ps);
+		ps->surface = es;
+		ps->hotspot_x = 0;
+		ps->hotspot_y = 0;
 
-	if (!device->sprite->output) {
-		wl_list_insert(&compositor->surface_list,
-			       &device->sprite->link);
-		weston_surface_assign_output(device->sprite);
+		es->pickable = 0;
+		wl_list_insert(&device->pointer_surfaces, &ps->link);
 	}
+}
 
-	buffer = buffer_resource->data;
-	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);
+static void
+input_device_set_hotspot(struct wl_client *client,
+			 struct wl_resource *resource,
+			 int32_t x, int32_t y)
+{
+	struct weston_input_device *device = resource->data;
+	struct weston_pointer_surface *ps;
+
+	ps = device_client_pointer_surface(device, client);
+	if (!ps)
+		return;
 
-	weston_buffer_attach(buffer, &device->sprite->surface);
+	ps->hotspot_x = x;
+	ps->hotspot_y = y;
+
+	if (device->sprite == ps->surface) {
+		device->hotspot_x = x;
+		device->hotspot_y = y;
+
+		weston_surface_set_position(device->sprite,
+					    device->input_device.x - x,
+					    device->input_device.y - y);
+		weston_compositor_schedule_repaint(device->compositor);
+	}
 }
 
 const static struct wl_input_device_interface input_device_interface = {
-	input_device_attach,
+	input_device_set_pointer_surface,
+	input_device_set_hotspot,
 };
 
 static void unbind_input_device(struct wl_resource *resource)
@@ -1737,7 +1784,8 @@ 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);
+	wl_list_init(&device->pointer_surfaces);
+	device->sprite = NULL;
 
 	device->compositor = ec;
 	device->hotspot_x = 16;
@@ -1751,15 +1799,81 @@ weston_input_device_init(struct weston_input_device *device,
 WL_EXPORT void
 weston_input_device_release(struct weston_input_device *device)
 {
+	struct weston_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)
+		pointer_surface_destroy(ps);
 
 	wl_input_device_release(&device->input_device);
 }
 
+static struct weston_pointer_surface *
+device_client_pointer_surface(struct weston_input_device *device,
+			      struct wl_client *client)
+{
+	struct weston_pointer_surface *ps;
+
+	wl_list_for_each(ps, &device->pointer_surfaces, link)
+		if (ps->surface->surface.resource.client == client)
+			return ps;
+
+	return NULL;
+}
+
+static void
+device_update_cursor_sprite(struct wl_input_device *device,
+			    struct weston_surface *surface)
+{
+	struct weston_input_device *wd = (struct weston_input_device *) device;
+	struct weston_pointer_surface *ps;
+	struct wl_client *client;
+
+	if (!surface)
+		return;
+
+	client = surface->surface.resource.client;
+
+	ps = device_client_pointer_surface(wd, client);
+	if (!ps)
+		return;
+
+	if (wd->sprite) {
+		if (client == wd->sprite->surface.resource.client)
+			return;
+
+		if (wd->sprite->output) {
+			weston_surface_damage_below(wd->sprite);
+			wd->sprite->output = NULL;
+			wl_list_remove(&wd->sprite->link);
+		}
+	}
+
+	wd->sprite = ps->surface;
+	wd->hotspot_x = ps->hotspot_x;
+	wd->hotspot_y = ps->hotspot_y;
+
+	if (!ps->surface->output) {
+		wl_list_insert(weston_compositor_top(wd->compositor),
+			       &ps->surface->link);
+		weston_surface_set_position(ps->surface,
+					    device->x - wd->hotspot_x,
+					    device->y - wd->hotspot_y);
+		weston_surface_assign_output(ps->surface);
+	}
+}
+
+WL_EXPORT void
+weston_compositor_update_cursor_sprites(struct weston_compositor *ec)
+{
+	struct weston_surface *es = (struct weston_surface *)
+		ec->input_device->pointer_focus;
+
+	device_update_cursor_sprite(ec->input_device, es);
+}
+
 static  void
 weston_input_update_drag_surface(struct wl_input_device *input_device,
 				 int dx, int dy)
diff --git a/src/compositor.h b/src/compositor.h
index 4c82e79..130f4f6 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -79,6 +79,12 @@ struct weston_output {
 	void (*destroy)(struct weston_output *output);
 };
 
+struct weston_pointer_surface {
+	struct weston_surface *surface;
+	int hotspot_x, hotspot_y;
+	struct wl_list link;
+};
+
 struct weston_input_device {
 	struct wl_input_device input_device;
 	struct weston_compositor *compositor;
@@ -89,6 +95,8 @@ struct weston_input_device {
 	uint32_t modifier_state;
 	int hw_cursor;
 
+	struct wl_list pointer_surfaces;
+
 	uint32_t num_tp;
 	struct wl_surface *touch_focus;
 	struct wl_listener touch_focus_listener;
@@ -360,6 +368,8 @@ weston_compositor_wake(struct weston_compositor *compositor);
 void
 weston_compositor_activity(struct weston_compositor *compositor);
 void
+weston_compositor_update_cursor_sprites(struct weston_compositor *compositor);
+void
 weston_compositor_update_drag_surfaces(struct weston_compositor *compositor);
 
 
-- 
1.7.5.4



More information about the wayland-devel mailing list