1 /* mim-config.c -- M17N input method configuration
2 Copyright (C) 2007, 2011
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n-im-config package; a sub-part of the
9 The m17n library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public License
11 as published by the Free Software Foundation; either version 2.1 of
12 the License, or (at your option) any later version.
14 The m17n library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with the m17n library; if not, write to the Free
21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 #include <m17n-misc.h>
32 #include <gdk/gdkkeysyms.h>
34 #include "m17n-im-config.h"
36 #define _(String) dgettext (PACKAGE, String)
38 #define CONFIG_CALLBACK_DATA " config-callback-data"
39 #define CONFIG_STATUS_DATA " config-status-data"
40 #define CONFIG_TREE_VIEW " config-tree-view"
42 typedef void (*MimConfigCallbackFunc) (GtkWidget *widget, gpointer data);
44 typedef struct _MimConfigCallback
47 MimConfigCallbackFunc func;
51 typedef struct _MimConfigStatus
53 /* Number of available input methods. */
55 /* Number of modified input methods. */
59 /* Status of variables and commands of an input method. */
64 MIM_STATUS_CUSTOMIZED,
70 static char *mim_status_str[MIM_STATUS_MAX];
73 get_mim_status (MSymbol lang, MSymbol name)
76 enum MimStatus status = MIM_STATUS_NO;
78 for (plist = minput_get_variable (lang, name, Mnil);
79 plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
81 MPlist *p = mplist_value (plist);
82 MSymbol status_symbol;
84 p = mplist_next (mplist_next (p));
85 status_symbol = mplist_value (p);
86 if (status_symbol == Mconfigured)
87 return MIM_STATUS_MODIFIED;
88 if (status_symbol == Mcustomized)
89 status = MIM_STATUS_CUSTOMIZED;
90 else if (status == MIM_STATUS_NO)
91 status = MIM_STATUS_DEFAULT;
93 for (plist = minput_get_command (lang, name, Mnil);
94 plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
96 MPlist *p = mplist_value (plist);
97 MSymbol status_symbol;
99 p = mplist_next (mplist_next (p));
100 status_symbol = mplist_value (p);
101 if (status_symbol == Mconfigured)
102 return MIM_STATUS_MODIFIED;
103 if (status_symbol == Mcustomized)
104 status = MIM_STATUS_CUSTOMIZED;
105 else if (status == MIM_STATUS_NO)
106 status = MIM_STATUS_DEFAULT;
111 /* Columns of each row. */
114 /* parent: language name
117 /* parent: NULL or "modified"
118 child: "default", "customized", or "modified" */
120 /* parent: num of modified children
121 child: enum MimStatus */
124 child: symbolic language name. */
127 child: symbolic IM name. */
129 /* number of columns */
133 /* Called when a row is expanded. We may have to initialize
136 tree_expanded_cb (GtkTreeView *tree, GtkTreeIter *parent,
137 GtkTreePath *path, gpointer data)
143 model = gtk_tree_view_get_model (tree);
144 if (gtk_tree_model_iter_children (model, &iter, parent))
148 gtk_tree_model_get (model, &iter, COL_STATUS_STR, &status_str, -1);
151 /* The first child is not yet initialized, and that means
152 the remaining children are not initialized either. */
153 gtk_tree_model_get (model, &iter, COL_LANG, &lang, -1);
155 enum MimStatus im_status;
157 gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
158 im_status = get_mim_status (lang, name);
159 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
160 COL_STATUS_STR, mim_status_str[im_status],
161 COL_STATUS, im_status,
163 } while (gtk_tree_model_iter_next (model, &iter));
168 static void config_im (GtkTreeView *tree, MSymbol lang, MSymbol name);
171 update_child_row (GtkTreeModel *model, GtkTreeIter *iter,
172 enum MimStatus status, MimConfigStatus *config_status,
178 inc_modified = (status == MIM_STATUS_MODIFIED ? 1 : -1);
180 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
181 COL_STATUS_STR, mim_status_str[status],
182 COL_STATUS, status, -1);
183 if (gtk_tree_model_iter_parent (model, &parent, iter))
188 gtk_tree_model_get (model, &parent, COL_STATUS, &num_modified, -1);
189 num_modified += inc_modified;
190 gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
191 COL_STATUS, num_modified, -1);
192 if (num_modified <= 1)
194 status_str = (status == MIM_STATUS_MODIFIED
195 ? mim_status_str[MIM_STATUS_MODIFIED] : NULL);
196 gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
197 COL_STATUS_STR, status_str);
202 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
203 config_status->num_modified += inc_modified;
204 if (tree && config_status->num_modified <= 1)
206 MimConfigCallback *callback;
208 callback = g_object_get_data (G_OBJECT (tree), CONFIG_CALLBACK_DATA);
210 callback->func (callback->widget, callback->data);
215 tree_activated_cb (GtkTreeView *tree, GtkTreePath *path,
216 GtkTreeViewColumn *column, gpointer data)
221 model = gtk_tree_view_get_model (tree);
222 if (gtk_tree_model_get_iter (model, &iter, path))
226 gtk_tree_model_get (model, &iter, COL_LANG, &lang, COL_NAME, &name, -1);
229 /* child row for an IM */
230 enum MimStatus old, new;
232 old = get_mim_status (lang, name);
233 config_im (tree, lang, name);
234 new = get_mim_status (lang, name);
236 update_child_row (model, &iter, new, NULL, tree);
240 /* parent row for a language */
241 if (gtk_tree_view_row_expanded (tree, path))
242 gtk_tree_view_collapse_row (tree, path);
244 gtk_tree_view_expand_row (tree, path, TRUE);
249 typedef struct _MimTable
260 sort_im (const void *p1, const void *p2)
262 const MimTable *t1 = p1;
263 const MimTable *t2 = p2;
266 if (t1->symlang == t2->symlang)
270 if (t1->lang_in_locale != t2->lang_in_locale)
271 return (t1->lang_in_locale ? -1 : 1);
272 if ((! t1->encoded_lang) != (! t2->encoded_lang))
273 return (t1->encoded_lang ? -1 : 1);
274 if (t1->encoded_lang)
275 result = strcoll (t1->encoded_lang, t2->encoded_lang);
276 else if ((! t1->lang) != (! t2->lang))
277 return (t1->lang ? -1 : 1);
279 result = strcmp (t1->lang, t2->lang);
282 return (result ? result : strcmp (t1->name, t2->name));
285 static GtkTreeStore *
286 make_store_for_input_methods ()
292 char *lang, *other = _("Other");
293 GtkTreeIter iter1, iter2;
294 enum MimStatus status;
295 MimConfigStatus *config_status;
296 unsigned char conv_buf[256];
297 MConverter *converter;
298 int locale_is_utf8 = 0;
302 Meng = msymbol ("eng");
303 store = gtk_tree_store_new (NUM_COLS,
304 G_TYPE_STRING, /* COL_TAG */
305 G_TYPE_STRING, /* COL_STATUS_STR */
306 G_TYPE_UINT, /* COL_STATUS */
307 G_TYPE_POINTER, /* COL_LANG */
308 G_TYPE_POINTER /* COL_NAME */
311 config_status = g_new0 (MimConfigStatus, 1);
312 gtk_tree_store_append (store, &iter1, NULL);
313 status = get_mim_status (Mt, Mnil);
314 gtk_tree_store_set (store, &iter1,
315 COL_TAG, _("global"),
316 COL_STATUS_STR, mim_status_str[status],
322 imlist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
323 config_status->num_im = mplist_length (imlist);
324 imtable = g_newa (MimTable, config_status->num_im);
327 MLocale *locale = mlocale_set (LC_MESSAGES, NULL);
328 MSymbol coding = locale ? mlocale_get_prop (locale, Mcoding) : Mnil;
332 else if (coding == msymbol ("utf-8"))
339 converter = mconv_buffer_converter (coding, conv_buf, sizeof conv_buf);
341 converter->last_block = 1;
345 for (i = 0, p = imlist; mplist_key (p) != Mnil; p = mplist_next (p))
347 MDatabase *mdb = (MDatabase *) mplist_value (p);
348 MSymbol *tag = mdatabase_tag (mdb);
351 if (tag[1] == Mnil || tag[2] == Mnil)
354 imtable[i].symlang = tag[1];
355 imtable[i].symname = tag[2];
356 imtable[i].name = msymbol_name (tag[2]);
357 imtable[i].lang = imtable[i].encoded_lang = NULL;
358 imtable[i].lang_in_locale = 0;
362 pl = mlanguage_name_list (tag[1], Mnil, Mnil, Mnil);
364 imtable[i].lang_in_locale = 1;
366 pl = mlanguage_name_list (tag[1], Meng, Mnil, Mnil);
369 MText *mt = mplist_value (pl);
374 mconv_reset_converter (converter);
375 nbytes = mconv_encode (converter, mt);
376 if (converter->result == MCONVERSION_RESULT_SUCCESS)
378 imtable[i].encoded_lang = alloca (nbytes + 1);
379 if (imtable[i].encoded_lang)
381 memcpy (imtable[i].encoded_lang, conv_buf, nbytes);
382 imtable[i].encoded_lang[nbytes] = '\0';
386 else if (locale_is_utf8)
387 imtable[i].encoded_lang
388 = mtext_data (mt, NULL, NULL, NULL, NULL);
389 imtable[i].lang = mtext_data (mt, NULL, NULL, NULL, NULL);
392 imtable[i].lang = msymbol_name (tag[1]);
397 mconv_free_converter (converter);
398 m17n_object_unref (imlist);
399 config_status->num_im = i;
400 qsort (imtable, config_status->num_im, sizeof (MimTable), sort_im);
402 for (lang = NULL, i = 0; i < config_status->num_im; i++)
404 gchar *langname = imtable[i].lang;
408 if (lang != langname)
410 gtk_tree_store_append (store, &iter1, NULL);
411 gtk_tree_store_set (store, &iter1,
413 COL_STATUS_STR, NULL,
420 gtk_tree_store_append (store, &iter2, &iter1);
421 gtk_tree_store_set (store, &iter2,
422 COL_TAG, imtable[i].name,
423 COL_STATUS_STR, NULL,
424 COL_LANG, imtable[i].symlang,
425 COL_NAME, imtable[i].symname,
428 config_status->num_modified = 0;
429 g_object_set_data_full (G_OBJECT (store), CONFIG_STATUS_DATA,
430 config_status, g_free);
435 reset_to_default (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
438 enum MimStatus status, new_status;
440 MimConfigStatus *config_status = data;
441 MPlist *empty = mplist ();
443 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
446 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
447 if (status == MIM_STATUS_DEFAULT)
449 minput_config_variable (lang, name, Mnil, empty);
450 minput_config_command (lang, name, Mnil, empty);
451 new_status = get_mim_status (lang, name);
452 if (status != new_status)
453 update_child_row (model, iter, new_status, config_status, NULL);
458 revert_to_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
461 enum MimStatus status;
463 MimConfigStatus *config_status = data;
465 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
468 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
469 if (status != MIM_STATUS_MODIFIED)
471 minput_config_variable (lang, name, Mnil, NULL);
472 minput_config_command (lang, name, Mnil, NULL);
473 status = get_mim_status (lang, name);
474 update_child_row (model, iter, status, config_status, NULL);
479 set_as_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
482 enum MimStatus status;
484 MimConfigStatus *config_status = data;
486 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
489 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
490 if (status != MIM_STATUS_MODIFIED)
492 status = get_mim_status (lang, name);
493 update_child_row (model, iter, status, config_status, NULL);
497 static int initialized = 0;
500 destroy_cb (GtkWidget *widget, gpointer data)
507 /****************************************************/
508 /* Configuration of a specific variable or command. */
509 /****************************************************/
511 /* Common staffs to variable and command */
515 /* Data type name ("Value" or "Key bindings"). */
516 gchar *data_type_name;
517 MSymbol lang, name, item;
518 /* Fill in widgets in DIALOG for configuring a specific variable or
520 void (*setup_dialog) (GtkWidget *dialog, struct ConfigControl *control);
521 /* Update the contents of DATA widget. */
522 void (*update_data) (struct ConfigControl *control);
523 /* Convert PLIST to string. PLIST is a variable value or command
525 GString *(*data_string) (MPlist *plist);
526 /* minput_get_variable or minput_get_command. */
527 MPlist *(*get) (MSymbol, MSymbol, MSymbol);
528 /* minput_config_variable or minput_config_command. */
529 int (*config) (MSymbol, MSymbol, MSymbol, MPlist *);
530 /* If non-NULL, a function to call before finishing a dialog. */
531 gboolean (*config_on_ok) (struct ConfigControl *control);
533 /* Widget showing the current data (value or key bindings) */
536 /* Button widget to configure the data to the default. */
539 /* Button widget to cancel the configuration. */
542 /* Label widget showing the current status. */
546 struct CommandControl
548 struct ConfigControl control;
562 struct VariableControl
564 struct ConfigControl control;
566 /* type of current variable: Minteger, Msymbol, or Mtext */
570 enum WidgetType wtype;
573 #define CONFIG_CONTROL(control) ((struct ConfigControl *) (control))
574 #define COMMAND_CONTROL(control) ((struct CommandControl *) (control))
575 #define VARIABLE_CONTROL(control) ((struct VariableControl *) (control))
577 #define CURRENT_DATA \
582 (control->get (control->lang, control->name, control->item))))))
584 #define CURRENT_STATUS \
589 (control->get (control->lang, control->name, control->item))))))
591 #define CURRENT_DESCRIPTION \
596 (control->get (control->lang, control->name, control->item)))), \
597 NULL, NULL, NULL, NULL))
599 #define CONFIG_DATA(plist) \
600 control->config (control->lang, control->name, control->item, \
603 static MPlist *entry_keyseq;
606 update_status (struct ConfigControl *control)
608 MSymbol status = CURRENT_STATUS;
610 if (status == Mconfigured)
612 gtk_label_set_text (GTK_LABEL (control->status),
613 mim_status_str[MIM_STATUS_MODIFIED]);
614 gtk_widget_set_sensitive (control->default_, TRUE);
615 gtk_widget_set_sensitive (control->revert, TRUE);
617 else if (status == Mcustomized)
619 gtk_label_set_text (GTK_LABEL (control->status),
620 mim_status_str[MIM_STATUS_CUSTOMIZED]);
621 gtk_widget_set_sensitive (control->default_, TRUE);
622 gtk_widget_set_sensitive (control->revert, FALSE);
626 gtk_label_set_text (GTK_LABEL (control->status),
627 mim_status_str[MIM_STATUS_DEFAULT]);
628 gtk_widget_set_sensitive (control->default_, FALSE);
629 gtk_widget_set_sensitive (control->revert, FALSE);
634 help_cb (GtkButton *button, gpointer data)
636 struct ConfigControl *control = data;
639 msg = gtk_message_dialog_new (GTK_WINDOW
640 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
641 GTK_DIALOG_DESTROY_WITH_PARENT,
645 (gchar *) CURRENT_DESCRIPTION);
646 gtk_dialog_run (GTK_DIALOG (msg));
647 gtk_widget_destroy (msg);
651 default_cb (GtkButton *button, gpointer data)
653 MPlist *empty = mplist ();
654 struct ConfigControl *control = data;
657 m17n_object_unref (empty);
658 control->update_data (control);
659 update_status (control);
660 control->config_on_ok = NULL;
664 revert_cb (GtkButton *button, gpointer data)
666 struct ConfigControl *control = data;
669 control->update_data (control);
670 update_status (control);
671 control->config_on_ok = NULL;
675 ok_cb (GtkButton *button, gpointer data)
677 struct ConfigControl *control = data;
679 if (control->config_on_ok)
681 if (! control->config_on_ok (control))
683 revert_cb (NULL, control);
686 control->config_on_ok = NULL;
688 if (control->config == minput_config_command)
689 m17n_object_unref (entry_keyseq);
690 gtk_dialog_response (GTK_DIALOG
691 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
697 /* Variable or command name */
699 /* Status (default, modified, or customized). */
701 /* Variable value or command key bindings. */
703 /* Number of columns of list store. */
709 set_list_element (GtkListStore *store, GtkTreeIter *iter,
710 struct ConfigControl *control, MPlist *plist)
716 plist = mplist_value (control->get (control->lang, control->name,
718 plist = mplist_next (mplist_next (plist));
720 status = mplist_value (plist);
721 if (status == Mconfigured)
722 status_str = mim_status_str[MIM_STATUS_MODIFIED];
723 else if (status == Mcustomized)
724 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
726 status_str = mim_status_str[MIM_STATUS_DEFAULT];
727 plist = mplist_next (plist);
728 gtk_list_store_set (store, iter,
729 CONFIG_COL_ITEM, msymbol_name (control->item),
730 CONFIG_COL_STATUS, status_str,
731 CONFIG_COL_DATA, control->data_string (plist)->str,
735 /* Called when an item (command or variable) name is activated.
736 Create a dialog widget to config that itme. */
739 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
740 GtkTreeViewColumn *col, gpointer data)
744 GtkWidget *dialog, *label, *help, *hbox, *ok;
746 struct ConfigControl *control = CONFIG_CONTROL (data);
748 model = gtk_tree_view_get_model (parent);
749 if (! gtk_tree_model_get_iter (model, &iter, path))
751 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
752 control->item = msymbol (item);
754 dialog = (gtk_dialog_new_with_buttons
755 (msymbol_name (control->item),
756 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
757 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
759 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
761 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
763 hbox = gtk_hbox_new (FALSE, 12);
764 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
765 label = gtk_label_new (_("Status"));
766 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
767 label = gtk_label_new (": ");
768 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
769 control->status = gtk_label_new (NULL);
770 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
771 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
772 hbox, FALSE, FALSE, 0);
774 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
775 g_signal_connect (G_OBJECT (help), "clicked",
776 G_CALLBACK (help_cb), control);
777 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
778 help, FALSE, FALSE, 0);
779 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
780 g_signal_connect (G_OBJECT (ok), "clicked",
781 G_CALLBACK (ok_cb), control);
782 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
783 ok, FALSE, FALSE, 0);
785 control->setup_dialog (dialog, control);
787 update_status (control);
788 gtk_widget_show_all (dialog);
789 gtk_dialog_run (GTK_DIALOG (dialog));
790 gtk_tree_model_get_iter (model, &iter, path);
791 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
792 gtk_widget_destroy (dialog);
796 /* Create a list view widget listing variable or command names with
797 their current status and data. */
800 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
806 plist = control->get (lang, name, Mnil);
807 /* plist == ((command/variable description status data ...) ...) */
809 return gtk_label_new (_("No customizable item."));
810 store = gtk_list_store_new (NUM_CONFIG_COLS,
811 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
812 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
817 pl = mplist_value (plist);
818 /* pl == (command/variable description status data ...) */
819 control->item = mplist_value (pl);
820 gtk_list_store_append (store, &iter);
821 set_list_element (store, &iter, control, pl);
824 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
825 g_object_unref (G_OBJECT (store));
826 gtk_tree_view_insert_column_with_attributes
827 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
828 "text", CONFIG_COL_ITEM, NULL);
829 gtk_tree_view_insert_column_with_attributes
830 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
831 "text", CONFIG_COL_STATUS, NULL);
832 gtk_tree_view_insert_column_with_attributes
833 (GTK_TREE_VIEW (view), -1, control->data_type_name,
834 gtk_cell_renderer_text_new (),
835 "text", CONFIG_COL_DATA, NULL);
836 g_signal_connect (G_OBJECT (view), "row-activated",
837 G_CALLBACK (item_activated_cb), control);
842 static struct VariableControl var;
843 static struct CommandControl cmd;
846 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
848 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
850 var.control.lang = cmd.control.lang = lang;
851 var.control.name = cmd.control.name = name;
852 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
854 dialog = (gtk_dialog_new_with_buttons
855 (name == Mnil ? "global" : msymbol_name (name),
856 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
857 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
858 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
860 gtk_widget_set_size_request (dialog, 500, 300);
861 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
863 vbox = gtk_vbox_new (FALSE, 0);
864 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
865 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
867 notebook = gtk_notebook_new ();
868 gtk_container_add (GTK_CONTAINER (vbox), notebook);
870 /* Variables' page */
871 scrolled = gtk_scrolled_window_new (NULL, NULL);
872 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
873 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
874 label = gtk_label_new_with_mnemonic (_("_Variables"));
875 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
876 vbox = gtk_vbox_new (FALSE, 0);
877 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
879 gtk_box_pack_start (GTK_BOX (vbox),
880 create_item_list (lang, name, CONFIG_CONTROL (&var)),
883 /* Commands' pages */
884 scrolled = gtk_scrolled_window_new (NULL, NULL);
885 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
886 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
887 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
888 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
889 vbox = gtk_vbox_new (FALSE, 0);
890 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
892 gtk_box_pack_start (GTK_BOX (vbox),
893 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
896 gtk_widget_show_all (dialog);
897 gtk_dialog_run (GTK_DIALOG (dialog));
898 gtk_widget_destroy (dialog);
902 /* Staffs for variable configuration. */
905 variable_update_data (struct ConfigControl *control)
911 plist = CURRENT_DATA;
912 /* plist == (value [valid-value ...]) */
913 key = mplist_key (plist);
914 value = mplist_value (plist);
916 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
919 gtk_entry_set_text (GTK_ENTRY (control->data),
920 msymbol_name ((MSymbol) value));
921 else if (key == Mtext)
922 /* Fixme : Assuming the return value is in UTF-8 */
923 gtk_entry_set_text (GTK_ENTRY (control->data),
924 mtext_data ((MText *) value,
925 NULL, NULL, NULL, NULL));
926 else /* key == Minteger */
929 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
930 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
933 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
937 for (i = 0, plist = mplist_next (plist);
938 plist && mplist_key (plist) == key;
939 i++, plist = mplist_next (plist))
940 if (mplist_value (plist) == value)
942 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
944 else /* ci->wtype == SPIN_BUTTON_WIDGET */
945 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
946 (gdouble) (int) value);
950 config_with_entry (struct ConfigControl *control)
952 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
953 MPlist *plist = mplist ();
956 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
958 mplist_add (plist, Msymbol, msymbol (text));
961 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
965 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
966 mplist_add (plist, Mtext, mt);
968 m17n_object_unref (mt);
970 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
974 if (sscanf (text, "%d", &i) == 1)
976 mplist_add (plist, Minteger, (void *) i);
983 msg = gtk_message_dialog_new (GTK_WINDOW
984 (gtk_widget_get_toplevel (control->data)),
985 GTK_DIALOG_DESTROY_WITH_PARENT,
988 _("The value must be an integer."));
989 gtk_dialog_run (GTK_DIALOG (msg));
990 gtk_widget_destroy (msg);
995 m17n_object_unref (plist);
1000 config_with_combo (struct ConfigControl *control)
1002 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
1003 MPlist *plist = mplist ();
1005 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1007 mplist_add (plist, Msymbol, msymbol (text));
1008 CONFIG_DATA (plist);
1010 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1014 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
1015 mplist_add (plist, Mtext, mt);
1016 CONFIG_DATA (plist);
1017 m17n_object_unref (mt);
1019 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
1023 sscanf (text, "%d", &i);
1024 mplist_add (plist, Minteger, (void *) i);
1025 CONFIG_DATA (plist);
1027 m17n_object_unref (plist);
1032 config_with_spin (struct ConfigControl *control)
1034 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
1035 MPlist *plist = mplist ();
1037 mplist_add (plist, Minteger, (void *) i);
1038 CONFIG_DATA (plist);
1039 m17n_object_unref (plist);
1044 changed_cb (GtkEntry *entry, gpointer data)
1046 struct ConfigControl *control = data;
1048 gtk_widget_set_sensitive (control->default_, TRUE);
1049 gtk_widget_set_sensitive (control->revert, TRUE);
1050 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
1051 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
1052 control->config_on_ok = config_with_entry;
1053 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
1054 control->config_on_ok = config_with_combo;
1056 control->config_on_ok = config_with_spin;
1060 variable_data_string (MPlist *plist)
1062 static GString *str;
1065 str = g_string_sized_new (80);
1067 g_string_truncate (str, 0);
1069 if (mplist_key (plist) == Msymbol)
1070 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
1071 else if (mplist_key (plist) == Mtext)
1072 /* Fixme : Assuming the return value is in UTF-8 */
1073 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
1074 NULL, NULL, NULL, NULL));
1075 else /* mplist_key (plist) == Minteger */
1076 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1081 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1085 GtkWidget *hbox, *vbox;
1087 plist = CURRENT_DATA;
1088 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1089 value = mplist_value (plist);
1090 plist = mplist_next (plist);
1092 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1094 if (mplist_key (plist) == Msymbol)
1098 control->data = gtk_combo_box_new_text ();
1099 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1100 for (i = 0; mplist_key (plist) == Msymbol;
1101 plist = mplist_next (plist), i++)
1103 if (mplist_value (plist) == value)
1105 gtk_combo_box_append_text
1106 (GTK_COMBO_BOX (control->data),
1107 msymbol_name ((MSymbol) mplist_value (plist)));
1109 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1110 g_signal_connect (GTK_OBJECT (control->data), "changed",
1111 G_CALLBACK (changed_cb), control);
1115 control->data = gtk_entry_new ();
1116 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1117 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1118 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1119 g_signal_connect (GTK_OBJECT (control->data), "changed",
1120 G_CALLBACK (changed_cb), control);
1121 g_signal_connect (GTK_OBJECT (control->data), "activate",
1122 G_CALLBACK (ok_cb), control);
1125 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1127 if (plist && mplist_key (plist) == Mtext)
1131 control->data = gtk_combo_box_new_text ();
1132 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1133 for (i = 0; plist && mplist_key (plist) == Mtext;
1134 plist = mplist_next (plist), i++)
1136 if (! mtext_cmp ((MText *) mplist_value (plist),
1139 /* Fixme : Assuming the return value is in UTF-8 */
1140 gtk_combo_box_append_text
1141 (GTK_COMBO_BOX (control->data),
1142 mtext_data ((MText *) mplist_value (plist),
1143 NULL, NULL, NULL, NULL));
1145 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1146 g_signal_connect (GTK_OBJECT (control->data), "changed",
1147 G_CALLBACK (changed_cb), control);
1151 control->data = gtk_entry_new ();
1152 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1153 /* Fixme : Assuming the return value is in UTF-8 */
1154 gtk_entry_set_text (GTK_ENTRY (control->data),
1155 mtext_data (value, NULL, NULL, NULL, NULL));
1156 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1157 g_signal_connect (GTK_OBJECT (control->data), "changed",
1158 G_CALLBACK (changed_cb), control);
1159 g_signal_connect (GTK_OBJECT (control->data), "activate",
1160 G_CALLBACK (ok_cb), control);
1163 else /* control->vtype == Minteger */
1165 if (plist && mplist_key (plist) == Minteger)
1169 control->data = gtk_combo_box_new_text ();
1170 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1171 for (i = 0; plist && mplist_key (plist) == Minteger;
1172 plist = mplist_next (plist), i++)
1176 if (mplist_value (plist) == value)
1178 g_snprintf (buf, sizeof (buf), "%d",
1179 (gint) mplist_value (plist));
1180 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1182 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1183 g_signal_connect (GTK_OBJECT (control->data), "changed",
1184 G_CALLBACK (changed_cb), control);
1186 else if (plist && mplist_key (plist) == Mplist)
1189 gdouble lower, upper;
1191 plist = mplist_value (plist);
1192 lower = (gdouble) (int) mplist_value (plist);
1193 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1194 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1196 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1197 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1198 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1199 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1201 g_signal_connect (GTK_OBJECT (control->data), "changed",
1202 G_CALLBACK (changed_cb), control);
1208 control->data = gtk_entry_new ();
1209 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1210 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1211 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1212 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1213 g_signal_connect (GTK_OBJECT (control->data), "changed",
1214 G_CALLBACK (changed_cb), control);
1215 g_signal_connect (GTK_OBJECT (control->data), "activate",
1216 G_CALLBACK (ok_cb), control);
1220 control->default_ = gtk_button_new_from_stock (_("_Default"));
1221 g_signal_connect (G_OBJECT (control->default_), "clicked",
1222 G_CALLBACK (default_cb), control);
1224 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1225 g_signal_connect (G_OBJECT (control->revert), "clicked",
1226 G_CALLBACK (revert_cb), control);
1228 hbox = gtk_hbutton_box_new ();
1229 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1230 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1231 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1232 vbox = gtk_vbox_new (FALSE, 12);
1233 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1234 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1235 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1236 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1237 vbox, FALSE, FALSE, 0);
1238 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1242 /* Staffs for command configuration. */
1245 selection_cb (GtkTreeSelection *selection, gpointer data)
1247 gtk_widget_set_sensitive
1248 (COMMAND_CONTROL (data)->delete,
1249 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1253 delete_cb (GtkButton *button, gpointer data)
1255 GtkTreeSelection *selection;
1256 GtkTreeModel *model;
1259 struct ConfigControl *control = data;
1261 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1262 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1264 if (! gtk_tree_model_get_iter_first (model, &iter))
1268 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1270 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1271 mplist_add (new, Mplist, mplist_value (pl));
1272 gtk_tree_model_iter_next (model, &iter);
1275 m17n_object_unref (new);
1276 control->update_data (control);
1277 update_status (control);
1281 create_deleting_section (struct ConfigControl *control)
1283 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1284 GtkListStore *store;
1285 GtkWidget *label, *scrolled, *hbox, *vbox;
1286 GtkTreeViewColumn *column;
1287 GtkCellRenderer *renderer;
1288 GtkTreeSelection *selection;
1290 label = gtk_label_new (_("Current key bindings:"));
1292 store = gtk_list_store_new (1, G_TYPE_STRING);
1293 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1294 g_object_unref (G_OBJECT (store));
1295 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1296 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1297 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1298 g_signal_connect (G_OBJECT (selection), "changed",
1299 G_CALLBACK (selection_cb), control);
1301 scrolled = gtk_scrolled_window_new (NULL, NULL);
1302 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1303 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1304 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1307 column = gtk_tree_view_column_new ();
1308 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1309 renderer = gtk_cell_renderer_text_new ();
1310 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1311 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1313 control->update_data (control);
1315 control->default_ = gtk_button_new_from_stock (_("_Default"));
1316 g_signal_connect (G_OBJECT (control->default_), "clicked",
1317 G_CALLBACK (default_cb), control);
1319 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1320 g_signal_connect (G_OBJECT (control->revert), "clicked",
1321 G_CALLBACK (revert_cb), control);
1323 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1324 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1325 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1326 G_CALLBACK (delete_cb), control);
1328 vbox = gtk_vbox_new (FALSE, 12);
1329 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1331 hbox = gtk_hbox_new (FALSE, 6);
1332 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1333 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1335 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1337 hbox = gtk_hbutton_box_new ();
1338 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1339 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1340 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1341 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1342 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1343 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1348 static unsigned modifier_state = 0;
1352 ALT_MASK_BIT = META_MASK_BIT << 1,
1353 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1354 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1358 update_entry (GtkEntry *entry)
1360 if (mplist_key (entry_keyseq) == Mnil)
1361 gtk_entry_set_text (entry, "");
1367 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1368 gtk_entry_set_text (entry, name);
1369 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1370 p = mplist_next (p))
1372 name = msymbol_name ((MSymbol) mplist_value (p));
1373 gtk_entry_append_text (entry, " ");
1374 gtk_entry_append_text (entry, name);
1376 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1381 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1388 struct CommandControl *cmd_control = data;
1390 c = gdk_keyval_to_unicode (event->keyval);
1393 switch (event->keyval)
1395 case GDK_Meta_L: case GDK_Meta_R:
1396 modifier_state |= META_MASK_BIT; return TRUE;
1397 case GDK_Alt_L: case GDK_Alt_R:
1398 modifier_state |= ALT_MASK_BIT; return TRUE;
1399 case GDK_Super_L: case GDK_Super_R:
1400 modifier_state |= SUPER_MASK_BIT; return TRUE;
1401 case GDK_Hyper_L: case GDK_Hyper_R:
1402 modifier_state |= HYPER_MASK_BIT; return TRUE;
1404 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1407 name = gdk_keyval_name (event->keyval);
1410 nbytes = strlen (name);
1416 mtext_cat_char (mt, c);
1417 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1418 (unsigned char *) name, 32);
1419 m17n_object_unref (mt);
1422 if (c == 0 && event->state & GDK_SHIFT_MASK)
1423 buf[i++] = 'S', buf[i++] = '-';
1424 if (event->state & GDK_CONTROL_MASK)
1425 buf[i++] = 'C', buf[i++] = '-';
1426 if (modifier_state & META_MASK_BIT)
1427 buf[i++] = 'M', buf[i++] = '-';
1428 if (modifier_state & ALT_MASK_BIT)
1429 buf[i++] = 'A', buf[i++] = '-';
1430 if (modifier_state & SUPER_MASK_BIT)
1431 buf[i++] = 's', buf[i++] = '-';
1432 if (modifier_state & HYPER_MASK_BIT)
1433 buf[i++] = 'H', buf[i++] = '-';
1434 strncpy (buf + i, name, nbytes);
1435 buf[i + nbytes] = 0;
1436 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1437 update_entry (entry);
1438 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1439 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1444 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1448 c = gdk_keyval_to_unicode (event->keyval);
1451 switch (event->keyval)
1453 case GDK_Meta_L: case GDK_Meta_R:
1454 modifier_state &= ~META_MASK_BIT; break;
1455 case GDK_Alt_L: case GDK_Alt_R:
1456 modifier_state &= ~ALT_MASK_BIT; break;
1457 case GDK_Super_L: case GDK_Super_R:
1458 modifier_state &= ~SUPER_MASK_BIT; break;
1459 case GDK_Hyper_L: case GDK_Hyper_R:
1460 modifier_state &= ~HYPER_MASK_BIT; break;
1467 clear_cb (GtkButton *button, gpointer data)
1469 struct CommandControl *cmd_control = data;
1471 mplist_set (entry_keyseq, Mnil, NULL);
1472 gtk_widget_grab_focus (cmd_control->entry);
1473 update_entry (GTK_ENTRY (cmd_control->entry));
1474 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1475 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1479 add_cb (GtkButton *button, gpointer data)
1482 GtkTreeModel *model;
1484 struct ConfigControl *control = data;
1486 if (mplist_length (entry_keyseq) == 0)
1488 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1489 if (gtk_tree_model_get_iter_first (model, &iter))
1491 gchar *keyseq = control->data_string (entry_keyseq)->str;
1495 gtk_tree_model_get (model, &iter, 0, &str, -1);
1496 if (strcmp (keyseq, str) == 0)
1497 /* entry_keyseq is already registered. */
1499 } while (gtk_tree_model_iter_next (model, &iter));
1501 new = mplist_copy (CURRENT_DATA);
1502 mplist_add (new, Mplist, entry_keyseq);
1504 m17n_object_unref (new);
1505 control->update_data (control);
1506 update_status (control);
1507 clear_cb (NULL, control);
1511 create_adding_section (struct ConfigControl *control)
1513 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1514 GtkWidget *label, *hbox, *vbox;
1516 label = gtk_label_new (_("New key binding:"));
1518 entry_keyseq = mplist ();
1519 cmd_control->entry = gtk_entry_new ();
1520 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1521 G_CALLBACK (key_pressed_cb), cmd_control);
1522 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1523 G_CALLBACK (key_released_cb), cmd_control);
1525 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1526 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1527 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1528 G_CALLBACK (clear_cb), cmd_control);
1530 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1531 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1532 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1533 G_CALLBACK (add_cb), cmd_control);
1535 vbox = gtk_vbox_new (FALSE, 12);
1536 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1538 hbox = gtk_hbox_new (FALSE, 6);
1539 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1540 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1542 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1544 hbox = gtk_hbutton_box_new ();
1545 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1546 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1547 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1548 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1549 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1555 append_key_sequence (GString *str, MPlist *keyseq)
1557 static MSymbol space_symbol;
1561 space_symbol = msymbol (" ");
1563 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1565 MSymbol key = (MSymbol) mplist_value (p);
1568 g_string_append_c (str, ' ');
1569 if (key == space_symbol)
1570 g_string_append (str, "Space");
1572 g_string_append (str, msymbol_name (key));
1577 command_data_string (MPlist *plist)
1579 static GString *str;
1582 str = g_string_sized_new (80);
1584 g_string_truncate (str, 0);
1586 if (mplist_key (plist) == Mplist)
1590 /* PLIST == ((KEY KEY ...) ...) */
1591 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1594 g_string_append (str, ", ");
1595 append_key_sequence (str, mplist_value (pl));
1600 /* PLIST == (KEY KEY ...) */
1601 append_key_sequence (str, plist);
1607 command_update_data (struct ConfigControl *control)
1609 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1610 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1614 gtk_list_store_clear (store);
1615 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1617 gtk_list_store_append (store, &iter);
1618 gtk_list_store_set (store, &iter,
1619 0, control->data_string (mplist_value (pl))->str,
1625 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1627 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1628 create_deleting_section (control), FALSE, FALSE, 0);
1629 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1630 create_adding_section (control), FALSE, FALSE, 0);
1631 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1638 mim_config_new (GCallback func, gpointer data)
1640 GtkWidget *tree, *config;
1641 GtkTreeStore *store;
1642 GtkCellRenderer *renderer;
1643 GtkTreeViewColumn *column;
1648 if (merror_code < 0)
1654 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1655 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1658 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1659 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1660 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1661 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1663 var.control.data_type_name = _("Value");
1664 var.control.setup_dialog = variable_setup_dialog;
1665 var.control.update_data = variable_update_data;
1666 var.control.data_string = variable_data_string;
1667 var.control.get = minput_get_variable;
1668 var.control.config = minput_config_variable;
1670 cmd.control.data_type_name = _("Key Bindings");
1671 cmd.control.setup_dialog = command_setup_dialog;
1672 cmd.control.update_data = command_update_data;
1673 cmd.control.data_string = command_data_string;
1674 cmd.control.get = minput_get_command;
1675 cmd.control.config = minput_config_command;
1677 store = make_store_for_input_methods ();
1678 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1679 g_object_unref (G_OBJECT (store));
1681 renderer = gtk_cell_renderer_text_new ();
1682 column = (gtk_tree_view_column_new_with_attributes
1683 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1684 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1686 renderer = gtk_cell_renderer_text_new ();
1687 column = (gtk_tree_view_column_new_with_attributes
1688 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1689 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1691 g_signal_connect (G_OBJECT (tree), "row-expanded",
1692 G_CALLBACK (tree_expanded_cb), NULL);
1693 g_signal_connect (G_OBJECT (tree), "row-activated",
1694 G_CALLBACK (tree_activated_cb), NULL);
1696 config =gtk_scrolled_window_new (NULL, NULL);
1697 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1698 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1699 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1700 g_signal_connect (G_OBJECT (config), "destroy",
1701 G_CALLBACK (destroy_cb), NULL);
1703 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1706 MimConfigCallback *callback;
1708 callback = g_new (MimConfigCallback, 1);
1709 callback->widget = config;
1710 callback->func = (MimConfigCallbackFunc) func;
1711 callback->data = data;
1712 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1720 mim_config_modified (GtkWidget *config)
1723 GtkTreeModel *model;
1724 MimConfigStatus *config_status;
1726 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1727 model = gtk_tree_view_get_model (tree);
1728 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1730 return (config_status->num_modified > 0 ? TRUE : FALSE);
1734 mim_config_default (GtkWidget *config)
1737 GtkTreeModel *model;
1738 MimConfigStatus *config_status;
1740 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1741 model = gtk_tree_view_get_model (tree);
1742 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1743 gtk_tree_model_foreach (model, reset_to_default, config_status);
1748 mim_config_revert (GtkWidget *config)
1751 GtkTreeModel *model;
1752 MimConfigStatus *config_status;
1754 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1755 model = gtk_tree_view_get_model (tree);
1756 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1758 if (config_status->num_modified == 0)
1760 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1765 mim_config_save (GtkWidget *config)
1768 GtkTreeModel *model;
1769 MimConfigStatus *config_status;
1771 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1772 model = gtk_tree_view_get_model (tree);
1773 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1775 if (config_status->num_modified == 0)
1777 minput_save_config ();
1778 gtk_tree_model_foreach (model, set_as_saved, config_status);
1783 mim_config_get_tree_view (GtkWidget *config)
1787 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);