26339935920e14b97cbc89d090796fdf462a5f06
[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_WINDOW_MAPPING, _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)
316      return NULL;
317
318    EINA_LIST_FOREACH(key_bindings, l, bind)
319      {
320         if (bind->key && !strcmp(key, bind->key) && (bind->mod == mod) && (bind->any_mod == any_mod))
321         return bind;
322      }
323    return NULL;
324 }
325
326 EAPI void
327 e_bindings_key_del(E_Binding_Context ctxt, const char *key, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
328 {
329    E_Binding_Key *bind;
330    Eina_List *l;
331
332    EINA_LIST_FOREACH(key_bindings, l, bind)
333      {
334         if ((bind->ctxt == ctxt) &&
335             (key) && (bind->key) && (!strcmp(bind->key, key)) &&
336             (bind->mod == mod) &&
337             (bind->any_mod == any_mod) &&
338             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
339              ((!bind->action) && (!action))) &&
340             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
341              ((!bind->params) && (!params))))
342           {
343              _e_bindings_key_free(bind);
344              key_bindings = eina_list_remove_list(key_bindings, l);
345              break;
346           }
347      }
348 }
349
350 EAPI void
351 e_bindings_key_grab(E_Binding_Context ctxt, Ecore_X_Window win)
352 {
353    E_Binding_Key *bind;
354    Eina_List *l;
355
356    EINA_LIST_FOREACH(key_bindings, l, bind)
357      {
358         if (_e_bindings_context_match(bind->ctxt, ctxt))
359           {
360              ecore_x_window_key_grab(win, bind->key,
361                                      _e_ecore_modifiers(bind->mod), bind->any_mod);
362           }
363      }
364 }
365
366 EAPI void
367 e_bindings_key_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
368 {
369    E_Binding_Key *bind;
370    Eina_List *l;
371
372    EINA_LIST_FOREACH(key_bindings, l, bind)
373      {
374         if (_e_bindings_context_match(bind->ctxt, ctxt))
375           {
376              ecore_x_window_key_ungrab(win, bind->key,
377                                        _e_ecore_modifiers(bind->mod), bind->any_mod);
378           }
379      }
380 }
381
382 EAPI E_Action *
383 e_bindings_key_down_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
384 {
385    E_Binding_Modifier mod = 0;
386    E_Binding_Key *bind;
387    Eina_List *l;
388
389    mod = _e_bindings_modifiers(ev->modifiers);
390    EINA_LIST_FOREACH(key_bindings, l, bind)
391      {
392         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
393             ((bind->any_mod) || (bind->mod == mod)))
394           {
395              if (_e_bindings_context_match(bind->ctxt, ctxt))
396                {
397                   E_Action *act;
398         
399                   act = e_action_find(bind->action);
400                   if (act)
401                     {
402                        if (act->func.go_key)
403                          act->func.go_key(obj, bind->params, ev);
404                        else if (act->func.go)
405                          act->func.go(obj, bind->params);
406                        return act;
407                     }
408                   return NULL;
409                }
410           }
411      }
412    return NULL;
413 }
414
415 EAPI E_Action *
416 e_bindings_key_up_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
417 {
418    E_Binding_Modifier mod = 0;
419    E_Binding_Key *bind;
420    Eina_List *l;
421
422    mod = _e_bindings_modifiers(ev->modifiers);
423    EINA_LIST_FOREACH(key_bindings, l, bind)
424      {
425         if ((bind->key) && (!strcmp(bind->key, ev->keyname)) &&
426             ((bind->any_mod) || (bind->mod == mod)))
427           {
428              if (_e_bindings_context_match(bind->ctxt, ctxt))
429                {
430                   E_Action *act;
431                   
432                   act = e_action_find(bind->action);
433                   if (act)
434                     {
435                        if (act->func.end_key)
436                          act->func.end_key(obj, bind->params, ev);
437                        else if (act->func.end)
438                          act->func.end(obj, bind->params);
439                        return act;
440                     }
441                   return NULL;
442                }
443           }
444      }
445    return NULL;
446 }
447
448 EAPI void
449 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)
450 {
451    E_Binding_Edge *bind;
452    
453    bind = calloc(1, sizeof(E_Binding_Edge));
454    bind->ctxt = ctxt;
455    bind->edge = edge;
456    bind->mod = mod;
457    bind->any_mod = any_mod;
458    bind->delay = delay;
459    if (action) bind->action = eina_stringshare_add(action);
460    if (params) bind->params = eina_stringshare_add(params);
461    edge_bindings = eina_list_append(edge_bindings, bind);
462
463    e_zone_edge_new(edge);
464 }
465
466 EAPI E_Binding_Edge *
467 e_bindings_edge_get(const char *action, E_Zone_Edge edge, Eina_Bool click)
468 {
469    E_Binding_Edge *bind;
470    Eina_List *l;
471
472    EINA_LIST_FOREACH(edge_bindings, l, bind)
473      {
474         if ((bind->edge == edge) &&
475               ((click && (bind->delay == -1.0))
476                || (!click && (bind->delay >= 0.0))) &&
477               bind->action && action &&
478               !strcmp(action, bind->action))
479           return bind;
480      }
481    return NULL;
482 }
483
484 EAPI void
485 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)
486 {
487    E_Binding_Edge *bind;
488    Eina_List *l;
489    int ref_count = 0;
490
491    EINA_LIST_FOREACH(edge_bindings, l, bind)
492      {
493         if ((bind->edge == edge))
494           {
495              if ((bind->ctxt == ctxt) &&
496                  (bind->mod == mod) &&
497                  ((bind->delay * 1000) == (delay * 1000)) &&
498                  (bind->any_mod == any_mod) &&
499                  (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
500                   ((!bind->action) && (!action))) &&
501                  (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
502                   ((!bind->params) && (!params))))
503                {
504                   _e_bindings_edge_free(bind);
505                   edge_bindings = eina_list_remove_list(edge_bindings, l);
506                }
507              else ref_count++;
508           }
509      }
510
511    if (!ref_count)
512      e_zone_edge_free(edge);
513 }
514
515 EAPI E_Action *
516 e_bindings_edge_in_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
517 {
518    E_Binding_Modifier mod = 0;
519    E_Binding_Edge *bind;
520    E_Desk *current = NULL;
521    E_Action *act = NULL;
522    Eina_List *l;
523    
524    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
525    if (current->fullscreen_borders && (!e_config->fullscreen_flip)) return NULL;
526
527    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
528    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
529    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
530    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
531    EINA_LIST_FOREACH(edge_bindings, l, bind)
532      {
533         /* A value of -1.0 for the delay indicates it as a mouse-click binding on that edge */
534         if (((bind->edge == ev->edge)) && (bind->delay >= 0.0) &&
535             ((bind->any_mod) || (bind->mod == mod)))
536           {
537              if (_e_bindings_context_match(bind->ctxt, ctxt))
538                {
539                   act = e_action_find(bind->action);
540                   if (act)
541                     {
542                        E_Binding_Edge_Data *ed = E_NEW(E_Binding_Edge_Data, 1);
543                        E_Event_Zone_Edge *ev2 = E_NEW(E_Event_Zone_Edge, 1);
544
545                        /* The original event will be freed before it can be
546                         * used again */
547                        ev2->zone  = ev->zone;
548                        ev2->edge  = ev->edge;
549                        ev2->x     = ev->x;
550                        ev2->y     = ev->y;
551
552                        ed->bind = bind;
553                        ed->obj  = obj;
554                        ed->act  = act;
555                        ed->ev   = ev2;
556                        bind->timer = ecore_timer_add(((double) bind->delay), _e_bindings_edge_cb_timer, ed);
557                     }
558                }
559           }
560      }
561    return act;
562 }
563
564 EAPI E_Action *
565 e_bindings_edge_out_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
566 {
567    E_Binding_Modifier mod = 0;
568    E_Binding_Edge *bind;
569    E_Action *act = NULL;
570    Eina_List *l;
571
572    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
573    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
574    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
575    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
576    EINA_LIST_FOREACH(edge_bindings, l, bind)
577      {
578         /* A value of -1.0 for the delay indicates it as a mouse-click binding on that edge */
579         if ((bind->edge == ev->edge) && (bind->delay >= 0.0) &&
580             ((bind->any_mod) || (bind->mod == mod)))
581           {
582              if (_e_bindings_context_match(bind->ctxt, ctxt))
583                {
584                   if (bind->timer)
585                     {
586                        E_Binding_Edge_Data *ed;
587
588                        ed = ecore_timer_del(bind->timer);
589                        if (ed)
590                          {
591                             E_FREE(ed->ev);
592                             E_FREE(ed);
593                          }
594                     }
595                   bind->timer = NULL;
596
597                   act = e_action_find(bind->action);
598                   if (act && act->func.end)
599                     act->func.end(obj, bind->params);
600                }
601           }
602      }
603    return act;
604 }
605
606 EAPI E_Action *
607 e_bindings_edge_down_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
608 {
609    E_Binding_Modifier mod = 0;
610    E_Binding_Edge *bind;
611    E_Desk *current = NULL;
612    E_Action *act = NULL;
613    Eina_List *l;
614    
615    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
616    if (current->fullscreen_borders && (!e_config->fullscreen_flip)) return NULL;
617
618    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
619    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
620    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
621    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
622    EINA_LIST_FOREACH(edge_bindings, l, bind)
623      {
624         if (((bind->edge == ev->edge)) && (bind->delay == -1.0) &&
625             ((bind->any_mod) || (bind->mod == mod)))
626           {
627              if (_e_bindings_context_match(bind->ctxt, ctxt))
628                {
629                   act = e_action_find(bind->action);
630                   if (act)
631                     {
632                        if (act->func.go_edge)
633                          act->func.go_edge(obj, bind->params, ev);
634                        else if (act->func.go)
635                          act->func.go(obj, bind->params);
636                     }
637                }
638           }
639      }
640    return act;
641 }
642
643 EAPI E_Action *
644 e_bindings_edge_up_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
645 {
646    E_Binding_Modifier mod = 0;
647    E_Binding_Edge *bind;
648    E_Action *act = NULL;
649    Eina_List *l;
650
651    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
652    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
653    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
654    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
655    EINA_LIST_FOREACH(edge_bindings, l, bind)
656      {
657         if ((bind->edge == ev->edge) && (bind->delay == -1.0) &&
658               ((bind->any_mod) || (bind->mod == mod)))
659           {
660              if (_e_bindings_context_match(bind->ctxt, ctxt))
661                {
662                   act = e_action_find(bind->action);
663                   if (act && act->func.end)
664                     act->func.end(obj, bind->params);
665                }
666           }
667      }
668    return act;
669 }
670
671 EAPI void
672 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)
673 {
674    E_Binding_Signal *bind;
675    
676    bind = calloc(1, sizeof(E_Binding_Signal));
677    bind->ctxt = ctxt;
678    if (sig) bind->sig = eina_stringshare_add(sig);
679    if (src) bind->src = eina_stringshare_add(src);
680    bind->mod = mod;
681    bind->any_mod = any_mod;
682    if (action) bind->action = eina_stringshare_add(action);
683    if (params) bind->params = eina_stringshare_add(params);
684    signal_bindings = eina_list_append(signal_bindings, bind);
685 }
686
687 EAPI void
688 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)
689 {
690    E_Binding_Signal *bind;
691    Eina_List *l;
692
693    EINA_LIST_FOREACH(signal_bindings, l, bind)
694      {
695         if ((bind->ctxt == ctxt) &&
696             (((bind->sig) && (sig) && (!strcmp(bind->sig, sig))) ||
697              ((!bind->sig) && (!sig))) &&
698             (((bind->src) && (src) && (!strcmp(bind->src, src))) ||
699              ((!bind->src) && (!src))) &&
700             (bind->mod == mod) &&
701             (bind->any_mod == any_mod) &&
702             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
703              ((!bind->action) && (!action))) &&
704             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
705              ((!bind->params) && (!params))))
706           {
707              _e_bindings_signal_free(bind);
708              signal_bindings = eina_list_remove_list(signal_bindings, l);
709              break;
710           }
711      }
712 }
713
714 EAPI E_Action  *
715 e_bindings_signal_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, const char *sig, const char *src, E_Binding_Signal **bind_ret)
716 {
717    E_Binding_Modifier mod = 0;
718    E_Binding_Signal *bind;
719    Eina_List *l;
720    
721    if (strstr(sig, "MOD:Shift")) mod |= E_BINDING_MODIFIER_SHIFT;
722    if (strstr(sig, "MOD:Control")) mod |= E_BINDING_MODIFIER_CTRL;
723    if (strstr(sig, "MOD:Alt")) mod |= E_BINDING_MODIFIER_ALT;
724    if (strstr(sig, "MOD:Super")) mod |= E_BINDING_MODIFIER_WIN;
725    EINA_LIST_FOREACH(signal_bindings, l, bind)
726      {
727         if ((e_util_glob_match(sig, bind->sig)) &&
728             (e_util_glob_match(src, bind->src)) &&
729             ((bind->any_mod) || (bind->mod == mod)))
730           {
731              if (_e_bindings_context_match(bind->ctxt, ctxt))
732                {
733                   E_Action *act;
734                   
735                   act = e_action_find(bind->action);
736                   if (bind_ret) *bind_ret = bind;
737                   return act;
738                }
739           }
740      }
741    return NULL;
742 }
743
744 EAPI E_Action *
745 e_bindings_signal_handle(E_Binding_Context ctxt, E_Object *obj, const char *sig, const char *src)
746 {
747    E_Action *act;
748    E_Binding_Signal *bind;
749
750    if (sig[0] == 0) sig = NULL;
751    if (src[0] == 0) src = NULL;
752    act = e_bindings_signal_find(ctxt, obj, sig, src, &bind);
753    if (act)
754      {
755         if (act->func.go_signal)
756           act->func.go_signal(obj, bind->params, sig, src);
757         else if (act->func.go)
758           act->func.go(obj, bind->params);
759         return act;
760      }
761    return act;
762 }
763
764 EAPI void
765 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)
766 {
767    E_Binding_Wheel *bind;
768
769    bind = calloc(1, sizeof(E_Binding_Wheel));
770    bind->ctxt = ctxt;
771    bind->direction = direction;
772    bind->z = z;
773    bind->mod = mod;
774    bind->any_mod = any_mod;
775    if (action) bind->action = eina_stringshare_add(action);
776    if (params) bind->params = eina_stringshare_add(params);
777    wheel_bindings = eina_list_append(wheel_bindings, bind);
778 }
779
780 EAPI void
781 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)
782 {
783    E_Binding_Wheel *bind;
784    Eina_List *l;
785
786    EINA_LIST_FOREACH(wheel_bindings, l, bind)
787      {
788         if ((bind->ctxt == ctxt) &&
789             (bind->direction == direction) &&
790             (bind->z == z) &&
791             (bind->mod == mod) &&
792             (bind->any_mod == any_mod) &&
793             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
794              ((!bind->action) && (!action))) &&
795             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
796              ((!bind->params) && (!params))))
797           {
798              _e_bindings_wheel_free(bind);
799              wheel_bindings = eina_list_remove_list(wheel_bindings, l);
800              break;
801           }
802      }
803 }
804
805 EAPI void
806 e_bindings_wheel_grab(E_Binding_Context ctxt, Ecore_X_Window win)
807 {
808    E_Binding_Wheel *bind;
809    Eina_List *l;
810
811    EINA_LIST_FOREACH(wheel_bindings, l, bind)
812      {
813         if (_e_bindings_context_match(bind->ctxt, ctxt))
814           {
815              int button = 0;
816
817              if (bind->direction == 0)
818                {
819                   if (bind->z < 0) button = 4;
820                   else if (bind->z > 0) button = 5;
821                }
822              else if (bind->direction == 1)
823                {
824                   if (bind->z < 0) button = 6;
825                   else if (bind->z > 0) button = 7;
826                }
827              if (button != 0)
828                ecore_x_window_button_grab(win, button,
829                                           ECORE_X_EVENT_MASK_MOUSE_DOWN,
830                                           _e_ecore_modifiers(bind->mod), bind->any_mod);
831           }
832      }
833 }
834
835 EAPI void
836 e_bindings_wheel_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
837 {
838    E_Binding_Wheel *bind;
839    Eina_List *l;
840
841    EINA_LIST_FOREACH(wheel_bindings, l, bind)
842      {
843         if (_e_bindings_context_match(bind->ctxt, ctxt))
844           {
845              int button = 0;
846              
847              if (bind->direction == 0)
848                {
849                   if (bind->z < 0) button = 4;
850                   else if (bind->z > 0) button = 5;
851                }
852              else if (bind->direction == 1)
853                {
854                   if (bind->z < 0) button = 6;
855                   else if (bind->z > 0) button = 7;
856                }
857              if (button != 0)
858                ecore_x_window_button_ungrab(win, button,
859                                             _e_ecore_modifiers(bind->mod), bind->any_mod);
860           }
861      }
862 }
863
864 EAPI E_Action *
865 e_bindings_wheel_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, Ecore_Event_Mouse_Wheel *ev, E_Binding_Wheel **bind_ret)
866 {
867    E_Binding_Modifier mod = 0;
868    E_Binding_Wheel *bind;
869    Eina_List *l;
870
871    mod = _e_bindings_modifiers(ev->modifiers);
872    EINA_LIST_FOREACH(wheel_bindings, l, bind)
873      {
874         if ((bind->direction == ev->direction) &&
875             (((bind->z < 0) && (ev->z < 0)) || ((bind->z > 0) && (ev->z > 0))) &&
876             ((bind->any_mod) || (bind->mod == mod)))
877           {
878              if (_e_bindings_context_match(bind->ctxt, ctxt))
879                {
880                   E_Action *act;
881                   
882                   act = e_action_find(bind->action);
883                   if (bind_ret) *bind_ret = bind;
884                   return act;
885                }
886           }
887      }
888    return NULL;
889 }
890
891 EAPI E_Action *
892 e_bindings_wheel_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Wheel *ev)
893 {
894    E_Action *act;
895    E_Binding_Wheel *bind;
896
897    act = e_bindings_wheel_find(ctxt, obj, ev, &bind);
898    if (act)
899      {
900         if (act->func.go_wheel)
901           act->func.go_wheel(obj, bind->params, ev);
902         else if (act->func.go)
903           act->func.go(obj, bind->params);
904         return act;
905      }
906    return act;
907 }
908
909 EAPI void 
910 e_bindings_acpi_add(E_Binding_Context ctxt, int type, int status, const char *action, const char *params) 
911 {
912    E_Binding_Acpi *bind;
913
914    bind = E_NEW(E_Binding_Acpi, 1);
915    bind->ctxt = ctxt;
916    bind->type = type;
917    bind->status = status;
918    if (action) bind->action = eina_stringshare_add(action);
919    if (params) bind->params = eina_stringshare_add(params);
920    acpi_bindings = eina_list_append(acpi_bindings, bind);
921 }
922
923 EAPI void 
924 e_bindings_acpi_del(E_Binding_Context ctxt, int type, int status, const char *action, const char *params) 
925 {
926    E_Binding_Acpi *bind;
927    Eina_List *l;
928
929    EINA_LIST_FOREACH(acpi_bindings, l, bind)
930      {
931         if ((bind->ctxt == ctxt) &&
932             (bind->type == type) && (bind->status == status) && 
933             (((bind->action) && (action) && (!strcmp(bind->action, action))) ||
934                 ((!bind->action) && (!action))) &&
935             (((bind->params) && (params) && (!strcmp(bind->params, params))) ||
936                 ((!bind->params) && (!params))))
937           {
938              _e_bindings_acpi_free(bind);
939              acpi_bindings = eina_list_remove_list(acpi_bindings, l);
940              break;
941           }
942      }
943 }
944
945 EAPI E_Action *
946 e_bindings_acpi_find(E_Binding_Context ctxt, E_Object *obj __UNUSED__, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret) 
947 {
948    E_Binding_Acpi *bind;
949    Eina_List *l;
950
951    EINA_LIST_FOREACH(acpi_bindings, l, bind)
952      {
953         if (bind->type == ev->type)
954           {
955              /* if binding status is -1, then we don't compare event status */
956              if (bind->status != -1) 
957                {
958                   /* binding status is set to something, compare event status */
959                   if (bind->status != ev->status) continue;
960                }
961              if (_e_bindings_context_match(bind->ctxt, ctxt))
962                {
963                   E_Action *act;
964
965                   act = e_action_find(bind->action);
966                   if (bind_ret) *bind_ret = bind;
967                   return act;
968                }
969           }
970      }
971    return NULL;
972 }
973
974 EAPI E_Action *
975 e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev) 
976 {
977    E_Action *act;
978    E_Binding_Acpi *bind;
979
980    act = e_bindings_acpi_find(ctxt, obj, ev, &bind);
981    if (act)
982      {
983         if (act->func.go_acpi)
984           act->func.go_acpi(obj, bind->params, ev);
985         else if (act->func.go)
986           act->func.go(obj, bind->params);
987         return act;
988      }
989    return act;
990 }
991
992 /* local subsystem functions */
993 static Eina_Bool
994 _e_bindings_mapping_change_event_cb(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
995 {
996 //  Ecore_X_Event_Mapping_Change *ev = event;
997   
998   e_managers_keys_ungrab();
999   e_border_button_bindings_ungrab_all();
1000   e_border_button_bindings_grab_all();
1001   e_managers_keys_grab();
1002   return ECORE_CALLBACK_PASS_ON;
1003 }
1004
1005 static void
1006 _e_bindings_mouse_free(E_Binding_Mouse *bind)
1007 {
1008    if (bind->action) eina_stringshare_del(bind->action);
1009    if (bind->params) eina_stringshare_del(bind->params);
1010    free(bind);
1011 }
1012
1013 static void
1014 _e_bindings_key_free(E_Binding_Key *bind)
1015 {
1016    if (bind->key) eina_stringshare_del(bind->key);
1017    if (bind->action) eina_stringshare_del(bind->action);
1018    if (bind->params) eina_stringshare_del(bind->params);
1019    free(bind);
1020 }
1021
1022 static void
1023 _e_bindings_edge_free(E_Binding_Edge *bind)
1024 {
1025    if (bind->action) eina_stringshare_del(bind->action);
1026    if (bind->params) eina_stringshare_del(bind->params);
1027    if (bind->timer)
1028      {
1029         E_Binding_Edge_Data *ed;
1030
1031         ed = ecore_timer_del(bind->timer);
1032         E_FREE(ed);
1033      }
1034    free(bind);
1035 }
1036
1037 static void
1038 _e_bindings_signal_free(E_Binding_Signal *bind)
1039 {
1040    if (bind->sig) eina_stringshare_del(bind->sig);
1041    if (bind->src) eina_stringshare_del(bind->src);
1042    if (bind->action) eina_stringshare_del(bind->action);
1043    if (bind->params) eina_stringshare_del(bind->params);
1044    free(bind);
1045 }
1046
1047 static void
1048 _e_bindings_wheel_free(E_Binding_Wheel *bind)
1049 {
1050    if (bind->action) eina_stringshare_del(bind->action);
1051    if (bind->params) eina_stringshare_del(bind->params);
1052    free(bind);
1053 }
1054
1055 static void 
1056 _e_bindings_acpi_free(E_Binding_Acpi *bind) 
1057 {
1058    if (bind->action) eina_stringshare_del(bind->action);
1059    if (bind->params) eina_stringshare_del(bind->params);
1060    E_FREE(bind);
1061 }
1062
1063 static int
1064 _e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt)
1065 {
1066    if (bctxt == E_BINDING_CONTEXT_ANY &&
1067        !(ctxt == E_BINDING_CONTEXT_ZONE)) return 1;
1068    if (ctxt == E_BINDING_CONTEXT_UNKNOWN) return 0;
1069    if (bctxt == ctxt) return 1;
1070    return 0;
1071 }
1072
1073 static E_Binding_Modifier
1074 _e_bindings_modifiers(unsigned int modifiers)
1075 {
1076    E_Binding_Modifier mod = 0;
1077
1078    if (modifiers & ECORE_EVENT_MODIFIER_SHIFT) mod |= E_BINDING_MODIFIER_SHIFT;
1079    if (modifiers & ECORE_EVENT_MODIFIER_CTRL) mod |= E_BINDING_MODIFIER_CTRL;
1080    if (modifiers & ECORE_EVENT_MODIFIER_ALT) mod |= E_BINDING_MODIFIER_ALT;
1081    if (modifiers & ECORE_EVENT_MODIFIER_WIN) mod |= E_BINDING_MODIFIER_WIN;
1082    /* FIXME: there is a good reason numlock was ignored. sometimes people
1083     * have it on, sometimes they don't, and often they have no idea. waaaay
1084     * back in E 0.1->0.13 or so days this caused issues thus numlock,
1085     * scrollock and capslock are not usable modifiers.
1086     * 
1087     * if we REALLY want to be able to use numlock we need to add more binding
1088     * flags and config that says "REALLY pay attention to numlock for this
1089     * binding" field in the binding (like there is a "any_mod" flag - we need a
1090     * "num_lock_respect" field)
1091     * 
1092     * also it should be an E_BINDING_MODIFIER_LOCK_NUM as the ecore lock flag
1093     * may vary from system to system as different xservers may have differing
1094     * modifier masks for numlock (it is queried at startup).
1095     * 
1096    if (ev->modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
1097     */
1098
1099    return mod;
1100 }
1101
1102 static int
1103 _e_ecore_modifiers(E_Binding_Modifier modifiers)
1104 {
1105    int mod = 0;
1106
1107    if (modifiers & E_BINDING_MODIFIER_SHIFT) mod |= ECORE_EVENT_MODIFIER_SHIFT;
1108    if (modifiers & E_BINDING_MODIFIER_CTRL) mod |= ECORE_EVENT_MODIFIER_CTRL;
1109    if (modifiers & E_BINDING_MODIFIER_ALT) mod |= ECORE_EVENT_MODIFIER_ALT;
1110    if (modifiers & E_BINDING_MODIFIER_WIN) mod |= ECORE_EVENT_MODIFIER_WIN;
1111    /* see comment in e_bindings on numlock
1112       if (modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
1113    */
1114
1115    return mod;
1116 }
1117
1118 static Eina_Bool
1119 _e_bindings_edge_cb_timer(void *data)
1120 {
1121    E_Binding_Edge_Data *ed;
1122    E_Event_Zone_Edge *ev;
1123    E_Binding_Edge *bind;
1124    E_Action *act;
1125    E_Object *obj;
1126
1127    ed = data;
1128    bind = ed->bind;
1129    act = ed->act;
1130    obj = ed->obj;
1131    ev = ed->ev;
1132
1133    E_FREE(ed);
1134
1135    if (act->func.go_edge)
1136      act->func.go_edge(obj, bind->params, ev);
1137    else if (act->func.go)
1138      act->func.go(obj, bind->params);
1139
1140    bind->timer = NULL;
1141
1142    /* Duplicate event */
1143    E_FREE(ev);
1144
1145    return ECORE_CALLBACK_CANCEL;
1146 }
1147