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;
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 status = get_mim_status (lang, name);
492 update_child_row (model, iter, status, config_status, NULL);
496 static int initialized = 0;
499 destroy_cb (GtkWidget *widget, gpointer data)
506 /****************************************************/
507 /* Configuration of a specific variable or command. */
508 /****************************************************/
510 /* Common staffs to variable and command */
514 /* Data type name ("Value" or "Key bindings"). */
515 gchar *data_type_name;
516 MSymbol lang, name, item;
517 /* Fill in widgets in DIALOG for configuring a specific variable or
519 void (*setup_dialog) (GtkWidget *dialog, struct ConfigControl *control);
520 /* Update the contents of DATA widget. */
521 void (*update_data) (struct ConfigControl *control);
522 /* Convert PLIST to string. PLIST is a variable value or command
524 GString *(*data_string) (MPlist *plist);
525 /* minput_get_variable or minput_get_command. */
526 MPlist *(*get) (MSymbol, MSymbol, MSymbol);
527 /* minput_config_variable or minput_config_command. */
528 int (*config) (MSymbol, MSymbol, MSymbol, MPlist *);
529 /* If non-NULL, a function to call before finishing a dialog. */
530 gboolean (*config_on_ok) (struct ConfigControl *control);
532 /* Widget showing the current data (value or key bindings) */
535 /* Button widget to configure the data to the default. */
538 /* Button widget to cancel the configuration. */
541 /* Label widget showing the current status. */
545 struct CommandControl
547 struct ConfigControl control;
561 struct VariableControl
563 struct ConfigControl control;
565 /* type of current variable: Minteger, Msymbol, or Mtext */
569 enum WidgetType wtype;
572 #define CONFIG_CONTROL(control) ((struct ConfigControl *) (control))
573 #define COMMAND_CONTROL(control) ((struct CommandControl *) (control))
574 #define VARIABLE_CONTROL(control) ((struct VariableControl *) (control))
576 #define CURRENT_DATA \
581 (control->get (control->lang, control->name, control->item))))))
583 #define CURRENT_STATUS \
588 (control->get (control->lang, control->name, control->item))))))
590 #define CURRENT_DESCRIPTION \
595 (control->get (control->lang, control->name, control->item)))), \
596 NULL, NULL, NULL, NULL))
598 #define CONFIG_DATA(plist) \
599 control->config (control->lang, control->name, control->item, \
602 static MPlist *entry_keyseq;
605 update_status (struct ConfigControl *control)
607 MSymbol status = CURRENT_STATUS;
609 if (status == Mconfigured)
611 gtk_label_set_text (GTK_LABEL (control->status),
612 mim_status_str[MIM_STATUS_MODIFIED]);
613 gtk_widget_set_sensitive (control->default_, TRUE);
614 gtk_widget_set_sensitive (control->revert, TRUE);
616 else if (status == Mcustomized)
618 gtk_label_set_text (GTK_LABEL (control->status),
619 mim_status_str[MIM_STATUS_CUSTOMIZED]);
620 gtk_widget_set_sensitive (control->default_, TRUE);
621 gtk_widget_set_sensitive (control->revert, FALSE);
625 gtk_label_set_text (GTK_LABEL (control->status),
626 mim_status_str[MIM_STATUS_DEFAULT]);
627 gtk_widget_set_sensitive (control->default_, FALSE);
628 gtk_widget_set_sensitive (control->revert, FALSE);
633 help_cb (GtkButton *button, gpointer data)
635 struct ConfigControl *control = data;
638 msg = gtk_message_dialog_new (GTK_WINDOW
639 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
640 GTK_DIALOG_DESTROY_WITH_PARENT,
643 CURRENT_DESCRIPTION);
644 gtk_dialog_run (GTK_DIALOG (msg));
645 gtk_widget_destroy (msg);
649 default_cb (GtkButton *button, gpointer data)
651 MPlist *empty = mplist ();
652 struct ConfigControl *control = data;
655 m17n_object_unref (empty);
656 control->update_data (control);
657 update_status (control);
658 control->config_on_ok = NULL;
662 revert_cb (GtkButton *button, gpointer data)
664 struct ConfigControl *control = data;
667 control->update_data (control);
668 update_status (control);
669 control->config_on_ok = NULL;
673 ok_cb (GtkButton *button, gpointer data)
675 struct ConfigControl *control = data;
677 if (control->config_on_ok)
679 if (! control->config_on_ok (control))
681 revert_cb (NULL, control);
684 control->config_on_ok = NULL;
686 if (control->config == minput_config_command)
687 m17n_object_unref (entry_keyseq);
688 gtk_dialog_response (GTK_DIALOG
689 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
695 /* Variable or command name */
697 /* Status (default, modified, or customized). */
699 /* Variable value or command key bindings. */
701 /* Number of columns of list store. */
707 set_list_element (GtkListStore *store, GtkTreeIter *iter,
708 struct ConfigControl *control, MPlist *plist)
714 plist = mplist_value (control->get (control->lang, control->name,
716 plist = mplist_next (mplist_next (plist));
718 status = mplist_value (plist);
719 if (status == Mconfigured)
720 status_str = mim_status_str[MIM_STATUS_MODIFIED];
721 else if (status == Mcustomized)
722 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
724 status_str = mim_status_str[MIM_STATUS_DEFAULT];
725 plist = mplist_next (plist);
726 gtk_list_store_set (store, iter,
727 CONFIG_COL_ITEM, msymbol_name (control->item),
728 CONFIG_COL_STATUS, status_str,
729 CONFIG_COL_DATA, control->data_string (plist)->str,
733 /* Called when an item (command or variable) name is activated.
734 Create a dialog widget to config that itme. */
737 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
738 GtkTreeViewColumn *col, gpointer data)
742 GtkWidget *dialog, *label, *help, *hbox, *ok;
744 struct ConfigControl *control = CONFIG_CONTROL (data);
746 model = gtk_tree_view_get_model (parent);
747 if (! gtk_tree_model_get_iter (model, &iter, path))
749 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
750 control->item = msymbol (item);
752 dialog = (gtk_dialog_new_with_buttons
753 (msymbol_name (control->item),
754 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
755 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
757 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
759 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
761 hbox = gtk_hbox_new (FALSE, 12);
762 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
763 label = gtk_label_new (_("Status"));
764 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
765 label = gtk_label_new (": ");
766 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
767 control->status = gtk_label_new (NULL);
768 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
769 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
770 hbox, FALSE, FALSE, 0);
772 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
773 g_signal_connect (G_OBJECT (help), "clicked",
774 G_CALLBACK (help_cb), control);
775 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
776 help, FALSE, FALSE, 0);
777 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
778 g_signal_connect (G_OBJECT (ok), "clicked",
779 G_CALLBACK (ok_cb), control);
780 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
781 ok, FALSE, FALSE, 0);
783 control->setup_dialog (dialog, control);
785 update_status (control);
786 gtk_widget_show_all (dialog);
787 gtk_dialog_run (GTK_DIALOG (dialog));
788 gtk_tree_model_get_iter (model, &iter, path);
789 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
790 gtk_widget_destroy (dialog);
794 /* Create a list view widget listing variable or command names with
795 their current status and data. */
798 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
804 plist = control->get (lang, name, Mnil);
805 /* plist == ((command/variable description status data ...) ...) */
807 return gtk_label_new (_("No customizable item."));
808 store = gtk_list_store_new (NUM_CONFIG_COLS,
809 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
810 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
815 pl = mplist_value (plist);
816 /* pl == (command/variable description status data ...) */
817 control->item = mplist_value (pl);
818 gtk_list_store_append (store, &iter);
819 set_list_element (store, &iter, control, pl);
822 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
823 g_object_unref (G_OBJECT (store));
824 gtk_tree_view_insert_column_with_attributes
825 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
826 "text", CONFIG_COL_ITEM, NULL);
827 gtk_tree_view_insert_column_with_attributes
828 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
829 "text", CONFIG_COL_STATUS, NULL);
830 gtk_tree_view_insert_column_with_attributes
831 (GTK_TREE_VIEW (view), -1, control->data_type_name,
832 gtk_cell_renderer_text_new (),
833 "text", CONFIG_COL_DATA, NULL);
834 g_signal_connect (G_OBJECT (view), "row-activated",
835 G_CALLBACK (item_activated_cb), control);
840 static struct VariableControl var;
841 static struct CommandControl cmd;
844 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
846 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
848 var.control.lang = cmd.control.lang = lang;
849 var.control.name = cmd.control.name = name;
850 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
852 dialog = (gtk_dialog_new_with_buttons
853 (name == Mnil ? "global" : msymbol_name (name),
854 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
855 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
856 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
858 gtk_widget_set_size_request (dialog, 500, 300);
859 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
861 vbox = gtk_vbox_new (FALSE, 0);
862 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
863 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
865 notebook = gtk_notebook_new ();
866 gtk_container_add (GTK_CONTAINER (vbox), notebook);
868 /* Variables' page */
869 scrolled = gtk_scrolled_window_new (NULL, NULL);
870 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
871 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
872 label = gtk_label_new_with_mnemonic (_("_Variables"));
873 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
874 vbox = gtk_vbox_new (FALSE, 0);
875 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
877 gtk_box_pack_start (GTK_BOX (vbox),
878 create_item_list (lang, name, CONFIG_CONTROL (&var)),
881 /* Commands' pages */
882 scrolled = gtk_scrolled_window_new (NULL, NULL);
883 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
884 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
885 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
886 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
887 vbox = gtk_vbox_new (FALSE, 0);
888 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
890 gtk_box_pack_start (GTK_BOX (vbox),
891 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
894 gtk_widget_show_all (dialog);
895 gtk_dialog_run (GTK_DIALOG (dialog));
896 gtk_widget_destroy (dialog);
900 /* Staffs for variable configuration. */
903 variable_update_data (struct ConfigControl *control)
909 plist = CURRENT_DATA;
910 /* plist == (value [valid-value ...]) */
911 key = mplist_key (plist);
912 value = mplist_value (plist);
914 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
917 gtk_entry_set_text (GTK_ENTRY (control->data),
918 msymbol_name ((MSymbol) value));
919 else if (key == Mtext)
920 /* Fixme : Assuming the return value is in UTF-8 */
921 gtk_entry_set_text (GTK_ENTRY (control->data),
922 mtext_data ((MText *) value,
923 NULL, NULL, NULL, NULL));
924 else /* key == Minteger */
927 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
928 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
931 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
935 for (i = 0, plist = mplist_next (plist);
936 plist && mplist_key (plist) == key;
937 i++, plist = mplist_next (plist))
938 if (mplist_value (plist) == value)
940 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
942 else /* ci->wtype == SPIN_BUTTON_WIDGET */
943 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
944 (gdouble) (int) value);
948 config_with_entry (struct ConfigControl *control)
950 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
951 MPlist *plist = mplist ();
954 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
956 mplist_add (plist, Msymbol, msymbol (text));
959 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
963 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
964 mplist_add (plist, Mtext, mt);
966 m17n_object_unref (mt);
968 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
972 if (sscanf (text, "%d", &i) == 1)
974 mplist_add (plist, Minteger, (void *) i);
981 msg = gtk_message_dialog_new (GTK_WINDOW
982 (gtk_widget_get_toplevel (control->data)),
983 GTK_DIALOG_DESTROY_WITH_PARENT,
986 _("The value must be an integer."));
987 gtk_dialog_run (GTK_DIALOG (msg));
988 gtk_widget_destroy (msg);
993 m17n_object_unref (plist);
998 config_with_combo (struct ConfigControl *control)
1000 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
1001 MPlist *plist = mplist ();
1003 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1005 mplist_add (plist, Msymbol, msymbol (text));
1006 CONFIG_DATA (plist);
1008 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1012 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
1013 mplist_add (plist, Mtext, mt);
1014 CONFIG_DATA (plist);
1015 m17n_object_unref (mt);
1017 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
1021 sscanf (text, "%d", &i);
1022 mplist_add (plist, Minteger, (void *) i);
1023 CONFIG_DATA (plist);
1025 m17n_object_unref (plist);
1030 config_with_spin (struct ConfigControl *control)
1032 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
1033 MPlist *plist = mplist ();
1035 mplist_add (plist, Minteger, (void *) i);
1036 CONFIG_DATA (plist);
1037 m17n_object_unref (plist);
1042 changed_cb (GtkEntry *entry, gpointer data)
1044 struct ConfigControl *control = data;
1046 gtk_widget_set_sensitive (control->default_, TRUE);
1047 gtk_widget_set_sensitive (control->revert, TRUE);
1048 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
1049 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
1050 control->config_on_ok = config_with_entry;
1051 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
1052 control->config_on_ok = config_with_combo;
1054 control->config_on_ok = config_with_spin;
1058 variable_data_string (MPlist *plist)
1060 static GString *str;
1063 str = g_string_sized_new (80);
1065 g_string_truncate (str, 0);
1067 if (mplist_key (plist) == Msymbol)
1068 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
1069 else if (mplist_key (plist) == Mtext)
1070 /* Fixme : Assuming the return value is in UTF-8 */
1071 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
1072 NULL, NULL, NULL, NULL));
1073 else /* mplist_key (plist) == Minteger */
1074 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1079 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1083 GtkWidget *hbox, *vbox;
1085 plist = CURRENT_DATA;
1086 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1087 value = mplist_value (plist);
1088 plist = mplist_next (plist);
1090 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1092 if (mplist_key (plist) == Msymbol)
1096 control->data = gtk_combo_box_new_text ();
1097 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1098 for (i = 0; mplist_key (plist) == Msymbol;
1099 plist = mplist_next (plist), i++)
1101 if (mplist_value (plist) == value)
1103 gtk_combo_box_append_text
1104 (GTK_COMBO_BOX (control->data),
1105 msymbol_name ((MSymbol) mplist_value (plist)));
1107 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1108 g_signal_connect (GTK_OBJECT (control->data), "changed",
1109 G_CALLBACK (changed_cb), control);
1113 control->data = gtk_entry_new ();
1114 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1115 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1116 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1117 g_signal_connect (GTK_OBJECT (control->data), "changed",
1118 G_CALLBACK (changed_cb), control);
1119 g_signal_connect (GTK_OBJECT (control->data), "activate",
1120 G_CALLBACK (ok_cb), control);
1123 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1125 if (plist && mplist_key (plist) == Mtext)
1129 control->data = gtk_combo_box_new_text ();
1130 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1131 for (i = 0; plist && mplist_key (plist) == Mtext;
1132 plist = mplist_next (plist), i++)
1134 if (! mtext_cmp ((MText *) mplist_value (plist),
1137 /* Fixme : Assuming the return value is in UTF-8 */
1138 gtk_combo_box_append_text
1139 (GTK_COMBO_BOX (control->data),
1140 mtext_data ((MText *) mplist_value (plist),
1141 NULL, NULL, NULL, NULL));
1143 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1144 g_signal_connect (GTK_OBJECT (control->data), "changed",
1145 G_CALLBACK (changed_cb), control);
1149 control->data = gtk_entry_new ();
1150 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1151 /* Fixme : Assuming the return value is in UTF-8 */
1152 gtk_entry_set_text (GTK_ENTRY (control->data),
1153 mtext_data (value, NULL, NULL, NULL, NULL));
1154 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1155 g_signal_connect (GTK_OBJECT (control->data), "changed",
1156 G_CALLBACK (changed_cb), control);
1157 g_signal_connect (GTK_OBJECT (control->data), "activate",
1158 G_CALLBACK (ok_cb), control);
1161 else /* control->vtype == Minteger */
1163 if (plist && mplist_key (plist) == Minteger)
1167 control->data = gtk_combo_box_new_text ();
1168 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1169 for (i = 0; plist && mplist_key (plist) == Minteger;
1170 plist = mplist_next (plist), i++)
1174 if (mplist_value (plist) == value)
1176 g_snprintf (buf, sizeof (buf), "%d",
1177 (gint) mplist_value (plist));
1178 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1180 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1181 g_signal_connect (GTK_OBJECT (control->data), "changed",
1182 G_CALLBACK (changed_cb), control);
1184 else if (plist && mplist_key (plist) == Mplist)
1187 gdouble lower, upper;
1189 plist = mplist_value (plist);
1190 lower = (gdouble) (int) mplist_value (plist);
1191 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1192 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1194 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1195 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1196 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1197 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1199 g_signal_connect (GTK_OBJECT (control->data), "changed",
1200 G_CALLBACK (changed_cb), control);
1206 control->data = gtk_entry_new ();
1207 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1208 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1209 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1210 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1211 g_signal_connect (GTK_OBJECT (control->data), "changed",
1212 G_CALLBACK (changed_cb), control);
1213 g_signal_connect (GTK_OBJECT (control->data), "activate",
1214 G_CALLBACK (ok_cb), control);
1218 control->default_ = gtk_button_new_from_stock (_("_Default"));
1219 g_signal_connect (G_OBJECT (control->default_), "clicked",
1220 G_CALLBACK (default_cb), control);
1222 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1223 g_signal_connect (G_OBJECT (control->revert), "clicked",
1224 G_CALLBACK (revert_cb), control);
1226 hbox = gtk_hbutton_box_new ();
1227 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1228 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1229 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1230 vbox = gtk_vbox_new (FALSE, 12);
1231 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1232 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1233 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1234 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1235 vbox, FALSE, FALSE, 0);
1236 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1240 /* Staffs for command configuration. */
1243 selection_cb (GtkTreeSelection *selection, gpointer data)
1245 gtk_widget_set_sensitive
1246 (COMMAND_CONTROL (data)->delete,
1247 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1251 delete_cb (GtkButton *button, gpointer data)
1253 GtkTreeSelection *selection;
1254 GtkTreeModel *model;
1257 struct ConfigControl *control = data;
1259 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1260 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1262 if (! gtk_tree_model_get_iter_first (model, &iter))
1266 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1268 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1269 mplist_add (new, Mplist, mplist_value (pl));
1270 gtk_tree_model_iter_next (model, &iter);
1273 m17n_object_unref (new);
1274 control->update_data (control);
1275 update_status (control);
1279 create_deleting_section (struct ConfigControl *control)
1281 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1282 GtkListStore *store;
1283 GtkWidget *label, *scrolled, *hbox, *vbox;
1284 GtkTreeViewColumn *column;
1285 GtkCellRenderer *renderer;
1286 GtkTreeSelection *selection;
1288 label = gtk_label_new (_("Current key bindings:"));
1290 store = gtk_list_store_new (1, G_TYPE_STRING);
1291 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1292 g_object_unref (G_OBJECT (store));
1293 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1294 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1295 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1296 g_signal_connect (G_OBJECT (selection), "changed",
1297 G_CALLBACK (selection_cb), control);
1299 scrolled = gtk_scrolled_window_new (NULL, NULL);
1300 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1301 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1302 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1305 column = gtk_tree_view_column_new ();
1306 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1307 renderer = gtk_cell_renderer_text_new ();
1308 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1309 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1311 control->update_data (control);
1313 control->default_ = gtk_button_new_from_stock (_("_Default"));
1314 g_signal_connect (G_OBJECT (control->default_), "clicked",
1315 G_CALLBACK (default_cb), control);
1317 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1318 g_signal_connect (G_OBJECT (control->revert), "clicked",
1319 G_CALLBACK (revert_cb), control);
1321 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1322 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1323 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1324 G_CALLBACK (delete_cb), control);
1326 vbox = gtk_vbox_new (FALSE, 12);
1327 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1329 hbox = gtk_hbox_new (FALSE, 6);
1330 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1331 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1333 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1335 hbox = gtk_hbutton_box_new ();
1336 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1337 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1338 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1339 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1340 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1341 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1346 static unsigned modifier_state = 0;
1350 ALT_MASK_BIT = META_MASK_BIT << 1,
1351 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1352 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1356 update_entry (GtkEntry *entry)
1358 if (mplist_key (entry_keyseq) == Mnil)
1359 gtk_entry_set_text (entry, "");
1365 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1366 gtk_entry_set_text (entry, name);
1367 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1368 p = mplist_next (p))
1370 name = msymbol_name ((MSymbol) mplist_value (p));
1371 gtk_entry_append_text (entry, " ");
1372 gtk_entry_append_text (entry, name);
1374 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1379 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1386 struct CommandControl *cmd_control = data;
1388 c = gdk_keyval_to_unicode (event->keyval);
1391 switch (event->keyval)
1393 case GDK_Meta_L: case GDK_Meta_R:
1394 modifier_state |= META_MASK_BIT; return TRUE;
1395 case GDK_Alt_L: case GDK_Alt_R:
1396 modifier_state |= ALT_MASK_BIT; return TRUE;
1397 case GDK_Super_L: case GDK_Super_R:
1398 modifier_state |= SUPER_MASK_BIT; return TRUE;
1399 case GDK_Hyper_L: case GDK_Hyper_R:
1400 modifier_state |= HYPER_MASK_BIT; return TRUE;
1402 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1405 name = gdk_keyval_name (event->keyval);
1408 nbytes = strlen (name);
1414 mtext_cat_char (mt, c);
1415 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1416 (unsigned char *) name, 32);
1417 m17n_object_unref (mt);
1420 if (c == 0 && event->state & GDK_SHIFT_MASK)
1421 buf[i++] = 'S', buf[i++] = '-';
1422 if (event->state & GDK_CONTROL_MASK)
1423 buf[i++] = 'C', buf[i++] = '-';
1424 if (modifier_state & META_MASK_BIT)
1425 buf[i++] = 'M', buf[i++] = '-';
1426 if (modifier_state & ALT_MASK_BIT)
1427 buf[i++] = 'A', buf[i++] = '-';
1428 if (modifier_state & SUPER_MASK_BIT)
1429 buf[i++] = 's', buf[i++] = '-';
1430 if (modifier_state & HYPER_MASK_BIT)
1431 buf[i++] = 'H', buf[i++] = '-';
1432 strncpy (buf + i, name, nbytes);
1433 buf[i + nbytes] = 0;
1434 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1435 update_entry (entry);
1436 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1437 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1442 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1446 c = gdk_keyval_to_unicode (event->keyval);
1449 switch (event->keyval)
1451 case GDK_Meta_L: case GDK_Meta_R:
1452 modifier_state &= ~META_MASK_BIT; break;
1453 case GDK_Alt_L: case GDK_Alt_R:
1454 modifier_state &= ~ALT_MASK_BIT; break;
1455 case GDK_Super_L: case GDK_Super_R:
1456 modifier_state &= ~SUPER_MASK_BIT; break;
1457 case GDK_Hyper_L: case GDK_Hyper_R:
1458 modifier_state &= ~HYPER_MASK_BIT; break;
1465 clear_cb (GtkButton *button, gpointer data)
1467 struct CommandControl *cmd_control = data;
1469 mplist_set (entry_keyseq, Mnil, NULL);
1470 gtk_widget_grab_focus (cmd_control->entry);
1471 update_entry (GTK_ENTRY (cmd_control->entry));
1472 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1473 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1477 add_cb (GtkButton *button, gpointer data)
1480 GtkTreeModel *model;
1482 struct ConfigControl *control = data;
1484 if (mplist_length (entry_keyseq) == 0)
1486 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1487 if (gtk_tree_model_get_iter_first (model, &iter))
1489 gchar *keyseq = control->data_string (entry_keyseq)->str;
1493 gtk_tree_model_get (model, &iter, 0, &str, -1);
1494 if (strcmp (keyseq, str) == 0)
1495 /* entry_keyseq is already registered. */
1497 } while (gtk_tree_model_iter_next (model, &iter));
1499 new = mplist_copy (CURRENT_DATA);
1500 mplist_add (new, Mplist, entry_keyseq);
1502 m17n_object_unref (new);
1503 control->update_data (control);
1504 update_status (control);
1505 clear_cb (NULL, control);
1509 create_adding_section (struct ConfigControl *control)
1511 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1512 GtkWidget *label, *hbox, *vbox;
1514 label = gtk_label_new (_("New key binding:"));
1516 entry_keyseq = mplist ();
1517 cmd_control->entry = gtk_entry_new ();
1518 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1519 G_CALLBACK (key_pressed_cb), cmd_control);
1520 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1521 G_CALLBACK (key_released_cb), cmd_control);
1523 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1524 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1525 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1526 G_CALLBACK (clear_cb), cmd_control);
1528 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1529 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1530 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1531 G_CALLBACK (add_cb), cmd_control);
1533 vbox = gtk_vbox_new (FALSE, 12);
1534 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1536 hbox = gtk_hbox_new (FALSE, 6);
1537 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1538 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1540 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1542 hbox = gtk_hbutton_box_new ();
1543 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1544 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1545 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1546 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1547 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1553 append_key_sequence (GString *str, MPlist *keyseq)
1555 static MSymbol space_symbol;
1559 space_symbol = msymbol (" ");
1561 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1563 MSymbol key = (MSymbol) mplist_value (p);
1566 g_string_append_c (str, ' ');
1567 if (key == space_symbol)
1568 g_string_append (str, "Space");
1570 g_string_append (str, msymbol_name (key));
1575 command_data_string (MPlist *plist)
1577 static GString *str;
1580 str = g_string_sized_new (80);
1582 g_string_truncate (str, 0);
1584 if (mplist_key (plist) == Mplist)
1588 /* PLIST == ((KEY KEY ...) ...) */
1589 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1592 g_string_append (str, ", ");
1593 append_key_sequence (str, mplist_value (pl));
1598 /* PLIST == (KEY KEY ...) */
1599 append_key_sequence (str, plist);
1605 command_update_data (struct ConfigControl *control)
1607 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1608 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1612 gtk_list_store_clear (store);
1613 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1615 gtk_list_store_append (store, &iter);
1616 gtk_list_store_set (store, &iter,
1617 0, control->data_string (mplist_value (pl))->str,
1623 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1625 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1626 create_deleting_section (control), FALSE, FALSE, 0);
1627 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1628 create_adding_section (control), FALSE, FALSE, 0);
1629 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1636 mim_config_new (GCallback func, gpointer data)
1638 GtkWidget *tree, *config;
1639 GtkTreeStore *store;
1640 GtkCellRenderer *renderer;
1641 GtkTreeViewColumn *column;
1646 if (merror_code < 0)
1652 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1653 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1656 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1657 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1658 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1659 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1661 var.control.data_type_name = _("Value");
1662 var.control.setup_dialog = variable_setup_dialog;
1663 var.control.update_data = variable_update_data;
1664 var.control.data_string = variable_data_string;
1665 var.control.get = minput_get_variable;
1666 var.control.config = minput_config_variable;
1668 cmd.control.data_type_name = _("Key Bindings");
1669 cmd.control.setup_dialog = command_setup_dialog;
1670 cmd.control.update_data = command_update_data;
1671 cmd.control.data_string = command_data_string;
1672 cmd.control.get = minput_get_command;
1673 cmd.control.config = minput_config_command;
1675 store = make_store_for_input_methods ();
1676 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1677 g_object_unref (G_OBJECT (store));
1679 renderer = gtk_cell_renderer_text_new ();
1680 column = (gtk_tree_view_column_new_with_attributes
1681 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1682 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1684 renderer = gtk_cell_renderer_text_new ();
1685 column = (gtk_tree_view_column_new_with_attributes
1686 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1687 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1689 g_signal_connect (G_OBJECT (tree), "row-expanded",
1690 G_CALLBACK (tree_expanded_cb), NULL);
1691 g_signal_connect (G_OBJECT (tree), "row-activated",
1692 G_CALLBACK (tree_activated_cb), NULL);
1694 config =gtk_scrolled_window_new (NULL, NULL);
1695 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1696 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1697 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1698 g_signal_connect (G_OBJECT (config), "destroy",
1699 G_CALLBACK (destroy_cb), NULL);
1701 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1704 MimConfigCallback *callback;
1706 callback = g_new (MimConfigCallback, 1);
1707 callback->widget = config;
1708 callback->func = (MimConfigCallbackFunc) func;
1709 callback->data = data;
1710 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1718 mim_config_modified (GtkWidget *config)
1721 GtkTreeModel *model;
1722 MimConfigStatus *config_status;
1724 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1725 model = gtk_tree_view_get_model (tree);
1726 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1728 return (config_status->num_modified > 0 ? TRUE : FALSE);
1732 mim_config_default (GtkWidget *config)
1735 GtkTreeModel *model;
1736 MimConfigStatus *config_status;
1738 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1739 model = gtk_tree_view_get_model (tree);
1740 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1741 gtk_tree_model_foreach (model, reset_to_default, config_status);
1746 mim_config_revert (GtkWidget *config)
1749 GtkTreeModel *model;
1750 MimConfigStatus *config_status;
1752 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1753 model = gtk_tree_view_get_model (tree);
1754 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1756 if (config_status->num_modified == 0)
1758 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1763 mim_config_save (GtkWidget *config)
1766 GtkTreeModel *model;
1767 MimConfigStatus *config_status;
1769 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1770 model = gtk_tree_view_get_model (tree);
1771 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1773 if (config_status->num_modified == 0)
1775 minput_save_config ();
1776 gtk_tree_model_foreach (model, set_as_saved, config_status);
1781 mim_config_get_tree_view (GtkWidget *config)
1785 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);