[RFC] weston: implement inert objects for keyboard/pointer/touch

David FORT rdp.effort at gmail.com
Fri Oct 16 02:53:42 PDT 2015


This patch implements inert objects for wl_keyboard, wl_pointer and wl_touch.
The target case is when the server has just send a capability event about a
disappearing object, and the client binds the corresponding object. We bind an
inert object: an object does nothing when it is requested. If the client behave
correctly, this object should be released when the capability event is received
and treated (calling the corresponding release request).
As a consequence, we can rely on seat->[keyboard|pointer|touch]_state to know
if the seat has the corresponding object.
Weston doesn't really handle multiple mice for one wl_pointer, so I have removed
the corresponding code and tests (it was quite a weston_test hack BTW).
Finally I have fixed a wrong behaviour: the capabilities event's documentation states
that the capabilities should be sent when a new capability is set on the seat. So
attaching a second mouse to an existing wl_pointer should not broadcast seat
capabilities (and the same for keyboard and touch).
---
 desktop-shell/exposay.c  |  16 ++--
 desktop-shell/shell.c    |  21 +++--
 src/compositor-wayland.c |  10 +-
 src/compositor-x11.c     |  12 ++-
 src/compositor.h         |   3 -
 src/input.c              | 235 ++++++++++++++++++++++++++---------------------
 src/libinput-device.c    |   2 +-
 src/screen-share.c       |   2 +
 src/text-backend.c       |  44 +++++----
 src/zoom.c               |   7 +-
 tests/devices-test.c     |  20 ----
 tests/weston-test.c      |  18 ++--
 xwayland/dnd.c           |   3 +-
 13 files changed, 216 insertions(+), 177 deletions(-)

diff --git a/desktop-shell/exposay.c b/desktop-shell/exposay.c
index 08b86a3..d6919b3 100644
--- a/desktop-shell/exposay.c
+++ b/desktop-shell/exposay.c
@@ -574,21 +574,23 @@ exposay_transition_active(struct desktop_shell *shell)
 	bool animate = false;
 
 	shell->exposay.workspace = get_current_workspace(shell);
-	shell->exposay.focus_prev = get_default_view(keyboard->focus);
-	shell->exposay.focus_current = get_default_view(keyboard->focus);
+	if (keyboard) {
+		shell->exposay.focus_prev = get_default_view(keyboard->focus);
+		shell->exposay.focus_current = get_default_view(keyboard->focus);
+	}
 	shell->exposay.clicked = NULL;
 	wl_list_init(&shell->exposay.surface_list);
 
 	lower_fullscreen_layer(shell, NULL);
 	shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
-	weston_keyboard_start_grab(keyboard,
-	                           &shell->exposay.grab_kbd);
-	weston_keyboard_set_focus(keyboard, NULL);
+	if (keyboard) {
+		weston_keyboard_start_grab(keyboard, &shell->exposay.grab_kbd);
+		weston_keyboard_set_focus(keyboard, NULL);
+	}
 
 	shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
 	if (pointer) {
-		weston_pointer_start_grab(pointer,
-		                          &shell->exposay.grab_ptr);
+		weston_pointer_start_grab(pointer, &shell->exposay.grab_ptr);
 		weston_pointer_clear_focus(pointer);
 	}
 	wl_list_for_each(shell_output, &shell->output_list, link) {
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 3eb3f5c..cdddf09 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -380,7 +380,8 @@ shell_grab_start(struct shell_grab *grab,
 	struct desktop_shell *shell = shsurf->shell;
 	struct weston_touch *touch = weston_seat_get_touch(pointer->seat);
 
-	popup_grab_end(pointer);
+	if (pointer)
+		popup_grab_end(pointer);
 	if (touch)
 		touch_popup_grab_end(touch);
 
@@ -391,11 +392,13 @@ shell_grab_start(struct shell_grab *grab,
 		      &grab->shsurf_destroy_listener);
 
 	shsurf->grabbed = 1;
-	weston_pointer_start_grab(pointer, &grab->grab);
+	if (pointer)
+		weston_pointer_start_grab(pointer, &grab->grab);
 	if (shell->child.desktop_shell) {
 		desktop_shell_send_grab_cursor(shell->child.desktop_shell,
 					       cursor);
-		weston_pointer_set_focus(pointer,
+		if (pointer)
+			weston_pointer_set_focus(pointer,
 					 get_default_view(shell->grab_surface),
 					 wl_fixed_from_int(0),
 					 wl_fixed_from_int(0));
@@ -925,12 +928,10 @@ restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
 		wl_list_insert(&shell->compositor->seat_list,
 			       &state->seat->link);
 
-		if (!keyboard)
-			continue;
-
 		surface = state->keyboard_focus;
 
-		weston_keyboard_set_focus(keyboard, surface);
+		if (keyboard)
+			weston_keyboard_set_focus(keyboard, surface);
 	}
 
 	/* For any remaining seats that we don't have a focus state
@@ -955,6 +956,9 @@ replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
 	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	struct focus_state *state;
 
+	if (!keyboard)
+		return;
+
 	wl_list_for_each(state, &ws->focus_list, link) {
 		if (state->seat == seat) {
 			focus_state_set_focus(state, keyboard->focus);
@@ -1483,6 +1487,9 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
 	struct workspace *to;
 	struct focus_state *state;
 
+	if (!keyboard)
+		return;
+
 	surface = weston_surface_get_main_surface(keyboard->focus);
 	view = get_default_view(surface);
 	if (view == NULL ||
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 7b11ae4..2cdf7a5 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -1589,10 +1589,12 @@ input_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
 		serial_out = wl_display_next_serial(b->compositor->wl_display);
 
 	keyboard = weston_seat_get_keyboard(&input->base);
-	xkb_state_update_mask(keyboard->xkb_state.state,
-			      mods_depressed, mods_latched,
-			      mods_locked, 0, 0, group);
-	notify_modifiers(&input->base, serial_out);
+	if (keyboard) {
+		xkb_state_update_mask(keyboard->xkb_state.state,
+					  mods_depressed, mods_latched,
+					  mods_locked, 0, 0, group);
+		notify_modifiers(&input->base, serial_out);
+	}
 }
 
 static void
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 9a23996..42356e6 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -189,11 +189,15 @@ x11_backend_get_keymap(struct x11_backend *b)
 static uint32_t
 get_xkb_mod_mask(struct x11_backend *b, uint32_t in)
 {
-	struct weston_keyboard *keyboard =
-		weston_seat_get_keyboard(&b->core_seat);
-	struct weston_xkb_info *info = keyboard->xkb_info;
+	struct weston_keyboard *keyboard = weston_seat_get_keyboard(&b->core_seat);
+	struct weston_xkb_info *info;
 	uint32_t ret = 0;
 
+	if (!keyboard)
+		return 0;
+
+	info = keyboard->xkb_info;
+
 	if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
 		ret |= (1 << info->shift_mod);
 	if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
@@ -1028,6 +1032,8 @@ update_xkb_state_from_core(struct x11_backend *b, uint16_t x11_mask)
 	struct weston_keyboard *keyboard
 		= weston_seat_get_keyboard(&b->core_seat);
 
+	if (!keyboard)
+		return;
 	xkb_state_update_mask(keyboard->xkb_state.state,
 			      keyboard->modifiers.mods_depressed & mask,
 			      keyboard->modifiers.mods_latched & mask,
diff --git a/src/compositor.h b/src/compositor.h
index 2e2a185..de38514 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -508,9 +508,6 @@ struct weston_seat {
 	struct weston_pointer *pointer_state;
 	struct weston_keyboard *keyboard_state;
 	struct weston_touch *touch_state;
-	int pointer_device_count;
-	int keyboard_device_count;
-	int touch_device_count;
 
 	struct weston_output *output; /* constraint */
 
diff --git a/src/input.c b/src/input.c
index 500c39a..6cd2650 100644
--- a/src/input.c
+++ b/src/input.c
@@ -55,10 +55,8 @@ weston_seat_repick(struct weston_seat *seat)
 {
 	const struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
-	if (!pointer)
-		return;
-
-	pointer->grab->interface->focus(pointer->grab);
+	if (pointer)
+		pointer->grab->interface->focus(pointer->grab);
 }
 
 static void
@@ -618,11 +616,11 @@ seat_send_updated_caps(struct weston_seat *seat)
 	enum wl_seat_capability caps = 0;
 	struct wl_resource *resource;
 
-	if (seat->pointer_device_count > 0)
+	if (seat->pointer_state)
 		caps |= WL_SEAT_CAPABILITY_POINTER;
-	if (seat->keyboard_device_count > 0)
+	if (seat->keyboard_state)
 		caps |= WL_SEAT_CAPABILITY_KEYBOARD;
-	if (seat->touch_device_count > 0)
+	if (seat->touch_state)
 		caps |= WL_SEAT_CAPABILITY_TOUCH;
 
 	wl_resource_for_each(resource, &seat->base_resource_list) {
@@ -982,7 +980,8 @@ notify_motion(struct weston_seat *seat,
 	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);
+	if (pointer)
+		pointer->grab->interface->motion(pointer->grab, time, pointer->x + dx, pointer->y + dy);
 }
 
 static void
@@ -1029,7 +1028,8 @@ notify_motion_absolute(struct weston_seat *seat,
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	weston_compositor_wake(ec);
-	pointer->grab->interface->motion(pointer->grab, time, x, y);
+	if (pointer)
+		pointer->grab->interface->motion(pointer->grab, time, x, y);
 }
 
 WL_EXPORT void
@@ -1054,6 +1054,9 @@ notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
 	struct weston_compositor *compositor = seat->compositor;
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
+	if (!pointer)
+		return;
+
 	if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
 		weston_compositor_idle_inhibit(compositor);
 		if (pointer->button_count == 0) {
@@ -1092,7 +1095,7 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
 	if (!value)
 		return;
 
-	if (weston_compositor_run_axis_binding(compositor, pointer,
+	if (!pointer || weston_compositor_run_axis_binding(compositor, pointer,
 					       time, axis, value))
 		return;
 
@@ -1159,12 +1162,16 @@ WL_EXPORT void
 notify_modifiers(struct weston_seat *seat, uint32_t serial)
 {
 	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-	struct weston_keyboard_grab *grab = keyboard->grab;
+	struct weston_keyboard_grab *grab;
 	uint32_t mods_depressed, mods_latched, mods_locked, group;
 	uint32_t mods_lookup;
 	enum weston_led leds = 0;
 	int changed = 0;
 
+	if (!keyboard)
+		return;
+
+	grab = keyboard->grab;
 	/* Serialize and update our internal state, checking to see if it's
 	 * different to the previous state. */
 	mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
@@ -1233,6 +1240,9 @@ update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
 	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 	enum xkb_key_direction direction;
 
+	if (!keyboard)
+		return;
+
 	/* Keyboard modifiers don't exist in raw keyboard mode */
 	if (!seat->compositor->use_xkbcommon)
 		return;
@@ -1281,6 +1291,9 @@ update_keymap(struct weston_seat *seat)
 	xkb_mod_mask_t latched_mods;
 	xkb_mod_mask_t locked_mods;
 
+	if (!keyboard)
+		return;
+
 	xkb_info = weston_xkb_info_create(keyboard->pending_keymap);
 
 	xkb_keymap_unref(keyboard->pending_keymap);
@@ -1353,8 +1366,8 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 	   enum weston_key_state_update update_state)
 {
 	struct weston_compositor *compositor = seat->compositor;
-	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-	struct weston_keyboard_grab *grab = keyboard->grab;
+	struct weston_keyboard *keyboard;
+	struct weston_keyboard_grab *grab;
 	uint32_t *k, *end;
 
 	if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
@@ -1363,6 +1376,11 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 		weston_compositor_idle_release(compositor);
 	}
 
+	keyboard = weston_seat_get_keyboard(seat);
+	if (!keyboard)
+		return;
+	grab = keyboard->grab;
+
 	end = keyboard->keys.data + keyboard->keys.size;
 	for (k = keyboard->keys.data; k < end; k++) {
 		if (*k == key) {
@@ -1412,7 +1430,7 @@ notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
 {
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
-	if (output) {
+	if (output && pointer) {
 		weston_pointer_move(pointer, x, y);
 	} else {
 		/* FIXME: We should call weston_pointer_set_focus(seat,
@@ -1440,6 +1458,9 @@ notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
 	struct weston_surface *surface;
 	uint32_t *k, serial;
 
+	if (!keyboard)
+		return;
+
 	serial = wl_display_next_serial(compositor->wl_display);
 	wl_array_copy(&keyboard->keys, keys);
 	wl_array_for_each(k, &keyboard->keys) {
@@ -1466,25 +1487,30 @@ notify_keyboard_focus_out(struct weston_seat *seat)
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 	uint32_t *k, serial;
 
-	serial = wl_display_next_serial(compositor->wl_display);
-	wl_array_for_each(k, &keyboard->keys) {
-		weston_compositor_idle_release(compositor);
-		update_modifier_state(seat, serial, *k,
-				      WL_KEYBOARD_KEY_STATE_RELEASED);
+	if (keyboard) {
+		serial = wl_display_next_serial(compositor->wl_display);
+		wl_array_for_each(k, &keyboard->keys) {
+			weston_compositor_idle_release(compositor);
+			update_modifier_state(seat, serial, *k,
+						  WL_KEYBOARD_KEY_STATE_RELEASED);
+		}
 	}
 
 	seat->modifier_state = 0;
 
-	if (keyboard->focus) {
-		seat->saved_kbd_focus = keyboard->focus;
-		seat->saved_kbd_focus_listener.notify =
-			destroy_device_saved_kbd_focus;
-		wl_signal_add(&keyboard->focus->destroy_signal,
-			      &seat->saved_kbd_focus_listener);
+	if (keyboard) {
+		if (keyboard->focus) {
+			seat->saved_kbd_focus = keyboard->focus;
+			seat->saved_kbd_focus_listener.notify =
+				destroy_device_saved_kbd_focus;
+			wl_signal_add(&keyboard->focus->destroy_signal,
+					  &seat->saved_kbd_focus_listener);
+		}
+
+		weston_keyboard_set_focus(keyboard, NULL);
+		weston_keyboard_cancel_grab(keyboard);
 	}
 
-	weston_keyboard_set_focus(keyboard, NULL);
-	weston_keyboard_cancel_grab(keyboard);
 	if (pointer)
 		weston_pointer_cancel_grab(pointer);
 }
@@ -1545,10 +1571,15 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
 {
 	struct weston_compositor *ec = seat->compositor;
 	struct weston_touch *touch = weston_seat_get_touch(seat);
-	struct weston_touch_grab *grab = touch->grab;
+	struct weston_touch_grab *grab;
 	struct weston_view *ev;
 	wl_fixed_t sx, sy;
 
+	if (!touch)
+		return;
+
+	grab = touch->grab;
+
 	/* Update grab's global coordinates. */
 	if (touch_id == touch->grab_touch_id && touch_type != WL_TOUCH_UP) {
 		touch->grab_x = x;
@@ -1620,9 +1651,12 @@ WL_EXPORT void
 notify_touch_frame(struct weston_seat *seat)
 {
 	struct weston_touch *touch = weston_seat_get_touch(seat);
-	struct weston_touch_grab *grab = touch->grab;
+	struct weston_touch_grab *grab;
 
-	grab->interface->frame(grab);
+	if (touch) {
+		grab = touch->grab;
+		grab->interface->frame(grab);
+	}
 }
 
 static int
@@ -1735,34 +1769,46 @@ static const struct wl_pointer_interface pointer_interface = {
 };
 
 static void
+inert_pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
+		   uint32_t serial, struct wl_resource *surface_resource,
+		   int32_t x, int32_t y)
+{
+	/* in the "normal" pointer_set_cursor, we're setting a surface role only
+	 * if we have pointer focus. An inert pointer doesn't really have a focus so
+	 * we don't do anything on the surface */
+}
+
+static const struct wl_pointer_interface inert_pointer_interface = {
+	inert_pointer_set_cursor,
+	pointer_release
+};
+
+static void
 seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 		 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 (!pointer)
-		return;
-
-        cr = wl_resource_create(client, &wl_pointer_interface,
-				wl_resource_get_version(resource), id);
+	cr = wl_resource_create(client, &wl_pointer_interface,
+			wl_resource_get_version(resource), id);
 	if (cr == NULL) {
 		wl_client_post_no_memory(client);
 		return;
 	}
 
+	if (!pointer) {
+		/*weston_log("binding inert pointer for seat %p\n", seat);*/
+		wl_resource_set_implementation(cr, &inert_pointer_interface, NULL,
+					       NULL);
+		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(&pointer->resource_list, wl_resource_get_link(cr));
 	wl_resource_set_implementation(cr, &pointer_interface, pointer,
 				       unbind_resource);
@@ -1796,6 +1842,10 @@ static const struct wl_keyboard_interface keyboard_interface = {
 	keyboard_release
 };
 
+static const struct wl_keyboard_interface inert_keyboard_interface = {
+	keyboard_release
+};
+
 static bool
 should_send_modifiers_to_client(struct weston_seat *seat,
 				struct wl_client *client)
@@ -1823,27 +1873,23 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 		  uint32_t id)
 {
 	struct weston_seat *seat = wl_resource_get_user_data(resource);
-	/* 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)
-		return;
-
-        cr = wl_resource_create(client, &wl_keyboard_interface,
-				wl_resource_get_version(resource), id);
+	cr = wl_resource_create(client, &wl_keyboard_interface,
+			wl_resource_get_version(resource), id);
 	if (cr == NULL) {
 		wl_client_post_no_memory(client);
 		return;
 	}
 
+	if (!keyboard) {
+		/*weston_log("binding inert keyboard for seat %p\n", seat);*/
+		wl_resource_set_implementation(cr, &inert_keyboard_interface, NULL,
+				NULL);
+		return;
+	}
+
 	/* May be moved to focused list later by either
 	 * weston_keyboard_set_focus or directly if this client is already
 	 * focused */
@@ -1906,32 +1952,32 @@ static const struct wl_touch_interface touch_interface = {
 	touch_release
 };
 
+static const struct wl_touch_interface inert_touch_interface = {
+	touch_release
+};
+
 static void
 seat_get_touch(struct wl_client *client, struct wl_resource *resource,
 	       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 (!touch)
-		return;
-
-        cr = wl_resource_create(client, &wl_touch_interface,
-				wl_resource_get_version(resource), id);
+	cr = wl_resource_create(client, &wl_touch_interface,
+			wl_resource_get_version(resource), id);
 	if (cr == NULL) {
 		wl_client_post_no_memory(client);
 		return;
 	}
 
+	if (!touch) {
+		/*weston_log("binding inert touch for seat %p\n", seat);*/
+		wl_resource_set_implementation(cr, &inert_touch_interface, NULL, NULL);
+		return;
+	}
+
+
 	if (touch->focus &&
 	    wl_resource_get_client(touch->focus->surface->resource) == client) {
 		wl_list_insert(&touch->focus_resource_list,
@@ -2180,9 +2226,7 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
 	struct weston_keyboard *keyboard;
 
 	if (seat->keyboard_state) {
-		seat->keyboard_device_count += 1;
-		if (seat->keyboard_device_count == 1)
-			seat_send_updated_caps(seat);
+		weston_log("seat %p already has a keyboard device\n", seat);
 		return 0;
 	}
 
@@ -2216,7 +2260,6 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
 #endif
 
 	seat->keyboard_state = keyboard;
-	seat->keyboard_device_count = 1;
 	keyboard->seat = seat;
 
 	seat_send_updated_caps(seat);
@@ -2257,12 +2300,12 @@ weston_keyboard_reset_state(struct weston_keyboard *keyboard)
 WL_EXPORT void
 weston_seat_release_keyboard(struct weston_seat *seat)
 {
-	seat->keyboard_device_count--;
-	assert(seat->keyboard_device_count >= 0);
-	if (seat->keyboard_device_count == 0) {
+	if (seat->keyboard_state) {
 		weston_keyboard_set_focus(seat->keyboard_state, NULL);
 		weston_keyboard_cancel_grab(seat->keyboard_state);
 		weston_keyboard_reset_state(seat->keyboard_state);
+		seat->keyboard_state = NULL;
+
 		seat_send_updated_caps(seat);
 	}
 }
@@ -2273,9 +2316,7 @@ weston_seat_init_pointer(struct weston_seat *seat)
 	struct weston_pointer *pointer;
 
 	if (seat->pointer_state) {
-		seat->pointer_device_count += 1;
-		if (seat->pointer_device_count == 1)
-			seat_send_updated_caps(seat);
+		weston_log("seat %p already has a pointer device\n", seat);
 		return;
 	}
 
@@ -2284,7 +2325,6 @@ weston_seat_init_pointer(struct weston_seat *seat)
 		return;
 
 	seat->pointer_state = pointer;
-	seat->pointer_device_count = 1;
 	pointer->seat = seat;
 
 	seat_send_updated_caps(seat);
@@ -2295,8 +2335,7 @@ weston_seat_release_pointer(struct weston_seat *seat)
 {
 	struct weston_pointer *pointer = seat->pointer_state;
 
-	seat->pointer_device_count--;
-	if (seat->pointer_device_count == 0) {
+	if (seat->pointer_state) {
 		weston_pointer_clear_focus(pointer);
 		weston_pointer_cancel_grab(pointer);
 
@@ -2304,12 +2343,9 @@ weston_seat_release_pointer(struct weston_seat *seat)
 			pointer_unmap_sprite(pointer);
 
 		weston_pointer_reset_state(pointer);
-		seat_send_updated_caps(seat);
+		seat->pointer_state = NULL;
 
-		/* seat->pointer is intentionally not destroyed so that
-		 * a newly attached pointer on this seat will retain
-		 * the previous cursor co-ordinates.
-		 */
+		seat_send_updated_caps(seat);
 	}
 }
 
@@ -2319,9 +2355,7 @@ weston_seat_init_touch(struct weston_seat *seat)
 	struct weston_touch *touch;
 
 	if (seat->touch_state) {
-		seat->touch_device_count += 1;
-		if (seat->touch_device_count == 1)
-			seat_send_updated_caps(seat);
+		weston_log("seat %p already has a touch device\n", seat);
 		return;
 	}
 
@@ -2330,7 +2364,6 @@ weston_seat_init_touch(struct weston_seat *seat)
 		return;
 
 	seat->touch_state = touch;
-	seat->touch_device_count = 1;
 	touch->seat = seat;
 
 	seat_send_updated_caps(seat);
@@ -2339,11 +2372,12 @@ weston_seat_init_touch(struct weston_seat *seat)
 WL_EXPORT void
 weston_seat_release_touch(struct weston_seat *seat)
 {
-	seat->touch_device_count--;
-	if (seat->touch_device_count == 0) {
+	if (seat->touch_state) {
 		weston_touch_set_focus(seat->touch_state, NULL);
 		weston_touch_cancel_grab(seat->touch_state);
 		weston_touch_reset_state(seat->touch_state);
+		seat->touch_state = NULL;
+
 		seat_send_updated_caps(seat);
 	}
 }
@@ -2413,10 +2447,7 @@ weston_seat_get_keyboard(struct weston_seat *seat)
 	if (!seat)
 		return NULL;
 
-	if (seat->keyboard_device_count)
-		return seat->keyboard_state;
-
-	return NULL;
+	return seat->keyboard_state;
 }
 
 /** Get a seat's pointer pointer
@@ -2435,10 +2466,7 @@ weston_seat_get_pointer(struct weston_seat *seat)
 	if (!seat)
 		return NULL;
 
-	if (seat->pointer_device_count)
-		return seat->pointer_state;
-
-	return NULL;
+	return seat->pointer_state;
 }
 
 /** Get a seat's touch pointer
@@ -2457,8 +2485,5 @@ weston_seat_get_touch(struct weston_seat *seat)
 	if (!seat)
 		return NULL;
 
-	if (seat->touch_device_count)
-		return seat->touch_state;
-
-	return NULL;
+	return seat->touch_state;
 }
diff --git a/src/libinput-device.c b/src/libinput-device.c
index 2cbfb88..ddd8e2c 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -547,7 +547,7 @@ evdev_notify_keyboard_focus(struct weston_seat *seat,
 {
 	struct wl_array keys;
 
-	if (seat->keyboard_device_count == 0)
+	if (!seat->keyboard_state)
 		return;
 
 	wl_array_init(&keys);
diff --git a/src/screen-share.c b/src/screen-share.c
index d961c89..e20aede 100644
--- a/src/screen-share.c
+++ b/src/screen-share.c
@@ -283,6 +283,8 @@ ss_seat_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
 		serial_out = wl_display_next_serial(c->wl_display);
 
 	keyboard = weston_seat_get_keyboard(&seat->base);
+	if (!keyboard)
+		return;
 	xkb_state_update_mask(keyboard->xkb_state.state,
 			      mods_depressed, mods_latched,
 			      mods_locked, 0, 0, group);
diff --git a/src/text-backend.c b/src/text-backend.c
index 8c9e30d..f3f30dc 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -664,15 +664,17 @@ input_method_context_grab_keyboard(struct wl_client *client,
 
 	context->keyboard = cr;
 
-	wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-				keyboard->xkb_info->keymap_fd,
-				keyboard->xkb_info->keymap_size);
-
-	if (keyboard->grab != &keyboard->default_grab) {
-		weston_keyboard_end_grab(keyboard);
+	if (keyboard) {
+		wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+					keyboard->xkb_info->keymap_fd,
+					keyboard->xkb_info->keymap_size);
+
+		if (keyboard->grab != &keyboard->default_grab) {
+			weston_keyboard_end_grab(keyboard);
+		}
+		weston_keyboard_start_grab(keyboard, &keyboard->input_method_grab);
+		keyboard->input_method_resource = cr;
 	}
-	weston_keyboard_start_grab(keyboard, &keyboard->input_method_grab);
-	keyboard->input_method_resource = cr;
 }
 
 static void
@@ -686,10 +688,14 @@ input_method_context_key(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 	struct weston_seat *seat = context->input_method->seat;
-	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-	struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
+	struct weston_keyboard *keyboard;
+	struct weston_keyboard_grab *default_grab;
 
-	default_grab->interface->key(default_grab, time, key, state_w);
+	keyboard = weston_seat_get_keyboard(seat);
+	if (keyboard) {
+		default_grab = &keyboard->default_grab;
+		default_grab->interface->key(default_grab, time, key, state_w);
+	}
 }
 
 static void
@@ -705,13 +711,17 @@ input_method_context_modifiers(struct wl_client *client,
 		wl_resource_get_user_data(resource);
 
 	struct weston_seat *seat = context->input_method->seat;
-	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-	struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
+	struct weston_keyboard *keyboard;
+	struct weston_keyboard_grab *default_grab;
 
-	default_grab->interface->modifiers(default_grab,
-					   serial, mods_depressed,
-					   mods_latched, mods_locked,
-					   group);
+	keyboard = weston_seat_get_keyboard(seat);
+	if (keyboard) {
+		default_grab = &keyboard->default_grab;
+		default_grab->interface->modifiers(default_grab,
+						   serial, mods_depressed,
+						   mods_latched, mods_locked,
+						   group);
+	}
 }
 
 static void
diff --git a/src/zoom.c b/src/zoom.c
index 08c0693..8658f08 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -124,6 +124,8 @@ weston_output_update_zoom(struct weston_output *output)
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
 	assert(output->zoom.active);
+	if (!pointer)
+		return;
 
 	output->zoom.current.x = wl_fixed_to_double(pointer->x);
 	output->zoom.current.y = wl_fixed_to_double(pointer->y);
@@ -155,8 +157,9 @@ weston_output_activate_zoom(struct weston_output *output,
 	output->zoom.active = true;
 	output->zoom.seat = seat;
 	output->disable_planes++;
-	wl_signal_add(&pointer->motion_signal,
-		      &output->zoom.motion_listener);
+	if (pointer)
+		wl_signal_add(&pointer->motion_signal,
+				&output->zoom.motion_listener);
 }
 
 WL_EXPORT void
diff --git a/tests/devices-test.c b/tests/devices-test.c
index 8f9feec..8851c17 100644
--- a/tests/devices-test.c
+++ b/tests/devices-test.c
@@ -74,26 +74,6 @@ TEST(seat_capabilities_test)
 	assert(cl->input->pointer);
 	assert(cl->input->keyboard);
 	assert(cl->input->touch);
-
-	/* add extra devices */
-	weston_test_device_add(cl->test->weston_test, "keyboard");
-	weston_test_device_add(cl->test->weston_test, "pointer");
-	weston_test_device_add(cl->test->weston_test, "touch");
-	client_roundtrip(cl);
-
-	/* remove extra devices */
-	weston_test_device_release(cl->test->weston_test, "keyboard");
-	weston_test_device_release(cl->test->weston_test, "pointer");
-	weston_test_device_release(cl->test->weston_test, "touch");
-	client_roundtrip(cl);
-
-	/* we still should have all the capabilities, since the devices
-	 * were doubled */
-	assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
-
-	assert(cl->input->pointer);
-	assert(cl->input->keyboard);
-	assert(cl->input->touch);
 }
 
 #define COUNT 15
diff --git a/tests/weston-test.c b/tests/weston-test.c
index b593f1e..28aefad 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -85,7 +85,8 @@ notify_pointer_position(struct weston_test *test, struct wl_resource *resource)
 	struct weston_seat *seat = get_seat(test);
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
-	weston_test_send_pointer_position(resource, pointer->x, pointer->y);
+	if (pointer)
+		weston_test_send_pointer_position(resource, pointer->x, pointer->y);
 }
 
 static void
@@ -146,9 +147,10 @@ move_pointer(struct wl_client *client, struct wl_resource *resource,
 	struct weston_seat *seat = get_seat(test);
 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
 
-	notify_motion(seat, 100,
-		      wl_fixed_from_int(x) - pointer->x,
-		      wl_fixed_from_int(y) - pointer->y);
+	if (pointer)
+		notify_motion(seat, 100,
+				  wl_fixed_from_int(x) - pointer->x,
+				  wl_fixed_from_int(y) - pointer->y);
 
 	notify_pointer_position(test, resource);
 }
@@ -177,11 +179,13 @@ activate_surface(struct wl_client *client, struct wl_resource *resource,
 	keyboard = weston_seat_get_keyboard(seat);
 	if (surface) {
 		weston_surface_activate(surface, seat);
-		notify_keyboard_focus_in(seat, &keyboard->keys,
-					 STATE_UPDATE_AUTOMATIC);
+		if (keyboard)
+			notify_keyboard_focus_in(seat, &keyboard->keys,
+					STATE_UPDATE_AUTOMATIC);
 	}
 	else {
-		notify_keyboard_focus_out(seat);
+		if (keyboard)
+			notify_keyboard_focus_out(seat);
 		weston_surface_activate(surface, seat);
 	}
 }
diff --git a/xwayland/dnd.c b/xwayland/dnd.c
index a036b30..94a9563 100644
--- a/xwayland/dnd.c
+++ b/xwayland/dnd.c
@@ -214,7 +214,8 @@ handle_enter(struct weston_wm *wm, xcb_client_message_event_t *client_message)
 	}
 
 	free(reply);
-	weston_pointer_start_drag(pointer, &source->base, NULL, NULL);
+	if (pointer)
+		weston_pointer_start_drag(pointer, &source->base, NULL, NULL);
 }
 
 int
-- 
1.9.1



More information about the wayland-devel mailing list