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