Add Ctrl+space customization.
[platform/upstream/ibus.git] / src / ibusfactory.c
index 738c150..54a94fe 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
@@ -18,9 +19,9 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-
 #include "ibusfactory.h"
 #include "ibusengine.h"
+#include "ibusmarshalers.h"
 #include "ibusshare.h"
 #include "ibusinternal.h"
 
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_FACTORY, IBusFactoryPrivate))
 
 enum {
+    CREATE_ENGINE,
     LAST_SIGNAL,
 };
 
+enum {
+    PROP_0,
+};
+
 /* IBusFactoryPriv */
 struct _IBusFactoryPrivate {
     guint id;
-    IBusConnection *connection;
     GList          *engine_list;
     GHashTable     *engine_table;
 };
-typedef struct _IBusFactoryPrivate IBusFactoryPrivate;
+
+static guint            factory_signals[LAST_SIGNAL] = { 0 };
 
 /* functions prototype */
-static void     ibus_factory_class_init     (IBusFactoryClass   *klass);
-static void     ibus_factory_init           (IBusFactory        *factory);
-static void     ibus_factory_destroy        (IBusFactory        *factory);
-static gboolean ibus_factory_ibus_message   (IBusFactory        *factory,
-                                             IBusConnection     *connection,
-                                             IBusMessage        *message);
+static void      ibus_factory_destroy        (IBusFactory        *factory);
+static void      ibus_factory_set_property   (IBusFactory        *engine,
+                                              guint               prop_id,
+                                              const GValue       *value,
+                                              GParamSpec         *pspec);
+static void      ibus_factory_get_property   (IBusFactory        *factory,
+                                              guint               prop_id,
+                                              GValue             *value,
+                                              GParamSpec         *pspec);
+static void      ibus_factory_service_method_call
+                                              (IBusService        *service,
+                                               GDBusConnection    *connection,
+                                               const gchar        *sender,
+                                               const gchar        *object_path,
+                                               const gchar        *interface_name,
+                                               const gchar        *method_name,
+                                               GVariant           *parameters,
+                                               GDBusMethodInvocation
+                                                                  *invocation);
+static GVariant *ibus_factory_service_get_property
+                                             (IBusService        *service,
+                                              GDBusConnection    *connection,
+                                              const gchar        *sender,
+                                              const gchar        *object_path,
+                                              const gchar        *interface_name,
+                                              const gchar        *property_name,
+                                              GError            **error);
+static gboolean  ibus_factory_service_set_property
+                                             (IBusService        *service,
+                                              GDBusConnection    *connection,
+                                              const gchar        *sender,
+                                              const gchar        *object_path,
+                                              const gchar        *interface_name,
+                                              const gchar        *property_name,
+                                              GVariant           *value,
+                                              GError            **error);
+static void      ibus_factory_engine_destroy_cb
+                                             (IBusEngine         *engine,
+                                              IBusFactory        *factory);
+
+G_DEFINE_TYPE (IBusFactory, ibus_factory, IBUS_TYPE_SERVICE)
+
+static const gchar introspection_xml[] =
+    "<node>"
+    "  <interface name='org.freedesktop.IBus.Factory'>"
+    "    <method name='CreateEngine'>"
+    "      <arg direction='in'  type='s' name='name' />"
+    "      <arg direction='out' type='o' />"
+    "    </method>"
+    "  </interface>"
+    "</node>";
+
+static IBusEngine *
+ibus_factory_real_create_engine (IBusFactory    *factory,
+                                 const gchar    *engine_name)
+{
+    GType engine_type;
+    gchar *object_path = NULL;
+    IBusEngine *engine = NULL;
 
-static void     _engine_destroy_cb          (IBusEngine         *engine,
-                                             IBusFactory        *factory);
+    engine_type = (GType) g_hash_table_lookup (factory->priv->engine_table,
+                                               engine_name);
 
-static IBusServiceClass *factory_parent_class = NULL;
+    g_return_val_if_fail (engine_type != G_TYPE_INVALID, NULL);
 
-GType
-ibus_factory_get_type (void)
-{
-    static GType type = 0;
-
-    static const GTypeInfo type_info = {
-        sizeof (IBusFactoryClass),
-        (GBaseInitFunc)     NULL,
-        (GBaseFinalizeFunc) NULL,
-        (GClassInitFunc)    ibus_factory_class_init,
-        NULL,               /* class finalize */
-        NULL,               /* class data */
-        sizeof (IBusFactory),
-        0,
-        (GInstanceInitFunc) ibus_factory_init,
-    };
-
-    if (type == 0) {
-        type = g_type_register_static (IBUS_TYPE_SERVICE,
-                    "IBusFactory",
-                    &type_info,
-                    (GTypeFlags) 0);
-    }
-    return type;
+    object_path = g_strdup_printf ("/org/freedesktop/IBus/Engine/%d",
+                                   ++factory->priv->id);
+    engine = ibus_engine_new_with_type (engine_type,
+                                        engine_name,
+                                        object_path,
+                                        ibus_service_get_connection ((IBusService *)factory));
+    g_free (object_path);
+
+    return engine;
 }
 
-IBusFactory *
-ibus_factory_new (IBusConnection *connection)
+static gboolean
+_ibus_factory_create_engine_accumulator (GSignalInvocationHint *ihint,
+                                         GValue                *return_accu,
+                                         const GValue          *handler_return,
+                                         gpointer               dummy)
 {
-    g_assert (IBUS_IS_CONNECTION (connection));
-
-    IBusFactory *factory;
-    IBusFactoryPrivate *priv;
+    gboolean retval = TRUE;
+    GObject *object = g_value_get_object (handler_return);
 
-    factory = (IBusFactory *) g_object_new (IBUS_TYPE_FACTORY,
-                                            "path", IBUS_PATH_FACTORY,
-                                            NULL);
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
-
-    priv->connection = g_object_ref (connection);
-    ibus_service_add_to_connection ((IBusService *)factory, connection);
+    if (object != NULL) {
+        g_value_copy (handler_return, return_accu);
+        retval = FALSE;
+    }
 
-    return factory;
+    return retval;
 }
 
 static void
-ibus_factory_class_init (IBusFactoryClass *klass)
+ibus_factory_class_init (IBusFactoryClass *class)
 {
-    // GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
-
-    factory_parent_class = (IBusServiceClass *) g_type_class_peek_parent (klass);
+    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
 
-    g_type_class_add_private (klass, sizeof (IBusFactoryPrivate));
+    gobject_class->set_property = (GObjectSetPropertyFunc) ibus_factory_set_property;
+    gobject_class->get_property = (GObjectGetPropertyFunc) ibus_factory_get_property;
 
     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_factory_destroy;
 
-    IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) ibus_factory_ibus_message;
-
+    IBUS_SERVICE_CLASS (class)->service_method_call  = ibus_factory_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_get_property = ibus_factory_service_get_property;
+    IBUS_SERVICE_CLASS (class)->service_set_property = ibus_factory_service_set_property;
+    class->create_engine = ibus_factory_real_create_engine;
+
+    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
+
+    g_type_class_add_private (class, sizeof (IBusFactoryPrivate));
+
+    /**
+     * IBusFactory::create-engine:
+     * @factory: the factory which received the signal
+     * @engine_name: the engine_name which received the signal
+     * @returns: (transfer full): An IBusEngine
+     *
+     * The ::create-engine signal is a signal to create IBusEngine
+     * with @engine_name, which gets emitted when IBusFactory
+     * received CreateEngine dbus method. The callback functions
+     * will be called until a callback returns a non-null object
+     * of IBusEngine.
+     */
+    factory_signals[CREATE_ENGINE] =
+        g_signal_new (I_("create-engine"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusFactoryClass, create_engine),
+            _ibus_factory_create_engine_accumulator,
+            NULL,
+            _ibus_marshal_OBJECT__STRING,
+            IBUS_TYPE_ENGINE,
+            1,
+            G_TYPE_STRING);
 }
 
 static void
 ibus_factory_init (IBusFactory *factory)
 {
-    IBusFactoryPrivate *priv;
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
-
-    priv->id = 0;
-    priv->connection = NULL;
-    priv->engine_table = g_hash_table_new_full (g_str_hash,
-                                                g_str_equal,
-                                                g_free,
-                                                NULL);
-    priv->engine_list =  NULL;
+    factory->priv = IBUS_FACTORY_GET_PRIVATE (factory);
+    factory->priv->engine_table =
+        g_hash_table_new_full (g_str_hash,
+                               g_str_equal,
+                               g_free,
+                               NULL);
 }
 
 static void
 ibus_factory_destroy (IBusFactory *factory)
 {
     GList *list;
-    IBusFactoryPrivate *priv;
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
 
-    list = g_list_copy (priv->engine_list);
-    g_list_foreach (list, (GFunc) ibus_object_destroy, NULL);
-    g_list_free (priv->engine_list);
-    g_list_free (list);
-    priv->engine_list = NULL;
+    list = g_list_copy (factory->priv->engine_list);
+    g_list_free_full (list, (GDestroyNotify)ibus_object_destroy);
+    g_list_free(factory->priv->engine_list);
+    factory->priv->engine_list = NULL;
 
-    if (priv->engine_table) {
-        g_hash_table_destroy (priv->engine_table);
+    if (factory->priv->engine_table) {
+        g_hash_table_destroy (factory->priv->engine_table);
     }
 
-    if (priv->connection) {
-        ibus_service_remove_from_connection ((IBusService *)factory,
-                                             priv->connection);
-        g_object_unref (priv->connection);
-    }
+    IBUS_OBJECT_CLASS(ibus_factory_parent_class)->destroy (IBUS_OBJECT (factory));
+}
 
-    IBUS_OBJECT_CLASS(factory_parent_class)->destroy (IBUS_OBJECT (factory));
+static void
+ibus_factory_set_property (IBusFactory  *factory,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+    switch (prop_id) {
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (factory, prop_id, pspec);
+    }
 }
 
 static void
-_engine_destroy_cb (IBusEngine  *engine,
-                    IBusFactory *factory)
+ibus_factory_get_property (IBusFactory *factory,
+                           guint        prop_id,
+                           GValue      *value,
+                           GParamSpec  *pspec)
 {
-    IBusFactoryPrivate *priv;
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
+    switch (prop_id) {
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (factory, prop_id, pspec);
+    }
+}
 
-    priv->engine_list = g_list_remove (priv->engine_list, engine);
+static void
+ibus_factory_engine_destroy_cb (IBusEngine  *engine,
+                                IBusFactory *factory)
+{
+    factory->priv->engine_list = g_list_remove (factory->priv->engine_list, engine);
     g_object_unref (engine);
 }
 
-static gboolean
-ibus_factory_ibus_message (IBusFactory    *factory,
-                           IBusConnection *connection,
-                           IBusMessage    *message)
+static void
+ibus_factory_service_method_call (IBusService           *service,
+                                  GDBusConnection       *connection,
+                                  const gchar           *sender,
+                                  const gchar           *object_path,
+                                  const gchar           *interface_name,
+                                  const gchar           *method_name,
+                                  GVariant              *parameters,
+                                  GDBusMethodInvocation *invocation)
 {
-    g_assert (IBUS_IS_FACTORY (factory));
-    g_assert (IBUS_IS_CONNECTION (connection));
-    g_assert (message != NULL);
-
-    IBusMessage *reply_message;
-    IBusFactoryPrivate *priv;
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
-
-    g_assert (priv->connection == connection);
-
-    if (ibus_message_is_method_call (message,
-                                     IBUS_INTERFACE_FACTORY,
-                                     "CreateEngine")) {
-        gchar *engine_name;
-        gchar *path;
-        IBusError *error;
-        IBusEngine *engine;
-        gboolean retval;
-        GType engine_type;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_STRING, &engine_name,
-                                        G_TYPE_INVALID);
-
-        if (!retval) {
-            reply_message = ibus_message_new_error_printf (message,
-                                        DBUS_ERROR_INVALID_ARGS,
-                                        "The 1st arg should be engine name");
-            ibus_connection_send (connection, reply_message);
-            ibus_message_unref (reply_message);
-            return TRUE;
+    IBusFactory *factory = IBUS_FACTORY (service);
+
+    if (g_strcmp0 (method_name, "CreateEngine") == 0) {
+        gchar *engine_name = NULL;
+        IBusEngine *engine = NULL;
+
+        g_variant_get (parameters, "(&s)", &engine_name);
+        g_signal_emit (factory, factory_signals[CREATE_ENGINE],
+                       0, engine_name, &engine);
+
+        if (engine != NULL) {
+            gchar *object_path = NULL;
+            GValue value = { 0, };
+
+            g_value_init (&value, G_TYPE_STRING);
+            g_object_get_property (G_OBJECT (engine), "object-path", &value);
+            object_path = g_value_dup_string (&value);
+            g_value_unset (&value);
+
+            g_assert (engine != NULL);
+            g_assert (object_path != NULL);
+            g_object_ref_sink (engine);
+            factory->priv->engine_list = g_list_append (factory->priv->engine_list, engine);
+            g_signal_connect (engine,
+                              "destroy",
+                              G_CALLBACK (ibus_factory_engine_destroy_cb),
+                              factory);
+            g_dbus_method_invocation_return_value (invocation,
+                                                   g_variant_new ("(o)", object_path));
+            g_free (object_path);
         }
+        else {
+            gchar *error_message = g_strdup_printf ("Can not fond engine %s", engine_name);
+            g_dbus_method_invocation_return_error (invocation,
+                                                   G_DBUS_ERROR,
+                                                   G_DBUS_ERROR_FAILED,
+                                                   error_message);
+            g_free (error_message);
+        }
+        return;
+    }
 
-        engine_type = (GType )g_hash_table_lookup (priv->engine_table, engine_name);
-
-        if (engine_type == G_TYPE_INVALID) {
-             reply_message = ibus_message_new_error_printf (message,
-                                        DBUS_ERROR_FAILED,
-                                        "Can not create engine %s", engine_name);
-            ibus_connection_send (connection, reply_message);
-            ibus_message_unref (reply_message);
-            return TRUE;
+    IBUS_SERVICE_CLASS (ibus_factory_parent_class)->
+            service_method_call (service,
+                                 connection,
+                                 sender,
+                                 object_path,
+                                 interface_name,
+                                 method_name,
+                                 parameters,
+                                 invocation);
+}
 
-        }
+static GVariant *
+ibus_factory_service_get_property (IBusService        *service,
+                                   GDBusConnection    *connection,
+                                   const gchar        *sender,
+                                   const gchar        *object_path,
+                                   const gchar        *interface_name,
+                                   const gchar        *property_name,
+                                   GError            **error)
+{
+    return IBUS_SERVICE_CLASS (ibus_factory_parent_class)->
+                service_get_property (service,
+                                      connection,
+                                      sender,
+                                      object_path,
+                                      interface_name,
+                                      property_name,
+                                      error);
+}
 
-        path = g_strdup_printf ("/org/freedesktop/IBus/Engine/%d", ++priv->id);
+static gboolean
+ibus_factory_service_set_property (IBusService        *service,
+                                   GDBusConnection    *connection,
+                                   const gchar        *sender,
+                                   const gchar        *object_path,
+                                   const gchar        *interface_name,
+                                   const gchar        *property_name,
+                                   GVariant           *value,
+                                   GError            **error)
+{
+    return IBUS_SERVICE_CLASS (ibus_factory_parent_class)->
+                service_set_property (service,
+                                      connection,
+                                      sender,
+                                      object_path,
+                                      interface_name,
+                                      property_name,
+                                      value,
+                                      error);
+}
 
-        engine = g_object_new (engine_type,
-                               "name", engine_name,
-                               "path", path,
-                               "connection", priv->connection,
-                               NULL);
+IBusFactory *
+ibus_factory_new (GDBusConnection *connection)
+{
+    g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
 
-        priv->engine_list = g_list_append (priv->engine_list, engine);
-        g_signal_connect (engine,
-                          "destroy",
-                          G_CALLBACK (_engine_destroy_cb),
-                          factory);
-
-        reply_message = ibus_message_new_method_return (message);
-        ibus_message_append_args (reply_message,
-                                  IBUS_TYPE_OBJECT_PATH, &path,
-                                  G_TYPE_INVALID);
-        g_free (path);
-        ibus_connection_send (connection, reply_message);
-        ibus_message_unref (reply_message);
-        return TRUE;
-    }
+    IBusFactory *object = g_object_new (IBUS_TYPE_FACTORY,
+                                        "object-path", IBUS_PATH_FACTORY,
+                                        "connection", connection,
+                                        NULL);
 
-    return factory_parent_class->ibus_message ((IBusService *)factory,
-                                               connection,
-                                               message);
+    return IBUS_FACTORY (object);
 }
 
 void
@@ -251,12 +366,23 @@ ibus_factory_add_engine (IBusFactory *factory,
                          const gchar *engine_name,
                          GType        engine_type)
 {
-    g_assert (IBUS_IS_FACTORY (factory));
-    g_assert (engine_name);
-    g_assert (g_type_is_a (engine_type, IBUS_TYPE_ENGINE));
+    g_return_if_fail (IBUS_IS_FACTORY (factory));
+    g_return_if_fail (engine_name != NULL);
+    g_return_if_fail (g_type_is_a (engine_type, IBUS_TYPE_ENGINE));
+
+    g_hash_table_insert (factory->priv->engine_table, g_strdup (engine_name), (gpointer) engine_type);
+}
+
+IBusEngine *
+ibus_factory_create_engine (IBusFactory    *factory,
+                            const gchar    *engine_name)
+{
+    IBusEngine *engine = NULL;
+
+    g_assert (engine_name != NULL);
 
-    IBusFactoryPrivate *priv;
-    priv = IBUS_FACTORY_GET_PRIVATE (factory);
+    g_signal_emit (factory, factory_signals[CREATE_ENGINE],
+                   0, engine_name, &engine);
 
-    g_hash_table_insert (priv->engine_table, g_strdup (engine_name), (gpointer) engine_type);
+    return engine;
 }