1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2000 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19 #include "locale.h"
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 //#include "gtkintl.h"
25 #include <gtk/gtk.h>
26 #if !GTK_CHECK_VERSION(3,0,0)
27 #include <gtk/gtklabel.h>
28 #include <gtk/gtksignal.h>
29 #include <gtk/gtkwindow.h>
30 #include <gdk/gdk.h>
31 #endif
32 #include "gtkimcontextgcin.h"
33 // #include "gcin.h" // for debug only
34 #include "gcin-im-client.h"
35 #include <X11/keysym.h>
36
37 #define DBG 0
38
39
40 #if !GTK_CHECK_VERSION(3,0,0)
41 #define gdk_window_get_screen gdk_drawable_get_screen
42 #endif
43
44
45 typedef struct _GtkGCINInfo GtkGCINInfo;
46
47 #define FLAG_CHROME 1
48 #define FLAG_FIREFOX 2
49
50 struct _GtkIMContextGCIN
51 {
52 GtkIMContext object;
53
54 GdkWindow *client_window;
55 #if 0
56 GtkWidget *client_widget;
57 #endif
58 GCIN_client_handle *gcin_ch;
59 int timeout_handle;
60 char *pe_str;
61 int old_sub_comp_len;
62 gboolean pe_started;
63 GCIN_PREEDIT_ATTR *pe_att;
64 int pe_attN;
65 int pe_cursor;
66 int flags;
67 };
68
69
70 static void gtk_im_context_gcin_class_init (GtkIMContextGCINClass *class);
71 static void gtk_im_context_gcin_init (GtkIMContextGCIN *im_context_gcin);
72 static void gtk_im_context_gcin_finalize (GObject *obj);
73 static void gtk_im_context_gcin_set_client_window (GtkIMContext *context,
74 GdkWindow *client_window);
75 static gboolean gtk_im_context_gcin_filter_keypress (GtkIMContext *context,
76 GdkEventKey *key);
77 static void gtk_im_context_gcin_reset (GtkIMContext *context);
78 static void gtk_im_context_gcin_focus_in (GtkIMContext *context);
79 static void gtk_im_context_gcin_focus_out (GtkIMContext *context);
80 static void gtk_im_context_gcin_set_cursor_location (GtkIMContext *context,
81 GdkRectangle *area);
82 static void gtk_im_context_gcin_set_use_preedit (GtkIMContext *context,
83 gboolean use_preedit);
84 static void gtk_im_context_gcin_get_preedit_string (GtkIMContext *context,
85 gchar **str,
86 PangoAttrList **attrs,
87 gint *cursor_pos);
88
89 // static GObjectClass *parent_class;
90
91 GType gtk_type_im_context_gcin = 0;
92
93 void
gtk_im_context_gcin_register_type(GTypeModule * type_module)94 gtk_im_context_gcin_register_type (GTypeModule *type_module)
95 {
96 static const GTypeInfo im_context_gcin_info =
97 {
98 sizeof (GtkIMContextGCINClass),
99 (GBaseInitFunc) NULL,
100 (GBaseFinalizeFunc) NULL,
101 (GClassInitFunc) gtk_im_context_gcin_class_init,
102 NULL, /* class_finalize */
103 NULL, /* class_data */
104 sizeof (GtkIMContextGCIN),
105 0,
106 (GInstanceInitFunc) gtk_im_context_gcin_init,
107 };
108
109 gtk_type_im_context_gcin =
110 g_type_module_register_type (type_module,
111 GTK_TYPE_IM_CONTEXT,
112 "GtkIMContextGCIN",
113 &im_context_gcin_info, 0);
114 }
115
116 static void
reinitialize_all_ics(GtkGCINInfo * info)117 reinitialize_all_ics (GtkGCINInfo *info)
118 {
119 #if DBG
120 puts("reinitialize_all_ics");
121 #endif
122 }
123
124 #if 0
125 static void gcin_display_closed (GdkDisplay *display,
126 gboolean is_error,
127 GtkIMContextGCIN *context_xim)
128 {
129 #if DBG
130 puts("gcin_display_closed");
131 #endif
132 if (!context_xim->gcin_ch)
133 return;
134
135 gcin_im_client_close(context_xim->gcin_ch);
136 context_xim->gcin_ch = NULL;
137 }
138 #endif
139
140 GdkScreen *gdk_window_get_screen (GdkWindow *window);
141
142 static void
get_im(GtkIMContextGCIN * context_xim)143 get_im (GtkIMContextGCIN *context_xim)
144 {
145 GdkWindow *client_window = context_xim->client_window;
146 if (!client_window)
147 return;
148 GdkScreen *screen = gdk_window_get_screen (client_window);
149 if (!screen)
150 return;
151
152 GdkDisplay *display = gdk_screen_get_display (screen);
153 if (!display)
154 return;
155
156 #if DBG
157 setbuf(stdout, NULL);
158 #endif
159
160 if (!context_xim->gcin_ch) {
161 if (!(context_xim->gcin_ch = gcin_im_client_open(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()))))
162 perror("cannot open gcin_ch");
163 #if 1
164 context_xim->timeout_handle = 0;
165 context_xim->pe_attN = 0;
166 context_xim->pe_att = NULL;
167 context_xim->pe_str = NULL;
168 context_xim->pe_cursor = 0;
169 context_xim->pe_started = FALSE;
170 #endif
171
172 char tt[128];
173 int len = readlink("/proc/self/exe", tt, sizeof(tt));
174 if (len>0) {
175 tt[len]=0;
176 if (strstr(tt, "chrome"))
177 context_xim->flags = FLAG_CHROME;
178 else if (strstr(tt, "firefox"))
179 context_xim->flags = FLAG_FIREFOX;
180 }
181
182 #if 0
183 // coredump
184 g_signal_connect (display, "closed",
185 G_CALLBACK (gcin_display_closed), context_xim);
186 #endif
187 }
188 }
189
190 ///
191 static void
gtk_im_context_gcin_class_init(GtkIMContextGCINClass * class)192 gtk_im_context_gcin_class_init (GtkIMContextGCINClass *class)
193 {
194 GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
195 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
196
197 // parent_class = g_type_class_peek_parent (class);
198 im_context_class->set_client_window = gtk_im_context_gcin_set_client_window;
199 im_context_class->filter_keypress = gtk_im_context_gcin_filter_keypress;
200 im_context_class->reset = gtk_im_context_gcin_reset;
201 im_context_class->get_preedit_string = gtk_im_context_gcin_get_preedit_string;
202 im_context_class->focus_in = gtk_im_context_gcin_focus_in;
203 im_context_class->focus_out = gtk_im_context_gcin_focus_out;
204 im_context_class->set_cursor_location = gtk_im_context_gcin_set_cursor_location;
205 im_context_class->set_use_preedit = gtk_im_context_gcin_set_use_preedit;
206 gobject_class->finalize = gtk_im_context_gcin_finalize;
207 }
208
209
210 static void
gtk_im_context_gcin_init(GtkIMContextGCIN * im_context_gcin)211 gtk_im_context_gcin_init (GtkIMContextGCIN *im_context_gcin)
212 {
213 im_context_gcin->timeout_handle = 0;
214 im_context_gcin->pe_attN = 0;
215 im_context_gcin->pe_att = NULL;
216 im_context_gcin->pe_str = NULL;
217 im_context_gcin->pe_cursor = 0;
218 im_context_gcin->gcin_ch = NULL;
219 // test_gdm();
220
221 #if DBG
222 printf("gtk_im_context_gcin_init %p\n", im_context_gcin);
223 #endif
224 // dirty hack for mozilla...
225 }
226
227
clear_preedit(GtkIMContextGCIN * context_gcin)228 void clear_preedit(GtkIMContextGCIN *context_gcin)
229 {
230 if (!context_gcin)
231 return;
232
233 if (context_gcin->pe_str) {
234 free(context_gcin->pe_str);
235 context_gcin->pe_str = NULL;
236 }
237
238 if (context_gcin->pe_att) {
239 free(context_gcin->pe_att);
240 context_gcin->pe_att = NULL;
241 context_gcin->pe_attN = 0;
242 }
243
244 context_gcin->pe_cursor = 0;
245 }
246
247
248 static void
gtk_im_context_gcin_finalize(GObject * obj)249 gtk_im_context_gcin_finalize (GObject *obj)
250 {
251 #if DBG
252 printf("gtk_im_context_gcin_finalize %p\n", obj);
253 #endif
254 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (obj);
255 clear_preedit(context_xim);
256
257 if (context_xim->gcin_ch) {
258 gcin_im_client_close(context_xim->gcin_ch);
259 context_xim->gcin_ch = NULL;
260 }
261 }
262
263
set_ic_client_window(GtkIMContextGCIN * context_xim,GdkWindow * client_window)264 static void set_ic_client_window (GtkIMContextGCIN *context_xim,
265 GdkWindow *client_window)
266 {
267 #if DBG
268 printf("set_ic_client_window %p %p\n", context_xim, client_window);
269 #endif
270 if (!client_window)
271 return;
272
273 context_xim->client_window = client_window;
274
275 if (context_xim->client_window) {
276 get_im (context_xim);
277 if (context_xim->gcin_ch) {
278 gcin_im_client_set_window(context_xim->gcin_ch, GDK_WINDOW_XID(client_window));
279 }
280 }
281 }
282
283
284 ///
285 static void
gtk_im_context_gcin_set_client_window(GtkIMContext * context,GdkWindow * client_window)286 gtk_im_context_gcin_set_client_window (GtkIMContext *context,
287 GdkWindow *client_window)
288 {
289 #if DBG
290 printf("gtk_im_context_gcin_set_client_window\n");
291 #endif
292 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (context);
293 set_ic_client_window (context_xim, client_window);
294 }
295
296 ///
297 GtkIMContext *
gtk_im_context_gcin_new(void)298 gtk_im_context_gcin_new (void)
299 {
300 #if DBG
301 printf("gtk_im_context_gcin_new\n");
302 #endif
303 GtkIMContextGCIN *result;
304
305 result = GTK_IM_CONTEXT_GCIN (g_object_new (GTK_TYPE_IM_CONTEXT_GCIN, NULL));
306
307 return GTK_IM_CONTEXT (result);
308 }
309
310 #include <gdk/gdkkeysyms.h>
311
312 #if 0
313 static gboolean open_gcin_win(int sub_comp_len, GtkIMContextGCIN *context_xim)
314 {
315 return !(context_xim->old_sub_comp_len & 1) && (sub_comp_len & 1)
316 || !(context_xim->old_sub_comp_len & 2) && (sub_comp_len & 2)
317 || !(context_xim->old_sub_comp_len & 4) && (sub_comp_len & 4);
318 }
319 #endif
320
321
322 ///
323 static gboolean
gtk_im_context_gcin_filter_keypress(GtkIMContext * context,GdkEventKey * event)324 gtk_im_context_gcin_filter_keypress (GtkIMContext *context,
325 GdkEventKey *event)
326 {
327 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (context);
328
329 gchar static_buffer[256];
330 unsigned char *buffer = static_buffer;
331 // char *buffer = static_buffer;
332 gint buffer_size = sizeof(static_buffer) - 1;
333 gsize num_bytes = 0;
334 KeySym keysym = 0;
335 Status status;
336 gboolean result = FALSE;
337 #if !GTK_CHECK_VERSION(3,0,0)
338 GdkWindow *root_window = gdk_screen_get_root_window (gdk_drawable_get_screen (event->window));
339 #else
340 GdkWindow *root_window = NULL;
341 GdkScreen *screen = gdk_window_get_screen (event->window);
342 if (screen)
343 root_window = gdk_screen_get_root_window (screen);
344 else
345 return result;
346 #endif
347
348 XKeyPressedEvent xevent;
349 xevent.type = (event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
350 xevent.serial = 0; /* hope it doesn't matter */
351 xevent.send_event = event->send_event;
352 xevent.display = GDK_WINDOW_XDISPLAY (event->window);
353 xevent.window = GDK_WINDOW_XID (event->window);
354 xevent.root = GDK_WINDOW_XID (root_window);
355 xevent.subwindow = xevent.window;
356 xevent.time = event->time;
357 xevent.x = xevent.x_root = 0;
358 xevent.y = xevent.y_root = 0;
359 xevent.state = event->state;
360 xevent.keycode = event->hardware_keycode;
361 xevent.same_screen = True;
362 num_bytes = XLookupString (&xevent, buffer, buffer_size, &keysym, NULL);
363
364 char *rstr = NULL;
365
366 #if (!FREEBSD || MAC_OS)
367 #if DBG
368 if (event->type == GDK_KEY_PRESS)
369 printf("kval %x %x\n",event->keyval, keysym);
370 #endif
371
372 int uni = gdk_keyval_to_unicode(event->keyval);
373 if (uni) {
374 gsize rn;
375 GError *err = NULL;
376 char *utf8 = g_convert((char *)&uni, 4, "UTF-8", "UTF-32", &rn, &num_bytes, &err);
377
378 if (utf8) {
379 // printf("conv %s\n", utf8);
380 strcpy(buffer, utf8);
381 g_free(utf8);
382 }
383 }
384 #endif
385
386 gboolean preedit_changed = FALSE;
387 gboolean context_pe_started = context_xim->pe_started;
388 gboolean context_has_str = context_xim->pe_str && context_xim->pe_str[0];
389 char *tstr = NULL;
390 int sub_comp_len = 0;
391 GCIN_PREEDIT_ATTR att[GCIN_PREEDIT_ATTR_MAX_N];
392 int cursor_pos;
393 gboolean has_str = FALSE;
394
395 if (event->type == GDK_KEY_PRESS) {
396 result = gcin_im_client_forward_key_press(context_xim->gcin_ch,
397 keysym, xevent.state, &rstr);
398 } else {
399 // printf("release %x %x\n", xevent.state, event->state);
400 result = gcin_im_client_forward_key_release(context_xim->gcin_ch,
401 keysym, xevent.state, &rstr);
402 }
403
404 preedit_changed = result;
405
406 int attN = gcin_im_client_get_preedit(context_xim->gcin_ch, &tstr, att, &cursor_pos, &sub_comp_len);
407 has_str = tstr && tstr[0];
408
409
410 #if DBG
411 printf("result keysym:%x %d sub_comp_len:%x tstr:%p\n", keysym, result, sub_comp_len, tstr);
412 #endif
413
414 if (sub_comp_len) {
415 has_str = TRUE;
416 // preedit_changed = TRUE;
417 }
418
419 context_xim->old_sub_comp_len = sub_comp_len;
420
421 if (!context_pe_started && has_str) {
422 #if DBG
423 printf("emit preedit-start\n");
424 #endif
425 #if 1
426 g_signal_emit_by_name (context, "preedit-start");
427 #endif
428 context_pe_started = context_xim->pe_started = TRUE;
429 preedit_changed = TRUE;
430 }
431
432 if (context_has_str != has_str || (tstr && context_xim->pe_str && strcmp(tstr, context_xim->pe_str))) {
433 if (context_xim->pe_str)
434 free(context_xim->pe_str);
435 context_xim->pe_str = tstr;
436 preedit_changed = TRUE;
437 }
438
439
440 int attsz = sizeof(GCIN_PREEDIT_ATTR)*attN;
441 if (context_xim->pe_attN != attN ||
442 context_xim->pe_att && memcmp(context_xim->pe_att, att, attsz)) {
443 // printf("att changed pe_att:%x:%d %d\n", context_xim->pe_att, context_xim->pe_attN, attN);
444 context_xim->pe_attN = attN;
445 if (context_xim->pe_att)
446 free(context_xim->pe_att);
447
448 context_xim->pe_att = NULL;
449 if (attN)
450 context_xim->pe_att = malloc(attsz);
451 memcpy(context_xim->pe_att, att, attsz);
452 // printf("context_xim->pe_att %x\n", context_xim->pe_att);
453 preedit_changed = TRUE;
454 }
455
456 if (context_xim->pe_cursor != cursor_pos) {
457 #if DBG
458 printf("cursor changed %d %d\n", context_xim->pe_cursor, cursor_pos);
459 #endif
460 context_xim->pe_cursor = cursor_pos;
461 preedit_changed = TRUE;
462 }
463
464 #if DBG
465 printf("seq:%d rstr:%s result:%d num_bytes:%d %x\n", context_xim->gcin_ch->seq, rstr, result, num_bytes, (unsigned int)buffer[0]);
466 #endif
467 if (event->type == GDK_KEY_PRESS && !rstr && !result && num_bytes &&
468 #if 1
469 buffer[0]>=0x20 && buffer[0]!=0x7f
470 #else
471 (event->keyval < 0xf000 || buffer[0]>=0x20 && buffer[0] < 0x7f)
472 #endif
473 && !(xevent.state & (Mod1Mask|ControlMask))) {
474 rstr = (char *)malloc(num_bytes + 1);
475 memcpy(rstr, buffer, num_bytes);
476 rstr[num_bytes] = 0;
477 result = TRUE;
478 }
479
480 #if 1
481 if (preedit_changed && (context_xim->flags & FLAG_FIREFOX)) {
482 #if DBG
483 printf("preedit-change\n");
484 #endif
485 g_signal_emit_by_name(context_xim, "preedit_changed");
486 }
487 #endif
488
489 #if DBG
490 printf("seq:%d event->type:%d iiiii %d %x %d rstr:%p\n",context_xim->gcin_ch->seq, event->type, result, keysym,
491 num_bytes, rstr);
492 #endif
493 if (rstr) {
494 #if DBG
495 printf("emit %s\n", rstr);
496 #endif
497 g_signal_emit_by_name (context_xim, "commit", rstr);
498 free(rstr);
499 }
500
501
502 if (!has_str && context_pe_started) {
503 clear_preedit(context_xim);
504 preedit_changed = FALSE;
505 context_xim->pe_started = FALSE;
506 #if DBG
507 printf("preedit-end %x\n", has_str);
508 #endif
509 #if 1
510 if (!(context_xim->flags & FLAG_CHROME))
511 g_signal_emit_by_name(context_xim, "preedit_changed");
512 #endif
513 #if 1
514 g_signal_emit_by_name (context_xim, "preedit-end");
515 #endif
516 }
517
518 #if 1
519 if (preedit_changed && !(context_xim->flags & FLAG_FIREFOX)) {
520 #if DBG
521 printf("preedit-change\n");
522 #endif
523 g_signal_emit_by_name(context_xim, "preedit_changed");
524 }
525 #endif
526
527
528 return result;
529 }
530
531 ///
532 static void
gtk_im_context_gcin_focus_in(GtkIMContext * context)533 gtk_im_context_gcin_focus_in (GtkIMContext *context)
534 {
535 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (context);
536 #if DBG
537 printf("gtk_im_context_gcin_focus_in\n");
538 #endif
539 if (context_xim->gcin_ch) {
540 gcin_im_client_focus_in(context_xim->gcin_ch);
541 }
542
543 return;
544 }
545
546 static void
gtk_im_context_gcin_focus_out(GtkIMContext * context)547 gtk_im_context_gcin_focus_out (GtkIMContext *context)
548 {
549 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (context);
550 // printf("gtk_im_context_gcin_focus_out\n");
551
552 if (context_xim->gcin_ch) {
553 char *rstr;
554 gcin_im_client_focus_out2(context_xim->gcin_ch , &rstr);
555 context_xim->pe_started = FALSE;
556
557 if (rstr) {
558 g_signal_emit_by_name (context, "commit", rstr);
559 clear_preedit(context_xim);
560 g_signal_emit_by_name(context, "preedit_changed");
561 free(rstr);
562 }
563
564 }
565
566 return;
567 }
568
569 ///
570 static void
gtk_im_context_gcin_set_cursor_location(GtkIMContext * context,GdkRectangle * area)571 gtk_im_context_gcin_set_cursor_location (GtkIMContext *context,
572 GdkRectangle *area)
573 {
574 #if DBG
575 printf("a gtk_im_context_gcin_set_cursor_location %d,%d,%d\n", area->x, area->y, area->height);
576 #endif
577 if (!area) {
578 return;
579 }
580
581
582 GtkIMContextGCIN *context_xim = GTK_IM_CONTEXT_GCIN (context);
583
584 if (!context_xim->gcin_ch) {
585 get_im(context_xim);
586 }
587
588 if (context_xim->gcin_ch) {
589 gcin_im_client_set_cursor_location(context_xim->gcin_ch, area->x, area->y + area->height);
590 }
591
592 #if DBG
593 printf("b gtk_im_context_gcin_set_cursor_location %d,%d,%d\n", area->x, area->y, area->height);
594 #endif
595
596 return;
597 }
598
599 ///
600 static void
gtk_im_context_gcin_set_use_preedit(GtkIMContext * context,gboolean use_preedit)601 gtk_im_context_gcin_set_use_preedit (GtkIMContext *context,
602 gboolean use_preedit)
603 {
604 GtkIMContextGCIN *context_gcin = GTK_IM_CONTEXT_GCIN (context);
605 #if DBG
606 printf("gtk_im_context_gcin_set_use_preedit %p %d\n", context_gcin->gcin_ch, use_preedit);
607 #endif
608 if (!context_gcin->gcin_ch)
609 return;
610 int ret;
611 if (use_preedit)
612 gcin_im_client_set_flags(context_gcin->gcin_ch, FLAG_GCIN_client_handle_use_preedit, &ret);
613 else
614 gcin_im_client_clear_flags(context_gcin->gcin_ch, FLAG_GCIN_client_handle_use_preedit, &ret);
615 }
616
617
618 ///
619 static void
gtk_im_context_gcin_reset(GtkIMContext * context)620 gtk_im_context_gcin_reset (GtkIMContext *context)
621 {
622 GtkIMContextGCIN *context_gcin = GTK_IM_CONTEXT_GCIN (context);
623 #if DBG
624 printf("gtk_im_context_gcin_reset %p\n", context_gcin);
625 #endif
626
627 context_gcin->pe_started = FALSE;
628 #if 1
629 if (context_gcin->gcin_ch) {
630 gcin_im_client_reset(context_gcin->gcin_ch);
631 if (context_gcin->pe_str && context_gcin->pe_str[0]) {
632 #if DBG
633 printf("clear %p\n", context_gcin);
634 #endif
635 clear_preedit(context_gcin);
636 g_signal_emit_by_name(context, "preedit_changed");
637 }
638 }
639 #endif
640 }
641
642 /* Mask of feedback bits that we render
643 */
644
645 static void
add_preedit_attr(PangoAttrList * attrs,const gchar * str,GCIN_PREEDIT_ATTR * att)646 add_preedit_attr (PangoAttrList *attrs,
647 const gchar *str, GCIN_PREEDIT_ATTR *att)
648 {
649 // printf("att %d %d\n", att->ofs0, att->ofs1);
650 PangoAttribute *attr;
651 gint start_index = g_utf8_offset_to_pointer (str, att->ofs0) - str;
652 gint end_index = g_utf8_offset_to_pointer (str, att->ofs1) - str;
653
654 if (att->flag & GCIN_PREEDIT_ATTR_FLAG_UNDERLINE)
655 {
656 attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
657 attr->start_index = start_index;
658 attr->end_index = end_index;
659 pango_attr_list_change (attrs, attr);
660 }
661
662 if (att->flag & GCIN_PREEDIT_ATTR_FLAG_REVERSE)
663 {
664 attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
665 attr->start_index = start_index;
666 attr->end_index = end_index;
667 pango_attr_list_change (attrs, attr);
668
669 attr = pango_attr_background_new (0, 0, 0);
670 attr->start_index = start_index;
671 attr->end_index = end_index;
672 pango_attr_list_change (attrs, attr);
673 }
674 }
675
676 static void
gtk_im_context_gcin_get_preedit_string(GtkIMContext * context,gchar ** str,PangoAttrList ** attrs,gint * cursor_pos)677 gtk_im_context_gcin_get_preedit_string (GtkIMContext *context,
678 gchar **str,
679 PangoAttrList **attrs,
680 gint *cursor_pos)
681 {
682 GtkIMContextGCIN *context_gcin = GTK_IM_CONTEXT_GCIN (context);
683
684 #if DBG
685 printf("gtk_im_context_gcin_get_preedit_string %p %p %p\n", str, attrs, cursor_pos);
686 #endif
687
688 if (context_gcin->gcin_ch && cursor_pos) {
689 int ret;
690 gcin_im_client_set_flags(context_gcin->gcin_ch, FLAG_GCIN_client_handle_use_preedit, &ret);
691 }
692
693 if (cursor_pos)
694 *cursor_pos = 0;
695
696 if (attrs)
697 *attrs = pango_attr_list_new ();
698
699 if (!str)
700 return;
701
702 #if 1
703 if (!context_gcin->gcin_ch) {
704 empty:
705 *str=g_strdup("");
706 return;
707 }
708
709 if (cursor_pos) {
710 *cursor_pos = context_gcin->pe_cursor;
711 }
712
713 if (context_gcin->pe_str) {
714 *str=g_strdup(context_gcin->pe_str);
715 } else {
716 goto empty;
717 }
718
719 #if DBG
720 printf("gtk_im_context_gcin_get_preedit_string %p attN:%d '%s'\n", context_gcin->pe_att,
721 context_gcin->pe_attN, *str);
722 #endif
723 int i;
724 if (attrs)
725 for(i=0; i < context_gcin->pe_attN; i++) {
726 add_preedit_attr(*attrs, *str, &(context_gcin->pe_att[i]));
727 }
728
729 #else
730 if (str)
731 *str = g_strdup("");
732 #endif
733 }
734
735
736 /**
737 * gtk_im_context_gcin_shutdown:
738 *
739 * Destroys all the status windows that are kept by the GCIN contexts. This
740 * function should only be called by the GCIN module exit routine.
741 **/
742 void
gtk_im_context_gcin_shutdown(void)743 gtk_im_context_gcin_shutdown (void)
744 {
745 #if DBG
746 printf("shutdown\n");
747 #endif
748 }
749