/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* vim:set et sts=4: */
/* ibus - The Input Bus
* Copyright (C) 2011 Google, Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <string.h>
#include "ibus.h"
static IBusBus *bus;
static void
call_next_async_function (IBusInputContext *context);
static gboolean
fatal_handler(const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
if (!g_strcmp0 (message, "org.freedesktop.IBus.InputContext.GetEngine: GDBus.Error:org.freedesktop.DBus.Error.Failed: Input context does not have engine."))
return FALSE; /* do not call abort. */
return TRUE;
}
static gchar *
get_last_engine_id (const GList *engines)
{
const char *result = NULL;
for (; engines; engines = g_list_next (engines)) {
IBusEngineDesc *engine_desc = IBUS_ENGINE_DESC (engines->data);
g_assert (engine_desc);
result = ibus_engine_desc_get_name (engine_desc);
}
return g_strdup (result);
}
static void
call_basic_ipcs (IBusInputContext *context)
{
ibus_input_context_set_cursor_location (context, 0, 0, 1, 1);
ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS);
ibus_input_context_property_activate (context, "dummy.prop.name", PROP_STATE_CHECKED);
ibus_input_context_reset (context);
/* When enable() is called, ibus-daemon may start a global (or preloaded,
* or default) engine in an asynchrnous manner and return immediately.
* Therefore, it is not guaranteed that ibus_input_context_is_enabled()
* returns TRUE. */
ibus_input_context_focus_in (context);
}
static void
test_input_context (void)
{
GList *engines;
gchar *active_engine_name = NULL;
IBusInputContext *context;
IBusEngineDesc *engine_desc;
gchar *current_ic;
context = ibus_bus_create_input_context (bus, "test");
call_basic_ipcs (context);
engines = ibus_bus_list_active_engines (bus);
if (engines != NULL) {
active_engine_name = get_last_engine_id (engines);
} else {
active_engine_name = g_strdup ("dummy");
}
g_assert (active_engine_name);
g_debug ("Use '%s' for testing.", active_engine_name);
ibus_input_context_set_engine (context, active_engine_name);
current_ic = ibus_bus_current_input_context (bus);
g_assert (!strcmp (current_ic, g_dbus_proxy_get_object_path ((GDBusProxy *)context)));
g_test_log_set_fatal_handler (fatal_handler, NULL);
engine_desc = ibus_input_context_get_engine (context);
if (engine_desc) {
/* FIXME race condition between ibus_input_context_set_engine and _get_engine.
* ibus_input_context_get_engine is not guaranteed to return non-NULL
* (even if we use synchronous set_engine()) because ibus-daemon sets a context
* engine in an asynchronous manner. See _context_request_engine_cb in
* ibusimpl.c which handles context_signals[REQUEST_ENGINE] signal. */
g_assert (!strcmp (active_engine_name, ibus_engine_desc_get_name(engine_desc)));
g_object_unref (engine_desc);
engine_desc = NULL;
}
ibus_input_context_process_key_event (context, 0, 0, 0);
/* An engine is set. Try to call basic IPCs again. */
call_basic_ipcs (context);
g_free (current_ic);
g_object_unref (context);
g_free (active_engine_name);
g_list_foreach (engines, (GFunc) g_object_unref, NULL);
g_list_free (engines);
}
static void
finish_get_engine_async (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
IBusInputContext *context = IBUS_INPUT_CONTEXT (source_object);
GError *error = NULL;
IBusEngineDesc *desc = ibus_input_context_get_engine_async_finish (context,
res,
&error);
if (desc) {
g_object_unref (desc);
}
g_debug ("ibus_context_get_engine_async_finish: OK");
call_next_async_function (context);
}
static void
start_get_engine_async (IBusInputContext *context)
{
ibus_input_context_get_engine_async (context,
-1, /* timeout */
NULL, /* cancellable */
finish_get_engine_async,
NULL); /* user_data */
}
static void
finish_process_key_event_async (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
IBusInputContext *context = IBUS_INPUT_CONTEXT (source_object);
GError *error = NULL;
gboolean result = ibus_input_context_process_key_event_async_finish (context,
res,
&error);
g_assert (result || error == NULL);
g_debug ("ibus_context_process_key_event_async_finish: OK");
call_next_async_function (context);
}
static void
start_process_key_event_async (IBusInputContext *context)
{
ibus_input_context_process_key_event_async (context,
0, 0, 0,
-1, /* timeout */
NULL, /* cancellable */
finish_process_key_event_async,
NULL); /* user_data */
}
static gboolean
test_async_apis_finish (gpointer user_data)
{
ibus_quit ();
return FALSE;
}
static void
test_async_apis (void)
{
g_debug ("start");
IBusInputContext *context;
context = ibus_bus_create_input_context (bus, "test");
call_basic_ipcs (context);
call_next_async_function (context);
ibus_main ();
}
static void
call_next_async_function (IBusInputContext *context)
{
static void (*async_functions[])(IBusInputContext *) = {
start_get_engine_async,
start_process_key_event_async,
};
static guint index = 0;
// Use g_timeout_add to make sure test_async_apis finishes even if async_functions is empty.
if (index >= G_N_ELEMENTS (async_functions))
g_timeout_add (1, test_async_apis_finish, NULL);
else
(*async_functions[index++])(context);
}
gint
main (gint argc,
gchar **argv)
{
gint result;
ibus_init ();
g_test_init (&argc, &argv, NULL);
bus = ibus_bus_new ();
g_test_add_func ("/ibus/input_context", test_input_context);
g_test_add_func ("/ibus/input_context_async_with_callback", test_async_apis);
result = g_test_run ();
g_object_unref (bus);
return result;
}