e_desk_area: remove use_desk_area config value
[platform/upstream/enlightenment.git] / src / bin / services / e_service_quickpanel.c
1 #include "services/e_service_quickpanel_intern.h"
2 #include "e_service_gesture_intern.h"
3 #include "services/e_service_region_intern.h"
4 #include "e_pixmap_intern.h"
5 #include "e_policy_intern.h"
6 #include "e_policy_wl_intern.h"
7 #include "e_policy_private_data.h"
8 #include "e_client_intern.h"
9 #include "e_comp_object_intern.h"
10 #include "e_layout_intern.h"
11
12 #define SMART_NAME            "quickpanel_object"
13 #define INTERNAL_ENTRY                       \
14    Mover_Data *md;                           \
15    md = evas_object_smart_data_get(obj);     \
16    if (!md) return
17
18 #define QP_SHOW(qp)                          \
19 do                                           \
20 {                                            \
21    if (qp->ec && !qp->ec->visible)           \
22      {                                       \
23         qp->show_block = EINA_FALSE;         \
24         qp->ec->visible = EINA_TRUE;         \
25         evas_object_show(qp->ec->frame);     \
26                                              \
27         if (qp->bg_rect)                     \
28           {                                  \
29              ELOGF("QUICKPANEL", "SHOW BG_RECT...", qp->ec);      \
30              evas_object_stack_below(qp->bg_rect, qp->ec->frame); \
31              evas_object_show(qp->bg_rect);  \
32           }                                  \
33      }                                       \
34 } while (0)
35
36 #define QP_HIDE(qp)                          \
37 do                                           \
38 {                                            \
39    if (qp->ec && qp->ec->visible)            \
40      {                                       \
41         qp->show_block = EINA_TRUE;          \
42         qp->ec->visible = EINA_FALSE;        \
43         evas_object_hide(qp->ec->frame);     \
44                                              \
45         if (qp->bg_rect)                     \
46           {                                  \
47              ELOGF("QUICKPANEL", "HIDE BG_RECT...", qp->ec);  \
48              evas_object_hide(qp->bg_rect);  \
49           }                                  \
50      }                                       \
51 } while (0)
52
53 #define QP_VISIBLE_SET(qp, vis)              \
54 do                                           \
55 {                                            \
56    if (vis) QP_SHOW(qp);                     \
57    else     QP_HIDE(qp);                     \
58 } while(0)
59
60 #define BACKEND_FUNC_CALL(f, ...)            \
61 do                                           \
62 {                                            \
63    if ((qp_mgr_funcs) &&                     \
64        (qp_mgr_funcs->f))                    \
65      {                                       \
66         qp_mgr_funcs->f(__VA_ARGS__);        \
67         return;                              \
68      }                                       \
69 } while(0)
70
71 #define BACKEND_FUNC_CALL_RET(f, ...)        \
72 do                                           \
73 {                                            \
74    if ((qp_mgr_funcs) &&                     \
75        (qp_mgr_funcs->f))                    \
76      {                                       \
77         return qp_mgr_funcs->f(__VA_ARGS__); \
78      }                                       \
79 } while(0)
80
81 typedef struct _E_Policy_Quickpanel E_Policy_Quickpanel;
82 typedef struct _Mover_Data Mover_Data;
83
84 typedef struct _E_QP_Client E_QP_Client;
85
86 struct _E_Policy_Quickpanel
87 {
88    E_Client *ec;
89    E_Zone *zone;
90    E_Service_Quickpanel_Type type;
91
92    E_Client *below;
93    E_Client *stacking;
94    Evas_Object *mover;
95    Evas_Object *indi_obj;
96    Evas_Object *handler_obj;
97    Evas_Object *bg_rect;
98
99    Eina_List *intercept_hooks;
100    Eina_List *hooks;
101    Eina_List *events;
102    Ecore_Idle_Enterer *idle_enterer;
103    Ecore_Event_Handler *buf_change_hdlr;
104
105    struct
106    {
107       int x, y;
108       unsigned int timestamp;
109       float accel;
110    } mouse_info;
111
112    struct
113    {
114       Ecore_Animator *animator;
115       E_Service_Quickpanel_Effect_Type type;
116       int x, y, from, to;
117       int disable_ref;
118       Eina_Bool final_visible_state;
119       Eina_Bool active;
120    } effect;
121
122    struct
123    {
124       Eina_Bool below;
125    } changes;
126
127    E_Policy_Angle_Map rotation;
128    E_Maximize saved_maximize;
129
130    Eina_Bool show_block;
131    Eina_Bool need_scroll_update;
132    Eina_Bool scroll_lock;
133
134    struct
135    {
136       int x, y, w, h;
137    } geom;
138
139    E_Client *gesture_target;
140 };
141
142 struct _Mover_Data
143 {
144    E_Policy_Quickpanel *qp;
145    E_Client *ec;
146
147    Evas_Object *smart_obj; //smart object
148    Evas_Object *qp_layout_obj; // quickpanel's e_layout_object
149    Evas_Object *handler_mirror_obj; // quickpanel handler mirror object
150    Evas_Object *base_clip; // clipper for quickapnel base object
151    Evas_Object *handler_clip; // clipper for quickpanel handler object
152
153    Eina_Rectangle handler_rect;
154 };
155
156 struct _E_QP_Client
157 {
158    E_Client *ec;
159    E_Quickpanel_Type type;
160    int ref;
161    struct
162    {
163       Eina_Bool vis;
164       E_Quickpanel_Client_Scroll_State scrollable;
165    } hint;
166 };
167
168 static Eina_List *qp_services = NULL; /* list of E_Policy_Quickpanel for quickpanel services */
169 static Evas_Smart *_mover_smart = NULL;
170 static Eina_Bool _changed = EINA_FALSE;
171 static E_QP_Mgr_Funcs *qp_mgr_funcs = NULL;
172
173 Eina_List *qp_clients = NULL; /* list of E_QP_Client */
174
175 static void          _e_qp_srv_effect_update(E_Policy_Quickpanel *qp, int x, int y);
176 static E_QP_Client * _e_qp_client_ec_get(E_Client *ec, E_Quickpanel_Type type);
177 static Eina_Bool     _e_qp_client_scrollable_update(E_Policy_Quickpanel *qp);
178 static Eina_Bool     _e_qp_client_scrollable_state_set(E_Client *ec, E_Quickpanel_Type type, E_Quickpanel_Client_Scroll_State state);
179 static E_Quickpanel_Client_Scroll_State _e_qp_client_scrollable_state_get(E_Client *ec, E_Quickpanel_Type type);
180
181 static void          _quickpanel_client_evas_cb_show(void *data, Evas *evas, Evas_Object *obj, void *event);
182 static void          _quickpanel_client_evas_cb_hide(void *data, Evas *evas, Evas_Object *obj, void *event);
183 static void          _quickpanel_client_evas_cb_move(void *data, Evas *evas, Evas_Object *obj, void *event);
184
185 static Eina_Bool     _quickpanel_check_skip_client(E_Client *ec);
186
187 inline static Eina_Bool
188 _e_qp_srv_is_effect_finish_job_started(E_Policy_Quickpanel *qp)
189 {
190    return !!qp->effect.animator;
191 }
192
193 inline static Eina_Bool
194 _e_qp_srv_effect_final_visible_state_get(E_Policy_Quickpanel *qp)
195 {
196    return !!qp->effect.final_visible_state;
197 }
198
199 inline static Eina_Bool
200 _e_qp_srv_is_effect_running(E_Policy_Quickpanel *qp)
201 {
202    return !!qp->effect.active;
203 }
204
205 /* look for E_Policy_Quickpanel instance of qp service
206  * which is same as given ec
207  *
208  * @param ec window of qp service
209  * @return E_Policy_Quickpanel instance of qp service
210  */
211 static E_Policy_Quickpanel *
212 _quickpanel_service_get(E_Client *ec)
213 {
214    E_Policy_Quickpanel *qp;
215    Eina_List *l;
216
217    EINA_LIST_FOREACH(qp_services, l, qp)
218      if (qp->ec == ec)
219        return qp;
220
221    return NULL;
222 }
223
224 /* look for E_Policy_Quickpanel instance of qp service
225  * which has same type as given qp_client
226  *
227  * @param qp_client instance of qp client
228  * @return instance of qp service
229  */
230 static E_Policy_Quickpanel *
231 _quickpanel_get_with_client_type(E_QP_Client *qp_client)
232 {
233    E_Policy_Quickpanel *qp;
234    Eina_List *l;
235
236    /* look for a qp service which has same type as given qp client */
237    EINA_LIST_FOREACH(qp_services, l, qp)
238      if (qp->type == (E_Service_Quickpanel_Type)qp_client->type)
239        return qp;
240
241    return NULL;
242 }
243
244 static void
245 _mover_intercept_show(void *data, Evas_Object *obj)
246 {
247    Mover_Data *md;
248    E_Client *ec;
249    E_Desk *desk;
250    Evas *e;
251    E_Map *map;
252    E_Map *map2;
253    Evas_Object *effect_obj;
254    E_Policy_Quickpanel *qp;
255
256    md = data;
257    qp = md->qp;
258    ec = md->ec;
259
260    /* force update */
261    e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
262    e_comp_object_dirty(ec->frame);
263    e_comp_object_render(ec->frame);
264
265    // desk-zoom-set apply map on all e_desk's smart_data(clients)
266    // to properly pack a quickpanel window on the mover's e_layout_object
267    // (to became a member of mover) it shouldn't be in e_desk's clists.
268    // because mover (also smart obj) is a member of e_desk
269    // otherwize, desk-zoom will mutiplied on a ec again.
270    if (e_config->qp_add_on_desk_smart)
271      {
272         desk = e_desk_current_get(qp->zone);
273         e_desk_client_del(desk, ec);
274      }
275
276    e_layout_pack(md->qp_layout_obj, ec->frame);
277
278   // create base_clip
279    e = evas_object_evas_get(obj);
280    md->base_clip = evas_object_rectangle_add(e);
281    e_layout_pack(md->qp_layout_obj, md->base_clip);
282    e_layout_child_move(md->base_clip, 0, 0);
283    e_layout_child_resize(md->base_clip, ec->w, ec->h);
284    evas_object_color_set(md->base_clip, 255, 255, 255, 255);
285    evas_object_show(md->base_clip);
286    evas_object_clip_set(ec->frame, md->base_clip);
287
288    // create handler_mirror_obj
289    md->handler_mirror_obj =  e_comp_object_util_mirror_add(ec->frame);
290    effect_obj = e_comp_object_effect_object_get(ec->frame);
291    if (evas_object_map_enable_get(effect_obj))
292      {
293         map = e_comp_object_map_get(effect_obj);
294         map2 = e_map_dup(map);
295         e_comp_object_map_set(md->handler_mirror_obj, map2);
296         e_comp_object_map_enable_set(md->handler_mirror_obj, EINA_TRUE);
297         e_map_free(map2);
298         e_map_free(map);
299      }
300
301    e_layout_pack(md->qp_layout_obj, md->handler_mirror_obj);
302    e_layout_child_move(md->handler_mirror_obj, 0, 0);
303    e_layout_child_resize(md->handler_mirror_obj, ec->w, ec->h);
304    evas_object_show(md->handler_mirror_obj);
305
306    // create handler_clip
307    md->handler_clip = evas_object_rectangle_add(e);
308    e_layout_pack(md->qp_layout_obj, md->handler_clip);
309    e_layout_child_move(md->handler_clip, md->handler_rect.x, md->handler_rect.y);
310    e_layout_child_resize(md->handler_clip, md->handler_rect.w, md->handler_rect.h);
311    if (e_config->qp_handler.use_alpha)
312      evas_object_color_set(md->handler_clip, 255, 255, 255, e_config->qp_handler.alpha);
313    else
314      evas_object_color_set(md->handler_clip, 255, 255, 255, 255);
315    evas_object_show(md->handler_clip);
316    evas_object_clip_set(md->handler_mirror_obj, md->handler_clip);
317
318    evas_object_show(obj);
319
320    if (e_config->qp_add_on_desk_smart)
321      {
322         desk = e_desk_current_get(qp->zone);
323         e_desk_smart_member_add(desk, obj);
324      }
325 }
326
327 static void
328 _mover_smart_add(Evas_Object *obj)
329 {
330    Mover_Data *md;
331
332    md = E_NEW(Mover_Data, 1);
333    if (EINA_UNLIKELY(!md))
334      return;
335
336    md->smart_obj = obj;
337    md->qp_layout_obj = e_layout_add(evas_object_evas_get(obj));
338    evas_object_color_set(md->qp_layout_obj, 255, 255, 255, 255);
339    evas_object_smart_member_add(md->qp_layout_obj, md->smart_obj);
340
341    evas_object_smart_data_set(obj, md);
342
343    evas_object_move(obj, -1 , -1);
344    evas_object_intercept_show_callback_add(obj, _mover_intercept_show, md);
345 }
346
347 static void
348 _mover_smart_del(Evas_Object *obj)
349 {
350    E_Client *ec;
351    E_Desk *desk;
352    E_Policy_Quickpanel *qp;
353
354    INTERNAL_ENTRY;
355
356    qp = md->qp;
357    ec = md->ec;
358    if (md->base_clip)
359      {
360         evas_object_clip_unset(md->base_clip);
361         e_layout_unpack(md->base_clip);
362         evas_object_del(md->base_clip);
363      }
364    if (md->handler_clip)
365      {
366         evas_object_clip_unset(md->handler_clip);
367         e_layout_unpack(md->handler_clip);
368         evas_object_del(md->handler_clip);
369      }
370    if (md->handler_mirror_obj)
371      {
372         e_layout_unpack(md->handler_mirror_obj);
373         evas_object_del(md->handler_mirror_obj);
374      }
375
376    if (md->qp_layout_obj) evas_object_del(md->qp_layout_obj);
377
378    evas_object_color_set(ec->frame, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity);
379
380    e_comp_client_override_del(ec);
381
382    /* force update
383     * we need to force update 'E_Client' here even if update only evas_object,
384     * because our render loop would not be started by chaning evas object,
385     * we need to make a change on the 'E_Client'. */
386    e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
387    e_comp_object_dirty(ec->frame);
388    e_comp_object_render(ec->frame);
389
390    e_layout_unpack(ec->frame);
391
392    if (e_config->qp_add_on_desk_smart)
393      {
394         desk = e_desk_current_get(qp->zone);
395         e_desk_smart_member_add(desk, ec->frame);
396      }
397
398    free(md);
399 }
400
401 static void
402 _mover_smart_show(Evas_Object *obj)
403 {
404    INTERNAL_ENTRY;
405
406    evas_object_show(md->qp_layout_obj);
407 }
408
409 static void
410 _mover_smart_hide(Evas_Object *obj)
411 {
412    INTERNAL_ENTRY;
413
414    evas_object_hide(md->qp_layout_obj);
415 }
416
417 static void
418 _mover_smart_move(Evas_Object *obj, int x, int y)
419 {
420    INTERNAL_ENTRY;
421
422    evas_object_move(md->qp_layout_obj, x, y);
423 }
424
425 static void
426 _mover_smart_resize(Evas_Object *obj, int w, int h)
427 {
428    INTERNAL_ENTRY;
429
430    e_layout_virtual_size_set(md->qp_layout_obj, w, h);
431    evas_object_resize(md->qp_layout_obj, w, h);
432 }
433
434 static void
435 _mover_smart_init(void)
436 {
437    if (_mover_smart) return;
438    {
439       static const Evas_Smart_Class sc =
440       {
441          SMART_NAME,
442          EVAS_SMART_CLASS_VERSION,
443          _mover_smart_add,
444          _mover_smart_del,
445          _mover_smart_move,
446          _mover_smart_resize,
447          _mover_smart_show,
448          _mover_smart_hide,
449          NULL, /* color_set */
450          NULL, /* clip_set */
451          NULL, /* clip_unset */
452          NULL, /* calculate */
453          NULL, /* member_add */
454          NULL, /* member_del */
455
456          NULL, /* parent */
457          NULL, /* callbacks */
458          NULL, /* interfaces */
459          NULL  /* data */
460       };
461       _mover_smart = evas_smart_class_new(&sc);
462    }
463 }
464
465 static Evas_Object *
466 _e_qp_srv_mover_new(E_Policy_Quickpanel *qp)
467 {
468    Evas_Object *mover;
469    Mover_Data *md;
470    int x, y, w, h;
471    E_Desk *desk;
472    int tx, ty;
473
474    e_comp_client_override_add(qp->ec);
475
476    _mover_smart_init();
477    mover = evas_object_smart_add(evas_object_evas_get(qp->ec->frame), _mover_smart);
478
479    /* Should setup 'md' before call evas_object_show() */
480    md = evas_object_smart_data_get(mover);
481    EINA_SAFETY_ON_NULL_RETURN_VAL(md, NULL);
482
483    md->ec = qp->ec;
484
485    evas_object_layer_set(md->smart_obj, qp->ec->layer);
486
487    e_service_region_rectangle_get(qp->handler_obj, qp->rotation, &x, &y, &w, &h);
488    EINA_RECTANGLE_SET(&md->handler_rect, x, y, w, h);
489
490    tx = qp->zone->x;
491    ty = qp->zone->y;
492    desk = e_desk_current_get(qp->zone);
493    if (desk)
494      {
495         tx = desk->geom.x;
496         ty = desk->geom.y;
497      }
498
499    evas_object_move(mover, tx, ty);
500    evas_object_resize(mover, qp->ec->w, qp->ec->h);
501    evas_object_show(mover);
502
503    qp->mover = mover;
504
505    return mover;
506 }
507
508 static Eina_Bool
509 _e_qp_srv_mover_object_relocate(E_Policy_Quickpanel *qp, int x, int y)
510 {
511    E_Client *ec;
512    Mover_Data *md;
513    int tx, ty, tw, th;
514    E_Map *map;
515    E_Map *map2 = NULL;
516    Evas_Object *effect_obj;
517    int map_count, i;
518
519    ec = qp->ec;
520
521    md = evas_object_smart_data_get(qp->mover);
522    EINA_SAFETY_ON_NULL_RETURN_VAL(md, EINA_FALSE);
523
524    effect_obj = e_comp_object_effect_object_get(ec->frame);
525    if (evas_object_map_enable_get(effect_obj))
526      {
527         map = e_comp_object_map_get(effect_obj);
528         map2 = e_map_dup(map);
529         e_map_free(map);
530      }
531    else
532      {
533         e_comp_object_map_set(md->handler_mirror_obj, NULL);
534         e_comp_object_map_enable_set(md->handler_mirror_obj, EINA_FALSE);
535      }
536
537    evas_object_geometry_get(qp->mover, &tx, &ty, &tw, &th);
538
539    switch (qp->rotation)
540      {
541       case E_POLICY_ANGLE_MAP_90:
542          if (x < tx) goto ret_false;
543          if ((x + md->handler_rect.w) > (tx+tw)) goto ret_false;
544
545          e_layout_child_move(md->base_clip, 0, 0);
546          e_layout_child_resize(md->base_clip, x - tx, ec->h);
547
548          e_layout_child_move(md->handler_mirror_obj, x - tx - ec->w + md->handler_rect.w, 0);
549          e_layout_child_move(md->handler_clip, x - tx, 0);
550
551          if (map2)
552            {
553               map_count = e_map_count_get(map2);
554               for (i = 0; i < map_count; i++)
555                 {
556                    int mx, my, mz;
557                    e_map_point_coord_get(map2, i, &mx, &my, &mz);
558                    e_map_point_coord_set(map2, i, mx + (x - tx - ec->w + md->handler_rect.w), my, mz);
559                 }
560            }
561          break;
562
563       case E_POLICY_ANGLE_MAP_180:
564          if (y > (ty+th)) goto ret_false;
565          if ((y - md->handler_rect.h) < ty) goto ret_false;
566
567          e_layout_child_move(md->base_clip, 0, y - ty);
568          e_layout_child_resize(md->base_clip, ec->w, ty + ec->h - y);
569
570          e_layout_child_move(md->handler_mirror_obj, 0, y - ty - md->handler_rect.h);
571          e_layout_child_move(md->handler_clip, 0, y - ty - md->handler_rect.h);
572
573          if (map2)
574            {
575               map_count = e_map_count_get(map2);
576               for (i = 0; i < map_count; i++)
577                 {
578                    int mx, my, mz;
579                    e_map_point_coord_get(map2, i, &mx, &my, &mz);
580                    e_map_point_coord_set(map2, i, mx, my + (y - ty - md->handler_rect.h), mz);
581                 }
582            }
583          break;
584
585       case E_POLICY_ANGLE_MAP_270:
586          if ((x + md->handler_rect.w) > (tx+tw)) goto ret_false;
587          if ((x - md->handler_rect.w) < tx) goto ret_false;
588
589          e_layout_child_move(md->base_clip, x - tx, 0);
590          e_layout_child_resize(md->base_clip, tx + ec->w - x, ec->h);
591
592          e_layout_child_move(md->handler_mirror_obj, x - tx - md->handler_rect.w, 0);
593          e_layout_child_move(md->handler_clip, x - tx - md->handler_rect.w, 0);
594
595          if (map2)
596            {
597               map_count = e_map_count_get(map2);
598               for (i = 0; i < map_count; i++)
599                 {
600                    int mx, my, mz;
601                    e_map_point_coord_get(map2, i, &mx, &my, &mz);
602                    e_map_point_coord_set(map2, i, mx + (x - tx - md->handler_rect.w), my, mz);
603                 }
604            }
605          break;
606
607       default:
608          if (y < ty) goto ret_false;
609          if ((y + md->handler_rect.h) > (ty+th)) goto ret_false;
610
611          e_layout_child_move(md->base_clip, 0, 0);
612          e_layout_child_resize(md->base_clip, ec->w, y - ty);
613
614          e_layout_child_move(md->handler_mirror_obj, 0, y - ty - ec->h + md->handler_rect.h);
615          e_layout_child_move(md->handler_clip, 0, y - ty);
616
617          if (map2)
618            {
619               map_count = e_map_count_get(map2);
620               for (i = 0; i < map_count; i++)
621                 {
622                    int mx, my, mz;
623                    e_map_point_coord_get(map2, i, &mx, &my, &mz);
624                    e_map_point_coord_set(map2, i, mx, my + (y - ty - ec->h + md->handler_rect.h), mz);
625                 }
626            }
627      }
628
629    if (map2)
630      {
631         e_comp_object_map_set(md->handler_mirror_obj, map2);
632         e_comp_object_map_enable_set(md->handler_mirror_obj, EINA_TRUE);
633         e_map_free(map2);
634      }
635
636    return EINA_TRUE;
637
638 ret_false:
639    if (map2) e_map_free(map2);
640    return EINA_FALSE;
641 }
642
643 static void
644 _e_qp_srv_mover_cb_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
645 {
646    E_Policy_Quickpanel *qp;
647
648    qp = data;
649    QP_VISIBLE_SET(qp, qp->effect.final_visible_state);
650    E_FREE_FUNC(qp->effect.animator, ecore_animator_del);
651 }
652
653 static void
654 _e_qp_srv_event_free(void *d EINA_UNUSED, E_Event_Client *ev)
655 {
656    e_object_unref(E_OBJECT(ev->ec));
657    E_FREE(ev);
658 }
659
660 static void
661 _e_qp_srv_visible_state_change_event(E_Client *ec, int vis_state)
662 {
663    E_Event_Client_Property *ev;
664
665    if (!ec) return;
666
667    ev = E_NEW(E_Event_Client_Property, 1);
668    if (!ev) return;
669
670    ev->ec = ec;
671    ev->property = vis_state;
672    e_object_ref(E_OBJECT(ec));
673    ecore_event_add(E_EVENT_POLICY_QUICKPANEL_VISIBLE_STATE_CHANGE, ev, (Ecore_End_Cb)_e_qp_srv_event_free, NULL);
674 }
675
676 static void
677 _e_qp_srv_effect_finish_job_end(E_Policy_Quickpanel *qp)
678 {
679    E_QP_Client *qp_client;
680    E_Client *focused;
681    Eina_List *l;
682
683    EINA_SAFETY_ON_NULL_RETURN(qp->ec);
684
685    if (qp->mover)
686      {
687         evas_object_event_callback_del(qp->mover, EVAS_CALLBACK_DEL, _e_qp_srv_mover_cb_del);
688         E_FREE_FUNC(qp->mover, evas_object_del);
689      }
690
691    QP_VISIBLE_SET(qp, qp->effect.final_visible_state);
692    qp->effect.active = EINA_FALSE;
693
694    e_zone_orientation_block_set(qp->zone, "quickpanel-mover", EINA_FALSE);
695
696    /* send visible event to only client with the same type of quickpanel service */
697    EINA_LIST_FOREACH(qp_clients, l, qp_client)
698      {
699         if (qp->type == (E_Service_Quickpanel_Type)qp_client->type)
700           e_tzsh_qp_state_visible_update(qp_client->ec,
701                                          qp->effect.final_visible_state,
702                                          qp_client->type);
703      }
704
705    focused = e_client_focused_get();
706    if (focused)
707      {
708         if (qp->effect.final_visible_state)
709           e_policy_aux_message_send(focused, "quickpanel_state", "shown", NULL);
710         else
711           e_policy_aux_message_send(focused, "quickpanel_state", "hidden", NULL);
712      }
713
714    if ((qp->below) &&
715        (qp->below != focused))
716      {
717         if (qp->effect.final_visible_state)
718           e_policy_aux_message_send(qp->below, "quickpanel_state", "shown", NULL);
719         else
720           e_policy_aux_message_send(qp->below, "quickpanel_state", "hidden", NULL);
721      }
722
723    if (qp->gesture_target)
724      {
725         if ((qp->gesture_target != focused) &&
726             (qp->gesture_target != qp->below))
727           {
728              if (qp->effect.final_visible_state)
729                e_policy_aux_message_send(qp->gesture_target, "quickpanel_state", "shown", NULL);
730              else
731                {
732                   e_policy_aux_message_send(qp->gesture_target, "quickpanel_state", "hidden", NULL);
733                   qp->gesture_target = NULL;
734                }
735           }
736      }
737
738    _e_qp_srv_visible_state_change_event(qp->ec, qp->effect.final_visible_state);
739
740    if (qp->effect.final_visible_state)
741      {
742         if ((!qp->ec->focused) &&
743             (qp->ec->icccm.accepts_focus || qp->ec->icccm.take_focus) &&
744             (evas_object_visible_get(qp->ec->frame) == EINA_TRUE))
745           {
746              ELOGF("QUICKPANEL", "effect finished but not focused. focus set to quickpanel", qp->ec);
747              e_client_focus_latest_set(qp->ec);
748           }
749      }
750
751    EC_CHANGED(qp->ec);
752 }
753
754 static Eina_Bool
755 _e_qp_srv_effect_finish_job_op(void *data, double pos)
756 {
757    E_Policy_Quickpanel *qp;
758    int new_x = 0, new_y = 0;
759    double progress = 0;
760
761    qp = data;
762    progress = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0, 0);
763    switch (qp->rotation)
764      {
765       case E_POLICY_ANGLE_MAP_90:
766       case E_POLICY_ANGLE_MAP_270:
767          new_x = qp->effect.from + (qp->effect.to * progress);
768          break;
769       default:
770       case E_POLICY_ANGLE_MAP_180:
771          new_y = qp->effect.from + (qp->effect.to * progress);
772          break;
773      }
774    _e_qp_srv_effect_update(qp, new_x, new_y);
775
776    if (pos == 1.0)
777      {
778         E_FREE_FUNC(qp->effect.animator, ecore_animator_del);
779
780         _e_qp_srv_effect_finish_job_end(qp);
781
782         return ECORE_CALLBACK_CANCEL;
783      }
784
785    return ECORE_CALLBACK_PASS_ON;
786 }
787
788 static void
789 _e_qp_srv_effect_finish_job_start(E_Policy_Quickpanel *qp, Eina_Bool visible)
790 {
791    int from;
792    int to;
793    double duration;
794    const double ref = 0.1;
795
796    int tw, th;
797    if (qp->effect.type == E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE)
798      {
799         tw = qp->geom.w;
800         th = qp->geom.h;
801      }
802    else
803      {
804         tw = qp->zone->w;
805         th = qp->zone->h;
806      }
807
808    switch (qp->rotation)
809      {
810       case E_POLICY_ANGLE_MAP_90:
811          from = qp->effect.x;
812          to = (visible) ? (tw - from) : (-from);
813          duration = ((double)abs(to) / ((double)tw / 2)) * ref;
814          break;
815       case E_POLICY_ANGLE_MAP_180:
816          from = qp->effect.y;
817          to = (visible) ? (-from) : (th - from);
818          duration = ((double)abs(to) / ((double)th / 2)) * ref;
819          break;
820       case E_POLICY_ANGLE_MAP_270:
821          from = qp->effect.x;
822          to = (visible) ? (-from) : (tw - from);
823          duration = ((double)abs(to) / ((double)tw / 2)) * ref;
824          break;
825       default:
826          from = qp->effect.y;
827          to = (visible) ? (th - from) : (-from);
828          duration = ((double)abs(to) / ((double)th / 2)) * ref;
829          break;
830      }
831
832    if (duration == 0.0)
833      {
834         if (visible != qp->effect.final_visible_state)
835           qp->effect.final_visible_state = visible;
836
837         _e_qp_srv_effect_finish_job_end(qp);
838         return;
839      }
840
841    /* start move effect */
842    qp->effect.from = from;
843    qp->effect.to = to;
844    qp->effect.final_visible_state = visible;
845    qp->effect.animator =
846       ecore_animator_timeline_add(duration, _e_qp_srv_effect_finish_job_op, qp);
847
848    if (qp->mover)
849      evas_object_event_callback_add(qp->mover, EVAS_CALLBACK_DEL, _e_qp_srv_mover_cb_del, qp);
850 }
851
852 static void
853 _e_qp_srv_effect_finish_job_stop(E_Policy_Quickpanel *qp)
854 {
855    if (qp->mover)
856      evas_object_event_callback_del(qp->mover, EVAS_CALLBACK_DEL, _e_qp_srv_mover_cb_del);
857    E_FREE_FUNC(qp->effect.animator, ecore_animator_del);
858
859    if (qp->effect.final_visible_state)
860      {
861         if ((qp->ec) &&
862             (!qp->ec->focused) &&
863             (qp->ec->icccm.accepts_focus || qp->ec->icccm.take_focus) &&
864             (evas_object_visible_get(qp->ec->frame) == EINA_TRUE))
865           {
866              ELOGF("QUICKPANEL", "effect finished but not focused. focus set to quickpanel", qp->ec);
867              e_client_focus_latest_set(qp->ec);
868           }
869      }
870 }
871
872
873 static Eina_Bool
874 _quickpanel_send_gesture_to_indicator(void)
875 {
876    if (e_config->qp_ignore_indicator_mode)
877      return EINA_FALSE;
878
879    E_Client *focused;
880    focused = e_client_focused_get();
881    if (focused)
882      {
883         ELOGF("TZ_IND", "INDICATOR state:%d, opacity:%d, vtype:%d",
884               focused, focused->indicator.state, focused->indicator.opacity_mode, focused->indicator.visible_type);
885
886         if (focused->indicator.state == 2) // state: on
887           {
888              if (focused->indicator.visible_type == 0) // visible: hidden
889                {
890                   /* cancel touch events sended up to now */
891                   e_comp_wl_touch_cancel();
892                   e_policy_wl_indicator_flick_send(focused);
893                   return EINA_TRUE;
894                }
895           }
896         else // state: off, unknown
897           {
898              return EINA_TRUE;
899           }
900      }
901
902    return EINA_FALSE;
903 }
904
905 static Eina_Bool
906 _e_qp_srv_visibility_eval_by_mouse_info(E_Policy_Quickpanel *qp)
907 {
908    Eina_Bool is_half;
909    int tw, th;
910    const float sensitivity = 1.5; /* hard coded. (arbitary) */
911
912    if (qp->effect.type == E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE)
913      {
914         tw = qp->geom.w;
915         th = qp->geom.h;
916      }
917    else
918      {
919         tw = qp->zone->w;
920         th = qp->zone->h;
921      }
922
923    switch (qp->rotation)
924      {
925       case E_POLICY_ANGLE_MAP_90:
926          is_half = (qp->mouse_info.x > (tw / 2));
927          break;
928       case E_POLICY_ANGLE_MAP_180:
929          is_half = (qp->mouse_info.y < (th / 2));
930          break;
931       case E_POLICY_ANGLE_MAP_270:
932          is_half = (qp->mouse_info.x < (tw / 2));
933          break;
934       case E_POLICY_ANGLE_MAP_0:
935       default:
936          is_half = (qp->mouse_info.y > (th / 2));
937          break;
938      }
939
940    if ((qp->mouse_info.accel > sensitivity) ||
941        ((qp->mouse_info.accel > -sensitivity) && is_half))
942      return EINA_TRUE;
943
944    return EINA_FALSE;
945 }
946
947 static void
948 _e_qp_srv_mouse_info_update(E_Policy_Quickpanel *qp, int x, int y, unsigned int timestamp)
949 {
950    int dp;
951    unsigned int dt;
952
953    /* Calculate the acceleration of movement,
954     * determine the visibility of quickpanel based on the result. */
955    dt = timestamp - qp->mouse_info.timestamp;
956    if (dt)
957      {
958         switch (qp->rotation)
959           {
960            case E_POLICY_ANGLE_MAP_90:
961               dp = x - qp->mouse_info.x;
962               break;
963            case E_POLICY_ANGLE_MAP_180:
964               dp = qp->mouse_info.y - y;
965               break;
966            case E_POLICY_ANGLE_MAP_270:
967               dp = qp->mouse_info.x - x;
968               break;
969            default:
970               dp = y - qp->mouse_info.y;
971               break;
972           }
973         qp->mouse_info.accel = (float)dp / (float)dt;
974      }
975
976    qp->mouse_info.x = x;
977    qp->mouse_info.y = y;
978    qp->mouse_info.timestamp = timestamp;
979 }
980
981 static void
982 _e_qp_srv_effect_start(E_Policy_Quickpanel *qp)
983 {
984    if (qp->effect.disable_ref)
985      return;
986
987    /* Pause changing zone orientation during mover object is working. */
988    e_zone_orientation_block_set(qp->zone, "quickpanel-mover", EINA_TRUE);
989
990    qp->effect.active = EINA_TRUE;
991    QP_SHOW(qp);
992    if (qp->effect.type == E_SERVICE_QUICKPANEL_EFFECT_TYPE_SWIPE)
993      _e_qp_srv_mover_new(qp);
994 }
995
996 static void
997 _e_qp_srv_qp_move(E_Policy_Quickpanel *qp, int x, int y)
998 {
999    E_Client *ec;
1000    int new_x, new_y;
1001    int dim;
1002    double weight;
1003
1004    if (!qp) return;
1005    if (!qp->ec) return;
1006
1007    ec = qp->ec;
1008
1009    new_x = 0;
1010    new_y = 0;
1011
1012    switch (qp->rotation)
1013      {
1014       case E_POLICY_ANGLE_MAP_90:
1015          new_x = x - qp->geom.w;
1016          break;
1017       case E_POLICY_ANGLE_MAP_180:
1018          new_y = y;
1019          break;
1020       case E_POLICY_ANGLE_MAP_270:
1021          new_x = x;
1022          break;
1023       default:
1024          new_y = y - qp->geom.h;
1025          if (new_y > 0) new_y = 0;
1026          break;
1027      }
1028
1029    if (qp->bg_rect)
1030      {
1031         weight = y / (double)qp->geom.h;
1032         if (weight > 1) weight = 1;
1033         else if (weight < 0) weight = 0;
1034
1035         dim = (int)(178 * weight);
1036         evas_object_color_set(qp->bg_rect, 0, 0, 0, dim);
1037      }
1038
1039    e_client_util_move_without_frame(ec, new_x, new_y);
1040 }
1041
1042 static void
1043 _e_qp_srv_effect_update(E_Policy_Quickpanel *qp, int x, int y)
1044 {
1045    Eina_Bool res;
1046
1047    res = _e_qp_srv_is_effect_running(qp);
1048    if (!res)
1049      return;
1050
1051    qp->effect.x = x;
1052    qp->effect.y = y;
1053
1054    switch (qp->effect.type)
1055      {
1056       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_SWIPE:
1057          _e_qp_srv_mover_object_relocate(qp, x, y);
1058          break;
1059       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE:
1060          _e_qp_srv_qp_move(qp, x, y);
1061          break;
1062       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_APP_CUSTOM:
1063          ERR("Undefine behavior for APP_CUSTOM type");
1064          break;
1065       default:
1066          ERR("Unknown effect type");
1067          break;
1068      }
1069 }
1070
1071 static void
1072 _e_qp_srv_effect_finish(E_Policy_Quickpanel *qp, Eina_Bool final_visible_state)
1073 {
1074    Eina_Bool vis;
1075    Eina_Bool res;
1076
1077    res = _e_qp_srv_is_effect_running(qp);
1078    if (!res)
1079      return;
1080
1081    res = _e_qp_srv_is_effect_finish_job_started(qp);
1082    if (res)
1083      {
1084         vis = _e_qp_srv_effect_final_visible_state_get(qp);
1085         if (vis == final_visible_state)
1086           return;
1087
1088         _e_qp_srv_effect_finish_job_stop(qp);
1089      }
1090    _e_qp_srv_effect_finish_job_start(qp, final_visible_state);
1091 }
1092
1093 static void
1094 _e_qp_srv_effect_stop(E_Policy_Quickpanel *qp)
1095 {
1096    Eina_Bool res;
1097
1098    res = _e_qp_srv_is_effect_running(qp);
1099    if (!res)
1100      return;
1101
1102    qp->effect.active = EINA_FALSE;
1103
1104    res = _e_qp_srv_is_effect_finish_job_started(qp);
1105    if (res)
1106      _e_qp_srv_effect_finish_job_end(qp);
1107    else
1108      {
1109         e_zone_orientation_block_set(qp->zone, "quickpanel-mover", EINA_FALSE);
1110         QP_VISIBLE_SET(qp, EINA_FALSE);
1111         E_FREE_FUNC(qp->mover, evas_object_del);
1112      }
1113 }
1114
1115 inline static void
1116 _e_qp_srv_effect_disable_unref(E_Policy_Quickpanel *qp)
1117 {
1118    if (qp->effect.disable_ref > 0)
1119      qp->effect.disable_ref--;
1120 }
1121
1122 static void
1123 _e_qp_srv_effect_disable_ref(E_Policy_Quickpanel *qp)
1124 {
1125    qp->effect.disable_ref++;
1126    if (qp->effect.disable_ref == 1)
1127      _e_qp_srv_effect_stop(qp);
1128 }
1129
1130 static Eina_Bool
1131 _e_qp_check_scrollable(E_Policy_Quickpanel *qp)
1132 {
1133    E_Client *ec = NULL;
1134    E_QP_Client *qp_client = NULL;
1135    Eina_Bool scrollable = EINA_TRUE;
1136    int x, y, w, h;
1137    int zx = 0, zy = 0, zw = 0, zh = 0;
1138
1139    if (!qp) return EINA_FALSE;
1140    if (!qp->ec) return EINA_FALSE;
1141
1142    e_zone_useful_geometry_get(qp->zone, &zx, &zy, &zw, &zh);
1143
1144    for (ec = e_client_below_get(qp->ec); ec; ec = e_client_below_get(ec))
1145      {
1146         if (!ec->visible) continue;
1147         if (_quickpanel_check_skip_client(ec)) continue;
1148         e_client_geometry_get(ec, &x, &y, &w, &h);
1149         if (!E_INTERSECTS(x, y, w, h, zx, zy, zw, zh)) continue;
1150
1151         qp_client = _e_qp_client_ec_get(ec, (E_Quickpanel_Type)qp->type);
1152         if (!qp_client) continue;
1153         if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_RETAIN)
1154           continue;
1155
1156         if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_SET)
1157           scrollable = EINA_TRUE;
1158         else
1159           {
1160              ELOGF("QUICKPANEL", "Scroll locked by owner client (ec:%p, win:%zx)", qp->below, ec, e_client_util_win_get(ec));
1161              scrollable = EINA_FALSE;
1162           }
1163         break;
1164      }
1165
1166    return scrollable;
1167 }
1168
1169 static void
1170 _region_obj_cb_gesture_start(void *data, Evas_Object *handler, int nfingers, int x, int y, unsigned int timestamp)
1171 {
1172    E_Policy_Quickpanel *qp;
1173    E_QP_Client *qp_client;
1174    E_Client *focused;
1175    E_Client *pos_ec = NULL;
1176    E_Desk *desk = NULL;
1177    int indi_x, indi_y, indi_w, indi_h;
1178    const int sensitivity = 50;
1179    Eina_Bool res;
1180    Eina_Bool scrollable = EINA_TRUE;
1181
1182    ELOGF("QUICKPANEL", "Start gesture for quickpanel", NULL);
1183
1184    qp = data;
1185    if (EINA_UNLIKELY(!qp))
1186      return;
1187
1188    if (EINA_UNLIKELY(!qp->ec))
1189      return;
1190
1191    if (e_object_is_del(E_OBJECT(qp->ec)))
1192      return;
1193
1194    desk = e_desk_current_get(qp->zone);
1195    if (desk)
1196      pos_ec = e_client_under_position_get(desk, x, y, NULL);
1197
1198    if (!pos_ec)
1199      {
1200         ELOGF("QUICKPANEL", "NO visible client under pos(%d,%d)", NULL, x, y);
1201         return;
1202      }
1203
1204    if (handler == qp->indi_obj)
1205      {
1206         int ix, iy, iw, ih;
1207
1208         e_service_region_rectangle_get(qp->indi_obj, qp->rotation, &indi_x, &indi_y, &indi_w, &indi_h);
1209         switch (qp->rotation)
1210           {
1211            case E_POLICY_ANGLE_MAP_90:
1212               ix = pos_ec->x;
1213               iy = pos_ec->y;
1214               iw = indi_w + sensitivity;
1215               ih = pos_ec->h;
1216               break;
1217            case E_POLICY_ANGLE_MAP_180:
1218               ix = pos_ec->x;
1219               iy = pos_ec->y + pos_ec->h - (indi_h + sensitivity);
1220               iw = pos_ec->w;
1221               ih = indi_h + sensitivity;
1222               break;
1223            case E_POLICY_ANGLE_MAP_270:
1224               ix = pos_ec->x + pos_ec->w - (indi_w + sensitivity);
1225               iy = pos_ec->y;
1226               iw = indi_w + sensitivity;
1227               ih = pos_ec->h;
1228               break;
1229            case E_POLICY_ANGLE_MAP_0:
1230            default:
1231               ix = pos_ec->x;
1232               iy = pos_ec->y;
1233               iw = pos_ec->w;
1234               ih = indi_h + sensitivity;
1235               break;
1236           }
1237
1238         if (!E_INSIDE(x, y, ix, iy, iw, ih))
1239           {
1240              ELOGF("QUICKPANEL", "NOT in indicator area", NULL);
1241              return;
1242           }
1243
1244         if (_quickpanel_send_gesture_to_indicator())
1245           {
1246              ELOGF("QUICKPANEL", "SEND to change indicator state", NULL);
1247              return;
1248           }
1249      }
1250
1251    // check quickpanel service window's scroll lock state
1252    if (qp->scroll_lock)
1253      {
1254         ELOGF("QUICKPANEL", "Scroll locked by quickpanel service", NULL);
1255         return;
1256      }
1257
1258    /* Do not show and scroll the quickpanel window if the qp_client winodw
1259     * which is placed at the below of the quickpanel window doesn't want
1260     * to show and scroll the quickpanel window.
1261     */
1262    qp_client = _e_qp_client_ec_get(qp->below, (E_Quickpanel_Type)qp->type);
1263    if (qp_client)
1264      {
1265         if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_UNSET)
1266           {
1267              ELOGF("QUICKPANEL", "Scroll locked by current client", qp->below);
1268              return;
1269           }
1270         else if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_RETAIN)
1271           {
1272              ELOGF("QUICKPANEL", "Scroll follow by previous client", qp->below);
1273              scrollable = _e_qp_check_scrollable(qp);
1274              if (!scrollable) return;
1275           }
1276      }
1277
1278    res = _e_qp_srv_is_effect_running(qp);
1279    if (res)
1280      {
1281         INF("Already animated");
1282         return;
1283      }
1284
1285    focused = e_client_focused_get();
1286    if (focused)
1287      e_policy_aux_message_send(focused, "quickpanel_state", "moving", NULL);
1288
1289    qp->gesture_target = focused;
1290
1291    if ((qp->below) &&
1292        (qp->below != focused))
1293      e_policy_aux_message_send(qp->below, "quickpanel_state", "moving", NULL);
1294
1295    /* cancel touch events sended up to now */
1296    e_comp_wl_touch_cancel();
1297
1298    _e_qp_srv_mouse_info_update(qp, x, y, timestamp);
1299    _e_qp_srv_effect_start(qp);
1300    _e_qp_srv_effect_update(qp, x, y);
1301 }
1302
1303 static void
1304 _region_obj_cb_gesture_move(void *data, Evas_Object *handler, int nfingers, int x, int y, unsigned int timestamp)
1305 {
1306    E_Policy_Quickpanel *qp;
1307    Eina_Bool res;
1308
1309    qp = data;
1310    res = _e_qp_srv_is_effect_running(qp);
1311    if (!res)
1312      return;
1313
1314    _e_qp_srv_mouse_info_update(qp, x, y, timestamp);
1315    _e_qp_srv_effect_update(qp, x, y);
1316 }
1317
1318 static void
1319 _region_obj_cb_gesture_end(void *data EINA_UNUSED, Evas_Object *handler, int nfingers, int x, int y, unsigned int timestamp)
1320 {
1321    E_Policy_Quickpanel *qp;
1322    Eina_Bool res, v;
1323
1324    qp = data;
1325    res = _e_qp_srv_is_effect_running(qp);
1326    if (!res)
1327      return;
1328
1329    v = _e_qp_srv_visibility_eval_by_mouse_info(qp);
1330    _e_qp_srv_effect_finish(qp, v);
1331 }
1332
1333 static void
1334 _quickpanel_free(E_Policy_Quickpanel *qp)
1335 {
1336    ELOGF("QUICKPANEL", "Remove Client | qp %p", qp->ec, qp);
1337
1338    evas_object_event_callback_del(qp->ec->frame, EVAS_CALLBACK_SHOW, _quickpanel_client_evas_cb_show);
1339    evas_object_event_callback_del(qp->ec->frame, EVAS_CALLBACK_HIDE, _quickpanel_client_evas_cb_hide);
1340    evas_object_event_callback_del(qp->ec->frame, EVAS_CALLBACK_MOVE, _quickpanel_client_evas_cb_move);
1341
1342    if (qp->bg_rect)
1343      evas_object_del(qp->bg_rect);
1344
1345    E_FREE_FUNC(qp->mover, evas_object_del);
1346    E_FREE_FUNC(qp->indi_obj, evas_object_del);
1347    E_FREE_FUNC(qp->handler_obj, evas_object_del);
1348    E_FREE_FUNC(qp->effect.animator, ecore_animator_del);
1349    E_FREE_FUNC(qp->idle_enterer, ecore_idle_enterer_del);
1350    E_FREE_LIST(qp->events, ecore_event_handler_del);
1351    E_FREE_LIST(qp->hooks, e_client_hook_del);
1352    E_FREE_LIST(qp->intercept_hooks, e_comp_object_intercept_hook_del);
1353
1354    qp_services = eina_list_remove(qp_services, qp);
1355    E_FREE(qp);
1356 }
1357
1358 static void
1359 _quickpanel_hook_client_del(void *d, E_Client *ec)
1360 {
1361    E_Policy_Quickpanel *qp;
1362
1363    qp = d;
1364    if (EINA_UNLIKELY(!qp))
1365      return;
1366
1367    if (!ec) return;
1368
1369    if (qp->ec != ec)
1370      return;
1371
1372    e_zone_orientation_force_update_del(qp->zone, ec);
1373
1374    _quickpanel_free(qp);
1375 }
1376
1377 static void
1378 _quickpanel_client_evas_cb_show(void *data, Evas *evas, Evas_Object *obj, void *event)
1379 {
1380    E_Policy_Quickpanel *qp;
1381    E_Client *ec;
1382
1383    qp = data;
1384    if (EINA_UNLIKELY(!qp))
1385      return;
1386
1387    evas_object_show(qp->handler_obj);
1388    evas_object_raise(qp->handler_obj);
1389    evas_object_hide(qp->indi_obj);
1390
1391    ec = qp->ec;
1392    if (ec)
1393      e_pixmap_buffer_clear_cancel(ec->pixmap);
1394
1395    E_FREE_FUNC(qp->buf_change_hdlr, ecore_event_handler_del);
1396 }
1397
1398 static Eina_Bool
1399 _quickpanel_cb_buffer_change(void *data, int type, void *event)
1400 {
1401    E_Policy_Quickpanel *qp;
1402    E_Event_Client *ev;
1403    E_Client *ec;
1404    int x, y, w, h;
1405    Eina_Bool vis = EINA_FALSE;
1406
1407    qp = data;
1408    if (!qp->ec)
1409      goto end;
1410
1411    ev = event;
1412    ec = ev->ec;
1413    if (qp->ec != ec)
1414      goto end;
1415
1416    /* skip force render if ec is visible */
1417    if (ec->visible)
1418      goto end;
1419
1420    /* render forcibly */
1421    e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
1422    e_comp_object_dirty(ec->frame);
1423    e_comp_object_render(ec->frame);
1424
1425    /* make frame event */
1426    e_pixmap_image_clear(ec->pixmap, EINA_TRUE);
1427
1428    /* use single buffer if qp service's ec is invisible */
1429    evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
1430
1431    if (E_INTERSECTS(x, y, w, h,
1432                     qp->zone->x,
1433                     qp->zone->y,
1434                     qp->zone->w,
1435                     qp->zone->h))
1436      vis = evas_object_visible_get(ec->frame);
1437
1438    if (!vis)
1439      e_pixmap_buffer_clear(ec->pixmap, EINA_TRUE);
1440
1441 end:
1442    return ECORE_CALLBACK_PASS_ON;
1443 }
1444
1445 static void
1446 _quickpanel_client_evas_cb_hide(void *data, Evas *evas, Evas_Object *obj, void *event)
1447 {
1448    E_Policy_Quickpanel *qp;
1449
1450    qp = data;
1451    if (EINA_UNLIKELY(!qp))
1452      return;
1453
1454    evas_object_hide(qp->handler_obj);
1455    evas_object_show(qp->indi_obj);
1456
1457    if (qp->need_scroll_update)
1458      _e_qp_client_scrollable_update(qp);
1459
1460    e_pixmap_buffer_clear(qp->ec->pixmap, EINA_TRUE);
1461 }
1462
1463 static void
1464 _quickpanel_client_evas_cb_move(void *data, Evas *evas, Evas_Object *obj, void *event)
1465 {
1466    E_Policy_Quickpanel *qp;
1467    int x, y, hx, hy;
1468
1469    qp = data;
1470    if (EINA_UNLIKELY(!qp))
1471      return;
1472
1473    e_service_region_rectangle_get(qp->handler_obj, qp->rotation, &hx, &hy, NULL, NULL);
1474    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1475    evas_object_move(qp->handler_obj, x + hx, y + hy);
1476 }
1477
1478 static void
1479 _quickpanel_handler_obj_region_convert_set(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, int x, int y, int w, int h, int tx, int ty, int tw, int th)
1480 {
1481    int nx, ny, nw, nh;
1482
1483    switch (ridx)
1484      {
1485       case E_POLICY_ANGLE_MAP_0:
1486          nx = tx;
1487          ny = ty + th - h;
1488          nw = w;
1489          nh = h;
1490          break;
1491
1492       case E_POLICY_ANGLE_MAP_90:
1493          nx = tx + tw - w;
1494          ny = ty;
1495          nw = w;
1496          nh = h;
1497          break;
1498
1499       case E_POLICY_ANGLE_MAP_180:
1500          nx = tx;
1501          ny = ty;
1502          nw = w;
1503          nh = h;
1504          break;
1505
1506       case E_POLICY_ANGLE_MAP_270:
1507          nx = tx;
1508          ny = ty;
1509          nw = w;
1510          nh = h;
1511          break;
1512
1513       default:
1514          nx = tx;
1515          ny = ty + th - h;
1516          nw = w;
1517          nh = h;
1518          break;
1519      }
1520
1521    e_service_region_rectangle_set(qp->handler_obj, ridx, nx, ny, nw, nh);
1522    ELOGF("QUICKPANEL", "handler obj:%p, angle:%d, geo(%d,%d,%d,%d)", NULL, qp->handler_obj, ridx, nx, ny, nw, nh);
1523 }
1524
1525 static void
1526 _quickpanel_handler_rect_add(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, int x, int y, int w, int h, int tx, int ty, int tw, int th)
1527 {
1528    E_Client *ec;
1529    Evas_Object *obj;
1530
1531    ec = qp->ec;
1532
1533    ELOGF("QUICKPANEL", "Handler Geo Set | x %d, y %d, w %d, h %d",
1534          NULL, x, y, w, h);
1535
1536    if (qp->handler_obj)
1537      goto end;
1538
1539    obj = e_service_region_object_new(ec);
1540    evas_object_name_set(obj, "qp::handler_obj");
1541    if (!obj)
1542      return;
1543
1544    e_service_region_gesture_set(obj,
1545                                 POL_GESTURE_TYPE_NONE,
1546                                 1,
1547                                 _region_obj_cb_gesture_start,
1548                                 _region_obj_cb_gesture_move,
1549                                 _region_obj_cb_gesture_end, qp);
1550
1551    /* Add handler object to smart member to follow the client's stack */
1552    evas_object_smart_member_add(obj, ec->frame);
1553    evas_object_propagate_events_set(obj, 0);
1554    if (evas_object_visible_get(ec->frame))
1555      evas_object_show(obj);
1556
1557    qp->handler_obj = obj;
1558
1559 end:
1560    _quickpanel_handler_obj_region_convert_set(qp, ridx, x, y, w, h, tx, ty, tw, th);
1561 }
1562
1563 void _quickpanel_indi_obj_region_convert_set(E_Policy_Quickpanel *qp, int angle, int x, int y, int w, int h, int tx, int ty, int tw, int th)
1564 {
1565    int nx, ny, nw, nh;
1566
1567    if ((w <= 0) || (h <= 0)) return;
1568
1569    switch (angle)
1570      {
1571       case E_POLICY_ANGLE_MAP_0:
1572          nx = tx;
1573          ny = ty;
1574          nw = w;
1575          nh = h;
1576          break;
1577
1578       case E_POLICY_ANGLE_MAP_90:
1579          nx = tx;
1580          ny = ty;
1581          nw = w;
1582          nh = h;
1583          break;
1584
1585       case E_POLICY_ANGLE_MAP_180:
1586          nx = tx;
1587          ny = ty + th - h;
1588          nw = w;
1589          nh = h;
1590          break;
1591
1592       case E_POLICY_ANGLE_MAP_270:
1593          nx = tx + tw - w;
1594          ny = ty;
1595          nw = w;
1596          nh = h;
1597          break;
1598
1599       default:
1600          nx = tx;
1601          ny = ty;
1602          nw = w;
1603          nh = h;
1604          break;
1605      }
1606
1607    e_service_region_rectangle_set(qp->indi_obj, angle, nx, ny, nw, nh);
1608    ELOGF("QUICKPANEL", "indicator obj:%p, angle:%d, geo(%d,%d,%d,%d)", NULL, qp->indi_obj, angle, nx, ny, nw, nh);
1609 }
1610
1611 static void
1612 _quickpanel_handler_region_set(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, Eina_Tiler *tiler)
1613 {
1614    Eina_Iterator *it;
1615    Eina_Rectangle *r;
1616    E_Desk *desk = NULL;
1617    int tx, ty, tw, th;
1618
1619    /* FIXME supported single rectangle, not tiler */
1620
1621    tx = qp->zone->x;
1622    ty = qp->zone->y;
1623    tw = qp->zone->w;
1624    th = qp->zone->h;
1625
1626    desk = e_desk_current_get(qp->zone);
1627    if (desk)
1628      {
1629         tx = desk->geom.x;
1630         ty = desk->geom.y;
1631         tw = desk->geom.w;
1632         th = desk->geom.h;
1633      }
1634
1635    it = eina_tiler_iterator_new(tiler);
1636    EINA_ITERATOR_FOREACH(it, r)
1637      {
1638         _quickpanel_handler_rect_add(qp, ridx, r->x, r->y, r->w, r->h, tx, ty, tw, th);
1639         _quickpanel_indi_obj_region_convert_set(qp, ridx, r->x, r->y, r->w, r->h, tx, ty, tw, th);
1640         break;
1641      }
1642    eina_iterator_free(it);
1643 }
1644
1645 static void
1646 _quickpanel_contents_region_set(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, Eina_Tiler *tiler)
1647 {
1648    // Do Something
1649    Eina_Iterator *it;
1650    Eina_Rectangle *r;
1651
1652    it = eina_tiler_iterator_new(tiler);
1653    EINA_ITERATOR_FOREACH(it, r)
1654      {
1655         qp->geom.x = r->x;
1656         qp->geom.y = r->y;
1657         qp->geom.w = r->w;
1658         qp->geom.h = r->h;
1659      }
1660    eina_iterator_free(it);
1661 }
1662
1663 static void
1664 _e_qp_srv_visible_handle(E_Policy_Quickpanel *qp, Eina_Bool vis)
1665 {
1666    Eina_Bool res = EINA_FALSE;
1667
1668    // If vis is true, show (with effect) the quickpanel service.
1669    // Otherwise, hide (with effect) the quickpanel service.
1670
1671    res = _e_qp_srv_is_effect_running(qp);
1672    if (res)
1673      _e_qp_srv_effect_finish(qp, vis);
1674    else if ((qp->ec) && ((qp->ec->visible) || (vis)))
1675      {
1676         _e_qp_srv_effect_start(qp);
1677         _e_qp_srv_effect_update(qp, qp->effect.x, qp->effect.y);
1678         _e_qp_srv_effect_finish(qp, vis);
1679      }
1680 }
1681
1682 static void
1683 _e_qp_srv_visible_set(E_Policy_Quickpanel *qp, Eina_Bool vis)
1684 {
1685    Eina_Bool res;
1686
1687    res = _e_qp_client_scrollable_update(qp);
1688    if (!res) return;
1689
1690    if (qp->effect.disable_ref)
1691      {
1692         QP_VISIBLE_SET(qp, vis);
1693         return;
1694      }
1695
1696    _e_qp_srv_visible_handle(qp, vis);
1697 }
1698
1699 EINTERN void
1700 e_qp_control_by_command(E_Client *ec, int operation)
1701 {
1702    E_Policy_Quickpanel *qp = NULL;
1703
1704    qp = _quickpanel_service_get(ec);
1705    if (!qp)
1706      {
1707         /* look for a first quick panel service */
1708         qp = eina_list_nth(qp_services, 0);
1709      }
1710
1711    if (qp)
1712      {
1713         if (operation == 0)
1714           _e_qp_srv_visible_handle(qp, EINA_FALSE);
1715         else if (operation == 1)
1716           _e_qp_srv_visible_handle(qp, EINA_TRUE);
1717         else if (operation == 2)
1718           e_service_quickpanel_scroll_lock_set(qp->ec, EINA_TRUE);
1719         else
1720           e_service_quickpanel_scroll_lock_set(qp->ec, EINA_FALSE);
1721      }
1722 }
1723
1724 static Eina_Bool
1725 _quickpanel_cb_rotation_begin(void *data, int type, void *event)
1726 {
1727    E_Policy_Quickpanel *qp;
1728    E_Event_Client *ev = event;
1729    E_Client *ec;
1730
1731    qp = data;
1732    if (EINA_UNLIKELY(!qp))
1733      goto end;
1734
1735    ec = ev->ec;
1736    if (EINA_UNLIKELY(!ec))
1737      goto end;
1738
1739    if (qp->ec != ec)
1740      goto end;
1741
1742    E_FREE_FUNC(qp->mover, evas_object_del);
1743
1744    _e_qp_srv_effect_disable_ref(qp);
1745
1746 end:
1747    return ECORE_CALLBACK_PASS_ON;
1748 }
1749
1750 static Eina_Bool
1751 _quickpanel_cb_rotation_cancel(void *data, int type, void *event)
1752 {
1753    E_Policy_Quickpanel *qp;
1754    E_Event_Client *ev = event;
1755    E_Client *ec;
1756
1757    qp = data;
1758    if (EINA_UNLIKELY(!qp))
1759      goto end;
1760
1761    ec = ev->ec;
1762    if (EINA_UNLIKELY(!ec))
1763      goto end;
1764
1765    if (qp->ec != ec)
1766      goto end;
1767
1768    _e_qp_srv_effect_disable_unref(qp);
1769
1770 end:
1771    return ECORE_CALLBACK_PASS_ON;
1772 }
1773
1774 static Eina_Bool
1775 _quickpanel_cb_rotation_done(void *data, int type, void *event)
1776 {
1777    E_Policy_Quickpanel *qp;
1778    E_Event_Client *ev = event;
1779    E_Client *ec;
1780    E_QP_Client *qp_client;
1781    Eina_List *l;
1782    Eina_Bool vis;
1783
1784    qp = data;
1785    if (EINA_UNLIKELY(!qp))
1786      goto end;
1787
1788    ec = ev->ec;
1789    if (EINA_UNLIKELY(!ec))
1790      goto end;
1791
1792    if (qp->ec != ec)
1793      goto end;
1794
1795    qp->rotation = e_policy_angle_map(ec->e.state.rot.ang.curr);
1796
1797    vis = evas_object_visible_get(ec->frame);
1798    switch (qp->rotation)
1799      {
1800       case E_POLICY_ANGLE_MAP_90:
1801          qp->effect.x = vis ? qp->zone->w : 0;
1802          break;
1803       case E_POLICY_ANGLE_MAP_180:
1804          qp->effect.y = vis ? 0 : qp->zone->h;
1805          break;
1806       case E_POLICY_ANGLE_MAP_270:
1807          qp->effect.x = vis ? 0 : qp->zone->w;
1808          break;
1809       default:
1810          qp->effect.y = vis ? qp->zone->h : 0;
1811          break;
1812      }
1813
1814    _e_qp_srv_effect_disable_unref(qp);
1815
1816    /* send orientation event to only client with the same type of quickpanel service */
1817    EINA_LIST_FOREACH(qp_clients, l, qp_client)
1818      {
1819         if (qp->type == (E_Service_Quickpanel_Type)qp_client->type)
1820           e_tzsh_qp_state_orientation_update(qp_client->ec,
1821                                              qp->rotation,
1822                                              qp_client->type);
1823      }
1824
1825 end:
1826    return ECORE_CALLBACK_PASS_ON;
1827 }
1828
1829 static Eina_Bool
1830 _quickpanel_check_skip_client(E_Client *ec)
1831 {
1832    Eina_Bool skip = EINA_FALSE;
1833
1834    if (!ec) return EINA_TRUE;
1835
1836    if (e_policy_client_is_keyboard(ec) ||
1837        e_policy_client_is_keyboard_sub(ec) ||
1838        e_policy_client_is_cursor(ec))
1839      {
1840         skip = EINA_TRUE;
1841      }
1842
1843    return skip;
1844 }
1845
1846 /* NOTE: if the state(show/hide/stack) of windows which are stacked below
1847  * quickpanel is changed, we close the quickpanel.
1848  * the most major senario is that quickpanel should be closed when WiFi popup to
1849  * show the available connection list is shown by click the button on
1850  * the quickpanel to turn on the WiFi.
1851  * @see  _quickpanel_cb_client_show(),
1852  *       _quickpanel_cb_client_hide()
1853  *       _quickpanel_cb_client_move()
1854  *       _quickpanel_cb_client_stack()
1855  *       _quickpanel_cb_client_remove()
1856  *       _quickpanel_idle_enter()
1857  */
1858 static E_Client *
1859 _quickpanel_below_visible_client_get(E_Policy_Quickpanel *qp)
1860 {
1861    E_Client *ec;
1862    int zx, zy, zw, zh;
1863
1864    if (!qp->zone) return NULL;
1865
1866    zx = qp->zone->x;
1867    zy = qp->zone->y;
1868    zw = qp->zone->w;
1869    zh = qp->zone->h;
1870
1871    for (ec = e_client_below_get(qp->ec); ec; ec = e_client_below_get(ec))
1872      {
1873         if (!ec->visible) continue;
1874         if (_quickpanel_check_skip_client(ec)) continue;
1875         if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh)) continue;
1876         return ec;
1877      }
1878
1879    return NULL;
1880 }
1881
1882 static void
1883 _quickpanel_below_change_eval(void *data, void *event)
1884 {
1885    E_Policy_Quickpanel *qp;
1886    E_Event_Client *ev;
1887
1888    qp = data;
1889    if (EINA_UNLIKELY(!qp))
1890      return;
1891
1892    ev = event;
1893    if (EINA_UNLIKELY((!ev) || (!ev->ec)))
1894      return;
1895
1896    if (_quickpanel_check_skip_client(ev->ec))
1897      return;
1898
1899    qp->changes.below = EINA_TRUE;
1900    _changed = EINA_TRUE;
1901 }
1902
1903 static Eina_Bool
1904 _quickpanel_cb_client_show(void *data, int type, void *event)
1905 {
1906    _quickpanel_below_change_eval(data, event);
1907    return ECORE_CALLBACK_PASS_ON;
1908 }
1909
1910 static Eina_Bool
1911 _quickpanel_cb_client_hide(void *data, int type, void *event)
1912 {
1913    _quickpanel_below_change_eval(data, event);
1914    return ECORE_CALLBACK_PASS_ON;
1915 }
1916
1917 static Eina_Bool
1918 _quickpanel_cb_client_move(void *data, int type, void *event)
1919 {
1920    _quickpanel_below_change_eval(data, event);
1921    return ECORE_CALLBACK_PASS_ON;
1922 }
1923
1924 static Eina_Bool
1925 _quickpanel_cb_client_stack(void *data, int type, void *event)
1926 {
1927    E_Policy_Quickpanel *qp;
1928    E_Event_Client *ev;
1929
1930    qp = data;
1931    EINA_SAFETY_ON_NULL_GOTO(qp, end);
1932
1933    ev = event;
1934    EINA_SAFETY_ON_NULL_GOTO(ev, end);
1935
1936    qp->stacking = ev->ec;
1937
1938    DBG("Stacking Client '%s'(%p)",
1939        ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec);
1940
1941    if (evas_object_visible_get(ev->ec->frame))
1942      _quickpanel_below_change_eval(data, event);
1943 end:
1944    return ECORE_CALLBACK_PASS_ON;
1945 }
1946
1947 static Eina_Bool
1948 _quickpanel_cb_client_remove(void *data, int type, void *event)
1949 {
1950    E_Policy_Quickpanel *qp;
1951    E_Event_Client *ev;
1952
1953    qp = data;
1954    EINA_SAFETY_ON_NULL_GOTO(qp, end);
1955
1956    ev = event;
1957    EINA_SAFETY_ON_NULL_GOTO(ev, end);
1958
1959    if (qp->stacking == ev->ec)
1960      qp->stacking = NULL;
1961
1962    if (qp->below == ev->ec)
1963      qp->below = NULL;
1964
1965    if (qp->gesture_target == ev->ec)
1966      qp->gesture_target = NULL;
1967
1968    if (!stopping)
1969      _quickpanel_below_change_eval(data, event);
1970 end:
1971    return ECORE_CALLBACK_PASS_ON;
1972 }
1973
1974 static Eina_Bool
1975 _quickpanel_cb_client_focus_in(void *data, int type, void *event)
1976 {
1977    E_Policy_Quickpanel *qp;
1978    E_Event_Client *ev;
1979    E_Client *ec;
1980
1981    qp = data;
1982    EINA_SAFETY_ON_NULL_GOTO(qp, end);
1983
1984    ev = event;
1985    EINA_SAFETY_ON_NULL_GOTO(ev, end);
1986
1987    ec = ev->ec;
1988    EINA_SAFETY_ON_NULL_GOTO(ec, end);
1989
1990    if (ec == qp->ec)
1991      goto end;
1992
1993    if (ec->visible)
1994      {
1995         DBG("Focus changed to '%s'(%zx), Hide QP",
1996             ec->icccm.name ? ec->icccm.name : "", e_client_util_win_get(ec));
1997         e_service_quickpanel_hide(qp->ec);
1998      }
1999 end:
2000    return ECORE_CALLBACK_PASS_ON;
2001 }
2002
2003 static Eina_Bool
2004 _quickpanel_cb_desk_geometry_change(void *data, int type, void *event)
2005 {
2006    E_Policy_Quickpanel *qp;
2007    E_Event_Desk_Geometry_Change *ev;
2008    E_Desk *desk = NULL;
2009    int x, y, w, h;
2010    int angle;
2011
2012    qp = data;
2013    EINA_SAFETY_ON_NULL_GOTO(qp, end);
2014
2015    ev = event;
2016    EINA_SAFETY_ON_NULL_GOTO(ev, end);
2017
2018    desk = e_desk_current_get(qp->zone);
2019    EINA_SAFETY_ON_NULL_GOTO(desk, end);
2020
2021    for (angle = E_POLICY_ANGLE_MAP_0; angle < E_POLICY_ANGLE_MAP_NUM; angle++)
2022      {
2023         e_service_region_rectangle_get(qp->indi_obj, angle, &x, &y, &w, &h);
2024         if ((w > 0) && (h > 0))
2025           _quickpanel_indi_obj_region_convert_set(qp, angle, x, y, w, h, ev->desk->geom.x, ev->desk->geom.y, ev->desk->geom.w, ev->desk->geom.h);
2026
2027         e_service_region_rectangle_get(qp->handler_obj, angle, &x, &y, &w, &h);
2028         if ((w > 0) && (h > 0))
2029           _quickpanel_handler_obj_region_convert_set(qp, angle, x, y, w, h, ev->desk->geom.x, ev->desk->geom.y, ev->desk->geom.w, ev->desk->geom.h);
2030      }
2031
2032    evas_object_move(qp->ec->frame, ev->desk->geom.x, ev->desk->geom.y);
2033
2034 end:
2035    return ECORE_CALLBACK_PASS_ON;
2036 }
2037
2038 static Eina_Bool
2039 _quickpanel_cb_client_zone_set(void *data, int type EINA_UNUSED, void *event)
2040 {
2041    E_Policy_Quickpanel *qp;
2042    E_Event_Client_Zone_Set *ev;
2043
2044    qp = data;
2045    ev = event;
2046
2047    if (qp->ec != ev->ec)
2048      goto end;
2049
2050    if (qp->zone == ev->zone)
2051      goto end;
2052
2053    ELOGF("QUICKPANEL", "Change Zone | qp %p old(%p) new(%p)", qp->ec, qp, qp->zone, ev->zone);
2054
2055    qp->zone = ev->zone;
2056
2057 end:
2058    return ECORE_CALLBACK_PASS_ON;
2059 }
2060
2061 static Evas_Object *
2062 _quickpanel_indicator_object_new(E_Policy_Quickpanel *qp)
2063 {
2064    Evas_Object *indi_obj;
2065    E_Desk *desk;
2066
2067    indi_obj = e_service_region_object_new(qp->ec);
2068    evas_object_name_set(indi_obj, "qp::indicator_obj");
2069    if (!indi_obj)
2070      return NULL;
2071
2072    evas_object_repeat_events_set(indi_obj, EINA_FALSE);
2073    /* FIXME: make me move to explicit layer something like POL_LAYER */
2074    evas_object_layer_set(indi_obj, EVAS_LAYER_MAX - 1);
2075
2076    e_service_region_gesture_set(indi_obj,
2077                                 POL_GESTURE_TYPE_LINE,
2078                                 1,
2079                                 _region_obj_cb_gesture_start,
2080                                 _region_obj_cb_gesture_move,
2081                                 _region_obj_cb_gesture_end, qp);
2082
2083    evas_object_show(indi_obj);
2084
2085    if (e_config->qp_add_on_desk_smart)
2086      {
2087         desk = e_desk_current_get(qp->zone);
2088         e_desk_smart_member_add(desk, indi_obj);
2089      }
2090
2091    return indi_obj;
2092 }
2093
2094 static Eina_Bool
2095 _quickpanel_idle_enter(void *data)
2096 {
2097    E_Policy_Quickpanel *qp;
2098
2099    if (!_changed)
2100      goto end;
2101    _changed = EINA_FALSE;
2102
2103    qp = data;
2104    if (EINA_UNLIKELY(!qp))
2105      goto end;
2106
2107    if (qp->changes.below)
2108      {
2109         E_Client *below;
2110         E_Client *below_old;
2111
2112         below = _quickpanel_below_visible_client_get(qp);
2113         if (qp->below != below)
2114           {
2115              DBG("qp->below '%s'(%p) new_below '%s'(%p)\n",
2116                  qp->below ? (qp->below->icccm.name ? qp->below->icccm.name : "") : "",
2117                  qp->below,
2118                  below ? (below->icccm.name ? below->icccm.name : "") : "",
2119                  below);
2120
2121              below_old = qp->below;
2122              qp->below = below;
2123
2124              /* QUICKFIX
2125               * hide the quickpanel, if below client is the stacking client.
2126               * it means to find out whether or not it was launched.
2127               */
2128              if ((qp->below) &&
2129                  (qp->below->icccm.accepts_focus))
2130                {
2131                   if ((qp->stacking == below) &&
2132                       (qp->ec->visible))
2133                     {
2134                        if (below_old)
2135                          e_policy_aux_message_send(below_old, "quickpanel_state", "hidden", NULL);
2136
2137                        e_service_quickpanel_hide(qp->ec);
2138                     }
2139                }
2140
2141              _e_qp_client_scrollable_update(qp);
2142           }
2143
2144         qp->changes.below = EINA_FALSE;
2145      }
2146
2147 end:
2148    return ECORE_CALLBACK_RENEW;
2149 }
2150
2151 static Eina_Bool
2152 _quickpanel_intercept_hook_show(void *data, E_Client *ec)
2153 {
2154    E_Policy_Quickpanel *qp;
2155
2156    qp = data;
2157    if (EINA_UNLIKELY(!qp))
2158      goto end;
2159
2160    if (qp->ec != ec)
2161      goto end;
2162
2163    if (qp->show_block)
2164      {
2165         ec->visible = EINA_FALSE;
2166         return EINA_FALSE;
2167      }
2168
2169 end:
2170    return EINA_TRUE;
2171 }
2172
2173 static E_QP_Client *
2174 _e_qp_client_ec_get(E_Client *ec, E_Quickpanel_Type type)
2175 {
2176    E_QP_Client *qp_client = NULL;
2177    Eina_List *l;
2178
2179    EINA_LIST_FOREACH(qp_clients, l, qp_client)
2180      {
2181         if ((qp_client->ec == ec) && (qp_client->type == type))
2182           return qp_client;
2183      }
2184
2185    return qp_client;
2186 }
2187
2188 /* return value
2189  *  EINA_TRUE : user can scroll the QP.
2190  *  EINA_FALSE: user can't scroll QP since below window doesn't want.
2191  */
2192 static Eina_Bool
2193 _e_qp_client_scrollable_update(E_Policy_Quickpanel *qp)
2194 {
2195    Eina_Bool res = EINA_TRUE;
2196
2197    EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE);
2198    EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE);
2199    EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE);
2200
2201    if (qp->ec->visible)
2202      {
2203         qp->need_scroll_update = EINA_TRUE;
2204         return EINA_TRUE;
2205      }
2206    qp->need_scroll_update = EINA_FALSE;
2207
2208    if (!qp->below)
2209      {
2210         evas_object_pass_events_set(qp->handler_obj, EINA_FALSE);
2211         evas_object_pass_events_set(qp->indi_obj, EINA_FALSE);
2212         return EINA_TRUE;
2213      }
2214
2215    return res;
2216 }
2217
2218 EINTERN E_Service_Quickpanel_Type
2219 e_service_quickpanel_type_get(E_Client *ec)
2220 {
2221    E_Policy_Quickpanel *qp = NULL;
2222    E_Service_Quickpanel_Type type = E_SERVICE_QUICKPANEL_TYPE_UNKNOWN;
2223
2224    BACKEND_FUNC_CALL_RET(quickpanel_type_get, ec);
2225
2226    qp = _quickpanel_service_get(ec);
2227    if (qp) type = qp->type;
2228
2229    return type;
2230 }
2231
2232 /* window for quickpanel service */
2233 EINTERN void
2234 e_service_quickpanel_client_add(E_Client *ec, E_Service_Quickpanel_Type type)
2235 {
2236    E_Policy_Quickpanel *qp = NULL;
2237    E_Layer layer;
2238    E_Zone *zone;
2239
2240    BACKEND_FUNC_CALL(quickpanel_client_add, ec, type);
2241
2242    /* check for client being deleted */
2243    if (e_object_is_del(E_OBJECT(ec))) return;
2244
2245    /* check for wayland pixmap */
2246    if (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_WL) return;
2247
2248    /* check if ec has been assigned to zone. */
2249    zone = e_comp_zone_find_by_ec(ec);
2250    EINA_SAFETY_ON_NULL_RETURN(zone);
2251
2252    qp = E_NEW(E_Policy_Quickpanel, 1);
2253    EINA_SAFETY_ON_NULL_RETURN(qp);
2254
2255    ELOGF("QUICKPANEL", "Set Client | qp %p", ec, qp);
2256
2257    qp->ec = ec;
2258    qp->zone = zone;
2259    qp->show_block = EINA_TRUE;
2260    qp->effect.type = E_SERVICE_QUICKPANEL_EFFECT_TYPE_SWIPE; /* default effect type */
2261    qp->below = _quickpanel_below_visible_client_get(qp);
2262    qp->type = type;
2263
2264    if (type == E_SERVICE_QUICKPANEL_TYPE_SYSTEM_DEFAULT)
2265      {
2266         qp->indi_obj = _quickpanel_indicator_object_new(qp);
2267         EINA_SAFETY_ON_NULL_GOTO(qp->indi_obj, indi_err);
2268
2269         e_client_window_role_set(ec, "quickpanel_system_default");
2270      }
2271    else if (type == E_SERVICE_QUICKPANEL_TYPE_CONTEXT_MENU)
2272      {
2273         /* don't support swipe type of effect for the qp context menu in public
2274          * you have to make your own qp module and provide backend functions
2275          * if you want to change type of effect of qp context menu
2276          */
2277         qp->effect.type = E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE;
2278         e_client_window_role_set(ec, "quickpanel_context_menu");
2279      }
2280    else if (type == E_SERVICE_QUICKPANEL_TYPE_APPS_MENU)
2281      {
2282         /* don't support swipe type of effect for the qp apps menu in public
2283          * you have to make your own qp module and provide backend functions
2284          * if you want to change type of effect of qp apps menu
2285          */
2286         qp->effect.type = E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE;
2287         e_client_window_role_set(ec, "quickpanel_apps_menu");
2288      }
2289
2290 #ifdef REFACTOR_DESK_AREA
2291    // set quickpanel layer
2292    layer = e_client_layer_get(ec);
2293 #else
2294    // set quickpanel layer
2295    layer = e_client_desk_area_original_layer_get(ec);
2296 #endif
2297
2298    if (E_POLICY_QUICKPANEL_LAYER != layer)
2299      e_client_layer_set(ec, E_POLICY_QUICKPANEL_LAYER);
2300
2301    // set skip iconify
2302    ec->exp_iconify.skip_iconify = 1;
2303
2304    // disable effect
2305    e_policy_animatable_lock(ec, E_POLICY_ANIMATABLE_NEVER, EINA_TRUE);
2306
2307    qp->geom.x = ec->x;
2308    qp->geom.y = ec->y;
2309    qp->geom.w = ec->w;
2310    qp->geom.h = ec->h;
2311
2312    // bg rect
2313    if (e_config->qp_use_bg_rect)
2314      {
2315         Evas_Object *o;
2316         o = evas_object_rectangle_add(e_comp->evas);
2317
2318         qp->bg_rect = o;
2319         evas_object_layer_set(o, E_POLICY_QUICKPANEL_LAYER);
2320         evas_object_name_set(o, "qp::bg_rect");
2321         evas_object_move(o, 0, 0);
2322         evas_object_resize(o, qp->zone->w, qp->zone->h);
2323         evas_object_color_set(o, 0, 0, 0, 0);
2324         evas_object_lower(o);
2325      }
2326    else
2327      qp->bg_rect = NULL;
2328
2329    /* add quickpanel to force update list of zone */
2330    e_zone_orientation_force_update_add(qp->zone, ec);
2331
2332    QP_HIDE(qp);
2333
2334    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,                    _quickpanel_client_evas_cb_show,     qp);
2335    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE,                    _quickpanel_client_evas_cb_hide,     qp);
2336    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE,                    _quickpanel_client_evas_cb_move,     qp);
2337    E_CLIENT_HOOK_APPEND(qp->hooks,           E_CLIENT_HOOK_DEL,                     _quickpanel_hook_client_del,         qp);
2338    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN,  _quickpanel_cb_rotation_begin,       qp);
2339    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL, _quickpanel_cb_rotation_cancel,      qp);
2340    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_ROTATION_CHANGE_END,    _quickpanel_cb_rotation_done,        qp);
2341    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_SHOW,                   _quickpanel_cb_client_show,          qp);
2342    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_HIDE,                   _quickpanel_cb_client_hide,          qp);
2343    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_MOVE,                   _quickpanel_cb_client_move,          qp);
2344    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_STACK,                  _quickpanel_cb_client_stack,         qp);
2345    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_REMOVE,                 _quickpanel_cb_client_remove,        qp);
2346    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_BUFFER_CHANGE,          _quickpanel_cb_buffer_change,        qp);
2347    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_FOCUS_IN,               _quickpanel_cb_client_focus_in,      qp);
2348    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_CLIENT_ZONE_SET,               _quickpanel_cb_client_zone_set,      qp);
2349    E_LIST_HANDLER_APPEND(qp->events,         E_EVENT_DESK_GEOMETRY_CHANGE,          _quickpanel_cb_desk_geometry_change, qp);
2350
2351    E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(qp->intercept_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _quickpanel_intercept_hook_show, qp);
2352
2353    qp->idle_enterer = ecore_idle_enterer_add(_quickpanel_idle_enter, qp);
2354
2355    qp_services = eina_list_append(qp_services, qp);
2356
2357    return;
2358
2359 indi_err:
2360    free(qp);
2361 }
2362
2363 EINTERN void
2364 e_service_quickpanel_client_del(E_Client *ec)
2365 {
2366    E_Policy_Quickpanel *qp;
2367    Eina_List *l, *ll;
2368
2369    BACKEND_FUNC_CALL(quickpanel_client_del, ec);
2370
2371    EINA_LIST_FOREACH_SAFE(qp_services, l, ll, qp)
2372      {
2373         if (qp->ec == ec)
2374           {
2375              _quickpanel_free(qp);
2376              break;
2377           }
2378      }
2379 }
2380
2381 EINTERN void
2382 e_service_quickpanel_effect_type_set(E_Client *ec, E_Service_Quickpanel_Effect_Type type)
2383 {
2384    E_Policy_Quickpanel *qp;
2385
2386    BACKEND_FUNC_CALL(quickpanel_effect_type_set, ec, type);
2387
2388    qp = _quickpanel_service_get(ec);
2389    if (!qp)
2390      return;
2391
2392    if ((qp->ec != ec))
2393      return;
2394
2395    if (qp->effect.type == type)
2396      return;
2397
2398    qp->effect.type = type;
2399    switch (type)
2400      {
2401       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_SWIPE:
2402          ec->lock_client_location = 1;
2403          e_policy_user_geometry_set(ec, E_POLICY_USERGEOM_SERVICE, EINA_FALSE);
2404          if ((ec->maximized == E_MAXIMIZE_NONE) &&
2405              (qp->saved_maximize != E_MAXIMIZE_NONE))
2406            e_client_maximize(ec, qp->saved_maximize);
2407          break;
2408       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_MOVE:
2409          ec->lock_client_location = 0;
2410          e_policy_user_geometry_set(ec, E_POLICY_USERGEOM_SERVICE, EINA_TRUE);
2411          if (ec->maximized != E_MAXIMIZE_NONE)
2412            {
2413               qp->saved_maximize = ec->maximized;
2414               e_client_unmaximize(ec, ec->maximized);
2415            }
2416          e_client_util_move_resize_without_frame(ec, 0, 0, qp->zone->w, qp->zone->h);
2417          break;
2418       case E_SERVICE_QUICKPANEL_EFFECT_TYPE_APP_CUSTOM:
2419          WRN("APP_CUSTOM effect type is not supported yet");
2420          /* TODO */
2421          break;
2422       default:
2423          ERR("Unkown effect type");
2424          break;
2425      }
2426 }
2427
2428 EINTERN void
2429 e_service_quickpanel_scroll_lock_set(E_Client *ec, Eina_Bool lock)
2430 {
2431    E_Policy_Quickpanel *qp = NULL;
2432
2433    BACKEND_FUNC_CALL(quickpanel_scroll_lock_set, ec, lock);
2434
2435    qp = _quickpanel_service_get(ec);
2436    if (!qp) return;
2437
2438    if (qp->scroll_lock == lock)
2439      return;
2440
2441    ELOGF("QUICKPANEL", "Scroll lock is set to %d", NULL, lock);
2442    qp->scroll_lock = lock;
2443 }
2444
2445 EINTERN Eina_Bool
2446 e_service_quickpanel_region_set(E_Client *ec, int type, int angle, Eina_Tiler *tiler)
2447 {
2448    E_Policy_Quickpanel *qp;
2449    E_Policy_Angle_Map ridx;
2450
2451    BACKEND_FUNC_CALL_RET(quickpanel_region_set, ec, type, angle, tiler);
2452
2453    EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), EINA_FALSE);
2454
2455    qp = _quickpanel_service_get(ec);
2456    EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE);
2457
2458    ridx = e_policy_angle_map(angle);
2459    if (type == E_QUICKPANEL_REGION_TYPE_HANDLER)
2460      _quickpanel_handler_region_set(qp, ridx, tiler);
2461    else if (type == E_QUICKPANEL_REGION_TYPE_CONTENTS)
2462      _quickpanel_contents_region_set(qp, ridx, tiler);
2463
2464    return EINA_TRUE;
2465 }
2466
2467 EINTERN void
2468 e_service_quickpanel_show(E_Client *ec)
2469 {
2470    E_Policy_Quickpanel *qp;
2471
2472    BACKEND_FUNC_CALL(quickpanel_show, ec);
2473
2474    qp = _quickpanel_service_get(ec);
2475    EINA_SAFETY_ON_NULL_RETURN(qp);
2476    EINA_SAFETY_ON_NULL_RETURN(qp->ec);
2477    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec)));
2478
2479    _e_qp_srv_visible_set(qp, EINA_TRUE);
2480 }
2481
2482 EINTERN void
2483 e_service_quickpanel_hide(E_Client *ec)
2484 {
2485    E_Policy_Quickpanel *qp;
2486
2487    BACKEND_FUNC_CALL(quickpanel_hide, ec);
2488
2489    qp = _quickpanel_service_get(ec);
2490    EINA_SAFETY_ON_NULL_RETURN(qp);
2491    EINA_SAFETY_ON_NULL_RETURN(qp->ec);
2492    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec)));
2493
2494    _e_qp_srv_visible_set(qp, EINA_FALSE);
2495 }
2496
2497 /* check if at least one quickpanel is visible */
2498 EINTERN Eina_Bool
2499 e_qps_visible_get(void)
2500 {
2501    E_Policy_Quickpanel *qp;
2502    E_Client *ec;
2503    Eina_Bool vis;
2504    int x, y, w, h;
2505    Eina_List *l;
2506
2507    BACKEND_FUNC_CALL_RET(qps_visible_get);
2508
2509    EINA_LIST_FOREACH(qp_services, l, qp)
2510      {
2511         ec = qp->ec;
2512         if (!ec) continue;
2513         if (e_object_is_del(E_OBJECT(ec))) continue;
2514
2515         evas_object_geometry_get(ec->frame,
2516                                  &x, &y, &w, &h);
2517
2518         if (E_INTERSECTS(x, y, w, h,
2519                          qp->zone->x,
2520                          qp->zone->y,
2521                          qp->zone->w,
2522                          qp->zone->h))
2523           {
2524              vis = evas_object_visible_get(ec->frame);
2525              if (vis) return EINA_TRUE;
2526           }
2527      }
2528
2529    return EINA_FALSE;
2530 }
2531
2532 EINTERN Eina_Bool
2533 e_qp_visible_get(E_Client *ec, E_Quickpanel_Type type)
2534 {
2535    E_Policy_Quickpanel *qp;
2536    E_QP_Client *qp_client;
2537    Eina_Bool vis = EINA_FALSE;
2538    int x, y, w, h;
2539
2540    BACKEND_FUNC_CALL_RET(qp_visible_get, ec, type);
2541
2542    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
2543    EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), EINA_FALSE);
2544
2545    qp_client = _e_qp_client_ec_get(ec, type);
2546    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE);
2547
2548    qp = _quickpanel_get_with_client_type(qp_client);
2549    EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE);
2550    EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE);
2551
2552    evas_object_geometry_get(qp->ec->frame, &x, &y, &w, &h);
2553
2554    if (E_INTERSECTS(x, y, w, h, qp->zone->x, qp->zone->y, qp->zone->w, qp->zone->h))
2555      vis = evas_object_visible_get(qp->ec->frame);
2556
2557    return vis;
2558 }
2559
2560 EINTERN int
2561 e_qp_orientation_get(E_Client *ec, E_Quickpanel_Type type)
2562 {
2563    E_Policy_Quickpanel *qp;
2564    E_QP_Client *qp_client;
2565
2566    BACKEND_FUNC_CALL_RET(qp_orientation_get, ec, type);
2567
2568    qp_client = _e_qp_client_ec_get(ec, type);
2569    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE);
2570
2571    qp = _quickpanel_get_with_client_type(qp_client);
2572    EINA_SAFETY_ON_NULL_RETURN_VAL(qp, E_POLICY_ANGLE_MAP_0);
2573    EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, E_POLICY_ANGLE_MAP_0);
2574    EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), E_POLICY_ANGLE_MAP_0);
2575
2576    return qp->rotation;
2577 }
2578
2579 EINTERN void
2580 e_qp_client_add(E_Client *ec, E_Quickpanel_Type type)
2581 {
2582    E_QP_Client *qp_client;
2583
2584    BACKEND_FUNC_CALL(qp_client_add, ec, type);
2585
2586    EINA_SAFETY_ON_NULL_RETURN(ec);
2587    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec)));
2588
2589    qp_client = _e_qp_client_ec_get(ec, type);
2590    if (qp_client)
2591      {
2592         qp_client->ref++;
2593         return;
2594      }
2595
2596    qp_client = E_NEW(E_QP_Client, 1);
2597    EINA_SAFETY_ON_NULL_RETURN(qp_client);
2598
2599    qp_client->ec = ec;
2600    qp_client->ref = 1;
2601    qp_client->hint.vis = EINA_TRUE;
2602    qp_client->hint.scrollable = E_QUICKPANEL_CLIENT_SCROLL_STATE_SET;
2603    qp_client->type = type;
2604
2605    qp_clients = eina_list_append(qp_clients, qp_client);
2606 }
2607
2608 EINTERN void
2609 e_qp_client_del(E_Client *ec, E_Quickpanel_Type type)
2610 {
2611    E_QP_Client *qp_client;
2612
2613    BACKEND_FUNC_CALL(qp_client_del, ec, type);
2614
2615    EINA_SAFETY_ON_NULL_RETURN(ec);
2616
2617    qp_client = _e_qp_client_ec_get(ec, type);
2618    EINA_SAFETY_ON_NULL_RETURN(qp_client);
2619
2620    qp_client->ref--;
2621    if (qp_client->ref != 0) return;
2622
2623    qp_clients = eina_list_remove(qp_clients, qp_client);
2624
2625    E_FREE(qp_client);
2626 }
2627
2628 static Eina_Bool
2629 _check_scrollable_state(E_QP_Client *qp_client)
2630 {
2631    if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_SET)
2632      return EINA_TRUE;
2633    else if (qp_client->hint.scrollable == E_QUICKPANEL_CLIENT_SCROLL_STATE_UNSET)
2634      return EINA_FALSE;
2635    else
2636      {
2637         E_Policy_Quickpanel *qp;
2638         qp = _quickpanel_get_with_client_type(qp_client);
2639         if (!qp) return EINA_FALSE;
2640
2641         return _e_qp_check_scrollable(qp);
2642      }
2643 }
2644
2645 EINTERN void
2646 e_qp_client_show(E_Client *ec, E_Quickpanel_Type type)
2647 {
2648    E_Policy_Quickpanel *qp;
2649    E_QP_Client *qp_client;
2650
2651    ELOGF("QUICKPANEL", "Request to Show Quickpanel (type:%d)", ec, type);
2652    BACKEND_FUNC_CALL(qp_client_show, ec, type);
2653
2654    qp_client = _e_qp_client_ec_get(ec, type);
2655    EINA_SAFETY_ON_NULL_RETURN(qp_client);
2656
2657    Eina_Bool scrollable = _check_scrollable_state(qp_client);
2658    if (!scrollable)
2659      {
2660         ELOGF("QUICKPANEL", "Doesn't Show Quickpanel. scrollable_state:%d", ec, qp_client->hint.scrollable);
2661         return;
2662      }
2663
2664    qp = _quickpanel_get_with_client_type(qp_client);
2665    EINA_SAFETY_ON_NULL_RETURN(qp);
2666    EINA_SAFETY_ON_NULL_RETURN(qp->ec);
2667    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec)));
2668
2669    _e_qp_srv_visible_set(qp, EINA_TRUE);
2670 }
2671
2672 EINTERN void
2673 e_qp_client_hide(E_Client *ec, E_Quickpanel_Type type)
2674 {
2675    E_Policy_Quickpanel *qp;
2676    E_QP_Client *qp_client;
2677
2678    ELOGF("QUICKPANEL", "Request to Hide Quickpanel (type:%d)", ec, type);
2679    BACKEND_FUNC_CALL(qp_client_hide, ec, type);
2680
2681    qp_client = _e_qp_client_ec_get(ec, type);
2682    EINA_SAFETY_ON_NULL_RETURN(qp_client);
2683
2684    Eina_Bool scrollable = _check_scrollable_state(qp_client);
2685    if (!scrollable)
2686      {
2687         ELOGF("QUICKPANEL", "Doesn't Hide Quickpanel. scrollable_state:%d", ec, qp_client->hint.scrollable);
2688         return;
2689      }
2690
2691    qp = _quickpanel_get_with_client_type(qp_client);
2692    EINA_SAFETY_ON_NULL_RETURN(qp);
2693    EINA_SAFETY_ON_NULL_RETURN(qp->ec);
2694    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec)));
2695
2696    _e_qp_srv_visible_set(qp, EINA_FALSE);
2697 }
2698
2699 EINTERN Eina_Bool
2700 e_qp_client_scrollable_set(E_Client *ec, E_Quickpanel_Type type, Eina_Bool set)
2701 {
2702    /*
2703       USE e_qp_client_scrollable_state_set() function instead of this function.
2704       This will be DEPRECATED.
2705    */
2706    Eina_Bool ret;
2707
2708    ELOGF("QUICKPANEL", "Request to Set scrollable state of Quickpanel (type:%d) to %d", ec, type, set);
2709    BACKEND_FUNC_CALL_RET(qp_client_scrollable_set, ec, type, set);
2710
2711    if (set)
2712      ret = _e_qp_client_scrollable_state_set(ec, type, E_QUICKPANEL_CLIENT_SCROLL_STATE_SET);
2713    else
2714      ret = _e_qp_client_scrollable_state_set(ec, type, E_QUICKPANEL_CLIENT_SCROLL_STATE_UNSET);
2715
2716    return ret;
2717 }
2718
2719 EINTERN Eina_Bool
2720 e_qp_client_scrollable_get(E_Client *ec, E_Quickpanel_Type type)
2721 {
2722    /*
2723       USE e_qp_client_scrollable_state_get() function instead of this function.
2724       This will be DEPRECATED.
2725    */
2726    int scrollable_state;
2727
2728    BACKEND_FUNC_CALL_RET(qp_client_scrollable_get, ec, type);
2729
2730    scrollable_state = _e_qp_client_scrollable_state_get(ec, type);
2731    if (scrollable_state == E_QUICKPANEL_CLIENT_SCROLL_STATE_UNSET)
2732      return EINA_FALSE;
2733    else
2734      return EINA_TRUE;
2735 }
2736
2737 static Eina_Bool
2738 _e_qp_client_scrollable_state_set(E_Client *ec, E_Quickpanel_Type type, E_Quickpanel_Client_Scroll_State state)
2739 {
2740    E_Policy_Quickpanel *qp;
2741    E_QP_Client *qp_client;
2742
2743    qp_client = _e_qp_client_ec_get(ec, type);
2744    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE);
2745
2746    if (qp_client->hint.scrollable != state)
2747      qp_client->hint.scrollable = state;
2748
2749    qp = _quickpanel_get_with_client_type(qp_client);
2750    EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE);
2751    EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE);
2752    EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE);
2753
2754    _e_qp_client_scrollable_update(qp);
2755
2756    return EINA_TRUE;
2757 }
2758
2759 static E_Quickpanel_Client_Scroll_State
2760 _e_qp_client_scrollable_state_get(E_Client *ec, E_Quickpanel_Type type)
2761 {
2762    E_QP_Client *qp_client;
2763
2764    qp_client = _e_qp_client_ec_get(ec, type);
2765    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, E_QUICKPANEL_CLIENT_SCROLL_STATE_UNSET);
2766
2767    return qp_client->hint.scrollable;
2768 }
2769
2770 EINTERN Eina_Bool
2771 e_qp_client_scrollable_state_set(E_Client *ec, E_Quickpanel_Type type, E_Quickpanel_Client_Scroll_State state)
2772 {
2773    ELOGF("QUICKPANEL", "Request to Set scrollable state of Quickpanel(type:%d) to %d", ec, type, state);
2774    BACKEND_FUNC_CALL_RET(qp_client_scrollable_state_set, ec, type, state);
2775
2776    return _e_qp_client_scrollable_state_set(ec, type, state);
2777 }
2778
2779 EINTERN E_Quickpanel_Client_Scroll_State
2780 e_qp_client_scrollable_state_get(E_Client *ec, E_Quickpanel_Type type)
2781 {
2782    E_QP_Client *qp_client;
2783
2784    BACKEND_FUNC_CALL_RET(qp_client_scrollable_state_get, ec, type);
2785
2786    qp_client = _e_qp_client_ec_get(ec, type);
2787    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE);
2788
2789    return qp_client->hint.scrollable;
2790 }
2791
2792 E_API Eina_Bool
2793 e_service_quickpanel_module_func_set(E_QP_Mgr_Funcs *fp)
2794 {
2795    EINA_SAFETY_ON_FALSE_RETURN_VAL(e_config->use_module_srv.qp, EINA_FALSE);
2796    EINA_SAFETY_ON_FALSE_RETURN_VAL((qp_mgr_funcs == NULL), EINA_FALSE);
2797    EINA_SAFETY_ON_NULL_RETURN_VAL(fp, EINA_FALSE);
2798
2799    qp_mgr_funcs = E_NEW(E_QP_Mgr_Funcs, 1);
2800    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_mgr_funcs, EINA_FALSE);
2801
2802    qp_mgr_funcs->quickpanel_client_add = fp->quickpanel_client_add;
2803    qp_mgr_funcs->quickpanel_client_del = fp->quickpanel_client_del;
2804    qp_mgr_funcs->quickpanel_show = fp->quickpanel_show;
2805    qp_mgr_funcs->quickpanel_hide = fp->quickpanel_hide;
2806    qp_mgr_funcs->quickpanel_region_set = fp->quickpanel_region_set;
2807    qp_mgr_funcs->quickpanel_effect_type_set = fp->quickpanel_effect_type_set;
2808    qp_mgr_funcs->quickpanel_scroll_lock_set = fp->quickpanel_scroll_lock_set;
2809    qp_mgr_funcs->quickpanel_type_get = fp->quickpanel_type_get;
2810    qp_mgr_funcs->qps_visible_get = fp->qps_visible_get;
2811    qp_mgr_funcs->qp_visible_get = fp->qp_visible_get;
2812    qp_mgr_funcs->qp_orientation_get = fp->qp_orientation_get;
2813    qp_mgr_funcs->qp_client_add = fp->qp_client_add;
2814    qp_mgr_funcs->qp_client_del = fp->qp_client_del;
2815    qp_mgr_funcs->qp_client_show = fp->qp_client_show;
2816    qp_mgr_funcs->qp_client_hide = fp->qp_client_hide;
2817    qp_mgr_funcs->qp_client_scrollable_set = fp->qp_client_scrollable_set;
2818    qp_mgr_funcs->qp_client_scrollable_get = fp->qp_client_scrollable_get;
2819    qp_mgr_funcs->qp_client_scrollable_state_set = fp->qp_client_scrollable_state_set;
2820    qp_mgr_funcs->qp_client_scrollable_state_get = fp->qp_client_scrollable_state_get;
2821    return EINA_TRUE;
2822 }
2823
2824 E_API Eina_Bool
2825 e_service_quickpanel_module_func_unset(void)
2826 {
2827    EINA_SAFETY_ON_FALSE_RETURN_VAL(e_config->use_module_srv.qp, EINA_FALSE);
2828    EINA_SAFETY_ON_NULL_RETURN_VAL(qp_mgr_funcs, EINA_FALSE);
2829
2830    E_FREE(qp_mgr_funcs);
2831
2832    return EINA_TRUE;
2833 }
2834
2835 E_API Eina_List *
2836 e_service_quickpanels_get(void)
2837 {
2838    Eina_List *l, *list = NULL;
2839    E_Policy_Quickpanel *qp;
2840
2841    EINA_LIST_FOREACH(qp_services, l, qp)
2842      {
2843         list = eina_list_append(list, qp->ec);
2844      }
2845
2846    return list;
2847 }