7 #include <gdk/gdkkeysyms.h>
10 #define _(String) dgettext (PACKAGE, String)
12 #define CURRENT_BINDINGS \
18 (current_lang, current_name, current_command))))))
20 #define CURRENT_STATUS \
26 (current_lang, current_name, current_command))))))
28 #define CONFIG_COMMAND(plist) \
29 minput_config_command (current_lang, current_name, current_command, \
32 static unsigned modifier_state = 0;
33 static MPlist *entry_keyseq;
34 static MSymbol current_lang, current_name, current_command;
47 ALT_MASK_BIT = META_MASK_BIT << 1,
48 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
49 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
53 keyseq_equal (MPlist *pl1, MPlist *pl2)
55 if (mplist_length (pl1) != mplist_length (pl2))
57 while (pl1 && mplist_key (pl1) == Msymbol)
59 if (mplist_value (pl1) != mplist_value (pl2))
61 pl1 = mplist_next (pl1);
62 pl2 = mplist_next (pl2);
68 update_entry (GtkEntry *entry)
70 if (mplist_key (entry_keyseq) == Mnil)
71 gtk_entry_set_text (entry, "");
77 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
78 gtk_entry_set_text (entry, name);
79 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
82 name = msymbol_name ((MSymbol) mplist_value (p));
83 gtk_entry_append_text (entry, " ");
84 gtk_entry_append_text (entry, name);
86 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
91 update_binding_store (GtkWidget *view)
97 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
98 gtk_list_store_clear (store);
100 for (pl = CURRENT_BINDINGS;
101 pl && mplist_key (pl) == Mplist;
102 pl = mplist_next (pl))
104 gtk_list_store_append (store, &iter);
105 gtk_list_store_set (store, &iter, 0, mplist_value (pl), -1);
110 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
117 struct BindingWidgets *bw = data;
119 c = gdk_keyval_to_unicode (event->keyval);
122 switch (event->keyval)
124 case GDK_Meta_L: case GDK_Meta_R:
125 modifier_state |= META_MASK_BIT; return TRUE;
126 case GDK_Alt_L: case GDK_Alt_R:
127 modifier_state |= ALT_MASK_BIT; return TRUE;
128 case GDK_Super_L: case GDK_Super_R:
129 modifier_state |= SUPER_MASK_BIT; return TRUE;
130 case GDK_Hyper_L: case GDK_Hyper_R:
131 modifier_state |= HYPER_MASK_BIT; return TRUE;
133 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
136 name = gdk_keyval_name (event->keyval);
139 nbytes = strlen (name);
145 mtext_cat_char (mt, c);
146 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
147 (unsigned char *) name, 32);
148 m17n_object_unref (mt);
151 if (c == 0 && event->state & GDK_SHIFT_MASK)
152 buf[i++] = 'S', buf[i++] = '-';
153 if (event->state & GDK_CONTROL_MASK)
154 buf[i++] = 'C', buf[i++] = '-';
155 if (modifier_state & META_MASK_BIT)
156 buf[i++] = 'M', buf[i++] = '-';
157 if (modifier_state & ALT_MASK_BIT)
158 buf[i++] = 'A', buf[i++] = '-';
159 if (modifier_state & SUPER_MASK_BIT)
160 buf[i++] = 's', buf[i++] = '-';
161 if (modifier_state & HYPER_MASK_BIT)
162 buf[i++] = 'H', buf[i++] = '-';
163 strncpy (buf + i, name, nbytes);
165 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
166 update_entry (entry);
167 gtk_widget_set_sensitive (bw->clear, TRUE);
168 gtk_widget_set_sensitive (bw->add, TRUE);
173 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
177 c = gdk_keyval_to_unicode (event->keyval);
180 switch (event->keyval)
182 case GDK_Meta_L: case GDK_Meta_R:
183 modifier_state &= ~META_MASK_BIT; break;
184 case GDK_Alt_L: case GDK_Alt_R:
185 modifier_state &= ~ALT_MASK_BIT; break;
186 case GDK_Super_L: case GDK_Super_R:
187 modifier_state &= ~SUPER_MASK_BIT; break;
188 case GDK_Hyper_L: case GDK_Hyper_R:
189 modifier_state &= ~HYPER_MASK_BIT; break;
196 clear_cb (GtkButton *button, gpointer data)
198 struct BindingWidgets *bw = data;
200 mplist_set (entry_keyseq, Mnil, NULL);
201 gtk_widget_grab_focus (bw->entry);
202 update_entry (GTK_ENTRY (bw->entry));
203 gtk_widget_set_sensitive (bw->clear, FALSE);
204 gtk_widget_set_sensitive (bw->add, FALSE);
208 add_cb (GtkButton *button, gpointer data)
210 MPlist *new, *pl, *last;
213 struct BindingWidgets *bw = data;
215 if (mplist_length (entry_keyseq) == 0)
218 for (pl = CURRENT_BINDINGS;
219 pl && mplist_key (pl) == Mplist;
220 pl = mplist_next (pl))
222 if (! keyseq_equal (mplist_value (pl), entry_keyseq))
223 mplist_add (new, Mplist, mplist_value (pl));
226 /* entry_keyseq is already registered. */
227 m17n_object_unref (new);
231 mplist_add (new, Mplist, entry_keyseq);
232 CONFIG_COMMAND (new);
233 m17n_object_unref (new);
235 /* We cannot use ENTRY_KEYSEQ for gtk_list_store_set (). We must
236 use a pointer to the internally copied one. */
237 new = CURRENT_BINDINGS;
239 pl && mplist_key (pl) == Mplist;
240 last = pl, pl = mplist_next (pl));
241 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (bw->view)));
242 gtk_list_store_append (store, &iter);
243 gtk_list_store_set (store, &iter, 0, mplist_value (last), -1);
244 update_binding_store (bw->view);
246 gtk_widget_set_sensitive (bw->clear, FALSE);
247 gtk_widget_set_sensitive (bw->add, FALSE);
251 create_adding_section (struct BindingWidgets *bw)
253 GtkWidget *label, *hbox, *vbox;
255 label = gtk_label_new (_("New key binding:"));
257 entry_keyseq = mplist ();
258 bw->entry = gtk_entry_new ();
259 g_signal_connect (G_OBJECT (bw->entry), "key-press-event",
260 G_CALLBACK (key_pressed_cb), bw);
261 g_signal_connect (G_OBJECT (bw->entry), "key-release-event",
262 G_CALLBACK (key_released_cb), bw);
264 bw->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
265 gtk_widget_set_sensitive (bw->clear, FALSE);
266 g_signal_connect (G_OBJECT (bw->clear), "clicked",
267 G_CALLBACK (clear_cb), bw);
269 bw->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
270 gtk_widget_set_sensitive (bw->add, FALSE);
271 g_signal_connect (G_OBJECT (bw->add), "clicked",
272 G_CALLBACK (add_cb), bw);
274 vbox = gtk_vbox_new (FALSE, 6);
275 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
277 hbox = gtk_hbox_new (FALSE, 6);
278 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
279 gtk_container_add (GTK_CONTAINER (vbox), hbox);
281 gtk_container_add (GTK_CONTAINER (vbox), bw->entry);
283 hbox = gtk_hbutton_box_new ();
284 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
285 gtk_box_set_spacing (GTK_BOX (hbox), 6);
286 gtk_container_add (GTK_CONTAINER (hbox), bw->clear);
287 gtk_container_add (GTK_CONTAINER (hbox), bw->add);
288 gtk_container_add (GTK_CONTAINER (vbox), hbox);
294 selection_cb (GtkTreeSelection *selection, gpointer data)
296 struct BindingWidgets *bw = data;
298 gtk_widget_set_sensitive
300 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
304 keyseq_render_function (GtkTreeViewColumn *column,
305 GtkCellRenderer *renderer,
314 gtk_tree_model_get (model, iter, 0, &keyseq, -1);
315 for (pl = keyseq, n = 0;
316 pl && mplist_key (pl) == Msymbol;
317 pl = mplist_next (pl))
318 n += strlen (msymbol_name ((MSymbol) mplist_value (pl))) + 1;
319 if (n < sizeof (buf))
323 pl && mplist_key (pl) == Msymbol;
324 pl = mplist_next (pl))
326 strcat (buf, msymbol_name ((MSymbol) mplist_value (pl)));
329 g_object_set (renderer, "foreground-set", FALSE, NULL);
333 g_snprintf (buf, sizeof (buf), _("Too long to display"));
334 g_object_set (renderer, "foreground", "Red", "foreground-set", TRUE,
337 g_object_set (renderer, "text", buf, NULL);
341 default_cb (GtkButton *button, gpointer data)
343 MPlist *empty = mplist ();
344 struct BindingWidgets *bw = data;
346 CONFIG_COMMAND (empty);
347 m17n_object_unref (empty);
348 update_binding_store (bw->view);
352 revert_cb (GtkButton *button, gpointer data)
354 struct BindingWidgets *bw = data;
356 CONFIG_COMMAND (NULL);
357 update_binding_store (bw->view);
361 delete_cb (GtkButton *button, gpointer data)
363 GtkTreeSelection *selection;
366 MPlist *keyseq, *new, *pl;
367 struct BindingWidgets *bw = data;
369 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (bw->view));
370 if (! gtk_tree_selection_get_selected (selection, &model, &iter))
372 gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
374 for (pl = CURRENT_BINDINGS;
375 pl && mplist_key (pl) == Mplist;
376 pl = mplist_next (pl))
377 if (! keyseq_equal (mplist_value (pl), keyseq))
378 mplist_add (new, Mplist, mplist_value (pl));
379 CONFIG_COMMAND (new);
380 m17n_object_unref (new);
381 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
382 update_binding_store (bw->view);
383 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
387 create_deleting_section (struct BindingWidgets *bw)
390 GtkWidget *scrolled, *default_, *revert, *delete, *hbox, *vbox;
391 GtkTreeViewColumn *column;
392 GtkCellRenderer *renderer;
394 GtkTreeSelection *selection;
397 store = gtk_list_store_new (1, G_TYPE_POINTER);
398 bw->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
399 g_object_unref (G_OBJECT (store));
400 update_binding_store (bw->view);
401 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(bw->view));
402 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
403 g_signal_connect (G_OBJECT (selection), "changed",
404 G_CALLBACK (selection_cb), bw);
406 scrolled = gtk_scrolled_window_new (NULL, NULL);
407 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
408 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
409 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
412 column = gtk_tree_view_column_new ();
413 gtk_tree_view_column_set_title (column, _("Current Key Bindings"));
414 gtk_tree_view_append_column (GTK_TREE_VIEW (bw->view), column);
416 renderer = gtk_cell_renderer_text_new ();
417 gtk_tree_view_column_pack_start (column, renderer, TRUE);
418 gtk_tree_view_column_set_cell_data_func
419 (column, renderer, keyseq_render_function, NULL, NULL);
421 default_ = gtk_button_new_from_stock (_("_Default"));
422 g_signal_connect (G_OBJECT (default_), "clicked",
423 G_CALLBACK (default_cb), bw);
425 revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
426 g_signal_connect (G_OBJECT (revert), "clicked",
427 G_CALLBACK (revert_cb), bw);
429 bw->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
430 gtk_widget_set_sensitive (bw->delete, FALSE);
431 g_signal_connect (G_OBJECT (bw->delete), "clicked",
432 G_CALLBACK (delete_cb), bw);
434 vbox = gtk_vbox_new (FALSE, 6);
435 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
437 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
439 hbox = gtk_hbutton_box_new ();
440 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
441 gtk_box_set_spacing (GTK_BOX (hbox), 6);
442 gtk_container_add (GTK_CONTAINER (hbox), default_);
443 gtk_container_add (GTK_CONTAINER (hbox), revert);
444 gtk_container_add (GTK_CONTAINER (hbox), bw->delete);
445 gtk_container_add (GTK_CONTAINER (vbox), hbox);
451 set_status (GtkListStore *store, GtkTreeIter *iter)
456 status = CURRENT_STATUS;
457 if (status == Mnil || status == Minherited)
458 status_str = _("default");
459 else if (status == Mcustomized)
460 status_str = _("customized");
462 status_str = _("modified");
463 gtk_list_store_set (store, iter, 1, status_str, -1);
467 activated_cb (GtkTreeView *parent, GtkTreePath *path,
468 GtkTreeViewColumn *col, gpointer data)
473 struct BindingWidgets bw;
476 model = gtk_tree_view_get_model (parent);
477 if (! gtk_tree_model_get_iter (model, &iter, path))
479 gtk_tree_model_get (model, &iter, 0, &command, -1);
480 current_command = msymbol (command);
482 dialog = (gtk_dialog_new_with_buttons
484 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
485 GTK_DIALOG_DESTROY_WITH_PARENT,
486 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
488 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
489 create_adding_section (&bw));
490 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
491 create_deleting_section (&bw));
493 gtk_widget_show_all (dialog);
494 gtk_dialog_run (GTK_DIALOG (dialog));
495 gtk_tree_model_get_iter (model, &iter, path);
496 set_status (GTK_LIST_STORE (model), &iter);
497 gtk_widget_destroy (dialog);
498 m17n_object_unref (entry_keyseq);
502 create_command_entries (GtkTooltips *tip, MSymbol lang, MSymbol name)
506 GtkCellRenderer *renderer;
512 plist = minput_get_command (lang, name, Mnil);
514 * plist == ((command description status keyseq keyseq ...)
515 * (command description status keyseq keyseq ...)
519 return gtk_label_new (_("No commands for this method."));
521 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
522 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
526 MSymbol command, status;
530 pl = mplist_value (plist);
531 /* pl == (command description status keyseq keyseq ...) */
532 current_command = command = mplist_value (pl);
534 pl = mplist_next (pl);
535 /* pl == (description status keyseq keyseq ...) */
536 if (mplist_key (pl) == Mtext)
537 /* Fixme : Assuming the return value is in UTF-8 */
538 desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
542 pl = mplist_next (pl);
543 /* pl == (status keyseq keyseq ...) */
544 status = mplist_value (pl);
545 gtk_list_store_append (store, &iter);
546 gtk_list_store_set (store, &iter,
547 0, msymbol_name (command),
549 set_status (store, &iter);
551 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
552 g_object_unref (G_OBJECT (store));
553 renderer = gtk_cell_renderer_text_new ();
554 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
560 renderer = gtk_cell_renderer_text_new ();
561 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
567 g_signal_connect (G_OBJECT (view), "row-activated",
568 G_CALLBACK (activated_cb), NULL);