60cdac2109d898f810b7a181488b4d654bae21b7
[profile/ivi/weekeyboard.git] / src / wkb-ibus.c
1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <Ecore.h>
23 #include <Eldbus.h>
24
25 #include "wkb-ibus.h"
26
27 int _wkb_ibus_log_dom = -1;
28
29 #define CHECK_MESSAGE_ERRORS(_msg) \
30    do \
31      { \
32         const char *error, *error_msg; \
33         if (eldbus_message_error_get(_msg, &error, &error_msg)) \
34           { \
35              ERR("Dbus message error: %s: %s", error, error_msg); \
36              return; \
37           } \
38         DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
39      } while (0);
40
41 struct _wkb_ibus_service
42 {
43    Eldbus_Service_Interface *interface;
44
45    Eldbus_Signal_Handler *name_acquired;
46    Eldbus_Signal_Handler *name_lost;
47 };
48
49 struct _wkb_ibus_context
50 {
51    char *address;
52    Eldbus_Connection *conn;
53    Ecore_Exe *ibus_daemon;
54 #if 0
55    struct _wkb_ibus_service config;
56 #else
57    Eldbus_Proxy *config;
58 #endif
59    struct _wkb_ibus_service panel;
60    int refcount;
61    Eina_Bool address_pending;
62 };
63
64 static struct _wkb_ibus_context *ctx = NULL;
65
66 static void
67 _wkb_config_value_changed_cb(void *data, const Eldbus_Message *msg)
68 {
69    const char *section, name;
70    Eldbus_Message_Iter *value;
71
72    CHECK_MESSAGE_ERRORS(msg)
73
74    if (!eldbus_message_arguments_get(msg, "ssv", &section, &name, &value))
75      {
76         ERR("Error reading message arguments");
77         return;
78      }
79
80    DBG("section: '%s', name: '%s', value: '%p", section, name, value);
81 }
82
83 static void
84 _wkb_name_owner_changed_cb(void *data, const char *bus, const char *old_id, const char *new_id)
85 {
86    DBG("NameOwnerChanged Bus=%s | old=%s | new=%s", bus, old_id, new_id);
87
88 #if 0
89 #else
90    if (strcmp(bus, IBUS_SERVICE_CONFIG) == 0)
91      {
92         if (*new_id)
93           {
94              Eldbus_Object *obj;
95
96              if (ctx->config)
97                 return;
98
99              ecore_main_loop_glib_integrate();
100              obj = eldbus_object_get(ctx->conn, IBUS_SERVICE_CONFIG, IBUS_PATH_CONFIG);
101              ctx->config = eldbus_proxy_get(obj, IBUS_INTERFACE_CONFIG);
102              eldbus_proxy_signal_handler_add(ctx->config, "ValueChanged", _wkb_config_value_changed_cb, ctx);
103
104              INF("Got config proxy");
105           }
106         else
107           {
108              if (!ctx->config)
109                 return;
110
111              eldbus_proxy_unref(ctx->config);
112              ctx->config = NULL;
113           }
114      }
115 #endif
116 }
117
118 static void
119 _wkb_name_acquired_cb(void *data, const Eldbus_Message *msg)
120 {
121    const char *name;
122
123    DBG("NameAcquired");
124
125    CHECK_MESSAGE_ERRORS(msg)
126
127    if (!eldbus_message_arguments_get(msg, "s", &name))
128      {
129         ERR("Error reading message arguments");
130         return;
131      }
132
133    if (strcmp(name, IBUS_INTERFACE_PANEL) == 0)
134      {
135         if (!ctx->panel.interface)
136           {
137              ctx->panel.interface = wkb_ibus_panel_register(ctx->conn);
138              INF("Registering Panel Interface: %s", ctx->panel.interface ? "Success" : "Fail");
139           }
140         else
141           {
142              INF("Panel Interface already registered");
143           }
144      }
145 #if 0
146    else if (strcmp(name, IBUS_INTERFACE_CONFIG) == 0)
147      {
148         if (!ctx->config.interface)
149           {
150              ctx->config.interface = wkb_ibus_config_register(ctx->conn);
151              INF("Registering Config Interface: %s", ctx->config.interface ? "Success" : "Fail");
152           }
153         else
154           {
155              INF("Config Interface already registered");
156           }
157      }
158 #endif
159    else
160      {
161         WRN("Unexpected name %s", name);
162      }
163 }
164
165 static void
166 _wkb_name_lost_cb(void *data, const Eldbus_Message *msg)
167 {
168    const char *name;
169
170    DBG("NameLost");
171
172    CHECK_MESSAGE_ERRORS(msg)
173
174    if (!eldbus_message_arguments_get(msg, "s", &name))
175      {
176         ERR("Error reading message arguments");
177         return;
178      }
179
180    DBG("Name = %s", name);
181 }
182
183 static Eina_Bool
184 _wkb_ibus_shutdown_idler(void *data)
185 {
186    wkb_ibus_shutdown();
187    return ECORE_CALLBACK_CANCEL;
188 }
189
190 static void
191 _wkb_name_request_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
192 {
193    const char *error, *error_msg;
194    unsigned int reply;
195
196    DBG("NameRequest callback");
197
198    if (eldbus_message_error_get(msg, &error, &error_msg))
199      {
200         ERR("DBus message error: %s: %s", error, error_msg);
201         goto error;
202      }
203
204    if (!eldbus_message_arguments_get(msg, "u", &reply))
205      {
206         ERR("Error reading message arguments");
207         goto error;
208      }
209
210    if (reply != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER &&
211        reply != ELDBUS_NAME_REQUEST_REPLY_ALREADY_OWNER)
212      {
213         ERR("Not primary owner: reply=%d", reply);
214         goto error;
215      }
216
217    return;
218
219 error:
220    ecore_idler_add(_wkb_ibus_shutdown_idler, NULL);
221 }
222
223 static void
224 _wkb_name_release_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
225 {
226    unsigned int reply;
227
228    CHECK_MESSAGE_ERRORS(msg)
229
230    if (!eldbus_message_arguments_get(msg, "u", &reply))
231      {
232         ERR("Error reading message arguments");
233         return;
234      }
235
236    if (reply != ELDBUS_NAME_RELEASE_REPLY_RELEASED)
237      {
238         ERR("Unexpected name release reply: %d", reply);
239         return;
240      }
241 }
242
243 static void
244 _wkb_ibus_launch_daemon(void)
245 {
246     DBG("Launching ibus-daemon");
247     ctx->ibus_daemon = ecore_exe_run("ibus-daemon -s", NULL);
248     if (!ctx->ibus_daemon)
249       {
250          ERR("Error launching ibus-daemon process");
251          return;
252       }
253 }
254
255 static Eina_Bool
256 _wkb_ibus_query_address_cb(void *data, int type, void *event)
257 {
258    Ecore_Exe_Event_Data *exe_data = (Ecore_Exe_Event_Data *)event;
259
260    if (strncmp(exe_data->data, "(null)", exe_data->size) == 0)
261      {
262         INF("IBus daemon is not running.");
263         _wkb_ibus_launch_daemon();
264         goto end;
265      }
266    else if (strstr(exe_data->data, "unknown command") != NULL)
267      {
268         ERR("ibus command does not support the 'address' argument");
269         goto end;
270      }
271
272    free(ctx->address);
273    ctx->address = strndup(exe_data->data, exe_data->size);
274
275 end:
276    ecore_idler_add(ecore_exe_free, exe_data->exe);
277    ctx->address_pending = EINA_FALSE;
278    return ECORE_CALLBACK_DONE;
279 }
280
281
282 static void
283 _wkb_ibus_query_address(void)
284 {
285    const char *ibus_addr;
286    Ecore_Exe *ibus_exec = NULL;
287
288    /* Check for IBUS_ADDRESS environment variable */
289    if ((ibus_addr = getenv("IBUS_ADDRESS")) != NULL)
290      {
291         DBG("Got IBus address from IBUS_ADDRESS environment variable %s", ibus_addr);
292         ctx->address = strdup(ibus_addr);
293         return;
294      }
295
296    /* Get IBus address by invoking 'ibus address' from command line */
297    DBG("Querying IBus address from using 'ibus address' command");
298    ibus_exec = ecore_exe_pipe_run("ibus address",
299                                   ECORE_EXE_PIPE_READ |
300                                   ECORE_EXE_PIPE_READ_LINE_BUFFERED,
301                                   NULL);
302    if (!ibus_exec)
303      {
304         ERR("Unable to retrieve IBus address");
305         return;
306      }
307
308    ctx->address_pending = EINA_TRUE;
309    ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _wkb_ibus_query_address_cb, NULL);
310 }
311
312 Eina_Bool
313 wkb_ibus_connect(void)
314 {
315    if (ctx->conn)
316       return EINA_TRUE;
317
318    if (!ctx->address)
319      {
320         INF("IBus address is not set.", ctx->address_pending);
321         if (!ctx->address_pending)
322             _wkb_ibus_query_address();
323
324         return EINA_FALSE;
325     }
326
327    INF("Connecting to IBus at address '%s'", ctx->address);
328    ctx->conn = eldbus_address_connection_get(ctx->address);
329
330    if (!ctx->conn)
331      {
332         ERR("Error connecting to IBus");
333         return EINA_FALSE;
334      }
335
336    /* Panel */
337    eldbus_name_owner_changed_callback_add(ctx->conn,
338                                           IBUS_SERVICE_PANEL,
339                                           _wkb_name_owner_changed_cb,
340                                           ctx, EINA_TRUE);
341
342    ctx->panel.name_acquired = eldbus_signal_handler_add(ctx->conn,
343                                                         ELDBUS_FDO_BUS,
344                                                         ELDBUS_FDO_PATH,
345                                                         IBUS_INTERFACE_PANEL,
346                                                         "NameAcquired",
347                                                         _wkb_name_acquired_cb,
348                                                         ctx);
349
350    ctx->panel.name_lost = eldbus_signal_handler_add(ctx->conn,
351                                                     ELDBUS_FDO_BUS,
352                                                     ELDBUS_FDO_PATH,
353                                                     IBUS_INTERFACE_PANEL,
354                                                     "NameLost",
355                                                     _wkb_name_lost_cb,
356                                                     ctx);
357
358    eldbus_name_request(ctx->conn, IBUS_SERVICE_PANEL,
359                        ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
360                        _wkb_name_request_cb, ctx);
361
362    /* Config */
363    eldbus_name_owner_changed_callback_add(ctx->conn,
364                                           IBUS_SERVICE_CONFIG,
365                                           _wkb_name_owner_changed_cb,
366                                           ctx, EINA_TRUE);
367
368 #if 0
369    ctx->config.name_acquired = eldbus_signal_handler_add(ctx->conn,
370                                                          ELDBUS_FDO_BUS,
371                                                          ELDBUS_FDO_PATH,
372                                                          IBUS_INTERFACE_CONFIG,
373                                                          "NameAcquired",
374                                                          _wkb_name_acquired_cb,
375                                                          ctx);
376
377    ctx->config.name_lost = eldbus_signal_handler_add(ctx->conn,
378                                                      ELDBUS_FDO_BUS,
379                                                      ELDBUS_FDO_PATH,
380                                                      IBUS_INTERFACE_CONFIG,
381                                                      "NameLost",
382                                                      _wkb_name_lost_cb,
383                                                      ctx);
384
385    eldbus_name_request(ctx->conn, IBUS_SERVICE_CONFIG,
386                        ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
387                        _wkb_name_request_cb, ctx);
388 #endif
389    return EINA_TRUE;
390 }
391
392
393 int
394 wkb_ibus_init(void)
395 {
396    if (ctx && ctx->refcount > 0)
397       goto end;
398
399    if (!eina_init())
400      {
401         fprintf(stderr, "Error initializing Eina\n");
402         return 0;
403      }
404
405    _wkb_ibus_log_dom = eina_log_domain_register("wkb-ibus", EINA_COLOR_LIGHTCYAN);
406    if (_wkb_ibus_log_dom < 0)
407       {
408          EINA_LOG_ERR("Unable to register 'wkb-ibus' log domain");
409          eina_shutdown();
410          return 0;
411       }
412
413    if (!ctx && !(ctx = calloc(1, sizeof(*ctx))))
414      {
415         ERR("Error calloc\n");
416         eina_shutdown();
417         return 0;
418      }
419
420    _wkb_ibus_query_address();
421
422 end:
423    return ++ctx->refcount;
424 }
425
426 void
427 wkb_ibus_shutdown(void)
428 {
429    if (!ctx)
430      {
431         fprintf(stderr, "Not initialized\n");
432         return;
433      }
434
435    if (ctx->refcount == 0)
436      {
437         ERR("Refcount already 0");
438         goto end;
439      }
440
441    if (--(ctx->refcount) != 0)
442       return;
443
444    DBG("Shutting down");
445    wkb_ibus_disconnect();
446
447    free(ctx->address);
448
449    if (ctx->ibus_daemon)
450      {
451         DBG("Terminating ibus-daemon");
452         ecore_exe_terminate(ctx->ibus_daemon);
453         ecore_exe_free(ctx->ibus_daemon);
454      }
455
456 end:
457    free(ctx);
458    ctx = NULL;
459
460    ecore_main_loop_quit();
461    DBG("Main loop quit");
462 }
463
464 void
465 wkb_ibus_disconnect(void)
466 {
467    if (!ctx->conn)
468      {
469         ERR("Not connected");
470         return;
471      }
472
473    DBG("Disconnect");
474
475    if (ctx->panel.interface)
476      {
477         eldbus_name_release(ctx->conn, IBUS_SERVICE_PANEL, _wkb_name_release_cb, ctx);
478         eldbus_signal_handler_del(ctx->panel.name_acquired);
479         eldbus_signal_handler_del(ctx->panel.name_lost);
480         eldbus_service_interface_unregister(ctx->panel.interface);
481         ctx->panel.interface = NULL;
482      }
483
484    if (ctx->config)
485      {
486         eldbus_proxy_unref(ctx->config);
487         ctx->config = NULL;
488      }
489 #if 0
490    if (ctx->config.interface)
491      {
492         eldbus_name_release(ctx->conn, IBUS_SERVICE_CONFIG, _wkb_name_release_cb, ctx);
493         eldbus_signal_handler_del(ctx->config.name_acquired);
494         eldbus_signal_handler_del(ctx->config.name_lost);
495         eldbus_service_interface_unregister(ctx->config.interface);
496         ctx->config.interface = NULL;
497      }
498 #endif
499
500    eldbus_connection_unref(ctx->conn);
501 }
502
503 Eina_Bool
504 wkb_ibus_is_connected(void)
505 {
506     return ctx->conn != NULL;
507 }