tizen 2.4 release
[apps/home/quickpanel.git] / daemon / minictrl / minictrl.c
1 /*
2  * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18
19 #include <Elementary.h>
20 #include <glib.h>
21 #include <string.h>
22 #include <stdbool.h>
23
24 #include <minicontrol-viewer.h>
25 #include <minicontrol-internal.h>
26 #include <bundle.h>
27 #include <tzsh.h>
28 #include <tzsh_quickpanel_service.h>
29
30 #include "common.h"
31 #include "common_uic.h"
32 #include "quickpanel-ui.h"
33 #include "quickpanel_def.h"
34 #include "list_util.h"
35 #include "quickpanel_debug_util.h"
36 #include "minictrl.h"
37 #include "vi_manager.h"
38
39 #ifdef QP_SCREENREADER_ENABLE
40 #include "accessibility.h"
41 #endif
42
43 #define MINICONTROL_TYPE_STR_VIEWER "::[viewer="
44 #define MINICONTROL_TYPE_STR_QUICKPANEL "QUICKPANEL"
45 #define MINICONTROL_TYPE_STR_LOCKSCREEN "LOCKSCREEN"
46 #define MINICONTROL_TYPE_STR_ONGOING "_ongoing]"
47 #define MINICONTROL_VIEW_DATA "MINICONTROL_VIEW_DATA"
48
49 #define THRESHOLD_DELETE_START 30
50 #define THRESHOLD_DELETE_START_Y_LIMIT 60
51 #define THRESHOLD_DISTANCE (200)
52 #define THRESHOLD_DISTANCE_LOCK (500)
53
54 #define MINICONTROL_BUNDLE_KEY_WIDTH "width"
55 #define MINICONTROL_BUNDLE_KEY_HEIGHT "height"
56
57 #define BUNDLE_BUFFER_LENGTH 100
58
59 typedef enum _gesture_state_type {
60         STATE_NORMAL = 0,
61         STATE_GESTURE_WAIT,
62         STATE_GESTURE_CANCELED,
63         STATE_DELETED,
64 } gesture_state_type;
65
66 struct _viewer_item {
67         char *name;
68         unsigned int width;
69         unsigned int height;
70         Evas_Object *viewer;
71         void *data;
72
73         //for flick gesture
74         QP_VI *vi;
75         int obj_w;
76         int obj_h;
77         int press_x;
78         int press_y;
79         int distance;
80         int need_to_cancel_press;
81         gesture_state_type state;
82         int deletable;
83 };
84
85 static struct _info {
86         GHashTable *prov_table;
87 } s_info = {
88         .prov_table = NULL,
89 };
90
91 static int _viewer_check(const char *name)
92 {
93         char *pos_start = NULL;
94
95         if (!name) {
96                 ERR("Name is NULL");
97                 return 0;
98         }
99
100         if ((pos_start = strstr(name, MINICONTROL_TYPE_STR_VIEWER)) != NULL) {
101                 if (strstr(pos_start, MINICONTROL_TYPE_STR_QUICKPANEL) != NULL) {
102                         return 1;
103                 } else {
104                         return 0;
105                 }
106         } else if (strstr(name, MINICONTROL_TYPE_STR_LOCKSCREEN) != NULL) {
107                 return 0;
108         }
109
110         return 1;
111 }
112
113 static void _viewer_unfreeze(Evas_Object *viewer)
114 {
115         int i = 0, freezed_count = 0;
116
117         if (!viewer) {
118                 ERR("Invalid parameter");
119                 return;
120         }
121
122         freezed_count = elm_object_scroll_freeze_get(viewer);
123
124         for (i = 0 ; i < freezed_count; i++) {
125                 elm_object_scroll_freeze_pop(viewer);
126         }
127 }
128
129 static Evas_Object *_get_minictrl_obj(Evas_Object *layout)
130 {
131         if (!layout) {
132                 ERR("Invalid parameter");
133                 return NULL;
134         }
135
136         return elm_object_part_content_get(layout, "elm.icon");
137 }
138
139 static void _viewer_set_size(Evas_Object *layout, void *data, int width, int height)
140 {
141         Evas_Object *viewer;
142         struct appdata *ad;
143         int max_width;
144         int resized_width;
145         int is_landscape;
146
147         if (!layout || !data || width < 0 || height < 0) {
148                 ERR("Invalid parameters (%p, %p, %d, %d)", layout, data, width, height);
149                 return;
150         }
151
152         viewer = _get_minictrl_obj(layout);
153         if (!viewer) {
154                 ERR("Unable to get the 'viewer'");
155                 return;
156         }
157
158         ad = data;
159
160         if (ad->angle == 0 || ad->angle == 180) {
161                 is_landscape = 0;
162         } else {
163                 is_landscape = 1;
164         }
165
166         if (width > ad->win_width) {
167                 ERR("MC Size is not valid. it is larger than window size: %dx%d (%dx%d) %d", width, height, ad->win_width, ad->win_height, ad->angle);
168         }
169
170         max_width  = is_landscape ? ad->win_height : ad->win_width;
171         resized_width = (width > max_width) ? max_width : width;
172
173         SERR("minicontroller view is resized to w:%d/%d(%d) h:%d Landscape[%d]", resized_width, max_width, width, height, is_landscape);
174
175         evas_object_size_hint_min_set(viewer, resized_width, height);
176         evas_object_size_hint_max_set(viewer, resized_width, height);
177 }
178
179 static void _viewer_item_free(struct _viewer_item *item)
180 {
181         struct appdata *ad;
182
183         ad = quickpanel_get_app_data();
184         if (!ad || !ad->list || !item) {
185                 ERR("Invalid paramter %p, %p, %p", ad, ad ? ad->list : NULL, item);
186                 return;
187         }
188
189         free(item->name);
190
191         if (item->viewer) {
192                 quickpanel_list_util_item_unpack_by_object(ad->list, item->viewer, 0, 0);
193                 quickpanel_list_util_item_del_tag(item->viewer);
194                 evas_object_del(item->viewer);
195         }
196
197         free(item);
198 }
199
200 static bool _check_deletable(Evas_Object *obj)
201 {
202         struct _viewer_item *vit;
203
204         vit = evas_object_data_get(obj, MINICONTROL_VIEW_DATA);
205         if (vit) {
206                 return vit->deletable;
207         }
208
209         return TRUE;
210 }
211
212 static void _mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
213 {
214         Evas_Event_Mouse_Down *ev;
215         struct _viewer_item *vit;
216
217         vit = evas_object_data_get(obj, MINICONTROL_VIEW_DATA);
218         ev = (Evas_Event_Mouse_Down *)event_info;
219
220         if (!ev || !vit) {
221                 ERR("ev %p, vit %p");
222                 return;
223         }
224
225         evas_object_geometry_get(obj, NULL, NULL, &vit->obj_w, &vit->obj_h);
226
227         vit->press_x = ev->canvas.x;
228         vit->press_y = ev->canvas.y;
229         vit->state = STATE_NORMAL;
230
231         SDBG("mouse down:%d %d %d", vit->obj_w, vit->obj_h, vit->state);
232
233         if (vit->vi != NULL) {
234                 quickpanel_vi_user_event_del(vit->vi);
235                 vit->vi = NULL;
236         }
237
238         vit->need_to_cancel_press = 0;
239 }
240
241 static void _mouse_move_cb(void* data, Evas* e, Evas_Object* obj, void* event_info)
242 {
243         static int vi_start_x = 0;
244         static int delta_prev = -1;
245         int delta_x;
246         int x;
247         int y;
248         int w;
249         int h;
250         Evas_Event_Mouse_Move* ev;
251         struct _viewer_item *vit;
252         struct appdata *ad;
253
254         ad = data;
255         ev = event_info;
256         vit = evas_object_data_get(obj, MINICONTROL_VIEW_DATA);
257         if (!ev || !vit || !ad) {
258                 ERR("ev: %p, vit: %p, ad: %p", ev, vit, ad);
259                 return;
260         }
261
262         if (vit->state == STATE_GESTURE_CANCELED) {
263                 DBG("deletion has been canceled");
264                 return;
265         }
266
267         if (!_check_deletable(obj)) {
268                 DBG("vit->deletable is false");
269                 return;
270         }
271
272         evas_object_geometry_get(obj, &x, &y, &w, &h);
273         delta_x = (ev->cur.output.x - vit->press_x) / 2;
274
275         switch (vit->state) {
276         case STATE_NORMAL:
277                 if (abs(delta_x) >= THRESHOLD_DELETE_START) {
278                         QP_VI *vi;
279
280                         DBG("start a deletion");
281                         vit->state = STATE_GESTURE_WAIT;
282
283                         vi_start_x = delta_x;
284
285                         vi = quickpanel_vi_new_with_data(
286                                         VI_OP_DELETE,
287                                         QP_ITEM_TYPE_NOTI,
288                                         NULL,
289                                         obj,
290                                         NULL,
291                                         NULL,
292                                         NULL,
293                                         NULL, /* _drag_cancel_cb, */
294                                         NULL, /* vi == null */
295                                         NULL,
296                                         0,
297                                         0);
298
299                         if (vi) {
300                                 vit->vi = vi;
301                                 quickpanel_vi_user_event_add(vi);
302                         } else {
303                                 ERR("Unable to create a 'vi'");
304                         }
305
306                         vit->need_to_cancel_press = 1;
307                 }
308                 break;
309         case STATE_GESTURE_WAIT:
310                 if (delta_prev != delta_x) {
311                         Evas_Map *map;
312
313                         map = evas_map_new(4);
314                         if (map != NULL) {
315                                 evas_map_util_points_populate_from_object(map, obj);
316                                 evas_map_util_points_populate_from_geometry(map, x + delta_x - vi_start_x, y, w, h, 0);
317                                 evas_object_map_enable_set(obj, EINA_TRUE);
318                                 evas_object_map_set(obj, map);
319                                 evas_map_free(map);
320                                 _viewer_unfreeze(ad->scroller);
321                         }
322                         delta_prev = delta_x;
323                 }
324                 break;
325         default:
326                 break;
327         }
328
329         vit->distance = delta_x;
330 }
331
332 static void _minictrl_remove(const char *name, void *data)
333 {
334         DBG("_minictrl_remove [%s]", name);
335
336         minicontrol_viewer_send_event(name, MINICONTROL_EVENT_REQUEST_HIDE, NULL);
337
338         if (s_info.prov_table) {
339                 if (g_hash_table_remove(s_info.prov_table, name)) {
340                         DBG("success to remove %s", name);
341                         if (!data) {
342                                 ERR("data is NULL");
343                                 /**
344                                  * @todo
345                                  * Oh, this function doesn't handles "data".
346                                  * Why does this has to check its existence??
347                                  */
348                                 return;
349                         }
350                 } else {
351                         WARN("unknown provider name : %s", name);
352                 }
353         }
354 }
355
356 static void _mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
357 {
358         struct _viewer_item *vit;
359         struct appdata *ad;
360         int swipe_distance;
361
362         ad = data;
363         vit = evas_object_data_get(obj, MINICONTROL_VIEW_DATA);
364         if (!vit || !ad) {
365                 ERR("vit: %p, ad: %p", vit, ad);
366                 return;
367         }
368
369         _viewer_unfreeze(ad->scroller);
370
371         if (!_check_deletable(obj)) {
372                 swipe_distance = THRESHOLD_DISTANCE_LOCK;
373         } else {
374                 swipe_distance = THRESHOLD_DISTANCE;
375         }
376
377         switch (vit->state) {
378         case STATE_GESTURE_WAIT:
379                 if (abs(vit->distance) >= (swipe_distance - 10)) {
380                         Elm_Transit *transit_flick;
381                         int x;
382
383                         x = abs(vit->distance) - THRESHOLD_DELETE_START;
384
385                         if (vit->distance > 0) {
386                                 evas_object_map_set(obj, NULL);
387                                 transit_flick = elm_transit_add();
388                                 if (transit_flick != NULL) {
389                                         elm_transit_effect_translation_add(transit_flick, x, 0, 480, 0);
390                                         elm_transit_object_add(transit_flick, obj);
391                                         elm_transit_duration_set(transit_flick, 0.25 * (480 - x ) / 480);
392                                         elm_transit_tween_mode_set(transit_flick, ELM_TRANSIT_TWEEN_MODE_LINEAR);
393                                         elm_transit_objects_final_state_keep_set(transit_flick, EINA_TRUE);
394                                         elm_transit_go(transit_flick);
395                                         _minictrl_remove(vit->name, vit->data);
396                                 }
397                         } else if (vit->distance < 0) {
398                                 evas_object_map_set(obj, NULL);
399                                 transit_flick = elm_transit_add();
400                                 if (transit_flick != NULL) {
401                                         elm_transit_effect_translation_add(transit_flick, -x, 0, -480, 0);
402                                         elm_transit_object_add(transit_flick, obj);
403                                         elm_transit_duration_set(transit_flick, 0.25 * ( 480 - x ) / 480);
404                                         elm_transit_tween_mode_set(transit_flick, ELM_TRANSIT_TWEEN_MODE_LINEAR);
405                                         elm_transit_objects_final_state_keep_set(transit_flick, EINA_TRUE);
406                                         elm_transit_go(transit_flick);
407                                         _minictrl_remove(vit->name, vit->data);
408                                 }
409                         }
410                 } else {
411                         evas_object_map_enable_set(obj, EINA_FALSE);
412                 }
413
414                 if (vit->vi != NULL) {
415                         quickpanel_vi_user_event_del(vit->vi);
416                         vit->vi = NULL;
417                 }
418                 break;
419         case STATE_GESTURE_CANCELED:
420                 evas_object_map_enable_set(obj, EINA_FALSE);
421
422                 if (vit->vi != NULL) {
423                         quickpanel_vi_user_event_del(vit->vi);
424                         vit->vi = NULL;
425                 }
426                 break;
427         default:
428                 break;
429         }
430
431         vit->state = STATE_NORMAL;
432 }
433
434 static Evas_Object *_minictrl_create_view(struct appdata *ad, const char *name)
435 {
436         Evas_Object *layout;
437         Evas_Object *viewer;
438         Evas_Object *focus;
439
440         if (!ad || !ad->list || !name) {
441                 ERR("Invalid parameters: %p %p %p", ad, ad ? ad->list : NULL, name);
442                 return NULL;
443         }
444
445         layout = elm_layout_add(ad->list);
446         if (!layout) {
447                 ERR("Unable to create a layout");
448                 return NULL;
449         }
450
451         elm_layout_file_set(layout, DEFAULT_EDJ, "quickpanel/minictrl/default");
452         evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
453         evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
454         evas_object_show(layout);
455
456         viewer = minicontrol_viewer_add(layout, name);
457         if (!viewer) {
458                 ERR("fail to add viewer - %s", name);
459                 evas_object_del(layout);
460                 return NULL;
461         }
462         elm_object_focus_allow_set(viewer, EINA_TRUE);
463         elm_object_part_content_set(layout, "elm.icon", viewer);
464
465         evas_object_event_callback_add(viewer, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, ad);
466         evas_object_event_callback_add(viewer, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, ad);
467         evas_object_event_callback_add(viewer, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, ad);
468
469         focus = quickpanel_accessibility_ui_get_focus_object(layout);
470         elm_object_part_content_set(layout, "focus", focus);
471 #ifdef QP_SCREENREADER_ENABLE
472         Evas_Object *ao;
473         ao = quickpanel_accessibility_screen_reader_object_get(layout, SCREEN_READER_OBJ_TYPE_ELM_OBJECT, "focus", layout);
474         if (ao != NULL) {
475                 elm_access_info_cb_set(ao, ELM_ACCESS_TYPE, quickpanel_accessibility_info_cb, _NOT_LOCALIZED("Mini controller"));
476         }
477 #endif
478
479         return layout;
480 }
481
482 static int _minictrl_is_ongoing(const char *str)
483 {
484         if (str == NULL) {
485                 return 0;
486         }
487
488         if (strstr(str, MINICONTROL_TYPE_STR_ONGOING) != NULL) {
489                 return 1;
490         } else {
491                 return 0;
492         }
493 }
494
495 static void _minictrl_add(const char *name, unsigned int width, unsigned int height, void *data)
496 {
497         qp_item_data *qid = NULL;
498         struct _viewer_item *vit = NULL;
499         qp_item_type_e type;
500         struct appdata *ad;
501         Evas_Object *viewer = NULL;
502
503         if (!name || !data) {
504                 ERR("name: %p, data: %p", name, data);
505                 return;
506         }
507
508         ad = data;
509         if (!ad->list) {
510                 ERR("List is null");
511                 return;
512         }
513
514         if (s_info.prov_table) {
515                 struct _viewer_item *found;
516
517                 found = g_hash_table_lookup(s_info.prov_table, name);
518                 if (found) {
519                         ERR("already have it : %s", name);
520                         return;
521                 }
522         } else {
523                 ERR("s_info.prov_table is NULL");
524                 return;
525         }
526
527         /* elm_plug receives 'server_del' event,
528          * if it repeats connect and disconnect frequently.
529          *
530          */
531         viewer = _minictrl_create_view(ad, name);
532         if (!viewer) {
533                 ERR("Failed to create view[%s]", name);
534                 return;
535         }
536
537         _viewer_set_size(viewer, ad, width, height);
538         quickpanel_uic_initial_resize(viewer,
539                         (height > QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT)
540                         ? height : QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT);
541
542         vit = malloc(sizeof(*vit));
543         if (!vit) {
544                 ERR("fail to alloc vit");
545                 evas_object_del(viewer);
546                 return;
547         }
548
549         if (_minictrl_is_ongoing(name) == 1) {
550                 type = QP_ITEM_TYPE_MINICTRL_ONGOING;
551         } else {
552                 type = QP_ITEM_TYPE_MINICTRL_MIDDLE;
553         }
554
555         qid = quickpanel_list_util_item_new(type, vit);
556         if (!qid) {
557                 ERR("fail to alloc vit");
558                 evas_object_del(viewer);
559                 free(vit);
560                 return;
561         }
562
563         vit->name = strdup(name);
564         if (!vit->name) {
565                 ERR("strdup: %d", errno);
566                 quickpanel_list_util_item_del(qid);
567                 evas_object_del(viewer);
568                 free(vit);
569                 return;
570         }
571         vit->width = width;
572         vit->height = height;
573         vit->viewer = viewer;
574         vit->data = data;
575         vit->deletable = 1;
576         quickpanel_list_util_item_set_tag(vit->viewer, qid);
577         quickpanel_list_util_sort_insert(ad->list, vit->viewer);
578         evas_object_data_set(_get_minictrl_obj(viewer), MINICONTROL_VIEW_DATA, vit);
579
580         g_hash_table_insert(s_info.prov_table, g_strdup(name), vit);
581
582         DBG("success to add minicontrol %s", name);
583         quickpanel_minictrl_rotation_report(vit->name, ad->angle);
584 }
585
586 static void _anim_init_resize(void *data)
587 {
588         QP_VI *vi;
589         Evas_Object *item;
590
591         vi = data;
592         if (!vi) {
593                 ERR("Invalid parameter");
594                 return;
595         }
596
597         item = vi->target;
598         if (!item) {
599                 ERR("Invalid target");
600                 return;
601         }
602
603         evas_object_color_set(item, 0, 0, 0, 0);
604 }
605
606 static Eina_Bool _anim_init_cb(void *data)
607 {
608         QP_VI *vi;
609         int i;
610         static qp_vi_op_table anim_init_table[] = {
611                 {
612                         .op_type = VI_OP_RESIZE,
613                         .handler = _anim_init_resize,
614                 },
615                 {
616                         .op_type = VI_OP_NONE,
617                         .handler = NULL,
618                 },
619         };
620         
621         vi = data;
622         if (!vi) {
623                 ERR("Invalid parameter");
624                 return EINA_FALSE;
625         }
626
627         for (i = 0; anim_init_table[i].op_type != VI_OP_NONE; i++) {
628                 if (anim_init_table[i].op_type != vi->op_type) {
629                         continue;
630                 }
631
632                 anim_init_table[i].handler(vi);
633                 break;
634         }
635
636         return EINA_TRUE;
637 }
638
639 static void _reorder_transit_del_cb(void *data, Elm_Transit *transit)
640 {
641         QP_VI *vi;
642         Evas_Object *item;
643         struct appdata *ad;
644
645         vi = data;
646         if (!vi) {
647                 ERR("vi is null");
648                 return;
649         }
650
651         item = vi->target;
652         if (!item) {
653                 ERR("Target is null");
654                 return;
655         }
656
657         ad = quickpanel_get_app_data();
658         if (!ad) {
659                 ERR("ad is null");
660                 return;
661         }
662
663         _viewer_set_size(item, ad, vi->extra_flag_1, vi->extra_flag_2);
664         quickpanel_uic_initial_resize(item,
665                         (vi->extra_flag_2 > QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT)
666                         ? vi->extra_flag_2 : QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT);
667 }
668
669 static void _anim_job_resize(void *data)
670 {
671         Elm_Transit *transit_layout_parent;
672         struct _viewer_item *viewer_item;
673         Elm_Transit *transit_fadein;
674         struct appdata *ad;
675         Evas_Object *item;
676         int to_w, to_h;
677         QP_VI *vi;
678
679         vi = data;
680         ad = quickpanel_get_app_data();
681         if (!ad || !vi || !vi->target || !vi->extra_data_2) {
682                 ERR("Invalid parameters: %p %p %p %p", ad, vi, vi ? vi->target : NULL, vi ? vi->extra_data_2 : NULL);
683                 return;
684         }
685
686         item = vi->target;
687         to_w = vi->extra_flag_1;
688         to_h = vi->extra_flag_2;
689         viewer_item = vi->extra_data_2;
690
691         transit_layout_parent = quickpanel_list_util_get_reorder_transit(viewer_item->viewer, NULL, to_h - viewer_item->height);
692         if (transit_layout_parent != NULL) {
693                 elm_transit_del_cb_set(transit_layout_parent, _reorder_transit_del_cb, vi);
694         } else {
695                 _viewer_set_size(item, ad, to_w, to_h);
696                 quickpanel_uic_initial_resize(item,
697                                 (to_h > QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT)
698                                 ? to_h : QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT);
699         }
700
701         transit_fadein = elm_transit_add();
702         if (transit_fadein != NULL) {
703                 elm_transit_object_add(transit_fadein, item);
704                 elm_transit_effect_color_add(transit_fadein, 0, 0, 0, 0, 255, 255, 255, 255);
705                 elm_transit_duration_set(transit_fadein, 0.35);
706                 elm_transit_tween_mode_set(transit_fadein, quickpanel_vim_get_tweenmode(VI_OP_INSERT));
707                 elm_transit_del_cb_set(transit_fadein, quickpanel_vi_done_cb_for_transit, vi);
708                 elm_transit_objects_final_state_keep_set(transit_fadein, EINA_TRUE);
709
710                 if (transit_layout_parent != NULL) {
711                         elm_transit_chain_transit_add(transit_layout_parent, transit_fadein);
712                         elm_transit_go(transit_layout_parent);
713                 } else {
714                         elm_transit_go(transit_fadein);
715                 }
716         } else {
717                 ERR("Failed to create all the transit");
718                 quickpanel_vi_done(vi);
719         }
720 }
721
722 static Eina_Bool _anim_job_cb(void *data)
723 {
724         QP_VI *vi;
725         int i;
726         static qp_vi_op_table anim_job_table[] = {
727                 {
728                         .op_type = VI_OP_RESIZE,
729                         .handler = _anim_job_resize,
730                 },
731                 {
732                         .op_type = VI_OP_NONE,
733                         .handler = NULL,
734                 },
735         };
736
737         vi = data;
738         if (!vi) {
739                 ERR("Invalid parameter");
740                 return EINA_FALSE;
741         }
742
743         for (i = 0; anim_job_table[i].op_type != VI_OP_NONE; i++) {
744                 if (anim_job_table[i].op_type != vi->op_type) {
745                         continue;
746                 }
747
748                 anim_job_table[i].handler(vi);
749                 break;
750         }
751
752         return EINA_TRUE;
753 }
754
755 static void _anim_done_resize(void *data)
756 {
757         QP_VI *vi;
758         struct _viewer_item *viewer_item;
759         struct appdata *ad;
760         Evas_Object *item;
761
762         vi = data;
763         if (!vi) {
764                 ERR("Invalid parameter");
765                 return;
766         }
767
768         ad = quickpanel_get_app_data();
769         if (!ad) {
770                 ERR("Invalid ad");
771                 return;
772         }
773
774         item = vi->target;
775         if (!item) {
776                 ERR("Invalid target");
777                 return;
778         }
779
780         viewer_item = vi->extra_data_2;
781         if (!viewer_item) {
782                 ERR("viewer_item is null");
783                 return;
784         }
785
786         viewer_item->width = vi->extra_flag_1;
787         viewer_item->height = vi->extra_flag_2;
788
789         _viewer_set_size(item, ad, viewer_item->width, viewer_item->height);
790         quickpanel_uic_initial_resize(item,
791                         (viewer_item->height > QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT)
792                         ? viewer_item->height : QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT);
793         evas_object_color_set(item, 255, 255, 255, 255);
794 }
795
796 static Eina_Bool _anim_done_cb(void *data)
797 {
798         QP_VI *vi;
799         int i;
800         static qp_vi_op_table anim_done_table[] = {
801                 {
802                         .op_type = VI_OP_RESIZE,
803                         .handler = _anim_done_resize,
804                 },
805                 {
806                         .op_type = VI_OP_NONE,
807                         .handler = NULL,
808                 },
809         };
810
811         vi = data;
812         if (!vi) {
813                 ERR("Invalid parameter");
814                 return EINA_FALSE;
815         }
816
817         for (i = 0; anim_done_table[i].op_type != VI_OP_NONE; i++) {
818                 if (anim_done_table[i].op_type != vi->op_type) {
819                         continue;
820                 }
821
822                 anim_done_table[i].handler(vi);
823                 break;
824         }
825
826         return EINA_TRUE;
827 }
828
829 static void _minictrl_resize_vi(Evas_Object *list, struct _viewer_item *item, int to_w, int to_h)
830 {
831         QP_VI *vi;
832
833         if (!list || !item) {
834                 ERR("Invalid parameter: list: %p, item: %p", list, item);
835                 return;
836         }
837
838         vi = quickpanel_vi_new_with_data(
839                         VI_OP_RESIZE,
840                         QP_ITEM_TYPE_MINICTRL_MIDDLE,
841                         list,
842                         item->viewer,
843                         _anim_init_cb,
844                         _anim_job_cb,
845                         _anim_done_cb,
846                         _anim_done_cb,
847                         NULL, /* vi == NULL */
848                         item,
849                         to_w,
850                         to_h);
851
852         if (vi) {
853                 quickpanel_vi_start(vi);
854         } else {
855                 ERR("Unable to create 'vi'");
856         }
857 }
858
859 static void _minictrl_update(const char *name, unsigned int width, unsigned int height, void *data)
860 {
861         struct appdata *ad = data;
862         struct _viewer_item *found = NULL;
863
864         if (!s_info.prov_table || !ad) {
865                 ERR("name: %s, table: %p, ad: %p", name, s_info.prov_table, ad);
866                 return;
867         }
868
869         found = g_hash_table_lookup(s_info.prov_table, name);
870         if (!found) {
871                 WARN("unknown provider name : %s", name);
872                 return;
873         }
874
875         if (found->viewer) {
876                 if (found->height != height || found->width != width) {
877                         _minictrl_resize_vi(ad->list, found, width, height);
878                 } else {
879                         _viewer_set_size(found->viewer, ad, width, height);
880                         quickpanel_uic_initial_resize(found->viewer,
881                                         (height > QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT)
882                                         ? height : QP_THEME_LIST_ITEM_MINICONTRL_HEIGHT + QP_THEME_LIST_ITEM_SEPERATOR_HEIGHT);
883                 }
884         }
885 }
886
887 static void _minictrl_lock(const char *name)
888 {
889         struct _viewer_item *found;
890
891         if (!s_info.prov_table) {
892                 ERR("table is empty: %s", name);
893                 return;
894         }
895
896         DBG("minictrl_lock %s", name);
897         found = g_hash_table_lookup(s_info.prov_table, name);
898         if (!found) {
899                 WARN("unknown provider name : %s", name);
900                 return;
901         }
902
903         if (found->viewer) {
904                 struct _viewer_item *vit;
905
906                 vit = evas_object_data_del(_get_minictrl_obj(found->viewer), MINICONTROL_VIEW_DATA);
907                 if (vit) {
908                         vit->deletable = 0;
909                         evas_object_data_set(_get_minictrl_obj(found->viewer), MINICONTROL_VIEW_DATA, vit);
910                 } else {
911                         WARN("vit is NULL");
912                 }
913         }
914 }
915
916 static void _mctrl_viewer_event_cb(minicontrol_event_e event, const char *name, bundle *event_arg, void *data)
917 {
918         struct appdata *ad;
919         int ret;
920         int *width;
921         int *height;
922         int _width;
923         int _height;
924         size_t bundle_size;
925
926         if (!data || !name) {
927                 ERR("Invalid parameter");
928                 return;
929         }
930
931         ad = data;
932
933         if (_viewer_check(name) == 0) {
934                 ERR("%s: ignored", name);
935                 return;
936         }
937
938         if ((int)event == MINICONTROL_EVENT_REQUEST_LOCK) {
939                 /**
940                  * This event type is extra one. not in the enumeration list.
941                  */
942                 _minictrl_lock(name);
943         } else {
944                 switch (event) {
945                 case MINICONTROL_EVENT_START:
946                         ret = bundle_get_byte(event_arg, MINICONTROL_BUNDLE_KEY_WIDTH, (void **)&width, &bundle_size);
947                         if (ret != BUNDLE_ERROR_NONE || bundle_size != sizeof(int)) {
948                                 ERR("Failed to get bundle value(width) %d : %d", ret, bundle_size);
949                                 _width = 0;
950                                 width = &_width;
951                         }
952
953                         ret = bundle_get_byte(event_arg, MINICONTROL_BUNDLE_KEY_HEIGHT, (void **)&height, &bundle_size);
954                         if (ret != BUNDLE_ERROR_NONE || bundle_size != sizeof(int)) {
955                                 ERR("Failed to get bundle value(height) : %d", ret);
956                                 _height = 0;
957                                 height = &_height;
958                         }
959
960                         DBG("Name: %s, Size: %dx%d", name, *width, *height);
961                         _minictrl_add(name, *width, *height, data);
962                         break;
963                 case MINICONTROL_EVENT_RESIZE:
964                         ret = bundle_get_byte(event_arg, MINICONTROL_BUNDLE_KEY_WIDTH, (void **)&width, &bundle_size);
965                         if (ret != BUNDLE_ERROR_NONE || bundle_size != sizeof(int)) {
966                                 ERR("Failed to get bundle value(width) %d : %d", ret, bundle_size);
967                                 _width = 0;
968                                 width = &_width;
969                         }
970
971                         ret = bundle_get_byte(event_arg, MINICONTROL_BUNDLE_KEY_HEIGHT, (void **)&height, &bundle_size);
972                         if (ret != BUNDLE_ERROR_NONE || bundle_size != sizeof(int)) {
973                                 ERR("Failed to get bundle value(height) : %d", ret);
974                                 _height = 0;
975                                 height = &_height;
976                         }
977
978                         DBG("Name: %s, Size: %dx%d", name, *width, *height);
979                         _minictrl_update(name, *width, *height, data);
980                         break;
981                 case MINICONTROL_EVENT_STOP:
982                         _minictrl_remove(name, data);
983                         break;
984                 case MINICONTROL_EVENT_REQUEST_HIDE:
985                         quickpanel_uic_close_quickpanel(true, 0);
986                         break;
987                 case MINICONTROL_EVENT_REQUEST_ANGLE:
988                         if (ad->list != NULL) {
989                                 SERR("need to broadcasting angle by %s ", name, event);
990                                 quickpanel_minictrl_rotation_report(name, ad->angle);
991                         }
992                         break;
993                 default:
994                         break;
995                 }
996         }
997 }
998
999 static int _init(void *data)
1000 {
1001         minicontrol_error_e ret;
1002
1003         if (!data) {
1004                 ERR("Invalid parameter");
1005                 return QP_FAIL;
1006         }
1007
1008         s_info.prov_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1009                         (GDestroyNotify)g_free,
1010                         (GDestroyNotify)_viewer_item_free);
1011
1012         ret = minicontrol_viewer_set_event_cb(_mctrl_viewer_event_cb, data);
1013         if (ret != MINICONTROL_ERROR_NONE) {
1014                 ERR("fail to minicontrol_viewer_set_event_cb()- %d", ret);
1015                 return QP_FAIL;
1016         }
1017
1018         return QP_OK;
1019 }
1020
1021 static int _fini(void *data)
1022 {
1023         minicontrol_error_e ret;
1024
1025         ret = minicontrol_viewer_unset_event_cb();
1026
1027         if (ret != MINICONTROL_ERROR_NONE) {
1028                 ERR("fail to minicontrol_viewer_unset_event_cb()- %d", ret);
1029         }
1030
1031         if (s_info.prov_table) {
1032                 g_hash_table_destroy(s_info.prov_table);
1033                 s_info.prov_table = NULL;
1034         }
1035
1036         return QP_OK;
1037 }
1038
1039 static int _suspend(void *data)
1040 {
1041         struct appdata *ad;
1042
1043         ad = data;
1044         if (!ad) {
1045                 ERR("Invalid parameter");
1046                 return QP_FAIL;
1047         }
1048
1049         if (ad->list != NULL) {
1050                 _viewer_unfreeze(ad->scroller);
1051         }
1052
1053         return QP_OK;
1054 }
1055
1056 static int _resume(void *data)
1057 {
1058         struct appdata *ad;
1059
1060         ad = data;
1061         if (!ad) {
1062                 ERR("Invalid parameter");
1063                 return QP_FAIL;
1064         }
1065
1066         if (ad->list != NULL) {
1067                 _viewer_unfreeze(ad->scroller);
1068         }
1069
1070         return QP_OK;
1071 }
1072
1073 HAPI void quickpanel_minictrl_rotation_report(const char* name, int angle)
1074 {
1075         bundle *event_arg_bundle;
1076
1077         if (!name) {
1078                 ERR("Invalid parameter");
1079                 return;
1080         }
1081
1082         SINFO("minicontrol name:%s rotation:%d", name, angle);
1083
1084         if (s_info.prov_table == NULL) {
1085                 return;
1086         }
1087
1088         if (g_hash_table_size(s_info.prov_table) <= 0) {
1089                 return;
1090         }
1091
1092         event_arg_bundle = bundle_create();
1093         if (event_arg_bundle) {
1094                 char bundle_value_buffer[BUNDLE_BUFFER_LENGTH] = { 0, };
1095
1096                 snprintf(bundle_value_buffer, sizeof(bundle_value_buffer) - 1, "%d", angle);
1097                 bundle_add_str(event_arg_bundle, "angle", bundle_value_buffer);
1098                 minicontrol_viewer_send_event(name, MINICONTROL_EVENT_REPORT_ANGLE, event_arg_bundle);
1099                 bundle_free(event_arg_bundle);
1100         }
1101 }
1102
1103
1104 static void _minictrl_send_view_event_cb(gpointer key, gpointer value, gpointer user_data)
1105 {
1106         if (!key) {
1107                 ERR("Key is null");
1108                 return;
1109         }
1110
1111         bundle *event_arg_bundle;
1112
1113         event_arg_bundle = bundle_create();
1114         if (event_arg_bundle) {
1115                 minicontrol_viewer_event_e event;
1116
1117                 event = (minicontrol_viewer_event_e)user_data;
1118                 minicontrol_viewer_send_event(key, event, event_arg_bundle);
1119                 bundle_free(event_arg_bundle);
1120         }
1121 }
1122
1123 static void _minictrl_opened(void *data)
1124 {
1125         DBG("");
1126         g_hash_table_foreach(s_info.prov_table, _minictrl_send_view_event_cb, (gpointer)MINICONTROL_VIEWER_EVENT_SHOW);
1127 }
1128
1129 static void _minictrl_closed(void *data)
1130 {
1131         DBG("");
1132         g_hash_table_foreach(s_info.prov_table, _minictrl_send_view_event_cb, (gpointer)MINICONTROL_VIEWER_EVENT_HIDE);
1133 }
1134
1135 QP_Module minictrl = {
1136         .name = "minictrl",
1137         .init = _init,
1138         .fini = _fini,
1139         .suspend = _suspend,
1140         .resume = _resume,
1141         .hib_enter = NULL,
1142         .hib_leave = NULL,
1143         .lang_changed = NULL,
1144         .refresh = NULL,
1145         .get_height = NULL,
1146         .qp_opened = _minictrl_opened,
1147         .qp_closed = _minictrl_closed,
1148 };
1149
1150 /* End of a file */