Bug Summary

File:modules/input/ctkimcontextxim.c
Warning:line 569, column 51
Access to field 'ics' results in a dereference of a null pointer (loaded from field 'im_info')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkimcontextxim.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/modules/input -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D CTK_LOCALEDIR="/usr/share/locale" -I ../.. -I ../../cdk -I ../../cdk -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D CTK_COMPILATION -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/modules/input -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-173409-43638-1 -x c ctkimcontextxim.c
1/* CTK - 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, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19#include "locale.h"
20#include <string.h>
21#include <stdlib.h>
22
23#include "ctkimcontextxim.h"
24
25#include "ctk/ctkintl.h"
26
27typedef struct _StatusWindow StatusWindow;
28typedef struct _CtkXIMInfo CtkXIMInfo;
29
30struct _CtkIMContextXIM
31{
32 CtkIMContext object;
33
34 CtkXIMInfo *im_info;
35
36 gchar *locale;
37 gchar *mb_charset;
38
39 CdkWindow *client_window;
40 CtkWidget *client_widget;
41
42 /* The status window for this input context; we claim the
43 * status window when we are focused and have created an XIC
44 */
45 StatusWindow *status_window;
46
47 gint preedit_size;
48 gint preedit_length;
49 gunichar *preedit_chars;
50 XIMFeedback *feedbacks;
51
52 gint preedit_cursor;
53
54 XIMCallback preedit_start_callback;
55 XIMCallback preedit_done_callback;
56 XIMCallback preedit_draw_callback;
57 XIMCallback preedit_caret_callback;
58
59 XIMCallback status_start_callback;
60 XIMCallback status_done_callback;
61 XIMCallback status_draw_callback;
62
63 XIMCallback string_conversion_callback;
64
65 XIC ic;
66
67 guint filter_key_release : 1;
68 guint use_preedit : 1;
69 guint finalizing : 1;
70 guint in_toplevel : 1;
71 guint has_focus : 1;
72};
73
74struct _CtkXIMInfo
75{
76 CdkScreen *screen;
77 XIM im;
78 char *locale;
79 XIMStyle preedit_style_setting;
80 XIMStyle status_style_setting;
81 XIMStyle style;
82 CtkSettings *settings;
83 gulong status_set;
84 gulong preedit_set;
85 gulong display_closed_cb;
86 XIMStyles *xim_styles;
87 GSList *ics;
88
89 guint reconnecting :1;
90 guint supports_string_conversion;
91};
92
93/* A context status window; these are kept in the status_windows list. */
94struct _StatusWindow
95{
96 CtkWidget *window;
97
98 /* Toplevel window to which the status window corresponds */
99 CtkWidget *toplevel;
100
101 /* Currently focused CtkIMContextXIM for the toplevel, if any */
102 CtkIMContextXIM *context;
103};
104
105static void ctk_im_context_xim_class_init (CtkIMContextXIMClass *class);
106static void ctk_im_context_xim_init (CtkIMContextXIM *im_context_xim);
107static void ctk_im_context_xim_finalize (GObject *obj);
108static void ctk_im_context_xim_set_client_window (CtkIMContext *context,
109 CdkWindow *client_window);
110static gboolean ctk_im_context_xim_filter_keypress (CtkIMContext *context,
111 CdkEventKey *key);
112static void ctk_im_context_xim_reset (CtkIMContext *context);
113static void ctk_im_context_xim_focus_in (CtkIMContext *context);
114static void ctk_im_context_xim_focus_out (CtkIMContext *context);
115static void ctk_im_context_xim_set_cursor_location (CtkIMContext *context,
116 CdkRectangle *area);
117static void ctk_im_context_xim_set_use_preedit (CtkIMContext *context,
118 gboolean use_preedit);
119static void ctk_im_context_xim_get_preedit_string (CtkIMContext *context,
120 gchar **str,
121 PangoAttrList **attrs,
122 gint *cursor_pos);
123
124static void reinitialize_ic (CtkIMContextXIM *context_xim);
125static void set_ic_client_window (CtkIMContextXIM *context_xim,
126 CdkWindow *client_window);
127
128static void setup_styles (CtkXIMInfo *info);
129
130static void update_client_widget (CtkIMContextXIM *context_xim);
131static void update_status_window (CtkIMContextXIM *context_xim);
132
133static StatusWindow *status_window_get (CtkWidget *toplevel);
134static void status_window_free (StatusWindow *status_window);
135static void status_window_set_text (StatusWindow *status_window,
136 const gchar *text);
137
138static void xim_destroy_callback (XIM xim,
139 XPointer client_data,
140 XPointer call_data);
141
142static XIC ctk_im_context_xim_get_ic (CtkIMContextXIM *context_xim);
143static void xim_info_display_closed (CdkDisplay *display,
144 gboolean is_error,
145 CtkXIMInfo *info);
146
147static GObjectClass *parent_class;
148
149GType ctk_type_im_context_xim = 0;
150
151static GSList *open_ims = NULL((void*)0);
152
153/* List of status windows for different toplevels */
154static GSList *status_windows = NULL((void*)0);
155
156void
157ctk_im_context_xim_register_type (GTypeModule *type_module)
158{
159 const GTypeInfo im_context_xim_info =
160 {
161 .class_size = sizeof (CtkIMContextXIMClass),
162 .base_init = (GBaseInitFunc) NULL((void*)0),
163 .base_finalize = (GBaseFinalizeFunc) NULL((void*)0),
164 .class_init = (GClassInitFunc) ctk_im_context_xim_class_init,
165 .instance_size = sizeof (CtkIMContextXIM),
166 .n_preallocs = 0,
167 .instance_init = (GInstanceInitFunc) ctk_im_context_xim_init,
168 };
169
170 ctk_type_im_context_xim =
171 g_type_module_register_type (type_module,
172 CTK_TYPE_IM_CONTEXT(ctk_im_context_get_type ()),
173 "CtkIMContextXIM",
174 &im_context_xim_info, 0);
175}
176
177#define PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L) (XIMPreeditCallbacks0x0002L | XIMPreeditPosition0x0004L | \
178 XIMPreeditArea0x0001L | XIMPreeditNothing0x0008L | XIMPreeditNone0x0010L)
179#define STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L) (XIMStatusCallbacks0x0200L | XIMStatusArea0x0100L | \
180 XIMStatusNothing0x0400L | XIMStatusNone0x0800L)
181#define ALLOWED_MASK(0x0002L | 0x0008L | 0x0010L | 0x0200L | 0x0400L | 0x0800L) (XIMPreeditCallbacks0x0002L | XIMPreeditNothing0x0008L | XIMPreeditNone0x0010L | \
182 XIMStatusCallbacks0x0200L | XIMStatusNothing0x0400L | XIMStatusNone0x0800L)
183
184static XIMStyle
185choose_better_style (XIMStyle style1, XIMStyle style2)
186{
187 XIMStyle s1, s2, u;
188
189 if (style1 == 0) return style2;
190 if (style2 == 0) return style1;
191 if ((style1 & (PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L) | STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L)))
192 == (style2 & (PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L) | STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L))))
193 return style1;
194
195 s1 = style1 & PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L);
196 s2 = style2 & PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L);
197 u = s1 | s2;
198 if (s1 != s2) {
199 if (u & XIMPreeditCallbacks0x0002L)
200 return (s1 == XIMPreeditCallbacks0x0002L) ? style1 : style2;
201 else if (u & XIMPreeditPosition0x0004L)
202 return (s1 == XIMPreeditPosition0x0004L) ? style1 :style2;
203 else if (u & XIMPreeditArea0x0001L)
204 return (s1 == XIMPreeditArea0x0001L) ? style1 : style2;
205 else if (u & XIMPreeditNothing0x0008L)
206 return (s1 == XIMPreeditNothing0x0008L) ? style1 : style2;
207 else if (u & XIMPreeditNone0x0010L)
208 return (s1 == XIMPreeditNone0x0010L) ? style1 : style2;
209 } else {
210 s1 = style1 & STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L);
211 s2 = style2 & STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L);
212 u = s1 | s2;
213 if (u & XIMStatusCallbacks0x0200L)
214 return (s1 == XIMStatusCallbacks0x0200L) ? style1 : style2;
215 else if (u & XIMStatusArea0x0100L)
216 return (s1 == XIMStatusArea0x0100L) ? style1 : style2;
217 else if (u & XIMStatusNothing0x0400L)
218 return (s1 == XIMStatusNothing0x0400L) ? style1 : style2;
219 else if (u & XIMStatusNone0x0800L)
220 return (s1 == XIMStatusNone0x0800L) ? style1 : style2;
221 }
222 return 0; /* Get rid of stupid warning */
223}
224
225static void
226reinitialize_all_ics (CtkXIMInfo *info)
227{
228 GSList *tmp_list;
229
230 for (tmp_list = info->ics; tmp_list; tmp_list = tmp_list->next)
231 reinitialize_ic (tmp_list->data);
232}
233
234static void
235setup_styles (CtkXIMInfo *info)
236{
237 unsigned long settings_preference;
238 XIMStyles *xim_styles = info->xim_styles;
239
240 settings_preference = info->status_style_setting|info->preedit_style_setting;
241 info->style = 0;
242 if (xim_styles)
243 {
244 int i;
245
246 for (i = 0; i < xim_styles->count_styles; i++)
247 if ((xim_styles->supported_styles[i] & ALLOWED_MASK(0x0002L | 0x0008L | 0x0010L | 0x0200L | 0x0400L | 0x0800L)) == xim_styles->supported_styles[i])
248 {
249 if (settings_preference == xim_styles->supported_styles[i])
250 {
251 info->style = settings_preference;
252 break;
253 }
254 info->style = choose_better_style (info->style,
255 xim_styles->supported_styles[i]);
256 }
257 }
258 if (info->style == 0)
259 info->style = XIMPreeditNothing0x0008L | XIMStatusNothing0x0400L;
260}
261
262static void
263setup_im (CtkXIMInfo *info)
264{
265 XIMValuesList *ic_values = NULL((void*)0);
266 XIMCallback im_destroy_callback;
267 CdkDisplay *display;
268
269 if (info->im == NULL((void*)0))
270 return;
271
272 im_destroy_callback.client_data = (XPointer)info;
273 im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
274 XSetIMValues (info->im,
275 XNDestroyCallback"destroyCallback", &im_destroy_callback,
276 NULL((void*)0));
277
278 XGetIMValues (info->im,
279 XNQueryInputStyle"queryInputStyle", &info->xim_styles,
280 XNQueryICValuesList"queryICValuesList", &ic_values,
281 NULL((void*)0));
282
283 info->supports_string_conversion = FALSE(0);
284 if (ic_values)
285 {
286 int i;
287
288 for (i = 0; i < ic_values->count_values; i++)
289 if (strcmp (ic_values->supported_values[i],
290 XNStringConversionCallback"stringConversionCallback") == 0)
291 {
292 info->supports_string_conversion = TRUE(!(0));
293 break;
294 }
295
296#if 0
297 for (i = 0; i < ic_values->count_values; i++)
298 g_print ("%s\n", ic_values->supported_values[i]);
299 for (i = 0; i < xim_styles->count_styles; i++)
300 g_print ("%#x\n", xim_styles->supported_styles[i]);
301#endif
302
303 XFree (ic_values);
304 }
305
306 info->status_style_setting = XIMStatusCallbacks0x0200L;
307 info->preedit_style_setting = XIMPreeditCallbacks0x0002L;
308 setup_styles (info);
309 reinitialize_all_ics (info);
310
311 display = cdk_screen_get_display (info->screen);
312 info->display_closed_cb = g_signal_connect (display, "closed",g_signal_connect_data ((display), ("closed"), (((GCallback) (
xim_info_display_closed))), (info), ((void*)0), (GConnectFlags
) 0)
313 G_CALLBACK (xim_info_display_closed), info)g_signal_connect_data ((display), ("closed"), (((GCallback) (
xim_info_display_closed))), (info), ((void*)0), (GConnectFlags
) 0)
;
314}
315
316static void
317xim_info_display_closed (CdkDisplay *display,
318 gboolean is_error G_GNUC_UNUSED__attribute__ ((__unused__)),
319 CtkXIMInfo *info)
320{
321 GSList *ics, *tmp_list;
322
323 open_ims = g_slist_remove (open_ims, info);
324
325 ics = info->ics;
326 info->ics = NULL((void*)0);
327
328 for (tmp_list = ics; tmp_list; tmp_list = tmp_list->next)
329 set_ic_client_window (tmp_list->data, NULL((void*)0));
330
331 g_slist_free (ics);
332
333 if (info->status_set)
334 g_signal_handler_disconnect (info->settings, info->status_set);
335 if (info->preedit_set)
336 g_signal_handler_disconnect (info->settings, info->preedit_set);
337 if (info->display_closed_cb)
338 g_signal_handler_disconnect (display, info->display_closed_cb);
339
340 if (info->xim_styles)
341 XFree (info->xim_styles);
342 g_free (info->locale);
343
344 if (info->im)
345 XCloseIM (info->im);
346
347 g_free (info);
348}
349
350static void
351xim_instantiate_callback (Display *display, XPointer client_data,
352 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
353{
354 CtkXIMInfo *info = (CtkXIMInfo*)client_data;
355 XIM im = NULL((void*)0);
356
357 im = XOpenIM (display, NULL((void*)0), NULL((void*)0), NULL((void*)0));
358
359 if (!im)
360 return;
361
362 info->im = im;
363 setup_im (info);
364
365 XUnregisterIMInstantiateCallback (display, NULL((void*)0), NULL((void*)0), NULL((void*)0),
366 xim_instantiate_callback,
367 (XPointer)info);
368 info->reconnecting = FALSE(0);
369}
370
371/* initialize info->im */
372static void
373xim_info_try_im (CtkXIMInfo *info)
374{
375 CdkScreen *screen = info->screen;
376 CdkDisplay *display = cdk_screen_get_display (screen);
377
378 g_assert (info->im == NULL)do { if (info->im == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "ctkimcontextxim.c", 378, ((const char*) (__func__
)), "info->im == NULL"); } while (0)
;
379 if (info->reconnecting)
380 return;
381
382 if (XSupportsLocale ())
383 {
384 if (!XSetLocaleModifiers (""))
385 g_warning ("Unable to set locale modifiers with XSetLocaleModifiers()");
386 info->im = XOpenIM (CDK_DISPLAY_XDISPLAY (display)(cdk_x11_display_get_xdisplay (display)), NULL((void*)0), NULL((void*)0), NULL((void*)0));
387 if (!info->im)
388 {
389 XRegisterIMInstantiateCallback (CDK_DISPLAY_XDISPLAY(display)(cdk_x11_display_get_xdisplay (display)),
390 NULL((void*)0), NULL((void*)0), NULL((void*)0),
391 xim_instantiate_callback,
392 (XPointer)info);
393 info->reconnecting = TRUE(!(0));
394 return;
395 }
396 setup_im (info);
397 }
398}
399
400static void
401xim_destroy_callback (XIM xim G_GNUC_UNUSED__attribute__ ((__unused__)),
402 XPointer client_data,
403 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
404{
405 CtkXIMInfo *info = (CtkXIMInfo*)client_data;
406
407 info->im = NULL((void*)0);
408
409 g_signal_handler_disconnect (info->settings, info->status_set);
410 info->status_set = 0;
411 g_signal_handler_disconnect (info->settings, info->preedit_set);
412 info->preedit_set = 0;
413
414 reinitialize_all_ics (info);
415 xim_info_try_im (info);
416 return;
417}
418
419static CtkXIMInfo *
420get_im (CdkWindow *client_window,
421 const char *locale)
422{
423 GSList *tmp_list;
424 CtkXIMInfo *info;
425 CdkScreen *screen = cdk_window_get_screen (client_window);
426
427 info = NULL((void*)0);
428 tmp_list = open_ims;
429 while (tmp_list)
430 {
431 CtkXIMInfo *tmp_info = tmp_list->data;
432 if (tmp_info->screen == screen &&
433 strcmp (tmp_info->locale, locale) == 0)
434 {
435 if (tmp_info->im)
436 {
437 return tmp_info;
438 }
439 else
440 {
441 tmp_info = tmp_info;
442 break;
443 }
444 }
445 tmp_list = tmp_list->next;
446 }
447
448 if (info == NULL((void*)0))
449 {
450 info = g_new (CtkXIMInfo, 1)((CtkXIMInfo *) g_malloc_n ((1), sizeof (CtkXIMInfo)));
451 open_ims = g_slist_prepend (open_ims, info);
452
453 info->screen = screen;
454 info->locale = g_strdup (locale)g_strdup_inline (locale);
455 info->xim_styles = NULL((void*)0);
456 info->preedit_style_setting = 0;
457 info->status_style_setting = 0;
458 info->settings = NULL((void*)0);
459 info->preedit_set = 0;
460 info->status_set = 0;
461 info->display_closed_cb = 0;
462 info->ics = NULL((void*)0);
463 info->reconnecting = FALSE(0);
464 info->im = NULL((void*)0);
465 }
466
467 xim_info_try_im (info);
468 return info;
469}
470
471static void
472ctk_im_context_xim_class_init (CtkIMContextXIMClass *class)
473{
474 CtkIMContextClass *im_context_class = CTK_IM_CONTEXT_CLASS (class)((((CtkIMContextClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_im_context_get_type ()))))))
;
475 GObjectClass *gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
476
477 parent_class = g_type_class_peek_parent (class);
478
479 im_context_class->set_client_window = ctk_im_context_xim_set_client_window;
480 im_context_class->filter_keypress = ctk_im_context_xim_filter_keypress;
481 im_context_class->reset = ctk_im_context_xim_reset;
482 im_context_class->get_preedit_string = ctk_im_context_xim_get_preedit_string;
483 im_context_class->focus_in = ctk_im_context_xim_focus_in;
484 im_context_class->focus_out = ctk_im_context_xim_focus_out;
485 im_context_class->set_cursor_location = ctk_im_context_xim_set_cursor_location;
486 im_context_class->set_use_preedit = ctk_im_context_xim_set_use_preedit;
487 gobject_class->finalize = ctk_im_context_xim_finalize;
488}
489
490static void
491ctk_im_context_xim_init (CtkIMContextXIM *im_context_xim)
492{
493 im_context_xim->use_preedit = TRUE(!(0));
494 im_context_xim->filter_key_release = FALSE(0);
495 im_context_xim->finalizing = FALSE(0);
496 im_context_xim->has_focus = FALSE(0);
497 im_context_xim->in_toplevel = FALSE(0);
498}
499
500static void
501ctk_im_context_xim_finalize (GObject *obj)
502{
503 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (obj)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((ctk_type_im_context_xim))))))
;
504
505 context_xim->finalizing = TRUE(!(0));
506
507 if (context_xim->im_info && !context_xim->im_info->ics->next)
1
Assuming field 'im_info' is null
508 {
509 if (context_xim->im_info->reconnecting)
510 {
511 CdkDisplay *display;
512
513 display = cdk_screen_get_display (context_xim->im_info->screen);
514 XUnregisterIMInstantiateCallback (CDK_DISPLAY_XDISPLAY (display)(cdk_x11_display_get_xdisplay (display)),
515 NULL((void*)0), NULL((void*)0), NULL((void*)0),
516 xim_instantiate_callback,
517 (XPointer)context_xim->im_info);
518 }
519 else if (context_xim->im_info->im)
520 {
521 XIMCallback im_destroy_callback;
522
523 im_destroy_callback.client_data = NULL((void*)0);
524 im_destroy_callback.callback = NULL((void*)0);
525 XSetIMValues (context_xim->im_info->im,
526 XNDestroyCallback"destroyCallback", &im_destroy_callback,
527 NULL((void*)0));
528 }
529 }
530
531 set_ic_client_window (context_xim, NULL((void*)0));
2
Calling 'set_ic_client_window'
532
533 g_free (context_xim->locale);
534 g_free (context_xim->mb_charset);
535
536 G_OBJECT_CLASS (parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->finalize (obj);
537}
538
539static void
540reinitialize_ic (CtkIMContextXIM *context_xim)
541{
542 if (context_xim->ic)
4
Assuming field 'ic' is null
5
Taking false branch
543 {
544 XDestroyIC (context_xim->ic);
545 context_xim->ic = NULL((void*)0);
546 update_status_window (context_xim);
547
548 if (context_xim->preedit_length)
549 {
550 context_xim->preedit_length = 0;
551 if (!context_xim->finalizing)
552 g_signal_emit_by_name (context_xim, "preedit-changed");
553 }
554 }
555 /*
556 reset filter_key_release flag, otherwise keystrokes will be doubled
557 until reconnecting to XIM.
558 */
559 context_xim->filter_key_release = FALSE(0);
560}
6
Returning without writing to 'context_xim->client_window', which participates in a condition later
7
Returning without writing to 'context_xim->im_info'
561
562static void
563set_ic_client_window (CtkIMContextXIM *context_xim,
564 CdkWindow *client_window)
565{
566 reinitialize_ic (context_xim);
3
Calling 'reinitialize_ic'
8
Returning from 'reinitialize_ic'
567 if (context_xim->client_window)
9
Assuming field 'client_window' is non-null
10
Taking true branch
568 {
569 context_xim->im_info->ics = g_slist_remove (context_xim->im_info->ics, context_xim);
11
Access to field 'ics' results in a dereference of a null pointer (loaded from field 'im_info')
570 context_xim->im_info = NULL((void*)0);
571 }
572
573 context_xim->client_window = client_window;
574
575 if (context_xim->client_window)
576 {
577 context_xim->im_info = get_im (context_xim->client_window, context_xim->locale);
578 context_xim->im_info->ics = g_slist_prepend (context_xim->im_info->ics, context_xim);
579 }
580
581 update_client_widget (context_xim);
582}
583
584static void
585ctk_im_context_xim_set_client_window (CtkIMContext *context,
586 CdkWindow *client_window)
587{
588 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
589
590 set_ic_client_window (context_xim, client_window);
591}
592
593CtkIMContext *
594ctk_im_context_xim_new (void)
595{
596 CtkIMContextXIM *result;
597 const gchar *charset;
598
599 if (!CDK_IS_X11_DISPLAY(cdk_display_get_default())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cdk_display_get_default())); GType __t = ((cdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
600 return NULL((void*)0);
601 result = g_object_new (CTK_TYPE_IM_CONTEXT_XIM(ctk_type_im_context_xim), NULL((void*)0));
602
603 result->locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
604
605 g_get_charset (&charset);
606 result->mb_charset = g_strdup (charset)g_strdup_inline (charset);
607
608 return CTK_IM_CONTEXT (result)((((CtkIMContext*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), ((ctk_im_context_get_type ()))))))
;
609}
610
611static char *
612mb_to_utf8 (CtkIMContextXIM *context_xim,
613 const char *str)
614{
615 GError *error = NULL((void*)0);
616 gchar *result;
617
618 if (strcmp (context_xim->mb_charset, "UTF-8") == 0)
619 result = g_strdup (str)g_strdup_inline (str);
620 else
621 {
622 result = g_convert (str, -1,
623 "UTF-8", context_xim->mb_charset,
624 NULL((void*)0), NULL((void*)0), &error);
625 if (!result)
626 {
627 g_warning ("Error converting text from IM to UTF-8: %s\n", error->message);
628 g_error_free (error);
629 }
630 }
631
632 return result;
633}
634
635static gboolean
636ctk_im_context_xim_filter_keypress (CtkIMContext *context,
637 CdkEventKey *event)
638{
639 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
640 XIC ic = ctk_im_context_xim_get_ic (context_xim);
641 gchar static_buffer[256];
642 gchar *buffer = static_buffer;
643 gint buffer_size = sizeof(static_buffer) - 1;
644 gint num_bytes = 0;
645 KeySym keysym;
646 Statusint status;
647 gboolean result = FALSE(0);
648 CdkWindow *root_window;
649 CdkWindow *window;
650 XKeyPressedEvent xevent;
651
652 if (context_xim->client_window == NULL((void*)0))
653 return FALSE(0);
654
655 if (event->type == CDK_KEY_RELEASE && !context_xim->filter_key_release)
656 return FALSE(0);
657
658 root_window = cdk_screen_get_root_window (cdk_window_get_screen (event->window));
659 window = cdk_window_get_toplevel (event->window);
660
661 xevent.type = (event->type == CDK_KEY_PRESS) ? KeyPress2 : KeyRelease3;
662 xevent.serial = 0; /* hope it doesn't matter */
663 xevent.send_event = event->send_event;
664 xevent.display = CDK_WINDOW_XDISPLAY (window)((cdk_x11_display_get_xdisplay (cdk_window_get_display (window
))))
;
665 xevent.window = CDK_WINDOW_XID (window)(cdk_x11_window_get_xid (window));
666 xevent.root = CDK_WINDOW_XID (root_window)(cdk_x11_window_get_xid (root_window));
667 xevent.subwindow = xevent.window;
668 xevent.time = event->time;
669 xevent.x = xevent.x_root = 0;
670 xevent.y = xevent.y_root = 0;
671 xevent.state = event->state;
672 xevent.keycode = event->hardware_keycode;
673 xevent.same_screen = True1;
674
675 if (XFilterEvent ((XEvent *)&xevent, CDK_WINDOW_XID (context_xim->client_window)(cdk_x11_window_get_xid (context_xim->client_window))))
676 return TRUE(!(0));
677
678 if (event->state &
679 (ctk_accelerator_get_default_mod_mask () & ~(CDK_SHIFT_MASK | CDK_CONTROL_MASK)))
680 return FALSE(0);
681
682 again:
683 if (ic)
684 num_bytes = XmbLookupString (ic, &xevent, buffer, buffer_size, &keysym, &status);
685 else
686 {
687 num_bytes = XLookupString (&xevent, buffer, buffer_size, &keysym, NULL((void*)0));
688 status = XLookupBoth4;
689 }
690
691 if (status == XBufferOverflow-1)
692 {
693 buffer_size = num_bytes;
694 if (buffer != static_buffer)
695 g_free (buffer);
696 buffer = g_malloc (num_bytes + 1);
697 goto again;
698 }
699
700 /* I don't know how we should properly handle XLookupKeysym or XLookupBoth
701 * here ... do input methods actually change the keysym? we can't really
702 * feed it back to accelerator processing at this point...
703 */
704 if (status == XLookupChars2 || status == XLookupBoth4)
705 {
706 char *result_utf8;
707
708 buffer[num_bytes] = '\0';
709
710 result_utf8 = mb_to_utf8 (context_xim, buffer);
711 if (result_utf8)
712 {
713 if ((guchar)result_utf8[0] >= 0x20 &&
714 result_utf8[0] != 0x7f) /* Some IM have a nasty habit of converting
715 * control characters into strings
716 */
717 {
718 g_signal_emit_by_name (context, "commit", result_utf8);
719 result = TRUE(!(0));
720 }
721
722 g_free (result_utf8);
723 }
724 }
725
726 if (buffer != static_buffer)
727 g_free (buffer);
728
729 return result;
730}
731
732static void
733ctk_im_context_xim_focus_in (CtkIMContext *context)
734{
735 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
736
737 if (!context_xim->has_focus)
738 {
739 XIC ic = ctk_im_context_xim_get_ic (context_xim);
740
741 context_xim->has_focus = TRUE(!(0));
742 update_status_window (context_xim);
743
744 if (ic)
745 XSetICFocus (ic);
746 }
747
748 return;
749}
750
751static void
752ctk_im_context_xim_focus_out (CtkIMContext *context)
753{
754 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
755
756 if (context_xim->has_focus)
757 {
758 XIC ic = ctk_im_context_xim_get_ic (context_xim);
759
760 context_xim->has_focus = FALSE(0);
761 update_status_window (context_xim);
762
763 if (ic)
764 XUnsetICFocus (ic);
765 }
766
767 return;
768}
769
770static void
771ctk_im_context_xim_set_cursor_location (CtkIMContext *context,
772 CdkRectangle *area)
773{
774 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
775 XIC ic = ctk_im_context_xim_get_ic (context_xim);
776
777 XVaNestedList preedit_attr;
778 XPoint spot;
779
780 if (!ic)
781 return;
782
783 spot.x = area->x;
784 spot.y = area->y + area->height;
785
786 preedit_attr = XVaCreateNestedList (0,
787 XNSpotLocation"spotLocation", &spot,
788 NULL((void*)0));
789 XSetICValues (ic,
790 XNPreeditAttributes"preeditAttributes", preedit_attr,
791 NULL((void*)0));
792 XFree(preedit_attr);
793
794 return;
795}
796
797static void
798ctk_im_context_xim_set_use_preedit (CtkIMContext *context,
799 gboolean use_preedit)
800{
801 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
802
803 use_preedit = use_preedit != FALSE(0);
804
805 if (context_xim->use_preedit != use_preedit)
806 {
807 context_xim->use_preedit = use_preedit;
808 reinitialize_ic (context_xim);
809 }
810
811 return;
812}
813
814static void
815ctk_im_context_xim_reset (CtkIMContext *context)
816{
817 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
818 XIC ic = ctk_im_context_xim_get_ic (context_xim);
819 gchar *result;
820
821 /* restore conversion state after resetting ic later */
822 XIMPreeditState preedit_state = XIMPreeditUnKnown0L;
823 XVaNestedList preedit_attr;
824 gboolean have_preedit_state = FALSE(0);
825
826 if (!ic)
827 return;
828
829
830 if (context_xim->preedit_length == 0)
831 return;
832
833 preedit_attr = XVaCreateNestedList(0,
834 XNPreeditState"preeditState", &preedit_state,
835 NULL((void*)0));
836 if (!XGetICValues(ic,
837 XNPreeditAttributes"preeditAttributes", preedit_attr,
838 NULL((void*)0)))
839 have_preedit_state = TRUE(!(0));
840
841 XFree(preedit_attr);
842
843 result = XmbResetIC (ic);
844
845 preedit_attr = XVaCreateNestedList(0,
846 XNPreeditState"preeditState", preedit_state,
847 NULL((void*)0));
848 if (have_preedit_state)
849 XSetICValues(ic,
850 XNPreeditAttributes"preeditAttributes", preedit_attr,
851 NULL((void*)0));
852
853 XFree(preedit_attr);
854
855 if (result)
856 {
857 char *result_utf8 = mb_to_utf8 (context_xim, result);
858 if (result_utf8)
859 {
860 g_signal_emit_by_name (context, "commit", result_utf8);
861 g_free (result_utf8);
862 }
863 }
864
865 if (context_xim->preedit_length)
866 {
867 context_xim->preedit_length = 0;
868 g_signal_emit_by_name (context, "preedit-changed");
869 }
870
871 XFree (result);
872}
873
874/* Mask of feedback bits that we render
875 */
876#define FEEDBACK_MASK(1L | (1L<<1)) (XIMReverse1L | XIMUnderline(1L<<1))
877
878static void
879add_feedback_attr (PangoAttrList *attrs,
880 const gchar *str,
881 XIMFeedback feedback,
882 gint start_pos,
883 gint end_pos)
884{
885 PangoAttribute *attr;
886
887 gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str;
888 gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str;
889
890 if (feedback & XIMUnderline(1L<<1))
891 {
892 attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
893 attr->start_index = start_index;
894 attr->end_index = end_index;
895
896 pango_attr_list_change (attrs, attr);
897 }
898
899 if (feedback & XIMReverse1L)
900 {
901 attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
902 attr->start_index = start_index;
903 attr->end_index = end_index;
904
905 pango_attr_list_change (attrs, attr);
906
907 attr = pango_attr_background_new (0, 0, 0);
908 attr->start_index = start_index;
909 attr->end_index = end_index;
910
911 pango_attr_list_change (attrs, attr);
912 }
913
914 if (feedback & ~FEEDBACK_MASK(1L | (1L<<1)))
915 g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK(1L | (1L<<1)));
916}
917
918static void
919ctk_im_context_xim_get_preedit_string (CtkIMContext *context,
920 gchar **str,
921 PangoAttrList **attrs,
922 gint *cursor_pos)
923{
924 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
925 gchar *utf8 = g_ucs4_to_utf8 (context_xim->preedit_chars, context_xim->preedit_length, NULL((void*)0), NULL((void*)0), NULL((void*)0));
926
927 if (attrs)
928 {
929 int i;
930 XIMFeedback last_feedback = 0;
931 gint start = -1;
932
933 *attrs = pango_attr_list_new ();
934
935 for (i = 0; i < context_xim->preedit_length; i++)
936 {
937 XIMFeedback new_feedback = context_xim->feedbacks[i] & FEEDBACK_MASK(1L | (1L<<1));
938 if (new_feedback != last_feedback)
939 {
940 if (start >= 0)
941 add_feedback_attr (*attrs, utf8, last_feedback, start, i);
942
943 last_feedback = new_feedback;
944 start = i;
945 }
946 }
947
948 if (start >= 0)
949 add_feedback_attr (*attrs, utf8, last_feedback, start, i);
950 }
951
952 if (str)
953 *str = utf8;
954 else
955 g_free (utf8);
956
957 if (cursor_pos)
958 *cursor_pos = context_xim->preedit_cursor;
959}
960
961static int
962preedit_start_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
963 XPointer client_data,
964 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
965{
966 CtkIMContext *context = CTK_IM_CONTEXT (client_data)((((CtkIMContext*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((client_data)), ((ctk_im_context_get_type ()))))))
;
967 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
968
969 if (!context_xim->finalizing)
970 g_signal_emit_by_name (context, "preedit-start");
971
972 return -1; /* No length limit */
973}
974
975static void
976preedit_done_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
977 XPointer client_data,
978 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
979{
980 CtkIMContext *context = CTK_IM_CONTEXT (client_data)((((CtkIMContext*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((client_data)), ((ctk_im_context_get_type ()))))))
;
981 CtkIMContextXIM *context_xim = CTK_IM_CONTEXT_XIM (context)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((context)), ((ctk_type_im_context_xim))))))
;
982
983 if (context_xim->preedit_length)
984 {
985 context_xim->preedit_length = 0;
986 if (!context_xim->finalizing)
987 g_signal_emit_by_name (context_xim, "preedit-changed");
988 }
989
990 if (!context_xim->finalizing)
991 g_signal_emit_by_name (context, "preedit-end");
992}
993
994static gint
995xim_text_to_utf8 (CtkIMContextXIM *context, XIMText *xim_text, gchar **text)
996{
997 gint text_length = 0;
998 GError *error = NULL((void*)0);
999 gchar *result = NULL((void*)0);
1000
1001 if (xim_text && xim_text->string.multi_byte)
1002 {
1003 if (xim_text->encoding_is_wchar)
1004 {
1005 g_warning ("Wide character return from Xlib not currently supported");
1006 *text = NULL((void*)0);
1007 return 0;
1008 }
1009
1010 if (strcmp (context->mb_charset, "UTF-8") == 0)
1011 result = g_strdup (xim_text->string.multi_byte)g_strdup_inline (xim_text->string.multi_byte);
1012 else
1013 result = g_convert (xim_text->string.multi_byte,
1014 -1,
1015 "UTF-8",
1016 context->mb_charset,
1017 NULL((void*)0), NULL((void*)0), &error);
1018
1019 if (result)
1020 {
1021 text_length = g_utf8_strlen (result, -1);
1022
1023 if (text_length != xim_text->length)
1024 {
1025 g_warning ("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
1026 }
1027 }
1028 else
1029 {
1030 g_warning ("Error converting text from IM to UCS-4: %s", error->message);
1031 g_error_free (error);
1032
1033 *text = NULL((void*)0);
1034 return 0;
1035 }
1036
1037 *text = result;
1038 return text_length;
1039 }
1040 else
1041 {
1042 *text = NULL((void*)0);
1043 return 0;
1044 }
1045}
1046
1047static void
1048preedit_draw_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1049 XPointer client_data,
1050 XIMPreeditDrawCallbackStruct *call_data)
1051{
1052 CtkIMContextXIM *context = CTK_IM_CONTEXT_XIM (client_data)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((client_data)), ((ctk_type_im_context_xim))))))
;
1053
1054 XIMText *new_xim_text = call_data->text;
1055 gint new_text_length;
1056 gunichar *new_text = NULL((void*)0);
1057 gint i;
1058 gint diff;
1059 gint new_length;
1060 gchar *tmp;
1061
1062 gint chg_first = CLAMP (call_data->chg_first, 0, context->preedit_length)(((call_data->chg_first) > (context->preedit_length)
) ? (context->preedit_length) : (((call_data->chg_first
) < (0)) ? (0) : (call_data->chg_first)))
;
1063 gint chg_length = CLAMP (call_data->chg_length, 0, context->preedit_length - chg_first)(((call_data->chg_length) > (context->preedit_length
- chg_first)) ? (context->preedit_length - chg_first) : (
((call_data->chg_length) < (0)) ? (0) : (call_data->
chg_length)))
;
1064
1065 context->preedit_cursor = call_data->caret;
1066
1067 if (chg_first != call_data->chg_first || chg_length != call_data->chg_length)
1068 g_warning ("Invalid change to preedit string, first=%d length=%d (orig length == %d)",
1069 call_data->chg_first, call_data->chg_length, context->preedit_length);
1070
1071 new_text_length = xim_text_to_utf8 (context, new_xim_text, &tmp);
1072 if (tmp)
1073 {
1074 new_text = g_utf8_to_ucs4_fast (tmp, -1, NULL((void*)0));
1075 g_free (tmp);
1076 }
1077
1078 diff = new_text_length - chg_length;
1079 new_length = context->preedit_length + diff;
1080
1081 if (new_length > context->preedit_size)
1082 {
1083 context->preedit_size = new_length;
1084 context->preedit_chars = g_renew (gunichar, context->preedit_chars, new_length)((gunichar *) g_realloc_n (context->preedit_chars, (new_length
), sizeof (gunichar)))
;
1085 context->feedbacks = g_renew (XIMFeedback, context->feedbacks, new_length)((XIMFeedback *) g_realloc_n (context->feedbacks, (new_length
), sizeof (XIMFeedback)))
;
1086 }
1087
1088 if (diff < 0)
1089 {
1090 for (i = chg_first + chg_length ; i < context->preedit_length; i++)
1091 {
1092 context->preedit_chars[i + diff] = context->preedit_chars[i];
1093 context->feedbacks[i + diff] = context->feedbacks[i];
1094 }
1095 }
1096 else
1097 {
1098 for (i = context->preedit_length - 1; i >= chg_first + chg_length ; i--)
1099 {
1100 context->preedit_chars[i + diff] = context->preedit_chars[i];
1101 context->feedbacks[i + diff] = context->feedbacks[i];
1102 }
1103 }
1104
1105 for (i = 0; i < new_text_length; i++)
1106 {
1107 context->preedit_chars[chg_first + i] = new_text[i];
1108 context->feedbacks[chg_first + i] = new_xim_text->feedback[i];
1109 }
1110
1111 context->preedit_length += diff;
1112
1113 g_free (new_text);
1114
1115 if (!context->finalizing)
1116 g_signal_emit_by_name (context, "preedit-changed");
1117}
1118
1119
1120static void
1121preedit_caret_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1122 XPointer client_data,
1123 XIMPreeditCaretCallbackStruct *call_data)
1124{
1125 CtkIMContextXIM *context = CTK_IM_CONTEXT_XIM (client_data)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((client_data)), ((ctk_type_im_context_xim))))))
;
1126
1127 if (call_data->direction == XIMAbsolutePosition)
1128 {
1129 context->preedit_cursor = call_data->position;
1130 if (!context->finalizing)
1131 g_signal_emit_by_name (context, "preedit-changed");
1132 }
1133 else
1134 {
1135 g_warning ("Caret movement command: %d %d %d not supported",
1136 call_data->position, call_data->direction, call_data->style);
1137 }
1138}
1139
1140static void
1141status_start_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1142 XPointer client_data G_GNUC_UNUSED__attribute__ ((__unused__)),
1143 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1144{
1145 return;
1146}
1147
1148static void
1149status_done_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1150 XPointer client_data G_GNUC_UNUSED__attribute__ ((__unused__)),
1151 XPointer call_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1152{
1153 return;
1154}
1155
1156static void
1157status_draw_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1158 XPointer client_data,
1159 XIMStatusDrawCallbackStruct *call_data)
1160{
1161 CtkIMContextXIM *context = CTK_IM_CONTEXT_XIM (client_data)((((CtkIMContextXIM*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((client_data)), ((ctk_type_im_context_xim))))))
;
1162
1163 if (call_data->type == XIMTextType)
1164 {
1165 gchar *text;
1166 xim_text_to_utf8 (context, call_data->data.text, &text);
1167
1168 if (context->status_window)
1169 status_window_set_text (context->status_window, text ? text : "");
1170 }
1171 else /* bitmap */
1172 {
1173 g_print ("Status drawn with bitmap - id = %#lx\n", call_data->data.bitmap);
1174 }
1175}
1176
1177static void
1178string_conversion_callback (XIC xic G_GNUC_UNUSED__attribute__ ((__unused__)),
1179 XPointer client_data,
1180 XPointer call_data)
1181{
1182 CtkIMContextXIM *context_xim;
1183 XIMStringConversionCallbackStruct *conv_data;
1184 gchar *surrounding;
1185 gint cursor_index;
1186
1187 context_xim = (CtkIMContextXIM *)client_data;
1188 conv_data = (XIMStringConversionCallbackStruct *)call_data;
1189
1190 if (ctk_im_context_get_surrounding ((CtkIMContext *)context_xim,
1191 &surrounding, &cursor_index))
1192 {
1193 gchar *text = NULL((void*)0);
1194 gsize text_len = 0;
1195 gint subst_offset = 0, subst_nchars = 0;
1196 gint i;
1197 gchar *p = surrounding + cursor_index, *q;
1198 gshort position = (gshort)conv_data->position;
1199
1200 if (position > 0)
1201 {
1202 for (i = position; i > 0 && *p; --i)
1203 p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
1204 if (i > 0)
1205 return;
1206 }
1207 /* According to X11R6.4 Xlib - C Library Reference Manual
1208 * section 13.5.7.3 String Conversion Callback,
1209 * XIMStringConversionPosition is starting position _relative_
1210 * to current client's cursor position. So it should be able
1211 * to be negative, or referring to a position before the cursor
1212 * would be impossible. But current X protocol defines this as
1213 * unsigned short. So, compiler may warn about the value range
1214 * here. We hope the X protocol is fixed soon.
1215 */
1216 else if (position < 0)
1217 {
1218 for (i = position; i < 0 && p > surrounding; ++i)
1219 p = g_utf8_prev_char (p);
1220 if (i < 0)
1221 return;
1222 }
1223
1224 switch (conv_data->direction)
1225 {
1226 case XIMForwardChar:
1227 for (i = conv_data->factor, q = p; i > 0 && *q; --i)
1228 q = g_utf8_next_char (q)((q) + g_utf8_skip[*(const guchar *)(q)]);
1229 if (i > 0)
1230 break;
1231 text = g_locale_from_utf8 (p, q - p, NULL((void*)0), &text_len, NULL((void*)0));
1232 subst_offset = position;
1233 subst_nchars = conv_data->factor;
1234 break;
1235
1236 case XIMBackwardChar:
1237 for (i = conv_data->factor, q = p; i > 0 && q > surrounding; --i)
1238 q = g_utf8_prev_char (q);
1239 if (i > 0)
1240 break;
1241 text = g_locale_from_utf8 (q, p - q, NULL((void*)0), &text_len, NULL((void*)0));
1242 subst_offset = position - conv_data->factor;
1243 subst_nchars = conv_data->factor;
1244 break;
1245
1246 case XIMForwardWord:
1247 case XIMBackwardWord:
1248 case XIMCaretUp:
1249 case XIMCaretDown:
1250 case XIMNextLine:
1251 case XIMPreviousLine:
1252 case XIMLineStart:
1253 case XIMLineEnd:
1254 case XIMAbsolutePosition:
1255 case XIMDontChange:
1256 default:
1257 break;
1258 }
1259 /* block out any failure happenning to "text", including conversion */
1260 if (text)
1261 {
1262 conv_data->text = (XIMStringConversionText *)
1263 malloc (sizeof (XIMStringConversionText));
1264 if (conv_data->text)
1265 {
1266 conv_data->text->length = text_len;
1267 conv_data->text->feedback = NULL((void*)0);
1268 conv_data->text->encoding_is_wchar = False0;
1269 conv_data->text->string.mbs = (char *)malloc (text_len);
1270 if (conv_data->text->string.mbs)
1271 memcpy (conv_data->text->string.mbs, text, text_len);
1272 else
1273 {
1274 free (conv_data->text);
1275 conv_data->text = NULL((void*)0);
1276 }
1277 }
1278
1279 g_free (text);
1280 }
1281 if (conv_data->operation == XIMStringConversionSubstitution(0x0001)
1282 && subst_nchars > 0)
1283 {
1284 ctk_im_context_delete_surrounding ((CtkIMContext *)context_xim,
1285 subst_offset, subst_nchars);
1286 }
1287
1288 g_free (surrounding);
1289 }
1290}
1291
1292
1293static XVaNestedList
1294set_preedit_callback (CtkIMContextXIM *context_xim)
1295{
1296 context_xim->preedit_start_callback.client_data = (XPointer)context_xim;
1297 context_xim->preedit_start_callback.callback = (XIMProc)preedit_start_callback;
1298 context_xim->preedit_done_callback.client_data = (XPointer)context_xim;
1299 context_xim->preedit_done_callback.callback = (XIMProc)preedit_done_callback;
1300 context_xim->preedit_draw_callback.client_data = (XPointer)context_xim;
1301 context_xim->preedit_draw_callback.callback = (XIMProc)preedit_draw_callback;
1302 context_xim->preedit_caret_callback.client_data = (XPointer)context_xim;
1303 context_xim->preedit_caret_callback.callback = (XIMProc)preedit_caret_callback;
1304 return XVaCreateNestedList (0,
1305 XNPreeditStartCallback"preeditStartCallback", &context_xim->preedit_start_callback,
1306 XNPreeditDoneCallback"preeditDoneCallback", &context_xim->preedit_done_callback,
1307 XNPreeditDrawCallback"preeditDrawCallback", &context_xim->preedit_draw_callback,
1308 XNPreeditCaretCallback"preeditCaretCallback", &context_xim->preedit_caret_callback,
1309 NULL((void*)0));
1310}
1311
1312static XVaNestedList
1313set_status_callback (CtkIMContextXIM *context_xim)
1314{
1315 context_xim->status_start_callback.client_data = (XPointer)context_xim;
1316 context_xim->status_start_callback.callback = (XIMProc)status_start_callback;
1317 context_xim->status_done_callback.client_data = (XPointer)context_xim;
1318 context_xim->status_done_callback.callback = (XIMProc)status_done_callback;
1319 context_xim->status_draw_callback.client_data = (XPointer)context_xim;
1320 context_xim->status_draw_callback.callback = (XIMProc)status_draw_callback;
1321
1322 return XVaCreateNestedList (0,
1323 XNStatusStartCallback"statusStartCallback", &context_xim->status_start_callback,
1324 XNStatusDoneCallback"statusDoneCallback", &context_xim->status_done_callback,
1325 XNStatusDrawCallback"statusDrawCallback", &context_xim->status_draw_callback,
1326 NULL((void*)0));
1327}
1328
1329
1330static void
1331set_string_conversion_callback (CtkIMContextXIM *context_xim, XIC xic)
1332{
1333 if (!context_xim->im_info->supports_string_conversion)
1334 return;
1335
1336 context_xim->string_conversion_callback.client_data = (XPointer)context_xim;
1337 context_xim->string_conversion_callback.callback = (XIMProc)string_conversion_callback;
1338
1339 XSetICValues (xic,
1340 XNStringConversionCallback"stringConversionCallback",
1341 (XPointer)&context_xim->string_conversion_callback,
1342 NULL((void*)0));
1343}
1344
1345static XIC
1346ctk_im_context_xim_get_ic (CtkIMContextXIM *context_xim)
1347{
1348 if (context_xim->im_info == NULL((void*)0) || context_xim->im_info->im == NULL((void*)0))
1349 return NULL((void*)0);
1350
1351 if (context_xim->client_window == NULL((void*)0))
1352 return NULL((void*)0);
1353
1354 if (!context_xim->ic)
1355 {
1356 const char *name1 = NULL((void*)0);
1357 XVaNestedList list1 = NULL((void*)0);
1358 const char *name2 = NULL((void*)0);
1359 XVaNestedList list2 = NULL((void*)0);
1360 XIMStyle im_style = 0;
1361 XIC xic = NULL((void*)0);
1362
1363 if (context_xim->use_preedit &&
1364 (context_xim->im_info->style & PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L)) == XIMPreeditCallbacks0x0002L)
1365 {
1366 im_style |= XIMPreeditCallbacks0x0002L;
1367 name1 = XNPreeditAttributes"preeditAttributes";
1368 list1 = set_preedit_callback (context_xim);
1369 }
1370 else if ((context_xim->im_info->style & PREEDIT_MASK(0x0002L | 0x0004L | 0x0001L | 0x0008L | 0x0010L)) == XIMPreeditNone0x0010L)
1371 im_style |= XIMPreeditNone0x0010L;
1372 else
1373 im_style |= XIMPreeditNothing0x0008L;
1374
1375 if ((context_xim->im_info->style & STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L)) == XIMStatusCallbacks0x0200L)
1376 {
1377 im_style |= XIMStatusCallbacks0x0200L;
1378 if (name1 == NULL((void*)0))
1379 {
1380 name1 = XNStatusAttributes"statusAttributes";
1381 list1 = set_status_callback (context_xim);
1382 }
1383 else
1384 {
1385 name2 = XNStatusAttributes"statusAttributes";
1386 list2 = set_status_callback (context_xim);
1387 }
1388 }
1389 else if ((context_xim->im_info->style & STATUS_MASK(0x0200L | 0x0100L | 0x0400L | 0x0800L)) == XIMStatusNone0x0800L)
1390 im_style |= XIMStatusNone0x0800L;
1391 else
1392 im_style |= XIMStatusNothing0x0400L;
1393
1394 xic = XCreateIC (context_xim->im_info->im,
1395 XNInputStyle"inputStyle", im_style,
1396 XNClientWindow"clientWindow", CDK_WINDOW_XID (context_xim->client_window)(cdk_x11_window_get_xid (context_xim->client_window)),
1397 name1, list1,
1398 name2, list2,
1399 NULL((void*)0));
1400 if (list1)
1401 XFree (list1);
1402 if (list2)
1403 XFree (list2);
1404
1405 if (xic)
1406 {
1407 /* Don't filter key released events with XFilterEvents unless
1408 * input methods ask for. This is a workaround for Solaris input
1409 * method bug in C and European locales. It doubles each key
1410 * stroke if both key pressed and released events are filtered.
1411 * (bugzilla #81759)
1412 */
1413 gulong mask = 0xaaaaaaaa;
1414 XGetICValues (xic,
1415 XNFilterEvents"filterEvents", &mask,
1416 NULL((void*)0));
1417 context_xim->filter_key_release = (mask & KeyReleaseMask(1L<<1)) != 0;
1418 set_string_conversion_callback (context_xim, xic);
1419 }
1420
1421 context_xim->ic = xic;
1422
1423 update_status_window (context_xim);
1424
1425 if (xic && context_xim->has_focus)
1426 XSetICFocus (xic);
1427 }
1428 return context_xim->ic;
1429}
1430
1431/*****************************************************************
1432 * Status Window handling
1433 *
1434 * A status window is a small window attached to the toplevel
1435 * that is used to display information to the user about the
1436 * current input operation.
1437 *
1438 * We claim the toplevel's status window for an input context if:
1439 *
1440 * A) The input context has a toplevel
1441 * B) The input context has the focus
1442 * C) The input context has an XIC associated with it
1443 *
1444 * Tracking A) and C) is pretty reliable since we
1445 * compute A) and create the XIC for C) ourselves.
1446 * For B) we basically have to depend on our callers
1447 * calling ::focus-in and ::focus-out at the right time.
1448 *
1449 * The toplevel is computed by walking up the CdkWindow
1450 * hierarchy from context->client_window until we find a
1451 * window that is owned by some widget, and then calling
1452 * ctk_widget_get_toplevel() on that widget. This should
1453 * handle both cases where we might have CdkWindows without widgets,
1454 * and cases where CtkWidgets have strange window hierarchies
1455 * (like a torn off CtkHandleBox.)
1456 *
1457 * The status window is visible if and only if there is text
1458 * for it; whenever a new CtkIMContextXIM claims the status
1459 * window, we blank out any existing text. We actually only
1460 * create a CtkWindow for the status window the first time
1461 * it is shown; this is an important optimization when we are
1462 * using XIM with something like a simple compose-key input
1463 * method that never needs a status window.
1464 *****************************************************************/
1465
1466/* Called when we no longer need a status window
1467*/
1468static void
1469disclaim_status_window (CtkIMContextXIM *context_xim)
1470{
1471 if (context_xim->status_window)
1472 {
1473 g_assert (context_xim->status_window->context == context_xim)do { if (context_xim->status_window->context == context_xim
) ; else g_assertion_message_expr (((gchar*) 0), "ctkimcontextxim.c"
, 1473, ((const char*) (__func__)), "context_xim->status_window->context == context_xim"
); } while (0)
;
1474
1475 status_window_set_text (context_xim->status_window, "");
1476
1477 context_xim->status_window->context = NULL((void*)0);
1478 context_xim->status_window = NULL((void*)0);
1479 }
1480}
1481
1482/* Called when we need a status window
1483 */
1484static void
1485claim_status_window (CtkIMContextXIM *context_xim)
1486{
1487 if (!context_xim->status_window && context_xim->client_widget)
1488 {
1489 CtkWidget *toplevel = ctk_widget_get_toplevel (context_xim->client_widget);
1490 if (toplevel && ctk_widget_is_toplevel (toplevel))
1491 {
1492 StatusWindow *status_window = status_window_get (toplevel);
1493
1494 if (status_window->context)
1495 disclaim_status_window (status_window->context);
1496
1497 status_window->context = context_xim;
1498 context_xim->status_window = status_window;
1499 }
1500 }
1501}
1502
1503/* Basic call made whenever something changed that might cause
1504 * us to need, or not to need a status window.
1505 */
1506static void
1507update_status_window (CtkIMContextXIM *context_xim)
1508{
1509 if (context_xim->ic && context_xim->in_toplevel && context_xim->has_focus)
1510 claim_status_window (context_xim);
1511 else
1512 disclaim_status_window (context_xim);
1513}
1514
1515/* Updates the in_toplevel flag for @context_xim
1516 */
1517static void
1518update_in_toplevel (CtkIMContextXIM *context_xim)
1519{
1520 if (context_xim->client_widget)
1521 {
1522 CtkWidget *toplevel = ctk_widget_get_toplevel (context_xim->client_widget);
1523
1524 context_xim->in_toplevel = (toplevel && ctk_widget_is_toplevel (toplevel));
1525 }
1526 else
1527 context_xim->in_toplevel = FALSE(0);
1528
1529 /* Some paranoia, in case we don't get a focus out */
1530 if (!context_xim->in_toplevel)
1531 context_xim->has_focus = FALSE(0);
1532
1533 update_status_window (context_xim);
1534}
1535
1536/* Callback when @widget's toplevel changes. It will always
1537 * change from NULL to a window, or a window to NULL;
1538 * we use that intermediate NULL state to make sure
1539 * that we disclaim the toplevel status window for the old
1540 * window.
1541 */
1542static void
1543on_client_widget_hierarchy_changed (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
1544 CtkWidget *old_toplevel G_GNUC_UNUSED__attribute__ ((__unused__)),
1545 CtkIMContextXIM *context_xim)
1546{
1547 update_in_toplevel (context_xim);
1548}
1549
1550/* Finds the CtkWidget that owns the window, or if none, the
1551 * widget owning the nearest parent that has a widget.
1552 */
1553static CtkWidget *
1554widget_for_window (CdkWindow *window)
1555{
1556 while (window)
1557 {
1558 gpointer user_data;
1559 cdk_window_get_user_data (window, &user_data);
1560 if (user_data)
1561 return user_data;
1562
1563 window = cdk_window_get_parent (window);
1564 }
1565
1566 return NULL((void*)0);
1567}
1568
1569/* Called when context_xim->client_window changes; takes care of
1570 * removing and/or setting up our watches for the toplevel
1571 */
1572static void
1573update_client_widget (CtkIMContextXIM *context_xim)
1574{
1575 CtkWidget *new_client_widget = widget_for_window (context_xim->client_window);
1576
1577 if (new_client_widget != context_xim->client_widget)
1578 {
1579 if (context_xim->client_widget)
1580 {
1581 g_signal_handlers_disconnect_by_func (context_xim->client_widget,g_signal_handlers_disconnect_matched ((context_xim->client_widget
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_client_widget_hierarchy_changed
))), (context_xim))
1582 G_CALLBACK (on_client_widget_hierarchy_changed),g_signal_handlers_disconnect_matched ((context_xim->client_widget
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_client_widget_hierarchy_changed
))), (context_xim))
1583 context_xim)g_signal_handlers_disconnect_matched ((context_xim->client_widget
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_client_widget_hierarchy_changed
))), (context_xim))
;
1584 }
1585 context_xim->client_widget = new_client_widget;
1586 if (context_xim->client_widget)
1587 {
1588 g_signal_connect (context_xim->client_widget, "hierarchy-changed",g_signal_connect_data ((context_xim->client_widget), ("hierarchy-changed"
), (((GCallback) (on_client_widget_hierarchy_changed))), (context_xim
), ((void*)0), (GConnectFlags) 0)
1589 G_CALLBACK (on_client_widget_hierarchy_changed),g_signal_connect_data ((context_xim->client_widget), ("hierarchy-changed"
), (((GCallback) (on_client_widget_hierarchy_changed))), (context_xim
), ((void*)0), (GConnectFlags) 0)
1590 context_xim)g_signal_connect_data ((context_xim->client_widget), ("hierarchy-changed"
), (((GCallback) (on_client_widget_hierarchy_changed))), (context_xim
), ((void*)0), (GConnectFlags) 0)
;
1591 }
1592
1593 update_in_toplevel (context_xim);
1594 }
1595}
1596
1597/* Called when the toplevel is destroyed; frees the status window
1598 */
1599static void
1600on_status_toplevel_destroy (CtkWidget *toplevel G_GNUC_UNUSED__attribute__ ((__unused__)),
1601 StatusWindow *status_window)
1602{
1603 status_window_free (status_window);
1604}
1605
1606/* Called when the screen for the toplevel changes; updates the
1607 * screen for the status window to match.
1608 */
1609static void
1610on_status_toplevel_notify_screen (CtkWindow *toplevel,
1611 GParamSpec *pspec G_GNUC_UNUSED__attribute__ ((__unused__)),
1612 StatusWindow *status_window)
1613{
1614 if (status_window->window)
1615 ctk_window_set_screen (CTK_WINDOW (status_window->window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((status_window->window)), ((ctk_window_get_type ()))))
))
,
1616 ctk_widget_get_screen (CTK_WIDGET (toplevel)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_widget_get_type ()))))))
));
1617}
1618
1619/* Called when the toplevel window is moved; updates the position of
1620 * the status window to follow it.
1621 */
1622static gboolean
1623on_status_toplevel_configure (CtkWidget *toplevel,
1624 CdkEventConfigure *event G_GNUC_UNUSED__attribute__ ((__unused__)),
1625 StatusWindow *status_window)
1626{
1627 CdkRectangle rect;
1628 CtkRequisition requisition;
1629 gint y;
1630 gint height;
1631
1632 if (status_window->window)
1633 {
1634G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push clang diagnostic ignored "-Wdeprecated-declarations"
1635 height = cdk_screen_get_height (ctk_widget_get_screen (toplevel));
1636G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop
1637
1638 cdk_window_get_frame_extents (ctk_widget_get_window (toplevel),
1639 &rect);
1640 ctk_widget_get_preferred_size ( (status_window->window),
1641 &requisition, NULL((void*)0));
1642
1643 if (rect.y + rect.height + requisition.height < height)
1644 y = rect.y + rect.height;
1645 else
1646 y = height - requisition.height;
1647
1648 ctk_window_move (CTK_WINDOW (status_window->window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((status_window->window)), ((ctk_window_get_type ()))))
))
, rect.x, y);
1649 }
1650
1651 return FALSE(0);
1652}
1653
1654/* Frees a status window and removes its link from the status_windows list
1655 */
1656static void
1657status_window_free (StatusWindow *status_window)
1658{
1659 status_windows = g_slist_remove (status_windows, status_window);
1660
1661 if (status_window->context)
1662 status_window->context->status_window = NULL((void*)0);
1663
1664 g_signal_handlers_disconnect_by_func (status_window->toplevel,g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_destroy
))), (status_window))
1665 G_CALLBACK (on_status_toplevel_destroy),g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_destroy
))), (status_window))
1666 status_window)g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_destroy
))), (status_window))
;
1667 g_signal_handlers_disconnect_by_func (status_window->toplevel,g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_notify_screen
))), (status_window))
1668 G_CALLBACK (on_status_toplevel_notify_screen),g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_notify_screen
))), (status_window))
1669 status_window)g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_notify_screen
))), (status_window))
;
1670 g_signal_handlers_disconnect_by_func (status_window->toplevel,g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_configure
))), (status_window))
1671 G_CALLBACK (on_status_toplevel_configure),g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_configure
))), (status_window))
1672 status_window)g_signal_handlers_disconnect_matched ((status_window->toplevel
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (on_status_toplevel_configure
))), (status_window))
;
1673
1674 if (status_window->window)
1675 ctk_widget_destroy (status_window->window);
1676
1677 g_object_set_data (G_OBJECT (status_window->toplevel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((status_window->toplevel)), (((GType) ((20) << (
2))))))))
, "ctk-im-xim-status-window", NULL((void*)0));
1678
1679 g_free (status_window);
1680}
1681
1682/* Finds the status window object for a toplevel, creating it if necessary.
1683 */
1684static StatusWindow *
1685status_window_get (CtkWidget *toplevel)
1686{
1687 StatusWindow *status_window;
1688
1689 status_window = g_object_get_data (G_OBJECT (toplevel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), (((GType) ((20) << (2))))))))
, "ctk-im-xim-status-window");
1690 if (status_window)
1691 return status_window;
1692
1693 status_window = g_new0 (StatusWindow, 1)((StatusWindow *) g_malloc0_n ((1), sizeof (StatusWindow)));
1694 status_window->toplevel = toplevel;
1695
1696 status_windows = g_slist_prepend (status_windows, status_window);
1697
1698 g_signal_connect (toplevel, "destroy",g_signal_connect_data ((toplevel), ("destroy"), (((GCallback)
(on_status_toplevel_destroy))), (status_window), ((void*)0),
(GConnectFlags) 0)
1699 G_CALLBACK (on_status_toplevel_destroy),g_signal_connect_data ((toplevel), ("destroy"), (((GCallback)
(on_status_toplevel_destroy))), (status_window), ((void*)0),
(GConnectFlags) 0)
1700 status_window)g_signal_connect_data ((toplevel), ("destroy"), (((GCallback)
(on_status_toplevel_destroy))), (status_window), ((void*)0),
(GConnectFlags) 0)
;
1701 g_signal_connect (toplevel, "configure-event",g_signal_connect_data ((toplevel), ("configure-event"), (((GCallback
) (on_status_toplevel_configure))), (status_window), ((void*)
0), (GConnectFlags) 0)
1702 G_CALLBACK (on_status_toplevel_configure),g_signal_connect_data ((toplevel), ("configure-event"), (((GCallback
) (on_status_toplevel_configure))), (status_window), ((void*)
0), (GConnectFlags) 0)
1703 status_window)g_signal_connect_data ((toplevel), ("configure-event"), (((GCallback
) (on_status_toplevel_configure))), (status_window), ((void*)
0), (GConnectFlags) 0)
;
1704 g_signal_connect (toplevel, "notify::screen",g_signal_connect_data ((toplevel), ("notify::screen"), (((GCallback
) (on_status_toplevel_notify_screen))), (status_window), ((void
*)0), (GConnectFlags) 0)
1705 G_CALLBACK (on_status_toplevel_notify_screen),g_signal_connect_data ((toplevel), ("notify::screen"), (((GCallback
) (on_status_toplevel_notify_screen))), (status_window), ((void
*)0), (GConnectFlags) 0)
1706 status_window)g_signal_connect_data ((toplevel), ("notify::screen"), (((GCallback
) (on_status_toplevel_notify_screen))), (status_window), ((void
*)0), (GConnectFlags) 0)
;
1707
1708 g_object_set_data (G_OBJECT (toplevel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), (((GType) ((20) << (2))))))))
, "ctk-im-xim-status-window", status_window);
1709
1710 return status_window;
1711}
1712
1713/* Creates the widgets for the status window; called when we
1714 * first need to show text for the status window.
1715 */
1716static void
1717status_window_make_window (StatusWindow *status_window)
1718{
1719 CtkWidget *window;
1720 CtkWidget *status_label;
1721
1722 status_window->window = ctk_window_new (CTK_WINDOW_POPUP);
1723 window = status_window->window;
1724
1725 ctk_window_set_resizable (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, FALSE(0));
1726
1727 status_label = ctk_label_new ("");
1728 g_object_set (status_label, "margin", 1, NULL((void*)0));
1729 ctk_widget_show (status_label);
1730
1731 ctk_container_add (CTK_CONTAINER (window)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_container_get_type ()))))))
, status_label);
1732
1733 ctk_window_set_screen (CTK_WINDOW (status_window->window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((status_window->window)), ((ctk_window_get_type ()))))
))
,
1734 ctk_widget_get_screen (status_window->toplevel));
1735
1736 on_status_toplevel_configure (status_window->toplevel, NULL((void*)0), status_window);
1737}
1738
1739/* Updates the text in the status window, hiding or
1740 * showing the window as necessary.
1741 */
1742static void
1743status_window_set_text (StatusWindow *status_window,
1744 const gchar *text)
1745{
1746 if (text[0])
1747 {
1748 CtkWidget *label;
1749
1750 if (!status_window->window)
1751 status_window_make_window (status_window);
1752
1753 label = ctk_bin_get_child (CTK_BIN (status_window->window)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((status_window->window)), ((ctk_bin_get_type ()))))))
);
1754 ctk_label_set_text (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, text);
1755
1756 ctk_widget_show (status_window->window);
1757 }
1758 else
1759 {
1760 if (status_window->window)
1761 ctk_widget_hide (status_window->window);
1762 }
1763}
1764
1765/**
1766 * ctk_im_context_xim_shutdown:
1767 *
1768 * Destroys all the status windows that are kept by the XIM contexts. This
1769 * function should only be called by the XIM module exit routine.
1770 **/
1771void
1772ctk_im_context_xim_shutdown (void)
1773{
1774 while (status_windows)
1775 status_window_free (status_windows->data);
1776
1777 while (open_ims)
1778 {
1779 CtkXIMInfo *info = open_ims->data;
1780 CdkDisplay *display = cdk_screen_get_display (info->screen);
1781
1782 xim_info_display_closed (display, FALSE(0), info);
1783 open_ims = g_slist_remove_link (open_ims, open_ims);
1784 }
1785}