[PATCH 1/5] text: Fix serials handling and use Unicode offsets
Jan Arne Petersen
jpetersen at openismus.com
Mon Apr 15 04:37:15 PDT 2013
From: Jan Arne Petersen <jpetersen at openismus.com>
Simplify the serial handling and document it better.
Also use Unicode character offsets instead of byte offsets.
Signed-off-by: Jan Arne Petersen <jpetersen at openismus.com>
---
clients/editor.c | 241 ++++++++++++++++++++++++---------------------
clients/keyboard.c | 42 +++-----
clients/weston-simple-im.c | 28 +++---
protocol/input-method.xml | 45 +++++----
protocol/text.xml | 77 +++++++++------
src/input-panel.c | 9 --
src/text-backend.c | 33 +++----
tests/text-test.c | 8 +-
8 files changed, 237 insertions(+), 246 deletions(-)
diff --git a/clients/editor.c b/clients/editor.c
index e61eda0..84f24e9 100644
--- a/clients/editor.c
+++ b/clients/editor.c
@@ -56,6 +56,8 @@ struct text_entry {
struct {
int32_t cursor;
int32_t anchor;
+ uint32_t delete_index;
+ uint32_t delete_length;
} pending_commit;
struct text_input *text_input;
PangoLayout *layout;
@@ -63,6 +65,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;
@@ -79,24 +82,6 @@ struct editor {
};
static const char *
-utf8_start_char(const char *text, const char *p)
-{
- for (; p >= text; --p) {
- if ((*p & 0xc0) != 0x80)
- return p;
- }
- return NULL;
-}
-
-static const char *
-utf8_prev_char(const char *text, const char *p)
-{
- if (p > text)
- return utf8_start_char(text, --p);
- return NULL;
-}
-
-static const char *
utf8_end_char(const char *p)
{
while ((*p & 0xc0) == 0x80)
@@ -112,6 +97,39 @@ utf8_next_char(const char *p)
return NULL;
}
+static uint32_t
+utf8_offset_to_byte_offset(const char *p,
+ uint32_t offset)
+{
+ const char *q = p;
+ while (offset--) {
+ q = utf8_next_char(q);
+ }
+
+ return q - p;
+}
+
+static uint32_t
+utf8_pointer_to_offset(const char *s,
+ const char *p)
+{
+ uint32_t offset;
+ for (offset = 0; s < p; offset++) {
+ s = utf8_next_char(s);
+ }
+ return offset;
+}
+
+static uint32_t
+utf8_characters(const char *p)
+{
+ uint32_t offset;
+ for (offset = 0; *p != 0; offset++) {
+ p = utf8_next_char(p);
+ }
+ return offset;
+}
+
static void text_entry_redraw_handler(struct widget *widget, void *data);
static void text_entry_button_handler(struct widget *widget,
struct input *input, uint32_t time,
@@ -138,9 +156,22 @@ 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);
+
+ if (entry->pending_commit.delete_length) {
+ text_entry_delete_text(entry,
+ entry->pending_commit.delete_index,
+ entry->pending_commit.delete_length);
+ }
+
text_entry_insert_at_cursor(entry, text,
entry->pending_commit.cursor,
entry->pending_commit.anchor);
@@ -175,39 +206,33 @@ 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)
{
struct text_entry *entry = data;
- uint32_t cursor_index = index + entry->cursor;
- const char *start, *end;
+ uint32_t text_length;
+
+ entry->pending_commit.delete_index = entry->cursor + index;
+ entry->pending_commit.delete_length = length;
- if (cursor_index > strlen(entry->text)) {
+ text_length = utf8_characters(entry->text);
+
+ if (entry->pending_commit.delete_index > text_length) {
fprintf(stderr, "Invalid cursor index %d\n", index);
+ entry->pending_commit.delete_length = 0;
return;
}
- if (cursor_index + length > strlen(entry->text)) {
+ if (entry->pending_commit.delete_index + length > text_length) {
fprintf(stderr, "Invalid length %d\n", length);
+ entry->pending_commit.delete_length = 0;
return;
}
-
- if (length == 0)
- return;
-
- start = utf8_start_char(entry->text, entry->text + cursor_index);
- end = utf8_end_char(entry->text + cursor_index + length);
-
- text_entry_delete_text(entry,
- start - entry->text,
- end - start);
}
static void
text_input_cursor_position(void *data,
struct text_input *text_input,
- uint32_t serial,
int32_t index,
int32_t anchor)
{
@@ -220,7 +245,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)
@@ -257,14 +281,14 @@ text_input_preedit_styling(void *data,
}
if (attr1) {
- attr1->start_index = entry->cursor + index;
- attr1->end_index = entry->cursor + index + length;
+ attr1->start_index = utf8_offset_to_byte_offset(entry->text, entry->cursor + index);
+ attr1->end_index = utf8_offset_to_byte_offset(entry->text, entry->cursor + index + length);
pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
}
if (attr2) {
- attr2->start_index = entry->cursor + index;
- attr2->end_index = entry->cursor + index + length;
+ attr2->start_index = utf8_offset_to_byte_offset(entry->text, entry->cursor + index);
+ attr2->end_index = utf8_offset_to_byte_offset(entry->text, entry->cursor + index + length);
pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
}
}
@@ -272,7 +296,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;
@@ -302,7 +325,6 @@ text_input_keysym(void *data,
struct text_entry *entry = data;
const char *state_label = "release";
const char *key_label = "Unknown";
- const char *new_char;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
state_label = "pressed";
@@ -314,37 +336,26 @@ text_input_keysym(void *data,
return;
if (key == XKB_KEY_Left)
- new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
+ entry->cursor = entry->cursor > 0 ? entry->cursor - 1 : entry->cursor;
else
- new_char = utf8_next_char(entry->text + entry->cursor);
+ entry->cursor = entry->cursor < utf8_characters(entry->text) ? entry->cursor + 1 : entry->cursor;
- if (new_char != NULL) {
- entry->cursor = new_char - entry->text;
- if (!(modifiers & entry->keysym.shift_mask))
- entry->anchor = entry->cursor;
- widget_schedule_redraw(entry->widget);
- }
+ if (!(modifiers & entry->keysym.shift_mask))
+ entry->anchor = entry->cursor;
+ widget_schedule_redraw(entry->widget);
return;
}
if (key == XKB_KEY_BackSpace) {
- const char *start, *end;
-
if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
return;
text_entry_commit_and_reset(entry);
- start = utf8_prev_char(entry->text, entry->text + entry->cursor);
-
- if (start == NULL)
- return;
-
- end = utf8_end_char(entry->text + entry->cursor);
text_entry_delete_text(entry,
- start - entry->text,
- end - start);
+ entry->cursor - 1,
+ 1);
return;
}
@@ -374,6 +385,9 @@ text_input_enter(void *data,
entry->active = 1;
+ text_entry_update(entry);
+ entry->reset_serial = entry->serial;
+
widget_schedule_redraw(entry->widget);
}
@@ -461,7 +475,7 @@ text_entry_create(struct editor *editor, const char *text)
entry->window = editor->window;
entry->text = strdup(text);
entry->active = 0;
- entry->cursor = strlen(text);
+ entry->cursor = utf8_characters(text);
entry->anchor = entry->cursor;
entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
text_input_add_listener(entry->text_input, &text_input_listener, entry);
@@ -552,10 +566,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);
}
@@ -574,15 +585,16 @@ text_entry_update_layout(struct text_entry *entry)
char *text;
PangoAttrList *attr_list;
- assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
- (entry->preedit.text ? strlen(entry->preedit.text) : 0));
+ assert(entry->cursor <= (utf8_characters(entry->text) +
+ (entry->preedit.text ? utf8_characters(entry->preedit.text) : 0)));
if (entry->preedit.text) {
+ uint32_t old_cursor = utf8_offset_to_byte_offset(entry->text, entry->cursor);
text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
- strncpy(text, entry->text, entry->cursor);
- strcpy(text + entry->cursor, entry->preedit.text);
- strcpy(text + entry->cursor + strlen(entry->preedit.text),
- entry->text + entry->cursor);
+ strncpy(text, entry->text, old_cursor);
+ strcpy(text + old_cursor, entry->preedit.text);
+ strcpy(text + old_cursor + strlen(entry->preedit.text),
+ entry->text + old_cursor);
} else {
text = strdup(entry->text);
}
@@ -592,6 +604,9 @@ text_entry_update_layout(struct text_entry *entry)
int end_index = MAX(entry->cursor, entry->anchor);
PangoAttribute *attr;
+ start_index = utf8_offset_to_byte_offset(entry->text, start_index);
+ end_index = utf8_offset_to_byte_offset(entry->text, end_index);
+
attr_list = pango_attr_list_copy(entry->preedit.attr_list);
if (!attr_list)
@@ -617,7 +632,7 @@ text_entry_update_layout(struct text_entry *entry)
attr_list = pango_attr_list_new();
attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
- attr->start_index = entry->cursor;
+ attr->start_index = utf8_offset_to_byte_offset(entry->text, entry->cursor);
attr->end_index = entry->cursor + strlen(entry->preedit.text);
pango_attr_list_insert(attr_list, attr);
}
@@ -653,7 +668,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
@@ -662,19 +677,21 @@ text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
{
char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
- strncpy(new_text, entry->text, entry->cursor);
- strcpy(new_text + entry->cursor, text);
- strcpy(new_text + entry->cursor + strlen(text),
- entry->text + entry->cursor);
+ uint32_t old_cursor = utf8_offset_to_byte_offset(entry->text, entry->cursor);
+
+ strncpy(new_text, entry->text, old_cursor);
+ strcpy(new_text + old_cursor, text);
+ strcpy(new_text + old_cursor + strlen(text),
+ entry->text + old_cursor);
free(entry->text);
entry->text = new_text;
if (anchor >= 0)
- entry->anchor = entry->cursor + strlen(text) + anchor;
+ entry->anchor = entry->cursor + utf8_characters(text) + anchor;
else
entry->anchor = entry->cursor + 1 + anchor;
if (cursor >= 0)
- entry->cursor += strlen(text) + cursor;
+ entry->cursor += utf8_characters(text) + cursor;
else
entry->cursor += 1 + cursor;
@@ -714,8 +731,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
@@ -754,7 +772,7 @@ text_entry_try_invoke_preedit_action(struct text_entry *entry,
cursor = index + trailing;
if (cursor < entry->cursor ||
- cursor > entry->cursor + strlen(entry->preedit.text)) {
+ cursor > entry->cursor + utf8_characters(entry->preedit.text)) {
return 0;
}
@@ -777,7 +795,7 @@ text_entry_set_cursor_position(struct text_entry *entry,
pango_layout_xy_to_index(entry->layout,
x * PANGO_SCALE, y * PANGO_SCALE,
&index, &trailing);
- entry->cursor = index + trailing;
+ entry->cursor = utf8_pointer_to_offset(entry->text, entry->text + index + trailing);
text_entry_update_layout(entry);
@@ -795,7 +813,7 @@ text_entry_set_anchor_position(struct text_entry *entry,
pango_layout_xy_to_index(entry->layout,
x * PANGO_SCALE, y * PANGO_SCALE,
&index, &trailing);
- entry->anchor = index + trailing;
+ entry->anchor = utf8_pointer_to_offset(entry->text, entry->text + index + trailing);
text_entry_update_layout(entry);
@@ -808,13 +826,18 @@ static void
text_entry_delete_text(struct text_entry *entry,
uint32_t index, uint32_t length)
{
+ uint32_t s, e;
+
if (entry->cursor > index)
entry->cursor -= length;
entry->anchor = entry->cursor;
- entry->text[index] = '\0';
- strcat(entry->text, entry->text + index + length);
+ s = utf8_offset_to_byte_offset(entry->text, index);
+ e = utf8_offset_to_byte_offset(entry->text, index + length);
+
+ entry->text[s] = '\0';
+ strcat(entry->text, entry->text + e);
text_entry_update_layout(entry);
@@ -843,6 +866,7 @@ text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rect
struct rectangle allocation;
PangoRectangle extents;
PangoRectangle cursor_pos;
+ const char *text;
widget_get_allocation(entry->widget, &allocation);
@@ -854,9 +878,11 @@ text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rect
return;
}
+
+ text = pango_layout_get_text(entry->layout);
pango_layout_get_extents(entry->layout, &extents, NULL);
pango_layout_get_cursor_pos(entry->layout,
- entry->cursor + entry->preedit.cursor,
+ utf8_offset_to_byte_offset(text, entry->cursor + entry->preedit.cursor),
&cursor_pos, NULL);
rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
@@ -870,13 +896,15 @@ text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
{
PangoRectangle extents;
PangoRectangle cursor_pos;
+ const char *text;
if (entry->preedit.text && entry->preedit.cursor < 0)
return;
+ text = pango_layout_get_text(entry->layout);
pango_layout_get_extents(entry->layout, &extents, NULL);
pango_layout_get_cursor_pos(entry->layout,
- entry->cursor + entry->preedit.cursor,
+ utf8_offset_to_byte_offset(text, entry->cursor + entry->preedit.cursor),
&cursor_pos, NULL);
cairo_set_line_width(cr, 1.0);
@@ -1033,7 +1061,6 @@ key_handler(struct window *window,
{
struct editor *editor = data;
struct text_entry *entry;
- const char *start, *end, *new_char;
char text[16];
if (!editor->active_entry)
@@ -1048,39 +1075,24 @@ key_handler(struct window *window,
case XKB_KEY_BackSpace:
text_entry_commit_and_reset(entry);
- start = utf8_prev_char(entry->text, entry->text + entry->cursor);
-
- if (start == NULL)
- break;
-
- end = utf8_end_char(entry->text + entry->cursor);
- text_entry_delete_text(entry,
- start - entry->text,
- end - start);
+ if (entry->cursor > 0)
+ text_entry_delete_text(entry,
+ entry->cursor - 1,
+ 1);
break;
case XKB_KEY_Delete:
text_entry_commit_and_reset(entry);
- start = utf8_start_char(entry->text, entry->text + entry->cursor);
-
- if (start == NULL)
- break;
-
- end = utf8_next_char(start);
-
- if (end == NULL)
- break;
-
- text_entry_delete_text(entry,
- start - entry->text,
- end - start);
+ if (entry->cursor < utf8_characters(entry->text))
+ text_entry_delete_text(entry,
+ entry->cursor,
+ 1);
break;
case XKB_KEY_Left:
text_entry_commit_and_reset(entry);
- new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
- if (new_char != NULL) {
- entry->cursor = new_char - entry->text;
+ if (entry->cursor > 0) {
+ entry->cursor--;
entry->anchor = entry->cursor;
widget_schedule_redraw(entry->widget);
}
@@ -1088,9 +1100,8 @@ key_handler(struct window *window,
case XKB_KEY_Right:
text_entry_commit_and_reset(entry);
- new_char = utf8_next_char(entry->text + entry->cursor);
- if (new_char != NULL) {
- entry->cursor = new_char - entry->text;
+ if (entry->cursor < utf8_characters(entry->text)) {
+ entry->cursor++;
entry->anchor = entry->cursor;
widget_schedule_redraw(entry->widget);
}
diff --git a/clients/keyboard.c b/clients/keyboard.c
index 17fb683..4fc8e73 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -387,15 +387,7 @@ virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
strlen(keyboard->preedit_string) == 0)
return;
- 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,
@@ -412,14 +404,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,8 +439,10 @@ 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);
+ input_method_context_commit_string(keyboard->keyboard->context,
+ keyboard->keyboard->serial,
+ "");
} else {
keyboard->keyboard->preedit_string[strlen(keyboard->keyboard->preedit_string) - 1] = '\0';
virtual_keyboard_send_preedit(keyboard->keyboard, -1);
@@ -579,26 +571,16 @@ 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;
fprintf(stderr, "Reset pre-edit buffer\n");
if (strlen(keyboard->preedit_string)) {
- input_method_context_preedit_cursor(context,
- serial,
- 0);
- input_method_context_preedit_string(context,
- serial,
- "",
- "");
free(keyboard->preedit_string);
keyboard->preedit_string = strdup("");
}
-
- keyboard->serial = serial;
}
static void
@@ -628,12 +610,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 +655,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 +684,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,
@@ -799,8 +783,6 @@ keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard
input_panel_surface_set_toplevel(ips,
output_get_wl_output(output),
INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
-
- fprintf(stderr, "%s, %p\n", __FUNCTION__, output_get_wl_output(output));
}
int
diff --git a/clients/weston-simple-im.c b/clients/weston-simple-im.c
index 9d31e3b..a532003 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 d9ae4a9..d483087 100644
--- a/protocol/input-method.xml
+++ b/protocol/input-method.xml
@@ -33,13 +33,23 @@
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 Unicode
+ characters.
+
+ 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">
<description summary="commit string">
Send the commit string text to the applications text model and
- set the cursor at index (as byte index) relative to the
- beginning of inserted text.
+ set the cursor at index (as Unicode character offset) relative to
+ the beginning of inserted text.
</description>
<arg name="serial" type="uint"/>
<arg name="text" type="string"/>
@@ -57,34 +67,32 @@
<request name="preedit_styling">
<description summary="pre-edit styling">
Sets styling information on composing text. The style is applied for
- length (in bytes) characters from index relative to the beginning of the
- composing text (as byte index). Multiple styles can be applied to a
- composing text.
+ length in Unicode characters from index relative to the beginning of
+ the composing text (as Unicode characters offset). Multiple styles can
+ be applied to a composing text.
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"/>
</request>
<request name="preedit_cursor">
<description summary="pre-edit cursor">
- Sets the cursor position inside the composing text (as byte index)
- relative to the start of the composing text.
+ Sets the cursor position inside the composing text (as Unicode
+ characters offset) relative to the start of the composing text.
+
+ When index is negative no cursor should be displayed.
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>
@@ -137,17 +145,17 @@
<event name="surrounding_text">
<description summary="surrounding text event">
The plain surrounding text around the input position. Cursor is the
- position in bytes within the surrounding text relative to the beginning
- of the text. Anchor is the position in bytes of the selection anchor
- within the surrounding text relative to the beginning of the text. If
- there is no selected text anchor is the same as cursor.
+ position in Unicode characters within the surrounding text relative to
+ the beginning of the text. Anchor is the position in Unicode characters
+ of the selection anchor within the surrounding text relative to the
+ beginning of the text. If there is no selected text anchor is the same
+ as cursor.
</description>
<arg name="text" type="string"/>
<arg name="cursor" type="uint"/>
<arg name="anchor" type="uint"/>
</event>
<event name="reset">
- <arg name="serial" type="uint"/>
</event>
<event name="content_type">
<arg name="hint" type="uint"/>
@@ -157,7 +165,9 @@
<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>
@@ -176,7 +186,6 @@
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">
diff --git a/protocol/text.xml b/protocol/text.xml
index 02c5041..ba372bf 100644
--- a/protocol/text.xml
+++ b/protocol/text.xml
@@ -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
@@ -38,6 +38,16 @@
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.
+
+ Text is generally UTF-8 encoded, indices and lengths are in Unicode
+ characters.
+
+ 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 +58,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,14 +85,14 @@
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">
- Sets the plain surrounding text around the input position. Cursor is the
- byte index within the surrounding text. Anchor is the byte index of the
+ Sets the plain surrounding text around the input position. Text is
+ UTF-8 encoded. Cursor is the Unicode character offset within the
+ surrounding text. Anchor is the Unicode character offset of the
selection anchor within the surrounding text. If there is no selected
- text anchor then it is the same as cursor.
+ text anchor is the same as cursor.
</description>
<arg name="text" type="string"/>
<arg name="cursor" type="uint"/>
@@ -162,6 +171,7 @@
<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"/>
@@ -202,9 +212,12 @@
be removed.
The commit text can be used to replace the preedit text on reset
- (for example on unfocus).
+ (for example on unfocus).
+
+ The text input should also handle all preedit_style and preedit_cursor
+ events occuring directly before preedit_string.
</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>
@@ -221,57 +234,59 @@
<event name="preedit_styling">
<description summary="pre-edit styling">
Sets styling information on composing text. The style is applied for
- length (in bytes) characters from index relative to the beginning of
- the composing text (as byte index). Multiple styles can be applied
- to a composing text.
+ length Unicode characters from index relative to the beginning of
+ the composing text (as Unicode character offset). Multiple styles can
+ be applied to a composing text by sending multiple preedit_styling
+ events.
- This event should be handled as part of a following preedit_string
- event.
+ This event is 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"/>
</event>
<event name="preedit_cursor">
<description summary="pre-edit cursor">
- Sets the cursor position inside the composing text (as byte index)
- relative to the start of the composing text.
+ Sets the cursor position inside the composing text (as Unicode character
+ offset) relative to the start of the composing text. When index is a
+ negative number no cursor is shown.
- This event should be handled as part of a following preedit_string
- event.
+ This event is 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">
<description summary="commit">
Notify when text should be inserted into the editor widget. The text to
commit could be either just a single character after a key press or the
- result of some composing (pre-edit). It also sets the new cursor
- position (as byte index) relative to the beginning of inserted text.
+ result of some composing (pre-edit).
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">
<description summary="set cursor to new position">
- Notify when the cursor or anchor position should be modified. It
- should take effect after the next commit_string event.
+ Notify when the cursor or anchor position should be modified.
+
+ This event should be handled as part of a following commit_string
+ event.
</description>
- <arg name="serial" type="uint"/>
<arg name="index" type="int"/>
<arg name="anchor" type="int"/>
</event>
<event name="delete_surrounding_text">
<description summary="delete surrounding text">
Notify when the text around the current cursor position should be
- deleted. Index is relative to the current cursor (as byte index).
- Length is the length of deleted text (in bytes).
+ deleted.
+
+ Index is relative to the current cursor (in Unicode characters).
+ Length is the length of deleted text (in Unicode characters).
+
+ This event should be handled as part of a following commit_string
+ event.
</description>
- <arg name="serial" type="uint"/>
<arg name="index" type="int"/>
<arg name="length" type="uint"/>
</event>
@@ -284,7 +299,7 @@
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"/>
@@ -295,7 +310,7 @@
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">
@@ -311,7 +326,7 @@
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>
diff --git a/src/input-panel.c b/src/input-panel.c
index 78dfe21..81a82f8 100644
--- a/src/input-panel.c
+++ b/src/input-panel.c
@@ -97,12 +97,6 @@ show_input_panels(struct wl_listener *listener, void *data)
input_panel->text_input.surface = (struct weston_surface*)data;
- fprintf(stderr,
- "%s layer visible: %d input panel visible: %d\n",
- __FUNCTION__,
- input_panel->layer.visible,
- input_panel->showing_input_panels);
-
if (input_panel->showing_input_panels)
return;
@@ -150,7 +144,6 @@ overlay_panel_get_position(struct input_panel_surface *surface,
struct input_panel *input_panel = surface->input_panel;
if (!surface->overlay_panel) {
- fprintf(stderr, "%s: surface is not overlay panel\n", __FUNCTION__);
return;
}
@@ -434,7 +427,6 @@ input_panel_show_layer(struct input_panel *input_panel,
struct weston_layer *next)
{
if (input_panel->layer.visible) {
- fprintf(stderr, "%s - input panel layer is already shown.\n", __FUNCTION__);
return;
}
@@ -458,7 +450,6 @@ WL_EXPORT void
input_panel_hide_layer(struct input_panel *input_panel)
{
if (!input_panel->layer.visible) {
- fprintf(stderr, "%s - input panel layer is already hidden.\n", __FUNCTION__);
return;
}
diff --git a/src/text-backend.c b/src/text-backend.c
index a14e048..e965a0d 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -104,8 +104,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);
@@ -168,7 +167,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)
{
@@ -192,7 +190,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);
@@ -216,8 +214,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;
@@ -225,7 +222,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);
}
}
@@ -282,7 +279,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;
@@ -290,7 +288,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);
}
}
@@ -458,49 +456,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
@@ -694,8 +688,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;
@@ -720,7 +713,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 1feae66..d8ffc38 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);
--
1.8.1.4
More information about the wayland-devel
mailing list