3
Copyright (c) 2003-2011 uim Project http://code.google.com/p/uim/
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>
39
#include <uim/uim-scm.h>
46
#include <sys/types.h>
49
#include "../gtk/caret-state-indicator.h"
51
#define UIM_TYPE_CANDIDATE_WINDOW (candidate_window_get_type())
52
#define UIM_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), candidate_window_get_type(), UIMCandidateWindow))
53
#define UIM_IS_CANDIDATE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UIM_TYPE_CANDIDATE_WINDOW))
54
#define UIM_IS_CANDIDATE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UIM_TYPE_CANDIDATE_WINDOW))
55
#define UIM_CANDIDATE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UIM_TYPE_CANDIDATE_WINDOW, UIMCandidateWindowClass))
57
typedef struct _UIMCandidateWindow UIMCandidateWindow;
58
typedef struct _UIMCandidateWindowClass UIMCandidateWindowClass;
60
struct _UIMCandidateWindow {
65
GtkWidget *scrolled_window;
72
gchar *tbl_cell2label;
84
GtkWidget *caret_state_indicator;
90
struct _UIMCandidateWindowClass {
91
GtkWindowClass parent_class;
94
void (*index_changed) (UIMCandidateWindowClass *candwin);
97
static UIMCandidateWindow *cwin; /* use single candwin */
99
GType candidate_window_get_type(void);
100
UIMCandidateWindow *candidate_window_new(void);
102
/* copied from uim-cand-win-gtk.c */
103
static gint uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin);
104
static void uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index);
105
static void uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page);
106
static void uim_cand_win_gtk_set_page_candidates(UIMCandidateWindow *cwin, guint page, GSList *candidates);
108
static void uim_cand_win_gtk_layout(void);
109
static void uim_cand_win_gtk_show(UIMCandidateWindow *cwin);
111
#define CANDWIN_DEFAULT_WIDTH 80
114
INDEX_CHANGED_SIGNAL,
126
#define TABLE_NR_COLUMNS 13
127
#define TABLE_NR_ROWS 8
128
#define TABLE_NR_CELLS (TABLE_NR_COLUMNS * TABLE_NR_ROWS)
129
#define CELLINDEX(row,col) ((row) * TABLE_NR_COLUMNS + (col))
131
static gchar default_tbl_cell2label[TABLE_NR_CELLS] = {
132
'1','2','3','4','5', '6','7','8','9','0', '-','^','\\',
133
'q','w','e','r','t', 'y','u','i','o','p', '@','[','\0',
134
'a','s','d','f','g', 'h','j','k','l',';', ':',']','\0',
135
'z','x','c','v','b', 'n','m',',','.','/', '\0','\0',' ',
136
'!','"','#','$','%', '&','\'','(',')','\0', '=','~','|',
137
'Q','W','E','R','T', 'Y','U','I','O','P', '`','{','\0',
138
'A','S','D','F','G', 'H','J','K','L','+', '*','}','\0',
139
'Z','X','C','V','B', 'N','M','<','>','?', '_','\0','\0',
141
/* table consists of four blocks
145
#define BLOCK_A_ROW_START 0
146
#define BLOCK_A_ROW_END 4
147
#define BLOCK_A_COLUMN_START 10
148
#define BLOCK_A_COLUMN_END TABLE_NR_COLUMNS
149
#define BLOCK_LRS_ROW_START BLOCK_A_ROW_END
150
#define BLOCK_LRS_ROW_END TABLE_NR_ROWS
151
#define BLOCK_LRS_COLUMN_START 0
152
#define BLOCK_LRS_COLUMN_END BLOCK_A_COLUMN_START
153
#define BLOCK_AS_ROW_START BLOCK_LRS_ROW_START
154
#define BLOCK_AS_ROW_END BLOCK_LRS_ROW_END
155
#define BLOCK_AS_COLUMN_START BLOCK_LRS_COLUMN_END
156
#define BLOCK_AS_COLUMN_END TABLE_NR_COLUMNS
157
#define BLOCK_LR_NR_CELLS (BLOCK_A_ROW_END * BLOCK_A_COLUMN_START)
158
#define BLOCK_LRS_NR_CELLS ((BLOCK_LRS_ROW_END - BLOCK_LRS_ROW_START) * (BLOCK_LRS_COLUMN_END - BLOCK_LRS_COLUMN_START))
160
#define BLOCK_SPACING 20
161
#define HOMEPOSITION_SPACING 2
162
#define SPACING_LEFT_BLOCK_COLUMN 4
163
#define SPACING_RIGHT_BLOCK_COLUMN (BLOCK_A_COLUMN_START - 1)
164
#define SPACING_UP_BLOCK_ROW (BLOCK_A_ROW_END - 1)
165
#define SPACING_LEFTHAND_FAR_COLUMN 3
166
#define SPACING_RIGHTHAND_FAR_COLUMN 5
167
#define SPACING_UPPER_FAR_ROW 0
168
#define SPACING_SHIFT_UPPER_FAR_ROW 4
170
struct index_button {
171
gint cand_index_in_page;
175
static void candidate_window_init(UIMCandidateWindow *cwin);
176
static void candidate_window_class_init(UIMCandidateWindowClass *klass);
178
static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
180
static GType candidate_window_type = 0;
181
static GTypeInfo const object_info = {
182
sizeof (UIMCandidateWindowClass),
185
(GClassInitFunc) candidate_window_class_init,
188
sizeof(UIMCandidateWindow),
190
(GInstanceInitFunc) candidate_window_init,
193
static gint cand_win_gtk_signals[NR_SIGNALS] = {0};
195
static unsigned int read_tag;
197
static void init_candidate_win(void);
198
static void candwin_activate(gchar **str);
199
static void candwin_update(gchar **str);
200
static void candwin_move(char **str);
201
static void candwin_show(void);
202
static void candwin_deactivate(void);
203
static void candwin_set_nr_candidates(gchar **str);
204
static void candwin_set_page_candidates(gchar **str);
205
static void candwin_show_page(gchar **str);
206
static void str_parse(char *str);
207
static gchar *init_tbl_cell2label(void);
208
static void clear_button(struct index_button *idxbutton,
209
const gchar *tbl_cell2label, gint cell_index);
210
static GtkButton *get_button(GPtrArray *buttons, gint idx);
212
static void index_changed_cb(UIMCandidateWindow *cwin)
214
fprintf(stdout, "index\n");
215
fprintf(stdout, "%d\n\n", uim_cand_win_gtk_get_index(cwin));
220
candidate_window_get_type(void)
222
if (!candidate_window_type)
223
candidate_window_type = g_type_register_static(GTK_TYPE_WINDOW,
224
"UIMCandidateWindow", &object_info, (GTypeFlags)0);
225
return candidate_window_type;
228
static void candidate_window_class_init(UIMCandidateWindowClass *klass)
230
cand_win_gtk_signals[INDEX_CHANGED_SIGNAL]
231
= g_signal_new("index-changed",
232
G_TYPE_FROM_CLASS(klass),
234
G_STRUCT_OFFSET(UIMCandidateWindowClass, index_changed),
236
g_cclosure_marshal_VOID__VOID,
241
candidate_window_new(void)
243
GObject *obj = g_object_new(UIM_TYPE_CANDIDATE_WINDOW, "type",
244
GTK_WINDOW_POPUP, NULL);
245
return UIM_CANDIDATE_WINDOW(obj);
248
/* copied from uim-cand-win-gtk.c */
250
update_label(UIMCandidateWindow *cwin)
254
if (cwin->candidate_index >= 0)
255
g_snprintf(label_str, sizeof(label_str), "%d / %d",
256
cwin->candidate_index + 1 , cwin->nr_candidates);
258
g_snprintf(label_str, sizeof(label_str), "- / %d",
259
cwin->nr_candidates);
261
gtk_label_set_text(GTK_LABEL(cwin->num_label), label_str);
265
button_clicked(GtkButton *button, gpointer data)
267
UIMCandidateWindow *cwin = UIM_CANDIDATE_WINDOW(data);
271
for (i = 0; i < TABLE_NR_CELLS; i++) {
273
struct index_button *idxbutton;
274
idxbutton = g_ptr_array_index(cwin->buttons, i);
278
p = idxbutton->button;
280
idx = idxbutton->cand_index_in_page;
284
if (idx >= 0 && cwin->display_limit) {
285
if (idx >= (gint)cwin->display_limit) {
286
idx %= cwin->display_limit;
288
cwin->candidate_index = cwin->page_index * cwin->display_limit + idx;
290
cwin->candidate_index = idx;
292
if (cwin->candidate_index >= (gint)cwin->nr_candidates) {
293
cwin->candidate_index = -1;
295
g_signal_emit_by_name(G_OBJECT(cwin), "index-changed");
299
cb_table_view_destroy(GtkWidget *widget, GPtrArray *stores)
303
g_return_if_fail(GTK_IS_TABLE(widget));
305
for (i = cwin->stores->len - 1; i >= 0; i--) {
306
GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
308
gtk_list_store_clear(store);
309
g_object_unref(G_OBJECT(store));
312
g_ptr_array_free(cwin->stores, TRUE);
314
for (i = 0; i < (gint)cwin->buttons->len; i++) {
315
if (cwin->buttons->pdata[i]) {
316
g_free(cwin->buttons->pdata[i]);
317
/* GtkButton is destroyed by container */
320
g_ptr_array_free(cwin->buttons, TRUE);
322
if (cwin->tbl_cell2label != default_tbl_cell2label) {
323
g_free(cwin->tbl_cell2label);
328
init_candidate_win(void) {
329
cwin = candidate_window_new();
330
g_signal_connect(G_OBJECT(cwin), "index-changed",
331
G_CALLBACK(index_changed_cb), NULL);
332
g_signal_connect(G_OBJECT(cwin), "configure_event",
333
G_CALLBACK(configure_event_cb), NULL);
337
candidate_window_init(UIMCandidateWindow *cwin)
339
GdkRectangle cursor_location;
342
cwin->vbox = gtk_vbox_new(FALSE, 0);
343
cwin->frame = gtk_frame_new(NULL);
345
cwin->stores = g_ptr_array_new();
346
cwin->buttons = g_ptr_array_new();
347
cwin->tbl_cell2label = init_tbl_cell2label();
349
gtk_window_set_default_size(GTK_WINDOW(cwin),
350
CANDWIN_DEFAULT_WIDTH, -1);
353
cwin->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
354
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cwin->scrolled_window),
357
gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->scrolled_window, TRUE, TRUE, 0);
359
cwin->view = gtk_table_new(TABLE_NR_ROWS, TABLE_NR_COLUMNS, FALSE);
360
g_signal_connect(G_OBJECT(cwin->view), "destroy",
361
G_CALLBACK(cb_table_view_destroy), cwin->stores);
362
cwin->viewport = gtk_viewport_new(NULL, NULL);
363
gtk_container_add(GTK_CONTAINER(cwin->viewport), cwin->view);
364
gtk_container_add(GTK_CONTAINER(cwin->scrolled_window), cwin->viewport);
365
gtk_container_set_resize_mode(GTK_CONTAINER(cwin->viewport), GTK_RESIZE_PARENT);
366
for (row = 0; row < TABLE_NR_ROWS; row++) {
367
for (col = 0; col < TABLE_NR_COLUMNS; col++) {
369
struct index_button *idxbutton;
370
button = gtk_button_new_with_label(" ");
371
g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), cwin);
372
gtk_table_attach_defaults(GTK_TABLE(cwin->view), button,
373
col, col + 1, row, row + 1);
374
idxbutton = g_malloc(sizeof(struct index_button));
376
idxbutton->button = GTK_BUTTON(button);
377
clear_button(idxbutton, cwin->tbl_cell2label, CELLINDEX(row, col));
379
g_ptr_array_add(cwin->buttons, idxbutton);
382
gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_LEFT_BLOCK_COLUMN,
384
gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_RIGHT_BLOCK_COLUMN,
386
gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_UP_BLOCK_ROW,
388
gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_LEFTHAND_FAR_COLUMN,
389
HOMEPOSITION_SPACING);
390
gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_RIGHTHAND_FAR_COLUMN,
391
HOMEPOSITION_SPACING);
392
gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_UPPER_FAR_ROW,
393
HOMEPOSITION_SPACING);
394
gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_SHIFT_UPPER_FAR_ROW,
395
HOMEPOSITION_SPACING);
397
gtk_container_add(GTK_CONTAINER(cwin->frame), cwin->vbox);
398
gtk_container_add(GTK_CONTAINER(cwin), cwin->frame);
399
gtk_container_set_border_width(GTK_CONTAINER(cwin->frame), 0);
401
cwin->num_label = gtk_label_new("");
403
gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->num_label, FALSE, FALSE, 0);
407
cwin->is_active = FALSE;
408
cwin->need_hilite = FALSE;
409
cwin->caret_state_indicator = caret_state_indicator_new();
411
cursor_location.x = 0;
412
cursor_location.y = 0;
413
cursor_location.height = 0;
414
caret_state_indicator_set_cursor_location(cwin->caret_state_indicator, &cursor_location);
418
init_tbl_cell2label(void)
423
uim_lisp *ary0, *ary;
426
list = uim_scm_symbol_value("uim-candwin-prog-layout");
427
if (list == NULL || !uim_scm_listp(list)) {
428
return default_tbl_cell2label;
430
ary0 = ary = (uim_lisp *)uim_scm_list2array(list, &len, NULL);
431
if (ary == NULL || len <= 0) {
435
return default_tbl_cell2label;
437
table = (gchar *)g_malloc0(TABLE_NR_CELLS);
440
return default_tbl_cell2label;
442
for (i = 0; i < len && i < TABLE_NR_CELLS; i++, ary++) {
444
#if 0 /* 0 for investigation (Because uim-candwin-tbl-gtk is standalone,
445
bad effects to other programs are smaller than gtk-immodule)
447
if (!uim_scm_strp(*ary)) {
448
/* XXX: output notify message? */
451
return default_tbl_cell2label;
454
str = uim_scm_c_str(*ary);
456
/* XXX: only use first char */
466
assign_cellbutton(GPtrArray *buttons, const gchar *tbl_cell2label,
467
const gchar labelchar, gint cand_index, gint display_limit,
471
struct index_button *idxbutton;
473
if (labelchar != '\0') {
474
/* find button by labelchar */
475
for (i = 0; i < TABLE_NR_CELLS; i++) {
476
if (tbl_cell2label[i] == labelchar) {
477
idxbutton = g_ptr_array_index(buttons, i);
481
if (idxbutton->cand_index_in_page != -1) {
482
break; /* already used */
484
idxbutton->cand_index_in_page = cand_index;
486
return idxbutton->button;
490
/* labelchar not found || already used */
493
for (i = 0; i < TABLE_NR_CELLS; i++) {
494
if (display_limit && display_limit <= BLOCK_LR_NR_CELLS + BLOCK_LRS_NR_CELLS
495
&& i % TABLE_NR_COLUMNS >= BLOCK_A_COLUMN_START) {
496
/* skip blockA which is far from home position */
497
i += TABLE_NR_COLUMNS - BLOCK_A_COLUMN_START - 1;
500
idxbutton = g_ptr_array_index(buttons, i);
504
if (idxbutton->cand_index_in_page == -1) {
505
idxbutton->cand_index_in_page = cand_index;
507
return idxbutton->button;
511
/* failed to assign button */
517
candwin_activate(gchar **str)
519
gsize rbytes, wbytes;
520
gint i, nr_stores = 1;
523
const gchar *charset;
525
GSList *candidates = NULL;
527
if (cwin->stores == NULL)
528
cwin->stores = g_ptr_array_new();
530
/* remove old data */
531
for (i = cwin->stores->len - 1; i >= 0; i--) {
532
GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
534
gtk_list_store_clear(store);
535
g_object_unref(G_OBJECT(store));
539
if (!strncmp(str[1], "charset=", 8))
540
charset = str[1] + 8;
544
if (!strncmp(str[2], "display_limit=", 14)) {
545
display_limit = atoi(str[2] + 14);
552
for ( ; str[i]; i++) {
553
if (strcmp(str[i], "") == 0) {
556
utf8_str = g_convert(str[i],
560
&rbytes, &wbytes, NULL);
562
candidates = g_slist_prepend(candidates, utf8_str);
565
candidates = g_slist_reverse(candidates);
567
cwin->candidate_index = -1;
568
cwin->nr_candidates = j - 1;
569
cwin->display_limit = display_limit;
570
cwin->need_hilite = FALSE;
572
if (candidates == NULL)
575
/* calculate number of GtkListStores to create */
577
nr_stores = cwin->nr_candidates / display_limit;
578
if (cwin->nr_candidates > display_limit * nr_stores)
582
/* create GtkListStores, and set candidates */
583
for (i = 0; i < nr_stores; i++) {
584
GtkListStore *store = gtk_list_store_new(LISTSTORE_NR_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
587
g_ptr_array_add(cwin->stores, store);
590
for (j = i * display_limit, node = g_slist_nth(candidates, j);
591
display_limit ? j < display_limit * (i + 1) : j < cwin->nr_candidates;
592
j++, node = g_slist_next(node))
596
gchar *str = node->data;
597
gchar **column = g_strsplit(str, "\a", 3);
598
gtk_list_store_append(store, &ti);
599
gtk_list_store_set(store, &ti,
600
COLUMN_HEADING, column[0],
601
COLUMN_CANDIDATE, column[1],
602
COLUMN_ANNOTATION, column[2],
607
/* No need to set any data for empty row. */
611
g_slist_free(candidates);
613
uim_cand_win_gtk_set_page(cwin, 0);
616
uim_cand_win_gtk_show(cwin);
617
cwin->is_active = TRUE;
621
candwin_update(gchar **str)
623
int index, need_hilite;
624
sscanf(str[1], "%d", &index);
625
sscanf(str[2], "%d", &need_hilite);
626
cwin->need_hilite = (need_hilite == 1) ? TRUE : FALSE;
628
uim_cand_win_gtk_set_index(cwin, index);
632
candwin_move(char **str)
634
sscanf(str[1], "%d", &cwin->pos_x);
635
sscanf(str[2], "%d", &cwin->pos_y);
637
uim_cand_win_gtk_layout();
644
uim_cand_win_gtk_show(cwin);
648
candwin_deactivate(void)
650
gtk_widget_hide(GTK_WIDGET(cwin));
651
cwin->is_active = FALSE;
655
caret_state_show(gchar **str)
659
sscanf(str[1], "%d", &timeout);
660
caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, str[2]);
662
caret_state_indicator_set_timeout(cwin->caret_state_indicator, timeout * 1000);
663
gtk_widget_show_all(GTK_WIDGET(cwin->caret_state_indicator));
669
caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, NULL);
675
gtk_widget_hide(cwin->caret_state_indicator);
679
candwin_set_nr_candidates(gchar **str)
681
guint nr, display_limit;
682
gint i, nr_stores = 1;
684
sscanf(str[1], "%ud", &nr);
685
sscanf(str[2], "%ud", &display_limit);
687
cwin->candidate_index = -1;
688
cwin->nr_candidates = nr;
689
cwin->display_limit = display_limit;
690
cwin->need_hilite = FALSE;
691
cwin->is_active = TRUE;
693
if (cwin->stores == NULL)
694
cwin->stores = g_ptr_array_new();
696
/* remove old data */
697
for (i = cwin->stores->len - 1; i >= 0; i--) {
698
GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
700
gtk_list_store_clear(store);
701
g_object_unref(G_OBJECT(store));
705
/* calculate number of GtkListStores to create */
707
nr_stores = nr / display_limit;
708
if (nr > display_limit * nr_stores)
712
/* setup dummy array */
713
for (i = 0; i < nr_stores; i++)
714
g_ptr_array_add(cwin->stores, NULL);
718
candwin_set_page_candidates(gchar **str)
720
gsize rbytes, wbytes;
724
const gchar *charset;
725
GSList *candidates = NULL;
728
if (!strncmp(str[1], "charset=", 8))
729
charset = str[1] + 8;
733
if (!strncmp(str[2], "page=", 5)) {
734
page = atoi(str[2] + 5);
737
/* shouldn't happen */
742
for ( ; str[i]; i++) {
743
if (strcmp(str[i], "") == 0) {
746
utf8_str = g_convert(str[i],
750
&rbytes, &wbytes, NULL);
752
candidates = g_slist_prepend(candidates, utf8_str);
755
candidates = g_slist_reverse(candidates);
757
uim_cand_win_gtk_set_page_candidates(cwin, page, candidates);
758
g_slist_free(candidates);
762
candwin_show_page(gchar **str)
766
sscanf(str[1], "%d", &page);
768
uim_cand_win_gtk_set_page(cwin, page);
769
uim_cand_win_gtk_show(cwin);
772
static void str_parse(gchar *str)
777
tmp = g_strsplit(str, "\f", 0);
781
if (strcmp("activate", command) == 0) {
782
candwin_activate(tmp);
783
} else if (strcmp("select", command) == 0) {
785
} else if (strcmp("show", command) == 0) {
787
} else if (strcmp("hide", command) == 0) {
788
gtk_widget_hide(GTK_WIDGET(cwin));
789
} else if (strcmp("move", command) == 0) {
791
} else if (strcmp("deactivate", command) == 0) {
792
candwin_deactivate();
793
} else if (strcmp("show_caret_state", command) == 0) {
794
caret_state_show(tmp);
795
} else if (strcmp("update_caret_state", command) == 0) {
796
caret_state_update();
797
} else if (strcmp("hide_caret_state", command) == 0) {
799
} else if (strcmp("set_nr_candidates", command) == 0) {
800
candwin_set_nr_candidates(tmp);
801
} else if (strcmp("set_page_candidates", command) == 0) {
802
candwin_set_page_candidates(tmp);
803
} else if (strcmp("show_page", command) == 0) {
804
candwin_show_page(tmp);
810
#define CANDIDATE_BUFFER_SIZE 4096
812
read_cb(GIOChannel *channel, GIOCondition c, gpointer p)
814
char buf[CANDIDATE_BUFFER_SIZE];
815
char *read_buf = strdup("");
819
int fd = g_io_channel_unix_get_fd(channel);
821
while (uim_helper_fd_readable(fd) > 0) {
822
n = read(fd, buf, CANDIDATE_BUFFER_SIZE - 1);
830
read_buf = realloc(read_buf, strlen(read_buf) + n + 1);
831
strcat(read_buf, buf);
834
tmp = g_strsplit(read_buf, "\f\f", 0);
846
main(int argc, char *argv[])
850
/* disable uim context in annotation window */
851
setenv("GTK_IM_MODULE", "gtk-im-context-simple", 1);
853
gtk_init(&argc, &argv);
857
init_candidate_win();
859
channel = g_io_channel_unix_new(0);
860
read_tag = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR,
862
g_io_channel_unref(channel);
870
/* copied from uim-cand-win-gtk.c */
872
uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin)
874
g_return_val_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin), -1);
876
return cwin->candidate_index;
879
/* copied from uim-cand-win-gtk.c */
881
uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index)
885
g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
887
if (index >= (gint) cwin->nr_candidates)
888
cwin->candidate_index = 0;
890
cwin->candidate_index = index;
892
if (cwin->candidate_index >= 0 && cwin->display_limit)
893
new_page = cwin->candidate_index / cwin->display_limit;
895
new_page = cwin->page_index;
897
if (cwin->page_index != new_page)
898
uim_cand_win_gtk_set_page(cwin, new_page);
904
clear_button(struct index_button *idxbutton, const gchar *tbl_cell2label,
907
GtkButton *button = NULL;
908
gboolean is_blank_cell = (tbl_cell2label[cell_index] == '\0') ? TRUE : FALSE;
910
idxbutton->cand_index_in_page = -1;
911
button = idxbutton->button;
912
gtk_button_set_relief(button,
913
is_blank_cell ? GTK_RELIEF_NONE : GTK_RELIEF_HALF);
914
gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
915
gtk_button_set_label(button, " ");
919
clear_all_buttons(GPtrArray *buttons, const gchar *tbl_cell2label)
923
for (i = 0; i < TABLE_NR_CELLS; i++) {
924
struct index_button *idxbutton;
926
idxbutton = g_ptr_array_index(buttons, i);
927
/* if skip clearing, button becomes too thin */
928
/* if (idxbutton && idxbutton->cand_index_in_page != -1) */
929
clear_button(idxbutton, tbl_cell2label, i);
934
update_table_button(GtkTreeModel *model, GPtrArray *buttons,
935
const gchar *tbl_cell2label, gint display_limit)
941
clear_all_buttons(buttons, tbl_cell2label);
942
has_next = gtk_tree_model_get_iter_first(model, &ti);
944
gchar *heading = NULL;
945
gchar *cand_str = NULL;
946
GtkButton *button = NULL;
948
gtk_tree_model_get(model, &ti, COLUMN_HEADING, &heading,
949
COLUMN_CANDIDATE, &cand_str, TERMINATOR);
950
if (cand_str != NULL) {
951
gboolean has_label = FALSE;
952
gchar ch = (heading == NULL) ? '\0' : heading[0];
953
button = assign_cellbutton(buttons, tbl_cell2label, ch, cand_index,
954
display_limit, &has_label);
955
if (button != NULL) {
956
gtk_button_set_relief(button,
957
has_label ? GTK_RELIEF_NORMAL : GTK_RELIEF_HALF);
958
gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
959
gtk_button_set_label(button, cand_str);
966
has_next = gtk_tree_model_iter_next(model, &ti);
970
/* copied from uim-cand-win-gtk.c */
972
uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page)
977
g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
978
g_return_if_fail(cwin->stores);
980
len = cwin->stores->len;
981
g_return_if_fail(len);
985
else if (page >= (gint) len)
990
update_table_button(GTK_TREE_MODEL(cwin->stores->pdata[new_page]),
991
cwin->buttons, cwin->tbl_cell2label,
992
cwin->display_limit);
994
cwin->page_index = new_page;
996
if (cwin->display_limit) {
997
if (cwin->candidate_index >= 0)
999
= (new_page * cwin->display_limit) + (cwin->candidate_index % cwin->display_limit);
1003
new_index = cwin->candidate_index;
1006
if (new_index >= (gint) cwin->nr_candidates)
1007
new_index = cwin->nr_candidates - 1;
1009
/* shrink the window */
1010
gtk_window_resize(GTK_WINDOW(cwin), CANDWIN_DEFAULT_WIDTH, 1);
1012
uim_cand_win_gtk_set_index(cwin, new_index);
1015
/* copied from uim-cand-win-gtk.c and adjusted */
1017
uim_cand_win_gtk_set_page_candidates(UIMCandidateWindow *cwin,
1021
GtkListStore *store;
1025
g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
1027
if (candidates == NULL)
1030
len = g_slist_length(candidates);
1032
/* create GtkListStores, and set candidates */
1033
store = gtk_list_store_new(LISTSTORE_NR_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1035
cwin->stores->pdata[page] = store;
1036
/* set candidates */
1037
for (j = 0, node = g_slist_nth(candidates, j);
1039
j++, node = g_slist_next(node))
1044
gchar *str = node->data;
1045
gchar **column = g_strsplit(str, "\a", 3);
1046
gtk_list_store_append(store, &ti);
1047
gtk_list_store_set(store, &ti,
1048
COLUMN_HEADING, column[0],
1049
COLUMN_CANDIDATE, column[1],
1050
COLUMN_ANNOTATION, column[2],
1060
uim_cand_win_gtk_layout()
1063
int screen_width, screen_height;
1065
screen_width = gdk_screen_get_width(gdk_screen_get_default());
1066
screen_height = gdk_screen_get_height(gdk_screen_get_default());
1068
if (screen_width < cwin->pos_x + cwin->width)
1069
x = cwin->pos_x - cwin->width;
1073
if (screen_height < cwin->pos_y + cwin->height)
1074
y = cwin->pos_y - cwin->height - 20; /* FIXME: Preedit height is needed to
1075
be sent by uim-xim */
1079
gtk_window_move(GTK_WINDOW(cwin), x, y);
1083
is_empty_block(GPtrArray *buttons, gint rowstart, gint rowend, gint colstart, gint colend)
1086
for (row = rowstart; row < rowend; row++) {
1087
for (col = colstart; col < colend; col++) {
1088
struct index_button *idxbutton;
1089
idxbutton = g_ptr_array_index(buttons, CELLINDEX(row, col));
1090
if (idxbutton && idxbutton->cand_index_in_page != -1) {
1099
show_table(GtkTable *view, GPtrArray *buttons)
1101
/* hide empty blocks.
1102
* pattern0(full table)
1104
* blockLRS blockAS (for shift key)
1105
* pattern1(minimal blocks)
1107
* pattern2(without shift blocks)
1109
* pattern3(without symbol blocks)
1114
gint hide_row, hide_col;
1115
gint row_spacing, col_spacing;
1116
gboolean blockA, blockAS, blockLRS;
1117
blockA = !is_empty_block(buttons, BLOCK_A_ROW_START, BLOCK_A_ROW_END,
1118
BLOCK_A_COLUMN_START, BLOCK_A_COLUMN_END);
1119
blockAS = !is_empty_block(buttons, BLOCK_AS_ROW_START, BLOCK_AS_ROW_END,
1120
BLOCK_AS_COLUMN_START, BLOCK_AS_COLUMN_END);
1121
blockLRS = !is_empty_block(buttons, BLOCK_LRS_ROW_START, BLOCK_LRS_ROW_END,
1122
BLOCK_LRS_COLUMN_START, BLOCK_LRS_COLUMN_END);
1124
hide_row = TABLE_NR_ROWS;
1125
hide_col = TABLE_NR_COLUMNS;
1126
if (blockAS) { /* pattern0(full table) */
1127
hide_row = TABLE_NR_ROWS;
1128
hide_col = TABLE_NR_COLUMNS;
1129
} else if (blockLRS) {
1130
if (blockA) { /* pattern0(full table) */
1131
hide_row = TABLE_NR_ROWS;
1132
hide_col = TABLE_NR_COLUMNS;
1133
} else { /* pattern3(without symbol blocks) */
1134
hide_row = TABLE_NR_ROWS;
1135
hide_col = BLOCK_A_COLUMN_START;
1137
} else if (blockA) { /* pattern2(without shift blocks) */
1138
hide_row = BLOCK_A_ROW_END;
1139
hide_col = TABLE_NR_COLUMNS;
1140
} else { /* pattern1(minimal blocks) */
1141
hide_row = BLOCK_A_ROW_END;
1142
hide_col = BLOCK_A_COLUMN_START;
1145
for (row = 0; row < TABLE_NR_ROWS; row++) {
1146
for (col = 0; col < TABLE_NR_COLUMNS; col++) {
1147
GtkButton *button = NULL;
1148
button = get_button(buttons, CELLINDEX(row, col));
1149
if (row >= hide_row || col >= hide_col) {
1150
gtk_widget_hide(GTK_WIDGET(button));
1152
gtk_widget_show(GTK_WIDGET(button));
1156
if (hide_col <= BLOCK_A_COLUMN_START) {
1159
col_spacing = BLOCK_SPACING;
1161
if (hide_row <= BLOCK_LRS_ROW_START) {
1164
row_spacing = BLOCK_SPACING;
1166
gtk_table_set_col_spacing(view, SPACING_RIGHT_BLOCK_COLUMN, col_spacing);
1167
gtk_table_set_row_spacing(view, SPACING_UP_BLOCK_ROW, row_spacing);
1169
gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW,
1170
HOMEPOSITION_SPACING);
1172
gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW, 0);
1174
/* gtk_table_resize(view, hide_row, hide_col); */
1175
gtk_widget_show(GTK_WIDGET(view));
1180
uim_cand_win_gtk_show(UIMCandidateWindow *cwin)
1182
show_table(GTK_TABLE(cwin->view), cwin->buttons);
1183
gtk_widget_show(GTK_WIDGET(cwin->viewport));
1184
gtk_widget_show(GTK_WIDGET(cwin->scrolled_window));
1185
gtk_widget_show(GTK_WIDGET(cwin->num_label));
1186
gtk_widget_show(GTK_WIDGET(cwin->vbox));
1187
gtk_widget_show(GTK_WIDGET(cwin->frame));
1188
gtk_widget_show(GTK_WIDGET(cwin));
1192
configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
1194
cwin->width = event->width;
1195
cwin->height = event->height;
1197
uim_cand_win_gtk_layout();
1203
get_button(GPtrArray *buttons, gint idx)
1205
GtkButton *button = NULL;
1206
struct index_button *idxbutton;
1208
idxbutton = g_ptr_array_index(buttons, idx);
1210
button = idxbutton->button;