modules/information/ext_storage: fix sigsegv
[apps/core/preloaded/indicator-win.git] / src / util.c
1 /*
2  *  Indicator
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20
21
22 #include <vconf.h>
23 #include <app.h>
24 #include <app_common.h>
25 #include <Eina.h>
26 #include <system_settings.h>
27
28 #include "common.h"
29 #include "indicator.h"
30 #include "main.h"
31 #include "indicator_gui.h"
32 #include "util.h"
33 #include "icon.h"
34 #include "box.h"
35 #include "log.h"
36
37 #define APP_CONTROL_OPERATION_POPUP_SEARCH "http://samsung.com/appcontrol/operation/search"
38
39 #define DEFAULT_DIR     ICONDIR
40 #define DIR_PREFIX      "Theme_%02d_"
41 #define LABEL_STRING    "<color=#%02x%02x%02x%02x>%s</color>"
42
43 typedef struct {
44         wifi_connection_state_changed_cb cb;
45         void *data;
46 } wifi_handler_t;
47
48 typedef struct {
49         system_settings_key_e key;
50         system_settings_changed_cb cb;
51         void *data;
52 } system_settings_handler_t;
53
54 typedef struct {
55         runtime_info_key_e key;
56         runtime_info_changed_cb cb;
57         void *data;
58 } runtime_info_handler_t;
59
60 static Eina_List *wifi_callbacks;
61 static Eina_List *ss_callbacks;
62 static Eina_List *ri_callbacks;
63
64 char *util_set_label_text_color(const char *txt)
65 {
66         Eina_Strbuf *temp_buf = NULL;
67         Eina_Bool buf_result = EINA_FALSE;
68         char *ret_str = NULL;
69
70         retif(txt == NULL, NULL, "Invalid parameter!");
71
72         temp_buf = eina_strbuf_new();
73         buf_result = eina_strbuf_append_printf(temp_buf,
74                                 LABEL_STRING, FONT_COLOR, txt);
75
76         if (buf_result == EINA_FALSE)
77                 DBG("Failed to make label string!");
78         else
79                 ret_str = eina_strbuf_string_steal(temp_buf);
80
81         eina_strbuf_free(temp_buf);
82         return ret_str;
83 }
84
85 const char *util_get_icon_dir(void)
86 {
87         return util_get_res_file_path(DEFAULT_DIR);
88 }
89
90
91
92 void util_signal_emit(void* data, const char *emission, const char *source)
93 {
94         struct appdata *ad = NULL;
95         Evas_Object *edje = NULL;
96
97         ret_if(!data);
98
99         ad = (struct appdata *)data;
100
101         char *filter1 = "indicator.connection.updown";
102         char *filter2 = "indicator.wifi.updown";
103         if (strncmp(filter1, emission, strlen(filter1)) != 0
104                         && strncmp(filter2, emission, strlen(filter2)) != 0) {
105                 SECURE_DBG("emission %s",emission);
106         }
107
108         edje = elm_layout_edje_get(ad->win.layout);
109         ret_if(!edje);
110         edje_object_signal_emit(edje, emission, source);
111 }
112
113
114
115 void util_part_text_emit(void* data, const char *part, const char *text)
116 {
117         struct appdata *ad = (struct appdata *)data;
118         retif(data == NULL, , "Invalid parameter!");
119         Evas_Object *edje;
120
121         retif(ad->win.layout == NULL, , "Invalid parameter!");
122         edje = elm_layout_edje_get(ad->win.layout);
123         edje_object_part_text_set(edje, part, text);
124 }
125
126
127
128 void util_signal_emit_by_win(void* data, const char *emission, const char *source)
129 {
130         win_info *win = NULL;
131         Evas_Object *edje = NULL;
132
133         ret_if(!data);
134
135         win = (win_info*)data;
136         ret_if(!win->layout);
137
138         _D("emission %s", emission);
139
140         edje = elm_layout_edje_get(win->layout);
141         edje_object_signal_emit(edje, emission, source);
142 }
143
144
145
146 void util_part_text_emit_by_win(void* data, const char *part, const char *text)
147 {
148         win_info *win = (win_info*)data;
149         retif(data == NULL, , "Invalid parameter!");
150         Evas_Object *edje;
151
152         retif(win->layout == NULL, , "Invalid parameter!");
153         edje = elm_layout_edje_get(win->layout);
154         edje_object_part_text_set(edje, part, text);
155 }
156
157
158
159 void util_battery_percentage_part_content_set(void* data, const char *part, const char *img_path)
160 {
161         struct appdata *ad = (struct appdata *)data;
162         retif(data == NULL, , "Invalid parameter!");
163         Evas_Object *icon = NULL;
164         char path[PATH_MAX];
165
166         retif(ad->win.layout == NULL, , "Invalid parameter!");
167
168         icon = elm_image_add(ad->win.layout);
169         retif(!icon, , "Cannot create elm icon object!");
170
171         if (strncmp(img_path, "/", 1) != 0)
172         {
173                 snprintf(path, sizeof(path), "%s/%s", util_get_icon_dir(), img_path);
174         }
175         else
176         {
177                 strncpy(path, img_path, sizeof(path)-1);
178         }
179
180         if (!ecore_file_exists(path))
181         {
182                 ERR("icon file does not exist!!: %s",path);
183                 return;
184         }
185         elm_image_file_set(icon, path, NULL);
186         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
187         elm_object_part_content_set(ad->win.layout, part, icon);
188 }
189
190
191
192 void util_send_status_message_start(void* data,double duration)
193 {
194         Ecore_Evas *ee_port;
195         win_info* win = (win_info*)data;
196         retif(data == NULL, , "Invalid parameter!");
197         struct appdata *ad = win->data;
198         Indicator_Data_Animation msg = {0,};
199
200         msg.xwin = ad->active_indi_win;
201         msg.duration = duration;
202
203         DBG("status start %x, %f",ad->active_indi_win,duration);
204         ee_port = ecore_evas_ecore_evas_get(evas_object_evas_get(win->win));
205         ecore_evas_msg_send(ee_port, MSG_DOMAIN_CONTROL_INDICATOR, MSG_ID_INDICATOR_ANI_START, &(msg), sizeof(Indicator_Data_Animation));
206
207 }
208
209
210
211 void util_launch_search(void* data)
212 {
213         int lock_state = SYSTEM_SETTINGS_LOCK_STATE_UNLOCK;
214         app_control_h service;
215
216         int ret = system_settings_get_value_int(SYSTEM_SETTINGS_KEY_LOCK_STATE, &lock_state);
217         retm_if(ret != SYSTEM_SETTINGS_ERROR_NONE, "system_settings_get_value_int failed %s", get_error_message(ret));
218
219         /* In Lock Screen, home button don't have to do */
220         if (lock_state == SYSTEM_SETTINGS_LOCK_STATE_LOCK) {
221                 return;
222         }
223
224         if (util_check_system_status() == FAIL) {
225                 DBG("util_check_system_status failed");
226                 return;
227         }
228
229         app_control_create(&service);
230         app_control_set_operation(service, APP_CONTROL_OPERATION_MAIN);
231         app_control_set_app_id(service, SEARCH_PKG_NAME);
232
233         ret = app_control_send_launch_request(service, NULL, NULL);
234
235         if(ret != APP_CONTROL_ERROR_NONE) {
236                 ERR("Cannot launch app");
237         }
238
239         app_control_destroy(service);
240 }
241
242
243
244 int util_check_system_status(void)
245 {
246         int ret, value = -1;
247
248         ret = vconf_get_int(VCONFKEY_PWLOCK_STATE, &value);
249         if (ret == OK &&
250             (value == VCONFKEY_PWLOCK_BOOTING_LOCK ||
251              value == VCONFKEY_PWLOCK_RUNNING_LOCK))
252                 return FAIL;
253
254         return OK;
255 }
256
257
258
259 #ifdef _SUPPORT_SCREEN_READER
260 Evas_Object *util_access_object_register(Evas_Object *object, Evas_Object *layout)
261 {
262         if ((object == NULL) || (layout == NULL)) {
263                 ERR("Access object doesn't exist!!! %x %x",object,layout);
264                 return NULL;
265         }
266
267         return elm_access_object_register(object, layout);
268 }
269
270
271
272 void util_access_object_unregister(Evas_Object *object)
273 {
274         if (object == NULL) {
275                 ERR("Access object doesn't exist!!! %x",object);
276                 return NULL;
277         }
278
279         elm_access_object_unregister(object);
280 }
281
282
283
284 void util_access_object_info_set(Evas_Object *object, int info_type, char *info_text)
285 {
286         if ((object == NULL) || (info_text == NULL)) {
287                 ERR("Access info set fails %x, %x!!!",object,info_text);
288                 return;
289         }
290
291         elm_access_info_set(object, info_type, (const char *)info_text);
292 }
293
294
295
296 void util_access_object_activate_cb_set(Evas_Object *object, Elm_Access_Activate_Cb activate_cb, void *cb_data)
297 {
298         if ((object == NULL) || (activate_cb == NULL)) {
299                 ERR("Access activated cb set fails %x %x!!!",object,activate_cb);
300                 return;
301         }
302
303         elm_access_activate_cb_set(object, activate_cb, cb_data);
304 }
305
306
307
308 void util_access_object_info_cb_set(Evas_Object *object, int type, Elm_Access_Info_Cb info_cb, void *cb_data)
309 {
310         if ((object == NULL) || (info_cb == NULL)) {
311                 ERR("Access info cb set fails  %x %x!!!",object,info_cb);
312                 return;
313         }
314
315         elm_access_info_cb_set(object, type, info_cb, cb_data);
316 }
317
318
319
320 void util_icon_access_register(icon_s *icon)
321 {
322
323         if(icon == NULL)
324         {
325                 ERR("ICON NULL");
326                 return;
327         }
328
329         if(icon->tts_enable == EINA_TRUE && icon->ao==NULL)
330         {
331                 Evas_Object *to = NULL;
332
333                 to = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(icon->img_obj.obj), "elm.rect.icon.access");
334                 icon->ao = util_access_object_register(to, icon->img_obj.obj);
335
336                 if(icon->access_cb!=NULL)
337                 {
338                         util_access_object_info_cb_set(icon->ao,ELM_ACCESS_INFO,icon->access_cb,icon->ad);
339                 }
340         }
341 }
342
343
344
345 void util_icon_access_unregister(icon_s *icon)
346 {
347         if(icon == NULL)
348         {
349                 ERR("ICON NULL");
350                 return;
351         }
352
353         if(icon->tts_enable == EINA_TRUE&&icon->ao!=NULL)
354         {
355                 util_access_object_unregister(icon->ao);
356                 icon->ao = NULL;
357         }
358 }
359 #endif /* _SUPPORT_SCREEN_READER */
360
361
362
363 static char* _get_timezone_from_vconf(void)
364 {
365         char *szTimezone = NULL;
366         szTimezone = vconf_get_str(VCONFKEY_SETAPPL_TIMEZONE_ID);
367         if(szTimezone == NULL)
368         {
369                 ERR("Cannot get time zone.");
370                 return strdup("N/A");
371         }
372
373         return szTimezone;
374 }
375
376
377
378 char* util_get_timezone_str(void)
379 {
380         enum { BUFFERSIZE = 1024 };
381         char buf[BUFFERSIZE];
382         ssize_t len = readlink("/opt/etc/localtime", buf, sizeof(buf)-1);
383
384         if (len != -1)
385         {
386                 buf[len] = '\0';
387         }
388         else
389         {
390                 ERR("NO TIMEZONEINFO");
391                 return _get_timezone_from_vconf();
392         }
393         return (char*)strdup(buf+20);   // Asia/Seoul
394 }
395
396
397
398 Eina_Bool util_win_prop_angle_get(Ecore_X_Window win, int *req)
399 {
400         Eina_Bool res = EINA_FALSE;
401 #if 0
402         int ret, count;
403         int angle[2] = {-1, -1};
404         unsigned char* prop_data = NULL;
405         ret = ecore_x_window_prop_property_get(win, ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
406         if (ret <= 0) {
407                 if (prop_data) free(prop_data);
408                 return res;
409         }
410
411         if (ret && prop_data) {
412                 memcpy (&angle, prop_data, sizeof (int)*count);
413                 if (count == 2) res = EINA_TRUE;
414         }
415
416         if (prop_data) free(prop_data);
417         *req  = angle[0]; //current angle
418
419         if (angle[0] == -1 && angle[1] == -1) res = EINA_FALSE;
420 #endif
421
422         return res;
423 }
424
425
426 #if 0
427 int util_get_block_width(void* data, const char* part)
428 {
429         Evas_Object * eo = NULL;
430         int geo_dx = 0;
431         int geo_dy = 0;
432         retif(data == NULL,-1, "Invalid parameter!");
433         retif(part == NULL,-1, "Invalid parameter!");
434
435         win_info* win = (win_info*)data;
436
437         eo = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(win->layout), part);
438
439         evas_object_geometry_get(eo, NULL, NULL, &geo_dx, &geo_dy);
440
441         return geo_dx;
442 }
443
444
445
446 int util_get_string_width(void* data, const char* part)
447 {
448         Evas_Object * eo = NULL;
449         int text_dx = 0;
450         int text_dy = 0;
451         retif(data == NULL,-1, "Invalid parameter!");
452         retif(part == NULL,-1, "Invalid parameter!");
453
454         win_info* win = (win_info*)data;
455
456         eo = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(win->layout), part);
457
458         evas_object_textblock_size_formatted_get(eo, &text_dx, &text_dy);
459
460         return text_dx;
461 }
462 #endif
463
464
465 int util_is_orf(void)
466 {
467         return 1;
468 }
469
470
471
472 int util_check_noti_ani(const char* path)
473 {
474         retv_if(!path, 0);
475         if (!strcmp(path,"reserved://indicator/ani/downloading")
476                 || !strcmp(path,"reserved://indicator/ani/uploading")) {
477                 return 1;
478         }
479         return 0;
480 }
481
482
483
484 void util_start_noti_ani(void* data)
485 {
486         icon_s *icon = (icon_s *)data;
487         retif(data == NULL, , "Invalid parameter!");
488
489         if(util_check_noti_ani(icon->img_obj.data))
490         {
491                 DBG("%s",icon->name);
492                 if(!strcmp(icon->img_obj.data,"reserved://indicator/ani/downloading"))
493                 {
494                         icon_ani_set(icon,ICON_ANI_DOWNLOADING);
495                 }
496                 else
497                 {
498                         icon_ani_set(icon,ICON_ANI_UPLOADING);
499                 }
500         }
501 }
502
503
504
505 void util_stop_noti_ani(void* data)
506 {
507         icon_s *icon = (icon_s *)data;
508         retif(data == NULL, , "Invalid parameter!");
509
510         if(util_check_noti_ani(icon->img_obj.data))
511         {
512                 Evas_Object *img_edje;
513                 img_edje = elm_layout_edje_get(icon->img_obj.obj);
514                 DBG("%s",icon->name);
515                 if(!strcmp(icon->img_obj.data,"reserved://indicator/ani/downloading"))
516                 {
517                         edje_object_signal_emit(img_edje, "indicator.ani.downloading.stop","elm.swallow.icon");
518                 }
519                 else
520                 {
521                         edje_object_signal_emit(img_edje, "indicator.ani.uploading.stop","elm.swallow.icon");
522                 }
523         }
524 }
525
526
527
528 void util_char_replace(char *text, char s, char t)
529 {
530         retif(text == NULL, , "invalid argument");
531
532         int i = 0, text_len = 0;
533
534         text_len = strlen(text);
535
536         for (i = 0; i < text_len; i++) {
537                 if (*(text + i) == s) {
538                         *(text + i) = t;
539                 }
540         }
541 }
542
543
544
545 static bool _is_empty_str(const char *str)
546 {
547         if (NULL == str || '\0' == str[0])
548                 return true;
549         return false;
550 }
551
552
553
554 char *util_safe_str(const char *str, const char *strSearch)
555 {
556         if (_is_empty_str(str))
557                 return NULL;
558
559         return strstr(str, strSearch);
560 }
561
562
563
564 int util_dynamic_state_get(void)
565 {
566         int val = 0;
567         //vconf_get_bool(VCONFKEY_SETAPPL_DYNAMIC_STATUS_BAR, &val);
568         return val;
569 }
570
571
572
573 Ecore_File_Monitor* util_file_monitor_add(const char* file_path, Ecore_File_Monitor_Cb callback_func, void *ad)
574 {
575         SECURE_DBG("File path : %s", file_path);
576         Ecore_File_Monitor* pFileMonitor = NULL;
577         pFileMonitor = ecore_file_monitor_add(file_path, callback_func, ad);
578         if(pFileMonitor == NULL) SECURE_DBG("ecore_file_monitor_add return NULL !!");
579
580         return pFileMonitor;
581 }
582
583
584
585 void util_file_monitor_remove(Ecore_File_Monitor* pFileMonitor)
586 {
587         if(pFileMonitor == NULL) return;
588
589         ecore_file_monitor_del(pFileMonitor);
590         pFileMonitor = NULL;
591 }
592
593 const char *util_get_file_path(enum app_subdir dir, const char *relative)
594 {
595         static char buf[PATH_MAX];
596         char *prefix;
597
598         switch (dir) {
599         case APP_DIR_DATA:
600                 prefix = app_get_data_path();
601                 break;
602         case APP_DIR_CACHE:
603                 prefix = app_get_cache_path();
604                 break;
605         case APP_DIR_RESOURCE:
606                 prefix = app_get_resource_path();
607                 break;
608         case APP_DIR_SHARED_DATA:
609                 prefix = app_get_shared_data_path();
610                 break;
611         case APP_DIR_SHARED_RESOURCE:
612                 prefix = app_get_shared_resource_path();
613                 break;
614         case APP_DIR_SHARED_TRUSTED:
615                 prefix = app_get_shared_trusted_path();
616                 break;
617         case APP_DIR_EXTERNAL_DATA:
618                 prefix = app_get_external_data_path();
619                 break;
620         case APP_DIR_EXTERNAL_CACHE:
621                 prefix = app_get_external_cache_path();
622                 break;
623         case APP_DIR_EXTERNAL_SHARED_DATA:
624                 prefix = app_get_external_shared_data_path();
625                 break;
626         default:
627                 LOGE("Not handled directory type.");
628                 return NULL;
629         }
630         size_t res = eina_file_path_join(buf, sizeof(buf), prefix, relative);
631         free(prefix);
632         if (res > sizeof(buf)) {
633                 LOGE("Path exceeded PATH_MAX");
634                 return NULL;
635         }
636
637         return &buf[0];
638 }
639
640 static void _wifi_state_cb(wifi_connection_state_e state, wifi_ap_h ap, void *user_data)
641 {
642         Eina_List *l;
643         wifi_handler_t *hdl;
644
645         EINA_LIST_FOREACH(wifi_callbacks, l, hdl) {
646                 if (hdl->cb) hdl->cb(state, ap, hdl->data);
647         }
648 }
649
650 int util_wifi_set_connection_state_changed_cb(wifi_connection_state_changed_cb cb, void *data)
651 {
652         wifi_handler_t *hdl = malloc(sizeof(wifi_handler_t));
653         if (!hdl) {
654                 return -1;
655         }
656
657         if (!wifi_callbacks) {
658                 int err = wifi_set_connection_state_changed_cb(_wifi_state_cb, NULL);
659                 if (err != WIFI_ERROR_NONE) {
660                         free(hdl);
661                         return -1;
662                 }
663         }
664
665         hdl->cb = cb;
666         hdl->data = data;
667         wifi_callbacks = eina_list_append(wifi_callbacks, cb);
668
669         return 0;
670 }
671
672 void util_wifi_unset_connection_state_changed_cb(wifi_connection_state_changed_cb cb)
673 {
674         Eina_List *l, *l2;
675         wifi_handler_t *hdl;
676
677         EINA_LIST_FOREACH_SAFE(wifi_callbacks, l, l2, hdl) {
678                 if (hdl->cb == cb) {
679                         wifi_callbacks = eina_list_remove_list(wifi_callbacks, l);
680                         free(hdl);
681                 }
682         }
683         if (!wifi_callbacks)
684                 wifi_unset_connection_state_changed_cb();
685 }
686
687 static void _system_settings_cb(system_settings_key_e key, void *data)
688 {
689         Eina_List *l;
690         system_settings_handler_t *hdl;
691
692         EINA_LIST_FOREACH(ss_callbacks, l, hdl) {
693                 if (hdl->key == key) {
694                         if (hdl->cb) hdl->cb(key, hdl->data);
695                 }
696         }
697 }
698
699 int util_system_settings_set_changed_cb(system_settings_key_e key, system_settings_changed_cb cb, void *data)
700 {
701         system_settings_handler_t *handler = malloc(sizeof(system_settings_handler_t));
702         if (!handler) {
703                 return -1;
704         }
705
706         system_settings_unset_changed_cb(key);
707         int err = system_settings_set_changed_cb(key, _system_settings_cb, NULL);
708         if (err != SYSTEM_SETTINGS_ERROR_NONE) {
709                 ERR("system_settings_set_changed_cb failed: %s", get_error_message(err));
710                 free(handler);
711                 return -1;
712         }
713
714         handler->key = key;
715         handler->cb = cb;
716         handler->data = data;
717
718         ss_callbacks = eina_list_append(ss_callbacks, handler);
719
720         return 0;
721 }
722
723 void util_system_settings_unset_changed_cb(system_settings_key_e key, system_settings_changed_cb cb)
724 {
725         Eina_List *l, *l2;
726         system_settings_handler_t *hdl;
727         Eina_Bool del_key_cb = EINA_TRUE;
728
729         EINA_LIST_FOREACH_SAFE(ss_callbacks, l, l2, hdl) {
730                 if (hdl->key == key) {
731                         if (hdl->cb == cb) {
732                                 ss_callbacks = eina_list_remove_list(ss_callbacks, l);
733                                 free(hdl);
734                         }
735                         else {
736                                 del_key_cb = EINA_FALSE;
737                         }
738                 }
739         }
740         if (del_key_cb)
741                 system_settings_unset_changed_cb(key);
742 }
743
744 static void _runtime_info_cb(runtime_info_key_e key, void *data)
745 {
746         Eina_List *l;
747         runtime_info_handler_t *hdl;
748
749         EINA_LIST_FOREACH(ri_callbacks, l, hdl) {
750                 if (hdl->key == key) {
751                         if (hdl->cb) hdl->cb(key, hdl->data);
752                 }
753         }
754 }
755
756 int util_runtime_info_set_changed_cb(runtime_info_key_e key, runtime_info_changed_cb cb, void *data)
757 {
758         runtime_info_handler_t *handler = malloc(sizeof(runtime_info_handler_t));
759         if (!handler) {
760                 return -1;
761         }
762
763         runtime_info_unset_changed_cb(key);
764         int err = runtime_info_set_changed_cb(key, _runtime_info_cb, NULL);
765         if (err != RUNTIME_INFO_ERROR_NONE) {
766                 ERR("runtime_info_set_changed_cb failed: %s", get_error_message(err));
767                 free(handler);
768                 return -1;
769         }
770
771         handler->key = key;
772         handler->cb = cb;
773         handler->data = data;
774
775         ri_callbacks = eina_list_append(ri_callbacks, handler);
776
777         return 0;
778 }
779
780 void util_runtime_info_unset_changed_cb(runtime_info_key_e key, runtime_info_changed_cb cb)
781 {
782         Eina_List *l, *l2;
783         runtime_info_handler_t *hdl;
784         Eina_Bool del_key_cb = EINA_TRUE;
785
786         EINA_LIST_FOREACH_SAFE(ri_callbacks, l, l2, hdl) {
787                 if (hdl->key == key) {
788                         if (hdl->cb == cb) {
789                                 ri_callbacks = eina_list_remove_list(ri_callbacks, l);
790                                 free(hdl);
791                         }
792                         else {
793                                 del_key_cb = EINA_FALSE;
794                         }
795                 }
796         }
797         if (del_key_cb)
798                 runtime_info_unset_changed_cb(key);
799
800 }
801
802 /* End of file */