[PATCH weston v3 1/2] text: Fix text-input for multi-seat

Derek Foreman derekf at osg.samsung.com
Fri May 8 15:08:40 PDT 2015


Multi-seat configurations currently break the text-backend, crashing
weston.  This is an attempt to clean up any crashes and have somewhat
sensible input panel behavior with multi-seat.

Store a link to the manager that created a text_input, use this to
ensure that only a single panel gets popped up at a time, since there
is only one manager.

Replace deactivate_text_input with deactivate_input_method: multiple
input methods may focus the same text_input, so deactivating a text_input
is weird in multi-seat and confusing to perform.

In destroy_input_method_context set the context's input_method's context
pointer to NULL to prevent a dangling pointer.

Reviewed-by: Jan Arne Petersen <janarne at gmail.com>
Reviewed-by: Bryce Harrington <bryce at osg.samsung.com>
Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
---
 src/text-backend.c | 76 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 48 insertions(+), 28 deletions(-)

diff --git a/src/text-backend.c b/src/text-backend.c
index 4dc7179..65b4e5e 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -33,6 +33,7 @@
 #include "text-server-protocol.h"
 #include "input-method-server-protocol.h"
 
+struct text_input_manager;
 struct input_method;
 struct input_method_context;
 struct text_backend;
@@ -49,12 +50,16 @@ struct text_input {
 	pixman_box32_t cursor_rectangle;
 
 	bool input_panel_visible;
+
+	struct text_input_manager *manager;
 };
 
 struct text_input_manager {
 	struct wl_global *text_input_manager_global;
 	struct wl_listener destroy_listener;
 
+	struct text_input *current_panel;
+
 	struct weston_compositor *ec;
 };
 
@@ -113,25 +118,28 @@ static void
 input_method_init_seat(struct weston_seat *seat);
 
 static void
-deactivate_text_input(struct text_input *text_input,
-		      struct input_method *input_method)
+deactivate_input_method(struct input_method *input_method)
 {
+	struct text_input *text_input = input_method->model;
 	struct weston_compositor *ec = text_input->ec;
 
-	if (input_method->model == text_input) {
-		if (input_method->context && input_method->input_method_binding) {
-			input_method_context_end_keyboard_grab(input_method->context);
-			wl_input_method_send_deactivate(input_method->input_method_binding,
-							input_method->context->resource);
-			input_method->context->model = NULL;
-		}
-
-		wl_list_remove(&input_method->link);
-		input_method->model = NULL;
-		input_method->context = NULL;
+	if (input_method->context && input_method->input_method_binding) {
+		input_method_context_end_keyboard_grab(input_method->context);
+		wl_input_method_send_deactivate(input_method->input_method_binding,
+						input_method->context->resource);
+	}
+
+	wl_list_remove(&input_method->link);
+	input_method->model = NULL;
+	input_method->context = NULL;
+
+	if (wl_list_empty(&text_input->input_methods) &&
+	    text_input->input_panel_visible) {
 		wl_signal_emit(&ec->hide_input_panel_signal, ec);
-		wl_text_input_send_leave(text_input->resource);
+		text_input->input_panel_visible = false;
+		text_input->manager->current_panel = NULL;
 	}
+	wl_text_input_send_leave(text_input->resource);
 }
 
 static void
@@ -141,7 +149,7 @@ destroy_text_input(struct wl_resource *resource)
 	struct input_method *input_method, *next;
 
 	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link)
-		deactivate_text_input(text_input, input_method);
+		deactivate_input_method(input_method);
 
 	free(text_input);
 }
@@ -175,16 +183,14 @@ text_input_activate(struct wl_client *client,
 	struct text_input *text_input = wl_resource_get_user_data(resource);
 	struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
 	struct input_method *input_method = weston_seat->input_method;
-	struct text_input *old = weston_seat->input_method->model;
 	struct weston_compositor *ec = text_input->ec;
+	struct text_input *current;
 
-	if (old == text_input)
+	if (input_method->model == text_input)
 		return;
 
-	if (old) {
-		deactivate_text_input(old,
-				      weston_seat->input_method);
-	}
+	if (input_method->model)
+		deactivate_input_method(input_method);
 
 	input_method->model = text_input;
 	wl_list_insert(&text_input->input_methods, &input_method->link);
@@ -194,9 +200,18 @@ text_input_activate(struct wl_client *client,
 
 	input_method_context_create(text_input, input_method);
 
+	current = text_input->manager->current_panel;
+
+	if (current && current != text_input) {
+		current->input_panel_visible = false;
+		wl_signal_emit(&ec->hide_input_panel_signal, ec);
+		text_input->manager->current_panel = NULL;
+	}
+
 	if (text_input->input_panel_visible) {
 		wl_signal_emit(&ec->show_input_panel_signal, text_input->surface);
 		wl_signal_emit(&ec->update_input_panel_signal, &text_input->cursor_rectangle);
+		text_input->manager->current_panel = text_input;
 	}
 
 	wl_text_input_send_enter(text_input->resource, text_input->surface->resource);
@@ -207,11 +222,10 @@ text_input_deactivate(struct wl_client *client,
 		      struct wl_resource *resource,
 		      struct wl_resource *seat)
 {
-	struct text_input *text_input = wl_resource_get_user_data(resource);
 	struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
 
-	deactivate_text_input(text_input,
-			      weston_seat->input_method);
+	if (weston_seat->input_method->model)
+		deactivate_input_method(weston_seat->input_method);
 }
 
 static void
@@ -318,8 +332,11 @@ text_input_hide_input_panel(struct wl_client *client,
 
 	text_input->input_panel_visible = false;
 
-	if (!wl_list_empty(&text_input->input_methods))
+	if (!wl_list_empty(&text_input->input_methods) &&
+	    text_input == text_input->manager->current_panel) {
+		text_input->manager->current_panel = NULL;
 		wl_signal_emit(&ec->hide_input_panel_signal, ec);
+	}
 }
 
 static void
@@ -370,6 +387,7 @@ static void text_input_manager_create_text_input(struct wl_client *client,
 				       text_input, destroy_text_input);
 
 	text_input->ec = text_input_manager->ec;
+	text_input->manager = text_input_manager;
 
 	wl_list_init(&text_input->input_methods);
 };
@@ -719,6 +737,9 @@ destroy_input_method_context(struct wl_resource *resource)
 		wl_resource_destroy(context->keyboard);
 	}
 
+	if (context->input_method && context->input_method->context == context)
+		context->input_method->context = NULL;
+
 	free(context);
 }
 
@@ -823,7 +844,7 @@ input_method_notifier_destroy(struct wl_listener *listener, void *data)
 		container_of(listener, struct input_method, destroy_listener);
 
 	if (input_method->model)
-		deactivate_text_input(input_method->model, input_method);
+		deactivate_input_method(input_method);
 
 	wl_global_destroy(input_method->input_method_global);
 	wl_list_remove(&input_method->destroy_listener.link);
@@ -843,8 +864,7 @@ handle_keyboard_focus(struct wl_listener *listener, void *data)
 		return;
 
 	if (!surface || input_method->model->surface != surface)
-		deactivate_text_input(input_method->model,
-				      input_method);
+		deactivate_input_method(input_method);
 }
 
 static void
-- 
2.1.4



More information about the wayland-devel mailing list