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;
on_handle_get_candidates(ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
const gchar *preedit_str,
guint fetch_size,
AppData *appdata)
if (preedit_str == NULL || fetch_size == 0) {
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;
GVariantBuilder *candidates_pinyin_indices = 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"));
candidates_pinyin_indices = g_variant_builder_new(G_VARIANT_TYPE("aa(ii)"));
get_candidates(appdata->db, preedit_str, fetch_size, candidates_builder, matched_lengths_builder, candidates_pinyin_indices);
result = g_variant_new("(asauaa(ii))", candidates_builder, matched_lengths_builder, candidates_pinyin_indices);
g_assert_nonnull(result);
g_dbus_method_invocation_return_value(invocation, result);
g_variant_builder_unref(candidates_builder);
g_variant_builder_unref(matched_lengths_builder);
g_variant_builder_unref(candidates_pinyin_indices);
on_handle_commit_candidate(ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
const gchar *candidate,
GVariant *candidate_pinyin_indices,
AppData *appdata)
commit_candidate(appdata->db, candidate, candidate_pinyin_indices);
g_dbus_method_invocation_return_value(invocation, NULL);
on_handle_delete_candidate(ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
const char *candidate,
AppData *appdata)
g_dbus_method_invocation_return_value(invocation, NULL);
g_message("delete single character %s is a no-op", candidate);
g_dbus_method_invocation_return_value(invocation, NULL);
/* insert phrase to userdb.not_phrase table. */
char *sql = NULL;
gboolean rb = FALSE;
sql = sqlite3_mprintf("INSERT INTO userdb.not_phrase (phrase) VALUES (%Q);", candidate);
rb = sqlite3_exec_simple(appdata->db, sql);
g_warning("insert phrase to not_phrase table failed");
/* delete phrase from userdb.py_phrase_x table. */
guint table_suffix = len - 1;
sql = sqlite3_mprintf("DELETE FROM userdb.py_phrase_%u WHERE phrase = %Q;", table_suffix, candidate);
rb = sqlite3_exec_simple(appdata->db, sql);
g_warning("delete phrase from py_phrase_%u table failed", table_suffix);
g_dbus_method_invocation_return_value(invocation, NULL);
on_handle_quit(ZeroPinyinService *object,
GDBusMethodInvocation *invocation,
AppData *appdata)
g_application_quit(appdata->app);
g_dbus_method_invocation_return_value(invocation, NULL);
on_bus_acquired(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
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-commit-candidate",
G_CALLBACK(on_handle_commit_candidate),
appdata);
g_signal_connect(appdata->interface,
"handle-delete-candidate",
G_CALLBACK(on_handle_delete_candidate),
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_error_free(err);
g_application_quit(G_APPLICATION(appdata->app));
g_message("interface exported at %s", ZERO_PINYIN_OBJECT_PATH);
on_name_acquired(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
on_name_lost(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
/* this won't happen if this is the only app that tries to take the
* name, because GApplication already have primary instance
* concept. None primary instance will just send 'activate' signal to
* primary instance and exit. They will not try to register ibus at
* all. */
g_message("on_name_lost() name=%s exiting", name);
g_application_quit(G_APPLICATION(appdata->app));
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
AppData *appdata = (AppData *) user_data;
g_application_quit(appdata->app);
/**
* init appdata->db
*/
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;
}
/* 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);
g_warning("attach maindb failed, query will not work.");
goto attach_fail;
}
/* 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);
g_warning("attach userdb failed, query will not work.");
goto attach_fail;
}
sql = "CREATE TABLE IF NOT EXISTS userdb.not_phrase (phrase TEXT UNIQUE);";
g_warning("create userdb.not_phrase table failed, query will not work.");
sql = NULL;
goto attach_fail;
}
appdata->db = db;
return;
attach_fail:
db_fail:
appdata->db = NULL;
}
/**
* allow graceful shutdown by Ctrl-C and SIGTERM.
*/
static void
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)
}
static void
on_shutdown(GApplication *app,
AppData *appdata)
if (appdata->owner_id > 0) {
appdata->owner_id = 0;
}
if (appdata->db != NULL) {
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);
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);