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,
28 #include <m17n-misc.h>
31 #include <gdk/gdkkeysyms.h>
33 #include "m17n-im-config.h"
35 #define _(String) dgettext (PACKAGE, String)
37 #define CONFIG_CALLBACK_DATA " config-callback-data"
38 #define CONFIG_STATUS_DATA " config-status-data"
39 #define CONFIG_TREE_VIEW " config-tree-view"
41 typedef void (*MimConfigCallbackFunc) (GtkWidget *widget, gpointer data);
43 typedef struct _MimConfigCallback
46 MimConfigCallbackFunc func;
50 typedef struct _MimConfigStatus
52 /* Number of available input methods. */
54 /* Number of modified input methods. */
58 /* Status of variables and commands of an input method. */
63 MIM_STATUS_CUSTOMIZED,
69 static char *mim_status_str[MIM_STATUS_MAX];
72 get_mim_status (MSymbol lang, MSymbol name)
75 enum MimStatus status = MIM_STATUS_NO;
77 for (plist = minput_get_variable (lang, name, Mnil);
78 plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
80 MPlist *p = mplist_value (plist);
81 MSymbol status_symbol;
83 p = mplist_next (mplist_next (p));
84 status_symbol = mplist_value (p);
85 if (status_symbol == Mconfigured)
86 return MIM_STATUS_MODIFIED;
87 if (status_symbol == Mcustomized)
88 status = MIM_STATUS_CUSTOMIZED;
89 else if (status == MIM_STATUS_NO)
90 status = MIM_STATUS_DEFAULT;
92 for (plist = minput_get_command (lang, name, Mnil);
93 plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
95 MPlist *p = mplist_value (plist);
96 MSymbol status_symbol;
98 p = mplist_next (mplist_next (p));
99 status_symbol = mplist_value (p);
100 if (status_symbol == Mconfigured)
101 return MIM_STATUS_MODIFIED;
102 if (status_symbol == Mcustomized)
103 status = MIM_STATUS_CUSTOMIZED;
104 else if (status == MIM_STATUS_NO)
105 status = MIM_STATUS_DEFAULT;
110 /* Columns of each row. */
113 /* parent: language name
116 /* parent: NULL or "modified"
117 child: "default", "customized", or "modified" */
119 /* parent: num of modified children
120 child: enum MimStatus */
123 child: symbolic language name. */
126 child: symbolic IM name. */
128 /* number of columns */
132 /* Called when a row is expanded. We may have to initialize
135 tree_expanded_cb (GtkTreeView *tree, GtkTreeIter *parent,
136 GtkTreePath *path, gpointer data)
142 model = gtk_tree_view_get_model (tree);
143 if (gtk_tree_model_iter_children (model, &iter, parent))
147 gtk_tree_model_get (model, &iter, COL_STATUS_STR, &status_str, -1);
150 /* The first child is not yet initialized, and that means
151 the remaining children are not initialized either. */
152 gtk_tree_model_get (model, &iter, COL_LANG, &lang, -1);
154 enum MimStatus im_status;
156 gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
157 im_status = get_mim_status (lang, name);
158 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
159 COL_STATUS_STR, mim_status_str[im_status],
160 COL_STATUS, im_status,
162 } while (gtk_tree_model_iter_next (model, &iter));
167 static void config_im (GtkTreeView *tree, MSymbol lang, MSymbol name);
170 update_child_row (GtkTreeModel *model, GtkTreeIter *iter,
171 enum MimStatus status, MimConfigStatus *config_status,
177 inc_modified = (status == MIM_STATUS_MODIFIED ? 1 : -1);
179 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
180 COL_STATUS_STR, mim_status_str[status],
181 COL_STATUS, status, -1);
182 if (gtk_tree_model_iter_parent (model, &parent, iter))
187 gtk_tree_model_get (model, &parent, COL_STATUS, &num_modified, -1);
188 num_modified += inc_modified;
189 gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
190 COL_STATUS, num_modified, -1);
191 if (num_modified <= 1)
193 status_str = (status == MIM_STATUS_MODIFIED
194 ? mim_status_str[MIM_STATUS_MODIFIED] : NULL);
195 gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
196 COL_STATUS_STR, status_str);
201 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
202 config_status->num_modified += inc_modified;
203 if (tree && config_status->num_modified <= 1)
205 MimConfigCallback *callback;
207 callback = g_object_get_data (G_OBJECT (tree), CONFIG_CALLBACK_DATA);
209 callback->func (callback->widget, callback->data);
214 tree_activated_cb (GtkTreeView *tree, GtkTreePath *path,
215 GtkTreeViewColumn *column, gpointer data)
220 model = gtk_tree_view_get_model (tree);
221 if (gtk_tree_model_get_iter (model, &iter, path))
225 gtk_tree_model_get (model, &iter, COL_LANG, &lang, COL_NAME, &name, -1);
228 /* child row for an IM */
229 enum MimStatus old, new;
231 old = get_mim_status (lang, name);
232 config_im (tree, lang, name);
233 new = get_mim_status (lang, name);
235 update_child_row (model, &iter, new, NULL, tree);
239 /* parent row for a language */
240 if (gtk_tree_view_row_expanded (tree, path))
241 gtk_tree_view_collapse_row (tree, path);
243 gtk_tree_view_expand_row (tree, path, TRUE);
248 typedef struct _MimTable
257 sort_im (const void *p1, const void *p2)
259 const MimTable *t1 = p1;
260 const MimTable *t2 = p2;
261 int result = strcmp (t1->lang, t2->lang);
263 return (result ? result : strcmp (t1->name, t2->name));
266 static GtkTreeStore *
267 make_store_for_input_methods ()
274 GtkTreeIter iter1, iter2;
275 enum MimStatus status;
276 MimConfigStatus *config_status;
278 store = gtk_tree_store_new (NUM_COLS,
279 G_TYPE_STRING, /* COL_TAG */
280 G_TYPE_STRING, /* COL_STATUS_STR */
281 G_TYPE_UINT, /* COL_STATUS */
282 G_TYPE_POINTER, /* COL_LANG */
283 G_TYPE_POINTER /* COL_NAME */
286 config_status = g_new0 (MimConfigStatus, 1);
287 gtk_tree_store_append (store, &iter1, NULL);
288 status = get_mim_status (Mt, Mnil);
289 gtk_tree_store_set (store, &iter1,
290 COL_TAG, _("global"),
291 COL_STATUS_STR, mim_status_str[status],
297 imlist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
298 config_status->num_im = mplist_length (imlist);
299 imtable = g_newa (MimTable, config_status->num_im);
300 for (i = 0, p = imlist; mplist_key (p) != Mnil; p = mplist_next (p))
302 MDatabase *mdb = (MDatabase *) mplist_value (p);
303 MSymbol *tag = mdatabase_tag (mdb);
305 if (tag[1] != Mnil && tag[2] != Mnil)
307 MSymbol language = mlanguage_name (tag[1]);
309 if (language != Mnil)
310 imtable[i].lang = msymbol_name (language);
312 /* `~' is for putting this element at the tail by sort. */
313 imtable[i].lang = _("~other");
314 imtable[i].name = msymbol_name (tag[2]);
315 imtable[i].symlang = tag[1];
316 imtable[i].symname = tag[2];
320 m17n_object_unref (imlist);
321 config_status->num_im = i;
322 qsort (imtable, config_status->num_im, sizeof (MimTable), sort_im);
324 for (lang = NULL, i = 0; i < config_status->num_im; i++)
326 if (lang != imtable[i].lang)
330 gtk_tree_store_append (store, &iter1, NULL);
331 lang = imtable[i].lang;
335 gchar *native = NULL;
338 if (imtable[i].symlang != Mt
339 && (native_text = mlanguage_text (imtable[i].symlang)))
341 enum MTextFormat fmt;
343 native = mtext_data (native_text, &fmt, &nbytes,
345 if (fmt != MTEXT_FORMAT_US_ASCII
346 && fmt != MTEXT_FORMAT_UTF_8)
351 name = alloca (strlen (lang) + nbytes + 4);
352 sprintf (name, "%s (%s)", lang, native);
360 gtk_tree_store_set (store, &iter1,
362 COL_STATUS_STR, NULL,
368 gtk_tree_store_append (store, &iter2, &iter1);
369 gtk_tree_store_set (store, &iter2,
370 COL_TAG, imtable[i].name,
371 COL_STATUS_STR, NULL,
372 COL_LANG, imtable[i].symlang,
373 COL_NAME, imtable[i].symname,
376 config_status->num_modified = 0;
377 g_object_set_data_full (G_OBJECT (store), CONFIG_STATUS_DATA,
378 config_status, g_free);
383 revert_to_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
386 enum MimStatus status;
388 MimConfigStatus *config_status = data;
390 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
393 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
394 if (status != MIM_STATUS_MODIFIED)
396 minput_config_variable (lang, name, Mnil, NULL);
397 minput_config_command (lang, name, Mnil, NULL);
398 status = get_mim_status (lang, name);
399 update_child_row (model, iter, status, config_status, NULL);
404 set_as_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
407 enum MimStatus status;
409 MimConfigStatus *config_status = data;
411 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
414 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
415 if (status != MIM_STATUS_MODIFIED)
417 status = get_mim_status (lang, name);
418 update_child_row (model, iter, status, config_status, NULL);
422 static int initialized = 0;
425 destroy_cb (GtkWidget *widget, gpointer data)
432 /****************************************************/
433 /* Configuration of a specific variable or command. */
434 /****************************************************/
436 /* Common staffs to variable and command */
440 /* Data type name ("Value" or "Key bindings"). */
441 gchar *data_type_name;
442 MSymbol lang, name, item;
443 /* Fill in widgets in DIALOG for configuring a specific variable or
445 void (*setup_dialog) (GtkWidget *dialog, struct ConfigControl *control);
446 /* Update the contents of DATA widget. */
447 void (*update_data) (struct ConfigControl *control);
448 /* Convert PLIST to string. PLIST is a variable value or command
450 GString *(*data_string) (MPlist *plist);
451 /* minput_get_variable or minput_get_command. */
452 MPlist *(*get) (MSymbol, MSymbol, MSymbol);
453 /* minput_config_variable or minput_config_command. */
454 int (*config) (MSymbol, MSymbol, MSymbol, MPlist *);
455 /* If non-NULL, a function to call before finishing a dialog. */
456 gboolean (*config_on_ok) (struct ConfigControl *control);
458 /* Widget showing the current data (value or key bindings) */
461 /* Button widget to configure the data to the default. */
464 /* Button widget to cancel the configuration. */
467 /* Label widget showing the current status. */
471 struct CommandControl
473 struct ConfigControl control;
487 struct VariableControl
489 struct ConfigControl control;
491 /* type of current variable: Minteger, Msymbol, or Mtext */
495 enum WidgetType wtype;
498 #define CONFIG_CONTROL(control) ((struct ConfigControl *) (control))
499 #define COMMAND_CONTROL(control) ((struct CommandControl *) (control))
500 #define VARIABLE_CONTROL(control) ((struct VariableControl *) (control))
502 #define CURRENT_DATA \
507 (control->get (control->lang, control->name, control->item))))))
509 #define CURRENT_STATUS \
514 (control->get (control->lang, control->name, control->item))))))
516 #define CURRENT_DESCRIPTION \
521 (control->get (control->lang, control->name, control->item)))), \
522 NULL, NULL, NULL, NULL))
524 #define CONFIG_DATA(plist) \
525 control->config (control->lang, control->name, control->item, \
528 static MPlist *entry_keyseq;
531 update_status (struct ConfigControl *control)
533 MSymbol status = CURRENT_STATUS;
535 if (status == Mconfigured)
537 gtk_label_set_text (GTK_LABEL (control->status),
538 mim_status_str[MIM_STATUS_MODIFIED]);
539 gtk_widget_set_sensitive (control->default_, TRUE);
540 gtk_widget_set_sensitive (control->revert, TRUE);
542 else if (status == Mcustomized)
544 gtk_label_set_text (GTK_LABEL (control->status),
545 mim_status_str[MIM_STATUS_CUSTOMIZED]);
546 gtk_widget_set_sensitive (control->default_, TRUE);
547 gtk_widget_set_sensitive (control->revert, FALSE);
551 gtk_label_set_text (GTK_LABEL (control->status),
552 mim_status_str[MIM_STATUS_DEFAULT]);
553 gtk_widget_set_sensitive (control->default_, FALSE);
554 gtk_widget_set_sensitive (control->revert, FALSE);
559 help_cb (GtkButton *button, gpointer data)
561 struct ConfigControl *control = data;
564 msg = gtk_message_dialog_new (GTK_WINDOW
565 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
566 GTK_DIALOG_DESTROY_WITH_PARENT,
569 CURRENT_DESCRIPTION);
570 gtk_dialog_run (GTK_DIALOG (msg));
571 gtk_widget_destroy (msg);
575 default_cb (GtkButton *button, gpointer data)
577 MPlist *empty = mplist ();
578 struct ConfigControl *control = data;
581 m17n_object_unref (empty);
582 control->update_data (control);
583 update_status (control);
584 control->config_on_ok = NULL;
588 revert_cb (GtkButton *button, gpointer data)
590 struct ConfigControl *control = data;
593 control->update_data (control);
594 update_status (control);
595 control->config_on_ok = NULL;
599 ok_cb (GtkButton *button, gpointer data)
601 struct ConfigControl *control = data;
603 if (control->config_on_ok)
605 if (! control->config_on_ok (control))
607 revert_cb (NULL, control);
610 control->config_on_ok = NULL;
612 if (control->config == minput_config_command)
613 m17n_object_unref (entry_keyseq);
614 gtk_dialog_response (GTK_DIALOG
615 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
621 /* Variable or command name */
623 /* Status (default, modified, or customized). */
625 /* Variable value or command key bindings. */
627 /* Number of columns of list store. */
633 set_list_element (GtkListStore *store, GtkTreeIter *iter,
634 struct ConfigControl *control, MPlist *plist)
640 plist = mplist_value (control->get (control->lang, control->name,
642 plist = mplist_next (mplist_next (plist));
644 status = mplist_value (plist);
645 if (status == Mconfigured)
646 status_str = mim_status_str[MIM_STATUS_MODIFIED];
647 else if (status == Mcustomized)
648 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
650 status_str = mim_status_str[MIM_STATUS_DEFAULT];
651 plist = mplist_next (plist);
652 gtk_list_store_set (store, iter,
653 CONFIG_COL_ITEM, msymbol_name (control->item),
654 CONFIG_COL_STATUS, status_str,
655 CONFIG_COL_DATA, control->data_string (plist)->str,
659 /* Called when an item (command or variable) name is activated.
660 Create a dialog widget to config that itme. */
663 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
664 GtkTreeViewColumn *col, gpointer data)
668 GtkWidget *dialog, *label, *help, *hbox, *ok;
670 struct ConfigControl *control = CONFIG_CONTROL (data);
672 model = gtk_tree_view_get_model (parent);
673 if (! gtk_tree_model_get_iter (model, &iter, path))
675 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
676 control->item = msymbol (item);
678 dialog = (gtk_dialog_new_with_buttons
679 (msymbol_name (control->item),
680 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
681 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
683 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
685 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
687 hbox = gtk_hbox_new (FALSE, 12);
688 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
689 label = gtk_label_new (_("Status"));
690 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
691 label = gtk_label_new (": ");
692 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
693 control->status = gtk_label_new (NULL);
694 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
695 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
696 hbox, FALSE, FALSE, 0);
698 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
699 g_signal_connect (G_OBJECT (help), "clicked",
700 G_CALLBACK (help_cb), control);
701 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
702 help, FALSE, FALSE, 0);
703 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
704 g_signal_connect (G_OBJECT (ok), "clicked",
705 G_CALLBACK (ok_cb), control);
706 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
707 ok, FALSE, FALSE, 0);
709 control->setup_dialog (dialog, control);
711 update_status (control);
712 gtk_widget_show_all (dialog);
713 gtk_dialog_run (GTK_DIALOG (dialog));
714 gtk_tree_model_get_iter (model, &iter, path);
715 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
716 gtk_widget_destroy (dialog);
720 /* Create a list view widget listing variable or command names with
721 their current status and data. */
724 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
730 plist = control->get (lang, name, Mnil);
731 /* plist == ((command/variable description status data ...) ...) */
733 return gtk_label_new (_("No customizable item."));
734 store = gtk_list_store_new (NUM_CONFIG_COLS,
735 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
736 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
741 pl = mplist_value (plist);
742 /* pl == (command/variable description status data ...) */
743 control->item = mplist_value (pl);
744 gtk_list_store_append (store, &iter);
745 set_list_element (store, &iter, control, pl);
748 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
749 g_object_unref (G_OBJECT (store));
750 gtk_tree_view_insert_column_with_attributes
751 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
752 "text", CONFIG_COL_ITEM, NULL);
753 gtk_tree_view_insert_column_with_attributes
754 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
755 "text", CONFIG_COL_STATUS, NULL);
756 gtk_tree_view_insert_column_with_attributes
757 (GTK_TREE_VIEW (view), -1, control->data_type_name,
758 gtk_cell_renderer_text_new (),
759 "text", CONFIG_COL_DATA, NULL);
760 g_signal_connect (G_OBJECT (view), "row-activated",
761 G_CALLBACK (item_activated_cb), control);
766 static struct VariableControl var;
767 static struct CommandControl cmd;
770 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
772 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
774 var.control.lang = cmd.control.lang = lang;
775 var.control.name = cmd.control.name = name;
776 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
778 dialog = (gtk_dialog_new_with_buttons
779 (name == Mnil ? "global" : msymbol_name (name),
780 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
781 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
782 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
784 gtk_widget_set_size_request (dialog, 500, 300);
785 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
787 vbox = gtk_vbox_new (FALSE, 0);
788 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
789 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
791 notebook = gtk_notebook_new ();
792 gtk_container_add (GTK_CONTAINER (vbox), notebook);
794 /* Variables' page */
795 scrolled = gtk_scrolled_window_new (NULL, NULL);
796 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
797 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
798 label = gtk_label_new_with_mnemonic (_("_Variables"));
799 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
800 vbox = gtk_vbox_new (FALSE, 0);
801 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
803 gtk_box_pack_start (GTK_BOX (vbox),
804 create_item_list (lang, name, CONFIG_CONTROL (&var)),
807 /* Commands' pages */
808 scrolled = gtk_scrolled_window_new (NULL, NULL);
809 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
810 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
811 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
812 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
813 vbox = gtk_vbox_new (FALSE, 0);
814 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
816 gtk_box_pack_start (GTK_BOX (vbox),
817 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
820 gtk_widget_show_all (dialog);
821 gtk_dialog_run (GTK_DIALOG (dialog));
822 gtk_widget_destroy (dialog);
826 /* Staffs for variable configuration. */
829 variable_update_data (struct ConfigControl *control)
835 plist = CURRENT_DATA;
836 /* plist == (value [valid-value ...]) */
837 key = mplist_key (plist);
838 value = mplist_value (plist);
840 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
843 gtk_entry_set_text (GTK_ENTRY (control->data),
844 msymbol_name ((MSymbol) value));
845 else if (key == Mtext)
846 /* Fixme : Assuming the return value is in UTF-8 */
847 gtk_entry_set_text (GTK_ENTRY (control->data),
848 mtext_data ((MText *) value,
849 NULL, NULL, NULL, NULL));
850 else /* key == Minteger */
853 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
854 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
857 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
861 for (i = 0, plist = mplist_next (plist);
862 plist && mplist_key (plist) == key;
863 i++, plist = mplist_next (plist))
864 if (mplist_value (plist) == value)
866 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
868 else /* ci->wtype == SPIN_BUTTON_WIDGET */
869 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
870 (gdouble) (int) value);
874 config_with_entry (struct ConfigControl *control)
876 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
877 MPlist *plist = mplist ();
880 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
882 mplist_add (plist, Msymbol, msymbol (text));
885 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
889 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
890 mplist_add (plist, Mtext, mt);
892 m17n_object_unref (mt);
894 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
898 if (sscanf (text, "%d", &i) == 1)
900 mplist_add (plist, Minteger, (void *) i);
907 msg = gtk_message_dialog_new (GTK_WINDOW
908 (gtk_widget_get_toplevel (control->data)),
909 GTK_DIALOG_DESTROY_WITH_PARENT,
912 _("The value must be an integer."));
913 gtk_dialog_run (GTK_DIALOG (msg));
914 gtk_widget_destroy (msg);
919 m17n_object_unref (plist);
924 config_with_combo (struct ConfigControl *control)
926 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
927 MPlist *plist = mplist ();
929 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
931 mplist_add (plist, Msymbol, msymbol (text));
934 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
938 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
939 mplist_add (plist, Mtext, mt);
941 m17n_object_unref (mt);
943 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
947 sscanf (text, "%d", &i);
948 mplist_add (plist, Minteger, (void *) i);
951 m17n_object_unref (plist);
956 config_with_spin (struct ConfigControl *control)
958 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
959 MPlist *plist = mplist ();
961 mplist_add (plist, Minteger, (void *) i);
963 m17n_object_unref (plist);
968 changed_cb (GtkEntry *entry, gpointer data)
970 struct ConfigControl *control = data;
972 gtk_widget_set_sensitive (control->default_, TRUE);
973 gtk_widget_set_sensitive (control->revert, TRUE);
974 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
975 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
976 control->config_on_ok = config_with_entry;
977 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
978 control->config_on_ok = config_with_combo;
980 control->config_on_ok = config_with_spin;
984 variable_data_string (MPlist *plist)
989 str = g_string_sized_new (80);
991 g_string_truncate (str, 0);
993 if (mplist_key (plist) == Msymbol)
994 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
995 else if (mplist_key (plist) == Mtext)
996 /* Fixme : Assuming the return value is in UTF-8 */
997 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
998 NULL, NULL, NULL, NULL));
999 else /* mplist_key (plist) == Minteger */
1000 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1005 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1009 GtkWidget *hbox, *vbox;
1011 plist = CURRENT_DATA;
1012 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1013 value = mplist_value (plist);
1014 plist = mplist_next (plist);
1016 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1018 if (mplist_key (plist) == Msymbol)
1022 control->data = gtk_combo_box_new_text ();
1023 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1024 for (i = 0; mplist_key (plist) == Msymbol;
1025 plist = mplist_next (plist), i++)
1027 if (mplist_value (plist) == value)
1029 gtk_combo_box_append_text
1030 (GTK_COMBO_BOX (control->data),
1031 msymbol_name ((MSymbol) mplist_value (plist)));
1033 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1034 g_signal_connect (GTK_OBJECT (control->data), "changed",
1035 G_CALLBACK (changed_cb), control);
1039 control->data = gtk_entry_new ();
1040 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1041 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1042 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1043 g_signal_connect (GTK_OBJECT (control->data), "changed",
1044 G_CALLBACK (changed_cb), control);
1045 g_signal_connect (GTK_OBJECT (control->data), "activate",
1046 G_CALLBACK (ok_cb), control);
1049 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1051 if (plist && mplist_key (plist) == Mtext)
1055 control->data = gtk_combo_box_new_text ();
1056 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1057 for (i = 0; plist && mplist_key (plist) == Mtext;
1058 plist = mplist_next (plist), i++)
1060 if (! mtext_cmp ((MText *) mplist_value (plist),
1063 /* Fixme : Assuming the return value is in UTF-8 */
1064 gtk_combo_box_append_text
1065 (GTK_COMBO_BOX (control->data),
1066 mtext_data ((MText *) mplist_value (plist),
1067 NULL, NULL, NULL, NULL));
1069 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1070 g_signal_connect (GTK_OBJECT (control->data), "changed",
1071 G_CALLBACK (changed_cb), control);
1075 control->data = gtk_entry_new ();
1076 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1077 /* Fixme : Assuming the return value is in UTF-8 */
1078 gtk_entry_set_text (GTK_ENTRY (control->data),
1079 mtext_data (value, NULL, NULL, NULL, NULL));
1080 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1081 g_signal_connect (GTK_OBJECT (control->data), "changed",
1082 G_CALLBACK (changed_cb), control);
1083 g_signal_connect (GTK_OBJECT (control->data), "activate",
1084 G_CALLBACK (ok_cb), control);
1087 else /* control->vtype == Minteger */
1089 if (plist && mplist_key (plist) == Minteger)
1093 control->data = gtk_combo_box_new_text ();
1094 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1095 for (i = 0; plist && mplist_key (plist) == Minteger;
1096 plist = mplist_next (plist), i++)
1100 if (mplist_value (plist) == value)
1102 g_snprintf (buf, sizeof (buf), "%d",
1103 (gint) mplist_value (plist));
1104 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1106 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1107 g_signal_connect (GTK_OBJECT (control->data), "changed",
1108 G_CALLBACK (changed_cb), control);
1110 else if (plist && mplist_key (plist) == Mplist)
1113 gdouble lower, upper;
1115 plist = mplist_value (plist);
1116 lower = (gdouble) (int) mplist_value (plist);
1117 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1118 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1120 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1121 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1122 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1123 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1125 g_signal_connect (GTK_OBJECT (control->data), "changed",
1126 G_CALLBACK (changed_cb), control);
1132 control->data = gtk_entry_new ();
1133 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1134 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1135 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1136 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1137 g_signal_connect (GTK_OBJECT (control->data), "changed",
1138 G_CALLBACK (changed_cb), control);
1139 g_signal_connect (GTK_OBJECT (control->data), "activate",
1140 G_CALLBACK (ok_cb), control);
1144 control->default_ = gtk_button_new_from_stock (_("_Default"));
1145 g_signal_connect (G_OBJECT (control->default_), "clicked",
1146 G_CALLBACK (default_cb), control);
1148 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1149 g_signal_connect (G_OBJECT (control->revert), "clicked",
1150 G_CALLBACK (revert_cb), control);
1152 hbox = gtk_hbutton_box_new ();
1153 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1154 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1155 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1156 vbox = gtk_vbox_new (FALSE, 12);
1157 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1158 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1159 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1160 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1161 vbox, FALSE, FALSE, 0);
1162 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1166 /* Staffs for command configuration. */
1169 selection_cb (GtkTreeSelection *selection, gpointer data)
1171 gtk_widget_set_sensitive
1172 (COMMAND_CONTROL (data)->delete,
1173 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1177 delete_cb (GtkButton *button, gpointer data)
1179 GtkTreeSelection *selection;
1180 GtkTreeModel *model;
1183 struct ConfigControl *control = data;
1185 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1186 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1188 if (! gtk_tree_model_get_iter_first (model, &iter))
1192 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1194 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1195 mplist_add (new, Mplist, mplist_value (pl));
1196 gtk_tree_model_iter_next (model, &iter);
1199 m17n_object_unref (new);
1200 control->update_data (control);
1201 update_status (control);
1205 create_deleting_section (struct ConfigControl *control)
1207 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1208 GtkListStore *store;
1209 GtkWidget *label, *scrolled, *hbox, *vbox;
1210 GtkTreeViewColumn *column;
1211 GtkCellRenderer *renderer;
1212 GtkTreeSelection *selection;
1214 label = gtk_label_new (_("Current key bindings:"));
1216 store = gtk_list_store_new (1, G_TYPE_STRING);
1217 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1218 g_object_unref (G_OBJECT (store));
1219 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1220 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1221 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1222 g_signal_connect (G_OBJECT (selection), "changed",
1223 G_CALLBACK (selection_cb), control);
1225 scrolled = gtk_scrolled_window_new (NULL, NULL);
1226 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1227 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1228 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1231 column = gtk_tree_view_column_new ();
1232 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1233 renderer = gtk_cell_renderer_text_new ();
1234 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1235 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1237 control->update_data (control);
1239 control->default_ = gtk_button_new_from_stock (_("_Default"));
1240 g_signal_connect (G_OBJECT (control->default_), "clicked",
1241 G_CALLBACK (default_cb), control);
1243 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1244 g_signal_connect (G_OBJECT (control->revert), "clicked",
1245 G_CALLBACK (revert_cb), control);
1247 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1248 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1249 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1250 G_CALLBACK (delete_cb), control);
1252 vbox = gtk_vbox_new (FALSE, 12);
1253 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1255 hbox = gtk_hbox_new (FALSE, 6);
1256 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1257 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1259 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1261 hbox = gtk_hbutton_box_new ();
1262 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1263 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1264 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1265 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1266 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1267 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1272 static unsigned modifier_state = 0;
1276 ALT_MASK_BIT = META_MASK_BIT << 1,
1277 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1278 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1282 update_entry (GtkEntry *entry)
1284 if (mplist_key (entry_keyseq) == Mnil)
1285 gtk_entry_set_text (entry, "");
1291 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1292 gtk_entry_set_text (entry, name);
1293 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1294 p = mplist_next (p))
1296 name = msymbol_name ((MSymbol) mplist_value (p));
1297 gtk_entry_append_text (entry, " ");
1298 gtk_entry_append_text (entry, name);
1300 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1305 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1312 struct CommandControl *cmd_control = data;
1314 c = gdk_keyval_to_unicode (event->keyval);
1317 switch (event->keyval)
1319 case GDK_Meta_L: case GDK_Meta_R:
1320 modifier_state |= META_MASK_BIT; return TRUE;
1321 case GDK_Alt_L: case GDK_Alt_R:
1322 modifier_state |= ALT_MASK_BIT; return TRUE;
1323 case GDK_Super_L: case GDK_Super_R:
1324 modifier_state |= SUPER_MASK_BIT; return TRUE;
1325 case GDK_Hyper_L: case GDK_Hyper_R:
1326 modifier_state |= HYPER_MASK_BIT; return TRUE;
1328 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1331 name = gdk_keyval_name (event->keyval);
1334 nbytes = strlen (name);
1340 mtext_cat_char (mt, c);
1341 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1342 (unsigned char *) name, 32);
1343 m17n_object_unref (mt);
1346 if (c == 0 && event->state & GDK_SHIFT_MASK)
1347 buf[i++] = 'S', buf[i++] = '-';
1348 if (event->state & GDK_CONTROL_MASK)
1349 buf[i++] = 'C', buf[i++] = '-';
1350 if (modifier_state & META_MASK_BIT)
1351 buf[i++] = 'M', buf[i++] = '-';
1352 if (modifier_state & ALT_MASK_BIT)
1353 buf[i++] = 'A', buf[i++] = '-';
1354 if (modifier_state & SUPER_MASK_BIT)
1355 buf[i++] = 's', buf[i++] = '-';
1356 if (modifier_state & HYPER_MASK_BIT)
1357 buf[i++] = 'H', buf[i++] = '-';
1358 strncpy (buf + i, name, nbytes);
1359 buf[i + nbytes] = 0;
1360 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1361 update_entry (entry);
1362 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1363 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1368 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1372 c = gdk_keyval_to_unicode (event->keyval);
1375 switch (event->keyval)
1377 case GDK_Meta_L: case GDK_Meta_R:
1378 modifier_state &= ~META_MASK_BIT; break;
1379 case GDK_Alt_L: case GDK_Alt_R:
1380 modifier_state &= ~ALT_MASK_BIT; break;
1381 case GDK_Super_L: case GDK_Super_R:
1382 modifier_state &= ~SUPER_MASK_BIT; break;
1383 case GDK_Hyper_L: case GDK_Hyper_R:
1384 modifier_state &= ~HYPER_MASK_BIT; break;
1391 clear_cb (GtkButton *button, gpointer data)
1393 struct CommandControl *cmd_control = data;
1395 mplist_set (entry_keyseq, Mnil, NULL);
1396 gtk_widget_grab_focus (cmd_control->entry);
1397 update_entry (GTK_ENTRY (cmd_control->entry));
1398 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1399 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1403 add_cb (GtkButton *button, gpointer data)
1406 GtkTreeModel *model;
1408 struct ConfigControl *control = data;
1410 if (mplist_length (entry_keyseq) == 0)
1412 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1413 if (gtk_tree_model_get_iter_first (model, &iter))
1415 gchar *keyseq = control->data_string (entry_keyseq)->str;
1419 gtk_tree_model_get (model, &iter, 0, &str, -1);
1420 if (strcmp (keyseq, str) == 0)
1421 /* entry_keyseq is already registered. */
1423 } while (gtk_tree_model_iter_next (model, &iter));
1425 new = mplist_copy (CURRENT_DATA);
1426 mplist_add (new, Mplist, entry_keyseq);
1428 m17n_object_unref (new);
1429 control->update_data (control);
1430 update_status (control);
1431 clear_cb (NULL, control);
1435 create_adding_section (struct ConfigControl *control)
1437 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1438 GtkWidget *label, *hbox, *vbox;
1440 label = gtk_label_new (_("New key binding:"));
1442 entry_keyseq = mplist ();
1443 cmd_control->entry = gtk_entry_new ();
1444 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1445 G_CALLBACK (key_pressed_cb), cmd_control);
1446 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1447 G_CALLBACK (key_released_cb), cmd_control);
1449 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1450 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1451 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1452 G_CALLBACK (clear_cb), cmd_control);
1454 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1455 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1456 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1457 G_CALLBACK (add_cb), cmd_control);
1459 vbox = gtk_vbox_new (FALSE, 12);
1460 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1462 hbox = gtk_hbox_new (FALSE, 6);
1463 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1464 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1466 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1468 hbox = gtk_hbutton_box_new ();
1469 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1470 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1471 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1472 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1473 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1479 append_key_sequence (GString *str, MPlist *keyseq)
1481 static MSymbol space_symbol;
1485 space_symbol = msymbol (" ");
1487 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1489 MSymbol key = (MSymbol) mplist_value (p);
1492 g_string_append_c (str, ' ');
1493 if (key == space_symbol)
1494 g_string_append (str, "Space");
1496 g_string_append (str, msymbol_name (key));
1501 command_data_string (MPlist *plist)
1503 static GString *str;
1506 str = g_string_sized_new (80);
1508 g_string_truncate (str, 0);
1510 if (mplist_key (plist) == Mplist)
1514 /* PLIST == ((KEY KEY ...) ...) */
1515 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1518 g_string_append (str, ", ");
1519 append_key_sequence (str, mplist_value (pl));
1524 /* PLIST == (KEY KEY ...) */
1525 append_key_sequence (str, plist);
1531 command_update_data (struct ConfigControl *control)
1533 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1534 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1538 gtk_list_store_clear (store);
1539 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1541 gtk_list_store_append (store, &iter);
1542 gtk_list_store_set (store, &iter,
1543 0, control->data_string (mplist_value (pl))->str,
1549 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1551 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1552 create_deleting_section (control), FALSE, FALSE, 0);
1553 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1554 create_adding_section (control), FALSE, FALSE, 0);
1555 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1562 mim_config_new (GCallback func, gpointer data)
1564 GtkWidget *tree, *config;
1565 GtkTreeStore *store;
1566 GtkCellRenderer *renderer;
1567 GtkTreeViewColumn *column;
1572 if (merror_code < 0)
1578 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1579 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1582 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1583 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1584 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1585 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1587 var.control.data_type_name = _("Value");
1588 var.control.setup_dialog = variable_setup_dialog;
1589 var.control.update_data = variable_update_data;
1590 var.control.data_string = variable_data_string;
1591 var.control.get = minput_get_variable;
1592 var.control.config = minput_config_variable;
1594 cmd.control.data_type_name = _("Key Bindings");
1595 cmd.control.setup_dialog = command_setup_dialog;
1596 cmd.control.update_data = command_update_data;
1597 cmd.control.data_string = command_data_string;
1598 cmd.control.get = minput_get_command;
1599 cmd.control.config = minput_config_command;
1601 store = make_store_for_input_methods ();
1602 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1603 g_object_unref (G_OBJECT (store));
1605 renderer = gtk_cell_renderer_text_new ();
1606 column = (gtk_tree_view_column_new_with_attributes
1607 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1608 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1610 renderer = gtk_cell_renderer_text_new ();
1611 column = (gtk_tree_view_column_new_with_attributes
1612 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1613 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1615 g_signal_connect (G_OBJECT (tree), "row-expanded",
1616 G_CALLBACK (tree_expanded_cb), NULL);
1617 g_signal_connect (G_OBJECT (tree), "row-activated",
1618 G_CALLBACK (tree_activated_cb), NULL);
1620 config =gtk_scrolled_window_new (NULL, NULL);
1621 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1622 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1623 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1624 g_signal_connect (G_OBJECT (config), "destroy",
1625 G_CALLBACK (destroy_cb), NULL);
1627 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1630 MimConfigCallback *callback;
1632 callback = g_new (MimConfigCallback, 1);
1633 callback->widget = config;
1634 callback->func = (MimConfigCallbackFunc) func;
1635 callback->data = data;
1636 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1644 mim_config_modified (GtkWidget *config)
1647 GtkTreeModel *model;
1648 MimConfigStatus *config_status;
1650 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1651 model = gtk_tree_view_get_model (tree);
1652 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1654 return (config_status->num_modified > 0 ? TRUE : FALSE);
1658 mim_config_revert (GtkWidget *config)
1661 GtkTreeModel *model;
1662 MimConfigStatus *config_status;
1664 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1665 model = gtk_tree_view_get_model (tree);
1666 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1668 if (config_status->num_modified == 0)
1670 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1675 mim_config_save (GtkWidget *config)
1678 GtkTreeModel *model;
1679 MimConfigStatus *config_status;
1681 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1682 model = gtk_tree_view_get_model (tree);
1683 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1685 if (config_status->num_modified == 0)
1687 minput_save_config ();
1688 gtk_tree_model_foreach (model, set_as_saved, config_status);
1693 mim_config_get_tree_view (GtkWidget *config)
1697 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);