3
Copyright (c) 2003-2005 uim Project http://uim.freedesktop.org/
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions
11
1. Redistributions of source code must retain the above copyright
12
notice, this list of conditions and the following disclaimer.
13
2. Redistributions in binary form must reproduce the above copyright
14
notice, this list of conditions and the following disclaimer in the
15
documentation and/or other materials provided with the distribution.
16
3. Neither the name of authors nor the names of its contributors
17
may be used to endorse or promote products derived from this software
18
without specific prior written permission.
20
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
#include <uim/uim-helper.h>
41
#include <glib/gprintf.h>
44
#include <sys/types.h>
47
#include "../gtk/caret-state-indicator.h"
49
#define UIM_TYPE_CANDIDATE_WINDOW (candidate_window_get_type())
50
#define UIM_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), candidate_window_get_type(), UIMCandidateWindow))
51
#define UIM_IS_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UIM_TYPE_CANDIDATE_WINDOW))
52
#define UIM_IS_CANDIDATE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UIM_TYPE_CANDIDATE_WINDOW))
53
#define UIM_CANDIDATE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UIM_TYPE_CANDIDATE_WINDOW, UIMCandidateWindowClass))
55
typedef struct _UIMCandidateWindow UIMCandidateWindow;
56
typedef struct _UIMCandidateWindowClass UIMCandidateWindowClass;
58
struct _UIMCandidateWindow {
76
GtkWidget *caret_state_indicator;
81
struct _UIMCandidateWindowClass {
82
GtkWindowClass parent_class;
85
void (*index_changed) (UIMCandidateWindowClass *candwin);
88
static UIMCandidateWindow *cwin; /* use static one */
90
GType candidate_window_get_type(void);
91
UIMCandidateWindow *candidate_window_new(void);
93
/* copied from uim-cand-win-gtk.c */
94
static gint uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin);
95
static void uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index);
96
static void uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page);
98
static void uim_cand_win_gtk_layout(void);
100
#define NR_CANDIDATES 10 /* FIXME! not used */
101
#define CANDWIN_DEFAULT_WIDTH 80
104
INDEX_CHANGED_SIGNAL,
114
static void candidate_window_init(UIMCandidateWindow *cwin);
115
static void candidate_window_class_init(UIMCandidateWindowClass *klass);
117
static gboolean tree_selection_changed(GtkTreeSelection *selection,
120
gboolean path_currently_selected,
124
static gboolean tree_view_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data);
126
static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
128
static GType candidate_window_type = 0;
129
static GTypeInfo const object_info = {
130
sizeof (UIMCandidateWindowClass),
133
(GClassInitFunc) candidate_window_class_init,
136
sizeof(UIMCandidateWindow),
138
(GInstanceInitFunc) candidate_window_init,
141
static gint cand_win_gtk_signals[NR_SIGNALS] = {0};
143
static unsigned int read_tag;
145
static void init_candidate_win(void);
146
static void candwin_activate(gchar **str);
147
static void candwin_update(gchar **str);
148
static void candwin_move(char **str);
149
static void candwin_show(void);
150
static void candwin_deactivate(void);
151
static void str_parse(char *str);
153
static void index_changed_cb(UIMCandidateWindow *cwin)
155
fprintf(stdout, "index\n");
156
fprintf(stdout, "%d\n\n", uim_cand_win_gtk_get_index(cwin));
161
candidate_window_get_type(void)
163
if (!candidate_window_type)
164
candidate_window_type = g_type_register_static(GTK_TYPE_WINDOW,
165
"UIMCandidateWindow", &object_info, (GTypeFlags)0);
166
return candidate_window_type;
169
static void candidate_window_class_init(UIMCandidateWindowClass *klass)
171
cand_win_gtk_signals[INDEX_CHANGED_SIGNAL]
172
= g_signal_new("index-changed",
173
G_TYPE_FROM_CLASS(klass),
175
G_STRUCT_OFFSET(UIMCandidateWindowClass, index_changed),
177
g_cclosure_marshal_VOID__VOID,
182
candidate_window_new(void)
184
GObject *obj = g_object_new(UIM_TYPE_CANDIDATE_WINDOW, "type",
185
GTK_WINDOW_POPUP, NULL);
186
return UIM_CANDIDATE_WINDOW(obj);
189
/* copied from uim-cand-win-gtk.c */
191
update_label(UIMCandidateWindow *cwin)
195
if (cwin->candidate_index >= 0)
196
g_snprintf(label_str, sizeof(label_str), "%d / %d",
197
cwin->candidate_index + 1 , cwin->nr_candidates);
199
g_snprintf(label_str, sizeof(label_str), "- / %d",
200
cwin->nr_candidates);
202
gtk_label_set_text(GTK_LABEL(cwin->num_label), label_str);
205
/* copied from uim-cand-win-gtk.c */
207
tree_selection_changed(GtkTreeSelection *selection,
210
gboolean path_currently_selected,
213
/* candidate_window *cwin = data; */
220
indicies = gtk_tree_path_get_indices(path);
221
g_return_val_if_fail(indicies, TRUE);
222
idx = *indicies + cwin->display_limit * cwin->page_index;
224
if (!path_currently_selected && cwin->candidate_index != idx) {
225
if (cwin->candidate_index >= 0) {
226
cwin->candidate_index = idx;
227
g_signal_emit(G_OBJECT(cwin),
228
cand_win_gtk_signals[INDEX_CHANGED_SIGNAL], 0);
233
if (cwin->candidate_index < 0)
245
/* copied from uim-cand-win-gtk.c */
247
tree_view_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
250
gboolean exist, retval = FALSE;
253
fprintf(stderr, "tree_view_button_press\n");
254
g_return_val_if_fail(GTK_IS_TREE_VIEW(widget), FALSE);
255
g_return_val_if_fail(UIM_CANDIDATE_WINDOW(data), FALSE);
257
/* cwin = UIM_CANDIDATE_WINDOW(data); */
259
exist = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
261
&path, NULL, NULL, NULL);
265
indicies = gtk_tree_path_get_indices(path);
267
/* don't relay button press event to empty row */
268
if (cwin->display_limit * cwin->page_index + *indicies >= cwin->nr_candidates)
272
gtk_tree_path_free(path);
279
cb_tree_view_destroy(GtkWidget *widget, GPtrArray *stores)
283
g_return_if_fail(GTK_IS_TREE_VIEW(widget));
285
for (i = cwin->stores->len - 1; i >= 0; i--) {
286
GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
287
gtk_list_store_clear(store);
288
g_object_unref(G_OBJECT(store));
290
g_ptr_array_free(cwin->stores, TRUE);
294
init_candidate_win(void) {
295
cwin = candidate_window_new();
296
g_signal_connect(G_OBJECT(cwin), "index-changed",
297
G_CALLBACK(index_changed_cb), NULL);
298
g_signal_connect(G_OBJECT(cwin), "configure_event",
299
G_CALLBACK(configure_event_cb), NULL);
303
candidate_window_init(UIMCandidateWindow *cwin)
305
GtkCellRenderer *renderer;
306
GtkTreeViewColumn *column;
307
GtkWidget *scrolled_window;
310
GtkTreeSelection *selection;
311
GdkRectangle cursor_location;
313
vbox = gtk_vbox_new(FALSE, 0);
314
frame = gtk_frame_new(NULL);
316
cwin->stores = g_ptr_array_new();
318
gtk_window_set_default_size(GTK_WINDOW(cwin),
319
CANDWIN_DEFAULT_WIDTH, -1);
322
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
323
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
326
gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
328
cwin->view = gtk_tree_view_new();
329
g_signal_connect(G_OBJECT(cwin->view), "destroy",
330
G_CALLBACK(cb_tree_view_destroy), cwin->stores);
331
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(cwin->view), TRUE);
332
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cwin->view), FALSE);
333
gtk_container_add(GTK_CONTAINER(scrolled_window), cwin->view);
335
gtk_container_add(GTK_CONTAINER(frame), vbox);
336
gtk_container_add(GTK_CONTAINER(cwin), frame);
337
gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
339
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cwin->view));
341
gtk_tree_selection_set_select_function(selection,
342
tree_selection_changed,
346
renderer = gtk_cell_renderer_text_new();
347
g_object_set(renderer, "scale", 1.2, NULL);
349
column = gtk_tree_view_column_new_with_attributes("No",
354
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
355
gtk_tree_view_append_column(GTK_TREE_VIEW(cwin->view), column);
357
renderer = gtk_cell_renderer_text_new();
358
g_object_set(renderer, "scale", 1.2, NULL);
359
/* g_object_set(renderer, "size-points", 20.0, NULL); */
360
column = gtk_tree_view_column_new_with_attributes("Text",
365
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
366
gtk_tree_view_append_column(GTK_TREE_VIEW(cwin->view), column);
368
cwin->num_label = gtk_label_new("");
370
gtk_box_pack_start(GTK_BOX(vbox), cwin->num_label, FALSE, FALSE, 0);
373
g_signal_connect(G_OBJECT(cwin->view), "button-press-event",
374
G_CALLBACK(tree_view_button_press), cwin);
379
cwin->is_active = FALSE;
380
cwin->caret_state_indicator = caret_state_indicator_new();
382
cursor_location.x = 0;
383
cursor_location.y = 0;
384
cursor_location.height = 0;
385
caret_state_indicator_set_cursor_location(cwin->caret_state_indicator, &cursor_location);
389
candwin_activate(gchar **str)
391
gsize rbytes, wbytes;
392
gint i, nr_stores = 1;
395
const gchar *charset;
397
GSList *candidates = NULL;
399
if (cwin->stores == NULL)
400
cwin->stores = g_ptr_array_new();
402
/* remove old data */
403
for (i = cwin->stores->len - 1; i >= 0; i--) {
404
GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
405
gtk_list_store_clear(store);
406
g_object_unref(G_OBJECT(store));
409
if (!strncmp(str[1], "charset=", 8))
410
charset = str[1] + 8;
414
if (!strncmp(str[2], "display_limit=", 14)) {
415
display_limit = atoi(str[2] + 14);
422
for ( ; str[i]; i++) {
423
if (strcmp(str[i], "") == 0) {
426
utf8_str = g_convert(str[i],
430
&rbytes, &wbytes, NULL);
432
candidates = g_slist_append(candidates, utf8_str);
436
cwin->candidate_index = -1;
437
cwin->nr_candidates = j - 1;
438
cwin->display_limit = display_limit;
440
if (candidates == NULL)
443
/* calculate number of GtkListStores to create */
445
nr_stores = cwin->nr_candidates / display_limit;
446
if (cwin->nr_candidates > display_limit * nr_stores)
450
/* create GtkListStores, and set candidates */
451
for (i = 0; i < nr_stores; i++) {
452
GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
455
g_ptr_array_add(cwin->stores, store);
458
for (j = i * display_limit, node = g_slist_nth(candidates, j);
459
display_limit ? j < display_limit * (i + 1) : j < cwin->nr_candidates;
460
j++, node = g_slist_next(node))
464
gchar *str = node->data;
465
gchar **column = g_strsplit(str, "\t", 2);
466
gtk_list_store_append(store, &ti);
467
gtk_list_store_set(store, &ti,
468
COLUMN_HEADING, column[0],
469
COLUMN_CANDIDATE, column[1],
474
/* No need to set any data for empty row. */
479
uim_cand_win_gtk_set_page(cwin, 0);
482
gtk_widget_show_all(GTK_WIDGET(cwin));
483
cwin->is_active = TRUE;
487
candwin_update(gchar **str)
490
sscanf(str[1], "%d", &index);
492
uim_cand_win_gtk_set_index(cwin, index);
496
candwin_move(char **str)
498
sscanf(str[1], "%d", &cwin->pos_x);
499
sscanf(str[2], "%d", &cwin->pos_y);
501
uim_cand_win_gtk_layout();
508
gtk_widget_show_all(GTK_WIDGET(cwin));
512
candwin_deactivate(void)
514
gtk_widget_hide(GTK_WIDGET(cwin));
515
cwin->is_active = FALSE;
519
caret_state_show(gchar **str)
523
sscanf(str[1], "%d", &timeout);
524
caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, str[2]);
526
caret_state_indicator_set_timeout(cwin->caret_state_indicator, timeout * 1000);
527
gtk_widget_show_all(GTK_WIDGET(cwin->caret_state_indicator));
533
caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, NULL);
539
gtk_widget_hide(cwin->caret_state_indicator);
542
static void str_parse(gchar *str)
547
tmp = g_strsplit(str, "\n", 0);
551
if (strcmp("activate", command) == 0) {
552
candwin_activate(tmp);
553
} else if (strcmp("select", command) == 0) {
555
} else if (strcmp("show", command) == 0) {
557
} else if (strcmp("hide", command) == 0) {
558
gtk_widget_hide_all(GTK_WIDGET(cwin));
559
} else if (strcmp("move", command) == 0) {
561
} else if (strcmp("deactivate", command) == 0) {
562
candwin_deactivate();
563
} else if (strcmp("show_caret_state", command) == 0) {
564
caret_state_show(tmp);
565
} else if (strcmp("update_caret_state", command) == 0) {
566
caret_state_update();
567
} else if (strcmp("hide_caret_state", command) == 0) {
574
#define CANDIDATE_BUFFER_SIZE 4096
576
read_cb(GIOChannel *channel, GIOCondition c, gpointer p)
578
char buf[CANDIDATE_BUFFER_SIZE];
579
char *read_buf = strdup("");
583
int fd = g_io_channel_unix_get_fd(channel);
585
while (uim_helper_fd_readable(fd) > 0) {
586
n = read(fd, buf, CANDIDATE_BUFFER_SIZE - 1);
594
read_buf = realloc(read_buf, strlen(read_buf) + n + 1);
595
strcat(read_buf, buf);
598
tmp = g_strsplit(read_buf, "\n\n", 0);
610
main(int argc, char *argv[])
615
gtk_init(&argc, &argv);
617
init_candidate_win();
619
channel = g_io_channel_unix_new(0);
620
read_tag = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR,
622
g_io_channel_unref(channel);
628
/* copied from uim-cand-win-gtk.c */
630
uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin)
632
g_return_val_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin), -1);
634
return cwin->candidate_index;
637
/* copied from uim-cand-win-gtk.c */
639
uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index)
643
g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
645
if (index >= (gint) cwin->nr_candidates)
646
cwin->candidate_index = 0;
648
cwin->candidate_index = index;
650
if (cwin->candidate_index >= 0 && cwin->display_limit)
651
new_page = cwin->candidate_index / cwin->display_limit;
653
new_page = cwin->page_index;
655
if (cwin->page_index != new_page)
656
uim_cand_win_gtk_set_page(cwin, new_page);
658
if (cwin->candidate_index >= 0) {
662
if (cwin->display_limit)
663
pos = cwin->candidate_index % cwin->display_limit;
665
path = gtk_tree_path_new_from_indices(pos, -1);
666
gtk_tree_view_set_cursor(GTK_TREE_VIEW(cwin->view),
668
gtk_tree_path_free(path);
671
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cwin
674
gtk_tree_selection_unselect_all(selection);
678
/* copied from uim-cand-win-gtk.c */
680
uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page)
685
g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
686
g_return_if_fail(cwin->stores);
688
len = cwin->stores->len;
689
g_return_if_fail(len);
692
gtk_tree_view_set_model(GTK_TREE_VIEW(cwin->view),
693
GTK_TREE_MODEL(cwin->stores->pdata[len - 1]));
695
} else if (page >= (gint) len) {
696
gtk_tree_view_set_model(GTK_TREE_VIEW(cwin->view),
697
GTK_TREE_MODEL(cwin->stores->pdata[0]));
700
gtk_tree_view_set_model(GTK_TREE_VIEW(cwin->view),
702
GTK_TREE_MODEL(cwin->stores->pdata[page]));
706
cwin->page_index = new_page;
708
if (cwin->display_limit) {
709
if (cwin->candidate_index >= 0)
711
= (new_page * cwin->display_limit) + (cwin->candidate_index % cwin->display_limit);
715
new_index = cwin->candidate_index;
718
if (new_index >= (gint) cwin->nr_candidates)
719
new_index = cwin->nr_candidates - 1;
721
/* shrink the window */
722
gtk_window_resize(GTK_WINDOW(cwin), CANDWIN_DEFAULT_WIDTH, 1);
724
uim_cand_win_gtk_set_index(cwin, new_index);
728
uim_cand_win_gtk_layout()
731
int screen_width, screen_height;
733
screen_width = gdk_screen_get_width(gdk_screen_get_default());
734
screen_height = gdk_screen_get_height(gdk_screen_get_default());
736
if (screen_width < cwin->pos_x + cwin->width)
737
x = cwin->pos_x - cwin->width;
741
if (screen_height < cwin->pos_y + cwin->height)
742
y = cwin->pos_y - cwin->height - 20; /* FIXME: Preedit height is needed to
743
be sent by uim-xim */
747
gtk_window_move(GTK_WINDOW(cwin), x, y);
751
configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
753
cwin->width = event->width;
754
cwin->height = event->height;
756
uim_cand_win_gtk_layout();