input: Don't test keyboard/pointer/touch pointers

Keyboards and pointers aren't freed when devices are removed, so we should
really be testing keyboard_device_count and pointer_device_count in most
cases, not the actual pointers. Otherwise we end up with different
behaviour after removing a device than we had before it was inserted.

This commit renames the touch/keyboard/pointer pointers and adds helper
functions to get them that hide this complexity and return NULL when
*_device_count is 0.

Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
diff --git a/src/input.c b/src/input.c
index bbcaec5..8f24ccd 100644
--- a/src/input.c
+++ b/src/input.c
@@ -53,7 +53,7 @@
 WL_EXPORT void
 weston_seat_repick(struct weston_seat *seat)
 {
-	const struct weston_pointer *pointer = seat->pointer;
+	const struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	if (!pointer)
 		return;
@@ -391,7 +391,8 @@
 				uint32_t mods_locked, uint32_t group)
 {
 	struct weston_keyboard *keyboard = grab->keyboard;
-	struct weston_pointer *pointer = grab->keyboard->seat->pointer;
+	struct weston_pointer *pointer =
+		weston_seat_get_pointer(grab->keyboard->seat);
 	struct wl_resource *resource;
 	struct wl_list *resource_list;
 
@@ -626,7 +627,7 @@
 			 struct weston_view *view,
 			 wl_fixed_t sx, wl_fixed_t sy)
 {
-	struct weston_keyboard *kbd = pointer->seat->keyboard;
+	struct weston_keyboard *kbd = weston_seat_get_keyboard(pointer->seat);
 	struct wl_resource *resource;
 	struct wl_display *display = pointer->seat->compositor->wl_display;
 	uint32_t serial;
@@ -946,7 +947,7 @@
 	      uint32_t time, wl_fixed_t dx, wl_fixed_t dy)
 {
 	struct weston_compositor *ec = seat->compositor;
-	struct weston_pointer *pointer = seat->pointer;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	weston_compositor_wake(ec);
 	pointer->grab->interface->motion(pointer->grab, time, pointer->x + dx, pointer->y + dy);
@@ -956,7 +957,7 @@
 run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	uint32_t diff;
 	unsigned int i;
 	struct {
@@ -993,7 +994,7 @@
 		       uint32_t time, wl_fixed_t x, wl_fixed_t y)
 {
 	struct weston_compositor *ec = seat->compositor;
-	struct weston_pointer *pointer = seat->pointer;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	weston_compositor_wake(ec);
 	pointer->grab->interface->motion(pointer->grab, time, x, y);
@@ -1004,9 +1005,10 @@
 			struct weston_seat *seat)
 {
 	struct weston_compositor *compositor = seat->compositor;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 
-	if (seat->keyboard) {
-		weston_keyboard_set_focus(seat->keyboard, surface);
+	if (keyboard) {
+		weston_keyboard_set_focus(keyboard, surface);
 		wl_data_device_set_keyboard_focus(seat);
 	}
 
@@ -1018,7 +1020,7 @@
 	      enum wl_pointer_button_state state)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_pointer *pointer = seat->pointer;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
 		weston_compositor_idle_inhibit(compositor);
@@ -1049,7 +1051,7 @@
 	    wl_fixed_t value)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_pointer *pointer = seat->pointer;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 	struct wl_resource *resource;
 	struct wl_list *resource_list;
 
@@ -1124,7 +1126,7 @@
 WL_EXPORT void
 notify_modifiers(struct weston_seat *seat, uint32_t serial)
 {
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	struct weston_keyboard_grab *grab = keyboard->grab;
 	uint32_t mods_depressed, mods_latched, mods_locked, group;
 	uint32_t mods_lookup;
@@ -1196,7 +1198,7 @@
 update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
 		      enum wl_keyboard_key_state state)
 {
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	enum xkb_key_direction direction;
 
 	/* Keyboard modifiers don't exist in raw keyboard mode */
@@ -1240,7 +1242,7 @@
 static void
 update_keymap(struct weston_seat *seat)
 {
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	struct wl_resource *resource;
 	struct weston_xkb_info *xkb_info;
 	struct xkb_state *state;
@@ -1319,7 +1321,7 @@
 	   enum weston_key_state_update update_state)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	struct weston_keyboard_grab *grab = keyboard->grab;
 	uint32_t *k, *end;
 
@@ -1376,8 +1378,10 @@
 notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
 		     wl_fixed_t x, wl_fixed_t y)
 {
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
 	if (output) {
-		weston_pointer_move(seat->pointer, x, y);
+		weston_pointer_move(pointer, x, y);
 	} else {
 		/* FIXME: We should call weston_pointer_set_focus(seat,
 		 * NULL) here, but somehow that breaks re-entry... */
@@ -1400,7 +1404,7 @@
 			 enum weston_key_state_update update_state)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	struct weston_surface *surface;
 	uint32_t *k, serial;
 
@@ -1426,7 +1430,8 @@
 notify_keyboard_focus_out(struct weston_seat *seat)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_keyboard *keyboard = seat->keyboard;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 	uint32_t *k, serial;
 
 	serial = wl_display_next_serial(compositor->wl_display);
@@ -1448,8 +1453,8 @@
 
 	weston_keyboard_set_focus(keyboard, NULL);
 	weston_keyboard_cancel_grab(keyboard);
-	if (seat->pointer)
-		weston_pointer_cancel_grab(seat->pointer);
+	if (pointer)
+		weston_pointer_cancel_grab(pointer);
 }
 
 WL_EXPORT void
@@ -1507,7 +1512,7 @@
              wl_fixed_t x, wl_fixed_t y, int touch_type)
 {
 	struct weston_compositor *ec = seat->compositor;
-	struct weston_touch *touch = seat->touch;
+	struct weston_touch *touch = weston_seat_get_touch(seat);
 	struct weston_touch_grab *grab = touch->grab;
 	struct weston_view *ev;
 	wl_fixed_t sx, sy;
@@ -1586,7 +1591,7 @@
 WL_EXPORT void
 notify_touch_frame(struct weston_seat *seat)
 {
-	struct weston_touch *touch = seat->touch;
+	struct weston_touch *touch = weston_seat_get_touch(seat);
 	struct weston_touch_grab *grab = touch->grab;
 
 	grab->interface->frame(grab);
@@ -1706,9 +1711,18 @@
 		 uint32_t id)
 {
 	struct weston_seat *seat = wl_resource_get_user_data(resource);
+	/* We use the pointer_state directly, which means we'll
+	 * give a wl_pointer if the seat has ever had one - even though
+	 * the spec explicitly states that this request only takes effect
+	 * if the seat has the pointer capability.
+	 *
+	 * This prevents a race between the compositor sending new
+	 * capabilities and the client trying to use the old ones.
+	 */
+	struct weston_pointer *pointer = seat->pointer_state;
 	struct wl_resource *cr;
 
-	if (!seat->pointer)
+	if (!pointer)
 		return;
 
         cr = wl_resource_create(client, &wl_pointer_interface,
@@ -1721,25 +1735,25 @@
 	/* 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,
+	wl_list_insert(&pointer->resource_list, wl_resource_get_link(cr));
+	wl_resource_set_implementation(cr, &pointer_interface, pointer,
 				       unbind_resource);
 
-	if (seat->pointer->focus && seat->pointer->focus->surface->resource &&
-	    wl_resource_get_client(seat->pointer->focus->surface->resource) == client) {
+	if (pointer->focus && pointer->focus->surface->resource &&
+	    wl_resource_get_client(pointer->focus->surface->resource) == client) {
 		wl_fixed_t sx, sy;
 
-		weston_view_from_global_fixed(seat->pointer->focus,
-					      seat->pointer->x,
-					      seat->pointer->y,
+		weston_view_from_global_fixed(pointer->focus,
+					      pointer->x,
+					      pointer->y,
 					      &sx, &sy);
 
 		wl_list_remove(wl_resource_get_link(cr));
-		wl_list_insert(&seat->pointer->focus_resource_list,
+		wl_list_insert(&pointer->focus_resource_list,
 			       wl_resource_get_link(cr));
 		wl_pointer_send_enter(cr,
-				      seat->pointer->focus_serial,
-				      seat->pointer->focus->surface->resource,
+				      pointer->focus_serial,
+				      pointer->focus->surface->resource,
 				      sx, sy);
 	}
 }
@@ -1758,16 +1772,19 @@
 should_send_modifiers_to_client(struct weston_seat *seat,
 				struct wl_client *client)
 {
-	if (seat->keyboard &&
-	    seat->keyboard->focus &&
-	    seat->keyboard->focus->resource &&
-	    wl_resource_get_client(seat->keyboard->focus->resource) == client)
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+	if (keyboard &&
+	    keyboard->focus &&
+	    keyboard->focus->resource &&
+	    wl_resource_get_client(keyboard->focus->resource) == client)
 		return true;
 
-	if (seat->pointer &&
-	    seat->pointer->focus &&
-	    seat->pointer->focus->surface->resource &&
-	    wl_resource_get_client(seat->pointer->focus->surface->resource) == client)
+	if (pointer &&
+	    pointer->focus &&
+	    pointer->focus->surface->resource &&
+	    wl_resource_get_client(pointer->focus->surface->resource) == client)
 		return true;
 
 	return false;
@@ -1778,7 +1795,15 @@
 		  uint32_t id)
 {
 	struct weston_seat *seat = wl_resource_get_user_data(resource);
-	struct weston_keyboard *keyboard = seat->keyboard;
+	/* We use the keyboard_state directly, which means we'll
+	 * give a wl_keyboard if the seat has ever had one - even though
+	 * the spec explicitly states that this request only takes effect
+	 * if the seat has the keyboard capability.
+	 *
+	 * This prevents a race between the compositor sending new
+	 * capabilities and the client trying to use the old ones.
+	 */
+	struct weston_keyboard *keyboard = seat->keyboard_state;
 	struct wl_resource *cr;
 
 	if (!keyboard)
@@ -1858,9 +1883,18 @@
 	       uint32_t id)
 {
 	struct weston_seat *seat = wl_resource_get_user_data(resource);
+	/* We use the touch_state directly, which means we'll
+	 * give a wl_touch if the seat has ever had one - even though
+	 * the spec explicitly states that this request only takes effect
+	 * if the seat has the touch capability.
+	 *
+	 * This prevents a race between the compositor sending new
+	 * capabilities and the client trying to use the old ones.
+	 */
+	struct weston_touch *touch = seat->touch_state;
 	struct wl_resource *cr;
 
-	if (!seat->touch)
+	if (!touch)
 		return;
 
         cr = wl_resource_create(client, &wl_touch_interface,
@@ -1870,12 +1904,12 @@
 		return;
 	}
 
-	if (seat->touch->focus &&
-	    wl_resource_get_client(seat->touch->focus->surface->resource) == client) {
-		wl_list_insert(&seat->touch->resource_list,
+	if (touch->focus &&
+	    wl_resource_get_client(touch->focus->surface->resource) == client) {
+		wl_list_insert(&touch->resource_list,
 			       wl_resource_get_link(cr));
 	} else {
-		wl_list_insert(&seat->touch->focus_resource_list,
+		wl_list_insert(&touch->focus_resource_list,
 			       wl_resource_get_link(cr));
 	}
 	wl_resource_set_implementation(cr, &touch_interface,
@@ -1901,11 +1935,11 @@
 	wl_resource_set_implementation(resource, &seat_interface, data,
 				       unbind_resource);
 
-	if (seat->pointer_device_count)
+	if (weston_seat_get_pointer(seat))
 		caps |= WL_SEAT_CAPABILITY_POINTER;
-	if (seat->keyboard_device_count)
+	if (weston_seat_get_keyboard(seat))
 		caps |= WL_SEAT_CAPABILITY_KEYBOARD;
-	if (seat->touch_device_count)
+	if (weston_seat_get_touch(seat))
 		caps |= WL_SEAT_CAPABILITY_TOUCH;
 
 	wl_seat_send_capabilities(resource, caps);
@@ -2095,17 +2129,19 @@
 WL_EXPORT void
 weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap)
 {
-	if (!seat->keyboard || !keymap)
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+
+	if (!keyboard || !keymap)
 		return;
 
 #ifdef ENABLE_XKBCOMMON
 	if (!seat->compositor->use_xkbcommon)
 		return;
 
-	xkb_keymap_unref(seat->keyboard->pending_keymap);
-	seat->keyboard->pending_keymap = xkb_keymap_ref(keymap);
+	xkb_keymap_unref(keyboard->pending_keymap);
+	keyboard->pending_keymap = xkb_keymap_ref(keymap);
 
-	if (seat->keyboard->keys.size == 0)
+	if (keyboard->keys.size == 0)
 		update_keymap(seat);
 #endif
 }
@@ -2115,7 +2151,7 @@
 {
 	struct weston_keyboard *keyboard;
 
-	if (seat->keyboard) {
+	if (seat->keyboard_state) {
 		seat->keyboard_device_count += 1;
 		if (seat->keyboard_device_count == 1)
 			seat_send_updated_caps(seat);
@@ -2151,7 +2187,7 @@
 	}
 #endif
 
-	seat->keyboard = keyboard;
+	seat->keyboard_state = keyboard;
 	seat->keyboard_device_count = 1;
 	keyboard->seat = seat;
 
@@ -2196,9 +2232,9 @@
 	seat->keyboard_device_count--;
 	assert(seat->keyboard_device_count >= 0);
 	if (seat->keyboard_device_count == 0) {
-		weston_keyboard_set_focus(seat->keyboard, NULL);
-		weston_keyboard_cancel_grab(seat->keyboard);
-		weston_keyboard_reset_state(seat->keyboard);
+		weston_keyboard_set_focus(seat->keyboard_state, NULL);
+		weston_keyboard_cancel_grab(seat->keyboard_state);
+		weston_keyboard_reset_state(seat->keyboard_state);
 		seat_send_updated_caps(seat);
 	}
 }
@@ -2208,7 +2244,7 @@
 {
 	struct weston_pointer *pointer;
 
-	if (seat->pointer) {
+	if (seat->pointer_state) {
 		seat->pointer_device_count += 1;
 		if (seat->pointer_device_count == 1)
 			seat_send_updated_caps(seat);
@@ -2219,7 +2255,7 @@
 	if (pointer == NULL)
 		return;
 
-	seat->pointer = pointer;
+	seat->pointer_state = pointer;
 	seat->pointer_device_count = 1;
 	pointer->seat = seat;
 
@@ -2229,7 +2265,7 @@
 WL_EXPORT void
 weston_seat_release_pointer(struct weston_seat *seat)
 {
-	struct weston_pointer *pointer = seat->pointer;
+	struct weston_pointer *pointer = seat->pointer_state;
 
 	seat->pointer_device_count--;
 	if (seat->pointer_device_count == 0) {
@@ -2256,7 +2292,7 @@
 {
 	struct weston_touch *touch;
 
-	if (seat->touch) {
+	if (seat->touch_state) {
 		seat->touch_device_count += 1;
 		if (seat->touch_device_count == 1)
 			seat_send_updated_caps(seat);
@@ -2267,7 +2303,7 @@
 	if (touch == NULL)
 		return;
 
-	seat->touch = touch;
+	seat->touch_state = touch;
 	seat->touch_device_count = 1;
 	touch->seat = seat;
 
@@ -2279,9 +2315,9 @@
 {
 	seat->touch_device_count--;
 	if (seat->touch_device_count == 0) {
-		weston_touch_set_focus(seat->touch, NULL);
-		weston_touch_cancel_grab(seat->touch);
-		weston_touch_reset_state(seat->touch);
+		weston_touch_set_focus(seat->touch_state, NULL);
+		weston_touch_cancel_grab(seat->touch_state);
+		weston_touch_reset_state(seat->touch_state);
 		seat_send_updated_caps(seat);
 	}
 }
@@ -2321,12 +2357,12 @@
 	if (seat->saved_kbd_focus)
 		wl_list_remove(&seat->saved_kbd_focus_listener.link);
 
-	if (seat->pointer)
-		weston_pointer_destroy(seat->pointer);
-	if (seat->keyboard)
-		weston_keyboard_destroy(seat->keyboard);
-	if (seat->touch)
-		weston_touch_destroy(seat->touch);
+	if (seat->pointer_state)
+		weston_pointer_destroy(seat->pointer_state);
+	if (seat->keyboard_state)
+		weston_keyboard_destroy(seat->keyboard_state);
+	if (seat->touch_state)
+		weston_touch_destroy(seat->touch_state);
 
 	free (seat->seat_name);
 
@@ -2334,3 +2370,69 @@
 
 	wl_signal_emit(&seat->destroy_signal, seat);
 }
+
+/** Get a seat's keyboard pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's keyboard pointer, or NULL if no keyboard is present
+ *
+ * The keyboard pointer for a seat isn't freed when all keyboards are removed,
+ * so it should only be used when the seat's keyboard_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a keyboard is present.
+ */
+WL_EXPORT struct weston_keyboard *
+weston_seat_get_keyboard(struct weston_seat *seat)
+{
+	if (!seat)
+		return NULL;
+
+	if (seat->keyboard_device_count)
+		return seat->keyboard_state;
+
+	return NULL;
+}
+
+/** Get a seat's pointer pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's pointer pointer, or NULL if no pointer device is present
+ *
+ * The pointer pointer for a seat isn't freed when all mice are removed,
+ * so it should only be used when the seat's pointer_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a pointing device is present.
+ */
+WL_EXPORT struct weston_pointer *
+weston_seat_get_pointer(struct weston_seat *seat)
+{
+	if (!seat)
+		return NULL;
+
+	if (seat->pointer_device_count)
+		return seat->pointer_state;
+
+	return NULL;
+}
+
+/** Get a seat's touch pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's touch pointer, or NULL if no touch device is present
+ *
+ * The touch pointer for a seat isn't freed when all touch devices are removed,
+ * so it should only be used when the seat's touch_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a touch device is present.
+ */
+WL_EXPORT struct weston_touch *
+weston_seat_get_touch(struct weston_seat *seat)
+{
+	if (!seat)
+		return NULL;
+
+	if (seat->touch_device_count)
+		return seat->touch_state;
+
+	return NULL;
+}