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);
1165 /* Staffs for command configuration. */
1168 selection_cb (GtkTreeSelection *selection, gpointer data)
1170 gtk_widget_set_sensitive
1171 (COMMAND_CONTROL (data)->delete,
1172 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1176 delete_cb (GtkButton *button, gpointer data)
1178 GtkTreeSelection *selection;
1179 GtkTreeModel *model;
1182 struct ConfigControl *control = data;
1184 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1185 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1187 if (! gtk_tree_model_get_iter_first (model, &iter))
1191 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1193 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1194 mplist_add (new, Mplist, mplist_value (pl));
1195 gtk_tree_model_iter_next (model, &iter);
1198 m17n_object_unref (new);
1199 control->update_data (control);
1200 update_status (control);
1204 create_deleting_section (struct ConfigControl *control)
1206 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1207 GtkListStore *store;
1208 GtkWidget *label, *scrolled, *hbox, *vbox;
1209 GtkTreeViewColumn *column;
1210 GtkCellRenderer *renderer;
1211 GtkTreeSelection *selection;
1213 label = gtk_label_new (_("Current key bindings:"));
1215 store = gtk_list_store_new (1, G_TYPE_STRING);
1216 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1217 g_object_unref (G_OBJECT (store));
1218 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1219 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1220 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1221 g_signal_connect (G_OBJECT (selection), "changed",
1222 G_CALLBACK (selection_cb), control);
1224 scrolled = gtk_scrolled_window_new (NULL, NULL);
1225 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1226 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1227 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1230 column = gtk_tree_view_column_new ();
1231 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1232 renderer = gtk_cell_renderer_text_new ();
1233 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1234 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1236 control->update_data (control);
1238 control->default_ = gtk_button_new_from_stock (_("_Default"));
1239 g_signal_connect (G_OBJECT (control->default_), "clicked",
1240 G_CALLBACK (default_cb), control);
1242 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1243 g_signal_connect (G_OBJECT (control->revert), "clicked",
1244 G_CALLBACK (revert_cb), control);
1246 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1247 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1248 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1249 G_CALLBACK (delete_cb), control);
1251 vbox = gtk_vbox_new (FALSE, 5);
1252 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1254 hbox = gtk_hbox_new (FALSE, 6);
1255 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
1256 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1258 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1260 hbox = gtk_hbutton_box_new ();
1261 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1262 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1263 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1264 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1265 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1266 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1271 static unsigned modifier_state = 0;
1275 ALT_MASK_BIT = META_MASK_BIT << 1,
1276 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1277 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1281 update_entry (GtkEntry *entry)
1283 if (mplist_key (entry_keyseq) == Mnil)
1284 gtk_entry_set_text (entry, "");
1290 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1291 gtk_entry_set_text (entry, name);
1292 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1293 p = mplist_next (p))
1295 name = msymbol_name ((MSymbol) mplist_value (p));
1296 gtk_entry_append_text (entry, " ");
1297 gtk_entry_append_text (entry, name);
1299 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1304 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1311 struct CommandControl *cmd_control = data;
1313 c = gdk_keyval_to_unicode (event->keyval);
1316 switch (event->keyval)
1318 case GDK_Meta_L: case GDK_Meta_R:
1319 modifier_state |= META_MASK_BIT; return TRUE;
1320 case GDK_Alt_L: case GDK_Alt_R:
1321 modifier_state |= ALT_MASK_BIT; return TRUE;
1322 case GDK_Super_L: case GDK_Super_R:
1323 modifier_state |= SUPER_MASK_BIT; return TRUE;
1324 case GDK_Hyper_L: case GDK_Hyper_R:
1325 modifier_state |= HYPER_MASK_BIT; return TRUE;
1327 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1330 name = gdk_keyval_name (event->keyval);
1333 nbytes = strlen (name);
1339 mtext_cat_char (mt, c);
1340 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1341 (unsigned char *) name, 32);
1342 m17n_object_unref (mt);
1345 if (c == 0 && event->state & GDK_SHIFT_MASK)
1346 buf[i++] = 'S', buf[i++] = '-';
1347 if (event->state & GDK_CONTROL_MASK)
1348 buf[i++] = 'C', buf[i++] = '-';
1349 if (modifier_state & META_MASK_BIT)
1350 buf[i++] = 'M', buf[i++] = '-';
1351 if (modifier_state & ALT_MASK_BIT)
1352 buf[i++] = 'A', buf[i++] = '-';
1353 if (modifier_state & SUPER_MASK_BIT)
1354 buf[i++] = 's', buf[i++] = '-';
1355 if (modifier_state & HYPER_MASK_BIT)
1356 buf[i++] = 'H', buf[i++] = '-';
1357 strncpy (buf + i, name, nbytes);
1358 buf[i + nbytes] = 0;
1359 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1360 update_entry (entry);
1361 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1362 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1367 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1371 c = gdk_keyval_to_unicode (event->keyval);
1374 switch (event->keyval)
1376 case GDK_Meta_L: case GDK_Meta_R:
1377 modifier_state &= ~META_MASK_BIT; break;
1378 case GDK_Alt_L: case GDK_Alt_R:
1379 modifier_state &= ~ALT_MASK_BIT; break;
1380 case GDK_Super_L: case GDK_Super_R:
1381 modifier_state &= ~SUPER_MASK_BIT; break;
1382 case GDK_Hyper_L: case GDK_Hyper_R:
1383 modifier_state &= ~HYPER_MASK_BIT; break;
1390 clear_cb (GtkButton *button, gpointer data)
1392 struct CommandControl *cmd_control = data;
1394 mplist_set (entry_keyseq, Mnil, NULL);
1395 gtk_widget_grab_focus (cmd_control->entry);
1396 update_entry (GTK_ENTRY (cmd_control->entry));
1397 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1398 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1402 add_cb (GtkButton *button, gpointer data)
1405 GtkTreeModel *model;
1407 struct ConfigControl *control = data;
1409 if (mplist_length (entry_keyseq) == 0)
1411 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1412 if (gtk_tree_model_get_iter_first (model, &iter))
1414 gchar *keyseq = control->data_string (entry_keyseq)->str;
1418 gtk_tree_model_get (model, &iter, 0, &str, -1);
1419 if (strcmp (keyseq, str) == 0)
1420 /* entry_keyseq is already registered. */
1422 } while (gtk_tree_model_iter_next (model, &iter));
1424 new = mplist_copy (CURRENT_DATA);
1425 mplist_add (new, Mplist, entry_keyseq);
1427 m17n_object_unref (new);
1428 control->update_data (control);
1429 update_status (control);
1430 clear_cb (NULL, control);
1434 create_adding_section (struct ConfigControl *control)
1436 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1437 GtkWidget *label, *hbox, *vbox;
1439 label = gtk_label_new (_("New key binding:"));
1441 entry_keyseq = mplist ();
1442 cmd_control->entry = gtk_entry_new ();
1443 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1444 G_CALLBACK (key_pressed_cb), cmd_control);
1445 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1446 G_CALLBACK (key_released_cb), cmd_control);
1448 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1449 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1450 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1451 G_CALLBACK (clear_cb), cmd_control);
1453 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1454 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1455 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1456 G_CALLBACK (add_cb), cmd_control);
1458 vbox = gtk_vbox_new (FALSE, 5);
1459 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1461 hbox = gtk_hbox_new (FALSE, 6);
1462 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
1463 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1465 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1467 hbox = gtk_hbutton_box_new ();
1468 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1469 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1470 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1471 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1472 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1478 append_key_sequence (GString *str, MPlist *keyseq)
1480 static MSymbol space_symbol;
1484 space_symbol = msymbol (" ");
1486 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1488 MSymbol key = (MSymbol) mplist_value (p);
1491 g_string_append_c (str, ' ');
1492 if (key == space_symbol)
1493 g_string_append (str, "Space");
1495 g_string_append (str, msymbol_name (key));
1500 command_data_string (MPlist *plist)
1502 static GString *str;
1505 str = g_string_sized_new (80);
1507 g_string_truncate (str, 0);
1509 if (mplist_key (plist) == Mplist)
1513 /* PLIST == ((KEY KEY ...) ...) */
1514 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1517 g_string_append (str, ", ");
1518 append_key_sequence (str, mplist_value (pl));
1523 /* PLIST == (KEY KEY ...) */
1524 append_key_sequence (str, plist);
1530 command_update_data (struct ConfigControl *control)
1532 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1533 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1537 gtk_list_store_clear (store);
1538 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1540 gtk_list_store_append (store, &iter);
1541 gtk_list_store_set (store, &iter,
1542 0, control->data_string (mplist_value (pl))->str,
1548 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1550 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1551 create_deleting_section (control), FALSE, FALSE, 0);
1552 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1553 create_adding_section (control), FALSE, FALSE, 0);
1560 mim_config_new (GCallback func, gpointer data)
1562 GtkWidget *tree, *config;
1563 GtkTreeStore *store;
1564 GtkCellRenderer *renderer;
1565 GtkTreeViewColumn *column;
1570 if (merror_code < 0)
1576 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1577 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1580 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1581 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1582 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1583 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1585 var.control.data_type_name = _("Value");
1586 var.control.setup_dialog = variable_setup_dialog;
1587 var.control.update_data = variable_update_data;
1588 var.control.data_string = variable_data_string;
1589 var.control.get = minput_get_variable;
1590 var.control.config = minput_config_variable;
1592 cmd.control.data_type_name = _("Key Bindings");
1593 cmd.control.setup_dialog = command_setup_dialog;
1594 cmd.control.update_data = command_update_data;
1595 cmd.control.data_string = command_data_string;
1596 cmd.control.get = minput_get_command;
1597 cmd.control.config = minput_config_command;
1599 store = make_store_for_input_methods ();
1600 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1601 g_object_unref (G_OBJECT (store));
1603 renderer = gtk_cell_renderer_text_new ();
1604 column = (gtk_tree_view_column_new_with_attributes
1605 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1606 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1608 renderer = gtk_cell_renderer_text_new ();
1609 column = (gtk_tree_view_column_new_with_attributes
1610 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1611 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1613 g_signal_connect (G_OBJECT (tree), "row-expanded",
1614 G_CALLBACK (tree_expanded_cb), NULL);
1615 g_signal_connect (G_OBJECT (tree), "row-activated",
1616 G_CALLBACK (tree_activated_cb), NULL);
1618 config =gtk_scrolled_window_new (NULL, NULL);
1619 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1620 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1621 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1622 g_signal_connect (G_OBJECT (config), "destroy",
1623 G_CALLBACK (destroy_cb), NULL);
1625 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1628 MimConfigCallback *callback;
1630 callback = g_new (MimConfigCallback, 1);
1631 callback->widget = config;
1632 callback->func = (MimConfigCallbackFunc) func;
1633 callback->data = data;
1634 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1642 mim_config_modified (GtkWidget *config)
1645 GtkTreeModel *model;
1646 MimConfigStatus *config_status;
1648 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1649 model = gtk_tree_view_get_model (tree);
1650 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1652 return (config_status->num_modified > 0 ? TRUE : FALSE);
1656 mim_config_revert (GtkWidget *config)
1659 GtkTreeModel *model;
1660 MimConfigStatus *config_status;
1662 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1663 model = gtk_tree_view_get_model (tree);
1664 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1666 if (config_status->num_modified == 0)
1668 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1673 mim_config_save (GtkWidget *config)
1676 GtkTreeModel *model;
1677 MimConfigStatus *config_status;
1679 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1680 model = gtk_tree_view_get_model (tree);
1681 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1683 if (config_status->num_modified == 0)
1685 minput_save_config ();
1686 gtk_tree_model_foreach (model, set_as_saved, config_status);
1691 mim_config_get_tree_view (GtkWidget *config)
1695 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);