tizen 2.4 release
[framework/uifw/libeom.git] / src / dbus / eom-dbus.c
1 /**************************************************************************
2
3 eom (external output manager)
4
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact:
8 SooChan Lim <sc1.lim@samsung.com>
9 Boram Park <boram1288.park@samsung.com>
10 Changyeon Lee <cyeon.lee@samsung.com>
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sub license, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
19
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
22 of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
28 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32 **************************************************************************/
33
34 #include <config.h>
35 #include <dbus/dbus.h>
36 #include <string.h>
37 #include "eom.h"
38 #include "eom-log.h"
39 #include "eom-dbus.h"
40 #include "eom-private.h"
41
42 #define EOM_DBUS_SERVER     "org.eom.server"
43 #define EOM_DBUS_CLIENT     "org.eom.client"
44 #define EOM_DBUS_INTERFACE  "org.eom.interface"
45 #define EOM_DBUS_PATH       "/org/eom/path"
46
47 #define STR_LEN 128
48
49 #define REPLY_TIME  1000
50 #define ARGV_NUM    64
51
52 typedef struct _EomDBusClientMethod {
53         char name[STR_LEN];
54         notify_func func;
55         void *data;
56         struct _EomDBusClientMethod *next;
57 } EomDBusClientMethod;
58
59 typedef struct _EomDBusClientInfo {
60         DBusConnection *conn;
61         char name[STR_LEN];
62         char rule[STR_LEN];
63         GSource *src;
64         EomDBusClientMethod *methods;
65         int fd;
66 } EomDBusClientInfo;
67
68 static EomDBusClientInfo client_info;
69
70 static bool dbus_initialized;
71 static EomDBusClientMethod dbus_method;
72
73 static void _eom_dbus_client_deinitialize(EomDBusClientInfo *info);
74
75 static int
76 _eom_dbus_need_private_conn(void)
77 {
78         char *env = getenv("EOM_PRIVATE_CONN");
79
80         if (env) {
81                 return (atoi(env) > 0) ? 1 : 0;
82                 INFO("EOM_PRIVATE_CONN = %s", env);
83         }
84
85         return 0;
86 }
87
88 static int
89 _eom_dbus_convert_gvalue_to_message(GArray *array, DBusMessage *msg)
90 {
91         DBusMessageIter iter;
92         GValue *v = NULL;
93         GType type;
94         int i;
95
96         if (!array)
97                 return 1;
98
99         if (array->len <= 0)
100                 return 1;
101
102         dbus_message_iter_init_append(msg, &iter);
103
104         INFO("[EOM_CLIENT:%s] len(%d)", client_info.name, array->len);
105
106         for (i = 0; i < array->len; i++) {
107                 v = &g_array_index(array, GValue, i);
108                 type = v->g_type;
109
110                 INFO("[EOM_CLIENT:%s] type(%d)", client_info.name, (int)type);
111
112                 switch (type) {
113                 case G_TYPE_INT:
114                         {
115                                 int integer = g_value_get_int(v);
116
117                                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &integer)) {
118                                         ERR("[EOM_CLIENT:%s] failed: int append", client_info.name);
119                                         return 0;
120                                 }
121                         }
122                         break;
123                 default:
124                         return 0;
125                 }
126         }
127
128         return 1;
129 }
130
131 static GArray*
132 _eom_dbus_convert_message_to_gvalue(DBusMessage *msg)
133 {
134         GArray *array;
135         DBusMessageIter iter;
136
137         if (!dbus_message_iter_init(msg, &iter))
138                 return NULL;
139
140         array = g_array_new(FALSE, FALSE, sizeof(GValue));
141
142         do {
143                 int type = dbus_message_iter_get_arg_type(&iter);
144                 GValue v = G_VALUE_INIT;
145
146                 INFO("[EOM_CLIENT:%s] type(%c(%d))", client_info.name, (char)type, type);
147
148                 switch (type) {
149                 case DBUS_TYPE_INT32:
150                         {
151                                 int integer = 0;
152                                 dbus_message_iter_get_basic(&iter, &integer);
153                                 g_value_init(&v, G_TYPE_INT);
154                                 g_value_set_int(&v, integer);
155                                 array = g_array_append_val(array, v);
156                                 g_value_unset(&v);
157                         }
158                         break;
159                 default:
160                         NEVER_GET_HERE();
161                         g_array_free(array, FALSE);
162                         return NULL;
163                 }
164         } while (dbus_message_iter_has_next(&iter) && dbus_message_iter_next(&iter));
165
166         return array;
167 }
168
169 static void
170 _eom_dbus_client_process_message(EomDBusClientInfo *info, DBusMessage *msg)
171 {
172         EomDBusClientMethod **prev;
173         DBusError err;
174
175         dbus_error_init(&err);
176
177         INFO("[CLIENT] Process a message (%s.%s)",
178                 dbus_message_get_interface(msg), dbus_message_get_member(msg));
179
180         RET_IF_FAIL(info->conn != NULL);
181
182         for (prev = &info->methods; *prev; prev = &(*prev)->next) {
183                 EomDBusClientMethod *method = *prev;
184
185                 if (!strcmp(dbus_message_get_member(msg), method->name)) {
186                         GArray *array = _eom_dbus_convert_message_to_gvalue(msg);
187
188                         if (method->func)
189                                 method->func(method->data, array);
190
191                         if (array)
192                                 g_array_free(array, FALSE);
193
194                         dbus_error_free(&err);
195
196                         return;
197                 }
198         }
199 }
200
201
202 gboolean
203 _eom_dbus_client_cb(GIOChannel *src, GIOCondition cond, gpointer data)
204 {
205         EomDBusClientInfo *info = (EomDBusClientInfo *)data;
206
207         if (!info || !info->conn || info->fd < 0)
208                 return false;
209
210         do {
211                 if (info->conn)
212                         dbus_connection_read_write_dispatch(info->conn, 0);
213         } while (info->conn &&
214                         dbus_connection_get_is_connected(info->conn) &&
215                         dbus_connection_get_dispatch_status(info->conn) ==
216                         DBUS_DISPATCH_DATA_REMAINS);
217
218         return true;
219 }
220
221
222 static DBusHandlerResult
223 _eom_dbus_client_msg_handler(DBusConnection *connection, DBusMessage *msg, void *data)
224 {
225         EomDBusClientInfo *info = (EomDBusClientInfo *)data;
226
227         if (!info || !info->conn || !msg)
228                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
229
230         INFO("[Client] Got a message (%s.%s)",
231                 dbus_message_get_interface(msg), dbus_message_get_member(msg));
232
233         _eom_dbus_client_process_message(info, msg);
234
235         return DBUS_HANDLER_RESULT_HANDLED;
236 }
237
238 static DBusHandlerResult
239 _eom_dbus_client_msg_filter(DBusConnection *conn, DBusMessage *msg, void *data)
240 {
241         EomDBusClientInfo *info = (EomDBusClientInfo *)data;
242
243         if (!info)
244                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
245
246         if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected")) {
247                 INFO("[EOM] disconnected by signal");
248                 _eom_dbus_client_deinitialize(info);
249
250                 return DBUS_HANDLER_RESULT_HANDLED;
251         }
252
253         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
254 }
255
256 static int
257 _eom_dbus_client_initialize(EomDBusClientInfo *info)
258 {
259         DBusError err;
260         int ret;
261         DBusObjectPathVTable vtable = {.message_function = _eom_dbus_client_msg_handler, };
262         GIOChannel *channel;
263
264         dbus_error_init(&err);
265
266         if (_eom_dbus_need_private_conn())
267                 info->conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
268         else
269                 info->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
270
271         if (dbus_error_is_set(&err)) {
272                 ERR("[EOM] failed: connection (%s)", err.message);
273                 goto free_err;
274         }
275         if (!info->conn) {
276                 ERR("[EOM] failed: connection NULL");
277                 goto free_err;
278         }
279
280         ret = dbus_bus_request_name(info->conn, info->name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
281         if (dbus_error_is_set(&err)) {
282                 ERR("[EOM] failed: request name (%s)", err.message);
283                 goto free_conn;
284         }
285         if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
286                 ERR("[EOM] failed: Not Primary Owner (%d)", ret);
287                 goto free_conn;
288         }
289
290         snprintf(info->rule, sizeof(info->rule), "interface='%s'", EOM_DBUS_INTERFACE);
291
292         dbus_bus_add_match(info->conn, info->rule, &err);
293         dbus_connection_flush(info->conn);
294         if (dbus_error_is_set(&err)) {
295                 ERR("[EOM] failed: add match (%s)", err.message);
296                 goto free_name;
297         }
298
299         if (!dbus_connection_register_object_path(info->conn, EOM_DBUS_PATH, &vtable, info)) {
300                 ERR("[EOM] failed: register object path");
301                 goto free_match;
302         }
303
304         dbus_connection_set_exit_on_disconnect(info->conn, FALSE);
305
306         if (!dbus_connection_add_filter(info->conn, _eom_dbus_client_msg_filter, info, NULL)) {
307                 ERR("[EOM] failed: add filter (%s)", err.message);
308                 goto free_register;
309         }
310
311         if (!dbus_connection_get_unix_fd(info->conn, &info->fd) || info->fd < 0) {
312                 ERR("[EOM] failed: get fd");
313                 goto free_filter;
314         }
315
316         dbus_error_free(&err);
317
318         channel = g_io_channel_unix_new(info->fd);
319         g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
320
321         info->src = g_io_create_watch(channel, G_IO_IN);
322         g_source_set_callback(info->src, (GSourceFunc)_eom_dbus_client_cb, (gpointer)info, NULL);
323         g_source_attach(info->src, NULL);
324
325         g_io_channel_unref(channel);
326
327         INFO("[EOM_CLIENT] connected");
328
329         return 1;
330
331 free_filter:
332         dbus_connection_remove_filter(info->conn, _eom_dbus_client_msg_filter, info);
333 free_register:
334         dbus_connection_unregister_object_path(info->conn, EOM_DBUS_PATH);
335 free_match:
336         dbus_bus_remove_match(info->conn, info->rule, &err);
337         dbus_error_free(&err);
338 free_name:
339         dbus_bus_release_name(info->conn, info->name, &err);
340         dbus_error_free(&err);
341 free_conn:
342         dbus_connection_close(info->conn);
343 free_err:
344         dbus_error_free(&err);
345         info->conn = NULL;
346         info->fd = -1;
347
348         return 0;
349 }
350
351 static void
352 _eom_dbus_client_deinitialize(EomDBusClientInfo *info)
353 {
354         DBusError err;
355
356         if (!info->conn)
357                 return;
358
359         if (info->src) {
360                 g_source_destroy(info->src);
361                 g_source_unref(info->src);
362         }
363
364         if (info->conn) {
365                 dbus_error_init(&err);
366                 dbus_bus_remove_match(info->conn, info->rule, &err);
367                 dbus_error_free(&err);
368                 dbus_bus_release_name(info->conn, info->name, &err);
369                 dbus_error_free(&err);
370                 dbus_connection_unref(info->conn);
371         }
372
373         memset(info, 0, sizeof(EomDBusClientInfo));
374         info->fd = -1;
375
376         INFO("[EOM] disconnected");
377 }
378
379
380 static bool
381 _eom_dbus_client_connect(void)
382 {
383         if (client_info.conn)
384                 return true;
385
386         snprintf(client_info.name, STR_LEN, "org.eom.client%d", getpid());
387
388         client_info.fd = -1;
389
390         if (!_eom_dbus_client_initialize(&client_info))
391                 return false;
392
393         return true;
394 }
395
396 static void
397 _eom_dbus_client_disconnect(void)
398 {
399         _eom_dbus_client_deinitialize(&client_info);
400 }
401
402 static bool
403 _eom_dbus_client_add_method(EomDBusClientMethod *method)
404 {
405         EomDBusClientMethod **prev;
406
407         for (prev = &client_info.methods; *prev; prev = &(*prev)->next);
408
409         method->next = NULL;
410         *prev = method;
411
412         return true;
413 }
414
415 static void
416 _eom_dbus_client_remove_method(EomDBusClientMethod *method)
417 {
418         EomDBusClientMethod **prev;
419
420         for (prev = &client_info.methods; *prev; prev = &(*prev)->next)
421                 if (*prev == method) {
422                         *prev = method->next;
423                         method->next = NULL;
424                         break;
425                 }
426 }
427
428 bool
429 eom_dbus_client_init(notify_func func)
430 {
431         if (dbus_initialized)
432                 return true;
433
434         if (!_eom_dbus_client_connect())
435                 return false;
436
437         snprintf(dbus_method.name, sizeof(dbus_method.name), "%s", "Notify");
438         dbus_method.func = func;
439         dbus_method.data = NULL;
440         _eom_dbus_client_add_method(&dbus_method);
441
442         dbus_initialized = true;
443
444         INFO("dbus init");
445
446         return true;
447 }
448
449 void
450 eom_dbus_client_deinit(GList *cb_info_list)
451 {
452         if (!dbus_initialized)
453                 return;
454
455         /* An output instance and a callback can be created and be added only by user.
456          * If there is cb_info_list, it means that user is still
457          * watching and interested with eom dbus message.
458          */
459         if (cb_info_list)
460                 return;
461
462         _eom_dbus_client_remove_method(&dbus_method);
463         _eom_dbus_client_disconnect();
464
465         dbus_initialized = false;
466 }
467
468 GArray*
469 eom_dbus_client_send_message(char *method, GArray *array)
470 {
471         DBusMessage *msg = NULL;
472         DBusMessage *reply_msg = NULL;
473         GArray *ret_array = NULL;
474         DBusError err;
475
476         RETV_IF_FAIL(client_info.conn != NULL, NULL);
477
478         dbus_error_init(&err);
479
480         msg = dbus_message_new_method_call(EOM_DBUS_SERVER, EOM_DBUS_PATH, EOM_DBUS_INTERFACE, method);
481         GOTO_IF_FAIL(msg != NULL, err_send);
482
483         INFO("[EOM_CLIENT:%s] Send message(%s)", client_info.name, method);
484
485         if (!_eom_dbus_convert_gvalue_to_message(array, msg)) {
486                 ERR("[EOM_CLIENT:%s] failed: gvalue_to_message", client_info.name);
487                 goto err_send;
488         }
489
490         reply_msg = dbus_connection_send_with_reply_and_block(client_info.conn, msg, REPLY_TIME, &err);
491         if (dbus_error_is_set(&err)) {
492                 ERR("[EOM_CLIENT:%s] failed: send (%s)", client_info.name, err.message);
493                 goto err_send;
494         }
495         GOTO_IF_FAIL(reply_msg != NULL, err_send);
496
497         INFO("[EOM_CLIENT:%s] Got reply", client_info.name);
498
499         ret_array = _eom_dbus_convert_message_to_gvalue(reply_msg);
500
501         dbus_message_unref(msg);
502         dbus_message_unref(reply_msg);
503         dbus_error_free(&err);
504
505         return ret_array;
506 err_send:
507         if (msg)
508                 dbus_message_unref(msg);
509         if (reply_msg)
510                 dbus_message_unref(reply_msg);
511
512         dbus_error_free(&err);
513
514         return NULL;
515 }
516
517
518 GArray *
519 eom_dbus_client_get_output_ids(void)
520 {
521         GArray *array = NULL;
522
523         array = eom_dbus_client_send_message("GetOutputIDs", NULL);
524         RETV_IF_FAIL(array != NULL, NULL);
525
526         return array;
527 }
528
529 GArray *
530 eom_dbus_client_get_output_info(eom_output_id output_id)
531 {
532         GArray *array = NULL;
533         GArray *msg_array;
534         GValue v = G_VALUE_INIT;
535
536         msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
537
538         g_value_init(&v, G_TYPE_INT);
539         g_value_set_int(&v, output_id);
540         msg_array = g_array_append_val(msg_array, v);
541
542         array = eom_dbus_client_send_message("GetOutputInfo", msg_array);
543         GOTO_IF_FAIL(array != NULL, fail);
544
545         g_array_free(msg_array, FALSE);
546
547         return array;
548 fail:
549         g_array_free(msg_array, FALSE);
550
551         return NULL;
552 }
553
554 GArray *
555 eom_dbus_client_set_attribute(eom_output_id output_id, eom_output_attribute_e attr)
556 {
557         GArray *array = NULL;
558         GArray *msg_array;
559         GValue v = G_VALUE_INIT;
560         int pid = 0;
561
562         pid = getpid();
563
564         INFO("output_id: %d, pid: %d, attr: %d\n", output_id, pid, attr);
565
566         msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
567
568         /* 0:output_id, 1:pid, 2:eom_attribuete_e */
569         g_value_init(&v, G_TYPE_INT);
570         g_value_set_int(&v, output_id);
571         msg_array = g_array_append_val(msg_array, v);
572         g_value_set_int(&v, pid);
573         msg_array = g_array_append_val(msg_array, v);
574         g_value_set_int(&v, attr);
575         msg_array = g_array_append_val(msg_array, v);
576
577         array = eom_dbus_client_send_message("SetOutputAttribute", msg_array);
578         GOTO_IF_FAIL(array != NULL, fail);
579
580         g_array_free(msg_array, FALSE);
581
582         return array;
583 fail:
584         g_array_free(msg_array, FALSE);
585
586         return NULL;
587 }
588
589 GArray *
590 eom_dbus_client_set_window(eom_output_id output_id, Evas_Object *win)
591 {
592         GArray *array = NULL;
593         GArray *msg_array;
594         GValue v = G_VALUE_INIT;
595         int pid = 0;
596         Ecore_X_Window xwin;
597         int ret = 0;
598
599         pid = getpid();
600         xwin = elm_win_xwindow_get(win);
601
602         INFO("output_id: %d, pid: %d, xwin: %d\n", output_id, pid, xwin);
603
604         msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
605
606         /* 0:output_id, 1:pid, 2:eom_attribuete_e */
607         g_value_init(&v, G_TYPE_INT);
608         g_value_set_int(&v, output_id);
609         msg_array = g_array_append_val(msg_array, v);
610         g_value_set_int(&v, pid);
611         msg_array = g_array_append_val(msg_array, v);
612         g_value_set_int(&v, xwin);
613         msg_array = g_array_append_val(msg_array, v);
614
615         array = eom_dbus_client_send_message("SetWindow", msg_array);
616         RETV_IF_FAIL(array != NULL, NULL);
617
618         g_array_free(msg_array, FALSE);
619
620         ret = g_value_get_int(&g_array_index(array, GValue, 0));
621         GOTO_IF_FAIL(ret != 0, fail);
622
623 #ifdef HAVE_TIZEN_2_X
624         const char *profile = "desktop";
625         elm_win_profiles_set(win, &profile, 1);
626 #endif
627         elm_win_fullscreen_set(win, EINA_TRUE);
628
629         return array;
630 fail:
631         g_array_free(msg_array, FALSE);
632
633         return NULL;
634 }
635