1 /* kbd-interface.c
2  *  functions for implementing the customize keyboard dialog
3  *
4  *  for Denemo, thu GNU graphical music notation editor
5  *  (c) 2000-2005 Matthew Hiller
6  */
7 
8 #include <config.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <string.h>
13 
14 #include <gdk/gdkkeysyms.h>
15 #include <gtk/gtk.h>
16 
17 #include "core/kbd-custom.h"
18 #include "core/prefops.h"
19 #include "ui/mousing.h"
20 #include "ui/palettes.h"
21 #include "core/utils.h"
22 #include "core/view.h"
23 
24 
25 static gint
get_command_position(GtkTreeModel * model,gint command_idx)26 get_command_position(GtkTreeModel* model, gint command_idx){
27   gboolean valid;
28   command_row* row1 = NULL;
29   command_row* row2 = NULL;
30   gint i = 0;
31   GtkTreeIter iter;
32 
33   valid = gtk_tree_model_get_iter_first (model, &iter);
34   keymap_get_command_row(Denemo.map, &row2, command_idx);
35 
36   while (valid){
37     gtk_tree_model_get (model, &iter, COL_ROW, &row1, -1);
38     if(row1 && row1 == row2)
39       return i;
40     i++;
41     valid = gtk_tree_model_iter_next (model, &iter);
42   }
43   return -1;
44 }
45 
46 #if 0
47 static void
48 validate_keymap_name (GtkEntry * entry, GtkDialog * dialog)
49 {
50   const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry));
51   gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, strlen (name) > 0);
52 }
53 #endif
54 
55 static gboolean
capture_add_binding(GtkWidget * widget,GdkEventKey * event,gpointer user_data)56 capture_add_binding (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
57 {
58   GdkModifierType modifiers;
59   guint command_idx;
60   GtkTreeModel *model;
61   GtkTreeSelection *selection;
62   GtkTreeIter iter;
63   GtkTreePath *path;
64   gint *array;
65   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
66   //get the shortcut
67   if (isModifier (event))
68     return TRUE;
69   dnm_clean_event (event);
70   modifiers = dnm_sanitize_key_state (event);
71   gchar *name = dnm_accelerator_name (event->keyval, event->state);
72   if (!strcmp(name, "VoidSymbol"))
73     {
74         warningdialog (_("VoidSymbol not allowed"));
75         return TRUE;
76     }
77   if (cbdata->two_key == 1)
78     {
79       gint command_idx = lookup_command_for_keybinding_name (Denemo.map, name);
80       if (command_idx == -1)
81         {
82           cbdata->first_keyval = event->keyval;
83           cbdata->first_modifiers = modifiers;
84           cbdata->two_key = 2;
85           return TRUE;
86         }
87       else
88         {
89           cbdata->two_key = 0;
90           gchar *msg = g_strdup_printf (_("The command %s has the shortcut: %s\nDelete it first or start again selecting an unused keypress."), lookup_name_from_idx (Denemo.map, command_idx), name);
91           warningdialog (msg);
92           g_free (msg);
93           g_free (name);
94           g_warning ("trying to set a two key starting with a single");
95           return TRUE;
96         }
97     }
98   //get the command_index
99   selection = gtk_tree_view_get_selection (cbdata->command_view);
100   gtk_tree_selection_get_selected (selection, &model, &iter);
101   path = gtk_tree_model_get_path (model, &iter);
102   array = gtk_tree_path_get_indices (path);
103   command_idx = array[0]; //this fails in general, yielding the value in cbdata, instead ...
104   gchar* cname = NULL;
105   gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
106   command_idx = lookup_command_from_name (Denemo.map, cname);
107   if(command_idx != cbdata->command_id)
108     g_warning("correct command idx %d compare %d for action of name %s\n", command_idx, cbdata->command_id, cname);
109   gtk_tree_path_free (path);
110 
111 
112   if (cbdata->two_key == 0 && (GList *) g_hash_table_lookup (Denemo.map->continuations_table, name))
113     {
114       //g_warning("There is a two key binding starting with this");
115       gchar *msg = g_strdup_printf (_("There is at least one two-key shortcut that starts with: %s\nFind them using the Find button\nDelete it/those first or start again selecting an unused keypress."), name);
116       warningdialog (msg);
117       g_free (msg);
118       g_free (name);
119       return TRUE;
120     }
121   g_free (name);
122   //set the new binding
123   if (cbdata->two_key == 2)
124     add_twokeybinding_to_idx (Denemo.map, cbdata->first_keyval, cbdata->first_modifiers, event->keyval, modifiers, command_idx, POS_FIRST);
125   else
126     add_keybinding_to_idx (Denemo.map, event->keyval, modifiers, command_idx, POS_FIRST);
127 
128   command_row* row = NULL;
129   keymap_get_command_row (Denemo.map, &row, command_idx);
130   GtkListStore* bindings_model = GTK_LIST_STORE(gtk_tree_view_get_model(cbdata->binding_view));
131   update_bindings_model(bindings_model, row->bindings);
132 
133   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
134   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
135   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
136   cbdata->two_key = 0;
137   return TRUE;
138 }
139 
140 static gboolean
capture_look_binding(GtkWidget * widget,GdkEventKey * event,gpointer user_data)141 capture_look_binding (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
142 {
143   GdkModifierType modifiers;
144   GtkTreeModel *model;
145   GtkTreeSelection *selection;
146   GtkTreeIter iter;
147   GtkTreePath *path;
148   gint command_idx;
149   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
150   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
151   //get the shortcut
152   if (isModifier (event))
153     return TRUE;
154   dnm_clean_event (event);
155   modifiers = dnm_sanitize_key_state (event);
156 
157   //look for the keybinding
158   command_idx = lookup_command_for_keybinding (Denemo.map, event->keyval, modifiers);
159   //if the binding is associated to a command
160   if (command_idx == -1)
161     {
162       gchar *name = dnm_accelerator_name (event->keyval, event->state);
163       GList *g = (GList *) g_hash_table_lookup (Denemo.map->continuations_table, name);
164 
165       GString *continuations = g_string_new ("");
166       GString *final_list = g_string_new ("");
167       for (; g; g = g->next)
168         {
169           g_string_append_printf (continuations, "%s%s%s", name, ",", (gchar *) g->data);
170           command_idx = lookup_command_for_keybinding_name (Denemo.map, continuations->str);
171           const gchar *this = lookup_name_from_idx (Denemo.map, command_idx);
172           g_string_append_printf (final_list, "%s,%s=%s ", name, (gchar *) g->data, this);
173           g_string_assign (continuations, "");
174         }
175       if (final_list->len)
176         cbdata->twokeylist = final_list;
177     }
178   if (command_idx != -1)
179   {
180       model = gtk_tree_view_get_model (cbdata->command_view);
181       gint pos = get_command_position(model, command_idx);
182       selection = gtk_tree_view_get_selection (cbdata->command_view);
183       gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
184       gtk_tree_selection_select_iter (selection, &iter);
185       path = gtk_tree_model_get_path (model, &iter);
186       gtk_tree_view_scroll_to_cell (cbdata->command_view, path, NULL, FALSE, 0, 0);
187       gtk_tree_path_free (path);
188     }
189   else
190     gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("No command has this keyboard shortcut"));
191   if (cbdata->twokeylist)
192     {
193       gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, cbdata->twokeylist->str);
194       g_string_free (cbdata->twokeylist, TRUE);
195       cbdata->twokeylist = NULL;
196     }
197   //clean the GUI
198   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
199   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
200 
201   return TRUE;
202 }
203 
204 static gboolean
stop_capture_binding(GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,gpointer user_data)205 stop_capture_binding (GtkWidget * widget, G_GNUC_UNUSED GdkEventFocus * event, gpointer user_data)
206 {
207   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
208   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
209   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
210   g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
211   return FALSE;
212 }
213 
214 static void
kbd_interface_add_binding(GtkButton * button,gpointer user_data)215 kbd_interface_add_binding (GtkButton * button, gpointer user_data)
216 {
217   GtkTreeSelection *selection;
218   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
219   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
220   // check a command is selected
221   selection = gtk_tree_view_get_selection (cbdata->command_view);
222   if (!gtk_tree_selection_get_selected (selection, NULL, NULL))
223     return;
224   gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("Press a shortcut sequence for this command"));
225   cbdata->handler_key_press = g_signal_connect (GTK_WIDGET (button), "key-press-event", G_CALLBACK (capture_add_binding), user_data);
226   cbdata->handler_focus_out = g_signal_connect (GTK_WIDGET (button), "focus-out-event", G_CALLBACK (stop_capture_binding), user_data);
227   Denemo.accelerator_status = TRUE;
228 }
229 
230 static void
kbd_interface_add_2binding(GtkButton * button,gpointer user_data)231 kbd_interface_add_2binding (GtkButton * button, gpointer user_data)
232 {
233   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
234   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
235   cbdata->two_key = 1;
236   kbd_interface_add_binding (button, user_data);
237 }
238 
239 static void
kbd_interface_look_binding(GtkButton * button,gpointer user_data)240 kbd_interface_look_binding (GtkButton * button, gpointer user_data)
241 {
242   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
243   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
244   gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("Press a shortcut sequence whose command you seek"));
245   cbdata->handler_key_press = g_signal_connect (GTK_WIDGET (button), "key-press-event", G_CALLBACK (capture_look_binding), user_data);
246   cbdata->handler_focus_out = g_signal_connect (GTK_WIDGET (button), "focus-out-event", G_CALLBACK (stop_capture_binding), user_data);
247 }
248 
249 static void
kbd_interface_del_binding(G_GNUC_UNUSED GtkButton * button,gpointer user_data)250 kbd_interface_del_binding (G_GNUC_UNUSED GtkButton * button, gpointer user_data)
251 {
252   GtkTreeSelection *selection;
253   gchar *binding;
254   GtkTreeModel *model;
255   GtkTreeIter iter;
256   command_row* row = NULL;
257   keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
258   gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
259   selection = gtk_tree_view_get_selection (cbdata->binding_view);
260   //if no binding is selected, we do nothing
261   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
262     return;
263   //else get the binding and remove it
264   gtk_tree_model_get (model, &iter, 0, &binding, -1);
265 
266   gint command_id_ptr = lookup_command_for_keybinding_name(Denemo.map, binding);
267   remove_keybinding_from_name (Denemo.map, binding);
268 
269   if(command_id_ptr > -1){
270     if(keymap_get_command_row (Denemo.map, &row, command_id_ptr))
271       update_bindings_model(GTK_LIST_STORE(model), row->bindings);
272   }
273   else
274     g_debug("Cannot find command to delete.\n");
275   g_free (binding);
276   Denemo.accelerator_status = TRUE;
277 }
278 
279 static void
execute_current(keyboard_dialog_data * data)280 execute_current (keyboard_dialog_data *data)
281 {
282   GtkTreeModel *model;
283   GtkTreeSelection *selection;
284   GtkTreeIter iter;
285   gchar* cname = NULL;
286   selection = gtk_tree_view_get_selection (data->command_view);
287   gtk_tree_selection_get_selected (selection, &model, &iter);
288   gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
289   gint command_idx = lookup_command_from_name (Denemo.map, cname);
290   if(command_idx != data->command_id)
291     g_warning("correct command idx %d compare %d for action of name %s\n", command_idx, data->command_id, cname);
292  execute_callback_from_idx (Denemo.map, command_idx);
293 }
294 static void
add_current_to_palette(keyboard_dialog_data * data)295 add_current_to_palette (keyboard_dialog_data *data)
296 {
297   GtkTreeModel *model;
298   GtkTreeSelection *selection;
299   GtkTreeIter iter;
300   gchar* cname = NULL;
301   selection = gtk_tree_view_get_selection (data->command_view);
302   gtk_tree_selection_get_selected (selection, &model, &iter);
303   gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
304   gint command_idx = lookup_command_from_name (Denemo.map, cname);
305   place_action_in_palette (command_idx, NULL);
306 }
307 
308 
309 
310 
311 typedef struct ModifierPointerInfo
312 {
313   guint button_mask;
314   guint cursor_number;
315 } ModifierPointerInfo;
316 
317 #define DENEMO_MODIFIER_MASK (255)
318 static void
keyboard_modifier_callback(GtkWidget * w,GdkEventButton * event,ModifierPointerInfo * info)319 keyboard_modifier_callback (GtkWidget * w, GdkEventButton * event, ModifierPointerInfo * info)
320 {
321   gint mask = info->button_mask;
322   gint state = (event->state & DENEMO_MODIFIER_MASK) | mask;
323   gint cursor_number = info->cursor_number;
324   GdkCursor *cursor = gdk_cursor_new (cursor_number);
325   //g_hash_table_lookup(Denemo.map->cursors, &state);
326 
327   // show_type(w, "button mod callback: ");
328   GString *str = g_string_new ("");
329   g_string_append_printf (str, "Cursor Shape:- %d\n Mouse:- %s\nKeyboard:", cursor_number, mask ? (mask & GDK_BUTTON1_MASK ? "Left Button Drag" : "Right Button Drag") : "No Button Press");
330   append_modifier_name (str, state);
331 #define POINTER_PROMPT  "To change the cursor shape for a mouse/keyboard state:\nSelect Cursor Shape number\nChoose mouse state and then click here\nwhile holding modifier key\nand/or engaging Caps/Num lock for the keyboard state. Finally save command set."
332   gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
333 //g_string_append(str, "\n");
334 //  g_string_append(str, POINTER_PROMPT);
335 
336   gtk_button_set_label ((GtkButton *) w, str->str);
337   //gtk_widget_set_tooltip(w, POINTER_PROMPT);
338   assign_cursor (state, cursor_number);
339   g_string_free (str, TRUE);
340 }
341 
342 
343 
344 
345 static void
load_system_keymap_dialog_response(void)346 load_system_keymap_dialog_response (void)
347 {
348   load_system_keymap_dialog ();
349 
350 }
351 
352 static void
load_keymap_dialog_response(void)353 load_keymap_dialog_response (void)
354 {
355   load_keymap_dialog ();
356 
357 }
358 
359 static GtkWidget *SearchEntry = NULL;
360 static GtkWidget *SearchNext = NULL;
361 
362 static  keyboard_dialog_data cbdata;
363 
get_command_view(void)364 GtkWidget *get_command_view(void)
365 {
366 return  GTK_WIDGET(cbdata.command_view);
367 }
368 
369 static void
shortcut_button_choice_callback(GtkWidget * w,gboolean * left)370 shortcut_button_choice_callback (GtkWidget * w, gboolean * left)
371 {
372   g_debug ("left at %p is %d\n", left, *left);
373   *left = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
374   g_debug ("left at %p is now %d\n", left, *left);
375 }
376 
377 static void
button_move_callback(GtkWidget * w,mouse_gesture * g)378 button_move_callback (GtkWidget * w, mouse_gesture * g)
379 {
380   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
381     *g = GESTURE_MOVE;
382   //g_debug("move %d\n", *g);
383 }
384 
385 static void
button_press_callback(GtkWidget * w,mouse_gesture * g)386 button_press_callback (GtkWidget * w, mouse_gesture * g)
387 {
388   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
389     *g = GESTURE_PRESS;
390   //g_debug("press  %d\n", *g);
391 }
392 
393 static void
button_release_callback(GtkWidget * w,mouse_gesture * g)394 button_release_callback (GtkWidget * w, mouse_gesture * g)
395 {
396   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
397     *g = GESTURE_RELEASE;
398   //g_debug("release %d \n", *g);
399 }
400 
401 typedef struct ModifierAction
402 {
403   GtkAction *action;
404   gint modnum;                  /* GdkModifierType number 0...12 */
405   mouse_gesture gesture;        /* if this is for press move or release */
406   gboolean left;                /* if this is for left or right mouse button */
407 } ModifierAction;
408 
409 
410 static void
button_modifier_callback(GtkWidget * w,GdkEventButton * event,ModifierAction * ma)411 button_modifier_callback (GtkWidget * w, GdkEventButton * event, ModifierAction * ma)
412 {
413   ma->modnum = event->state;
414   // show_type(w, "button mod callback: ");
415   GString *str = g_string_new ("Keyboard:");
416   append_modifier_name (str, ma->modnum);
417   if (!ma->modnum)
418     g_string_assign (str, _("No keyboard modifier keys\nPress with modifier key to change"));
419   else
420     g_string_append (str, _("\nPress with modifier key to change"));
421   gtk_button_set_label (GTK_BUTTON (w), str->str);
422   g_string_free (str, TRUE);
423 }
424 
425 
426 
427 // info->action is the action for which the mouse shortcut is to be set
428 static void
setMouseAction(ModifierAction * info)429 setMouseAction (ModifierAction * info)
430 {
431   GString *modname = mouse_shortcut_name (info->modnum, info->gesture, info->left);
432   gint command_idx = lookup_command_for_keybinding_name (Denemo.map, modname->str);
433   GtkAction *current_action = NULL;
434   gchar *title = NULL;
435   gchar *prompt = NULL;
436   if (command_idx >= 0)
437     {
438       current_action = (GtkAction *) lookup_action_from_idx (Denemo.map, command_idx);
439       title = g_strdup_printf (_("The Command %s Responds to this Shortcut"), lookup_name_from_idx (Denemo.map, command_idx));
440       prompt = g_strdup_printf (_("Lose the shortcut %s for this?"), modname->str);
441     }
442   if (current_action == NULL || confirm (title, prompt))
443     {
444       remove_keybinding_from_name (Denemo.map, modname->str);   //by_name
445       const gchar *name = gtk_action_get_name (info->action);
446       command_idx = lookup_command_from_name (Denemo.map, name);
447       if (command_idx >= 0)
448         add_named_binding_to_idx (Denemo.map, modname->str, command_idx, POS_LAST);
449     }
450   g_free (title);
451   g_free (prompt);
452   g_string_free (modname, TRUE);
453 }
454 
455 static void
mouse_shortcut_dialog(ModifierAction * info)456 mouse_shortcut_dialog (ModifierAction * info)
457 {
458   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Set Mouse Shortcut"),
459                                                    GTK_WINDOW (Denemo.window),
460                                                    (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
461                                                    _("_OK"), GTK_RESPONSE_ACCEPT,
462                                                    _("_Cancel"), GTK_RESPONSE_REJECT,
463                                                    NULL);
464 
465 
466   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
467 
468   GtkWidget *hbox = gtk_hbox_new (FALSE, 1);
469   GtkWidget *vbox = gtk_vbox_new (FALSE, 1);
470   gtk_container_add (GTK_CONTAINER (content_area), hbox);
471   gtk_container_add (GTK_CONTAINER (hbox), vbox);
472 
473   gchar *name = (gchar *) gtk_action_get_name (info->action);
474   gchar *prompt = g_strdup_printf (_("Setting mouse shortcut for %s"), name);
475   GtkWidget *label = gtk_label_new (prompt);
476   g_free (prompt);
477   gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
478   GtkWidget *frame = gtk_frame_new (_("Choose the mouse button"));
479   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
480   gtk_container_add (GTK_CONTAINER (vbox), frame);
481   GtkWidget *vbox2 = gtk_vbox_new (FALSE, 8);
482   gtk_container_add (GTK_CONTAINER (frame), vbox2);
483 
484   info->left = TRUE;
485   GtkWidget *widget = gtk_radio_button_new_with_label (NULL, _("Left"));
486   g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (shortcut_button_choice_callback), &info->left);
487   gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, TRUE, 0);
488   GtkWidget *widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Right"));
489   gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
490 
491 
492   frame = gtk_frame_new (_("Choose mouse action"));
493   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
494   gtk_container_add (GTK_CONTAINER (vbox), frame);
495   vbox2 = gtk_vbox_new (FALSE, 8);
496   gtk_container_add (GTK_CONTAINER (frame), vbox2);
497   info->gesture = GESTURE_PRESS;
498   widget = gtk_radio_button_new_with_label (NULL, _("Press Button"));
499   g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (button_press_callback), &info->gesture);
500   gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, TRUE, 0);
501   widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Release Button"));
502   g_signal_connect (G_OBJECT (widget2), "toggled", G_CALLBACK (button_release_callback), &info->gesture);
503   gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
504   widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Drag"));
505   g_signal_connect (G_OBJECT (widget2), "toggled", G_CALLBACK (button_move_callback), &info->gesture);
506   gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
507 
508   widget = gtk_button_new_with_label (_("Hold Modifier Keys, Engage Caps or Num Lock\nand click here to set shortcut."));
509   g_signal_connect (G_OBJECT (widget), "button-release-event", G_CALLBACK (button_modifier_callback), info);
510   gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
511 
512 
513 
514   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
515   gtk_widget_show_all (dialog);
516   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
517     {
518       setMouseAction (info);
519       Denemo.accelerator_status = TRUE;
520     }
521   gtk_widget_destroy (dialog);
522 }
523 
524 
525 static void
createMouseShortcut(GtkAction * action)526 createMouseShortcut (GtkAction * action)
527 {
528   static ModifierAction info;
529   info.action = action;
530   info.gesture = GESTURE_PRESS;
531   info.modnum = 0;
532   info.left = TRUE;
533   mouse_shortcut_dialog (&info);
534 }
535 
createMouseShortcut_from_data(keyboard_dialog_data * data)536 static void createMouseShortcut_from_data (keyboard_dialog_data *data) {
537   GtkTreeModel *model;
538   GtkTreeSelection *selection;
539   GtkTreeIter iter;
540   gchar* cname = NULL;
541   selection = gtk_tree_view_get_selection (data->command_view);
542   gtk_tree_selection_get_selected (selection, &model, &iter);
543   gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
544   gint command_idx = lookup_command_from_name (Denemo.map, cname);
545     if(command_idx != -1)
546         {
547         GtkAction *action = (GtkAction *) lookup_action_from_idx (Denemo.map, command_idx);
548         createMouseShortcut (action);
549         }
550 }
551 void
configure_keyboard_dialog_init_idx(GtkAction * dummy,gint command_idx)552 configure_keyboard_dialog_init_idx (GtkAction * dummy, gint command_idx)
553 {
554   GtkWidget *frame;
555   GtkWidget *vbox, *outer_hbox;
556   GtkWidget *table;
557   GtkWidget *label;
558   GtkWidget *addbutton;
559   GtkWidget *add2button;
560   GtkWidget *delbutton;
561   GtkWidget *lookbutton;
562   GtkWidget *statusbar;
563   GtkWidget *button_save;
564   GtkWidget *button_save_as;
565   GtkWidget *button_load;
566   GtkWidget *button_load_from;
567 
568   GtkWidget *command_view;
569   GtkWidget *binding_view;
570   GtkWidget *command_tree_view;
571   GtkWidget *binding_tree_view;
572   GtkWidget *text_view;
573   GtkWidget *scrolled_text_view;
574 
575   GtkTreeSelection *selection;
576   GtkTreeIter iter;
577   GtkTreeModel *model;
578   GtkTreePath *path;
579   guint context_id;
580 
581   if(Denemo.command_manager)   {
582       model = gtk_tree_view_get_model (GTK_TREE_VIEW (cbdata.command_view));
583       if (command_idx == -1)
584         {
585         //selecting the first command
586         gtk_tree_model_get_iter_first (model, &iter);
587         }
588       else
589         {
590       gint pos = get_command_position(model, command_idx);
591       gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
592         }
593       gtk_widget_grab_focus (SearchEntry);
594       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cbdata.command_view));
595       gtk_tree_selection_select_iter (selection, &iter);
596       path = gtk_tree_model_get_path (model, &iter);
597       gtk_tree_view_scroll_to_cell ((GtkTreeView *) cbdata.command_view, path, NULL, FALSE, 0, 0);
598       gtk_tree_path_free (path);
599       if(!gtk_widget_get_visible(Denemo.command_manager))
600         activate_action ("/MainMenu/ViewMenu/" "ToggleCommandManager");
601       return;
602     }
603    if(SearchEntry==NULL) {
604     SearchEntry = gtk_entry_new ();
605     SearchNext = gtk_button_new_with_label ("→");
606     gtk_widget_set_tooltip_text (SearchEntry, _("Type search text here. Enter words that might be in the command label,\nor part of the text of a tooltip or the internal name.\nThe search is case insensitive. It goes on to the next match each time you enter letter that doesn't match the current command so check at each keypress.\nThe search re-starts from the top when you delete a letter."));
607     gtk_widget_set_tooltip_text (SearchNext, _("Search for the next matching command. Starts again at the top once it has reached the end."));
608     }   //The actual searching is done in kbd-custom.c by passing in the globals SearchEntry and SearchNext, ugh!
609   //getting a binding view and a command view and connecting the change of
610   //command selection the the change of the model displayed by the binding view
611   binding_view = keymap_get_binding_view ();
612   binding_tree_view = gtk_bin_get_child (GTK_BIN (binding_view));
613   command_view = GTK_WIDGET (keymap_get_command_view (Denemo.map, SearchEntry, SearchNext));
614   command_tree_view = gtk_bin_get_child (GTK_BIN (command_view));
615 
616   Denemo.command_manager = gtk_window_new (GTK_WINDOW_TOPLEVEL);
617   gtk_window_set_title(GTK_WINDOW(Denemo.command_manager), (_("Command Center")));
618   if (Denemo.prefs.newbie)
619     gtk_widget_set_tooltip_text (Denemo.command_manager,
620                                  _
621                                  ("This window allows you find and execute commands.\nOnce you have selected a command the box at the top gives information about that command,"
622                                  "\nwhile the panel to the side gives any shortcuts for the command."
623                                  "\nYou can add a selected command to a palette, or set single-key or two-key shortcuts."
624                                  "\nYou can also hide commands, so they don't appear in the menus.\n"
625                                  "You can save the shortcuts as your default command set, or as a command set which you may wish to load in the future.\n"
626                                  "This window is also where you can load such a stored command set."));
627 
628   outer_hbox = gtk_hbox_new (FALSE, 8);
629   gtk_container_add (GTK_CONTAINER (Denemo.command_manager), outer_hbox);
630   vbox = gtk_vbox_new (FALSE, 8);
631 
632 
633 
634   gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
635   gtk_box_pack_start (GTK_BOX (outer_hbox), vbox, TRUE, TRUE, 0);
636 
637 
638   frame = gtk_frame_new (_("Help for Selected Command"));
639   gtk_frame_set_shadow_type ((GtkFrame *) frame, GTK_SHADOW_IN);
640   gtk_widget_set_size_request (frame, -1, 200);
641   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
642   text_view = gtk_text_view_new ();
643   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
644   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);
645   scrolled_text_view = gtk_scrolled_window_new (gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0), gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0));
646   gtk_container_add (GTK_CONTAINER (scrolled_text_view), text_view);
647   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_text_view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
648   gtk_container_add (GTK_CONTAINER (frame), scrolled_text_view);
649 
650 
651 
652   {
653   GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 8);
654   gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, TRUE, TRUE, 0);
655   gtk_box_pack_start (GTK_BOX (inner_hbox), gtk_widget_get_parent(command_view), TRUE, TRUE, 0);
656   {
657     GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 8);
658   gtk_box_pack_start (GTK_BOX (inner_hbox), inner_vbox,  TRUE, TRUE, 0);
659   GtkWidget *label = gtk_label_new ("");
660   gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
661   gtk_label_set_markup (GTK_LABEL (label), _("List of shortcuts\nfor <i>selected</i> command\nfrom table on left.\nSelect a shortcut\nto remove\nwith button below."));
662 
663   gtk_box_pack_start (GTK_BOX (inner_vbox), label,  TRUE, TRUE, 0);
664   gtk_box_pack_start (GTK_BOX (inner_vbox), binding_view,  FALSE, TRUE, 0);
665   delbutton = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
666     gtk_box_pack_start (GTK_BOX (inner_vbox), delbutton, FALSE, TRUE, 0);
667 }
668   }
669 
670   vbox = gtk_vbox_new (FALSE, 8);
671   gtk_box_pack_end (GTK_BOX (outer_hbox), vbox, FALSE, TRUE, 0);
672 
673    {
674   GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 8);
675   gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
676    button_save = gtk_button_new_with_label (_("Save as Default Command Set"));
677     gtk_box_pack_start (GTK_BOX (inner_hbox), button_save, FALSE, TRUE, 0);
678   gtk_widget_set_tooltip_text (button_save, _("Use this to save the changes you have made so that they are used every time you start Denemo. The changes are stored under a directory (folder) called .denemo-* in your home directory. Look in subdirectory actions for Default.commands"));
679   button_save_as = gtk_button_new_with_label (_("Save as a Custom Command Set"));
680     gtk_box_pack_start (GTK_BOX (inner_hbox), button_save_as, FALSE, TRUE, 0);
681 
682   button_load = gtk_button_new_with_label (_("Load a Standard Command Set"));
683     inner_hbox = gtk_hbox_new (FALSE, 8);
684   gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
685     button_load = gtk_button_new_with_label (_("Load a Standard Command Set"));
686     gtk_box_pack_start (GTK_BOX (inner_hbox), button_load, FALSE, TRUE, 0);
687 
688   button_load_from = gtk_button_new_with_label (_("Load a Custom Command Set"));
689     gtk_box_pack_start (GTK_BOX (inner_hbox), button_load_from, FALSE, TRUE, 0);
690 
691    }
692 
693   GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 1);
694   gtk_box_pack_end (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
695     GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 1);
696   gtk_box_pack_end (GTK_BOX (inner_hbox), inner_vbox, FALSE, TRUE, 0);
697   addbutton = gtk_button_new_from_stock (GTK_STOCK_ADD);
698   gtk_button_set_label (GTK_BUTTON (addbutton), _("Add 1-Key Shortcut"));
699   gtk_widget_set_tooltip_text (addbutton, _("Create a single keypress (with modifier keys - Control, Shift ... - if needed) as a keyboard shortcut for the currently selected command."));
700   gtk_box_pack_end (GTK_BOX (inner_vbox), addbutton, FALSE, TRUE, 0);
701 
702   add2button = gtk_button_new_from_stock (GTK_STOCK_ADD);
703   gtk_button_set_label (GTK_BUTTON (add2button), _("Add 2-Key Shortcut"));
704   gtk_widget_set_tooltip_text (add2button, _("Create a two keypress sequence as a keyboard shortcut for the currently selected command."));
705   gtk_box_pack_end (GTK_BOX (inner_vbox), add2button, FALSE, TRUE, 0);
706 
707   lookbutton = gtk_button_new_from_stock (GTK_STOCK_FIND);
708   gtk_button_set_label (GTK_BUTTON (lookbutton), _("Find Command for Shortcut"));
709   gtk_widget_set_tooltip_text (lookbutton, _("Finds the command (if any) for a (one key) Keyboard Shortcut\n"
710                                               "Click button then press the key shortcut you are looking for."));
711   gtk_box_pack_end (GTK_BOX (inner_vbox), lookbutton, FALSE, TRUE, 0);
712 
713 
714   inner_vbox = gtk_vbox_new (FALSE, 1);
715   gtk_box_pack_start (GTK_BOX (inner_hbox), inner_vbox, FALSE, TRUE, 0);
716   GtkWidget *execute_button = gtk_button_new_with_label (_("Execute Selected Command"));
717   gtk_widget_set_tooltip_text (execute_button, _("Executes the currently selected command in the list of commands\nEnsure the cursor is in the movement and at the position if needed for the command."));
718   gtk_box_pack_end (GTK_BOX (inner_vbox), execute_button, FALSE, TRUE, 0);
719   GtkWidget *palette_button = gtk_button_new_with_label (_("Add to Palette"));
720   gtk_widget_set_tooltip_text (palette_button, _("Adds the currently selected command in the list of commands to a palette\nYou can create a new, custom palette, and you can change the label of the button you create by right-clicking on it."));
721   gtk_box_pack_end (GTK_BOX (inner_vbox), palette_button, FALSE, TRUE, 0);
722   g_signal_connect_swapped (G_OBJECT (execute_button), "clicked", G_CALLBACK (execute_current), &cbdata);
723   g_signal_connect_swapped (G_OBJECT (palette_button), "clicked", G_CALLBACK (add_current_to_palette), &cbdata);
724 
725 
726 
727 
728 
729   statusbar = gtk_statusbar_new ();
730   context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "");
731   //FIXME gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);
732   gtk_box_pack_end (GTK_BOX (vbox), statusbar, FALSE, TRUE, 0);
733 
734   cbdata.addbutton = GTK_BUTTON (addbutton);
735   cbdata.add2button = GTK_BUTTON (add2button);
736   cbdata.delbutton = GTK_BUTTON (delbutton);
737   cbdata.lookbutton = GTK_BUTTON (lookbutton);
738   cbdata.statusbar = GTK_STATUSBAR (statusbar);
739   cbdata.context_id = context_id;
740   cbdata.command_view = GTK_TREE_VIEW (command_tree_view);
741   cbdata.binding_view = GTK_TREE_VIEW (binding_tree_view);
742   cbdata.text_view = GTK_TEXT_VIEW (text_view);
743   cbdata.command_id = -1;
744   cbdata.two_key = 0;
745   cbdata.twokeylist = NULL;
746 
747   //setup the link between command_view and binding_view
748   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (command_tree_view));
749   gtk_tree_selection_set_select_function (selection, keymap_change_binding_view_on_command_selection, &cbdata, NULL);
750 
751   model = gtk_tree_view_get_model (GTK_TREE_VIEW (command_tree_view));
752   if (command_idx == -1)
753     {
754       //selecting the first command
755       gtk_tree_model_get_iter_first (model, &iter);
756     }
757   else
758     {
759       gint pos = get_command_position(model, command_idx);
760       gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
761       path = gtk_tree_model_get_path (model, &iter);
762       gtk_tree_view_scroll_to_cell ((GtkTreeView *) command_tree_view, path, NULL, FALSE, 0, 0);
763       gtk_tree_path_free (path);
764     }
765   gtk_widget_grab_focus (SearchEntry);
766   gtk_tree_selection_select_iter (selection, &iter);
767 
768 
769   GtkWidget *shortcut_button = gtk_button_new_with_label (_("Set Mouse Shortcut"));
770   gtk_widget_set_tooltip_text (shortcut_button, _("Set mouse shortcut"));
771   g_signal_connect_swapped (G_OBJECT (shortcut_button), "button-release-event", G_CALLBACK (createMouseShortcut_from_data), &cbdata);
772   gtk_box_pack_end (GTK_BOX (vbox), shortcut_button, FALSE, TRUE, 0);
773 
774 
775   //Connecting signals
776   g_signal_connect (addbutton, "clicked", G_CALLBACK (kbd_interface_add_binding), &cbdata);
777   g_signal_connect (add2button, "clicked", G_CALLBACK (kbd_interface_add_2binding), &cbdata);
778 
779   g_signal_connect (lookbutton, "clicked", G_CALLBACK (kbd_interface_look_binding), &cbdata);
780   g_signal_connect (delbutton, "clicked", G_CALLBACK (kbd_interface_del_binding), &cbdata);
781 
782   g_signal_connect (G_OBJECT (button_save), "clicked", G_CALLBACK (save_default_keymap_file), NULL);
783   g_signal_connect (G_OBJECT (button_save_as), "clicked", G_CALLBACK (save_keymap_dialog), NULL);
784   g_signal_connect (G_OBJECT (button_load), "clicked", G_CALLBACK (load_system_keymap_dialog_response), NULL);
785   g_signal_connect (G_OBJECT (button_load_from), "clicked", G_CALLBACK (load_keymap_dialog_response), NULL);
786 
787   gtk_widget_show_all (Denemo.command_manager);
788   g_signal_connect (Denemo.command_manager, "delete-event", G_CALLBACK (keymap_cleanup_command_view), &cbdata);
789 }
790 
791 void
configure_keyboard_dialog(GtkAction * action,DenemoScriptParam * param)792 configure_keyboard_dialog (GtkAction * action, DenemoScriptParam * param)
793 {
794   configure_keyboard_dialog_init_idx (action, -1);
795 }
796 
797