2 * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <bundle_internal.h>
26 #include <glib-object.h>
28 #include <app_control.h>
29 #include <app_control_internal.h>
30 #include <Elementary.h>
31 #include <widget_errno.h>
32 #include <widget_instance.h>
33 #include <widget_service.h>
34 #include <widget_service_internal.h>
35 #include <aul_app_com.h>
36 #include <Ecore_Wayland.h>
37 #include <system_info.h>
39 #include <vconf-internal-keys.h>
40 #include <screen_connector_provider.h>
42 #include "widget_app.h"
43 #include "widget-log.h"
44 #include "widget-private.h"
45 #include "widget_app_internal.h"
51 #define STR_MAX_BUF 128
52 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
53 #define K_REASON "__WC_K_REASON__"
54 #define APP_TYPE_WIDGET "widgetapp"
55 #define STATUS_FOREGROUND "fg"
56 #define STATUS_BACKGROUND "bg"
58 typedef enum _widget_obj_state_e {
70 struct app_event_handler {
71 app_event_type_e type;
76 struct app_event_info {
77 app_event_type_e type;
81 typedef struct _widget_class widget_class_s;
83 #define WIDGET_APP_EVENT_MAX 5
84 static GList *handler_list[WIDGET_APP_EVENT_MAX] = {NULL, };
86 static int caller_pid;
87 static widget_app_lifecycle_callback_s *app_ops;
88 static void *app_user_data;
90 static widget_class_h class_provider;
91 static int exit_called;
92 static char *package_id;
93 static bool fg_signal;
94 static bool is_permanent;
96 static void _widget_core_set_appcore_event_cb(void);
97 static void _widget_core_unset_appcore_event_cb(void);
98 static int __instance_update(widget_class_h handle, const char *id, int force, const char *content);
100 static void __free_handler_cb(gpointer data)
106 static void __free_handler_list(void)
110 for (i = 0; i < WIDGET_APP_EVENT_MAX; i++) {
111 g_list_free_full(handler_list[i], __free_handler_cb);
112 handler_list[i] = NULL;
116 static inline bool _is_widget_feature_enabled(void)
118 static bool feature = false;
119 static bool retrieved = false;
122 if (retrieved == true)
125 ret = system_info_get_platform_bool(
126 "http://tizen.org/feature/shell.appwidget", &feature);
127 if (ret != SYSTEM_INFO_ERROR_NONE) {
128 _E("failed to get system info"); /* LCOV_EXCL_LINE */
129 return false; /* LCOV_EXCL_LINE */
137 static gint __comp_by_id(gconstpointer a, gconstpointer b)
139 widget_context_s *wc = (widget_context_s *)a;
141 return strcmp(wc->id, (const char *)b);
144 static widget_context_s *__find_context_by_id(const char *id)
147 GList *contexts = _widget_app_get_contexts();
152 ret = g_list_find_custom(contexts, id, __comp_by_id);
159 static gint __comp_by_state(gconstpointer a, gconstpointer b)
161 widget_context_s *wc = (widget_context_s *)a;
163 if (wc->state == (widget_obj_state_e)GPOINTER_TO_INT(b))
169 static widget_context_s *__find_context_by_state(widget_obj_state_e state)
172 GList *contexts = _widget_app_get_contexts();
174 ret = g_list_find_custom(contexts, GINT_TO_POINTER((int)state), __comp_by_state);
181 static gint __comp_by_win(gconstpointer a, gconstpointer b)
183 int win = GPOINTER_TO_INT(b);
184 widget_context_s *wc = (widget_context_s *)a;
186 return (wc && wc->win_id == win) ? 0 : -1;
189 static widget_context_s *__find_context_by_win(int win)
191 GList *contexts = _widget_app_get_contexts();
192 GList *ret = g_list_find_custom(contexts, GINT_TO_POINTER(win), __comp_by_win);
200 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
203 bundle *b = bundle_create();
204 char pkgid[256] = {0, };
208 _E("out of memory"); /* LCOV_EXCL_LINE */
209 return -1; /* LCOV_EXCL_LINE */
212 if (package_id == NULL) {
213 ret = aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid));
215 package_id = strdup(pkgid);
218 bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
219 bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
220 bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
222 bundle_add_str(b, AUL_K_PKGID, package_id);
224 _D("send lifecycle %s(%d)", instance_id, status);
225 ret = aul_app_com_send("widget.status", b);
227 _E("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */
234 static int __send_update_status(const char *class_id, const char *instance_id,
235 int status, int err, bundle *extra)
239 bundle_raw *raw = NULL;
241 char *viewer_endpoint = _widget_app_get_viewer_endpoint();
246 _E("out of memory"); /* LCOV_EXCL_LINE */
247 return -1; /* LCOV_EXCL_LINE */
251 snprintf(err_str, sizeof(err_str), "%d", err);
252 bundle_add_str(b, AUL_K_WIDGET_ERROR_CODE, err_str);
255 bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
256 bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
257 bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
260 bundle_encode(extra, &raw, &len);
261 bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw);
262 aul_widget_instance_add(class_id, instance_id);
265 _D("send update %s(%d) to %s", instance_id, status, viewer_endpoint);
266 aul_app_com_send(viewer_endpoint, b);
269 case WIDGET_INSTANCE_EVENT_CREATE:
270 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
272 case WIDGET_INSTANCE_EVENT_DESTROY:
273 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
275 case WIDGET_INSTANCE_EVENT_PAUSE:
276 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
278 case WIDGET_INSTANCE_EVENT_RESUME:
279 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
284 __send_lifecycle_event(class_id, instance_id, lifecycle);
293 static gboolean __timeout_cb(gpointer user_data)
295 widget_context_s *wc = user_data;
297 if (wc->state == WC_RUNNING) {
298 _D("Periodic update!");
299 __instance_update(wc->provider, wc->id, 0, NULL);
300 } else if (wc->state == WC_PAUSED ||
301 wc->state == WC_READY) {
302 wc->pending_update = true;
303 if (wc->periodic_timer) {
305 g_source_remove(wc->periodic_timer);
306 wc->periodic_timer = 0;
310 return G_SOURCE_CONTINUE;
313 static int __instance_resume(widget_class_h handle, const char *id, int send_update)
315 widget_context_s *wc = __find_context_by_id(id);
319 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
320 return -1; /* LCOV_EXCL_LINE */
323 if (wc->state == WC_RUNNING) {
324 _D("%s is already in running state", id); /* LCOV_EXCL_LINE */
325 return 0; /* LCOV_EXCL_LINE */
328 if (wc->state == WC_TERMINATED) {
329 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
330 return 0; /* LCOV_EXCL_LINE */
333 wc->state = WC_RUNNING;
334 if (wc->pending_update) {
335 _D("pending update!");
336 wc->pending_update = false;
337 __instance_update(wc->provider, wc->id, 0, wc->pending_content);
339 if (wc->period > 0) {
340 _D("Restart timer!");
341 wc->periodic_timer = g_timeout_add_seconds(wc->period,
346 if (handle->ops.resume)
347 handle->ops.resume(wc, handle->user_data);
349 _D("%s is resumed", id);
351 ret = __send_update_status(handle->classid, wc->id,
352 WIDGET_INSTANCE_EVENT_RESUME, 0, NULL);
354 _D("Send fg signal to resourceD");
355 aul_send_app_status_change_signal(getpid(),
369 static int __instance_pause(widget_class_h handle, const char *id, int send_update)
371 widget_context_s *wc = __find_context_by_id(id);
375 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
376 return -1; /* LCOV_EXCL_LINE */
379 if (wc->state == WC_PAUSED) {
380 _D("%s is already in paused state", id); /* LCOV_EXCL_LINE */
381 return 0; /* LCOV_EXCL_LINE */
384 if (wc->state == WC_TERMINATED) {
385 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
386 return 0; /* LCOV_EXCL_LINE */
389 if (handle->ops.pause)
390 handle->ops.pause(wc, handle->user_data);
392 wc->state = WC_PAUSED;
393 _D("%s is paused", id);
395 ret = __send_update_status(handle->classid, wc->id,
396 WIDGET_INSTANCE_EVENT_PAUSE, 0, NULL);
397 wc = __find_context_by_state(WC_RUNNING);
398 if (!wc && fg_signal) {
399 _D("Send bg signal to resourceD");
400 aul_send_app_status_change_signal(getpid(),
414 static int __instance_resize(widget_class_h handle, const char *id, int w, int h)
416 widget_context_s *wc = __find_context_by_id(id);
420 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
421 return -1; /* LCOV_EXCL_LINE */
424 if (handle->ops.resize)
425 handle->ops.resize(wc, w, h, handle->user_data);
427 _D("%s is resized to %dx%d", id, w, h);
428 ret = __send_update_status(handle->classid, wc->id,
429 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, 0, NULL);
434 static void __update_pending_content(widget_context_s *wc, const char *content)
436 if (wc->pending_content) {
437 free(wc->pending_content);
438 wc->pending_content = NULL;
442 wc->pending_content = strdup(content);
443 if (wc->pending_content == NULL)
448 /* LCOV_EXCL_START */
449 static int __instance_update_all(widget_class_h handle, int force, const char *content)
451 widget_context_s *wc;
454 GList *context = _widget_app_get_contexts();
457 b = bundle_decode((const bundle_raw *)content, strlen(content));
459 if (handle->ops.update) {
461 wc = (widget_context_s *)context->data;
462 context = context->next;
463 if (wc->state != WC_RUNNING && !force) {
464 __update_pending_content(wc, content);
465 wc->pending_update = true;
469 handle->ops.update(wc, b, force, handle->user_data);
470 ret = __send_update_status(handle->classid, wc->id,
471 WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
472 _D("updated:%s", wc->id);
483 /* LCOV_EXCL_START */
484 static int __instance_update(widget_class_h handle, const char *id, int force, const char *content)
486 widget_context_s *wc = __find_context_by_id(id);
490 _E("context not found: %s", id);
494 if (wc->state != WC_RUNNING && !force) {
495 __update_pending_content(wc, content);
496 wc->pending_update = true;
501 b = bundle_decode((const bundle_raw *)content, strlen(content));
503 if (handle->ops.update) {
504 handle->ops.update(wc, b, force, handle->user_data);
505 ret = __send_update_status(handle->classid, wc->id,
506 WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
507 _D("updated:%s", id);
517 static int __instance_create(widget_class_h handle, const char *id,
518 const char *content, int w, int h, double period)
520 widget_context_s *wc = NULL;
523 bundle *content_info = NULL;
525 wc = (widget_context_s *)calloc(1, sizeof(widget_context_s));
528 return WIDGET_ERROR_OUT_OF_MEMORY;
531 wc->state = WC_READY;
533 wc->provider = handle;
538 wc->content = strdup(content);
539 content_info = bundle_decode((const bundle_raw *)content, strlen(content));
542 _widget_app_add_context(wc);
544 ret = handle->ops.create(wc, content_info, w, h, handle->user_data);
546 _W("Create callback resturns error(%d)", ret);
547 send_ret = __send_update_status(handle->classid, wc->id,
548 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, ret, NULL);
550 _E("Fail to send abort status (%d)", send_ret);
552 _widget_app_remove_context(wc);
559 if (_widget_app_get_contexts() == NULL && !exit_called)
562 ret = __send_update_status(handle->classid, wc->id,
563 WIDGET_INSTANCE_EVENT_CREATE, 0, NULL);
568 aul_widget_instance_add(handle->classid, id);
572 wc->periodic_timer = g_timeout_add_seconds(period,
578 bundle_free(content_info);
583 static int __instance_destroy(widget_class_h handle, const char *id,
584 widget_app_destroy_type_e reason, int send_update)
586 widget_context_s *wc = __find_context_by_id(id);
588 int event = WIDGET_INSTANCE_EVENT_TERMINATE;
589 bundle *content_info;
592 _E("could not find widget obj: %s, clear amd info", id); /* LCOV_EXCL_LINE */
593 aul_widget_instance_del(handle->classid, id); /* LCOV_EXCL_LINE */
594 return WIDGET_ERROR_NONE; /* LCOV_EXCL_LINE */
597 wc->state = WC_TERMINATED;
599 content_info = bundle_decode((const bundle_raw *)wc->content, strlen(wc->content));
601 content_info = bundle_create();
603 handle->ops.destroy(wc, reason, content_info,
606 if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) {
608 event = WIDGET_INSTANCE_EVENT_DESTROY;
609 aul_widget_instance_del(handle->classid, id);
611 is_permanent = false;
612 ret = __send_update_status(handle->classid, id,
613 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
617 bundle_free(content_info);
619 ret = __send_update_status(handle->classid, id, event, 0, NULL);
621 _widget_app_remove_context(wc);
629 if (wc->periodic_timer)
630 g_source_remove(wc->periodic_timer);
632 if (wc->pending_content)
633 free(wc->pending_content);
637 if (_widget_app_get_contexts() == NULL && !exit_called) /* all instance destroyed */
643 static int __instance_change_period(const char *id, double period)
645 widget_context_s *wc = __find_context_by_id(id);
648 _E("could not find widget obj: %s", id);
652 if (wc->periodic_timer) {
654 g_source_remove(wc->periodic_timer);
655 wc->periodic_timer = 0;
659 if (wc->period > 0) {
660 _D("Restart timer!");
661 wc->periodic_timer = g_timeout_add_seconds(wc->period,
668 static widget_class_h __find_class_handler(const char *class_id,
669 widget_class_h handle)
671 if (!class_id || !handle)
674 widget_class_h head = handle;
677 if (head->classid && strcmp(head->classid, class_id) == 0)
686 /* LCOV_EXCL_START */
687 static void __resize_window(char *id, int w, int h)
689 widget_context_s *wc = __find_context_by_id(id);
692 _E("can not find instance: %s", id);
697 evas_object_resize(wc->win, w, h);
699 _E("unable to find window of %d", wc->id);
703 static void __control(bundle *b)
705 char *class_id = NULL;
707 char *operation = NULL;
708 char *content = NULL;
715 char *force_str = NULL;
716 double *period = NULL;
717 double update_period = 0;
718 widget_class_h handle = NULL;
722 bundle_get_str(b, WIDGET_K_CLASS, &class_id);
723 /* for previous version compatibility, use appid for default class id */
724 if (class_id == NULL)
727 bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
728 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
730 handle = __find_class_handler(class_id, class_provider);
732 _E("no handle provided: %s", class_id); /* LCOV_EXCL_LINE */
737 _E("no operation provided");
741 bundle_get_str(b, WIDGET_K_FORCE, &force_str);
743 if (force_str && strcmp(force_str, "true") == 0)
748 bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
749 bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
750 bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
752 w = (int)g_ascii_strtoll(w_str, &remain, 10);
755 h = (int)g_ascii_strtoll(h_str, &remain, 10);
757 ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period, &size);
758 if (ret == BUNDLE_ERROR_NONE)
759 update_period = *period;
761 if (strcmp(operation, "create") == 0) {
762 __instance_create(handle, id, content, w, h, update_period);
763 } else if (strcmp(operation, "resize") == 0) {
764 __resize_window(id, w, h);
765 __instance_resize(handle, id, w, h);
766 } else if (strcmp(operation, "update") == 0) {
768 __instance_update(handle, id, force, content);
770 __instance_update_all(handle, force, content);
772 } else if (strcmp(operation, "destroy") == 0) {
773 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_PERMANENT, UPDATE_ALL);
774 } else if (strcmp(operation, "resume") == 0) {
775 __instance_resume(handle, id, UPDATE_ALL);
776 } else if (strcmp(operation, "pause") == 0) {
777 __instance_pause(handle, id, UPDATE_ALL);
778 } else if (strcmp(operation, "terminate") == 0) {
779 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
780 } else if (strcmp(operation, "period") == 0) {
781 __instance_change_period(id, update_period);
786 LOGD("error on control");
790 static void __pause_all(int send_update)
792 GList *contexts = _widget_app_get_contexts();
793 GList *iter = g_list_first(contexts);
795 while (iter != NULL) {
796 widget_context_s *cxt = (widget_context_s *)iter->data;
798 switch (cxt->state) {
800 __instance_resume(cxt->provider, cxt->id, send_update);
801 __instance_pause(cxt->provider, cxt->id, send_update);
804 __instance_pause(cxt->provider, cxt->id, send_update);
807 LOGD("pause %s", cxt->id);
808 iter = g_list_next(iter);
812 /* LCOV_EXCL_START */
813 static void __resume_all(int send_update)
815 GList *contexts = _widget_app_get_contexts();
816 GList *iter = g_list_first(contexts);
818 while (iter != NULL) {
819 widget_context_s *cxt = (widget_context_s *)iter->data;
821 switch (cxt->state) {
823 __instance_resume(cxt->provider, cxt->id, send_update);
826 __instance_resume(cxt->provider, cxt->id, send_update);
829 iter = g_list_next(iter);
834 static void __destroy_all(int reason, int send_update)
836 GList *contexts = _widget_app_get_contexts();
837 GList *iter = g_list_first(contexts);
839 __pause_all(send_update);
840 while (iter != NULL) {
841 widget_context_s *cxt = (widget_context_s *)iter->data;
842 iter = g_list_next(iter);
843 switch (cxt->state) {
845 LOGD("destroy %d : %s", cxt->state, cxt->id);
846 __instance_destroy(cxt->provider, cxt->id, reason, send_update);
852 static Eina_Bool __visibility_cb(void *data, int type, void *event)
854 Ecore_Wl_Event_Window_Visibility_Change *ev = event;
855 widget_context_s *cxt = __find_context_by_win(ev->win);
857 LOGD("visiblity change: %d %d", (unsigned int)ev->win, (unsigned int)ev->fully_obscured);
860 LOGE("unknown window error: %d", ev->win);
861 return ECORE_CALLBACK_RENEW;
864 if ((cxt->state == WC_READY || cxt->state == WC_PAUSED)
865 && ev->fully_obscured == 0) {
866 __instance_resume(cxt->provider, cxt->id, UPDATE_ALL);
867 } else if (cxt->state == WC_RUNNING && ev->fully_obscured == 1) {
868 __instance_pause(cxt->provider, cxt->id, UPDATE_ALL);
870 LOGD("cxt:%s state:%d obscured:%d", cxt->id, cxt->state, ev->fully_obscured);
873 return ECORE_CALLBACK_RENEW;
876 /* LCOV_EXCL_START */
877 static Eina_Bool __lower_cb(void *data, int type, void *event)
880 return ECORE_CALLBACK_RENEW;
884 static Eina_Bool __configure_cb(void *data, int type, void *event)
886 Ecore_Wl_Event_Window_Configure *ev = event;
887 widget_context_s *cxt = __find_context_by_win(ev->win);
889 LOGD("configure: %d %d", ev->w, ev->h);
892 LOGE("unknown window error: %d", ev->win); /* LCOV_EXCL_LINE */
893 return ECORE_CALLBACK_RENEW; /* LCOV_EXCL_LINE */
896 if (cxt->state == WC_PAUSED || cxt->state == WC_RUNNING)
897 __instance_resize(cxt->provider, cxt->id, ev->w, ev->h);
898 LOGD("cxt:%s resized to %dx%d", cxt->id, ev->w, ev->h);
900 return ECORE_CALLBACK_RENEW;
903 static void __add_climsg()
905 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE, __visibility_cb, NULL);
906 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER, __lower_cb, NULL);
907 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, __configure_cb, NULL);
910 static void __get_content(bundle *b)
912 char *instance_id = NULL;
913 widget_context_s *cxt = NULL;
915 bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
919 cxt = __find_context_by_id(instance_id);
921 _E("can not find instance id:%s", instance_id);
926 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, cxt->content);
927 _D("content info of %s found", cxt->id);
929 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
930 _D("empty content info added");
934 static int __aul_handler(aul_type type, bundle *b, void *data)
942 bundle_get_str(b, WIDGET_K_CALLER, &caller);
944 caller_pid = g_ascii_strtoll(caller, &remain,
947 /* using caller appid and query pid using caller appid? */
955 __resume_all(UPDATE_ALL);
960 case AUL_WIDGET_CONTENT:
970 static char *__get_domain_name(char *appid)
975 _E("appid is NULL"); /* LCOV_EXCL_LINE */
976 return NULL; /* LCOV_EXCL_LINE */
979 name_token = strrchr(appid, '.');
981 if (name_token == NULL) {
982 _E("appid is invalid"); /* LCOV_EXCL_LINE */
983 return appid; /* LCOV_EXCL_LINE */
991 /* LCOV_EXCL_START */
992 static void __on_poweroff(keynode_t *key, void *data)
996 val = vconf_keynode_get_int(key);
998 case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
999 case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
1000 _I("power off changed: %d", val);
1003 case VCONFKEY_SYSMAN_POWER_OFF_NONE:
1004 case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
1010 /* LCOV_EXCL_STOP */
1012 extern int _set_i18n(const char *name);
1013 extern void aul_finalize();
1015 static int __before_loop(int argc, char **argv)
1020 char *viewer_endpoint = NULL;
1022 #if !(GLIB_CHECK_VERSION(2, 36, 0))
1026 kb = bundle_import_from_argv(argc, argv);
1028 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
1029 if (viewer_endpoint) {
1030 _E("viewer endpoint :%s", viewer_endpoint);
1031 _widget_app_set_viewer_endpoint(viewer_endpoint);
1033 _E("endpoint is missing");
1039 _E("failed to get launch argv"); /* LCOV_EXCL_LINE */
1042 screen_connector_provider_init();
1043 elm_init(argc, argv);
1045 r = aul_launch_init(__aul_handler, NULL);
1047 /* LCOV_EXCL_START */
1048 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1050 "Fail to call the aul_launch_init");
1051 /* LCOV_EXCL_STOP */
1054 r = aul_launch_argv_handler(argc, argv);
1056 /* LCOV_EXCL_START */
1057 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1059 "Fail to call the aul_launch_argv_handler");
1060 /* LCOV_EXCL_STOP */
1063 r = app_get_id(&appid);
1064 if (r != APP_ERROR_NONE)
1067 name = __get_domain_name(appid);
1070 /* LCOV_EXCL_START */
1071 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1073 "Fail to call __get_domain_name");
1074 /* LCOV_EXCL_STOP */
1077 r = _set_i18n(name);
1080 /* LCOV_EXCL_START */
1081 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1083 "Fail to call _set_i18n");
1084 /* LCOV_EXCL_STOP */
1089 _widget_core_set_appcore_event_cb();
1091 class_provider = app_ops->create(app_user_data);
1092 if (class_provider == NULL) {
1093 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1094 __FUNCTION__, "widget_class is NULL");
1097 vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL);
1099 return WIDGET_ERROR_NONE;
1102 static void __after_loop()
1105 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff);
1107 __pause_all(UPDATE_LOCAL);
1108 __destroy_all(WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
1110 if (app_ops->terminate)
1111 app_ops->terminate(app_user_data);
1114 screen_connector_provider_fini();
1116 _widget_app_free_viewer_endpoint();
1117 _widget_core_unset_appcore_event_cb();
1118 __free_handler_list();
1131 /* Check loader case */
1132 if (getenv("AUL_LOADER_INIT")) {
1133 unsetenv("AUL_LOADER_INIT");
1139 static void __on_low_memory(keynode_t *key, void *data)
1143 val = vconf_keynode_get_int(key);
1144 if (val == VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
1145 app_event_handler_h handler;
1146 struct app_event_info event;
1148 _I("widget_app_low_memory");
1150 event.type = APP_EVENT_LOW_MEMORY;
1151 event.value = (void *)&val;
1153 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_MEMORY]);
1156 handler = (app_event_handler_h) iter->data;
1157 handler->cb(&event, handler->data);
1158 iter = g_list_next(iter);
1163 static void __on_low_battery(keynode_t *key, void *data)
1167 val = vconf_keynode_get_int(key);
1168 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
1169 app_event_handler_h handler;
1170 struct app_event_info event;
1172 _I("widget_app_low_battery");
1174 event.type = APP_EVENT_LOW_BATTERY;
1175 event.value = (void *)&val;
1177 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_BATTERY]);
1180 handler = (app_event_handler_h) iter->data;
1181 handler->cb(&event, handler->data);
1182 iter = g_list_next(iter);
1187 static void __on_lang_changed(keynode_t *key, void *data)
1192 val = vconf_keynode_get_str(key);
1194 app_event_handler_h handler;
1195 struct app_event_info event;
1197 _I("widget_app_lang_changed");
1199 event.type = APP_EVENT_LANGUAGE_CHANGED;
1200 event.value = (void *)val;
1202 GList *iter = g_list_first(handler_list[APP_EVENT_LANGUAGE_CHANGED]);
1205 handler = (app_event_handler_h) iter->data;
1206 handler->cb(&event, handler->data);
1207 iter = g_list_next(iter);
1211 static void __on_region_changed(keynode_t *key, void *data)
1216 val = vconf_keynode_get_str(key);
1218 app_event_handler_h handler;
1219 struct app_event_info event;
1221 _I("widget_app_region_changed");
1223 event.type = APP_EVENT_REGION_FORMAT_CHANGED;
1224 event.value = (void *)val;
1226 GList *iter = g_list_first(handler_list[APP_EVENT_REGION_FORMAT_CHANGED]);
1229 handler = (app_event_handler_h) iter->data;
1230 handler->cb(&event, handler->data);
1231 iter = g_list_next(iter);
1235 static void __register_event(int event_type)
1237 switch (event_type) {
1238 case APP_EVENT_LOW_MEMORY:
1239 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
1242 case APP_EVENT_LOW_BATTERY:
1243 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
1246 case APP_EVENT_LANGUAGE_CHANGED:
1247 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_lang_changed, NULL);
1250 case APP_EVENT_REGION_FORMAT_CHANGED:
1251 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed, NULL);
1256 static void __unregister_event(int event_type)
1258 switch (event_type) {
1259 case APP_EVENT_LOW_MEMORY:
1260 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
1263 case APP_EVENT_LOW_BATTERY:
1264 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
1267 case APP_EVENT_LANGUAGE_CHANGED:
1268 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_lang_changed);
1271 case APP_EVENT_REGION_FORMAT_CHANGED:
1272 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed);
1277 static void _widget_core_set_appcore_event_cb(void)
1279 __register_event(APP_EVENT_LANGUAGE_CHANGED);
1280 __register_event(APP_EVENT_REGION_FORMAT_CHANGED);
1283 static void _widget_core_unset_appcore_event_cb(void)
1285 __unregister_event(APP_EVENT_LANGUAGE_CHANGED);
1286 __unregister_event(APP_EVENT_REGION_FORMAT_CHANGED);
1289 EXPORT_API int widget_app_main(int argc, char **argv,
1290 widget_app_lifecycle_callback_s *callback, void *user_data)
1294 if (!_is_widget_feature_enabled()) {
1295 _E("not supported"); /* LCOV_EXCL_LINE */
1296 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1299 if (argc <= 0 || argv == NULL || callback == NULL)
1300 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1301 __FUNCTION__, NULL);
1303 if (callback->create == NULL)
1304 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1306 "widget_app_create_cb() callback must be "
1309 app_user_data = user_data;
1310 r = __before_loop(argc, argv);
1320 aul_status_update(STATUS_DYING);
1323 return WIDGET_ERROR_NONE;
1326 EXPORT_API int widget_app_exit(void)
1328 if (!_is_widget_feature_enabled()) {
1329 _E("not supported"); /* LCOV_EXCL_LINE */
1330 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1334 return WIDGET_ERROR_NONE;
1339 if (!_widget_app_get_contexts() && is_permanent)
1342 return WIDGET_ERROR_NONE;
1345 /* LCOV_EXCL_START */
1346 static gboolean __finish_event_cb(gpointer user_data)
1348 if (user_data == NULL)
1351 widget_context_s *wc = (widget_context_s *)user_data;
1353 switch (wc->state) {
1355 __instance_resume(wc->provider, wc->id, UPDATE_LOCAL);
1357 __instance_pause(wc->provider, wc->id, UPDATE_LOCAL);
1359 __instance_destroy(wc->provider, wc->id,
1360 WIDGET_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
1368 /* LCOV_EXCL_STOP */
1370 EXPORT_API int widget_app_terminate_context(widget_context_h context)
1372 if (!_is_widget_feature_enabled()) {
1373 _E("not supported"); /* LCOV_EXCL_LINE */
1374 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1377 if (context == NULL)
1378 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1379 __FUNCTION__, NULL);
1381 g_idle_add(__finish_event_cb, context);
1382 return WIDGET_ERROR_NONE;
1385 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
1387 GList *contexts = _widget_app_get_contexts();
1389 widget_context_s *wc;
1391 if (!_is_widget_feature_enabled()) {
1392 _E("not supported"); /* LCOV_EXCL_LINE */
1393 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1397 return WIDGET_ERROR_INVALID_PARAMETER;
1399 list = g_list_first(contexts);
1402 wc = (widget_context_s *)list->data;
1410 return WIDGET_ERROR_NONE;
1413 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
1414 app_event_type_e event_type, app_event_cb callback,
1420 r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1422 return WIDGET_ERROR_FAULT;
1425 return WIDGET_ERROR_NOT_SUPPORTED;
1427 app_event_handler_h handler;
1429 if (event_handler == NULL || callback == NULL)
1430 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1432 if (event_type < APP_EVENT_LOW_MEMORY
1433 || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
1434 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1436 if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
1437 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
1439 GList *iter = g_list_first(handler_list[event_type]);
1442 handler = (app_event_handler_h) iter->data;
1444 if (handler->cb == callback)
1445 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1447 iter = g_list_next(iter);
1450 handler = calloc(1, sizeof(struct app_event_handler));
1452 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
1454 if (g_list_length(handler_list[event_type]) == 0)
1455 __register_event(event_type);
1457 handler->type = event_type;
1458 handler->cb = callback;
1459 handler->data = user_data;
1460 handler_list[event_type] = g_list_append(handler_list[event_type], handler);
1462 *event_handler = handler;
1464 return WIDGET_ERROR_NONE;
1467 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
1473 r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1475 return WIDGET_ERROR_FAULT;
1478 return WIDGET_ERROR_NOT_SUPPORTED;
1480 app_event_type_e type;
1482 if (event_handler == NULL)
1483 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1485 type = event_handler->type;
1486 if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
1487 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1489 handler_list[type] = g_list_remove(handler_list[type], event_handler);
1490 free(event_handler);
1492 if (g_list_length(handler_list[type]) == 0)
1493 __unregister_event(type);
1495 return WIDGET_ERROR_NONE;
1498 EXPORT_API const char *widget_app_get_id(widget_context_h context)
1500 if (!_is_widget_feature_enabled()) {
1501 _E("not supported"); /* LCOV_EXCL_LINE */
1502 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1503 return NULL; /* LCOV_EXCL_LINE */
1507 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1511 set_last_result(WIDGET_ERROR_NONE);
1515 static void _win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
1517 /* Remove data used in accessibility */
1519 plug_id = evas_object_data_del(obj, "___PLUGID");
1523 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
1526 widget_context_s *cxt = (widget_context_s *)context;
1527 Evas_Object *ret_win;
1528 Ecore_Wl_Window *wl_win;
1529 struct wl_surface *surface;
1533 if (!_is_widget_feature_enabled()) {
1534 _E("not supported"); /* LCOV_EXCL_LINE */
1535 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1538 if (context == NULL || win == NULL)
1539 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1540 __FUNCTION__, NULL);
1542 ret_win = elm_win_add(NULL, cxt->id, ELM_WIN_BASIC);
1543 if (ret_win == NULL) {
1544 _E("failed to create window"); /* LCOV_EXCL_LINE */
1545 goto fault; /* LCOV_EXCL_LINE */
1548 elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
1549 elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
1551 wl_win = elm_win_wl_window_get(ret_win);
1552 if (wl_win == NULL) {
1553 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
1557 surface = ecore_wl_window_surface_get(wl_win);
1558 if (surface == NULL) {
1559 _E("failed to get surface"); /* LCOV_EXCL_LINE */
1560 goto fault; /* LCOV_EXCL_LINE */
1562 screen_connector_provider_remote_enable(cxt->id, surface);
1564 ecore_wl_window_class_name_set(wl_win, cxt->id);
1565 elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
1569 cxt->win_id = ecore_wl_window_id_get(wl_win);
1571 /* Set data to use in accessibility */
1572 snprintf(buffer, sizeof(buffer), "%s:%d", cxt->id, getpid());
1573 evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
1574 evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, _win_del_cb, NULL);
1576 _D("window created: %d", cxt->win_id);
1578 return WIDGET_ERROR_NONE;
1581 if (ret_win) /* LCOV_EXCL_LINE */
1582 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
1584 return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
1588 widget_class_h _widget_class_create(widget_class_s *prev, const char *class_id,
1589 widget_instance_lifecycle_callback_s callback, void *user_data)
1593 if (!_is_widget_feature_enabled()) {
1594 _E("not supported"); /* LCOV_EXCL_LINE */
1595 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1599 if (class_id == NULL) {
1600 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1604 wc = (widget_class_s *)calloc(1, sizeof(widget_class_s));
1606 _E("failed to calloc : %s", __FUNCTION__); /* LCOV_EXCL_LINE */
1607 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); /* LCOV_EXCL_LINE */
1608 return NULL; /* LCOV_EXCL_LINE */
1611 wc->classid = strdup(class_id);
1612 wc->user_data = user_data;
1617 set_last_result(WIDGET_ERROR_NONE);
1625 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1626 const char *class_id,
1627 widget_instance_lifecycle_callback_s callback, void *user_data)
1629 return _widget_class_create(widget_class, class_id, callback,
1633 EXPORT_API widget_class_h widget_app_class_create(
1634 widget_instance_lifecycle_callback_s callback, void *user_data)
1636 return _widget_class_create(class_provider, appid, callback, user_data);
1639 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1641 if (!_is_widget_feature_enabled()) {
1642 _E("not supported"); /* LCOV_EXCL_LINE */
1643 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1646 if (context == NULL)
1647 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1648 __FUNCTION__, NULL);
1652 return WIDGET_ERROR_NONE;
1655 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1657 if (!_is_widget_feature_enabled()) {
1658 _E("not supported"); /* LCOV_EXCL_LINE */
1659 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1662 if (context == NULL || tag == NULL)
1663 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1664 __FUNCTION__, NULL);
1666 *tag = context->tag;
1668 return WIDGET_ERROR_NONE;
1671 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1672 bundle *content_info)
1674 const char *class_id = NULL;
1676 bundle_raw *raw = NULL;
1679 if (!_is_widget_feature_enabled()) {
1680 _E("not supported"); /* LCOV_EXCL_LINE */
1681 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1684 if (context == NULL || content_info == NULL)
1685 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1686 __FUNCTION__, NULL);
1688 if (context->provider == NULL)
1689 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1690 __FUNCTION__, NULL);
1692 class_id = context->provider->classid;
1693 if (class_id == NULL)
1694 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1696 ret = __send_update_status(class_id, context->id,
1697 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
1699 if (context->content)
1700 free(context->content);
1702 bundle_encode(content_info, &raw, &len);
1704 context->content = strdup((const char *)raw);
1706 context->content = NULL;
1710 /* LCOV_EXCL_START */
1711 _E("failed to send content info: %s of %s (%d)", context->id,
1713 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1715 /* LCOV_EXCL_STOP */
1718 return WIDGET_ERROR_NONE;
1721 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1724 if (!_is_widget_feature_enabled()) {
1725 _E("not supported"); /* LCOV_EXCL_LINE */
1726 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1729 if (!context || !title)
1730 return WIDGET_ERROR_INVALID_PARAMETER;
1733 elm_win_title_set(context->win, title);
1735 return WIDGET_ERROR_NONE;