1 /*
2 ** 1999-03-16 - Configure controls. Initially, this will only have global keyboard shortcuts
3 ** to deal with, but it may get more in the future. This module relies heavily
4 ** on the services provided by the 'controls' module, of course.
5 */
6
7 #include "gentoo.h"
8
9 #include "cmdseq_dialog.h"
10
11 #include "cmdseq.h"
12 #include "controls.h"
13 #include "dialog.h"
14 #include "guiutil.h"
15 #include "strutil.h"
16
17 #include "configure.h"
18 #include "cfg_module.h"
19 #include "cfg_cmdseq.h" /* For ccs_current(). */
20 #include "cfg_controls.h"
21
22 #define NODE "Controls"
23
24 /* ----------------------------------------------------------------------------------------- */
25
26 #include "graphics/icon_mouse1.xpm"
27 #include "graphics/icon_mouse2.xpm"
28 #include "graphics/icon_mouse3.xpm"
29 #include "graphics/icon_mouse4.xpm"
30 #include "graphics/icon_mouse5.xpm"
31
32 /* ----------------------------------------------------------------------------------------- */
33
34 typedef struct {
35 GtkWidget *vbox; /* Root page container. Very standard. */
36
37 GtkWidget *kframe; /* Keyboard frame. */
38 GtkListStore *kstore; /* Stores keyboard shortcuts. */
39 GtkWidget *kview; /* A tree view for the keyboard shortcuts. */
40 GtkWidget *kdtable; /* Key definition table. */
41 GtkWidget *kdkey; /* Definition key name (entry). */
42 GtkWidget *kdcmd; /* Definition cmdsequence (entry). */
43 GtkWidget *kdcmdpick; /* Definition command pick button. */
44 GtkWidget *kadd; /* Keyboard add button. */
45 GtkWidget *kdel; /* Keyboard delete button. */
46
47 GtkWidget *mframe; /* Dirpane mouse button config frame. */
48 GtkListStore *mstore; /* Stores mouse button configs. */
49 GtkWidget *mview; /* A tree view for mouse button settings. */
50 GtkWidget *mscwin; /* Scrolling window (obsolete). */
51 GtkWidget *mdtable; /* Definition table. */
52 GtkWidget *mdcombo; /* Combobox showing mouse button for mapping. */
53 GtkWidget *mdcmd;
54 GtkWidget *mdcmdpick;
55 GtkWidget *mhbox;
56 GtkWidget *madd, *mdel;
57
58 GdkPixbuf *mpbuf[5]; /* Mouse icon pixbufs. */
59
60 GtkWidget *cmccmd; /* Entry widget for Click-M-Click command. */
61 GtkWidget *cmcdelay; /* HScale widget for cmc delay. */
62
63 GtkWidget *nonumlock; /* Ignore numlock check button. */
64
65 MainInfo *min; /* This is handy sometimes. */
66 CtrlInfo *ctrlinfo; /* The control info we're editing. */
67
68 gboolean modified; /* Indicates that a change has been made. */
69 } P_Controls;
70
71 enum {
72 KEY_COLUMN_KEYNAME = 0,
73 KEY_COLUMN_CMDSEQ,
74 KEY_COLUMN_KEY,
75
76 KEY_COLUMN_COUNT
77 };
78
79 enum {
80 MOUSE_COLUMN_ICON = 0,
81 MOUSE_COLUMN_BUTTON,
82 MOUSE_COLUMN_STATE,
83 MOUSE_COLUMN_CMDSEQ,
84 MOUSE_COLUMN_MOUSE,
85
86 MOUSE_COLUMN_COUNT
87 };
88
89 static P_Controls the_page;
90
91 /* ----------------------------------------------------------------------------------------- */
92
93 /* 1999-03-16 - Reset the key definition widgets to their idle state. */
reset_key_widgets(P_Controls * page)94 static void reset_key_widgets(P_Controls *page)
95 {
96 gtk_entry_set_text(GTK_ENTRY(page->kdkey), "");
97 gtk_entry_set_text(GTK_ENTRY(page->kdcmd), "");
98 gtk_widget_set_sensitive(page->kdtable, FALSE);
99 gtk_widget_set_sensitive(page->kadd, TRUE);
100 gtk_widget_set_sensitive(page->kdel, FALSE);
101 }
102
103 /* 1999-06-13 - Reset mouse editing widgets. */
reset_mouse_widgets(P_Controls * page)104 static void reset_mouse_widgets(P_Controls *page)
105 {
106 gtk_combo_box_set_active(GTK_COMBO_BOX(page->mdcombo), -1);
107 gtk_entry_set_text(GTK_ENTRY(page->mdcmd), "");
108 gtk_widget_set_sensitive(page->mdtable, FALSE);
109 gtk_widget_set_sensitive(page->madd, TRUE);
110 gtk_widget_set_sensitive(page->mdel, FALSE);
111 }
112
113 /* 1999-03-16 - Reset all widgets on page to their most idle state. */
reset_widgets(P_Controls * page)114 static void reset_widgets(P_Controls *page)
115 {
116 const gchar *cmd;
117
118 reset_key_widgets(page);
119 reset_mouse_widgets(page);
120 cmd = ctrl_clickmclick_get_cmdseq(page->ctrlinfo);
121 gtk_entry_set_text(GTK_ENTRY(page->cmccmd), cmd ? cmd : "");
122 gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(page->cmcdelay)), ctrl_clickmclick_get_delay(page->ctrlinfo));
123 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->nonumlock), ctrl_numlock_ignore_get(page->ctrlinfo));
124 }
125
126 /* ----------------------------------------------------------------------------------------- */
127
list_store_append_key(P_Controls * page,const CtrlKey * key,GtkTreeIter * iter)128 static void list_store_append_key(P_Controls *page, const CtrlKey *key, GtkTreeIter *iter)
129 {
130 GtkTreeIter myiter;
131
132 /* If caller didn't provide an iter to use, use our local. */
133 if(iter == NULL)
134 iter = &myiter;
135 gtk_list_store_insert_with_values(page->kstore, iter, -1,
136 KEY_COLUMN_KEYNAME, ctrl_key_get_keyname(key),
137 KEY_COLUMN_CMDSEQ, ctrl_key_get_cmdseq(key),
138 KEY_COLUMN_KEY, key,
139 -1);
140 }
141
142 /* 1999-03-16 - Populate keyboard clist. */
populate_key_list(P_Controls * page)143 static void populate_key_list(P_Controls *page)
144 {
145 const GSList *iter;
146
147 gtk_list_store_clear(page->kstore);
148 for(iter = ctrl_keys_get_list(page->ctrlinfo); iter != NULL; iter = g_slist_next(iter))
149 list_store_append_key(page, iter->data, NULL);
150 }
151
list_store_append_mouse(P_Controls * page,const CtrlMouse * mouse,GtkTreeIter * iter)152 static void list_store_append_mouse(P_Controls *page, const CtrlMouse *mouse, GtkTreeIter *iter)
153 {
154 gchar *bname[] = { N_("Left"), N_("Middle"), N_("Right"), N_("Wheel Up"), N_("Wheel Down") };
155 guint btn;
156 GtkTreeIter myiter;
157
158 /* If caller didn't provide an iter to use, use our local. */
159 if(iter == NULL)
160 iter = &myiter;
161 btn = ctrl_mouse_get_button(mouse) - 1;
162 gtk_list_store_insert_with_values(page->mstore, iter, -1,
163 MOUSE_COLUMN_ICON, page->mpbuf[btn],
164 MOUSE_COLUMN_BUTTON, _(bname[btn]),
165 MOUSE_COLUMN_STATE, gtk_accelerator_name(0U, ctrl_mouse_get_state(mouse)),
166 MOUSE_COLUMN_CMDSEQ, ctrl_mouse_get_cmdseq(mouse),
167 MOUSE_COLUMN_MOUSE, mouse,
168 -1);
169 }
170
171 /* 1999-06-13 - Populate the mouse command mapping list. */
populate_mouse_list(P_Controls * page)172 static void populate_mouse_list(P_Controls *page)
173 {
174 const GSList *iter;
175
176 gtk_list_store_clear(page->mstore);
177 for(iter = ctrl_mouse_get_list(page->ctrlinfo); iter != NULL; iter = g_slist_next(iter))
178 list_store_append_mouse(page, iter->data, NULL);
179 }
180
181 /* ----------------------------------------------------------------------------------------- */
182
183 /* 2009-03-14 - Keyboard list selection changed. Updated widgetry for editing. */
evt_kselection_changed(GtkTreeSelection * ts,gpointer user)184 static void evt_kselection_changed(GtkTreeSelection *ts, gpointer user)
185 {
186 P_Controls *page = user;
187 GtkTreeModel *model;
188 GtkTreeIter iter;
189 CtrlKey *key = NULL;
190
191 if(gtk_tree_selection_get_selected(ts, &model, &iter))
192 gtk_tree_model_get(model, &iter, KEY_COLUMN_KEY, &key, -1);
193 gtk_entry_set_text(GTK_ENTRY(page->kdkey), key != NULL ? ctrl_key_get_keyname(key) : "");
194 gtk_entry_set_text(GTK_ENTRY(page->kdcmd), key != NULL ? ctrl_key_get_cmdseq(key) : "");
195 gtk_widget_set_sensitive(page->kdtable, key != NULL);
196 gtk_widget_set_sensitive(page->kdel, key != NULL);
197 }
198
199 /* 1999-03-16 - User pressed something in the key definition entry. Convert to name and set it.
200 ** 2009-03-14 - Adapted for new GTK+ 2.0 list selection management. 10 years is a good interval. :)
201 */
evt_kkey_press(GtkWidget * wid,GdkEventKey * evt,gpointer user)202 static gint evt_kkey_press(GtkWidget *wid, GdkEventKey *evt, gpointer user)
203 {
204 P_Controls *page = user;
205 GtkTreeModel *model;
206 GtkTreeIter iter;
207 CtrlKey *key = NULL;
208
209 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->kview)), &model, &iter))
210 {
211 gchar *keyname = gtk_accelerator_name(evt->keyval, evt->state);
212
213 gtk_tree_model_get(model, &iter, 2, &key, -1);
214 ctrl_key_set_keyname(page->ctrlinfo, key, keyname);
215 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, keyname, -1);
216 gtk_entry_set_text(GTK_ENTRY(page->kdkey), keyname);
217 g_signal_stop_emission_by_name(G_OBJECT(wid), "key_press_event");
218 page->modified = TRUE;
219 }
220 return TRUE;
221 }
222
223 /* 1999-03-16 - User edited the command sequence, so store the new one. */
evt_kcmd_changed(GtkWidget * wid,gpointer user)224 static gint evt_kcmd_changed(GtkWidget *wid, gpointer user)
225 {
226 P_Controls *page = user;
227 GtkTreeModel *model;
228 GtkTreeIter iter;
229 CtrlKey *key = NULL;
230
231 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->kview)), &model, &iter))
232 {
233 const gchar *cmdseq = gtk_entry_get_text(GTK_ENTRY(wid));
234
235 gtk_tree_model_get(model, &iter, 2, &key, -1);
236 if(!ctrl_key_has_cmdseq(page->ctrlinfo, key, cmdseq))
237 {
238 ctrl_key_set_cmdseq(page->ctrlinfo, key, cmdseq);
239 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, cmdseq, -1);
240 page->modified = TRUE;
241 }
242 }
243 return TRUE;
244 }
245
246 /* ----------------------------------------------------------------------------------------- */
247
248 /* 1999-03-16 - User clicked the "pick" button for key command sequence.
249 ** 1999-03-29 - Rewritten for new, simpler, csq_dialog() semantics.
250 */
evt_kcmdpick_clicked(GtkWidget * wid,gpointer user)251 static gint evt_kcmdpick_clicked(GtkWidget *wid, gpointer user)
252 {
253 P_Controls *page = user;
254 const gchar *cmd;
255
256 if((cmd = csq_dialog_sync_new_wait(page->min, ccs_get_current())) != NULL)
257 gtk_entry_set_text(GTK_ENTRY(page->kdcmd), cmd);
258 return TRUE;
259 }
260
261 /* ----------------------------------------------------------------------------------------- */
262
263 /* 1999-03-16 - User just hit the "Add" key button so, er, add a key. */
evt_kadd_clicked(GtkWidget * wid,gpointer user)264 static gint evt_kadd_clicked(GtkWidget *wid, gpointer user)
265 {
266 P_Controls *page = user;
267 CtrlKey *key;
268 GtkTreeIter iter;
269 GtkTreePath *path;
270
271 key = ctrl_key_add_unique(page->ctrlinfo);
272 ctrl_key_set_cmdseq(page->ctrlinfo, key, "");
273 gtk_list_store_insert_with_values(page->kstore, &iter, -1,
274 0, ctrl_key_get_keyname(key),
275 1, ctrl_key_get_cmdseq(key),
276 2, key,
277 -1);
278 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->kview)), &iter);
279 path = gtk_tree_model_get_path(GTK_TREE_MODEL(page->kstore), &iter);
280 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->kview), path, NULL, TRUE, 0.5f, 0.0f);
281 gtk_tree_path_free(path);
282 gtk_widget_grab_focus(page->kdkey);
283 page->modified = TRUE;
284
285 return TRUE;
286 }
287
288 /* 1999-03-16 - User hit the "Delete" button for keys. */
evt_kdel_clicked(GtkWidget * wid,gpointer user)289 static gint evt_kdel_clicked(GtkWidget *wid, gpointer user)
290 {
291 P_Controls *page = user;
292 GtkTreeModel *model;
293 GtkTreeIter iter;
294 CtrlKey *key = NULL;
295
296 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->kview)), &model, &iter))
297 {
298 gtk_tree_model_get(model, &iter, 2, &key, -1);
299 ctrl_key_remove(page->ctrlinfo, key);
300 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
301 page->modified = TRUE;
302 }
303 return TRUE;
304 }
305
306 /* ----------------------------------------------------------------------------------------- */
307
308 /* 2009-03-14 - The selection in the mouse binding list has changed. Deal with it. */
evt_mselection_changed(GtkTreeSelection * ts,gpointer user)309 static void evt_mselection_changed(GtkTreeSelection *ts, gpointer user)
310 {
311 P_Controls *page = user;
312 GtkTreeModel *model;
313 GtkTreeIter iter;
314 CtrlMouse *mouse = NULL;
315
316 if(gtk_tree_selection_get_selected(ts, &model, &iter))
317 gtk_tree_model_get(model, &iter, MOUSE_COLUMN_MOUSE, &mouse, -1);
318 gtk_entry_set_text(GTK_ENTRY(page->mdcmd), mouse != NULL ? ctrl_mouse_get_cmdseq(mouse) : "");
319 gtk_combo_box_set_active(GTK_COMBO_BOX(page->mdcombo), ctrl_mouse_get_button(mouse) - 1);
320 gtk_widget_set_sensitive(page->mdtable, mouse != NULL);
321 gtk_widget_set_sensitive(page->mdel, mouse != NULL);
322 }
323
evt_mbutton_changed(GtkWidget * wid,gpointer user)324 static void evt_mbutton_changed(GtkWidget *wid, gpointer user)
325 {
326 P_Controls *page = user;
327 GtkTreeSelection *ts;
328 GtkTreeIter ti, biter;
329 CtrlMouse *mouse;
330 guint btn;
331
332 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview));
333 if(ts == NULL || !gtk_tree_selection_get_selected(ts, NULL, &ti))
334 return;
335 gtk_tree_model_get(GTK_TREE_MODEL(page->mstore), &ti, MOUSE_COLUMN_MOUSE, &mouse, -1);
336 btn = gtk_combo_box_get_active(GTK_COMBO_BOX(page->mdcombo));
337 ctrl_mouse_set_button(mouse, btn + 1);
338
339 /* Almost-too-clever: grab the translated mouse button label from the GtkComboBox's model. */
340 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(page->mdcombo), &biter))
341 {
342 gchar *button;
343
344 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(page->mdcombo)), &biter, 1, &button, -1);
345
346 gtk_list_store_set(GTK_LIST_STORE(page->mstore), &ti,
347 MOUSE_COLUMN_ICON, page->mpbuf[btn],
348 MOUSE_COLUMN_BUTTON, button,
349 -1);
350 g_free(button);
351 }
352 }
353
354 /* 1999-06-13 - User just hit the "Edit Modifiers..." button. Bring up a little dialog. */
evt_mstate_clicked(GtkWidget * wid,gpointer user)355 static void evt_mstate_clicked(GtkWidget *wid, gpointer user)
356 {
357 P_Controls *page = user;
358 GtkTreeSelection *ts;
359 GtkTreeIter ti;
360 CtrlMouse *mouse;
361 Dialog *dlg;
362 guint i, x, y,
363 mask[] = { GDK_SHIFT_MASK, GDK_CONTROL_MASK, GDK_MOD1_MASK, GDK_MOD2_MASK,
364 GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK };
365 GtkWidget *grid, *label, *check[sizeof mask / sizeof mask[0]];
366
367 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview));
368 if(ts == NULL || !gtk_tree_selection_get_selected(ts, NULL, &ti))
369 return;
370 gtk_tree_model_get(GTK_TREE_MODEL(page->mstore), &ti, MOUSE_COLUMN_MOUSE, &mouse, -1);
371
372 grid = gtk_grid_new();
373 label = gtk_label_new(_("The following modifier key(s) must\n"
374 "be held down when the mouse button\n"
375 "is clicked to trigger the command"));
376 gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 2, 1);
377 for(i = 0, x = 0, y = 1; i < sizeof mask / sizeof mask[0]; i++, y++)
378 {
379 check[i] = gtk_check_button_new_with_label(gtk_accelerator_name(0, mask[i]));
380 if(ctrl_mouse_get_state(mouse) & mask[i])
381 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check[i]), TRUE);
382 gtk_grid_attach(GTK_GRID(grid), check[i], x, y, 1, 1);
383 if(i == (sizeof mask / sizeof *mask) / 2)
384 x++, y = 0;
385 }
386 dlg = dlg_dialog_sync_new(grid, _("Edit Modifiers"), NULL);
387 if(dlg_dialog_sync_wait(dlg) == DLG_POSITIVE)
388 {
389 guint ns = 0U;
390
391 for(i = 0; i < sizeof mask / sizeof mask[0]; i++)
392 {
393 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check[i])))
394 ns |= mask[i];
395 }
396 ctrl_mouse_set_state(mouse, ns);
397 gtk_list_store_set(GTK_LIST_STORE(page->mstore), &ti, MOUSE_COLUMN_STATE, gtk_accelerator_name(0, ns), -1);
398 page->modified = TRUE;
399 }
400 dlg_dialog_sync_destroy(dlg);
401 }
402
403 /* 1999-06-13 - User is editing the command name. Update mapping. */
evt_mcmd_changed(GtkWidget * wid,gpointer user)404 static void evt_mcmd_changed(GtkWidget *wid, gpointer user)
405 {
406 P_Controls *page = user;
407 GtkTreeSelection *ts;
408 GtkTreeIter ti;
409 CtrlMouse *mouse;
410 const gchar *cmdseq;
411
412 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview));
413 if(ts == NULL || !gtk_tree_selection_get_selected(ts, NULL, &ti))
414 return;
415 gtk_tree_model_get(GTK_TREE_MODEL(page->mstore), &ti, MOUSE_COLUMN_MOUSE, &mouse, -1);
416 if((cmdseq = gtk_entry_get_text(GTK_ENTRY(page->mdcmd))) != NULL)
417 {
418 ctrl_mouse_set_cmdseq(mouse, cmdseq);
419 gtk_list_store_set(page->mstore, &ti, MOUSE_COLUMN_CMDSEQ, cmdseq, -1);
420 page->modified = TRUE;
421 }
422 }
423
424 /* 1999-06-13 - User clicked details button for mouse mapping command. Pop up dialog. */
evt_mcmdpick_clicked(GtkWidget * wid,gpointer user)425 static void evt_mcmdpick_clicked(GtkWidget *wid, gpointer user)
426 {
427 P_Controls *page = user;
428 const gchar *cmd;
429
430 if((cmd = csq_dialog_sync_new_wait(page->min, ccs_get_current())) != NULL)
431 gtk_entry_set_text(GTK_ENTRY(page->mdcmd), cmd);
432 }
433
434 /* 1999-06-20 - User clicked the "Add" button for mouse bindings, so add one. */
evt_madd_clicked(GtkWidget * wid,gpointer user)435 static void evt_madd_clicked(GtkWidget *wid, gpointer user)
436 {
437 P_Controls *page = user;
438 CtrlMouse *mouse;
439 GtkTreeIter iter;
440 GtkTreePath *path;
441
442 mouse = ctrl_mouse_add(page->ctrlinfo, 1U, 0U, "");
443 if(mouse != NULL)
444 {
445 list_store_append_mouse(page, mouse, &iter);
446 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview)), &iter);
447 path = gtk_tree_model_get_path(GTK_TREE_MODEL(page->mstore), &iter);
448 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->mview), path, NULL, TRUE, 0.5f, 0.0f);
449 gtk_tree_path_free(path);
450 page->modified = TRUE;
451 }
452 }
453
454 /* 1999-06-21 - The Delete-button has been clicked, remove current mouse command mapping. */
evt_mdel_clicked(GtkWidget * wid,gpointer user)455 static void evt_mdel_clicked(GtkWidget *wid, gpointer user)
456 {
457 P_Controls *page = user;
458 GtkTreeModel *model;
459 GtkTreeIter iter;
460 CtrlMouse *mouse;
461
462 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview)), &model, &iter))
463 {
464 gtk_tree_model_get(model, &iter, MOUSE_COLUMN_MOUSE, &mouse, -1);
465 ctrl_mouse_remove(page->ctrlinfo, mouse);
466 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
467 page->modified = TRUE;
468 }
469 }
470
471 /* 2003-10-09 - User set a new Click-M-Click command. */
evt_clickmclick_changed(GtkWidget * wid,gpointer user)472 static void evt_clickmclick_changed(GtkWidget *wid, gpointer user)
473 {
474 P_Controls *page = user;
475
476 if(page)
477 {
478 const gchar *text = gtk_entry_get_text(GTK_ENTRY(wid));
479
480 ctrl_clickmclick_set_cmdseq(page->ctrlinfo, text);
481 gtk_widget_set_sensitive(page->cmcdelay, *text);
482 page->modified = TRUE;
483 }
484 }
485
486 /* 2003-10-09 - User wants help in picking a command for Click-M-Click. */
evt_clickmclick_pick_clicked(GtkWidget * wid,gpointer user)487 static void evt_clickmclick_pick_clicked(GtkWidget *wid, gpointer user)
488 {
489 P_Controls *page = user;
490
491 if(page)
492 {
493 const gchar *cmd = csq_dialog_sync_new_wait(page->min, ccs_get_current());
494 if(cmd)
495 gtk_entry_set_text(GTK_ENTRY(page->cmccmd), cmd);
496 }
497 }
498
499 /* 2003-10-09 - Maximum allowed delay for Click-M-Click recognition changed. */
evt_clickmclick_delay_changed(GtkAdjustment * adj,gpointer user)500 static void evt_clickmclick_delay_changed(GtkAdjustment *adj, gpointer user)
501 {
502 P_Controls *page = user;
503
504 if(page)
505 ctrl_clickmclick_set_delay(page->ctrlinfo, gtk_adjustment_get_value(adj));
506 }
507
508 /* ----------------------------------------------------------------------------------------- */
509
510 /* 2000-02-18 - User hit the "Ignore Num Lock?" toggle. Update editing state. */
evt_nonumlock_clicked(GtkWidget * wid,gpointer user)511 static void evt_nonumlock_clicked(GtkWidget *wid, gpointer user)
512 {
513 P_Controls *page = user;
514
515 if(page != NULL)
516 {
517 ctrl_numlock_ignore_set(page->ctrlinfo, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wid)));
518 page->modified = TRUE;
519 }
520 }
521
522 /* ----------------------------------------------------------------------------------------- */
523
build_mouse_menu(P_Controls * page)524 static void build_mouse_menu(P_Controls *page)
525 {
526 gchar **gfx[] = { icon_mouse1_xpm, icon_mouse2_xpm, icon_mouse3_xpm, icon_mouse4_xpm, icon_mouse5_xpm },
527 *label[] = { N_("Left"), N_("Middle"), N_("Right"), N_("Wheel Up"), N_("Wheel Down") };
528 guint i;
529 GtkListStore *mmodel;
530 GtkCellRenderer *cr;
531
532 for(i = 0; i < sizeof gfx / sizeof *gfx; i++)
533 page->mpbuf[i] = gdk_pixbuf_new_from_xpm_data((const gchar **) gfx[i]);
534
535 /* Now build a full TreeModel for the GtkOptionMenu replacement. Pfew!
536 ** NOTE: Unlike key and mouse true models, we don't store the button index
537 ** in the model; instead we just use get/set active() on the GtkComboBox.
538 */
539 mmodel = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
540 for(i = 0; i < sizeof gfx / sizeof *gfx; ++i)
541 {
542 GtkTreeIter iter;
543 gtk_list_store_insert_with_values(mmodel, &iter, -1, 0, page->mpbuf[i], 1, _(label[i]), -1);
544 }
545 page->mdcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(mmodel));
546 cr = gtk_cell_renderer_pixbuf_new();
547 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(page->mdcombo), cr, FALSE);
548 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(page->mdcombo), cr,
549 "pixbuf", 0,
550 NULL);
551
552 cr = gtk_cell_renderer_text_new();
553 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(page->mdcombo), cr, TRUE);
554 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(page->mdcombo), cr,
555 "text", 1,
556 NULL);
557
558 g_signal_connect(G_OBJECT(page->mdcombo), "changed", G_CALLBACK(evt_mbutton_changed), page);
559 gtk_grid_attach(GTK_GRID(page->mdtable), page->mdcombo, 1, 0, 1, 1);
560 }
561
cct_init(MainInfo * min,gchar ** name)562 static GtkWidget * cct_init(MainInfo *min, gchar **name)
563 {
564 P_Controls *page = &the_page;
565 GtkWidget *vbox, *frame, *label, *wid, *hbox, *scwin;
566 GtkAdjustment *adj;
567 GtkCellRenderer *cr;
568 GtkTreeViewColumn *vc;
569 GtkTreeSelection *ts;
570
571 if(name == NULL)
572 return NULL;
573 *name = _("Controls");
574
575 page->min = min;
576 page->modified = FALSE;
577
578 page->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
579
580 page->kframe = gtk_frame_new(_("Global Keyboard Shortcuts"));
581 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
582 page->kstore = gtk_list_store_new(KEY_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
583 page->kview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(page->kstore));
584 cr = gtk_cell_renderer_text_new();
585 vc = gtk_tree_view_column_new_with_attributes("(Key)", cr, "text", 0, NULL);
586 gtk_tree_view_append_column(GTK_TREE_VIEW(page->kview), vc);
587 vc = gtk_tree_view_column_new_with_attributes("(Command)", cr, "text", 1, NULL);
588 gtk_tree_view_append_column(GTK_TREE_VIEW(page->kview), vc);
589 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(page->kview), FALSE);
590 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->kview));
591 gtk_tree_selection_set_mode(ts, GTK_SELECTION_SINGLE);
592 g_signal_connect(G_OBJECT(ts), "changed", G_CALLBACK(evt_kselection_changed), page);
593 scwin = gtk_scrolled_window_new(NULL, NULL);
594 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
595 gtk_container_add(GTK_CONTAINER(scwin), page->kview);
596 gtk_box_pack_start(GTK_BOX(vbox), scwin, TRUE, TRUE, 0);
597
598 page->kdtable = gtk_grid_new();
599 label = gtk_label_new(_("Key"));
600 gtk_grid_attach(GTK_GRID(page->kdtable), label, 0, 0, 1, 1);
601 page->kdkey = gtk_entry_new();
602 g_signal_connect(G_OBJECT(page->kdkey), "key_press_event", G_CALLBACK(evt_kkey_press), page);
603 gtk_editable_set_editable(GTK_EDITABLE(page->kdkey), FALSE);
604 gtk_grid_attach(GTK_GRID(page->kdtable), page->kdkey, 1, 0, 3, 1);
605 label = gtk_label_new(_("Command"));
606 gtk_grid_attach(GTK_GRID(page->kdtable), label, 0, 1, 1, 1);
607 page->kdcmd = gtk_entry_new();
608 gtk_widget_set_hexpand(page->kdcmd, TRUE);
609 gtk_widget_set_halign(page->kdcmd, GTK_ALIGN_FILL);
610 g_signal_connect(G_OBJECT(page->kdcmd), "changed", G_CALLBACK(evt_kcmd_changed), page);
611 gtk_grid_attach(GTK_GRID(page->kdtable), page->kdcmd, 1, 1, 1, 1);
612 page->kdcmdpick = gui_details_button_new();
613 g_signal_connect(G_OBJECT(page->kdcmdpick), "clicked", G_CALLBACK(evt_kcmdpick_clicked), page);
614 gtk_grid_attach(GTK_GRID(page->kdtable), page->kdcmdpick, 2, 1, 1, 1);
615 gtk_box_pack_start(GTK_BOX(vbox), page->kdtable, FALSE, FALSE, 0);
616 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
617 page->kadd = gtk_button_new_with_label(_("Add"));
618 g_signal_connect(G_OBJECT(page->kadd), "clicked", G_CALLBACK(evt_kadd_clicked), page);
619 gtk_box_pack_start(GTK_BOX(hbox), page->kadd, TRUE, TRUE, 5);
620 page->kdel = gtk_button_new_with_label(_("Delete"));
621 g_signal_connect(G_OBJECT(page->kdel), "clicked", G_CALLBACK(evt_kdel_clicked), page);
622 gtk_box_pack_start(GTK_BOX(hbox), page->kdel, TRUE, TRUE, 5);
623 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
624 gtk_container_add(GTK_CONTAINER(page->kframe), vbox);
625 gtk_box_pack_start(GTK_BOX(page->vbox), page->kframe, TRUE, TRUE, 0);
626
627 page->mframe = gtk_frame_new(_("Dirpane Mouse Buttons"));
628 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
629
630 page->mstore = gtk_list_store_new(MOUSE_COLUMN_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
631 page->mview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(page->mstore));
632 cr = gtk_cell_renderer_pixbuf_new();
633 vc = gtk_tree_view_column_new_with_attributes("(BIcon)", cr, "pixbuf", 0, NULL);
634 gtk_tree_view_append_column(GTK_TREE_VIEW(page->mview), vc);
635 cr = gtk_cell_renderer_text_new();
636 vc = gtk_tree_view_column_new_with_attributes("(Button)", cr, "text", 1, NULL);
637 gtk_tree_view_append_column(GTK_TREE_VIEW(page->mview), vc);
638 vc = gtk_tree_view_column_new_with_attributes("(Modifier)", cr, "text", 2, NULL);
639 gtk_tree_view_append_column(GTK_TREE_VIEW(page->mview), vc);
640 vc = gtk_tree_view_column_new_with_attributes("(Command)", cr, "text", 3, NULL);
641 gtk_tree_view_append_column(GTK_TREE_VIEW(page->mview), vc);
642 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(page->mview), FALSE);
643 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->mview));
644 gtk_tree_selection_set_mode(ts, GTK_SELECTION_SINGLE);
645 g_signal_connect(G_OBJECT(ts), "changed", G_CALLBACK(evt_mselection_changed), page);
646 scwin = gtk_scrolled_window_new(NULL, NULL);
647 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
648 gtk_container_add(GTK_CONTAINER(scwin), page->mview);
649 gtk_box_pack_start(GTK_BOX(vbox), scwin, TRUE, TRUE, 0);
650
651 page->mdtable = gtk_grid_new();
652 label = gtk_label_new(_("Button"));
653 gtk_grid_attach(GTK_GRID(page->mdtable), label, 0, 0, 1, 1);
654 build_mouse_menu(page);
655 wid = gtk_button_new_with_label(_("Edit Modifiers..."));
656 g_signal_connect(G_OBJECT(wid), "clicked", G_CALLBACK(evt_mstate_clicked), page);
657 gtk_grid_attach(GTK_GRID(page->mdtable), wid, 2, 0, 2, 1);
658 label = gtk_label_new(_("Command"));
659 gtk_grid_attach(GTK_GRID(page->mdtable), label, 0, 1, 1, 1);
660 page->mdcmd = gtk_entry_new();
661 gtk_widget_set_hexpand(page->mdcmd, TRUE);
662 gtk_widget_set_halign(page->mdcmd, GTK_ALIGN_FILL);
663 g_signal_connect(G_OBJECT(page->mdcmd), "changed", G_CALLBACK(evt_mcmd_changed), page);
664 gtk_grid_attach(GTK_GRID(page->mdtable), page->mdcmd, 1, 1, 2, 1);
665 page->mdcmdpick = gui_details_button_new();
666 g_signal_connect(G_OBJECT(page->mdcmdpick), "clicked", G_CALLBACK(evt_mcmdpick_clicked), page);
667 gtk_grid_attach(GTK_GRID(page->mdtable), page->mdcmdpick, 3, 1, 1, 1);
668 gtk_box_pack_start(GTK_BOX(vbox), page->mdtable, FALSE, FALSE, 0);
669 page->mhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
670 page->madd = gtk_button_new_with_label(_("Add"));
671 g_signal_connect(G_OBJECT(page->madd), "clicked", G_CALLBACK(evt_madd_clicked), page);
672 gtk_box_pack_start(GTK_BOX(page->mhbox), page->madd, TRUE, TRUE, 5);
673 page->mdel = gtk_button_new_with_label(_("Delete"));
674 g_signal_connect(G_OBJECT(page->mdel), "clicked", G_CALLBACK(evt_mdel_clicked), page);
675 gtk_box_pack_start(GTK_BOX(page->mhbox), page->mdel, TRUE, TRUE, 5);
676 gtk_box_pack_start(GTK_BOX(vbox), page->mhbox, FALSE, FALSE, 5);
677 gtk_container_add(GTK_CONTAINER(page->mframe), vbox);
678 gtk_box_pack_start(GTK_BOX(page->vbox), page->mframe, TRUE, TRUE, 0);
679
680 frame = gtk_frame_new(_("Click-M-Click Gesture"));
681 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
682 label = gtk_label_new(_("Command"));
683 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
684 page->cmccmd = gtk_entry_new();
685 g_signal_connect(G_OBJECT(page->cmccmd), "changed", G_CALLBACK(evt_clickmclick_changed), page);
686 gtk_box_pack_start(GTK_BOX(hbox), page->cmccmd, TRUE, TRUE, 0);
687 wid = gui_details_button_new();
688 g_signal_connect(G_OBJECT(wid), "clicked", G_CALLBACK(evt_clickmclick_pick_clicked), page);
689 gtk_box_pack_start(GTK_BOX(hbox), wid, FALSE, FALSE, 0);
690 label = gtk_label_new(_("Time Limit"));
691 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
692 adj = gtk_adjustment_new(0.400f, 0.100f, 1.5f, 0.1f, 0.1f, 0.0f);
693 g_signal_connect(G_OBJECT(adj), "value_changed", G_CALLBACK(evt_clickmclick_delay_changed), page);
694 page->cmcdelay = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(adj));
695 gtk_scale_set_value_pos(GTK_SCALE(page->cmcdelay), GTK_POS_RIGHT);
696 gtk_scale_set_digits(GTK_SCALE(page->cmcdelay), 3);
697 gtk_box_pack_start(GTK_BOX(hbox), page->cmcdelay, TRUE, TRUE, 0);
698 gtk_container_add(GTK_CONTAINER(frame), hbox);
699 gtk_box_pack_start(GTK_BOX(page->vbox), frame, FALSE, FALSE, 0);
700
701 page->nonumlock = gtk_check_button_new_with_label(_("Ignore Num Lock For All Bindings?"));
702 g_signal_connect(G_OBJECT(page->nonumlock), "clicked", G_CALLBACK(evt_nonumlock_clicked), page);
703 gtk_box_pack_start(GTK_BOX(page->vbox), page->nonumlock, FALSE, FALSE, 0);
704
705 gtk_widget_show_all(page->vbox);
706 return page->vbox;
707 }
708
709 /* ----------------------------------------------------------------------------------------- */
710
711 /* 1999-03-16 - Update the controls config page by grabbing current settings. */
cct_update(MainInfo * min)712 static void cct_update(MainInfo *min)
713 {
714 the_page.ctrlinfo = ctrl_copy(min->cfg.ctrlinfo);
715 populate_key_list(&the_page);
716 populate_mouse_list(&the_page);
717 reset_widgets(&the_page);
718 }
719
720 /* ----------------------------------------------------------------------------------------- */
721
722 /* 1999-03-17 - The user just accepted the settings, so make them current. */
cct_accept(MainInfo * min)723 static void cct_accept(MainInfo *min)
724 {
725 P_Controls *page = &the_page;
726
727 if(page->modified)
728 {
729 if(ctrl_mouse_ambiguity_exists(page->ctrlinfo))
730 {
731 dlg_dialog_async_new_simple(_("Note: The mouse button control settings\n"
732 "are ambiguous: the same button+modifier\n"
733 "is used for more than one function. This\n"
734 "might make their behaviour pretty weird..."),
735 _("Warning"), _("_OK"), NULL, NULL);
736 }
737 ctrl_destroy(min->cfg.ctrlinfo);
738 min->cfg.ctrlinfo = page->ctrlinfo;
739 page->ctrlinfo = NULL;
740 cfg_set_flags(CFLG_RESET_KEYBOARD);
741 page->modified = FALSE;
742 }
743 }
744
745 /* ----------------------------------------------------------------------------------------- */
746
keys_save(CtrlInfo * ctrl,FILE * out)747 static void keys_save(CtrlInfo *ctrl, FILE *out)
748 {
749 GSList *keys, *iter;
750
751 xml_put_node_open(out, "Keys");
752 if((keys = ctrl_keys_get_list(ctrl)) != NULL)
753 {
754 for(iter = keys; iter != NULL; iter = g_slist_next(iter))
755 {
756 const gchar *key, *cmd;
757
758 if((key = ctrl_key_get_keyname(iter->data)) && (cmd = ctrl_key_get_cmdseq(iter->data)))
759 {
760 xml_put_node_open(out, "Key");
761 xml_put_text(out, "keyname", key);
762 xml_put_text(out, "cmdseq", cmd);
763 xml_put_node_close(out, "Key");
764 }
765 }
766 g_slist_free(keys);
767 }
768 xml_put_node_close(out, "Keys");
769 }
770
771 /* 1999-06-20 - Save out all mouse command bindings. */
mouse_save(CtrlInfo * ctrl,FILE * out)772 static void mouse_save(CtrlInfo *ctrl, FILE *out)
773 {
774 GSList *mouse, *iter;
775
776 xml_put_node_open(out, "MouseButtons");
777 if((mouse = ctrl_mouse_get_list(ctrl)) != NULL)
778 {
779 for(iter = mouse; iter != NULL; iter = g_slist_next(iter))
780 {
781 xml_put_node_open(out, "MouseButton");
782 xml_put_uinteger(out, "button", ctrl_mouse_get_button(iter->data));
783 xml_put_uinteger(out, "state", ctrl_mouse_get_state(iter->data));
784 xml_put_text(out, "cmdseq", ctrl_mouse_get_cmdseq(iter->data));
785 xml_put_node_close(out, "MouseButton");
786 }
787 g_slist_free(mouse);
788 }
789 xml_put_node_close(out, "MouseButtons");
790 }
791
clickmclick_save(const CtrlInfo * ctrl,FILE * out)792 static void clickmclick_save(const CtrlInfo *ctrl, FILE *out)
793 {
794 xml_put_node_open(out, "ClickMClick");
795 xml_put_text(out, "cmdseq", ctrl_clickmclick_get_cmdseq(ctrl));
796 xml_put_real(out, "delay", ctrl_clickmclick_get_delay(ctrl));
797 xml_put_node_close(out, "ClickMClick");
798 }
799
800 /* 2004-04-25 - Save general bindings. */
general_save(const CtrlInfo * ctrl,FILE * out)801 static void general_save(const CtrlInfo *ctrl, FILE *out)
802 {
803 GSList *list;
804
805 if((list = ctrl_general_get_contexts(ctrl)) != NULL) /* Only emit toplevel if there are bindings. */
806 {
807 const GSList *iter;
808
809 xml_put_node_open(out, "Generals");
810 for(iter = list; iter != NULL; iter = g_slist_next(iter))
811 {
812 xml_put_node_open(out, "General");
813 xml_put_text(out, "context", (const gchar *) iter->data);
814 xml_put_text(out, "cmdseq", ctrl_general_get_cmdseq(ctrl, (const gchar *) iter->data));
815 xml_put_node_close(out, "General");
816 }
817 g_slist_free(list);
818 xml_put_node_close(out, "Generals");
819 }
820 }
821
822 /* 1999-03-17 - Save the current control settings right out in given <file>. */
cct_save(MainInfo * min,FILE * out)823 static gint cct_save(MainInfo *min, FILE *out)
824 {
825 xml_put_node_open(out, "Controls");
826 keys_save(min->cfg.ctrlinfo, out);
827 mouse_save(min->cfg.ctrlinfo, out);
828 clickmclick_save(min->cfg.ctrlinfo, out);
829 general_save(min->cfg.ctrlinfo, out);
830 xml_put_boolean(out, "ignore_numlock", ctrl_numlock_ignore_get(min->cfg.ctrlinfo));
831 xml_put_node_close(out, "Controls");
832
833 return TRUE;
834 }
835
836 /* ----------------------------------------------------------------------------------------- */
837
838 /* 1999-03-17 - Load in and install a single key mapping. */
key_load(const XmlNode * node,gpointer user)839 static void key_load(const XmlNode *node, gpointer user)
840 {
841 const gchar *name, *cmd;
842
843 if(xml_get_text(node, "keyname", &name) && xml_get_text(node, "cmdseq", &cmd))
844 ctrl_key_add(((MainInfo *) user)->cfg.ctrlinfo, name, csq_cmdseq_map_name(cmd, "keyboard shortcut"));
845 }
846
847 /* 1999-03-17 - Load in all key mappings. */
keys_load(MainInfo * min,const XmlNode * node)848 static void keys_load(MainInfo *min, const XmlNode *node)
849 {
850 xml_node_visit_children(node, key_load, min);
851 }
852
853 /* 1999-06-20 - Load and install a single mouse command mapping. */
mousebutton_load(const XmlNode * node,gpointer user)854 static void mousebutton_load(const XmlNode *node, gpointer user)
855 {
856 const gchar *cmd;
857 guint button, state;
858
859 if(xml_get_uinteger(node, "button", &button) && xml_get_uinteger(node, "state", &state) && xml_get_text(node, "cmdseq", &cmd))
860 ctrl_mouse_add(((MainInfo *) user)->cfg.ctrlinfo, button, state, csq_cmdseq_map_name(cmd, "dirpane mouse button"));
861 }
862
863 /* 1999-06-20 - Load in the mouse command bindings. */
mousebuttons_load(MainInfo * min,const XmlNode * node)864 static void mousebuttons_load(MainInfo *min, const XmlNode *node)
865 {
866 xml_node_visit_children(node, mousebutton_load, min);
867 }
868
869 /* 2004-04-26 - Load a general command binding. */
general_load(const XmlNode * node,gpointer user)870 static void general_load(const XmlNode *node, gpointer user)
871 {
872 const gchar *ctx, *cmd;
873
874 if(xml_get_text(node, "context", &ctx) && xml_get_text(node, "cmdseq", &cmd))
875 ctrl_general_set_cmdseq(((MainInfo *) user)->cfg.ctrlinfo, ctx, cmd);
876 }
877
878 /* 2004-04-26 - Load a bunch of general command bindings. */
generals_load(MainInfo * min,const XmlNode * node)879 static void generals_load(MainInfo *min, const XmlNode *node)
880 {
881 xml_node_visit_children(node, general_load, min);
882 }
883
884 /* 1999-03-17 - Load in the control config information. Replaces current. */
cct_load(MainInfo * min,const XmlNode * node)885 static void cct_load(MainInfo *min, const XmlNode *node)
886 {
887 const XmlNode *data;
888
889 if((node = xml_tree_search(node, "Controls")) != NULL)
890 {
891 gboolean tmp;
892
893 if((data = xml_tree_search(node, "Keys")) != NULL)
894 {
895 ctrl_keys_uninstall_all(min->cfg.ctrlinfo);
896 ctrl_key_remove_all(min->cfg.ctrlinfo);
897 keys_load(min, data);
898 }
899 if((data = xml_tree_search(node, "MouseButtons")) != NULL)
900 {
901 ctrl_mouse_remove_all(min->cfg.ctrlinfo);
902 mousebuttons_load(min, data);
903 }
904 if((data = xml_tree_search(node, "ClickMClick")) != NULL)
905 {
906 const gchar *cmd;
907 gfloat delay;
908 if(xml_get_text(data, "cmdseq", &cmd) && xml_get_real(data, "delay", &delay))
909 {
910 ctrl_clickmclick_set_cmdseq(min->cfg.ctrlinfo, cmd);
911 ctrl_clickmclick_set_delay(min->cfg.ctrlinfo, delay);
912 }
913 }
914 if((data = xml_tree_search(node, "Generals")) != NULL)
915 {
916 ctrl_general_clear(min->cfg.ctrlinfo);
917 generals_load(min, data);
918 }
919 if(xml_get_boolean(node, "ignore_numlock", &tmp))
920 ctrl_numlock_ignore_set(min->cfg.ctrlinfo, tmp);
921 }
922 }
923
924 /* ----------------------------------------------------------------------------------------- */
925
cct_describe(MainInfo * min)926 const CfgModule * cct_describe(MainInfo *min)
927 {
928 static const CfgModule desc = { NODE, cct_init, cct_update, cct_accept, cct_save, cct_load, NULL };
929
930 return &desc;
931 }
932