text: Fix serial handling
authorJan Arne Petersen <jpetersen@openismus.com>
Thu, 18 Apr 2013 14:47:33 +0000 (16:47 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 2 May 2013 20:41:48 +0000 (16:41 -0400)
Signed-off-by: Jan Arne Petersen <jpetersen@openismus.com>
clients/editor.c
clients/keyboard.c
clients/weston-simple-im.c
protocol/input-method.xml
protocol/text.xml
src/text-backend.c
tests/text-test.c

index e61eda0..c40815a 100644 (file)
@@ -63,6 +63,7 @@ struct text_entry {
                xkb_mod_mask_t shift_mask;
        } keysym;
        uint32_t serial;
+       uint32_t reset_serial;
        uint32_t content_purpose;
        uint32_t click_to_show;
        char *preferred_language;
@@ -138,6 +139,12 @@ text_input_commit_string(void *data,
 {
        struct text_entry *entry = data;
 
+       if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
+               fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
+                       serial, entry->serial, entry->reset_serial);
+               return;
+       }
+
        text_entry_reset_preedit(entry);
 
        text_entry_delete_selected_text(entry);
@@ -175,7 +182,6 @@ text_input_preedit_string(void *data,
 static void
 text_input_delete_surrounding_text(void *data,
                                   struct text_input *text_input,
-                                  uint32_t serial,
                                   int32_t index,
                                   uint32_t length)
 {
@@ -207,7 +213,6 @@ text_input_delete_surrounding_text(void *data,
 static void
 text_input_cursor_position(void *data,
                           struct text_input *text_input,
-                          uint32_t serial,
                           int32_t index,
                           int32_t anchor)
 {
@@ -220,7 +225,6 @@ text_input_cursor_position(void *data,
 static void
 text_input_preedit_styling(void *data,
                           struct text_input *text_input,
-                          uint32_t serial,
                           uint32_t index,
                           uint32_t length,
                           uint32_t style)
@@ -272,7 +276,6 @@ text_input_preedit_styling(void *data,
 static void
 text_input_preedit_cursor(void *data,
                          struct text_input *text_input,
-                         uint32_t serial,
                          int32_t index)
 {
        struct text_entry *entry = data;
@@ -374,6 +377,9 @@ text_input_enter(void *data,
 
        entry->active = 1;
 
+       text_entry_update(entry);
+       entry->reset_serial = entry->serial;
+
        widget_schedule_redraw(entry->widget);
 }
 
@@ -552,10 +558,7 @@ text_entry_activate(struct text_entry *entry,
        if (!entry->click_to_show)
                text_input_show_input_panel(entry->text_input);
 
-       entry->serial++;
-
        text_input_activate(entry->text_input,
-                           entry->serial,
                            seat,
                            surface);
 }
@@ -653,7 +656,7 @@ text_entry_update(struct text_entry *entry)
        text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
                                        cursor_rectangle.width, cursor_rectangle.height);
 
-       text_input_commit_state(entry->text_input);
+       text_input_commit_state(entry->text_input, ++entry->serial);
 }
 
 static void
@@ -714,8 +717,9 @@ text_entry_commit_and_reset(struct text_entry *entry)
                free(commit);
        }
 
-       entry->serial++;
-       text_input_reset(entry->text_input, entry->serial);
+       text_input_reset(entry->text_input);
+       text_entry_update(entry);
+       entry->reset_serial = entry->serial;
 }
 
 static void
index 17fb683..9dd210a 100644 (file)
@@ -395,7 +395,6 @@ virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
                                            "",
                                            "");
        input_method_context_cursor_position(keyboard->context,
-                                            keyboard->serial,
                                             0, 0);
        input_method_context_commit_string(keyboard->context,
                                           keyboard->serial,
@@ -412,14 +411,12 @@ virtual_keyboard_send_preedit(struct virtual_keyboard *keyboard,
 
        if (keyboard->preedit_style)
                input_method_context_preedit_styling(keyboard->context,
-                                                    keyboard->serial,
                                                     0,
                                                     strlen(keyboard->preedit_string),
                                                     keyboard->preedit_style);
        if (cursor > 0)
                index = cursor;
        input_method_context_preedit_cursor(keyboard->context,
-                                           keyboard->serial,
                                            index);
        input_method_context_preedit_string(keyboard->context,
                                            keyboard->serial,
@@ -449,7 +446,6 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
 
                        if (strlen(keyboard->keyboard->preedit_string) == 0) {
                                input_method_context_delete_surrounding_text(keyboard->keyboard->context,
-                                                                            keyboard->keyboard->serial,
                                                                             -1, 1);
                        } else {
                                keyboard->keyboard->preedit_string[strlen(keyboard->keyboard->preedit_string) - 1] = '\0';
@@ -579,8 +575,7 @@ handle_surrounding_text(void *data,
 
 static void
 handle_reset(void *data,
-            struct input_method_context *context,
-            uint32_t serial)
+            struct input_method_context *context)
 {
        struct virtual_keyboard *keyboard = data;
 
@@ -597,8 +592,6 @@ handle_reset(void *data,
                free(keyboard->preedit_string);
                keyboard->preedit_string = strdup("");
        }
-
-       keyboard->serial = serial;
 }
 
 static void
@@ -628,12 +621,15 @@ handle_invoke_action(void *data,
 }
 
 static void
-handle_commit(void *data,
-             struct input_method_context *context)
+handle_commit_state(void *data,
+                   struct input_method_context *context,
+                   uint32_t serial)
 {
        struct virtual_keyboard *keyboard = data;
        const struct layout *layout;
 
+       keyboard->serial = serial;
+
        layout = get_current_layout(keyboard);
 
        if (keyboard->surrounding_text)
@@ -670,15 +666,14 @@ static const struct input_method_context_listener input_method_context_listener
        handle_reset,
        handle_content_type,
        handle_invoke_action,
-       handle_commit,
+       handle_commit_state,
        handle_preferred_language
 };
 
 static void
 input_method_activate(void *data,
                      struct input_method *input_method,
-                     struct input_method_context *context,
-                     uint32_t serial)
+                     struct input_method_context *context)
 {
        struct virtual_keyboard *keyboard = data;
        struct wl_array modifiers_map;
@@ -700,7 +695,7 @@ input_method_activate(void *data,
        free(keyboard->surrounding_text);
        keyboard->surrounding_text = NULL;
 
-       keyboard->serial = serial;
+       keyboard->serial = 0;
 
        keyboard->context = context;
        input_method_context_add_listener(context,
index 9d31e3b..a532003 100644 (file)
@@ -112,16 +112,13 @@ handle_surrounding_text(void *data,
 
 static void
 handle_reset(void *data,
-            struct input_method_context *context,
-            uint32_t serial)
+            struct input_method_context *context)
 {
        struct simple_im *keyboard = data;
 
        fprintf(stderr, "Reset pre-edit buffer\n");
 
        keyboard->compose_state = state_normal;
-
-       keyboard->serial = serial;
 }
 
 static void
@@ -141,9 +138,13 @@ handle_invoke_action(void *data,
 }
 
 static void
-handle_commit(void *data,
-             struct input_method_context *context)
+handle_commit_state(void *data,
+                   struct input_method_context *context,
+                   uint32_t serial)
 {
+       struct simple_im *keyboard = data;
+
+       keyboard->serial = serial;
 }
 
 static void
@@ -158,7 +159,7 @@ static const struct input_method_context_listener input_method_context_listener
        handle_reset,
        handle_content_type,
        handle_invoke_action,
-       handle_commit,
+       handle_commit_state,
        handle_preferred_language
 };
 
@@ -285,8 +286,7 @@ static const struct wl_keyboard_listener input_method_keyboard_listener = {
 static void
 input_method_activate(void *data,
                      struct input_method *input_method,
-                     struct input_method_context *context,
-                     uint32_t serial)
+                     struct input_method_context *context)
 {
        struct simple_im *keyboard = data;
 
@@ -295,7 +295,7 @@ input_method_activate(void *data,
 
        keyboard->compose_state = state_normal;
 
-       keyboard->serial = serial;
+       keyboard->serial = 0;
 
        keyboard->context = context;
        input_method_context_add_listener(context,
@@ -396,7 +396,7 @@ simple_im_key_handler(struct simple_im *keyboard,
 
                for (i = 0; i < sizeof(ignore_keys_on_compose) / sizeof(ignore_keys_on_compose[0]); i++) {
                        if (sym == ignore_keys_on_compose[i]) {
-                               input_method_context_key(context, serial, time, key, state);
+                               input_method_context_key(context, keyboard->serial, time, key, state);
                                return;
                        }
                }
@@ -412,13 +412,11 @@ simple_im_key_handler(struct simple_im *keyboard,
                if (cs) {
                        if (cs->keys[i + 1] == 0) {
                                input_method_context_preedit_cursor(keyboard->context,
-                                                                   keyboard->serial,
                                                                    0);
                                input_method_context_preedit_string(keyboard->context,
                                                                    keyboard->serial,
                                                                    "", "");
                                input_method_context_cursor_position(keyboard->context,
-                                                                    keyboard->serial,
                                                                     0, 0);
                                input_method_context_commit_string(keyboard->context,
                                                                   keyboard->serial,
@@ -432,7 +430,6 @@ simple_im_key_handler(struct simple_im *keyboard,
                                }
 
                                input_method_context_preedit_cursor(keyboard->context,
-                                                                   keyboard->serial,
                                                                    strlen(text));
                                input_method_context_preedit_string(keyboard->context,
                                                                    keyboard->serial,
@@ -446,13 +443,11 @@ simple_im_key_handler(struct simple_im *keyboard,
                                idx += xkb_keysym_to_utf8(keyboard->compose_seq.keys[j], text + idx, sizeof(text) - idx);
                        }
                        input_method_context_preedit_cursor(keyboard->context,
-                                                           keyboard->serial,
                                                            0);
                        input_method_context_preedit_string(keyboard->context,
                                                            keyboard->serial,
                                                            "", "");
                        input_method_context_cursor_position(keyboard->context,
-                                                            keyboard->serial,
                                                             0, 0);
                        input_method_context_commit_string(keyboard->context,
                                                           keyboard->serial,
@@ -471,7 +466,6 @@ simple_im_key_handler(struct simple_im *keyboard,
                return;
 
        input_method_context_cursor_position(keyboard->context,
-                                            keyboard->serial,
                                             0, 0);
        input_method_context_commit_string(keyboard->context,
                                           keyboard->serial,
index d9ae4a9..dd905c2 100644 (file)
       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.
+
+      Serials are used to synchronize the state between the text input and
+      an input method. New serials are sent by the text input in the
+      commit_state request and are used by the input method to indicate
+      the known text input state in events like preedit_string, commit_string,
+      and keysym. The text input can then ignore events from the input method
+      which are based on an outdated state (for example after a reset).
     </description>
     <request name="destroy" type="destructor"/>
     <request name="commit_string">
@@ -63,7 +70,6 @@
 
         This request should be sent before sending preedit_string request.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="uint"/>
       <arg name="length" type="uint"/>
       <arg name="style" type="uint"/>
 
         This request should be sent before sending preedit_string request.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
     </request>
     <request name="delete_surrounding_text">
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
       <arg name="length" type="uint"/>
     </request>
     <request name="cursor_position">
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
       <arg name="anchor" type="int"/>
     </request>
       <arg name="anchor" type="uint"/>
     </event>
     <event name="reset">
-      <arg name="serial" type="uint"/>
     </event>
     <event name="content_type">
       <arg name="hint" type="uint"/>
       <arg name="button" type="uint"/>
       <arg name="index" type="uint"/>
     </event>
-    <event name="commit"/>
+    <event name="commit_state">
+      <arg name="serial" type="uint"/>
+    </event>
     <event name="preferred_language">
       <arg name="language" type="string"/>
     </event>
         which allows communication with the text model.
       </description>
       <arg name="id" type="new_id" interface="input_method_context"/>
-      <arg name="serial" type="uint"/>
     </event>
     <event name="deactivate">
       <description summary="activate event">
index 02c5041..58a6ab5 100644 (file)
@@ -2,7 +2,7 @@
 <protocol name="text">
 
   <copyright>
-    Copyright © 2012 Intel Corporation
+    Copyright © 2012, 2013 Intel Corporation
 
     Permission to use, copy, modify, distribute, and sell this
     software and its documentation for any purpose is hereby granted
       the pre-edit and commit events. Using this interface removes the need
       for applications to directly process hardware key events and compose text
       out of them.
+
+      Serials are used to synchronize the state between the text input and
+      an input method. New serials are sent by the text input in the
+      commit_state request and are used by the input method to indicate
+      the known text input state in events like preedit_string, commit_string,
+      and keysym. The text input can then ignore events from the input method
+      which are based on an outdated state (for example after a reset).
     </description>
     <request name="activate">
       <description summary="request activation">
@@ -48,7 +55,6 @@
         text-input object and tracked for focus lost. The enter event
         is emitted on successful activation.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="seat" type="object" interface="wl_seat"/>
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
@@ -76,7 +82,6 @@
         reset, for example after the text was changed outside of the normal
         input method flow.
       </description>
-      <arg name="serial" type="uint"/>
     </request>
     <request name="set_surrounding_text">
       <description summary="sets the surrounding text">
       <arg name="language" type="string"/>
     </request>
     <request name="commit_state">
+      <arg name="serial" type="uint" summary="used to identify the known state"/>
     </request>
     <request name="invoke_action">
       <arg name="button" type="uint"/>
         The commit text can be used to replace the preedit text on reset
         (for example on unfocus).
       </description>
-      <arg name="serial" type="uint"/>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
       <arg name="text" type="string"/>
       <arg name="commit" type="string"/>
     </event>
         This event should be handled as part of a following preedit_string
         event.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="uint"/>
       <arg name="length" type="uint"/>
       <arg name="style" type="uint"/>
         This event should be handled as part of a following preedit_string
         event.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
     </event>
     <event name="commit_string">
 
         Any previously set composing text should be removed.
       </description>
-      <arg name="serial" type="uint"/>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
       <arg name="text" type="string"/>
     </event>
     <event name="cursor_position">
         Notify when the cursor or anchor position should be modified. It
         should take effect after the next commit_string event.
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
       <arg name="anchor" type="int"/>
     </event>
         deleted. Index is relative to the current cursor (as byte index).
         Length is the length of deleted text (in bytes).
       </description>
-      <arg name="serial" type="uint"/>
       <arg name="index" type="int"/>
       <arg name="length" type="uint"/>
     </event>
         wl_keyboard key_state. Modifiers are a mask for effective modifiers
         (where the modifier indices are set by the modifiers_map event)
       </description>
-      <arg name="serial" type="uint"/>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
       <arg name="time" type="uint"/>
       <arg name="sym" type="uint"/>
       <arg name="state" type="uint"/>
         Sets the language of the input text. The "language" argument is a RFC-3066 
         format language tag.
       </description>
-      <arg name="serial" type="uint"/>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
       <arg name="language" type="string"/>
     </event>
     <enum name="text_direction">
         editor when there is no input yet done and making sure neutral
         direction text is laid out properly.
       </description>
-      <arg name="serial" type="uint"/>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
       <arg name="direction" type="uint"/>
     </event>
   </interface>
index 53aa92c..39439dd 100644 (file)
@@ -98,8 +98,7 @@ struct text_backend {
 };
 
 static void input_method_context_create(struct text_input *model,
-                                       struct input_method *input_method,
-                                       uint32_t serial);
+                                       struct input_method *input_method);
 static void input_method_context_end_keyboard_grab(struct input_method_context *context);
 
 static void input_method_init_seat(struct weston_seat *seat);
@@ -161,7 +160,6 @@ text_input_set_surrounding_text(struct wl_client *client,
 static void
 text_input_activate(struct wl_client *client,
                    struct wl_resource *resource,
-                   uint32_t serial,
                    struct wl_resource *seat,
                    struct wl_resource *surface)
 {
@@ -185,7 +183,7 @@ text_input_activate(struct wl_client *client,
 
        text_input->surface = surface->data;
 
-       input_method_context_create(text_input, input_method, serial);
+       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);
@@ -209,8 +207,7 @@ text_input_deactivate(struct wl_client *client,
 
 static void
 text_input_reset(struct wl_client *client,
-                struct wl_resource *resource,
-                uint32_t serial)
+                struct wl_resource *resource)
 {
        struct text_input *text_input = resource->data;
        struct input_method *input_method, *next;
@@ -218,7 +215,7 @@ text_input_reset(struct wl_client *client,
        wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
                if (!input_method->context)
                        continue;
-               input_method_context_send_reset(&input_method->context->resource, serial);
+               input_method_context_send_reset(&input_method->context->resource);
        }
 }
 
@@ -275,7 +272,8 @@ text_input_invoke_action(struct wl_client *client,
 
 static void
 text_input_commit_state(struct wl_client *client,
-                       struct wl_resource *resource)
+                       struct wl_resource *resource,
+                       uint32_t serial)
 {
        struct text_input *text_input = resource->data;
        struct input_method *input_method, *next;
@@ -283,7 +281,7 @@ text_input_commit_state(struct wl_client *client,
        wl_list_for_each_safe(input_method, next, &text_input->input_methods, link) {
                if (!input_method->context)
                        continue;
-               input_method_context_send_commit(&input_method->context->resource);
+               input_method_context_send_commit_state(&input_method->context->resource, serial);
        }
 }
 
@@ -451,49 +449,45 @@ input_method_context_preedit_string(struct wl_client *client,
 static void
 input_method_context_preedit_styling(struct wl_client *client,
                                     struct wl_resource *resource,
-                                    uint32_t serial,
                                     uint32_t index,
                                     uint32_t length,
                                     uint32_t style)
 {
        struct input_method_context *context = resource->data;
 
-       text_input_send_preedit_styling(&context->model->resource, serial, index, length, style);
+       text_input_send_preedit_styling(&context->model->resource, index, length, style);
 }
 
 static void
 input_method_context_preedit_cursor(struct wl_client *client,
                                    struct wl_resource *resource,
-                                   uint32_t serial,
                                    int32_t cursor)
 {
        struct input_method_context *context = resource->data;
 
-       text_input_send_preedit_cursor(&context->model->resource, serial, cursor);
+       text_input_send_preedit_cursor(&context->model->resource, cursor);
 }
 
 static void
 input_method_context_delete_surrounding_text(struct wl_client *client,
                                             struct wl_resource *resource,
-                                            uint32_t serial,
                                             int32_t index,
                                             uint32_t length)
 {
        struct input_method_context *context = resource->data;
 
-       text_input_send_delete_surrounding_text(&context->model->resource, serial, index, length);
+       text_input_send_delete_surrounding_text(&context->model->resource, index, length);
 }
 
 static void
 input_method_context_cursor_position(struct wl_client *client,
                                     struct wl_resource *resource,
-                                    uint32_t serial,
                                     int32_t index,
                                     int32_t anchor)
 {
        struct input_method_context *context = resource->data;
 
-       text_input_send_cursor_position(&context->model->resource, serial, index, anchor);
+       text_input_send_cursor_position(&context->model->resource, index, anchor);
 }
 
 static void
@@ -687,8 +681,7 @@ destroy_input_method_context(struct wl_resource *resource)
 
 static void
 input_method_context_create(struct text_input *model,
-                           struct input_method *input_method,
-                           uint32_t serial)
+                           struct input_method *input_method)
 {
        struct input_method_context *context;
 
@@ -713,7 +706,7 @@ input_method_context_create(struct text_input *model,
 
        wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
 
-       input_method_send_activate(input_method->input_method_binding, &context->resource, serial);
+       input_method_send_activate(input_method->input_method_binding, &context->resource);
 }
 
 static void
index 1feae66..d8ffc38 100644 (file)
@@ -51,7 +51,6 @@ text_input_preedit_string(void *data,
 static void
 text_input_delete_surrounding_text(void *data,
                                   struct text_input *text_input,
-                                  uint32_t serial,
                                   int32_t index,
                                   uint32_t length)
 {
@@ -60,7 +59,6 @@ text_input_delete_surrounding_text(void *data,
 static void
 text_input_cursor_position(void *data,
                           struct text_input *text_input,
-                          uint32_t serial,
                           int32_t index,
                           int32_t anchor)
 {
@@ -69,7 +67,6 @@ text_input_cursor_position(void *data,
 static void
 text_input_preedit_styling(void *data,
                           struct text_input *text_input,
-                          uint32_t serial,
                           uint32_t index,
                           uint32_t length,
                           uint32_t style)
@@ -79,7 +76,6 @@ text_input_preedit_styling(void *data,
 static void
 text_input_preedit_cursor(void *data,
                          struct text_input *text_input,
-                         uint32_t serial,
                          int32_t index)
 {
 }
@@ -195,7 +191,7 @@ TEST(text_test)
        assert(client->input->keyboard->focus == client->surface);
 
        /* Activate test model and make sure we get enter event. */
-       text_input_activate(text_input, 0, client->input->wl_seat,
+       text_input_activate(text_input, client->input->wl_seat,
                            client->surface->wl_surface);
        client_roundtrip(client);
        assert(state.activated == 1 && state.deactivated == 0);
@@ -206,7 +202,7 @@ TEST(text_test)
        assert(state.activated == 1 && state.deactivated == 1);
 
        /* Activate test model again. */
-       text_input_activate(text_input, 0, client->input->wl_seat,
+       text_input_activate(text_input, client->input->wl_seat,
                            client->surface->wl_surface);
        client_roundtrip(client);
        assert(state.activated == 2 && state.deactivated == 1);