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);
277 result = strcmp (t1->lang, t2->lang);
280 return (result ? result : strcmp (t1->name, t2->name));
283 static GtkTreeStore *
284 make_store_for_input_methods ()
290 char *lang, *other = _("Other");
291 GtkTreeIter iter1, iter2;
292 enum MimStatus status;
293 MimConfigStatus *config_status;
294 unsigned char conv_buf[256];
295 MConverter *converter;
296 int locale_is_utf8 = 0;
300 Meng = msymbol ("eng");
301 store = gtk_tree_store_new (NUM_COLS,
302 G_TYPE_STRING, /* COL_TAG */
303 G_TYPE_STRING, /* COL_STATUS_STR */
304 G_TYPE_UINT, /* COL_STATUS */
305 G_TYPE_POINTER, /* COL_LANG */
306 G_TYPE_POINTER /* COL_NAME */
309 config_status = g_new0 (MimConfigStatus, 1);
310 gtk_tree_store_append (store, &iter1, NULL);
311 status = get_mim_status (Mt, Mnil);
312 gtk_tree_store_set (store, &iter1,
313 COL_TAG, _("global"),
314 COL_STATUS_STR, mim_status_str[status],
320 imlist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
321 config_status->num_im = mplist_length (imlist);
322 imtable = g_newa (MimTable, config_status->num_im);
325 MLocale *locale = mlocale_set (LC_MESSAGES, NULL);
326 MSymbol coding = locale ? mlocale_get_prop (locale, Mcoding) : Mnil;
330 else if (coding == msymbol ("utf-8"))
337 converter = mconv_buffer_converter (coding, conv_buf, sizeof conv_buf);
339 converter->last_block = 1;
343 for (i = 0, p = imlist; mplist_key (p) != Mnil; p = mplist_next (p))
345 MDatabase *mdb = (MDatabase *) mplist_value (p);
346 MSymbol *tag = mdatabase_tag (mdb);
349 if (tag[1] == Mnil || tag[2] == Mnil)
352 imtable[i].symlang = tag[1];
353 imtable[i].symname = tag[2];
354 imtable[i].name = msymbol_name (tag[2]);
355 imtable[i].lang = imtable[i].encoded_lang = NULL;
356 imtable[i].lang_in_locale = 0;
360 pl = mlanguage_name_list (tag[1], Mnil, Mnil, Mnil);
362 imtable[i].lang_in_locale = 1;
364 pl = mlanguage_name_list (tag[1], Meng, Mnil, Mnil);
367 MText *mt = mplist_value (pl);
372 mconv_reset_converter (converter);
373 nbytes = mconv_encode (converter, mt);
374 if (converter->result == MCONVERSION_RESULT_SUCCESS)
376 imtable[i].encoded_lang = alloca (nbytes + 1);
377 if (imtable[i].encoded_lang)
379 memcpy (imtable[i].encoded_lang, conv_buf, nbytes);
380 imtable[i].encoded_lang[nbytes] = '\0';
384 else if (locale_is_utf8)
385 imtable[i].encoded_lang
386 = mtext_data (mt, NULL, NULL, NULL, NULL);
387 imtable[i].lang = mtext_data (mt, NULL, NULL, NULL, NULL);
390 imtable[i].lang = msymbol_name (tag[1]);
395 mconv_free_converter (converter);
396 m17n_object_unref (imlist);
397 config_status->num_im = i;
398 qsort (imtable, config_status->num_im, sizeof (MimTable), sort_im);
400 for (lang = NULL, i = 0; i < config_status->num_im; i++)
402 gchar *langname = imtable[i].lang;
406 if (lang != langname)
408 gtk_tree_store_append (store, &iter1, NULL);
409 gtk_tree_store_set (store, &iter1,
411 COL_STATUS_STR, NULL,
418 gtk_tree_store_append (store, &iter2, &iter1);
419 gtk_tree_store_set (store, &iter2,
420 COL_TAG, imtable[i].name,
421 COL_STATUS_STR, NULL,
422 COL_LANG, imtable[i].symlang,
423 COL_NAME, imtable[i].symname,
426 config_status->num_modified = 0;
427 g_object_set_data_full (G_OBJECT (store), CONFIG_STATUS_DATA,
428 config_status, g_free);
433 revert_to_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
436 enum MimStatus status;
438 MimConfigStatus *config_status = data;
440 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
443 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
444 if (status != MIM_STATUS_MODIFIED)
446 minput_config_variable (lang, name, Mnil, NULL);
447 minput_config_command (lang, name, Mnil, NULL);
448 status = get_mim_status (lang, name);
449 update_child_row (model, iter, status, config_status, NULL);
454 set_as_saved (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
457 enum MimStatus status;
459 MimConfigStatus *config_status = data;
461 gtk_tree_model_get (model, iter, COL_LANG, &lang, COL_NAME, &name, -1);
464 gtk_tree_model_get (model, iter, COL_STATUS, &status, -1);
465 if (status != MIM_STATUS_MODIFIED)
467 status = get_mim_status (lang, name);
468 update_child_row (model, iter, status, config_status, NULL);
472 static int initialized = 0;
475 destroy_cb (GtkWidget *widget, gpointer data)
482 /****************************************************/
483 /* Configuration of a specific variable or command. */
484 /****************************************************/
486 /* Common staffs to variable and command */
490 /* Data type name ("Value" or "Key bindings"). */
491 gchar *data_type_name;
492 MSymbol lang, name, item;
493 /* Fill in widgets in DIALOG for configuring a specific variable or
495 void (*setup_dialog) (GtkWidget *dialog, struct ConfigControl *control);
496 /* Update the contents of DATA widget. */
497 void (*update_data) (struct ConfigControl *control);
498 /* Convert PLIST to string. PLIST is a variable value or command
500 GString *(*data_string) (MPlist *plist);
501 /* minput_get_variable or minput_get_command. */
502 MPlist *(*get) (MSymbol, MSymbol, MSymbol);
503 /* minput_config_variable or minput_config_command. */
504 int (*config) (MSymbol, MSymbol, MSymbol, MPlist *);
505 /* If non-NULL, a function to call before finishing a dialog. */
506 gboolean (*config_on_ok) (struct ConfigControl *control);
508 /* Widget showing the current data (value or key bindings) */
511 /* Button widget to configure the data to the default. */
514 /* Button widget to cancel the configuration. */
517 /* Label widget showing the current status. */
521 struct CommandControl
523 struct ConfigControl control;
537 struct VariableControl
539 struct ConfigControl control;
541 /* type of current variable: Minteger, Msymbol, or Mtext */
545 enum WidgetType wtype;
548 #define CONFIG_CONTROL(control) ((struct ConfigControl *) (control))
549 #define COMMAND_CONTROL(control) ((struct CommandControl *) (control))
550 #define VARIABLE_CONTROL(control) ((struct VariableControl *) (control))
552 #define CURRENT_DATA \
557 (control->get (control->lang, control->name, control->item))))))
559 #define CURRENT_STATUS \
564 (control->get (control->lang, control->name, control->item))))))
566 #define CURRENT_DESCRIPTION \
571 (control->get (control->lang, control->name, control->item)))), \
572 NULL, NULL, NULL, NULL))
574 #define CONFIG_DATA(plist) \
575 control->config (control->lang, control->name, control->item, \
578 static MPlist *entry_keyseq;
581 update_status (struct ConfigControl *control)
583 MSymbol status = CURRENT_STATUS;
585 if (status == Mconfigured)
587 gtk_label_set_text (GTK_LABEL (control->status),
588 mim_status_str[MIM_STATUS_MODIFIED]);
589 gtk_widget_set_sensitive (control->default_, TRUE);
590 gtk_widget_set_sensitive (control->revert, TRUE);
592 else if (status == Mcustomized)
594 gtk_label_set_text (GTK_LABEL (control->status),
595 mim_status_str[MIM_STATUS_CUSTOMIZED]);
596 gtk_widget_set_sensitive (control->default_, TRUE);
597 gtk_widget_set_sensitive (control->revert, FALSE);
601 gtk_label_set_text (GTK_LABEL (control->status),
602 mim_status_str[MIM_STATUS_DEFAULT]);
603 gtk_widget_set_sensitive (control->default_, FALSE);
604 gtk_widget_set_sensitive (control->revert, FALSE);
609 help_cb (GtkButton *button, gpointer data)
611 struct ConfigControl *control = data;
614 msg = gtk_message_dialog_new (GTK_WINDOW
615 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
616 GTK_DIALOG_DESTROY_WITH_PARENT,
619 CURRENT_DESCRIPTION);
620 gtk_dialog_run (GTK_DIALOG (msg));
621 gtk_widget_destroy (msg);
625 default_cb (GtkButton *button, gpointer data)
627 MPlist *empty = mplist ();
628 struct ConfigControl *control = data;
631 m17n_object_unref (empty);
632 control->update_data (control);
633 update_status (control);
634 control->config_on_ok = NULL;
638 revert_cb (GtkButton *button, gpointer data)
640 struct ConfigControl *control = data;
643 control->update_data (control);
644 update_status (control);
645 control->config_on_ok = NULL;
649 ok_cb (GtkButton *button, gpointer data)
651 struct ConfigControl *control = data;
653 if (control->config_on_ok)
655 if (! control->config_on_ok (control))
657 revert_cb (NULL, control);
660 control->config_on_ok = NULL;
662 if (control->config == minput_config_command)
663 m17n_object_unref (entry_keyseq);
664 gtk_dialog_response (GTK_DIALOG
665 (gtk_widget_get_toplevel (GTK_WIDGET (button))),
671 /* Variable or command name */
673 /* Status (default, modified, or customized). */
675 /* Variable value or command key bindings. */
677 /* Number of columns of list store. */
683 set_list_element (GtkListStore *store, GtkTreeIter *iter,
684 struct ConfigControl *control, MPlist *plist)
690 plist = mplist_value (control->get (control->lang, control->name,
692 plist = mplist_next (mplist_next (plist));
694 status = mplist_value (plist);
695 if (status == Mconfigured)
696 status_str = mim_status_str[MIM_STATUS_MODIFIED];
697 else if (status == Mcustomized)
698 status_str = mim_status_str[MIM_STATUS_CUSTOMIZED];
700 status_str = mim_status_str[MIM_STATUS_DEFAULT];
701 plist = mplist_next (plist);
702 gtk_list_store_set (store, iter,
703 CONFIG_COL_ITEM, msymbol_name (control->item),
704 CONFIG_COL_STATUS, status_str,
705 CONFIG_COL_DATA, control->data_string (plist)->str,
709 /* Called when an item (command or variable) name is activated.
710 Create a dialog widget to config that itme. */
713 item_activated_cb (GtkTreeView *parent, GtkTreePath *path,
714 GtkTreeViewColumn *col, gpointer data)
718 GtkWidget *dialog, *label, *help, *hbox, *ok;
720 struct ConfigControl *control = CONFIG_CONTROL (data);
722 model = gtk_tree_view_get_model (parent);
723 if (! gtk_tree_model_get_iter (model, &iter, path))
725 gtk_tree_model_get (model, &iter, CONFIG_COL_ITEM, &item, -1);
726 control->item = msymbol (item);
728 dialog = (gtk_dialog_new_with_buttons
729 (msymbol_name (control->item),
730 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
731 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
733 gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area),
735 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
737 hbox = gtk_hbox_new (FALSE, 12);
738 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
739 label = gtk_label_new (_("Status"));
740 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
741 label = gtk_label_new (": ");
742 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
743 control->status = gtk_label_new (NULL);
744 gtk_box_pack_start (GTK_BOX (hbox), control->status, FALSE, FALSE, 0);
745 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
746 hbox, FALSE, FALSE, 0);
748 help = gtk_button_new_from_stock (GTK_STOCK_HELP);
749 g_signal_connect (G_OBJECT (help), "clicked",
750 G_CALLBACK (help_cb), control);
751 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
752 help, FALSE, FALSE, 0);
753 ok = gtk_button_new_from_stock (GTK_STOCK_OK);
754 g_signal_connect (G_OBJECT (ok), "clicked",
755 G_CALLBACK (ok_cb), control);
756 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area),
757 ok, FALSE, FALSE, 0);
759 control->setup_dialog (dialog, control);
761 update_status (control);
762 gtk_widget_show_all (dialog);
763 gtk_dialog_run (GTK_DIALOG (dialog));
764 gtk_tree_model_get_iter (model, &iter, path);
765 set_list_element (GTK_LIST_STORE (model), &iter, control, NULL);
766 gtk_widget_destroy (dialog);
770 /* Create a list view widget listing variable or command names with
771 their current status and data. */
774 create_item_list (MSymbol lang, MSymbol name, struct ConfigControl *control)
780 plist = control->get (lang, name, Mnil);
781 /* plist == ((command/variable description status data ...) ...) */
783 return gtk_label_new (_("No customizable item."));
784 store = gtk_list_store_new (NUM_CONFIG_COLS,
785 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
786 for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
791 pl = mplist_value (plist);
792 /* pl == (command/variable description status data ...) */
793 control->item = mplist_value (pl);
794 gtk_list_store_append (store, &iter);
795 set_list_element (store, &iter, control, pl);
798 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
799 g_object_unref (G_OBJECT (store));
800 gtk_tree_view_insert_column_with_attributes
801 (GTK_TREE_VIEW (view), -1, _("Name"), gtk_cell_renderer_text_new (),
802 "text", CONFIG_COL_ITEM, NULL);
803 gtk_tree_view_insert_column_with_attributes
804 (GTK_TREE_VIEW (view), -1, _("Status"), gtk_cell_renderer_text_new (),
805 "text", CONFIG_COL_STATUS, NULL);
806 gtk_tree_view_insert_column_with_attributes
807 (GTK_TREE_VIEW (view), -1, control->data_type_name,
808 gtk_cell_renderer_text_new (),
809 "text", CONFIG_COL_DATA, NULL);
810 g_signal_connect (G_OBJECT (view), "row-activated",
811 G_CALLBACK (item_activated_cb), control);
816 static struct VariableControl var;
817 static struct CommandControl cmd;
820 config_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
822 GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
824 var.control.lang = cmd.control.lang = lang;
825 var.control.name = cmd.control.name = name;
826 var.control.config_on_ok = cmd.control.config_on_ok = NULL;
828 dialog = (gtk_dialog_new_with_buttons
829 (name == Mnil ? "global" : msymbol_name (name),
830 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
831 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
832 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
834 gtk_widget_set_size_request (dialog, 500, 300);
835 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
837 vbox = gtk_vbox_new (FALSE, 0);
838 gtk_container_set_border_width (GTK_CONTAINER(vbox), 5);
839 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
841 notebook = gtk_notebook_new ();
842 gtk_container_add (GTK_CONTAINER (vbox), notebook);
844 /* Variables' page */
845 scrolled = gtk_scrolled_window_new (NULL, NULL);
846 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
847 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
848 label = gtk_label_new_with_mnemonic (_("_Variables"));
849 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
850 vbox = gtk_vbox_new (FALSE, 0);
851 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
853 gtk_box_pack_start (GTK_BOX (vbox),
854 create_item_list (lang, name, CONFIG_CONTROL (&var)),
857 /* Commands' pages */
858 scrolled = gtk_scrolled_window_new (NULL, NULL);
859 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
860 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
861 label = gtk_label_new_with_mnemonic (_("Co_mmands"));
862 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
863 vbox = gtk_vbox_new (FALSE, 0);
864 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
866 gtk_box_pack_start (GTK_BOX (vbox),
867 create_item_list (lang, name, CONFIG_CONTROL (&cmd)),
870 gtk_widget_show_all (dialog);
871 gtk_dialog_run (GTK_DIALOG (dialog));
872 gtk_widget_destroy (dialog);
876 /* Staffs for variable configuration. */
879 variable_update_data (struct ConfigControl *control)
885 plist = CURRENT_DATA;
886 /* plist == (value [valid-value ...]) */
887 key = mplist_key (plist);
888 value = mplist_value (plist);
890 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
893 gtk_entry_set_text (GTK_ENTRY (control->data),
894 msymbol_name ((MSymbol) value));
895 else if (key == Mtext)
896 /* Fixme : Assuming the return value is in UTF-8 */
897 gtk_entry_set_text (GTK_ENTRY (control->data),
898 mtext_data ((MText *) value,
899 NULL, NULL, NULL, NULL));
900 else /* key == Minteger */
903 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
904 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
907 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
911 for (i = 0, plist = mplist_next (plist);
912 plist && mplist_key (plist) == key;
913 i++, plist = mplist_next (plist))
914 if (mplist_value (plist) == value)
916 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), i);
918 else /* ci->wtype == SPIN_BUTTON_WIDGET */
919 gtk_spin_button_set_value (GTK_SPIN_BUTTON (control->data),
920 (gdouble) (int) value);
924 config_with_entry (struct ConfigControl *control)
926 const gchar *text = gtk_entry_get_text (GTK_ENTRY (control->data));
927 MPlist *plist = mplist ();
930 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
932 mplist_add (plist, Msymbol, msymbol (text));
935 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
939 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
940 mplist_add (plist, Mtext, mt);
942 m17n_object_unref (mt);
944 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
948 if (sscanf (text, "%d", &i) == 1)
950 mplist_add (plist, Minteger, (void *) i);
957 msg = gtk_message_dialog_new (GTK_WINDOW
958 (gtk_widget_get_toplevel (control->data)),
959 GTK_DIALOG_DESTROY_WITH_PARENT,
962 _("The value must be an integer."));
963 gtk_dialog_run (GTK_DIALOG (msg));
964 gtk_widget_destroy (msg);
969 m17n_object_unref (plist);
974 config_with_combo (struct ConfigControl *control)
976 gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (control->data));
977 MPlist *plist = mplist ();
979 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
981 mplist_add (plist, Msymbol, msymbol (text));
984 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
988 mt = mconv_decode_buffer (Mcoding_utf_8, (guchar *) text, strlen (text));
989 mplist_add (plist, Mtext, mt);
991 m17n_object_unref (mt);
993 else /* VARIABLE_CONTROL (control)->vtype == Minteger */
997 sscanf (text, "%d", &i);
998 mplist_add (plist, Minteger, (void *) i);
1001 m17n_object_unref (plist);
1006 config_with_spin (struct ConfigControl *control)
1008 gint i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (control->data));
1009 MPlist *plist = mplist ();
1011 mplist_add (plist, Minteger, (void *) i);
1012 CONFIG_DATA (plist);
1013 m17n_object_unref (plist);
1018 changed_cb (GtkEntry *entry, gpointer data)
1020 struct ConfigControl *control = data;
1022 gtk_widget_set_sensitive (control->default_, TRUE);
1023 gtk_widget_set_sensitive (control->revert, TRUE);
1024 gtk_label_set_text (GTK_LABEL (control->status), _("modified"));
1025 if (VARIABLE_CONTROL (control)->wtype == ENTRY_WIDGET)
1026 control->config_on_ok = config_with_entry;
1027 else if (VARIABLE_CONTROL (control)->wtype == COMBO_BOX_WIDGET)
1028 control->config_on_ok = config_with_combo;
1030 control->config_on_ok = config_with_spin;
1034 variable_data_string (MPlist *plist)
1036 static GString *str;
1039 str = g_string_sized_new (80);
1041 g_string_truncate (str, 0);
1043 if (mplist_key (plist) == Msymbol)
1044 g_string_append (str, msymbol_name ((MSymbol) mplist_value (plist)));
1045 else if (mplist_key (plist) == Mtext)
1046 /* Fixme : Assuming the return value is in UTF-8 */
1047 g_string_append (str, mtext_data ((MText *) mplist_value (plist),
1048 NULL, NULL, NULL, NULL));
1049 else /* mplist_key (plist) == Minteger */
1050 g_string_append_printf (str, "%d", (gint) mplist_value (plist));
1055 variable_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1059 GtkWidget *hbox, *vbox;
1061 plist = CURRENT_DATA;
1062 VARIABLE_CONTROL (control)->vtype = mplist_key (plist);
1063 value = mplist_value (plist);
1064 plist = mplist_next (plist);
1066 if (VARIABLE_CONTROL (control)->vtype == Msymbol)
1068 if (mplist_key (plist) == Msymbol)
1072 control->data = gtk_combo_box_new_text ();
1073 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1074 for (i = 0; mplist_key (plist) == Msymbol;
1075 plist = mplist_next (plist), i++)
1077 if (mplist_value (plist) == value)
1079 gtk_combo_box_append_text
1080 (GTK_COMBO_BOX (control->data),
1081 msymbol_name ((MSymbol) mplist_value (plist)));
1083 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1084 g_signal_connect (GTK_OBJECT (control->data), "changed",
1085 G_CALLBACK (changed_cb), control);
1089 control->data = gtk_entry_new ();
1090 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1091 gtk_entry_set_text (GTK_ENTRY (control->data), msymbol_name (value));
1092 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1093 g_signal_connect (GTK_OBJECT (control->data), "changed",
1094 G_CALLBACK (changed_cb), control);
1095 g_signal_connect (GTK_OBJECT (control->data), "activate",
1096 G_CALLBACK (ok_cb), control);
1099 else if (VARIABLE_CONTROL (control)->vtype == Mtext)
1101 if (plist && mplist_key (plist) == Mtext)
1105 control->data = gtk_combo_box_new_text ();
1106 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1107 for (i = 0; plist && mplist_key (plist) == Mtext;
1108 plist = mplist_next (plist), i++)
1110 if (! mtext_cmp ((MText *) mplist_value (plist),
1113 /* Fixme : Assuming the return value is in UTF-8 */
1114 gtk_combo_box_append_text
1115 (GTK_COMBO_BOX (control->data),
1116 mtext_data ((MText *) mplist_value (plist),
1117 NULL, NULL, NULL, NULL));
1119 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1120 g_signal_connect (GTK_OBJECT (control->data), "changed",
1121 G_CALLBACK (changed_cb), control);
1125 control->data = gtk_entry_new ();
1126 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1127 /* Fixme : Assuming the return value is in UTF-8 */
1128 gtk_entry_set_text (GTK_ENTRY (control->data),
1129 mtext_data (value, NULL, NULL, NULL, NULL));
1130 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1131 g_signal_connect (GTK_OBJECT (control->data), "changed",
1132 G_CALLBACK (changed_cb), control);
1133 g_signal_connect (GTK_OBJECT (control->data), "activate",
1134 G_CALLBACK (ok_cb), control);
1137 else /* control->vtype == Minteger */
1139 if (plist && mplist_key (plist) == Minteger)
1143 control->data = gtk_combo_box_new_text ();
1144 VARIABLE_CONTROL (control)->wtype = COMBO_BOX_WIDGET;
1145 for (i = 0; plist && mplist_key (plist) == Minteger;
1146 plist = mplist_next (plist), i++)
1150 if (mplist_value (plist) == value)
1152 g_snprintf (buf, sizeof (buf), "%d",
1153 (gint) mplist_value (plist));
1154 gtk_combo_box_append_text (GTK_COMBO_BOX (control->data), buf);
1156 gtk_combo_box_set_active (GTK_COMBO_BOX (control->data), nth);
1157 g_signal_connect (GTK_OBJECT (control->data), "changed",
1158 G_CALLBACK (changed_cb), control);
1160 else if (plist && mplist_key (plist) == Mplist)
1163 gdouble lower, upper;
1165 plist = mplist_value (plist);
1166 lower = (gdouble) (int) mplist_value (plist);
1167 upper = (gdouble) (int) mplist_value (mplist_next (plist));
1168 adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
1170 control->data = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
1171 VARIABLE_CONTROL (control)->wtype = SPIN_BUTTON_WIDGET;
1172 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (control->data), TRUE);
1173 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (control->data),
1175 g_signal_connect (GTK_OBJECT (control->data), "changed",
1176 G_CALLBACK (changed_cb), control);
1182 control->data = gtk_entry_new ();
1183 VARIABLE_CONTROL (control)->wtype = ENTRY_WIDGET;
1184 g_snprintf (buf, sizeof (buf), "%d", (gint) value);
1185 gtk_entry_set_text (GTK_ENTRY (control->data), buf);
1186 gtk_editable_set_editable (GTK_EDITABLE (control->data), TRUE);
1187 g_signal_connect (GTK_OBJECT (control->data), "changed",
1188 G_CALLBACK (changed_cb), control);
1189 g_signal_connect (GTK_OBJECT (control->data), "activate",
1190 G_CALLBACK (ok_cb), control);
1194 control->default_ = gtk_button_new_from_stock (_("_Default"));
1195 g_signal_connect (G_OBJECT (control->default_), "clicked",
1196 G_CALLBACK (default_cb), control);
1198 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1199 g_signal_connect (G_OBJECT (control->revert), "clicked",
1200 G_CALLBACK (revert_cb), control);
1202 hbox = gtk_hbutton_box_new ();
1203 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1204 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1205 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1206 vbox = gtk_vbox_new (FALSE, 12);
1207 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1208 gtk_box_pack_start (GTK_BOX (vbox), control->data, FALSE, FALSE, 0);
1209 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1210 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1211 vbox, FALSE, FALSE, 0);
1212 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1216 /* Staffs for command configuration. */
1219 selection_cb (GtkTreeSelection *selection, gpointer data)
1221 gtk_widget_set_sensitive
1222 (COMMAND_CONTROL (data)->delete,
1223 gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
1227 delete_cb (GtkButton *button, gpointer data)
1229 GtkTreeSelection *selection;
1230 GtkTreeModel *model;
1233 struct ConfigControl *control = data;
1235 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1236 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1238 if (! gtk_tree_model_get_iter_first (model, &iter))
1242 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1244 if (! gtk_tree_selection_iter_is_selected (selection, &iter))
1245 mplist_add (new, Mplist, mplist_value (pl));
1246 gtk_tree_model_iter_next (model, &iter);
1249 m17n_object_unref (new);
1250 control->update_data (control);
1251 update_status (control);
1255 create_deleting_section (struct ConfigControl *control)
1257 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1258 GtkListStore *store;
1259 GtkWidget *label, *scrolled, *hbox, *vbox;
1260 GtkTreeViewColumn *column;
1261 GtkCellRenderer *renderer;
1262 GtkTreeSelection *selection;
1264 label = gtk_label_new (_("Current key bindings:"));
1266 store = gtk_list_store_new (1, G_TYPE_STRING);
1267 control->data = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1268 g_object_unref (G_OBJECT (store));
1269 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (control->data), FALSE);
1270 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (control->data));
1271 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1272 g_signal_connect (G_OBJECT (selection), "changed",
1273 G_CALLBACK (selection_cb), control);
1275 scrolled = gtk_scrolled_window_new (NULL, NULL);
1276 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1277 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1278 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1281 column = gtk_tree_view_column_new ();
1282 gtk_tree_view_append_column (GTK_TREE_VIEW (control->data), column);
1283 renderer = gtk_cell_renderer_text_new ();
1284 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1285 gtk_tree_view_column_set_attributes (column, renderer, "text", 0, NULL);
1287 control->update_data (control);
1289 control->default_ = gtk_button_new_from_stock (_("_Default"));
1290 g_signal_connect (G_OBJECT (control->default_), "clicked",
1291 G_CALLBACK (default_cb), control);
1293 control->revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
1294 g_signal_connect (G_OBJECT (control->revert), "clicked",
1295 G_CALLBACK (revert_cb), control);
1297 cmd_control->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
1298 gtk_widget_set_sensitive (cmd_control->delete, FALSE);
1299 g_signal_connect (G_OBJECT (cmd_control->delete), "clicked",
1300 G_CALLBACK (delete_cb), control);
1302 vbox = gtk_vbox_new (FALSE, 12);
1303 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1305 hbox = gtk_hbox_new (FALSE, 6);
1306 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1307 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1309 gtk_container_add (GTK_CONTAINER (vbox), scrolled);
1311 hbox = gtk_hbutton_box_new ();
1312 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1313 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1314 gtk_container_add (GTK_CONTAINER (hbox), control->default_);
1315 gtk_container_add (GTK_CONTAINER (hbox), control->revert);
1316 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->delete);
1317 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1322 static unsigned modifier_state = 0;
1326 ALT_MASK_BIT = META_MASK_BIT << 1,
1327 SUPER_MASK_BIT = ALT_MASK_BIT << 1,
1328 HYPER_MASK_BIT = SUPER_MASK_BIT << 1
1332 update_entry (GtkEntry *entry)
1334 if (mplist_key (entry_keyseq) == Mnil)
1335 gtk_entry_set_text (entry, "");
1341 name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
1342 gtk_entry_set_text (entry, name);
1343 for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
1344 p = mplist_next (p))
1346 name = msymbol_name ((MSymbol) mplist_value (p));
1347 gtk_entry_append_text (entry, " ");
1348 gtk_entry_append_text (entry, name);
1350 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
1355 key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1362 struct CommandControl *cmd_control = data;
1364 c = gdk_keyval_to_unicode (event->keyval);
1367 switch (event->keyval)
1369 case GDK_Meta_L: case GDK_Meta_R:
1370 modifier_state |= META_MASK_BIT; return TRUE;
1371 case GDK_Alt_L: case GDK_Alt_R:
1372 modifier_state |= ALT_MASK_BIT; return TRUE;
1373 case GDK_Super_L: case GDK_Super_R:
1374 modifier_state |= SUPER_MASK_BIT; return TRUE;
1375 case GDK_Hyper_L: case GDK_Hyper_R:
1376 modifier_state |= HYPER_MASK_BIT; return TRUE;
1378 if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
1381 name = gdk_keyval_name (event->keyval);
1384 nbytes = strlen (name);
1390 mtext_cat_char (mt, c);
1391 nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
1392 (unsigned char *) name, 32);
1393 m17n_object_unref (mt);
1396 if (c == 0 && event->state & GDK_SHIFT_MASK)
1397 buf[i++] = 'S', buf[i++] = '-';
1398 if (event->state & GDK_CONTROL_MASK)
1399 buf[i++] = 'C', buf[i++] = '-';
1400 if (modifier_state & META_MASK_BIT)
1401 buf[i++] = 'M', buf[i++] = '-';
1402 if (modifier_state & ALT_MASK_BIT)
1403 buf[i++] = 'A', buf[i++] = '-';
1404 if (modifier_state & SUPER_MASK_BIT)
1405 buf[i++] = 's', buf[i++] = '-';
1406 if (modifier_state & HYPER_MASK_BIT)
1407 buf[i++] = 'H', buf[i++] = '-';
1408 strncpy (buf + i, name, nbytes);
1409 buf[i + nbytes] = 0;
1410 mplist_add (entry_keyseq, Msymbol, msymbol (buf));
1411 update_entry (entry);
1412 gtk_widget_set_sensitive (cmd_control->clear, TRUE);
1413 gtk_widget_set_sensitive (cmd_control->add, TRUE);
1418 key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
1422 c = gdk_keyval_to_unicode (event->keyval);
1425 switch (event->keyval)
1427 case GDK_Meta_L: case GDK_Meta_R:
1428 modifier_state &= ~META_MASK_BIT; break;
1429 case GDK_Alt_L: case GDK_Alt_R:
1430 modifier_state &= ~ALT_MASK_BIT; break;
1431 case GDK_Super_L: case GDK_Super_R:
1432 modifier_state &= ~SUPER_MASK_BIT; break;
1433 case GDK_Hyper_L: case GDK_Hyper_R:
1434 modifier_state &= ~HYPER_MASK_BIT; break;
1441 clear_cb (GtkButton *button, gpointer data)
1443 struct CommandControl *cmd_control = data;
1445 mplist_set (entry_keyseq, Mnil, NULL);
1446 gtk_widget_grab_focus (cmd_control->entry);
1447 update_entry (GTK_ENTRY (cmd_control->entry));
1448 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1449 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1453 add_cb (GtkButton *button, gpointer data)
1456 GtkTreeModel *model;
1458 struct ConfigControl *control = data;
1460 if (mplist_length (entry_keyseq) == 0)
1462 model = gtk_tree_view_get_model (GTK_TREE_VIEW (control->data));
1463 if (gtk_tree_model_get_iter_first (model, &iter))
1465 gchar *keyseq = control->data_string (entry_keyseq)->str;
1469 gtk_tree_model_get (model, &iter, 0, &str, -1);
1470 if (strcmp (keyseq, str) == 0)
1471 /* entry_keyseq is already registered. */
1473 } while (gtk_tree_model_iter_next (model, &iter));
1475 new = mplist_copy (CURRENT_DATA);
1476 mplist_add (new, Mplist, entry_keyseq);
1478 m17n_object_unref (new);
1479 control->update_data (control);
1480 update_status (control);
1481 clear_cb (NULL, control);
1485 create_adding_section (struct ConfigControl *control)
1487 struct CommandControl *cmd_control = COMMAND_CONTROL (control);
1488 GtkWidget *label, *hbox, *vbox;
1490 label = gtk_label_new (_("New key binding:"));
1492 entry_keyseq = mplist ();
1493 cmd_control->entry = gtk_entry_new ();
1494 g_signal_connect (G_OBJECT (cmd_control->entry), "key-press-event",
1495 G_CALLBACK (key_pressed_cb), cmd_control);
1496 g_signal_connect (G_OBJECT (cmd_control->entry), "key-release-event",
1497 G_CALLBACK (key_released_cb), cmd_control);
1499 cmd_control->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1500 gtk_widget_set_sensitive (cmd_control->clear, FALSE);
1501 g_signal_connect (G_OBJECT (cmd_control->clear), "clicked",
1502 G_CALLBACK (clear_cb), cmd_control);
1504 cmd_control->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1505 gtk_widget_set_sensitive (cmd_control->add, FALSE);
1506 g_signal_connect (G_OBJECT (cmd_control->add), "clicked",
1507 G_CALLBACK (add_cb), cmd_control);
1509 vbox = gtk_vbox_new (FALSE, 12);
1510 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1512 hbox = gtk_hbox_new (FALSE, 6);
1513 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1514 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1516 gtk_container_add (GTK_CONTAINER (vbox), cmd_control->entry);
1518 hbox = gtk_hbutton_box_new ();
1519 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
1520 gtk_box_set_spacing (GTK_BOX (hbox), 6);
1521 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->clear);
1522 gtk_container_add (GTK_CONTAINER (hbox), cmd_control->add);
1523 gtk_container_add (GTK_CONTAINER (vbox), hbox);
1529 append_key_sequence (GString *str, MPlist *keyseq)
1531 static MSymbol space_symbol;
1535 space_symbol = msymbol (" ");
1537 for (p = keyseq ; mplist_key (p) != Mnil; p = mplist_next (p))
1539 MSymbol key = (MSymbol) mplist_value (p);
1542 g_string_append_c (str, ' ');
1543 if (key == space_symbol)
1544 g_string_append (str, "Space");
1546 g_string_append (str, msymbol_name (key));
1551 command_data_string (MPlist *plist)
1553 static GString *str;
1556 str = g_string_sized_new (80);
1558 g_string_truncate (str, 0);
1560 if (mplist_key (plist) == Mplist)
1564 /* PLIST == ((KEY KEY ...) ...) */
1565 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1568 g_string_append (str, ", ");
1569 append_key_sequence (str, mplist_value (pl));
1574 /* PLIST == (KEY KEY ...) */
1575 append_key_sequence (str, plist);
1581 command_update_data (struct ConfigControl *control)
1583 GtkTreeView *tree = GTK_TREE_VIEW (control->data);
1584 GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
1588 gtk_list_store_clear (store);
1589 for (pl = CURRENT_DATA; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1591 gtk_list_store_append (store, &iter);
1592 gtk_list_store_set (store, &iter,
1593 0, control->data_string (mplist_value (pl))->str,
1599 command_setup_dialog (GtkWidget *dialog, struct ConfigControl *control)
1601 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1602 create_deleting_section (control), FALSE, FALSE, 0);
1603 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1604 create_adding_section (control), FALSE, FALSE, 0);
1605 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
1612 mim_config_new (GCallback func, gpointer data)
1614 GtkWidget *tree, *config;
1615 GtkTreeStore *store;
1616 GtkCellRenderer *renderer;
1617 GtkTreeViewColumn *column;
1622 if (merror_code < 0)
1628 bindtextdomain ("m17n-im-config", GETTEXTDIR);
1629 bind_textdomain_codeset ("m17n-im-config", "UTF-8");
1632 mim_status_str[MIM_STATUS_DEFAULT] = _("default");
1633 mim_status_str[MIM_STATUS_CUSTOMIZED] = _("customized");
1634 mim_status_str[MIM_STATUS_MODIFIED] = _("modified");
1635 mim_status_str[MIM_STATUS_NO] = _("uncustomizable");
1637 var.control.data_type_name = _("Value");
1638 var.control.setup_dialog = variable_setup_dialog;
1639 var.control.update_data = variable_update_data;
1640 var.control.data_string = variable_data_string;
1641 var.control.get = minput_get_variable;
1642 var.control.config = minput_config_variable;
1644 cmd.control.data_type_name = _("Key Bindings");
1645 cmd.control.setup_dialog = command_setup_dialog;
1646 cmd.control.update_data = command_update_data;
1647 cmd.control.data_string = command_data_string;
1648 cmd.control.get = minput_get_command;
1649 cmd.control.config = minput_config_command;
1651 store = make_store_for_input_methods ();
1652 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1653 g_object_unref (G_OBJECT (store));
1655 renderer = gtk_cell_renderer_text_new ();
1656 column = (gtk_tree_view_column_new_with_attributes
1657 (_("Input Method"), renderer, "text", COL_TAG, NULL));
1658 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1660 renderer = gtk_cell_renderer_text_new ();
1661 column = (gtk_tree_view_column_new_with_attributes
1662 (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
1663 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1665 g_signal_connect (G_OBJECT (tree), "row-expanded",
1666 G_CALLBACK (tree_expanded_cb), NULL);
1667 g_signal_connect (G_OBJECT (tree), "row-activated",
1668 G_CALLBACK (tree_activated_cb), NULL);
1670 config =gtk_scrolled_window_new (NULL, NULL);
1671 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (config),
1672 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1673 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (config), tree);
1674 g_signal_connect (G_OBJECT (config), "destroy",
1675 G_CALLBACK (destroy_cb), NULL);
1677 g_object_set_data (G_OBJECT (config), CONFIG_TREE_VIEW, tree);
1680 MimConfigCallback *callback;
1682 callback = g_new (MimConfigCallback, 1);
1683 callback->widget = config;
1684 callback->func = (MimConfigCallbackFunc) func;
1685 callback->data = data;
1686 g_object_set_data_full (G_OBJECT (tree), CONFIG_CALLBACK_DATA,
1694 mim_config_modified (GtkWidget *config)
1697 GtkTreeModel *model;
1698 MimConfigStatus *config_status;
1700 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1701 model = gtk_tree_view_get_model (tree);
1702 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1704 return (config_status->num_modified > 0 ? TRUE : FALSE);
1708 mim_config_revert (GtkWidget *config)
1711 GtkTreeModel *model;
1712 MimConfigStatus *config_status;
1714 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1715 model = gtk_tree_view_get_model (tree);
1716 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1718 if (config_status->num_modified == 0)
1720 gtk_tree_model_foreach (model, revert_to_saved, config_status);
1725 mim_config_save (GtkWidget *config)
1728 GtkTreeModel *model;
1729 MimConfigStatus *config_status;
1731 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);
1732 model = gtk_tree_view_get_model (tree);
1733 config_status = g_object_get_data (G_OBJECT (model), CONFIG_STATUS_DATA);
1735 if (config_status->num_modified == 0)
1737 minput_save_config ();
1738 gtk_tree_model_foreach (model, set_as_saved, config_status);
1743 mim_config_get_tree_view (GtkWidget *config)
1747 tree = g_object_get_data (G_OBJECT (config), CONFIG_TREE_VIEW);