1 /**************************************************************************
3 eom (external output manager)
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
8 SooChan Lim <sc1.lim@samsung.com>
9 Boram Park <boram1288.park@samsung.com>
10 Changyeon Lee <cyeon.lee@samsung.com>
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:
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
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.
32 **************************************************************************/
35 #include <dbus/dbus.h>
40 #include "eom-private.h"
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"
49 #define REPLY_TIME 1000
52 typedef struct _EomDBusClientMethod {
56 struct _EomDBusClientMethod *next;
57 } EomDBusClientMethod;
59 typedef struct _EomDBusClientInfo {
64 EomDBusClientMethod *methods;
68 static EomDBusClientInfo client_info;
70 static bool dbus_initialized;
71 static EomDBusClientMethod dbus_method;
73 static void _eom_dbus_client_deinitialize(EomDBusClientInfo *info);
76 _eom_dbus_need_private_conn(void)
78 char *env = getenv("EOM_PRIVATE_CONN");
81 return (atoi(env) > 0) ? 1 : 0;
82 INFO("EOM_PRIVATE_CONN = %s", env);
89 _eom_dbus_convert_gvalue_to_message(GArray *array, DBusMessage *msg)
102 dbus_message_iter_init_append(msg, &iter);
104 INFO("[EOM_CLIENT:%s] len(%d)", client_info.name, array->len);
106 for (i = 0; i < array->len; i++) {
107 v = &g_array_index(array, GValue, i);
110 INFO("[EOM_CLIENT:%s] type(%d)", client_info.name, (int)type);
115 int integer = g_value_get_int(v);
117 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &integer)) {
118 ERR("[EOM_CLIENT:%s] failed: int append", client_info.name);
132 _eom_dbus_convert_message_to_gvalue(DBusMessage *msg)
135 DBusMessageIter iter;
137 if (!dbus_message_iter_init(msg, &iter))
140 array = g_array_new(FALSE, FALSE, sizeof(GValue));
143 int type = dbus_message_iter_get_arg_type(&iter);
144 GValue v = G_VALUE_INIT;
146 INFO("[EOM_CLIENT:%s] type(%c(%d))", client_info.name, (char)type, type);
149 case DBUS_TYPE_INT32:
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);
161 g_array_free(array, FALSE);
164 } while (dbus_message_iter_has_next(&iter) && dbus_message_iter_next(&iter));
170 _eom_dbus_client_process_message(EomDBusClientInfo *info, DBusMessage *msg)
172 EomDBusClientMethod **prev;
175 dbus_error_init(&err);
177 INFO("[CLIENT] Process a message (%s.%s)",
178 dbus_message_get_interface(msg), dbus_message_get_member(msg));
180 RET_IF_FAIL(info->conn != NULL);
182 for (prev = &info->methods; *prev; prev = &(*prev)->next) {
183 EomDBusClientMethod *method = *prev;
185 if (!strcmp(dbus_message_get_member(msg), method->name)) {
186 GArray *array = _eom_dbus_convert_message_to_gvalue(msg);
189 method->func(method->data, array);
192 g_array_free(array, FALSE);
194 dbus_error_free(&err);
203 _eom_dbus_client_cb(GIOChannel *src, GIOCondition cond, gpointer data)
205 EomDBusClientInfo *info = (EomDBusClientInfo *)data;
207 if (!info || !info->conn || info->fd < 0)
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);
222 static DBusHandlerResult
223 _eom_dbus_client_msg_handler(DBusConnection *connection, DBusMessage *msg, void *data)
225 EomDBusClientInfo *info = (EomDBusClientInfo *)data;
227 if (!info || !info->conn || !msg)
228 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
230 INFO("[Client] Got a message (%s.%s)",
231 dbus_message_get_interface(msg), dbus_message_get_member(msg));
233 _eom_dbus_client_process_message(info, msg);
235 return DBUS_HANDLER_RESULT_HANDLED;
238 static DBusHandlerResult
239 _eom_dbus_client_msg_filter(DBusConnection *conn, DBusMessage *msg, void *data)
241 EomDBusClientInfo *info = (EomDBusClientInfo *)data;
244 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
246 if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected")) {
247 INFO("[EOM] disconnected by signal");
248 _eom_dbus_client_deinitialize(info);
250 return DBUS_HANDLER_RESULT_HANDLED;
253 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
257 _eom_dbus_client_initialize(EomDBusClientInfo *info)
261 DBusObjectPathVTable vtable = {.message_function = _eom_dbus_client_msg_handler, };
264 dbus_error_init(&err);
266 if (_eom_dbus_need_private_conn())
267 info->conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
269 info->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
271 if (dbus_error_is_set(&err)) {
272 ERR("[EOM] failed: connection (%s)", err.message);
276 ERR("[EOM] failed: connection NULL");
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);
285 if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
286 ERR("[EOM] failed: Not Primary Owner (%d)", ret);
290 snprintf(info->rule, sizeof(info->rule), "interface='%s'", EOM_DBUS_INTERFACE);
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);
299 if (!dbus_connection_register_object_path(info->conn, EOM_DBUS_PATH, &vtable, info)) {
300 ERR("[EOM] failed: register object path");
304 dbus_connection_set_exit_on_disconnect(info->conn, FALSE);
306 if (!dbus_connection_add_filter(info->conn, _eom_dbus_client_msg_filter, info, NULL)) {
307 ERR("[EOM] failed: add filter (%s)", err.message);
311 if (!dbus_connection_get_unix_fd(info->conn, &info->fd) || info->fd < 0) {
312 ERR("[EOM] failed: get fd");
316 dbus_error_free(&err);
318 channel = g_io_channel_unix_new(info->fd);
319 g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
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);
325 g_io_channel_unref(channel);
327 INFO("[EOM_CLIENT] connected");
332 dbus_connection_remove_filter(info->conn, _eom_dbus_client_msg_filter, info);
334 dbus_connection_unregister_object_path(info->conn, EOM_DBUS_PATH);
336 dbus_bus_remove_match(info->conn, info->rule, &err);
337 dbus_error_free(&err);
339 dbus_bus_release_name(info->conn, info->name, &err);
340 dbus_error_free(&err);
342 dbus_connection_close(info->conn);
344 dbus_error_free(&err);
352 _eom_dbus_client_deinitialize(EomDBusClientInfo *info)
360 g_source_destroy(info->src);
361 g_source_unref(info->src);
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);
373 memset(info, 0, sizeof(EomDBusClientInfo));
376 INFO("[EOM] disconnected");
381 _eom_dbus_client_connect(void)
383 if (client_info.conn)
386 snprintf(client_info.name, STR_LEN, "org.eom.client%d", getpid());
390 if (!_eom_dbus_client_initialize(&client_info))
397 _eom_dbus_client_disconnect(void)
399 _eom_dbus_client_deinitialize(&client_info);
403 _eom_dbus_client_add_method(EomDBusClientMethod *method)
405 EomDBusClientMethod **prev;
407 for (prev = &client_info.methods; *prev; prev = &(*prev)->next);
416 _eom_dbus_client_remove_method(EomDBusClientMethod *method)
418 EomDBusClientMethod **prev;
420 for (prev = &client_info.methods; *prev; prev = &(*prev)->next)
421 if (*prev == method) {
422 *prev = method->next;
429 eom_dbus_client_init(notify_func func)
431 if (dbus_initialized)
434 if (!_eom_dbus_client_connect())
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);
442 dbus_initialized = true;
450 eom_dbus_client_deinit(GList *cb_info_list)
452 if (!dbus_initialized)
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.
462 _eom_dbus_client_remove_method(&dbus_method);
463 _eom_dbus_client_disconnect();
465 dbus_initialized = false;
469 eom_dbus_client_send_message(char *method, GArray *array)
471 DBusMessage *msg = NULL;
472 DBusMessage *reply_msg = NULL;
473 GArray *ret_array = NULL;
476 RETV_IF_FAIL(client_info.conn != NULL, NULL);
478 dbus_error_init(&err);
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);
483 INFO("[EOM_CLIENT:%s] Send message(%s)", client_info.name, method);
485 if (!_eom_dbus_convert_gvalue_to_message(array, msg)) {
486 ERR("[EOM_CLIENT:%s] failed: gvalue_to_message", client_info.name);
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);
495 GOTO_IF_FAIL(reply_msg != NULL, err_send);
497 INFO("[EOM_CLIENT:%s] Got reply", client_info.name);
499 ret_array = _eom_dbus_convert_message_to_gvalue(reply_msg);
501 dbus_message_unref(msg);
502 dbus_message_unref(reply_msg);
503 dbus_error_free(&err);
508 dbus_message_unref(msg);
510 dbus_message_unref(reply_msg);
512 dbus_error_free(&err);
519 eom_dbus_client_get_output_ids(void)
521 GArray *array = NULL;
523 array = eom_dbus_client_send_message("GetOutputIDs", NULL);
524 RETV_IF_FAIL(array != NULL, NULL);
530 eom_dbus_client_get_output_info(eom_output_id output_id)
532 GArray *array = NULL;
534 GValue v = G_VALUE_INIT;
536 msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
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);
542 array = eom_dbus_client_send_message("GetOutputInfo", msg_array);
543 GOTO_IF_FAIL(array != NULL, fail);
545 g_array_free(msg_array, FALSE);
549 g_array_free(msg_array, FALSE);
555 eom_dbus_client_set_attribute(eom_output_id output_id, eom_output_attribute_e attr)
557 GArray *array = NULL;
559 GValue v = G_VALUE_INIT;
564 INFO("output_id: %d, pid: %d, attr: %d\n", output_id, pid, attr);
566 msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
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);
577 array = eom_dbus_client_send_message("SetOutputAttribute", msg_array);
578 GOTO_IF_FAIL(array != NULL, fail);
580 g_array_free(msg_array, FALSE);
584 g_array_free(msg_array, FALSE);
590 eom_dbus_client_set_window(eom_output_id output_id, Evas_Object *win)
592 GArray *array = NULL;
594 GValue v = G_VALUE_INIT;
600 xwin = elm_win_xwindow_get(win);
602 INFO("output_id: %d, pid: %d, xwin: %d\n", output_id, pid, xwin);
604 msg_array = g_array_new(FALSE, FALSE, sizeof(GValue));
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);
615 array = eom_dbus_client_send_message("SetWindow", msg_array);
616 RETV_IF_FAIL(array != NULL, NULL);
618 g_array_free(msg_array, FALSE);
620 ret = g_value_get_int(&g_array_index(array, GValue, 0));
621 GOTO_IF_FAIL(ret != 0, fail);
623 #ifdef HAVE_TIZEN_2_X
624 const char *profile = "desktop";
625 elm_win_profiles_set(win, &profile, 1);
627 elm_win_fullscreen_set(win, EINA_TRUE);
631 g_array_free(msg_array, FALSE);