#include #include "ibus.h" #include "ibuscomposetable.h" #define GREEN "\033[0;32m" #define RED "\033[0;31m" #define NC "\033[0m" IBusBus *m_bus; IBusComposeTable *m_compose_table; IBusEngine *m_engine; int m_retval; static gboolean window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data); static IBusEngine * create_engine_cb (IBusFactory *factory, const gchar *name, gpointer data) { static int i = 1; gchar *engine_path = g_strdup_printf ("/org/freedesktop/IBus/engine/simpletest/%d", i++); gchar *compose_path = NULL; const gchar * const *langs; const gchar * const *l; m_engine = ibus_engine_new_with_type (IBUS_TYPE_ENGINE_SIMPLE, name, engine_path, ibus_bus_get_connection (m_bus)); g_free (engine_path); langs = g_get_language_names (); for (l = langs; *l; l++) { if (g_str_has_prefix (*l, "en_US")) break; if (g_strcmp0 (*l, "C") == 0) break; compose_path = g_build_filename ("/usr/share/X11/locale", *l, "Compose", NULL); if (g_file_test (compose_path, G_FILE_TEST_EXISTS)) break; g_free (compose_path); compose_path = NULL; } if (compose_path != NULL) { m_compose_table = ibus_compose_table_new_with_file (compose_path); if (m_compose_table == NULL) g_warning ("Your locale uses en_US compose table."); else ibus_engine_simple_add_table (IBUS_ENGINE_SIMPLE (m_engine), m_compose_table->data, m_compose_table->max_seq_len, m_compose_table->n_seqs); } else { g_warning ("Your locale uses en_US compose file."); } return m_engine; } static gboolean register_ibus_engine () { IBusFactory *factory; IBusComponent *component; IBusEngineDesc *desc; m_bus = ibus_bus_new (); if (!ibus_bus_is_connected (m_bus)) { g_critical ("ibus-daemon is not running."); return FALSE; } factory = ibus_factory_new (ibus_bus_get_connection (m_bus)); g_signal_connect (factory, "create-engine", G_CALLBACK (create_engine_cb), NULL); component = ibus_component_new ( "org.freedesktop.IBus.SimpleTest", "Simple Engine Test", "0.0.1", "GPL", "Takao Fujiwara ", "https://github.com/ibus/ibus/wiki", "", "ibus"); desc = ibus_engine_desc_new ( "xkbtest:us::eng", "XKB Test", "XKB Test", "en", "GPL", "Takao Fujiwara ", "ibus-engine", "us"); ibus_component_add_engine (component, desc); ibus_bus_register_component (m_bus, component); return TRUE; } static gboolean finit (gpointer data) { m_retval = -1; g_warning ("time out"); gtk_main_quit (); return FALSE; } static void set_engine_cb (GObject *object, GAsyncResult *res, gpointer data) { IBusBus *bus = IBUS_BUS (object); GtkWidget *entry = GTK_WIDGET (data); GError *error = NULL; int i, j; int index_stride; if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) { g_warning ("set engine failed: %s", error->message); g_error_free (error); return; } if (m_compose_table == NULL) { gtk_main_quit (); return; } index_stride = m_compose_table->max_seq_len + 2; for (i = 0; i < (m_compose_table->n_seqs * index_stride); i += index_stride) { for (j = i; j < i + (index_stride - 1); j++) { guint keyval = m_compose_table->data[j]; guint keycode = 0; guint modifiers = 0; gboolean retval; if (keyval == 0) break; g_signal_emit_by_name (m_engine, "process-key-event", keyval, keycode, modifiers, &retval); modifiers |= IBUS_RELEASE_MASK; g_signal_emit_by_name (m_engine, "process-key-event", keyval, keycode, modifiers, &retval); } } g_signal_handlers_disconnect_by_func (entry, G_CALLBACK (window_focus_in_event_cb), NULL); g_timeout_add_seconds (10, finit, NULL); } static gboolean window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data) { g_assert (m_bus != NULL); ibus_bus_set_global_engine_async (m_bus, "xkbtest:us::eng", -1, NULL, set_engine_cb, entry); return FALSE; } static void window_inserted_text_cb (GtkEntryBuffer *buffer, guint position, const gchar *chars, guint nchars, gpointer data) { /* https://gitlab.gnome.org/GNOME/gtk/commit/9981f46e0b * The latest GTK does not emit "inserted-text" when the text is "". */ #if !GTK_CHECK_VERSION (3, 22, 16) static int n_loop = 0; #endif static guint stride = 0; guint i; int seq; gunichar code = g_utf8_get_char (chars); const gchar *test; GtkEntry *entry = GTK_ENTRY (data); g_assert (m_compose_table != NULL); #if !GTK_CHECK_VERSION (3, 22, 16) if (n_loop % 2 == 1) { n_loop = 0; return; } #endif i = stride + (m_compose_table->max_seq_len + 2) - 1; seq = (i + 1) / (m_compose_table->max_seq_len + 2); if (m_compose_table->data[i] == code) { test = GREEN "PASS" NC; } else { test = RED "FAIL" NC; m_retval = -1; } g_print ("%05d/%05d %s expected: %04X typed: %04X\n", seq, m_compose_table->n_seqs, test, m_compose_table->data[i], code); if (seq == m_compose_table->n_seqs) { gtk_main_quit (); return; } stride += m_compose_table->max_seq_len + 2; #if !GTK_CHECK_VERSION (3, 22, 16) n_loop++; #endif gtk_entry_set_text (entry, ""); } static void create_window () { GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); GtkWidget *entry = gtk_entry_new (); GtkEntryBuffer *buffer; g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (entry, "focus-in-event", G_CALLBACK (window_focus_in_event_cb), NULL); buffer = gtk_entry_get_buffer (GTK_ENTRY (entry)); g_signal_connect (buffer, "inserted-text", G_CALLBACK (window_inserted_text_cb), entry); gtk_container_add (GTK_CONTAINER (window), entry); gtk_widget_show_all (window); } int main (int argc, char *argv[]) { ibus_init (); gtk_init (&argc, &argv); if (!register_ibus_engine ()) return -1; create_window (); gtk_main (); return m_retval; }