8b2a94a53b843d34feae71554274a61af12b9d46
[platform/core/appfw/data-provider-slave.git] / 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 <unistd.h>
19 #include <errno.h>
20 #include <malloc.h>
21
22 #include <Elementary.h>
23 #include <Eina.h>
24 #include <Ecore.h>
25 #include <Ecore_X.h>
26
27 #include <app.h>
28 #include <dlog.h>
29 #include <aul.h>
30 #include <sqlite3.h>
31
32 #include <widget_provider.h> /* widget_provider */
33 #include <widget_errno.h> /* widget_service */
34 #include <widget_script.h> /* widget_service - widget_event_info */
35 #include <widget_conf.h>
36 #include <widget/widget_internal.h> /* widget - WIDGET_SYS_EVENT_XXX */
37 #include <widget/widget.h> /* widget - WIDGET_SYS_EVENT_XXX */
38
39 #include "critical_log.h"
40 #include "debug.h"
41 #include "client.h"
42 #include "so_handler.h"
43 #include "widget.h"
44 #include "util.h"
45 #include "conf.h"
46 #include "main.h"
47
48 struct pre_callback_item {
49         widget_pre_callback_t cb;
50         void *data;
51 };
52
53 static struct info {
54         Ecore_Timer *ping_timer;
55         Eina_List *widget_pre_callback_list[WIDGET_PRE_CALLBACK_COUNT];
56 } s_info = {
57         .ping_timer = NULL,
58         .widget_pre_callback_list = { NULL, },
59 };
60
61 static void invoke_pre_callback(widget_pre_callback_e type, const char *id)
62 {
63         Eina_List *l;
64         Eina_List *n;
65         struct pre_callback_item *item;
66
67         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
68                 item->cb(id, item->data);
69         }
70 }
71
72 int widget_provider_app_add_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
73 {
74         struct pre_callback_item *item;
75         Eina_List *l;
76
77         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
78                 return WIDGET_ERROR_INVALID_PARAMETER;
79         }
80
81         EINA_LIST_FOREACH(s_info.widget_pre_callback_list[type], l, item) {
82                 if (item->cb == cb && item->data == data) {
83                         return WIDGET_ERROR_ALREADY_EXIST;
84                 }
85         }
86
87         item = malloc(sizeof(*item));
88         if (!item) {
89                 ErrPrint("malloc: %d\n", errno);
90                 return WIDGET_ERROR_OUT_OF_MEMORY;
91         }
92
93         item->cb = cb;
94         item->data = data;
95
96         s_info.widget_pre_callback_list[type] = eina_list_append(s_info.widget_pre_callback_list[type], item);
97         return 0;
98 }
99
100 int widget_provider_app_del_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
101 {
102         Eina_List *l;
103         Eina_List *n;
104         struct pre_callback_item *item;
105
106         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
107                 ErrPrint("Invalid parameter\n");
108                 return WIDGET_ERROR_INVALID_PARAMETER;
109         }
110
111         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
112                 if (item->cb == cb && item->data == data) {
113                         s_info.widget_pre_callback_list[type] = eina_list_remove_list(s_info.widget_pre_callback_list[type], l);
114                         free(item);
115                         return WIDGET_ERROR_NONE;
116                 }
117         }
118
119         return WIDGET_ERROR_NOT_EXIST;
120 }
121
122 static int method_new(struct widget_event_arg *arg, int *width, int *height, double *priority, void *data)
123 {
124         int ret;
125         struct widget_create_arg _arg;
126         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",
127                         arg->pkgname,
128                         arg->id,
129                         arg->info.widget_create.content,
130                         arg->info.widget_create.timeout,
131                         arg->info.widget_create.has_script,
132                         arg->info.widget_create.period,
133                         arg->info.widget_create.cluster, arg->info.widget_create.category,
134                         arg->info.widget_create.skip_need_to_create,
135                         arg->info.widget_create.abi,
136                         arg->info.widget_create.width,
137                         arg->info.widget_create.height);
138
139         if (!arg->info.widget_create.content || !strlen(arg->info.widget_create.content)) {
140                 DbgPrint("Use default content: \"%s\"\n", WIDGET_CONF_DEFAULT_CONTENT);
141                 arg->info.widget_create.content = WIDGET_CONF_DEFAULT_CONTENT;
142         }
143
144         _arg.content = arg->info.widget_create.content;
145         _arg.timeout = arg->info.widget_create.timeout;
146         _arg.has_widget_script = arg->info.widget_create.has_script;
147         _arg.period = arg->info.widget_create.period;
148         _arg.cluster = arg->info.widget_create.cluster;
149         _arg.category = arg->info.widget_create.category;
150         _arg.abi = arg->info.widget_create.abi;
151         _arg.skip_need_to_create = arg->info.widget_create.skip_need_to_create;
152         _arg.direct_addr = arg->info.widget_create.direct_addr;
153
154         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
155
156         ret = widget_create(arg->pkgname, arg->id,
157                         &_arg,
158                         width, height, priority,
159                         &arg->info.widget_create.out_content,
160                         &arg->info.widget_create.out_title);
161
162         if (ret == 0) {
163                 if (arg->info.widget_create.width > 0 && arg->info.widget_create.height > 0) {
164                         DbgPrint("Create size: %dx%d (created: %dx%d)\n", arg->info.widget_create.width, arg->info.widget_create.height, *width, *height);
165                         if (*width != arg->info.widget_create.width || *height != arg->info.widget_create.height) {
166                                 int tmp;
167                                 tmp = widget_viewer_resize_widget(arg->pkgname, arg->id, arg->info.widget_create.width, arg->info.widget_create.height);
168                                 DbgPrint("widget_resize returns: %d\n", tmp);
169                                 if (tmp == (int)WIDGET_ERROR_NONE) {
170                                         /*!
171                                          * \note
172                                          * Just returns resized canvas size.
173                                          * Even if it is not ready to render contents.
174                                          * Provider will allocate render buffer using this size.
175                                          */
176                                         *width = arg->info.widget_create.width;
177                                         *height = arg->info.widget_create.height;
178                                 }
179                         }
180                 }
181
182                 arg->info.widget_create.out_is_pinned_up = (widget_viewer_is_pinned_up(arg->pkgname, arg->id) == 1);
183         } else {
184                 ErrPrint("widget_create returns %d\n", ret);
185         }
186
187         if (widget_is_all_paused()) {
188                 DbgPrint("Box is paused\n");
189                 (void)widget_system_event(arg->pkgname, arg->id, WIDGET_SYS_EVENT_PAUSED);
190         }
191
192         return ret;
193 }
194
195 static int method_renew(struct widget_event_arg *arg, void *data)
196 {
197         int ret;
198         int w;
199         int h;
200         double priority;
201         struct widget_create_arg _arg;
202
203         DbgPrint("Re-create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], abi[%s]\n",
204                         arg->pkgname, arg->id,
205                         arg->info.widget_recreate.content,
206                         arg->info.widget_recreate.timeout,
207                         arg->info.widget_recreate.has_script,
208                         arg->info.widget_recreate.period,
209                         arg->info.widget_recreate.cluster,
210                         arg->info.widget_recreate.category,
211                         arg->info.widget_recreate.abi);
212
213         if (!arg->info.widget_recreate.content || !strlen(arg->info.widget_recreate.content)) {
214                 DbgPrint("Use default content: \"%s\"\n", WIDGET_CONF_DEFAULT_CONTENT);
215                 arg->info.widget_recreate.content = WIDGET_CONF_DEFAULT_CONTENT;
216         }
217
218         _arg.content = arg->info.widget_recreate.content;
219         _arg.timeout = arg->info.widget_recreate.timeout;
220         _arg.has_widget_script = arg->info.widget_recreate.has_script;
221         _arg.period = arg->info.widget_recreate.period;
222         _arg.cluster = arg->info.widget_recreate.cluster;
223         _arg.category = arg->info.widget_recreate.category;
224         _arg.abi = arg->info.widget_recreate.abi;
225         _arg.skip_need_to_create = 1;
226         _arg.direct_addr = arg->info.widget_recreate.direct_addr;
227
228         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
229
230         ret = widget_create(arg->pkgname, arg->id,
231                         &_arg,
232                         &w, &h, &priority,
233                         &arg->info.widget_recreate.out_content,
234                         &arg->info.widget_recreate.out_title);
235         if (ret == 0) {
236                 if (w != arg->info.widget_recreate.width || h != arg->info.widget_recreate.height) {
237                         int tmp;
238                         tmp = widget_viewer_resize_widget(arg->pkgname, arg->id, arg->info.widget_recreate.width, arg->info.widget_recreate.height);
239                         if (tmp < 0) {
240                                 DbgPrint("Resize[%dx%d] returns: %d\n", arg->info.widget_recreate.width, arg->info.widget_recreate.height, tmp);
241                         }
242                 } else {
243                         DbgPrint("No need to change the size: %dx%d\n", w, h);
244                 }
245
246                 arg->info.widget_recreate.out_is_pinned_up = (widget_viewer_is_pinned_up(arg->pkgname, arg->id) == 1);
247         } else {
248                 ErrPrint("widget_create returns %d\n", ret);
249         }
250
251         if (widget_is_all_paused()) {
252                 DbgPrint("Box is paused\n");
253                 (void)widget_system_event(arg->pkgname, arg->id, WIDGET_SYS_EVENT_PAUSED);
254         }
255
256         return ret;
257 }
258
259 static int method_delete(struct widget_event_arg *arg, void *data)
260 {
261         int ret;
262
263         DbgPrint("pkgname[%s] id[%s]\n", arg->pkgname, arg->id);
264
265         if (arg->info.widget_destroy.type == WIDGET_DESTROY_TYPE_DEFAULT || arg->info.widget_destroy.type == WIDGET_DESTROY_TYPE_UNINSTALL) {
266                 DbgPrint("Box is deleted from the viewer\n");
267                 (void)widget_system_event(arg->pkgname, arg->id, WIDGET_SYS_EVENT_DELETED);
268         }
269
270         invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, arg->id);
271         ret = widget_destroy(arg->pkgname, arg->id, 0);
272         return ret;
273 }
274
275 static int method_content_event(struct widget_event_arg *arg, void *data)
276 {
277         int ret;
278         struct widget_event_info info;
279
280         info = arg->info.content_event.info;
281
282         ret = widget_script_event(arg->pkgname, arg->id,
283                         arg->info.content_event.signal_name, arg->info.content_event.source,
284                         &info);
285         return ret;
286 }
287
288 static int method_clicked(struct widget_event_arg *arg, void *data)
289 {
290         int ret;
291
292         DbgPrint("pkgname[%s] id[%s] event[%s] timestamp[%lf] x[%lf] y[%lf]\n",
293                         arg->pkgname, arg->id,
294                         arg->info.clicked.event, arg->info.clicked.timestamp,
295                         arg->info.clicked.x, arg->info.clicked.y);
296         ret = widget_clicked(arg->pkgname, arg->id,
297                         arg->info.clicked.event,
298                         arg->info.clicked.timestamp, arg->info.clicked.x, arg->info.clicked.y);
299
300         return ret;
301 }
302
303 static int method_text_signal(struct widget_event_arg *arg, void *data)
304 {
305         int ret;
306         struct widget_event_info info;
307
308         info = arg->info.text_signal.info;
309
310         DbgPrint("pkgname[%s] id[%s] signal_name[%s] source[%s]\n", arg->pkgname, arg->id, arg->info.text_signal.signal_name, arg->info.text_signal.source);
311         ret = widget_script_event(arg->pkgname, arg->id,
312                         arg->info.text_signal.signal_name, arg->info.text_signal.source,
313                         &info);
314
315         return ret;
316 }
317
318 static int method_resize(struct widget_event_arg *arg, void *data)
319 {
320         int ret;
321
322         invoke_pre_callback(WIDGET_PRE_RESIZE_CALLBACK, arg->id);
323
324         DbgPrint("pkgname[%s] id[%s] w[%d] h[%d]\n", arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h);
325         ret = widget_viewer_resize_widget(arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h);
326
327         return ret;
328 }
329
330 static int method_set_period(struct widget_event_arg *arg, void *data)
331 {
332         int ret;
333         DbgPrint("pkgname[%s] id[%s] period[%lf]\n", arg->pkgname, arg->id, arg->info.set_period.period);
334         ret = widget_viewer_set_period(arg->pkgname, arg->id, arg->info.set_period.period);
335         return ret;
336 }
337
338 static int method_change_group(struct widget_event_arg *arg, void *data)
339 {
340         int ret;
341         DbgPrint("pkgname[%s] id[%s] cluster[%s] category[%s]\n", arg->pkgname, arg->id, arg->info.change_group.cluster, arg->info.change_group.category);
342         ret = widget_change_group(arg->pkgname, arg->id, arg->info.change_group.cluster, arg->info.change_group.category);
343         return ret;
344 }
345
346 static int method_pinup(struct widget_event_arg *arg, void *data)
347 {
348         DbgPrint("pkgname[%s] id[%s] state[%d]\n", arg->pkgname, arg->id, arg->info.pinup.state);
349         arg->info.pinup.content_info = widget_pinup(arg->pkgname, arg->id, arg->info.pinup.state);
350         return arg->info.pinup.content_info ? WIDGET_ERROR_NONE : WIDGET_ERROR_NOT_SUPPORTED;
351 }
352
353 static int method_update_content(struct widget_event_arg *arg, void *data)
354 {
355         int ret;
356
357         if (!arg->id || !strlen(arg->id)) {
358                 if (arg->info.update_content.content && strlen(arg->info.update_content.content)) {
359                         DbgPrint("pkgname[%s] content[%s]\n", arg->pkgname, arg->info.update_content.content);
360                         ret = widget_set_content_info_all(arg->pkgname, arg->info.update_content.content);
361                 } else {
362                         DbgPrint("pkgname[%s] cluster[%s] category[%s]\n", arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category);
363                         ret = widget_update_all(arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category, arg->info.update_content.force);
364                 }
365         } else {
366                 if (arg->info.update_content.content && strlen(arg->info.update_content.content)) {
367                         DbgPrint("id[%s] content[%s]\n", arg->id, arg->info.update_content.content);
368                         ret = widget_set_content_info(arg->pkgname, arg->id, arg->info.update_content.content);
369                 } else {
370                         DbgPrint("Update [%s]\n", arg->id);
371                         ret = widget_update(arg->pkgname, arg->id, arg->info.update_content.force);
372                 }
373         }
374
375         return ret;
376 }
377
378 static int method_pause(struct widget_event_arg *arg, void *data)
379 {
380         widget_pause_all();
381
382         if (s_info.ping_timer) {
383                 ecore_timer_freeze(s_info.ping_timer);
384         }
385
386         if (WIDGET_CONF_SLAVE_AUTO_CACHE_FLUSH) {
387                 elm_cache_all_flush();
388                 sqlite3_release_memory(WIDGET_CONF_SQLITE_FLUSH_MAX);
389                 malloc_trim(0);
390         }
391
392         return WIDGET_ERROR_NONE;
393 }
394
395 static int method_resume(struct widget_event_arg *arg, void *data)
396 {
397         widget_resume_all();
398
399         if (s_info.ping_timer) {
400                 ecore_timer_thaw(s_info.ping_timer);
401         }
402
403         return WIDGET_ERROR_NONE;
404 }
405
406 static Eina_Bool send_ping_cb(void *data)
407 {
408         widget_provider_send_ping();
409         return ECORE_CALLBACK_RENEW;
410 }
411
412 static int method_disconnected(struct widget_event_arg *arg, void *data)
413 {
414         if (s_info.ping_timer) {
415                 ecore_timer_del(s_info.ping_timer);
416                 s_info.ping_timer = NULL;
417         }
418
419         main_app_exit();
420         return WIDGET_ERROR_NONE;
421 }
422
423 static int method_connected(struct widget_event_arg *arg, void *data)
424 {
425         int ret;
426         ret = widget_provider_send_hello();
427         if (ret == 0) {
428                 double ping_interval;
429
430                 ping_interval = WIDGET_CONF_DEFAULT_PING_TIME / 2.0f;
431                 DbgPrint("Ping Timer: %lf\n", ping_interval);
432
433                 s_info.ping_timer = ecore_timer_add(ping_interval, send_ping_cb, NULL);
434                 if (!s_info.ping_timer) {
435                         ErrPrint("Failed to add a ping timer\n");
436                 }
437         }
438
439         return WIDGET_ERROR_NONE;
440 }
441
442 static int method_gbar_created(struct widget_event_arg *arg, void *data)
443 {
444         int ret;
445
446         ret = widget_open_gbar(arg->pkgname, arg->id);
447         if (ret < 0) {
448                 DbgPrint("%s Open PD: %d\n", arg->id, ret);
449         }
450
451         return WIDGET_ERROR_NONE;
452 }
453
454 static int method_gbar_destroyed(struct widget_event_arg *arg, void *data)
455 {
456         int ret;
457
458         ret = widget_close_gbar(arg->pkgname, arg->id);
459         if (ret < 0) {
460                 DbgPrint("%s Close PD: %d\n", arg->id, ret);
461         }
462
463         return WIDGET_ERROR_NONE;
464 }
465
466 static int method_gbar_moved(struct widget_event_arg *arg, void *data)
467 {
468         int ret;
469         struct widget_event_info info;
470
471         memset(&info, 0, sizeof(info));
472         info.pointer.x = arg->info.gbar_move.x;
473         info.pointer.y = arg->info.gbar_move.y;
474         info.pointer.down = 0;
475
476         ret = widget_script_event(arg->pkgname, arg->id,
477                         "gbar,move", util_uri_to_path(arg->id), &info);
478         return ret;
479 }
480
481 static int method_widget_pause(struct widget_event_arg *arg, void *data)
482 {
483         int ret;
484
485         ret = widget_pause(arg->pkgname, arg->id);
486
487         if (WIDGET_CONF_SLAVE_AUTO_CACHE_FLUSH) {
488                 elm_cache_all_flush();
489                 sqlite3_release_memory(WIDGET_CONF_SQLITE_FLUSH_MAX);
490                 malloc_trim(0);
491         }
492
493         return ret;
494 }
495
496 static int method_widget_resume(struct widget_event_arg *arg, void *data)
497 {
498         return widget_resume(arg->pkgname, arg->id);
499 }
500
501 static int method_viewer_connected(struct widget_event_arg *arg, void *data)
502 {
503         return widget_viewer_connected(arg->pkgname, arg->id, arg->info.viewer_connected.direct_addr);
504 }
505
506 static int method_viewer_disconnected(struct widget_event_arg *arg, void *data)
507 {
508         return widget_viewer_disconnected(arg->pkgname, arg->id, arg->info.viewer_disconnected.direct_addr);
509 }
510
511 static int method_orientation(struct widget_event_arg *arg, void *data)
512 {
513         int ret = widget_set_orientation(arg->pkgname, arg->id, arg->info.orientation.degree);
514         invoke_pre_callback(WIDGET_PRE_ORIENTATION_CALLBACK, arg->id);
515         return ret;
516 }
517
518 HAPI int client_init(const char *name, const char *abi, const char *accel, int secured)
519 {
520         struct widget_event_table table = {
521                 .widget_create = method_new,
522                 .widget_recreate = method_renew,
523                 .widget_destroy = method_delete,
524                 .content_event = method_content_event,
525                 .clicked = method_clicked,
526                 .text_signal = method_text_signal,
527                 .resize = method_resize,
528                 .set_period = method_set_period,
529                 .change_group = method_change_group,
530                 .pinup = method_pinup,
531                 .update_content = method_update_content,
532                 .pause = method_pause,
533                 .resume = method_resume,
534                 .disconnected = method_disconnected,
535                 .connected = method_connected,
536                 .gbar_create = method_gbar_created,
537                 .gbar_destroy = method_gbar_destroyed,
538                 .gbar_move = method_gbar_moved,
539                 .widget_pause = method_widget_pause,
540                 .widget_resume = method_widget_resume,
541                 .viewer_connected = method_viewer_connected,
542                 .viewer_disconnected = method_viewer_disconnected,
543                 .orientation = method_orientation,
544         };
545
546         widget_provider_prepare_init(abi, accel, secured);
547         return widget_provider_init(util_screen_get(), name, &table, NULL, 1, 1);
548 }
549
550 HAPI int client_fini(void)
551 {
552         (void)widget_provider_fini();
553         return WIDGET_ERROR_NONE;
554 }
555
556 /* End of a file */
557