*** empty log message ***
authorntakahas <ntakahas>
Thu, 12 Apr 2007 07:47:39 +0000 (07:47 +0000)
committerntakahas <ntakahas>
Thu, 12 Apr 2007 07:47:39 +0000 (07:47 +0000)
src/Makefile.am
src/command.c [new file with mode: 0644]
src/mim-config.c
src/variable.c [new file with mode: 0644]

index e938300..329877d 100644 (file)
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -DGETTEXTDIR=\"@GETTEXTDIR@\"
 
 lib_LTLIBRARIES = libm17n-im-config.la
 
-libm17n_im_config_la_SOURCES = m17n-im-config.h mim-config.c
+libm17n_im_config_la_SOURCES = m17n-im-config.h mim-config.c variable.c command.c
 libm17n_im_config_la_LIBADD = @GTK2_LIBS@ @M17NLIB_LIBS@
 
 if ENABLE_PROG
diff --git a/src/command.c b/src/command.c
new file mode 100644 (file)
index 0000000..b58d4b3
--- /dev/null
@@ -0,0 +1,412 @@
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+#include <m17n.h>
+
+static MSymbol current_lang, current_name, current_command;
+
+static MPlist *
+get_command_bindings (MSymbol lang, MSymbol name, MSymbol command)
+{
+  return (mplist_next
+         (mplist_next
+          (mplist_next
+           (mplist_value
+            (minput_get_command (lang, name, command))))));
+}
+
+static int
+keyseq_equal (MPlist *pl1, MPlist *pl2)
+{
+  if (mplist_length (pl1) != mplist_length (pl2))
+    return 0;
+  while (pl1 && mplist_key (pl1) == Msymbol)
+    {
+      if (mplist_value (pl1) != mplist_value (pl2))
+       return 0;
+      pl1 = mplist_next (pl1);
+      pl2 = mplist_next (pl2);
+    }
+  return 1;
+}
+
+static void
+keyseq_render_function (GtkTreeViewColumn *column,
+                       GtkCellRenderer *renderer,
+                       GtkTreeModel *model,
+                       GtkTreeIter *iter,
+                       gpointer data)
+{
+  MPlist *keyseq, *pl;
+  gint n;
+  gchar buf[1024];
+
+  gtk_tree_model_get (model, iter, 0, &keyseq, -1);
+  for (pl = keyseq, n = 0;
+       pl && mplist_key (pl) == Msymbol;
+       pl = mplist_next (pl))
+    n += strlen (msymbol_name ((MSymbol) mplist_value (pl))) + 1;
+  if (n < sizeof (buf))
+    {
+      buf[0] = '\0';
+      for (pl = keyseq;
+          pl && mplist_key (pl) == Msymbol;
+          pl = mplist_next (pl))
+       {
+         strcat (buf, msymbol_name ((MSymbol) mplist_value (pl)));
+         strcat (buf, " ");
+       }
+      g_object_set (renderer, "foreground-set", FALSE, NULL);
+    }
+  else
+    {
+      g_snprintf (buf, sizeof (buf), "Too long to display");
+      g_object_set (renderer, "foreground", "Red", "foreground-set", TRUE,
+                   NULL);
+    }
+  g_object_set (renderer, "text", buf, NULL);
+}
+
+static void
+delete_cb (GtkButton *button, GtkWidget *view)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  MPlist *keyseq, *old, *new, *pl;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
+
+      old = get_command_bindings (current_lang, current_name, current_command);
+      new = mplist ();
+      for (pl = old; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
+       if (! keyseq_equal (mplist_value (pl), keyseq))
+         mplist_add (new, Mplist, mplist_value (pl));
+      minput_config_command (current_lang, current_name, current_command, new);
+      m17n_object_unref (new);
+      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+    }
+}
+  
+
+static void
+delete_keyseq (GtkWidget *view, MSymbol lang, MSymbol name, MSymbol command)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  MPlist *keyseq, *old, *new, *pl;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
+      old = get_command_bindings (lang, name, command);
+      new = mplist ();
+      for (pl = old;
+          pl && mplist_key (pl) == Mplist;
+          pl = mplist_next (pl))
+       if (! keyseq_equal (mplist_value (pl), keyseq))
+         mplist_add (new, Mplist, mplist_value (pl));
+      minput_config_command (lang, name, command, new);
+      m17n_object_unref (new);
+      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+    }
+}
+
+static MPlist *entry_keyseq;
+
+static void
+update_entry (GtkEntry *entry)
+{
+  if (mplist_key (entry_keyseq) == Mnil)
+    gtk_entry_set_text (entry, "");
+  else
+    {
+      MPlist *p;
+      gchar *name;
+
+      name = msymbol_name ((MSymbol) mplist_value (entry_keyseq));
+      gtk_entry_set_text (entry, name);
+      for (p = mplist_next (entry_keyseq); mplist_key (p) != Mnil;
+          p = mplist_next (p))
+       {
+         name = msymbol_name ((MSymbol) mplist_value (p));
+         gtk_entry_append_text (entry, " ");
+         gtk_entry_append_text (entry, name);
+       }
+      gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+    }
+}
+
+enum KeyMaskBit {
+  META_MASK_BIT = 1,
+  ALT_MASK_BIT = META_MASK_BIT << 1,
+  SUPER_MASK_BIT = ALT_MASK_BIT << 1,
+  HYPER_MASK_BIT = SUPER_MASK_BIT << 1
+};
+
+static unsigned modifier_state = 0;
+
+gboolean
+key_pressed (GtkEntry *entry, GdkEventKey *event, gpointer data)
+{
+  guint c;
+  MText *mt;
+  char buf[32];
+  char *name;
+  int nbytes, i;
+
+  c = gdk_keyval_to_unicode (event->keyval);
+  if (c == 0)
+    {
+      switch (event->keyval)
+       {
+       case GDK_Meta_L: case GDK_Meta_R:
+         modifier_state |= META_MASK_BIT; return TRUE;
+       case GDK_Alt_L: case GDK_Alt_R:
+         modifier_state |= ALT_MASK_BIT; return TRUE;
+       case GDK_Super_L: case GDK_Super_R:
+         modifier_state |= SUPER_MASK_BIT; return TRUE;
+       case GDK_Hyper_L: case GDK_Hyper_R:
+         modifier_state |= HYPER_MASK_BIT; return TRUE;
+       default:
+         if (event->keyval >= GDK_Shift_L && event->keyval <= GDK_Shift_Lock)
+           return TRUE;
+       }
+      name = gdk_keyval_name (event->keyval);
+      if (! name)
+       return TRUE;
+      nbytes = strlen (name);
+    }
+  else
+    {
+      name = alloca (8);
+      mt = mtext ();
+      mtext_cat_char (mt, c);
+      nbytes = mconv_encode_buffer (msymbol ("utf-8"), mt,
+                                   (unsigned char *) name, 32);
+      m17n_object_unref (mt);
+    }
+  i = 0;
+  if (c == 0 && event->state & GDK_SHIFT_MASK)
+    buf[i++] = 'S', buf[i++] = '-';
+  if (event->state & GDK_CONTROL_MASK)
+    buf[i++] = 'C', buf[i++] = '-';
+  if (modifier_state & META_MASK_BIT)
+    buf[i++] = 'M', buf[i++] = '-';
+  if (modifier_state & ALT_MASK_BIT)
+    buf[i++] = 'A', buf[i++] = '-';
+  if (modifier_state & SUPER_MASK_BIT)
+    buf[i++] = 's', buf[i++] = '-';
+  if (modifier_state & HYPER_MASK_BIT)
+    buf[i++] = 'H', buf[i++] = '-';
+  strncpy (buf + i, name, nbytes);
+  buf[i + nbytes] = 0;
+  mplist_add (entry_keyseq, Msymbol, msymbol (buf));
+  update_entry (entry);
+  return TRUE;
+}
+
+gboolean
+key_released (GtkEntry *entry, GdkEventKey *event, gpointer data)
+{
+  guint c;
+
+  c = gdk_keyval_to_unicode (event->keyval);
+  if (c == 0)
+    {
+      switch (event->keyval)
+       {
+       case GDK_Meta_L: case GDK_Meta_R:
+         modifier_state &= ~META_MASK_BIT; break;
+       case GDK_Alt_L: case GDK_Alt_R:
+         modifier_state &= ~ALT_MASK_BIT; break;
+       case GDK_Super_L: case GDK_Super_R:
+         modifier_state &= ~SUPER_MASK_BIT; break;
+       case GDK_Hyper_L: case GDK_Hyper_R:
+         modifier_state &= ~HYPER_MASK_BIT; break;
+       }
+    }
+  return FALSE;
+}
+
+static void
+clear_cb (GtkButton *button, GtkWidget *entry)
+{
+  mplist_set (entry_keyseq, Mnil, NULL);
+  gtk_widget_grab_focus (entry);
+  update_entry (GTK_ENTRY (entry));
+}
+
+static void
+add_cb (GtkButton *button, GtkListStore *store)
+{
+  MPlist *old, *new, *pl, *last;
+  GtkTreeIter iter;
+  GtkWidget *view;
+
+  if (mplist_length (entry_keyseq) == 0)
+    return;
+  old = get_command_bindings (current_lang, current_name, current_command);
+  new = mplist ();
+  for (pl = old; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
+    {
+      if (! keyseq_equal (mplist_value (pl), entry_keyseq))
+       mplist_add (new, Mplist, mplist_value (pl));
+      else
+       {
+         /* entry_keyseq is already registered. */
+         m17n_object_unref (new);
+         return;
+       }
+    }
+  mplist_add (new, Mplist, entry_keyseq);
+  minput_config_command (current_lang, current_name, current_command, new);
+  m17n_object_unref (new);
+
+  /* We cannot use ENTRY_KEYSEQ for gtk_list_store_set ().  We must
+     use a pointer to the internally copied one. */
+  new = get_command_bindings (current_lang, current_name, current_command);
+  for (pl = new; pl && mplist_key (pl) == Mplist;
+       last = pl, pl = mplist_next (pl))
+  gtk_list_store_append (store, &iter);
+  gtk_list_store_set (store, &iter, 0, mplist_value (last), -1);
+  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+}
+
+static void
+command_cb (GtkButton *button, GtkWidget *frame)
+{
+  GtkWidget *dialog, *view, *scrolled;
+  GtkWidget *delete, *entry, *add, *clear;
+  GtkListStore *store;
+  GtkTreeIter iter;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  MPlist *bindings, *pl, *cmd;
+  gint response;
+
+  current_lang = g_object_get_data (G_OBJECT (button), "mim_lang");
+  current_name = g_object_get_data (G_OBJECT (button), "mim_name");
+  current_command = g_object_get_data (G_OBJECT (button), "mim_command");
+  bindings = get_command_bindings (current_lang, current_name, current_command);
+
+  dialog = (gtk_dialog_new_with_buttons
+           (msymbol_name (current_command),
+            GTK_WINDOW (gtk_widget_get_toplevel (frame)),
+            GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+            GTK_STOCK_OK, GTK_RESPONSE_OK,
+            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+            NULL));
+
+  store = gtk_list_store_new (1, G_TYPE_POINTER);
+  for (pl = bindings; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
+    {
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter, 0, mplist_value (pl), -1);
+    }
+  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  g_object_unref (G_OBJECT (store));
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, "Current bindings");
+  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_set_cell_data_func
+    (column, renderer, keyseq_render_function, NULL, NULL);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), view);
+
+  delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
+  g_signal_connect (G_OBJECT (delete), "clicked",
+                   G_CALLBACK (delete_cb), view);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), delete);
+
+  entry_keyseq = mplist ();
+
+  entry = gtk_entry_new ();
+  g_signal_connect (G_OBJECT (entry), "key-press-event",
+                   G_CALLBACK (key_pressed), NULL);
+  g_signal_connect (G_OBJECT (entry), "key-release-event",
+                   G_CALLBACK (key_released), NULL);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), entry);
+
+  clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
+  g_signal_connect (G_OBJECT (clear), "clicked",
+                   G_CALLBACK (clear_cb), entry);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), clear);
+
+  add = gtk_button_new_from_stock (GTK_STOCK_ADD);
+  g_signal_connect (G_OBJECT (add), "clicked",
+                   G_CALLBACK (add_cb), store);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), add);
+
+  gtk_widget_show_all (dialog);
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+
+  m17n_object_unref (entry_keyseq);
+}
+
+void
+create_command_entries (GtkWidget *frame, GtkTooltips *tip,
+                       MSymbol lang, MSymbol name)
+{
+  GtkWidget *vbox;
+  MPlist *plist;
+
+  plist = minput_get_command (lang, name, Mnil);
+  if (! plist)
+    {
+      GtkWidget *message;
+
+      message = gtk_label_new ("No commands for this method");
+      gtk_container_add (GTK_CONTAINER (frame), message);
+      return;
+    }
+
+  /*
+   * plist == ((command description status keyseq keyseq ...)
+   *           (command description status keyseq keyseq ...)
+   *           ...)
+   */
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (frame), vbox);
+
+  for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
+    {
+      GtkWidget *button;
+      MPlist *pl;
+      MSymbol command;
+      gchar *desc;
+
+      pl = mplist_value (plist);
+      /* pl == (command description status keyseq keyseq ...) */
+      command = mplist_value (pl);
+      button = gtk_button_new_with_label (msymbol_name (command));
+      gtk_container_add (GTK_CONTAINER (vbox), button);
+
+      pl = mplist_next (pl);
+      /* pl == (description status keyseq keyseq ...) */
+      if (mplist_key (pl) == Mtext)
+       /* Fixme : Assuming the return value is in UTF-8 */
+       desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
+      else
+       desc = NULL;
+      gtk_tooltips_set_tip (tip, button, desc, NULL);
+
+      g_object_set_data (G_OBJECT (button), "mim_lang", lang);
+      g_object_set_data (G_OBJECT (button), "mim_name", name);
+      g_object_set_data (G_OBJECT (button), "mim_command", command);
+      g_signal_connect (G_OBJECT (button), "clicked",
+                       G_CALLBACK (command_cb), frame);
+    }
+  m17n_object_unref (plist);
+}
+
index 5c5218a..697a763 100644 (file)
@@ -161,58 +161,38 @@ tree_expanded_cb (GtkTreeView *tree, GtkTreeIter *parent,
 static void
 edit_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
 {
-  GtkWidget *dialog, *label;
+  GtkWidget *dialog, *frame, *table;
+  GtkTooltips *tip = gtk_tooltips_new ();
   gint response;
+  MPlist *plist;
 
   dialog = (gtk_dialog_new_with_buttons
-           (_("Edit"),
+           (msymbol_name (name),
             GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
             GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
             _("Default"), 0,
             GTK_STOCK_REVERT_TO_SAVED, GTK_RESPONSE_NO,
-            GTK_STOCK_EDIT, GTK_RESPONSE_YES,
             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
             NULL));
-  label = gtk_label_new (msymbol_name (name));
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), label);
-  gtk_widget_show_all (dialog);
-  response = gtk_dialog_run (GTK_DIALOG (dialog));
-  if (response != GTK_RESPONSE_CANCEL
-      && lang == Mt && (name == Mnil || name == msymbol ("unicode")))
-    {
-      MSymbol variable = msymbol (name == Mnil ? "candidates-group-size"
-                                 : "prompt");
-
-      if (response == GTK_RESPONSE_NO)
-       {
-         minput_config_variable (lang, name, variable, NULL);
-       }
-      else if (response == 0)
-       {
-         MPlist *plist = mplist ();
 
-         minput_config_variable (lang, name, variable, plist);
-         m17n_object_unref (plist);
-       }
-      else
-       {
-         MPlist *plist = mplist ();
+  frame = gtk_frame_new (_("Variables"));
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
+                     FALSE, FALSE, 0);
+  create_variable_entries (frame, tip, lang, name);
 
-         if (name == Mnil)
-           {
-             mplist_add (plist, Minteger, (void *) 3);
-           }
-         else
-           {
-             MText *mt = mtext_from_data (">>", 2, MTEXT_FORMAT_US_ASCII);
-             mplist_add (plist, Mtext, mt);
-             m17n_object_unref (mt);
-           }
-         minput_config_variable (lang, name, variable, plist);
-         m17n_object_unref (plist);
-       }
-    }
+  frame = gtk_frame_new (_("Commands"));
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
+                     FALSE, FALSE, 0);
+  create_command_entries (frame, tip, lang, name);
 
+  gtk_widget_show_all (dialog);
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  if (response == 0)
+    printf ("Default\n");
+  else if (response == GTK_RESPONSE_NO)
+    printf ("GTK_RESPONSE_NO\n");
+  else if (response == GTK_RESPONSE_CANCEL)
+    printf ("GTK_RESPONSE_CANCEL\n");
   gtk_widget_destroy (dialog);
 }
 
diff --git a/src/variable.c b/src/variable.c
new file mode 100644 (file)
index 0000000..b8475da
--- /dev/null
@@ -0,0 +1,301 @@
+#include <gtk/gtk.h>
+#include <m17n.h>
+#include <stdio.h>
+#include <string.h>
+
+static void
+entry_cb (GtkWidget *entry, gpointer data)
+{
+  const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
+  MSymbol lang, name, variable, key;
+  MPlist *plist = mplist ();
+
+  lang = g_object_get_data (G_OBJECT (entry), "mim_lang");
+  name = g_object_get_data (G_OBJECT (entry), "mim_name");
+  variable = g_object_get_data (G_OBJECT (entry), "mim_variable");
+  key = g_object_get_data (G_OBJECT (entry), "mim_key");
+
+  if (key == Msymbol)
+    {
+      mplist_add (plist, Msymbol, msymbol (text));
+      minput_config_variable (lang, name, variable, plist);
+    }
+  else if (key == Mtext)
+    {
+      MText *mt;
+
+      mt = mtext_from_data (text, strlen (text), MTEXT_FORMAT_UTF_8);
+      mplist_add (plist, Mtext, mt);
+      minput_config_variable (lang, name, variable, plist);
+      m17n_object_unref (mt);
+    }
+  else if (key == Minteger)
+    {
+      int i;
+      gchar buf[32];
+
+      if (sscanf (text, "%d", &i) == 1)
+       {
+         mplist_add (plist, Minteger, (void *) i);
+           minput_config_variable (lang, name, variable, plist);
+       }
+      else
+       {
+         printf ("Invalid value\n");
+       }
+      sprintf (buf, "%d", (int) mplist_value (plist));
+      gtk_entry_set_text (GTK_ENTRY (entry), buf);
+      gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+    }
+  m17n_object_unref (plist);
+}
+
+static void
+combo_cb (GtkWidget *combo, gpointer data)
+{
+  gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combo));
+  MSymbol lang, name, variable, key;
+  MPlist *plist = mplist ();
+
+  lang = g_object_get_data (G_OBJECT (combo), "mim_lang");
+  name = g_object_get_data (G_OBJECT (combo), "mim_name");
+  variable = g_object_get_data (G_OBJECT (combo), "mim_variable");
+  key = g_object_get_data (G_OBJECT (combo), "mim_key");
+
+  if (key == Msymbol)
+    {
+      mplist_add (plist, Msymbol, msymbol (text));
+      minput_config_variable (lang, name, variable, plist);
+    }
+  else if (key == Mtext)
+    {
+      MText *mt;
+
+      mt = mtext_from_data (text, strlen (text), MTEXT_FORMAT_UTF_8);
+      mplist_add (plist, Mtext, mt);
+      minput_config_variable (lang, name, variable, plist);
+      m17n_object_unref (mt);
+    }
+  else if (key == Minteger)
+    {
+      int i;
+      gchar buf[32];
+
+      if (sscanf (text, "%d", &i) == 1)
+       {
+         mplist_add (plist, Minteger, (void *) i);
+         minput_config_variable (lang, name, variable, plist);
+       }
+      else
+       {
+         printf ("Invalid value\n");
+       }
+    }
+  m17n_object_unref (plist);
+}
+
+static void
+spin_cb (GtkWidget *spin, gpointer data)
+{
+  MSymbol lang, name, variable;
+  MPlist *plist = mplist ();
+
+  lang = g_object_get_data (G_OBJECT (spin), "mim_lang");
+  name = g_object_get_data (G_OBJECT (spin), "mim_name");
+  variable = g_object_get_data (G_OBJECT (spin), "mim_variable");
+
+  mplist_add
+    (plist, Minteger,
+     (void *) gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)));
+  minput_config_variable (lang, name, variable, plist);
+  m17n_object_unref (plist);
+}
+
+void
+create_variable_entries (GtkWidget *frame, GtkTooltips *tip,
+                        MSymbol lang, MSymbol name)
+{
+  GtkWidget *table;
+  MPlist *plist;
+  gint row;
+
+  plist = minput_get_variable (lang, name, Mnil);
+  if (! plist)
+    {
+      GtkWidget *message;
+
+      message = gtk_label_new ("No variables for this method");
+      gtk_container_add (GTK_CONTAINER (frame), message);
+      return;
+    }
+
+  /*
+   * plist == ((variable description status value [valid-value ...])
+   *           (variable description status value [valid-value ...])
+   *           ...)
+   */
+  table = gtk_table_new (2, mplist_length (plist), FALSE);
+  gtk_container_add (GTK_CONTAINER (frame), table);
+
+  for (row = 0; plist && mplist_key (plist) == Mplist;
+       row++, plist = mplist_next (plist))
+    {
+      GtkWidget *label, *widget;
+      MPlist *pl, *data;
+      MSymbol variable, key;
+      void *value;
+      gchar *desc;
+
+      pl = mplist_value (plist);
+      variable = mplist_value (pl);
+      label = gtk_label_new (msymbol_name (variable));
+      gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, row, row + 1);
+
+      pl = mplist_next (pl);
+      if (mplist_key (pl) == Mtext)
+       /* Fixme : Assuming the return value is in UTF-8 */
+       desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
+      else
+       desc = NULL;
+
+      pl = mplist_next (mplist_next (pl)); /* ignore status */
+      key = mplist_key (pl);
+      value = mplist_value (pl);
+      pl = mplist_next (pl);
+
+      if (key == Msymbol)
+       {
+         if (mplist_key (pl) == Msymbol)
+           {
+             int i, nth = -1;
+
+             widget = gtk_combo_box_new_text ();
+             for (i = 0; pl && mplist_key (pl) == Msymbol;
+                  pl = mplist_next (pl), i++)
+               {
+                 if (mplist_value (pl) == value)
+                   nth = i;
+                 gtk_combo_box_append_text (GTK_COMBO_BOX (widget),
+                                            msymbol_name (mplist_value (pl)));
+               }
+             if (nth != -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
+             g_signal_connect (G_OBJECT (widget), "changed",
+                               G_CALLBACK (combo_cb), NULL);
+           }
+         else
+           {
+             widget = gtk_entry_new ();
+             gtk_entry_set_text (GTK_ENTRY (widget), msymbol_name (value));
+             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
+             g_signal_connect (G_OBJECT (widget), "activate",
+                               G_CALLBACK (entry_cb), NULL);
+           }
+       }
+      
+      else if (key == Mtext)
+       {
+         if (mplist_key (pl) == Mtext)
+           {
+             int i, nth = -1;
+
+             widget = gtk_combo_box_new_text ();
+             for (i = 0; pl && mplist_key (pl) == Mtext;
+                  pl = mplist_next (pl), i++)
+               {
+                 if (! mtext_cmp (mplist_value (pl), value))
+                   nth = i;
+                 /* Fixme : Assuming the return value is in UTF-8 */
+                 gtk_combo_box_append_text
+                   (GTK_COMBO_BOX (widget),
+                    mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL));
+               }
+             if (nth != -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
+             g_signal_connect (G_OBJECT (widget), "changed",
+                               G_CALLBACK (combo_cb), NULL);
+           }
+         else
+           {
+             widget = gtk_entry_new ();
+             /* Fixme : Assuming the return value is in UTF-8 */
+             gtk_entry_set_text (GTK_ENTRY (widget),
+                                 mtext_data (value, NULL, NULL, NULL, NULL));
+             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
+             g_signal_connect (G_OBJECT (widget), "activate",
+                               G_CALLBACK (entry_cb), NULL);
+           }
+       }
+
+      else if (key == Minteger)
+       {
+         if (mplist_key (pl) == Minteger)
+           {
+             int i, nth = -1;
+
+             widget = gtk_combo_box_new_text ();
+             for (i = 0; pl && mplist_key (pl) == Minteger;
+                  pl = mplist_next (pl), i++)
+               {
+                 gchar buf[32];
+
+                 if (mplist_value (pl) == value)
+                   nth = i;
+                 snprintf (buf, 31, "%d", (int) mplist_value (pl));
+                 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), buf);
+               }
+             if (nth != -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
+             g_signal_connect (G_OBJECT (widget), "changed",
+                               G_CALLBACK (combo_cb), NULL);
+           }
+         else if (mplist_key (pl) == Mplist)
+           {
+             GtkAdjustment *adj;
+             gdouble lower, upper;
+
+             pl = mplist_value (pl);
+             lower = (gdouble) (int) mplist_value (pl);
+             pl = mplist_next (pl);
+             upper = (gdouble) (int) mplist_value (pl);
+             adj = (GtkAdjustment *)
+               gtk_adjustment_new ((gdouble) (int) value, (gdouble) lower,
+                                   (gdouble) upper, 1.0, 10.0, 0);
+             widget = gtk_spin_button_new (adj, 0, 0);
+             gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
+             gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (widget),
+                                                GTK_UPDATE_IF_VALID);
+             g_signal_connect (G_OBJECT (widget), "value_changed",
+                               G_CALLBACK (spin_cb), NULL);
+           }
+         else
+           {
+             gchar buf[32];
+
+             widget = gtk_entry_new ();
+             snprintf (buf, 31, "%d", (int) value);
+             gtk_entry_set_text (GTK_ENTRY (widget), buf);
+             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
+             g_signal_connect (G_OBJECT (widget), "activate",
+                               G_CALLBACK (entry_cb), NULL);
+           }
+       }
+
+      else
+       {
+         widget = gtk_entry_new ();
+         gtk_entry_set_text (GTK_ENTRY (widget), "???");
+         gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
+         g_signal_connect (G_OBJECT (widget), "activate",
+                           G_CALLBACK (entry_cb), NULL);
+       }
+
+      gtk_tooltips_set_tip (tip, widget, desc, NULL);
+      g_object_set_data (G_OBJECT (widget), "mim_lang", lang);
+      g_object_set_data (G_OBJECT (widget), "mim_name", name);
+      g_object_set_data (G_OBJECT (widget), "mim_variable", variable);
+      g_object_set_data (G_OBJECT (widget), "mim_key", key);
+      gtk_table_attach_defaults        (GTK_TABLE (table), widget,
+                                1, 2, row, row + 1);
+    }
+}