Tizen 2.1 release
[platform/core/uifw/e17.git] / src / modules / illume2 / e_mod_quickpanel.c
1 #include "e_illume_private.h"
2 #include "e_mod_quickpanel.h"
3
4 /* local function prototypes */
5 static Eina_Bool _e_mod_quickpanel_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event);
6 static Eina_Bool _e_mod_quickpanel_cb_mouse_up(void *data, int type __UNUSED__, void *event);
7 static Eina_Bool _e_mod_quickpanel_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event);
8 static Eina_Bool _e_mod_quickpanel_cb_border_remove(void *data __UNUSED__, int type __UNUSED__, void *event);
9 static Eina_Bool _e_mod_quickpanel_cb_border_resize(void *data __UNUSED__, int type __UNUSED__, void *event);
10 static Eina_Bool _e_mod_quickpanel_cb_border_uniconify(void *data __UNUSED__, int type __UNUSED__, void *event);
11 static void _e_mod_quickpanel_cb_post_fetch(void *data __UNUSED__, void *data2);
12 static void _e_mod_quickpanel_cb_free(E_Illume_Quickpanel *qp);
13 static Eina_Bool _e_mod_quickpanel_cb_delay_hide(void *data);
14 static void _e_mod_quickpanel_slide(E_Illume_Quickpanel *qp, int visible, double len);
15 static void _e_mod_quickpanel_hide(E_Illume_Quickpanel *qp);
16 static Eina_Bool _e_mod_quickpanel_cb_animate(void *data);
17 static void _e_mod_quickpanel_position_update(E_Illume_Quickpanel *qp);
18 static void _e_mod_quickpanel_animate_down(E_Illume_Quickpanel *qp);
19 static void _e_mod_quickpanel_animate_up(E_Illume_Quickpanel *qp);
20 static void _e_mod_quickpanel_clickwin_show(E_Illume_Quickpanel *qp);
21 static void _e_mod_quickpanel_clickwin_hide(E_Illume_Quickpanel *qp);
22
23 /* local variables */
24 static Eina_List *_qp_hdls = NULL;
25 static E_Border_Hook *_qp_hook = NULL;
26
27 int 
28 e_mod_quickpanel_init(void) 
29 {
30    /* add handlers for messages we are interested in */
31    _qp_hdls = 
32      eina_list_append(_qp_hdls, 
33                       ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, 
34                                               _e_mod_quickpanel_cb_client_message, 
35                                               NULL));
36    _qp_hdls = 
37      eina_list_append(_qp_hdls, 
38                       ecore_event_handler_add(E_EVENT_BORDER_ADD, 
39                                               _e_mod_quickpanel_cb_border_add, 
40                                               NULL));
41    _qp_hdls = 
42      eina_list_append(_qp_hdls, 
43                       ecore_event_handler_add(E_EVENT_BORDER_REMOVE, 
44                                               _e_mod_quickpanel_cb_border_remove,
45                                               NULL));
46    _qp_hdls = 
47      eina_list_append(_qp_hdls, 
48                       ecore_event_handler_add(E_EVENT_BORDER_RESIZE, 
49                                               _e_mod_quickpanel_cb_border_resize, 
50                                               NULL));
51    _qp_hdls = 
52      eina_list_append(_qp_hdls, 
53                       ecore_event_handler_add(E_EVENT_BORDER_UNICONIFY, 
54                                               _e_mod_quickpanel_cb_border_uniconify, 
55                                               NULL));
56
57    /* add hook for new borders so we can test for qp borders */
58    _qp_hook = e_border_hook_add(E_BORDER_HOOK_EVAL_PRE_POST_FETCH, 
59                                 _e_mod_quickpanel_cb_post_fetch, NULL);
60
61    return 1;
62 }
63
64 int 
65 e_mod_quickpanel_shutdown(void) 
66 {
67    Ecore_Event_Handler *hdl;
68
69    /* delete the event handlers */
70    EINA_LIST_FREE(_qp_hdls, hdl)
71      ecore_event_handler_del(hdl);
72
73    /* delete the border hook */
74    if (_qp_hook) e_border_hook_del(_qp_hook);
75    _qp_hook = NULL;
76
77    return 1;
78 }
79
80 E_Illume_Quickpanel *
81 e_mod_quickpanel_new(E_Zone *zone) 
82 {
83    E_Illume_Quickpanel *qp;
84
85    /* try to allocate a new quickpanel object */
86    qp = E_OBJECT_ALLOC(E_Illume_Quickpanel, E_ILLUME_QP_TYPE, 
87                        _e_mod_quickpanel_cb_free);
88    if (!qp) return NULL;
89
90    /* set quickpanel zone */
91    qp->zone = zone;
92    qp->vert.dir = 0;
93    qp->mouse_hdl = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, 
94                                            _e_mod_quickpanel_cb_mouse_up, qp);
95
96    return qp;
97 }
98
99 void 
100 e_mod_quickpanel_show(E_Illume_Quickpanel *qp) 
101 {
102    E_Illume_Config_Zone *cz;
103    int duration;
104
105    if (!qp) return;
106
107    /* delete the animator if it exists */
108    if (qp->animator) ecore_animator_del(qp->animator);
109    qp->animator = NULL;
110
111    /* delete any existing timer */
112    if (qp->timer) ecore_timer_del(qp->timer);
113    qp->timer = NULL;
114
115    /* if it's already visible, or has no borders to show, then get out */
116    if ((qp->visible) || (!qp->borders)) return;
117
118    duration = _e_illume_cfg->animation.quickpanel.duration;
119
120    /* grab the height of the indicator */
121    cz = e_illume_zone_config_get(qp->zone->num);
122    qp->vert.isize = cz->indicator.size;
123
124    /* check animation duration */
125    if (duration <= 0) 
126      {
127         Eina_List *l;
128         E_Border *bd;
129         int ny = 0;
130
131         ny = qp->vert.isize;
132         if (qp->vert.dir == 1) ny = 0;
133
134         /* if we are not animating, just show the borders */
135         EINA_LIST_FOREACH(qp->borders, l, bd) 
136           {
137              if (!bd->visible) e_illume_border_show(bd);
138              if (qp->vert.dir == 0) 
139                {
140                   e_border_fx_offset(bd, 0, ny);
141                   ny += bd->h;
142                }
143              else 
144                {
145                   ny -= bd->h;
146                   e_border_fx_offset(bd, 0, ny);
147                }
148           }
149         qp->visible = 1;
150         _e_mod_quickpanel_clickwin_show(qp);
151      }
152    else 
153      _e_mod_quickpanel_slide(qp, 1, (double)duration / 1000.0);
154 }
155
156 void 
157 e_mod_quickpanel_hide(E_Illume_Quickpanel *qp) 
158 {
159    if (!qp->visible) return;
160    if (!qp->timer) 
161      qp->timer = ecore_timer_add(0.2, _e_mod_quickpanel_cb_delay_hide, qp);
162 }
163
164 /* local functions */
165 static Eina_Bool
166 _e_mod_quickpanel_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event) 
167 {
168    Ecore_X_Event_Client_Message *ev;
169
170    ev = event;
171    if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE) 
172      {
173         E_Zone *zone;
174
175         if ((zone = e_util_zone_window_find(ev->win))) 
176           {
177              E_Illume_Quickpanel *qp;
178
179              if ((qp = e_illume_quickpanel_by_zone_get(zone))) 
180                {
181                   if (ev->data.l[0] == (int)ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF)
182                     _e_mod_quickpanel_hide(qp);
183                   else
184                     e_mod_quickpanel_show(qp);
185                }
186           }
187      }
188    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE) 
189      {
190         E_Zone *zone;
191
192         if ((zone = e_util_zone_window_find(ev->win))) 
193           {
194              E_Illume_Quickpanel *qp;
195
196              if ((qp = e_illume_quickpanel_by_zone_get(zone))) 
197                {
198                   if (qp->visible) 
199                     _e_mod_quickpanel_hide(qp);
200                   else 
201                     e_mod_quickpanel_show(qp);
202                }
203           }
204      }
205    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE) 
206      {
207         E_Border *bd;
208         E_Illume_Quickpanel *qp;
209
210         if (!(bd = e_border_find_by_client_window(ev->win))) 
211           return ECORE_CALLBACK_PASS_ON;
212         if (!(qp = e_illume_quickpanel_by_zone_get(bd->zone))) 
213           return ECORE_CALLBACK_PASS_ON;
214         _e_mod_quickpanel_position_update(qp);
215      }
216
217    return ECORE_CALLBACK_PASS_ON;
218 }
219
220 static Eina_Bool
221 _e_mod_quickpanel_cb_mouse_up(void *data, int type __UNUSED__, void *event) 
222 {
223    Ecore_Event_Mouse_Button *ev;
224    E_Illume_Quickpanel *qp;
225
226    ev = event;
227    if (!(qp = data)) return ECORE_CALLBACK_PASS_ON;
228    if (ev->event_window != qp->clickwin) return ECORE_CALLBACK_PASS_ON;
229    if (qp->visible) e_mod_quickpanel_hide(qp);
230    return ECORE_CALLBACK_PASS_ON;
231 }
232
233 static Eina_Bool
234 _e_mod_quickpanel_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event) 
235 {
236    E_Event_Border_Add *ev;
237    E_Illume_Quickpanel *qp;
238    E_Zone *zone;
239    int iy;
240
241    ev = event;
242    if (!ev->border->client.illume.quickpanel.quickpanel) 
243      return ECORE_CALLBACK_PASS_ON;
244
245    if (!(zone = ev->border->zone)) return ECORE_CALLBACK_PASS_ON;
246
247    /* if this border should be on a different zone, get requested zone */
248    if ((int)zone->num != ev->border->client.illume.quickpanel.zone) 
249      {
250         E_Container *con;
251         int zn = 0;
252
253         /* find this zone */
254         if (!(con = e_container_current_get(e_manager_current_get())))
255           return ECORE_CALLBACK_PASS_ON;
256         zn = ev->border->client.illume.quickpanel.zone;
257         zone = e_util_container_zone_number_get(con->num, zn);
258         if (!zone) zone = e_util_container_zone_number_get(con->num, 0);
259         if (!zone) return ECORE_CALLBACK_PASS_ON;
260      }
261
262    if (!(qp = e_illume_quickpanel_by_zone_get(zone))) 
263      return ECORE_CALLBACK_PASS_ON;
264
265    /* set position and zone */
266    e_illume_border_indicator_pos_get(zone, NULL, &iy);
267    if ((ev->border->x != zone->x) || (ev->border->y != iy)) 
268      e_border_move(ev->border, zone->x, iy);
269    if (ev->border->zone != zone) 
270      e_border_zone_set(ev->border, zone);
271    
272    /* hide this border */
273    e_illume_border_hide(ev->border);
274
275    qp->vert.size += ev->border->h;
276
277    /* add this border to QP border collection */
278    qp->borders = eina_list_append(qp->borders, ev->border);
279
280    return ECORE_CALLBACK_PASS_ON;
281 }
282
283 static Eina_Bool
284 _e_mod_quickpanel_cb_border_remove(void *data __UNUSED__, int type __UNUSED__, void *event) 
285 {
286    E_Event_Border_Remove *ev;
287    E_Illume_Quickpanel *qp;
288    E_Zone *zone;
289    Eina_List *l;
290    E_Border *bd;
291
292    ev = event;
293    if (!ev->border->client.illume.quickpanel.quickpanel) 
294      return ECORE_CALLBACK_PASS_ON;
295
296    if (!(zone = ev->border->zone)) return ECORE_CALLBACK_PASS_ON;
297
298    /* if this border should be on a different zone, get requested zone */
299    if ((int)zone->num != ev->border->client.illume.quickpanel.zone) 
300      {
301         E_Container *con;
302         int zn = 0;
303
304         /* find this zone */
305         if (!(con = e_container_current_get(e_manager_current_get())))
306           return ECORE_CALLBACK_PASS_ON;
307         zn = ev->border->client.illume.quickpanel.zone;
308         zone = e_util_container_zone_number_get(con->num, zn);
309         if (!zone) zone = e_util_container_zone_number_get(con->num, 0);
310         if (!zone) return ECORE_CALLBACK_PASS_ON;
311      }
312
313    if (!(qp = e_illume_quickpanel_by_zone_get(zone))) 
314      return ECORE_CALLBACK_PASS_ON;
315
316    /* add this border to QP border collection */
317    if (qp->borders) 
318      qp->borders = eina_list_remove(qp->borders, ev->border);
319
320    qp->vert.size = 0;
321    EINA_LIST_FOREACH(qp->borders, l, bd)
322      qp->vert.size += bd->h;
323
324    return ECORE_CALLBACK_PASS_ON;
325 }
326
327 static Eina_Bool
328 _e_mod_quickpanel_cb_border_resize(void *data __UNUSED__, int type __UNUSED__, void *event) 
329 {
330    E_Event_Border_Resize *ev;
331    E_Illume_Quickpanel *qp;
332    Eina_List *l;
333    E_Border *bd;
334
335    ev = event;
336    if (!ev->border->client.illume.quickpanel.quickpanel) 
337      return ECORE_CALLBACK_PASS_ON;
338    if (!(qp = e_illume_quickpanel_by_zone_get(ev->border->zone))) 
339      return ECORE_CALLBACK_PASS_ON;
340
341    qp->vert.size = 0;
342    EINA_LIST_FOREACH(qp->borders, l, bd)
343      qp->vert.size += bd->h;
344
345    return ECORE_CALLBACK_PASS_ON;
346 }
347
348 static Eina_Bool 
349 _e_mod_quickpanel_cb_border_uniconify(void *data __UNUSED__, int type __UNUSED__, void *event) 
350 {
351    E_Event_Border_Uniconify *ev;
352    E_Illume_Quickpanel *qp;
353
354    ev = event;
355    if (!ev->border->client.illume.quickpanel.quickpanel)
356      return ECORE_CALLBACK_PASS_ON;
357    if (!(qp = e_illume_quickpanel_by_zone_get(ev->border->zone)))
358      return ECORE_CALLBACK_PASS_ON;
359    e_mod_quickpanel_show(qp);
360    return ECORE_CALLBACK_PASS_ON;
361 }
362
363 static void 
364 _e_mod_quickpanel_cb_post_fetch(void *data __UNUSED__, void *data2) 
365 {
366    E_Border *bd;
367
368    if (!(bd = data2)) return;
369    if (!bd->client.illume.quickpanel.quickpanel) return;
370    bd->stolen = 1;
371 }
372
373 static void 
374 _e_mod_quickpanel_cb_free(E_Illume_Quickpanel *qp) 
375 {
376    E_Border *bd;
377
378    /* delete the animator if it exists */
379    if (qp->animator) ecore_animator_del(qp->animator);
380    qp->animator = NULL;
381
382    /* delete the timer if it exists */
383    if (qp->timer) ecore_timer_del(qp->timer);
384    qp->timer = NULL;
385
386    /* delete the clickwin */
387    if (qp->clickwin) ecore_x_window_free(qp->clickwin);
388    qp->clickwin = 0;
389
390    /* delete the mouse handler */
391    if (qp->mouse_hdl) ecore_event_handler_del(qp->mouse_hdl);
392    qp->mouse_hdl = NULL;
393
394    /* set the borders of this quickpanel to not stolen */
395    EINA_LIST_FREE(qp->borders, bd)
396      bd->stolen = 0;
397
398    /* free the structure */
399    E_FREE(qp);
400 }
401
402 static Eina_Bool
403 _e_mod_quickpanel_cb_delay_hide(void *data) 
404 {
405    E_Illume_Quickpanel *qp;
406
407    if (!(qp = data)) return ECORE_CALLBACK_CANCEL;
408    _e_mod_quickpanel_hide(qp);
409    return ECORE_CALLBACK_CANCEL;
410 }
411
412 static void 
413 _e_mod_quickpanel_slide(E_Illume_Quickpanel *qp, int visible, double len) 
414 {
415    if (!qp) return;
416    qp->start = ecore_loop_time_get();
417    qp->len = len;
418    qp->vert.adjust_start = qp->vert.adjust;
419    qp->vert.adjust_end = 0;
420    if (qp->vert.dir == 0) 
421      {
422         if (visible) qp->vert.adjust_end = qp->vert.size;
423      }
424    else 
425      {
426         if (visible) qp->vert.adjust_end = -qp->vert.size;
427      }
428
429    if (!qp->animator) 
430      qp->animator = ecore_animator_add(_e_mod_quickpanel_cb_animate, qp);
431 }
432
433 static void 
434 _e_mod_quickpanel_hide(E_Illume_Quickpanel *qp) 
435 {
436    int duration;
437
438    if (!qp) return;
439
440    /* delete the animator if it exists */
441    if (qp->animator) ecore_animator_del(qp->animator);
442    qp->animator = NULL;
443
444    /* delete the timer if it exists */
445    if (qp->timer) ecore_timer_del(qp->timer);
446    qp->timer = NULL;
447
448    /* if it's not visible, we can't hide it */
449    if (!qp->visible) return;
450
451    duration = _e_illume_cfg->animation.quickpanel.duration;
452
453    if (duration <= 0) 
454      {
455         Eina_List *l;
456         E_Border *bd;
457
458         /* if we are not animating, hide the qp borders */
459         EINA_LIST_REVERSE_FOREACH(qp->borders, l, bd) 
460           {
461              e_border_fx_offset(bd, 0, 0);
462              if (bd->visible) e_illume_border_hide(bd);
463           }
464         qp->visible = 0;
465         _e_mod_quickpanel_clickwin_hide(qp);
466      }
467    else
468      _e_mod_quickpanel_slide(qp, 0, (double)duration / 1000.0);
469 }
470
471 static Eina_Bool
472 _e_mod_quickpanel_cb_animate(void *data) 
473 {
474    E_Illume_Quickpanel *qp;
475    double t, v = 1.0;
476
477    if (!(qp = data)) return ECORE_CALLBACK_CANCEL;
478    t = (ecore_loop_time_get() - qp->start);
479    if (t > qp->len) t = qp->len;
480    if (qp->len > 0.0) 
481      {
482         v = (t / qp->len);
483         v = (1.0 - v);
484         v = (v * v * v * v);
485         v = (1.0 - v);
486      }
487    else 
488      t = qp->len;
489
490    qp->vert.adjust = ((qp->vert.adjust_end * v) + 
491                       (qp->vert.adjust_start * (1.0 - v)));
492
493    if (qp->vert.dir == 0) _e_mod_quickpanel_animate_down(qp);
494    else _e_mod_quickpanel_animate_up(qp);
495
496    if (t == qp->len) 
497      {
498         qp->animator = NULL;
499         if (qp->visible) 
500           {
501              qp->visible = 0;
502              _e_mod_quickpanel_clickwin_hide(qp);
503           }
504         else 
505           {
506              qp->visible = 1;
507              _e_mod_quickpanel_clickwin_show(qp);
508           }
509         return ECORE_CALLBACK_CANCEL;
510      }
511
512    return ECORE_CALLBACK_RENEW;
513 }
514
515 static void 
516 _e_mod_quickpanel_position_update(E_Illume_Quickpanel *qp) 
517 {
518    Eina_List *l;
519    E_Border *bd;
520    int iy = 0;
521
522    if (!qp) return;
523    _e_mod_quickpanel_hide(qp);
524    if (!qp->zone) return;
525    e_illume_border_indicator_pos_get(qp->zone, NULL, &iy);
526    EINA_LIST_FOREACH(qp->borders, l, bd) 
527      e_border_move(bd, qp->zone->x, iy);
528
529    qp->vert.dir = 0;
530    if ((iy + qp->vert.isize + qp->vert.size) > qp->zone->h) qp->vert.dir = 1;
531 }
532
533 static void 
534 _e_mod_quickpanel_animate_down(E_Illume_Quickpanel *qp) 
535 {
536    Eina_List *l;
537    E_Border *bd;
538    int pbh = 0;
539
540    if (!qp) return;
541    pbh = (qp->vert.isize - qp->vert.size);
542    EINA_LIST_FOREACH(qp->borders, l, bd) 
543      {
544         /* don't adjust borders that are being deleted */
545         if (e_object_is_del(E_OBJECT(bd))) continue;
546         if (bd->fx.y != (qp->vert.adjust + pbh)) 
547           e_border_fx_offset(bd, 0, (qp->vert.adjust + pbh));
548         pbh += bd->h;
549
550         if (!qp->visible) 
551           {
552              if (bd->fx.y > 0) 
553                {
554                   if (!bd->visible) e_illume_border_show(bd);
555                }
556           }
557         else 
558           {
559              if (bd->fx.y <= 10) 
560                {
561                   if (bd->visible) e_illume_border_hide(bd);
562                }
563           }
564      }
565 }
566
567 static void 
568 _e_mod_quickpanel_animate_up(E_Illume_Quickpanel *qp) 
569 {
570    Eina_List *l;
571    E_Border *bd;
572    int pbh = 0;
573
574    if (!qp) return;
575    pbh = qp->vert.size;
576    EINA_LIST_FOREACH(qp->borders, l, bd) 
577      {
578         /* don't adjust borders that are being deleted */
579         if (e_object_is_del(E_OBJECT(bd))) continue;
580         pbh -= bd->h;
581         if (bd->fx.y != (qp->vert.adjust + pbh)) 
582           e_border_fx_offset(bd, 0, (qp->vert.adjust + pbh));
583
584         if (!qp->visible) 
585           {
586              if (bd->fx.y < 0) 
587                {
588                   if (!bd->visible) e_illume_border_show(bd);
589                }
590           }
591         else 
592           {
593              if (bd->fx.y >= -10) 
594                {
595                   if (bd->visible) e_illume_border_hide(bd);
596                }
597           }
598      }
599 }
600
601 static void 
602 _e_mod_quickpanel_clickwin_show(E_Illume_Quickpanel *qp) 
603 {
604    E_Border *ind;
605
606    if ((!qp) || (!qp->borders) || (!qp->zone)) return;
607    if (!(ind = eina_list_nth(qp->borders, 0))) return;
608
609    if (qp->clickwin) ecore_x_window_free(qp->clickwin);
610    qp->clickwin = 0;
611    qp->clickwin = ecore_x_window_input_new(qp->zone->container->win, 
612                                            qp->zone->x, qp->zone->y, 
613                                            qp->zone->w, qp->zone->h);
614
615    ecore_x_window_configure(qp->clickwin, 
616                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | 
617                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, 
618                             qp->zone->x, qp->zone->y, 
619                             qp->zone->w, qp->zone->h, 0, 
620                             ind->win, ECORE_X_WINDOW_STACK_BELOW);
621
622    ecore_x_window_show(qp->clickwin);
623 }
624
625 static void 
626 _e_mod_quickpanel_clickwin_hide(E_Illume_Quickpanel *qp) 
627 {
628    if (!qp) return;
629    if (qp->clickwin) ecore_x_window_free(qp->clickwin);
630    qp->clickwin = 0;
631 }