[PATCH weston 2/2] input-method: Make wl_input_method_context reactivatable

Daiki Ueno ueno at gnu.org
Wed Feb 26 01:21:05 PST 2014


Change the semantics of wl_input_method_context
activation/deactivation mechanism, similar to what wl_text_input does.

Previously, a wl_input_method_context object is created upon
wl_input_method::activate event and cannot persist after deactivation,
while the counterpart wl_text_input object persists after
deactivation.

This patch moves activate/deactivate events from wl_input_method to
wl_input_method_context and allow those to be called multiple times on
a same wl_input_method_context object.  Also, to advertise a new
wl_input_method_context a dedicated event wl_input_method::context is
added.

All included clients are changed to follow the API change.  Also, the
backend wl_text_input implementation is modified to track input method
contexts (not input methods) attached to wl_text_input.
---
 clients/editor.c          |   2 -
 clients/keyboard.c        |  54 +++++++------
 protocol/input-method.xml |  30 ++++----
 src/text-backend.c        | 187 ++++++++++++++++++++++------------------------
 4 files changed, 137 insertions(+), 136 deletions(-)

diff --git a/clients/editor.c b/clients/editor.c
index 76e2346..0cc3af6 100644
--- a/clients/editor.c
+++ b/clients/editor.c
@@ -436,8 +436,6 @@ text_input_leave(void *data,
 
 	entry->active = 0;
 
-	wl_text_input_hide_input_panel(text_input);
-
 	widget_schedule_redraw(entry->widget);
 }
 
diff --git a/clients/keyboard.c b/clients/keyboard.c
index 6876cde..414d682 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -803,19 +803,9 @@ handle_preferred_language(void *data,
 		keyboard->preferred_language = strdup(language);
 }
 
-static const struct wl_input_method_context_listener input_method_context_listener = {
-	handle_surrounding_text,
-	handle_reset,
-	handle_content_type,
-	handle_invoke_action,
-	handle_commit_state,
-	handle_preferred_language
-};
-
 static void
-input_method_activate(void *data,
-		      struct wl_input_method *input_method,
-		      struct wl_input_method_context *context)
+handle_activate(void *data,
+		struct wl_input_method_context *context)
 {
 	struct virtual_keyboard *keyboard = data;
 	struct wl_array modifiers_map;
@@ -823,8 +813,7 @@ input_method_activate(void *data,
 
 	keyboard->keyboard->state = keyboardstate_default;
 
-	if (keyboard->context)
-		wl_input_method_context_destroy(keyboard->context);
+	dbg("activated %u\n", wl_proxy_get_id ((struct wl_proxy *) context));
 
 	if (keyboard->preedit_string)
 		free(keyboard->preedit_string);
@@ -840,9 +829,6 @@ input_method_activate(void *data,
 	keyboard->serial = 0;
 
 	keyboard->context = context;
-	wl_input_method_context_add_listener(context,
-					     &input_method_context_listener,
-					     keyboard);
 
 	wl_array_init(&modifiers_map);
 	keysym_modifiers_add(&modifiers_map, "Shift");
@@ -865,22 +851,44 @@ input_method_activate(void *data,
 }
 
 static void
-input_method_deactivate(void *data,
-			struct wl_input_method *input_method,
-			struct wl_input_method_context *context)
+handle_deactivate(void *data,
+		  struct wl_input_method_context *context)
 {
 	struct virtual_keyboard *keyboard = data;
 
 	if (!keyboard->context)
 		return;
 
-	wl_input_method_context_destroy(keyboard->context);
+	dbg("deactivated %u\n", wl_proxy_get_id ((struct wl_proxy *) context));
+
 	keyboard->context = NULL;
 }
 
+static const struct wl_input_method_context_listener input_method_context_listener = {
+	handle_surrounding_text,
+	handle_reset,
+	handle_content_type,
+	handle_invoke_action,
+	handle_commit_state,
+	handle_preferred_language,
+	handle_activate,
+	handle_deactivate
+};
+
+static void
+input_method_context(void *data,
+		     struct wl_input_method *input_method,
+		     struct wl_input_method_context *context)
+{
+	struct virtual_keyboard *keyboard = data;
+
+	wl_input_method_context_add_listener(context,
+					     &input_method_context_listener,
+					     keyboard);
+}
+
 static const struct wl_input_method_listener input_method_listener = {
-	input_method_activate,
-	input_method_deactivate
+	input_method_context
 };
 
 static void
diff --git a/protocol/input-method.xml b/protocol/input-method.xml
index 448440e..6f2d3af 100644
--- a/protocol/input-method.xml
+++ b/protocol/input-method.xml
@@ -31,8 +31,6 @@
       Corresponds to a text model on input method side. An input method context
       is created on text model activation on the input method side. It allows to
       receive information about the text model from the application via events.
-      Input method contexts do not keep state after deactivation and should be
-      destroyed after deactivation is handled.
 
       Text is generally UTF-8 encoded, indices and lengths are in bytes.
 
@@ -213,6 +211,16 @@
     <event name="preferred_language">
       <arg name="language" type="string"/>
     </event>
+    <event name="activate">
+      <description summary="activate event">
+	The input method context became active.
+      </description>
+    </event>
+    <event name="deactivate">
+      <description summary="deactivate event">
+	The input method context became inactive.
+      </description>
+    </event>
   </interface>
 
   <interface name="wl_input_method" version="1">
@@ -222,20 +230,12 @@
       object per seat. On activate there is a new input method context object
       created which allows the input method to communicate with the text model.
     </description>
-    <event name="activate">
-      <description summary="activate event">
-        A text model was activated. Creates an input method context object
-        which allows communication with the text model.
-      </description>
-      <arg name="id" type="new_id" interface="wl_input_method_context"/>
-    </event>
-    <event name="deactivate">
-      <description summary="activate event">
-        The text model corresponding to the context argument was deactivated.
-        The input method context should be destroyed after deactivation is
-        handled.
+    <event name="context">
+      <description summary="introduce a new wl_input_method_context">
+        Introduces a new wl_input_method_context object created for a
+        text model.
       </description>
-      <arg name="context" type="object" interface="wl_input_method_context"/>
+      <arg name="context" type="new_id" interface="wl_input_method_context"/>
     </event>
   </interface>
 
diff --git a/src/text-backend.c b/src/text-backend.c
index d6a6f3b..cefd39f 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -41,7 +41,7 @@ struct text_input {
 
 	struct weston_compositor *ec;
 
-	struct wl_list input_methods;
+	struct wl_list contexts;
 
 	struct weston_surface *surface;
 
@@ -65,14 +65,10 @@ struct input_method {
 	struct weston_seat *seat;
 	struct text_input *model;
 
-	struct wl_list link;
-
 	struct wl_listener keyboard_focus_listener;
 
 	int focus_listener_initialized;
 
-	struct input_method_context *context;
-
 	struct text_backend *text_backend;
 };
 
@@ -111,35 +107,59 @@ static void input_method_context_end_keyboard_grab(struct input_method_context *
 static void input_method_init_seat(struct weston_seat *seat);
 
 static void
+activate_text_input(struct text_input *text_input,
+		    struct input_method *input_method)
+{
+	struct weston_compositor *ec = text_input->ec;
+	struct input_method_context *context, *next;
+
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		if (context->input_method == input_method) {
+			wl_input_method_context_send_activate(context->resource);
+			break;
+		}
+	}
+
+	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);
+	}
+
+	input_method->model = text_input;
+
+	wl_text_input_send_enter(text_input->resource, text_input->surface->resource);
+}
+
+static void
 deactivate_text_input(struct text_input *text_input,
 		      struct input_method *input_method)
 {
 	struct weston_compositor *ec = text_input->ec;
+	struct input_method_context *context, *next;
 
-	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_for_each_safe(context, next, &text_input->contexts, link) {
+		if (context->input_method == input_method) {
+			input_method_context_end_keyboard_grab(context);
 
-		wl_list_remove(&input_method->link);
-		input_method->model = NULL;
-		input_method->context = NULL;
-		wl_signal_emit(&ec->hide_input_panel_signal, ec);
-		wl_text_input_send_leave(text_input->resource);
+			wl_input_method_context_send_deactivate(context->resource);
+			break;
+		}
 	}
+
+	input_method->model = NULL;
+
+	wl_signal_emit(&ec->hide_input_panel_signal, ec);
+	wl_text_input_send_leave(text_input->resource);
 }
 
 static void
 destroy_text_input(struct wl_resource *resource)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link)
-		deactivate_text_input(text_input, input_method);
+	wl_list_for_each_safe(context, next, &text_input->contexts, link)
+		deactivate_text_input(text_input, context->input_method);
 
 	free(text_input);
 }
@@ -152,12 +172,10 @@ text_input_set_surrounding_text(struct wl_client *client,
 				uint32_t anchor)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_surrounding_text(input_method->context->resource,
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_surrounding_text(context->resource,
 							      text,
 							      cursor,
 							      anchor);
@@ -174,7 +192,6 @@ text_input_activate(struct wl_client *client,
 	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;
 
 	if (old == text_input)
 		return;
@@ -184,20 +201,12 @@ text_input_activate(struct wl_client *client,
 				      weston_seat->input_method);
 	}
 
-	input_method->model = text_input;
-	wl_list_insert(&text_input->input_methods, &input_method->link);
 	input_method_init_seat(weston_seat);
 
 	text_input->surface = wl_resource_get_user_data(surface);
 
 	input_method_context_create(text_input, input_method);
-
-	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);
-	}
-
-	wl_text_input_send_enter(text_input->resource, text_input->surface->resource);
+	activate_text_input(text_input, input_method);
 }
 
 static void
@@ -217,12 +226,10 @@ text_input_reset(struct wl_client *client,
 		 struct wl_resource *resource)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_reset(input_method->context->resource);
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_reset(context->resource);
 	}
 }
 
@@ -252,12 +259,10 @@ text_input_set_content_type(struct wl_client *client,
 			    uint32_t purpose)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_content_type(input_method->context->resource, hint, purpose);
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_content_type(context->resource, hint, purpose);
 	}
 }
 
@@ -268,12 +273,10 @@ text_input_invoke_action(struct wl_client *client,
 			 uint32_t index)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_invoke_action(input_method->context->resource, button, index);
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_invoke_action(context->resource, button, index);
 	}
 }
 
@@ -283,12 +286,10 @@ text_input_commit_state(struct wl_client *client,
 			uint32_t serial)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_commit_state(input_method->context->resource, serial);
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_commit_state(context->resource, serial);
 	}
 }
 
@@ -301,7 +302,7 @@ text_input_show_input_panel(struct wl_client *client,
 
 	text_input->input_panel_visible = 1;
 
-	if (!wl_list_empty(&text_input->input_methods)) {
+	if (!wl_list_empty(&text_input->contexts)) {
 		wl_signal_emit(&ec->show_input_panel_signal, text_input->surface);
 		wl_signal_emit(&ec->update_input_panel_signal, &text_input->cursor_rectangle);
 	}
@@ -316,7 +317,7 @@ text_input_hide_input_panel(struct wl_client *client,
 
 	text_input->input_panel_visible = 0;
 
-	if (!wl_list_empty(&text_input->input_methods))
+	if (!wl_list_empty(&text_input->contexts))
 		wl_signal_emit(&ec->hide_input_panel_signal, ec);
 }
 
@@ -326,12 +327,10 @@ text_input_set_preferred_language(struct wl_client *client,
 				  const char *language)
 {
 	struct text_input *text_input = wl_resource_get_user_data(resource);
-	struct input_method *input_method, *next;
+	struct input_method_context *context, *next;
 
-	wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
-		if (!input_method->context)
-			continue;
-		wl_input_method_context_send_preferred_language(input_method->context->resource,
+	wl_list_for_each_safe(context, next, &text_input->contexts, link) {
+		wl_input_method_context_send_preferred_language(context->resource,
 								language);
 	}
 }
@@ -367,7 +366,7 @@ static void text_input_manager_create_text_input(struct wl_client *client,
 
 	text_input->ec = text_input_manager->ec;
 
-	wl_list_init(&text_input->input_methods);
+	wl_list_init(&text_input->contexts);
 };
 
 static const struct wl_text_input_manager_interface text_input_manager_implementation = {
@@ -438,9 +437,8 @@ input_method_context_commit_string(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_commit_string(context->model->resource,
-						 serial, text);
+	wl_text_input_send_commit_string(context->model->resource,
+					 serial, text);
 }
 
 static void
@@ -453,9 +451,8 @@ input_method_context_preedit_string(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_preedit_string(context->model->resource,
-						  serial, text, commit);
+	wl_text_input_send_preedit_string(context->model->resource,
+					  serial, text, commit);
 }
 
 static void
@@ -468,9 +465,8 @@ input_method_context_preedit_styling(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_preedit_styling(context->model->resource,
-						   index, length, style);
+	wl_text_input_send_preedit_styling(context->model->resource,
+					   index, length, style);
 }
 
 static void
@@ -481,9 +477,8 @@ input_method_context_preedit_cursor(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_preedit_cursor(context->model->resource,
-						  cursor);
+	wl_text_input_send_preedit_cursor(context->model->resource,
+					  cursor);
 }
 
 static void
@@ -495,9 +490,8 @@ input_method_context_delete_surrounding_text(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_delete_surrounding_text(context->model->resource,
-							   index, length);
+	wl_text_input_send_delete_surrounding_text(context->model->resource,
+						   index, length);
 }
 
 static void
@@ -509,9 +503,8 @@ input_method_context_cursor_position(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_cursor_position(context->model->resource,
-						   index, anchor);
+	wl_text_input_send_cursor_position(context->model->resource,
+					   index, anchor);
 }
 
 static void
@@ -522,8 +515,7 @@ input_method_context_modifiers_map(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_modifiers_map(context->model->resource, map);
+	wl_text_input_send_modifiers_map(context->model->resource, map);
 }
 
 static void
@@ -538,9 +530,8 @@ input_method_context_keysym(struct wl_client *client,
 	struct input_method_context *context =
 		wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_keysym(context->model->resource,
-					  serial, time, sym, state, modifiers);
+	wl_text_input_send_keysym(context->model->resource,
+				  serial, time, sym, state, modifiers);
 }
 
 static void
@@ -668,9 +659,8 @@ input_method_context_language(struct wl_client *client,
 {
 	struct input_method_context *context = wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_language(context->model->resource,
-					    serial, language);
+	wl_text_input_send_language(context->model->resource,
+				    serial, language);
 }
 
 static void
@@ -681,9 +671,8 @@ input_method_context_text_direction(struct wl_client *client,
 {
 	struct input_method_context *context = wl_resource_get_user_data(resource);
 
-	if (context->model)
-		wl_text_input_send_text_direction(context->model->resource,
-						  serial, direction);
+	wl_text_input_send_text_direction(context->model->resource,
+					  serial, direction);
 }
 
 
@@ -709,6 +698,8 @@ destroy_input_method_context(struct wl_resource *resource)
 {
 	struct input_method_context *context = wl_resource_get_user_data(resource);
 
+	wl_list_remove (&context->link);
+
 	if (context->keyboard) {
 		wl_resource_destroy(context->keyboard);
 	}
@@ -726,6 +717,12 @@ input_method_context_create(struct text_input *model,
 	if (!input_method->input_method_binding)
 		return;
 
+	wl_list_for_each(context, &model->contexts, link) {
+		if (context->model == model &&
+		    context->input_method == input_method)
+			return;
+	}
+
 	context = calloc(1, sizeof *context);
 	if (context == NULL)
 		return;
@@ -740,10 +737,10 @@ input_method_context_create(struct text_input *model,
 
 	context->model = model;
 	context->input_method = input_method;
-	input_method->context = context;
 
+	wl_input_method_send_context(binding, context->resource);
 
-	wl_input_method_send_activate(binding, context->resource);
+	wl_list_insert(&model->contexts, &context->link);
 }
 
 static void
@@ -769,7 +766,6 @@ unbind_input_method(struct wl_resource *resource)
 	struct text_backend *text_backend = input_method->text_backend;
 
 	input_method->input_method_binding = NULL;
-	input_method->context = NULL;
 
 	text_backend->input_method.binding = NULL;
 }
@@ -920,7 +916,6 @@ handle_seat_created(struct wl_listener *listener,
 	input_method->seat = seat;
 	input_method->model = NULL;
 	input_method->focus_listener_initialized = 0;
-	input_method->context = NULL;
 	input_method->text_backend = text_backend;
 
 	input_method->input_method_global =
-- 
1.9.0.rc3



More information about the wayland-devel mailing list