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