[weston,7/7] text: Fix text-input for multi-seat

Submitted by Derek Foreman on Dec. 5, 2014, 9:38 p.m.

Details

Message ID 1417815521-11304-8-git-send-email-derekf@osg.samsung.com
State Accepted
Commit 516d603515de3df40a04b722cf4851209e9d5588
Headers show

Not browsing as part of any series.

Commit Message

Derek Foreman Dec. 5, 2014, 9:38 p.m.
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.

Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
---
 src/text-backend.c | 76 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 48 insertions(+), 28 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/text-backend.c b/src/text-backend.c
index b8b526e..46113e3 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

Comments

On Fri Dec 05 2014 at 10:47:05 PM Derek Foreman <derekf@osg.samsung.com>
wrote:

> 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.
>
> Signed-off-by: Derek Foreman <derekf@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 b8b526e..46113e3 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.3
>

Looks good.

Regards
Jan Arne
On Fri, Dec 05, 2014 at 03:38:41PM -0600, Derek Foreman wrote:
> 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.
> 
> Signed-off-by: Derek Foreman <derekf@osg.samsung.com>

Offhand I think this looks ok, but the commit message could benefit with
a more detailed explanation.  E.g. why do text_input and
text_input_manager have mutual pointers to one another?

> ---
>  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 b8b526e..46113e3 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.3
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel