1 #include "e.h"
2 
3 /* local subsystem functions */
4 static void               _e_bindings_mouse_free(E_Binding_Mouse *bind);
5 static void               _e_bindings_key_free(E_Binding_Key *bind);
6 static void               _e_bindings_edge_free(E_Binding_Edge *bind);
7 static void               _e_bindings_signal_free(E_Binding_Signal *bind);
8 static void               _e_bindings_wheel_free(E_Binding_Wheel *bind);
9 static void               _e_bindings_acpi_free(E_Binding_Acpi *bind);
10 static Eina_Bool          _e_bindings_edge_cb_timer(void *data);
11 
12 /* local subsystem globals */
13 
14 static Eina_List *mouse_bindings = NULL;
15 static Eina_List *key_bindings = NULL;
16 static Eina_List *edge_bindings = NULL;
17 static Eina_List *signal_bindings = NULL;
18 static Eina_List *wheel_bindings = NULL;
19 static Eina_List *acpi_bindings = NULL;
20 
21 static unsigned int bindings_disabled = 0;
22 
23 EINTERN E_Action *(*e_binding_key_list_cb)(E_Binding_Context, Ecore_Event_Key*, E_Binding_Modifier, E_Binding_Key **);
24 
25 typedef struct _E_Binding_Edge_Data E_Binding_Edge_Data;
26 
27 struct _E_Binding_Edge_Data
28 {
29    E_Binding_Edge    *bind;
30    E_Event_Zone_Edge *ev;
31    E_Action          *act;
32    E_Object          *obj;
33 };
34 
35 /* externally accessible functions */
36 
37 EINTERN int
e_bindings_init(void)38 e_bindings_init(void)
39 {
40    E_Config_Binding_Signal *ebs;
41    E_Config_Binding_Mouse *ebm;
42    E_Config_Binding_Wheel *ebw;
43    E_Config_Binding_Edge *ebe;
44    E_Config_Binding_Key *ebk;
45    E_Config_Binding_Acpi *eba;
46    Eina_List *l;
47 
48    EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm)
49      e_bindings_mouse_add(ebm->context, ebm->button, ebm->modifiers,
50                           ebm->any_mod, ebm->action, ebm->params);
51 
52    EINA_LIST_FOREACH(e_bindings->key_bindings, l, ebk)
53      e_bindings_key_add(ebk->context, ebk->key, ebk->modifiers,
54                         ebk->any_mod, ebk->action, ebk->params);
55 
56    EINA_LIST_FOREACH(e_bindings->edge_bindings, l, ebe)
57      e_bindings_edge_add(ebe->context, ebe->edge, ebe->drag_only, ebe->modifiers,
58                          ebe->any_mod, ebe->action, ebe->params, ebe->delay);
59 
60    EINA_LIST_FOREACH(e_bindings->signal_bindings, l, ebs)
61      {
62         e_bindings_signal_add(ebs->context, ebs->signal, ebs->source, ebs->modifiers,
63                               ebs->any_mod, ebs->action, ebs->params);
64         /* FIXME: Can this be solved in a generic way? */
65         /* FIXME: Only change cursor if action is allowed! */
66         if ((ebs->action) && (ebs->signal) && (ebs->source) &&
67             (!strcmp(ebs->action, "window_resize")) &&
68             (!strncmp(ebs->signal, "mouse,down,", 11)) &&
69             (!strncmp(ebs->source, "e.event.resize.", 15)))
70           {
71              char params[32];
72 
73              snprintf(params, sizeof(params), "resize_%s", ebs->params);
74              e_bindings_signal_add(ebs->context, "mouse,in", ebs->source, ebs->modifiers,
75                                    ebs->any_mod, "pointer_resize_push", params);
76              e_bindings_signal_add(ebs->context, "mouse,out", ebs->source, ebs->modifiers,
77                                    ebs->any_mod, "pointer_resize_pop", params);
78           }
79      }
80 
81    EINA_LIST_FOREACH(e_bindings->wheel_bindings, l, ebw)
82      e_bindings_wheel_add(ebw->context, ebw->direction, ebw->z, ebw->modifiers,
83                           ebw->any_mod, ebw->action, ebw->params);
84 
85    EINA_LIST_FOREACH(e_bindings->acpi_bindings, l, eba)
86      e_bindings_acpi_add(eba->context, eba->type, eba->status,
87                          eba->action, eba->params);
88 
89    return 1;
90 }
91 
92 EINTERN int
e_bindings_shutdown(void)93 e_bindings_shutdown(void)
94 {
95    E_FREE_LIST(mouse_bindings, _e_bindings_mouse_free);
96    E_FREE_LIST(key_bindings, _e_bindings_key_free);
97    E_FREE_LIST(edge_bindings, _e_bindings_edge_free);
98    E_FREE_LIST(signal_bindings, _e_bindings_signal_free);
99    E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free);
100    E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free);
101 
102    return 1;
103 }
104 
105 E_API int
e_bindings_modifiers_to_ecore_convert(E_Binding_Modifier modifiers)106 e_bindings_modifiers_to_ecore_convert(E_Binding_Modifier modifiers)
107 {
108    int mod = 0;
109 
110    if (modifiers & E_BINDING_MODIFIER_SHIFT) mod |= ECORE_EVENT_MODIFIER_SHIFT;
111    if (modifiers & E_BINDING_MODIFIER_CTRL) mod |= ECORE_EVENT_MODIFIER_CTRL;
112    if (modifiers & E_BINDING_MODIFIER_ALT) mod |= ECORE_EVENT_MODIFIER_ALT;
113    if (modifiers & E_BINDING_MODIFIER_WIN) mod |= ECORE_EVENT_MODIFIER_WIN;
114    /* see comment in e_bindings on numlock
115       if (modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
116     */
117 
118    return mod;
119 }
120 
121 E_API void
e_bindings_ecore_event_mouse_wheel_convert(const Ecore_Event_Mouse_Wheel * ev,E_Binding_Event_Wheel * event)122 e_bindings_ecore_event_mouse_wheel_convert(const Ecore_Event_Mouse_Wheel *ev, E_Binding_Event_Wheel *event)
123 {
124    memset(event, 0, sizeof(E_Binding_Event_Wheel));
125    event->direction = ev->direction;
126    event->z = ev->z;
127    event->canvas.x = e_comp_canvas_x_root_adjust(ev->root.x);
128    event->canvas.y = e_comp_canvas_y_root_adjust(ev->root.y);
129    event->timestamp = ev->timestamp;
130    event->modifiers = e_bindings_modifiers_from_ecore(ev->modifiers);
131 }
132 
133 E_API void
e_bindings_ecore_event_mouse_button_convert(const Ecore_Event_Mouse_Button * ev,E_Binding_Event_Mouse_Button * event)134 e_bindings_ecore_event_mouse_button_convert(const Ecore_Event_Mouse_Button *ev, E_Binding_Event_Mouse_Button *event)
135 {
136    memset(event, 0, sizeof(E_Binding_Event_Mouse_Button));
137    event->button = ev->buttons;
138    event->canvas.x = e_comp_canvas_x_root_adjust(ev->root.x);
139    event->canvas.y = e_comp_canvas_y_root_adjust(ev->root.y);
140    event->timestamp = ev->timestamp;
141    event->modifiers = e_bindings_modifiers_from_ecore(ev->modifiers);
142 
143    event->double_click = !!ev->double_click;
144    event->triple_click = !!ev->triple_click;
145 }
146 
147 E_API void
e_bindings_evas_event_mouse_wheel_convert(const Evas_Event_Mouse_Wheel * ev,E_Binding_Event_Wheel * event)148 e_bindings_evas_event_mouse_wheel_convert(const Evas_Event_Mouse_Wheel *ev, E_Binding_Event_Wheel *event)
149 {
150    memset(event, 0, sizeof(E_Binding_Event_Wheel));
151    event->direction = ev->direction;
152    event->z = ev->z;
153    event->canvas.x = ev->output.x, event->canvas.y = ev->output.y;
154    event->timestamp = ev->timestamp;
155 
156    event->modifiers |= (E_BINDING_MODIFIER_SHIFT * evas_key_modifier_is_set(ev->modifiers, "Shift"));
157    event->modifiers |= (E_BINDING_MODIFIER_CTRL * evas_key_modifier_is_set(ev->modifiers, "Control"));
158    event->modifiers |= (E_BINDING_MODIFIER_ALT * evas_key_modifier_is_set(ev->modifiers, "Alt"));
159    event->modifiers |= (E_BINDING_MODIFIER_WIN * evas_key_modifier_is_set(ev->modifiers, "Super"));
160    event->modifiers |= (E_BINDING_MODIFIER_WIN * evas_key_modifier_is_set(ev->modifiers, "Hyper"));
161    event->modifiers |= (E_BINDING_MODIFIER_ALTGR * evas_key_modifier_is_set(ev->modifiers, "AltGr"));
162 
163 /* TODO
164    if (modifiers & ECORE_EVENT_LOCK_SCROLL)
165      evas_key_lock_on(e, "Scroll_Lock");
166    else evas_key_lock_off(e, "Scroll_Lock");
167 
168    if (modifiers & ECORE_EVENT_LOCK_NUM)
169      evas_key_lock_on(e, "Num_Lock");
170    else evas_key_lock_off(e, "Num_Lock");
171 
172    if (modifiers & ECORE_EVENT_LOCK_CAPS)
173      evas_key_lock_on(e, "Caps_Lock");
174    else evas_key_lock_off(e, "Caps_Lock");
175 
176    if (modifiers & ECORE_EVENT_LOCK_SHIFT)
177      evas_key_lock_on(e, "Shift_Lock");
178    else evas_key_lock_off(e, "Shift_Lock");
179 */
180 }
181 
182 E_API int
e_bindings_evas_modifiers_convert(Evas_Modifier * modifiers)183 e_bindings_evas_modifiers_convert(Evas_Modifier *modifiers)
184 {
185    int mod = 0;
186 
187    mod |= (E_BINDING_MODIFIER_SHIFT * evas_key_modifier_is_set(modifiers, "Shift"));
188    mod |= (E_BINDING_MODIFIER_CTRL * evas_key_modifier_is_set(modifiers, "Control"));
189    mod |= (E_BINDING_MODIFIER_ALT * evas_key_modifier_is_set(modifiers, "Alt"));
190    mod |= (E_BINDING_MODIFIER_WIN * evas_key_modifier_is_set(modifiers, "Super"));
191    mod |= (E_BINDING_MODIFIER_WIN * evas_key_modifier_is_set(modifiers, "Hyper"));
192    mod |= (E_BINDING_MODIFIER_ALTGR * evas_key_modifier_is_set(modifiers, "AltGr"));
193    return mod;
194 }
195 
196 E_API void
e_bindings_evas_event_mouse_button_convert(const Evas_Event_Mouse_Down * ev,E_Binding_Event_Mouse_Button * event)197 e_bindings_evas_event_mouse_button_convert(const Evas_Event_Mouse_Down *ev, E_Binding_Event_Mouse_Button *event)
198 {
199    memset(event, 0, sizeof(E_Binding_Event_Mouse_Button));
200    event->button = ev->button;
201    event->canvas.x = ev->output.x, event->canvas.y = ev->output.y;
202    event->timestamp = ev->timestamp;
203 
204    event->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers);
205 
206    event->hold = (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD);
207    event->scroll = (ev->event_flags & EVAS_EVENT_FLAG_ON_SCROLL);
208 
209    event->double_click = (ev->flags & EVAS_BUTTON_DOUBLE_CLICK);
210    event->triple_click = (ev->flags & EVAS_BUTTON_TRIPLE_CLICK);
211 
212 /* TODO
213    if (modifiers & ECORE_EVENT_LOCK_SCROLL)
214      evas_key_lock_on(e, "Scroll_Lock");
215    else evas_key_lock_off(e, "Scroll_Lock");
216 
217    if (modifiers & ECORE_EVENT_LOCK_NUM)
218      evas_key_lock_on(e, "Num_Lock");
219    else evas_key_lock_off(e, "Num_Lock");
220 
221    if (modifiers & ECORE_EVENT_LOCK_CAPS)
222      evas_key_lock_on(e, "Caps_Lock");
223    else evas_key_lock_off(e, "Caps_Lock");
224 
225    if (modifiers & ECORE_EVENT_LOCK_SHIFT)
226      evas_key_lock_on(e, "Shift_Lock");
227    else evas_key_lock_off(e, "Shift_Lock");
228 */
229 }
230 
231 E_API void
e_bindings_signal_reset(void)232 e_bindings_signal_reset(void)
233 {
234    E_Config_Binding_Signal *ebs;
235    Eina_List *l;
236    E_FREE_LIST(signal_bindings, _e_bindings_signal_free);
237 
238    EINA_LIST_FOREACH(e_bindings->signal_bindings, l, ebs)
239      {
240         e_bindings_signal_add(ebs->context, ebs->signal, ebs->source, ebs->modifiers,
241                               ebs->any_mod, ebs->action, ebs->params);
242         /* FIXME: Can this be solved in a generic way? */
243         /* FIXME: Only change cursor if action is allowed! */
244         if ((ebs->action) && (ebs->signal) && (ebs->source) &&
245             (!strcmp(ebs->action, "window_resize")) &&
246             (!strncmp(ebs->signal, "mouse,down,", 11)) &&
247             (!strncmp(ebs->source, "e.event.resize.", 15)))
248           {
249              char params[32];
250 
251              snprintf(params, sizeof(params), "resize_%s", ebs->params);
252              e_bindings_signal_add(ebs->context, "mouse,in", ebs->source, ebs->modifiers,
253                                    ebs->any_mod, "pointer_resize_push", params);
254              e_bindings_signal_add(ebs->context, "mouse,out", ebs->source, ebs->modifiers,
255                                    ebs->any_mod, "pointer_resize_pop", params);
256           }
257      }
258 }
259 
260 E_API void
e_bindings_acpi_reset(void)261 e_bindings_acpi_reset(void)
262 {
263    E_Config_Binding_Acpi *eba;
264    Eina_List *l;
265 
266    E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free);
267 
268    EINA_LIST_FOREACH(e_bindings->acpi_bindings, l, eba)
269      e_bindings_acpi_add(eba->context, eba->type, eba->status,
270                          eba->action, eba->params);
271 }
272 
273 E_API void
e_bindings_wheel_reset(void)274 e_bindings_wheel_reset(void)
275 {
276    E_Config_Binding_Wheel *ebw;
277    Eina_List *l;
278 
279    E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free);
280 
281    EINA_LIST_FOREACH(e_bindings->wheel_bindings, l, ebw)
282      e_bindings_wheel_add(ebw->context, ebw->direction, ebw->z, ebw->modifiers,
283                           ebw->any_mod, ebw->action, ebw->params);
284 }
285 
286 E_API void
e_bindings_edge_reset(void)287 e_bindings_edge_reset(void)
288 {
289    E_Config_Binding_Edge *ebe;
290    Eina_List *l;
291 
292    E_FREE_LIST(edge_bindings, _e_bindings_edge_free);
293 
294    EINA_LIST_FOREACH(e_bindings->edge_bindings, l, ebe)
295      e_bindings_edge_add(ebe->context, ebe->edge, ebe->drag_only, ebe->modifiers,
296                          ebe->any_mod, ebe->action, ebe->params, ebe->delay);
297 }
298 
299 E_API void
e_bindings_mouse_reset(void)300 e_bindings_mouse_reset(void)
301 {
302    E_Config_Binding_Mouse *ebm;
303    Eina_List *l;
304 
305    E_FREE_LIST(mouse_bindings, _e_bindings_mouse_free);
306 
307    EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm)
308      e_bindings_mouse_add(ebm->context, ebm->button, ebm->modifiers,
309                           ebm->any_mod, ebm->action, ebm->params);
310 }
311 
312 E_API void
e_bindings_key_reset(void)313 e_bindings_key_reset(void)
314 {
315    E_Config_Binding_Key *ebk;
316    Eina_List *l;
317 
318    e_comp_canvas_keys_ungrab();
319    E_FREE_LIST(key_bindings, _e_bindings_key_free);
320 
321    EINA_LIST_FOREACH(e_bindings->key_bindings, l, ebk)
322      e_bindings_key_add(ebk->context, ebk->key, ebk->modifiers,
323                         ebk->any_mod, ebk->action, ebk->params);
324    e_comp_canvas_keys_grab();
325 }
326 
327 E_API void
e_bindings_reset(void)328 e_bindings_reset(void)
329 {
330    e_bindings_signal_reset();
331    e_bindings_mouse_reset();
332    e_bindings_wheel_reset();
333    e_bindings_edge_reset();
334    e_bindings_key_reset();
335 }
336 
337 E_API void
e_bindings_mouse_add(E_Binding_Context ctxt,int button,E_Binding_Modifier mod,int any_mod,const char * action,const char * params)338 e_bindings_mouse_add(E_Binding_Context ctxt, int button, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
339 {
340    E_Binding_Mouse *binding;
341 
342    binding = calloc(1, sizeof(E_Binding_Mouse));
343    binding->ctxt = ctxt;
344    binding->button = button;
345    binding->mod = mod;
346    binding->any_mod = any_mod;
347    if (action) binding->action = eina_stringshare_add(action);
348    if (params) binding->params = eina_stringshare_add(params);
349    mouse_bindings = eina_list_append(mouse_bindings, binding);
350 }
351 
352 E_API void
e_bindings_mouse_del(E_Binding_Context ctxt,int button,E_Binding_Modifier mod,int any_mod,const char * action,const char * params)353 e_bindings_mouse_del(E_Binding_Context ctxt, int button, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
354 {
355    E_Binding_Mouse *binding;
356    Eina_List *l;
357 
358    EINA_LIST_FOREACH(mouse_bindings, l, binding)
359      {
360         if ((binding->ctxt == ctxt) &&
361             (binding->button == button) &&
362             (binding->mod == mod) &&
363             (binding->any_mod == any_mod) &&
364             (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
365              ((!binding->action) && (!action))) &&
366             (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
367              ((!binding->params) && (!params))))
368           {
369              _e_bindings_mouse_free(binding);
370              mouse_bindings = eina_list_remove_list(mouse_bindings, l);
371              break;
372           }
373      }
374 }
375 
376 E_API void
e_bindings_mouse_grab(E_Binding_Context ctxt,Ecore_X_Window win)377 e_bindings_mouse_grab(E_Binding_Context ctxt, Ecore_X_Window win)
378 {
379    E_Binding_Mouse *binding;
380    Eina_List *l;
381 
382    EINA_LIST_FOREACH(mouse_bindings, l, binding)
383      {
384         if (binding->ctxt == E_BINDING_CONTEXT_ANY) continue;
385         if (e_bindings_context_match(binding->ctxt, ctxt))
386           {
387 #ifndef HAVE_WAYLAND_ONLY
388              ecore_x_window_button_grab(win, binding->button,
389                                         ECORE_X_EVENT_MASK_MOUSE_DOWN |
390                                         ECORE_X_EVENT_MASK_MOUSE_UP |
391                                         ECORE_X_EVENT_MASK_MOUSE_MOVE,
392                                         e_bindings_modifiers_to_ecore_convert(binding->mod),
393                                         binding->any_mod);
394 #endif
395           }
396      }
397 #ifdef HAVE_WAYLAND_ONLY
398    (void)win;
399 #endif
400 }
401 
402 E_API void
e_bindings_mouse_ungrab(E_Binding_Context ctxt,Ecore_X_Window win)403 e_bindings_mouse_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
404 {
405    E_Binding_Mouse *binding;
406    Eina_List *l;
407 
408    EINA_LIST_FOREACH(mouse_bindings, l, binding)
409      {
410         if (binding->ctxt == E_BINDING_CONTEXT_ANY) continue;
411         if (e_bindings_context_match(binding->ctxt, ctxt))
412           {
413 #ifndef HAVE_WAYLAND_ONLY
414              ecore_x_window_button_ungrab(win, binding->button,
415                                           e_bindings_modifiers_to_ecore_convert(binding->mod), binding->any_mod);
416 #endif
417           }
418      }
419 #ifdef HAVE_WAYLAND_ONLY
420    (void)win;
421 #endif
422 }
423 
424 E_API E_Action *
e_bindings_mouse_button_find(E_Binding_Context ctxt,E_Binding_Event_Mouse_Button * ev,E_Binding_Mouse ** bind_ret)425 e_bindings_mouse_button_find(E_Binding_Context ctxt, E_Binding_Event_Mouse_Button *ev, E_Binding_Mouse **bind_ret)
426 {
427    E_Binding_Mouse *binding;
428    Eina_List *start = NULL, *l;
429    E_Action *act = NULL;
430 
431    if (bind_ret && *bind_ret)
432      start = eina_list_data_find_list(mouse_bindings, *bind_ret);
433    if (start)
434      {
435         start = start->next;
436         if (!start)
437           {
438              *bind_ret = NULL;
439              return NULL;
440           }
441      }
442    EINA_LIST_FOREACH(start ?: mouse_bindings, l, binding)
443      {
444         if ((binding->button == (int)ev->button) &&
445             ((binding->any_mod) || (binding->mod == ev->modifiers)))
446           {
447              if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
448              if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
449              act = e_action_find(binding->action);
450              if (bind_ret) *bind_ret = binding;
451              if (!act) continue;
452              if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
453           }
454      }
455    return act;
456 }
457 
458 E_API char *
e_bindings_mouse_action_modifiers_text_generate(E_Binding_Context ctxt,const char * action,unsigned int * modifiers,unsigned int * button)459 e_bindings_mouse_action_modifiers_text_generate(E_Binding_Context ctxt, const char *action, unsigned int *modifiers, unsigned int *button)
460 {
461    Eina_Strbuf *sbuf;
462    Eina_Bool shift;
463    Eina_Bool ctrl;
464    Eina_Bool alt;
465    Eina_Bool win;
466    Eina_Bool altgr;
467    static const char *names[] =
468    {
469       "Shift",
470       "Control",
471       "Alt",
472       "Win",
473       "AltGr",
474    };
475 
476    struct
477    {
478       Eina_Bool *val;
479       const char *name;
480    } keys[5];
481    unsigned int current, i;
482    Eina_Bool found = EINA_FALSE;
483    Eina_List *l;
484    char *ret;
485    E_Config_Binding_Mouse *ebm;
486 
487    keys[0].val = &shift;
488    keys[1].val = &ctrl;
489    keys[2].val = &alt;
490    keys[3].val = &win;
491    keys[4].val = &altgr;
492 
493    EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm)
494      if ((ebm->context == (int)ctxt) && eina_streq(ebm->action, action))
495        {
496           current = ebm->modifiers;
497           if (modifiers) *modifiers = current;
498           if (button) *button = ebm->button;
499           found = EINA_TRUE;
500           break;
501        }
502    if (!found) return NULL;
503    sbuf = eina_strbuf_new();
504    for (i = 0; i < 5; i++)
505      {
506         keys[i].name = names[i];
507         *keys[i].val = (current & (1 << i));
508         if (!*keys[i].val) continue;
509         if (eina_strbuf_length_get(sbuf))
510           eina_strbuf_append_char(sbuf, '+');
511         eina_strbuf_append_printf(sbuf, "<hilight>%s</hilight>", _(keys[i].name));
512      }
513    ret = eina_strbuf_string_steal(sbuf);
514    eina_strbuf_free(sbuf);
515    return ret;
516 }
517 
518 E_API E_Action *
e_bindings_mouse_down_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Binding_Event_Mouse_Button * ev)519 e_bindings_mouse_down_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Binding_Event_Mouse_Button *ev)
520 {
521    E_Action *act;
522    E_Binding_Mouse *binding = NULL;
523 
524    if (bindings_disabled) return NULL;
525    while (1)
526      {
527         act = e_bindings_mouse_button_find(ctxt, ev, &binding);
528         if (!act) break;
529         if (act->func.go_mouse)
530           {
531              if (!act->func.go_mouse(obj, binding->params, ev))
532                continue;
533           }
534         else if (act->func.go)
535           act->func.go(obj, binding->params);
536         break;
537      }
538    return act;
539 }
540 
541 E_API E_Action *
e_bindings_mouse_down_evas_event_handle(E_Binding_Context ctxt,E_Object * obj,Evas_Event_Mouse_Down * ev)542 e_bindings_mouse_down_evas_event_handle(E_Binding_Context ctxt, E_Object *obj, Evas_Event_Mouse_Down *ev)
543 {
544    E_Binding_Event_Mouse_Button event;
545 
546    e_bindings_evas_event_mouse_button_convert(ev, &event);
547 
548    return e_bindings_mouse_down_event_handle(ctxt, obj, &event);
549 }
550 
551 E_API E_Action *
e_bindings_mouse_down_ecore_event_handle(E_Binding_Context ctxt,E_Object * obj,Ecore_Event_Mouse_Button * ev)552 e_bindings_mouse_down_ecore_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Button *ev)
553 {
554    E_Binding_Event_Mouse_Button event;
555 
556    e_bindings_ecore_event_mouse_button_convert(ev, &event);
557 
558    return e_bindings_mouse_down_event_handle(ctxt, obj, &event);
559 }
560 
561 E_API E_Action *
e_bindings_mouse_up_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Binding_Event_Mouse_Button * ev)562 e_bindings_mouse_up_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Binding_Event_Mouse_Button *ev)
563 {
564    E_Action *act;
565    E_Binding_Mouse *binding = NULL;
566 
567    if (bindings_disabled) return NULL;
568    while (1)
569      {
570         act = e_bindings_mouse_button_find(ctxt, ev, &binding);
571         if (!act) break;
572         if (act->func.end_mouse)
573           {
574              if (!act->func.end_mouse(obj, binding->params, ev))
575                continue;
576           }
577         else if (act->func.end)
578           act->func.end(obj, binding->params);
579         break;
580      }
581    return act;
582 }
583 
584 E_API E_Action *
e_bindings_mouse_up_evas_event_handle(E_Binding_Context ctxt,E_Object * obj,Evas_Event_Mouse_Up * ev)585 e_bindings_mouse_up_evas_event_handle(E_Binding_Context ctxt, E_Object *obj, Evas_Event_Mouse_Up *ev)
586 {
587    E_Binding_Event_Mouse_Button event;
588 
589    e_bindings_evas_event_mouse_button_convert((Evas_Event_Mouse_Down*)ev, &event);
590 
591    return e_bindings_mouse_up_event_handle(ctxt, obj, &event);
592 }
593 
594 E_API E_Action *
e_bindings_mouse_up_ecore_event_handle(E_Binding_Context ctxt,E_Object * obj,Ecore_Event_Mouse_Button * ev)595 e_bindings_mouse_up_ecore_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Button *ev)
596 {
597    E_Binding_Event_Mouse_Button event;
598 
599    e_bindings_ecore_event_mouse_button_convert(ev, &event);
600 
601    return e_bindings_mouse_up_event_handle(ctxt, obj, &event);
602 }
603 
604 E_API void
e_bindings_key_add(E_Binding_Context ctxt,const char * key,E_Binding_Modifier mod,int any_mod,const char * action,const char * params)605 e_bindings_key_add(E_Binding_Context ctxt, const char *key, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
606 {
607    E_Binding_Key *binding;
608 
609    binding = calloc(1, sizeof(E_Binding_Key));
610    binding->ctxt = ctxt;
611    binding->key = eina_stringshare_add(key);
612    binding->mod = mod;
613    binding->any_mod = any_mod;
614    if (action) binding->action = eina_stringshare_add(action);
615    if (params) binding->params = eina_stringshare_add(params);
616    key_bindings = eina_list_append(key_bindings, binding);
617 }
618 
619 E_API E_Binding_Key *
e_bindings_key_get(const char * action)620 e_bindings_key_get(const char *action)
621 {
622    E_Binding_Key *binding;
623    Eina_List *l;
624 
625    EINA_LIST_FOREACH(key_bindings, l, binding)
626      {
627         if (binding->action && action && !strcmp(action, binding->action))
628           return binding;
629      }
630    return NULL;
631 }
632 
633 E_API E_Binding_Key *
e_bindings_key_find(const char * key,E_Binding_Modifier mod,int any_mod)634 e_bindings_key_find(const char *key, E_Binding_Modifier mod, int any_mod)
635 {
636    E_Binding_Key *binding;
637    Eina_List *l;
638 
639    if (!key) return NULL;
640 
641    EINA_LIST_FOREACH(key_bindings, l, binding)
642      {
643         if ((binding->key) && (!strcmp(key, binding->key)) &&
644             (binding->mod == mod) && (binding->any_mod == any_mod))
645           return binding;
646      }
647 
648    return NULL;
649 }
650 
651 E_API void
e_bindings_key_del(E_Binding_Context ctxt,const char * key,E_Binding_Modifier mod,int any_mod,const char * action,const char * params)652 e_bindings_key_del(E_Binding_Context ctxt, const char *key, E_Binding_Modifier mod, int any_mod, const char *action, const char *params)
653 {
654    E_Binding_Key *binding;
655    Eina_List *l;
656 
657    EINA_LIST_FOREACH(key_bindings, l, binding)
658      {
659         if ((binding->ctxt == ctxt) &&
660             (key) && (binding->key) && (!strcmp(binding->key, key)) &&
661             (binding->mod == mod) &&
662             (binding->any_mod == any_mod) &&
663             (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
664              ((!binding->action) && (!action))) &&
665             (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
666              ((!binding->params) && (!params))))
667           {
668              _e_bindings_key_free(binding);
669              key_bindings = eina_list_remove_list(key_bindings, l);
670              break;
671           }
672      }
673 }
674 
675 E_API void
e_bindings_key_grab(E_Binding_Context ctxt,Ecore_X_Window win)676 e_bindings_key_grab(E_Binding_Context ctxt, Ecore_X_Window win)
677 {
678    E_Binding_Key *binding;
679    Eina_List *l;
680 
681    EINA_LIST_FOREACH(key_bindings, l, binding)
682      {
683         if (e_bindings_context_match(binding->ctxt, ctxt))
684           {
685              if (e_bindings_key_allowed(binding->key))
686                {
687 #ifndef HAVE_WAYLAND_ONLY
688                   ecore_x_window_key_grab(win, binding->key,
689                                           e_bindings_modifiers_to_ecore_convert(binding->mod), binding->any_mod);
690 #endif
691                }
692           }
693      }
694 #ifdef HAVE_WAYLAND_ONLY
695    (void)win;
696 #endif
697 }
698 
699 E_API void
e_bindings_key_ungrab(E_Binding_Context ctxt,Ecore_X_Window win)700 e_bindings_key_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
701 {
702    E_Binding_Key *binding;
703    Eina_List *l;
704 
705    EINA_LIST_FOREACH(key_bindings, l, binding)
706      {
707         if (e_bindings_context_match(binding->ctxt, ctxt))
708           {
709              if (e_bindings_key_allowed(binding->key))
710                {
711 #ifndef HAVE_WAYLAND_ONLY
712                   ecore_x_window_key_ungrab(win, binding->key,
713                                             e_bindings_modifiers_to_ecore_convert(binding->mod), binding->any_mod);
714 #endif
715                }
716           }
717      }
718 #ifdef HAVE_WAYLAND_ONLY
719    (void)win;
720 #endif
721 }
722 
723 EINTERN E_Binding_Key *e_binding_key_current;
724 
725 E_API E_Action *
e_bindings_key_down_event_handle(E_Binding_Context ctxt,E_Object * obj,Ecore_Event_Key * ev)726 e_bindings_key_down_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
727 {
728    E_Binding_Key *binding;
729    E_Action *act;
730 
731    if (bindings_disabled) return NULL;
732    act = e_bindings_key_event_find(ctxt, ev, &binding);
733    if (!act) return NULL;
734    e_binding_key_current = binding;
735    if (act->func.go_key)
736      act->func.go_key(obj, binding->params, ev);
737    else if (act->func.go)
738      act->func.go(obj, binding->params);
739    e_binding_key_current = NULL;
740    return act;
741 }
742 
743 E_API E_Action *
e_bindings_key_up_event_handle(E_Binding_Context ctxt,E_Object * obj,Ecore_Event_Key * ev)744 e_bindings_key_up_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Key *ev)
745 {
746    E_Binding_Key *binding;
747    E_Action *act;
748 
749    if (bindings_disabled) return NULL;
750    act = e_bindings_key_event_find(ctxt, ev, &binding);
751    if (!act) return NULL;
752    e_binding_key_current = binding;
753    if (act->func.end_key)
754      act->func.end_key(obj, binding->params, ev);
755    else if (act->func.end)
756      act->func.end(obj, binding->params);
757    e_binding_key_current = NULL;
758    return act;
759 }
760 
761 E_API E_Action *
e_bindings_key_event_find(E_Binding_Context ctxt,Ecore_Event_Key * ev,E_Binding_Key ** bind_ret)762 e_bindings_key_event_find(E_Binding_Context ctxt, Ecore_Event_Key *ev, E_Binding_Key **bind_ret)
763 {
764    E_Binding_Modifier mod = 0;
765    E_Binding_Key *binding;
766    Eina_List *l;
767    E_Action *act = NULL;
768 
769    mod = e_bindings_modifiers_from_ecore(ev->modifiers);
770    if (e_binding_key_list_cb)
771      {
772         act = e_binding_key_list_cb(ctxt, ev, mod, bind_ret);
773         if (act) return act;
774         if (bind_ret) *bind_ret = NULL;
775      }
776    EINA_LIST_FOREACH(key_bindings, l, binding)
777      {
778         if ((binding->key) && ((!strcmp(binding->key, ev->key)) || (!strcmp(binding->key, ev->keyname))) &&
779             ((binding->any_mod) || (binding->mod == mod)))
780           {
781              if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
782              if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
783              act = e_action_find(binding->action);
784              if (bind_ret) *bind_ret = binding;
785              if (!act) continue;
786              if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
787           }
788      }
789    return act;
790 }
791 
792 E_API Eina_Bool
e_bindings_key_allowed(const char * key)793 e_bindings_key_allowed(const char *key)
794 {
795    if (!key) return EINA_FALSE;
796    if ((!strcmp(key, "Shift_L")) ||
797        (!strcmp(key, "Shift_R")) ||
798        (!strcmp(key, "Control_L")) ||
799        (!strcmp(key, "Control_R")) ||
800        (!strcmp(key, "Alt_L")) ||
801        (!strcmp(key, "Alt_R")) ||
802        (!strcmp(key, "Meta_L")) ||
803        (!strcmp(key, "Meta_R")) ||
804        (!strcmp(key, "Hyper_L")) ||
805        (!strcmp(key, "Hyper_R")) ||
806        (!strcmp(key, "Super_L")) ||
807        (!strcmp(key, "Super_R")) ||
808        (!strcmp(key, "AltGr")) ||
809        (!strcmp(key, "Caps_Lock")) ||
810        (!strcmp(key, "Shift_Lock")) ||
811        (!strcmp(key, "Kana_Lock")) ||
812        (!strcmp(key, "Num_Lock")) ||
813        (!strcmp(key, "Scroll_Lock")))
814      return EINA_FALSE;
815    return EINA_TRUE;
816 }
817 
818 
819 E_API void
e_bindings_edge_add(E_Binding_Context ctxt,E_Zone_Edge edge,Eina_Bool drag_only,E_Binding_Modifier mod,int any_mod,const char * action,const char * params,float delay)820 e_bindings_edge_add(E_Binding_Context ctxt, E_Zone_Edge edge, Eina_Bool drag_only, E_Binding_Modifier mod, int any_mod, const char *action, const char *params, float delay)
821 {
822    E_Binding_Edge *binding;
823 
824    binding = calloc(1, sizeof(E_Binding_Edge));
825    binding->ctxt = ctxt;
826    binding->edge = edge;
827    binding->mod = mod;
828    binding->any_mod = any_mod;
829    binding->delay = delay;
830    binding->drag_only = drag_only;
831    if (action) binding->action = eina_stringshare_add(action);
832    if (params) binding->params = eina_stringshare_add(params);
833    edge_bindings = eina_list_append(edge_bindings, binding);
834 
835    e_zone_edge_new(edge);
836 }
837 
838 E_API Eina_Bool
e_bindings_edge_flippable_get(E_Zone_Edge edge)839 e_bindings_edge_flippable_get(E_Zone_Edge edge)
840 {
841    E_Binding_Edge *binding;
842    Eina_List *l;
843 
844    EINA_LIST_FOREACH(edge_bindings, l, binding)
845      {
846         if ((binding->edge == edge) && (binding->action))
847           {
848              if ((!strcmp(binding->action, "desk_flip_in_direction")) ||
849                  (!strcmp(binding->action, "desk_flip_by")))
850                return EINA_TRUE;
851           }
852      }
853    return EINA_FALSE;
854 }
855 
856 E_API Eina_Bool
e_bindings_edge_non_flippable_get(E_Zone_Edge edge)857 e_bindings_edge_non_flippable_get(E_Zone_Edge edge)
858 {
859    E_Binding_Edge *binding;
860    Eina_List *l;
861 
862    EINA_LIST_FOREACH(edge_bindings, l, binding)
863      {
864         if ((binding->edge == edge) && (binding->action))
865           {
866              if ((!strcmp(binding->action, "desk_flip_in_direction")) ||
867                  (!strcmp(binding->action, "desk_flip_by")))
868                continue;
869              return EINA_TRUE;
870           }
871      }
872    return EINA_FALSE;
873 }
874 
875 E_API E_Binding_Edge *
e_bindings_edge_get(const char * action,E_Zone_Edge edge,int click)876 e_bindings_edge_get(const char *action, E_Zone_Edge edge, int click)
877 {
878    E_Binding_Edge *binding;
879    Eina_List *l;
880 
881    EINA_LIST_FOREACH(edge_bindings, l, binding)
882      {
883         if ((binding->edge == edge) &&
884             ((click && EINA_FLT_EQ(binding->delay, -1.0 * click))
885              || (!click && (binding->delay >= 0.0))) &&
886             (binding->action) && (action) &&
887             (!strcmp(action, binding->action)))
888           return binding;
889      }
890    return NULL;
891 }
892 
893 E_API void
e_bindings_edge_del(E_Binding_Context ctxt,E_Zone_Edge edge,Eina_Bool drag_only,E_Binding_Modifier mod,int any_mod,const char * action,const char * params,float delay)894 e_bindings_edge_del(E_Binding_Context ctxt, E_Zone_Edge edge, Eina_Bool drag_only, E_Binding_Modifier mod, int any_mod, const char *action, const char *params, float delay)
895 {
896    E_Binding_Edge *binding;
897    Eina_List *l, *ll;
898    int ref_count = 0;
899 
900    EINA_LIST_FOREACH_SAFE(edge_bindings, l, ll, binding)
901      {
902         if (binding->edge == edge)
903           {
904              if ((binding->ctxt == ctxt) &&
905                  (binding->mod == mod) &&
906                  EINA_FLT_EQ(binding->delay, delay) &&
907                  (binding->any_mod == any_mod) &&
908                  (binding->drag_only == drag_only) &&
909                  (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
910                   ((!binding->action) && (!action))) &&
911                  (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
912                   ((!binding->params) && (!params))))
913                {
914                   _e_bindings_edge_free(binding);
915                   edge_bindings = eina_list_remove_list(edge_bindings, l);
916                }
917              else ref_count++;
918           }
919      }
920 
921    if (!ref_count)
922      e_zone_edge_free(edge);
923 }
924 
925 E_API E_Action *
e_bindings_edge_event_find(E_Binding_Context ctxt,E_Event_Zone_Edge * ev,Eina_Bool click,E_Binding_Edge ** bind_ret)926 e_bindings_edge_event_find(E_Binding_Context ctxt, E_Event_Zone_Edge *ev, Eina_Bool click, E_Binding_Edge **bind_ret)
927 {
928    E_Binding_Edge *binding;
929    E_Binding_Modifier mod = 0;
930    E_Action *act = NULL;
931    Eina_List *l;
932 
933    mod = e_bindings_modifiers_from_ecore(ev->modifiers);
934    EINA_LIST_FOREACH(edge_bindings, l, binding)
935      /* A value of <= -1.0 for the delay indicates it as a mouse-click binding on that edge */
936      if (((binding->edge == ev->edge)) &&
937          ((click && EINA_FLT_EQ(binding->delay, -1.0 * ev->button)) || (!click && (binding->delay >= 0.0))) &&
938          ((binding->drag_only == ev->drag) || ev->drag) &&
939          ((binding->any_mod) || (binding->mod == mod)))
940        {
941           if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
942           if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
943           act = e_action_find(binding->action);
944           if (bind_ret) *bind_ret = binding;
945           if (!act) continue;
946           if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
947        }
948    return act;
949 }
950 
951 E_API E_Action *
e_bindings_edge_in_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Event_Zone_Edge * ev)952 e_bindings_edge_in_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
953 {
954    E_Binding_Edge *binding = NULL;
955    E_Desk *current = NULL;
956    E_Action *act = NULL;
957    E_Binding_Edge_Data *ed;
958    E_Event_Zone_Edge *ev2;
959 
960    if (bindings_disabled) return NULL;
961    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
962    if (current->fullscreen_clients && (!e_config->fullscreen_flip)) return NULL;
963    act = e_bindings_edge_event_find(ctxt, ev, 0, &binding);
964    if ((!act) || (!binding)) return NULL;
965    ed = E_NEW(E_Binding_Edge_Data, 1);
966    ev2 = E_NEW(E_Event_Zone_Edge, 1);
967 
968    /* The original event will be freed before it can be
969     * used again */
970    ev2->zone = ev->zone;
971    ev2->edge = ev->edge;
972    ev2->x = ev->x;
973    ev2->y = ev->y;
974 
975    ed->bind = binding;
976    ed->obj = obj;
977    ed->act = act;
978    ed->ev = ev2;
979    binding->timer = ecore_timer_loop_add(((double)binding->delay), _e_bindings_edge_cb_timer, ed);
980    return act;
981 }
982 
983 E_API E_Action *
e_bindings_edge_out_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Event_Zone_Edge * ev)984 e_bindings_edge_out_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
985 {
986    E_Binding_Edge *binding = NULL;
987    E_Action *act = NULL;
988    E_Desk *current = NULL;
989 
990    if (bindings_disabled) return NULL;
991    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
992    if (current->fullscreen_clients && (!e_config->fullscreen_flip)) return NULL;
993    act = e_bindings_edge_event_find(ctxt, ev, 0, &binding);
994    if ((!act) || (!binding)) return NULL;
995    if (binding->timer)
996      {
997         E_Binding_Edge_Data *ed;
998 
999         ed = ecore_timer_del(binding->timer);
1000         if (ed)
1001           {
1002              E_FREE(ed->ev);
1003              E_FREE(ed);
1004           }
1005      }
1006    binding->timer = NULL;
1007 
1008    act = e_action_find(binding->action);
1009    if (act && act->func.end)
1010      act->func.end(obj, binding->params);
1011    return act;
1012 }
1013 
1014 E_API E_Action *
e_bindings_edge_down_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Event_Zone_Edge * ev)1015 e_bindings_edge_down_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
1016 {
1017    E_Binding_Edge *binding = NULL;
1018    E_Desk *current = NULL;
1019    E_Action *act = NULL;
1020 
1021    if (bindings_disabled) return NULL;
1022    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
1023    if (current->fullscreen_clients && (!e_config->fullscreen_flip)) return NULL;
1024    act = e_bindings_edge_event_find(ctxt, ev, 1, &binding);
1025    if ((!act) || (!binding)) return NULL;
1026    if (act->func.go_edge)
1027      act->func.go_edge(obj, binding->params, ev);
1028    else if (act->func.go)
1029      act->func.go(obj, binding->params);
1030    return act;
1031 }
1032 
1033 E_API E_Action *
e_bindings_edge_up_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Event_Zone_Edge * ev)1034 e_bindings_edge_up_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Zone_Edge *ev)
1035 {
1036    E_Binding_Edge *binding = NULL;
1037    E_Action *act = NULL;
1038    E_Desk *current = NULL;
1039 
1040    if (bindings_disabled) return NULL;
1041    current = e_desk_at_xy_get(ev->zone, ev->zone->desk_x_current, ev->zone->desk_y_current);
1042    if (current->fullscreen_clients && (!e_config->fullscreen_flip)) return NULL;
1043    act = e_bindings_edge_event_find(ctxt, ev, 1, &binding);
1044    if ((!act) || (!binding)) return NULL;
1045    act = e_action_find(binding->action);
1046    if (act && act->func.end)
1047      act->func.end(obj, binding->params);
1048    return act;
1049 }
1050 
1051 E_API void
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)1052 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)
1053 {
1054    E_Binding_Signal *binding;
1055 
1056    binding = calloc(1, sizeof(E_Binding_Signal));
1057    binding->ctxt = ctxt;
1058    if (sig) binding->sig = eina_stringshare_add(sig);
1059    if (src) binding->src = eina_stringshare_add(src);
1060    binding->mod = mod;
1061    binding->any_mod = any_mod;
1062    if (action) binding->action = eina_stringshare_add(action);
1063    if (params) binding->params = eina_stringshare_add(params);
1064    signal_bindings = eina_list_append(signal_bindings, binding);
1065 }
1066 
1067 E_API void
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)1068 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)
1069 {
1070    E_Binding_Signal *binding;
1071    Eina_List *l;
1072 
1073    EINA_LIST_FOREACH(signal_bindings, l, binding)
1074      {
1075         if ((binding->ctxt == ctxt) &&
1076             (((binding->sig) && (sig) && (!strcmp(binding->sig, sig))) ||
1077              ((!binding->sig) && (!sig))) &&
1078             (((binding->src) && (src) && (!strcmp(binding->src, src))) ||
1079              ((!binding->src) && (!src))) &&
1080             (binding->mod == mod) &&
1081             (binding->any_mod == any_mod) &&
1082             (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
1083              ((!binding->action) && (!action))) &&
1084             (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
1085              ((!binding->params) && (!params))))
1086           {
1087              _e_bindings_signal_free(binding);
1088              signal_bindings = eina_list_remove_list(signal_bindings, l);
1089              break;
1090           }
1091      }
1092 }
1093 
1094 E_API E_Action *
e_bindings_signal_find(E_Binding_Context ctxt,const char * sig,const char * src,E_Binding_Signal ** bind_ret)1095 e_bindings_signal_find(E_Binding_Context ctxt, const char *sig, const char *src, E_Binding_Signal **bind_ret)
1096 {
1097    E_Binding_Modifier mod = 0;
1098    E_Binding_Signal *binding;
1099    Eina_List *l;
1100    E_Action *act = NULL;
1101 
1102    if (strstr(sig, "MOD:Shift")) mod |= E_BINDING_MODIFIER_SHIFT;
1103    if (strstr(sig, "MOD:Control")) mod |= E_BINDING_MODIFIER_CTRL;
1104    if (strstr(sig, "MOD:Alt")) mod |= E_BINDING_MODIFIER_ALT;
1105    if (strstr(sig, "MOD:Super")) mod |= E_BINDING_MODIFIER_WIN;
1106    EINA_LIST_FOREACH(signal_bindings, l, binding)
1107      {
1108         if ((e_util_glob_match(sig, binding->sig)) &&
1109             (e_util_glob_match(src, binding->src)) &&
1110             ((binding->any_mod) || (binding->mod == mod)))
1111           {
1112              if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
1113              if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
1114              act = e_action_find(binding->action);
1115              if (bind_ret) *bind_ret = binding;
1116              if (!act) continue;
1117              if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
1118           }
1119      }
1120    return act;
1121 }
1122 
1123 E_API E_Action *
e_bindings_signal_handle(E_Binding_Context ctxt,E_Object * obj,const char * sig,const char * src)1124 e_bindings_signal_handle(E_Binding_Context ctxt, E_Object *obj, const char *sig, const char *src)
1125 {
1126    E_Action *act;
1127    E_Binding_Signal *binding;
1128 
1129    if (bindings_disabled) return NULL;
1130    if ((!sig) || (sig && (sig[0] == 0)))
1131      return NULL;
1132    if (src && (src[0] == 0)) src = NULL;
1133    act = e_bindings_signal_find(ctxt, sig, src, &binding);
1134    if (act)
1135      {
1136         if (act->func.go_signal)
1137           act->func.go_signal(obj, binding->params, sig, src);
1138         else if (act->func.go)
1139           act->func.go(obj, binding->params);
1140         return act;
1141      }
1142    return act;
1143 }
1144 
1145 E_API void
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)1146 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)
1147 {
1148    E_Binding_Wheel *binding;
1149 
1150    binding = calloc(1, sizeof(E_Binding_Wheel));
1151    binding->ctxt = ctxt;
1152    binding->direction = direction;
1153    binding->z = z;
1154    binding->mod = mod;
1155    binding->any_mod = any_mod;
1156    if (action) binding->action = eina_stringshare_add(action);
1157    if (params) binding->params = eina_stringshare_add(params);
1158    wheel_bindings = eina_list_append(wheel_bindings, binding);
1159 }
1160 
1161 E_API void
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)1162 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)
1163 {
1164    E_Binding_Wheel *binding;
1165    Eina_List *l;
1166 
1167    EINA_LIST_FOREACH(wheel_bindings, l, binding)
1168      {
1169         if ((binding->ctxt == ctxt) &&
1170             (binding->direction == direction) &&
1171             (binding->z == z) &&
1172             (binding->mod == mod) &&
1173             (binding->any_mod == any_mod) &&
1174             (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
1175              ((!binding->action) && (!action))) &&
1176             (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
1177              ((!binding->params) && (!params))))
1178           {
1179              _e_bindings_wheel_free(binding);
1180              wheel_bindings = eina_list_remove_list(wheel_bindings, l);
1181              break;
1182           }
1183      }
1184 }
1185 
1186 E_API void
e_bindings_wheel_grab(E_Binding_Context ctxt,Ecore_X_Window win)1187 e_bindings_wheel_grab(E_Binding_Context ctxt, Ecore_X_Window win)
1188 {
1189    E_Binding_Wheel *binding;
1190    Eina_List *l;
1191 
1192    EINA_LIST_FOREACH(wheel_bindings, l, binding)
1193      {
1194         if (binding->ctxt == E_BINDING_CONTEXT_ANY) continue;
1195         if (e_bindings_context_match(binding->ctxt, ctxt))
1196           {
1197              int button = 0;
1198 
1199              if (binding->direction == 0)
1200                {
1201                   if (binding->z < 0) button = 4;
1202                   else if (binding->z > 0)
1203                     button = 5;
1204                }
1205              else if (binding->direction == 1)
1206                {
1207                   if (binding->z < 0) button = 6;
1208                   else if (binding->z > 0)
1209                     button = 7;
1210                }
1211              if (button != 0)
1212                {
1213 #ifndef HAVE_WAYLAND_ONLY
1214                   ecore_x_window_button_grab(win, button,
1215                                              ECORE_X_EVENT_MASK_MOUSE_DOWN,
1216                                              e_bindings_modifiers_to_ecore_convert(binding->mod), binding->any_mod);
1217 #endif
1218                }
1219           }
1220      }
1221 #ifdef HAVE_WAYLAND_ONLY
1222    (void)win;
1223 #endif
1224 }
1225 
1226 E_API void
e_bindings_wheel_ungrab(E_Binding_Context ctxt,Ecore_X_Window win)1227 e_bindings_wheel_ungrab(E_Binding_Context ctxt, Ecore_X_Window win)
1228 {
1229    E_Binding_Wheel *binding;
1230    Eina_List *l;
1231 
1232    EINA_LIST_FOREACH(wheel_bindings, l, binding)
1233      {
1234         if (binding->ctxt == E_BINDING_CONTEXT_ANY) continue;
1235         if (e_bindings_context_match(binding->ctxt, ctxt))
1236           {
1237              int button = 0;
1238 
1239              if (binding->direction == 0)
1240                {
1241                   if (binding->z < 0) button = 4;
1242                   else if (binding->z > 0)
1243                     button = 5;
1244                }
1245              else if (binding->direction == 1)
1246                {
1247                   if (binding->z < 0) button = 6;
1248                   else if (binding->z > 0)
1249                     button = 7;
1250                }
1251              if (button != 0)
1252                {
1253 #ifndef HAVE_WAYLAND_ONLY
1254                   ecore_x_window_button_ungrab(win, button,
1255                                                e_bindings_modifiers_to_ecore_convert(binding->mod), binding->any_mod);
1256 #endif
1257                }
1258           }
1259      }
1260 #ifdef HAVE_WAYLAND_ONLY
1261    (void)win;
1262 #endif
1263 }
1264 
1265 E_API E_Action *
e_bindings_wheel_find(E_Binding_Context ctxt,E_Binding_Event_Wheel * ev,E_Binding_Wheel ** bind_ret)1266 e_bindings_wheel_find(E_Binding_Context ctxt, E_Binding_Event_Wheel *ev, E_Binding_Wheel **bind_ret)
1267 {
1268    E_Binding_Wheel *binding;
1269    Eina_List *start = NULL, *l;
1270    E_Action *act = NULL;
1271 
1272    if (bind_ret && *bind_ret)
1273      start = eina_list_data_find_list(wheel_bindings, *bind_ret);
1274    if (start)
1275      {
1276         start = start->next;
1277         if (!start)
1278           {
1279              *bind_ret = NULL;
1280              return NULL;
1281           }
1282      }
1283    EINA_LIST_FOREACH(start ?: wheel_bindings, l, binding)
1284      {
1285         if ((binding->direction == ev->direction) &&
1286             (((binding->z < 0) && (ev->z < 0)) || ((binding->z > 0) && (ev->z > 0))) &&
1287             ((binding->any_mod) || (binding->mod == ev->modifiers)))
1288           {
1289              if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
1290              if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
1291              act = e_action_find(binding->action);
1292              if (bind_ret) *bind_ret = binding;
1293              if (!act) continue;
1294              if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
1295           }
1296      }
1297    return act;
1298 }
1299 
1300 E_API E_Action *
e_bindings_wheel_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Binding_Event_Wheel * ev)1301 e_bindings_wheel_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Binding_Event_Wheel *ev)
1302 {
1303    E_Action *act;
1304    E_Binding_Wheel *binding = NULL;
1305 
1306    if (bindings_disabled) return NULL;
1307    while (1)
1308      {
1309         act = e_bindings_wheel_find(ctxt, ev, &binding);
1310         if (!act) break;
1311         if (act->func.go_wheel)
1312           {
1313              if (!act->func.go_wheel(obj, binding->params, ev))
1314                continue;
1315           }
1316         else if (act->func.go)
1317           act->func.go(obj, binding->params);
1318         break;
1319      }
1320    return act;
1321 }
1322 
1323 E_API E_Action *
e_bindings_wheel_evas_event_handle(E_Binding_Context ctxt,E_Object * obj,Evas_Event_Mouse_Wheel * ev)1324 e_bindings_wheel_evas_event_handle(E_Binding_Context ctxt, E_Object *obj, Evas_Event_Mouse_Wheel *ev)
1325 {
1326    E_Binding_Event_Wheel event;
1327 
1328    e_bindings_evas_event_mouse_wheel_convert(ev, &event);
1329 
1330    return e_bindings_wheel_event_handle(ctxt, obj, &event);
1331 }
1332 
1333 E_API E_Action *
e_bindings_wheel_ecore_event_handle(E_Binding_Context ctxt,E_Object * obj,Ecore_Event_Mouse_Wheel * ev)1334 e_bindings_wheel_ecore_event_handle(E_Binding_Context ctxt, E_Object *obj, Ecore_Event_Mouse_Wheel *ev)
1335 {
1336    E_Binding_Event_Wheel event;
1337 
1338    e_bindings_ecore_event_mouse_wheel_convert(ev, &event);
1339 
1340    return e_bindings_wheel_event_handle(ctxt, obj, &event);
1341 }
1342 
1343 E_API void
e_bindings_acpi_add(E_Binding_Context ctxt,int type,int status,const char * action,const char * params)1344 e_bindings_acpi_add(E_Binding_Context ctxt, int type, int status, const char *action, const char *params)
1345 {
1346    E_Binding_Acpi *binding;
1347 
1348    binding = E_NEW(E_Binding_Acpi, 1);
1349    binding->ctxt = ctxt;
1350    binding->type = type;
1351    binding->status = status;
1352    if (action) binding->action = eina_stringshare_add(action);
1353    if (params) binding->params = eina_stringshare_add(params);
1354    acpi_bindings = eina_list_append(acpi_bindings, binding);
1355 }
1356 
1357 E_API void
e_bindings_acpi_del(E_Binding_Context ctxt,int type,int status,const char * action,const char * params)1358 e_bindings_acpi_del(E_Binding_Context ctxt, int type, int status, const char *action, const char *params)
1359 {
1360    E_Binding_Acpi *binding;
1361    Eina_List *l;
1362 
1363    EINA_LIST_FOREACH(acpi_bindings, l, binding)
1364      {
1365         if ((binding->ctxt == ctxt) &&
1366             (binding->type == type) && (binding->status == status) &&
1367             (((binding->action) && (action) && (!strcmp(binding->action, action))) ||
1368              ((!binding->action) && (!action))) &&
1369             (((binding->params) && (params) && (!strcmp(binding->params, params))) ||
1370              ((!binding->params) && (!params))))
1371           {
1372              _e_bindings_acpi_free(binding);
1373              acpi_bindings = eina_list_remove_list(acpi_bindings, l);
1374              break;
1375           }
1376      }
1377 }
1378 
1379 E_API E_Action *
e_bindings_acpi_find(E_Binding_Context ctxt,E_Event_Acpi * ev,E_Binding_Acpi ** bind_ret)1380 e_bindings_acpi_find(E_Binding_Context ctxt, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret)
1381 {
1382    E_Binding_Acpi *binding;
1383    Eina_List *l;
1384    E_Action *act = NULL;
1385 
1386    EINA_LIST_FOREACH(acpi_bindings, l, binding)
1387      {
1388         if (binding->type == ev->type)
1389           {
1390              /* if binding status is -1, then we don't compare event status */
1391              if (binding->status != -1)
1392                {
1393                   /* binding status is set to something, compare event status */
1394                   if (binding->status != ev->status) continue;
1395                }
1396              if (!e_bindings_context_match(binding->ctxt, ctxt)) continue;
1397              if (act && (binding->ctxt == E_BINDING_CONTEXT_ANY)) continue;
1398              act = e_action_find(binding->action);
1399              if (bind_ret) *bind_ret = binding;
1400              if (!act) continue;
1401              if (binding->ctxt != E_BINDING_CONTEXT_ANY) break;
1402           }
1403      }
1404    return act;
1405 }
1406 
1407 E_API E_Action *
e_bindings_acpi_event_handle(E_Binding_Context ctxt,E_Object * obj,E_Event_Acpi * ev)1408 e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev)
1409 {
1410    E_Action *act;
1411    E_Binding_Acpi *binding = NULL;
1412 
1413    act = e_bindings_acpi_find(ctxt, ev, &binding);
1414    if ((act) && (binding))
1415      {
1416         if (act->func.go_acpi)
1417           act->func.go_acpi(obj, binding->params, ev);
1418         else if (act->func.go)
1419           act->func.go(obj, binding->params);
1420         return act;
1421      }
1422    return act;
1423 }
1424 
1425 E_API void
e_bindings_disabled_set(Eina_Bool disabled)1426 e_bindings_disabled_set(Eina_Bool disabled)
1427 {
1428    E_Client *ec;
1429    Ecore_Window win;
1430 
1431    if (disabled)
1432      {
1433         if ((!bindings_disabled) && (e_comp->comp_type == E_PIXMAP_TYPE_X))
1434           {
1435              e_bindings_key_ungrab(E_BINDING_CONTEXT_ANY, e_comp->root);
1436              E_CLIENT_FOREACH(ec)
1437                {
1438                   if (e_client_util_ignored_get(ec)) continue;
1439                   win = e_client_util_win_get(ec);
1440                   e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, win);
1441                   e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, win);
1442                }
1443           }
1444         bindings_disabled++;
1445      }
1446    else if (bindings_disabled)
1447      bindings_disabled--;
1448    if (bindings_disabled || (e_comp->comp_type != E_PIXMAP_TYPE_X)) return;
1449    e_bindings_key_grab(E_BINDING_CONTEXT_ANY, e_comp->root);
1450    E_CLIENT_FOREACH(ec)
1451      {
1452         if (e_client_util_ignored_get(ec)) continue;
1453         win = e_client_util_win_get(ec);
1454         e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, win);
1455         e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, win);
1456      }
1457 }
1458 
1459 static void
_e_bindings_mouse_free(E_Binding_Mouse * binding)1460 _e_bindings_mouse_free(E_Binding_Mouse *binding)
1461 {
1462    if (binding->action) eina_stringshare_del(binding->action);
1463    if (binding->params) eina_stringshare_del(binding->params);
1464    free(binding);
1465 }
1466 
1467 static void
_e_bindings_key_free(E_Binding_Key * binding)1468 _e_bindings_key_free(E_Binding_Key *binding)
1469 {
1470    if (binding->key) eina_stringshare_del(binding->key);
1471    if (binding->action) eina_stringshare_del(binding->action);
1472    if (binding->params) eina_stringshare_del(binding->params);
1473    free(binding);
1474 }
1475 
1476 static void
_e_bindings_edge_free(E_Binding_Edge * binding)1477 _e_bindings_edge_free(E_Binding_Edge *binding)
1478 {
1479    if (binding->action) eina_stringshare_del(binding->action);
1480    if (binding->params) eina_stringshare_del(binding->params);
1481    if (binding->timer)
1482      {
1483         E_Binding_Edge_Data *ed;
1484 
1485         ed = ecore_timer_del(binding->timer);
1486         E_FREE(ed);
1487      }
1488    free(binding);
1489 }
1490 
1491 static void
_e_bindings_signal_free(E_Binding_Signal * binding)1492 _e_bindings_signal_free(E_Binding_Signal *binding)
1493 {
1494    if (binding->sig) eina_stringshare_del(binding->sig);
1495    if (binding->src) eina_stringshare_del(binding->src);
1496    if (binding->action) eina_stringshare_del(binding->action);
1497    if (binding->params) eina_stringshare_del(binding->params);
1498    free(binding);
1499 }
1500 
1501 static void
_e_bindings_wheel_free(E_Binding_Wheel * binding)1502 _e_bindings_wheel_free(E_Binding_Wheel *binding)
1503 {
1504    if (binding->action) eina_stringshare_del(binding->action);
1505    if (binding->params) eina_stringshare_del(binding->params);
1506    free(binding);
1507 }
1508 
1509 static void
_e_bindings_acpi_free(E_Binding_Acpi * binding)1510 _e_bindings_acpi_free(E_Binding_Acpi *binding)
1511 {
1512    if (binding->action) eina_stringshare_del(binding->action);
1513    if (binding->params) eina_stringshare_del(binding->params);
1514    E_FREE(binding);
1515 }
1516 
1517 E_API int
e_bindings_context_match(E_Binding_Context bctxt,E_Binding_Context ctxt)1518 e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt)
1519 {
1520    if (bctxt == E_BINDING_CONTEXT_ANY &&
1521        !(ctxt == E_BINDING_CONTEXT_ZONE)) return 1;
1522    if (ctxt == E_BINDING_CONTEXT_UNKNOWN) return 0;
1523    if (bctxt == ctxt) return 1;
1524    return 0;
1525 }
1526 
1527 E_API E_Binding_Modifier
e_bindings_modifiers_from_ecore(unsigned int modifiers)1528 e_bindings_modifiers_from_ecore(unsigned int modifiers)
1529 {
1530    E_Binding_Modifier mod = 0;
1531 
1532 
1533    mod |= (E_BINDING_MODIFIER_SHIFT * !!(modifiers & ECORE_EVENT_MODIFIER_SHIFT));
1534    mod |= (E_BINDING_MODIFIER_CTRL * !!(modifiers & ECORE_EVENT_MODIFIER_CTRL));
1535    mod |= (E_BINDING_MODIFIER_ALT * !!(modifiers & ECORE_EVENT_MODIFIER_ALT));
1536    mod |= (E_BINDING_MODIFIER_WIN * !!(modifiers & ECORE_EVENT_MODIFIER_WIN));
1537    mod |= (E_BINDING_MODIFIER_ALTGR * !!(modifiers & ECORE_EVENT_MODIFIER_ALTGR));
1538    /* FIXME: there is a good reason numlock was ignored. sometimes people
1539     * have it on, sometimes they don't, and often they have no idea. waaaay
1540     * back in E 0.1->0.13 or so days this caused issues thus numlock,
1541     * scrollock and capslock are not usable modifiers.
1542     *
1543     * if we REALLY want to be able to use numlock we need to add more binding
1544     * flags and config that says "REALLY pay attention to numlock for this
1545     * binding" field in the binding (like there is a "any_mod" flag - we need a
1546     * "num_lock_respect" field)
1547     *
1548     * also it should be an E_BINDING_MODIFIER_LOCK_NUM as the ecore lock flag
1549     * may vary from system to system as different xservers may have differing
1550     * modifier masks for numlock (it is queried at startup).
1551     *
1552       if (ev->modifiers & ECORE_X_LOCK_NUM) mod |= ECORE_X_LOCK_NUM;
1553     */
1554 
1555    return mod;
1556 }
1557 
1558 static Eina_Bool
_e_bindings_edge_cb_timer(void * data)1559 _e_bindings_edge_cb_timer(void *data)
1560 {
1561    E_Binding_Edge_Data *ed;
1562    E_Event_Zone_Edge *ev;
1563    E_Binding_Edge *binding;
1564    E_Action *act;
1565    E_Object *obj;
1566 
1567    ed = data;
1568    binding = ed->bind;
1569    act = ed->act;
1570    obj = ed->obj;
1571    ev = ed->ev;
1572 
1573    E_FREE(ed);
1574    binding->timer = NULL;
1575 
1576    if (act->func.go_edge)
1577      act->func.go_edge(obj, binding->params, ev);
1578    else if (act->func.go)
1579      act->func.go(obj, binding->params);
1580 
1581    /* Duplicate event */
1582    E_FREE(ev);
1583 
1584    return ECORE_CALLBACK_CANCEL;
1585 }
1586