9
#include <gtk/gtkimcontext.h>
11
#include "scim-bridge-attribute.h"
12
#include "scim-bridge-client-imcontext-gtk.h"
13
#include "scim-bridge-client-kernel.h"
14
#include "scim-bridge-client-keyevent-utility-gtk.h"
15
#include "scim-bridge-exception.h"
16
#include "scim-bridge-imcontext-common.h"
17
#include "scim-bridge-output.h"
20
struct _ScimBridgeClientIMContextImpl
22
/* extends ScimBridgeIMContext */
23
/* Don't touch the first element */
24
ScimBridgeIMContextParent parent;
26
ScimBridgeClientIMContext *owner;
28
GdkWindow *client_window;
31
int preedit_cursor_position;
39
size_t preedit_string_length;
40
size_t preedit_string_capacity;
43
size_t commit_string_capacity;
45
ScimBridgeAttribute *preedit_attributes;
46
size_t preedit_attribute_count;
50
static GType scim_bridge_client_imcontext_type = 0;
51
static GObjectClass *imcontext_root_klass = NULL;
53
static gboolean initialized = FALSE;
55
/* Variables for scim */
56
static ScimBridgeClientIMContextImpl *scim_focused_imcontext = NULL;
58
/* Private variables for SCIM */
59
static GdkColor color_normal_background;
60
static GdkColor color_normal_text;
61
static GdkColor color_active_background;
62
static GdkColor color_active_text;
64
/* Helper functions */
65
static void gtk_im_slave_commit_cb (GtkIMContext *fallback_context, const char *str, ScimBridgeClientIMContext *context);
67
static void initialize ();
68
static void finalize ();
69
static void attach_imcontext_impl (ScimBridgeClientIMContext *ic);
70
static void detach_ic_impl (ScimBridgeClientIMContext *ic);
72
static void display_exception (ScimBridgeException *exception);
74
static gboolean do_update_preedit (gpointer data);
75
static gboolean do_commit (gpointer data);
76
static gboolean do_shutdown (gpointer data);
79
static void scim_bridge_client_imcontext_class_initialize (ScimBridgeClientIMContextClass *klass, gpointer *klass_data);
80
static void scim_bridge_client_imcontext_initialize (ScimBridgeClientIMContext *context, ScimBridgeClientIMContextClass *klass);
81
static void scim_bridge_client_imcontext_finalize (GObject *object);
83
static gboolean scim_bridge_client_imcontext_filter_keypress (GtkIMContext *context, GdkEventKey *event);
84
static void scim_bridge_client_imcontext_reset (GtkIMContext *context);
85
static void scim_bridge_client_imcontext_get_preedit_string (GtkIMContext *context, gchar **str, PangoAttrList **attrs, gint *cursor_pos);
86
static void scim_bridge_client_imcontext_set_use_preedit (GtkIMContext *context, gboolean use_preedit);
88
static void scim_bridge_client_imcontext_set_client_window (GtkIMContext *context, GdkWindow *window);
89
static void scim_bridge_client_imcontext_focus_in (GtkIMContext *context);
90
static void scim_bridge_client_imcontext_focus_out (GtkIMContext *context);
91
static void scim_bridge_client_imcontext_set_cursor_location (GtkIMContext *context, GdkRectangle *area);
93
/* Kernel implementations */
94
void scim_bridge_client_kernel_impl_cleanup ()
96
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_kernel_impl_cleanup");
98
ScimBridgeIMContext *iter;
99
for (iter = scim_bridge_client_kernel_get_first_imcontext (); iter != NULL; iter = scim_bridge_client_kernel_get_next_imcontext (iter)) {
100
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) iter;
101
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 1, "Freeing imcontext: %d", ic_impl->parent.id);
102
detach_ic_impl (ic_impl->owner);
105
scim_focused_imcontext = NULL;
107
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "Cleanup done...");
111
void scim_bridge_client_kernel_impl_finalized ()
113
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_kernel_impl_finalized");
118
void scim_bridge_client_kernel_impl_commit (ScimBridgeIMContext *ic)
120
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_commit");
122
if (!initialized) return;
124
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
125
if (ic_impl->commit_string_capacity < ic_impl->preedit_string_length) {
126
ic_impl->commit_string = realloc (ic_impl->commit_string, sizeof (char) * (ic_impl->preedit_string_length + 1));
127
ic_impl->commit_string_capacity = ic_impl->preedit_string_length;
129
strcpy (ic_impl->commit_string, ic_impl->preedit_string);
130
g_idle_add (do_commit, (gpointer) ic_impl->owner);
134
void scim_bridge_client_kernel_impl_set_preedit_string (ScimBridgeIMContext *ic, ucs4_t *wstr, size_t wstr_len)
136
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_string");
138
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
140
const size_t str_buflen = scim_bridge_string_strbuflen (wstr);
141
if (ic_impl->preedit_string == NULL || ic_impl->preedit_string_capacity < str_buflen) {
142
ic_impl->preedit_string = realloc (ic_impl->preedit_string, sizeof (char) * (str_buflen + 1));
143
ic_impl->preedit_string_capacity = str_buflen;
146
ScimBridgeException except;
147
scim_bridge_exception_initialize (&except);
148
if (scim_bridge_string_wcstombs (&except, ic_impl->preedit_string, wstr, ic_impl->preedit_string_capacity, &ic_impl->preedit_string_length)) {
149
scim_bridge_perrorln ("Cannot convert preedit wide string into utf8: %s", scim_bridge_exception_get_message (&except));
151
scim_bridge_exception_finalize (&except);
158
void scim_bridge_client_kernel_impl_set_preedit_attributes (ScimBridgeIMContext *ic, ScimBridgeAttribute *attrs, size_t attr_count)
160
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_attributes");
162
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
164
free (ic_impl->preedit_attributes);
165
ic_impl->preedit_attributes = attrs;
166
ic_impl->preedit_attribute_count = attr_count;
171
void scim_bridge_client_kernel_impl_set_preedit_cursor_position (ScimBridgeIMContext *ic, int cursor_position)
173
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_cursor_position");
175
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
177
ic_impl->preedit_cursor_position = cursor_position;
182
void scim_bridge_client_kernel_impl_set_preedit_shown (ScimBridgeIMContext *ic, int shown)
184
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_shown");
186
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
188
ic_impl->preedit_shown = shown;
193
void scim_bridge_client_kernel_impl_update_preedit (ScimBridgeIMContext *ic)
195
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_impl_update_preedit");
197
if (!initialized) return;
199
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
200
g_idle_add (do_update_preedit, (gpointer) ic_impl->owner);
204
void scim_bridge_client_kernel_impl_forward_keyevent (ScimBridgeIMContext *ic, const ScimBridgeKeyEvent *keyevent)
206
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_forward_keyevent");
208
if (!initialized) return;
210
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
211
GdkEventKey gdkevent = scim_bridge_keyevent_bridge_to_gdk (ic_impl->client_window, keyevent);
213
if (ic_impl->owner && ic_impl->owner->slave) {
214
if (!gtk_im_context_filter_keypress (ic_impl->owner->slave, &gdkevent)) {
215
gdk_event_put ((GdkEvent *) &gdkevent);
221
void scim_bridge_client_kernel_impl_beep (ScimBridgeIMContext *ic)
223
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
224
if (ic_impl) gdk_beep ();
228
void scim_bridge_client_kernel_impl_get_surrounding_string (ScimBridgeIMContext *ic, ucs4_t *wstr, const size_t max_length, size_t *fetch_len, int *cursor_pos)
230
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
236
if (gtk_im_context_get_surrounding (GTK_IM_CONTEXT (ic_impl->owner), &str, &cur_pos_in_utf8)) {
237
ScimBridgeException except;
238
scim_bridge_exception_initialize (&except);
241
if (scim_bridge_string_mbstowcs (&except, wstr, str, max_length, &wstr_len)) {
242
scim_bridge_perrorln ("Cannot convert the surrounding text into UCS4: %s", except.message);
243
scim_bridge_exception_finalize (&except);
249
char *sub_str = str + cur_pos_in_utf8;
250
ucs4_t *buf = alloca (sizeof (ucs4_t) * max_length);
252
if (scim_bridge_string_mbstowcs (&except, buf, sub_str, (size_t) max_length, &buf_len)) {
253
scim_bridge_perrorln ("Cannot convert cursor position into UCS4 order: %s", except.message);
254
scim_bridge_exception_finalize (&except);
261
scim_bridge_exception_finalize (&except);
263
*fetch_len = wstr_len;
264
*cursor_pos = *fetch_len - buf_len;
270
void scim_bridge_client_kernel_impl_delete_surrounding_string (ScimBridgeIMContext *ic, size_t offset, size_t length, int *retval)
272
ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
274
*retval = gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (ic_impl->owner), offset, length);
281
void scim_bridge_client_kernel_impl_exception_occured (ScimBridgeException *except)
283
display_exception (except);
285
g_idle_add (do_shutdown, NULL);
289
/* Helper function implmentations */
292
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "initialize");
295
gdk_color_parse ("gray92", &color_normal_background);
296
gdk_color_parse ("black", &color_normal_text);
297
gdk_color_parse ("light blue", &color_active_background);
298
gdk_color_parse ("black", &color_active_text);
300
scim_focused_imcontext = NULL;
302
ScimBridgeException except;
303
scim_bridge_exception_initialize (&except);
304
if (scim_bridge_client_initialize_kernel (&except)) {
305
display_exception (&except);
306
scim_bridge_exception_finalize (&except);
310
scim_bridge_exception_finalize (&except);
318
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "finalize");
321
ScimBridgeException except;
322
scim_bridge_exception_initialize (&except);
323
scim_bridge_client_finalize_kernel (&except);
324
scim_bridge_exception_finalize (&except);
329
void attach_imcontext_impl (ScimBridgeClientIMContext *ic)
331
ScimBridgeClientIMContextImpl *ic_impl = malloc (sizeof (ScimBridgeClientIMContextImpl));
333
ic_impl->client_window = NULL;
335
ic_impl->preedit_shown = 0;
336
ic_impl->preedit_string = NULL;
337
ic_impl->preedit_string_length = 0;
338
ic_impl->preedit_string_capacity = 0;
339
ic_impl->preedit_attributes = NULL;
340
ic_impl->preedit_attribute_count = 0;
342
ic_impl->commit_string = NULL;
343
ic_impl->commit_string_capacity = 0;
345
ic_impl->cursor_x = 0;
346
ic_impl->cursor_y = 0;
347
ic_impl->window_x = 0;
348
ic_impl->window_y = 0;
355
void detach_ic_impl (ScimBridgeClientIMContext *ic)
357
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
359
if (ic_impl->client_window) g_object_unref (ic_impl->client_window);
361
free (ic_impl->preedit_string);
362
free (ic_impl->preedit_attributes);
364
free (ic_impl->commit_string);
366
g_idle_remove_by_data ((gpointer) ic_impl->owner);
374
void gtk_im_slave_commit_cb (GtkIMContext *fallback_context, const char *str, ScimBridgeClientIMContext *context)
376
g_return_if_fail (str);
377
g_signal_emit_by_name (context, "commit", str);
381
void display_exception (ScimBridgeException *except)
383
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_kernel_impl_exception_occured");
384
scim_bridge_perrorln ("%s: %s", scim_bridge_exception_get_message (except), scim_bridge_exception_get_strerror (except));
388
gboolean do_update_preedit (gpointer data)
390
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_update_preedit");
393
ScimBridgeClientIMContext *ic = (ScimBridgeClientIMContext*) data;
394
g_signal_emit_by_name (ic, "preedit_changed");
401
gboolean do_commit (gpointer data)
403
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_commit");
406
ScimBridgeClientIMContext *ic = (ScimBridgeClientIMContext*) data;
407
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
408
g_signal_emit_by_name (ic, "commit", ic_impl->commit_string);
415
gboolean do_shutdown (gpointer data)
417
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_shutdown");
424
/* Implementations */
425
void scim_bridge_client_imcontext_class_initialize (ScimBridgeClientIMContextClass *klass, gpointer *klass_data)
427
GtkIMContextClass *imcontext_klass = GTK_IM_CONTEXT_CLASS (klass);
428
GObjectClass *gobject_klass = G_OBJECT_CLASS (klass);
430
imcontext_root_klass = (GObjectClass *) g_type_class_peek_parent (klass);
432
imcontext_klass->set_client_window = scim_bridge_client_imcontext_set_client_window;
433
imcontext_klass->filter_keypress = scim_bridge_client_imcontext_filter_keypress;
434
imcontext_klass->reset = scim_bridge_client_imcontext_reset;
435
imcontext_klass->get_preedit_string = scim_bridge_client_imcontext_get_preedit_string;
436
imcontext_klass->focus_in = scim_bridge_client_imcontext_focus_in;
437
imcontext_klass->focus_out = scim_bridge_client_imcontext_focus_out;
438
imcontext_klass->set_cursor_location = scim_bridge_client_imcontext_set_cursor_location;
439
imcontext_klass->set_use_preedit = scim_bridge_client_imcontext_set_use_preedit;
440
gobject_klass->finalize = scim_bridge_client_imcontext_finalize;
444
GType scim_bridge_client_imcontext_get_type ()
446
return scim_bridge_client_imcontext_type;
450
void scim_bridge_client_imcontext_register_type (GTypeModule *type_module)
452
static const GTypeInfo scim_bridge_client_imcontext_ckass_info = {
453
sizeof (ScimBridgeClientIMContextClass),
454
/* no base class initializer */
456
/* no base class finalizer */
458
/* class initializer */
459
(GClassInitFunc) scim_bridge_client_imcontext_class_initialize,
460
/* no class finalizer */
464
sizeof (ScimBridgeClientIMContext),
466
/* object initizlier */
467
(GtkObjectInitFunc) scim_bridge_client_imcontext_initialize,
470
if (!scim_bridge_client_imcontext_type)
471
scim_bridge_client_imcontext_type = g_type_module_register_type (type_module, GTK_TYPE_IM_CONTEXT, "ScimBridgeClientIMContext", &scim_bridge_client_imcontext_ckass_info, 0);
473
if (!initialized) initialize ();
477
void scim_bridge_client_imcontext_shutdown ()
479
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_shutdown");
481
if (!initialized) return;
483
ScimBridgeException except;
484
scim_bridge_exception_initialize (&except);
485
scim_bridge_client_trigger_kernel_finalizer (&except);
486
scim_bridge_exception_finalize (&except);
488
while (initialized) {
494
GtkIMContext *scim_bridge_client_imcontext_new ()
496
ScimBridgeClientIMContext *retval = SCIM_BRIDGE_CLIENT_IMCONTEXT (g_object_new (GTK_TYPE_SCIM_CLIENT_IMCONTEXT, NULL));
497
return GTK_IM_CONTEXT (retval);
501
void scim_bridge_client_imcontext_initialize (ScimBridgeClientIMContext *context, ScimBridgeClientIMContextClass *klass)
503
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_initialize");
505
/* slave exists for using gtk+'s table based input method */
506
context->slave = gtk_im_context_simple_new ();
507
g_signal_connect (G_OBJECT (context->slave), "commit", G_CALLBACK (gtk_im_slave_commit_cb), context);
509
attach_imcontext_impl (context);
511
ScimBridgeException except;
512
scim_bridge_exception_initialize (&except);
513
if (scim_bridge_client_kernel_alloc_imcontext (&except, (ScimBridgeIMContext*) context->impl)) {
514
display_exception (&except);
515
scim_bridge_exception_finalize (&except);
516
detach_ic_impl (context);
518
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 1, "imcontext: id = %d opponent = %d", context->impl->parent.id, context->impl->parent.opponent_id);
520
scim_focused_imcontext = NULL;
525
void scim_bridge_client_imcontext_finalize (GObject *object)
527
/* FIXME I think this function contains many bugs */
528
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_finalize");
530
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (object);
531
g_signal_handlers_disconnect_by_func (ic->slave, gtk_im_slave_commit_cb, ic);
532
g_object_unref (ic->slave);
534
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
536
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "id = %d", ic_impl->parent.id);
538
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "id = NULL");
542
ScimBridgeException except;
543
scim_bridge_exception_initialize (&except);
544
if (scim_bridge_client_kernel_free_imcontext (&except, (ScimBridgeIMContext*) ic_impl)) display_exception (&except);
545
scim_bridge_exception_finalize (&except);
550
scim_focused_imcontext = NULL;
552
imcontext_root_klass->finalize (object);
556
gboolean scim_bridge_client_imcontext_filter_keypress (GtkIMContext *context, GdkEventKey *event)
558
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_filter_keypress");
560
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
563
if (initialized && ic->impl) {
564
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
566
if (scim_focused_imcontext != ic_impl) scim_bridge_client_imcontext_focus_in (GTK_IM_CONTEXT (ic_impl->owner));
568
if (ic_impl->client_window) {
571
gdk_window_get_origin (ic_impl->client_window, &new_window_x, &new_window_y);
573
if (ic_impl->window_x != new_window_x || ic_impl->window_y != new_window_y) {
574
ic_impl->window_x = new_window_x;
575
ic_impl->window_y = new_window_y;
577
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 1, "The cursor location is changed: x = %d + %d\ty = %d + %d",
578
ic_impl->window_x, ic_impl->cursor_x, ic_impl->window_y, ic_impl->cursor_y);
580
ScimBridgeException except;
581
scim_bridge_exception_initialize (&except);
582
if (scim_bridge_client_kernel_cursor_location_changed (&except, (ScimBridgeIMContext*) ic_impl, ic_impl->window_x + ic_impl->cursor_x, ic_impl->window_y + ic_impl->cursor_y)) display_exception (&except);
583
scim_bridge_exception_finalize (&except);
587
ScimBridgeKeyEvent bridge_keyevent = scim_bridge_keyevent_gdk_to_bridge (ic_impl->client_window, event);
591
ScimBridgeException except;
592
scim_bridge_exception_initialize (&except);
593
if (scim_bridge_client_kernel_keyevent_occured (&except, (ScimBridgeIMContext*) ic_impl, &bridge_keyevent, &consumed)) {
594
display_exception (&except);
595
scim_bridge_exception_finalize (&except);
598
scim_bridge_exception_finalize (&except);
601
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 2, "Key event has been consumed...");
606
if (ic->slave) return gtk_im_context_filter_keypress (ic->slave, event);
613
void scim_bridge_client_imcontext_reset (GtkIMContext *context)
615
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_reset");
617
if (!initialized) return;
619
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
621
if (ic && ic->impl) {
622
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
624
ScimBridgeException except;
625
scim_bridge_exception_initialize (&except);
626
if (scim_bridge_client_kernel_reset_imcontext (&except, (ScimBridgeIMContext*) ic_impl)) display_exception (&except);
627
scim_bridge_exception_finalize (&except);
632
void scim_bridge_client_imcontext_get_preedit_string (GtkIMContext *context, gchar **str, PangoAttrList **pango_attrs, gint *cursor_pos)
634
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_get_preedit_string");
636
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
638
if (ic && ic->impl && ic->impl->preedit_shown && ic->impl->preedit_string) {
639
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
641
*str = g_strdup (ic_impl->preedit_string);
643
if (cursor_pos) *cursor_pos = ic_impl->preedit_cursor_position;
646
*pango_attrs = pango_attr_list_new ();
648
gboolean underline_exists = FALSE;
651
for (i = 0; i < ic_impl->preedit_attribute_count; ++i) {
652
ScimBridgeAttribute *attr = &ic_impl->preedit_attributes[i];
653
const int begin_pos = attr->begin;
654
const int end_pos = attr->end;
656
if (begin_pos < end_pos && 0 <= begin_pos && end_pos < ic_impl->preedit_string_length) {
657
const int start_index = g_utf8_offset_to_pointer (ic_impl->preedit_string, begin_pos) - ic_impl->preedit_string;
658
const int end_index = g_utf8_offset_to_pointer (ic_impl->preedit_string, end_pos) - ic_impl->preedit_string;
660
if (attr->type == SCIM_BRIDGE_ATTRIBUTE_DECORATE) {
661
if (attr->value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_UNDERLINE) {
662
PangoAttribute *pango_attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
663
pango_attr->start_index = start_index;
664
pango_attr->end_index = end_index;
665
pango_attr_list_insert (*pango_attrs, pango_attr);
666
underline_exists = TRUE;
667
} else if (attr->value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_REVERSE) {
668
PangoAttribute *pango_attr0 = pango_attr_foreground_new (color_normal_background.red, color_normal_background.green, color_normal_background.blue);
669
pango_attr0->start_index = start_index;
670
pango_attr0->end_index = end_index;
671
pango_attr_list_insert (*pango_attrs, pango_attr0);
673
PangoAttribute *pango_attr1 = pango_attr_background_new (color_normal_text.red, color_normal_text.green, color_normal_text.blue);
674
pango_attr1->start_index = start_index;
675
pango_attr1->end_index = end_index;
676
pango_attr_list_insert (*pango_attrs, pango_attr1);
677
} else if (attr->value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_HIGHLIGHT) {
678
PangoAttribute *pango_attr0 = pango_attr_foreground_new (color_active_text.red, color_active_text.green, color_active_text.blue);
679
pango_attr0->start_index = start_index;
680
pango_attr0->end_index = end_index;
681
pango_attr_list_insert (*pango_attrs, pango_attr0);
683
PangoAttribute *pango_attr1 = pango_attr_background_new (color_active_background.red, color_active_background.green, color_active_background.blue);
684
pango_attr1->start_index = start_index;
685
pango_attr1->end_index = end_index;
686
pango_attr_list_insert (*pango_attrs, pango_attr1);
688
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 3, "Unknown preedit decoration!");
690
} else if (attr->type == SCIM_BRIDGE_ATTRIBUTE_FOREGROUND) {
691
const ScimBridgeAttributeValue color = attr->value;
692
const unsigned int red = scim_bridge_attribute_get_red (color) * 256;
693
const unsigned int green = scim_bridge_attribute_get_green (color) * 256;
694
const unsigned int blue = scim_bridge_attribute_get_blue (color) * 256;
696
PangoAttribute *pango_attr = pango_attr_foreground_new (red, green, blue);
697
pango_attr->start_index = start_index;
698
pango_attr->end_index = end_index;
699
pango_attr_list_insert (*pango_attrs, pango_attr);
700
} else if (attr->type == SCIM_BRIDGE_ATTRIBUTE_BACKGROUND) {
701
const ScimBridgeAttributeValue color = attr->value;
702
const unsigned int red = scim_bridge_attribute_get_red (color) * 256;
703
const unsigned int green = scim_bridge_attribute_get_green (color) * 256;
704
const unsigned int blue = scim_bridge_attribute_get_blue (color) * 256;
706
PangoAttribute *pango_attr = pango_attr_background_new (red, green, blue);
707
pango_attr->start_index = start_index;
708
pango_attr->end_index = end_index;
709
pango_attr_list_insert (*pango_attrs, pango_attr);
715
/* If there is no underline at all, then draw underline under the whole preedit string.*/
716
if (!underline_exists) {
717
PangoAttribute *pango_attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
718
pango_attr->start_index = 0;
719
pango_attr->end_index = ic_impl->preedit_string_length;
720
pango_attr_list_insert (*pango_attrs, pango_attr);
724
if (str) *str = g_strdup ("");
725
if (cursor_pos) *cursor_pos = 0;
726
if (pango_attrs) *pango_attrs = pango_attr_list_new ();
731
void scim_bridge_client_imcontext_focus_in (GtkIMContext *context)
733
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3,"scim_bridge_client_imcontext_focus_in");
735
if (!initialized) return;
737
if (scim_focused_imcontext) scim_bridge_client_imcontext_focus_out (GTK_IM_CONTEXT (scim_focused_imcontext->owner));
739
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
741
if (ic && ic->impl) {
742
scim_focused_imcontext = ic->impl;
744
ScimBridgeException except;
745
scim_bridge_exception_initialize (&except);
746
if (scim_bridge_client_kernel_focus_changed (&except, (ScimBridgeIMContext*) scim_focused_imcontext, 1)) {
747
display_exception (&except);
749
scim_bridge_exception_finalize (&except);
754
void scim_bridge_client_imcontext_focus_out (GtkIMContext *context)
756
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_focus_out");
758
g_idle_remove_by_data ((gpointer) context);
760
if (!initialized) return;
762
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
764
if (ic && ic->impl && scim_focused_imcontext == ic->impl) {
765
ScimBridgeException except;
766
scim_bridge_exception_initialize (&except);
767
if (scim_bridge_client_kernel_focus_changed (&except, (ScimBridgeIMContext*) scim_focused_imcontext, 0)) display_exception (&except);
768
scim_bridge_exception_finalize (&except);
770
scim_focused_imcontext = NULL;
775
void scim_bridge_client_imcontext_set_client_window (GtkIMContext *context, GdkWindow *new_window)
777
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_client_window");
779
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
781
if (ic && ic->impl) {
782
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
784
if (ic_impl->client_window) g_object_unref (ic_impl->client_window);
785
if (new_window) g_object_ref (new_window);
787
ic_impl->client_window = new_window;
792
void scim_bridge_client_imcontext_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
794
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_cursor_location");
795
ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
797
if (ic && ic->impl) {
798
ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
800
const int new_cursor_x = area->x + area->width;
801
const int new_cursor_y = area->y + area->height + 8;
803
if (ic_impl->client_window) {
806
gdk_window_get_origin (ic_impl->client_window, &new_window_x, &new_window_y);
808
if (ic_impl->window_x + ic_impl->cursor_x != new_window_x + new_cursor_x || ic_impl->window_y + ic_impl->cursor_y != new_cursor_y + new_window_y) {
809
ic_impl->window_x = new_window_x;
810
ic_impl->window_y = new_window_y;
811
ic_impl->cursor_x = new_cursor_x;
812
ic_impl->cursor_y = new_cursor_y;
814
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 1, "The cursor location is changed: x = %d + %d\ty = %d + %d",
815
ic_impl->window_x, ic_impl->cursor_x, ic_impl->window_y, ic_impl->cursor_y);
817
ScimBridgeException except;
818
scim_bridge_exception_initialize (&except);
819
scim_bridge_client_kernel_cursor_location_changed (&except, (ScimBridgeIMContext*) ic_impl, ic_impl->window_x + ic_impl->cursor_x, ic_impl->window_y + ic_impl->cursor_y);
820
scim_bridge_exception_finalize (&except);
827
void scim_bridge_client_imcontext_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
829
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_use_preedit");
831
scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 9, "FIXME Not supported!");