Merge branch 'master' of git://github.com/phuang/ibus
[platform/upstream/ibus.git] / src / ibusfactory.c
1 /* vim:set et sts=4: */
2 /* ibus - The Input Bus
3  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
4  * Copyright (C) 2008-2010 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 #include <dbus/dbus.h>
22 #include "ibusfactory.h"
23 #include "ibusengine.h"
24 #include "ibusshare.h"
25 #include "ibusinternal.h"
26
27 #define IBUS_FACTORY_GET_PRIVATE(o)  \
28    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_FACTORY, IBusFactoryPrivate))
29
30 enum {
31     LAST_SIGNAL,
32 };
33
34 enum {
35     PROP_0,
36     PROP_CONNECTION,
37 };
38
39 /* IBusFactoryPriv */
40 struct _IBusFactoryPrivate {
41     guint id;
42     IBusConnection *connection;
43     GList          *engine_list;
44     GHashTable     *engine_table;
45 };
46 typedef struct _IBusFactoryPrivate IBusFactoryPrivate;
47
48 /* functions prototype */
49 static void     ibus_factory_destroy        (IBusFactory        *factory);
50 static void     ibus_factory_set_property   (IBusFactory        *engine,
51                                              guint               prop_id,
52                                              const GValue       *value,
53                                              GParamSpec         *pspec);
54 static void     ibus_factory_get_property   (IBusFactory        *factory,
55                                              guint               prop_id,
56                                              GValue             *value,
57                                              GParamSpec         *pspec);
58
59 static gboolean ibus_factory_ibus_message   (IBusFactory        *factory,
60                                              IBusConnection     *connection,
61                                              IBusMessage        *message);
62
63 static void     _engine_destroy_cb          (IBusEngine         *engine,
64                                              IBusFactory        *factory);
65
66 G_DEFINE_TYPE (IBusFactory, ibus_factory, IBUS_TYPE_SERVICE)
67
68 IBusFactory *
69 ibus_factory_new (IBusConnection *connection)
70 {
71     g_assert (IBUS_IS_CONNECTION (connection));
72
73     IBusFactory *factory;
74     IBusFactoryPrivate *priv;
75
76     factory = (IBusFactory *) g_object_new (IBUS_TYPE_FACTORY,
77                                             "path", IBUS_PATH_FACTORY,
78                                             "connection", connection,
79                                             NULL);
80     priv = IBUS_FACTORY_GET_PRIVATE (factory);
81
82     return factory;
83 }
84
85 static void
86 ibus_factory_class_init (IBusFactoryClass *klass)
87 {
88     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
89     IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
90
91     g_type_class_add_private (klass, sizeof (IBusFactoryPrivate));
92
93     gobject_class->set_property = (GObjectSetPropertyFunc) ibus_factory_set_property;
94     gobject_class->get_property = (GObjectGetPropertyFunc) ibus_factory_get_property;
95
96
97     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_factory_destroy;
98
99     IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) ibus_factory_ibus_message;
100
101     /**
102      * IBusFactory:connection:
103      *
104      * Connection of this IBusFactory.
105      **/
106     g_object_class_install_property (gobject_class,
107                 PROP_CONNECTION,
108                 g_param_spec_object ("connection",
109                 "connection",
110                 "The connection of factory object",
111                 IBUS_TYPE_CONNECTION,
112                 G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
113
114
115 }
116
117 static void
118 ibus_factory_init (IBusFactory *factory)
119 {
120     IBusFactoryPrivate *priv;
121     priv = IBUS_FACTORY_GET_PRIVATE (factory);
122
123     priv->id = 0;
124     priv->connection = NULL;
125     priv->engine_table = g_hash_table_new_full (g_str_hash,
126                                                 g_str_equal,
127                                                 g_free,
128                                                 NULL);
129     priv->engine_list =  NULL;
130 }
131
132 static void
133 ibus_factory_destroy (IBusFactory *factory)
134 {
135     GList *list;
136     IBusFactoryPrivate *priv;
137     priv = IBUS_FACTORY_GET_PRIVATE (factory);
138
139     list = g_list_copy (priv->engine_list);
140     g_list_foreach (list, (GFunc) ibus_object_destroy, NULL);
141     g_list_free (priv->engine_list);
142     g_list_free (list);
143     priv->engine_list = NULL;
144
145     if (priv->engine_table) {
146         g_hash_table_destroy (priv->engine_table);
147     }
148
149     if (priv->connection) {
150         g_object_unref (priv->connection);
151         priv->connection = NULL;
152     }
153
154     IBUS_OBJECT_CLASS(ibus_factory_parent_class)->destroy (IBUS_OBJECT (factory));
155 }
156
157 static void
158 ibus_factory_set_property (IBusFactory  *factory,
159                            guint         prop_id,
160                            const GValue *value,
161                            GParamSpec   *pspec)
162 {
163     IBusFactoryPrivate *priv;
164     priv = IBUS_FACTORY_GET_PRIVATE (factory);
165
166     switch (prop_id) {
167     case PROP_CONNECTION:
168         priv->connection = g_value_get_object (value);
169         g_object_ref_sink (priv->connection);
170         ibus_service_add_to_connection ((IBusService *) factory,
171                                         priv->connection);
172         break;
173
174     default:
175         G_OBJECT_WARN_INVALID_PROPERTY_ID (factory, prop_id, pspec);
176     }
177 }
178
179 static void
180 ibus_factory_get_property (IBusFactory *factory,
181                            guint        prop_id,
182                            GValue      *value,
183                            GParamSpec  *pspec)
184 {
185     IBusFactoryPrivate *priv;
186     priv = IBUS_FACTORY_GET_PRIVATE (factory);
187
188     switch (prop_id) {
189     case PROP_CONNECTION:
190         g_value_set_object (value, priv->connection);
191         break;
192
193     default:
194         G_OBJECT_WARN_INVALID_PROPERTY_ID (factory, prop_id, pspec);
195     }
196 }
197
198 static void
199 _engine_destroy_cb (IBusEngine  *engine,
200                     IBusFactory *factory)
201 {
202     IBusFactoryPrivate *priv;
203     priv = IBUS_FACTORY_GET_PRIVATE (factory);
204
205     priv->engine_list = g_list_remove (priv->engine_list, engine);
206     g_object_unref (engine);
207 }
208
209 static gboolean
210 ibus_factory_ibus_message (IBusFactory    *factory,
211                            IBusConnection *connection,
212                            IBusMessage    *message)
213 {
214     g_assert (IBUS_IS_FACTORY (factory));
215     g_assert (IBUS_IS_CONNECTION (connection));
216     g_assert (message != NULL);
217
218     IBusMessage *reply_message;
219     IBusFactoryPrivate *priv;
220     priv = IBUS_FACTORY_GET_PRIVATE (factory);
221
222     g_assert (priv->connection == connection);
223
224     if (ibus_message_is_method_call (message,
225                                      IBUS_INTERFACE_FACTORY,
226                                      "CreateEngine")) {
227         gchar *engine_name;
228         gchar *path;
229         IBusError *error;
230         IBusEngine *engine;
231         gboolean retval;
232         GType engine_type;
233
234         retval = ibus_message_get_args (message,
235                                         &error,
236                                         G_TYPE_STRING, &engine_name,
237                                         G_TYPE_INVALID);
238
239         if (!retval) {
240             reply_message = ibus_message_new_error_printf (message,
241                                         DBUS_ERROR_INVALID_ARGS,
242                                         "The 1st arg should be engine name");
243             ibus_connection_send (connection, reply_message);
244             ibus_message_unref (reply_message);
245             return TRUE;
246         }
247
248         engine_type = (GType )g_hash_table_lookup (priv->engine_table, engine_name);
249
250         if (engine_type == G_TYPE_INVALID) {
251              reply_message = ibus_message_new_error_printf (message,
252                                         DBUS_ERROR_FAILED,
253                                         "Can not create engine %s", engine_name);
254             ibus_connection_send (connection, reply_message);
255             ibus_message_unref (reply_message);
256             return TRUE;
257
258         }
259
260         path = g_strdup_printf ("/org/freedesktop/IBus/Engine/%d", ++priv->id);
261
262         engine = g_object_new (engine_type,
263                                "name", engine_name,
264                                "path", path,
265                                "connection", priv->connection,
266                                NULL);
267
268         priv->engine_list = g_list_append (priv->engine_list, engine);
269         g_signal_connect (engine,
270                           "destroy",
271                           G_CALLBACK (_engine_destroy_cb),
272                           factory);
273
274         reply_message = ibus_message_new_method_return (message);
275         ibus_message_append_args (reply_message,
276                                   IBUS_TYPE_OBJECT_PATH, &path,
277                                   G_TYPE_INVALID);
278         g_free (path);
279         ibus_connection_send (connection, reply_message);
280         ibus_message_unref (reply_message);
281         return TRUE;
282     }
283
284     return IBUS_SERVICE_CLASS (ibus_factory_parent_class)->ibus_message (
285                                 (IBusService *)factory,
286                                 connection,
287                                 message);
288 }
289
290 void
291 ibus_factory_add_engine (IBusFactory *factory,
292                          const gchar *engine_name,
293                          GType        engine_type)
294 {
295     g_assert (IBUS_IS_FACTORY (factory));
296     g_assert (engine_name);
297     g_assert (g_type_is_a (engine_type, IBUS_TYPE_ENGINE));
298
299     IBusFactoryPrivate *priv;
300     priv = IBUS_FACTORY_GET_PRIVATE (factory);
301
302     g_hash_table_insert (priv->engine_table, g_strdup (engine_name), (gpointer) engine_type);
303 }