~ubuntu-branches/ubuntu/precise/uim/precise

« back to all changes in this revision

Viewing changes to helper/candwin-tbl-gtk.c

  • Committer: Package Import Robot
  • Author(s): Ilya Barygin
  • Date: 2011-12-18 16:35:38 UTC
  • mfrom: (1.1.13) (15.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20111218163538-8ktir39z2mjpii8z
Tags: 1:1.7.1-3ubuntu1
* Merge from Debian testing (LP: #818199).
* Remaining changes:
  - debian/uim-qt.install: Fix plugin path for multiarch location.
* Dropped changes:
  - uim-applet-gnome removal (GNOME 3 applet is available)
  - 19_as-needed_compile_fix.dpatch (accepted into Debian package)
* translations.patch: add several files to POTFILE.in to prevent
  intltool-update failure.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
  Copyright (c) 2003-2011 uim Project http://code.google.com/p/uim/
 
4
 
 
5
  All rights reserved.
 
6
 
 
7
  Redistribution and use in source and binary forms, with or without
 
8
  modification, are permitted provided that the following conditions
 
9
  are met:
 
10
 
 
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.
 
19
 
 
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
 
30
  SUCH DAMAGE.
 
31
 
 
32
*/
 
33
 
 
34
#ifdef HAVE_CONFIG_H
 
35
#  include <config.h>
 
36
#endif
 
37
#include <uim/uim.h>
 
38
#include <uim/uim-helper.h>
 
39
#include <uim/uim-scm.h>
 
40
#include <gtk/gtk.h>
 
41
#include <gdk/gdkx.h>
 
42
#include <glib.h>
 
43
#include <stdlib.h>
 
44
#include <stdio.h>
 
45
#include <string.h>
 
46
#include <sys/types.h>
 
47
#include <unistd.h>
 
48
 
 
49
#include "../gtk/caret-state-indicator.h"
 
50
 
 
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))
 
56
 
 
57
typedef struct _UIMCandidateWindow      UIMCandidateWindow;
 
58
typedef struct _UIMCandidateWindowClass UIMCandidateWindowClass;
 
59
 
 
60
struct _UIMCandidateWindow {
 
61
  GtkWindow parent;
 
62
 
 
63
  GtkWidget *view;
 
64
  GtkWidget *num_label;
 
65
  GtkWidget *scrolled_window;
 
66
  GtkWidget *viewport;
 
67
  GtkWidget *vbox;
 
68
  GtkWidget *frame;
 
69
 
 
70
  GPtrArray *stores;
 
71
  GPtrArray *buttons;
 
72
  gchar *tbl_cell2label;
 
73
 
 
74
  guint nr_candidates;
 
75
  guint display_limit;
 
76
  gint candidate_index;
 
77
  gint page_index;
 
78
 
 
79
  gint pos_x;
 
80
  gint pos_y;
 
81
  gint width;
 
82
  gint height;
 
83
 
 
84
  GtkWidget *caret_state_indicator;
 
85
 
 
86
  gboolean is_active;
 
87
  gboolean need_hilite;
 
88
};
 
89
 
 
90
struct _UIMCandidateWindowClass {
 
91
  GtkWindowClass parent_class;
 
92
 
 
93
  /* signals */
 
94
  void (*index_changed) (UIMCandidateWindowClass *candwin);
 
95
};
 
96
 
 
97
static UIMCandidateWindow *cwin; /* use single candwin */
 
98
 
 
99
GType candidate_window_get_type(void);
 
100
UIMCandidateWindow *candidate_window_new(void);
 
101
 
 
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);
 
107
 
 
108
static void uim_cand_win_gtk_layout(void);
 
109
static void uim_cand_win_gtk_show(UIMCandidateWindow *cwin);
 
110
 
 
111
#define CANDWIN_DEFAULT_WIDTH   80
 
112
 
 
113
enum {
 
114
  INDEX_CHANGED_SIGNAL,
 
115
  NR_SIGNALS
 
116
};
 
117
 
 
118
enum {
 
119
  TERMINATOR = -1,
 
120
  COLUMN_HEADING,
 
121
  COLUMN_CANDIDATE,
 
122
  COLUMN_ANNOTATION,
 
123
  LISTSTORE_NR_COLUMNS
 
124
};
 
125
 
 
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))
 
130
/* 106 keyboard */
 
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',
 
140
};
 
141
/* table consists of four blocks
 
142
 *   blockLR  blockA
 
143
 *   blockLRS blockAS
 
144
 */
 
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))
 
159
 
 
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
 
169
 
 
170
struct index_button {
 
171
  gint cand_index_in_page;
 
172
  GtkButton *button;
 
173
};
 
174
 
 
175
static void candidate_window_init(UIMCandidateWindow *cwin);
 
176
static void candidate_window_class_init(UIMCandidateWindowClass *klass);
 
177
 
 
178
static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
 
179
 
 
180
static GType candidate_window_type = 0;
 
181
static GTypeInfo const object_info = {
 
182
  sizeof (UIMCandidateWindowClass),
 
183
  NULL,
 
184
  NULL,
 
185
  (GClassInitFunc) candidate_window_class_init,
 
186
  NULL,
 
187
  NULL,
 
188
  sizeof(UIMCandidateWindow),
 
189
  0,
 
190
  (GInstanceInitFunc) candidate_window_init,
 
191
};
 
192
 
 
193
static gint cand_win_gtk_signals[NR_SIGNALS] = {0};
 
194
 
 
195
static unsigned int read_tag;
 
196
 
 
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);
 
211
 
 
212
static void index_changed_cb(UIMCandidateWindow *cwin)
 
213
{
 
214
  fprintf(stdout, "index\n");
 
215
  fprintf(stdout, "%d\n\n", uim_cand_win_gtk_get_index(cwin));
 
216
  fflush(stdout);
 
217
}
 
218
 
 
219
GType
 
220
candidate_window_get_type(void)
 
221
{
 
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;
 
226
}
 
227
 
 
228
static void candidate_window_class_init(UIMCandidateWindowClass *klass)
 
229
{
 
230
  cand_win_gtk_signals[INDEX_CHANGED_SIGNAL]
 
231
    = g_signal_new("index-changed",
 
232
                   G_TYPE_FROM_CLASS(klass),
 
233
                   G_SIGNAL_RUN_FIRST,
 
234
                   G_STRUCT_OFFSET(UIMCandidateWindowClass, index_changed),
 
235
                   NULL, NULL,
 
236
                   g_cclosure_marshal_VOID__VOID,
 
237
                   G_TYPE_NONE, 0);
 
238
}
 
239
 
 
240
UIMCandidateWindow *
 
241
candidate_window_new(void)
 
242
{
 
243
  GObject *obj = g_object_new(UIM_TYPE_CANDIDATE_WINDOW, "type",
 
244
                  GTK_WINDOW_POPUP, NULL);
 
245
  return UIM_CANDIDATE_WINDOW(obj);
 
246
}
 
247
 
 
248
/* copied from uim-cand-win-gtk.c */
 
249
static void
 
250
update_label(UIMCandidateWindow *cwin)
 
251
{
 
252
  char label_str[20];
 
253
 
 
254
  if (cwin->candidate_index >= 0)
 
255
    g_snprintf(label_str, sizeof(label_str), "%d / %d",
 
256
               cwin->candidate_index + 1 , cwin->nr_candidates);
 
257
  else
 
258
    g_snprintf(label_str, sizeof(label_str), "- / %d",
 
259
               cwin->nr_candidates);
 
260
 
 
261
  gtk_label_set_text(GTK_LABEL(cwin->num_label), label_str);
 
262
}
 
263
 
 
264
static void
 
265
button_clicked(GtkButton *button, gpointer data)
 
266
{
 
267
  UIMCandidateWindow *cwin = UIM_CANDIDATE_WINDOW(data);
 
268
  gint i;
 
269
  gint idx = -1;
 
270
 
 
271
  for (i = 0; i < TABLE_NR_CELLS; i++) {
 
272
    GtkButton *p;
 
273
    struct index_button *idxbutton;
 
274
    idxbutton = g_ptr_array_index(cwin->buttons, i);
 
275
    if (!idxbutton) {
 
276
      continue;
 
277
    }
 
278
    p = idxbutton->button;
 
279
    if (p == button) {
 
280
      idx = idxbutton->cand_index_in_page;
 
281
      break;
 
282
    }
 
283
  }
 
284
  if (idx >= 0 && cwin->display_limit) {
 
285
    if (idx >= (gint)cwin->display_limit) {
 
286
      idx %= cwin->display_limit;
 
287
    }
 
288
    cwin->candidate_index = cwin->page_index * cwin->display_limit + idx;
 
289
  } else {
 
290
    cwin->candidate_index = idx;
 
291
  }
 
292
  if (cwin->candidate_index >= (gint)cwin->nr_candidates) {
 
293
    cwin->candidate_index = -1;
 
294
  }
 
295
  g_signal_emit_by_name(G_OBJECT(cwin), "index-changed");
 
296
}
 
297
 
 
298
static void
 
299
cb_table_view_destroy(GtkWidget *widget, GPtrArray *stores)
 
300
{
 
301
  gint i;
 
302
 
 
303
  g_return_if_fail(GTK_IS_TABLE(widget));
 
304
 
 
305
  for (i = cwin->stores->len - 1; i >= 0; i--) {
 
306
    GtkListStore *store = g_ptr_array_remove_index(cwin->stores, i);
 
307
    if (store) {
 
308
      gtk_list_store_clear(store);
 
309
      g_object_unref(G_OBJECT(store));
 
310
    }
 
311
  }
 
312
  g_ptr_array_free(cwin->stores, TRUE);
 
313
 
 
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 */
 
318
    }
 
319
  }
 
320
  g_ptr_array_free(cwin->buttons, TRUE);
 
321
 
 
322
  if (cwin->tbl_cell2label != default_tbl_cell2label) {
 
323
    g_free(cwin->tbl_cell2label);
 
324
  }
 
325
}
 
326
 
 
327
static void
 
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);
 
334
}
 
335
 
 
336
static void
 
337
candidate_window_init(UIMCandidateWindow *cwin)
 
338
{
 
339
  GdkRectangle cursor_location;
 
340
  gint row, col;
 
341
 
 
342
  cwin->vbox = gtk_vbox_new(FALSE, 0);
 
343
  cwin->frame = gtk_frame_new(NULL);
 
344
 
 
345
  cwin->stores = g_ptr_array_new();
 
346
  cwin->buttons = g_ptr_array_new();
 
347
  cwin->tbl_cell2label = init_tbl_cell2label();
 
348
 
 
349
  gtk_window_set_default_size(GTK_WINDOW(cwin),
 
350
                  CANDWIN_DEFAULT_WIDTH, -1);
 
351
 
 
352
 
 
353
  cwin->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 
354
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cwin->scrolled_window),
 
355
                                 GTK_POLICY_NEVER,
 
356
                                 GTK_POLICY_NEVER);
 
357
  gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->scrolled_window, TRUE, TRUE, 0);
 
358
 
 
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++) {
 
368
      GtkWidget *button;
 
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));
 
375
      if (idxbutton) {
 
376
        idxbutton->button = GTK_BUTTON(button);
 
377
        clear_button(idxbutton, cwin->tbl_cell2label, CELLINDEX(row, col));
 
378
      }
 
379
      g_ptr_array_add(cwin->buttons, idxbutton);
 
380
    }
 
381
  }
 
382
  gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_LEFT_BLOCK_COLUMN,
 
383
      BLOCK_SPACING);
 
384
  gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_RIGHT_BLOCK_COLUMN,
 
385
      BLOCK_SPACING);
 
386
  gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_UP_BLOCK_ROW,
 
387
      BLOCK_SPACING);
 
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);
 
396
 
 
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);
 
400
 
 
401
  cwin->num_label = gtk_label_new("");
 
402
 
 
403
  gtk_box_pack_start(GTK_BOX(cwin->vbox), cwin->num_label, FALSE, FALSE, 0);
 
404
 
 
405
  cwin->pos_x = 0;
 
406
  cwin->pos_y = 0;
 
407
  cwin->is_active = FALSE;
 
408
  cwin->need_hilite = FALSE;
 
409
  cwin->caret_state_indicator = caret_state_indicator_new();
 
410
 
 
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);
 
415
}
 
416
 
 
417
static gchar *
 
418
init_tbl_cell2label(void)
 
419
{
 
420
  gchar *table;
 
421
  uim_lisp list;
 
422
  size_t len = 0;
 
423
  uim_lisp *ary0, *ary;
 
424
  guint i;
 
425
 
 
426
  list = uim_scm_symbol_value("uim-candwin-prog-layout");
 
427
  if (list == NULL || !uim_scm_listp(list)) {
 
428
    return default_tbl_cell2label;
 
429
  }
 
430
  ary0 = ary = (uim_lisp *)uim_scm_list2array(list, &len, NULL);
 
431
  if (ary == NULL || len <= 0) {
 
432
    if (ary0) {
 
433
      free(ary0);
 
434
    }
 
435
    return default_tbl_cell2label;
 
436
  }
 
437
  table = (gchar *)g_malloc0(TABLE_NR_CELLS);
 
438
  if (table == NULL) {
 
439
    free(ary0);
 
440
    return default_tbl_cell2label;
 
441
  }
 
442
  for (i = 0; i < len && i < TABLE_NR_CELLS; i++, ary++) {
 
443
    char *str;
 
444
#if 0 /* 0 for investigation (Because uim-candwin-tbl-gtk is standalone,
 
445
         bad effects to other programs are smaller than gtk-immodule)
 
446
       */
 
447
    if (!uim_scm_strp(*ary)) {
 
448
      /* XXX: output notify message? */
 
449
      g_free(table);
 
450
      free(ary0);
 
451
      return default_tbl_cell2label;
 
452
    }
 
453
#endif
 
454
    str = uim_scm_c_str(*ary);
 
455
    if (str) {
 
456
      /* XXX: only use first char */
 
457
      table[i] = *str;
 
458
      free(str);
 
459
    }
 
460
  }
 
461
  free(ary0);
 
462
  return table;
 
463
}
 
464
 
 
465
static GtkButton*
 
466
assign_cellbutton(GPtrArray *buttons, const gchar *tbl_cell2label,
 
467
    const gchar labelchar, gint cand_index, gint display_limit,
 
468
    gboolean *has_label)
 
469
{
 
470
  gint i;
 
471
  struct index_button *idxbutton;
 
472
 
 
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);
 
478
        if (!idxbutton) {
 
479
          continue;
 
480
        }
 
481
        if (idxbutton->cand_index_in_page != -1) {
 
482
          break; /* already used */
 
483
        }
 
484
        idxbutton->cand_index_in_page = cand_index;
 
485
        *has_label = TRUE;
 
486
        return idxbutton->button;
 
487
      }
 
488
    }
 
489
  }
 
490
  /* labelchar not found || already used */
 
491
 
 
492
  /* find free cell */
 
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;
 
498
      continue;
 
499
    }
 
500
    idxbutton = g_ptr_array_index(buttons, i);
 
501
    if (!idxbutton) {
 
502
      continue;
 
503
    }
 
504
    if (idxbutton->cand_index_in_page == -1) {
 
505
      idxbutton->cand_index_in_page = cand_index;
 
506
      *has_label = FALSE;
 
507
      return idxbutton->button;
 
508
    }
 
509
  }
 
510
 
 
511
  /* failed to assign button */
 
512
  *has_label = FALSE;
 
513
  return NULL;
 
514
}
 
515
 
 
516
static void
 
517
candwin_activate(gchar **str)
 
518
{
 
519
  gsize rbytes, wbytes;
 
520
  gint i, nr_stores = 1;
 
521
  guint j = 1;
 
522
  gchar *utf8_str;
 
523
  const gchar *charset;
 
524
  guint display_limit;
 
525
  GSList *candidates = NULL;
 
526
 
 
527
  if (cwin->stores == NULL)
 
528
    cwin->stores = g_ptr_array_new();
 
529
 
 
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);
 
533
    if (store) {
 
534
      gtk_list_store_clear(store);
 
535
      g_object_unref(G_OBJECT(store));
 
536
    }
 
537
  }
 
538
 
 
539
  if (!strncmp(str[1], "charset=", 8))
 
540
    charset = str[1] + 8;
 
541
  else
 
542
    charset = "UTF-8";
 
543
 
 
544
  if (!strncmp(str[2], "display_limit=", 14)) {
 
545
    display_limit = atoi(str[2] + 14);
 
546
    i = 3;
 
547
  } else {
 
548
    display_limit = 0;
 
549
    i = 2;
 
550
  }
 
551
 
 
552
  for ( ; str[i]; i++) {
 
553
    if (strcmp(str[i], "") == 0) {
 
554
      break;
 
555
    }
 
556
    utf8_str = g_convert(str[i],
 
557
                         -1,
 
558
                         "UTF-8",
 
559
                         charset,
 
560
                         &rbytes, &wbytes, NULL);
 
561
 
 
562
    candidates = g_slist_prepend(candidates, utf8_str);
 
563
    j++;
 
564
  }
 
565
  candidates = g_slist_reverse(candidates);
 
566
 
 
567
  cwin->candidate_index = -1;
 
568
  cwin->nr_candidates = j - 1;
 
569
  cwin->display_limit = display_limit;
 
570
  cwin->need_hilite = FALSE;
 
571
 
 
572
  if (candidates == NULL)
 
573
    return;
 
574
 
 
575
  /* calculate number of GtkListStores to create */
 
576
  if (display_limit) {
 
577
    nr_stores = cwin->nr_candidates / display_limit;
 
578
    if (cwin->nr_candidates > display_limit * nr_stores)
 
579
      nr_stores++;
 
580
  }
 
581
 
 
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);
 
585
    GSList *node;
 
586
 
 
587
    g_ptr_array_add(cwin->stores, store);
 
588
 
 
589
    /* set candidates */
 
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))
 
593
    {
 
594
      GtkTreeIter ti;
 
595
      if (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],
 
603
                           TERMINATOR);
 
604
        g_strfreev(column);
 
605
        g_free(str);
 
606
      } else {
 
607
        /* No need to set any data for empty row. */
 
608
      }
 
609
    }
 
610
  }
 
611
  g_slist_free(candidates);
 
612
 
 
613
  uim_cand_win_gtk_set_page(cwin, 0);
 
614
  update_label(cwin);
 
615
 
 
616
  uim_cand_win_gtk_show(cwin);
 
617
  cwin->is_active = TRUE;
 
618
}
 
619
 
 
620
static void
 
621
candwin_update(gchar **str)
 
622
{
 
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;
 
627
 
 
628
  uim_cand_win_gtk_set_index(cwin, index);
 
629
}
 
630
 
 
631
static void
 
632
candwin_move(char **str)
 
633
{
 
634
  sscanf(str[1], "%d", &cwin->pos_x);
 
635
  sscanf(str[2], "%d", &cwin->pos_y);
 
636
 
 
637
  uim_cand_win_gtk_layout();
 
638
}
 
639
 
 
640
static void
 
641
candwin_show(void)
 
642
{
 
643
  if (cwin->is_active)
 
644
    uim_cand_win_gtk_show(cwin);
 
645
}
 
646
 
 
647
static void
 
648
candwin_deactivate(void)
 
649
{
 
650
  gtk_widget_hide(GTK_WIDGET(cwin));
 
651
  cwin->is_active = FALSE;
 
652
}
 
653
 
 
654
static void
 
655
caret_state_show(gchar **str)
 
656
{
 
657
  int timeout;
 
658
 
 
659
  sscanf(str[1], "%d", &timeout);
 
660
  caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, str[2]);
 
661
  if (timeout != 0)
 
662
    caret_state_indicator_set_timeout(cwin->caret_state_indicator, timeout * 1000);
 
663
  gtk_widget_show_all(GTK_WIDGET(cwin->caret_state_indicator));
 
664
}
 
665
 
 
666
static void
 
667
caret_state_update()
 
668
{
 
669
  caret_state_indicator_update(cwin->caret_state_indicator, cwin->pos_x, cwin->pos_y, NULL);
 
670
}
 
671
 
 
672
static void
 
673
caret_state_hide()
 
674
{
 
675
  gtk_widget_hide(cwin->caret_state_indicator);
 
676
}
 
677
 
 
678
static void
 
679
candwin_set_nr_candidates(gchar **str)
 
680
{
 
681
  guint nr, display_limit;
 
682
  gint i, nr_stores = 1;
 
683
 
 
684
  sscanf(str[1], "%ud", &nr);
 
685
  sscanf(str[2], "%ud", &display_limit);
 
686
 
 
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;
 
692
 
 
693
  if (cwin->stores == NULL)
 
694
    cwin->stores = g_ptr_array_new();
 
695
 
 
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);
 
699
    if (store) {
 
700
      gtk_list_store_clear(store);
 
701
      g_object_unref(G_OBJECT(store));
 
702
    }
 
703
  }
 
704
 
 
705
  /* calculate number of GtkListStores to create */
 
706
  if (display_limit) {
 
707
    nr_stores = nr / display_limit;
 
708
    if (nr > display_limit * nr_stores)
 
709
      nr_stores++;
 
710
  }
 
711
 
 
712
  /* setup dummy array */
 
713
  for (i = 0; i < nr_stores; i++)
 
714
    g_ptr_array_add(cwin->stores, NULL);
 
715
}
 
716
 
 
717
static void
 
718
candwin_set_page_candidates(gchar **str)
 
719
{
 
720
  gsize rbytes, wbytes;
 
721
  gint i;
 
722
  guint j = 1;
 
723
  gchar *utf8_str;
 
724
  const gchar *charset;
 
725
  GSList *candidates = NULL;
 
726
  int page;
 
727
 
 
728
  if (!strncmp(str[1], "charset=", 8))
 
729
    charset = str[1] + 8;
 
730
  else
 
731
    charset = "UTF-8";
 
732
 
 
733
  if (!strncmp(str[2], "page=", 5)) {
 
734
    page = atoi(str[2] + 5);
 
735
    i = 3;
 
736
  } else {
 
737
    /* shouldn't happen */
 
738
    page = 0;
 
739
    i = 2;
 
740
  }
 
741
 
 
742
  for ( ; str[i]; i++) {
 
743
    if (strcmp(str[i], "") == 0) {
 
744
      break;
 
745
    }
 
746
    utf8_str = g_convert(str[i],
 
747
                         -1,
 
748
                         "UTF-8",
 
749
                         charset,
 
750
                         &rbytes, &wbytes, NULL);
 
751
 
 
752
    candidates = g_slist_prepend(candidates, utf8_str);
 
753
    j++;
 
754
  }
 
755
  candidates = g_slist_reverse(candidates);
 
756
 
 
757
  uim_cand_win_gtk_set_page_candidates(cwin, page, candidates);
 
758
  g_slist_free(candidates);
 
759
}
 
760
 
 
761
static void
 
762
candwin_show_page(gchar **str)
 
763
{
 
764
  int page;
 
765
 
 
766
  sscanf(str[1], "%d", &page);
 
767
 
 
768
  uim_cand_win_gtk_set_page(cwin, page);
 
769
  uim_cand_win_gtk_show(cwin);
 
770
}
 
771
 
 
772
static void str_parse(gchar *str)
 
773
{
 
774
  gchar **tmp;
 
775
  gchar *command;
 
776
 
 
777
  tmp = g_strsplit(str, "\f", 0);
 
778
  command = tmp[0];
 
779
 
 
780
  if (command) {
 
781
    if (strcmp("activate", command) == 0) {
 
782
      candwin_activate(tmp);
 
783
    } else if (strcmp("select", command) == 0) {
 
784
      candwin_update(tmp);
 
785
    } else if (strcmp("show", command) == 0) {
 
786
      candwin_show();
 
787
    } else if (strcmp("hide", command) == 0) {
 
788
      gtk_widget_hide(GTK_WIDGET(cwin));
 
789
    } else if (strcmp("move", command) == 0) {
 
790
      candwin_move(tmp);
 
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) {
 
798
      caret_state_hide();
 
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);
 
805
    }
 
806
  }
 
807
  g_strfreev(tmp);
 
808
}
 
809
 
 
810
#define CANDIDATE_BUFFER_SIZE   4096
 
811
static gboolean
 
812
read_cb(GIOChannel *channel, GIOCondition c, gpointer p)
 
813
{
 
814
  char buf[CANDIDATE_BUFFER_SIZE];
 
815
  char *read_buf = strdup("");
 
816
  int i = 0;
 
817
  int n;
 
818
  gchar **tmp;
 
819
  int fd = g_io_channel_unix_get_fd(channel);
 
820
 
 
821
  while (uim_helper_fd_readable(fd) > 0) {
 
822
    n = read(fd, buf, CANDIDATE_BUFFER_SIZE - 1);
 
823
    if (n == 0) {
 
824
      close(fd);
 
825
      exit(EXIT_FAILURE);
 
826
    }
 
827
    if (n == -1)
 
828
      return TRUE;
 
829
    buf[n] = '\0';
 
830
    read_buf = realloc(read_buf, strlen(read_buf) + n + 1);
 
831
    strcat(read_buf, buf);
 
832
  }
 
833
 
 
834
  tmp = g_strsplit(read_buf, "\f\f", 0);
 
835
 
 
836
  while (tmp[i]) {
 
837
    str_parse(tmp[i]);
 
838
    i++;
 
839
  }
 
840
  g_strfreev(tmp);
 
841
  free(read_buf);
 
842
  return TRUE;
 
843
}
 
844
 
 
845
int
 
846
main(int argc, char *argv[])
 
847
{
 
848
  GIOChannel *channel;
 
849
 
 
850
  /* disable uim context in annotation window */
 
851
  setenv("GTK_IM_MODULE", "gtk-im-context-simple", 1);
 
852
 
 
853
  gtk_init(&argc, &argv);
 
854
  if (uim_init() < 0)
 
855
    return 0;
 
856
 
 
857
  init_candidate_win();
 
858
 
 
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,
 
861
                            read_cb, 0);
 
862
  g_io_channel_unref(channel);
 
863
 
 
864
  gtk_main();
 
865
  uim_quit();
 
866
 
 
867
  return 0;
 
868
}
 
869
 
 
870
/* copied from uim-cand-win-gtk.c */
 
871
static gint
 
872
uim_cand_win_gtk_get_index(UIMCandidateWindow *cwin)
 
873
{
 
874
  g_return_val_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin), -1);
 
875
 
 
876
  return cwin->candidate_index;
 
877
}
 
878
 
 
879
/* copied from uim-cand-win-gtk.c */
 
880
static void
 
881
uim_cand_win_gtk_set_index(UIMCandidateWindow *cwin, gint index)
 
882
{
 
883
  gint new_page;
 
884
 
 
885
  g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
 
886
 
 
887
  if (index >= (gint) cwin->nr_candidates)
 
888
    cwin->candidate_index = 0;
 
889
  else
 
890
    cwin->candidate_index = index;
 
891
 
 
892
  if (cwin->candidate_index >= 0 && cwin->display_limit)
 
893
    new_page = cwin->candidate_index / cwin->display_limit;
 
894
  else
 
895
    new_page = cwin->page_index;
 
896
 
 
897
  if (cwin->page_index != new_page)
 
898
    uim_cand_win_gtk_set_page(cwin, new_page);
 
899
 
 
900
  update_label(cwin);
 
901
}
 
902
 
 
903
static void
 
904
clear_button(struct index_button *idxbutton, const gchar *tbl_cell2label,
 
905
    gint cell_index)
 
906
{
 
907
  GtkButton *button = NULL;
 
908
  gboolean is_blank_cell = (tbl_cell2label[cell_index] == '\0') ? TRUE : FALSE;
 
909
 
 
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, "  ");
 
916
}
 
917
 
 
918
static void
 
919
clear_all_buttons(GPtrArray *buttons, const gchar *tbl_cell2label)
 
920
{
 
921
  gint i;
 
922
 
 
923
  for (i = 0; i < TABLE_NR_CELLS; i++) {
 
924
    struct index_button *idxbutton;
 
925
 
 
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);
 
930
  }
 
931
}
 
932
 
 
933
static void
 
934
update_table_button(GtkTreeModel *model, GPtrArray *buttons,
 
935
    const gchar *tbl_cell2label, gint display_limit)
 
936
{
 
937
  GtkTreeIter ti;
 
938
  gboolean has_next;
 
939
  gint cand_index = 0;
 
940
 
 
941
  clear_all_buttons(buttons, tbl_cell2label);
 
942
  has_next = gtk_tree_model_get_iter_first(model, &ti);
 
943
  while (has_next) {
 
944
    gchar *heading = NULL;
 
945
    gchar *cand_str = NULL;
 
946
    GtkButton *button = NULL;
 
947
 
 
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);
 
960
      }
 
961
    }
 
962
 
 
963
    g_free(cand_str);
 
964
    g_free(heading);
 
965
    cand_index++;
 
966
    has_next = gtk_tree_model_iter_next(model, &ti);
 
967
  }
 
968
}
 
969
 
 
970
/* copied from uim-cand-win-gtk.c */
 
971
static void
 
972
uim_cand_win_gtk_set_page(UIMCandidateWindow *cwin, gint page)
 
973
{
 
974
  guint len, new_page;
 
975
  gint new_index;
 
976
 
 
977
  g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
 
978
  g_return_if_fail(cwin->stores);
 
979
 
 
980
  len = cwin->stores->len;
 
981
  g_return_if_fail(len);
 
982
 
 
983
  if (page < 0)
 
984
    new_page = len - 1;
 
985
  else if (page >= (gint) len)
 
986
    new_page = 0;
 
987
  else
 
988
    new_page = page;
 
989
 
 
990
  update_table_button(GTK_TREE_MODEL(cwin->stores->pdata[new_page]),
 
991
                      cwin->buttons, cwin->tbl_cell2label,
 
992
                      cwin->display_limit);
 
993
 
 
994
  cwin->page_index = new_page;
 
995
 
 
996
  if (cwin->display_limit) {
 
997
    if (cwin->candidate_index >= 0)
 
998
      new_index
 
999
        = (new_page * cwin->display_limit) + (cwin->candidate_index % cwin->display_limit);
 
1000
    else
 
1001
      new_index = -1;
 
1002
  } else {
 
1003
    new_index = cwin->candidate_index;
 
1004
  }
 
1005
 
 
1006
  if (new_index >= (gint) cwin->nr_candidates)
 
1007
    new_index = cwin->nr_candidates - 1;
 
1008
 
 
1009
 /* shrink the window */
 
1010
  gtk_window_resize(GTK_WINDOW(cwin), CANDWIN_DEFAULT_WIDTH, 1);
 
1011
 
 
1012
  uim_cand_win_gtk_set_index(cwin, new_index);
 
1013
}
 
1014
 
 
1015
/* copied from uim-cand-win-gtk.c and adjusted */
 
1016
static void
 
1017
uim_cand_win_gtk_set_page_candidates(UIMCandidateWindow *cwin,
 
1018
                                     guint page,
 
1019
                                     GSList *candidates)
 
1020
{
 
1021
  GtkListStore *store;
 
1022
  GSList *node;
 
1023
  gint j, len;
 
1024
 
 
1025
  g_return_if_fail(UIM_IS_CANDIDATE_WINDOW(cwin));
 
1026
 
 
1027
  if (candidates == NULL)
 
1028
    return;
 
1029
 
 
1030
  len = g_slist_length(candidates);
 
1031
 
 
1032
  /* create GtkListStores, and set candidates */
 
1033
  store = gtk_list_store_new(LISTSTORE_NR_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
 
1034
 
 
1035
  cwin->stores->pdata[page] = store;
 
1036
  /* set candidates */
 
1037
  for (j = 0, node = g_slist_nth(candidates, j);
 
1038
       j < len;
 
1039
       j++, node = g_slist_next(node))
 
1040
  {
 
1041
    GtkTreeIter ti;
 
1042
 
 
1043
    if (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],
 
1051
                         TERMINATOR);
 
1052
 
 
1053
      g_strfreev(column);
 
1054
      g_free(str);
 
1055
    }
 
1056
  }
 
1057
}
 
1058
 
 
1059
static void
 
1060
uim_cand_win_gtk_layout()
 
1061
{
 
1062
  int x, y;
 
1063
  int screen_width, screen_height;
 
1064
 
 
1065
  screen_width = gdk_screen_get_width(gdk_screen_get_default());
 
1066
  screen_height = gdk_screen_get_height(gdk_screen_get_default());
 
1067
 
 
1068
  if (screen_width < cwin->pos_x + cwin->width)
 
1069
    x = cwin->pos_x - cwin->width;
 
1070
  else
 
1071
    x = cwin->pos_x;
 
1072
 
 
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 */
 
1076
  else
 
1077
    y = cwin->pos_y;
 
1078
 
 
1079
  gtk_window_move(GTK_WINDOW(cwin), x, y);
 
1080
}
 
1081
 
 
1082
static gboolean
 
1083
is_empty_block(GPtrArray *buttons, gint rowstart, gint rowend, gint colstart, gint colend)
 
1084
{
 
1085
  gint row, col;
 
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) {
 
1091
        return FALSE;
 
1092
      }
 
1093
    }
 
1094
  }
 
1095
  return TRUE;
 
1096
}
 
1097
 
 
1098
static void
 
1099
show_table(GtkTable *view, GPtrArray *buttons)
 
1100
{
 
1101
  /* hide empty blocks.
 
1102
   * pattern0(full table)
 
1103
   *   blockLR  blockA
 
1104
   *   blockLRS blockAS  (for shift key)
 
1105
   * pattern1(minimal blocks)
 
1106
   *   blockLR
 
1107
   * pattern2(without shift blocks)
 
1108
   *   blockLR  blockA
 
1109
   * pattern3(without symbol blocks)
 
1110
   *   blockLR
 
1111
   *   blockLRS
 
1112
   */
 
1113
  gint row, col;
 
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);
 
1123
 
 
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;
 
1136
    }
 
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;
 
1143
  }
 
1144
 
 
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));
 
1151
      } else {
 
1152
        gtk_widget_show(GTK_WIDGET(button));
 
1153
      }
 
1154
    }
 
1155
  }
 
1156
  if (hide_col <= BLOCK_A_COLUMN_START) {
 
1157
    col_spacing = 0;
 
1158
  } else {
 
1159
    col_spacing = BLOCK_SPACING;
 
1160
  }
 
1161
  if (hide_row <= BLOCK_LRS_ROW_START) {
 
1162
    row_spacing = 0;
 
1163
  } else {
 
1164
    row_spacing = BLOCK_SPACING;
 
1165
  }
 
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);
 
1168
  if (row_spacing) {
 
1169
    gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW,
 
1170
        HOMEPOSITION_SPACING);
 
1171
  } else {
 
1172
    gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW, 0);
 
1173
  }
 
1174
  /* gtk_table_resize(view, hide_row, hide_col); */
 
1175
  gtk_widget_show(GTK_WIDGET(view));
 
1176
}
 
1177
 
 
1178
 
 
1179
static void
 
1180
uim_cand_win_gtk_show(UIMCandidateWindow *cwin)
 
1181
{
 
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));
 
1189
}
 
1190
 
 
1191
static gboolean
 
1192
configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
 
1193
{
 
1194
  cwin->width = event->width;
 
1195
  cwin->height = event->height;
 
1196
 
 
1197
  uim_cand_win_gtk_layout();
 
1198
 
 
1199
  return FALSE;
 
1200
}
 
1201
 
 
1202
static GtkButton *
 
1203
get_button(GPtrArray *buttons, gint idx)
 
1204
{
 
1205
  GtkButton *button = NULL;
 
1206
  struct index_button *idxbutton;
 
1207
 
 
1208
  idxbutton = g_ptr_array_index(buttons, idx);
 
1209
  if (idxbutton) {
 
1210
    button = idxbutton->button;
 
1211
  }
 
1212
  return button;
 
1213
}