Icon provider. do not sucide.
[platform/framework/web/data-provider-slave.git] / icon_src / main.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 #if defined(LOG_TAG)
18 #undef LOG_TAG
19 #define LOG_TAG "ICON_PROVIDER"
20 #endif
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <Elementary.h>
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <gio/gio.h>
31 #include <Ecore.h>
32 #include <Ecore_X.h>
33 #include <app.h>
34 #include <Edje.h>
35 #include <Eina.h>
36
37 #include <vconf.h>
38 #include <dlog.h>
39 #include <bundle.h>
40 #include <livebox-service.h>
41 #include <livebox-errno.h>
42 #include <provider.h>
43
44 #include <system_settings.h>
45
46 #include <packet.h>
47 #include <com-core.h>
48 #include <com-core_packet.h>
49
50 #include <shortcut.h>
51
52 #include "util.h"
53 #include "debug.h"
54
55 #define UTILITY_ADDR    "/tmp/.utility.service"
56 #define DEFAULT_ICON_LAYOUT "/usr/apps/org.tizen.data-provider-slave/res/edje/icon.edj"
57 #define DEFAULT_ICON_GROUP "default"
58
59 #define TEXT_CLASS      "tizen"
60 #define DEFAULT_FONT_SIZE       -100
61
62 int script_handler_parse_desc(Evas_Object *edje, const char *descfile);
63
64 static struct info {
65         int client_fd;
66         const char *socket_file;
67         char *font_name;
68 } s_info = {
69         .client_fd = -1,
70         .socket_file = UTILITY_ADDR,
71         .font_name = NULL,
72 };
73
74 #define TTL     30.0f   /* Can alive only 30 seconds from the last event */
75 #define QUALITY_N_COMPRESS "quality=100 compress=1"
76
77 /*!
78  * Defined for liblivebox
79  */
80 const char *livebox_find_pkgname(const char *filename)
81 {
82         return NULL;
83 }
84
85 int livebox_request_update_by_id(const char *filename)
86 {
87         return LB_STATUS_ERROR_NOT_EXIST;
88 }
89
90 int livebox_trigger_update_monitor(const char *id, int is_pd)
91 {
92         return LB_STATUS_ERROR_INVALID;
93 }
94
95 static inline Evas *create_virtual_canvas(int w, int h)
96 {
97         Ecore_Evas *internal_ee;
98         Evas *internal_e;
99
100         // Create virtual canvas
101         internal_ee = ecore_evas_buffer_new(w, h);
102         if (!internal_ee) {
103                 ErrPrint("Failed to create a new canvas buffer\n");
104                 return NULL;
105         }
106
107         ecore_evas_alpha_set(internal_ee, EINA_TRUE);
108         ecore_evas_manual_render_set(internal_ee, EINA_TRUE);
109
110         // Get the "Evas" object from a virtual canvas
111         internal_e = ecore_evas_get(internal_ee);
112         if (!internal_e) {
113                 ecore_evas_free(internal_ee);
114                 ErrPrint("Faield to get Evas object\n");
115                 return NULL;
116         }
117
118         ecore_evas_resize(internal_ee, w, h);
119         ecore_evas_show(internal_ee);
120
121         return internal_e;
122 }
123
124 static inline int flush_data_to_file(Evas *e, char *data, const char *filename, int w, int h)
125 {
126         Evas_Object *output;
127
128         output = evas_object_image_add(e);
129         if (!output) {
130                 ErrPrint("Failed to create an image object\n");
131                 return EXIT_FAILURE;
132         }
133
134         evas_object_image_data_set(output, NULL);
135         evas_object_image_colorspace_set(output, EVAS_COLORSPACE_ARGB8888);
136         evas_object_image_alpha_set(output, EINA_TRUE);
137         evas_object_image_size_set(output, w, h);
138         evas_object_image_smooth_scale_set(output, EINA_TRUE);
139         evas_object_image_data_set(output, data);
140         evas_object_image_data_update_add(output, 0, 0, w, h);
141
142         if (evas_object_image_save(output, filename, NULL, QUALITY_N_COMPRESS) == EINA_FALSE) {
143                 evas_object_del(output);
144                 ErrPrint("Faield to save a captured image (%s)\n", filename);
145                 return EXIT_FAILURE;
146         }
147
148         evas_object_del(output);
149
150         if (access(filename, F_OK) != 0) {
151                 ErrPrint("File %s is not found\n", filename);
152                 return EXIT_FAILURE;
153         }
154
155         return EXIT_SUCCESS;
156 }
157
158 static inline int flush_to_file(Evas *e, const char *filename, int w, int h)
159 {
160         void *data;
161         Ecore_Evas *internal_ee;
162
163         internal_ee = ecore_evas_ecore_evas_get(e);
164         if (!internal_ee) {
165                 ErrPrint("Failed to get ecore evas\n");
166                 return EXIT_FAILURE;
167         }
168
169         ecore_evas_manual_render(internal_ee);
170
171         // Get a pointer of a buffer of the virtual canvas
172         data = (void *)ecore_evas_buffer_pixels_get(internal_ee);
173         if (!data) {
174                 ErrPrint("Failed to get pixel data\n");
175                 return EXIT_FAILURE;
176         }
177
178         return flush_data_to_file(e, data, filename, w, h);
179 }
180
181 static inline int destroy_virtual_canvas(Evas *e)
182 {
183         Ecore_Evas *ee;
184
185         ee = ecore_evas_ecore_evas_get(e);
186         if (!ee) {
187                 ErrPrint("Failed to ecore evas object\n");
188                 return EXIT_FAILURE;
189         }
190
191         ecore_evas_free(ee);
192         return EXIT_SUCCESS;
193 }
194
195 static int disconnected_cb(int handle, void *data)
196 {
197         s_info.client_fd = -1;
198         elm_exit();
199         return 0;
200 }
201
202 static inline int convert_shortcut_type_to_lb_type(int shortcut_type, char **str)
203 {
204         char *_str;
205
206         if (!str) {
207                 str = &_str;
208         }
209
210         switch (shortcut_type) {
211         case LIVEBOX_TYPE_1x1:
212                 *str = "1x1";
213                 return LB_SIZE_TYPE_1x1;
214         case LIVEBOX_TYPE_2x1:
215                 *str = "2x1";
216                 return LB_SIZE_TYPE_2x1;
217         case LIVEBOX_TYPE_2x2:
218                 *str = "2x2";
219                 return LB_SIZE_TYPE_2x2;
220         case LIVEBOX_TYPE_4x1:
221                 *str = "4x1";
222                 return LB_SIZE_TYPE_4x1;
223         case LIVEBOX_TYPE_4x2:
224                 *str = "4x2";
225                 return LB_SIZE_TYPE_4x2;
226         case LIVEBOX_TYPE_4x3:
227                 *str = "4x3";
228                 return LB_SIZE_TYPE_4x3;
229         case LIVEBOX_TYPE_4x4:
230                 *str = "4x4";
231                 return LB_SIZE_TYPE_4x4;
232         case LIVEBOX_TYPE_4x5:
233                 *str = "4x5";
234                 return LB_SIZE_TYPE_4x5;
235         case LIVEBOX_TYPE_4x6:
236                 *str = "4x6";
237                 return LB_SIZE_TYPE_4x6;
238         case LIVEBOX_TYPE_EASY_1x1:
239                 *str = "easy,1x1";
240                 return LB_SIZE_TYPE_EASY_1x1;
241         case LIVEBOX_TYPE_EASY_3x1:
242                 *str = "easy,3x1";
243                 return LB_SIZE_TYPE_EASY_3x1;
244         case LIVEBOX_TYPE_EASY_3x3:
245                 *str = "easy,3x3";
246                 return LB_SIZE_TYPE_EASY_3x3;
247         default:
248                 *str = "?x?";
249                 return LB_SIZE_TYPE_UNKNOWN;
250         }
251 }
252
253 static struct packet *icon_create(pid_t pid, int handle, const struct packet *packet)
254 {
255         Evas *e;
256         const char *edje_path;
257         const char *group;
258         const char *desc_file;
259         const char *output;
260         int size_type;
261         int ret;
262         int w;
263         int h;
264         Evas_Object *edje;
265         Evas_Object *parent;
266         char _group[16];
267         char *size_str;
268
269         ret = packet_get(packet, "sssis", &edje_path, &group, &desc_file, &size_type, &output);
270         if (ret != 5) {
271                 ErrPrint("Invalid parameters");
272                 ret = -EINVAL;
273                 goto out;
274         }
275
276         if (!edje_path || !strlen(edje_path)) {
277                 edje_path = DEFAULT_ICON_LAYOUT;
278         }
279
280         size_type = convert_shortcut_type_to_lb_type(size_type, &size_str);
281         if (!group || !strlen(group)) {
282                 snprintf(_group, sizeof(_group), DEFAULT_ICON_GROUP",%s", size_str);
283                 group = _group;
284         }
285         DbgPrint("Selected layout: %s(%s)\n", edje_path, group);
286
287         ret = livebox_service_get_size(size_type, &w, &h);
288         if (ret != LB_STATUS_SUCCESS) {
289                 ErrPrint("Unable to get size(%d): %d\n", size_type, ret);
290                 goto out;
291         }
292
293         e = create_virtual_canvas(w, h);
294         if (!e) {
295                 ErrPrint("Unable to create a canvas: %dx%d\n", w, h);
296                 ret = LB_STATUS_ERROR_FAULT;
297                 goto out;
298         }
299
300         parent = evas_object_rectangle_add(e);
301         if (!parent) {
302                 ErrPrint("Unable to create a parent\n");
303                 destroy_virtual_canvas(e);
304                 ret = LB_STATUS_ERROR_FAULT;
305                 goto out;
306         }
307
308         evas_object_resize(parent, w, h);
309         evas_object_color_set(parent, 0, 0, 0, 0);
310         evas_object_show(parent);
311
312         edje = elm_layout_add(parent);
313         if (!edje) {
314                 ErrPrint("Unable to add an edje object\n");
315                 evas_object_del(parent);
316                 destroy_virtual_canvas(e);
317                 goto out;
318         }
319
320         if (elm_layout_file_set(edje, edje_path, group) == EINA_FALSE) {
321                 Edje_Load_Error err;
322                 err = edje_object_load_error_get(elm_layout_edje_get(edje));
323                 ErrPrint("Uanble to load an edje %s(%s) - %s\n", edje_path, group, edje_load_error_str(err));
324                 evas_object_del(edje);
325                 evas_object_del(parent);
326                 destroy_virtual_canvas(e);
327                 goto out;
328         }
329
330         evas_object_resize(edje, w, h);
331         evas_object_show(edje);
332
333         if (script_handler_parse_desc(edje, desc_file) != LB_STATUS_SUCCESS) {
334                 ErrPrint("Unable to parse the %s\n", desc_file);
335         }
336
337         flush_to_file(e, output, w, h);
338         evas_object_del(edje);
339         evas_object_del(parent);
340         destroy_virtual_canvas(e);
341
342 out:
343         if (ret < 0) {
344                 /* Desc file should be deleted if it fails to create an icon image */
345                 if (unlink(desc_file) < 0) {
346                         ErrPrint("unlink(%s): %s\n", desc_file, strerror(errno));
347                 }
348         }
349
350         return packet_create_reply(packet, "i", ret);
351 }
352
353 static inline int client_init(void)
354 {
355         int ret;
356         struct packet *packet;
357         static struct method service_table[] = {
358                 {
359                         .cmd = "icon_create",
360                         .handler = icon_create,
361                 },
362                 {
363                         .cmd = NULL,
364                         .handler = NULL,
365                 },
366         };
367
368         com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
369
370         s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
371         if (s_info.client_fd < 0) {
372                 ErrPrint("Failed to make a connection to the master\n");
373                 return -EFAULT;
374         }
375
376         packet = packet_create_noack("service_register", "");
377         if (!packet) {
378                 ErrPrint("Failed to build a packet\n");
379                 return -EFAULT;
380         }
381
382         ret = com_core_packet_send_only(s_info.client_fd, packet);
383         DbgPrint("Service register sent: %d\n", ret);
384         packet_destroy(packet);
385         if (ret != 0) {
386                 com_core_packet_client_fini(s_info.client_fd);
387                 s_info.client_fd = -1;
388                 ret = -EFAULT;
389         } else {
390                 ret = 0;
391         }
392
393         DbgPrint("Server FD: %d\n", s_info.client_fd);
394         return ret;
395 }
396
397 static inline void client_fini(void)
398 {
399         if (s_info.client_fd < 0) {
400                 DbgPrint("Client is not initiated\n");
401                 return;
402         }
403
404         com_core_packet_client_fini(s_info.client_fd);
405         s_info.client_fd = -1;
406 }
407
408 static void update_font_cb(void *data)
409 {
410         Eina_List *list;
411         char *text;
412
413         list = edje_text_class_list();
414         DbgPrint("List: %p\n", list);
415         if (list) {
416                 EINA_LIST_FREE(list, text) {
417                         if (!strncasecmp(text, TEXT_CLASS, strlen(TEXT_CLASS))) {
418                                 DbgPrint("Update text class %s (%s, %d)\n", text, s_info.font_name, DEFAULT_FONT_SIZE);
419                                 edje_text_class_del(text);
420                                 edje_text_class_set(text, s_info.font_name, DEFAULT_FONT_SIZE);
421                         } else {
422                                 DbgPrint("Skip text class %s\n", text);
423                         }
424                 }
425         } else {
426                 DbgPrint("New (%s, %d)\n", s_info.font_name, DEFAULT_FONT_SIZE);
427                 edje_text_class_set(TEXT_CLASS, s_info.font_name, DEFAULT_FONT_SIZE);
428         }
429 }
430
431 static void font_changed_cb(keynode_t *node, void *user_data)
432 {
433         char *font_name;
434
435         if (s_info.font_name) {
436                 font_name = vconf_get_str("db/setting/accessibility/font_name");
437                 if (!font_name) {
438                         ErrPrint("Invalid font name (NULL)\n");
439                         return;
440                 }
441
442                 if (!strcmp(s_info.font_name, font_name)) {
443                         DbgPrint("Font is not changed (Old: %s(%p) <> New: %s(%p))\n", s_info.font_name, s_info.font_name, font_name, font_name);
444                         free(font_name);
445                         return;
446                 }
447
448                 DbgPrint("Release old font name: %s(%p)\n", s_info.font_name, s_info.font_name);
449                 free(s_info.font_name);
450         } else {
451                 int ret;
452
453                 font_name = NULL;
454                 ret = system_settings_get_value_string(SYSTEM_SETTINGS_KEY_FONT_TYPE, &font_name);
455                 if (ret != SYSTEM_SETTINGS_ERROR_NONE || !font_name) {
456                         ErrPrint("system settings: %d, font_name[%p]\n", ret, font_name);
457                         return;
458                 }
459         }
460
461         s_info.font_name = font_name;
462         DbgPrint("Font name is changed to %s(%p)\n", s_info.font_name, s_info.font_name);
463
464         update_font_cb(NULL);
465 }
466
467 static bool app_create(void *data)
468 {
469         int ret;
470
471         if (client_init() < 0) {
472                 ErrPrint("Unable to initiate the client\n");
473                 return FALSE;
474         }
475
476         /*!
477          * Send a request to reigister as a service.
478          */
479         ret = vconf_notify_key_changed("db/setting/accessibility/font_name", font_changed_cb, NULL);
480         DbgPrint("System font is changed: %d\n", ret);
481
482         font_changed_cb(NULL, NULL);
483         return TRUE;
484 }
485
486 static void app_terminate(void *data)
487 {
488         int ret;
489
490         ret = vconf_ignore_key_changed("db/setting/accessibility/font_name", font_changed_cb);
491         DbgPrint("Remove font change callback: %d\n", ret);
492
493         client_fini();
494
495         free(s_info.font_name);
496         s_info.font_name = NULL;
497         return;
498 }
499
500 static void app_pause(void *data)
501 {
502         /* Will not be called */
503         return;
504 }
505
506 static void app_resume(void *data)
507 {
508         /* Will not be called */
509         return;
510 }
511
512 static void app_service(service_h service, void *data)
513 {
514 }
515
516 int main(int argc, char *argv[])
517 {
518         int ret;
519         app_event_callback_s event_callback;
520
521         event_callback.create = app_create;
522         event_callback.terminate = app_terminate;
523         event_callback.pause = app_pause;
524         event_callback.resume = app_resume;
525         event_callback.service = app_service;
526         event_callback.low_memory = NULL;
527         event_callback.low_battery = NULL;
528         event_callback.device_orientation = NULL;
529         event_callback.language_changed = NULL;
530         event_callback.region_format_changed = NULL;
531
532         ret = app_efl_main(&argc, &argv, &event_callback, NULL);
533         return ret;
534 }
535
536 /* End of a file */