mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-02 17:00:19 +00:00
Merge branch 'im-context-work' into 'master'
Some im context work Closes #1004, #186, and #3521 See merge request GNOME/gtk!3143
This commit is contained in:
commit
e9b06b6346
@ -1831,7 +1831,6 @@ GtkIMContextSimple
|
||||
gtk_im_context_simple_new
|
||||
gtk_im_context_simple_add_table
|
||||
gtk_im_context_simple_add_compose_file
|
||||
GTK_MAX_COMPOSE_LEN
|
||||
<SUBSECTION Standard>
|
||||
GTK_IM_CONTEXT_SIMPLE
|
||||
GTK_IS_IM_CONTEXT_SIMPLE
|
||||
|
@ -26,16 +26,17 @@
|
||||
#include "gtkcomposetable.h"
|
||||
#include "gtkimcontextsimple.h"
|
||||
|
||||
#include "gtkimcontextsimpleprivate.h"
|
||||
|
||||
|
||||
#define GTK_COMPOSE_TABLE_MAGIC "GtkComposeTable"
|
||||
#define GTK_COMPOSE_TABLE_VERSION (1)
|
||||
#define GTK_COMPOSE_TABLE_VERSION (2)
|
||||
|
||||
/* Maximum length of sequences we parse */
|
||||
|
||||
#define MAX_COMPOSE_LEN 20
|
||||
|
||||
typedef struct {
|
||||
gunichar *sequence;
|
||||
gunichar value[2];
|
||||
char *comment;
|
||||
gunichar *sequence;
|
||||
char *value;
|
||||
} GtkComposeData;
|
||||
|
||||
|
||||
@ -43,7 +44,7 @@ static void
|
||||
gtk_compose_data_free (GtkComposeData *compose_data)
|
||||
{
|
||||
g_free (compose_data->sequence);
|
||||
g_free (compose_data->comment);
|
||||
g_free (compose_data->value);
|
||||
g_slice_free (GtkComposeData, compose_data);
|
||||
}
|
||||
|
||||
@ -76,58 +77,82 @@ parse_compose_value (GtkComposeData *compose_data,
|
||||
const char *val,
|
||||
const char *line)
|
||||
{
|
||||
char **words = g_strsplit (val, "\"", 3);
|
||||
gunichar uch;
|
||||
char *word;
|
||||
const char *p;
|
||||
gsize len;
|
||||
GString *value;
|
||||
gunichar ch;
|
||||
char *endp;
|
||||
|
||||
if (g_strv_length (words) < 3)
|
||||
len = strlen (val);
|
||||
if (val[0] != '"' || val[len - 1] != '"')
|
||||
{
|
||||
g_warning ("Need to double-quote the value: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
uch = g_utf8_get_char (words[1]);
|
||||
word = g_strndup (val + 1, len - 2);
|
||||
|
||||
if (uch == 0)
|
||||
{
|
||||
g_warning ("Invalid value: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
else if (uch == '\\')
|
||||
{
|
||||
uch = words[1][1];
|
||||
value = g_string_new ("");
|
||||
|
||||
/* The escaped string "\"" is separated with '\\' and '"'. */
|
||||
if (uch == '\0' && words[2][0] == '"')
|
||||
uch = '"';
|
||||
/* The escaped octal */
|
||||
else if (uch >= '0' && uch <= '8')
|
||||
uch = g_ascii_strtoll(words[1] + 1, NULL, 8);
|
||||
/* If we need to handle other escape sequences. */
|
||||
else if (uch != '\\')
|
||||
p = word;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '\\')
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
if (p[1] == '"')
|
||||
{
|
||||
g_string_append_c (value, '"');
|
||||
p += 2;
|
||||
}
|
||||
else if (p[1] == '\\')
|
||||
{
|
||||
g_string_append_c (value, '\\');
|
||||
p += 2;
|
||||
}
|
||||
else if (p[1] >= '0' && p[1] < '8')
|
||||
{
|
||||
ch = g_ascii_strtoll (p + 1, &endp, 8);
|
||||
if (ch == 0)
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
g_string_append_unichar (value, ch);
|
||||
p = endp;
|
||||
}
|
||||
else if (p[1] == 'x' || p[1] == 'X')
|
||||
{
|
||||
ch = g_ascii_strtoll (p + 2, &endp, 16);
|
||||
if (ch == 0)
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
g_string_append_unichar (value, ch);
|
||||
p = endp;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = g_utf8_get_char (p);
|
||||
g_string_append_unichar (value, ch);
|
||||
p = g_utf8_next_char (p);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_utf8_get_char (g_utf8_next_char (words[1])) > 0)
|
||||
{
|
||||
g_warning ("GTK supports to output one char only: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
compose_data->value = g_string_free (value, FALSE);
|
||||
|
||||
compose_data->value[1] = uch;
|
||||
|
||||
if (uch == '"')
|
||||
compose_data->comment = g_strdup (g_strstrip (words[2] + 1));
|
||||
else
|
||||
compose_data->comment = g_strdup (g_strstrip (words[2]));
|
||||
|
||||
g_strfreev (words);
|
||||
g_free (word);
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
g_strfreev (words);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -189,10 +214,10 @@ parse_compose_sequence (GtkComposeData *compose_data,
|
||||
}
|
||||
|
||||
g_strfreev (words);
|
||||
if (0 == n || n > GTK_MAX_COMPOSE_LEN)
|
||||
if (0 == n || n > MAX_COMPOSE_LEN)
|
||||
{
|
||||
g_warning ("The max length of compose sequences is %d: %s",
|
||||
GTK_MAX_COMPOSE_LEN, line);
|
||||
g_warning ("Suspicious compose sequence length (%d). Are you sure this is right?: %s",
|
||||
n, line);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -214,7 +239,10 @@ parse_compose_line (GList **compose_list,
|
||||
return;
|
||||
|
||||
if (g_str_has_prefix (line, "include "))
|
||||
return;
|
||||
{
|
||||
g_warning ("include in Compose files not supported: %s", line);
|
||||
return;
|
||||
}
|
||||
|
||||
components = g_strsplit (line, ":", 2);
|
||||
|
||||
@ -244,6 +272,8 @@ fail:
|
||||
gtk_compose_data_free (compose_data);
|
||||
}
|
||||
|
||||
extern const GtkComposeTableCompact gtk_compose_table_compact;
|
||||
|
||||
static GList *
|
||||
gtk_compose_list_parse_file (const char *compose_file)
|
||||
{
|
||||
@ -279,18 +309,19 @@ gtk_compose_list_check_duplicated (GList *compose_list)
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
static guint16 keysyms[GTK_MAX_COMPOSE_LEN + 1];
|
||||
static guint16 keysyms[MAX_COMPOSE_LEN + 1];
|
||||
int i;
|
||||
int n_compose = 0;
|
||||
gboolean compose_finish;
|
||||
gunichar output_char;
|
||||
char buf[8] = { 0, };
|
||||
|
||||
compose_data = list->data;
|
||||
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
keysyms[i] = 0;
|
||||
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
{
|
||||
gunichar codepoint = compose_data->sequence[i];
|
||||
keysyms[i] = (guint16) codepoint;
|
||||
@ -301,20 +332,21 @@ gtk_compose_list_check_duplicated (GList *compose_list)
|
||||
n_compose++;
|
||||
}
|
||||
|
||||
if (gtk_check_compact_table (>k_compose_table_compact,
|
||||
keysyms,
|
||||
n_compose,
|
||||
&compose_finish,
|
||||
NULL,
|
||||
&output_char) &&
|
||||
if (gtk_compose_table_compact_check (>k_compose_table_compact,
|
||||
keysyms, n_compose,
|
||||
&compose_finish,
|
||||
NULL,
|
||||
&output_char) &&
|
||||
compose_finish)
|
||||
{
|
||||
if (compose_data->value[1] == output_char)
|
||||
g_unichar_to_utf8 (output_char, buf);
|
||||
if (strcmp (compose_data->value, buf) == 0)
|
||||
removed_list = g_list_prepend (removed_list, compose_data);
|
||||
}
|
||||
else if (gtk_check_algorithmically (keysyms, n_compose, &output_char))
|
||||
{
|
||||
if (compose_data->value[1] == output_char)
|
||||
g_unichar_to_utf8 (output_char, buf);
|
||||
if (strcmp (compose_data->value, buf) == 0)
|
||||
removed_list = g_list_prepend (removed_list, compose_data);
|
||||
}
|
||||
}
|
||||
@ -343,7 +375,7 @@ gtk_compose_list_check_uint16 (GList *compose_list)
|
||||
int i;
|
||||
|
||||
compose_data = list->data;
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN; i++)
|
||||
{
|
||||
gunichar codepoint = compose_data->sequence[i];
|
||||
|
||||
@ -384,7 +416,7 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
{
|
||||
codepoint = compose_data->sequence[i];
|
||||
if (codepoint == 0)
|
||||
@ -401,17 +433,6 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
|
||||
if (p_n_index_stride)
|
||||
*p_n_index_stride = max_compose_len + 2;
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
codepoint = compose_data->value[1];
|
||||
if (codepoint > 0xffff)
|
||||
{
|
||||
compose_data->value[0] = codepoint / 0x10000;
|
||||
compose_data->value[1] = codepoint - codepoint / 0x10000 * 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
return compose_list;
|
||||
}
|
||||
|
||||
@ -436,61 +457,6 @@ gtk_compose_data_compare (gpointer a,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_compose_list_print (GList *compose_list,
|
||||
int max_compose_len,
|
||||
int n_index_stride)
|
||||
{
|
||||
GList *list;
|
||||
int i, j;
|
||||
GtkComposeData *compose_data;
|
||||
int total_size = 0;
|
||||
gunichar upper;
|
||||
gunichar lower;
|
||||
const char *comment;
|
||||
const char *keyval;
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
g_printf (" ");
|
||||
|
||||
for (i = 0; i < max_compose_len; i++)
|
||||
{
|
||||
if (compose_data->sequence[i] == 0)
|
||||
{
|
||||
for (j = i; j < max_compose_len; j++)
|
||||
{
|
||||
if (j == max_compose_len - 1)
|
||||
g_printf ("0,\n");
|
||||
else
|
||||
g_printf ("0, ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
keyval = gdk_keyval_name (compose_data->sequence[i]);
|
||||
if (i == max_compose_len - 1)
|
||||
g_printf ("%s,\n", keyval ? keyval : "(null)");
|
||||
else
|
||||
g_printf ("%s, ", keyval ? keyval : "(null)");
|
||||
}
|
||||
upper = compose_data->value[0];
|
||||
lower = compose_data->value[1];
|
||||
comment = compose_data->comment;
|
||||
|
||||
if (list == g_list_last (compose_list))
|
||||
g_printf (" %#06X, %#06X /* %s */\n", upper, lower, comment);
|
||||
else
|
||||
g_printf (" %#06X, %#06X, /* %s */\n", upper, lower, comment);
|
||||
|
||||
total_size += n_index_stride;
|
||||
}
|
||||
|
||||
g_printerr ("TOTAL_SIZE: %d\nMAX_COMPOSE_LEN: %d\nN_INDEX_STRIDE: %d\n",
|
||||
total_size, max_compose_len, n_index_stride);
|
||||
}
|
||||
|
||||
/* Implemented from g_str_hash() */
|
||||
static guint32
|
||||
gtk_compose_table_data_hash (gconstpointer v, int length)
|
||||
@ -546,6 +512,7 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
|
||||
guint16 max_seq_len = compose_table->max_seq_len;
|
||||
guint16 index_stride = max_seq_len + 2;
|
||||
guint16 n_seqs = compose_table->n_seqs;
|
||||
guint16 n_chars = compose_table->n_chars;
|
||||
guint32 i;
|
||||
|
||||
g_return_val_if_fail (compose_table != NULL, NULL);
|
||||
@ -553,44 +520,34 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
|
||||
g_return_val_if_fail (index_stride > 0, NULL);
|
||||
|
||||
length = strlen (header);
|
||||
total_length = length + sizeof (guint16) * (3 + index_stride * n_seqs);
|
||||
total_length = length + sizeof (guint16) * (4 + index_stride * n_seqs) + n_chars;
|
||||
if (count)
|
||||
*count = total_length;
|
||||
|
||||
p = contents = g_slice_alloc (total_length);
|
||||
p = contents = g_malloc (total_length);
|
||||
|
||||
memcpy (p, header, length);
|
||||
p += length;
|
||||
|
||||
/* Copy by byte for endian */
|
||||
#define BYTE_COPY_FROM_BUF(element) \
|
||||
bytes = GUINT16_TO_BE ((element)); \
|
||||
memcpy (p, &bytes, length); \
|
||||
p += length; \
|
||||
if (p - contents > total_length) \
|
||||
{ \
|
||||
g_warning ("data size %lld is bigger than %" G_GSIZE_FORMAT, \
|
||||
(long long) (p - contents), total_length); \
|
||||
g_free (contents); \
|
||||
if (count) \
|
||||
{ \
|
||||
*count = 0; \
|
||||
} \
|
||||
return NULL; \
|
||||
}
|
||||
#define APPEND_GUINT16(elt) \
|
||||
bytes = GUINT16_TO_BE (elt); \
|
||||
memcpy (p, &bytes, sizeof (guint16)); \
|
||||
p += sizeof (guint16);
|
||||
|
||||
length = sizeof (guint16);
|
||||
|
||||
BYTE_COPY_FROM_BUF (version);
|
||||
BYTE_COPY_FROM_BUF (max_seq_len);
|
||||
BYTE_COPY_FROM_BUF (n_seqs);
|
||||
APPEND_GUINT16 (version);
|
||||
APPEND_GUINT16 (max_seq_len);
|
||||
APPEND_GUINT16 (n_seqs);
|
||||
APPEND_GUINT16 (n_chars);
|
||||
|
||||
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
|
||||
{
|
||||
BYTE_COPY_FROM_BUF (compose_table->data[i]);
|
||||
APPEND_GUINT16 (compose_table->data[i]);
|
||||
}
|
||||
|
||||
#undef BYTE_COPY_FROM_BUF
|
||||
if (compose_table->n_chars > 0)
|
||||
memcpy (p, compose_table->char_data, compose_table->n_chars);
|
||||
|
||||
#undef APPEND_GUINT16
|
||||
|
||||
return contents;
|
||||
}
|
||||
@ -614,16 +571,17 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
GStatBuf original_buf;
|
||||
GStatBuf cache_buf;
|
||||
gsize total_length;
|
||||
gsize length;
|
||||
GError *error = NULL;
|
||||
guint16 bytes;
|
||||
guint16 version;
|
||||
guint16 max_seq_len;
|
||||
guint16 index_stride;
|
||||
guint16 n_seqs;
|
||||
guint16 n_chars;
|
||||
guint32 i;
|
||||
guint16 *gtk_compose_seqs = NULL;
|
||||
GtkComposeTable *retval;
|
||||
char *char_data = NULL;
|
||||
|
||||
hash = g_str_hash (compose_file);
|
||||
if ((path = gtk_compose_hash_get_cache_path (hash)) == NULL)
|
||||
@ -642,16 +600,10 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
/* Copy by byte for endian */
|
||||
#define BYTE_COPY_TO_BUF(element) \
|
||||
memcpy (&bytes, p, length); \
|
||||
element = GUINT16_FROM_BE (bytes); \
|
||||
p += length; \
|
||||
if (p - contents > total_length) \
|
||||
{ \
|
||||
g_warning ("Broken cache content %s in %s", path, #element); \
|
||||
goto out_load_cache; \
|
||||
}
|
||||
#define GET_GUINT16(elt) \
|
||||
memcpy (&bytes, p, sizeof (guint16)); \
|
||||
elt = GUINT16_FROM_BE (bytes); \
|
||||
p += sizeof (guint16);
|
||||
|
||||
p = contents;
|
||||
if (g_ascii_strncasecmp (p, GTK_COMPOSE_TABLE_MAGIC,
|
||||
@ -660,6 +612,7 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
g_warning ("The file is not a GtkComposeTable cache file %s", path);
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
p += strlen (GTK_COMPOSE_TABLE_MAGIC);
|
||||
if (p - contents > total_length)
|
||||
{
|
||||
@ -667,9 +620,7 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
length = sizeof (guint16);
|
||||
|
||||
BYTE_COPY_TO_BUF (version);
|
||||
GET_GUINT16 (version);
|
||||
if (version != GTK_COMPOSE_TABLE_VERSION)
|
||||
{
|
||||
g_warning ("cache version is different %u != %u",
|
||||
@ -677,8 +628,9 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
BYTE_COPY_TO_BUF (max_seq_len);
|
||||
BYTE_COPY_TO_BUF (n_seqs);
|
||||
GET_GUINT16 (max_seq_len);
|
||||
GET_GUINT16 (n_seqs);
|
||||
GET_GUINT16 (n_chars);
|
||||
|
||||
if (max_seq_len == 0 || n_seqs == 0)
|
||||
{
|
||||
@ -691,13 +643,22 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
|
||||
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
|
||||
{
|
||||
BYTE_COPY_TO_BUF (gtk_compose_seqs[i]);
|
||||
GET_GUINT16 (gtk_compose_seqs[i]);
|
||||
}
|
||||
|
||||
if (n_chars > 0)
|
||||
{
|
||||
char_data = g_new (char, n_chars + 1);
|
||||
memcpy (char_data, p, n_chars);
|
||||
char_data[n_chars] = '\0';
|
||||
}
|
||||
|
||||
retval = g_new0 (GtkComposeTable, 1);
|
||||
retval->data = gtk_compose_seqs;
|
||||
retval->max_seq_len = max_seq_len;
|
||||
retval->n_seqs = n_seqs;
|
||||
retval->char_data = char_data;
|
||||
retval->n_chars = n_chars;
|
||||
retval->id = hash;
|
||||
|
||||
g_free (contents);
|
||||
@ -705,10 +666,11 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
|
||||
return retval;
|
||||
|
||||
#undef BYTE_COPY_TO_BUF
|
||||
#undef GET_GUINT16
|
||||
|
||||
out_load_cache:
|
||||
g_free (gtk_compose_seqs);
|
||||
g_free (char_data);
|
||||
g_free (contents);
|
||||
g_free (path);
|
||||
return NULL;
|
||||
@ -739,7 +701,7 @@ gtk_compose_table_save_cache (GtkComposeTable *compose_table)
|
||||
}
|
||||
|
||||
out_save_cache:
|
||||
g_slice_free1 (length, contents);
|
||||
g_free (contents);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
@ -756,6 +718,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
GList *list;
|
||||
GtkComposeData *compose_data;
|
||||
GtkComposeTable *retval = NULL;
|
||||
gunichar codepoint;
|
||||
GString *char_data;
|
||||
|
||||
g_return_val_if_fail (compose_list != NULL, NULL);
|
||||
|
||||
@ -763,6 +727,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
|
||||
gtk_compose_seqs = g_new0 (guint16, length * n_index_stride);
|
||||
|
||||
char_data = g_string_new ("");
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
@ -776,8 +742,24 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
}
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->sequence[i];
|
||||
}
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->value[0];
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->value[1];
|
||||
|
||||
if (g_utf8_strlen (compose_data->value, -1) > 1)
|
||||
{
|
||||
if (char_data->len > 0)
|
||||
g_string_append_c (char_data, 0);
|
||||
|
||||
codepoint = char_data->len | (1 << 31);
|
||||
|
||||
g_string_append (char_data, compose_data->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
codepoint = g_utf8_get_char (compose_data->value);
|
||||
g_assert ((codepoint & (1 << 31)) == 0);
|
||||
}
|
||||
|
||||
gtk_compose_seqs[n++] = (codepoint & 0xffff0000) >> 16;
|
||||
gtk_compose_seqs[n++] = codepoint & 0xffff;
|
||||
}
|
||||
|
||||
retval = g_new0 (GtkComposeTable, 1);
|
||||
@ -785,6 +767,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
retval->max_seq_len = max_compose_len;
|
||||
retval->n_seqs = length;
|
||||
retval->id = hash;
|
||||
retval->n_chars = char_data->len;
|
||||
retval->char_data = g_string_free (char_data, FALSE);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -816,9 +800,6 @@ gtk_compose_table_new_with_file (const char *compose_file)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_getenv ("GTK_COMPOSE_TABLE_PRINT") != NULL)
|
||||
gtk_compose_list_print (compose_list, max_compose_len, n_index_stride);
|
||||
|
||||
compose_table = gtk_compose_table_new_with_list (compose_list,
|
||||
max_compose_len,
|
||||
n_index_stride,
|
||||
@ -841,9 +822,10 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
guint16 *gtk_compose_seqs = NULL;
|
||||
|
||||
g_return_val_if_fail (data != NULL, compose_tables);
|
||||
g_return_val_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN, compose_tables);
|
||||
g_return_val_if_fail (max_seq_len >= 0, compose_tables);
|
||||
g_return_val_if_fail (n_seqs >= 0, compose_tables);
|
||||
|
||||
n_index_stride = MIN (max_seq_len, GTK_MAX_COMPOSE_LEN) + 2;
|
||||
n_index_stride = max_seq_len + 2;
|
||||
if (!g_size_checked_mul (&length, n_index_stride, n_seqs))
|
||||
{
|
||||
g_critical ("Overflow in the compose sequences");
|
||||
@ -864,12 +846,14 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
compose_table->max_seq_len = max_seq_len;
|
||||
compose_table->n_seqs = n_seqs;
|
||||
compose_table->id = hash;
|
||||
compose_table->char_data = NULL;
|
||||
compose_table->n_chars = 0;
|
||||
|
||||
return g_slist_prepend (compose_tables, compose_table);
|
||||
}
|
||||
|
||||
GSList *
|
||||
gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file)
|
||||
{
|
||||
guint32 hash;
|
||||
@ -891,3 +875,409 @@ gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
gtk_compose_table_save_cache (compose_table);
|
||||
return g_slist_prepend (compose_tables, compose_table);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq (const void *key, const void *value)
|
||||
{
|
||||
int i = 0;
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
while (keysyms[i])
|
||||
{
|
||||
if (keysyms[i] < seq[i])
|
||||
return -1;
|
||||
else if (keysyms[i] > seq[i])
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_compose_table_check:
|
||||
* @table: the table to check
|
||||
* @compose_buffer: the key vals to match
|
||||
* @n_compose: number of non-zero key vals in @compose_buffer
|
||||
* @compose_finish: (out): return location for whether there may be longer matches
|
||||
* @compose_match: (out): return location for whether there is a match
|
||||
* @output: (out) (caller-allocates): return location for the match values
|
||||
*
|
||||
* Looks for matches for a key sequence in @table.
|
||||
*
|
||||
* Returns: %TRUE if there were any matches, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
gtk_compose_table_check (const GtkComposeTable *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
GString *output)
|
||||
{
|
||||
int row_stride = table->max_seq_len + 2;
|
||||
guint16 *seq;
|
||||
|
||||
*compose_finish = FALSE;
|
||||
*compose_match = FALSE;
|
||||
|
||||
g_string_set_size (output, 0);
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq = bsearch (compose_buffer,
|
||||
table->data, table->n_seqs,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
guint16 *prev_seq;
|
||||
|
||||
/* Back up to the first sequence that matches to make sure
|
||||
* we find the exact match if there is one.
|
||||
*/
|
||||
while (seq > table->data)
|
||||
{
|
||||
prev_seq = seq - row_stride;
|
||||
if (compare_seq (compose_buffer, prev_seq) != 0)
|
||||
break;
|
||||
seq = prev_seq;
|
||||
}
|
||||
|
||||
if (n_compose == table->max_seq_len ||
|
||||
seq[n_compose] == 0) /* complete sequence */
|
||||
{
|
||||
guint16 *next_seq;
|
||||
gunichar value;
|
||||
|
||||
value = (seq[table->max_seq_len] << 16) | seq[table->max_seq_len + 1];
|
||||
if ((value & (1 << 31)) != 0)
|
||||
g_string_append (output, &table->char_data[value & ~(1 << 31)]);
|
||||
else
|
||||
g_string_append_unichar (output, value);
|
||||
|
||||
*compose_match = TRUE;
|
||||
|
||||
/* We found a tentative match. See if there are any longer
|
||||
* sequences containing this subsequence
|
||||
*/
|
||||
next_seq = seq + row_stride;
|
||||
if (next_seq < table->data + row_stride * table->n_seqs)
|
||||
{
|
||||
if (compare_seq (compose_buffer, next_seq) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*compose_finish = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq_index (const void *key, const void *value)
|
||||
{
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
if (keysyms[0] < seq[0])
|
||||
return -1;
|
||||
else if (keysyms[0] > seq[0])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char)
|
||||
{
|
||||
int row_stride;
|
||||
guint16 *seq_index;
|
||||
guint16 *seq;
|
||||
int i;
|
||||
gboolean match;
|
||||
gunichar value;
|
||||
|
||||
if (compose_finish)
|
||||
*compose_finish = FALSE;
|
||||
if (compose_match)
|
||||
*compose_match = FALSE;
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq_index = bsearch (compose_buffer,
|
||||
table->data,
|
||||
table->n_index_size,
|
||||
sizeof (guint16) * table->n_index_stride,
|
||||
compare_seq_index);
|
||||
|
||||
if (!seq_index)
|
||||
return FALSE;
|
||||
|
||||
if (seq_index && n_compose == 1)
|
||||
return TRUE;
|
||||
|
||||
seq = NULL;
|
||||
match = FALSE;
|
||||
value = 0;
|
||||
|
||||
for (i = n_compose - 1; i < table->max_seq_len; i++)
|
||||
{
|
||||
row_stride = i + 1;
|
||||
|
||||
if (seq_index[i + 1] - seq_index[i] > 0)
|
||||
{
|
||||
seq = bsearch (compose_buffer + 1,
|
||||
table->data + seq_index[i],
|
||||
(seq_index[i + 1] - seq_index[i]) / row_stride,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
if (i == n_compose - 1)
|
||||
{
|
||||
value = seq[row_stride - 1];
|
||||
match = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
if (compose_finish)
|
||||
*compose_finish = TRUE;
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Checks if a keysym is a dead key.
|
||||
* Dead key keysym values are defined in ../gdk/gdkkeysyms.h and the
|
||||
* first is GDK_KEY_dead_grave. As X.Org is updated, more dead keys
|
||||
* are added and we need to update the upper limit.
|
||||
*/
|
||||
#define IS_DEAD_KEY(k) \
|
||||
((k) >= GDK_KEY_dead_grave && (k) <= GDK_KEY_dead_greek)
|
||||
|
||||
/* This function receives a sequence of Unicode characters and tries to
|
||||
* normalize it (NFC). We check for the case where the resulting string
|
||||
* has length 1 (single character).
|
||||
* NFC normalisation normally rearranges diacritic marks, unless these
|
||||
* belong to the same Canonical Combining Class.
|
||||
* If they belong to the same canonical combining class, we produce all
|
||||
* permutations of the diacritic marks, then attempt to normalize.
|
||||
*/
|
||||
static gboolean
|
||||
check_normalize_nfc (gunichar *combination_buffer,
|
||||
int n_compose)
|
||||
{
|
||||
gunichar *combination_buffer_temp;
|
||||
char *combination_utf8_temp = NULL;
|
||||
char *nfc_temp = NULL;
|
||||
int n_combinations;
|
||||
gunichar temp_swap;
|
||||
int i;
|
||||
|
||||
combination_buffer_temp = g_alloca (n_compose * sizeof (gunichar));
|
||||
|
||||
n_combinations = 1;
|
||||
|
||||
for (i = 1; i < n_compose; i++)
|
||||
n_combinations *= i;
|
||||
|
||||
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
|
||||
* We check if base character belongs to Greek Unicode block,
|
||||
* and if so, we replace tilde with perispomeni.
|
||||
*/
|
||||
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
|
||||
{
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
if (combination_buffer[i] == 0x303)
|
||||
combination_buffer[i] = 0x342;
|
||||
}
|
||||
|
||||
memcpy (combination_buffer_temp, combination_buffer, n_compose * sizeof (gunichar) );
|
||||
|
||||
for (i = 0; i < n_combinations; i++)
|
||||
{
|
||||
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
|
||||
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, n_compose, NULL, NULL, NULL);
|
||||
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (g_utf8_strlen (nfc_temp, -1) == 1)
|
||||
{
|
||||
memcpy (combination_buffer, combination_buffer_temp, n_compose * sizeof (gunichar) );
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
if (n_compose > 2)
|
||||
{
|
||||
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output_char)
|
||||
|
||||
{
|
||||
int i;
|
||||
gunichar *combination_buffer;
|
||||
char *combination_utf8, *nfc;
|
||||
|
||||
combination_buffer = alloca (sizeof (gunichar) * (n_compose + 1));
|
||||
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
|
||||
;
|
||||
if (i == n_compose)
|
||||
return TRUE;
|
||||
|
||||
if (i > 0 && i == n_compose - 1)
|
||||
{
|
||||
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
combination_buffer[n_compose] = 0;
|
||||
i--;
|
||||
while (i >= 0)
|
||||
{
|
||||
switch (compose_buffer[i])
|
||||
{
|
||||
#define CASE(keysym, unicode) \
|
||||
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
|
||||
|
||||
CASE (grave, 0x0300);
|
||||
CASE (acute, 0x0301);
|
||||
CASE (circumflex, 0x0302);
|
||||
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
|
||||
CASE (macron, 0x0304);
|
||||
CASE (breve, 0x0306);
|
||||
CASE (abovedot, 0x0307);
|
||||
CASE (diaeresis, 0x0308);
|
||||
CASE (abovering, 0x30A);
|
||||
CASE (hook, 0x0309);
|
||||
CASE (doubleacute, 0x030B);
|
||||
CASE (caron, 0x030C);
|
||||
CASE (cedilla, 0x0327);
|
||||
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
|
||||
CASE (iota, 0x0345);
|
||||
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (belowdot, 0x0323);
|
||||
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
|
||||
CASE (stroke, 0x335);
|
||||
CASE (abovecomma, 0x0313); /* Equivalent to psili */
|
||||
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
|
||||
CASE (doublegrave, 0x30F);
|
||||
CASE (belowring, 0x325);
|
||||
CASE (belowmacron, 0x331);
|
||||
CASE (belowcircumflex, 0x32D);
|
||||
CASE (belowtilde, 0x330);
|
||||
CASE (belowbreve, 0x32e);
|
||||
CASE (belowdiaeresis, 0x324);
|
||||
CASE (invertedbreve, 0x32f);
|
||||
CASE (belowcomma, 0x326);
|
||||
CASE (lowline, 0x332);
|
||||
CASE (aboveverticalline, 0x30D);
|
||||
CASE (belowverticalline, 0x329);
|
||||
CASE (longsolidusoverlay, 0x338);
|
||||
CASE (a, 0x363);
|
||||
CASE (A, 0x363);
|
||||
CASE (e, 0x364);
|
||||
CASE (E, 0x364);
|
||||
CASE (i, 0x365);
|
||||
CASE (I, 0x365);
|
||||
CASE (o, 0x366);
|
||||
CASE (O, 0x366);
|
||||
CASE (u, 0x367);
|
||||
CASE (U, 0x367);
|
||||
CASE (small_schwa, 0x1DEA);
|
||||
CASE (capital_schwa, 0x1DEA);
|
||||
#undef CASE
|
||||
default:
|
||||
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
/* If the buffer normalizes to a single character, then modify the order
|
||||
* of combination_buffer accordingly, if necessary, and return TRUE.
|
||||
*/
|
||||
if (check_normalize_nfc (combination_buffer, n_compose))
|
||||
{
|
||||
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
|
||||
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (output_char)
|
||||
*output_char = g_utf8_get_char (nfc);
|
||||
|
||||
g_free (combination_utf8);
|
||||
g_free (nfc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,10 @@ typedef struct _GtkComposeTableCompact GtkComposeTableCompact;
|
||||
struct _GtkComposeTable
|
||||
{
|
||||
guint16 *data;
|
||||
char *char_data;
|
||||
int max_seq_len;
|
||||
int n_seqs;
|
||||
int n_chars;
|
||||
guint32 id;
|
||||
};
|
||||
|
||||
@ -42,13 +44,32 @@ struct _GtkComposeTableCompact
|
||||
int n_index_stride;
|
||||
};
|
||||
|
||||
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
|
||||
GSList *gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
const guint16 *data,
|
||||
int max_seq_len,
|
||||
int n_seqs);
|
||||
GSList *gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file);
|
||||
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
|
||||
GSList * gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
const guint16 *data,
|
||||
int max_seq_len,
|
||||
int n_seqs);
|
||||
GSList * gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file);
|
||||
|
||||
gboolean gtk_compose_table_check (const GtkComposeTable *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
GString *output);
|
||||
|
||||
gboolean gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char);
|
||||
|
||||
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "gtkcomposetable.h"
|
||||
#include "gtkimmoduleprivate.h"
|
||||
|
||||
#include "gtkimcontextsimpleprivate.h"
|
||||
#include "gtkimcontextsimpleseqs.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
@ -61,8 +60,9 @@
|
||||
|
||||
struct _GtkIMContextSimplePrivate
|
||||
{
|
||||
guint16 compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
|
||||
gunichar tentative_match;
|
||||
guint16 *compose_buffer;
|
||||
int compose_buffer_len;
|
||||
GString *tentative_match;
|
||||
int tentative_match_len;
|
||||
|
||||
guint in_hex_sequence : 1;
|
||||
@ -174,8 +174,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
g_free (path);
|
||||
return;
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
|
||||
home = g_get_home_dir ();
|
||||
if (home == NULL)
|
||||
@ -190,8 +189,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
g_free (path);
|
||||
return;
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
|
||||
locale = g_getenv ("LC_CTYPE");
|
||||
if (locale == NULL)
|
||||
@ -224,8 +222,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
|
||||
if (g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
break;
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
}
|
||||
|
||||
g_free (x11_compose_file_dir);
|
||||
@ -237,8 +234,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables, path);
|
||||
G_UNLOCK (global_tables);
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -271,14 +267,27 @@ init_compose_table_async (GCancellable *cancellable,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
|
||||
gtk_im_context_simple_init (GtkIMContextSimple *context_simple)
|
||||
{
|
||||
im_context_simple->priv = gtk_im_context_simple_get_instance_private (im_context_simple);
|
||||
GtkIMContextSimplePrivate *priv;
|
||||
|
||||
priv = context_simple->priv = gtk_im_context_simple_get_instance_private (context_simple);
|
||||
|
||||
priv->compose_buffer_len = gtk_compose_table_compact.max_seq_len + 1;
|
||||
priv->compose_buffer = g_new0 (guint16, priv->compose_buffer_len);
|
||||
priv->tentative_match = g_string_new ("");
|
||||
priv->tentative_match_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_finalize (GObject *obj)
|
||||
{
|
||||
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj);
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;;
|
||||
|
||||
g_free (priv->compose_buffer);
|
||||
g_string_free (priv->tentative_match, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gtk_im_context_simple_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
@ -296,413 +305,29 @@ gtk_im_context_simple_new (void)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_commit_char (GtkIMContext *context,
|
||||
gunichar ch)
|
||||
gtk_im_context_simple_commit_string (GtkIMContextSimple *context_simple,
|
||||
const char *str)
|
||||
{
|
||||
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;
|
||||
char buf[10];
|
||||
int len;
|
||||
|
||||
g_return_if_fail (g_unichar_validate (ch));
|
||||
|
||||
len = g_unichar_to_utf8 (ch, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
g_signal_emit_by_name (context, "preedit-changed");
|
||||
g_signal_emit_by_name (context, "preedit-end");
|
||||
|
||||
g_signal_emit_by_name (context, "commit", &buf);
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq_index (const void *key, const void *value)
|
||||
static void
|
||||
gtk_im_context_simple_commit_char (GtkIMContextSimple *context_simple,
|
||||
gunichar ch)
|
||||
{
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
char buf[8] = { 0, };
|
||||
|
||||
if (keysyms[0] < seq[0])
|
||||
return -1;
|
||||
else if (keysyms[0] > seq[0])
|
||||
return 1;
|
||||
g_unichar_to_utf8 (ch, buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq (const void *key, const void *value)
|
||||
{
|
||||
int i = 0;
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
while (keysyms[i])
|
||||
{
|
||||
if (keysyms[i] < seq[i])
|
||||
return -1;
|
||||
else if (keysyms[i] > seq[i])
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_table (GtkIMContextSimple *context_simple,
|
||||
const GtkComposeTable *table,
|
||||
int n_compose)
|
||||
{
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;
|
||||
int row_stride = table->max_seq_len + 2;
|
||||
guint16 *seq;
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val. */
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq = bsearch (priv->compose_buffer,
|
||||
table->data, table->n_seqs,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
guint16 *prev_seq;
|
||||
|
||||
/* Back up to the first sequence that matches to make sure
|
||||
* we find the exact match if there is one.
|
||||
*/
|
||||
while (seq > table->data)
|
||||
{
|
||||
prev_seq = seq - row_stride;
|
||||
if (compare_seq (priv->compose_buffer, prev_seq) != 0)
|
||||
break;
|
||||
seq = prev_seq;
|
||||
}
|
||||
|
||||
if (n_compose == table->max_seq_len ||
|
||||
seq[n_compose] == 0) /* complete sequence */
|
||||
{
|
||||
guint16 *next_seq;
|
||||
gunichar value =
|
||||
0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1];
|
||||
|
||||
/* We found a tentative match. See if there are any longer
|
||||
* sequences containing this subsequence
|
||||
*/
|
||||
next_seq = seq + row_stride;
|
||||
if (next_seq < table->data + row_stride * table->n_seqs)
|
||||
{
|
||||
if (compare_seq (priv->compose_buffer, next_seq) == 0)
|
||||
{
|
||||
priv->tentative_match = value;
|
||||
priv->tentative_match_len = n_compose;
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Checks if a keysym is a dead key.
|
||||
* Dead key keysym values are defined in ../gdk/gdkkeysyms.h and the
|
||||
* first is GDK_KEY_dead_grave. As X.Org is updated, more dead keys
|
||||
* are added and we need to update the upper limit.
|
||||
*/
|
||||
#define IS_DEAD_KEY(k) \
|
||||
((k) >= GDK_KEY_dead_grave && (k) <= GDK_KEY_dead_greek)
|
||||
|
||||
gboolean
|
||||
gtk_check_compact_table (const GtkComposeTableCompact *table,
|
||||
guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char)
|
||||
{
|
||||
int row_stride;
|
||||
guint16 *seq_index;
|
||||
guint16 *seq;
|
||||
int i;
|
||||
gboolean match;
|
||||
gunichar value;
|
||||
|
||||
if (compose_finish)
|
||||
*compose_finish = FALSE;
|
||||
if (compose_match)
|
||||
*compose_match = FALSE;
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq_index = bsearch (compose_buffer,
|
||||
table->data,
|
||||
table->n_index_size,
|
||||
sizeof (guint16) * table->n_index_stride,
|
||||
compare_seq_index);
|
||||
|
||||
if (!seq_index)
|
||||
return FALSE;
|
||||
|
||||
if (seq_index && n_compose == 1)
|
||||
return TRUE;
|
||||
|
||||
seq = NULL;
|
||||
match = FALSE;
|
||||
value = 0;
|
||||
|
||||
for (i = n_compose - 1; i < table->max_seq_len; i++)
|
||||
{
|
||||
row_stride = i + 1;
|
||||
|
||||
if (seq_index[i + 1] - seq_index[i] > 0)
|
||||
{
|
||||
seq = bsearch (compose_buffer + 1,
|
||||
table->data + seq_index[i],
|
||||
(seq_index[i + 1] - seq_index[i]) / row_stride,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
if (i == n_compose - 1)
|
||||
{
|
||||
value = seq[row_stride - 1];
|
||||
match = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
if (compose_finish)
|
||||
*compose_finish = TRUE;
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This function receives a sequence of Unicode characters and tries to
|
||||
* normalize it (NFC). We check for the case where the resulting string
|
||||
* has length 1 (single character).
|
||||
* NFC normalisation normally rearranges diacritic marks, unless these
|
||||
* belong to the same Canonical Combining Class.
|
||||
* If they belong to the same canonical combining class, we produce all
|
||||
* permutations of the diacritic marks, then attempt to normalize.
|
||||
*/
|
||||
static gboolean
|
||||
check_normalize_nfc (gunichar* combination_buffer, int n_compose)
|
||||
{
|
||||
gunichar combination_buffer_temp[GTK_MAX_COMPOSE_LEN];
|
||||
char *combination_utf8_temp = NULL;
|
||||
char *nfc_temp = NULL;
|
||||
int n_combinations;
|
||||
gunichar temp_swap;
|
||||
int i;
|
||||
|
||||
n_combinations = 1;
|
||||
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
n_combinations *= i;
|
||||
|
||||
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
|
||||
* We check if base character belongs to Greek Unicode block,
|
||||
* and if so, we replace tilde with perispomeni.
|
||||
*/
|
||||
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
|
||||
{
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
if (combination_buffer[i] == 0x303)
|
||||
combination_buffer[i] = 0x342;
|
||||
}
|
||||
|
||||
memcpy (combination_buffer_temp, combination_buffer, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
|
||||
|
||||
for (i = 0; i < n_combinations; i++ )
|
||||
{
|
||||
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
|
||||
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, NULL, NULL, NULL);
|
||||
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (g_utf8_strlen (nfc_temp, -1) == 1)
|
||||
{
|
||||
memcpy (combination_buffer, combination_buffer_temp, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
if (n_compose > 2)
|
||||
{
|
||||
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output_char)
|
||||
|
||||
{
|
||||
int i;
|
||||
gunichar combination_buffer[GTK_MAX_COMPOSE_LEN];
|
||||
char *combination_utf8, *nfc;
|
||||
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
if (n_compose >= GTK_MAX_COMPOSE_LEN)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
|
||||
;
|
||||
if (i == n_compose)
|
||||
return TRUE;
|
||||
|
||||
if (i > 0 && i == n_compose - 1)
|
||||
{
|
||||
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
combination_buffer[n_compose] = 0;
|
||||
i--;
|
||||
while (i >= 0)
|
||||
{
|
||||
switch (compose_buffer[i])
|
||||
{
|
||||
#define CASE(keysym, unicode) \
|
||||
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
|
||||
|
||||
CASE (grave, 0x0300);
|
||||
CASE (acute, 0x0301);
|
||||
CASE (circumflex, 0x0302);
|
||||
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
|
||||
CASE (macron, 0x0304);
|
||||
CASE (breve, 0x0306);
|
||||
CASE (abovedot, 0x0307);
|
||||
CASE (diaeresis, 0x0308);
|
||||
CASE (abovering, 0x30A);
|
||||
CASE (hook, 0x0309);
|
||||
CASE (doubleacute, 0x030B);
|
||||
CASE (caron, 0x030C);
|
||||
CASE (cedilla, 0x0327);
|
||||
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
|
||||
CASE (iota, 0x0345);
|
||||
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (belowdot, 0x0323);
|
||||
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
|
||||
CASE (stroke, 0x335);
|
||||
CASE (abovecomma, 0x0313); /* Equivalent to psili */
|
||||
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
|
||||
CASE (doublegrave, 0x30F);
|
||||
CASE (belowring, 0x325);
|
||||
CASE (belowmacron, 0x331);
|
||||
CASE (belowcircumflex, 0x32D);
|
||||
CASE (belowtilde, 0x330);
|
||||
CASE (belowbreve, 0x32e);
|
||||
CASE (belowdiaeresis, 0x324);
|
||||
CASE (invertedbreve, 0x32f);
|
||||
CASE (belowcomma, 0x326);
|
||||
CASE (lowline, 0x332);
|
||||
CASE (aboveverticalline, 0x30D);
|
||||
CASE (belowverticalline, 0x329);
|
||||
CASE (longsolidusoverlay, 0x338);
|
||||
CASE (a, 0x363);
|
||||
CASE (A, 0x363);
|
||||
CASE (e, 0x364);
|
||||
CASE (E, 0x364);
|
||||
CASE (i, 0x365);
|
||||
CASE (I, 0x365);
|
||||
CASE (o, 0x366);
|
||||
CASE (O, 0x366);
|
||||
CASE (u, 0x367);
|
||||
CASE (U, 0x367);
|
||||
CASE (small_schwa, 0x1DEA);
|
||||
CASE (capital_schwa, 0x1DEA);
|
||||
#undef CASE
|
||||
default:
|
||||
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
/* If the buffer normalizes to a single character, then modify the order
|
||||
* of combination_buffer accordingly, if necessary, and return TRUE.
|
||||
*/
|
||||
if (check_normalize_nfc (combination_buffer, n_compose))
|
||||
{
|
||||
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
|
||||
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (output_char)
|
||||
*output_char = g_utf8_get_char (nfc);
|
||||
|
||||
g_free (combination_utf8);
|
||||
g_free (nfc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
gtk_im_context_simple_commit_string (context_simple, buf);
|
||||
}
|
||||
|
||||
/* In addition to the table-driven sequences, we allow Unicode hex
|
||||
@ -733,7 +358,7 @@ check_hex (GtkIMContextSimple *context_simple,
|
||||
char *nptr = NULL;
|
||||
char buf[7];
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
@ -773,7 +398,8 @@ check_hex (GtkIMContextSimple *context_simple,
|
||||
|
||||
if (g_unichar_validate (n))
|
||||
{
|
||||
priv->tentative_match = n;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
g_string_append_unichar (priv->tentative_match, n);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
|
||||
@ -809,18 +435,23 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
|
||||
/* No compose sequences found, check first if we have a partial
|
||||
* match pending.
|
||||
*/
|
||||
if (priv->tentative_match)
|
||||
if (priv->tentative_match_len > 0)
|
||||
{
|
||||
int len = priv->tentative_match_len;
|
||||
int i;
|
||||
guint16 compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
|
||||
guint16 *compose_buffer;
|
||||
char *str;
|
||||
|
||||
memcpy (compose_buffer, priv->compose_buffer, sizeof (compose_buffer));
|
||||
compose_buffer = alloca (sizeof (guint16) * priv->compose_buffer_len);
|
||||
|
||||
memcpy (compose_buffer, priv->compose_buffer, sizeof (guint16) * priv->compose_buffer_len);
|
||||
|
||||
str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
|
||||
for (i = 0; i < n_compose - len - 1; i++)
|
||||
{
|
||||
{
|
||||
GdkTranslatedKey translated;
|
||||
translated.keyval = compose_buffer[len + i];
|
||||
translated.consumed = 0;
|
||||
@ -858,7 +489,7 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
|
||||
ch = gdk_keyval_to_unicode (keyval);
|
||||
if (ch != 0 && !g_unichar_iscntrl (ch))
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, ch);
|
||||
gtk_im_context_simple_commit_char (context_simple, ch);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -942,7 +573,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
gunichar output_char;
|
||||
guint keyval, state;
|
||||
|
||||
while (priv->compose_buffer[n_compose] != 0)
|
||||
while (priv->compose_buffer[n_compose] != 0 && n_compose < priv->compose_buffer_len)
|
||||
n_compose++;
|
||||
|
||||
keyval = gdk_key_event_get_keyval (event);
|
||||
@ -954,10 +585,11 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
(keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R ||
|
||||
keyval == GDK_KEY_Shift_L || keyval == GDK_KEY_Shift_R))
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -972,7 +604,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* invalid hex sequence */
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
@ -1072,10 +704,11 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* Check for hex sequence restart */
|
||||
if (priv->in_hex_sequence && have_hex_mods && is_hex_start)
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1083,7 +716,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
if (n_compose > 0)
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
@ -1095,7 +728,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
priv->compose_buffer[0] = 0;
|
||||
priv->in_hex_sequence = TRUE;
|
||||
priv->modifiers_dropped = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-start");
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
@ -1106,7 +739,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* Then, check for compose sequences */
|
||||
if (priv->in_hex_sequence)
|
||||
{
|
||||
if (hex_keyval)
|
||||
if (hex_keyval && n_compose < 6)
|
||||
priv->compose_buffer[n_compose++] = hex_keyval;
|
||||
else if (is_escape)
|
||||
{
|
||||
@ -1115,13 +748,21 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
}
|
||||
else if (!is_hex_end)
|
||||
{
|
||||
/* non-hex character in hex sequence */
|
||||
/* non-hex character in hex sequence, or sequence too long */
|
||||
beep_surface (surface);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
priv->compose_buffer[n_compose++] = keyval;
|
||||
{
|
||||
if (n_compose + 1 == priv->compose_buffer_len)
|
||||
{
|
||||
priv->compose_buffer_len += 1;
|
||||
priv->compose_buffer = g_renew (guint16, priv->compose_buffer, priv->compose_buffer_len);
|
||||
}
|
||||
|
||||
priv->compose_buffer[n_compose++] = keyval;
|
||||
}
|
||||
|
||||
priv->compose_buffer[n_compose] = 0;
|
||||
|
||||
@ -1133,17 +774,18 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* space or return ends the sequence, and we eat the key */
|
||||
if (n_compose > 0 && is_hex_end)
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid hex sequence */
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
@ -1162,43 +804,65 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
else
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
GString *output;
|
||||
|
||||
output = g_string_new ("");
|
||||
|
||||
G_LOCK (global_tables);
|
||||
|
||||
tmp_list = global_tables;
|
||||
while (tmp_list)
|
||||
{
|
||||
if (check_table (context_simple, tmp_list->data, n_compose))
|
||||
if (gtk_compose_table_check ((GtkComposeTable *)tmp_list->data,
|
||||
priv->compose_buffer, n_compose,
|
||||
&compose_finish, &compose_match,
|
||||
output))
|
||||
{
|
||||
if (compose_finish)
|
||||
{
|
||||
if (compose_match)
|
||||
gtk_im_context_simple_commit_string (context_simple, output->str);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
g_string_assign (priv->tentative_match, output->str);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
G_UNLOCK (global_tables);
|
||||
|
||||
g_string_free (output, TRUE);
|
||||
|
||||
if (success)
|
||||
return TRUE;
|
||||
|
||||
if (gtk_check_compact_table (>k_compose_table_compact,
|
||||
priv->compose_buffer,
|
||||
n_compose, &compose_finish,
|
||||
&compose_match, &output_char))
|
||||
if (gtk_compose_table_compact_check (>k_compose_table_compact,
|
||||
priv->compose_buffer, n_compose,
|
||||
&compose_finish, &compose_match,
|
||||
&output_char))
|
||||
{
|
||||
if (compose_finish)
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
|
||||
output_char);
|
||||
}
|
||||
gtk_im_context_simple_commit_char (context_simple, output_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
priv->tentative_match = output_char;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
g_string_append_unichar (priv->tentative_match, output_char);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
@ -1206,18 +870,15 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
if (gtk_check_algorithmically (priv->compose_buffer, n_compose, &output_char))
|
||||
{
|
||||
if (output_char)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
|
||||
output_char);
|
||||
}
|
||||
return TRUE;
|
||||
gtk_im_context_simple_commit_char (context_simple, output_char);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The current compose_buffer doesn't match anything */
|
||||
return no_sequence_matches (context_simple, n_compose, (GdkEvent *)event);
|
||||
}
|
||||
@ -1230,10 +891,10 @@ gtk_im_context_simple_reset (GtkIMContext *context)
|
||||
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
if (priv->tentative_match || priv->in_hex_sequence)
|
||||
if (priv->tentative_match->len > 0 || priv->in_hex_sequence)
|
||||
{
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
g_signal_emit_by_name (context_simple, "preedit-end");
|
||||
@ -1260,9 +921,9 @@ 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 && priv->compose_buffer[0] != 0)
|
||||
else if (priv->tentative_match->len > 0 && priv->compose_buffer[0] != 0)
|
||||
{
|
||||
g_string_append_unichar (s, priv->tentative_match);
|
||||
g_string_append (s, priv->tentative_match->str);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1300,7 +961,6 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
|
||||
* @context_simple: A #GtkIMContextSimple
|
||||
* @data: (array): the table
|
||||
* @max_seq_len: Maximum length of a sequence in the table
|
||||
* (cannot be greater than #GTK_MAX_COMPOSE_LEN)
|
||||
* @n_seqs: number of sequences in the table
|
||||
*
|
||||
* Adds an additional table to search to the input context.
|
||||
@ -1320,7 +980,6 @@ gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple,
|
||||
int n_seqs)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_IM_CONTEXT_SIMPLE (context_simple));
|
||||
g_return_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN);
|
||||
|
||||
G_LOCK (global_tables);
|
||||
|
||||
@ -1345,8 +1004,7 @@ gtk_im_context_simple_add_compose_file (GtkIMContextSimple *context_simple,
|
||||
|
||||
G_LOCK (global_tables);
|
||||
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables,
|
||||
compose_file);
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables, compose_file);
|
||||
|
||||
G_UNLOCK (global_tables);
|
||||
}
|
||||
|
@ -27,10 +27,9 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GTK_MAX_COMPOSE_LEN:
|
||||
*
|
||||
* The maximum length of sequences in compose tables.
|
||||
/*
|
||||
* No longer used by GTK, just left here on the off chance that some
|
||||
* 3rd party code used this define.
|
||||
*/
|
||||
#define GTK_MAX_COMPOSE_LEN 7
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2000 Red Hat Software
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
|
||||
#define __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gdk/gdkkeysyms.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
extern const GtkComposeTableCompact gtk_compose_table_compact;
|
||||
|
||||
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output);
|
||||
gboolean gtk_check_compact_table (const GtkComposeTableCompact *table,
|
||||
guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__ */
|
1
testsuite/gtk/compose/basic
Normal file
1
testsuite/gtk/compose/basic
Normal file
@ -0,0 +1 @@
|
||||
<Multi_key> <s> <e> <q> : "!"
|
3
testsuite/gtk/compose/basic.expected
Normal file
3
testsuite/gtk/compose/basic.expected
Normal file
@ -0,0 +1,3 @@
|
||||
# n_seqs: 1
|
||||
# max_seq_len: 4
|
||||
<Uff20> <U73> <U65> <U71> : "!" # U21
|
1
testsuite/gtk/compose/codepoint
Normal file
1
testsuite/gtk/compose/codepoint
Normal file
@ -0,0 +1 @@
|
||||
<Multi_key> <U73> <U6F> <U7a> : "!"
|
3
testsuite/gtk/compose/codepoint.expected
Normal file
3
testsuite/gtk/compose/codepoint.expected
Normal file
@ -0,0 +1,3 @@
|
||||
# n_seqs: 1
|
||||
# max_seq_len: 4
|
||||
<Uff20> <U73> <U6f> <U7a> : "!" # U21
|
1
testsuite/gtk/compose/hex
Normal file
1
testsuite/gtk/compose/hex
Normal file
@ -0,0 +1 @@
|
||||
<Multi_key> <s> <e> <q> : "\x23fe\X23F3"
|
3
testsuite/gtk/compose/hex.expected
Normal file
3
testsuite/gtk/compose/hex.expected
Normal file
@ -0,0 +1,3 @@
|
||||
# n_seqs: 1
|
||||
# max_seq_len: 4
|
||||
<Uff20> <U73> <U65> <U71> : "⏾⏳"
|
1
testsuite/gtk/compose/long
Normal file
1
testsuite/gtk/compose/long
Normal file
@ -0,0 +1 @@
|
||||
<Multi_key> <e> <m> <m> <e> <n> <t> <a> <l> <e> <r> : "🧀"
|
3
testsuite/gtk/compose/long.expected
Normal file
3
testsuite/gtk/compose/long.expected
Normal file
@ -0,0 +1,3 @@
|
||||
# n_seqs: 1
|
||||
# max_seq_len: 11
|
||||
<Uff20> <U65> <U6d> <U6d> <U65> <U6e> <U74> <U61> <U6c> <U65> <U72> : "🧀" # U1f9c0
|
3
testsuite/gtk/compose/match
Normal file
3
testsuite/gtk/compose/match
Normal file
@ -0,0 +1,3 @@
|
||||
<Multi_key> <s> <e> <q> : "!"
|
||||
<Multi_key> <s> <e> <q> <u> : "?"
|
||||
<Multi_key> <z> <w> <i> <n> <e> <s> : "🥂"
|
3
testsuite/gtk/compose/multi
Normal file
3
testsuite/gtk/compose/multi
Normal file
@ -0,0 +1,3 @@
|
||||
<Multi_key> <s> <e> <q> : "!"
|
||||
<Multi_key> <u> <b> <2> <3> : "/"
|
||||
<Multi_key> <s> <a> <s> : "_"
|
5
testsuite/gtk/compose/multi.expected
Normal file
5
testsuite/gtk/compose/multi.expected
Normal file
@ -0,0 +1,5 @@
|
||||
# n_seqs: 3
|
||||
# max_seq_len: 5
|
||||
<Uff20> <U73> <U61> <U73> <U0> : "_" # U5f
|
||||
<Uff20> <U73> <U65> <U71> <U0> : "!" # U21
|
||||
<Uff20> <U75> <U62> <U32> <U33> : "/" # U2f
|
1
testsuite/gtk/compose/octal
Normal file
1
testsuite/gtk/compose/octal
Normal file
@ -0,0 +1 @@
|
||||
<Multi_key> <s> <e> <q> : "\041"
|
3
testsuite/gtk/compose/octal.expected
Normal file
3
testsuite/gtk/compose/octal.expected
Normal file
@ -0,0 +1,3 @@
|
||||
# n_seqs: 1
|
||||
# max_seq_len: 4
|
||||
<Uff20> <U73> <U65> <U71> : "!" # U21
|
4
testsuite/gtk/compose/strings
Normal file
4
testsuite/gtk/compose/strings
Normal file
@ -0,0 +1,4 @@
|
||||
<Multi_key> <s> <e> <q> : "!a"
|
||||
<Multi_key> <s> <e> <q> <u> : "?"
|
||||
<Multi_key> <u> <b> <2> <3> : "\121\122"
|
||||
<Multi_key> <s> <a> <s> : "\"\\"
|
6
testsuite/gtk/compose/strings.expected
Normal file
6
testsuite/gtk/compose/strings.expected
Normal file
@ -0,0 +1,6 @@
|
||||
# n_seqs: 4
|
||||
# max_seq_len: 5
|
||||
<Uff20> <U73> <U61> <U73> <U0> : "\"\\"
|
||||
<Uff20> <U73> <U65> <U71> <U0> : "!a"
|
||||
<Uff20> <U73> <U65> <U71> <U75> : "?" # U3f
|
||||
<Uff20> <U75> <U62> <U32> <U33> : "QR"
|
320
testsuite/gtk/composetable.c
Normal file
320
testsuite/gtk/composetable.c
Normal file
@ -0,0 +1,320 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "../gtk/gtkcomposetable.h"
|
||||
#include "../gtk/gtkimcontextsimpleseqs.h"
|
||||
#include "testsuite/testutils.h"
|
||||
|
||||
static void
|
||||
append_escaped (GString *str,
|
||||
const char *s)
|
||||
{
|
||||
for (const char *p = s; *p; p = g_utf8_next_char (p))
|
||||
{
|
||||
gunichar ch = g_utf8_get_char (p);
|
||||
if (ch == '"')
|
||||
g_string_append (str, "\\\"");
|
||||
else if (ch == '\\')
|
||||
g_string_append (str, "\\\\");
|
||||
else if (g_unichar_isprint (ch))
|
||||
g_string_append_unichar (str, ch);
|
||||
else
|
||||
{
|
||||
guint n[8] = { 0, };
|
||||
int i = 0;
|
||||
while (ch != 0)
|
||||
{
|
||||
n[i++] = ch & 7;
|
||||
ch = ch >> 3;
|
||||
}
|
||||
for (; i >= 0; i--)
|
||||
g_string_append_printf (str, "\\%o", n[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
gtk_compose_table_print (GtkComposeTable *table)
|
||||
{
|
||||
int i, j;
|
||||
guint16 *seq;
|
||||
GString *str;
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
g_string_append_printf (str, "# n_seqs: %d\n# max_seq_len: %d\n",
|
||||
table->n_seqs,
|
||||
table->max_seq_len);
|
||||
|
||||
for (i = 0, seq = table->data; i < table->n_seqs; i++, seq += table->max_seq_len + 2)
|
||||
{
|
||||
gunichar value;
|
||||
char buf[8] = { 0 };
|
||||
|
||||
for (j = 0; j < table->max_seq_len; j++)
|
||||
g_string_append_printf (str, "<U%x> ", seq[j]);
|
||||
|
||||
value = (seq[table->max_seq_len] << 16) | seq[table->max_seq_len + 1];
|
||||
if ((value & (1 << 31)) != 0)
|
||||
{
|
||||
const char *out = &table->char_data[value & ~(1 << 31)];
|
||||
|
||||
g_string_append (str, ": \"");
|
||||
append_escaped (str, out);
|
||||
g_string_append (str, "\"\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_unichar_to_utf8 (value, buf);
|
||||
g_string_append_printf (str, ": \"%s\" # U%x\n", buf, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
generate_output (const char *file)
|
||||
{
|
||||
GSList *tables = NULL;
|
||||
GtkComposeTable *table;
|
||||
char *output;
|
||||
|
||||
tables = gtk_compose_table_list_add_file (tables, file);
|
||||
table = tables->data;
|
||||
output = gtk_compose_table_print (table);
|
||||
|
||||
g_print ("%s", output);
|
||||
}
|
||||
|
||||
static void
|
||||
compose_table_compare (gconstpointer data)
|
||||
{
|
||||
const char *basename = data;
|
||||
GSList *tables = NULL;
|
||||
GtkComposeTable *table;
|
||||
char *file;
|
||||
char *expected;
|
||||
char *output;
|
||||
char *diff;
|
||||
GError *error = NULL;
|
||||
|
||||
file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", basename, NULL);
|
||||
expected = g_strconcat (file, ".expected", NULL);
|
||||
|
||||
tables = gtk_compose_table_list_add_file (tables, file);
|
||||
|
||||
g_assert_true (g_slist_length (tables) == 1);
|
||||
|
||||
table = tables->data;
|
||||
|
||||
output = gtk_compose_table_print (table);
|
||||
diff = diff_with_file (expected, output, -1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
if (diff && diff[0])
|
||||
{
|
||||
g_print ("Resulting output doesn't match reference:\n%s", diff);
|
||||
g_test_fail ();
|
||||
}
|
||||
|
||||
g_free (output);
|
||||
g_free (file);
|
||||
g_free (expected);
|
||||
}
|
||||
|
||||
/* Check matching against a small table */
|
||||
static void
|
||||
compose_table_match (void)
|
||||
{
|
||||
GSList *tables = NULL;
|
||||
GtkComposeTable *table;
|
||||
char *file;
|
||||
guint16 buffer[8] = { 0, };
|
||||
gboolean finish, match, ret;
|
||||
GString *output;
|
||||
|
||||
output = g_string_new ("");
|
||||
|
||||
file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "match", NULL);
|
||||
|
||||
tables = gtk_compose_table_list_add_file (tables, file);
|
||||
|
||||
g_assert_true (g_slist_length (tables) == 1);
|
||||
|
||||
table = tables->data;
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
buffer[1] = 0;
|
||||
ret = gtk_compose_table_check (table, buffer, 1, &finish, &match, output);
|
||||
g_assert_true (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_false (match);
|
||||
g_assert_true (output->len == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_a;
|
||||
buffer[1] = 0;
|
||||
ret = gtk_compose_table_check (table, buffer, 1, &finish, &match, output);
|
||||
g_assert_false (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_false (match);
|
||||
g_assert_true (output->len == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
buffer[1] = GDK_KEY_s;
|
||||
buffer[2] = GDK_KEY_e;
|
||||
ret = gtk_compose_table_check (table, buffer, 3, &finish, &match, output);
|
||||
g_assert_true (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_false (match);
|
||||
g_assert_true (output->len == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
buffer[1] = GDK_KEY_s;
|
||||
buffer[2] = GDK_KEY_e;
|
||||
buffer[3] = GDK_KEY_q;
|
||||
ret = gtk_compose_table_check (table, buffer, 4, &finish, &match, output);
|
||||
g_assert_true (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_true (match);
|
||||
g_assert_cmpstr (output->str, ==, "!");
|
||||
|
||||
g_string_set_size (output, 0);
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
buffer[1] = GDK_KEY_s;
|
||||
buffer[2] = GDK_KEY_e;
|
||||
buffer[3] = GDK_KEY_q;
|
||||
buffer[4] = GDK_KEY_u;
|
||||
ret = gtk_compose_table_check (table, buffer, 5, &finish, &match, output);
|
||||
g_assert_true (ret);
|
||||
g_assert_true (finish);
|
||||
g_assert_true (match);
|
||||
g_assert_cmpstr (output->str, ==, "?");
|
||||
|
||||
g_string_free (output, TRUE);
|
||||
g_free (file);
|
||||
}
|
||||
|
||||
/* just check some random sequences */
|
||||
static void
|
||||
compose_table_match_compact (void)
|
||||
{
|
||||
const GtkComposeTableCompact table = {
|
||||
gtk_compose_seqs_compact,
|
||||
5,
|
||||
30,
|
||||
6
|
||||
};
|
||||
guint16 buffer[8] = { 0, };
|
||||
gboolean finish, match, ret;
|
||||
gunichar ch;
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
|
||||
ret = gtk_compose_table_compact_check (&table, buffer, 1, &finish, &match, &ch);
|
||||
g_assert_true (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_false (match);
|
||||
g_assert_true (ch == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_a;
|
||||
buffer[1] = GDK_KEY_b;
|
||||
buffer[2] = GDK_KEY_c;
|
||||
|
||||
ret = gtk_compose_table_compact_check (&table, buffer, 3, &finish, &match, &ch);
|
||||
g_assert_false (ret);
|
||||
g_assert_false (finish);
|
||||
g_assert_false (match);
|
||||
g_assert_true (ch == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_Multi_key;
|
||||
buffer[1] = GDK_KEY_parenleft;
|
||||
buffer[2] = GDK_KEY_j;
|
||||
buffer[3] = GDK_KEY_parenright;
|
||||
|
||||
ret = gtk_compose_table_compact_check (&table, buffer, 4, &finish, &match, &ch);
|
||||
g_assert_true (ret);
|
||||
g_assert_true (finish);
|
||||
g_assert_true (match);
|
||||
g_assert_true (ch == 0x24d9); /* CIRCLED LATIN SMALL LETTER J */
|
||||
}
|
||||
|
||||
static void
|
||||
match_algorithmic (void)
|
||||
{
|
||||
guint16 buffer[8] = { 0, };
|
||||
gboolean ret;
|
||||
gunichar ch;
|
||||
|
||||
buffer[0] = GDK_KEY_a;
|
||||
buffer[1] = GDK_KEY_b;
|
||||
|
||||
ret = gtk_check_algorithmically (buffer, 2, &ch);
|
||||
g_assert_false (ret);
|
||||
g_assert_true (ch == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_dead_abovering;
|
||||
buffer[1] = GDK_KEY_A;
|
||||
|
||||
ret = gtk_check_algorithmically (buffer, 2, &ch);
|
||||
g_assert_true (ret);
|
||||
g_assert_true (ch == 0xc5);
|
||||
|
||||
buffer[0] = GDK_KEY_A;
|
||||
buffer[1] = GDK_KEY_dead_abovering;
|
||||
|
||||
ret = gtk_check_algorithmically (buffer, 2, &ch);
|
||||
g_assert_false (ret);
|
||||
g_assert_true (ch == 0);
|
||||
|
||||
buffer[0] = GDK_KEY_dead_dasia;
|
||||
buffer[1] = GDK_KEY_dead_perispomeni;
|
||||
buffer[2] = GDK_KEY_Greek_alpha;
|
||||
|
||||
ret = gtk_check_algorithmically (buffer, 3, &ch);
|
||||
g_assert_true (ret);
|
||||
g_assert_true (ch == 0x1f07);
|
||||
|
||||
buffer[0] = GDK_KEY_dead_perispomeni;
|
||||
buffer[1] = GDK_KEY_dead_dasia;
|
||||
buffer[2] = GDK_KEY_Greek_alpha;
|
||||
|
||||
ret = gtk_check_algorithmically (buffer, 3, &ch);
|
||||
g_assert_true (ret);
|
||||
g_assert_true (ch == 0x1f07);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
char *dir;
|
||||
|
||||
dir = g_dir_make_tmp ("composetableXXXXXX", NULL);
|
||||
g_setenv ("XDG_CACHE_HOME", dir, TRUE);
|
||||
g_free (dir);
|
||||
|
||||
if (argc == 3 && strcmp (argv[1], "--generate") == 0)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
generate_output (argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gtk_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_data_func ("/compose-table/basic", "basic", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/long", "long", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/octal", "octal", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/hex", "hex", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/codepoint", "codepoint", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/multi", "multi", compose_table_compare);
|
||||
g_test_add_data_func ("/compose-table/strings", "strings", compose_table_compare);
|
||||
g_test_add_func ("/compose-table/match", compose_table_match);
|
||||
g_test_add_func ("/compose-table/match-compact", compose_table_match_compact);
|
||||
g_test_add_func ("/compose-table/match-algorithmic", match_algorithmic);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@ -103,6 +103,13 @@ tests = [
|
||||
# Tests that test private apis and therefore are linked against libgtk-4.a
|
||||
internal_tests = [
|
||||
{ 'name': 'bitmask' },
|
||||
{
|
||||
'name': 'composetable',
|
||||
'sources': [
|
||||
'composetable.c',
|
||||
'../testutils.c'
|
||||
],
|
||||
},
|
||||
{ 'name': 'constraint-solver' },
|
||||
{ 'name': 'rbtree-crash' },
|
||||
{ 'name': 'propertylookuplistmodel' },
|
||||
|
Loading…
Reference in New Issue
Block a user