Revision: 7144
Author:   ek.kato
Date:     Thu Jun 16 23:54:38 2011
Log:      - Implement an experimental horizontal candidate window for GTK+
  immodule.

* gtk2/immodule/Makefile.am (IM_UIM_SOURCES) : Add
  uim-cand-win-horizontal-gtk.c uim-cand-win-horizontal-gtk.
* gtk3/immodule/Makefile.am (IM_UIM_SOURCES) : Ditto.
* gtk2/immodule/uim-cand-win-horizontal-gtk.c : Copied from
  uim-cand-win-tbl-gtk.c. Modified for the single row table.
* gtk2/immodule/uim-cand-win-horizontal-gtk.h : Copied from
  uim-cand-win-tbl-gtk.h.
* gtk2/immodule/uim-cand-win-gtk.h
  - (_UIMCandWinGtkClass) : Add create_sub_window and
    layout_sub_window members and make
    uim_cand_win_gtk_create_sub_window and
    uim_cand_win_gtk_layout_sub_window public.
* gtk2/immodule/uim-cand-win-gtk.c
  - (uim_cand_win_gtk_create_sub_window) : Make public and call
    member function of the class.
  - (uim_cand_win_gtk_layout_sub_window) : Ditto.
  - (uim_cand_win_gtk_real_create_sub_window) : Rename from
    uim_cand_win_gtk_create_sub_window.
  - (uim_cand_win_gtk_real_layout_sub_window) : Rename from
    uim_cand_win_gtk_layout_sub_window.
  - (uim_cand_win_gtk_class_init) : Set create_sub_window and
    layout_subwindow.
  - (uim_cand_win_gtk_layout) : Change positioning when right side
    of the candidate window exceeds the display's limit.
* gtk2/immodule/gtk-im-uim.c
  - Include "uim-cand-win-horizontal-gtk.h".
  - (im_uim_create_cand_win_gtk) : Check "uim-candwin-horizontal"
    prefix for uim-candwin-prog.

http://code.google.com/p/uim/source/detail?r=7144

Added:
 /trunk/gtk2/immodule/uim-cand-win-horizontal-gtk.c
 /trunk/gtk2/immodule/uim-cand-win-horizontal-gtk.h
Modified:
 /trunk/gtk2/immodule/Makefile.am
 /trunk/gtk2/immodule/gtk-im-uim.c
 /trunk/gtk2/immodule/uim-cand-win-gtk.c
 /trunk/gtk2/immodule/uim-cand-win-gtk.h
 /trunk/gtk3/immodule/Makefile.am

=======================================
--- /dev/null
+++ /trunk/gtk2/immodule/uim-cand-win-horizontal-gtk.c Thu Jun 16 23:54:38 2011
@@ -0,0 +1,603 @@
+/*
+
+  copyright (c) 2003-2011 uim Project http://code.google.com/p/uim/
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of authors nor the names of its contributors
+     may be used to endorse or promote products derived from this software
+     without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGE.
+
+*/
+
+#include <config.h>
+
+#include "uim-cand-win-horizontal-gtk.h"
+#include <string.h>
+#include <stdlib.h>
+#include <uim/uim.h>
+#include <uim/uim-scm.h>
+
+#define DEFAULT_MIN_WINDOW_WIDTH 60
+
+enum {
+  TERMINATOR = -1,
+  COLUMN_HEADING,
+  COLUMN_CANDIDATE,
+  COLUMN_ANNOTATION,
+  LISTSTORE_NR_COLUMNS
+};
+
+#define DEFAULT_NR_CELLS 10
+
+struct index_button {
+  gint cand_index_in_page;
+  GtkButton *button;
+};
+
+static void uim_cand_win_horizontal_gtk_init(UIMCandWinHorizontalGtk *cwin); +static void uim_cand_win_horizontal_gtk_class_init(UIMCandWinGtkClass *klass);
+static void uim_cand_win_horizontal_gtk_dispose(GObject *obj);
+static void button_clicked(GtkButton *button, gpointer data);
+static void clear_button(struct index_button *idxbutton, gint cell_index);
+static void show_table(GtkTable *view, GPtrArray *buttons);
+static void scale_label(GtkButton *button, double factor);
+
+
+static GType cand_win_horizontal_type = 0;
+static GTypeInfo const object_info = {
+  sizeof (UIMCandWinHorizontalGtkClass),
+  (GBaseInitFunc) NULL,
+  (GBaseFinalizeFunc) NULL,
+  (GClassInitFunc) uim_cand_win_horizontal_gtk_class_init,
+  (GClassFinalizeFunc) NULL,
+  NULL,                       /* class_data */
+  sizeof (UIMCandWinHorizontalGtk),
+  0,                          /* n_preallocs */
+  (GInstanceInitFunc) uim_cand_win_horizontal_gtk_init,
+};
+
+static GtkWindowClass *parent_class = NULL;
+
+GType
+uim_cand_win_horizontal_gtk_get_type(void)
+{
+  if (!cand_win_horizontal_type)
+ cand_win_horizontal_type = g_type_register_static(UIM_TYPE_CAND_WIN_GTK, "UIMCandWinHorizontalGtk",
+                                          &object_info, (GTypeFlags)0);
+  return cand_win_horizontal_type;
+}
+
+GType
+uim_cand_win_horizontal_gtk_register_type(GTypeModule *module)
+{
+  if (!cand_win_horizontal_type)
+    cand_win_horizontal_type = g_type_module_register_type(module,
+                                               UIM_TYPE_CAND_WIN_GTK,
+                                               "UIMCandWinHorizontalGtk",
+                                               &object_info, 0);
+  return cand_win_horizontal_type;
+}
+
+static void
+uim_cand_win_horizontal_gtk_class_init (UIMCandWinGtkClass *klass)
+{
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+  object_class->dispose = uim_cand_win_horizontal_gtk_dispose;
+
+ klass->set_index = (void (*)(UIMCandWinGtk *, gint))uim_cand_win_horizontal_gtk_set_index; + klass->set_page = (void (*)(UIMCandWinGtk *, gint))uim_cand_win_horizontal_gtk_set_page; + klass->create_sub_window = (void (*)(UIMCandWinGtk *))uim_cand_win_horizontal_gtk_create_sub_window; + klass->layout_sub_window = (void (*)(UIMCandWinGtk *))uim_cand_win_horizontal_gtk_layout_sub_window;
+}
+
+static void
+uim_cand_win_horizontal_gtk_init (UIMCandWinHorizontalGtk *horizontal_cwin)
+{
+  gint col;
+  GtkWidget *viewport;
+  UIMCandWinGtk *cwin;
+
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+
+  horizontal_cwin->buttons = g_ptr_array_new();
+  horizontal_cwin->selected = NULL;
+
+  gtk_widget_destroy(cwin->view);
+  cwin->view = gtk_table_new(1, DEFAULT_NR_CELLS, FALSE);
+  viewport = gtk_viewport_new(NULL, NULL);
+  gtk_container_add(GTK_CONTAINER(viewport), cwin->view);
+  gtk_container_add(GTK_CONTAINER(cwin->scrolled_window), viewport);
+ gtk_container_set_resize_mode(GTK_CONTAINER(viewport), GTK_RESIZE_PARENT);
+  for (col = 0; col < DEFAULT_NR_CELLS; col++) {
+    GtkWidget *button;
+    struct index_button *idxbutton;
+
+    button = gtk_button_new_with_label("");
+    scale_label(GTK_BUTTON(button), PANGO_SCALE_LARGE);
+ g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), horizontal_cwin); + gtk_table_attach_defaults(GTK_TABLE(cwin->view), button, col, col + 1, 0, 1);
+    idxbutton = g_malloc(sizeof(struct index_button));
+    if (idxbutton) {
+      idxbutton->button = GTK_BUTTON(button);
+      clear_button(idxbutton, col);
+    }
+    g_ptr_array_add(horizontal_cwin->buttons, idxbutton);
+  }
+
+  gtk_widget_show_all(cwin->view);
+  gtk_widget_show(viewport);
+
+ gtk_widget_set_size_request(cwin->num_label, DEFAULT_MIN_WINDOW_WIDTH, -1); + gtk_window_set_default_size(GTK_WINDOW(cwin), DEFAULT_MIN_WINDOW_WIDTH, -1);
+  gtk_window_set_resizable(GTK_WINDOW(cwin), FALSE);
+}
+
+static void
+button_clicked(GtkButton *button, gpointer data)
+{
+  UIMCandWinHorizontalGtk *horizontal_cwin = data;
+  UIMCandWinGtk *cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+  gint i;
+  gint idx = -1;
+  struct index_button *prev_selected;
+
+  prev_selected = horizontal_cwin->selected;
+  if (prev_selected) {
+    gtk_button_set_relief(prev_selected->button, GTK_RELIEF_NONE);
+  }
+
+  for (i = 0; i < (gint)horizontal_cwin->buttons->len; i++) {
+    GtkButton *p;
+    struct index_button *idxbutton;
+    idxbutton = g_ptr_array_index(horizontal_cwin->buttons, i);
+    if (!idxbutton) {
+      continue;
+    }
+    p = idxbutton->button;
+    if (p == button) {
+      idx = idxbutton->cand_index_in_page;
+      gtk_button_set_relief(button, GTK_RELIEF_HALF);
+      horizontal_cwin->selected = idxbutton;
+      break;
+    }
+  }
+  if (idx >= 0 && cwin->display_limit) {
+    if (idx >= (gint)cwin->display_limit) {
+      idx %= cwin->display_limit;
+    }
+    cwin->candidate_index = cwin->page_index * cwin->display_limit + idx;
+  } else {
+    cwin->candidate_index = idx;
+  }
+  if (cwin->candidate_index >= (gint)cwin->nr_candidates) {
+    cwin->candidate_index = -1;
+  }
+
+  g_signal_emit_by_name(G_OBJECT(cwin), "index-changed");
+}
+
+static void
+uim_cand_win_horizontal_gtk_dispose (GObject *obj)
+{
+  UIMCandWinHorizontalGtk *horizontal_cwin;
+
+  g_return_if_fail(UIM_IS_CAND_WIN_HORIZONTAL_GTK(obj));
+
+  horizontal_cwin = UIM_CAND_WIN_HORIZONTAL_GTK(obj);
+
+  if (horizontal_cwin->buttons) {
+    guint i;
+    for (i = 0; i < horizontal_cwin->buttons->len; i++) {
+      g_free(horizontal_cwin->buttons->pdata[i]);
+      /* GtkButton is destroyed by container */
+    }
+    g_ptr_array_free(horizontal_cwin->buttons, TRUE);
+    horizontal_cwin->buttons = NULL;
+  }
+  horizontal_cwin->selected = NULL;
+
+  if (G_OBJECT_CLASS (parent_class)->dispose)
+    G_OBJECT_CLASS (parent_class)->dispose(obj);
+}
+
+UIMCandWinHorizontalGtk *
+uim_cand_win_horizontal_gtk_new (void)
+{
+  GObject *obj = g_object_new(UIM_TYPE_CAND_WIN_HORIZONTAL_GTK,
+                             "type", GTK_WINDOW_POPUP,
+                             NULL);
+
+  return UIM_CAND_WIN_HORIZONTAL_GTK(obj);
+}
+
+static GtkButton*
+assign_cellbutton(UIMCandWinHorizontalGtk *horizontal_cwin,
+    gchar *heading, gint cand_index, gint display_limit)
+{
+  struct index_button *idxbutton;
+  int len;
+  GPtrArray *buttons;
+
+  buttons = horizontal_cwin->buttons;
+  len = buttons->len;
+
+  if (len <= cand_index) {
+    GtkWidget *button;
+
+    button = gtk_button_new_with_label("");
+    scale_label(GTK_BUTTON(button), PANGO_SCALE_LARGE);
+ g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), horizontal_cwin); + gtk_table_attach_defaults(GTK_TABLE(UIM_CAND_WIN_GTK(horizontal_cwin)->view), button, cand_index, cand_index + 1, 0, 1);
+    idxbutton = g_malloc(sizeof(struct index_button));
+    if (idxbutton) {
+      idxbutton->button = GTK_BUTTON(button);
+      clear_button(idxbutton, cand_index);
+      idxbutton->cand_index_in_page = cand_index;
+    }
+    g_ptr_array_add(horizontal_cwin->buttons, idxbutton);
+  } else {
+    idxbutton = g_ptr_array_index(buttons, cand_index);
+    idxbutton->cand_index_in_page = cand_index;
+  }
+
+  return idxbutton->button;
+}
+
+void
+uim_cand_win_horizontal_gtk_set_index(UIMCandWinHorizontalGtk *horizontal_cwin, gint index)
+{
+  gint new_page;
+  UIMCandWinGtk *cwin;
+
+  g_return_if_fail(UIM_IS_CAND_WIN_HORIZONTAL_GTK(horizontal_cwin));
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+
+  if (index >= (gint) cwin->nr_candidates)
+    cwin->candidate_index = 0;
+  else
+    cwin->candidate_index = index;
+
+  if (cwin->candidate_index >= 0 && cwin->display_limit)
+    new_page = cwin->candidate_index / cwin->display_limit;
+  else
+    new_page = cwin->page_index;
+
+  if (cwin->page_index != new_page)
+    uim_cand_win_gtk_set_page(cwin, new_page);
+
+  if (cwin->candidate_index >= 0) {
+    gint pos;
+    struct index_button *idxbutton, *prev_selected;
+
+    if (cwin->display_limit)
+      pos = cwin->candidate_index % cwin->display_limit;
+    else
+      pos = cwin->candidate_index;
+
+    idxbutton = g_ptr_array_index(horizontal_cwin->buttons, pos);
+    prev_selected = (gpointer)horizontal_cwin->selected;
+    if (prev_selected) {
+      gtk_button_set_relief(prev_selected->button, GTK_RELIEF_NONE);
+    }
+    gtk_button_set_relief(idxbutton->button, GTK_RELIEF_HALF);
+    horizontal_cwin->selected = idxbutton;
+
+    /* show subwin */
+    {
+      char *annotation = NULL;
+      GtkTreeModel *model = GTK_TREE_MODEL(cwin->stores->pdata[new_page]);
+      GtkTreeIter iter;
+
+      gtk_tree_model_iter_nth_child(model, &iter, NULL, pos);
+      gtk_tree_model_get(model, &iter, COLUMN_ANNOTATION, &annotation, -1);
+
+      if (annotation && *annotation) {
+       if (!cwin->sub_window.window)
+          uim_cand_win_gtk_create_sub_window(cwin);
+ gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(cwin->sub_window.text_view)), annotation, -1);
+          uim_cand_win_gtk_layout_sub_window(cwin);
+          gtk_widget_show(cwin->sub_window.window);
+          cwin->sub_window.active = TRUE;
+        } else {
+          if (cwin->sub_window.window) {
+            gtk_widget_hide(cwin->sub_window.window);
+            cwin->sub_window.active = FALSE;
+          }
+        }
+      free(annotation);
+    }
+  }
+
+  uim_cand_win_gtk_update_label(cwin);
+}
+
+static void
+scale_label(GtkButton *button, double scale)
+{
+  GtkWidget *label;
+  PangoAttrList *attrs = pango_attr_list_new();
+  PangoAttribute *attr = pango_attr_scale_new(scale);
+
+  pango_attr_list_insert(attrs, attr);
+  label = gtk_bin_get_child(GTK_BIN(button));
+  if (GTK_IS_LABEL(label))
+    gtk_label_set_attributes(GTK_LABEL(label), attrs);
+  pango_attr_list_unref(attrs);
+}
+
+static void
+clear_button(struct index_button *idxbutton,
+    gint cell_index)
+{
+  GtkButton *button;
+
+  idxbutton->cand_index_in_page = -1;
+  button = idxbutton->button;
+  gtk_button_set_relief(button, GTK_RELIEF_NONE);
+  gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+
+  gtk_button_set_label(button, "");
+  scale_label(button, PANGO_SCALE_LARGE);
+}
+
+static void
+clear_all_buttons(GPtrArray *buttons)
+{
+  gint i;
+
+  for (i = 0; i < (gint)buttons->len; i++) {
+    struct index_button *idxbutton;
+
+    idxbutton = g_ptr_array_index(buttons, i);
+    if (idxbutton && idxbutton->cand_index_in_page != -1) {
+      clear_button(idxbutton, i);
+    }
+  }
+}
+
+static void
+update_table_button(UIMCandWinHorizontalGtk *horizontal_cwin, guint new_page)
+{
+  UIMCandWinGtk *cwin;
+  GtkTreeModel *model;
+  GPtrArray *buttons;
+  GtkTreeIter ti;
+  gboolean has_next;
+  gint display_limit, len, cand_index = 0;
+
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+  model = GTK_TREE_MODEL(cwin->stores->pdata[new_page]);
+  buttons = horizontal_cwin->buttons;
+  display_limit = cwin->display_limit;
+  len = buttons->len;
+
+  clear_all_buttons(buttons);
+  has_next = gtk_tree_model_get_iter_first(model, &ti);
+  while (has_next) {
+    gchar *heading;
+    gchar *cand_str;
+    GtkButton *button = NULL;
+
+    gtk_tree_model_get(model, &ti, COLUMN_HEADING, &heading,
+        COLUMN_CANDIDATE, &cand_str, TERMINATOR);
+    if (cand_str != NULL) {
+ button = assign_cellbutton(horizontal_cwin, heading, cand_index, display_limit);
+      if (button != NULL) {
+        gtk_button_set_relief(button, GTK_RELIEF_NONE);
+        gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
+        if (heading && heading[0] != '\0') {
+          gchar *label = g_strdup_printf("%s: %s", heading, cand_str);
+          gtk_button_set_label(button, label);
+         g_free(label);
+
+       } else {
+          gtk_button_set_label(button, cand_str);
+       }
+       scale_label(button, PANGO_SCALE_LARGE);
+      }
+    }
+
+    g_free(cand_str);
+    g_free(heading);
+    cand_index++;
+    has_next = gtk_tree_model_iter_next(model, &ti);
+  }
+
+  if (cand_index < len) {
+    gint i;
+    for (i = len - 1; i >= cand_index; i--) {
+      struct index_button *idxbutton;
+      idxbutton = g_ptr_array_index(buttons, i);
+      if (idxbutton == horizontal_cwin->selected)
+        horizontal_cwin->selected = NULL;
+      gtk_widget_destroy(GTK_WIDGET(idxbutton->button));
+      g_free(idxbutton);
+      g_ptr_array_remove_index(buttons, i);
+    }
+
+    gtk_table_resize(GTK_TABLE(cwin->view), 1, cand_index);
+  }
+}
+
+void
+uim_cand_win_horizontal_gtk_set_page(UIMCandWinHorizontalGtk *horizontal_cwin, gint page)
+{
+  guint len, new_page;
+  gint new_index;
+  UIMCandWinGtk *cwin;
+
+  g_return_if_fail(UIM_IS_CAND_WIN_HORIZONTAL_GTK(horizontal_cwin));
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+  g_return_if_fail(cwin->stores);
+
+  len = cwin->stores->len;
+  g_return_if_fail(len);
+
+  if (page < 0)
+    new_page = len - 1;
+  else if (page >= (gint) len)
+    new_page = 0;
+  else
+    new_page = page;
+
+  update_table_button(horizontal_cwin, new_page);
+  show_table(GTK_TABLE(cwin->view), horizontal_cwin->buttons);
+
+  cwin->page_index = new_page;
+
+  if (cwin->display_limit) {
+    if (cwin->candidate_index >= 0)
+      new_index
+ = (new_page * cwin->display_limit) + (cwin->candidate_index % cwin->display_limit);
+    else
+      new_index = -1;
+  } else {
+    new_index = cwin->candidate_index;
+  }
+
+  if (new_index >= (gint) cwin->nr_candidates)
+    new_index = cwin->nr_candidates - 1;
+
+  uim_cand_win_gtk_set_index(cwin, new_index);
+}
+
+static void
+show_table(GtkTable *view, GPtrArray *buttons)
+{
+  gint col;
+
+  for (col = 0; col < (gint)buttons->len; col++) {
+    GtkButton *button = NULL;
+    struct index_button *idxbutton;
+
+    idxbutton = g_ptr_array_index(buttons, col);
+    button = idxbutton->button;
+
+    gtk_widget_show(GTK_WIDGET(button));
+  }
+  gtk_widget_show(GTK_WIDGET(view));
+}
+
+#define UIM_ANNOTATION_WIN_WIDTH 280
+#define UIM_ANNOTATION_WIN_HEIGHT 140
+
+void
+uim_cand_win_horizontal_gtk_create_sub_window(UIMCandWinHorizontalGtk *horizontal_cwin)
+{
+  GtkWidget *window, *scrwin, *text_view, *frame;
+  GdkGeometry hints;
+  UIMCandWinGtk *cwin;
+
+  g_return_if_fail(UIM_IS_CAND_WIN_HORIZONTAL_GTK(horizontal_cwin));
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+
+  if (cwin->sub_window.window)
+    return;
+
+  cwin->sub_window.window = window = gtk_window_new(GTK_WINDOW_POPUP);
+
+  frame = gtk_frame_new(NULL);
+  gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
+
+  hints.min_width = UIM_ANNOTATION_WIN_WIDTH;
+  hints.min_height = UIM_ANNOTATION_WIN_HEIGHT;
+  hints.max_width = UIM_ANNOTATION_WIN_WIDTH;
+  hints.max_height = UIM_ANNOTATION_WIN_HEIGHT;
+ gtk_window_set_geometry_hints(GTK_WINDOW(window), frame, &hints, GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE);
+
+ cwin->sub_window.scrolled_window = scrwin = gtk_scrolled_window_new(NULL, NULL);
+  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
+                                 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+  cwin->sub_window.text_view = text_view = gtk_text_view_new();
+  gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD_CHAR);
+  gtk_widget_show(text_view);
+
+  gtk_container_add(GTK_CONTAINER(scrwin), text_view);
+  gtk_container_add(GTK_CONTAINER(frame), scrwin);
+  gtk_container_add(GTK_CONTAINER(window), frame);
+  gtk_widget_show(frame);
+  gtk_widget_show(scrwin);
+  gtk_widget_show(text_view);
+}
+
+void
+uim_cand_win_horizontal_gtk_layout_sub_window(UIMCandWinHorizontalGtk *horizontal_cwin)
+{
+  UIMCandWinGtk *cwin;
+#if GTK_CHECK_VERSION(2, 90, 0)
+  gint x, y, w, h, x2, y2, w2, h2, x3, y3;
+#else
+  gint x, y, w, h, d, x2, y2, w2, h2, d2, x3, y3;
+#endif
+  struct index_button *idxbutton;
+
+  g_return_if_fail(UIM_IS_CAND_WIN_HORIZONTAL_GTK(horizontal_cwin));
+  cwin = UIM_CAND_WIN_GTK(horizontal_cwin);
+
+  if (!cwin->sub_window.window)
+    return;
+
+#if GTK_CHECK_VERSION(2, 90, 0)
+  gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(cwin)),
+                          &x, &y, &w, &h);
+#else
+  gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(cwin)),
+                          &x, &y, &w, &h, &d);
+#endif
+  gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(cwin)), &x, &y);
+
+#if GTK_CHECK_VERSION(2, 90, 0)
+  gdk_window_get_geometry(gtk_widget_get_window(cwin->sub_window.window),
+                          &x2, &y2, &w2, &h2);
+#else
+  gdk_window_get_geometry(gtk_widget_get_window(cwin->sub_window.window),
+                          &x2, &y2, &w2, &h2, &d2);
+#endif
+
+  if (horizontal_cwin->selected) {
+    GtkWidget *button;
+    idxbutton = horizontal_cwin->selected;
+    button = GTK_WIDGET(idxbutton->button);
+    gdk_window_get_origin(gtk_widget_get_window(button), &x3, &y3);
+
+#if GTK_CHECK_VERSION(2, 18, 0)
+    if (!gtk_widget_get_has_window(button)) {
+      GtkAllocation allocation;
+      gtk_widget_get_allocation(button, &allocation);
+      x3 += allocation.x;
+    }
+#else
+    if (GTK_WIDGET_NO_WINDOW(button))
+      x3 += button->allocation.x;
+#endif
+  }
+  y = y + h;
+
+  gtk_window_move(GTK_WINDOW(cwin->sub_window.window), x3, y);
+}
=======================================
--- /dev/null
+++ /trunk/gtk2/immodule/uim-cand-win-horizontal-gtk.h Thu Jun 16 23:54:38 2011
@@ -0,0 +1,72 @@
+/*
+
+  Copyright (c) 2003-2011 uim Project http://code.google.com/p/uim/
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of authors nor the names of its contributors
+     may be used to endorse or promote products derived from this software
+     without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGE.
+
+*/
+
+#ifndef UIM_GTK_UIM_CAND_WIN_HORIZONTAL_GTK_H
+#define UIM_GTK_UIM_CAND_WIN_HORIZONTAL_GTK_H
+
+#include "uim-cand-win-gtk.h"
+
+G_BEGIN_DECLS
+
+#define UIM_TYPE_CAND_WIN_HORIZONTAL_GTK (uim_cand_win_horizontal_gtk_get_type ()) +#define UIM_CAND_WIN_HORIZONTAL_GTK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UIM_TYPE_CAND_WIN_HORIZONTAL_GTK, UIMCandWinHorizontalGtk)) +#define UIM_CAND_WIN_HORIZONTAL_GTK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UIM_TYPE_CAND_WIN_HORIZONTAL_GTK, UIMCandWinHorizontalGtkClass)) +#define UIM_IS_CAND_WIN_HORIZONTAL_GTK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UIM_TYPE_CAND_WIN_HORIZONTAL_GTK)) +#define UIM_IS_CAND_WIN_HORIZONTAL_GTK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UIM_TYPE_CAND_WIN_HORIZONTAL_GTK)) +#define UIM_CAND_WIN_HORIZONTAL_GTK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UIM_TYPE_CAND_WIN_HORIZONTAL_GTK, UIMCandWinHorizontalGtkClass))
+
+typedef struct _UIMCandWinHorizontalGtk UIMCandWinHorizontalGtk;
+typedef struct _UIMCandWinHorizontalGtkClass UIMCandWinHorizontalGtkClass;
+
+struct _UIMCandWinHorizontalGtk {
+  UIMCandWinGtk parent;
+  GPtrArray *buttons;
+  gpointer selected;
+};
+
+struct _UIMCandWinHorizontalGtkClass {
+  UIMCandWinGtkClass parent_class;
+};
+
+GType uim_cand_win_horizontal_gtk_register_type(GTypeModule *module);
+GType uim_cand_win_horizontal_gtk_get_type(void);
+UIMCandWinHorizontalGtk  *uim_cand_win_horizontal_gtk_new(void);
+
+void uim_cand_win_horizontal_gtk_set_index(UIMCandWinHorizontalGtk *cwin, gint index); +void uim_cand_win_horizontal_gtk_set_page(UIMCandWinHorizontalGtk *cwin, gint page); +void uim_cand_win_horizontal_gtk_create_sub_window(UIMCandWinHorizontalGtk *cwin); +void uim_cand_win_horizontal_gtk_layout_sub_window(UIMCandWinHorizontalGtk *cwin);
+
+G_END_DECLS
+
+#endif /*UIM_GTK_UIM_CAND_WIN_HORIZONTAL_GTK_H */
=======================================
--- /trunk/gtk2/immodule/Makefile.am    Thu Jun 16 00:09:29 2011
+++ /trunk/gtk2/immodule/Makefile.am    Thu Jun 16 23:54:38 2011
@@ -24,6 +24,7 @@
        gtk-im-uim.c gtk-im-uim.h key-util-gtk.c key-util-gtk.h \
        uim-cand-win-gtk.c uim-cand-win-gtk.h \
        uim-cand-win-tbl-gtk.c uim-cand-win-tbl-gtk.h \
+       uim-cand-win-horizontal-gtk.c uim-cand-win-horizontal-gtk.h \
        caret-state-indicator.c caret-state-indicator.h \
        compose.c compose.h text-util.c text-util.h

=======================================
--- /trunk/gtk2/immodule/gtk-im-uim.c   Tue May 24 07:44:08 2011
+++ /trunk/gtk2/immodule/gtk-im-uim.c   Thu Jun 16 23:54:38 2011
@@ -60,6 +60,7 @@
 #include "gtk-im-uim.h"
 #include "uim-cand-win-gtk.h"
 #include "uim-cand-win-tbl-gtk.h"
+#include "uim-cand-win-horizontal-gtk.h"
 #include "caret-state-indicator.h"
 #include "key-util-gtk.h"
 #ifdef GDK_WINDOWING_X11
@@ -1416,14 +1417,21 @@
 static UIMCandWinGtk *
 im_uim_create_cand_win_gtk()
 {
-  UIMCandWinGtk *cwin;
+  UIMCandWinGtk *cwin = NULL;
   char *candwinprog = uim_scm_symbol_value_str("uim-candwin-prog");
-  if (candwinprog && !strncmp(candwinprog, "uim-candwin-tbl", 15)) {
-    cwin = UIM_CAND_WIN_GTK(uim_cand_win_tbl_gtk_new());
-  } else {
-    cwin = uim_cand_win_gtk_new();
-  }
+
+  if (candwinprog) {
+    if (!strncmp(candwinprog, "uim-candwin-tbl", 15))
+      cwin = UIM_CAND_WIN_GTK(uim_cand_win_tbl_gtk_new());
+    else if (!strncmp(candwinprog, "uim-candwin-horizontal", 22))
+      cwin = UIM_CAND_WIN_GTK(uim_cand_win_horizontal_gtk_new());
+  }
+
+  if (!cwin)
+    cwin = uim_cand_win_gtk_new();
+
   free(candwinprog);
+
   return cwin;
 }

=======================================
--- /trunk/gtk2/immodule/uim-cand-win-gtk.c     Tue May 24 07:44:08 2011
+++ /trunk/gtk2/immodule/uim-cand-win-gtk.c     Thu Jun 16 23:54:38 2011
@@ -60,12 +60,12 @@
 static void    uim_cand_win_gtk_dispose        (GObject *obj);
 static void    uim_cand_win_gtk_map            (GtkWidget *widget);
 static void    uim_cand_win_gtk_unmap          (GtkWidget *widget);
-static void    uim_cand_win_gtk_create_sub_window(UIMCandWinGtk *cwin);
-static void    uim_cand_win_gtk_layout_sub_window(UIMCandWinGtk *cwin);
 static void    uim_cand_win_gtk_real_set_index         (UIMCandWinGtk *cwin,
                                                         gint index);
 static void    uim_cand_win_gtk_real_set_page          (UIMCandWinGtk *cwin,
                                                         gint page);
+static void    uim_cand_win_gtk_real_create_sub_window(UIMCandWinGtk *cwin);
+static void    uim_cand_win_gtk_real_layout_sub_window (UIMCandWinGtk *cwin);

 static gboolean        tree_selection_change           (GtkTreeSelection 
*selection,
                                                 GtkTreeModel *model,
@@ -138,6 +138,8 @@

   klass->set_index = uim_cand_win_gtk_real_set_index;
   klass->set_page = uim_cand_win_gtk_real_set_page;
+  klass->create_sub_window = uim_cand_win_gtk_real_create_sub_window;
+  klass->layout_sub_window = uim_cand_win_gtk_real_layout_sub_window;
 }

 void
@@ -846,7 +848,8 @@
   cursor_y = cwin->cursor.y;

   if (sc_wi <  topwin_x + cursor_x + cw_wi) {
-    x = topwin_x + cursor_x - cw_wi;
+    /* x = topwin_x + cursor_x - cw_wi; */
+    x = sc_wi - cw_wi;
   } else {
     x = topwin_x + cursor_x;
   }
@@ -870,12 +873,18 @@

   cwin->cursor = *area;
 }
+
+void
+uim_cand_win_gtk_create_sub_window(UIMCandWinGtk *cwin)
+{
+  UIM_CAND_WIN_GTK_GET_CLASS (cwin)->create_sub_window(cwin);
+}

 #define UIM_ANNOTATION_WIN_WIDTH 200
 #define UIM_ANNOTATION_WIN_HEIGHT 200

-static void
-uim_cand_win_gtk_create_sub_window(UIMCandWinGtk *cwin)
+void
+uim_cand_win_gtk_real_create_sub_window(UIMCandWinGtk *cwin)
 {
   GtkWidget *window, *scrwin, *text_view, *frame;
   GdkGeometry hints;
@@ -911,8 +920,15 @@
   gtk_widget_show(text_view);
 }

-static void
+
+void
 uim_cand_win_gtk_layout_sub_window(UIMCandWinGtk *cwin)
+{
+  UIM_CAND_WIN_GTK_GET_CLASS (cwin)->layout_sub_window(cwin);
+}
+
+void
+uim_cand_win_gtk_real_layout_sub_window(UIMCandWinGtk *cwin)
 {
 #if GTK_CHECK_VERSION(2, 90, 0)
   gint x, y, w, h, sw, sh, x2, y2, w2, h2;
=======================================
--- /trunk/gtk2/immodule/uim-cand-win-gtk.h     Tue May 24 07:44:08 2011
+++ /trunk/gtk2/immodule/uim-cand-win-gtk.h     Thu Jun 16 23:54:38 2011
@@ -90,6 +90,8 @@
   /* member functions */
   void (*set_index)            (UIMCandWinGtk *cwin, gint index);
   void (*set_page)             (UIMCandWinGtk *cwin, gint page);
+  void (*create_sub_window)    (UIMCandWinGtk *cwin);
+  void (*layout_sub_window)    (UIMCandWinGtk *cwin);
 };


@@ -139,6 +141,9 @@

 void           uim_cand_win_gtk_update_label           (UIMCandWinGtk *cwin);

+void           uim_cand_win_gtk_create_sub_window(UIMCandWinGtk *cwin);
+void           uim_cand_win_gtk_layout_sub_window(UIMCandWinGtk *cwin);
+
 G_END_DECLS

 #endif /*UIM_GTK_UIM_CAND_WIN_GTK_H */
=======================================
--- /trunk/gtk3/immodule/Makefile.am    Tue May 24 07:44:08 2011
+++ /trunk/gtk3/immodule/Makefile.am    Thu Jun 16 23:54:38 2011
@@ -27,6 +27,8 @@
        ../../gtk2/immodule/uim-cand-win-gtk.h \
        ../../gtk2/immodule/uim-cand-win-tbl-gtk.c \
        ../../gtk2/immodule/uim-cand-win-tbl-gtk.h \
+       ../../gtk2/immodule/uim-cand-win-horizontal-gtk.c \
+       ../../gtk2/immodule/uim-cand-win-horizontal-gtk.h \
        ../../gtk2/immodule/caret-state-indicator.c \
        ../../gtk2/immodule/caret-state-indicator.h \
        ../../gtk2/immodule/compose.c ../../gtk2/immodule/compose.h \

Reply via email to