1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* IM-JA Japanese Input Method
3 *
4 * Copyright (C) 2003 Botond Botyanszki
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 *
20 * Based on ic.c from nabi by Choe Hwanjin
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <glib.h>
31 #include <gdk/gdkx.h>
32
33 #include "../error.h"
34 #include "../im-ja.h"
35 #include "../im-ja-impl.h"
36
37 #include "xim-ic.h"
38 #include "xim-server.h"
39 #include "xim-fontset.h"
40
41 extern IMJAXimServer *im_ja_xim_server;
42
43 static void im_ja_xim_ic_init_preedit(IMJAContext *ic);
44 /*static void debug_preedit(IMJAContext *ic);*/
45
46 #define streql(x, y) (strcmp((x), (y)) == 0)
47
48
im_ja_xim_connect_create(CARD16 id)49 IMJAXimConnect *im_ja_xim_connect_create(CARD16 id) {
50 IMJAXimConnect* connect;
51
52 IM_JA_DEBUG("im_ja_xim_connect_create\n");
53
54 connect = g_new0(IMJAXimConnect, 1);
55 connect->id = id;
56 connect->ic_list = NULL;
57 connect->next = NULL;
58
59 return connect;
60 }
61
im_ja_xim_connect_destroy(IMJAXimConnect * connect)62 void im_ja_xim_connect_destroy(IMJAXimConnect* connect) {
63 IMJAContext *ic;
64 GSList *list;
65
66 /* remove all input contexts */
67 list = connect->ic_list;
68 while (list != NULL) {
69 ic = (IMJAContext*)(list->data);
70 if (ic != NULL) im_ja_context_destroy(ic);
71 list = list->next;
72 }
73
74 g_slist_free(connect->ic_list);
75 g_free(connect);
76 }
77
im_ja_xim_connect_add_ic(IMJAXimConnect * connect,IMJAContext * ic)78 void im_ja_xim_connect_add_ic(IMJAXimConnect* connect, IMJAContext *ic) {
79 if (connect == NULL || ic == NULL) return;
80 connect->ic_list = g_slist_prepend(connect->ic_list, ic);
81 }
82
im_ja_xim_connect_remove_ic(IMJAXimConnect * connect,IMJAContext * ic)83 void im_ja_xim_connect_remove_ic(IMJAXimConnect* connect, IMJAContext *ic) {
84 if (connect == NULL || ic == NULL) return;
85 connect->ic_list = g_slist_remove(connect->ic_list, ic);
86 }
87
im_ja_xim_ic_init_values(IMJAContext * ic)88 void im_ja_xim_ic_init_values(IMJAContext *ic) {
89 IM_JA_DEBUG("im_ja_xim_ic_init_values\n");
90
91 ic->connect = im_ja_xim_server_get_connect_by_id(ic->connect_id);
92
93 /* preedit attr */
94 ic->preedit.width = 1; /* minimum window size is 1 x 1 */
95 ic->preedit.height = 1; /* minimum window size is 1 x 1 */
96 ic->preedit.foreground = im_ja_xim_server->preedit_fg;
97 ic->preedit.background = im_ja_xim_server->preedit_bg;
98 ic->preedit.state = XIMPreeditEnable;
99 ic->preedit.start = False;
100
101 /* set some sane values for the default colors */
102 if ((ic->original_colors[0].red == ic->original_colors[1].red)
103 && (ic->original_colors[0].green == ic->original_colors[1].green)
104 && (ic->original_colors[0].blue == ic->original_colors[1].blue)) {
105 IM_JA_DEBUG("**Warning** same fg and bg values\n");
106 ic->original_colors[0].red = 0xffff;
107 ic->original_colors[0].green = 0xffff;
108 ic->original_colors[0].blue = 0xffff;
109 ic->original_colors[1].red = 0;
110 ic->original_colors[1].green = 0;
111 ic->original_colors[1].blue = 0;
112 }
113
114 if (ic->prev_preedit_buf == NULL) {
115 ic->prev_preedit_buf = g_new0(gchar, BUFFERSIZE);
116 }
117 }
118
119
im_ja_xim_ic_is_destroyed(IMJAContext * ic)120 static gboolean im_ja_xim_ic_is_destroyed(IMJAContext *ic) {
121 if (ic->id > 0 && ic->id < im_ja_xim_server->ic_table_size) {
122 return im_ja_xim_server->ic_table[ic->id] == NULL;
123 }
124 else return TRUE;
125 }
126
127
im_ja_context_impl_destroy(IMJAContext * ic)128 void im_ja_context_impl_destroy(IMJAContext *ic) {
129 IM_JA_DEBUG("im_ja_context_impl_destroy\n");
130
131 if (im_ja_xim_ic_is_destroyed(ic)) return;
132
133 /* we do not delete, just save it in ic_freed */
134 if (im_ja_xim_server->ic_freed == NULL) {
135 im_ja_xim_server->ic_freed = ic;
136 im_ja_xim_server->ic_freed->next = NULL;
137 }
138 else {
139 ic->next = im_ja_xim_server->ic_freed;
140 im_ja_xim_server->ic_freed = ic;
141 }
142
143 im_ja_xim_server->ic_table[ic->id] = NULL;
144
145 ic->connect_id = 0;
146 ic->client_window = 0;
147 ic->focus_window = 0;
148 g_free(ic->resource_name);
149 ic->resource_name = NULL;
150 g_free(ic->resource_class);
151 ic->resource_class = NULL;
152
153 ic->connect = NULL;
154
155 ic->preedit.area.x = 0;
156 ic->preedit.area.y = 0;
157 ic->preedit.area.width = 0;
158 ic->preedit.area.height = 0;
159 ic->preedit.area_needed.x = 0;
160 ic->preedit.area_needed.y = 0;
161 ic->preedit.area_needed.width = 0;
162 ic->preedit.area_needed.height = 0;
163 ic->preedit.spot.x = 0;
164 ic->preedit.spot.y = 0;
165 ic->preedit.cmap = 0;
166
167 ic->preedit.width = 1;
168 ic->preedit.height = 1;
169 ic->preedit.ascent = 0;
170 ic->preedit.descent = 0;
171 ic->preedit.line_space = 0;
172 ic->preedit.cursor = 0;
173
174 ic->preedit.state = XIMPreeditEnable;
175 ic->preedit.start = False;
176
177 /* destroy preedit window */
178 if (ic->preedit.window != 0) {
179 XDestroyWindow(im_ja_xim_server->display, ic->preedit.window);
180 ic->preedit.window = 0;
181 /* XFreeGC ?? */
182 }
183
184 /* destroy fontset data */
185 if (ic->preedit.font_set) {
186 im_ja_xim_fontset_free(im_ja_xim_server->display, ic->preedit.font_set);
187 g_free(ic->preedit.base_font);
188 ic->preedit.font_set = NULL;
189 ic->preedit.base_font = NULL;
190 }
191
192 /* status attributes */
193 ic->status_attr.area.x = 0;
194 ic->status_attr.area.y = 0;
195 ic->status_attr.area.width = 0;
196 ic->status_attr.area.height = 0;
197
198 ic->status_attr.area_needed.x = 0;
199 ic->status_attr.area_needed.y = 0;
200 ic->status_attr.area_needed.width = 0;
201 ic->status_attr.area_needed.height = 0;
202
203 ic->status_attr.cmap = 0;
204 ic->status_attr.foreground = 0;
205 ic->status_attr.background = 0;
206 ic->status_attr.background = 0;
207 ic->status_attr.bg_pixmap = 0;
208 ic->status_attr.line_space = 0;
209 ic->status_attr.cursor = 0;
210 ic->status_attr.base_font = NULL;
211
212 }
213
214
215 /*
216 void im_ja_xim_ic_real_destroy(IMJAContext *ic) {
217 if (ic == NULL) return;
218
219 g_free(ic->resource_name);
220 g_free(ic->resource_class);
221 g_free(ic->preedit.base_font);
222 g_free(ic->status_attr.base_font);
223
224 if (ic->preedit.window != 0) {
225 XDestroyWindow(im_ja_xim_server->display, ic->preedit.window);
226 }
227 if (ic->preedit.font_set) {
228 im_ja_xim_fontset_free(im_ja_xim_server->display, ic->preedit.font_set);
229 }
230
231 if (ic->preedit.gc) XFreeGC(im_ja_xim_server->display, ic->preedit.gc);
232
233 g_free(ic);
234 }
235 */
236
237
im_ja_xim_ic_preedit_show(IMJAContext * ic)238 void im_ja_xim_ic_preedit_show(IMJAContext *ic) {
239 IM_JA_DEBUG("im_ja_xim_ic_preedit_show\n");
240 im_ja_xim_ic_init_preedit(ic);
241 if (ic->preedit.window == 0) {
242 IM_JA_DEBUG(" error: no preedit.window!\n");
243 return;
244 }
245
246 if (strlen(ic->preedit_buf) > 0) {
247 XFlush(im_ja_xim_server->display);
248 XMapRaised(im_ja_xim_server->display, ic->preedit.window);
249 /*debug_preedit(ic);*/
250 }
251 }
252
253 /*
254 static void im_ja_xim_ic_preedit_hide(IMJAContext *ic) {
255 if (ic->preedit.window == 0) return;
256
257 XUnmapWindow(im_ja_xim_server->display, ic->preedit.window);
258 }
259 */
260
261 /* move and resize preedit window */
im_ja_xim_ic_preedit_configure(IMJAContext * ic)262 static void im_ja_xim_ic_preedit_configure(IMJAContext *ic) {
263 IM_JA_DEBUG("im_ja_xim_ic_preedit_configure\n");
264
265 im_ja_xim_ic_init_preedit(ic);
266 if (ic->preedit.window == 0) {
267 IM_JA_DEBUG(" no preedit window!\n");
268 return;
269 }
270
271 IM_JA_DEBUG(" move&resize preedit\n");
272 XMoveResizeWindow(im_ja_xim_server->display, ic->preedit.window,
273 ic->preedit.spot.x - 1, /* -1 is for hiding the cursor of the window (hack ?) */
274 ic->preedit.spot.y - ic->preedit.ascent,
275 ic->preedit.width,
276 ic->preedit.height);
277 }
278
279 /*
280 static void debug_preedit(IMJAContext *ic) {
281 XWindowAttributes attribs;
282
283 if (ic->preedit.window == 0) {
284 IM_JA_DEBUG(" NO PREEDIT WINDOW\n");
285 return;
286 }
287
288 XGetWindowAttributes(im_ja_xim_server->display, ic->preedit.window, &attribs);
289
290 IM_JA_DEBUG(" PREEDIT WINDOW:\n");
291 IM_JA_DEBUG(" X: %d", attribs.x);
292 IM_JA_DEBUG(" Y: %d", attribs.y);
293 IM_JA_DEBUG(" WIDTH: %d", attribs.width);
294 IM_JA_DEBUG(" HEIGHT: %d", attribs.height);
295 IM_JA_DEBUG(" MAP STATE: ");
296 switch (attribs.map_state) {
297 case IsUnmapped:
298 IM_JA_DEBUG("Unmapped");
299 break;
300 case IsUnviewable:
301 IM_JA_DEBUG("Unviewable");
302 break;
303 case IsViewable:
304 IM_JA_DEBUG("Viewable");
305 break;
306 }
307
308
309 IM_JA_DEBUG("\n PREEDIT AREA:\n");
310 IM_JA_DEBUG(" X: %d", ic->preedit.area.x);
311 IM_JA_DEBUG(" Y: %d", ic->preedit.area.y);
312 IM_JA_DEBUG(" WIDTH: %d", ic->preedit.area.width);
313 IM_JA_DEBUG(" HEIGHT: %d\n", ic->preedit.area.height);
314
315 IM_JA_DEBUG(" SPOT:\n");
316 IM_JA_DEBUG(" X: %d", ic->preedit.spot.x);
317 IM_JA_DEBUG(" Y: %d\n", ic->preedit.spot.y);
318
319 IM_JA_DEBUG(" PREEDIT :\n");
320 IM_JA_DEBUG(" WIDTH: %d", ic->preedit.width);
321 IM_JA_DEBUG(" HEIGHT: %d\n", ic->preedit.height);
322 IM_JA_DEBUG(" ASCENT: %d", ic->preedit.ascent);
323 IM_JA_DEBUG(" DESCENT: %d\n", ic->preedit.descent);
324
325 }
326 */
327
328 /*
329 static void im_ja_preedit_area_update_attribs(IMJAContext *ic) {
330 XWindowAttributes attribs;
331
332 if (ic->preedit.window == 0) return;
333
334 XGetWindowAttributes(im_ja_xim_server->display, ic->preedit.window, &attribs);
335 ic->preedit.area.x = attribs.x;
336 ic->preedit.area.y = attribs.y;
337 ic->preedit.area.width = attribs.width;
338 ic->preedit.area.height = attribs.height;
339
340 }
341 */
342
im_ja_xim_ic_preedit_draw(IMJAContext * ic)343 void im_ja_xim_ic_preedit_draw(IMJAContext *ic) {
344 int width;
345 int cursor_pos;
346
347 /*
348 FIXME: GTKify this if possible:
349 - use preeditarea
350 - implement im_ja_xim_get_preedit_string() and use that
351 instead of directly accessing preedit_buf
352 */
353
354 /* FIXME2: this cannot draw multi line preedit
355 */
356
357 IM_JA_DEBUG("im_ja_xim_ic_preedit_draw\n");
358 if (strlen(ic->preedit_buf) == 0) return;
359
360 if (ic->preedit.window == 0) {
361 /* im_ja_xim_ic_preedit_window_new(ic); */
362 }
363
364 if (ic->preedit.font_set == 0) {
365 IM_JA_DEBUG(" NO PREEDIT FONTSET\n");
366 return;
367 }
368
369 if (ic->preedit.gc == 0) {
370 IM_JA_DEBUG(" NO PREEDIT GC\n");
371 return;
372 }
373
374 width = Xutf8TextEscapement(ic->preedit.font_set, ic->preedit_buf, strlen(ic->preedit_buf));
375 cursor_pos = Xutf8TextEscapement(ic->preedit.font_set, ic->preedit_buf, im_ja_get_cursor_pos_bytes(ic));
376
377 if (ic->preedit.width != width) {
378 ic->preedit.width = width;
379 ic->preedit.height = ic->preedit.ascent + ic->preedit.descent;
380 IM_JA_DEBUG(" resize preedit to %d x %d\n", ic->preedit.width, ic->preedit.height);
381 XResizeWindow(im_ja_xim_server->display, ic->preedit.window, ic->preedit.width, ic->preedit.height);
382 }
383
384 /* if preedit window is out of focus window
385 we force to put it in focus window (preedit.area) */
386 if (ic->preedit.spot.x + ic->preedit.width > ic->preedit.area.width) {
387 ic->preedit.spot.x = ic->preedit.area.width - ic->preedit.width;
388 XMoveWindow(im_ja_xim_server->display, ic->preedit.window,
389 ic->preedit.spot.x, ic->preedit.spot.y - ic->preedit.ascent);
390 }
391
392 /* debug_preedit(ic); */
393
394 Xutf8DrawString(im_ja_xim_server->display,
395 ic->preedit.window,
396 ic->preedit.font_set,
397 ic->preedit.gc,
398 0,
399 ic->preedit.ascent,
400 ic->preedit_buf,
401 strlen(ic->preedit_buf));
402
403 if (ic->preedit_reverse_start != ic->preedit_reverse_end) {
404 int reverse_start_pos;
405 int reverse_end_pos;
406 int reverse_length;
407
408 reverse_length = ic->preedit_reverse_end - ic->preedit_reverse_start;
409 reverse_start_pos = Xutf8TextEscapement(ic->preedit.font_set, ic->preedit_buf, ic->preedit_reverse_start);
410 reverse_end_pos = Xutf8TextEscapement(ic->preedit.font_set, ic->preedit_buf, ic->preedit_reverse_end);
411
412 /*
413 IM_JA_DEBUG("REVERSE LENGTH: %d\n", reverse_length);
414 IM_JA_DEBUG("REVERSE START POS: %d\n", reverse_start_pos);
415 IM_JA_DEBUG("REVERSE STRING: %s\n", ic->preedit_buf + ic->preedit_reverse_start);
416 */
417
418 XFillRectangle(im_ja_xim_server->display,
419 ic->preedit.window,
420 ic->preedit.gc,
421 reverse_start_pos,
422 0,
423 reverse_end_pos - reverse_start_pos,
424 ic->preedit.ascent + ic->preedit.descent);
425
426 Xutf8DrawString(im_ja_xim_server->display,
427 ic->preedit.window,
428 ic->preedit.font_set,
429 ic->preedit.reverse_gc,
430 reverse_start_pos,
431 ic->preedit.ascent,
432 ic->preedit_buf + ic->preedit_reverse_start,
433 reverse_length);
434 }
435
436 if (cursor_pos >= ic->preedit.width) cursor_pos--;
437
438 XFillRectangle(im_ja_xim_server->display,
439 ic->preedit.window,
440 ic->preedit.gc,
441 cursor_pos,
442 0,
443 1,
444 ic->preedit.ascent + ic->preedit.descent);
445
446 XDrawLine(im_ja_xim_server->display,
447 ic->preedit.window,
448 ic->preedit.gc,
449 0,
450 ic->preedit.ascent + ic->preedit.descent - 1,
451 ic->preedit.width - 1,
452 ic->preedit.ascent + ic->preedit.descent - 1);
453
454 XFlush(im_ja_xim_server->display);
455
456 }
457
im_ja_xim_ic_preedit_event_filter(GdkXEvent * xevent,GdkEvent * gevent,gpointer data)458 static GdkFilterReturn im_ja_xim_ic_preedit_event_filter(GdkXEvent *xevent, GdkEvent *gevent, gpointer data) {
459 IMJAContext *ic = (IMJAContext *)data;
460 XEvent *event = (XEvent*)xevent;
461
462 IM_JA_DEBUG("im_ja_xim_preedit_event_filter\n");
463
464 if (ic == NULL) return GDK_FILTER_REMOVE;
465 if (ic->preedit.window == 0) return GDK_FILTER_REMOVE;
466
467 if (event->xany.window != ic->preedit.window) return GDK_FILTER_CONTINUE;
468
469 switch (event->type) {
470 case DestroyNotify:
471 IM_JA_DEBUG("DESTROYNOTIFY\n");
472 if (!im_ja_xim_ic_is_destroyed(ic)) {
473 /* preedit window is destroyed, so we set it 0 */
474 ic->preedit.window = 0;
475 im_ja_context_destroy(ic);
476 }
477 return GDK_FILTER_REMOVE;
478 break;
479 case Expose:
480 IM_JA_DEBUG("Redraw Window\n");
481 im_ja_xim_ic_preedit_draw(ic);
482 break;
483 default:
484 IM_JA_DEBUG("event type: %d\n", event->type);
485 break;
486 }
487
488 return GDK_FILTER_CONTINUE;
489 }
490
491
im_ja_xim_ic_preedit_window_new(IMJAContext * ic)492 static void im_ja_xim_ic_preedit_window_new(IMJAContext *ic) {
493 GdkWindow *gdk_window;
494 Window parent = 0;
495 XSetWindowAttributes attr;
496
497 IM_JA_DEBUG("im_ja_xim_ic_preedit_window_new()\n");
498
499 if (ic->focus_window != 0) {
500 parent = ic->focus_window;
501 IM_JA_DEBUG(" using focus_window as parent\n");
502 }
503 else if (ic->client_window != 0) {
504 parent = ic->client_window;
505 IM_JA_DEBUG(" using client_window as parent\n");
506 }
507 /*
508 else {
509 parent = DefaultRootWindow(im_ja_xim_server->display);
510 IM_JA_DEBUG(" using root_window as parent\n");
511 }
512 */
513
514 if (parent == 0) {
515 IM_JA_DEBUG(" ERROR: no parent!\n");
516 return;
517 }
518
519 IM_JA_DEBUG(" creating %d x %d\n", ic->preedit.width, ic->preedit.height);
520
521 ic->preedit.window = XCreateSimpleWindow(im_ja_xim_server->display,
522 parent,
523 ic->preedit.spot.x,
524 ic->preedit.spot.y - ic->preedit.ascent,
525 ic->preedit.width,
526 ic->preedit.height,
527 0,
528 im_ja_xim_server->preedit_fg, /* FIXME */
529 im_ja_xim_server->preedit_bg); /* FIXME */
530
531 attr.override_redirect = True;
532 XChangeWindowAttributes(im_ja_xim_server->display, ic->preedit.window, CWOverrideRedirect,
533 &attr);
534
535 XSelectInput(im_ja_xim_server->display, ic->preedit.window,
536 ExposureMask | StructureNotifyMask);
537
538 /* install our preedit window event filter */
539 gdk_window = gdk_window_foreign_new(ic->preedit.window);
540 if (gdk_window != NULL) {
541 gdk_window_add_filter(gdk_window, im_ja_xim_ic_preedit_event_filter, (gpointer)ic);
542 g_object_unref(gdk_window);
543 }
544 IM_JA_DEBUG(" done.\n");
545 }
546
im_ja_xim_preedit_create_gc(IMJAContext * ic)547 static void im_ja_xim_preedit_create_gc(IMJAContext *ic) {
548 if (ic->preedit.gc == 0) {
549 XGCValues values;
550
551 values.foreground = im_ja_xim_server->preedit_fg;
552 values.background = im_ja_xim_server->preedit_bg;
553
554 ic->preedit.gc = XCreateGC(im_ja_xim_server->display,
555 im_ja_xim_server->window,
556 GCForeground | GCBackground,
557 &values);
558 }
559
560 if (ic->preedit.reverse_gc == 0) {
561 XGCValues rev_values;
562
563 rev_values.background = im_ja_xim_server->preedit_fg;
564 rev_values.foreground = im_ja_xim_server->preedit_bg;
565
566 /*
567 //rev_values.background = im_ja_xim_server->preedit_bg;
568 //rev_values.foreground = im_ja_xim_server->preedit_fg;
569 */
570 ic->preedit.reverse_gc = XCreateGC(im_ja_xim_server->display,
571 im_ja_xim_server->window,
572 GCForeground | GCBackground,
573 &rev_values);
574 }
575
576 }
577
im_ja_xim_ic_init_preedit(IMJAContext * ic)578 static void im_ja_xim_ic_init_preedit(IMJAContext *ic) {
579 IM_JA_DEBUG("im_ja_xim_ic_init_preedit()\n");
580 if (ic->input_style & XIMPreeditPosition) {
581 if ((ic->preedit.gc == 0) || (ic->preedit.reverse_gc == 0)) {
582 im_ja_xim_preedit_create_gc(ic);
583 }
584
585 /* For Preedit Position aka Over the Spot */
586 if (ic->preedit.window == 0) {
587 im_ja_xim_ic_preedit_window_new(ic);
588 }
589 }
590 }
591
im_ja_xim_ic_set_focus_window(IMJAContext * ic,Window focus_window)592 static void im_ja_xim_ic_set_focus_window(IMJAContext *ic, Window focus_window) {
593 XWindowAttributes attribs;
594
595 /* FIXME: focus window is client window (in gtkimcontext)?? */
596 IM_JA_DEBUG("im_ja_xim_ic_set_focus_window\n");
597
598
599 XGetWindowAttributes(im_ja_xim_server->display, focus_window, &attribs);
600
601 IM_JA_DEBUG(" FOCUS WINDOW: ");
602 IM_JA_DEBUG(" X: %d", attribs.x);
603 IM_JA_DEBUG(" Y: %d", attribs.y);
604 IM_JA_DEBUG(" WIDTH: %d", attribs.width);
605 IM_JA_DEBUG(" HEIGHT: %d\n", attribs.height);
606
607 ic->focus_window = focus_window;
608 im_ja_xim_ic_init_preedit(ic);
609 }
610
im_ja_xim_ic_set_preedit_foreground(IMJAContext * ic,unsigned long foreground)611 static void im_ja_xim_ic_set_preedit_foreground(IMJAContext *ic, unsigned long foreground) { /* FIXME: use conf */
612 IM_JA_DEBUG("im_ja_xim_ic_set_preedit_foreground: %d\n", (int) foreground);
613
614 /* foreground = im_ja_xim_server->preedit_fg; */
615 im_ja_xim_server->preedit_fg = foreground;
616 ic->preedit.foreground = foreground;
617
618 if (ic->focus_window == 0) return;
619
620 if ((ic->preedit.gc == 0) || (ic->preedit.reverse_gc == 0)) {
621 im_ja_xim_preedit_create_gc(ic);
622 }
623
624 XSetForeground(im_ja_xim_server->display, ic->preedit.gc, ic->preedit.foreground);
625
626 /* XSetForeground(im_ja_xim_server->display, ic->preedit.reverse_gc, ic->preedit.foreground); */
627 XSetBackground(im_ja_xim_server->display, ic->preedit.reverse_gc, ic->preedit.foreground);
628
629 }
630
631
im_ja_xim_ic_set_preedit_background(IMJAContext * ic,unsigned long background)632 static void im_ja_xim_ic_set_preedit_background(IMJAContext *ic, unsigned long background) { /* FIXME: use conf */
633 IM_JA_DEBUG("im_ja_xim_ic_set_preedit_background: %d\n", (int) background);
634
635 /* background = im_ja_xim_server->preedit_bg; */
636 im_ja_xim_server->preedit_bg = background;
637 ic->preedit.background = background;
638
639 if (ic->focus_window == 0) return;
640
641 if ((ic->preedit.gc == 0) || (ic->preedit.reverse_gc == 0)) {
642 im_ja_xim_preedit_create_gc(ic);
643 }
644
645 XSetBackground(im_ja_xim_server->display, ic->preedit.gc, ic->preedit.background);
646
647 /* XSetBackground(im_ja_xim_server->display, ic->preedit.reverse_gc, ic->preedit.background); */
648 XSetForeground(im_ja_xim_server->display, ic->preedit.reverse_gc, ic->preedit.background);
649
650 }
651
652
im_ja_xim_ic_load_preedit_fontset(IMJAContext * ic,char * font_name)653 static void im_ja_xim_ic_load_preedit_fontset(IMJAContext *ic, char *font_name) {
654 IMJAXimFontSet *fontset;
655
656 IM_JA_DEBUG("im_ja_xim_ic_load_preedit_fontset\n");
657
658 if (ic->preedit.base_font != NULL && strcmp(ic->preedit.base_font, font_name) == 0) {
659 /* same font, do not create fontset */
660 return;
661 }
662
663 if (ic->preedit.base_font != NULL) g_free(ic->preedit.base_font);
664 ic->preedit.base_font = g_strdup(font_name);
665 if (ic->preedit.font_set) im_ja_xim_fontset_free(im_ja_xim_server->display, ic->preedit.font_set);
666
667 fontset = im_ja_xim_fontset_create(im_ja_xim_server->display, font_name);
668 if (fontset == NULL) {
669 IM_JA_DEBUG("WARNING: FONTSET == NULL\n");
670 return;
671 }
672
673 ic->preedit.font_set = fontset->xfontset;
674 ic->preedit.ascent = fontset->ascent;
675 ic->preedit.descent = fontset->descent;
676 ic->preedit.height = ic->preedit.ascent + ic->preedit.descent;
677 ic->preedit.width = 1;
678 }
679
680
im_ja_xim_ic_set_spot(IMJAContext * ic,XPoint * point)681 static void im_ja_xim_ic_set_spot(IMJAContext *ic, XPoint *point) {
682
683 IM_JA_DEBUG("im_ja_xim_ic_set_spot\n");
684
685 if (point == NULL) return;
686
687 ic->preedit.spot.x = point->x + 1;
688 ic->preedit.spot.y = point->y;
689
690 IM_JA_DEBUG(" X: %d, Y: %d\n", ic->preedit.spot.x, ic->preedit.spot.y);
691
692 im_ja_cursor_location_changed(ic, ic->preedit.spot.x, ic->preedit.spot.y + 3);
693
694
695 /* if preedit window is out of focus window
696 * we force it in focus window (preedit.area) */
697 if (ic->preedit.spot.x + ic->preedit.width > ic->preedit.area.width) {
698 ic->preedit.spot.x = ic->preedit.area.width - ic->preedit.width;
699 }
700
701 im_ja_xim_ic_preedit_configure(ic);
702
703 /* FIXME
704 if (im_ja_xim_ic_is_empty(ic)) im_ja_xim_ic_preedit_hide(ic);
705 else
706 */
707 im_ja_xim_ic_preedit_show(ic);
708
709 }
710 /*
711 XIMPreeditCallbacks | XIMStatusCallbacks,
712 XIMPreeditCallbacks | XIMStatusArea,
713 XIMPreeditCallbacks | XIMStatusNothing,
714
715 XIMPreeditPosition | XIMStatusCallbacks,
716 XIMPreeditPosition | XIMStatusArea,
717 XIMPreeditPosition | XIMStatusNothing,
718
719 XIMPreeditArea | XIMStatusCallbacks,
720 XIMPreeditArea | XIMStatusArea,
721 XIMPreeditArea | XIMStatusNothing,
722
723 XIMPreeditNothing | XIMStatusNothing,
724 */
725
im_ja_xim_ic_set_client_window(IMJAContext * ic,Window win)726 static void im_ja_xim_ic_set_client_window(IMJAContext *ic, Window win) {
727 XWindowAttributes attribs;
728 GdkWindow *gdk_window;
729
730 IM_JA_DEBUG("im_ja_xim_ic_set_client_window\n");
731
732 ic->client_window = win;
733
734 if (ic->client_window == 0) {
735 IM_JA_DEBUG(" NO CLIENT WINDOW\n");
736 return;
737 }
738
739 XGetWindowAttributes(im_ja_xim_server->display, ic->client_window, &attribs);
740
741 IM_JA_DEBUG(" CLIENT WINDOW: ");
742 IM_JA_DEBUG(" X: %d", attribs.x);
743 IM_JA_DEBUG(" Y: %d", attribs.y);
744 IM_JA_DEBUG(" WIDTH: %d", attribs.width);
745 IM_JA_DEBUG(" HEIGHT: %d\n", attribs.height);
746
747 gdk_window = gdk_window_foreign_new(ic->client_window);
748 if (gdk_window != NULL) {
749 gdk_window_add_filter(gdk_window, im_ja_xim_ic_preedit_event_filter, (gpointer)ic);
750 g_object_unref(gdk_window);
751 }
752
753 }
754
755
print_xim_styles(XIMStyle style)756 static void print_xim_styles(XIMStyle style) {
757
758 IM_JA_DEBUG(" Supported styles:\n");
759 if (style & XIMPreeditCallbacks) IM_JA_DEBUG(" XIMPreeditCallbacks\n");
760 if (style & XIMPreeditPosition) IM_JA_DEBUG(" XIMPreeditPosition\n");
761 if (style & XIMPreeditArea) IM_JA_DEBUG(" XIMPreeditArea\n");
762 if (style & XIMPreeditNothing) IM_JA_DEBUG(" XIMPreeditNothing\n");
763
764 if (style & XIMStatusCallbacks) IM_JA_DEBUG(" XIMStatusCallbacks\n");
765 if (style & XIMStatusArea) IM_JA_DEBUG(" XIMStatusArea\n");
766 if (style & XIMStatusNothing) IM_JA_DEBUG(" XIMStatusNothing\n");
767 }
768
769
im_ja_xim_ic_set_values(IMJAContext * ic,IMChangeICStruct * data)770 void im_ja_xim_ic_set_values(IMJAContext *ic, IMChangeICStruct *data) {
771
772 XICAttribute *ic_attr = data->ic_attr;
773 XICAttribute *preedit_attr = data->preedit_attr;
774 XICAttribute *status_attr = data->status_attr;
775 CARD16 i;
776
777 IM_JA_DEBUG("im_ja_xim_ic_set_values\n");
778
779 if (ic == NULL) return;
780
781 for (i = 0; i < data->ic_attr_num; i++, ic_attr++) {
782 IM_JA_DEBUG(" ic attribute: %s\n", ic_attr->name);
783 if (streql(XNInputStyle, ic_attr->name)) {
784 ic->input_style = *(INT32*)ic_attr->value;
785 print_xim_styles(ic->input_style);
786 if (ic->input_style & XIMPreeditNothing) im_ja_set_use_preedit(ic, TRUE);
787 im_ja_xim_ic_init_preedit(ic);
788
789 }
790 else if (streql(XNClientWindow, ic_attr->name)) {
791 im_ja_xim_ic_set_client_window(ic, *(Window*)ic_attr->value);
792 }
793 else if (streql(XNFocusWindow, ic_attr->name)) {
794 im_ja_xim_ic_set_focus_window(ic, *(Window*)ic_attr->value);
795 }
796 else {
797 g_error("im_ja_xim: set unknown ic attribute: %s\n", ic_attr->name);
798 }
799 }
800
801 for (i = 0; i < data->preedit_attr_num; i++, preedit_attr++) {
802 IM_JA_DEBUG(" preedit attribute: %s\n", preedit_attr->name);
803 if (streql(XNSpotLocation, preedit_attr->name)) {
804 im_ja_xim_ic_set_spot(ic, (XPoint*)preedit_attr->value);
805 }
806 else if (streql(XNForeground, preedit_attr->name)) {
807 im_ja_xim_ic_set_preedit_foreground(ic, *(unsigned long*)preedit_attr->value);
808 }
809 else if (streql(XNBackground, preedit_attr->name)) {
810 im_ja_xim_ic_set_preedit_background(ic, *(unsigned long*)preedit_attr->value);
811 }
812 else if (streql(XNArea, preedit_attr->name)) {
813 ic->preedit.area = *(XRectangle*)preedit_attr->value;
814 }
815 else if (streql(XNLineSpace, preedit_attr->name)) {
816 ic->preedit.line_space = *(CARD32*)preedit_attr->value;
817 }
818 else if (streql(XNPreeditState, preedit_attr->name)) {
819 ic->preedit.state = *(XIMPreeditState*)preedit_attr->value;
820 }
821 else if (streql(XNFontSet, preedit_attr->name)) {
822 im_ja_xim_ic_load_preedit_fontset(ic, (char*)preedit_attr->value);
823 }
824 else {
825 g_print("Im_Ja_Xim: set unknown preedit attribute: %s\n",
826 preedit_attr->name);
827 }
828 }
829
830 for (i = 0; i < data->status_attr_num; i++, status_attr++) {
831 IM_JA_DEBUG(" status attribute: %s\n", status_attr->name);
832 if (streql(XNArea, status_attr->name)) {
833 ic->status_attr.area = *(XRectangle*)status_attr->value;
834 }
835 else if (streql(XNAreaNeeded, status_attr->name)) {
836 ic->status_attr.area_needed = *(XRectangle*)status_attr->value;
837 }
838 else if (streql(XNForeground, status_attr->name)) {
839 ic->status_attr.foreground = *(unsigned long*)status_attr->value;
840 }
841 else if (streql(XNBackground, status_attr->name)) {
842 ic->status_attr.background = *(unsigned long*)status_attr->value;
843 }
844 else if (streql(XNLineSpace, status_attr->name)) {
845 ic->status_attr.line_space = *(CARD32*)status_attr->value;
846 }
847 else if (streql(XNFontSet, status_attr->name)) {
848 g_free(ic->status_attr.base_font);
849 ic->status_attr.base_font = g_strdup((char*)status_attr->value);
850 }
851 else {
852 g_print("Im_Ja_Xim: set unknown status attributes: %s\n", status_attr->name);
853 }
854 }
855 }
856
857
im_ja_xim_ic_get_values(IMJAContext * ic,IMChangeICStruct * data)858 void im_ja_xim_ic_get_values(IMJAContext *ic, IMChangeICStruct *data) {
859 XICAttribute *ic_attr = data->ic_attr;
860 XICAttribute *preedit_attr = data->preedit_attr;
861 XICAttribute *status_attr = data->status_attr;
862 CARD16 i;
863
864 IM_JA_DEBUG("im_ja_xim_ic_get_values\n");
865
866 if (ic == NULL) return;
867
868
869 for (i = 0; i < data->ic_attr_num; i++, ic_attr++) {
870 IM_JA_DEBUG(" ic attribute: %s\n", ic_attr->name);
871 if (streql(XNFilterEvents, ic_attr->name)) {
872 ic_attr->value = (void *)malloc(sizeof(CARD32));
873 *(CARD32*)ic_attr->value = KeyPressMask | KeyReleaseMask;
874 ic_attr->value_length = sizeof(CARD32);
875 }
876 else if (streql(XNInputStyle, ic_attr->name)) {
877 ic_attr->value = (void *)malloc(sizeof(INT32));
878 *(INT32*)ic_attr->value = ic->input_style;
879 ic_attr->value_length = sizeof(INT32);
880 }
881 else if (streql(XNSeparatorofNestedList, ic_attr->name)) {
882 /* FIXME: what do I do here? */
883 ;
884 }
885 else {
886 g_error("im_ja_xim: get unknown ic attribute: %s\n", ic_attr->name);
887 }
888 }
889
890 for (i = 0; i < data->preedit_attr_num; i++, preedit_attr++) {
891 IM_JA_DEBUG(" preedit attribute: %s\n", preedit_attr->name);
892 if (streql(XNArea, preedit_attr->name)) {
893 preedit_attr->value = (void *)malloc(sizeof(XRectangle));
894 *(XRectangle*)preedit_attr->value = ic->preedit.area;
895 preedit_attr->value_length = sizeof(XRectangle);
896 }
897 else if (streql(XNAreaNeeded, preedit_attr->name)) {
898 preedit_attr->value = (void *)malloc(sizeof(XRectangle));
899 *(XRectangle*)preedit_attr->value = ic->preedit.area_needed;
900 preedit_attr->value_length = sizeof(XRectangle);
901 }
902 else if (streql(XNSpotLocation, preedit_attr->name)) {
903 preedit_attr->value = (void *)malloc(sizeof(XPoint));
904 *(XPoint*)preedit_attr->value = ic->preedit.spot;
905 preedit_attr->value_length = sizeof(XPoint);
906 }
907 else if (streql(XNForeground, preedit_attr->name)) {
908 preedit_attr->value = (void *)malloc(sizeof(long));
909 *(long*)preedit_attr->value = ic->preedit.foreground;
910 preedit_attr->value_length = sizeof(long);
911 }
912 else if (streql(XNBackground, preedit_attr->name)) {
913 preedit_attr->value = (void *)malloc(sizeof(long));
914 *(long*)preedit_attr->value = ic->preedit.background;
915 preedit_attr->value_length = sizeof(long);
916 }
917 else if (streql(XNLineSpace, preedit_attr->name)) {
918 preedit_attr->value = (void *)malloc(sizeof(long));
919 *(long*)preedit_attr->value = ic->preedit.line_space;
920 preedit_attr->value_length = sizeof(long);
921 }
922 else if (streql(XNPreeditState, preedit_attr->name)) {
923 preedit_attr->value = (void *)malloc(sizeof(XIMPreeditState));
924 *(XIMPreeditState*)preedit_attr->value = ic->preedit.state;
925 preedit_attr->value_length = sizeof(XIMPreeditState);
926 }
927 else if (streql(XNFontSet, preedit_attr->name)) {
928 CARD16 base_len = (CARD16)strlen(ic->preedit.base_font);
929 int total_len = sizeof(CARD16) + (CARD16)base_len;
930 char *p;
931
932 preedit_attr->value = (void *)malloc(total_len);
933 p = (char *)preedit_attr->value;
934 memmove(p, &base_len, sizeof(CARD16));
935 p += sizeof(CARD16);
936 strncpy(p, ic->preedit.base_font, base_len);
937 preedit_attr->value_length = total_len;
938 }
939 else {
940 g_print("im_ja_xim: get unknown preedit attribute: %s\n", preedit_attr->name);
941 }
942 }
943
944 for (i = 0; i < data->status_attr_num; i++, status_attr++) {
945 IM_JA_DEBUG(" status attribute: %s\n", status_attr->name);
946 if (streql(XNArea, status_attr->name)) {
947 status_attr->value = (void *)malloc(sizeof(XRectangle));
948 *(XRectangle*)status_attr->value = ic->status_attr.area;
949 status_attr->value_length = sizeof(XRectangle);
950 }
951 else if (streql(XNAreaNeeded, status_attr->name)) {
952 status_attr->value = (void *)malloc(sizeof(XRectangle));
953 *(XRectangle*)status_attr->value = ic->status_attr.area_needed;
954 status_attr->value_length = sizeof(XRectangle);
955 }
956 else if (streql(XNForeground, status_attr->name)) {
957 status_attr->value = (void *)malloc(sizeof(long));
958 *(long*)status_attr->value = ic->status_attr.foreground;
959 status_attr->value_length = sizeof(long);
960 }
961 else if (streql(XNBackground, status_attr->name)) {
962 status_attr->value = (void *)malloc(sizeof(long));
963 *(long*)status_attr->value = ic->status_attr.background;
964 status_attr->value_length = sizeof(long);
965 }
966 else if (streql(XNLineSpace, status_attr->name)) {
967 status_attr->value = (void *)malloc(sizeof(long));
968 *(long*)status_attr->value = ic->status_attr.line_space;
969 status_attr->value_length = sizeof(long);
970 }
971 else if (streql(XNFontSet, status_attr->name)) {
972 CARD16 base_len = (CARD16)strlen(ic->status_attr.base_font);
973 int total_len = sizeof(CARD16) + (CARD16)base_len;
974 char *p;
975
976 status_attr->value = (void *)malloc(total_len);
977 p = (char *)status_attr->value;
978 memmove(p, &base_len, sizeof(CARD16));
979 p += sizeof(CARD16);
980 strncpy(p, ic->status_attr.base_font, base_len);
981 status_attr->value_length = total_len;
982 }
983 else {
984 g_print("im_ja_xim: get unknown status attribute: %s\n", status_attr->name);
985 }
986 }
987
988 }
989
990
991 /*
992 void im_ja_xim_ic_reset(IMJAContext *ic) {
993 if (!im_ja_xim_ic_is_empty(ic)) im_ja_xim_ic_commit(ic);
994 }
995 */
996
im_ja_xim_ic_preedit_clear(IMJAContext * ic)997 void im_ja_xim_ic_preedit_clear(IMJAContext *ic) {
998 XIMText text;
999 XIMFeedback feedback[4] = { XIMUnderline, 0, 0, 0 };
1000 IMPreeditCBStruct data;
1001 XTextProperty tp;
1002 char *list[2];
1003 IMCommitStruct commit_data;
1004 int ret;
1005
1006 IM_JA_DEBUG("im_ja_xim_ic_preedit_clear()\n");
1007
1008 if (ic->input_style & XIMPreeditCallbacks) {
1009 data.major_code = XIM_PREEDIT_DRAW;
1010 data.minor_code = 0;
1011 data.connect_id = ic->connect_id;
1012 data.icid = ic->id;
1013 data.todo.draw.caret = 0;
1014 data.todo.draw.chg_first = 0;
1015 data.todo.draw.chg_length = g_utf8_strlen(ic->prev_preedit_buf, -1);
1016 data.todo.draw.text = &text;
1017
1018 text.feedback = feedback;
1019 text.encoding_is_wchar = False;
1020 text.string.multi_byte = ""; /*NULL;*/
1021 text.length = 0;
1022 IMCallCallback(im_ja_xim_server->xims, (XPointer)&data);
1023
1024 /* this commit is needed for kde/qt for some reason */
1025
1026 list[0] = "";
1027 list[1] = 0;
1028 ret = Xutf8TextListToTextProperty(im_ja_xim_server->display, list, 1,
1029 XCompoundTextStyle,
1030 &tp);
1031 commit_data.connect_id = ic->connect_id;
1032 commit_data.icid = ic->id;
1033 commit_data.flag = XimLookupChars;
1034 commit_data.commit_string = (char*) tp.value;
1035
1036 IMCommitString(im_ja_xim_server->xims, (XPointer)&commit_data);
1037 XFree(tp.value);
1038 }
1039 else if (ic->input_style & XIMPreeditPosition) {
1040 if (ic->preedit.window == 0) return;
1041 XUnmapWindow(im_ja_xim_server->display, ic->preedit.window);
1042 }
1043 memset(ic->prev_preedit_buf, 0, BUFFERSIZE);
1044
1045 }
1046
im_ja_xim_ic_preedit_start(IMJAContext * ic)1047 void im_ja_xim_ic_preedit_start(IMJAContext *ic) {
1048
1049 IM_JA_DEBUG("im_ja_xim_ic_preedit_start\n");
1050
1051 if (ic->preedit.start) return;
1052
1053 if (im_ja_xim_server->dynamic_event_flow) {
1054 IMPreeditStateStruct preedit_state;
1055
1056 preedit_state.connect_id = ic->connect_id;
1057 preedit_state.icid = ic->id;
1058 IMPreeditStart(im_ja_xim_server->xims, (XPointer)&preedit_state);
1059 }
1060
1061 if (ic->input_style & XIMPreeditCallbacks) {
1062 IMPreeditCBStruct preedit_data;
1063
1064 preedit_data.major_code = XIM_PREEDIT_START;
1065 preedit_data.minor_code = 0;
1066 preedit_data.connect_id = ic->connect_id;
1067 preedit_data.icid = ic->id;
1068 preedit_data.todo.return_value = 0;
1069 IMCallCallback(im_ja_xim_server->xims, (XPointer)&preedit_data);
1070 }
1071 else if (ic->input_style & XIMPreeditPosition) {
1072 ic->preedit.start = True;
1073 im_ja_xim_ic_preedit_clear(ic);
1074
1075 im_ja_xim_ic_set_preedit_foreground(ic, im_ja_xim_server->preedit_fg);
1076 im_ja_xim_ic_set_preedit_background(ic, im_ja_xim_server->preedit_bg);
1077 }
1078
1079 }
1080
1081
1082 /*
1083 void im_ja_xim_ic_preedit_done(IMJAContext *ic) {
1084 if (!ic->preedit.start) return;
1085
1086 if (ic->input_style & XIMPreeditCallbacks) {
1087 IMPreeditCBStruct preedit_data;
1088
1089 preedit_data.major_code = XIM_PREEDIT_DONE;
1090 preedit_data.minor_code = 0;
1091 preedit_data.connect_id = ic->connect_id;
1092 preedit_data.icid = ic->id;
1093 preedit_data.todo.return_value = 0;
1094 IMCallCallback(im_ja_xim_server->xims, (XPointer)&preedit_data);
1095 }
1096 else if (ic->input_style & XIMPreeditPosition) {
1097 ; // do nothing
1098 }
1099
1100 if (im_ja_xim_server->dynamic_event_flow) {
1101 IMPreeditStateStruct preedit_state;
1102
1103 preedit_state.connect_id = ic->connect_id;
1104 preedit_state.icid = ic->id;
1105 IMPreeditEnd(im_ja_xim_server->xims, (XPointer)&preedit_state);
1106 }
1107
1108 ic->preedit.start = False;
1109 }
1110 */
1111
1112