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);
474 static int initialized = 0;
477 destroy_cb (GtkWidget *widget, gpointer data)
484 /****************************************************/
485 /* Configuration of a specific variable or command. */
486 /****************************************************/
488 /* Common staffs to variable and command */
492 /* Data type name ("Value" or "Key bindings"). */
493 gchar *data_type_name;
494 MSymbol lang, name, item;
495 /* Fill in widgets in DIALOG for configuring a specific variable or
497 void (*setup_dialog) (GtkWidget *dialog, struct ConfigControl *control);
498 /* Update the contents of DATA widget. */
499 void (*update_data) (struct ConfigControl *control);
500 /* Convert PLIST to string. PLIST is a variable value or command
502 GString *(*data_string) (MPlist *plist);
503 /* minput_get_variable or minput_get_command. */
504 MPlist *(*get) (MSymbol, MSymbol, MSymbol);
505 /* minput_config_variable or minput_config_command. */
506 int (*config) (MSymbol, MSymbol, MSymbol, MPlist *);
507 /* If non-NULL, a function to call before finishing a dialog. */
508 gboolean (*config_on_ok) (struct ConfigControl *control);
510 /* Widget showing the current data (value or key bindings) */
513 /* Button widget to configure the data to the default. */
516 /* Button widget to cancel the configuration. */
519 /* Label widget showing the current status. */
523 struct CommandControl
525 struct ConfigControl control;
539 struct VariableControl
541 struct ConfigControl control;
543 /* type of current variable: Minteger, Msymbol, or Mtext */
547 enum WidgetType wtype;
550 #define CONFIG_CONTROL(control) ((struct ConfigControl *) (control))
551 #define COMMAND_CONTROL(control) ((struct CommandControl *) (control))
552 #define VARIABLE_CONTROL(control) ((struct VariableControl *) (control))
554 #define CURRENT_DATA \
559 (control->get (control->lang, control->name, control->item))))))
561 #define CURRENT_STATUS \
566 (control->get (control->lang, control->name, control->item))))))
568 #define CURRENT_DESCRIPTION \
573 (control->get (control->lang, control->name, control->item)))), \
574 NULL, NULL, NULL, NULL))
576 #define CONFIG_DATA(plist) \
577 control->config (control->lang, control->name, control->item, \
580 static MPlist *entry_keyseq;
583 update_status (struct ConfigControl *control)
585 MSymbol status = CURRENT_STATUS;
587 if (status == Mconfigured)
589 gtk_label_set_text (GTK_LABEL (control->status),
590 mim_status_str[MIM_STATUS_MODIFIED]);
591 gtk_widget_set_sensitive (control->default_, TRUE);
592 gtk_widget_set_sensitive (control->revert, TRUE);
594 else if (status == Mcustomized)
596 gtk_label_set_text (GTK_LABEL (control->status),
597 mim_status_str[MIM_STATUS_CUSTOMIZED]);
598 gtk_widget_set_sensitive (control->default_, TRUE);
599 gtk_widget_set_sensitive (control->revert, FALSE);
603 gtk_label_set_text (GTK_LABEL (control->status),
604 mim_status_str[MIM_STATUS_DEFAULT]);
605 gtk_widget_set_sensitive (control->default_, FALSE);
606 gtk_widget_set_sensitive (control->revert, FALSE);
611 help_cb (GtkButton *button, gpointer data)
613 struct ConfigControl *control = data;
616 msg = gtk_message_dialog_new (GTK_WINDOW
617 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
618 GTK_DIALOG_DESTROY_WITH_PARENT,
621 CURRENT_DESCRIPTION);
622 gtk_dialog_run (GTK_DIALOG (msg));
623 gtk_widget_destroy (msg);
627 default_cb (GtkButton *button, gpointer data)
629 MPlist *empty = mplist ();
630 struct ConfigControl *control = data;
633 m17n_object_unref (empty);
634 control->update_data (control);
635 update_status (control);
636 control->config_on_ok = NULL;
640 revert_cb (GtkButton *button, gpointer data)
642 struct ConfigControl *control = data;
645 control->update_data (control);
646 update_status (control);
647 control->config_on_ok = NULL;
651 ok_cb (GtkButton *button, gpointer data)
653 struct ConfigControl *control = data;
655 if (control->config_on_ok)
657 if (! control->config_on_ok (control))
659 revert_cb (NULL, control);
662 control->config_on_ok = NULL;
664 if (control->config == minput_config_command)
665 m17n_object_unref (entry_keyseq);
666 gtk_dialog_response (GTK_DIALOG
667 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
673 /* Variable or command name */
675 /* Status (default, modified, or customized). */
677 /* Variable value or command key bindings. */
679 /* Number of columns of list store. */
685 set_list_element (GtkListStore *store, GtkTreeIter *iter,
686 struct ConfigControl *control, MPlist *plist)
692 plist = mplist_value (control->get (control->lang, control->name,
694 plist = mplist_next (mplist_next (plist));
696 status = mplist_value (plist);
697 if (status == Mconfigured)
698 status_str = mim_status_str[MIM_STATUS_MODIFIED];
699 else if (status == Mcustomized)
700 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
702 status_str = mim_status_str[MIM_STATUS_DEFAULT];
703 plist = mplist_next (plist);
704 gtk_list_store_set (store, iter,
705 CONFIG_COL_ITEM, msymbol_name (control->item),
706 CONFIG_COL_STATUS, status_str,
707 CONFIG_COL_DATA, control->data_string (plist)->str,
711 /* Called when an item (command or variable) name is activated.
712 Create a dialog widget to config that itme. */
715 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
716 GtkTreeViewColumn *col, gpointer data)
720 GtkWidget *dialog, *label, *help, *hbox, *ok;
722 struct ConfigControl *control = CONFIG_CONTROL (data);
724 model = gtk_tree_view_get_model (parent);
725 if (! gtk_tree_model_get_iter (model, &iter, path))
727 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
728 control->item = msymbol (item);
730 dialog = (gtk_dialog_new_with_buttons
731 (msymbol_name (control->item),
732 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
733 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
735 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
737 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
739 hbox = gtk_hbox_new (FALSE, 12);
740 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
741 label = gtk_label_new (_("Status"));
742 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
743 label = gtk_label_new (": ");
744 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
745 control->status = gtk_label_new (NULL);
746 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
747 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
748 hbox, FALSE, FALSE, 0);
750 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
751 g_signal_connect (G_OBJECT (help), "clicked",
752 G_CALLBACK (help_cb), control);
753 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
754 help, FALSE, FALSE, 0);
755 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
756 g_signal_connect (G_OBJECT (ok), "clicked",
757 G_CALLBACK (ok_cb), control);
758 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
759 ok, FALSE, FALSE, 0);
761 control->setup_dialog (dialog, control);
763 update_status (control);
764 gtk_widget_show_all (dialog);
765 gtk_dialog_run (GTK_DIALOG (dialog));
766 gtk_tree_model_get_iter (model, &iter, path);
767 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
768 gtk_widget_destroy (dialog);
772 /* Create a list view widget listing variable or command names with
773 their current status and data. */
776 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
782 plist = control->get (lang, name, Mnil);
783 /* plist == ((command/variable description status data ...) ...) */
785 return gtk_label_new (_("No customizable item."));
786 store = gtk_list_store_new (NUM_CONFIG_COLS,
787 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
788 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
793 pl = mplist_value (plist);
794 /* pl == (command/variable description status data ...) */
795 control->item = mplist_value (pl);
796 gtk_list_store_append (store, &iter);
797 set_list_element (store, &iter, control, pl);
800 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
801 g_object_unref (G_OBJECT (store));
802 gtk_tree_view_insert_column_with_attributes
803 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
804 "text", CONFIG_COL_ITEM, NULL);
805 gtk_tree_view_insert_column_with_attributes
806 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
807 "text", CONFIG_COL_STATUS, NULL);
808 gtk_tree_view_insert_column_with_attributes
809 (GTK_TREE_VIEW (view), -1, control->data_type_name,
810 gtk_cell_renderer_text_new (),
811 "text", CONFIG_COL_DATA, NULL);
812 g_signal_connect (G_OBJECT (view), "row-activated",
813 G_CALLBACK (item_activated_cb), control);
818 static struct VariableControl var;
819 static struct CommandControl cmd;
822 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
824 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
826 var.control.lang = cmd.control.lang = lang;
827 var.control.name = cmd.control.name = name;
828 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
830 dialog = (gtk_dialog_new_with_buttons
831 (name == Mnil ? "global" : msymbol_name (name),
832 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
833 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
834 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
836 gtk_widget_set_size_request (dialog, 500, 300);
837 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
839 vbox = gtk_vbox_new (FALSE, 0);
840 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
841 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
843 notebook = gtk_notebook_new ();
844 gtk_container_add (GTK_CONTAINER (vbox), notebook);
846 /* Variables' page */
847 scrolled = gtk_scrolled_window_new (NULL, NULL);
848 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
849 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
850 label = gtk_label_new_with_mnemonic (_("_Variables"));
851 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
852 vbox = gtk_vbox_new (FALSE, 0);
853 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
855 gtk_box_pack_start (GTK_BOX (vbox),
856 create_item_list (lang, name, CONFIG_CONTROL (&var)),
859 /* Commands' pages */
860 scrolled = gtk_scrolled_window_new (NULL, NULL);
861 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
862 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
863 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
864 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
865 vbox = gtk_vbox_new (FALSE, 0);
866 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
868 gtk_box_pack_start (GTK_BOX (vbox),
869 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
872 gtk_widget_show_all (dialog);
873 gtk_dialog_run (GTK_DIALOG (dialog));
874 gtk_widget_destroy (dialog);
878 /* Staffs for variable configuration. */
881 variable_update_data (struct ConfigControl *control)
887 plist = CURRENT_DATA;
888 /* plist == (value [valid-value ...]) */
889 key = mplist_key (plist);
890 value = mplist_value (plist);
892 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
895 gtk_entry_set_text (GTK_ENTRY (control->data),
896 msymbol_name ((MSymbol) value));
897 else if (key == Mtext)
898 /* Fixme : Assuming the return value is in UTF-8 */
899 gtk_entry_set_text (GTK_ENTRY (control->data),
900 mtext_data ((MText *) value,
901 NULL, NULL, NULL, NULL));
902 else /* key == Minteger */
905 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
906 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
909 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
913 for (i = 0, plist = mplist_next (plist);
914 plist && mplist_key (plist) == key;
915 i++, plist = mplist_next (plist))
916 if (mplist_value (plist) == value)
918 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
920 else /* ci->wtype == SPIN_BUTTON_WIDGET */
921 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
922 (gdouble) (int) value);
926 config_with_entry (struct ConfigControl *control)
928 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
929 MPlist *plist = mplist ();
932 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
934 mplist_add (plist, Msymbol, msymbol (text));
937 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
941 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
942 mplist_add (plist, Mtext, mt);
944 m17n_object_unref (mt);
946 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
950 if (sscanf (text, "%d", &i) == 1)
952 mplist_add (plist, Minteger, (void *) i);
959 msg = gtk_message_dialog_new (GTK_WINDOW
960 (gtk_widget_get_toplevel (control->data)),
961 GTK_DIALOG_DESTROY_WITH_PARENT,
964 _("The value must be an integer."));
965 gtk_dialog_run (GTK_DIALOG (msg));
966 gtk_widget_destroy (msg);
971 m17n_object_unref (plist);
976 config_with_combo (struct ConfigControl *control)
978 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
979 MPlist *plist = mplist ();
981 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
983 mplist_add (plist, Msymbol, msymbol (text));
986 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
990 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
991 mplist_add (plist, Mtext, mt);
993 m17n_object_unref (mt);
995 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
999 sscanf (text, "%d", &i);
1000 mplist_add (plist, Minteger, (void *) i);
1001 CONFIG_DATA (plist);
1003 m17n_object_unref (plist);
1008 config_with_spin (struct ConfigControl *control)
1010 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
1011 MPlist *plist = mplist ();
1013 mplist_add (plist, Minteger, (void *) i);
1014 CONFIG_DATA (plist);
1015 m17n_object_unref (plist);
1020 changed_cb (GtkEntry *entry, gpointer data)
1022 struct ConfigControl *control = data;
1024 gtk_widget_set_sensitive (control->default_, TRUE);
1025 gtk_widget_set_sensitive (control->revert, TRUE);
1026 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
1027 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
1028 control->config_on_ok = config_with_entry;
1029 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
1030 control->config_on_ok = config_with_combo;
1032 control->config_on_ok = config_with_spin;
1036 variable_data_string (MPlist *plist)
1038 static GString *str;
1041 str = g_string_sized_new (80);
1043 g_string_truncate (str, 0);
1045 if (mplist_key (plist) == Msymbol)
1046 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
1047 else if (mplist_key (plist) == Mtext)
1048 /* Fixme : Assuming the return value is in UTF-8 */
1049 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
1050 NULL, NULL, NULL, NULL));
1051 else /* mplist_key (plist) == Minteger */
1052 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1057 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1061 GtkWidget *hbox, *vbox;
1063 plist = CURRENT_DATA;
1064 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1065 value = mplist_value (plist);
1066 plist = mplist_next (plist);
1068 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1070 if (mplist_key (plist) == Msymbol)
1074 control->data = gtk_combo_box_new_text ();
1075 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1076 for (i = 0; mplist_key (plist) == Msymbol;
1077 plist = mplist_next (plist), i++)
1079 if (mplist_value (plist) == value)
1081 gtk_combo_box_append_text
1082 (GTK_COMBO_BOX (control->data),
1083 msymbol_name ((MSymbol) mplist_value (plist)));
1085 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1086 g_signal_connect (GTK_OBJECT (control->data), "changed",
1087 G_CALLBACK (changed_cb), control);
1091 control->data = gtk_entry_new ();
1092 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1093 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1094 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1095 g_signal_connect (GTK_OBJECT (control->data), "changed",
1096 G_CALLBACK (changed_cb), control);
1097 g_signal_connect (GTK_OBJECT (control->data), "activate",
1098 G_CALLBACK (ok_cb), control);
1101 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1103 if (plist && mplist_key (plist) == Mtext)
1107 control->data = gtk_combo_box_new_text ();
1108 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1109 for (i = 0; plist && mplist_key (plist) == Mtext;
1110 plist = mplist_next (plist), i++)
1112 if (! mtext_cmp ((MText *) mplist_value (plist),
1115 /* Fixme : Assuming the return value is in UTF-8 */
1116 gtk_combo_box_append_text
1117 (GTK_COMBO_BOX (control->data),
1118 mtext_data ((MText *) mplist_value (plist),
1119 NULL, NULL, NULL, NULL));
1121 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1122 g_signal_connect (GTK_OBJECT (control->data), "changed",
1123 G_CALLBACK (changed_cb), control);
1127 control->data = gtk_entry_new ();
1128 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1129 /* Fixme : Assuming the return value is in UTF-8 */
1130 gtk_entry_set_text (GTK_ENTRY (control->data),
1131 mtext_data (value, NULL, NULL, NULL, NULL));
1132 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1133 g_signal_connect (GTK_OBJECT (control->data), "changed",
1134 G_CALLBACK (changed_cb), control);
1135 g_signal_connect (GTK_OBJECT (control->data), "activate",
1136 G_CALLBACK (ok_cb), control);
1139 else /* control->vtype == Minteger */
1141 if (plist && mplist_key (plist) == Minteger)
1145 control->data = gtk_combo_box_new_text ();
1146 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1147 for (i = 0; plist && mplist_key (plist) == Minteger;
1148 plist = mplist_next (plist), i++)
1152 if (mplist_value (plist) == value)
1154 g_snprintf (buf, sizeof (buf), "%d",
1155 (gint) mplist_value (plist));
1156 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1158 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1159 g_signal_connect (GTK_OBJECT (control->data), "changed",
1160 G_CALLBACK (changed_cb), control);
1162 else if (plist && mplist_key (plist) == Mplist)
1165 gdouble lower, upper;
1167 plist = mplist_value (plist);
1168 lower = (gdouble) (int) mplist_value (plist);
1169 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1170 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1172 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1173 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1174 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1175 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1177 g_signal_connect (GTK_OBJECT (control->data), "changed",
1178 G_CALLBACK (changed_cb), control);
1184 control->data = gtk_entry_new ();
1185 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1186 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1187 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1188 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1189 g_signal_connect (GTK_OBJECT (control->data), "changed",
1190 G_CALLBACK (changed_cb), control);
1191 g_signal_connect (GTK_OBJECT (control->data), "activate",
1192 G_CALLBACK (ok_cb), control);
1196 control->default_ = gtk_button_new_from_stock (_("_Default"));
1197 g_signal_connect (G_OBJECT (control->default_), "clicked",
1198 G_CALLBACK (default_cb), control);
1200 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1201 g_signal_connect (G_OBJECT (control->revert), "clicked",
1202 G_CALLBACK (revert_cb), control);
1204 hbox = gtk_hbutton_box_new ();
1205 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1206 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1207 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1208 vbox = gtk_vbox_new (FALSE, 12);
1209 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1210 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1211 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1212 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1213 vbox, FALSE, FALSE, 0);
1214 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1218 /* Staffs for command configuration. */
1221 selection_cb (GtkTreeSelection *selection, gpointer data)
1223 gtk_widget_set_sensitive
1224 (COMMAND_CONTROL (data)->delete,
1225 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1229 delete_cb (GtkButton *button, gpointer data)
1231 GtkTreeSelection *selection;
1232 GtkTreeModel *model;
1235 struct ConfigControl *control = data;
1237 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1238 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1240 if (! gtk_tree_model_get_iter_first (model, &iter))
1244 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1246 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1247 mplist_add (new, Mplist, mplist_value (pl));
1248 gtk_tree_model_iter_next (model, &iter);
1251 m17n_object_unref (new);
1252 control->update_data (control);
1253 update_status (control);
1257 create_deleting_section (struct ConfigControl *control)
1259 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1260 GtkListStore *store;
1261 GtkWidget *label, *scrolled, *hbox, *vbox;
1262 GtkTreeViewColumn *column;
1263 GtkCellRenderer *renderer;
1264 GtkTreeSelection *selection;
1266 label = gtk_label_new (_("Current key bindings:"));
1268 store = gtk_list_store_new (1, G_TYPE_STRING);
1269 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1270 g_object_unref (G_OBJECT (store));
1271 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1272 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1273 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1274 g_signal_connect (G_OBJECT (selection), "changed",
1275 G_CALLBACK (selection_cb), control);
1277 scrolled = gtk_scrolled_window_new (NULL, NULL);
1278 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1279 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1280 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1283 column = gtk_tree_view_column_new ();
1284 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1285 renderer = gtk_cell_renderer_text_new ();
1286 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1287 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1289 control->update_data (control);
1291 control->default_ = gtk_button_new_from_stock (_("_Default"));
1292 g_signal_connect (G_OBJECT (control->default_), "clicked",
1293 G_CALLBACK (default_cb), control);
1295 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1296 g_signal_connect (G_OBJECT (control->revert), "clicked",
1297 G_CALLBACK (revert_cb), control);
1299 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1300 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1301 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1302 G_CALLBACK (delete_cb), control);
1304 vbox = gtk_vbox_new (FALSE, 12);
1305 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1307 hbox = gtk_hbox_new (FALSE, 6);
1308 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1309 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1311 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1313 hbox = gtk_hbutton_box_new ();
1314 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1315 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1316 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1317 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1318 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1319 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1324 static unsigned modifier_state = 0;
1328 ALT_MASK_BIT = META_MASK_BIT << 1,
1329 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1330 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1334 update_entry (GtkEntry *entry)
1336 if (mplist_key (entry_keyseq) == Mnil)
1337 gtk_entry_set_text (entry, "");
1343 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1344 gtk_entry_set_text (entry, name);
1345 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1346 p = mplist_next (p))
1348 name = msymbol_name ((MSymbol) mplist_value (p));
1349 gtk_entry_append_text (entry, " ");
1350 gtk_entry_append_text (entry, name);
1352 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1357 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1364 struct CommandControl *cmd_control = data;
1366 c = gdk_keyval_to_unicode (event->keyval);
1369 switch (event->keyval)
1371 case GDK_Meta_L: case GDK_Meta_R:
1372 modifier_state |= META_MASK_BIT; return TRUE;
1373 case GDK_Alt_L: case GDK_Alt_R:
1374 modifier_state |= ALT_MASK_BIT; return TRUE;
1375 case GDK_Super_L: case GDK_Super_R:
1376 modifier_state |= SUPER_MASK_BIT; return TRUE;
1377 case GDK_Hyper_L: case GDK_Hyper_R:
1378 modifier_state |= HYPER_MASK_BIT; return TRUE;
1380 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1383 name = gdk_keyval_name (event->keyval);
1386 nbytes = strlen (name);
1392 mtext_cat_char (mt, c);
1393 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1394 (unsigned char *) name, 32);
1395 m17n_object_unref (mt);
1398 if (c == 0 && event->state & GDK_SHIFT_MASK)
1399 buf[i++] = 'S', buf[i++] = '-';
1400 if (event->state & GDK_CONTROL_MASK)
1401 buf[i++] = 'C', buf[i++] = '-';
1402 if (modifier_state & META_MASK_BIT)
1403 buf[i++] = 'M', buf[i++] = '-';
1404 if (modifier_state & ALT_MASK_BIT)
1405 buf[i++] = 'A', buf[i++] = '-';
1406 if (modifier_state & SUPER_MASK_BIT)
1407 buf[i++] = 's', buf[i++] = '-';
1408 if (modifier_state & HYPER_MASK_BIT)
1409 buf[i++] = 'H', buf[i++] = '-';
1410 strncpy (buf + i, name, nbytes);
1411 buf[i + nbytes] = 0;
1412 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1413 update_entry (entry);
1414 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1415 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1420 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1424 c = gdk_keyval_to_unicode (event->keyval);
1427 switch (event->keyval)
1429 case GDK_Meta_L: case GDK_Meta_R:
1430 modifier_state &= ~META_MASK_BIT; break;
1431 case GDK_Alt_L: case GDK_Alt_R:
1432 modifier_state &= ~ALT_MASK_BIT; break;
1433 case GDK_Super_L: case GDK_Super_R:
1434 modifier_state &= ~SUPER_MASK_BIT; break;
1435 case GDK_Hyper_L: case GDK_Hyper_R:
1436 modifier_state &= ~HYPER_MASK_BIT; break;
1443 clear_cb (GtkButton *button, gpointer data)
1445 struct CommandControl *cmd_control = data;
1447 mplist_set (entry_keyseq, Mnil, NULL);
1448 gtk_widget_grab_focus (cmd_control->entry);
1449 update_entry (GTK_ENTRY (cmd_control->entry));
1450 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1451 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1455 add_cb (GtkButton *button, gpointer data)
1458 GtkTreeModel *model;
1460 struct ConfigControl *control = data;
1462 if (mplist_length (entry_keyseq) == 0)
1464 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1465 if (gtk_tree_model_get_iter_first (model, &iter))
1467 gchar *keyseq = control->data_string (entry_keyseq)->str;
1471 gtk_tree_model_get (model, &iter, 0, &str, -1);
1472 if (strcmp (keyseq, str) == 0)
1473 /* entry_keyseq is already registered. */
1475 } while (gtk_tree_model_iter_next (model, &iter));
1477 new = mplist_copy (CURRENT_DATA);
1478 mplist_add (new, Mplist, entry_keyseq);
1480 m17n_object_unref (new);
1481 control->update_data (control);
1482 update_status (control);
1483 clear_cb (NULL, control);
1487 create_adding_section (struct ConfigControl *control)
1489 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1490 GtkWidget *label, *hbox, *vbox;
1492 label = gtk_label_new (_("New key binding:"));
1494 entry_keyseq = mplist ();
1495 cmd_control->entry = gtk_entry_new ();
1496 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1497 G_CALLBACK (key_pressed_cb), cmd_control);
1498 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1499 G_CALLBACK (key_released_cb), cmd_control);
1501 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1502 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1503 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1504 G_CALLBACK (clear_cb), cmd_control);
1506 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1507 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1508 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1509 G_CALLBACK (add_cb), cmd_control);
1511 vbox = gtk_vbox_new (FALSE, 12);
1512 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1514 hbox = gtk_hbox_new (FALSE, 6);
1515 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1516 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1518 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1520 hbox = gtk_hbutton_box_new ();
1521 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1522 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1523 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1524 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1525 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1531 append_key_sequence (GString *str, MPlist *keyseq)
1533 static MSymbol space_symbol;
1537 space_symbol = msymbol (" ");
1539 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1541 MSymbol key = (MSymbol) mplist_value (p);
1544 g_string_append_c (str, ' ');
1545 if (key == space_symbol)
1546 g_string_append (str, "Space");
1548 g_string_append (str, msymbol_name (key));
1553 command_data_string (MPlist *plist)
1555 static GString *str;
1558 str = g_string_sized_new (80);
1560 g_string_truncate (str, 0);
1562 if (mplist_key (plist) == Mplist)
1566 /* PLIST == ((KEY KEY ...) ...) */
1567 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1570 g_string_append (str, ", ");
1571 append_key_sequence (str, mplist_value (pl));
1576 /* PLIST == (KEY KEY ...) */
1577 append_key_sequence (str, plist);
1583 command_update_data (struct ConfigControl *control)
1585 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1586 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1590 gtk_list_store_clear (store);
1591 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1593 gtk_list_store_append (store, &iter);
1594 gtk_list_store_set (store, &iter,
1595 0, control->data_string (mplist_value (pl))->str,
1601 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1603 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1604 create_deleting_section (control), FALSE, FALSE, 0);
1605 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1606 create_adding_section (control), FALSE, FALSE, 0);
1607 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1614 mim_config_new (GCallback func, gpointer data)
1616 GtkWidget *tree, *config;
1617 GtkTreeStore *store;
1618 GtkCellRenderer *renderer;
1619 GtkTreeViewColumn *column;
1624 if (merror_code < 0)
1630 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1631 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1634 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1635 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1636 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1637 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1639 var.control.data_type_name = _("Value");
1640 var.control.setup_dialog = variable_setup_dialog;
1641 var.control.update_data = variable_update_data;
1642 var.control.data_string = variable_data_string;
1643 var.control.get = minput_get_variable;
1644 var.control.config = minput_config_variable;
1646 cmd.control.data_type_name = _("Key Bindings");
1647 cmd.control.setup_dialog = command_setup_dialog;
1648 cmd.control.update_data = command_update_data;
1649 cmd.control.data_string = command_data_string;
1650 cmd.control.get = minput_get_command;
1651 cmd.control.config = minput_config_command;
1653 store = make_store_for_input_methods ();
1654 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1655 g_object_unref (G_OBJECT (store));
1657 renderer = gtk_cell_renderer_text_new ();
1658 column = (gtk_tree_view_column_new_with_attributes
1659 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1660 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1662 renderer = gtk_cell_renderer_text_new ();
1663 column = (gtk_tree_view_column_new_with_attributes
1664 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1665 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1667 g_signal_connect (G_OBJECT (tree), "row-expanded",
1668 G_CALLBACK (tree_expanded_cb), NULL);
1669 g_signal_connect (G_OBJECT (tree), "row-activated",
1670 G_CALLBACK (tree_activated_cb), NULL);
1672 config =gtk_scrolled_window_new (NULL, NULL);
1673 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1674 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1675 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1676 g_signal_connect (G_OBJECT (config), "destroy",
1677 G_CALLBACK (destroy_cb), NULL);
1679 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1682 MimConfigCallback *callback;
1684 callback = g_new (MimConfigCallback, 1);
1685 callback->widget = config;
1686 callback->func = (MimConfigCallbackFunc) func;
1687 callback->data = data;
1688 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1696 mim_config_modified (GtkWidget *config)
1699 GtkTreeModel *model;
1700 MimConfigStatus *config_status;
1702 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1703 model = gtk_tree_view_get_model (tree);
1704 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1706 return (config_status->num_modified > 0 ? TRUE : FALSE);
1710 mim_config_revert (GtkWidget *config)
1713 GtkTreeModel *model;
1714 MimConfigStatus *config_status;
1716 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1717 model = gtk_tree_view_get_model (tree);
1718 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1720 if (config_status->num_modified == 0)
1722 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1727 mim_config_save (GtkWidget *config)
1730 GtkTreeModel *model;
1731 MimConfigStatus *config_status;
1733 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1734 model = gtk_tree_view_get_model (tree);
1735 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1737 if (config_status->num_modified == 0)
1739 minput_save_config ();
1740 gtk_tree_model_foreach (model, set_as_saved, config_status);
1745 mim_config_get_tree_view (GtkWidget *config)
1749 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);