~ubuntu-branches/ubuntu/trusty/scim-bridge/trusty

« back to all changes in this revision

Viewing changes to client-gtk/scim-bridge-client-imcontext-gtk.c

  • Committer: Bazaar Package Importer
  • Author(s): Hou ZhengPeng
  • Date: 2006-04-02 18:07:30 UTC
  • Revision ID: james.westby@ubuntu.com-20060402180730-x4zlfe8odh4yzcld
Tags: upstream-0.1.3
ImportĀ upstreamĀ versionĀ 0.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <alloca.h>
 
2
#include <assert.h>
 
3
#include <errno.h>
 
4
#include <stdlib.h>
 
5
#include <string.h>
 
6
#include <unistd.h>
 
7
 
 
8
#include <gtk/gtk.h>
 
9
#include <gtk/gtkimcontext.h>
 
10
 
 
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"
 
18
 
 
19
/* Typedef */
 
20
struct _ScimBridgeClientIMContextImpl
 
21
{
 
22
    /* extends ScimBridgeIMContext */
 
23
    /* Don't touch the first element */
 
24
    ScimBridgeIMContextParent parent;
 
25
 
 
26
    ScimBridgeClientIMContext *owner;
 
27
 
 
28
    GdkWindow *client_window;
 
29
 
 
30
    int preedit_shown;
 
31
    int preedit_cursor_position;
 
32
 
 
33
    int cursor_x;
 
34
    int cursor_y;
 
35
    int window_x;
 
36
    int window_y;
 
37
 
 
38
    char *preedit_string;
 
39
    size_t preedit_string_length;
 
40
    size_t preedit_string_capacity;
 
41
 
 
42
    char *commit_string;
 
43
    size_t commit_string_capacity;
 
44
 
 
45
    ScimBridgeAttribute *preedit_attributes;
 
46
    size_t preedit_attribute_count;
 
47
};
 
48
 
 
49
/* Private data */
 
50
static GType scim_bridge_client_imcontext_type = 0;
 
51
static GObjectClass *imcontext_root_klass = NULL;
 
52
 
 
53
static gboolean initialized = FALSE;
 
54
 
 
55
/* Variables for scim */
 
56
static ScimBridgeClientIMContextImpl *scim_focused_imcontext = NULL;
 
57
 
 
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;
 
63
 
 
64
/* Helper functions */
 
65
static void gtk_im_slave_commit_cb (GtkIMContext *fallback_context, const char *str, ScimBridgeClientIMContext *context);
 
66
 
 
67
static void initialize ();
 
68
static void finalize ();
 
69
static void attach_imcontext_impl (ScimBridgeClientIMContext *ic);
 
70
static void detach_ic_impl (ScimBridgeClientIMContext *ic);
 
71
 
 
72
static void display_exception (ScimBridgeException *exception);
 
73
 
 
74
static gboolean do_update_preedit (gpointer data);
 
75
static gboolean do_commit (gpointer data);
 
76
static gboolean do_shutdown (gpointer data);
 
77
 
 
78
/* Class functions */
 
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);
 
82
 
 
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);
 
87
 
 
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);
 
92
 
 
93
/* Kernel implementations */
 
94
void scim_bridge_client_kernel_impl_cleanup ()
 
95
{
 
96
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_kernel_impl_cleanup");
 
97
 
 
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);
 
103
    }
 
104
 
 
105
    scim_focused_imcontext = NULL;
 
106
 
 
107
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "Cleanup done...");
 
108
}
 
109
 
 
110
 
 
111
void scim_bridge_client_kernel_impl_finalized ()
 
112
{
 
113
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_kernel_impl_finalized");
 
114
    initialized = FALSE;
 
115
}
 
116
 
 
117
 
 
118
void scim_bridge_client_kernel_impl_commit (ScimBridgeIMContext *ic)
 
119
{
 
120
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_commit");
 
121
 
 
122
    if (!initialized) return;
 
123
 
 
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;
 
128
    }
 
129
    strcpy (ic_impl->commit_string, ic_impl->preedit_string);
 
130
    g_idle_add (do_commit, (gpointer) ic_impl->owner);
 
131
}
 
132
 
 
133
 
 
134
void scim_bridge_client_kernel_impl_set_preedit_string (ScimBridgeIMContext *ic, ucs4_t *wstr, size_t wstr_len)
 
135
{
 
136
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_string");
 
137
 
 
138
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
139
    if (ic_impl) {
 
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;
 
144
        }
 
145
 
 
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));
 
150
        }
 
151
        scim_bridge_exception_finalize (&except);
 
152
 
 
153
        free (wstr);
 
154
    }
 
155
}
 
156
 
 
157
 
 
158
void scim_bridge_client_kernel_impl_set_preedit_attributes (ScimBridgeIMContext *ic, ScimBridgeAttribute *attrs, size_t attr_count)
 
159
{
 
160
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_attributes");
 
161
 
 
162
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
163
    if (ic_impl) {
 
164
        free (ic_impl->preedit_attributes);
 
165
        ic_impl->preedit_attributes = attrs;
 
166
        ic_impl->preedit_attribute_count = attr_count;
 
167
    }
 
168
}
 
169
 
 
170
 
 
171
void scim_bridge_client_kernel_impl_set_preedit_cursor_position (ScimBridgeIMContext *ic, int cursor_position)
 
172
{
 
173
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_cursor_position");
 
174
 
 
175
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
176
    if (ic_impl) {
 
177
        ic_impl->preedit_cursor_position = cursor_position;
 
178
    }
 
179
}
 
180
 
 
181
 
 
182
void scim_bridge_client_kernel_impl_set_preedit_shown (ScimBridgeIMContext *ic, int shown)
 
183
{
 
184
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_set_preedit_shown");
 
185
 
 
186
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
187
    if (ic_impl) {
 
188
        ic_impl->preedit_shown = shown;
 
189
    }
 
190
}
 
191
 
 
192
 
 
193
void scim_bridge_client_kernel_impl_update_preedit (ScimBridgeIMContext *ic)
 
194
{
 
195
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_impl_update_preedit");
 
196
 
 
197
    if (!initialized) return;
 
198
 
 
199
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
200
    g_idle_add (do_update_preedit, (gpointer) ic_impl->owner);
 
201
}
 
202
 
 
203
 
 
204
void scim_bridge_client_kernel_impl_forward_keyevent (ScimBridgeIMContext *ic, const ScimBridgeKeyEvent *keyevent)
 
205
{
 
206
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 2, "scim_bridge_client_kernel_forward_keyevent");
 
207
 
 
208
    if (!initialized) return;
 
209
 
 
210
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
211
    GdkEventKey gdkevent = scim_bridge_keyevent_bridge_to_gdk (ic_impl->client_window, keyevent);
 
212
 
 
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);
 
216
        }
 
217
    }
 
218
}
 
219
 
 
220
 
 
221
void scim_bridge_client_kernel_impl_beep (ScimBridgeIMContext *ic)
 
222
{
 
223
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
224
    if (ic_impl) gdk_beep ();
 
225
}
 
226
 
 
227
 
 
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)
 
229
{
 
230
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
231
 
 
232
    *fetch_len = 0;
 
233
    if (ic_impl) {
 
234
        char *str;
 
235
        int cur_pos_in_utf8;
 
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);
 
239
 
 
240
            size_t wstr_len;
 
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);
 
244
 
 
245
                g_free (str);
 
246
                return;
 
247
            }
 
248
 
 
249
            char *sub_str = str + cur_pos_in_utf8;
 
250
            ucs4_t *buf = alloca (sizeof (ucs4_t) * max_length);
 
251
            size_t buf_len;
 
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);
 
255
 
 
256
                g_free (str);
 
257
                return;
 
258
            }
 
259
 
 
260
            g_free (str);
 
261
            scim_bridge_exception_finalize (&except);
 
262
 
 
263
            *fetch_len = wstr_len;
 
264
            *cursor_pos = *fetch_len - buf_len;
 
265
        }
 
266
    }
 
267
}
 
268
 
 
269
 
 
270
void scim_bridge_client_kernel_impl_delete_surrounding_string (ScimBridgeIMContext *ic, size_t offset, size_t length, int *retval)
 
271
{
 
272
    ScimBridgeClientIMContextImpl *ic_impl = (ScimBridgeClientIMContextImpl*) ic;
 
273
    if (ic_impl) {
 
274
        *retval = gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (ic_impl->owner), offset, length);
 
275
    } else {
 
276
        *retval = 0;
 
277
    }
 
278
}
 
279
 
 
280
 
 
281
void scim_bridge_client_kernel_impl_exception_occured (ScimBridgeException *except)
 
282
{
 
283
    display_exception (except);
 
284
 
 
285
    g_idle_add (do_shutdown, NULL);
 
286
}
 
287
 
 
288
 
 
289
/* Helper function implmentations  */
 
290
void initialize ()
 
291
{
 
292
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "initialize");
 
293
 
 
294
    /* Init colors.*/
 
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);
 
299
 
 
300
    scim_focused_imcontext = NULL;
 
301
 
 
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);
 
307
 
 
308
        return;
 
309
    }
 
310
    scim_bridge_exception_finalize (&except);
 
311
 
 
312
    initialized = TRUE;
 
313
}
 
314
 
 
315
 
 
316
void finalize ()
 
317
{
 
318
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "finalize");
 
319
 
 
320
    if (initialized) {
 
321
        ScimBridgeException except;
 
322
        scim_bridge_exception_initialize (&except);
 
323
        scim_bridge_client_finalize_kernel (&except);
 
324
        scim_bridge_exception_finalize (&except);
 
325
    }
 
326
}
 
327
 
 
328
 
 
329
void attach_imcontext_impl (ScimBridgeClientIMContext *ic)
 
330
{
 
331
    ScimBridgeClientIMContextImpl *ic_impl = malloc (sizeof (ScimBridgeClientIMContextImpl));
 
332
 
 
333
    ic_impl->client_window = NULL;
 
334
 
 
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;
 
341
 
 
342
    ic_impl->commit_string = NULL;
 
343
    ic_impl->commit_string_capacity = 0;
 
344
 
 
345
    ic_impl->cursor_x = 0;
 
346
    ic_impl->cursor_y = 0;
 
347
    ic_impl->window_x = 0;
 
348
    ic_impl->window_y = 0;
 
349
 
 
350
    ic_impl->owner = ic;
 
351
    ic->impl = ic_impl;
 
352
}
 
353
 
 
354
 
 
355
void detach_ic_impl (ScimBridgeClientIMContext *ic)
 
356
{
 
357
    ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
358
 
 
359
    if (ic_impl->client_window) g_object_unref (ic_impl->client_window);
 
360
 
 
361
    free (ic_impl->preedit_string);
 
362
    free (ic_impl->preedit_attributes);
 
363
 
 
364
    free (ic_impl->commit_string);
 
365
 
 
366
    g_idle_remove_by_data ((gpointer) ic_impl->owner);
 
367
 
 
368
    free (ic_impl);
 
369
 
 
370
    ic->impl = NULL;
 
371
}
 
372
 
 
373
 
 
374
void gtk_im_slave_commit_cb (GtkIMContext *fallback_context, const char *str, ScimBridgeClientIMContext *context)
 
375
{
 
376
    g_return_if_fail (str);
 
377
    g_signal_emit_by_name (context, "commit", str);
 
378
}
 
379
 
 
380
 
 
381
void display_exception (ScimBridgeException *except)
 
382
{
 
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));
 
385
}
 
386
 
 
387
 
 
388
gboolean do_update_preedit (gpointer data)
 
389
{
 
390
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_update_preedit");
 
391
 
 
392
    if (initialized) {
 
393
        ScimBridgeClientIMContext *ic = (ScimBridgeClientIMContext*) data;
 
394
        g_signal_emit_by_name (ic, "preedit_changed");
 
395
    }
 
396
 
 
397
    return FALSE;
 
398
}
 
399
 
 
400
 
 
401
gboolean do_commit (gpointer data)
 
402
{
 
403
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_commit");
 
404
 
 
405
    if (initialized) {
 
406
        ScimBridgeClientIMContext *ic = (ScimBridgeClientIMContext*) data;
 
407
        ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
408
        g_signal_emit_by_name (ic, "commit", ic_impl->commit_string);
 
409
    }
 
410
 
 
411
    return FALSE;
 
412
}
 
413
 
 
414
 
 
415
gboolean do_shutdown (gpointer data)
 
416
{
 
417
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 1, "do_shutdown");
 
418
 
 
419
    finalize ();
 
420
    return FALSE;
 
421
}
 
422
 
 
423
 
 
424
/* Implementations */
 
425
void scim_bridge_client_imcontext_class_initialize (ScimBridgeClientIMContextClass *klass, gpointer *klass_data)
 
426
{
 
427
    GtkIMContextClass *imcontext_klass = GTK_IM_CONTEXT_CLASS (klass);
 
428
    GObjectClass *gobject_klass = G_OBJECT_CLASS (klass);
 
429
 
 
430
    imcontext_root_klass = (GObjectClass *) g_type_class_peek_parent (klass);
 
431
 
 
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;
 
441
}
 
442
 
 
443
 
 
444
GType scim_bridge_client_imcontext_get_type ()
 
445
{
 
446
    return scim_bridge_client_imcontext_type;
 
447
}
 
448
 
 
449
 
 
450
void scim_bridge_client_imcontext_register_type (GTypeModule *type_module)
 
451
{
 
452
    static const GTypeInfo scim_bridge_client_imcontext_ckass_info = {
 
453
        sizeof (ScimBridgeClientIMContextClass),
 
454
        /* no base class initializer */
 
455
        NULL,
 
456
        /* no base class finalizer */
 
457
        NULL,
 
458
        /* class initializer */
 
459
        (GClassInitFunc) scim_bridge_client_imcontext_class_initialize,
 
460
        /* no class finalizer */
 
461
        NULL,
 
462
        /* no class data */
 
463
        NULL,
 
464
        sizeof (ScimBridgeClientIMContext),
 
465
        0,
 
466
        /* object initizlier */
 
467
        (GtkObjectInitFunc) scim_bridge_client_imcontext_initialize,
 
468
    };
 
469
 
 
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);
 
472
 
 
473
    if (!initialized) initialize ();
 
474
}
 
475
 
 
476
 
 
477
void scim_bridge_client_imcontext_shutdown ()
 
478
{
 
479
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_shutdown");
 
480
 
 
481
    if (!initialized) return;
 
482
 
 
483
    ScimBridgeException except;
 
484
    scim_bridge_exception_initialize (&except);
 
485
    scim_bridge_client_trigger_kernel_finalizer (&except);
 
486
    scim_bridge_exception_finalize (&except);
 
487
 
 
488
    while (initialized) {
 
489
        usleep (10);
 
490
    }
 
491
}
 
492
 
 
493
 
 
494
GtkIMContext *scim_bridge_client_imcontext_new ()
 
495
{
 
496
    ScimBridgeClientIMContext *retval = SCIM_BRIDGE_CLIENT_IMCONTEXT (g_object_new (GTK_TYPE_SCIM_CLIENT_IMCONTEXT, NULL));
 
497
    return GTK_IM_CONTEXT (retval);
 
498
}
 
499
 
 
500
 
 
501
void scim_bridge_client_imcontext_initialize (ScimBridgeClientIMContext *context, ScimBridgeClientIMContextClass *klass)
 
502
{
 
503
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_initialize");
 
504
 
 
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);
 
508
 
 
509
    attach_imcontext_impl (context);
 
510
 
 
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);
 
517
    } else {
 
518
        scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 1, "imcontext: id = %d opponent = %d", context->impl->parent.id, context->impl->parent.opponent_id);
 
519
 
 
520
        scim_focused_imcontext = NULL;
 
521
    }
 
522
}
 
523
 
 
524
 
 
525
void scim_bridge_client_imcontext_finalize (GObject *object)
 
526
{
 
527
    /* FIXME I think this function contains many bugs */
 
528
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_finalize");
 
529
 
 
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);
 
533
 
 
534
    ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
535
    if (ic_impl) {
 
536
        scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "id = %d", ic_impl->parent.id);
 
537
    } else {
 
538
        scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "id = NULL");
 
539
    }
 
540
 
 
541
    if (ic_impl) {
 
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);
 
546
 
 
547
        detach_ic_impl (ic);
 
548
    }
 
549
 
 
550
    scim_focused_imcontext = NULL;
 
551
 
 
552
    imcontext_root_klass->finalize (object);
 
553
}
 
554
 
 
555
 
 
556
gboolean scim_bridge_client_imcontext_filter_keypress (GtkIMContext *context, GdkEventKey *event)
 
557
{
 
558
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_filter_keypress");
 
559
 
 
560
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
561
 
 
562
    if (ic) {
 
563
        if (initialized && ic->impl) {
 
564
            ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
565
 
 
566
            if (scim_focused_imcontext != ic_impl) scim_bridge_client_imcontext_focus_in (GTK_IM_CONTEXT (ic_impl->owner));
 
567
 
 
568
            if (ic_impl->client_window) {
 
569
                int new_window_x;
 
570
                int new_window_y;
 
571
                gdk_window_get_origin (ic_impl->client_window, &new_window_x, &new_window_y);
 
572
 
 
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;
 
576
 
 
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);
 
579
 
 
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);
 
584
                }
 
585
            }
 
586
 
 
587
            ScimBridgeKeyEvent bridge_keyevent = scim_bridge_keyevent_gdk_to_bridge (ic_impl->client_window, event);
 
588
 
 
589
            int consumed = 0;
 
590
 
 
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);
 
596
                return FALSE;
 
597
            }
 
598
            scim_bridge_exception_finalize (&except);
 
599
 
 
600
            if (consumed) {
 
601
                scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 2, "Key event has been consumed...");
 
602
                return TRUE;
 
603
            }
 
604
        }
 
605
 
 
606
        if (ic->slave) return gtk_im_context_filter_keypress (ic->slave, event);
 
607
    }
 
608
 
 
609
    return FALSE;
 
610
}
 
611
 
 
612
 
 
613
void scim_bridge_client_imcontext_reset (GtkIMContext *context)
 
614
{
 
615
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_reset");
 
616
 
 
617
    if (!initialized) return;
 
618
 
 
619
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
620
 
 
621
    if (ic && ic->impl) {
 
622
        ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
623
 
 
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);
 
628
    }
 
629
}
 
630
 
 
631
 
 
632
void scim_bridge_client_imcontext_get_preedit_string (GtkIMContext *context, gchar **str, PangoAttrList **pango_attrs, gint *cursor_pos)
 
633
{
 
634
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_get_preedit_string");
 
635
 
 
636
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
637
 
 
638
    if (ic && ic->impl && ic->impl->preedit_shown && ic->impl->preedit_string) {
 
639
        ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
640
 
 
641
        *str = g_strdup (ic_impl->preedit_string);
 
642
 
 
643
        if (cursor_pos) *cursor_pos = ic_impl->preedit_cursor_position;
 
644
 
 
645
        if (pango_attrs) {
 
646
            *pango_attrs = pango_attr_list_new ();
 
647
 
 
648
            gboolean underline_exists = FALSE;
 
649
 
 
650
            int i;
 
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;
 
655
 
 
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;
 
659
 
 
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);
 
672
 
 
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);
 
682
 
 
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);
 
687
                        } else {
 
688
                            scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_CLIENT, 3, "Unknown preedit decoration!");
 
689
                        }
 
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;
 
695
 
 
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;
 
705
 
 
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);
 
710
                    }
 
711
 
 
712
                }
 
713
 
 
714
            }
 
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);
 
721
            }
 
722
        }
 
723
    } else {
 
724
        if (str) *str = g_strdup ("");
 
725
        if (cursor_pos) *cursor_pos = 0;
 
726
        if (pango_attrs) *pango_attrs = pango_attr_list_new ();
 
727
    }
 
728
}
 
729
 
 
730
 
 
731
void scim_bridge_client_imcontext_focus_in (GtkIMContext *context)
 
732
{
 
733
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3,"scim_bridge_client_imcontext_focus_in");
 
734
 
 
735
    if (!initialized) return;
 
736
 
 
737
    if (scim_focused_imcontext) scim_bridge_client_imcontext_focus_out (GTK_IM_CONTEXT (scim_focused_imcontext->owner));
 
738
 
 
739
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
740
 
 
741
    if (ic && ic->impl) {
 
742
        scim_focused_imcontext = ic->impl;
 
743
 
 
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);
 
748
        }
 
749
        scim_bridge_exception_finalize (&except);
 
750
    }
 
751
}
 
752
 
 
753
 
 
754
void scim_bridge_client_imcontext_focus_out (GtkIMContext *context)
 
755
{
 
756
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_focus_out");
 
757
 
 
758
    g_idle_remove_by_data ((gpointer) context);
 
759
 
 
760
    if (!initialized) return;
 
761
 
 
762
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
763
 
 
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);
 
769
 
 
770
        scim_focused_imcontext = NULL;
 
771
    }
 
772
}
 
773
 
 
774
 
 
775
void scim_bridge_client_imcontext_set_client_window (GtkIMContext *context, GdkWindow *new_window)
 
776
{
 
777
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_client_window");
 
778
 
 
779
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
780
 
 
781
    if (ic && ic->impl) {
 
782
        ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
783
 
 
784
        if (ic_impl->client_window) g_object_unref (ic_impl->client_window);
 
785
        if (new_window) g_object_ref (new_window);
 
786
 
 
787
        ic_impl->client_window = new_window;
 
788
    }
 
789
}
 
790
 
 
791
 
 
792
void scim_bridge_client_imcontext_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
 
793
{
 
794
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_cursor_location");
 
795
    ScimBridgeClientIMContext *ic = SCIM_BRIDGE_CLIENT_IMCONTEXT (context);
 
796
 
 
797
    if (ic && ic->impl) {
 
798
        ScimBridgeClientIMContextImpl *ic_impl = ic->impl;
 
799
 
 
800
        const int new_cursor_x = area->x + area->width;
 
801
        const int new_cursor_y = area->y + area->height + 8;
 
802
 
 
803
        if (ic_impl->client_window) {
 
804
            int new_window_x;
 
805
            int new_window_y;
 
806
            gdk_window_get_origin (ic_impl->client_window, &new_window_x, &new_window_y);
 
807
 
 
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;
 
813
 
 
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);
 
816
 
 
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);
 
821
            }
 
822
        }
 
823
    }
 
824
}
 
825
 
 
826
 
 
827
void scim_bridge_client_imcontext_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
 
828
{
 
829
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 3, "scim_bridge_client_imcontext_set_use_preedit");
 
830
 
 
831
    scim_bridge_pdebugln (SCIM_BRIDGE_DEBUG_IMCONTEXT, 9, "FIXME Not supported!");
 
832
}