1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a unix video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/keysym.h>
29 
30 #include "common.h"
31 #include "kbindings_common.h"
32 
33 
34 #undef TRACE_KBINDINGS
35 
36 #define  KBEDIT_NOOP           0
37 #define  KBEDIT_ALIASING       1
38 #define  KBEDIT_EDITING        2
39 
40 typedef struct {
41   kbinding_t           *kbt;
42 
43   xitk_window_t        *xwin;
44   xitk_widget_list_t   *widget_list;
45   int                   running;
46   int                   visible;
47 
48   xitk_widget_t        *browser;
49   kbinding_entry_t     *ksel;
50 
51   xitk_widget_t        *alias;
52   xitk_widget_t        *edit;
53   xitk_widget_t        *delete;
54   xitk_widget_t        *save;
55   xitk_widget_t        *done;
56   xitk_widget_t        *grab;
57 
58   xitk_widget_t        *comment;
59   xitk_widget_t        *key;
60 
61   xitk_widget_t        *ctrl;
62   xitk_widget_t        *meta;
63   xitk_widget_t        *mod3;
64   xitk_widget_t        *mod4;
65   xitk_widget_t        *mod5;
66 
67   int                   num_entries;
68   char                **entries;
69   char                **shortcuts;
70 
71   int                   grabbing;
72   int                   action_wanted; /* See KBEDIT_ defines */
73 
74   xitk_register_key_t   kreg;
75 } _kbedit_t;
76 
77 static _kbedit_t    *kbedit = NULL;
78 
79 #define WINDOW_WIDTH        530
80 #define WINDOW_HEIGHT       456
81 #define MAX_DISP_ENTRIES    11
82 
83 #define DEFAULT_DISPLAY_MODE   1
84 #define LIRC_DISPLAY_MODE      2
85 
86 /*
87   Remap file entries syntax are:
88   ...
89   WindowReduce {
90       key = less
91       modifier = none
92   }
93 
94   Alias {
95       entry = WindowReduce
96       key = w
97       modifier = control
98   }
99   ...
100   WindowReduce action key is <less>, with no modifier usage.
101   There is an alias: C-w (control w> keystroke will have same
102                      action than WindowReduce.
103 
104   modifier entry is optional.
105   modifier key can be multiple:
106  ...
107   WindowReduce {
108       key = less
109       modifier = control, meta
110   }
111   ...
112   Here, WindowReduce action keystroke will be CM-<
113 
114   Key modifier name are:
115     none, control, ctrl, meta, alt, mod3, mod4, mod5.
116 
117   shift,lock and numlock modifier are voluntary not handled.
118 
119 */
120 
121 
_kbindings_display_kbindings_to_stream(kbinding_t * kbt,int mode,FILE * stream)122 static void _kbindings_display_kbindings_to_stream(kbinding_t *kbt, int mode, FILE *stream) {
123   char               buf[256];
124   kbinding_entry_t **k;
125   int          i;
126 
127   if(kbt == NULL) {
128     xine_error(_("OOCH: key binding table is NULL.\n"));
129     return;
130   }
131 
132   switch(mode) {
133   case LIRC_DISPLAY_MODE:
134     fprintf(stream, "##\n# xine key bindings.\n"
135 		    "# Automatically generated by %s version %s.\n##\n\n", PACKAGE, VERSION);
136 
137     for(k = kbt->entry, i = 0; k[i]->action != NULL; i++) {
138       if(!k[i]->is_alias) {
139 	snprintf(buf, sizeof(buf), "# %s\n", k[i]->comment);
140 	strlcat(buf, "begin\n"
141 		     "\tremote = xxxxx\n"
142 		     "\tbutton = xxxxx\n"
143 		     "\tprog   = xine\n"
144 		     "\trepeat = 0\n", sizeof(buf));
145 	snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\tconfig = %s\n", k[i]->action);
146 	strlcat(buf, "end\n\n", sizeof(buf));
147 	fputs(buf, stream);
148       }
149     }
150     fprintf(stream, "##\n# End of xine key bindings.\n##\n");
151     break;
152 
153   case DEFAULT_DISPLAY_MODE:
154   default:
155     fprintf(stream, "##\n# xine key bindings.\n"
156 		    "# Automatically generated by %s version %s.\n##\n\n", PACKAGE, VERSION);
157 
158     for(k = kbt->entry, i = 0; k[i]->action != NULL; i++) {
159       snprintf(buf, sizeof(buf), "# %s\n", k[i]->comment);
160 
161       if(k[i]->is_alias) {
162 	sprintf(buf+strlen(buf), "Alias {\n\tentry = %s\n", k[i]->action);
163       }
164       else
165 	sprintf(buf+strlen(buf), "%s {\n", k[i]->action);
166 
167       sprintf(buf+strlen(buf), "\tkey = %s\n\tmodifier = ", k[i]->key);
168       if(k[i]->modifier == KEYMOD_NOMOD)
169 	strlcat(buf, "none, ", sizeof(buf));
170       if(k[i]->modifier & KEYMOD_CONTROL)
171 	strlcat(buf, "control, ", sizeof(buf));
172       if(k[i]->modifier & KEYMOD_META)
173 	strlcat(buf, "meta, ", sizeof(buf));
174       if(k[i]->modifier & KEYMOD_MOD3)
175 	strlcat(buf, "mod3, ", sizeof(buf));
176       if(k[i]->modifier & KEYMOD_MOD4)
177 	strlcat(buf, "mod4, ", sizeof(buf));
178       if(k[i]->modifier & KEYMOD_MOD5)
179 	strlcat(buf, "mod5, ", sizeof(buf));
180       buf[strlen(buf) - 2] = '\n';
181       buf[strlen(buf) - 1] = '\0';
182       strlcat(buf, "}\n\n", sizeof(buf));
183       fputs(buf, stream);
184     }
185     fprintf(stream, "##\n# End of xine key bindings.\n##\n");
186     break;
187   }
188 
189 }
190 /*
191  * Display all key bindings from kbt key binding table.
192  */
_kbindings_display_kbindings(kbinding_t * kbt,int mode)193 static void _kbindings_display_kbindings(kbinding_t *kbt, int mode) {
194   _kbindings_display_kbindings_to_stream(kbt, mode, stdout);
195 }
196 
197 /*
198  * Convert a modifier to key binding modifier style.
199  */
kbindings_convert_modifier(int mod,int * modifier)200 static void kbindings_convert_modifier(int mod, int *modifier) {
201 
202   ABORT_IF_NULL(modifier);
203 
204   *modifier = KEYMOD_NOMOD;
205 
206   if(mod & MODIFIER_CTRL)
207     *modifier |= KEYMOD_CONTROL;
208   if(mod & MODIFIER_META)
209     *modifier |= KEYMOD_META;
210   if(mod & MODIFIER_MOD3)
211     *modifier |= KEYMOD_MOD3;
212   if(mod & MODIFIER_MOD4)
213     *modifier |= KEYMOD_MOD4;
214   if(mod & MODIFIER_MOD5)
215     *modifier |= KEYMOD_MOD5;
216 }
217 
218 /*
219  * Save current key binding table to keymap file.
220  */
kbindings_save_kbinding(kbinding_t * kbt)221 void kbindings_save_kbinding(kbinding_t *kbt) {
222   gGui_t *gui = gGui;
223   FILE   *f;
224 
225   if((f = fopen(gui->keymap_file, "w+")) == NULL) {
226     return;
227   }
228   else {
229     _kbindings_display_kbindings_to_stream(kbt, DEFAULT_DISPLAY_MODE, f);
230     fclose(f);
231   }
232 }
233 
234 /*
235  * Return a duplicated table from kbt.
236  */
_kbindings_duplicate_kbindings(kbinding_t * kbt)237 static kbinding_t *_kbindings_duplicate_kbindings(kbinding_t *kbt) {
238   int         i;
239   kbinding_t *k;
240 
241   ABORT_IF_NULL(kbt);
242 
243   k = (kbinding_t *) calloc(1, sizeof(kbinding_t));
244 
245   for(i = 0; kbt->entry[i]->action != NULL; i++) {
246     k->entry[i]            = (kbinding_entry_t *) calloc(1, sizeof(kbinding_entry_t));
247     k->entry[i]->comment   = strdup(kbt->entry[i]->comment);
248     k->entry[i]->action    = strdup(kbt->entry[i]->action);
249     k->entry[i]->action_id = kbt->entry[i]->action_id;
250     k->entry[i]->key       = strdup(kbt->entry[i]->key);
251     k->entry[i]->modifier  = kbt->entry[i]->modifier;
252     k->entry[i]->is_alias  = kbt->entry[i]->is_alias;
253     k->entry[i]->is_gui    = kbt->entry[i]->is_gui;
254   }
255 
256   k->entry[i]            = (kbinding_entry_t *) calloc(1, sizeof(kbinding_entry_t));
257   k->entry[i]->comment   = NULL;
258   k->entry[i]->action    = NULL;
259   k->entry[i]->action_id = 0;
260   k->entry[i]->key       = NULL;
261   k->entry[i]->modifier  = 0;
262   k->entry[i]->is_alias  = 0;
263   k->entry[i]->is_gui    = 0;
264   k->num_entries         = i + 1;
265 
266   return k;
267 }
268 
269 /*
270  * Free key binding table kbt, then set it to default table.
271  */
kbindings_reset_kbinding(kbinding_t * kbt)272 void kbindings_reset_kbinding(kbinding_t *kbt) {
273 
274   ABORT_IF_NULL(kbt);
275 
276   _kbindings_free_bindings_no_kbt(kbt);
277   _kbindings_init_to_default_no_kbt(kbt);
278 }
279 
280 /*
281  * This could be used to create a default key binding file
282  * with 'xine --keymap > $HOME/.xine_keymap'
283  */
kbindings_display_default_bindings(void)284 void kbindings_display_default_bindings(void) {
285   kbinding_t *kbt = NULL;
286 
287   kbt = _kbindings_init_to_default();
288 
289   _kbindings_display_kbindings(kbt, DEFAULT_DISPLAY_MODE);
290   _kbindings_free_bindings(kbt);
291 }
292 
293 /*
294  * This could be used to create a default key binding file
295  * with 'xine --keymap=lirc > $HOME/.lircrc'
296  */
kbindings_display_default_lirc_bindings(void)297 void kbindings_display_default_lirc_bindings(void) {
298   kbinding_t *kbt = NULL;
299 
300   kbt = _kbindings_init_to_default();
301 
302   _kbindings_display_kbindings(kbt, LIRC_DISPLAY_MODE);
303   _kbindings_free_bindings(kbt);
304 }
305 
306 /*
307  * This could be used to create a key binding file from key binding
308  * object k, with 'xine --keymap > $HOME/.xine_keymap'
309  */
kbindings_display_current_bindings(kbinding_t * kbt)310 void kbindings_display_current_bindings(kbinding_t *kbt) {
311 
312   ABORT_IF_NULL(kbt);
313 
314   _kbindings_display_kbindings(kbt, DEFAULT_DISPLAY_MODE);
315 }
316 
317 /*
318  * Return action id from key binding kbt entry.
319  */
kbindings_get_action_id(kbinding_entry_t * kbt)320 action_id_t kbindings_get_action_id(kbinding_entry_t *kbt) {
321 
322   if(kbt == NULL)
323     return ACTID_NOKEY;
324 
325   return kbt->action_id;
326 }
327 
_kbindings_get_shortcut_from_kbe(kbinding_entry_t * kbe)328 static const char *_kbindings_get_shortcut_from_kbe(kbinding_entry_t *kbe) {
329   gGui_t *gui = gGui;
330   static char shortcut[32];
331 
332   if(kbe) {
333     shortcut[0] = 0;
334 
335     if(gui->shortcut_style == 0) {
336       if(kbe->modifier & KEYMOD_CONTROL)
337 	snprintf(shortcut+strlen(shortcut), sizeof(shortcut)-strlen(shortcut), "%s+", _("Ctrl"));
338       if(kbe->modifier & KEYMOD_META)
339 	snprintf(shortcut+strlen(shortcut), sizeof(shortcut)-strlen(shortcut), "%s+", _("Alt"));
340       if(kbe->modifier & KEYMOD_MOD3)
341 	strlcat(shortcut, "M3+", sizeof(shortcut));
342       if(kbe->modifier & KEYMOD_MOD4)
343 	strlcat(shortcut, "M4+", sizeof(shortcut));
344       if(kbe->modifier & KEYMOD_MOD5)
345 	strlcat(shortcut, "M5+", sizeof(shortcut));
346     }
347     else {
348       if(kbe->modifier & KEYMOD_CONTROL)
349 	strlcat(shortcut, "C-", sizeof(shortcut));
350       if(kbe->modifier & KEYMOD_META)
351 	strlcat(shortcut, "M-", sizeof(shortcut));
352       if(kbe->modifier & KEYMOD_MOD3)
353 	strlcat(shortcut, "M3-", sizeof(shortcut));
354       if(kbe->modifier & KEYMOD_MOD4)
355 	strlcat(shortcut, "M4-", sizeof(shortcut));
356       if(kbe->modifier & KEYMOD_MOD5)
357 	strlcat(shortcut, "M5-", sizeof(shortcut));
358     }
359 
360     strlcat(shortcut, kbe->key, sizeof(shortcut));
361 
362     return shortcut;
363   }
364   return NULL;
365 }
366 
kbindings_get_shortcut(kbinding_t * kbt,char * action)367 char *kbindings_get_shortcut(kbinding_t *kbt, char *action) {
368   kbinding_entry_t  *k;
369   static char        shortcut[32];
370 
371   if(kbt) {
372     if(action && (k = kbindings_lookup_action(kbt, action))) {
373       if(strcmp(k->key, "VOID")) {
374 	snprintf(shortcut, sizeof(shortcut), "%c%s%c", '[', _kbindings_get_shortcut_from_kbe(k), ']');
375 	return shortcut;
376       }
377     }
378   }
379   return NULL;
380 }
381 
382 /*
383  * Try to find and entry in key binding table matching with key and modifier value.
384  */
kbindings_lookup_binding(kbinding_t * kbt,const char * key,int modifier)385 static kbinding_entry_t *kbindings_lookup_binding(kbinding_t *kbt, const char *key, int modifier) {
386   kbinding_entry_t *kret = NULL, *k;
387   int               i;
388 
389   if((key == NULL) || (kbt == NULL))
390     return NULL;
391 
392 #ifdef TRACE_KBINDINGS
393   printf("Looking for: '%s' [", key);
394   if(modifier == KEYMOD_NOMOD)
395     printf("none, ");
396   if(modifier & KEYMOD_CONTROL)
397     printf("control, ");
398   if(modifier & KEYMOD_META)
399     printf("meta, ");
400   if(modifier & KEYMOD_MOD3)
401     printf("mod3, ");
402   if(modifier & KEYMOD_MOD4)
403     printf("mod4, ");
404   if(modifier & KEYMOD_MOD5)
405     printf("mod5, ");
406   printf("\b\b]\n");
407 #endif
408 
409   /* Be case sensitive */
410   for(i = 0, k = kbt->entry[0]; kbt->entry[i]->action != NULL; i++, k = kbt->entry[i]) {
411     if(k && k->key && strlen(k->key) && ((!(strcmp(k->key, key))) && (modifier == k->modifier))) {
412       kret = k;
413       goto __found;
414     }
415   }
416 
417   /* Not case sensitive */
418   /*
419   for(i = 0, k = kbt[0]; kbt[i]->action != NULL; i++, k = kbt[i]) {
420     if((!(strcasecmp(k->key, key))) && (modifier == k->modifier))
421       return k;
422   }
423   */
424   /* Last chance */
425   for(i = 0, k = kbt->entry[0]; kbt->entry[i]->action != NULL; i++, k = kbt->entry[i]) {
426     if(k && k->key && strlen(k->key) && ((!(strcmp(k->key, key))) && (k->modifier == KEYMOD_NOMOD))) {
427       kret = k;
428       break;
429     }
430   }
431 
432  __found:
433 
434   /* Keybinding unknown */
435   return kret;
436 }
437 
438 /* Convert X(Button|Key)(Press|Release) events into string identifier. */
xevent2id(XEvent * event,int * modifier,char * buf,int size)439 static int xevent2id(XEvent *event, int *modifier, char *buf, int size) {
440   int    mod;
441   KeySym mkey;
442   char  *keySym;
443 
444   if (event == NULL)
445     return -1;
446 
447   switch (event->type) {
448   case ButtonPress:
449   case ButtonRelease:
450     (void) xitk_get_key_modifier(event, &mod);
451     kbindings_convert_modifier(mod, modifier);
452     snprintf(buf, size, "XButton_%d", event->xbutton.button);
453     return 0;
454 
455   case KeyPress:
456   case KeyRelease:
457     (void) xitk_get_key_modifier(event, &mod);
458     kbindings_convert_modifier(mod, modifier);
459     mkey = xitk_get_key_pressed(event);
460 
461     switch (mkey) {
462       default:
463         gGui->x_lock_display (event->xany.display);
464         keySym = XKeysymToString(mkey);
465         gGui->x_unlock_display (event->xany.display);
466         if (keySym != NULL) {
467           strlcpy(buf, keySym, size);
468           return 0;
469         }
470       case 0: /* Key without assigned KeySymbol */
471       case XK_VoidSymbol:
472         /* For keys without assigned KeySyms. */
473         snprintf(buf, size, "XKey_%d", event->xkey.keycode);
474         return 0;
475     }
476 
477   default:
478     memset(buf, 0, size);
479     return -1;
480   }
481 }
482 
483 /*
484  * Handle key event from an XEvent.
485  */
kbindings_handle_kbinding(kbinding_t * kbt,XEvent * event)486 void kbindings_handle_kbinding(kbinding_t *kbt, XEvent *event) {
487   gGui_t *gui = gGui;
488   int               modifier;
489   char              buf[256];
490   kbinding_entry_t *k;
491 
492   if(!gui->kbindings_enabled || (kbt == NULL) || (event == NULL))
493     return;
494 
495   if (xevent2id(event, &modifier, buf, sizeof(buf)))
496     return;
497   k = kbindings_lookup_binding(kbt, buf, modifier);
498   if(k && !(gui->no_gui && k->is_gui))
499     gui_execute_action_id (gui, k->action_id);
500 #if 0  /* DEBUG */
501   else
502     printf("%s unhandled\n", kbuf);
503 #endif
504 }
505 
506 /*
507  * ***** Key Binding Editor ******
508  */
509 /*
510  * return 1 if key binding editor is ON
511  */
kbedit_is_running(void)512 int kbedit_is_running(void) {
513 
514   if(kbedit != NULL)
515     return kbedit->running;
516 
517   return 0;
518 }
519 
520 /*
521  * Return 1 if setup panel is visible
522  */
kbedit_is_visible(void)523 int kbedit_is_visible(void) {
524   gGui_t *gui = gGui;
525 
526   if(kbedit != NULL) {
527     if(gui->use_root_window)
528       return xitk_is_window_visible(gui->display, xitk_window_get_window(kbedit->xwin));
529     else
530       return kbedit->visible && xitk_is_window_visible(gui->display, xitk_window_get_window(kbedit->xwin));
531   }
532 
533   return 0;
534 }
535 
536 /*
537  * Raise kbedit->xwin
538  */
kbedit_raise_window(void)539 void kbedit_raise_window(void) {
540 
541   if(kbedit != NULL)
542     raise_window(xitk_window_get_window(kbedit->xwin), kbedit->visible, kbedit->running);
543 }
544 
545 /*
546  * Hide/show the kbedit panel
547  */
kbedit_toggle_visibility(xitk_widget_t * w,void * data)548 void kbedit_toggle_visibility (xitk_widget_t *w, void *data) {
549   if(kbedit != NULL)
550     toggle_window(xitk_window_get_window(kbedit->xwin), kbedit->widget_list,
551 		  &kbedit->visible, kbedit->running);
552 }
553 
kbedit_create_browser_entries(void)554 static void kbedit_create_browser_entries(void) {
555   gGui_t *gui = gGui;
556   xitk_font_t  *fs;
557   int           i;
558 
559   if(kbedit->num_entries) {
560     for(i = 0; i < kbedit->num_entries; i++) {
561       free((char *)kbedit->entries[i]);
562       free((char *)kbedit->shortcuts[i]);
563     }
564     free((char **)kbedit->entries);
565     free((char **)kbedit->shortcuts);
566   }
567 
568   fs = xitk_font_load_font(gui->display, br_fontname);
569   xitk_font_set_font(fs, (XITK_WIDGET_LIST_GC(kbedit->widget_list)));
570 
571   kbedit->entries   = (char **) calloc(kbedit->kbt->num_entries, sizeof(char *));
572   kbedit->shortcuts = (char **) calloc(kbedit->kbt->num_entries, sizeof(char *));
573   kbedit->num_entries = kbedit->kbt->num_entries - 1;
574 
575   for(i = 0; i < kbedit->num_entries; i++) {
576     char  buf[2048];
577     const char *sc = _kbindings_get_shortcut_from_kbe(kbedit->kbt->entry[i]);
578     char  shortcut[32];
579 
580     snprintf(shortcut, sizeof(shortcut), "%c%s%c", '[', (sc ? sc : "VOID"), ']');
581 
582     if(kbedit->kbt->entry[i]->is_alias)
583       snprintf(buf, sizeof(buf), "@{%s}", kbedit->kbt->entry[i]->comment);
584     else
585       strlcpy(buf, kbedit->kbt->entry[i]->comment, sizeof(buf));
586 
587     kbedit->entries[i]   = strdup(buf);
588     kbedit->shortcuts[i] = strdup(shortcut);
589   }
590 
591   kbedit->entries[i]   = NULL;
592   kbedit->shortcuts[i] = NULL;
593 
594   xitk_font_unload_font(fs);
595 }
596 
kbedit_display_kbinding(const char * action,kbinding_entry_t * kbe)597 static void kbedit_display_kbinding(const char *action, kbinding_entry_t *kbe) {
598 
599   if(action && kbe) {
600 
601     xitk_label_change_label(kbedit->comment, action);
602     xitk_label_change_label(kbedit->key, kbe->key);
603 
604     xitk_checkbox_set_state(kbedit->ctrl, (kbe->modifier & KEYMOD_CONTROL) ? 1 : 0);
605     xitk_checkbox_set_state(kbedit->meta, (kbe->modifier & KEYMOD_META) ? 1 : 0);
606     xitk_checkbox_set_state(kbedit->mod3, (kbe->modifier & KEYMOD_MOD3) ? 1 : 0);
607     xitk_checkbox_set_state(kbedit->mod4, (kbe->modifier & KEYMOD_MOD4) ? 1 : 0);
608     xitk_checkbox_set_state(kbedit->mod5, (kbe->modifier & KEYMOD_MOD5) ? 1 : 0);
609   }
610 }
611 
612 /*
613  *
614  */
kbedit_select(int s)615 static void kbedit_select(int s) {
616 
617   xitk_enable_and_show_widget(kbedit->alias);
618   xitk_enable_and_show_widget(kbedit->edit);
619   xitk_enable_and_show_widget(kbedit->delete);
620 
621   kbedit->ksel = kbedit->kbt->entry[s];
622   kbedit_display_kbinding(kbedit->entries[s], kbedit->kbt->entry[s]);
623 }
624 
625 /*
626  *
627  */
kbedit_unset(void)628 static void kbedit_unset(void) {
629 
630   if(xitk_labelbutton_get_state(kbedit->alias))
631     xitk_labelbutton_set_state(kbedit->alias, 0);
632 
633   if(xitk_labelbutton_get_state(kbedit->edit))
634     xitk_labelbutton_set_state(kbedit->edit, 0);
635 
636   xitk_disable_widget(kbedit->alias);
637   xitk_disable_widget(kbedit->edit);
638   xitk_disable_widget(kbedit->delete);
639   xitk_disable_widget(kbedit->grab);
640   kbedit->ksel = NULL;
641 
642   xitk_label_change_label(kbedit->comment, _("Nothing selected"));
643   xitk_label_change_label(kbedit->key, _("None"));
644 
645   xitk_checkbox_set_state(kbedit->ctrl, 0);
646   xitk_checkbox_set_state(kbedit->meta, 0);
647   xitk_checkbox_set_state(kbedit->mod3, 0);
648   xitk_checkbox_set_state(kbedit->mod4, 0);
649   xitk_checkbox_set_state(kbedit->mod5, 0);
650 }
651 
652 /*
653  * Check for redundancy.
654  * return: -2 on failure (null pointer passed)
655  *         -1 on success
656  *         >=0 if a redundant entry found (bkt array entry num).
657  */
bkedit_check_redundancy(kbinding_t * kbt,kbinding_entry_t * kbe)658 static int bkedit_check_redundancy(kbinding_t *kbt, kbinding_entry_t *kbe) {
659   int ret = -1;
660 
661   if(kbt && kbe) {
662     int i;
663 
664     for(i = 0; kbt->entry[i]->action != NULL; i++) {
665       if((!strcmp(kbt->entry[i]->key, kbe->key)) &&
666 	 (kbt->entry[i]->modifier == kbe->modifier) &&
667 	 (strcasecmp(kbt->entry[i]->key, "void"))) {
668 	return i;
669       }
670     }
671   }
672   else
673     ret = -2;
674 
675   return ret;
676 }
677 
678 /*
679  *
680  */
kbedit_exit(xitk_widget_t * w,void * data)681 static void kbedit_exit(xitk_widget_t *w, void *data) {
682   gGui_t *gui = gGui;
683 
684   if(kbedit) {
685     window_info_t wi;
686 
687     kbedit->running = 0;
688     kbedit->visible = 0;
689 
690     if((xitk_get_window_info(kbedit->kreg, &wi))) {
691       config_update_num("gui.kbedit_x", wi.x);
692       config_update_num("gui.kbedit_y", wi.y);
693       WINDOW_INFO_ZERO(&wi);
694     }
695 
696     xitk_unregister_event_handler(&kbedit->kreg);
697 
698     xitk_destroy_widgets(kbedit->widget_list);
699     xitk_window_destroy_window(gui->imlib_data, kbedit->xwin);
700 
701     kbedit->xwin = NULL;
702     /* xitk_dlist_init (&kbedit->widget_list->list); */
703 
704     gui->x_lock_display (gui->display);
705     XFreeGC(gui->display, (XITK_WIDGET_LIST_GC(kbedit->widget_list)));
706     gui->x_unlock_display (gui->display);
707 
708     XITK_WIDGET_LIST_FREE(kbedit->widget_list);
709 
710     {
711       int i;
712 
713       for(i = 0; i < kbedit->num_entries; i++) {
714 	free((char *)kbedit->entries[i]);
715 	free((char *)kbedit->shortcuts[i]);
716       }
717 
718       free((char **)kbedit->entries);
719       free((char **)kbedit->shortcuts);
720     }
721 
722     kbindings_free_kbinding(&kbedit->kbt);
723 
724     free(kbedit);
725     kbedit = NULL;
726     gui->ssaver_enabled = 1;
727 
728     try_to_set_input_focus(gui->video_window);
729   }
730 }
731 
732 /*
733  *
734  */
kbedit_sel(xitk_widget_t * w,void * data,int s)735 static void kbedit_sel(xitk_widget_t *w, void *data, int s) {
736 
737   if(s >= 0)
738     kbedit_select(s);
739 }
740 
741 /*
742  * Create an alias from the selected entry.
743  */
kbedit_alias(xitk_widget_t * w,void * data,int state)744 static void kbedit_alias(xitk_widget_t *w, void *data, int state) {
745 
746   xitk_labelbutton_set_state(kbedit->edit, 0);
747 
748   if(state) {
749     xitk_enable_widget(kbedit->grab);
750     kbedit->action_wanted = KBEDIT_ALIASING;
751   }
752   else {
753     xitk_disable_widget(kbedit->grab);
754     kbedit->action_wanted = KBEDIT_NOOP;
755   }
756 }
757 
758 /*
759  * Change shortcut, should take care about reduncancy.
760  */
kbedit_edit(xitk_widget_t * w,void * data,int state)761 static void kbedit_edit(xitk_widget_t *w, void *data, int state) {
762 
763   xitk_labelbutton_set_state(kbedit->alias, 0);
764 
765   if(state) {
766     xitk_enable_widget(kbedit->grab);
767     kbedit->action_wanted = KBEDIT_EDITING;
768   }
769   else {
770     xitk_disable_widget(kbedit->grab);
771     kbedit->action_wanted = KBEDIT_NOOP;
772   }
773 
774 }
775 
776 /*
777  * Remove selected entry, but alias ones only.
778  */
kbedit_delete(xitk_widget_t * w,void * data)779 static void kbedit_delete(xitk_widget_t *w, void *data) {
780   int s = xitk_browser_get_current_selected(kbedit->browser);
781 
782   xitk_labelbutton_set_state(kbedit->alias, 0);
783   xitk_labelbutton_set_state(kbedit->edit, 0);
784   xitk_disable_widget(kbedit->grab);
785 
786   /* We can delete alias entries, only */
787   if(s >= 0) {
788 
789     if(kbedit->kbt->entry[s]->is_alias) {
790       xitk_browser_release_all_buttons(kbedit->browser);
791 
792       free(kbedit->kbt->entry[s]->comment);
793       free(kbedit->kbt->entry[s]->action);
794       free(kbedit->kbt->entry[s]->key);
795       free(kbedit->kbt->entry[s]);
796 
797 
798       for(; s < kbedit->num_entries; s++)
799 	kbedit->kbt->entry[s] = kbedit->kbt->entry[s + 1];
800 
801       kbedit->kbt->entry[s]->comment = NULL;
802       kbedit->kbt->entry[s]->action  = NULL;
803       kbedit->kbt->entry[s]->key     = NULL;
804 
805       kbedit->kbt->num_entries--;
806 
807       kbedit_create_browser_entries();
808 
809       xitk_browser_update_list(kbedit->browser,
810 			       (const char* const*) kbedit->entries,
811 			       (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
812     }
813     else
814       xine_error(_("You can only delete alias entries."));
815 
816   }
817 }
818 
819 /*
820  * Reset to xine's default table.
821  */
kbedit_reset(xitk_widget_t * w,void * data)822 static void kbedit_reset(xitk_widget_t *w, void *data) {
823 
824   xitk_labelbutton_set_state(kbedit->alias, 0);
825   xitk_labelbutton_set_state(kbedit->edit, 0);
826   xitk_disable_widget(kbedit->grab);
827 
828   kbindings_reset_kbinding(kbedit->kbt);
829   kbedit_create_browser_entries();
830   xitk_browser_update_list(kbedit->browser,
831 			   (const char* const*) kbedit->entries,
832 			   (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
833 }
834 
835 /*
836  * Save keymap file, then set global table to hacked one
837  */
kbedit_save(xitk_widget_t * w,void * data)838 static void kbedit_save(xitk_widget_t *w, void *data) {
839   gGui_t *gui = gGui;
840   xitk_labelbutton_set_state(kbedit->alias, 0);
841   xitk_labelbutton_set_state(kbedit->edit, 0);
842   xitk_disable_widget(kbedit->grab);
843 
844   kbindings_free_kbinding(&gui->kbindings);
845   gui->kbindings = _kbindings_duplicate_kbindings(kbedit->kbt);
846   kbindings_save_kbinding(gui->kbindings);
847 }
848 
849 /*
850  * Forget and dismiss kbeditor
851  */
kbedit_end(void)852 void kbedit_end(void) {
853   kbedit_exit(NULL, NULL);
854 }
855 
kbedit_accept_yes(xitk_widget_t * w,void * data,int state)856 static void kbedit_accept_yes(xitk_widget_t *w, void *data, int state) {
857   kbinding_entry_t *kbe = (kbinding_entry_t *) data;
858 
859   switch(kbedit->action_wanted) {
860 
861   case KBEDIT_ALIASING:
862     if(kbedit->kbt->num_entries >= MAX_ENTRIES) {
863       xine_error(_("No more space for additional entries!"));
864       return;
865     }
866 
867     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->comment   = strdup(kbedit->ksel->comment);
868     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->action    = strdup(kbedit->ksel->action);
869     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->action_id = kbedit->ksel->action_id;
870     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->key       = strdup(kbe->key);
871     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->modifier  = kbe->modifier;
872     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->is_alias  = 1;
873     kbedit->kbt->entry[kbedit->kbt->num_entries - 1]->is_gui    = kbe->is_gui;
874 
875     kbedit->kbt->entry[kbedit->kbt->num_entries]            = (kbinding_entry_t *) calloc(1, sizeof(kbinding_entry_t));
876     kbedit->kbt->entry[kbedit->kbt->num_entries]->comment   = NULL;
877     kbedit->kbt->entry[kbedit->kbt->num_entries]->action    = NULL;
878     kbedit->kbt->entry[kbedit->kbt->num_entries]->action_id = 0;
879     kbedit->kbt->entry[kbedit->kbt->num_entries]->key       = NULL;
880     kbedit->kbt->entry[kbedit->kbt->num_entries]->modifier  = 0;
881     kbedit->kbt->entry[kbedit->kbt->num_entries]->is_alias  = 0;
882     kbedit->kbt->entry[kbedit->kbt->num_entries]->is_gui    = 0;
883 
884     kbedit->kbt->num_entries++;
885 
886     kbedit_create_browser_entries();
887     xitk_browser_update_list(kbedit->browser,
888 			     (const char* const*) kbedit->entries,
889 			     (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
890     break;
891 
892   case KBEDIT_EDITING:
893     kbedit->ksel->key = (char *) realloc(kbedit->ksel->key, sizeof(char) * (strlen(kbe->key) + 1));
894     strcpy(kbedit->ksel->key, kbe->key);
895     kbedit->ksel->modifier = kbe->modifier;
896 
897     kbedit_create_browser_entries();
898     xitk_browser_update_list(kbedit->browser,
899 			     (const char* const*) kbedit->entries,
900 			     (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
901     break;
902   }
903 
904   kbedit->action_wanted = KBEDIT_NOOP;
905 
906   SAFE_FREE(kbe->comment);
907   SAFE_FREE(kbe->action);
908   SAFE_FREE(kbe->key);
909   SAFE_FREE(kbe);
910   kbedit_unset();
911 }
912 
kbedit_accept_no(xitk_widget_t * w,void * data,int state)913 static void kbedit_accept_no(xitk_widget_t *w, void *data, int state) {
914   kbinding_entry_t *kbe = (kbinding_entry_t *) data;
915 
916   kbedit->action_wanted = KBEDIT_NOOP;
917 
918   xitk_browser_update_list(kbedit->browser,
919 			   (const char* const*) kbedit->entries,
920 			   (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
921   SAFE_FREE(kbe->comment);
922   SAFE_FREE(kbe->action);
923   SAFE_FREE(kbe->key);
924   SAFE_FREE(kbe);
925   kbedit_unset();
926 }
927 
928 /*
929  * Grab key binding.
930  */
kbedit_grab(xitk_widget_t * w,void * data)931 static void kbedit_grab(xitk_widget_t *w, void *data) {
932   gGui_t *gui = gGui;
933   char              *olbl;
934   XEvent             xev;
935   int                mod, modifier;
936   xitk_window_t     *xwin;
937   kbinding_entry_t  *kbe;
938   int                redundant;
939 
940   /* We are already grabbing keybinding */
941   if(kbedit->grabbing)
942     return;
943 
944   olbl = strdup(xitk_labelbutton_get_label(kbedit->grab));
945 
946   kbedit->grabbing = 1;
947 
948   kbe = (kbinding_entry_t *) calloc(1, sizeof(kbinding_entry_t));
949   kbe->comment   = strdup(kbedit->ksel->comment);
950   kbe->action    = strdup(kbedit->ksel->action);
951   kbe->action_id = kbedit->ksel->action_id;
952   kbe->is_alias  = kbedit->ksel->is_alias;
953   kbe->is_gui    = kbedit->ksel->is_gui;
954 
955   xitk_labelbutton_change_label(kbedit->grab, _("Press Keyboard Keys..."));
956   gui->x_lock_display (gui->display);
957   XSync(gui->display, False);
958   gui->x_unlock_display (gui->display);
959 
960   {
961     int x, y, w, h;
962 
963     xitk_get_window_position(gui->display,
964 			     (xitk_window_get_window(kbedit->xwin)), &x, &y, &w, &h);
965 
966     xwin = xitk_window_create_dialog_window(gui->imlib_data,
967 					    _("Event Receiver Window:  Press keyboard keys to bind..."),
968 					    x, y, w, h);
969 
970     set_window_states_start((xitk_window_get_window(xwin)));
971   }
972 
973   gui->x_lock_display (gui->display);
974   XRaiseWindow(gui->display, (xitk_window_get_window(xwin)));
975   XMapWindow(gui->display, (xitk_window_get_window(xwin)));
976   gui->x_unlock_display (gui->display);
977 
978   try_to_set_input_focus(xitk_window_get_window(xwin));
979 
980   do {
981     /* Although only release events are evaluated, we must also grab the corresponding press */
982     /* events to hide them from the other GUI windows and prevent unexpected side effects.   */
983     gui->x_lock_display (gui->display);
984     XMaskEvent(gui->display, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask, &xev);
985     gui->x_unlock_display (gui->display);
986   } while ((xev.type != KeyRelease && xev.type != ButtonRelease) ||
987 	   xev.xany.window != xitk_window_get_window(xwin));
988 
989   (void) xitk_get_key_modifier(&xev, &mod);
990   kbindings_convert_modifier(mod, &modifier);
991 
992   kbe->modifier = modifier;
993 
994 
995   {
996     char buf[256];
997     xevent2id(&xev, &kbe->modifier, buf, sizeof(buf));
998     kbe->key = strdup(buf);
999     kbe->modifier &= ~MODIFIER_NUML;
1000   }
1001 
1002   xitk_labelbutton_change_label(kbedit->grab, olbl);
1003 
1004   xitk_window_destroy_window(gui->imlib_data, xwin);
1005 
1006   gui->x_lock_display (gui->display);
1007   XSync(gui->display, False);
1008   gui->x_unlock_display (gui->display);
1009 
1010   kbedit->grabbing = 0;
1011 
1012   if((redundant = bkedit_check_redundancy(kbedit->kbt, kbe)) == -1) {
1013     char shortcut[32];
1014 
1015     kbedit_display_kbinding(xitk_label_get_label(kbedit->comment), kbe);
1016 
1017     snprintf(shortcut, sizeof(shortcut), "%c%s%c", '[', _kbindings_get_shortcut_from_kbe(kbe), ']');
1018 
1019     /* Ask if user wants to store new shortcut */
1020     xitk_window_dialog_yesno_with_width(gui->imlib_data, _("Accept?"),
1021 					kbedit_accept_yes,
1022 					kbedit_accept_no,
1023 					(void *) kbe, 400, ALIGN_CENTER,
1024 					_("Store %s as\n'%s' key binding ?"),
1025 					shortcut, kbedit->ksel->comment);
1026   }
1027   else {
1028     /* error, redundant */
1029     if(redundant >= 0) {
1030       xine_error(_("This key binding is redundant with action:\n\"%s\".\n"),
1031 		 kbedit->kbt->entry[redundant]->comment);
1032     }
1033   }
1034 
1035   free(olbl);
1036   xitk_labelbutton_set_state(kbedit->alias, 0);
1037   xitk_labelbutton_set_state(kbedit->edit, 0);
1038   xitk_disable_widget(kbedit->grab);
1039 }
1040 
1041 /*
1042  *
1043  */
kbedit_handle_event(XEvent * event,void * data)1044 static void kbedit_handle_event(XEvent *event, void *data) {
1045 
1046   switch(event->type) {
1047 
1048   case KeyPress:
1049     if(xitk_get_key_pressed(event) == XK_Escape)
1050       kbedit_exit(NULL, NULL);
1051     else
1052       gui_handle_event (event, gGui);
1053     break;
1054 
1055   case KeyRelease: {
1056     xitk_widget_t *w;
1057 
1058     if(!kbedit || !kbedit->widget_list)
1059       return;
1060 
1061     w = xitk_get_focused_widget(kbedit->widget_list);
1062 
1063     if((w && (w != kbedit->done) && (w != kbedit->save))
1064        && (xitk_browser_get_current_selected(kbedit->browser) < 0)) {
1065       kbedit_unset();
1066     }
1067   }
1068   break;
1069 
1070   case ButtonRelease: {
1071     xitk_widget_t *w;
1072 
1073     if(!kbedit || !kbedit->widget_list)
1074       return;
1075 
1076     w = xitk_get_focused_widget(kbedit->widget_list);
1077 
1078     if((w && (w != kbedit->done) && (w != kbedit->save))
1079        && (xitk_browser_get_current_selected(kbedit->browser) < 0)) {
1080       kbedit_unset();
1081     }
1082 
1083   }
1084   break;
1085 
1086   }
1087 }
1088 
kbedit_reparent(void)1089 void kbedit_reparent(void) {
1090   if(kbedit)
1091     reparent_window((xitk_window_get_window(kbedit->xwin)));
1092 }
1093 
1094 /*
1095  *
1096  */
kbedit_window(void)1097 void kbedit_window(void) {
1098   gGui_t *gui = gGui;
1099   int                        x, y, y1;
1100   GC                         gc;
1101   xitk_pixmap_t             *bg;
1102   xitk_labelbutton_widget_t  lb;
1103   xitk_label_widget_t        l;
1104   xitk_browser_widget_t      br;
1105   xitk_checkbox_widget_t     cb;
1106   int                        btnw = 80;
1107   int                        fontheight;
1108   xitk_font_t               *fs;
1109   xitk_widget_t             *w;
1110 
1111   x = xine_config_register_num(__xineui_global_xine_instance, "gui.kbedit_x",
1112 			       80,
1113 			       CONFIG_NO_DESC,
1114 			       CONFIG_NO_HELP,
1115 			       CONFIG_LEVEL_DEB,
1116 			       CONFIG_NO_CB,
1117 			       CONFIG_NO_DATA);
1118   y = xine_config_register_num(__xineui_global_xine_instance, "gui.kbedit_y",
1119 			       80,
1120 			       CONFIG_NO_DESC,
1121 			       CONFIG_NO_HELP,
1122 			       CONFIG_LEVEL_DEB,
1123 			       CONFIG_NO_CB,
1124 			       CONFIG_NO_DATA);
1125 
1126   kbedit = (_kbedit_t *) calloc(1, sizeof(_kbedit_t));
1127 
1128   kbedit->kbt           = _kbindings_duplicate_kbindings(gui->kbindings);
1129   kbedit->action_wanted = KBEDIT_NOOP;
1130   kbedit->xwin          = xitk_window_create_dialog_window(gui->imlib_data,
1131 							   _("Key Binding Editor"),
1132 							   x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
1133   set_window_states_start((xitk_window_get_window(kbedit->xwin)));
1134 
1135   gui->x_lock_display (gui->display);
1136   gc = XCreateGC(gui->display,
1137 		 (xitk_window_get_window(kbedit->xwin)), None, None);
1138   gui->x_unlock_display (gui->display);
1139 
1140   kbedit->widget_list      = xitk_widget_list_new();
1141 
1142   xitk_widget_list_set(kbedit->widget_list,
1143 		       WIDGET_LIST_WINDOW, (void *) (xitk_window_get_window(kbedit->xwin)));
1144   xitk_widget_list_set(kbedit->widget_list, WIDGET_LIST_GC, gc);
1145 
1146   bg = xitk_image_create_xitk_pixmap(gui->imlib_data, WINDOW_WIDTH, WINDOW_HEIGHT);
1147 
1148   gui->x_lock_display (gui->display);
1149   XCopyArea(gui->display, (xitk_window_get_background(kbedit->xwin)), bg->pixmap,
1150 	    bg->gc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
1151   gui->x_unlock_display (gui->display);
1152 
1153   x = 15;
1154   y = 34;
1155 
1156   draw_rectangular_inner_box(gui->imlib_data, bg, x, y,
1157 			     (WINDOW_WIDTH - 30 - 1), (MAX_DISP_ENTRIES * 20 + 16 + 10 - 1));
1158 
1159   y += MAX_DISP_ENTRIES * 20 + 16 + 10 + 30;
1160   y1 = y; /* remember for later */
1161   draw_outter_frame(gui->imlib_data, bg,
1162 		    _("Binding Action"), hboldfontname,
1163 		    x, y,
1164 		    (WINDOW_WIDTH - 30), 45);
1165 
1166   y += 45 + 3;
1167   draw_outter_frame(gui->imlib_data, bg,
1168 		    _("Key"), hboldfontname,
1169 		    x, y,
1170 		    120, 45);
1171 
1172   draw_outter_frame(gui->imlib_data, bg,
1173 		    _("Modifiers"), hboldfontname,
1174 		    x + 130, y,
1175 		    (WINDOW_WIDTH - (x + 130) - 15), 45);
1176 
1177 
1178   xitk_window_change_background(gui->imlib_data, kbedit->xwin, bg->pixmap,
1179 				WINDOW_WIDTH, WINDOW_HEIGHT);
1180 
1181   xitk_image_destroy_xitk_pixmap(bg);
1182 
1183   kbedit_create_browser_entries();
1184 
1185   y = 34;
1186 
1187   XITK_WIDGET_INIT(&br, gui->imlib_data);
1188 
1189   br.arrow_up.skin_element_name    = NULL;
1190   br.slider.skin_element_name      = NULL;
1191   br.arrow_dn.skin_element_name    = NULL;
1192   br.browser.skin_element_name     = NULL;
1193   br.browser.max_displayed_entries = MAX_DISP_ENTRIES;
1194   br.browser.num_entries           = kbedit->num_entries;
1195   br.browser.entries               = (const char* const*)kbedit->entries;
1196   br.callback                      = kbedit_sel;
1197   br.dbl_click_callback            = NULL;
1198   br.parent_wlist                  = kbedit->widget_list;
1199   br.userdata                      = NULL;
1200   kbedit->browser = xitk_noskin_browser_create (kbedit->widget_list, &br,
1201     (XITK_WIDGET_LIST_GC(kbedit->widget_list)), x + 5, y + 5, WINDOW_WIDTH - (30 + 10 + 16), 20, 16, br_fontname);
1202   xitk_add_widget (kbedit->widget_list, kbedit->browser);
1203   xitk_enable_and_show_widget(kbedit->browser);
1204 
1205   xitk_browser_set_alignment(kbedit->browser, ALIGN_LEFT);
1206   xitk_browser_update_list(kbedit->browser,
1207 			   (const char* const*) kbedit->entries,
1208 			   (const char* const*) kbedit->shortcuts, kbedit->num_entries, xitk_browser_get_current_start(kbedit->browser));
1209 
1210   y = y1 - 30 + 4;
1211 
1212   XITK_WIDGET_INIT(&lb, gui->imlib_data);
1213 
1214   lb.button_type       = RADIO_BUTTON;
1215   lb.label             = _("Alias");
1216   lb.align             = ALIGN_CENTER;
1217   lb.callback          = NULL;
1218   lb.state_callback    = kbedit_alias;
1219   lb.userdata          = NULL;
1220   lb.skin_element_name = NULL;
1221   kbedit->alias = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1222     "Black", "Black", "White", hboldfontname);
1223   xitk_add_widget (kbedit->widget_list, kbedit->alias);
1224   xitk_enable_and_show_widget(kbedit->alias);
1225 
1226   x += btnw + 4;
1227 
1228   lb.button_type       = RADIO_BUTTON;
1229   lb.label             = _("Edit");
1230   lb.align             = ALIGN_CENTER;
1231   lb.callback          = NULL;
1232   lb.state_callback    = kbedit_edit;
1233   lb.userdata          = NULL;
1234   lb.skin_element_name = NULL;
1235   kbedit->edit = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1236     "Black", "Black", "White", hboldfontname);
1237   xitk_add_widget (kbedit->widget_list, kbedit->edit);
1238   xitk_enable_and_show_widget(kbedit->edit);
1239 
1240   x += btnw + 4;
1241 
1242   lb.button_type       = CLICK_BUTTON;
1243   lb.label             = _("Delete");
1244   lb.align             = ALIGN_CENTER;
1245   lb.callback          = kbedit_delete;
1246   lb.state_callback    = NULL;
1247   lb.userdata          = NULL;
1248   lb.skin_element_name = NULL;
1249   kbedit->delete = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1250     "Black", "Black", "White", hboldfontname);
1251   xitk_add_widget (kbedit->widget_list, kbedit->delete);
1252   xitk_enable_and_show_widget(kbedit->delete);
1253 
1254   x += btnw + 4;
1255 
1256   lb.button_type       = CLICK_BUTTON;
1257   lb.label             = _("Save");
1258   lb.align             = ALIGN_CENTER;
1259   lb.callback          = kbedit_save;
1260   lb.state_callback    = NULL;
1261   lb.userdata          = NULL;
1262   lb.skin_element_name = NULL;
1263   kbedit->save = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1264     "Black", "Black", "White", hboldfontname);
1265   xitk_add_widget (kbedit->widget_list, kbedit->save);
1266   xitk_enable_and_show_widget(kbedit->save);
1267 
1268   x += btnw + 4;
1269 
1270   lb.button_type       = CLICK_BUTTON;
1271   lb.label             = _("Reset");
1272   lb.align             = ALIGN_CENTER;
1273   lb.callback          = kbedit_reset;
1274   lb.state_callback    = NULL;
1275   lb.userdata          = NULL;
1276   lb.skin_element_name = NULL;
1277   w =  xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1278     "Black", "Black", "White", hboldfontname);
1279   xitk_add_widget (kbedit->widget_list, w);
1280   xitk_enable_and_show_widget(w);
1281 
1282   x += btnw + 4;
1283 
1284   lb.button_type       = CLICK_BUTTON;
1285   lb.label             = _("Done");
1286   lb.align             = ALIGN_CENTER;
1287   lb.callback          = kbedit_exit;
1288   lb.state_callback    = NULL;
1289   lb.userdata          = NULL;
1290   lb.skin_element_name = NULL;
1291   kbedit->done = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, btnw, 23,
1292     "Black", "Black", "White", hboldfontname);
1293   xitk_add_widget (kbedit->widget_list, kbedit->done);
1294   xitk_enable_and_show_widget(kbedit->done);
1295 
1296   x = 15;
1297 
1298   XITK_WIDGET_INIT(&l, gui->imlib_data);
1299 
1300   fs = xitk_font_load_font(gui->display, hboldfontname);
1301   xitk_font_set_font(fs, (XITK_WIDGET_LIST_GC(kbedit->widget_list)));
1302   fontheight = xitk_font_get_string_height(fs, " ");
1303   xitk_font_unload_font(fs);
1304 
1305   y = y1 + (45 / 2);                /* Checkbox                     */
1306   y1 = y - ((fontheight - 10) / 2); /* Text, v-centered to ckeckbox */
1307 
1308   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1309   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1310   l.skin_element_name = NULL;
1311   l.label             = "Binding Action";
1312   l.callback          = NULL;
1313   kbedit->comment = xitk_noskin_label_create (kbedit->widget_list, &l, x + 10, y1,
1314     WINDOW_WIDTH - 50 - 2, fontheight, hboldfontname);
1315   xitk_add_widget (kbedit->widget_list, kbedit->comment);
1316   xitk_enable_and_show_widget(kbedit->comment);
1317 
1318   y += 45 + 3;
1319   y1 += 45 + 3;
1320 
1321   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1322   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1323   l.skin_element_name = NULL;
1324   l.label             = "THE Key";
1325   l.callback          = NULL;
1326   kbedit->key = xitk_noskin_label_create (kbedit->widget_list, &l, x + 10, y1,
1327     100, fontheight, hboldfontname);
1328   xitk_add_widget (kbedit->widget_list, kbedit->key);
1329   xitk_enable_and_show_widget(kbedit->key);
1330 
1331   XITK_WIDGET_INIT(&cb, gui->imlib_data);
1332 
1333   x += 130 + 10;
1334 
1335   cb.callback          = NULL;
1336   cb.userdata          = NULL;
1337   cb.skin_element_name = NULL;
1338   kbedit->ctrl = xitk_noskin_checkbox_create (kbedit->widget_list, &cb, x, y, 10, 10);
1339   xitk_add_widget (kbedit->widget_list, kbedit->ctrl);
1340   xitk_show_widget(kbedit->ctrl);
1341   xitk_disable_widget(kbedit->ctrl);
1342 
1343 
1344   x += 15;
1345 
1346   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1347   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1348   l.skin_element_name = NULL;
1349   l.label             = _("ctrl");
1350   l.callback          = NULL;
1351   w =  xitk_noskin_label_create (kbedit->widget_list, &l, x, y1, 40, fontheight, hboldfontname);
1352   xitk_add_widget (kbedit->widget_list, w);
1353   xitk_enable_and_show_widget(w);
1354 
1355   x += 55;
1356 
1357   cb.callback          = NULL;
1358   cb.userdata          = NULL;
1359   cb.skin_element_name = NULL;
1360   kbedit->meta = xitk_noskin_checkbox_create (kbedit->widget_list, &cb, x, y, 10, 10);
1361   xitk_add_widget (kbedit->widget_list, kbedit->meta);
1362   xitk_show_widget(kbedit->meta);
1363   xitk_disable_widget(kbedit->meta);
1364 
1365 
1366   x += 15;
1367 
1368   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1369   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1370   l.skin_element_name = NULL;
1371   l.label             = _("meta");
1372   l.callback          = NULL;
1373   w =  xitk_noskin_label_create (kbedit->widget_list, &l, x, y1, 40, fontheight, hboldfontname);
1374   xitk_add_widget (kbedit->widget_list, w);
1375   xitk_enable_and_show_widget(w);
1376 
1377   x += 55;
1378 
1379   cb.callback          = NULL;
1380   cb.userdata          = NULL;
1381   cb.skin_element_name = NULL;
1382   kbedit->mod3 = xitk_noskin_checkbox_create (kbedit->widget_list, &cb, x, y, 10, 10);
1383   xitk_add_widget (kbedit->widget_list, kbedit->mod3);
1384   xitk_show_widget(kbedit->mod3);
1385   xitk_disable_widget(kbedit->mod3);
1386 
1387 
1388   x += 15;
1389 
1390   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1391   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1392   l.skin_element_name = NULL;
1393   l.label             = _("mod3");
1394   l.callback          = NULL;
1395   w =  xitk_noskin_label_create (kbedit->widget_list, &l, x, y1, 40, fontheight, hboldfontname);
1396   xitk_add_widget (kbedit->widget_list, w);
1397   xitk_enable_and_show_widget(w);
1398 
1399   x += 55;
1400 
1401   cb.callback          = NULL;
1402   cb.userdata          = NULL;
1403   cb.skin_element_name = NULL;
1404   kbedit->mod4 = xitk_noskin_checkbox_create (kbedit->widget_list, &cb, x, y, 10, 10);
1405   xitk_add_widget (kbedit->widget_list, kbedit->mod4);
1406   xitk_show_widget(kbedit->mod4);
1407   xitk_disable_widget(kbedit->mod4);
1408 
1409 
1410   x += 15;
1411 
1412   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1413   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1414   l.skin_element_name = NULL;
1415   l.label             = _("mod4");
1416   l.callback          = NULL;
1417   w =  xitk_noskin_label_create (kbedit->widget_list, &l, x, y1, 40, fontheight, hboldfontname);
1418   xitk_add_widget (kbedit->widget_list, w);
1419   xitk_enable_and_show_widget(w);
1420 
1421   x += 55;
1422 
1423   cb.callback          = NULL;
1424   cb.userdata          = NULL;
1425   cb.skin_element_name = NULL;
1426   kbedit->mod5 = xitk_noskin_checkbox_create (kbedit->widget_list, &cb, x, y, 10, 10);
1427   xitk_add_widget (kbedit->widget_list, kbedit->mod5);
1428   xitk_show_widget(kbedit->mod5);
1429   xitk_disable_widget(kbedit->mod5);
1430 
1431 
1432   x += 15;
1433 
1434   l.window            = (XITK_WIDGET_LIST_WINDOW(kbedit->widget_list));
1435   l.gc                = (XITK_WIDGET_LIST_GC(kbedit->widget_list));
1436   l.skin_element_name = NULL;
1437   l.label             = _("mod5");
1438   l.callback          = NULL;
1439   w =  xitk_noskin_label_create (kbedit->widget_list, &l, x, y1, 40, fontheight, hboldfontname);
1440   xitk_add_widget (kbedit->widget_list, w);
1441   xitk_enable_and_show_widget(w);
1442 
1443   x = 15;
1444   y = WINDOW_HEIGHT - (23 + 15);
1445 
1446   lb.button_type       = CLICK_BUTTON;
1447   lb.label             = _("Grab");
1448   lb.align             = ALIGN_CENTER;
1449   lb.callback          = kbedit_grab;
1450   lb.state_callback    = NULL;
1451   lb.userdata          = NULL;
1452   lb.skin_element_name = NULL;
1453   kbedit->grab = xitk_noskin_labelbutton_create (kbedit->widget_list, &lb, x, y, WINDOW_WIDTH - 30, 23,
1454     "Black", "Black", "White", hboldfontname);
1455   xitk_add_widget (kbedit->widget_list, kbedit->grab);
1456   xitk_enable_and_show_widget(kbedit->grab);
1457 
1458   kbedit_unset();
1459 
1460   kbedit->kreg = xitk_register_event_handler("kbedit",
1461 					     (xitk_window_get_window(kbedit->xwin)),
1462 					     kbedit_handle_event,
1463 					     NULL,
1464 					     NULL,
1465 					     kbedit->widget_list,
1466 					     NULL);
1467 
1468 
1469   gui->ssaver_enabled = 0;
1470   kbedit->visible      = 1;
1471   kbedit->running      = 1;
1472   kbedit_raise_window();
1473 
1474   try_to_set_input_focus(xitk_window_get_window(kbedit->xwin));
1475 }
1476 
1477