Revision: 7147
Author: ek.kato
Date: Fri Jun 17 02:17:18 2011
Log: - Add an experimental horizontal candidate window for uim-xim.
* gtk2/candwin/Makefile.am
* gtk3/candwin/Makefile.am
- (libexec_PROGRAMS) : Add uim-candwin-horizontal-gtk{3}.
- (uim_candwin_horizontal_gtk_SOURCES) : New.
- (uim_candwin_horizontal_gtk_LDADD) : Ditto.
- (uim_candwin_horizontal_gtk_CPPFLAGS) : Ditto.
- (uim_candwin_horizontal_gtk_CFLAGS) : Ditto.
* gtk2/candwin/horizontal-gtk.c : Copied from tbl-gtk.c. Add
subwindow and merge changes for horizontal table from GTK+
bridge.
http://code.google.com/p/uim/source/detail?r=7147
Added:
/trunk/gtk2/candwin/horizontal-gtk.c
Modified:
/trunk/gtk2/candwin/Makefile.am
/trunk/gtk3/candwin/Makefile.am
=======================================
--- /dev/null
+++ /trunk/gtk2/candwin/horizontal-gtk.c Fri Jun 17 02:17:18 2011
@@ -0,0 +1,1191 @@
+/*
+
+ 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.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <uim/uim.h>
+#include <uim/uim-helper.h>
+#include <uim/uim-scm.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../gtk2/immodule/caret-state-indicator.h"
+
+#define UIM_TYPE_CANDIDATE_WINDOW (candidate_window_get_type())
+#define UIM_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
candidate_window_get_type(), UIMCandidateWindow))
+#define UIM_IS_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
UIM_TYPE_CANDIDATE_WINDOW))
+#define UIM_IS_CANDIDATE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE
((klass), UIM_TYPE_CANDIDATE_WINDOW))
+#define UIM_CANDIDATE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS
((obj), UIM_TYPE_CANDIDATE_WINDOW, UIMCandidateWindowClass))
+
+#define UIM_ANNOTATION_WIN_WIDTH 280
+#define UIM_ANNOTATION_WIN_HEIGHT 140
+
+typedef struct _UIMCandidateWindow UIMCandidateWindow;
+typedef struct _UIMCandidateWindowClass UIMCandidateWindowClass;
+
+struct _UIMCandidateWindow {
+ GtkWindow parent;
+
+ GtkWidget *view;
+ GtkWidget *num_label;
+ GtkWidget *scrolled_window;
+ GtkWidget *viewport;
+ GtkWidget *vbox;
+ GtkWidget *frame;
+
+ GPtrArray *stores;
+ GPtrArray *buttons;
+ gpointer selected;
+
+ guint nr_candidates;
+ guint display_limit;
+ gint candidate_index;
+ gint page_index;
+
+ gint pos_x;
+ gint pos_y;
+ gint width;
+ gint height;
+
+ GtkWidget *caret_state_indicator;
+
+ gboolean is_active;
+ gboolean need_hilite;
+
+ /* sub window */
+ struct sub_window {
+ GtkWidget *window;
+ GtkWidget *scrolled_window;
+ GtkWidget *text_view;
+ gboolean active;
+ } sub_window;
+};
+
+struct _UIMCandidateWindowClass {
+ GtkWindowClass parent_class;
+
+ /* signals */
+ void (*index_changed) (UIMCandidateWindowClass *candwin);
+};
+
+static UIMCandidateWindow *cwin; /* use single candwin */
+
+GType candidate_window_get_type(void);
+UIMCandidateWindow *candidate_window_new(void);
+
+/* copied from uim-cand-win-gtk.c */
+static gint uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin);
+static void uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint
index);
+static void uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page);
+static void uim_cand_win_gtk_set_page_candidates(UIMCandidateWindow *cwin,
guint page, GSList *candidates);
+static void uim_cand_win_gtk_create_sub_window(UIMCandidateWindow *cwin);
+static void uim_cand_win_gtk_layout_sub_window(UIMCandidateWindow *cwin);
+
+static void uim_cand_win_gtk_layout(void);
+static void uim_cand_win_gtk_show(UIMCandidateWindow *cwin);
+
+#define CANDWIN_DEFAULT_WIDTH 60
+
+enum {
+ INDEX_CHANGED_SIGNAL,
+ NR_SIGNALS
+};
+
+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 candidate_window_init(UIMCandidateWindow *cwin);
+static void candidate_window_class_init(UIMCandidateWindowClass *klass);
+
+static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure
*event, gpointer data);
+
+static GType candidate_window_type = 0;
+static GTypeInfo const object_info = {
+ sizeof (UIMCandidateWindowClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) candidate_window_class_init,
+ NULL,
+ NULL,
+ sizeof(UIMCandidateWindow),
+ 0,
+ (GInstanceInitFunc) candidate_window_init,
+};
+
+static gint cand_win_gtk_signals[NR_SIGNALS] = {0};
+
+static unsigned int read_tag;
+
+static void init_candidate_win(void);
+static void candwin_activate(gchar **str);
+static void candwin_update(gchar **str);
+static void candwin_move(char **str);
+static void candwin_show(void);
+static void candwin_deactivate(void);
+static void candwin_set_nr_candidates(gchar **str);
+static void candwin_set_page_candidates(gchar **str);
+static void candwin_show_page(gchar **str);
+static void str_parse(char *str);
+static void clear_button(struct index_button *idxbutton, gint cell_index);
+static void scale_label(GtkButton *button, double factor);
+
+static void index_changed_cb(UIMCandidateWindow *cwin)
+{
+ fprintf(stdout, "index\n");
+ fprintf(stdout, "%d\n\n", uim_cand_win_gtk_get_index(cwin));
+ fflush(stdout);
+}
+
+GType
+candidate_window_get_type(void)
+{
+ if (!candidate_window_type)
+ candidate_window_type = g_type_register_static(GTK_TYPE_WINDOW,
+ "UIMCandidateWindow", &object_info, (GTypeFlags)0);
+ return candidate_window_type;
+}
+
+static void candidate_window_class_init(UIMCandidateWindowClass *klass)
+{
+ cand_win_gtk_signals[INDEX_CHANGED_SIGNAL]
+ = g_signal_new("index-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(UIMCandidateWindowClass, index_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+UIMCandidateWindow *
+candidate_window_new(void)
+{
+ GObject *obj = g_object_new(UIM_TYPE_CANDIDATE_WINDOW, "type",
+ GTK_WINDOW_POPUP, NULL);
+ return UIM_CANDIDATE_WINDOW(obj);
+}
+
+/* copied from uim-cand-win-gtk.c */
+static void
+update_label(UIMCandidateWindow *cwin)
+{
+ char label_str[20];
+
+ if (cwin->candidate_index >= 0)
+ g_snprintf(label_str, sizeof(label_str), "%d / %d",
+ cwin->candidate_index + 1 , cwin->nr_candidates);
+ else
+ g_snprintf(label_str, sizeof(label_str), "- / %d",
+ cwin->nr_candidates);
+
+ gtk_label_set_text(GTK_LABEL(cwin->num_label), label_str);
+}
+
+static void
+button_clicked(GtkButton *button, gpointer data)
+{
+ UIMCandidateWindow *cwin = UIM_CANDIDATE_WINDOW(data);
+ gint i;
+ gint idx = -1;
+ struct index_button *prev_selected;
+
+ prev_selected = cwin->selected;
+ if (prev_selected) {
+ gtk_button_set_relief(prev_selected->button, GTK_RELIEF_NONE);
+ }
+
+ for (i = 0; i < (gint)cwin->buttons->len; i++) {
+ GtkButton *p;
+ struct index_button *idxbutton;
+ idxbutton = g_ptr_array_index(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);
+ 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
+cb_table_view_destroy(GtkWidget *widget, GPtrArray *stores)
+{
+ gint i;
+
+ g_return_if_fail(GTK_IS_TABLE(widget));
+
+ for (i = cwin->stores->len - 1; i >= 0; i--) {
+ GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
+ if (store) {
+ gtk_list_store_clear(store);
+ g_object_unref(G_OBJECT(store));
+ }
+ }
+ g_ptr_array_free(cwin->stores, TRUE);
+
+ for (i = 0; i < (gint)cwin->buttons->len; i++) {
+ if (cwin->buttons->pdata[i]) {
+ g_free(cwin->buttons->pdata[i]);
+ /* GtkButton is destroyed by container */
+ }
+ }
+ g_ptr_array_free(cwin->buttons, TRUE);
+ cwin->buttons = NULL;
+ cwin->selected = NULL;
+}
+
+static void
+init_candidate_win(void) {
+ cwin = candidate_window_new();
+ g_signal_connect(G_OBJECT(cwin), "index-changed",
+ G_CALLBACK(index_changed_cb), NULL);
+ g_signal_connect(G_OBJECT(cwin), "configure_event",
+ G_CALLBACK(configure_event_cb), NULL);
+}
+
+static void
+candidate_window_init(UIMCandidateWindow *cwin)
+{
+ GdkRectangle cursor_location;
+ gint col;
+
+ cwin->vbox = gtk_vbox_new(FALSE, 0);
+ cwin->frame = gtk_frame_new(NULL);
+
+ cwin->stores = g_ptr_array_new();
+ cwin->buttons = g_ptr_array_new();
+ cwin->selected = NULL;
+
+ gtk_window_set_default_size(GTK_WINDOW(cwin),
+ CANDWIN_DEFAULT_WIDTH, -1);
+
+
+ cwin->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cwin->scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_NEVER);
+ gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->scrolled_window, TRUE,
TRUE, 0);
+
+ cwin->view = gtk_table_new(1, DEFAULT_NR_CELLS, FALSE);
+ g_signal_connect(G_OBJECT(cwin->view), "destroy",
+ G_CALLBACK(cb_table_view_destroy), cwin->stores);
+ cwin->viewport = gtk_viewport_new(NULL, NULL);
+ gtk_container_add(GTK_CONTAINER(cwin->viewport), cwin->view);
+ gtk_container_add(GTK_CONTAINER(cwin->scrolled_window), cwin->viewport);
+ gtk_container_set_resize_mode(GTK_CONTAINER(cwin->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), 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(cwin->buttons, idxbutton);
+ }
+
+ gtk_container_add(GTK_CONTAINER(cwin->frame), cwin->vbox);
+ gtk_container_add(GTK_CONTAINER(cwin), cwin->frame);
+ gtk_container_set_border_width(GTK_CONTAINER(cwin->frame), 0);
+
+ cwin->num_label = gtk_label_new("");
+
+ gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->num_label, FALSE, FALSE,
0);
+
+ cwin->pos_x = 0;
+ cwin->pos_y = 0;
+ cwin->is_active = FALSE;
+ cwin->need_hilite = FALSE;
+ cwin->caret_state_indicator = caret_state_indicator_new();
+
+ cursor_location.x = 0;
+ cursor_location.y = 0;
+ cursor_location.height = 0;
+ caret_state_indicator_set_cursor_location(cwin->caret_state_indicator,
&cursor_location);
+
+ cwin->sub_window.window = NULL;
+ cwin->sub_window.scrolled_window = NULL;
+ cwin->sub_window.text_view = NULL;
+ cwin->sub_window.active = FALSE;
+}
+
+static GtkButton*
+assign_cellbutton(GPtrArray *buttons, gint cand_index, gint display_limit)
+{
+ gint len;
+ struct index_button *idxbutton;
+ 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), cwin);
+ gtk_table_attach_defaults(GTK_TABLE(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(cwin->buttons, idxbutton);
+ } else {
+ idxbutton = g_ptr_array_index(buttons, cand_index);
+ idxbutton->cand_index_in_page = cand_index;
+ }
+
+ return idxbutton->button;
+}
+
+static void
+candwin_activate(gchar **str)
+{
+ gsize rbytes, wbytes;
+ gint i, nr_stores = 1;
+ guint j = 1;
+ gchar *utf8_str;
+ const gchar *charset;
+ guint display_limit;
+ GSList *candidates = NULL;
+
+ if (cwin->stores == NULL)
+ cwin->stores = g_ptr_array_new();
+
+ /* remove old data */
+ for (i = cwin->stores->len - 1; i >= 0; i--) {
+ GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
+ if (store) {
+ gtk_list_store_clear(store);
+ g_object_unref(G_OBJECT(store));
+ }
+ }
+
+ if (!strncmp(str[1], "charset=", 8))
+ charset = str[1] + 8;
+ else
+ charset = "UTF-8";
+
+ if (!strncmp(str[2], "display_limit=", 14)) {
+ display_limit = atoi(str[2] + 14);
+ i = 3;
+ } else {
+ display_limit = 0;
+ i = 2;
+ }
+
+ for ( ; str[i]; i++) {
+ if (strcmp(str[i], "") == 0) {
+ break;
+ }
+ utf8_str = g_convert(str[i],
+ -1,
+ "UTF-8",
+ charset,
+ &rbytes, &wbytes, NULL);
+
+ candidates = g_slist_prepend(candidates, utf8_str);
+ j++;
+ }
+ candidates = g_slist_reverse(candidates);
+
+ cwin->candidate_index = -1;
+ cwin->nr_candidates = j - 1;
+ cwin->display_limit = display_limit;
+ cwin->need_hilite = FALSE;
+
+ if (candidates == NULL)
+ return;
+
+ /* calculate number of GtkListStores to create */
+ if (display_limit) {
+ nr_stores = cwin->nr_candidates / display_limit;
+ if (cwin->nr_candidates > display_limit * nr_stores)
+ nr_stores++;
+ }
+
+ /* create GtkListStores, and set candidates */
+ for (i = 0; i < nr_stores; i++) {
+ GtkListStore *store = gtk_list_store_new(LISTSTORE_NR_COLUMNS,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ GSList *node;
+
+ g_ptr_array_add(cwin->stores, store);
+
+ /* set candidates */
+ for (j = i * display_limit, node = g_slist_nth(candidates, j);
+ display_limit ? j < display_limit * (i + 1) : j < cwin->nr_candidates;
+ j++, node = g_slist_next(node))
+ {
+ GtkTreeIter ti;
+ if (node) {
+ gchar *str = node->data;
+ gchar **column = g_strsplit(str, "\a", 3);
+ gtk_list_store_append(store, &ti);
+ gtk_list_store_set(store, &ti,
+ COLUMN_HEADING, column[0],
+ COLUMN_CANDIDATE, column[1],
+ COLUMN_ANNOTATION, column[2],
+ TERMINATOR);
+ g_strfreev(column);
+ g_free(str);
+ } else {
+ /* No need to set any data for empty row. */
+ }
+ }
+ }
+ g_slist_free(candidates);
+
+ uim_cand_win_gtk_set_page(cwin, 0);
+ update_label(cwin);
+
+ uim_cand_win_gtk_show(cwin);
+ cwin->is_active = TRUE;
+}
+
+static void
+candwin_update(gchar **str)
+{
+ int index, need_hilite;
+ sscanf(str[1], "%d", &index);
+ sscanf(str[2], "%d", &need_hilite);
+ cwin->need_hilite = (need_hilite == 1) ? TRUE : FALSE;
+
+ uim_cand_win_gtk_set_index(cwin, index);
+}
+
+static void
+candwin_move(char **str)
+{
+ sscanf(str[1], "%d", &cwin->pos_x);
+ sscanf(str[2], "%d", &cwin->pos_y);
+
+ uim_cand_win_gtk_layout();
+}
+
+static void
+candwin_show(void)
+{
+ if (cwin->is_active) {
+ uim_cand_win_gtk_show(cwin);
+ if (cwin->sub_window.active)
+ gtk_widget_show(cwin->sub_window.window);
+ }
+}
+
+static void
+candwin_deactivate(void)
+{
+ gtk_widget_hide(GTK_WIDGET(cwin));
+ cwin->is_active = FALSE;
+ if (cwin->sub_window.window)
+ gtk_widget_hide(cwin->sub_window.window);
+}
+
+static void
+caret_state_show(gchar **str)
+{
+ int timeout;
+
+ sscanf(str[1], "%d", &timeout);
+ caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x,
cwin->pos_y, str[2]);
+ if (timeout != 0)
+ caret_state_indicator_set_timeout(cwin->caret_state_indicator, timeout
* 1000);
+ gtk_widget_show_all(GTK_WIDGET(cwin->caret_state_indicator));
+}
+
+static void
+caret_state_update()
+{
+ caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x,
cwin->pos_y, NULL);
+}
+
+static void
+caret_state_hide()
+{
+ gtk_widget_hide(cwin->caret_state_indicator);
+}
+
+static void
+candwin_set_nr_candidates(gchar **str)
+{
+ guint nr, display_limit;
+ gint i, nr_stores = 1;
+
+ sscanf(str[1], "%ud", &nr);
+ sscanf(str[2], "%ud", &display_limit);
+
+ cwin->candidate_index = -1;
+ cwin->nr_candidates = nr;
+ cwin->display_limit = display_limit;
+ cwin->need_hilite = FALSE;
+ cwin->is_active = TRUE;
+
+ if (cwin->stores == NULL)
+ cwin->stores = g_ptr_array_new();
+
+ /* remove old data */
+ for (i = cwin->stores->len - 1; i >= 0; i--) {
+ GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
+ if (store) {
+ gtk_list_store_clear(store);
+ g_object_unref(G_OBJECT(store));
+ }
+ }
+
+ /* calculate number of GtkListStores to create */
+ if (display_limit) {
+ nr_stores = nr / display_limit;
+ if (nr > display_limit * nr_stores)
+ nr_stores++;
+ }
+
+ /* setup dummy array */
+ for (i = 0; i < nr_stores; i++)
+ g_ptr_array_add(cwin->stores, NULL);
+}
+
+static void
+candwin_set_page_candidates(gchar **str)
+{
+ gsize rbytes, wbytes;
+ gint i;
+ guint j = 1;
+ gchar *utf8_str;
+ const gchar *charset;
+ GSList *candidates = NULL;
+ int page;
+
+ if (!strncmp(str[1], "charset=", 8))
+ charset = str[1] + 8;
+ else
+ charset = "UTF-8";
+
+ if (!strncmp(str[2], "page=", 5)) {
+ page = atoi(str[2] + 5);
+ i = 3;
+ } else {
+ /* shouldn't happen */
+ page = 0;
+ i = 2;
+ }
+
+ for ( ; str[i]; i++) {
+ if (strcmp(str[i], "") == 0) {
+ break;
+ }
+ utf8_str = g_convert(str[i],
+ -1,
+ "UTF-8",
+ charset,
+ &rbytes, &wbytes, NULL);
+
+ candidates = g_slist_prepend(candidates, utf8_str);
+ j++;
+ }
+ candidates = g_slist_reverse(candidates);
+
+ uim_cand_win_gtk_set_page_candidates(cwin, page, candidates);
+ g_slist_free(candidates);
+}
+
+static void
+candwin_show_page(gchar **str)
+{
+ int page;
+
+ sscanf(str[1], "%d", &page);
+
+ uim_cand_win_gtk_set_page(cwin, page);
+ uim_cand_win_gtk_show(cwin);
+}
+
+static void str_parse(gchar *str)
+{
+ gchar **tmp;
+ gchar *command;
+
+ tmp = g_strsplit(str, "\f", 0);
+ command = tmp[0];
+
+ if (command) {
+ if (strcmp("activate", command) == 0) {
+ candwin_activate(tmp);
+ } else if (strcmp("select", command) == 0) {
+ candwin_update(tmp);
+ } else if (strcmp("show", command) == 0) {
+ candwin_show();
+ } else if (strcmp("hide", command) == 0) {
+ gtk_widget_hide(GTK_WIDGET(cwin));
+ if (cwin->sub_window.window)
+ gtk_widget_hide(cwin->sub_window.window);
+ } else if (strcmp("move", command) == 0) {
+ candwin_move(tmp);
+ } else if (strcmp("deactivate", command) == 0) {
+ candwin_deactivate();
+ } else if (strcmp("show_caret_state", command) == 0) {
+ caret_state_show(tmp);
+ } else if (strcmp("update_caret_state", command) == 0) {
+ caret_state_update();
+ } else if (strcmp("hide_caret_state", command) == 0) {
+ caret_state_hide();
+ } else if (strcmp("set_nr_candidates", command) == 0) {
+ candwin_set_nr_candidates(tmp);
+ } else if (strcmp("set_page_candidates", command) == 0) {
+ candwin_set_page_candidates(tmp);
+ } else if (strcmp("show_page", command) == 0) {
+ candwin_show_page(tmp);
+ }
+ }
+ g_strfreev(tmp);
+}
+
+#define CANDIDATE_BUFFER_SIZE 4096
+static gboolean
+read_cb(GIOChannel *channel, GIOCondition c, gpointer p)
+{
+ char buf[CANDIDATE_BUFFER_SIZE];
+ char *read_buf = strdup("");
+ int i = 0;
+ int n;
+ gchar **tmp;
+ int fd = g_io_channel_unix_get_fd(channel);
+
+ while (uim_helper_fd_readable(fd) > 0) {
+ n = read(fd, buf, CANDIDATE_BUFFER_SIZE - 1);
+ if (n == 0) {
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+ if (n == -1)
+ return TRUE;
+ buf[n] = '\0';
+ read_buf = realloc(read_buf, strlen(read_buf) + n + 1);
+ strcat(read_buf, buf);
+ }
+
+ tmp = g_strsplit(read_buf, "\f\f", 0);
+
+ while (tmp[i]) {
+ str_parse(tmp[i]);
+ i++;
+ }
+ g_strfreev(tmp);
+ free(read_buf);
+ return TRUE;
+}
+
+int
+main(int argc, char *argv[])
+{
+ GIOChannel *channel;
+
+ /* disable uim context in annotation window */
+ setenv("GTK_IM_MODULE", "gtk-im-context-simple", 1);
+
+ gtk_init(&argc, &argv);
+ if (uim_init() < 0)
+ return 0;
+
+ init_candidate_win();
+
+ channel = g_io_channel_unix_new(0);
+ read_tag = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR,
+ read_cb, 0);
+ g_io_channel_unref(channel);
+
+ gtk_main();
+ uim_quit();
+
+ return 0;
+}
+
+/* copied from uim-cand-win-gtk.c */
+static gint
+uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin)
+{
+ g_return_val_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin), -1);
+
+ return cwin->candidate_index;
+}
+
+/* copied from uim-cand-win-gtk.c */
+static void
+uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index)
+{
+ gint new_page;
+
+ g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(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(cwin->buttons, pos);
+ prev_selected = (gpointer)cwin->selected;
+ if (prev_selected) {
+ gtk_button_set_relief(prev_selected->button, GTK_RELIEF_NONE);
+ }
+ gtk_button_set_relief(idxbutton->button, GTK_RELIEF_HALF);
+ 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);
+ }
+ }
+
+ 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(GtkTreeModel *model, GPtrArray *buttons, gint
display_limit)
+{
+ GtkTreeIter ti;
+ gboolean has_next;
+ gint cand_index = 0;
+ gint len;
+
+ 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(buttons, 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 == cwin->selected)
+ 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);
+ }
+}
+
+/* copied from uim-cand-win-gtk.c */
+static void
+uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page)
+{
+ guint len, new_page;
+ gint new_index;
+
+ g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(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(GTK_TREE_MODEL(cwin->stores->pdata[new_page]),
+ cwin->buttons, cwin->display_limit);
+
+ 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;
+
+ /* shrink the window */
+ gtk_window_resize(GTK_WINDOW(cwin), CANDWIN_DEFAULT_WIDTH, 1);
+
+ uim_cand_win_gtk_set_index(cwin, new_index);
+}
+
+/* copied from uim-cand-win-gtk.c and adjusted */
+static void
+uim_cand_win_gtk_set_page_candidates(UIMCandidateWindow *cwin,
+ guint page,
+ GSList *candidates)
+{
+ GtkListStore *store;
+ GSList *node;
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/gtk2/candwin/Makefile.am Tue May 24 07:45:43 2011
+++ /trunk/gtk2/candwin/Makefile.am Fri Jun 17 02:17:18 2011
@@ -1,5 +1,5 @@
if GTK2
-libexec_PROGRAMS = uim-candwin-gtk uim-candwin-tbl-gtk
+libexec_PROGRAMS = uim-candwin-gtk uim-candwin-tbl-gtk
uim-candwin-horizontal-gtk
uim_candwin_gtk_SOURCES = gtk.c \
../immodule/caret-state-indicator.c \
@@ -16,4 +16,12 @@
$(top_builddir)/uim/libuim.la
uim_candwin_tbl_gtk_CPPFLAGS = -I$(top_srcdir)
uim_candwin_tbl_gtk_CFLAGS = @GTK2_CFLAGS@
+
+uim_candwin_horizontal_gtk_SOURCES = horizontal-gtk.c \
+ ../immodule/caret-state-indicator.c \
+ ../immodule/caret-state-indicator.h
+uim_candwin_horizontal_gtk_LDADD = @GTK2_LIBS@
$(top_builddir)/uim/libuim-scm.la \
+ $(top_builddir)/uim/libuim.la
+uim_candwin_horizontal_gtk_CPPFLAGS = -I$(top_srcdir)
+uim_candwin_horizontal_gtk_CFLAGS = @GTK2_CFLAGS@
endif
=======================================
--- /trunk/gtk3/candwin/Makefile.am Tue May 24 07:45:43 2011
+++ /trunk/gtk3/candwin/Makefile.am Fri Jun 17 02:17:18 2011
@@ -1,5 +1,5 @@
if GTK3
-libexec_PROGRAMS = uim-candwin-gtk3 uim-candwin-tbl-gtk3
+libexec_PROGRAMS = uim-candwin-gtk3 uim-candwin-tbl-gtk3
uim-candwin-horizontal-gtk3
uim_candwin_gtk3_SOURCES = ../../gtk2/candwin/gtk.c \
../../gtk2/immodule/caret-state-indicator.c \
../../gtk2/immodule/caret-state-indicator.h
@@ -15,4 +15,12 @@
$(top_builddir)/uim/libuim.la
uim_candwin_tbl_gtk3_CPPFLAGS = -I$(top_srcdir)
uim_candwin_tbl_gtk3_CFLAGS = @GTK3_CFLAGS@
+
+uim_candwin_horizontal_gtk3_SOURCES = ../../gtk2/candwin/horizontal-gtk.c
\
+ ../../gtk2/immodule/caret-state-indicator.c \
+ ../../gtk2/immodule/caret-state-indicator.h
+uim_candwin_horizontal_gtk3_LDADD = @GTK3_LIBS@
$(top_builddir)/uim/libuim-scm.la \
+ $(top_builddir)/uim/libuim.la
+uim_candwin_horizontal_gtk3_CPPFLAGS = -I$(top_srcdir)
+uim_candwin_horizontal_gtk3_CFLAGS = @GTK3_CFLAGS@
endif