From 00191c7c4a3bb049db95ca1fe612f0ba993cbaf7 Mon Sep 17 00:00:00 2001 From: Jan Arne Petersen Date: Thu, 18 Apr 2013 16:47:33 +0200 Subject: [PATCH] text: Fix serial handling Signed-off-by: Jan Arne Petersen --- clients/editor.c | 24 ++++++++++++++---------- clients/keyboard.c | 23 +++++++++-------------- clients/weston-simple-im.c | 28 +++++++++++----------------- protocol/input-method.xml | 17 ++++++++++------- protocol/text.xml | 26 ++++++++++++++------------ src/text-backend.c | 33 +++++++++++++-------------------- tests/text-test.c | 8 ++------ 7 files changed, 73 insertions(+), 86 deletions(-) diff --git a/clients/editor.c b/clients/editor.c index e61eda04..c40815ac 100644 --- a/clients/editor.c +++ b/clients/editor.c @@ -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 diff --git a/clients/keyboard.c b/clients/keyboard.c index 17fb6837..9dd210af 100644 --- a/clients/keyboard.c +++ b/clients/keyboard.c @@ -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, diff --git a/clients/weston-simple-im.c b/clients/weston-simple-im.c index 9d31e3b0..a5320039 100644 --- a/clients/weston-simple-im.c +++ b/clients/weston-simple-im.c @@ -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, diff --git a/protocol/input-method.xml b/protocol/input-method.xml index d9ae4a92..dd905c2d 100644 --- a/protocol/input-method.xml +++ b/protocol/input-method.xml @@ -33,6 +33,13 @@ 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). @@ -63,7 +70,6 @@ This request should be sent before sending preedit_string request. - @@ -75,16 +81,13 @@ This request should be sent before sending preedit_string request. - - - @@ -147,7 +150,6 @@ - @@ -157,7 +159,9 @@ - + + + @@ -176,7 +180,6 @@ which allows communication with the text model. - diff --git a/protocol/text.xml b/protocol/text.xml index 02c50410..58a6ab53 100644 --- a/protocol/text.xml +++ b/protocol/text.xml @@ -2,7 +2,7 @@ - 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 @@ -38,6 +38,13 @@ 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). @@ -48,7 +55,6 @@ text-input object and tracked for focus lost. The enter event is emitted on successful activation. - @@ -76,7 +82,6 @@ reset, for example after the text was changed outside of the normal input method flow. - @@ -162,6 +167,7 @@ + @@ -204,7 +210,7 @@ The commit text can be used to replace the preedit text on reset (for example on unfocus). - + @@ -228,7 +234,6 @@ This event should be handled as part of a following preedit_string event. - @@ -241,7 +246,6 @@ This event should be handled as part of a following preedit_string event. - @@ -253,7 +257,7 @@ Any previously set composing text should be removed. - + @@ -261,7 +265,6 @@ Notify when the cursor or anchor position should be modified. It should take effect after the next commit_string event. - @@ -271,7 +274,6 @@ deleted. Index is relative to the current cursor (as byte index). Length is the length of deleted text (in bytes). - @@ -284,7 +286,7 @@ wl_keyboard key_state. Modifiers are a mask for effective modifiers (where the modifier indices are set by the modifiers_map event) - + @@ -295,7 +297,7 @@ Sets the language of the input text. The "language" argument is a RFC-3066 format language tag. - + @@ -311,7 +313,7 @@ editor when there is no input yet done and making sure neutral direction text is laid out properly. - + diff --git a/src/text-backend.c b/src/text-backend.c index 53aa92cc..39439dd9 100644 --- a/src/text-backend.c +++ b/src/text-backend.c @@ -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 diff --git a/tests/text-test.c b/tests/text-test.c index 1feae666..d8ffc381 100644 --- a/tests/text-test.c +++ b/tests/text-test.c @@ -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);