update for beta release
[framework/uifw/e17.git] / src / bin / e_bindings.c
1 #include "e.h"
2
3 /* local subsystem functions */
4 static Eina_Bool _e_bindings_mapping_change_event_cb(void *data, int type, void *event);
5
6 static void _e_bindings_mouse_free(E_Binding_Mouse *bind);
7 static void _e_bindings_key_free(E_Binding_Key *bind);
8 static void _e_bindings_edge_free(E_Binding_Edge *bind);
9 static void _e_bindings_signal_free(E_Binding_Signal *bind);
10 static void _e_bindings_wheel_free(E_Binding_Wheel *bind);
11 static void _e_bindings_acpi_free(E_Binding_Acpi *bind);
12 static int _e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt);
13 static E_Binding_Modifier _e_bindings_modifiers(unsigned int modifiers);
14 static int _e_ecore_modifiers(E_Binding_Modifier modifiers);
15 static Eina_Bool _e_bindings_edge_cb_timer(void *data);
16
17 /* local subsystem globals */
18
19 static Ecore_Event_Handler *mapping_handler = NULL;
20
21 static Eina_List *mouse_bindings = NULL;
22 static Eina_List *key_bindings = NULL;
23 static Eina_List *edge_bindings = NULL;
24 static Eina_List *signal_bindings = NULL;
25 static Eina_List *wheel_bindings = NULL;
26 static Eina_List *acpi_bindings = NULL;
27
28 typedef struct _E_Binding_Edge_Data E_Binding_Edge_Data;
29
30 struct _E_Binding_Edge_Data
31 {
32    E_Binding_Edge    *bind;
33    E_Event_Zone_Edge *ev;
34    E_Action          *act;
35    E_Object          *obj;
36 };
37
38 /* externally accessible functions */
39
40 EINTERN int
41 e_bindings_init(void)
42 {
43    E_Config_Binding_Signal *ebs;
44    E_Config_Binding_Mouse *ebm;
45    E_Config_Binding_Wheel *ebw;
46    E_Config_Binding_Edge *ebe;
47    E_Config_Binding_Key *ebk;
48    E_Config_Binding_Acpi *eba;
49    Eina_List *l;
50
51    mapping_handler = ecore_event_handler_add
52       (ECORE_X_EVENT_MAPPING_CHANGE, _e_bindings_mapping_change_event_cb, NULL);
53
54    EINA_LIST_FOREACH(e_config->mouse_bindings, l, ebm)
55      e_bindings_mouse_add(ebm->context, ebm->button, ebm->modifiers,
56                           ebm->any_mod, ebm->action, ebm->params);
57
58    EINA_LIST_FOREACH(e_config->key_bindings, l, ebk)
59      e_bindings_key_add(ebk->context, ebk->key, ebk->modifiers,
60                         ebk->any_mod, ebk->action, ebk->params);
61
62    EINA_LIST_FOREACH(e_config->edge_bindings, l, ebe)
63      e_bindings_edge_add(ebe->context, ebe->edge, ebe->modifiers,
64                          ebe->any_mod, ebe->action, ebe->params, ebe->delay);
65
66    EINA_LIST_FOREACH(e_config->signal_bindings, l, ebs)
67      {
68         e_bindings_signal_add(ebs->context, ebs->signal, ebs->source, ebs->modifiers,
69                               ebs->any_mod, ebs->action, ebs->params);
70         /* FIXME: Can this be solved in a generic way? */
71         /* FIXME: Only change cursor if action is allowed! */
72         if ((ebs->action) && (ebs->signal) && (ebs->source) &&
73             (!strcmp(ebs->action, "window_resize")) &&
74             (!strncmp(ebs->signal, "mouse,down,", 11)) &&
75             (!strncmp(ebs->source, "e.event.resize.", 15)))
76           {
77              char params[32];
78
79              snprintf(params, sizeof(params), "resize_%s", ebs->params);
80              e_bindings_signal_add(ebs->context, "mouse,in", ebs->source, ebs->modifiers,
81                                    ebs->any_mod, "pointer_resize_push", params);
82              e_bindings_signal_add(ebs->context, "mouse,out", ebs->source, ebs->modifiers,
83                                    ebs->any_mod, "pointer_resize_pop", params);
84           }
85      }
86
87    EINA_LIST_FOREACH(e_config->wheel_bindings, l, ebw)
88      e_bindings_wheel_add(ebw->context, ebw->direction, ebw->z, ebw->modifiers,
89                           ebw->any_mod, ebw->action, ebw->params);
90
91    EINA_LIST_FOREACH(e_config->acpi_bindings, l, eba)
92      e_bindings_acpi_add(eba->context, eba->type, eba->status, 
93                          eba->action, eba->params);
94
95    return 1;
96 }
97
98 EINTERN int
99 e_bindings_shutdown(void)
100 {
101    E_FREE_LIST(mouse_bindings, _e_bindings_mouse_free);
102    E_FREE_LIST(key_bindings, _e_bindings_key_free);
103    E_FREE_LIST(edge_bindings, _e_bindings_edge_free);
104    E_FREE_LIST(signal_bindings, _e_bindings_signal_free);
105    E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free);
106    E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free);
107  
108    if (mapping_handler)
109       {
110          ecore_event_handler_del(mapping_handler);
111          mapping_handler = NULL;
112       }
113   
114    return 1;
115 }
116
117 EAPI void
118 e_bindings_mouse_add(E_Binding_Context ctxt, int button, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
119 {
120    E_Binding_Mouse *bind;
121
122    bind = calloc(1, sizeof(E_Binding_Mouse));
123    bind->ctxt = ctxt;
124    bind->button = button;
125    bind->mod = mod;
126    bind->any_mod = any_mod;
127    if (action) bind->action = eina_stringshare_add(action);
128    if (params) bind->params = eina_stringshare_add(params);
129    mouse_bindings = eina_list_append(mouse_bindings, bind);
130 }
131
132 EAPI void
133 e_bindings_mouse_del(E_Binding_Context ctxt, int button, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
134 {
135    E_Binding_Mouse *bind;
136    Eina_List *l;
137
138    EINA_LIST_FOREACH(mouse_bindings, l, bind)
139      {
140         if ((bind->ctxt == ctxt) &&
141             (bind->button == button) &&
142             (bind->mod == mod) &&
143             (bind->any_mod == any_mod) &&
144             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
145              ((!bind->action) && (!action))) &&
146             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
147              ((!bind->params) && (!params))))
148           {
149              _e_bindings_mouse_free(bind);
150              mouse_bindings = eina_list_remove_list(mouse_bindings, l);
151              break;
152           }
153      }
154 }
155
156 EAPI void
157 e_bindings_mouse_grab(E_Binding_Context ctxt, Ecore_X_Window win)
158 {
159    E_Binding_Mouse *bind;
160    Eina_List *l;
161
162    EINA_LIST_FOREACH(mouse_bindings, l, bind)
163      {
164         if (_e_bindings_context_match(bind->ctxt, ctxt))
165           {
166              ecore_x_window_button_grab(win, bind->button,
167                                         ECORE_X_EVENT_MASK_MOUSE_DOWN |
168                                         ECORE_X_EVENT_MASK_MOUSE_UP |
169                                         ECORE_X_EVENT_MASK_MOUSE_MOVE,
170                                         _e_ecore_modifiers(bind->mod),
171                                         bind->any_mod);
172           }
173      }
174 }
175
176 EAPI void
177 e_bindings_mouse_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
178 {
179    E_Binding_Mouse *bind;
180    Eina_List *l;
181
182    EINA_LIST_FOREACH(mouse_bindings, l, bind)
183      {
184         if (_e_bindings_context_match(bind->ctxt, ctxt))
185           {
186              ecore_x_window_button_ungrab(win, bind->button,
187                                           _e_ecore_modifiers(bind->mod), bind->any_mod);
188           }
189      }
190 }
191
192 EAPI E_Action *
193 e_bindings_mouse_down_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, Ecore_Event_Mouse_Button *ev, E_Binding_Mouse **bind_ret)
194 {
195    E_Binding_Modifier mod = 0;
196    E_Binding_Mouse *bind;
197    Eina_List *l;
198
199    mod = _e_bindings_modifiers(ev->modifiers);
200    EINA_LIST_FOREACH(mouse_bindings, l, bind)
201      {
202         if ((bind->button == (int) ev->buttons) &&
203             ((bind->any_mod) || (bind->mod == mod)))
204           {
205              if (_e_bindings_context_match(bind->ctxt, ctxt))
206                {
207                   E_Action *act;
208
209                   act = e_action_find(bind->action);
210                   if (bind_ret) *bind_ret = bind;
211                   return act;
212                }
213           }
214      }
215    return NULL;
216 }
217
218 EAPI E_Action *
219 e_bindings_mouse_down_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Button *ev)
220 {
221    E_Action *act;
222    E_Binding_Mouse *bind;
223
224    act = e_bindings_mouse_down_find(ctxt, obj, ev, &bind);
225    if (act)
226      {
227         if (act->func.go_mouse)
228           act->func.go_mouse(obj, bind->params, ev);
229         else if (act->func.go)
230           act->func.go(obj, bind->params);
231         return act;
232      }
233    return act;
234 }
235
236 EAPI E_Action *
237 e_bindings_mouse_up_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, Ecore_Event_Mouse_Button *ev, E_Binding_Mouse **bind_ret)
238 {
239    E_Binding_Modifier mod = 0;
240    E_Binding_Mouse *bind;
241    Eina_List *l;
242
243    mod = _e_bindings_modifiers(ev->modifiers);
244    EINA_LIST_FOREACH(mouse_bindings, l, bind)
245      {
246         if ((bind->button == (int) ev->buttons) &&
247             ((bind->any_mod) || (bind->mod == mod)))
248           {
249              if (_e_bindings_context_match(bind->ctxt, ctxt))
250                {
251                   E_Action *act;
252
253                   act = e_action_find(bind->action);
254                   if (bind_ret) *bind_ret = bind;
255                   return act;
256                }
257           }
258      }
259    return NULL;
260 }
261
262 EAPI E_Action *
263 e_bindings_mouse_up_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Button *ev)
264 {
265    E_Action *act;
266    E_Binding_Mouse *bind;
267
268    act = e_bindings_mouse_up_find(ctxt, obj, ev, &bind);
269    if (act)
270      {
271         if (act->func.end_mouse)
272           act->func.end_mouse(obj, bind->params, ev);
273         else if (act->func.end)
274           act->func.end(obj, bind->params);
275         return act;
276      }
277    return act;
278 }
279
280 EAPI void
281 e_bindings_key_add(E_Binding_Context ctxt, const char *key, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
282 {
283    E_Binding_Key *bind;
284
285    bind = calloc(1, sizeof(E_Binding_Key));
286    bind->ctxt = ctxt;
287    bind->key = eina_stringshare_add(key);
288    bind->mod = mod;
289    bind->any_mod = any_mod;
290    if (action) bind->action = eina_stringshare_add(action);
291    if (params) bind->params = eina_stringshare_add(params);
292    key_bindings = eina_list_append(key_bindings, bind);
293 }
294
295 EAPI E_Binding_Key *
296 e_bindings_key_get(const char *action)
297 {
298    E_Binding_Key *bind;
299    Eina_List *l;
300
301    EINA_LIST_FOREACH(key_bindings, l, bind)
302      {
303         if (bind->action && action && !strcmp(action, bind->action))
304           return bind;
305      }
306    return NULL;
307 }
308
309 EAPI E_Binding_Key *
310 e_bindings_key_find(const char *key, E_Binding_Modifier mod, int any_mod)
311 {
312    E_Binding_Key *bind;
313    Eina_List *l;
314
315    if (!key) return NULL;
316
317    EINA_LIST_FOREACH(key_bindings, l, bind)
318      {
319         if ((bind->key) && (!strcmp(key, bind->key)) &&
320             (bind->mod == mod) && (bind->any_mod == any_mod))
321           return bind;
322      }
323
324    return NULL;
325 }
326
327 EAPI void
328 e_bindings_key_del(E_Binding_Context ctxt, const char *key, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
329 {
330    E_Binding_Key *bind;
331    Eina_List *l;
332
333    EINA_LIST_FOREACH(key_bindings, l, bind)
334      {
335         if ((bind->ctxt == ctxt) &&
336             (key) && (bind->key) && (!strcmp(bind->key, key)) &&
337             (bind->mod == mod) &&
338             (bind->any_mod == any_mod) &&
339             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
340              ((!bind->action) && (!action))) &&
341             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
342              ((!bind->params) && (!params))))
343           {
344              _e_bindings_key_free(bind);
345              key_bindings = eina_list_remove_list(key_bindings, l);
346              break;
347           }
348      }
349 }
350
351 EAPI void
352 e_bindings_key_grab(E_Binding_Context ctxt, Ecore_X_Window win)
353 {
354    E_Binding_Key *bind;
355    Eina_List *l;
356
357    EINA_LIST_FOREACH(key_bindings, l, bind)
358      {
359         if (_e_bindings_context_match(bind->ctxt, ctxt))
360           {
361              ecore_x_window_key_grab(win, bind->key,
362                                      _e_ecore_modifiers(bind->mod), bind->any_mod);
363           }
364      }
365 }
366
367 EAPI void
368 e_bindings_key_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
369 {
370    E_Binding_Key *bind;
371    Eina_List *l;
372
373    EINA_LIST_FOREACH(key_bindings, l, bind)
374      {
375         if (_e_bindings_context_match(bind->ctxt, ctxt))
376           {
377              ecore_x_window_key_ungrab(win, bind->key,
378                                        _e_ecore_modifiers(bind->mod), bind->any_mod);
379           }
380      }
381 }
382
383 EAPI E_Action *
384 e_bindings_key_down_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
385 {
386    E_Binding_Modifier mod = 0;
387    E_Binding_Key *bind;
388    Eina_List *l;
389
390    mod = _e_bindings_modifiers(ev->modifiers);
391    EINA_LIST_FOREACH(key_bindings, l, bind)
392      {
393         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
394             ((bind->any_mod) || (bind->mod == mod)))
395           {
396              if (_e_bindings_context_match(bind->ctxt, ctxt))
397                {
398                   E_Action *act;
399
400                   act = e_action_find(bind->action);
401                   if (act)
402                     {
403                        if (act->func.go_key)
404                          act->func.go_key(obj, bind->params, ev);
405                        else if (act->func.go)
406                          act->func.go(obj, bind->params);
407                        return act;
408                     }
409                   return NULL;
410                }
411           }
412      }
413    return NULL;
414 }
415
416 EAPI E_Action *
417 e_bindings_key_up_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
418 {
419    E_Binding_Modifier mod = 0;
420    E_Binding_Key *bind;
421    Eina_List *l;
422
423    mod = _e_bindings_modifiers(ev->modifiers);
424    EINA_LIST_FOREACH(key_bindings, l, bind)
425      {
426         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
427             ((bind->any_mod) || (bind->mod == mod)))
428           {
429              if (_e_bindings_context_match(bind->ctxt, ctxt))
430                {
431                   E_Action *act;
432                   
433                   act = e_action_find(bind->action);
434                   if (act)
435                     {
436                        if (act->func.end_key)
437                          act->func.end_key(obj, bind->params, ev);
438                        else if (act->func.end)
439                          act->func.end(obj, bind->params);
440                        return act;
441                     }
442                   return NULL;
443                }
444           }
445      }
446    return NULL;
447 }
448
449 EAPI E_Action *
450 e_bindings_key_down_event_find(E_Binding_Context ctxt, Ecore_Event_Key *ev)
451 {
452    E_Binding_Modifier mod = 0;
453    E_Binding_Key *bind;
454    Eina_List *l;
455
456    mod = _e_bindings_modifiers(ev->modifiers);
457    EINA_LIST_FOREACH(key_bindings, l, bind)
458      {
459         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
460             ((bind->any_mod) || (bind->mod == mod)))
461           {
462              if (_e_bindings_context_match(bind->ctxt, ctxt))
463                {
464                   E_Action *act;
465
466                   act = e_action_find(bind->action);
467                   return act;
468                }
469           }
470      }
471    return NULL;
472 }
473
474 EAPI E_Action *
475 e_bindings_key_up_event_find(E_Binding_Context ctxt, Ecore_Event_Key *ev)
476 {
477    E_Binding_Modifier mod = 0;
478    E_Binding_Key *bind;
479    Eina_List *l;
480
481    mod = _e_bindings_modifiers(ev->modifiers);
482    EINA_LIST_FOREACH(key_bindings, l, bind)
483      {
484         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
485             ((bind->any_mod) || (bind->mod == mod)))
486           {
487              if (_e_bindings_context_match(bind->ctxt, ctxt))
488                {
489                   E_Action *act;
490
491                   act = e_action_find(bind->action);
492                   return act;
493                }
494           }
495      }
496    return NULL;
497 }
498
499 EAPI void
500 e_bindings_edge_add(E_Binding_Context ctxt, E_Zone_Edge edge, E_Binding_Modifier mod, int any_mod, const char *action, const char *params, float delay)
501 {
502    E_Binding_Edge *bind;
503
504    bind = calloc(1, sizeof(E_Binding_Edge));
505    bind->ctxt = ctxt;
506    bind->edge = edge;
507    bind->mod = mod;
508    bind->any_mod = any_mod;
509    bind->delay = delay;
510    if (action) bind->action = eina_stringshare_add(action);
511    if (params) bind->params = eina_stringshare_add(params);
512    edge_bindings = eina_list_append(edge_bindings, bind);
513
514    e_zone_edge_new(edge);
515 }
516
517 EAPI Eina_Bool
518 e_bindings_edge_flippable_get(E_Zone_Edge edge)
519 {
520    E_Binding_Edge *bind;
521    Eina_List *l;
522
523    EINA_LIST_FOREACH(edge_bindings, l, bind)
524      {
525         if ((bind->edge == edge) && (bind->action))
526           {
527              if ((!strcmp(bind->action, "desk_flip_in_direction")) ||
528                  (!strcmp(bind->action, "desk_flip_by")))
529                 return EINA_TRUE;
530           }
531      }
532    return EINA_FALSE;
533 }
534
535 EAPI E_Binding_Edge *
536 e_bindings_edge_get(const char *action, E_Zone_Edge edge, Eina_Bool click)
537 {
538    E_Binding_Edge *bind;
539    Eina_List *l;
540
541    EINA_LIST_FOREACH(edge_bindings, l, bind)
542      {
543         if ((bind->edge == edge) &&
544             ((click && (bind->delay == -1.0))
545              || (!click && (bind->delay >= 0.0))) &&
546             (bind->action) && (action) &&
547             (!strcmp(action, bind->action)))
548           return bind;
549      }
550    return NULL;
551 }
552
553 EAPI void
554 e_bindings_edge_del(E_Binding_Context ctxt, E_Zone_Edge edge, E_Binding_Modifier mod, int any_mod, const char *action, const char *params, float delay)
555 {
556    E_Binding_Edge *bind;
557    Eina_List *l;
558    int ref_count = 0;
559
560    EINA_LIST_FOREACH(edge_bindings, l, bind)
561      {
562         if ((bind->edge == edge))
563           {
564              if ((bind->ctxt == ctxt) &&
565                  (bind->mod == mod) &&
566                  ((bind->delay * 1000) == (delay * 1000)) &&
567                  (bind->any_mod == any_mod) &&
568                  (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
569                   ((!bind->action) && (!action))) &&
570                  (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
571                   ((!bind->params) && (!params))))
572                {
573                   _e_bindings_edge_free(bind);
574                   edge_bindings = eina_list_remove_list(edge_bindings, l);
575                }
576              else ref_count++;
577           }
578      }
579
580    if (!ref_count)
581      e_zone_edge_free(edge);
582 }
583
584 EAPI E_Action *
585 e_bindings_edge_in_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
586 {
587    E_Binding_Modifier mod = 0;
588    E_Binding_Edge *bind;
589    E_Desk *current = NULL;
590    E_Action *act = NULL;
591    Eina_List *l;
592
593    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
594    if (current->fullscreen_borders && (!e_config->fullscreen_flip)) return NULL;
595
596    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
597    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
598    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
599    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
600    EINA_LIST_FOREACH(edge_bindings, l, bind)
601      {
602         /* A value of -1.0 for the delay indicates it as a mouse-click binding on that edge */
603         if (((bind->edge == ev->edge)) && (bind->delay >= 0.0) &&
604             ((bind->any_mod) || (bind->mod == mod)))
605           {
606              if (_e_bindings_context_match(bind->ctxt, ctxt))
607                {
608                   act = e_action_find(bind->action);
609                   if (act)
610                     {
611                        E_Binding_Edge_Data *ed = E_NEW(E_Binding_Edge_Data, 1);
612                        E_Event_Zone_Edge *ev2 = E_NEW(E_Event_Zone_Edge, 1);
613
614                        /* The original event will be freed before it can be
615                         * used again */
616                        ev2->zone  = ev->zone;
617                        ev2->edge  = ev->edge;
618                        ev2->x     = ev->x;
619                        ev2->y     = ev->y;
620
621                        ed->bind = bind;
622                        ed->obj  = obj;
623                        ed->act  = act;
624                        ed->ev   = ev2;
625                        bind->timer = ecore_timer_add(((double) bind->delay), _e_bindings_edge_cb_timer, ed);
626                     }
627                }
628           }
629      }
630    return act;
631 }
632
633 EAPI E_Action *
634 e_bindings_edge_out_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
635 {
636    E_Binding_Modifier mod = 0;
637    E_Binding_Edge *bind;
638    E_Action *act = NULL;
639    Eina_List *l;
640
641    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
642    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
643    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
644    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
645    EINA_LIST_FOREACH(edge_bindings, l, bind)
646      {
647         /* A value of -1.0 for the delay indicates it as a mouse-click binding on that edge */
648         if ((bind->edge == ev->edge) && (bind->delay >= 0.0) &&
649             ((bind->any_mod) || (bind->mod == mod)))
650           {
651              if (_e_bindings_context_match(bind->ctxt, ctxt))
652                {
653                   if (bind->timer)
654                     {
655                        E_Binding_Edge_Data *ed;
656
657                        ed = ecore_timer_del(bind->timer);
658                        if (ed)
659                          {
660                             E_FREE(ed->ev);
661                             E_FREE(ed);
662                          }
663                     }
664                   bind->timer = NULL;
665
666                   act = e_action_find(bind->action);
667                   if (act && act->func.end)
668                     act->func.end(obj, bind->params);
669                }
670           }
671      }
672    return act;
673 }
674
675 EAPI E_Action *
676 e_bindings_edge_down_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
677 {
678    E_Binding_Modifier mod = 0;
679    E_Binding_Edge *bind;
680    E_Desk *current = NULL;
681    E_Action *act = NULL;
682    Eina_List *l;
683
684    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
685    if (current->fullscreen_borders && (!e_config->fullscreen_flip)) return NULL;
686
687    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
688    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
689    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
690    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
691    EINA_LIST_FOREACH(edge_bindings, l, bind)
692      {
693         if (((bind->edge == ev->edge)) && (bind->delay == -1.0) &&
694             ((bind->any_mod) || (bind->mod == mod)))
695           {
696              if (_e_bindings_context_match(bind->ctxt, ctxt))
697                {
698                   act = e_action_find(bind->action);
699                   if (act)
700                     {
701                        if (act->func.go_edge)
702                          act->func.go_edge(obj, bind->params, ev);
703                        else if (act->func.go)
704                          act->func.go(obj, bind->params);
705                     }
706                }
707           }
708      }
709    return act;
710 }
711
712 EAPI E_Action *
713 e_bindings_edge_up_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
714 {
715    E_Binding_Modifier mod = 0;
716    E_Binding_Edge *bind;
717    E_Action *act = NULL;
718    Eina_List *l;
719
720    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
721    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
722    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
723    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
724    EINA_LIST_FOREACH(edge_bindings, l, bind)
725      {
726         if ((bind->edge == ev->edge) && (bind->delay == -1.0) &&
727             ((bind->any_mod) || (bind->mod == mod)))
728           {
729              if (_e_bindings_context_match(bind->ctxt, ctxt))
730                {
731                   act = e_action_find(bind->action);
732                   if (act && act->func.end)
733                     act->func.end(obj, bind->params);
734                }
735           }
736      }
737    return act;
738 }
739
740 EAPI void
741 e_bindings_signal_add(E_Binding_Context ctxt, const char *sig, const char *src, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
742 {
743    E_Binding_Signal *bind;
744
745    bind = calloc(1, sizeof(E_Binding_Signal));
746    bind->ctxt = ctxt;
747    if (sig) bind->sig = eina_stringshare_add(sig);
748    if (src) bind->src = eina_stringshare_add(src);
749    bind->mod = mod;
750    bind->any_mod = any_mod;
751    if (action) bind->action = eina_stringshare_add(action);
752    if (params) bind->params = eina_stringshare_add(params);
753    signal_bindings = eina_list_append(signal_bindings, bind);
754 }
755
756 EAPI void
757 e_bindings_signal_del(E_Binding_Context ctxt, const char *sig, const char *src, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
758 {
759    E_Binding_Signal *bind;
760    Eina_List *l;
761
762    EINA_LIST_FOREACH(signal_bindings, l, bind)
763      {
764         if ((bind->ctxt == ctxt) &&
765             (((bind->sig) && (sig) && (!strcmp(bind->sig, sig))) ||
766              ((!bind->sig) && (!sig))) &&
767             (((bind->src) && (src) && (!strcmp(bind->src, src))) ||
768              ((!bind->src) && (!src))) &&
769             (bind->mod == mod) &&
770             (bind->any_mod == any_mod) &&
771             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
772              ((!bind->action) && (!action))) &&
773             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
774              ((!bind->params) && (!params))))
775           {
776              _e_bindings_signal_free(bind);
777              signal_bindings = eina_list_remove_list(signal_bindings, l);
778              break;
779           }
780      }
781 }
782
783 EAPI E_Action  *
784 e_bindings_signal_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, const char *sig, const char *src, E_Binding_Signal **bind_ret)
785 {
786    E_Binding_Modifier mod = 0;
787    E_Binding_Signal *bind;
788    Eina_List *l;
789
790    if (strstr(sig, "MOD:Shift")) mod |= E_BINDING_MODIFIER_SHIFT;
791    if (strstr(sig, "MOD:Control")) mod |= E_BINDING_MODIFIER_CTRL;
792    if (strstr(sig, "MOD:Alt")) mod |= E_BINDING_MODIFIER_ALT;
793    if (strstr(sig, "MOD:Super")) mod |= E_BINDING_MODIFIER_WIN;
794    EINA_LIST_FOREACH(signal_bindings, l, bind)
795      {
796         if ((e_util_glob_match(sig, bind->sig)) &&
797             (e_util_glob_match(src, bind->src)) &&
798             ((bind->any_mod) || (bind->mod == mod)))
799           {
800              if (_e_bindings_context_match(bind->ctxt, ctxt))
801                {
802                   E_Action *act;
803
804                   act = e_action_find(bind->action);
805                   if (bind_ret) *bind_ret = bind;
806                   return act;
807                }
808           }
809      }
810    return NULL;
811 }
812
813 EAPI E_Action *
814 e_bindings_signal_handle(E_Binding_Context ctxt, E_Object *obj, const char *sig, const char *src)
815 {
816    E_Action *act;
817    E_Binding_Signal *bind;
818
819    if (sig[0] == 0) sig = NULL;
820    if (src[0] == 0) src = NULL;
821    act = e_bindings_signal_find(ctxt, obj, sig, src, &bind);
822    if (act)
823      {
824         if (act->func.go_signal)
825           act->func.go_signal(obj, bind->params, sig, src);
826         else if (act->func.go)
827           act->func.go(obj, bind->params);
828         return act;
829      }
830    return act;
831 }
832
833 EAPI void
834 e_bindings_wheel_add(E_Binding_Context ctxt, int direction, int z, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
835 {
836    E_Binding_Wheel *bind;
837
838    bind = calloc(1, sizeof(E_Binding_Wheel));
839    bind->ctxt = ctxt;
840    bind->direction = direction;
841    bind->z = z;
842    bind->mod = mod;
843    bind->any_mod = any_mod;
844    if (action) bind->action = eina_stringshare_add(action);
845    if (params) bind->params = eina_stringshare_add(params);
846    wheel_bindings = eina_list_append(wheel_bindings, bind);
847 }
848
849 EAPI void
850 e_bindings_wheel_del(E_Binding_Context ctxt, int direction, int z, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
851 {
852    E_Binding_Wheel *bind;
853    Eina_List *l;
854
855    EINA_LIST_FOREACH(wheel_bindings, l, bind)
856      {
857         if ((bind->ctxt == ctxt) &&
858             (bind->direction == direction) &&
859             (bind->z == z) &&
860             (bind->mod == mod) &&
861             (bind->any_mod == any_mod) &&
862             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
863              ((!bind->action) && (!action))) &&
864             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
865              ((!bind->params) && (!params))))
866           {
867              _e_bindings_wheel_free(bind);
868              wheel_bindings = eina_list_remove_list(wheel_bindings, l);
869              break;
870           }
871      }
872 }
873
874 EAPI void
875 e_bindings_wheel_grab(E_Binding_Context ctxt, Ecore_X_Window win)
876 {
877    E_Binding_Wheel *bind;
878    Eina_List *l;
879
880    EINA_LIST_FOREACH(wheel_bindings, l, bind)
881      {
882         if (_e_bindings_context_match(bind->ctxt, ctxt))
883           {
884              int button = 0;
885
886              if (bind->direction == 0)
887                {
888                   if (bind->z < 0) button = 4;
889                   else if (bind->z > 0) button = 5;
890                }
891              else if (bind->direction == 1)
892                {
893                   if (bind->z < 0) button = 6;
894                   else if (bind->z > 0) button = 7;
895                }
896              if (button != 0)
897                ecore_x_window_button_grab(win, button,
898                                           ECORE_X_EVENT_MASK_MOUSE_DOWN,
899                                           _e_ecore_modifiers(bind->mod), bind->any_mod);
900           }
901      }
902 }
903
904 EAPI void
905 e_bindings_wheel_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
906 {
907    E_Binding_Wheel *bind;
908    Eina_List *l;
909
910    EINA_LIST_FOREACH(wheel_bindings, l, bind)
911      {
912         if (_e_bindings_context_match(bind->ctxt, ctxt))
913           {
914              int button = 0;
915
916              if (bind->direction == 0)
917                {
918                   if (bind->z < 0) button = 4;
919                   else if (bind->z > 0) button = 5;
920                }
921              else if (bind->direction == 1)
922                {
923                   if (bind->z < 0) button = 6;
924                   else if (bind->z > 0) button = 7;
925                }
926              if (button != 0)
927                ecore_x_window_button_ungrab(win, button,
928                                             _e_ecore_modifiers(bind->mod), bind->any_mod);
929           }
930      }
931 }
932
933 EAPI E_Action *
934 e_bindings_wheel_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, Ecore_Event_Mouse_Wheel *ev, E_Binding_Wheel **bind_ret)
935 {
936    E_Binding_Modifier mod = 0;
937    E_Binding_Wheel *bind;
938    Eina_List *l;
939
940    mod = _e_bindings_modifiers(ev->modifiers);
941    EINA_LIST_FOREACH(wheel_bindings, l, bind)
942      {
943         if ((bind->direction == ev->direction) &&
944             (((bind->z < 0) && (ev->z < 0)) || ((bind->z > 0) && (ev->z > 0))) &&
945             ((bind->any_mod) || (bind->mod == mod)))
946           {
947              if (_e_bindings_context_match(bind->ctxt, ctxt))
948                {
949                   E_Action *act;
950
951                   act = e_action_find(bind->action);
952                   if (bind_ret) *bind_ret = bind;
953                   return act;
954                }
955           }
956      }
957    return NULL;
958 }
959
960 EAPI E_Action *
961 e_bindings_wheel_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Wheel *ev)
962 {
963    E_Action *act;
964    E_Binding_Wheel *bind;
965
966    act = e_bindings_wheel_find(ctxt, obj, ev, &bind);
967    if (act)
968      {
969         if (act->func.go_wheel)
970           act->func.go_wheel(obj, bind->params, ev);
971         else if (act->func.go)
972           act->func.go(obj, bind->params);
973         return act;
974      }
975    return act;
976 }
977
978 EAPI void 
979 e_bindings_acpi_add(E_Binding_Context ctxt, int type, int status, const char *action, const char *params) 
980 {
981    E_Binding_Acpi *bind;
982
983    bind = E_NEW(E_Binding_Acpi, 1);
984    bind->ctxt = ctxt;
985    bind->type = type;
986    bind->status = status;
987    if (action) bind->action = eina_stringshare_add(action);
988    if (params) bind->params = eina_stringshare_add(params);
989    acpi_bindings = eina_list_append(acpi_bindings, bind);
990 }
991
992 EAPI void 
993 e_bindings_acpi_del(E_Binding_Context ctxt, int type, int status, const char *action, const char *params) 
994 {
995    E_Binding_Acpi *bind;
996    Eina_List *l;
997
998    EINA_LIST_FOREACH(acpi_bindings, l, bind)
999      {
1000         if ((bind->ctxt == ctxt) &&
1001             (bind->type == type) && (bind->status == status) && 
1002             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
1003              ((!bind->action) && (!action))) &&
1004             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
1005              ((!bind->params) && (!params))))
1006           {
1007              _e_bindings_acpi_free(bind);
1008              acpi_bindings = eina_list_remove_list(acpi_bindings, l);
1009              break;
1010           }
1011      }
1012 }
1013
1014 EAPI E_Action *
1015 e_bindings_acpi_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret) 
1016 {
1017    E_Binding_Acpi *bind;
1018    Eina_List *l;
1019
1020    EINA_LIST_FOREACH(acpi_bindings, l, bind)
1021      {
1022         if (bind->type == ev->type)
1023           {
1024              /* if binding status is -1, then we don't compare event status */
1025              if (bind->status != -1) 
1026                {
1027                   /* binding status is set to something, compare event status */
1028                   if (bind->status != ev->status) continue;
1029                }
1030              if (_e_bindings_context_match(bind->ctxt, ctxt))
1031                {
1032                   E_Action *act;
1033
1034                   act = e_action_find(bind->action);
1035                   if (bind_ret) *bind_ret = bind;
1036                   return act;
1037                }
1038           }
1039      }
1040    return NULL;
1041 }
1042
1043 EAPI E_Action *
1044 e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev) 
1045 {
1046    E_Action *act;
1047    E_Binding_Acpi *bind;
1048
1049    act = e_bindings_acpi_find(ctxt, obj, ev, &bind);
1050    if (act)
1051      {
1052         if (act->func.go_acpi)
1053           act->func.go_acpi(obj, bind->params, ev);
1054         else if (act->func.go)
1055           act->func.go(obj, bind->params);
1056         return act;
1057      }
1058    return act;
1059 }
1060
1061 /* local subsystem functions */
1062 static Eina_Bool
1063 _e_bindings_mapping_change_event_cb(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
1064 {
1065 //  Ecore_X_Event_Mapping_Change *ev = event;
1066   e_managers_keys_ungrab();
1067   e_border_button_bindings_ungrab_all();
1068   e_border_button_bindings_grab_all();
1069   e_managers_keys_grab();
1070   return ECORE_CALLBACK_PASS_ON;
1071 }
1072
1073 static void
1074 _e_bindings_mouse_free(E_Binding_Mouse *bind)
1075 {
1076    if (bind->action) eina_stringshare_del(bind->action);
1077    if (bind->params) eina_stringshare_del(bind->params);
1078    free(bind);
1079 }
1080
1081 static void
1082 _e_bindings_key_free(E_Binding_Key *bind)
1083 {
1084    if (bind->key) eina_stringshare_del(bind->key);
1085    if (bind->action) eina_stringshare_del(bind->action);
1086    if (bind->params) eina_stringshare_del(bind->params);
1087    free(bind);
1088 }
1089
1090 static void
1091 _e_bindings_edge_free(E_Binding_Edge *bind)
1092 {
1093    if (bind->action) eina_stringshare_del(bind->action);
1094    if (bind->params) eina_stringshare_del(bind->params);
1095    if (bind->timer)
1096      {
1097         E_Binding_Edge_Data *ed;
1098
1099         ed = ecore_timer_del(bind->timer);
1100         E_FREE(ed);
1101      }
1102    free(bind);
1103 }
1104
1105 static void
1106 _e_bindings_signal_free(E_Binding_Signal *bind)
1107 {
1108    if (bind->sig) eina_stringshare_del(bind->sig);
1109    if (bind->src) eina_stringshare_del(bind->src);
1110    if (bind->action) eina_stringshare_del(bind->action);
1111    if (bind->params) eina_stringshare_del(bind->params);
1112    free(bind);
1113 }
1114
1115 static void
1116 _e_bindings_wheel_free(E_Binding_Wheel *bind)
1117 {
1118    if (bind->action) eina_stringshare_del(bind->action);
1119    if (bind->params) eina_stringshare_del(bind->params);
1120    free(bind);
1121 }
1122
1123 static void 
1124 _e_bindings_acpi_free(E_Binding_Acpi *bind) 
1125 {
1126    if (bind->action) eina_stringshare_del(bind->action);
1127    if (bind->params) eina_stringshare_del(bind->params);
1128    E_FREE(bind);
1129 }
1130
1131 static int
1132 _e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt)
1133 {
1134    if (bctxt == E_BINDING_CONTEXT_ANY &&
1135        !(ctxt == E_BINDING_CONTEXT_ZONE)) return 1;
1136    if (ctxt == E_BINDING_CONTEXT_UNKNOWN) return 0;
1137    if (bctxt == ctxt) return 1;
1138    return 0;
1139 }
1140
1141 static E_Binding_Modifier
1142 _e_bindings_modifiers(unsigned int modifiers)
1143 {
1144    E_Binding_Modifier mod = 0;
1145
1146    if (modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
1147    if (modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
1148    if (modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
1149    if (modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
1150    /* FIXME: there is a good reason numlock was ignored. sometimes people
1151     * have it on, sometimes they don't, and often they have no idea. waaaay
1152     * back in E 0.1->0.13 or so days this caused issues thus numlock,
1153     * scrollock and capslock are not usable modifiers.
1154     * 
1155     * if we REALLY want to be able to use numlock we need to add more binding
1156     * flags and config that says "REALLY pay attention to numlock for this
1157     * binding" field in the binding (like there is a "any_mod" flag - we need a
1158     * "num_lock_respect" field)
1159     * 
1160     * also it should be an E_BINDING_MODIFIER_LOCK_NUM as the ecore lock flag
1161     * may vary from system to system as different xservers may have differing
1162     * modifier masks for numlock (it is queried at startup).
1163     * 
1164    if (ev->modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
1165     */
1166
1167    return mod;
1168 }
1169
1170 static int
1171 _e_ecore_modifiers(E_Binding_Modifier modifiers)
1172 {
1173    int mod = 0;
1174
1175    if (modifiers & E_BINDING_MODIFIER_SHIFT) mod |= ECORE_EVENT_MODIFIER_SHIFT;
1176    if (modifiers & E_BINDING_MODIFIER_CTRL) mod |= ECORE_EVENT_MODIFIER_CTRL;
1177    if (modifiers & E_BINDING_MODIFIER_ALT) mod |= ECORE_EVENT_MODIFIER_ALT;
1178    if (modifiers & E_BINDING_MODIFIER_WIN) mod |= ECORE_EVENT_MODIFIER_WIN;
1179    /* see comment in e_bindings on numlock
1180       if (modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
1181    */
1182
1183    return mod;
1184 }
1185
1186 static Eina_Bool
1187 _e_bindings_edge_cb_timer(void *data)
1188 {
1189    E_Binding_Edge_Data *ed;
1190    E_Event_Zone_Edge *ev;
1191    E_Binding_Edge *bind;
1192    E_Action *act;
1193    E_Object *obj;
1194
1195    ed = data;
1196    bind = ed->bind;
1197    act = ed->act;
1198    obj = ed->obj;
1199    ev = ed->ev;
1200
1201    E_FREE(ed);
1202
1203    if (act->func.go_edge)
1204      act->func.go_edge(obj, bind->params, ev);
1205    else if (act->func.go)
1206      act->func.go(obj, bind->params);
1207
1208    bind->timer = NULL;
1209
1210    /* Duplicate event */
1211    E_FREE(ev);
1212
1213    return ECORE_CALLBACK_CANCEL;
1214 }
1215