Newer
Older
#include <gio/gio.h>
#include <glib-unix.h>
#include "zero-pinyin-service.h"
#include "zero-pinyin-service-generated.h"
#include "../sqlite3_util.h"
#include <sqlite3.h>
sqlite3 *db;
} AppData;
static gboolean
on_handle_get_candidates (ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
const gchar *preedit_str,
guint fetch_size,
AppData *appdata)
if (preedit_str == NULL || fetch_size == 0) {
g_dbus_method_invocation_return_dbus_error (
invocation,
"org.gtk.GDBus.Failed",
"Bad param");
}
g_message ("get_candidates for preedit_str=%s fetch_size=%u",
preedit_str, fetch_size);
GVariant *result = NULL;
GVariantBuilder *candidates_builder = NULL;
GVariantBuilder *matched_lengths_builder = NULL;
/* get_candidates_test (preedit_str, fetch_size, candidates_builder, matched_lengths_builder); */
candidates_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
matched_lengths_builder = g_variant_builder_new (G_VARIANT_TYPE ("au"));
get_candidates (appdata->db, preedit_str, fetch_size, candidates_builder, matched_lengths_builder);
result = g_variant_new ("(asau)", candidates_builder, matched_lengths_builder);
g_assert_nonnull (result);
/* result is a GVarient tuple of two dbus arrays */
g_dbus_method_invocation_return_value (invocation, result);
g_variant_builder_unref (candidates_builder);
g_variant_builder_unref (matched_lengths_builder);
on_handle_quit (ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
AppData *appdata)
g_application_quit (appdata->app);
return TRUE;
}
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
AppData *appdata = (AppData*) user_data;
GError *err = NULL;
g_message ("on_bus_acquired() name=%s", name);
appdata->interface = zero_pinyin_service_skeleton_new ();
g_signal_connect (appdata->interface,
"handle-get-candidates",
G_CALLBACK (on_handle_get_candidates),
appdata);
g_signal_connect (appdata->interface,
"handle-quit",
G_CALLBACK (on_handle_quit),
appdata);
g_dbus_interface_skeleton_export (
G_DBUS_INTERFACE_SKELETON (appdata->interface),
ZERO_PINYIN_OBJECT_PATH,
&err);
if (err) {
g_warning ("export interface at %s failed: %s",
ZERO_PINYIN_OBJECT_PATH, err->message);
g_application_quit (G_APPLICATION (appdata->app));
g_message ("interface exported at %s", ZERO_PINYIN_OBJECT_PATH);
}
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_message ("on_name_acquired() name=%s", name);
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_message ("on_name_lost() name=%s", name);
}
static void
config_dbus_service (AppData *appdata)
{
appdata->owner_id = g_bus_own_name (
G_BUS_TYPE_SESSION,
ZERO_PINYIN_WELL_KNOWN_NAME,
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT|G_BUS_NAME_OWNER_FLAGS_REPLACE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
appdata,
NULL);
g_assert_cmpint (appdata->owner_id, >, 0);
}
/**
* handle SIGTERM gracefully.
*/
static gboolean
on_sigterm_received (gpointer user_data)
{
AppData *appdata = (AppData*) user_data;
g_application_quit (appdata->app);
return G_SOURCE_REMOVE;
}
/**
* init appdata->db
*/
config_db (AppData* appdata)
gboolean rb = FALSE;
static const char* SQLITE3_MEMORY_DB = ":memory:";
sqlite3* db = NULL;
gchar* sql = NULL;
ri = sqlite3_open (SQLITE3_MEMORY_DB, &db);
if (ri != SQLITE_OK) {
g_warning ("sqlite3_open :memory: db failed, query will not work.");
goto db_fail;
}
g_assert_nonnull (db);
/* TODO make db path configurable */
/* TODO remove user name in db path */
sql = sqlite3_mprintf ("ATTACH %Q AS maindb", "/home/sylecn/.cache/ibus/pinyin/main.db");
rb = sqlite3_exec_simple (db, sql);
if (! rb) {
g_warning ("attach maindb failed, query will not work.");
goto attach_fail;
}
sqlite3_free (sql);
/* TODO make db path configurable */
sql = sqlite3_mprintf ("ATTACH %Q AS userdb", "/home/sylecn/.cache/ibus/pinyin/user-1.0.db");
rb = sqlite3_exec_simple (db, sql);
if (! rb) {
g_warning ("attach userdb failed, query will not work.");
goto attach_fail;
}
appdata->db = db;
return;
attach_fail:
sqlite3_free (sql);
sqlite3_close (db);
db_fail:
appdata->db = NULL;
}
/**
* allow graceful shutdown by Ctrl-C and SIGTERM.
*/
static void
setup_sigint_sigterm_handler (AppData *appdata)
{
GSource *source = NULL;
source = g_unix_signal_source_new (SIGTERM);
g_source_set_callback (source, on_sigterm_received, appdata, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
source = g_unix_signal_source_new (SIGINT);
g_source_set_callback (source, on_sigterm_received, appdata, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
}
on_startup (GApplication* app,
AppData* appdata)
{
g_message ("zero-pinyin-service startup()");
config_db (appdata);
config_dbus_service (appdata);
setup_sigint_sigterm_handler (appdata);
g_application_hold (app);
}
static void
on_activate (GApplication *app,
AppData *appdata)
{
g_message ("zero-pinyin-service activate()");
}
static void
on_shutdown (GApplication *app,
AppData *appdata)
{
g_message ("zero-pinyin-service shutdown()");
if (appdata->owner_id > 0) {
g_bus_unown_name (appdata->owner_id);
appdata->owner_id = 0;
}
if (appdata->db != NULL) {
sqlite3_close (appdata->db);
appdata->db = NULL;
}
}
* provides zero-pinyin-service dbus service.
* it's a console app (GApplication) based on glib and gio.
app = g_application_new ("com.emacsos.zero.ZeroPinyinServiceApp",
G_APPLICATION_FLAGS_NONE);
g_assert_nonnull (app);
appdata.app = app;
g_signal_connect (app, "startup", G_CALLBACK (on_startup), &appdata);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), &appdata);
g_signal_connect (app, "shutdown", G_CALLBACK (on_shutdown), &appdata);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}