[gtk/matthiasc/for-master] imcontext: Fixes to the state machine
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/for-master] imcontext: Fixes to the state machine
- Date: Wed, 24 Feb 2021 18:34:25 +0000 (UTC)
commit 55f871c19375e8a6839eb59d984324f1ff6ebfc4
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Feb 24 13:31:31 2021 -0500
imcontext: Fixes to the state machine
It turns out that we we were sometimes emitting
preedit-end multiple times, and sometimes not at
all. Same for preedit-start. To fix this up, introduce
a in_compose_sequence flag, maintain it, and use it
in the right places.
After these changes, both
C-S-u 1 2 3 Enter
Compose a e
generate the right signals:
preedit-start, preedit-changed,..., preedit-end, commit
gtk/gtkimcontextsimple.c | 232 +++++++++++++++++++++++++++--------------------
1 file changed, 133 insertions(+), 99 deletions(-)
---
diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
index 86e133fc86..f2a08e2346 100644
--- a/gtk/gtkimcontextsimple.c
+++ b/gtk/gtkimcontextsimple.c
@@ -66,6 +66,7 @@ struct _GtkIMContextSimplePrivate
int tentative_match_len;
guint in_hex_sequence : 1;
+ guint in_compose_sequence : 1;
guint modifiers_dropped : 1;
};
@@ -309,13 +310,21 @@ gtk_im_context_simple_commit_string (GtkIMContextSimple *context_simple,
const char *str)
{
GtkIMContextSimplePrivate *priv = context_simple->priv;
- priv->in_hex_sequence = FALSE;
- g_string_set_size (priv->tentative_match, 0);
- priv->tentative_match_len = 0;
- priv->compose_buffer[0] = 0;
- g_signal_emit_by_name (context_simple, "preedit-changed");
- g_signal_emit_by_name (context_simple, "preedit-end");
+ if (priv->in_hex_sequence ||
+ priv->tentative_match_len > 0 ||
+ priv->compose_buffer[0] != 0)
+ {
+ g_string_set_size (priv->tentative_match, 0);
+ priv->tentative_match_len = 0;
+ priv->in_hex_sequence = FALSE;
+ priv->in_compose_sequence = FALSE;
+ priv->compose_buffer[0] = 0;
+
+ g_signal_emit_by_name (context_simple, "preedit-changed");
+ g_signal_emit_by_name (context_simple, "preedit-end");
+ }
+
g_signal_emit_by_name (context_simple, "commit", str);
}
@@ -432,6 +441,8 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
context = GTK_IM_CONTEXT (context_simple);
+ priv->in_compose_sequence = FALSE;
+
/* No compose sequences found, check first if we have a partial
* match pending.
*/
@@ -736,7 +747,6 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
return TRUE;
}
- /* Then, check for compose sequences */
if (priv->in_hex_sequence)
{
if (hex_keyval && n_compose < 6)
@@ -779,6 +789,8 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
char *str = g_strdup (priv->tentative_match->str);
gtk_im_context_simple_commit_string (context_simple, str);
g_free (str);
+
+ return TRUE;
}
else
{
@@ -801,7 +813,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
return TRUE;
}
}
- else
+ else /* Then, check for compose sequences */
{
gboolean success = FALSE;
GString *output;
@@ -818,6 +830,12 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
&compose_finish, &compose_match,
output))
{
+ if (!priv->in_compose_sequence)
+ {
+ priv->in_compose_sequence = TRUE;
+ g_signal_emit_by_name (context_simple, "preedit-start");
+ }
+
if (compose_finish)
{
if (compose_match)
@@ -852,6 +870,12 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
&compose_finish, &compose_match,
&output_char))
{
+ if (!priv->in_compose_sequence)
+ {
+ priv->in_compose_sequence = TRUE;
+ g_signal_emit_by_name (context_simple, "preedit-start");
+ }
+
if (compose_finish)
{
if (compose_match)
@@ -873,8 +897,15 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
if (gtk_check_algorithmically (priv->compose_buffer, n_compose, &output_char))
{
+ if (!priv->in_compose_sequence)
+ {
+ priv->in_compose_sequence = TRUE;
+ g_signal_emit_by_name (context_simple, "preedit-start");
+ }
+
if (output_char)
gtk_im_context_simple_commit_char (context_simple, output_char);
+
return TRUE;
}
}
@@ -921,107 +952,110 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
for (i = 0; priv->compose_buffer[i]; i++)
g_string_append_unichar (s, gdk_keyval_to_unicode (priv->compose_buffer[i]));
}
- else if (priv->tentative_match->len > 0 && priv->compose_buffer[0] != 0)
- {
- g_string_append (s, priv->tentative_match->str);
- }
- else
+ else if (priv->in_compose_sequence)
{
- for (i = 0; priv->compose_buffer[i]; i++)
+ if (priv->tentative_match_len > 0 && priv->compose_buffer[0] != 0)
{
- if (priv->compose_buffer[i] == GDK_KEY_Multi_key)
- {
- /* We only show the Compose key visibly when it is the
- * only glyph in the preedit, or when it occurs in the
- * middle of the sequence. Sadly, the official character,
- * U+2384, COMPOSITION SYMBOL, is bit too distracting, so
- * we use U+00B7, MIDDLE DOT.
- */
- if (priv->compose_buffer[1] == 0 || i > 0)
- g_string_append (s, "·");
- }
- else
+ g_string_append (s, priv->tentative_match->str);
+ }
+ else
+ {
+ for (i = 0; priv->compose_buffer[i]; i++)
{
- gunichar ch;
- gboolean need_space;
-
- if (GDK_KEY_dead_grave <= priv->compose_buffer[i] && priv->compose_buffer[i] <=
GDK_KEY_dead_greek)
+ if (priv->compose_buffer[i] == GDK_KEY_Multi_key)
{
- /* Sadly, not all the dead keysyms have spacing mark equivalents
- * in Unicode. For those that don't, we use space + the non-spacing
- * mark as an approximation
+ /* We only show the Compose key visibly when it is the
+ * only glyph in the preedit, or when it occurs in the
+ * middle of the sequence. Sadly, the official character,
+ * U+2384, COMPOSITION SYMBOL, is bit too distracting, so
+ * we use U+00B7, MIDDLE DOT.
*/
- switch (priv->compose_buffer[i])
+ if (priv->compose_buffer[1] == 0 || i > 0)
+ g_string_append (s, "·");
+ }
+ else
+ {
+ gunichar ch;
+ gboolean need_space;
+
+ if (GDK_KEY_dead_grave <= priv->compose_buffer[i] && priv->compose_buffer[i] <=
GDK_KEY_dead_greek)
{
-#define CASE(keysym, unicode, sp) \
- case GDK_KEY_dead_##keysym: ch = unicode; need_space = sp; break
-
- CASE (grave, 0x60, 0);
- CASE (acute, 0xb4, 0);
- CASE (circumflex, 0x5e, 0);
- CASE (tilde, 0x7e, 0);
- CASE (macron, 0xaf, 0);
- CASE (breve, 0x2d8, 0);
- CASE (abovedot, 0x307, 1);
- CASE (diaeresis, 0xa8, 0);
- CASE (abovering, 0x2da, 0);
- CASE (hook, 0x2c0, 0);
- CASE (doubleacute, 0x2dd, 0);
- CASE (caron, 0x2c7, 0);
- CASE (cedilla, 0xb8, 0);
- CASE (ogonek, 0x2db, 0);
- CASE (iota, 0x37a, 0);
- CASE (voiced_sound, 0x3099, 1);
- CASE (semivoiced_sound, 0x309a, 1);
- CASE (belowdot, 0x323, 1);
- CASE (horn, 0x31b, 1);
- CASE (stroke, 0x335, 1);
- CASE (abovecomma, 0x2bc, 0);
- CASE (abovereversedcomma, 0x2bd, 1);
- CASE (doublegrave, 0x30f, 1);
- CASE (belowring, 0x2f3, 0);
- CASE (belowmacron, 0x2cd, 0);
- CASE (belowcircumflex, 0x32d, 1);
- CASE (belowtilde, 0x330, 1);
- CASE (belowbreve, 0x32e, 1);
- CASE (belowdiaeresis, 0x324, 1);
- CASE (invertedbreve, 0x32f, 1);
- CASE (belowcomma, 0x326, 1);
- CASE (lowline, 0x5f, 0);
- CASE (aboveverticalline, 0x2c8, 0);
- CASE (belowverticalline, 0x2cc, 0);
- CASE (longsolidusoverlay, 0x338, 1);
- CASE (a, 0x363, 1);
- CASE (A, 0x363, 1);
- CASE (e, 0x364, 1);
- CASE (E, 0x364, 1);
- CASE (i, 0x365, 1);
- CASE (I, 0x365, 1);
- CASE (o, 0x366, 1);
- CASE (O, 0x366, 1);
- CASE (u, 0x367, 1);
- CASE (U, 0x367, 1);
- CASE (small_schwa, 0x1dea, 1);
- CASE (capital_schwa, 0x1dea, 1);
-#undef CASE
- default:
- need_space = FALSE;
- ch = gdk_keyval_to_unicode (priv->compose_buffer[i]);
- break;
+ /* Sadly, not all the dead keysyms have spacing mark equivalents
+ * in Unicode. For those that don't, we use space + the non-spacing
+ * mark as an approximation
+ */
+ switch (priv->compose_buffer[i])
+ {
+ #define CASE(keysym, unicode, sp) \
+ case GDK_KEY_dead_##keysym: ch = unicode; need_space = sp; break
+
+ CASE (grave, 0x60, 0);
+ CASE (acute, 0xb4, 0);
+ CASE (circumflex, 0x5e, 0);
+ CASE (tilde, 0x7e, 0);
+ CASE (macron, 0xaf, 0);
+ CASE (breve, 0x2d8, 0);
+ CASE (abovedot, 0x307, 1);
+ CASE (diaeresis, 0xa8, 0);
+ CASE (abovering, 0x2da, 0);
+ CASE (hook, 0x2c0, 0);
+ CASE (doubleacute, 0x2dd, 0);
+ CASE (caron, 0x2c7, 0);
+ CASE (cedilla, 0xb8, 0);
+ CASE (ogonek, 0x2db, 0);
+ CASE (iota, 0x37a, 0);
+ CASE (voiced_sound, 0x3099, 1);
+ CASE (semivoiced_sound, 0x309a, 1);
+ CASE (belowdot, 0x323, 1);
+ CASE (horn, 0x31b, 1);
+ CASE (stroke, 0x335, 1);
+ CASE (abovecomma, 0x2bc, 0);
+ CASE (abovereversedcomma, 0x2bd, 1);
+ CASE (doublegrave, 0x30f, 1);
+ CASE (belowring, 0x2f3, 0);
+ CASE (belowmacron, 0x2cd, 0);
+ CASE (belowcircumflex, 0x32d, 1);
+ CASE (belowtilde, 0x330, 1);
+ CASE (belowbreve, 0x32e, 1);
+ CASE (belowdiaeresis, 0x324, 1);
+ CASE (invertedbreve, 0x32f, 1);
+ CASE (belowcomma, 0x326, 1);
+ CASE (lowline, 0x5f, 0);
+ CASE (aboveverticalline, 0x2c8, 0);
+ CASE (belowverticalline, 0x2cc, 0);
+ CASE (longsolidusoverlay, 0x338, 1);
+ CASE (a, 0x363, 1);
+ CASE (A, 0x363, 1);
+ CASE (e, 0x364, 1);
+ CASE (E, 0x364, 1);
+ CASE (i, 0x365, 1);
+ CASE (I, 0x365, 1);
+ CASE (o, 0x366, 1);
+ CASE (O, 0x366, 1);
+ CASE (u, 0x367, 1);
+ CASE (U, 0x367, 1);
+ CASE (small_schwa, 0x1dea, 1);
+ CASE (capital_schwa, 0x1dea, 1);
+ #undef CASE
+ default:
+ need_space = FALSE;
+ ch = gdk_keyval_to_unicode (priv->compose_buffer[i]);
+ break;
+ }
+ if (ch)
+ {
+ if (need_space)
+ g_string_append_c (s, ' ');
+ g_string_append_unichar (s, ch);
+ }
}
- if (ch)
+ else
{
- if (need_space)
- g_string_append_c (s, ' ');
- g_string_append_unichar (s, ch);
+ ch = gdk_keyval_to_unicode (priv->compose_buffer[i]);
+ if (ch)
+ g_string_append_unichar (s, ch);
}
}
- else
- {
- ch = gdk_keyval_to_unicode (priv->compose_buffer[i]);
- if (ch)
- g_string_append_unichar (s, ch);
- }
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]