[PATCH weston 1/2 v2] input: Emit events on all resources for a client

Neil Roberts neil at linux.intel.com
Thu Sep 19 09:32:00 PDT 2013


Here is a second version of Robert's patch with the following changes:

I think the problem where clients would not immediately become active
when starting was caused by it calling weston_*_set_focus instead of
sending the enter event for the first keyboard or pointer resource.
The set_focus functions don't do anything if the surface already has
focus so the client was never getting the enter event. I've changed it
so that it uses the same code path regardless of whether it is the
first or a subsequent resource and now it just always explicitly sends
the enter event.

I've removed the focus listeners. We don't need them anymore because
the resource will automatically remove itself from the list when it is
destroyed and that will have the same effect as the old destroy
callback which would just unset the focus resource pointer. This
should remove the need for Robert's patch which changes the destroy
listeners to listen to the client resource.

When setting the pointer focus it will now send the keyboard modifiers
regardless of whether the focused client has a pointer resource. This
is not how it works in master and Rob's patch also changed it to do
this but I'm not sure if that was intentional. This is important
because otherwise if you get the pointer later than getting the
keyboard then the modifiers might not be up-to-date.

I've changed the move_resource function to just use wl_list_insert
which should have the same effect but will be faster because it
doesn't need to iterate the list.

In a couple of places the patch made it so that it would increment the
serial even if there are no resources for the pointer or keyboard.
I've changed these so that it checks if the resource list is empty to
make it retain the old behaviour. In particular this was happening in
binding_key and default_grab_key.

When getting the keyboard, it now sends the modifiers to the client
when it either has the pointer focus or the keyboard focus, instead of
only if it has the keyboard focus.

I've split up long lines and moved some bits of code into common
functions, for example to emit the modifiers event.

I've brought back the find_resource_for_surface functions so that the
set focus functions can avoid incrementing the serial if there is no
pointer or keyboard resource for the client of that surface.

I removed the duplicated checks for seat->touch_focus != surface in
wl_touch_set_focus because this is ensured right at the start of the
function so it is redundant to check it again.

I fixed the spelling of ‘focussed‘.

Regards,
- Neil

-- >8 --

From: Rob Bradford <rob at linux.intel.com>

The Wayland protocol permits a client to request the pointer, keyboard
and touch multiple times from the seat global. This is very useful in a
component like Clutter-GTK where we are combining two libraries that use
Wayland together.

This change migrates the weston input handling code to emit the
events for all the resources for the client by using the newly added
wl_resource_for_each macro to iterate over the resources that are
associated with the focused surface's client.

We maintain a list of focused resources on the pointer and keyboard
which is updated when the focus changes. However since we can have
resources created after the focus has already been set we must add the
resources to the right list and also update any state.

Additionally when setting the pointer focus it will now send the
keyboard modifiers regardless of whether the focused client has a
pointer resource. This is important because otherwise if the client
gets the pointer later than you getting the keyboard then the
modifiers might not be up-to-date.

Co-author: Neil Roberts <neil at linux.intel.com>
---
 src/bindings.c    |  21 +--
 src/compositor.h  |   9 +-
 src/data-device.c |  16 ++-
 src/input.c       | 399 +++++++++++++++++++++++++++++++++++-------------------
 src/shell.c       |  34 +++--
 5 files changed, 309 insertions(+), 170 deletions(-)

diff --git a/src/bindings.c b/src/bindings.c
index a871c26..f6ec9ea 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -160,7 +160,6 @@ binding_key(struct weston_keyboard_grab *grab,
 	struct weston_keyboard *keyboard = grab->keyboard;
 	struct wl_display *display = keyboard->seat->compositor->wl_display;
 
-	resource = grab->keyboard->focus_resource;
 	if (key == b->key) {
 		if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
 			weston_keyboard_end_grab(grab->keyboard);
@@ -168,9 +167,15 @@ binding_key(struct weston_keyboard_grab *grab,
 				keyboard->grab = &keyboard->input_method_grab;
 			free(b);
 		}
-	} else if (resource) {
+	} else if (!wl_list_empty(&keyboard->focus_resource_list)) {
 		serial = wl_display_next_serial(display);
-		wl_keyboard_send_key(resource, serial, time, key, state);
+		wl_resource_for_each(resource, &keyboard->focus_resource_list) {
+			wl_keyboard_send_key(resource,
+					     serial,
+					     time,
+					     key,
+					     state);
+		}
 	}
 }
 
@@ -181,12 +186,10 @@ binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
 {
 	struct wl_resource *resource;
 
-	resource = grab->keyboard->focus_resource;
-	if (!resource)
-		return;
-
-	wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-				   mods_latched, mods_locked, group);
+	wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) {
+		wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+					   mods_latched, mods_locked, group);
+	}
 }
 
 static const struct weston_keyboard_grab_interface binding_grab = {
diff --git a/src/compositor.h b/src/compositor.h
index a523c83..77de442 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -302,9 +302,8 @@ struct weston_pointer {
 	struct weston_seat *seat;
 
 	struct wl_list resource_list;
+	struct wl_list focus_resource_list;
 	struct weston_surface *focus;
-	struct wl_resource *focus_resource;
-	struct wl_listener focus_listener;
 	uint32_t focus_serial;
 	struct wl_signal focus_signal;
 
@@ -328,9 +327,8 @@ struct weston_touch {
 	struct weston_seat *seat;
 
 	struct wl_list resource_list;
+	struct wl_list focus_resource_list;
 	struct weston_surface *focus;
-	struct wl_resource *focus_resource;
-	struct wl_listener focus_listener;
 	uint32_t focus_serial;
 	struct wl_signal focus_signal;
 
@@ -423,9 +421,8 @@ struct weston_keyboard {
 	struct weston_seat *seat;
 
 	struct wl_list resource_list;
+	struct wl_list focus_resource_list;
 	struct weston_surface *focus;
-	struct wl_resource *focus_resource;
-	struct wl_listener focus_listener;
 	uint32_t focus_serial;
 	struct wl_signal focus_signal;
 
diff --git a/src/data-device.c b/src/data-device.c
index a29c4a8..3edeb3f 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -440,7 +440,9 @@ destroy_selection_data_source(struct wl_listener *listener, void *data)
 	seat->selection_data_source = NULL;
 
 	if (seat->keyboard && seat->keyboard->focus) {
-		client = wl_resource_get_client(seat->keyboard->focus->resource);
+		struct wl_resource *focus_resource =
+			seat->keyboard->focus->resource;
+		client = wl_resource_get_client(focus_resource);
 		data_device = wl_resource_find_for_client(&seat->drag_resource_list,
 							  client);
 		if (data_device)
@@ -471,7 +473,9 @@ weston_seat_set_selection(struct weston_seat *seat,
 	seat->selection_serial = serial;
 
 	if (seat->keyboard && seat->keyboard->focus) {
-		client = wl_resource_get_client(seat->keyboard->focus->resource);
+		struct wl_resource *focus_resource =
+			seat->keyboard->focus->resource;
+		client = wl_resource_get_client(focus_resource);
 		data_device = wl_resource_find_for_client(&seat->drag_resource_list,
 							  client);
 		if (data_device && source) {
@@ -635,8 +639,12 @@ wl_data_device_set_keyboard_focus(struct weston_seat *seat)
 		return;
 
 	if (seat->keyboard && seat->keyboard->focus) {
-		client = wl_resource_get_client(seat->keyboard->focus->resource);
-		data_device = wl_resource_find_for_client(&seat->drag_resource_list,
+		struct wl_resource *focus_resource =
+			seat->keyboard->focus->resource;
+		struct wl_list *drag_resource_list =
+			&seat->drag_resource_list;
+		client = wl_resource_get_client(focus_resource);
+		data_device = wl_resource_find_for_client(drag_resource_list,
 							  client);
 	}
 
diff --git a/src/input.c b/src/input.c
index 9c30460..2c057e1 100644
--- a/src/input.c
+++ b/src/input.c
@@ -71,30 +71,25 @@ weston_compositor_idle_release(struct weston_compositor *compositor)
 }
 
 static void
-lose_pointer_focus(struct wl_listener *listener, void *data)
+move_resources(struct wl_list *destination, struct wl_list *source)
 {
-	struct weston_pointer *pointer =
-		container_of(listener, struct weston_pointer, focus_listener);
-
-	pointer->focus_resource = NULL;
+	wl_list_insert_list(destination, source);
+	wl_list_init(source);
 }
 
 static void
-lose_keyboard_focus(struct wl_listener *listener, void *data)
-{
-	struct weston_keyboard *keyboard =
-		container_of(listener, struct weston_keyboard, focus_listener);
-
-	keyboard->focus_resource = NULL;
-}
-
-static void
-lose_touch_focus(struct wl_listener *listener, void *data)
-{
-	struct weston_touch *touch =
-		container_of(listener, struct weston_touch, focus_listener);
-
-	touch->focus_resource = NULL;
+move_resources_for_client(struct wl_list *destination,
+			  struct wl_list *source,
+			  struct wl_client *client)
+{
+	struct wl_resource *resource, *tmp;
+	wl_resource_for_each_safe(resource, tmp, source) {
+		if (wl_resource_get_client(resource) == client) {
+			wl_list_remove(wl_resource_get_link(resource));
+			wl_list_insert(destination,
+				       wl_resource_get_link(resource));
+		}
+	}
 }
 
 static void
@@ -120,12 +115,15 @@ default_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 {
 	struct weston_pointer *pointer = grab->pointer;
 	wl_fixed_t sx, sy;
+	struct wl_list *resource_list;
+	struct wl_resource *resource;
 
-	if (pointer->focus_resource) {
+	resource_list = &pointer->focus_resource_list;
+	wl_resource_for_each(resource, resource_list) {
 		weston_surface_from_global_fixed(pointer->focus,
 						 pointer->x, pointer->y,
 						 &sx, &sy);
-		wl_pointer_send_motion(pointer->focus_resource, time, sx, sy);
+		wl_pointer_send_motion(resource, time, sx, sy);
 	}
 }
 
@@ -141,11 +139,17 @@ default_grab_button(struct weston_pointer_grab *grab,
 	enum wl_pointer_button_state state = state_w;
 	struct wl_display *display = compositor->wl_display;
 	wl_fixed_t sx, sy;
+	struct wl_list *resource_list;
 
-	resource = pointer->focus_resource;
-	if (resource) {
+	resource_list = &pointer->focus_resource_list;
+	if (!wl_list_empty(resource_list)) {
 		serial = wl_display_next_serial(display);
-		wl_pointer_send_button(resource, serial, time, button, state_w);
+		wl_resource_for_each(resource, resource_list)
+			wl_pointer_send_button(resource,
+					       serial,
+					       time,
+					       button,
+					       state_w);
 	}
 
 	if (pointer->button_count == 0 &&
@@ -173,12 +177,17 @@ default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
 	struct weston_touch *touch = grab->touch;
 	struct wl_display *display = touch->seat->compositor->wl_display;
 	uint32_t serial;
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
+
+	resource_list = &touch->focus_resource_list;
 
-	if (touch->focus_resource && touch->focus) {
+	if (!wl_list_empty(resource_list) && touch->focus) {
 		serial = wl_display_next_serial(display);
-		wl_touch_send_down(touch->focus_resource, serial, time,
-				   touch->focus->resource,
-				   touch_id, sx, sy);
+		wl_resource_for_each(resource, resource_list)
+				wl_touch_send_down(resource, serial, time,
+						   touch->focus->resource,
+						   touch_id, sx, sy);
 	}
 }
 
@@ -189,10 +198,15 @@ default_grab_touch_up(struct weston_touch_grab *grab,
 	struct weston_touch *touch = grab->touch;
 	struct wl_display *display = touch->seat->compositor->wl_display;
 	uint32_t serial;
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
+
+	resource_list = &touch->focus_resource_list;
 
-	if (touch->focus_resource) {
+	if (!wl_list_empty(resource_list)) {
 		serial = wl_display_next_serial(display);
-		wl_touch_send_up(touch->focus_resource, serial, time, touch_id);
+		wl_resource_for_each(resource, resource_list)
+			wl_touch_send_up(resource, serial, time, touch_id);
 	}
 }
 
@@ -201,9 +215,13 @@ default_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
 			  int touch_id, wl_fixed_t sx, wl_fixed_t sy)
 {
 	struct weston_touch *touch = grab->touch;
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
 
-	if (touch->focus_resource) {
-		wl_touch_send_motion(touch->focus_resource, time,
+	resource_list = &touch->focus_resource_list;
+
+	wl_resource_for_each(resource, resource_list) {
+		wl_touch_send_motion(resource, time,
 				     touch_id, sx, sy);
 	}
 }
@@ -222,11 +240,46 @@ default_grab_key(struct weston_keyboard_grab *grab,
 	struct wl_resource *resource;
 	struct wl_display *display = keyboard->seat->compositor->wl_display;
 	uint32_t serial;
+	struct wl_list *resource_list;
 
-	resource = keyboard->focus_resource;
-	if (resource) {
+	resource_list = &keyboard->focus_resource_list;
+	if (!wl_list_empty(resource_list)) {
 		serial = wl_display_next_serial(display);
-		wl_keyboard_send_key(resource, serial, time, key, state);
+		wl_resource_for_each(resource, resource_list)
+			wl_keyboard_send_key(resource,
+					     serial,
+					     time,
+					     key,
+					     state);
+	}
+}
+
+static void
+send_modifiers_to_resource(struct weston_keyboard *keyboard,
+			   struct wl_resource *resource,
+			   uint32_t serial)
+{
+	wl_keyboard_send_modifiers(resource,
+				   serial,
+				   keyboard->modifiers.mods_depressed,
+				   keyboard->modifiers.mods_latched,
+				   keyboard->modifiers.mods_locked,
+				   keyboard->modifiers.group);
+}
+
+static void
+send_modifiers_to_client_in_list(struct wl_client *client,
+				 struct wl_list *list,
+				 uint32_t serial,
+				 struct weston_keyboard *keyboard)
+{
+	struct wl_resource *resource;
+
+	wl_resource_for_each(resource, list) {
+		if (wl_resource_get_client(resource) == client)
+			send_modifiers_to_resource(keyboard,
+						   resource,
+						   serial);
 	}
 }
 
@@ -248,27 +301,23 @@ default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
 		       uint32_t mods_locked, uint32_t group)
 {
 	struct weston_keyboard *keyboard = grab->keyboard;
-	struct weston_pointer *pointer = keyboard->seat->pointer;
-	struct wl_resource *resource, *pr;
-
-	resource = keyboard->focus_resource;
-	if (!resource)
-		return;
+	struct weston_pointer *pointer = grab->keyboard->seat->pointer;
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
 
-	wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-				   mods_latched, mods_locked, group);
+	resource_list = &keyboard->focus_resource_list;
 
+	wl_resource_for_each(resource, resource_list) {
+		wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+					   mods_latched, mods_locked, group);
+	}
 	if (pointer && pointer->focus && pointer->focus != keyboard->focus) {
-		pr = find_resource_for_surface(&keyboard->resource_list,
-					       pointer->focus);
-		if (pr) {
-			wl_keyboard_send_modifiers(pr,
-						   serial,
-						   keyboard->modifiers.mods_depressed,
-						   keyboard->modifiers.mods_latched,
-						   keyboard->modifiers.mods_locked,
-						   keyboard->modifiers.group);
-		}
+		struct wl_client *pointer_client =
+			wl_resource_get_client(pointer->focus->resource);
+		send_modifiers_to_client_in_list(pointer_client,
+						 &keyboard->resource_list,
+						 serial,
+						 keyboard);
 	}
 }
 
@@ -310,7 +359,7 @@ weston_pointer_create(void)
 		return NULL;
 
 	wl_list_init(&pointer->resource_list);
-	pointer->focus_listener.notify = lose_pointer_focus;
+	wl_list_init(&pointer->focus_resource_list);
 	pointer->default_grab.interface = &default_pointer_grab_interface;
 	pointer->default_grab.pointer = pointer;
 	pointer->grab = &pointer->default_grab;
@@ -332,8 +381,7 @@ weston_pointer_destroy(struct weston_pointer *pointer)
 		pointer_unmap_sprite(pointer);
 
 	/* XXX: What about pointer->resource_list? */
-	if (pointer->focus_resource)
-		wl_list_remove(&pointer->focus_listener.link);
+
 	free(pointer);
 }
 
@@ -347,8 +395,8 @@ weston_keyboard_create(void)
 	    return NULL;
 
 	wl_list_init(&keyboard->resource_list);
+	wl_list_init(&keyboard->focus_resource_list);
 	wl_array_init(&keyboard->keys);
-	keyboard->focus_listener.notify = lose_keyboard_focus;
 	keyboard->default_grab.interface = &default_keyboard_grab_interface;
 	keyboard->default_grab.keyboard = keyboard;
 	keyboard->grab = &keyboard->default_grab;
@@ -361,8 +409,7 @@ WL_EXPORT void
 weston_keyboard_destroy(struct weston_keyboard *keyboard)
 {
 	/* XXX: What about keyboard->resource_list? */
-	if (keyboard->focus_resource)
-		wl_list_remove(&keyboard->focus_listener.link);
+
 	wl_array_release(&keyboard->keys);
 	free(keyboard);
 }
@@ -377,7 +424,7 @@ weston_touch_create(void)
 		return NULL;
 
 	wl_list_init(&touch->resource_list);
-	touch->focus_listener.notify = lose_touch_focus;
+	wl_list_init(&touch->focus_resource_list);
 	touch->default_grab.interface = &default_touch_grab_interface;
 	touch->default_grab.touch = touch;
 	touch->grab = &touch->default_grab;
@@ -390,8 +437,7 @@ WL_EXPORT void
 weston_touch_destroy(struct weston_touch *touch)
 {
 	/* XXX: What about touch->resource_list? */
-	if (touch->focus_resource)
-		wl_list_remove(&touch->focus_listener.link);
+
 	free(touch);
 }
 
@@ -419,48 +465,73 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 			 wl_fixed_t sx, wl_fixed_t sy)
 {
 	struct weston_keyboard *kbd = pointer->seat->keyboard;
-	struct wl_resource *resource, *kr;
+	struct wl_resource *resource;
 	struct wl_display *display = pointer->seat->compositor->wl_display;
 	uint32_t serial;
+	struct wl_list *focus_resource_list;
 
-	resource = pointer->focus_resource;
-	if (resource && pointer->focus != surface) {
+	focus_resource_list = &pointer->focus_resource_list;
+
+	if (!wl_list_empty(focus_resource_list) && pointer->focus != surface) {
 		serial = wl_display_next_serial(display);
-		wl_pointer_send_leave(resource, serial,
-				      pointer->focus->resource);
-		wl_list_remove(&pointer->focus_listener.link);
+		wl_resource_for_each(resource, focus_resource_list) {
+			wl_pointer_send_leave(resource, serial,
+					      pointer->focus->resource);
+		}
+
+		move_resources(&pointer->resource_list, focus_resource_list);
 	}
 
-	resource = find_resource_for_surface(&pointer->resource_list,
-					     surface);
-	if (resource &&
-	    (pointer->focus != surface ||
-	     pointer->focus_resource != resource)) {
+	if (find_resource_for_surface(&pointer->resource_list, surface) &&
+	    pointer->focus != surface) {
+		struct wl_client *surface_client =
+			wl_resource_get_client(surface->resource);
+
 		serial = wl_display_next_serial(display);
-		if (kbd) {
-			kr = find_resource_for_surface(&kbd->resource_list,
-						       surface);
-			if (kr) {
-				wl_keyboard_send_modifiers(kr,
-							   serial,
-							   kbd->modifiers.mods_depressed,
-							   kbd->modifiers.mods_latched,
-							   kbd->modifiers.mods_locked,
-							   kbd->modifiers.group);
-			}
+
+		move_resources_for_client(focus_resource_list,
+					  &pointer->resource_list,
+					  surface_client);
+
+		wl_resource_for_each(resource, focus_resource_list) {
+			wl_pointer_send_enter(resource,
+					      serial,
+					      surface->resource,
+					      sx, sy);
 		}
-		wl_pointer_send_enter(resource, serial, surface->resource,
-				      sx, sy);
-		wl_resource_add_destroy_listener(resource,
-						 &pointer->focus_listener);
+
 		pointer->focus_serial = serial;
 	}
 
-	pointer->focus_resource = resource;
+	if (kbd && surface && kbd->focus != pointer->focus) {
+		struct wl_client *surface_client =
+			wl_resource_get_client(surface->resource);
+		send_modifiers_to_client_in_list(surface_client,
+						 &kbd->resource_list,
+						 serial,
+						 kbd);
+	}
+
 	pointer->focus = surface;
 	wl_signal_emit(&pointer->focus_signal, pointer);
 }
 
+static void
+send_enter_to_resource_list(struct wl_list *list,
+			    struct weston_keyboard *keyboard,
+			    struct weston_surface *surface,
+			    uint32_t serial)
+{
+	struct wl_resource *resource;
+
+	wl_resource_for_each(resource, list) {
+		send_modifiers_to_resource(keyboard, resource, serial);
+		wl_keyboard_send_enter(resource, serial,
+				       surface->resource,
+				       &keyboard->keys);
+	}
+}
+
 WL_EXPORT void
 weston_keyboard_set_focus(struct weston_keyboard *keyboard,
 			  struct weston_surface *surface)
@@ -468,34 +539,36 @@ weston_keyboard_set_focus(struct weston_keyboard *keyboard,
 	struct wl_resource *resource;
 	struct wl_display *display = keyboard->seat->compositor->wl_display;
 	uint32_t serial;
+	struct wl_list *focus_resource_list;
+
+	focus_resource_list = &keyboard->focus_resource_list;
 
-	if (keyboard->focus_resource && keyboard->focus != surface) {
-		resource = keyboard->focus_resource;
+	if (!wl_list_empty(focus_resource_list) && keyboard->focus != surface) {
 		serial = wl_display_next_serial(display);
-		wl_keyboard_send_leave(resource, serial,
-				       keyboard->focus->resource);
-		wl_list_remove(&keyboard->focus_listener.link);
+		wl_resource_for_each(resource, focus_resource_list) {
+			wl_keyboard_send_leave(resource, serial,
+					keyboard->focus->resource);
+		}
+		move_resources(&keyboard->resource_list, focus_resource_list);
 	}
 
-	resource = find_resource_for_surface(&keyboard->resource_list,
-					     surface);
-	if (resource &&
-	    (keyboard->focus != surface ||
-	     keyboard->focus_resource != resource)) {
+	if (find_resource_for_surface(&keyboard->resource_list, surface) &&
+	    keyboard->focus != surface) {
+		struct wl_client *surface_client =
+			wl_resource_get_client(surface->resource);
+
 		serial = wl_display_next_serial(display);
-		wl_keyboard_send_modifiers(resource, serial,
-					   keyboard->modifiers.mods_depressed,
-					   keyboard->modifiers.mods_latched,
-					   keyboard->modifiers.mods_locked,
-					   keyboard->modifiers.group);
-		wl_keyboard_send_enter(resource, serial, surface->resource,
-				       &keyboard->keys);
-		wl_resource_add_destroy_listener(resource,
-						 &keyboard->focus_listener);
+
+		move_resources_for_client(focus_resource_list,
+					  &keyboard->resource_list,
+					  surface_client);
+		send_enter_to_resource_list(focus_resource_list,
+					    keyboard,
+					    surface,
+					    serial);
 		keyboard->focus_serial = serial;
 	}
 
-	keyboard->focus_resource = resource;
 	keyboard->focus = surface;
 	wl_signal_emit(&keyboard->focus_signal, keyboard);
 }
@@ -705,6 +778,8 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
 	struct weston_surface *focus =
 		(struct weston_surface *) pointer->focus;
 	uint32_t serial = wl_display_next_serial(compositor->wl_display);
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
 
 	if (compositor->ping_handler && focus)
 		compositor->ping_handler(focus, serial);
@@ -718,8 +793,9 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
 						   time, axis, value))
 		return;
 
-	if (pointer->focus_resource)
-		wl_pointer_send_axis(pointer->focus_resource, time, axis,
+	resource_list = &pointer->focus_resource_list;
+	wl_resource_for_each(resource, resource_list)
+		wl_pointer_send_axis(resource, time, axis,
 				     value);
 }
 
@@ -976,30 +1052,26 @@ notify_keyboard_focus_out(struct weston_seat *seat)
 WL_EXPORT void
 weston_touch_set_focus(struct weston_seat *seat, struct weston_surface *surface)
 {
-	struct wl_resource *resource;
+	struct wl_list *focus_resource_list;
+
+	focus_resource_list = &seat->touch->focus_resource_list;
 
 	if (seat->touch->focus == surface)
 		return;
 
-	if (seat->touch->focus_resource)
-		wl_list_remove(&seat->touch->focus_listener.link);
-	seat->touch->focus = NULL;
-	seat->touch->focus_resource = NULL;
+	if (!wl_list_empty(focus_resource_list)) {
+		move_resources(&seat->touch->resource_list,
+			       focus_resource_list);
+	}
 
 	if (surface) {
-		resource =
-			find_resource_for_surface(&seat->touch->resource_list,
-						  surface);
-		if (!resource) {
-			weston_log("couldn't find resource\n");
-			return;
-		}
-
-		seat->touch->focus = surface;
-		seat->touch->focus_resource = resource;
-		wl_resource_add_destroy_listener(resource,
-						 &seat->touch->focus_listener);
+		struct wl_client *surface_client =
+			wl_resource_get_client(surface->resource);
+		move_resources_for_client(focus_resource_list,
+					  &seat->touch->resource_list,
+					  surface_client);
 	}
+	seat->touch->focus = surface;
 }
 
 /**
@@ -1187,6 +1259,9 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 		return;
 	}
 
+	/* May be moved to focused list later by either
+	 * weston_pointer_set_focus or directly if this client is already
+	 * focused */
 	wl_list_insert(&seat->pointer->resource_list, wl_resource_get_link(cr));
 	wl_resource_set_implementation(cr, &pointer_interface, seat->pointer,
 				       unbind_resource);
@@ -1202,10 +1277,14 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 						 seat->pointer->y,
 						 &sx,
 						 &sy);
-		weston_pointer_set_focus(seat->pointer,
-					 seat->pointer->focus,
-					 sx,
-					 sy);
+
+		wl_list_remove(wl_resource_get_link(cr));
+		wl_list_insert(&seat->pointer->focus_resource_list,
+			       wl_resource_get_link(cr));
+		wl_pointer_send_enter(cr,
+				      seat->pointer->focus_serial,
+				      surface->resource,
+				      sx, sy);
 	}
 }
 
@@ -1219,6 +1298,23 @@ static const struct wl_keyboard_interface keyboard_interface = {
 	keyboard_release
 };
 
+static int
+should_send_modifiers_to_client(struct weston_seat *seat,
+				struct wl_client *client)
+{
+	if (seat->keyboard &&
+	    seat->keyboard->focus &&
+	    wl_resource_get_client(seat->keyboard->focus->resource) == client)
+		return 1;
+
+	if (seat->pointer &&
+	    seat->pointer->focus &&
+	    wl_resource_get_client(seat->pointer->focus->resource) == client)
+		return 1;
+
+	return 0;
+}
+
 static void
 seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 		  uint32_t id)
@@ -1236,6 +1332,9 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 		return;
 	}
 
+	/* May be moved to focused list later by either
+	 * weston_keyboard_set_focus or directly if this client is already
+	 * focused */
 	wl_list_insert(&seat->keyboard->resource_list, wl_resource_get_link(cr));
 	wl_resource_set_implementation(cr, &keyboard_interface,
 				       seat, unbind_resource);
@@ -1252,11 +1351,30 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 		close(null_fd);
 	}
 
+	if (should_send_modifiers_to_client(seat, client)) {
+		send_modifiers_to_resource(seat->keyboard,
+					   cr,
+					   seat->keyboard->focus_serial);
+	}
+
 	if (seat->keyboard->focus &&
 	    wl_resource_get_client(seat->keyboard->focus->resource) == client) {
-		weston_keyboard_set_focus(seat->keyboard,
-					  seat->keyboard->focus);
-		wl_data_device_set_keyboard_focus(seat);
+		struct weston_surface *surface =
+			(struct weston_surface *) seat->keyboard->focus;
+
+		wl_list_remove(wl_resource_get_link(cr));
+		wl_list_insert(&seat->keyboard->focus_resource_list,
+			       wl_resource_get_link(cr));
+		wl_keyboard_send_enter(cr,
+				       seat->keyboard->focus_serial,
+				       surface->resource,
+				       &seat->keyboard->keys);
+
+		/* If this is the first keyboard resource for this
+		 * client... */
+		if (seat->keyboard->focus_resource_list.prev ==
+		    wl_resource_get_link(cr))
+			wl_data_device_set_keyboard_focus(seat);
 	}
 }
 
@@ -1287,7 +1405,14 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
 		return;
 	}
 
-	wl_list_insert(&seat->touch->resource_list, wl_resource_get_link(cr));
+	if (seat->touch->focus &&
+	    wl_resource_get_client(seat->touch->focus->resource) == client) {
+		wl_list_insert(&seat->touch->resource_list,
+			       wl_resource_get_link(cr));
+	} else {
+		wl_list_insert(&seat->touch->focus_resource_list,
+			       wl_resource_get_link(cr));
+	}
 	wl_resource_set_implementation(cr, &touch_interface,
 				       seat, unbind_resource);
 }
diff --git a/src/shell.c b/src/shell.c
index c1e0109..ab2d661 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -2158,13 +2158,14 @@ static void
 popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 {
 	struct weston_pointer *pointer = grab->pointer;
+	struct wl_resource *resource;
 	wl_fixed_t sx, sy;
 
-	if (pointer->focus_resource) {
+	wl_resource_for_each(resource, &pointer->focus_resource_list) {
 		weston_surface_from_global_fixed(pointer->focus,
 						 pointer->x, pointer->y,
 						 &sx, &sy);
-		wl_pointer_send_motion(pointer->focus_resource, time, sx, sy);
+		wl_pointer_send_motion(resource, time, sx, sy);
 	}
 }
 
@@ -2178,11 +2179,15 @@ popup_grab_button(struct weston_pointer_grab *grab,
 	struct wl_display *display = shseat->seat->compositor->wl_display;
 	enum wl_pointer_button_state state = state_w;
 	uint32_t serial;
+	struct wl_list *resource_list;
 
-	resource = grab->pointer->focus_resource;
-	if (resource) {
+	resource_list = &grab->pointer->focus_resource_list;
+	if (!wl_list_empty(resource_list)) {
 		serial = wl_display_get_serial(display);
-		wl_pointer_send_button(resource, serial, time, button, state);
+		wl_resource_for_each(resource, resource_list) {
+			wl_pointer_send_button(resource, serial,
+					       time, button, state);
+		}
 	} else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
 		   (shseat->popup_grab.initial_up ||
 		    time - shseat->seat->pointer->grab_time > 500)) {
@@ -4250,6 +4255,7 @@ debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
 	int send = 0, terminate = 0;
 	int check_binding = 1;
 	int i;
+	struct wl_list *resource_list;
 
 	if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
 		/* Do not run bindings on key releases */
@@ -4296,10 +4302,9 @@ debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
 	}
 
 	if (send) {
-		resource = grab->keyboard->focus_resource;
-
-		if (resource) {
-			serial = wl_display_next_serial(display);
+		serial = wl_display_next_serial(display);
+		resource_list = &grab->keyboard->focus_resource_list;
+		wl_resource_for_each(resource, resource_list) {
 			wl_keyboard_send_key(resource, serial, time, key, state);
 		}
 	}
@@ -4318,13 +4323,14 @@ debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
 			uint32_t mods_locked, uint32_t group)
 {
 	struct wl_resource *resource;
+	struct wl_list *resource_list;
 
-	resource = grab->keyboard->focus_resource;
-	if (!resource)
-		return;
+	resource_list = &grab->keyboard->focus_resource_list;
 
-	wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-				   mods_latched, mods_locked, group);
+	wl_resource_for_each(resource, resource_list) {
+		wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+					   mods_latched, mods_locked, group);
+	}
 }
 
 struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
-- 
1.8.3.1



More information about the wayland-devel mailing list