1 /* mim-config.c -- M17N input method configuration
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 revert_to_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
438 enum MimStatus status;
440 MimConfigStatus *config_status = data;
442 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
445 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
446 if (status != MIM_STATUS_MODIFIED)
448 minput_config_variable (lang, name, Mnil, NULL);
449 minput_config_command (lang, name, Mnil, NULL);
450 status = get_mim_status (lang, name);
451 update_child_row (model, iter, status, config_status, NULL);
456 set_as_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
459 enum MimStatus status;
461 MimConfigStatus *config_status = data;
463 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
466 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
467 if (status != MIM_STATUS_MODIFIED)
469 status = get_mim_status (lang, name);
470 update_child_row (model, iter, status, config_status, NULL);
475 reset_to_default (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
478 enum MimStatus status, new_status;
480 MimConfigStatus *config_status = data;
481 MPlist *empty = mplist ();
483 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
486 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
487 if (status == MIM_STATUS_DEFAULT)
489 minput_config_variable (lang, name, Mnil, empty);
490 minput_config_command (lang, name, Mnil, empty);
491 new_status = get_mim_status (lang, name);
492 if (status != new_status)
493 update_child_row (model, iter, new_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,
644 CURRENT_DESCRIPTION);
645 gtk_dialog_run (GTK_DIALOG (msg));
646 gtk_widget_destroy (msg);
650 default_cb (GtkButton *button, gpointer data)
652 MPlist *empty = mplist ();
653 struct ConfigControl *control = data;
656 m17n_object_unref (empty);
657 control->update_data (control);
658 update_status (control);
659 control->config_on_ok = NULL;
663 revert_cb (GtkButton *button, gpointer data)
665 struct ConfigControl *control = data;
668 control->update_data (control);
669 update_status (control);
670 control->config_on_ok = NULL;
674 ok_cb (GtkButton *button, gpointer data)
676 struct ConfigControl *control = data;
678 if (control->config_on_ok)
680 if (! control->config_on_ok (control))
682 revert_cb (NULL, control);
685 control->config_on_ok = NULL;
687 if (control->config == minput_config_command)
688 m17n_object_unref (entry_keyseq);
689 gtk_dialog_response (GTK_DIALOG
690 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
696 /* Variable or command name */
698 /* Status (default, modified, or customized). */
700 /* Variable value or command key bindings. */
702 /* Number of columns of list store. */
708 set_list_element (GtkListStore *store, GtkTreeIter *iter,
709 struct ConfigControl *control, MPlist *plist)
715 plist = mplist_value (control->get (control->lang, control->name,
717 plist = mplist_next (mplist_next (plist));
719 status = mplist_value (plist);
720 if (status == Mconfigured)
721 status_str = mim_status_str[MIM_STATUS_MODIFIED];
722 else if (status == Mcustomized)
723 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
725 status_str = mim_status_str[MIM_STATUS_DEFAULT];
726 plist = mplist_next (plist);
727 gtk_list_store_set (store, iter,
728 CONFIG_COL_ITEM, msymbol_name (control->item),
729 CONFIG_COL_STATUS, status_str,
730 CONFIG_COL_DATA, control->data_string (plist)->str,
734 /* Called when an item (command or variable) name is activated.
735 Create a dialog widget to config that itme. */
738 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
739 GtkTreeViewColumn *col, gpointer data)
743 GtkWidget *dialog, *label, *help, *hbox, *ok;
745 struct ConfigControl *control = CONFIG_CONTROL (data);
747 model = gtk_tree_view_get_model (parent);
748 if (! gtk_tree_model_get_iter (model, &iter, path))
750 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
751 control->item = msymbol (item);
753 dialog = (gtk_dialog_new_with_buttons
754 (msymbol_name (control->item),
755 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
756 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
758 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
760 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
762 hbox = gtk_hbox_new (FALSE, 12);
763 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
764 label = gtk_label_new (_("Status"));
765 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
766 label = gtk_label_new (": ");
767 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
768 control->status = gtk_label_new (NULL);
769 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
770 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
771 hbox, FALSE, FALSE, 0);
773 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
774 g_signal_connect (G_OBJECT (help), "clicked",
775 G_CALLBACK (help_cb), control);
776 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
777 help, FALSE, FALSE, 0);
778 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
779 g_signal_connect (G_OBJECT (ok), "clicked",
780 G_CALLBACK (ok_cb), control);
781 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
782 ok, FALSE, FALSE, 0);
784 control->setup_dialog (dialog, control);
786 update_status (control);
787 gtk_widget_show_all (dialog);
788 gtk_dialog_run (GTK_DIALOG (dialog));
789 gtk_tree_model_get_iter (model, &iter, path);
790 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
791 gtk_widget_destroy (dialog);
795 /* Create a list view widget listing variable or command names with
796 their current status and data. */
799 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
805 plist = control->get (lang, name, Mnil);
806 /* plist == ((command/variable description status data ...) ...) */
808 return gtk_label_new (_("No customizable item."));
809 store = gtk_list_store_new (NUM_CONFIG_COLS,
810 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
811 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
816 pl = mplist_value (plist);
817 /* pl == (command/variable description status data ...) */
818 control->item = mplist_value (pl);
819 gtk_list_store_append (store, &iter);
820 set_list_element (store, &iter, control, pl);
823 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
824 g_object_unref (G_OBJECT (store));
825 gtk_tree_view_insert_column_with_attributes
826 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
827 "text", CONFIG_COL_ITEM, NULL);
828 gtk_tree_view_insert_column_with_attributes
829 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
830 "text", CONFIG_COL_STATUS, NULL);
831 gtk_tree_view_insert_column_with_attributes
832 (GTK_TREE_VIEW (view), -1, control->data_type_name,
833 gtk_cell_renderer_text_new (),
834 "text", CONFIG_COL_DATA, NULL);
835 g_signal_connect (G_OBJECT (view), "row-activated",
836 G_CALLBACK (item_activated_cb), control);
841 static struct VariableControl var;
842 static struct CommandControl cmd;
845 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
847 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
849 var.control.lang = cmd.control.lang = lang;
850 var.control.name = cmd.control.name = name;
851 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
853 dialog = (gtk_dialog_new_with_buttons
854 (name == Mnil ? "global" : msymbol_name (name),
855 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
856 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
857 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
859 gtk_widget_set_size_request (dialog, 500, 300);
860 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
862 vbox = gtk_vbox_new (FALSE, 0);
863 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
864 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
866 notebook = gtk_notebook_new ();
867 gtk_container_add (GTK_CONTAINER (vbox), notebook);
869 /* Variables' page */
870 scrolled = gtk_scrolled_window_new (NULL, NULL);
871 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
872 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
873 label = gtk_label_new_with_mnemonic (_("_Variables"));
874 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
875 vbox = gtk_vbox_new (FALSE, 0);
876 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
878 gtk_box_pack_start (GTK_BOX (vbox),
879 create_item_list (lang, name, CONFIG_CONTROL (&var)),
882 /* Commands' pages */
883 scrolled = gtk_scrolled_window_new (NULL, NULL);
884 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
885 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
886 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
887 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
888 vbox = gtk_vbox_new (FALSE, 0);
889 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
891 gtk_box_pack_start (GTK_BOX (vbox),
892 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
895 gtk_widget_show_all (dialog);
896 gtk_dialog_run (GTK_DIALOG (dialog));
897 gtk_widget_destroy (dialog);
901 /* Staffs for variable configuration. */
904 variable_update_data (struct ConfigControl *control)
910 plist = CURRENT_DATA;
911 /* plist == (value [valid-value ...]) */
912 key = mplist_key (plist);
913 value = mplist_value (plist);
915 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
918 gtk_entry_set_text (GTK_ENTRY (control->data),
919 msymbol_name ((MSymbol) value));
920 else if (key == Mtext)
921 /* Fixme : Assuming the return value is in UTF-8 */
922 gtk_entry_set_text (GTK_ENTRY (control->data),
923 mtext_data ((MText *) value,
924 NULL, NULL, NULL, NULL));
925 else /* key == Minteger */
928 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
929 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
932 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
936 for (i = 0, plist = mplist_next (plist);
937 plist && mplist_key (plist) == key;
938 i++, plist = mplist_next (plist))
939 if (mplist_value (plist) == value)
941 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
943 else /* ci->wtype == SPIN_BUTTON_WIDGET */
944 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
945 (gdouble) (int) value);
949 config_with_entry (struct ConfigControl *control)
951 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
952 MPlist *plist = mplist ();
955 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
957 mplist_add (plist, Msymbol, msymbol (text));
960 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
964 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
965 mplist_add (plist, Mtext, mt);
967 m17n_object_unref (mt);
969 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
973 if (sscanf (text, "%d", &i) == 1)
975 mplist_add (plist, Minteger, (void *) i);
982 msg = gtk_message_dialog_new (GTK_WINDOW
983 (gtk_widget_get_toplevel (control->data)),
984 GTK_DIALOG_DESTROY_WITH_PARENT,
987 _("The value must be an integer."));
988 gtk_dialog_run (GTK_DIALOG (msg));
989 gtk_widget_destroy (msg);
994 m17n_object_unref (plist);
999 config_with_combo (struct ConfigControl *control)
1001 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
1002 MPlist *plist = mplist ();
1004 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1006 mplist_add (plist, Msymbol, msymbol (text));
1007 CONFIG_DATA (plist);
1009 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1013 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
1014 mplist_add (plist, Mtext, mt);
1015 CONFIG_DATA (plist);
1016 m17n_object_unref (mt);
1018 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
1022 sscanf (text, "%d", &i);
1023 mplist_add (plist, Minteger, (void *) i);
1024 CONFIG_DATA (plist);
1026 m17n_object_unref (plist);
1031 config_with_spin (struct ConfigControl *control)
1033 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
1034 MPlist *plist = mplist ();
1036 mplist_add (plist, Minteger, (void *) i);
1037 CONFIG_DATA (plist);
1038 m17n_object_unref (plist);
1043 changed_cb (GtkEntry *entry, gpointer data)
1045 struct ConfigControl *control = data;
1047 gtk_widget_set_sensitive (control->default_, TRUE);
1048 gtk_widget_set_sensitive (control->revert, TRUE);
1049 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
1050 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
1051 control->config_on_ok = config_with_entry;
1052 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
1053 control->config_on_ok = config_with_combo;
1055 control->config_on_ok = config_with_spin;
1059 variable_data_string (MPlist *plist)
1061 static GString *str;
1064 str = g_string_sized_new (80);
1066 g_string_truncate (str, 0);
1068 if (mplist_key (plist) == Msymbol)
1069 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
1070 else if (mplist_key (plist) == Mtext)
1071 /* Fixme : Assuming the return value is in UTF-8 */
1072 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
1073 NULL, NULL, NULL, NULL));
1074 else /* mplist_key (plist) == Minteger */
1075 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1080 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1084 GtkWidget *hbox, *vbox;
1086 plist = CURRENT_DATA;
1087 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1088 value = mplist_value (plist);
1089 plist = mplist_next (plist);
1091 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1093 if (mplist_key (plist) == Msymbol)
1097 control->data = gtk_combo_box_new_text ();
1098 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1099 for (i = 0; mplist_key (plist) == Msymbol;
1100 plist = mplist_next (plist), i++)
1102 if (mplist_value (plist) == value)
1104 gtk_combo_box_append_text
1105 (GTK_COMBO_BOX (control->data),
1106 msymbol_name ((MSymbol) mplist_value (plist)));
1108 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1109 g_signal_connect (GTK_OBJECT (control->data), "changed",
1110 G_CALLBACK (changed_cb), control);
1114 control->data = gtk_entry_new ();
1115 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1116 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1117 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1118 g_signal_connect (GTK_OBJECT (control->data), "changed",
1119 G_CALLBACK (changed_cb), control);
1120 g_signal_connect (GTK_OBJECT (control->data), "activate",
1121 G_CALLBACK (ok_cb), control);
1124 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1126 if (plist && mplist_key (plist) == Mtext)
1130 control->data = gtk_combo_box_new_text ();
1131 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1132 for (i = 0; plist && mplist_key (plist) == Mtext;
1133 plist = mplist_next (plist), i++)
1135 if (! mtext_cmp ((MText *) mplist_value (plist),
1138 /* Fixme : Assuming the return value is in UTF-8 */
1139 gtk_combo_box_append_text
1140 (GTK_COMBO_BOX (control->data),
1141 mtext_data ((MText *) mplist_value (plist),
1142 NULL, NULL, NULL, NULL));
1144 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1145 g_signal_connect (GTK_OBJECT (control->data), "changed",
1146 G_CALLBACK (changed_cb), control);
1150 control->data = gtk_entry_new ();
1151 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1152 /* Fixme : Assuming the return value is in UTF-8 */
1153 gtk_entry_set_text (GTK_ENTRY (control->data),
1154 mtext_data (value, NULL, NULL, NULL, NULL));
1155 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1156 g_signal_connect (GTK_OBJECT (control->data), "changed",
1157 G_CALLBACK (changed_cb), control);
1158 g_signal_connect (GTK_OBJECT (control->data), "activate",
1159 G_CALLBACK (ok_cb), control);
1162 else /* control->vtype == Minteger */
1164 if (plist && mplist_key (plist) == Minteger)
1168 control->data = gtk_combo_box_new_text ();
1169 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1170 for (i = 0; plist && mplist_key (plist) == Minteger;
1171 plist = mplist_next (plist), i++)
1175 if (mplist_value (plist) == value)
1177 g_snprintf (buf, sizeof (buf), "%d",
1178 (gint) mplist_value (plist));
1179 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1181 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1182 g_signal_connect (GTK_OBJECT (control->data), "changed",
1183 G_CALLBACK (changed_cb), control);
1185 else if (plist && mplist_key (plist) == Mplist)
1188 gdouble lower, upper;
1190 plist = mplist_value (plist);
1191 lower = (gdouble) (int) mplist_value (plist);
1192 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1193 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1195 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1196 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1197 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1198 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1200 g_signal_connect (GTK_OBJECT (control->data), "changed",
1201 G_CALLBACK (changed_cb), control);
1207 control->data = gtk_entry_new ();
1208 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1209 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1210 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1211 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1212 g_signal_connect (GTK_OBJECT (control->data), "changed",
1213 G_CALLBACK (changed_cb), control);
1214 g_signal_connect (GTK_OBJECT (control->data), "activate",
1215 G_CALLBACK (ok_cb), control);
1219 control->default_ = gtk_button_new_from_stock (_("_Default"));
1220 g_signal_connect (G_OBJECT (control->default_), "clicked",
1221 G_CALLBACK (default_cb), control);
1223 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1224 g_signal_connect (G_OBJECT (control->revert), "clicked",
1225 G_CALLBACK (revert_cb), control);
1227 hbox = gtk_hbutton_box_new ();
1228 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1229 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1230 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1231 vbox = gtk_vbox_new (FALSE, 12);
1232 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1233 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1234 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1235 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1236 vbox, FALSE, FALSE, 0);
1237 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1241 /* Staffs for command configuration. */
1244 selection_cb (GtkTreeSelection *selection, gpointer data)
1246 gtk_widget_set_sensitive
1247 (COMMAND_CONTROL (data)->delete,
1248 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1252 delete_cb (GtkButton *button, gpointer data)
1254 GtkTreeSelection *selection;
1255 GtkTreeModel *model;
1258 struct ConfigControl *control = data;
1260 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1261 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1263 if (! gtk_tree_model_get_iter_first (model, &iter))
1267 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1269 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1270 mplist_add (new, Mplist, mplist_value (pl));
1271 gtk_tree_model_iter_next (model, &iter);
1274 m17n_object_unref (new);
1275 control->update_data (control);
1276 update_status (control);
1280 create_deleting_section (struct ConfigControl *control)
1282 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1283 GtkListStore *store;
1284 GtkWidget *label, *scrolled, *hbox, *vbox;
1285 GtkTreeViewColumn *column;
1286 GtkCellRenderer *renderer;
1287 GtkTreeSelection *selection;
1289 label = gtk_label_new (_("Current key bindings:"));
1291 store = gtk_list_store_new (1, G_TYPE_STRING);
1292 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1293 g_object_unref (G_OBJECT (store));
1294 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1295 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1296 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1297 g_signal_connect (G_OBJECT (selection), "changed",
1298 G_CALLBACK (selection_cb), control);
1300 scrolled = gtk_scrolled_window_new (NULL, NULL);
1301 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1302 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1303 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1306 column = gtk_tree_view_column_new ();
1307 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1308 renderer = gtk_cell_renderer_text_new ();
1309 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1310 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1312 control->update_data (control);
1314 control->default_ = gtk_button_new_from_stock (_("_Default"));
1315 g_signal_connect (G_OBJECT (control->default_), "clicked",
1316 G_CALLBACK (default_cb), control);
1318 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1319 g_signal_connect (G_OBJECT (control->revert), "clicked",
1320 G_CALLBACK (revert_cb), control);
1322 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1323 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1324 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1325 G_CALLBACK (delete_cb), control);
1327 vbox = gtk_vbox_new (FALSE, 12);
1328 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1330 hbox = gtk_hbox_new (FALSE, 6);
1331 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1332 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1334 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1336 hbox = gtk_hbutton_box_new ();
1337 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1338 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1339 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1340 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1341 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1342 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1347 static unsigned modifier_state = 0;
1351 ALT_MASK_BIT = META_MASK_BIT << 1,
1352 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1353 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1357 update_entry (GtkEntry *entry)
1359 if (mplist_key (entry_keyseq) == Mnil)
1360 gtk_entry_set_text (entry, "");
1366 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1367 gtk_entry_set_text (entry, name);
1368 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1369 p = mplist_next (p))
1371 name = msymbol_name ((MSymbol) mplist_value (p));
1372 gtk_entry_append_text (entry, " ");
1373 gtk_entry_append_text (entry, name);
1375 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1380 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1387 struct CommandControl *cmd_control = data;
1389 c = gdk_keyval_to_unicode (event->keyval);
1392 switch (event->keyval)
1394 case GDK_Meta_L: case GDK_Meta_R:
1395 modifier_state |= META_MASK_BIT; return TRUE;
1396 case GDK_Alt_L: case GDK_Alt_R:
1397 modifier_state |= ALT_MASK_BIT; return TRUE;
1398 case GDK_Super_L: case GDK_Super_R:
1399 modifier_state |= SUPER_MASK_BIT; return TRUE;
1400 case GDK_Hyper_L: case GDK_Hyper_R:
1401 modifier_state |= HYPER_MASK_BIT; return TRUE;
1403 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1406 name = gdk_keyval_name (event->keyval);
1409 nbytes = strlen (name);
1415 mtext_cat_char (mt, c);
1416 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1417 (unsigned char *) name, 32);
1418 m17n_object_unref (mt);
1421 if (c == 0 && event->state & GDK_SHIFT_MASK)
1422 buf[i++] = 'S', buf[i++] = '-';
1423 if (event->state & GDK_CONTROL_MASK)
1424 buf[i++] = 'C', buf[i++] = '-';
1425 if (modifier_state & META_MASK_BIT)
1426 buf[i++] = 'M', buf[i++] = '-';
1427 if (modifier_state & ALT_MASK_BIT)
1428 buf[i++] = 'A', buf[i++] = '-';
1429 if (modifier_state & SUPER_MASK_BIT)
1430 buf[i++] = 's', buf[i++] = '-';
1431 if (modifier_state & HYPER_MASK_BIT)
1432 buf[i++] = 'H', buf[i++] = '-';
1433 strncpy (buf + i, name, nbytes);
1434 buf[i + nbytes] = 0;
1435 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1436 update_entry (entry);
1437 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1438 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1443 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1447 c = gdk_keyval_to_unicode (event->keyval);
1450 switch (event->keyval)
1452 case GDK_Meta_L: case GDK_Meta_R:
1453 modifier_state &= ~META_MASK_BIT; break;
1454 case GDK_Alt_L: case GDK_Alt_R:
1455 modifier_state &= ~ALT_MASK_BIT; break;
1456 case GDK_Super_L: case GDK_Super_R:
1457 modifier_state &= ~SUPER_MASK_BIT; break;
1458 case GDK_Hyper_L: case GDK_Hyper_R:
1459 modifier_state &= ~HYPER_MASK_BIT; break;
1466 clear_cb (GtkButton *button, gpointer data)
1468 struct CommandControl *cmd_control = data;
1470 mplist_set (entry_keyseq, Mnil, NULL);
1471 gtk_widget_grab_focus (cmd_control->entry);
1472 update_entry (GTK_ENTRY (cmd_control->entry));
1473 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1474 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1478 add_cb (GtkButton *button, gpointer data)
1481 GtkTreeModel *model;
1483 struct ConfigControl *control = data;
1485 if (mplist_length (entry_keyseq) == 0)
1487 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1488 if (gtk_tree_model_get_iter_first (model, &iter))
1490 gchar *keyseq = control->data_string (entry_keyseq)->str;
1494 gtk_tree_model_get (model, &iter, 0, &str, -1);
1495 if (strcmp (keyseq, str) == 0)
1496 /* entry_keyseq is already registered. */
1498 } while (gtk_tree_model_iter_next (model, &iter));
1500 new = mplist_copy (CURRENT_DATA);
1501 mplist_add (new, Mplist, entry_keyseq);
1503 m17n_object_unref (new);
1504 control->update_data (control);
1505 update_status (control);
1506 clear_cb (NULL, control);
1510 create_adding_section (struct ConfigControl *control)
1512 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1513 GtkWidget *label, *hbox, *vbox;
1515 label = gtk_label_new (_("New key binding:"));
1517 entry_keyseq = mplist ();
1518 cmd_control->entry = gtk_entry_new ();
1519 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1520 G_CALLBACK (key_pressed_cb), cmd_control);
1521 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1522 G_CALLBACK (key_released_cb), cmd_control);
1524 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1525 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1526 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1527 G_CALLBACK (clear_cb), cmd_control);
1529 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1530 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1531 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1532 G_CALLBACK (add_cb), cmd_control);
1534 vbox = gtk_vbox_new (FALSE, 12);
1535 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1537 hbox = gtk_hbox_new (FALSE, 6);
1538 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1539 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1541 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1543 hbox = gtk_hbutton_box_new ();
1544 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1545 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1546 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1547 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1548 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1554 append_key_sequence (GString *str, MPlist *keyseq)
1556 static MSymbol space_symbol;
1560 space_symbol = msymbol (" ");
1562 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1564 MSymbol key = (MSymbol) mplist_value (p);
1567 g_string_append_c (str, ' ');
1568 if (key == space_symbol)
1569 g_string_append (str, "Space");
1571 g_string_append (str, msymbol_name (key));
1576 command_data_string (MPlist *plist)
1578 static GString *str;
1581 str = g_string_sized_new (80);
1583 g_string_truncate (str, 0);
1585 if (mplist_key (plist) == Mplist)
1589 /* PLIST == ((KEY KEY ...) ...) */
1590 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1593 g_string_append (str, ", ");
1594 append_key_sequence (str, mplist_value (pl));
1599 /* PLIST == (KEY KEY ...) */
1600 append_key_sequence (str, plist);
1606 command_update_data (struct ConfigControl *control)
1608 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1609 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1613 gtk_list_store_clear (store);
1614 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1616 gtk_list_store_append (store, &iter);
1617 gtk_list_store_set (store, &iter,
1618 0, control->data_string (mplist_value (pl))->str,
1624 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1626 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1627 create_deleting_section (control), FALSE, FALSE, 0);
1628 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1629 create_adding_section (control), FALSE, FALSE, 0);
1630 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1637 mim_config_new (GCallback func, gpointer data)
1639 GtkWidget *tree, *config;
1640 GtkTreeStore *store;
1641 GtkCellRenderer *renderer;
1642 GtkTreeViewColumn *column;
1647 if (merror_code < 0)
1653 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1654 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1657 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1658 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1659 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1660 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1662 var.control.data_type_name = _("Value");
1663 var.control.setup_dialog = variable_setup_dialog;
1664 var.control.update_data = variable_update_data;
1665 var.control.data_string = variable_data_string;
1666 var.control.get = minput_get_variable;
1667 var.control.config = minput_config_variable;
1669 cmd.control.data_type_name = _("Key Bindings");
1670 cmd.control.setup_dialog = command_setup_dialog;
1671 cmd.control.update_data = command_update_data;
1672 cmd.control.data_string = command_data_string;
1673 cmd.control.get = minput_get_command;
1674 cmd.control.config = minput_config_command;
1676 store = make_store_for_input_methods ();
1677 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1678 g_object_unref (G_OBJECT (store));
1680 renderer = gtk_cell_renderer_text_new ();
1681 column = (gtk_tree_view_column_new_with_attributes
1682 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1683 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1685 renderer = gtk_cell_renderer_text_new ();
1686 column = (gtk_tree_view_column_new_with_attributes
1687 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1688 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1690 g_signal_connect (G_OBJECT (tree), "row-expanded",
1691 G_CALLBACK (tree_expanded_cb), NULL);
1692 g_signal_connect (G_OBJECT (tree), "row-activated",
1693 G_CALLBACK (tree_activated_cb), NULL);
1695 config =gtk_scrolled_window_new (NULL, NULL);
1696 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1697 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1698 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1699 g_signal_connect (G_OBJECT (config), "destroy",
1700 G_CALLBACK (destroy_cb), NULL);
1702 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1705 MimConfigCallback *callback;
1707 callback = g_new (MimConfigCallback, 1);
1708 callback->widget = config;
1709 callback->func = (MimConfigCallbackFunc) func;
1710 callback->data = data;
1711 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1719 mim_config_modified (GtkWidget *config)
1722 GtkTreeModel *model;
1723 MimConfigStatus *config_status;
1725 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1726 model = gtk_tree_view_get_model (tree);
1727 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1729 return (config_status->num_modified > 0 ? TRUE : FALSE);
1733 mim_config_default (GtkWidget *config)
1736 GtkTreeModel *model;
1737 MimConfigStatus *config_status;
1739 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1740 model = gtk_tree_view_get_model (tree);
1741 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1742 gtk_tree_model_foreach (model, reset_to_default, config_status);
1747 mim_config_revert (GtkWidget *config)
1750 GtkTreeModel *model;
1751 MimConfigStatus *config_status;
1753 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1754 model = gtk_tree_view_get_model (tree);
1755 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1757 if (config_status->num_modified == 0)
1759 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1764 mim_config_save (GtkWidget *config)
1767 GtkTreeModel *model;
1768 MimConfigStatus *config_status;
1770 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1771 model = gtk_tree_view_get_model (tree);
1772 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1774 if (config_status->num_modified == 0)
1776 minput_save_config ();
1777 gtk_tree_model_foreach (model, set_as_saved, config_status);
1782 mim_config_get_tree_view (GtkWidget *config)
1786 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);