ca1d4264b9cce9dbff5fee263f4389fc18f71af2
[framework/uifw/e17.git] / src / modules / conf_keybindings / e_int_config_mousebindings.c
1 #include "e.h"
2
3 #define TEXT_NO_PARAMS _("<None>")
4 #define EXAMPLE_STRING "example : "
5 #define E_BINDING_CONTEXT_NUMBER  10
6
7 #define TEXT_PRESS_MOUSE_BINIDING_SEQUENCE _("Please hold any modifier you want<br>" \
8                                              "and press any button on your mouse,<br> or roll a" \
9                                              " wheel, to assign mouse binding." \
10                                              "<br>Press <hilight>Escape</highlight> to abort.")
11
12 static void *_create_data(E_Config_Dialog *cfd);
13 static void _free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
14 static int _basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
15 static Evas_Object *_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata);
16
17 static void _fill_data(E_Config_Dialog_Data *cfdata);
18 static void _fill_actions_list(E_Config_Dialog_Data *cfdata);
19
20 /******************* Callbacks *************/
21 static void _binding_change_cb(void *data);
22 static void _action_change_cb(void *data);
23 static void _delete_mouse_binding_cb(void *data, void *data2);
24 static void _delete_all_mouse_binding_cb(void *data, void *data2);
25 static void _restore_mouse_binding_defaults_cb(void *data, void *data2);
26 static void _add_mouse_binding_cb(void *data, void *data2);
27 static void _modify_mouse_binding_cb(void *data, void *data2);
28
29 /******************* Updates *****************/
30 static void _update_action_list(E_Config_Dialog_Data *cfdata);
31 static void _update_action_params(E_Config_Dialog_Data *cfdata);
32 static void _update_mouse_binding_list(E_Config_Dialog_Data *cfdata);
33 static void _update_buttons(E_Config_Dialog_Data *cfdata);
34 static void _update_binding_context(E_Config_Dialog_Data *cfdata);
35
36 /****************** Helper *****************/
37 static void _find_key_binding_action(const char *action, const char *params, int *g, int *a, int *n);
38 static char *_helper_button_name_get(E_Config_Binding_Mouse *eb);
39 static char *_helper_wheel_name_get(E_Config_Binding_Wheel *bw);
40 static char *_helper_modifier_name_get(int mod);
41 static void _auto_apply_changes(E_Config_Dialog_Data *cfdata);
42
43 /********* Sorting ***************/
44 static int _mouse_binding_sort_cb(const void *d1, const void *d2);
45 static int _wheel_binding_sort_cb(const void *d1, const void *d2);
46
47 /********* grab window **********/
48 static void _grab_wnd_show(E_Config_Dialog_Data *cfdata);
49 static void _grab_wnd_hide(E_Config_Dialog_Data *cfdata);
50 static Eina_Bool _grab_mouse_down_cb(void *data, int type, void *event);
51 static Eina_Bool _grab_mouse_wheel_cb(void *data, int type, void *event);
52 static Eina_Bool _grab_key_down_cb(void *data, int type, void *event);
53
54 struct _E_Config_Dialog_Data
55 {
56   E_Config_Dialog *cfd;
57
58   Evas *evas;
59
60   struct
61     {
62        Eina_List *mouse;
63        Eina_List *wheel;
64     } binding;
65
66   struct
67     {
68        const char *binding;
69        const char *action;
70        char *params;
71        int context;
72
73        const char *cur;
74        int add; /*just to distinguesh among two buttons add/modify */
75
76        E_Dialog *dia;
77        Ecore_X_Window bind_win;
78        Eina_List *handlers;
79     } locals;
80
81   struct 
82     { 
83        Evas_Object *o_binding_list;
84        Evas_Object *o_action_list;
85        Evas_Object *o_params;
86        Evas_Object *o_del;
87        Evas_Object *o_mod;
88        Evas_Object *o_del_all;
89        struct {
90          Evas_Object *o_any, *o_border, *o_menu, *o_winlist, *o_popup, *o_zone,
91                      *o_container, *o_manager, *o_none;
92        } context;
93     } gui;
94 };
95
96 E_Config_Dialog *
97 e_int_config_mousebindings(E_Container *con, const char *params __UNUSED__)
98 {
99    E_Config_Dialog *cfd;
100    E_Config_Dialog_View *v;
101    
102    if (e_config_dialog_find("E", "keyboard_and_mouse/mouse_bindings")) return NULL;
103    v = E_NEW(E_Config_Dialog_View, 1);
104    
105    v->create_cfdata = _create_data;
106    v->free_cfdata = _free_data;
107    v->basic.apply_cfdata = _basic_apply_data;
108    v->basic.create_widgets = _basic_create_widgets;
109    v->override_auto_apply = 0;
110    
111    cfd = e_config_dialog_new(con,
112                              _("Mouse Bindings Settings"),
113                              "E", "keyboard_and_mouse/mouse_bindings",
114                              "preferences-desktop-mouse", 0, v, NULL);
115    return cfd;
116 }
117
118 static void
119 _fill_data(E_Config_Dialog_Data *cfdata)
120 {
121    Eina_List *l;
122    E_Config_Binding_Mouse *eb, *eb2;
123    E_Config_Binding_Wheel *bw, *bw2;
124
125    cfdata->locals.binding = eina_stringshare_add("");
126    cfdata->locals.action = eina_stringshare_add("");
127    cfdata->locals.params = strdup("");
128    cfdata->locals.context = E_BINDING_CONTEXT_ANY;
129    cfdata->binding.mouse = NULL;
130    cfdata->binding.wheel = NULL;
131    cfdata->locals.bind_win = 0;
132    cfdata->locals.handlers =  NULL;
133    cfdata->locals.dia = NULL;
134
135    EINA_LIST_FOREACH(e_config->mouse_bindings, l, eb)
136      {
137         eb2 = E_NEW(E_Config_Binding_Mouse, 1);
138         eb2->context = eb->context;
139         eb2->button = eb->button;
140         eb2->modifiers = eb->modifiers;
141         eb2->any_mod = eb->any_mod;
142         eb2->action = !eb->action ? NULL : eina_stringshare_add(eb->action);
143         eb2->params = !eb->params ? NULL : eina_stringshare_add(eb->params);
144
145         cfdata->binding.mouse = eina_list_append(cfdata->binding.mouse, eb2);
146      }
147
148    EINA_LIST_FOREACH(e_config->wheel_bindings, l, bw)
149      {
150         bw2 = E_NEW(E_Config_Binding_Wheel, 1);
151         bw2->context = bw->context;
152         bw2->direction = bw->direction;
153         bw2->z = bw->z;
154         bw2->modifiers = bw->modifiers;
155         bw2->any_mod = bw->any_mod;
156         bw2->action = !bw->action ? NULL : eina_stringshare_add(bw->action);
157         bw2->params = !bw->params ? NULL : eina_stringshare_add(bw->params);
158
159         cfdata->binding.wheel = eina_list_append(cfdata->binding.wheel, bw2);
160      }
161 }
162
163 static void *
164 _create_data(E_Config_Dialog *cfd)
165 {
166    E_Config_Dialog_Data *cfdata;
167    
168    cfdata = E_NEW(E_Config_Dialog_Data, 1);
169    
170    _fill_data(cfdata);
171    cfdata->cfd = cfd;
172    return cfdata;
173 }
174
175 static void
176 _free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
177 {
178    E_Config_Binding_Mouse *eb;
179    E_Config_Binding_Wheel *bw;
180
181    EINA_LIST_FREE(cfdata->binding.mouse, eb)
182      {
183         eina_stringshare_del(eb->action);
184         eina_stringshare_del(eb->params);
185         E_FREE(eb);
186      }
187
188    EINA_LIST_FREE(cfdata->binding.wheel, bw)
189      {
190         eina_stringshare_del(bw->action);
191         eina_stringshare_del(bw->params);
192         E_FREE(bw);
193      }
194
195    eina_stringshare_del(cfdata->locals.binding);
196    eina_stringshare_del(cfdata->locals.action);
197    eina_stringshare_del(cfdata->locals.cur);
198
199    if (cfdata->locals.params) free(cfdata->locals.params);
200    E_FREE(cfdata);
201 }
202
203 static int
204 _basic_apply_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
205
206    Eina_List *l;
207    E_Config_Binding_Mouse *eb, *eb2;
208    E_Config_Binding_Wheel *bw, *bw2;
209
210    _auto_apply_changes(cfdata);
211
212    e_border_button_bindings_ungrab_all();
213    EINA_LIST_FREE(e_config->mouse_bindings, eb)
214      {
215         e_bindings_mouse_del(eb->context, eb->button, eb->modifiers, eb->any_mod,
216                              eb->action, eb->params);
217         eina_stringshare_del(eb->action);
218         eina_stringshare_del(eb->params);
219         E_FREE(eb);
220      }
221
222    EINA_LIST_FOREACH(cfdata->binding.mouse, l, eb)
223      {
224         eb2 = E_NEW(E_Config_Binding_Mouse, 1);
225         eb2->context = eb->context;
226         eb2->button = eb->button;
227         eb2->modifiers = eb->modifiers;
228         eb2->any_mod = eb->any_mod;
229         eb2->action = !eb->action ? NULL : eina_stringshare_add(eb->action);
230         eb2->params = !eb->params ? NULL : eina_stringshare_add(eb->params);
231
232         e_config->mouse_bindings = eina_list_append(e_config->mouse_bindings, eb2);
233         e_bindings_mouse_add(eb2->context, eb2->button, eb2->modifiers, eb2->any_mod,
234                              eb2->action, eb2->params);
235      }
236
237    EINA_LIST_FREE(e_config->wheel_bindings, bw)
238      {
239         e_bindings_wheel_del(bw->context, bw->direction, bw->z, bw->modifiers, bw->any_mod,
240                              bw->action, bw->params);
241         eina_stringshare_del(bw->action);
242         eina_stringshare_del(bw->params);
243         E_FREE(bw);
244      }
245
246    EINA_LIST_FOREACH(cfdata->binding.wheel, l, bw)
247      {
248         bw2 = E_NEW(E_Config_Binding_Wheel, 1);
249         bw2->context = bw->context;
250         bw2->direction = bw->direction;
251         bw2->z = bw->z;
252         bw2->modifiers = bw->modifiers;
253         bw2->any_mod = bw->any_mod;
254         bw2->action = !bw->action ? NULL : eina_stringshare_add(bw->action);
255         bw2->params = !bw->params ? NULL : eina_stringshare_add(bw->params);
256
257         e_config->wheel_bindings = eina_list_append(e_config->wheel_bindings, bw2);
258         e_bindings_wheel_add(bw2->context, bw2->direction, bw2->z, bw2->modifiers,
259                              bw2->any_mod, bw2->action, bw2->params);
260      }
261    e_border_button_bindings_grab_all();
262
263    e_config_save_queue();
264    return 1;
265 }
266
267 static Evas_Object *
268 _basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
269 {
270    Evas_Object *o, *of, *ot, *ob;
271    E_Radio_Group *rg;
272    
273    cfdata->evas = evas;
274    o = e_widget_list_add(evas, 0, 1);
275    ot = e_widget_frametable_add(evas, _("Mouse Bindings"), 0);
276    ob = e_widget_ilist_add(evas, 32, 32, &(cfdata->locals.binding));
277    cfdata->gui.o_binding_list = ob;
278    e_widget_size_min_set(ob, 200, 200);
279    e_widget_frametable_object_append(ot, ob, 0, 0, 2, 1, 1, 1, 1, 1);
280
281    ob = e_widget_button_add(evas, _("Add Binding"), NULL, _add_mouse_binding_cb, cfdata, NULL);
282    e_widget_frametable_object_append(ot, ob, 0, 1, 1, 1, 1, 0, 1, 0);
283    ob = e_widget_button_add(evas, _("Delete Binding"), NULL, _delete_mouse_binding_cb, cfdata, NULL);
284    cfdata->gui.o_del = ob;
285    e_widget_disabled_set(ob, 1);
286    e_widget_frametable_object_append(ot, ob, 1, 1, 1, 1, 1, 0, 1, 0);
287    ob = e_widget_button_add(evas, _("Modify Binding"), NULL, _modify_mouse_binding_cb, cfdata, NULL);
288    cfdata->gui.o_mod = ob;
289    e_widget_disabled_set(ob, 1);
290    e_widget_frametable_object_append(ot, ob, 0, 2, 1, 1, 1, 0, 1, 0);
291    ob = e_widget_button_add(evas, _("Delete All"), NULL, _delete_all_mouse_binding_cb, cfdata, NULL);
292    cfdata->gui.o_del_all = ob;
293    e_widget_disabled_set(ob, 1);
294    e_widget_frametable_object_append(ot, ob, 1, 2, 1, 1, 1, 0, 1, 0);
295    ob = e_widget_button_add(evas, _("Restore Default Bindings"), "enlightenment",
296                             _restore_mouse_binding_defaults_cb, cfdata, NULL);
297    e_widget_frametable_object_append(ot, ob, 0, 3, 2, 1, 1, 0, 1, 0);
298    e_widget_list_object_append(o, ot, 1, 1, 0.5);
299
300    ot = e_widget_table_add(evas, 0);
301    of = e_widget_framelist_add(evas, _("Action"), 0);
302    ob = e_widget_ilist_add(evas, 24, 24, &(cfdata->locals.action));
303    cfdata->gui.o_action_list = ob;
304    e_widget_size_min_set(ob, 200, 200);
305    e_widget_framelist_object_append(of, ob);
306    e_widget_table_object_append(ot, of, 0, 0, 3, 1, 1, 1, 1, 1);
307    
308    of = e_widget_framelist_add(evas, _("Action Params"), 0);
309    ob = e_widget_entry_add(evas, &(cfdata->locals.params), NULL, NULL, NULL);
310    e_widget_disabled_set(ob, 1);
311    cfdata->gui.o_params = ob;
312    e_widget_framelist_object_append(of, ob);
313    e_widget_table_object_append(ot, of, 0, 1, 3, 1, 1, 1, 1, 0);
314
315    of = e_widget_frametable_add(evas, _("Action Context"), 1);
316    rg = e_widget_radio_group_new(&(cfdata->locals.context));
317    ob = e_widget_radio_add(evas, _("Any"), E_BINDING_CONTEXT_ANY, rg);
318    cfdata->gui.context.o_any = ob;
319    e_widget_disabled_set(ob, 1);
320    e_widget_frametable_object_append(of, ob, 0, 0, 1, 1, 1, 1, 1, 1);
321    ob = e_widget_radio_add(evas, _("Border"), E_BINDING_CONTEXT_BORDER, rg);
322    cfdata->gui.context.o_border = ob;
323    e_widget_disabled_set(ob, 1);
324    e_widget_frametable_object_append(of, ob, 0, 1, 1, 1, 1, 1, 1, 1);
325    ob = e_widget_radio_add(evas, _("Menu"), E_BINDING_CONTEXT_MENU, rg);
326    cfdata->gui.context.o_menu = ob;
327    e_widget_disabled_set(ob, 1);
328    e_widget_frametable_object_append(of, ob, 0, 2, 1, 1, 1, 1, 1, 1);
329    ob = e_widget_radio_add(evas, _("Win List"), E_BINDING_CONTEXT_WINLIST, rg);
330    cfdata->gui.context.o_winlist = ob;
331    e_widget_disabled_set(ob, 1);
332    e_widget_frametable_object_append(of, ob, 1, 0, 1, 1, 1, 1, 1, 1);
333    ob = e_widget_radio_add(evas, _("Popup"), E_BINDING_CONTEXT_POPUP, rg);
334    cfdata->gui.context.o_popup = ob;
335    e_widget_disabled_set(ob, 1);
336    e_widget_frametable_object_append(of, ob, 1, 1, 1, 1, 1, 1, 1, 1);
337    ob = e_widget_radio_add(evas, _("Zone"), E_BINDING_CONTEXT_ZONE, rg);
338    cfdata->gui.context.o_zone = ob;
339    e_widget_disabled_set(ob, 1);
340    e_widget_frametable_object_append(of, ob, 1, 2, 1, 1, 1, 1, 1, 1);
341    ob = e_widget_radio_add(evas, _("Container"), E_BINDING_CONTEXT_CONTAINER, rg);
342    cfdata->gui.context.o_container = ob;
343    e_widget_disabled_set(ob, 1);
344    e_widget_frametable_object_append(of, ob, 2, 0, 1, 1, 1, 1, 1, 1);
345    ob = e_widget_radio_add(evas, _("Manager"), E_BINDING_CONTEXT_MANAGER, rg);
346    cfdata->gui.context.o_manager = ob;
347    e_widget_disabled_set(ob, 1);
348    e_widget_frametable_object_append(of, ob, 2, 1, 1, 1, 1, 1, 1, 1);
349    ob = e_widget_radio_add(evas, _("None"), E_BINDING_CONTEXT_NONE, rg);
350    cfdata->gui.context.o_none = ob;
351    e_widget_disabled_set(ob, 1);
352    e_widget_frametable_object_append(of, ob, 2, 2, 1, 1, 1, 1, 1, 1);
353    e_widget_table_object_append(ot, of, 0, 2, 3, 1, 1, 1, 1, 0);
354    e_widget_list_object_append(o, ot, 1, 1, 0.5);
355    
356    _update_mouse_binding_list(cfdata);
357    _fill_actions_list(cfdata);
358    
359    e_dialog_resizable_set(cfd->dia, 1);
360    return o;
361 }
362
363 static void
364 _fill_actions_list(E_Config_Dialog_Data *cfdata)
365 {
366    char buf[1024];
367    Eina_List *l, *l2;
368    E_Action_Group *actg;
369    E_Action_Description *actd;
370    int g, a;
371
372    evas_event_freeze(evas_object_evas_get(cfdata->gui.o_action_list));
373    edje_freeze();
374    e_widget_ilist_freeze(cfdata->gui.o_action_list);
375    
376    e_widget_ilist_clear(cfdata->gui.o_action_list);
377    for (l = e_action_groups_get(), g = 0; l; l = l->next, g++)
378      {
379         actg = l->data;
380
381         if (!actg->acts) continue;
382
383         e_widget_ilist_header_append(cfdata->gui.o_action_list, NULL, _(actg->act_grp));
384
385         for (l2 = actg->acts, a = 0; l2; l2 = l2->next, a++)
386           {
387              actd = l2->data;
388
389              snprintf(buf, sizeof(buf), "%d %d", g, a);
390              e_widget_ilist_append(cfdata->gui.o_action_list, NULL, _(actd->act_name),
391                                    _action_change_cb, cfdata, buf);
392           }
393      }
394    e_widget_ilist_go(cfdata->gui.o_action_list);
395    e_widget_ilist_thaw(cfdata->gui.o_action_list);
396    edje_thaw();
397    evas_event_thaw(evas_object_evas_get(cfdata->gui.o_action_list));
398 }
399
400 /******************* Callbacks *************/
401 static void
402 _add_mouse_binding_cb(void *data, void *data2 __UNUSED__)
403 {
404    E_Config_Dialog_Data *cfdata;
405
406    cfdata = data;
407    _auto_apply_changes(cfdata);
408
409    cfdata->locals.add = 1;
410    _grab_wnd_show(cfdata);
411 }
412
413 static void
414 _modify_mouse_binding_cb(void *data, void *data2 __UNUSED__)
415 {
416    E_Config_Dialog_Data *cfdata;
417
418    cfdata = data;
419    _auto_apply_changes(cfdata);
420
421    cfdata->locals.add = 0;
422    _grab_wnd_show(cfdata);
423 }
424
425 static void
426 _action_change_cb(void *data)
427 {
428    E_Config_Dialog_Data *cfdata;
429
430    cfdata = data;
431    _update_action_params(cfdata);
432 }
433
434 static void
435 _binding_change_cb(void *data)
436 {
437    E_Config_Dialog_Data *cfdata;
438
439    cfdata = data;
440
441    _auto_apply_changes(cfdata);
442
443    eina_stringshare_del(cfdata->locals.cur);
444    cfdata->locals.cur = NULL;
445
446    if (cfdata->locals.binding[0]) 
447      cfdata->locals.cur = eina_stringshare_ref(cfdata->locals.binding);
448
449    _update_buttons(cfdata);
450    _update_action_list(cfdata);
451    _update_binding_context(cfdata);
452 }
453
454 static void
455 _delete_all_mouse_binding_cb(void *data, void *data2 __UNUSED__)
456 {
457    E_Config_Dialog_Data *cfdata;
458    E_Config_Binding_Mouse *eb;
459    E_Config_Binding_Wheel *bw;
460
461    cfdata = data;
462
463    /* FIXME: need confirmation dialog */
464    EINA_LIST_FREE(cfdata->binding.mouse, eb)
465      {
466         eina_stringshare_del(eb->action);
467         eina_stringshare_del(eb->params);
468         E_FREE(eb);
469      }
470
471    EINA_LIST_FREE(cfdata->binding.wheel, bw)
472      {
473         eina_stringshare_del(bw->action);
474         eina_stringshare_del(bw->params);
475         E_FREE(bw);
476      }
477
478    eina_stringshare_del(cfdata->locals.cur);
479    cfdata->locals.cur = NULL;
480
481    e_widget_ilist_clear(cfdata->gui.o_binding_list);
482    e_widget_ilist_go(cfdata->gui.o_binding_list);
483    e_widget_ilist_unselect(cfdata->gui.o_action_list);
484    e_widget_entry_clear(cfdata->gui.o_params);
485    e_widget_disabled_set(cfdata->gui.o_params, 1);
486
487    _update_buttons(cfdata);
488    _update_binding_context(cfdata);
489 }
490
491 static void
492 _delete_mouse_binding_cb(void *data, void *data2 __UNUSED__)
493 {
494    Eina_List *l;
495    int sel, n;
496    E_Config_Dialog_Data *cfdata;
497    E_Config_Binding_Mouse *eb;
498    E_Config_Binding_Wheel *bw;
499
500    cfdata = data;
501
502    sel = e_widget_ilist_selected_get(cfdata->gui.o_binding_list);
503    if (cfdata->locals.binding[0] == 'm')
504      {
505         sscanf(cfdata->locals.binding, "m%d", &n);
506         l = eina_list_nth_list(cfdata->binding.mouse, n);
507         if (l)
508           {
509              eb = eina_list_data_get(l);
510              eina_stringshare_del(eb->action);
511              eina_stringshare_del(eb->params);
512              E_FREE(eb);
513
514              cfdata->binding.mouse = eina_list_remove_list(cfdata->binding.mouse, l);
515           }
516      }
517    else if (cfdata->locals.binding[0] == 'w')
518      {
519         sscanf(cfdata->locals.binding, "w%d", &n);
520         l = eina_list_nth_list(cfdata->binding.wheel, n);
521         if (l)
522           {
523              bw = eina_list_data_get(l);
524              eina_stringshare_del(bw->action);
525              eina_stringshare_del(bw->params);
526              E_FREE(bw);
527
528              cfdata->binding.wheel = eina_list_remove_list(cfdata->binding.wheel, l);
529           }
530      }
531    else
532      return;
533
534    _update_mouse_binding_list(cfdata);
535    if (sel >= e_widget_ilist_count(cfdata->gui.o_binding_list))
536      sel = e_widget_ilist_count(cfdata->gui.o_binding_list) - 1;
537
538    eina_stringshare_del(cfdata->locals.cur);
539    cfdata->locals.cur = NULL;
540
541    if (!e_widget_ilist_count(cfdata->gui.o_binding_list))
542      {
543         _update_binding_context(cfdata);
544         _update_buttons(cfdata); 
545         
546         e_widget_ilist_unselect(cfdata->gui.o_action_list);
547         e_widget_entry_clear(cfdata->gui.o_params);
548         e_widget_disabled_set(cfdata->gui.o_params, 1);
549      }
550    else 
551      { 
552         if (e_widget_ilist_nth_is_header(cfdata->gui.o_binding_list, sel)) sel++;
553         e_widget_ilist_selected_set(cfdata->gui.o_binding_list, sel);
554         e_widget_ilist_nth_show(cfdata->gui.o_binding_list, sel, 0);
555      }
556 }
557
558 static void
559 _restore_mouse_binding_defaults_cb(void *data, void *data2 __UNUSED__)
560 {
561    E_Config_Binding_Mouse *eb;
562    E_Config_Binding_Wheel *bw;
563    E_Config_Dialog_Data *cfdata;
564
565    cfdata = data;
566
567    EINA_LIST_FREE(cfdata->binding.mouse, eb)
568      {
569         eina_stringshare_del(eb->action);
570         eina_stringshare_del(eb->params);
571         E_FREE(eb);
572      }
573
574    EINA_LIST_FREE(cfdata->binding.wheel, bw)
575      {
576         if (bw->action) eina_stringshare_del(bw->action);
577         if (bw->params) eina_stringshare_del(bw->params);
578         E_FREE(bw);
579      }
580 #define CFG_MOUSEBIND_DFLT(_context, _button, _modifiers, _anymod, _action, _params) \
581    eb = E_NEW(E_Config_Binding_Mouse, 1); \
582    eb->context = _context; \
583    eb->button = _button; \
584    eb->modifiers = _modifiers; \
585    eb->any_mod = _anymod; \
586    eb->action = _action == NULL ? NULL : eina_stringshare_add(_action); \
587    eb->params = _params == NULL ? NULL : eina_stringshare_add(_params); \
588    cfdata->binding.mouse = eina_list_append(cfdata->binding.mouse, eb) 
589    
590    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_BORDER, 1, E_BINDING_MODIFIER_ALT, 0, "window_move", NULL); 
591    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_BORDER, 2, E_BINDING_MODIFIER_ALT, 0, "window_resize", NULL); 
592    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_BORDER, 3, E_BINDING_MODIFIER_ALT, 0, "window_menu", NULL); 
593    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_ZONE, 1, 0, 0, "menu_show", "main"); 
594    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_ZONE, 2, 0, 0, "menu_show", "clients"); 
595    CFG_MOUSEBIND_DFLT(E_BINDING_CONTEXT_ZONE, 3, 0, 0, "menu_show", "favorites");
596
597 #define CFG_WHEELBIND_DFLT(_context, _direction, _z, _modifiers, _anymod, _action, _params) \
598    bw = E_NEW(E_Config_Binding_Wheel, 1); \
599    bw->context = _context; \
600    bw->direction = _direction; \
601    bw->z = _z; \
602    bw->modifiers = _modifiers; \
603    bw->any_mod = _anymod; \
604    bw->action = _action == NULL ? NULL : eina_stringshare_add(_action); \
605    bw->params = _params == NULL ? NULL : eina_stringshare_add(_params); \
606    cfdata->binding.wheel = eina_list_append(cfdata->binding.wheel, bw) 
607    
608    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_CONTAINER, 0, -1, E_BINDING_MODIFIER_ALT, 0, 
609          "desk_linear_flip_by", "-1"); 
610    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_CONTAINER, 1, -1, E_BINDING_MODIFIER_ALT, 0, 
611          "desk_linear_flip_by", "-1"); 
612    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_CONTAINER, 0, 1, E_BINDING_MODIFIER_ALT, 0, 
613          "desk_linear_flip_by", "1"); 
614    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_CONTAINER, 1, 1, E_BINDING_MODIFIER_ALT, 0, 
615          "desk_linear_flip_by", "1"); 
616    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_BORDER, 0, -1, E_BINDING_MODIFIER_ALT, 0, 
617          "desk_linear_flip_by", "-1"); 
618    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_BORDER, 1, -1, E_BINDING_MODIFIER_ALT, 0, 
619          "desk_linear_flip_by", "-1"); 
620    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_BORDER, 0, 1, E_BINDING_MODIFIER_ALT, 0, 
621          "desk_linear_flip_by", "1"); 
622    CFG_WHEELBIND_DFLT(E_BINDING_CONTEXT_BORDER, 1, 1, E_BINDING_MODIFIER_ALT, 0, 
623          "desk_linear_flip_by", "1");
624
625    eina_stringshare_del(cfdata->locals.cur);
626    cfdata->locals.cur = NULL;
627
628    _update_mouse_binding_list(cfdata);
629    _update_buttons(cfdata);
630    _update_binding_context(cfdata);
631
632    e_widget_ilist_unselect(cfdata->gui.o_action_list);
633    e_widget_entry_clear(cfdata->gui.o_params);
634    e_widget_disabled_set(cfdata->gui.o_params, 1);
635 }
636
637 /******************* Updates *****************/
638 static void
639 _update_action_list(E_Config_Dialog_Data *cfdata)
640 {
641    E_Config_Binding_Mouse *eb;
642    E_Config_Binding_Wheel *bw;
643    const char *action, *params;
644    int j = -1, i, n;
645
646    if (!cfdata->locals.cur) return;
647
648    if (cfdata->locals.cur[0] == 'm')
649      {
650         sscanf(cfdata->locals.cur, "m%d", &n);
651         eb = eina_list_nth(cfdata->binding.mouse, n);
652         if (!eb)
653           {
654              e_widget_ilist_unselect(cfdata->gui.o_action_list);
655              e_widget_entry_clear(cfdata->gui.o_params);
656              e_widget_disabled_set(cfdata->gui.o_params, 1);
657              return;
658           }
659         action = eb->action;
660         params = eb->params;
661      }
662    else if (cfdata->locals.cur[0] == 'w')
663      {
664         sscanf(cfdata->locals.cur, "w%d", &n);
665         bw = eina_list_nth(cfdata->binding.wheel, n);
666         if (!bw)
667           {
668              e_widget_ilist_unselect(cfdata->gui.o_action_list);
669              e_widget_entry_clear(cfdata->gui.o_params);
670              e_widget_disabled_set(cfdata->gui.o_params, 1);
671              return;
672           }
673         action = bw->action;
674         params = bw->params;
675      }
676    else
677      return;
678
679    _find_key_binding_action(action, params, NULL, NULL, &j);
680    if (j >= 0)
681      {
682         for (i = 0; i < e_widget_ilist_count(cfdata->gui.o_action_list); i++)
683           {
684              if (i > j) break;
685              if (e_widget_ilist_nth_is_header(cfdata->gui.o_action_list, i)) j++;
686           }
687      }
688
689    if (j >= 0)
690      {
691         if (j == e_widget_ilist_selected_get(cfdata->gui.o_action_list))
692           _update_action_params(cfdata);
693         else
694           e_widget_ilist_selected_set(cfdata->gui.o_action_list, j);
695      }
696    else
697      {
698         e_widget_ilist_unselect(cfdata->gui.o_action_list);
699         eina_stringshare_del(cfdata->locals.action);
700         cfdata->locals.action = eina_stringshare_add("");
701         e_widget_entry_clear(cfdata->gui.o_params);
702      }
703 }
704
705 static void
706 _update_mouse_binding_list(E_Config_Dialog_Data *cfdata)
707 {
708    char *icon = NULL, *button, *mods;
709    char label[1024], val[10];
710    int i = 0;
711    Eina_List *l;
712    E_Config_Binding_Mouse *eb;
713    E_Config_Binding_Wheel *bw;
714
715    evas_event_freeze(evas_object_evas_get(cfdata->gui.o_binding_list));
716    edje_freeze();
717    e_widget_ilist_freeze(cfdata->gui.o_binding_list);
718    
719    e_widget_ilist_clear(cfdata->gui.o_binding_list);
720
721    if (cfdata->binding.mouse) 
722      { 
723         cfdata->binding.mouse = eina_list_sort(cfdata->binding.mouse, 
724               eina_list_count(cfdata->binding.mouse), _mouse_binding_sort_cb);
725         
726         e_widget_ilist_header_append(cfdata->gui.o_binding_list, NULL, "Mouse Buttons");
727      }
728
729    EINA_LIST_FOREACH(cfdata->binding.mouse, l, eb)
730      {
731         Evas_Object *ic;
732
733         button = _helper_button_name_get(eb);
734         mods = _helper_modifier_name_get(eb->modifiers);
735
736         if (mods && mods[0])
737           snprintf(label, sizeof(label), "%s + %s", button ? button : "", mods);
738         else
739           snprintf(label, sizeof(label), "%s", button ? button : "");
740         if (button) free(button);
741         if (mods) free(mods);
742
743         switch (eb->button)
744           {
745            case 1:
746               icon = "preferences-desktop-mouse-left";
747               break;
748            case 2:
749               icon = "preferences-desktop-mouse-middle";
750               break;
751            case 3:
752               icon = "preferences-desktop-mouse-right";
753               break;
754            default:
755               icon = "preferences-desktop-mouse-extra";
756           }
757
758         snprintf(val, sizeof(val), "m%d", i);
759
760         ic = e_icon_add(cfdata->evas);
761         e_util_icon_theme_set(ic, icon);
762         e_widget_ilist_append(cfdata->gui.o_binding_list, ic, label, _binding_change_cb,
763                               cfdata, val);
764
765         i++;
766      }
767
768    if (cfdata->binding.wheel) 
769      {
770         cfdata->binding.wheel = eina_list_sort(cfdata->binding.wheel, 
771               eina_list_count(cfdata->binding.wheel), _wheel_binding_sort_cb); 
772         
773         e_widget_ilist_header_append(cfdata->gui.o_binding_list, NULL, "Mouse Wheels");
774      }
775
776    i = 0;
777    EINA_LIST_FOREACH(cfdata->binding.wheel, l, bw)
778      {
779         Evas_Object *ic;
780
781         button = _helper_wheel_name_get(bw);
782         mods = _helper_modifier_name_get(bw->modifiers);
783
784         if (mods && mods[0])
785           snprintf(label, sizeof(label), "%s + %s", button ? button : "", mods);
786         else
787           snprintf(label, sizeof(label), "%s", button ? button : "");
788         if (button) free(button);
789         if (mods) free(mods);
790
791         snprintf(val, sizeof(val), "w%d", i);
792
793         ic = e_icon_add(cfdata->evas);
794         e_util_icon_theme_set(ic, "preferences-desktop-mouse-wheel");
795         e_widget_ilist_append(cfdata->gui.o_binding_list, ic, label, _binding_change_cb,
796                               cfdata, val);
797
798         i++;
799      }
800
801    e_widget_ilist_go(cfdata->gui.o_binding_list);
802    e_widget_ilist_thaw(cfdata->gui.o_binding_list);
803    edje_thaw();
804    evas_event_thaw(evas_object_evas_get(cfdata->gui.o_binding_list));
805
806    if (eina_list_count(cfdata->binding.mouse) + eina_list_count(cfdata->binding.wheel))
807      e_widget_disabled_set(cfdata->gui.o_del_all, 0);
808    else
809      e_widget_disabled_set(cfdata->gui.o_del_all, 1);
810 }
811
812 static void
813 _update_action_params(E_Config_Dialog_Data *cfdata)
814 {
815    int g, a, b;
816    E_Action_Group *actg;
817    E_Action_Description *actd;
818    E_Config_Binding_Mouse *eb;
819    E_Config_Binding_Wheel *bw;
820    const char *action, *params;
821
822 #define MB_EXAMPLE_PARAMS \
823    if ((!actd->param_example) || (!actd->param_example[0])) \
824      e_widget_entry_text_set(cfdata->gui.o_params, TEXT_NO_PARAMS); \
825    else \
826      e_widget_entry_text_set(cfdata->gui.o_params, actd->param_example)
827
828    if ((!cfdata->locals.action) || (!cfdata->locals.action[0]))
829      {
830         e_widget_disabled_set(cfdata->gui.o_params, 1);
831         e_widget_entry_clear(cfdata->gui.o_params);
832      }
833    sscanf(cfdata->locals.action, "%d %d", &g, &a);
834
835    actg = eina_list_nth(e_action_groups_get(), g);
836    if (!actg) return;
837    actd = eina_list_nth(actg->acts, a);
838    if (!actd) return;
839
840    if (actd->act_params)
841      {
842         e_widget_disabled_set(cfdata->gui.o_params, 1);
843         e_widget_entry_text_set(cfdata->gui.o_params, actd->act_params);
844         return;
845      }
846
847    if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0]))
848      {
849         e_widget_disabled_set(cfdata->gui.o_params, 1);
850         MB_EXAMPLE_PARAMS;
851         return;
852      }
853
854    if (!actd->editable)
855      e_widget_disabled_set(cfdata->gui.o_params, 1);
856    else
857      e_widget_disabled_set(cfdata->gui.o_params, 0);
858
859    if (cfdata->locals.cur[0] == 'm')
860      {
861         sscanf(cfdata->locals.cur, "m%d", &b);
862         eb = eina_list_nth(cfdata->binding.mouse, b);
863         if (!eb)
864           {
865              e_widget_disabled_set(cfdata->gui.o_params, 1);
866              MB_EXAMPLE_PARAMS;
867              return;
868           }
869         action = eb->action;
870         params = eb->params;
871      }
872    else if (cfdata->locals.cur[0] == 'w')
873      {
874         sscanf(cfdata->locals.cur, "w%d", &b);
875         bw = eina_list_nth(cfdata->binding.wheel, b);
876         if (!bw)
877           {
878              e_widget_disabled_set(cfdata->gui.o_params, 1);
879              MB_EXAMPLE_PARAMS;
880              return;
881           }
882         action = bw->action;
883         params = bw->params;
884      }
885    else
886      { 
887         e_widget_disabled_set(cfdata->gui.o_params, 1);
888         MB_EXAMPLE_PARAMS;
889         return;
890      }
891
892    if (action)
893      {
894         if (!strcmp(action, actd->act_cmd))
895           {
896              if ((!params) || (!params[0]))
897                MB_EXAMPLE_PARAMS;
898              else
899                e_widget_entry_text_set(cfdata->gui.o_params, params);
900           }
901         else
902           MB_EXAMPLE_PARAMS;
903      }
904    else
905      MB_EXAMPLE_PARAMS;
906 }
907
908 static void
909 _update_buttons(E_Config_Dialog_Data *cfdata)
910 {
911    if (e_widget_ilist_count(cfdata->gui.o_binding_list))
912      e_widget_disabled_set(cfdata->gui.o_del_all, 0);
913    else
914      e_widget_disabled_set(cfdata->gui.o_del_all, 1);
915
916    if (!cfdata->locals.cur)
917      { 
918         e_widget_disabled_set(cfdata->gui.o_mod, 1); 
919         e_widget_disabled_set(cfdata->gui.o_del, 1);
920         return;
921      }
922
923    e_widget_disabled_set(cfdata->gui.o_mod, 0);
924    e_widget_disabled_set(cfdata->gui.o_del, 0);
925 }
926
927 static void
928 _update_binding_context(E_Config_Dialog_Data *cfdata)
929 {
930    int n;
931    E_Config_Binding_Mouse *eb;
932    E_Config_Binding_Wheel *bw;
933    E_Binding_Context ctxt;
934
935    /* disable all the radios. */
936    e_widget_radio_toggle_set(cfdata->gui.context.o_any, 1);
937    e_widget_disabled_set(cfdata->gui.context.o_any, 1);
938    e_widget_disabled_set(cfdata->gui.context.o_border, 1);
939    e_widget_disabled_set(cfdata->gui.context.o_menu, 1);
940    e_widget_disabled_set(cfdata->gui.context.o_winlist, 1);
941    e_widget_disabled_set(cfdata->gui.context.o_popup, 1);
942    e_widget_disabled_set(cfdata->gui.context.o_zone, 1);
943    e_widget_disabled_set(cfdata->gui.context.o_container, 1);
944    e_widget_disabled_set(cfdata->gui.context.o_manager, 1);
945    e_widget_disabled_set(cfdata->gui.context.o_none, 1);
946
947    if (!cfdata->locals.cur) return;
948
949    if (cfdata->locals.cur[0] == 'm')
950      {
951         sscanf(cfdata->locals.cur, "m%d", &n);
952         eb = eina_list_nth(cfdata->binding.mouse, n);
953         if (!eb) return;
954         ctxt = eb->context;
955      }
956    else if (cfdata->locals.cur[0] == 'w')
957      {
958         sscanf(cfdata->locals.cur, "w%d", &n);
959         bw = eina_list_nth(cfdata->binding.wheel, n);
960         if (!bw) return;
961         ctxt = bw->context;
962      }
963    else
964      return;
965
966    e_widget_disabled_set(cfdata->gui.context.o_any, 0);
967    e_widget_disabled_set(cfdata->gui.context.o_border, 0);
968    e_widget_disabled_set(cfdata->gui.context.o_menu, 0);
969    e_widget_disabled_set(cfdata->gui.context.o_winlist, 0);
970    e_widget_disabled_set(cfdata->gui.context.o_popup, 0);
971    e_widget_disabled_set(cfdata->gui.context.o_zone, 0);
972    e_widget_disabled_set(cfdata->gui.context.o_container, 0);
973    e_widget_disabled_set(cfdata->gui.context.o_manager, 0);
974    e_widget_disabled_set(cfdata->gui.context.o_none, 0);
975
976    if (ctxt == E_BINDING_CONTEXT_ANY) 
977      e_widget_radio_toggle_set(cfdata->gui.context.o_any, 1);
978    else if (ctxt == E_BINDING_CONTEXT_BORDER)
979      e_widget_radio_toggle_set(cfdata->gui.context.o_border, 1);
980    else if (ctxt == E_BINDING_CONTEXT_MENU)
981      e_widget_radio_toggle_set(cfdata->gui.context.o_menu, 1);
982    else if (ctxt == E_BINDING_CONTEXT_WINLIST)
983      e_widget_radio_toggle_set(cfdata->gui.context.o_winlist, 1);
984    else if (ctxt == E_BINDING_CONTEXT_POPUP)
985      e_widget_radio_toggle_set(cfdata->gui.context.o_popup, 1);
986    else if (ctxt == E_BINDING_CONTEXT_ZONE)
987      e_widget_radio_toggle_set(cfdata->gui.context.o_zone, 1);
988    else if (ctxt == E_BINDING_CONTEXT_CONTAINER)
989      e_widget_radio_toggle_set(cfdata->gui.context.o_container, 1);
990    else if (ctxt == E_BINDING_CONTEXT_MANAGER)
991      e_widget_radio_toggle_set(cfdata->gui.context.o_manager, 1);
992    else if (ctxt == E_BINDING_CONTEXT_NONE)
993      e_widget_radio_toggle_set(cfdata->gui.context.o_none, 1);
994 }
995
996 /****************** Helper *****************/
997 static void
998 _auto_apply_changes(E_Config_Dialog_Data *cfdata)
999 {
1000    int n, g, a;
1001    E_Config_Binding_Mouse *eb = NULL;
1002    E_Config_Binding_Wheel *bw = NULL;
1003
1004    E_Action_Group *actg;
1005    E_Action_Description *actd;
1006    const char **action = NULL, **params = NULL;
1007
1008    if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0])) return;
1009
1010    if (cfdata->locals.cur[0] == 'm')
1011      {
1012         sscanf(cfdata->locals.cur, "m%d", &n);
1013         eb = eina_list_nth(cfdata->binding.mouse, n);
1014         if (!eb) return;
1015
1016         eb->context = cfdata->locals.context;
1017         action = &(eb->action);
1018         params = &(eb->params);
1019      }
1020    else if (cfdata->locals.cur[0] == 'w')
1021      {
1022         sscanf(cfdata->locals.cur, "w%d", &n);
1023         bw = eina_list_nth(cfdata->binding.wheel, n);
1024         if (!bw) return;
1025
1026         bw->context = cfdata->locals.context;
1027         action = &(bw->action);
1028         params = &(bw->params);
1029      } 
1030    
1031    if (action && *action) eina_stringshare_del(*action); 
1032    if (params && *params) eina_stringshare_del(*params); 
1033    if (action) *action = NULL; 
1034    if (params) *params = NULL;
1035
1036    if ((!cfdata->locals.action) || (!cfdata->locals.action[0])) return;
1037
1038    sscanf(cfdata->locals.action, "%d %d", &g, &a);
1039
1040    actg = eina_list_nth(e_action_groups_get(), g);
1041    if (!actg) return;
1042    actd = eina_list_nth(actg->acts, a);
1043    if (!actd) return;
1044
1045    if (actd->act_cmd) *action = eina_stringshare_add(actd->act_cmd);
1046    if (actd->act_params) 
1047      *params = eina_stringshare_add(actd->act_params);
1048    else
1049      {
1050         int ok = 1;
1051         if (cfdata->locals.params)
1052           {
1053              if (!strcmp(cfdata->locals.params, TEXT_NO_PARAMS)) ok = 0;
1054
1055              if ((actd->param_example) && (!strcmp(cfdata->locals.params, actd->param_example)))
1056                ok = 0;
1057           }
1058         else
1059           ok = 0;
1060
1061         if (ok)
1062           *params = eina_stringshare_add(cfdata->locals.params);
1063      }
1064 }
1065
1066 static void
1067 _find_key_binding_action(const char *action, const char *params, int *g, int *a, int *n)
1068 {
1069    Eina_List *l, *l2;
1070    int gg = -1, aa = -1, nn = -1, found;
1071    E_Action_Group *actg;
1072    E_Action_Description *actd;
1073
1074    if (g) *g = -1;
1075    if (a) *a = -1;
1076    if (n) *n = -1;
1077
1078    found = 0;
1079    for (l = e_action_groups_get(), gg = 0, nn = 0; l; l = l->next, gg++)
1080      {
1081         actg = l->data;
1082
1083         for (l2 = actg->acts, aa = 0; l2; l2 = l2->next, aa++)
1084           {
1085              actd = l2->data;
1086
1087              if (!strcmp((!action ? "" : action), (!actd->act_cmd ? "" : actd->act_cmd)))
1088                {
1089                   if (!params || !params[0])
1090                     {
1091                        if ((!actd->act_params) || (!actd->act_params[0]))
1092                          {
1093                             if (g) *g = gg;
1094                             if (a) *a = aa;
1095                             if (n) *n = nn;
1096                             return;
1097                          }
1098                        else
1099                          continue;
1100                     }
1101                   else
1102                     {
1103                        if ((!actd->act_params) || (!actd->act_params[0]))
1104                          {
1105                             if (g) *g = gg;
1106                             if (a) *a = aa;
1107                             if (n) *n = nn;
1108                             found = 1;
1109                          }
1110                        else
1111                          {
1112                             if (!strcmp(params, actd->act_params))
1113                               {
1114                                  if (g) *g = gg;
1115                                  if (a) *a = aa;
1116                                  if (n) *n = nn;
1117                                  return;
1118                               }
1119                          }
1120                     }
1121                }
1122              nn++;
1123           }
1124         if (found) break;
1125      }
1126
1127    if (!found)
1128      {
1129         if (g) *g = -1;
1130         if (a) *a = -1;
1131         if (n) *n = -1;
1132      }
1133 }
1134
1135 static char *
1136 _helper_button_name_get(E_Config_Binding_Mouse *eb)
1137 {
1138    char *name = NULL;
1139    char buf[1024]="";
1140
1141    switch (eb->button)
1142      { 
1143       case 1:
1144          name = strdup("Left Button");
1145          break;
1146       case 2:
1147          name = strdup("Middle Button");
1148          break;
1149       case 3: 
1150          name = strdup("Right Button");
1151          break;
1152       case 4:
1153       case 5:
1154       case 6:
1155       case 7:
1156          break;
1157       default:
1158          snprintf(buf, sizeof(buf), "Extra Button (%d)", eb->button);
1159          name = strdup(buf);
1160      }
1161    return name;
1162 }
1163
1164 static char *
1165 _helper_wheel_name_get(E_Config_Binding_Wheel *bw)
1166 {
1167    char *name = NULL;
1168    char buf[1024] = "";
1169
1170    switch (bw->direction)
1171      {
1172       case 0:
1173          if (bw->z >= 0) 
1174            name = strdup("Mouse Wheel Up");
1175          else
1176            name = strdup("Mouse Wheel Down");
1177          break;
1178       default:
1179          if (bw->z >= 0) 
1180            snprintf(buf, sizeof(buf), "Extra Wheel (%d) Up", bw->direction);
1181          else
1182            snprintf(buf, sizeof(buf), "Extra Wheel (%d) Down", bw->direction);
1183          name = strdup(buf);
1184      }
1185    return name;
1186 }
1187
1188 static char *
1189 _helper_modifier_name_get(int mod)
1190 {
1191    char mods[1024] = "";
1192
1193    if (mod & E_BINDING_MODIFIER_SHIFT)
1194      snprintf(mods, sizeof(mods), "SHIFT");
1195
1196    if (mod & E_BINDING_MODIFIER_CTRL)
1197      {
1198         if (mods[0]) strcat(mods, " + ");
1199         strcat(mods, "CTRL");
1200      }
1201
1202    if (mod & E_BINDING_MODIFIER_ALT)
1203      {
1204         if (mods[0]) strcat(mods, " + ");
1205         strcat(mods, "ALT");
1206      }
1207
1208    if (mod & E_BINDING_MODIFIER_WIN)
1209      {
1210         if (mods[0]) strcat(mods, " + ");
1211         strcat(mods, "WIN");
1212      }
1213
1214    return strdup(mods);
1215 }
1216
1217 /********* Sorting ***************/
1218 static int
1219 _mouse_binding_sort_cb(const void *d1, const void *d2)
1220 {
1221    const E_Config_Binding_Mouse *eb, *eb2;
1222
1223    eb = d1;
1224    eb2 = d2;
1225
1226    if (eb->button < eb2->button) return -1;
1227    else if (eb->button > eb2->button) return 1;
1228    else
1229      {
1230         if (eb->modifiers < eb2->modifiers) return -1;
1231         else if (eb->modifiers > eb2->modifiers) return 1;
1232      }
1233    return 0;
1234 }
1235
1236 static int
1237 _wheel_binding_sort_cb(const void *d1, const void *d2)
1238 {
1239    const E_Config_Binding_Wheel *bw, *bw2;
1240
1241    bw = d1;
1242    bw2 = d2;
1243
1244    if (bw->direction < bw2->direction) return -1;
1245    else if (bw->direction > bw2->direction) return 1;
1246    else
1247      {
1248         if ((bw->z < 0) && (bw2->z > 0)) return 1;
1249         else if ((bw->z > 0) && (bw2->z < 0)) return -1;
1250         else if (((bw->z < 0) && (bw2->z < 0)) ||
1251                  ((bw->z > 0) && (bw2->z > 0)))
1252           {
1253              if (bw->modifiers < bw2->modifiers) return -1;
1254              else if (bw->modifiers > bw2->modifiers) return 1;
1255           }
1256      }
1257    return 0;
1258 }
1259
1260 static void
1261 _grab_wnd_show(E_Config_Dialog_Data *cfdata)
1262 {
1263    E_Manager *man;
1264
1265    if (cfdata->locals.bind_win != 0) return;
1266
1267    man = e_manager_current_get();
1268
1269    cfdata->locals.dia = e_dialog_new(e_container_current_get(man), 
1270                                      "E", "_mousebind_getmouse_dialog");
1271    if (!cfdata->locals.dia) return;
1272    e_dialog_title_set(cfdata->locals.dia, _("Mouse Binding Sequence"));
1273    e_dialog_icon_set(cfdata->locals.dia, "preferences-desktop-mouse", 48);
1274    e_dialog_text_set(cfdata->locals.dia, TEXT_PRESS_MOUSE_BINIDING_SEQUENCE);
1275    e_win_centered_set(cfdata->locals.dia->win, 1);
1276    e_win_borderless_set(cfdata->locals.dia->win, 1);
1277
1278    cfdata->locals.bind_win = ecore_x_window_input_new(man->root, 0, 0,
1279                                                       man->w, man->h);
1280    ecore_x_window_show(cfdata->locals.bind_win);
1281    e_grabinput_get(cfdata->locals.bind_win, 0, cfdata->locals.bind_win);
1282
1283    cfdata->locals.handlers = eina_list_append(cfdata->locals.handlers,
1284                               ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
1285                                  _grab_key_down_cb, cfdata));
1286
1287    cfdata->locals.handlers = eina_list_append(cfdata->locals.handlers,
1288                               ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
1289                                  _grab_mouse_down_cb, cfdata));
1290
1291    cfdata->locals.handlers = eina_list_append(cfdata->locals.handlers,
1292                               ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
1293                                  _grab_mouse_wheel_cb, cfdata));
1294
1295    e_dialog_show(cfdata->locals.dia);
1296    ecore_x_icccm_transient_for_set(cfdata->locals.dia->win->evas_win, cfdata->cfd->dia->win->evas_win);
1297 }
1298
1299 static void
1300 _grab_wnd_hide(E_Config_Dialog_Data *cfdata)
1301 {
1302    while (cfdata->locals.handlers)
1303      {
1304         ecore_event_handler_del(cfdata->locals.handlers->data);
1305         cfdata->locals.handlers = 
1306            eina_list_remove_list(cfdata->locals.handlers, cfdata->locals.handlers);
1307      }
1308    cfdata->locals.handlers = NULL;
1309    e_grabinput_release(cfdata->locals.bind_win, cfdata->locals.bind_win);
1310    ecore_x_window_free(cfdata->locals.bind_win);
1311    cfdata->locals.bind_win = 0;
1312
1313    e_object_del(E_OBJECT(cfdata->locals.dia));
1314    cfdata->locals.dia = NULL;
1315 }
1316
1317 static Eina_Bool
1318 _grab_mouse_down_cb(void *data, __UNUSED__ int type, void *event)
1319 {
1320    Eina_List *l;
1321    E_Config_Dialog_Data *cfdata;
1322    E_Config_Binding_Mouse *eb = NULL;
1323    E_Config_Binding_Wheel *bw;
1324    int mod = E_BINDING_MODIFIER_NONE, n;
1325
1326    Ecore_Event_Mouse_Button *ev;
1327    
1328    ev = event;
1329    cfdata = data;
1330
1331    if (ev->window != cfdata->locals.bind_win) return ECORE_CALLBACK_PASS_ON;
1332
1333    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
1334      mod |= E_BINDING_MODIFIER_SHIFT;
1335    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
1336      mod |= E_BINDING_MODIFIER_CTRL;
1337    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
1338      mod |= E_BINDING_MODIFIER_ALT;
1339    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
1340      mod |= E_BINDING_MODIFIER_WIN; 
1341       
1342    if (cfdata->locals.add) 
1343      { 
1344         eb = E_NEW(E_Config_Binding_Mouse, 1); 
1345         eb->context = E_BINDING_CONTEXT_ANY; 
1346         eb->button = ev->buttons; 
1347         eb->modifiers = mod; 
1348         eb->any_mod = 0; 
1349         eb->action = NULL; 
1350         eb->params = NULL; 
1351         
1352         cfdata->binding.mouse = eina_list_append(cfdata->binding.mouse, eb);
1353      }
1354    else
1355      {
1356         if (cfdata->locals.cur[0] == 'm')
1357           { 
1358              sscanf(cfdata->locals.cur, "m%d", &n); 
1359              eb = eina_list_nth(cfdata->binding.mouse, n); 
1360              if (eb) 
1361                { 
1362                   eb->button = ev->buttons; 
1363                   eb->modifiers = mod; 
1364                }
1365           }
1366         else if (cfdata->locals.cur[0] == 'w')
1367           {
1368              sscanf(cfdata->locals.cur, "w%d", &n);
1369              l = eina_list_nth_list(cfdata->binding.wheel, n);
1370              bw = eina_list_data_get(l);
1371
1372              eb = E_NEW(E_Config_Binding_Mouse, 1); 
1373              eb->context = bw->context;
1374              eb->button = ev->buttons; 
1375              eb->modifiers = mod; 
1376              eb->any_mod = 0; 
1377              eb->action = bw->action; 
1378              eb->params = bw->params; 
1379
1380              cfdata->binding.mouse = eina_list_append(cfdata->binding.mouse, eb);
1381
1382              bw->action = NULL;
1383              bw->params = NULL;
1384              E_FREE(bw);
1385              cfdata->binding.wheel = eina_list_remove_list(cfdata->binding.wheel, l);
1386           }
1387      } 
1388    _update_mouse_binding_list(cfdata); 
1389
1390    if (cfdata->locals.add)
1391      { 
1392         for (l = cfdata->binding.mouse, n = 0; l; l = l->next, n++)
1393           if (l->data == eb) break;
1394
1395         e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n + 1); 
1396
1397         eina_stringshare_del(cfdata->locals.action);
1398         cfdata->locals.action = eina_stringshare_add("");
1399         e_widget_ilist_unselect(cfdata->gui.o_action_list);
1400         e_widget_entry_clear(cfdata->gui.o_params);
1401         e_widget_disabled_set(cfdata->gui.o_params, 1);
1402      }
1403    else
1404      { 
1405         for (l = cfdata->binding.mouse, n = 0; l; l = l->next, n++) 
1406           if (l->data == eb) break; 
1407
1408         eina_stringshare_del(cfdata->locals.cur);
1409         cfdata->locals.cur = NULL;
1410
1411         e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n + 1);
1412      }
1413    _update_buttons(cfdata);
1414    _grab_wnd_hide(cfdata);
1415
1416    return ECORE_CALLBACK_PASS_ON;
1417 }
1418
1419 static Eina_Bool
1420 _grab_mouse_wheel_cb(void *data, __UNUSED__ int type, void *event)
1421 {
1422    Eina_List *l;
1423    E_Config_Binding_Wheel *bw = NULL;
1424    E_Config_Binding_Mouse *eb = NULL;
1425    E_Config_Dialog_Data *cfdata;
1426    Ecore_Event_Mouse_Wheel *ev; 
1427    int mod = E_BINDING_MODIFIER_NONE, n;
1428
1429    ev = event;
1430    cfdata = data;
1431
1432    if (ev->window != cfdata->locals.bind_win) return ECORE_CALLBACK_PASS_ON;
1433
1434    if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
1435      mod |= E_BINDING_MODIFIER_SHIFT;
1436    if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
1437      mod |= E_BINDING_MODIFIER_CTRL;
1438    if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
1439      mod |= E_BINDING_MODIFIER_ALT;
1440    if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
1441      mod |= E_BINDING_MODIFIER_WIN; 
1442    
1443    
1444    if (cfdata->locals.add)
1445      {
1446         bw = E_NEW(E_Config_Binding_Wheel, 1);
1447         bw->context = E_BINDING_CONTEXT_ANY;
1448         bw->direction = ev->direction;
1449         bw->z = ev->z;
1450         bw->modifiers = mod;
1451         bw->any_mod = 0;
1452         bw->action = NULL;
1453         bw->params = NULL; 
1454         
1455         cfdata->binding.wheel = eina_list_append(cfdata->binding.wheel, bw);
1456      }
1457    else 
1458      {
1459         if (cfdata->locals.cur[0] == 'm')
1460           {
1461              sscanf(cfdata->locals.cur, "m%d", &n);
1462              l = eina_list_nth_list(cfdata->binding.mouse, n);
1463              eb = eina_list_data_get(l);
1464              
1465              bw = E_NEW(E_Config_Binding_Wheel, 1);
1466              bw->context = eb->context;
1467              bw->direction = ev->direction;
1468              bw->z = ev->z;
1469              bw->modifiers = mod;
1470              bw->any_mod = 0;
1471              bw->action = eb->action;
1472              bw->params = eb->params; 
1473
1474              cfdata->binding.wheel = eina_list_append(cfdata->binding.wheel, bw);
1475
1476              E_FREE(eb);
1477              cfdata->binding.mouse = eina_list_remove_list(cfdata->binding.mouse, l);
1478           }
1479         else if (cfdata->locals.cur[0] == 'w')
1480           {
1481              sscanf(cfdata->locals.cur, "w%d", &n);
1482              bw = eina_list_nth(cfdata->binding.wheel, n);
1483              if (bw)
1484                {
1485                   bw->direction = ev->direction;
1486                   bw->z = ev->z;
1487                   bw->modifiers = mod;
1488                }
1489           }
1490      } 
1491    _update_mouse_binding_list(cfdata); 
1492
1493    if (cfdata->locals.add)
1494      { 
1495         for (l = cfdata->binding.wheel, n = 0; l; l = l->next, n++)
1496           if (l->data == bw) break;
1497
1498         if (eina_list_count(cfdata->binding.mouse))
1499           { 
1500              n += eina_list_count(cfdata->binding.mouse) + 2;
1501              e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n); 
1502           }
1503         else 
1504           e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n + 1); 
1505
1506         e_widget_ilist_unselect(cfdata->gui.o_action_list);
1507         eina_stringshare_del(cfdata->locals.action);
1508         cfdata->locals.action = eina_stringshare_add("");
1509         e_widget_entry_clear(cfdata->gui.o_params);
1510         e_widget_disabled_set(cfdata->gui.o_params, 1);
1511      }
1512    else
1513      {
1514         for (l = cfdata->binding.wheel, n = 0; l; l = l->next, n++)
1515           if (l->data == bw) break;
1516
1517         eina_stringshare_del(cfdata->locals.cur);
1518         cfdata->locals.cur = NULL;
1519
1520         if (eina_list_count(cfdata->binding.mouse)) 
1521           { 
1522              n += eina_list_count(cfdata->binding.mouse) + 2;
1523              e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n);
1524           }
1525         else
1526           e_widget_ilist_selected_set(cfdata->gui.o_binding_list, n + 1);
1527      }
1528    _update_buttons(cfdata);
1529
1530    _grab_wnd_hide(cfdata);
1531    return ECORE_CALLBACK_PASS_ON;
1532 }
1533
1534 static Eina_Bool
1535 _grab_key_down_cb(void *data, __UNUSED__ int type, void *event)
1536 {
1537    E_Config_Dialog_Data *cfdata;
1538    Ecore_Event_Key *ev = event;
1539
1540    cfdata = data;
1541
1542    if (ev->window != cfdata->locals.bind_win) return ECORE_CALLBACK_PASS_ON;
1543
1544    if (!strcmp(ev->keyname, "Escape") &&
1545        !(ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT) &&
1546        !(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) &&
1547        !(ev->modifiers & ECORE_EVENT_MODIFIER_ALT) &&
1548        !(ev->modifiers & ECORE_EVENT_MODIFIER_WIN))
1549      { 
1550         _grab_wnd_hide(cfdata);
1551      }
1552    return ECORE_CALLBACK_PASS_ON;
1553 }