#include <gtk/gtk.h>
#include "ibus.h"
#include "ibuscomposetable.h"
#define GREEN "\033[0;32m"
#define RED "\033[0;31m"
#define NC "\033[0m"
IBusBus *m_bus;
gchar *m_compose_file;
IBusComposeTable *m_compose_table;
IBusEngine *m_engine;
gchar *m_srcdir;
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);
if (m_compose_file) {
compose_path = g_build_filename (m_srcdir, m_compose_file, NULL);
} else {
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 <takao.fujiwara1@gmail.com>",
"https://github.com/ibus/ibus/wiki",
"",
"ibus");
desc = ibus_engine_desc_new (
"xkbtest:us::eng",
"XKB Test",
"XKB Test",
"en",
"GPL",
"Takao Fujiwara <takao.fujiwara1@gmail.com>",
"ibus-engine",
"us");
ibus_component_add_engine (component, desc);
ibus_bus_register_component (m_bus, component);
return TRUE;
}
static gboolean
finit (gpointer data)
{
g_test_incomplete ("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)) {
gchar *msg = g_strdup_printf ("set engine failed: %s", error->message);
g_test_incomplete (msg);
g_free (msg);
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;
g_test_fail ();
}
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);
}
static void
test_compose (void)
{
GLogLevelFlags flags;
if (!register_ibus_engine ()) {
g_test_fail ();
return;
}
create_window ();
/* FIXME:
* IBusIMContext opens GtkIMContextSimple as the slave and
* GtkIMContextSimple opens the compose table on el_GR.UTF-8, and the
* multiple outputs in el_GR's compose causes a warning in gtkcomposetable
* and the warning always causes a fatal in GTest:
" "GTK+ supports to output one char only: "
*/
flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
gtk_main ();
g_log_set_always_fatal (flags);
}
int
main (int argc, char *argv[])
{
const gchar *test_name;
gchar *test_path;
ibus_init ();
/* Avoid a warning of "AT-SPI: Could not obtain desktop path or name"
* with gtk_main().
*/
g_setenv ("NO_AT_BRIDGE", "1", TRUE);
g_test_init (&argc, &argv, NULL);
gtk_init (&argc, &argv);
m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup (".");
m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE"));
#if GLIB_CHECK_VERSION (2, 58, 0)
test_name = g_get_language_names_with_category ("LC_CTYPE")[0];
#else
test_name = g_getenv ("LANG");
#endif
test_path = g_build_filename ("/ibus-compose", test_name, NULL);
g_test_add_func (test_path, test_compose);
g_free (test_path);
return g_test_run ();
}