2756f860ffe4cd2e5a3d8ee060c038939bce2097
[apps/native/widget/widget-provider.git] / widget_provider_app / src / client.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <string.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include <widget_errno.h>
26 #include <widget_service.h>
27 #include <widget_conf.h>
28 #include <widget_abi.h>
29 #include <widget_util.h>
30
31 #include <app.h>
32 #include <dlog.h>
33 #include <pkgmgr-info.h>
34
35 #include <Ecore.h>
36 #include <Eina.h>
37
38 #include <packet.h>
39 #include <com-core_packet.h>
40
41 #include "widget_provider.h"
42 #include "widget_provider_buffer.h"
43 #include "debug.h"
44 #include "widget_provider_app.h"
45 #include "widget_provider_app_internal.h"
46 #include "client.h"
47 #include "util.h"
48 #include "connection.h"
49
50 #define PKGMGR_COMPONENT_TYPE_WATCH_APP "watchapp"
51 #define BUFFER_MAX 256
52
53 int errno;
54
55 struct item {
56         char *id;
57         void *update_timer;
58         struct widget_provider_event_callback *table;
59         int paused;
60         void *data;
61         Eina_List *handle_list;
62 };
63
64 struct internal_item {
65         char *id;
66         void *data;
67 };
68
69 static struct info {
70         int secured;
71         char *abi;
72         char *name;
73         char *hw_acceleration;
74         Ecore_Timer *ping_timer;
75         Eina_List *inst_list;
76         int paused;
77         int initialized;
78         Eina_List *internal_item_list;
79         Eina_List *widget_pre_callback_list[WIDGET_PRE_CALLBACK_COUNT];
80 } s_info = {
81         .secured = 0,
82         .abi = NULL,
83         .name = NULL,
84         .hw_acceleration = NULL,
85         .ping_timer = NULL,
86         .inst_list = NULL,
87         .paused = 1,
88         .initialized = 0,
89         .internal_item_list = NULL,
90         .widget_pre_callback_list = { NULL, },
91 };
92
93 struct pre_callback_item {
94         widget_pre_callback_t cb;
95         void *data;
96 };
97
98 static void invoke_pre_callback(widget_pre_callback_e type, const char *id)
99 {
100         Eina_List *l;
101         Eina_List *n;
102         struct pre_callback_item *item;
103
104         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
105                 item->cb(id, item->data);
106         }
107 }
108
109 static inline char *package_get_pkgid(const char *appid)
110 {
111         int ret;
112         pkgmgrinfo_appinfo_h handle;
113         char *new_appid = NULL;
114         char *pkgid = NULL;
115
116         ret = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
117         if (ret != PMINFO_R_OK) {
118                 ErrPrint("Failed to get appinfo\n");
119                 return NULL;
120         }
121
122         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &new_appid);
123         if (ret != PMINFO_R_OK) {
124                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
125                 ErrPrint("Failed to get pkgname for (%s)\n", appid);
126                 return NULL;
127         }
128
129         if (new_appid && new_appid[0] != '\0') {
130                 pkgid = strdup(new_appid);
131                 if (!pkgid) {
132                         ErrPrint("strdup: %s\n", strerror(errno));
133                 }
134         }
135         pkgmgrinfo_appinfo_destroy_appinfo(handle);
136
137         return pkgid;
138 }
139
140 char *widget_pkgname(void)
141 {
142         widget_list_h list_handle;
143         const char *abi_pkgname = NULL;
144         char *pkgid;
145         char *converted_provider_pkgname = NULL;
146         int verified;
147         char *widget_id;
148
149         pkgid = package_get_pkgid(provider_pkgname());
150         list_handle = widget_service_create_widget_list(pkgid, NULL);
151         abi_pkgname = s_info.abi ? widget_abi_get_pkgname_by_abi(s_info.abi) : NULL;
152         DbgFree(pkgid);
153         if (!abi_pkgname) {
154                 widget_service_destroy_widget_list(list_handle);
155                 ErrPrint("Failed to get pkgname[%s]", s_info.abi);
156                 return NULL;
157         }
158
159         verified = 0;
160         widget_id = NULL;
161         while (widget_service_get_item_from_widget_list(list_handle, NULL, &widget_id, NULL) == WIDGET_ERROR_NONE) {
162                 if (!widget_id) {
163                         ErrPrint("Invalid widget_id\n");
164                         continue;
165                 }
166
167                 // tmp == /APPID/.provider <<- PROVIDER UI-APP
168                 // widget_id == org.tizen.watch-hello <<-- WIDGET ID
169                 // provider_pkgname == org.tizen.watch-hello.provider
170                 converted_provider_pkgname = widget_util_replace_string(abi_pkgname, WIDGET_CONF_REPLACE_TAG_APPID, widget_id);
171                 if (!converted_provider_pkgname) {
172                         DbgFree(widget_id);
173                         widget_id = NULL;
174                         continue;
175                 }
176
177                 /* Verify the Package Name */
178                 verified = !strcmp(converted_provider_pkgname, provider_pkgname());
179                 DbgFree(converted_provider_pkgname);
180
181                 if (verified) {
182                         break;
183                 }
184
185                 DbgFree(widget_id);
186                 widget_id = NULL;
187         }
188
189         widget_service_destroy_widget_list(list_handle);
190         return widget_id;
191 }
192
193 static Eina_Bool periodic_updator(void *data)
194 {
195         struct item *item = data;
196
197         if (item->table->update) {
198                 int ret;
199                 ret = item->table->update(item->id, NULL, 0, item->table->data);
200                 if (ret < 0) {
201                         ErrPrint("Provider update: [%s] returns 0x%X\n", item->id, ret);
202                 }
203         }
204
205         return ECORE_CALLBACK_RENEW;
206 }
207
208 static struct method s_table[] = {
209         {
210                 .cmd = NULL,
211                 .handler = NULL,
212         },
213 };
214
215 static struct internal_item *internal_item_create(const char *uri)
216 {
217         struct internal_item *item;
218
219         item = malloc(sizeof(*item));
220         if (!item) {
221                 ErrPrint("Heap: %s\n", strerror(errno));
222                 return NULL;
223         }
224
225         item->id = strdup(uri);
226         if (!item->id) {
227                 ErrPrint("Heap: %s\n", strerror(errno));
228                 free(item);
229                 return NULL;
230         }
231
232         s_info.internal_item_list = eina_list_append(s_info.internal_item_list, item);
233
234         return item;
235 }
236
237 static void internal_item_destroy(struct internal_item *item)
238 {
239         s_info.internal_item_list = eina_list_remove(s_info.internal_item_list, item);
240
241         free(item->id);
242         free(item);
243 }
244
245 static struct internal_item *internal_item_find(const char *uri)
246 {
247         Eina_List *l;
248         struct internal_item *item;
249
250         EINA_LIST_FOREACH(s_info.internal_item_list, l, item) {
251                 if (!strcmp(item->id, uri)) {
252                         return item;
253                 }
254         }
255
256         return NULL;
257 }
258
259 static struct item *instance_create(const char *id, double period, struct widget_provider_event_callback *table, const char *direct_addr)
260 {
261         struct item *item;
262
263         item = calloc(1, sizeof(*item));
264         if (!item) {
265                 ErrPrint("Heap: %s\n", strerror(errno));
266                 return NULL;
267         }
268
269         item->id = strdup(id);
270         if (!item->id) {
271                 ErrPrint("Heap: %s\n", strerror(errno));
272                 free(item);
273                 return NULL;
274         }
275
276         /*
277          * If the "secured" flag is toggled,
278          * The master will send the update event to this provider app.
279          */
280         if (!s_info.secured && period > 0.0f) {
281                 item->update_timer = util_timer_add(period, periodic_updator, item);
282                 if (!item->update_timer) {
283                         ErrPrint("Failed to create a timer\n");
284                         free(item->id);
285                         free(item);
286                         return NULL;
287                 }
288         }
289
290         item->table = table;
291         if (direct_addr) {
292                 struct connection *conn_handle;
293
294                 conn_handle = connection_find_by_addr(direct_addr);
295                 if (!conn_handle) {
296                         conn_handle = connection_create(direct_addr, (void *)s_table);
297                         if (!conn_handle) {
298                                 ErrPrint("Failed to create a new connection\n");
299                         } else {
300                                 item->handle_list = eina_list_append(item->handle_list, conn_handle);
301                         }
302                 } else {
303                         item->handle_list = eina_list_append(item->handle_list, conn_handle);
304                         (void)connection_ref(conn_handle);
305                 }
306         }
307
308         item->paused = 1;
309         s_info.inst_list = eina_list_append(s_info.inst_list, item);
310
311         return item;
312 }
313
314 static void instance_destroy(struct item *item)
315 {
316         struct connection *conn_handle;
317         s_info.inst_list = eina_list_remove(s_info.inst_list, item);
318         if (item->update_timer) {
319                 util_timer_del(item->update_timer);
320         }
321         free(item->id);
322         EINA_LIST_FREE(item->handle_list, conn_handle) {
323                 (void)connection_unref(conn_handle);
324         }
325         free(item);
326 }
327
328 static struct item *instance_find(const char *id)
329 {
330         Eina_List *l;
331         struct item *item;
332
333         EINA_LIST_FOREACH(s_info.inst_list, l, item) {
334                 if (!strcmp(item->id, id)) {
335                         return item;
336                 }
337         }
338
339         return NULL;
340 }
341
342 static int method_new(struct widget_event_arg *arg, int *width, int *height, double *priority, void *data)
343 {
344         struct widget_provider_event_callback *table = data;
345         struct item *inst;
346         int ret;
347
348         DbgPrint("Create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], skip[%d], abi[%s], size: %dx%d\n",
349                         arg->pkgname, arg->id,
350                         arg->info.widget_create.content,
351                         arg->info.widget_create.timeout,
352                         arg->info.widget_create.has_script,
353                         arg->info.widget_create.period,
354                         arg->info.widget_create.cluster, arg->info.widget_create.category,
355                         arg->info.widget_create.skip_need_to_create,
356                         arg->info.widget_create.abi,
357                         arg->info.widget_create.width,
358                         arg->info.widget_create.height);
359
360         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
361
362         if (!table->create) {
363                 ErrPrint("Function is not implemented\n");
364                 return WIDGET_ERROR_NOT_SUPPORTED;
365         }
366
367         inst = instance_create(arg->id, arg->info.widget_create.period, table, arg->info.widget_create.direct_addr);
368         if (!inst) {
369                 return WIDGET_ERROR_FAULT;
370         }
371
372         ret = table->create(widget_util_uri_to_path(arg->id), arg->info.widget_create.content, arg->info.widget_create.width, arg->info.widget_create.height, table->data);
373         if (ret != WIDGET_ERROR_NONE) {
374                 ErrPrint("Failed to create an instance\n");
375                 instance_destroy(inst);
376         } else {
377                 struct widget_buffer *buffer;
378
379                 buffer = widget_provider_buffer_find_buffer(WIDGET_TYPE_WIDGET, arg->pkgname, arg->id);
380                 if (buffer) {
381                         int bps;
382                         (void)widget_provider_buffer_get_size(buffer, width, height, &bps);
383                 }
384         }
385
386         return ret;
387 }
388
389 static int method_renew(struct widget_event_arg *arg, void *data)
390 {
391         struct widget_provider_event_callback *table = data;
392         struct item *inst;
393         int ret;
394
395         DbgPrint("Re-create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], abi[%s], size: %dx%d\n",
396                         arg->pkgname, arg->id,
397                         arg->info.widget_recreate.content,
398                         arg->info.widget_recreate.timeout,
399                         arg->info.widget_recreate.has_script,
400                         arg->info.widget_recreate.period,
401                         arg->info.widget_recreate.cluster,
402                         arg->info.widget_recreate.category,
403                         arg->info.widget_recreate.abi,
404                         arg->info.widget_recreate.width,
405                         arg->info.widget_recreate.height);
406
407         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
408
409         if (!table->create) {
410                 ErrPrint("Function is not implemented\n");
411                 return WIDGET_ERROR_NOT_SUPPORTED;
412         }
413
414         inst = instance_create(arg->id, arg->info.widget_recreate.period, table, arg->info.widget_recreate.direct_addr);
415         if (!inst) {
416                 return WIDGET_ERROR_FAULT;
417         }
418
419         ret = table->create(widget_util_uri_to_path(arg->id), arg->info.widget_recreate.content, arg->info.widget_recreate.width, arg->info.widget_recreate.height, table->data);
420         if (ret < 0) {
421                 instance_destroy(inst);
422         }
423
424         return ret;
425 }
426
427 static int method_delete(struct widget_event_arg *arg, void *data)
428 {
429         struct widget_provider_event_callback *table = data;
430         struct item *inst;
431         int ret;
432
433         DbgPrint("pkgname[%s] id[%s]\n", arg->pkgname, arg->id);
434
435         invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, arg->id);
436
437         if (!table->destroy) {
438                 ErrPrint("Function is not implemented\n");
439                 return WIDGET_ERROR_NOT_SUPPORTED;
440         }
441
442         inst = instance_find(arg->id);
443         if (!inst) {
444                 return WIDGET_ERROR_INVALID_PARAMETER;
445         }
446
447         ret = table->destroy(widget_util_uri_to_path(arg->id), arg->info.widget_destroy.type, table->data);
448         instance_destroy(inst);
449         return ret;
450 }
451
452 static int method_content_event(struct widget_event_arg *arg, void *data)
453 {
454         struct widget_provider_event_callback *table = data;
455         int ret;
456
457         if (!table->text_signal) {
458                 ErrPrint("Function is not implemented\n");
459                 return WIDGET_ERROR_NOT_SUPPORTED;
460         }
461
462         ret = table->text_signal(widget_util_uri_to_path(arg->id),
463                         arg->info.content_event.signal_name, arg->info.content_event.source,
464                         &arg->info.content_event.info,
465                         table->data);
466
467         return ret;
468 }
469
470 static int method_clicked(struct widget_event_arg *arg, void *data)
471 {
472         int ret = WIDGET_ERROR_NONE;
473 #ifdef WIDGET_FEATURE_HANDLE_CLICKED_EVENT
474         struct widget_provider_event_callback *table = data;
475
476         DbgPrint("pkgname[%s] id[%s] event[%s] timestamp[%lf] x[%lf] y[%lf]\n",
477                         arg->pkgname, arg->id,
478                         arg->info.clicked.event, arg->info.clicked.timestamp,
479                         arg->info.clicked.x, arg->info.clicked.y);
480
481         if (!table->clicked) {
482                 ErrPrint("Function is not implemented\n");
483                 return WIDGET_ERROR_NOT_SUPPORTED;
484         }
485
486         ret = table->clicked(widget_util_uri_to_path(arg->id), arg->info.clicked.event, arg->info.clicked.x, arg->info.clicked.y, arg->info.clicked.timestamp, table->data);
487 #endif /* WIDGET_FEATURE_HANDLE_CLICKED_EVENT */
488
489         return ret;
490 }
491
492 static int method_text_signal(struct widget_event_arg *arg, void *data)
493 {
494         struct widget_provider_event_callback *table = data;
495         int ret;
496
497         if (!table->text_signal) {
498                 ErrPrint("Function is not implemented\n");
499                 return WIDGET_ERROR_NOT_SUPPORTED;
500         }
501
502         ret = table->text_signal(widget_util_uri_to_path(arg->id),
503                         arg->info.text_signal.signal_name, arg->info.text_signal.source,
504                         &arg->info.text_signal.info, table->data);
505
506         return ret;
507 }
508
509 static int method_resize(struct widget_event_arg *arg, void *data)
510 {
511         struct widget_provider_event_callback *table = data;
512         int ret;
513
514         invoke_pre_callback(WIDGET_PRE_RESIZE_CALLBACK, arg->id);
515
516         if (!table->resize) {
517                 ErrPrint("Function is not implemented\n");
518                 return WIDGET_ERROR_NOT_SUPPORTED;
519         }
520
521         DbgPrint("pkgname[%s] id[%s] w[%d] h[%d]\n", arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h);
522         ret = table->resize(widget_util_uri_to_path(arg->id), arg->info.resize.w, arg->info.resize.h, table->data);
523         return ret;
524 }
525
526 static int method_set_period(struct widget_event_arg *arg, void *data)
527 {
528         struct item *inst;
529
530         DbgPrint("pkgname[%s] id[%s] period[%lf]\n", arg->pkgname, arg->id, arg->info.set_period.period);
531         inst = instance_find(arg->id);
532         if (!inst) {
533                 return WIDGET_ERROR_INVALID_PARAMETER;
534         }
535
536         if (inst->update_timer) {
537                 util_timer_interval_set(inst->update_timer, arg->info.set_period.period);
538         }
539
540         return WIDGET_ERROR_NONE;
541 }
542
543 static int method_change_group(struct widget_event_arg *arg, void *data)
544 {
545         return WIDGET_ERROR_NOT_SUPPORTED;
546 }
547
548 static int method_pinup(struct widget_event_arg *arg, void *data)
549 {
550         return WIDGET_ERROR_NOT_SUPPORTED;
551 }
552
553 static int method_update_content(struct widget_event_arg *arg, void *data)
554 {
555         struct widget_provider_event_callback *table = data;
556         int ret;
557
558         if (!table->update) {
559                 return WIDGET_ERROR_NOT_SUPPORTED;
560         }
561
562         ret = table->update(widget_util_uri_to_path(arg->id), arg->info.update_content.content, arg->info.update_content.force, table->data);
563         return ret;
564 }
565
566 static int method_pause(struct widget_event_arg *arg, void *data)
567 {
568         struct widget_provider_event_callback *table = data;
569         Eina_List *l;
570         struct item *inst;
571
572         if (s_info.paused == 1) {
573                 DbgPrint("Already paused\n");
574                 return WIDGET_ERROR_NONE;
575         }
576
577         s_info.paused = 1;
578
579         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
580                 if (inst->paused == 1) {
581                         continue;
582                 }
583
584                 if (inst->update_timer) {
585                         util_timer_freeze(inst->update_timer);
586                 }
587
588                 if (table->pause) {
589                         table->pause(widget_util_uri_to_path(inst->id), table->data);
590                 }
591         }
592
593         if (s_info.ping_timer) {
594                 ecore_timer_freeze(s_info.ping_timer);
595         }
596
597         return WIDGET_ERROR_NONE;
598 }
599
600 static int method_resume(struct widget_event_arg *arg, void *data)
601 {
602         struct widget_provider_event_callback *table = data;
603         Eina_List *l;
604         struct item *inst;
605
606         if (s_info.paused == 0) {
607                 DbgPrint("Already resumed\n");
608                 return WIDGET_ERROR_NONE;
609         }
610
611         s_info.paused = 0;
612
613         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
614                 if (inst->paused == 1) {
615                         continue;
616                 }
617
618                 if (inst->update_timer) {
619                         util_timer_thaw(inst->update_timer);
620                 }
621
622                 if (table->resume) {
623                         table->resume(widget_util_uri_to_path(inst->id), table->data);
624                 }
625         }
626
627         if (s_info.ping_timer) {
628                 ecore_timer_thaw(s_info.ping_timer);
629         }
630
631         return WIDGET_ERROR_NONE;
632 }
633
634 static Eina_Bool send_ping_cb(void *data)
635 {
636         widget_provider_send_ping();
637
638         return ECORE_CALLBACK_RENEW;
639 }
640
641 static int method_disconnected(struct widget_event_arg *arg, void *data)
642 {
643         struct widget_provider_event_callback *table = data;
644         struct item *item;
645         Eina_List *l;
646         Eina_List *n;
647
648         /* arg == NULL */
649
650         if (s_info.ping_timer) {
651                 ecore_timer_del(s_info.ping_timer);
652                 s_info.ping_timer = NULL;
653         }
654
655         /**
656          * After clean up all connections to master, (why?)
657          * invoke destroy callback for every instances.
658          */
659         EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
660                 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
661
662                 if (table->destroy) {
663                         (void)table->destroy(widget_util_uri_to_path(item->id), WIDGET_DESTROY_TYPE_FAULT, item->table->data);
664                 }
665
666                 /**
667                  * instance_destroy will remove the "item" from this "inst_list"
668                  */
669                 instance_destroy(item);
670         }
671
672         if (table->disconnected) {
673                 table->disconnected(table->data);
674         }
675
676         client_fini();
677
678         return WIDGET_ERROR_NONE;
679 }
680
681 static int method_connected(struct widget_event_arg *arg, void *data)
682 {
683         int ret;
684         struct widget_provider_event_callback *table = data;
685
686         ret = widget_provider_send_hello();
687         if (ret == 0) {
688                 s_info.ping_timer = ecore_timer_add(WIDGET_CONF_DEFAULT_PING_TIME / 2.0f, send_ping_cb, NULL);
689                 if (!s_info.ping_timer) {
690                         ErrPrint("Failed to add a ping timer\n");
691                 }
692         }
693
694         if (table->connected) {
695                 table->connected(table->data);
696         }
697
698         return WIDGET_ERROR_NONE;
699 }
700
701 static int method_viewer_connected(struct widget_event_arg *arg, void *data)
702 {
703         struct item *item;
704
705         item = instance_find(arg->id);
706         if (!item) {
707                 return WIDGET_ERROR_INVALID_PARAMETER;
708         }
709
710         if (arg->info.viewer_connected.direct_addr && arg->info.viewer_connected.direct_addr[0]) {
711                 struct connection *handle;
712                 /**
713                  * \TODO: Create a new connection if the direct_addr is valid
714                  */
715                 handle = connection_find_by_addr(arg->info.viewer_connected.direct_addr);
716                 if (handle) {
717                         (void)connection_ref(handle);
718                 } else {
719                         handle = connection_create(arg->info.viewer_connected.direct_addr, (void *)s_table);
720                 }
721
722                 item->handle_list = eina_list_append(item->handle_list, handle);
723         } else {
724                 DbgPrint("Newly comming connection has no valid direct_addr\n");
725         }
726
727         return WIDGET_ERROR_NOT_SUPPORTED;
728 }
729
730 static int method_viewer_disconnected(struct widget_event_arg *arg, void *data)
731 {
732         struct item *item;
733
734         item = instance_find(arg->id);
735         if (!item) {
736                 return WIDGET_ERROR_INVALID_PARAMETER;
737         }
738
739         if (arg->info.viewer_disconnected.direct_addr && arg->info.viewer_disconnected.direct_addr[0]) {
740                 struct connection *handle;
741                 /**
742                  * \TODO: Create a new connection if the direct_addr is valid
743                  */
744                 handle = connection_find_by_addr(arg->info.viewer_disconnected.direct_addr);
745                 if (handle) {
746                         if (eina_list_data_find(item->handle_list, handle)) {
747                                 item->handle_list = eina_list_remove(item->handle_list, handle);
748                                 (void)connection_unref(handle);
749                         }
750                 } else {
751                         ErrPrint("There is no valid connection object: %s\n", arg->info.viewer_disconnected.direct_addr);
752                 }
753         } else {
754                 DbgPrint("Disconnected connection has no valid direct_addr\n");
755         }
756
757         return WIDGET_ERROR_NOT_SUPPORTED;
758 }
759
760 static int method_gbar_created(struct widget_event_arg *arg, void *data)
761 {
762         int ret = WIDGET_ERROR_NONE;
763 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
764         struct widget_provider_event_callback *table = data;
765
766         if (!table->gbar.create) {
767                 return WIDGET_ERROR_NOT_SUPPORTED;
768         }
769
770         ret = table->gbar.create(widget_util_uri_to_path(arg->id), arg->info.gbar_create.w, arg->info.gbar_create.h, arg->info.gbar_create.x, arg->info.gbar_create.y, table->data);
771 #else
772         ret = WIDGET_ERROR_NOT_SUPPORTED;
773 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
774         return ret;
775 }
776
777 static int method_gbar_destroyed(struct widget_event_arg *arg, void *data)
778 {
779         int ret = WIDGET_ERROR_NONE;
780 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
781         struct widget_provider_event_callback *table = data;
782
783         if (!table->gbar.destroy) {
784                 return WIDGET_ERROR_NOT_SUPPORTED;
785         }
786
787         ret = table->gbar.destroy(widget_util_uri_to_path(arg->id), arg->info.gbar_destroy.reason, table->data)
788 #else
789         ret = WIDGET_ERROR_NOT_SUPPORTED;
790 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
791         return ret;
792 }
793
794 static int method_gbar_moved(struct widget_event_arg *arg, void *data)
795 {
796         int ret = WIDGET_ERROR_NONE;
797 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
798         struct widget_provider_event_callback *table = data;
799         if (!table->gbar.resize_move) {
800                 return WIDGET_ERROR_NOT_SUPPORTED;
801         }
802
803         ret = table->gbar.resize_move(widget_util_uri_to_path(arg->id), arg->info.gbar_move.w, arg->info.gbar_move.h, arg->info.gbar_move.x, arg->info.gbar_move.y, table->data);
804 #else
805         ret = WIDGET_ERROR_NOT_SUPPORTED;
806 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
807         return ret;
808 }
809
810 static int method_widget_pause(struct widget_event_arg *arg, void *data)
811 {
812         struct widget_provider_event_callback *table = data;
813         int ret;
814         struct item *inst;
815
816         inst = instance_find(arg->id);
817         if (!inst) {
818                 return WIDGET_ERROR_INVALID_PARAMETER;
819         }
820
821         if (inst->paused == 1) {
822                 DbgPrint("Already paused\n");
823                 return WIDGET_ERROR_ALREADY_EXIST;
824         }
825
826         inst->paused = 1;
827
828         if (s_info.paused == 1) {
829                 return WIDGET_ERROR_NONE;
830         }
831
832         if (inst->update_timer) {
833                 util_timer_freeze(inst->update_timer);
834         }
835
836         if (!table->pause) {
837                 return WIDGET_ERROR_NOT_SUPPORTED;
838         }
839
840         ret = table->pause(widget_util_uri_to_path(arg->id), table->data);
841         return ret;
842 }
843
844 static int method_widget_resume(struct widget_event_arg *arg, void *data)
845 {
846         struct widget_provider_event_callback *table = data;
847         struct item *inst;
848         int ret;
849
850         inst = instance_find(arg->id);
851         if (!inst) {
852                 return WIDGET_ERROR_INVALID_PARAMETER;
853         }
854
855         if (inst->paused == 0) {
856                 return WIDGET_ERROR_ALREADY_EXIST;
857         }
858
859         inst->paused = 0;
860
861         if (s_info.paused == 1) {
862                 return WIDGET_ERROR_NONE;
863         }
864
865         if (inst->update_timer) {
866                 util_timer_thaw(inst->update_timer);
867         }
868
869         if (!table->resume) {
870                 return WIDGET_ERROR_NOT_SUPPORTED;
871         }
872
873         ret = table->resume(widget_util_uri_to_path(arg->id), table->data);
874         return ret;
875 }
876
877 static int connection_disconnected_cb(int handle, void *data)
878 {
879         struct connection *connection;
880         struct connection *conn_handle;
881         struct item *inst;
882         Eina_List *l;
883         Eina_List *k;
884         Eina_List *n;
885
886         connection = connection_find_by_fd(handle);
887         if (!connection) {
888                 return 0;
889         }
890
891         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
892                 EINA_LIST_FOREACH_SAFE(inst->handle_list, k, n, conn_handle) {
893                         if (conn_handle == connection) {
894                                 /**
895                                  * @note
896                                  * This instance has connection to client
897                                  * but now it is lost.
898                                  * by reset "handle",
899                                  * the provider_app_send_updated function will send event to the master.
900                                  */
901                                 DbgPrint("Disconnected: %s\n", inst->id);
902
903                                 /**
904                                  * To prevent from nested callback call.
905                                  * reset handle first.
906                                  */
907                                 inst->handle_list = eina_list_remove(inst->handle_list, conn_handle);
908
909                                 (void)connection_unref(conn_handle);
910                         }
911                 }
912         }
913
914         return 0;
915 }
916
917 void client_fini(void)
918 {
919         struct internal_item *item;
920
921         if (!s_info.initialized) {
922                 LOGE("Provider is not initialized\n");
923                 return;
924         }
925
926         DbgPrint("Finalize the Provider App Connection\n");
927         s_info.initialized = 0;
928
929         widget_provider_fini();
930
931         DbgPrint("Provider is disconnected(%s)\n", s_info.abi);
932         free(s_info.name);
933         free(s_info.abi);
934         free(s_info.hw_acceleration);
935
936         widget_conf_reset();
937         widget_abi_fini();
938
939         s_info.name = NULL;
940         s_info.abi = NULL;
941         s_info.hw_acceleration = NULL;
942
943         connection_del_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb);
944
945         EINA_LIST_FREE(s_info.internal_item_list, item) {
946                 DbgPrint("Internal item[%s] destroyed\n", item->id);
947                 free(item->id);
948                 free(item);
949         }
950 }
951
952 int client_is_initialized(void)
953 {
954         return s_info.initialized;
955 }
956
957 static int method_connected_sync(struct widget_event_arg *arg, void *data)
958 {
959         int ret;
960         struct widget_provider_event_callback *table = data;
961
962         /**
963          * @note
964          *
965          * hello_sync will invoke the widget_create funcion from its inside.
966          * So we should to call the connected event callback first.
967          * We should keep callback sequence.
968          *
969          * connected -> widget_created
970          */
971
972         if (table->connected) {
973                 table->connected(table->data);
974         }
975
976         ret = widget_provider_send_hello_sync(provider_pkgname());
977
978         if (ret == 0) {
979                 s_info.ping_timer = ecore_timer_add(WIDGET_CONF_DEFAULT_PING_TIME / 2.0f, send_ping_cb, NULL);
980                 if (!s_info.ping_timer) {
981                         ErrPrint("Failed to add a ping timer\n");
982                 }
983         }
984
985         return WIDGET_ERROR_NONE;
986 }
987
988 static int is_watchapp(void)
989 {
990         int result = 0;
991         pkgmgrinfo_appinfo_h handle = NULL;
992         char *value;
993
994         if (pkgmgrinfo_appinfo_get_appinfo(provider_pkgname(), &handle) != PMINFO_R_OK) {
995                 ErrPrint("appid[%s] is invalid\n", provider_pkgname());
996                 return 0;
997         }
998
999         if (pkgmgrinfo_appinfo_get_component_type(handle, &value) == PMINFO_R_OK) {
1000                 if (value) {
1001                         DbgPrint("component type: %s\n", value);
1002                 }
1003
1004                 if (!strcmp(value, PKGMGR_COMPONENT_TYPE_WATCH_APP)) {
1005                         result = 1;
1006                         DbgPrint("this app is watch app");
1007                 }
1008         }
1009
1010         pkgmgrinfo_appinfo_destroy_appinfo(handle);
1011
1012         return result;
1013 }
1014
1015 int client_init_sync(struct widget_provider_event_callback *table)
1016 {
1017         int ret;
1018         char *name = NULL;
1019         char *abi = NULL;
1020         char *hw_acceleration = NULL;
1021
1022         struct widget_event_table method_table = {
1023                 .widget_create = method_new,
1024                 .widget_recreate = method_renew,
1025                 .widget_destroy = method_delete,
1026                 .resize = method_resize,
1027                 .update_content = method_update_content,
1028                 .content_event = method_content_event,
1029                 .clicked = method_clicked,
1030                 .text_signal = method_text_signal,
1031                 .set_period = method_set_period,
1032                 .change_group = method_change_group,
1033                 .pinup = method_pinup,
1034                 .pause = method_pause,
1035                 .resume = method_resume,
1036                 .widget_pause = method_widget_pause,
1037                 .widget_resume = method_widget_resume,
1038                 .disconnected = method_disconnected,
1039                 .connected = method_connected_sync,
1040                 .viewer_connected = method_viewer_connected,
1041                 .viewer_disconnected = method_viewer_disconnected,
1042
1043                 /**
1044                  * Glance Bar
1045                  */
1046                 .gbar_create = method_gbar_created,
1047                 .gbar_destroy = method_gbar_destroyed,
1048                 .gbar_move = method_gbar_moved,
1049         };
1050
1051         if (s_info.initialized == 1) {
1052                 DbgPrint("Provider App is already initialized\n");
1053                 return WIDGET_ERROR_NONE;
1054         }
1055
1056         widget_abi_init();
1057
1058         if (s_info.name && s_info.abi) {
1059                 DbgPrint("Name and ABI is assigned already\n");
1060                 widget_abi_fini();
1061                 return WIDGET_ERROR_NONE;
1062         }
1063
1064         if (!widget_conf_is_loaded()) {
1065                 widget_conf_reset();
1066                 if (widget_conf_load() < 0) {
1067                         ErrPrint("Failed to load conf\n");
1068                 }
1069         }
1070
1071         if (!is_watchapp()) {
1072                 ErrPrint("This Provider is not watch app\n");
1073                 widget_conf_reset();
1074                 widget_abi_fini();
1075                 return WIDGET_ERROR_NONE;
1076         }
1077
1078         name = malloc(BUFFER_MAX);
1079         if (!name) {
1080                 widget_conf_reset();
1081                 widget_abi_fini();
1082                 return WIDGET_ERROR_OUT_OF_MEMORY;
1083         }
1084
1085         snprintf(name, BUFFER_MAX - 1, "%d.%lf", getpid(), util_timestamp());
1086
1087         abi = strdup("app");
1088         if (!abi) {
1089                 free(name);
1090                 widget_conf_reset();
1091                 widget_abi_fini();
1092                 return WIDGET_ERROR_OUT_OF_MEMORY;
1093         }
1094
1095         hw_acceleration = strdup("use-sw");
1096         if (!hw_acceleration) {
1097                 free(name);
1098                 free(abi);
1099                 widget_conf_reset();
1100                 widget_abi_fini();
1101                 return WIDGET_ERROR_OUT_OF_MEMORY;
1102         }
1103
1104         DbgPrint("Name assigned: %s (%s)\n", name, abi);
1105         DbgPrint("Secured: %s\n", "true");
1106         DbgPrint("hw-acceleration: %s\n", hw_acceleration);
1107
1108         widget_provider_prepare_init(abi, hw_acceleration, 1);
1109         ret = widget_provider_init(util_screen_get(), name, &method_table, table, 1, 1);
1110         ErrPrint("widget_provider_init return [%d]\n", ret);
1111         if (ret < 0) {
1112                 free(hw_acceleration);
1113                 free(name);
1114                 free(abi);
1115                 widget_conf_reset();
1116                 widget_abi_fini();
1117         } else {
1118                 s_info.initialized = 1;
1119                 s_info.name = name;
1120                 s_info.abi = abi;
1121                 s_info.secured = 1;
1122                 s_info.hw_acceleration = hw_acceleration;
1123
1124                 if (connection_add_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb, NULL) < 0) {
1125                         ErrPrint("Failed to add a disconnected event callback\n");
1126                 }
1127         }
1128
1129         return WIDGET_ERROR_NONE;
1130 }
1131
1132 int client_init(app_control_h service, struct widget_provider_event_callback *table)
1133 {
1134         int ret;
1135         char *secured = NULL;
1136         char *name = NULL;
1137         char *abi = NULL;
1138         char *hw_acceleration = NULL;
1139         struct widget_event_table method_table = {
1140                 .widget_create = method_new,
1141                 .widget_recreate = method_renew,
1142                 .widget_destroy = method_delete,
1143                 .gbar_create = method_gbar_created,
1144                 .gbar_destroy = method_gbar_destroyed,
1145                 .gbar_move = method_gbar_moved,
1146                 .resize = method_resize,
1147                 .update_content = method_update_content,
1148                 .content_event = method_content_event,
1149                 .clicked = method_clicked,
1150                 .text_signal = method_text_signal,
1151                 .set_period = method_set_period,
1152                 .change_group = method_change_group,
1153                 .pinup = method_pinup,
1154                 .pause = method_pause,
1155                 .resume = method_resume,
1156                 .widget_pause = method_widget_pause,
1157                 .widget_resume = method_widget_resume,
1158                 .disconnected = method_disconnected,
1159                 .connected = method_connected,
1160                 .viewer_connected = method_viewer_connected,
1161                 .viewer_disconnected = method_viewer_disconnected,
1162         };
1163
1164         if (s_info.initialized == 1) {
1165                 DbgPrint("Provider App is already initialized\n");
1166                 return WIDGET_ERROR_NONE;
1167         }
1168
1169         widget_abi_init();
1170
1171         if (s_info.name && s_info.abi) {
1172                 DbgPrint("Name and ABI is assigned already\n");
1173                 widget_abi_fini();
1174                 return WIDGET_ERROR_NONE;
1175         }
1176
1177         if (!widget_conf_is_loaded()) {
1178                 widget_conf_reset();
1179                 if (widget_conf_load() < 0) {
1180                         ErrPrint("Failed to load conf\n");
1181                 }
1182         }
1183
1184         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_NAME, &name);
1185         if (ret != APP_CONTROL_ERROR_NONE) {
1186                 ErrPrint("Name is not valid\n");
1187                 widget_conf_reset();
1188                 widget_abi_fini();
1189                 return WIDGET_ERROR_INVALID_PARAMETER;
1190         }
1191
1192         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_SECURED, &secured);
1193         if (ret != APP_CONTROL_ERROR_NONE) {
1194                 free(name);
1195                 ErrPrint("Secured is not valid\n");
1196                 widget_conf_reset();
1197                 widget_abi_fini();
1198                 return WIDGET_ERROR_INVALID_PARAMETER;
1199         }
1200
1201         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_ABI, &abi);
1202         if (ret != APP_CONTROL_ERROR_NONE) {
1203                 free(name);
1204                 free(secured);
1205                 widget_conf_reset();
1206                 widget_abi_fini();
1207                 return WIDGET_ERROR_INVALID_PARAMETER;
1208         }
1209
1210         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_HW_ACCELERATION, &hw_acceleration);
1211         if (ret != APP_CONTROL_ERROR_NONE) {
1212                 DbgPrint("hw-acceleration is not set\n");
1213         }
1214
1215         if (name && abi && secured) {
1216                 DbgPrint("Name assigned: %s (%s)\n", name, abi);
1217                 DbgPrint("Secured: %s\n", s_info.secured);
1218                 DbgPrint("hw-acceleration: %s\n", hw_acceleration);
1219
1220                 widget_provider_prepare_init(abi, hw_acceleration, !strcmp(secured, "true"));
1221                 ret = widget_provider_init(util_screen_get(), name, &method_table, table, 1, 1);
1222                 if (ret < 0) {
1223                         free(name);
1224                         free(abi);
1225                         widget_conf_reset();
1226                         widget_abi_fini();
1227                 } else {
1228                         s_info.initialized = 1;
1229                         s_info.name = name;
1230                         s_info.abi = abi;
1231                         s_info.secured = !strcasecmp(secured, "true");
1232                         s_info.hw_acceleration = hw_acceleration;
1233
1234                         if (connection_add_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb, NULL) < 0) {
1235                                 ErrPrint("Failed to add a disconnected event callback\n");
1236                         }
1237                 }
1238                 free(secured);
1239         } else {
1240                 free(name);
1241                 free(abi);
1242                 free(secured);
1243                 free(hw_acceleration);
1244                 widget_conf_reset();
1245                 widget_abi_fini();
1246                 ret = WIDGET_ERROR_INVALID_PARAMETER;
1247         }
1248
1249         return ret;
1250 }
1251
1252 PAPI int widget_provider_app_send_updated_event(const char *id, int idx, int x, int y, int w, int h, int for_gbar)
1253 {
1254         struct item *inst;
1255         char *uri;
1256         int ret = WIDGET_ERROR_DISABLED;
1257         char *desc_name = NULL;
1258         widget_damage_region_s region = {
1259                 .x = x,
1260                 .y = y,
1261                 .w = w,
1262                 .h = h,
1263         };
1264
1265         if (!id) {
1266                 return WIDGET_ERROR_INVALID_PARAMETER;
1267         }
1268
1269         uri = util_path_to_uri(id);
1270         if (!uri) {
1271                 return WIDGET_ERROR_OUT_OF_MEMORY;
1272         }
1273
1274         if (for_gbar) {
1275                 int len;
1276
1277                 len = strlen(id) + strlen(".desc") + 3;
1278                 desc_name = malloc(len);
1279                 if (!len) {
1280                         free(uri);
1281                         return WIDGET_ERROR_OUT_OF_MEMORY;
1282                 }
1283                 snprintf(desc_name, len, "%s.desc", id);
1284         }
1285
1286         /**
1287          * Do we have to search instance in this function?
1288          * This function is very frequently called one.
1289          * So we have to do not heavy operation in here!!!
1290          * Keep it in mind.
1291          */
1292         inst = instance_find(uri);
1293         if (inst && inst->handle_list) {
1294                 Eina_List *l;
1295                 struct connection *conn_handle;
1296
1297                 EINA_LIST_FOREACH(inst->handle_list, l, conn_handle) {
1298                         ret = widget_provider_send_direct_updated(connection_handle(conn_handle), provider_pkgname(), uri, idx, &region, for_gbar, desc_name);
1299                 }
1300         }
1301
1302         /**
1303          * by this logic,
1304          * Even if we lost direct connection to the viewer,
1305          * we will send this to the master again.
1306          */
1307         if (ret != WIDGET_ERROR_NONE) {
1308                 ret = widget_provider_send_updated(provider_pkgname(), uri, idx, &region, for_gbar, desc_name);
1309         }
1310
1311         free(desc_name);
1312         free(uri);
1313
1314         return ret;
1315 }
1316
1317 PAPI int widget_provider_app_send_buffer_updated_event(widget_buffer_h handle, int idx, int x, int y, int w, int h, int for_gbar)
1318 {
1319         struct item *inst;
1320         int ret = WIDGET_ERROR_DISABLED;
1321         char *desc_name = NULL;
1322         const char *uri;
1323         widget_damage_region_s region = {
1324                 .x = x,
1325                 .y = y,
1326                 .w = w,
1327                 .h = h,
1328         };
1329
1330         if (!handle) {
1331                 return WIDGET_ERROR_INVALID_PARAMETER;
1332         }
1333
1334         uri = widget_provider_buffer_id(handle);
1335         if (!uri) {
1336                 return WIDGET_ERROR_INVALID_PARAMETER;
1337         }
1338
1339         if (for_gbar) {
1340                 int len;
1341                 const char *id;
1342
1343                 id = widget_util_uri_to_path(uri);
1344                 if (!id) {
1345                         return WIDGET_ERROR_FAULT;
1346                 }
1347
1348                 len = strlen(id) + strlen(".desc") + 3;
1349                 desc_name = malloc(len);
1350                 if (!len) {
1351                         return WIDGET_ERROR_OUT_OF_MEMORY;
1352                 }
1353                 snprintf(desc_name, len, "%s.desc", id);
1354         }
1355
1356         /**
1357          * Do we have to search instance in this function?
1358          * This function is very frequently called one.
1359          * So we have to do not heavy operation in here!!!
1360          * Keep it in mind.
1361          */
1362         inst = instance_find(uri);
1363         if (inst && inst->handle_list) {
1364                 Eina_List *l;
1365                 struct connection *conn_handle;
1366
1367                 EINA_LIST_FOREACH(inst->handle_list, l, conn_handle) {
1368                         ret = widget_provider_send_direct_buffer_updated(connection_handle(conn_handle), handle, idx, &region, for_gbar, desc_name);
1369                 }
1370         }
1371
1372         /**
1373          * by this logic,
1374          * Even if we lost direct connection to the viewer,
1375          * we will send this to the master again.
1376          */
1377         if (ret != WIDGET_ERROR_NONE) {
1378                 ret = widget_provider_send_buffer_updated(handle, idx, &region, for_gbar, desc_name);
1379         }
1380
1381         free(desc_name);
1382
1383         return ret;
1384 }
1385
1386 PAPI int widget_provider_app_send_extra_info(const char *id, const char *content_info, const char *title)
1387 {
1388         char *uri;
1389         int ret;
1390
1391         if (!id) {
1392                 return WIDGET_ERROR_INVALID_PARAMETER;
1393         }
1394
1395         uri = util_path_to_uri(id);
1396         if (!uri) {
1397                 return WIDGET_ERROR_OUT_OF_MEMORY;
1398         }
1399
1400         ret = widget_provider_send_extra_info(provider_pkgname(), uri, 1.0f, content_info, title, NULL, NULL);
1401         free(uri);
1402
1403         return ret;
1404 }
1405
1406 PAPI int widget_provider_app_set_data(const char *id, void *data)
1407 {
1408         char *uri;
1409
1410         if (!id) {
1411                 return WIDGET_ERROR_INVALID_PARAMETER;
1412         }
1413
1414         uri = util_path_to_uri(id);
1415         if (!uri) {
1416                 return WIDGET_ERROR_OUT_OF_MEMORY;
1417         }
1418
1419         if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1420                 struct internal_item *item;
1421
1422                 item = internal_item_find(uri);
1423                 if (!item) {
1424                         if (!data) {
1425                                 free(uri);
1426                                 return WIDGET_ERROR_NOT_EXIST;
1427                         }
1428
1429                         item = internal_item_create(uri);
1430                         if (!item) {
1431                                 free(uri);
1432                                 return WIDGET_ERROR_FAULT;
1433                         }
1434                         free(uri);
1435                 } else {
1436                         free(uri);
1437                         if (!data) {
1438                                 internal_item_destroy(item);
1439                                 return WIDGET_ERROR_NONE;
1440                         }
1441                 }
1442
1443                 item->data = data;
1444         } else {
1445                 struct item *item;
1446
1447                 item = instance_find(uri);
1448                 free(uri);
1449                 if (!item) {
1450                         return WIDGET_ERROR_ALREADY_EXIST;
1451                 }
1452
1453                 item->data = data;
1454         }
1455
1456         return WIDGET_ERROR_NONE;
1457 }
1458
1459 PAPI void *widget_provider_app_get_data(const char *id)
1460 {
1461         char *uri;
1462         void *data = NULL;
1463
1464         if (!id) {
1465                 return NULL;
1466         }
1467
1468         uri = util_path_to_uri(id);
1469         if (!uri) {
1470                 return NULL;
1471         }
1472
1473         if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1474                 struct internal_item *item;
1475
1476                 item = internal_item_find(uri);
1477                 free(uri);
1478                 if (!item) {
1479                         return NULL;
1480                 }
1481                 data = item->data;
1482         } else {
1483                 struct item *item;
1484
1485                 item = instance_find(uri);
1486                 free(uri);
1487                 if (!item) {
1488                         return NULL;
1489                 }
1490                 data = item->data;
1491         }
1492
1493         return data;
1494 }
1495
1496 PAPI void *widget_provider_app_get_data_list(void)
1497 {
1498         struct item *item;
1499         Eina_List *return_list = NULL;
1500         Eina_List *l;
1501
1502         EINA_LIST_FOREACH(s_info.inst_list, l, item) {
1503                 return_list = eina_list_append(return_list, item->data);
1504         }
1505
1506         return return_list;
1507 }
1508
1509 PAPI int widget_provider_app_create_app(void)
1510 {
1511         return WIDGET_ERROR_NONE;
1512 }
1513
1514 PAPI int widget_provider_app_terminate_app(widget_destroy_type_e reason, int destroy_instances)
1515 {
1516         struct widget_provider_event_callback *table;
1517         struct item *item;
1518         Eina_List *l;
1519         Eina_List *n;
1520         int ret = 0;
1521
1522         DbgPrint("Reason: %d, %d\n", reason, destroy_instances);
1523
1524         if (!destroy_instances) {
1525                 DbgPrint("Do not destroy instances\n");
1526                 return WIDGET_ERROR_NONE;
1527         }
1528
1529         table = widget_provider_callback_data();
1530         if (!table) {
1531                 ErrPrint("Provider App is not initialized\n");
1532                 return WIDGET_ERROR_FAULT;
1533         }
1534
1535         EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
1536                 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
1537
1538                 if (table->destroy) {
1539                         (void)table->destroy(widget_util_uri_to_path(item->id), reason, table->data);
1540                 }
1541
1542                 instance_destroy(item);
1543                 ret++;
1544         }
1545
1546         DbgPrint("%d instances are destroyed\n", ret);
1547
1548         return ret ? WIDGET_ERROR_NONE : WIDGET_ERROR_NOT_EXIST;
1549 }
1550
1551 EAPI int widget_provider_app_add_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1552 {
1553         struct pre_callback_item *item;
1554         Eina_List *l;
1555
1556         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1557                 return WIDGET_ERROR_INVALID_PARAMETER;
1558         }
1559
1560         EINA_LIST_FOREACH(s_info.widget_pre_callback_list[type], l, item) {
1561                 if (item->cb == cb && item->data == data) {
1562                         return WIDGET_ERROR_ALREADY_EXIST;
1563                 }
1564         }
1565
1566         item = malloc(sizeof(*item));
1567         if (!item) {
1568                 ErrPrint("malloc: %s\n", strerror(errno));
1569                 return WIDGET_ERROR_OUT_OF_MEMORY;
1570         }
1571
1572         item->cb = cb;
1573         item->data = data;
1574
1575         s_info.widget_pre_callback_list[type] = eina_list_append(s_info.widget_pre_callback_list[type], item);
1576         return 0;
1577 }
1578
1579 EAPI int widget_provider_app_del_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1580 {
1581         Eina_List *l;
1582         Eina_List *n;
1583         struct pre_callback_item *item;
1584
1585         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1586                 ErrPrint("Invalid parameter\n");
1587                 return WIDGET_ERROR_INVALID_PARAMETER;
1588         }
1589
1590         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
1591                 if (item->cb == cb && item->data == data) {
1592                         s_info.widget_pre_callback_list[type] = eina_list_remove_list(s_info.widget_pre_callback_list[type], l);
1593                         free(item);
1594                         return WIDGET_ERROR_NONE;
1595                 }
1596         }
1597
1598         return WIDGET_ERROR_NOT_EXIST;
1599 }
1600
1601 /**
1602  * } End of a file
1603  */