mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-28 19:27:44 +00:00
418 lines
12 KiB
C
418 lines
12 KiB
C
/* vim:set et sts=4: */
|
|
|
|
/*
|
|
* Keyman Input Method for IBUS (The Input Bus)
|
|
*
|
|
* Copyright (C) 2018-2023 SIL Global
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 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
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU 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
|
|
*
|
|
*/
|
|
|
|
/*
|
|
This file is based on work from Mousetweaks
|
|
Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
|
|
*/
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#include "engine.h"
|
|
#include "keyman-service.h"
|
|
|
|
struct _KeymanServicePrivate
|
|
{
|
|
guint owner_id;
|
|
GDBusNodeInfo *ispec;
|
|
IBusEngine *engine;
|
|
|
|
gchar * name;
|
|
gchar * ldmlfile;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_NAME,
|
|
PROP_LDMLFILE
|
|
};
|
|
|
|
static const gchar introspection_xml[] =
|
|
"<node>"
|
|
" <interface name='com.Keyman'>"
|
|
" <property type='s' name='LDMLFile' access='read'/>"
|
|
" <property type='s' name='Name' access='read'/>"
|
|
" <method name='SendText'>"
|
|
" <arg type='s' name='text' direction='in' />"
|
|
" </method>"
|
|
" </interface>"
|
|
"</node>";
|
|
|
|
static void km_service_bus_acquired (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer data);
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE(KeymanService, km_service, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
km_service_init (KeymanService *service)
|
|
{
|
|
KeymanServicePrivate *priv;
|
|
GError *error = NULL;
|
|
|
|
g_message("WDG: km_service_init");
|
|
|
|
service->priv = priv = (KeymanServicePrivate*)km_service_get_instance_private(service);
|
|
|
|
priv->name = g_strdup ("None");
|
|
priv->ldmlfile = g_strdup ("");
|
|
priv->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
KEYMAN_DBUS_NAME,
|
|
G_BUS_NAME_OWNER_FLAGS_NONE,
|
|
km_service_bus_acquired,
|
|
NULL, NULL,
|
|
service, NULL);
|
|
priv->ispec = g_dbus_node_info_new_for_xml (introspection_xml, &error);
|
|
if (error)
|
|
{
|
|
g_warning ("%s\n", error->message);
|
|
g_error_free (error);
|
|
}
|
|
}
|
|
|
|
static void
|
|
km_service_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
KeymanService *service = KM_SERVICE (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
if (service->priv->name)
|
|
{
|
|
g_free(service->priv->name);
|
|
}
|
|
service->priv->name = g_value_dup_string (value);
|
|
break;
|
|
case PROP_LDMLFILE:
|
|
if (service->priv->ldmlfile)
|
|
{
|
|
g_free(service->priv->ldmlfile);
|
|
}
|
|
service->priv->ldmlfile = g_value_dup_string (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
km_service_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
KeymanService *service = KM_SERVICE (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
g_value_set_string (value, service->priv->name);
|
|
break;
|
|
case PROP_LDMLFILE:
|
|
g_value_set_string (value, service->priv->ldmlfile);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
km_service_dispose (GObject *object)
|
|
{
|
|
g_message("WDG: km_service_dispose");
|
|
KeymanServicePrivate *priv = KM_SERVICE (object)->priv;
|
|
|
|
if (priv->owner_id)
|
|
{
|
|
g_bus_unown_name (priv->owner_id);
|
|
priv->owner_id = 0;
|
|
}
|
|
|
|
if (priv->ispec)
|
|
{
|
|
g_dbus_node_info_unref (priv->ispec);
|
|
priv->ispec = NULL;
|
|
}
|
|
|
|
if (priv->name)
|
|
{
|
|
g_free(priv->name);
|
|
}
|
|
|
|
if (priv->ldmlfile)
|
|
{
|
|
g_free(priv->ldmlfile);
|
|
}
|
|
|
|
G_OBJECT_CLASS (km_service_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
km_service_class_init (KeymanServiceClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->get_property = km_service_get_property;
|
|
object_class->set_property = km_service_set_property;
|
|
object_class->dispose = km_service_dispose;
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_NAME,
|
|
g_param_spec_string ("name",
|
|
"Name",
|
|
"Name of the currently active Keyman keyboard",
|
|
"None",
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (object_class,
|
|
PROP_LDMLFILE,
|
|
g_param_spec_string ("ldmlfile",
|
|
"LDML file",
|
|
"On screen keyboard file for the currently active Keyman keyboard",
|
|
"",
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS));
|
|
}
|
|
|
|
static void
|
|
handle_method_call(
|
|
GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *method_name,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation,
|
|
gpointer user_data)
|
|
{
|
|
KeymanService *service = KM_SERVICE(user_data);
|
|
|
|
gsize sz;
|
|
if (g_strcmp0(method_name, "SendText") == 0) {
|
|
GVariant *param = g_variant_get_child_value(parameters, 0);
|
|
gchar *text = g_variant_dup_string(param, &sz);
|
|
|
|
km_service_send_text(service, text);
|
|
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
|
|
g_free(text);
|
|
g_variant_unref(param);
|
|
}
|
|
}
|
|
|
|
static GVariant *
|
|
handle_get_property (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *path,
|
|
const gchar *interface_name,
|
|
const gchar *property,
|
|
GError **error,
|
|
KeymanService *service)
|
|
{
|
|
GVariant *ret = NULL;
|
|
|
|
if (g_strcmp0 (property, "Name") == 0)
|
|
{
|
|
ret = g_variant_new_string (service->priv->name);
|
|
}
|
|
else if (g_strcmp0 (property, "LDMLFile") == 0)
|
|
{
|
|
ret = g_variant_new_string (service->priv->ldmlfile);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
handle_set_property (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *path,
|
|
const gchar *interface,
|
|
const gchar *property,
|
|
GVariant *value,
|
|
GError **error,
|
|
KeymanService *service)
|
|
{
|
|
gsize sz;
|
|
if (g_strcmp0 (property, "Name") == 0)
|
|
{
|
|
km_service_set_name (service, g_variant_dup_string (value, &sz));
|
|
}
|
|
else if (g_strcmp0 (property, "LDMLFile") == 0)
|
|
{
|
|
km_service_set_ldmlfile (service, g_variant_dup_string (value, &sz));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static const GDBusInterfaceVTable interface_vtable =
|
|
{
|
|
(GDBusInterfaceMethodCallFunc)handle_method_call,
|
|
(GDBusInterfaceGetPropertyFunc)handle_get_property,
|
|
(GDBusInterfaceSetPropertyFunc)handle_set_property
|
|
};
|
|
|
|
static void
|
|
emit_property_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
GDBusConnection *connection)
|
|
{
|
|
KeymanService *service = KM_SERVICE (object);
|
|
GError *error = NULL;
|
|
GVariantBuilder builder, inv_builder;
|
|
GVariant *prop_v;
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
|
|
g_variant_builder_init (&inv_builder, G_VARIANT_TYPE ("as"));
|
|
|
|
if (g_strcmp0 (pspec->name, "name") == 0)
|
|
{
|
|
g_variant_builder_add (&builder, "{sv}", "Name",
|
|
g_variant_new_string (service->priv->name));
|
|
}
|
|
else if (g_strcmp0 (pspec->name, "ldmlfile") == 0)
|
|
{
|
|
g_variant_builder_add (&builder, "{sv}", "LDMLFile",
|
|
g_variant_new_string (service->priv->ldmlfile));
|
|
}
|
|
|
|
prop_v = g_variant_new ("(sa{sv}as)",
|
|
KEYMAN_DBUS_IFACE,
|
|
&builder, &inv_builder);
|
|
|
|
if (!g_dbus_connection_emit_signal (connection, NULL,
|
|
KEYMAN_DBUS_PATH,
|
|
"org.freedesktop.DBus.Properties",
|
|
"PropertiesChanged",
|
|
prop_v, &error))
|
|
{
|
|
g_warning ("%s\n", error->message);
|
|
g_error_free (error);
|
|
}
|
|
}
|
|
|
|
static void
|
|
km_service_bus_acquired (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer data)
|
|
{
|
|
KeymanService *service = data;
|
|
if (service->priv->ispec) {
|
|
GError *error = NULL;
|
|
|
|
g_dbus_connection_register_object (connection,
|
|
KEYMAN_DBUS_PATH,
|
|
service->priv->ispec->interfaces[0],
|
|
&interface_vtable,
|
|
service, NULL, &error);
|
|
if (error)
|
|
{
|
|
g_warning ("%s", error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
g_signal_connect (service, "notify",
|
|
G_CALLBACK (emit_property_changed), connection);
|
|
}
|
|
}
|
|
|
|
KeymanService *
|
|
km_service_get_default(IBusEngine *engine)
|
|
{
|
|
static KeymanService *service = NULL;
|
|
|
|
// if (service)
|
|
// {
|
|
// g_free(service);
|
|
// service = g_object_new (KM_TYPE_SERVICE, NULL);
|
|
// g_object_add_weak_pointer (G_OBJECT (service), (gpointer *) &service);
|
|
// }
|
|
if (!service)
|
|
{
|
|
service = g_object_new(KM_TYPE_SERVICE, NULL);
|
|
g_object_add_weak_pointer (G_OBJECT (service), (gpointer *) &service);
|
|
}
|
|
|
|
KeymanServicePrivate *priv = KM_SERVICE(service)->priv;
|
|
priv->engine = engine;
|
|
|
|
return service;
|
|
}
|
|
|
|
void
|
|
km_service_set_name (KeymanService *service,
|
|
const gchar *name)
|
|
{
|
|
g_return_if_fail (KM_IS_SERVICE (service));
|
|
|
|
if (g_strcmp0(name,service->priv->name) != 0)
|
|
{
|
|
g_free(service->priv->name);
|
|
service->priv->name = g_strdup(name);
|
|
g_object_notify (G_OBJECT (service), "name");
|
|
}
|
|
}
|
|
|
|
// const gchar *
|
|
// km_service_get_name (KeymanService *service)
|
|
// {
|
|
// g_return_val_if_fail (KM_IS_SERVICE (service), -1);
|
|
|
|
// return service->priv->name;
|
|
// }
|
|
|
|
void
|
|
km_service_set_ldmlfile (KeymanService *service,
|
|
const gchar *xml)
|
|
{
|
|
g_return_if_fail (KM_IS_SERVICE (service));
|
|
|
|
if (g_strcmp0(xml,service->priv->ldmlfile) != 0)
|
|
{
|
|
g_free(service->priv->ldmlfile);
|
|
service->priv->ldmlfile = g_strdup(xml);
|
|
g_object_notify (G_OBJECT (service), "ldmlfile");
|
|
}
|
|
}
|
|
|
|
// const gchar *
|
|
// km_service_get_ldmlfile (KeymanService *service)
|
|
// {
|
|
// g_return_val_if_fail (KM_IS_SERVICE (service), -1);
|
|
|
|
// return service->priv->ldmlfile;
|
|
// }
|
|
|
|
void
|
|
km_service_send_text(KeymanService *service, const gchar *text) {
|
|
g_return_if_fail(KM_IS_SERVICE(service));
|
|
|
|
// engine will be NULL unless a keyman keyboard is active
|
|
if (!service->priv->engine)
|
|
return;
|
|
|
|
ibus_keyman_set_text(service->priv->engine, text);
|
|
}
|