]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkim-x11.c
Fixed off-by-one error when computing length.
[~andy/gtk] / gdk / x11 / gdkim-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <X11/Xlocale.h>
21 #include "gdk.h"
22 #include "gdkprivate.h"
23 #include "gdki18n.h"
24 #include "gdkx.h"
25
26 #if HAVE_CONFIG_H
27 #  include <config.h>
28 #  if STDC_HEADERS
29 #    include <string.h>
30 #  endif
31 #endif
32
33
34 /* If this variable is FALSE, it indicates that we should
35  * avoid trying to use multibyte conversion functions and
36  * assume everything is 1-byte per character
37  */
38 static gboolean gdk_use_mb;
39
40 #ifdef USE_XIM
41
42 #include <stdarg.h>
43 #include <X11/Xresource.h>
44
45 /* The following routines duplicate functionality in Xlib to
46  * translate from varargs to X's internal opaque XVaNestedList.
47  * 
48  * If all vendors have stuck close to the reference implementation,
49  * then we should hopefully be OK. 
50  */
51
52 typedef struct {
53   gchar   *name;
54   gpointer value;
55 } GdkImArg;
56
57 static void   gdk_im_instantiate_cb      (Display *display,
58                                           XPointer client_data,
59                                           XPointer call_data);
60 static void   gdk_im_destroy_cb          (XIM im,
61                                           XPointer client_data,
62                                           XPointer call_data);
63
64 static void   gdk_ic_real_new            (GdkIC *ic);
65
66 static GdkICAttributesType gdk_ic_real_set_attr (GdkIC *ic,
67                                                  GdkICAttr           *attr,
68                                                  GdkICAttributesType  mask);
69
70 static XIM        xim_im;                       /* global IM */
71 static XIMStyles* xim_styles;                   /* im supports these styles */
72 static XIMStyle xim_best_allowed_style;
73 static GList* xim_ic_list;
74
75 #endif /* USE_XIM */
76
77 /*
78  *--------------------------------------------------------------
79  * gdk_set_locale
80  *
81  * Arguments:
82  *
83  * Results:
84  *
85  * Side effects:
86  *
87  *--------------------------------------------------------------
88  */
89
90 gchar*
91 gdk_set_locale (void)
92 {
93   wchar_t result;
94   gchar *current_locale;
95
96   gdk_use_mb = FALSE;
97
98   if (!setlocale (LC_ALL,""))
99     g_message ("locale not supported by C library");
100   
101   if (!XSupportsLocale ())
102     {
103       g_message ("locale not supported by Xlib, locale set to C");
104       setlocale (LC_ALL, "C");
105     }
106   
107   if (!XSetLocaleModifiers (""))
108     g_message ("can not set locale modifiers");
109
110   current_locale = setlocale (LC_ALL, NULL);
111
112   if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
113     {
114       gdk_use_mb = TRUE;
115
116 #ifndef X_LOCALE
117       /* Detect GNU libc, where mb == UTF8. Not useful unless it's
118        * really a UTF8 locale. The below still probably will
119        * screw up on Greek, Cyrillic, etc, encoded as UTF8.
120        */
121       
122       if ((MB_CUR_MAX == 2) &&
123           (mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
124           result == 0x765)
125         {
126           if ((strlen (current_locale) < 4) ||
127               g_strcasecmp (current_locale + strlen(current_locale) - 4, "utf8"))
128             gdk_use_mb = FALSE;
129         }
130 #endif /* X_LOCALE */
131     }
132
133   GDK_NOTE (XIM,
134             g_message ("%s multi-byte string functions.", 
135                        gdk_use_mb ? "Using" : "Not using"));
136   
137   return current_locale;
138 }
139
140 #ifdef USE_XIM
141
142 /*
143  *--------------------------------------------------------------
144  * gdk_im_begin
145  *
146  *   Begin using input method with XIM Protocol(X11R6 standard)
147  *
148  * Arguments:
149  *   "ic" is the "Input Context" which is created by gtk_ic_new.
150  *   The input area is specified with "window".
151  *
152  * Results:
153  *   The gdk's event handling routine is switched to XIM based routine.
154  *   XIM based routine uses XFilterEvent to get rid of events used by IM,
155  *   and uses XmbLookupString instead of XLookupString.
156  *
157  * Side effects:
158  *
159  *--------------------------------------------------------------
160  */
161
162 void 
163 gdk_im_begin (GdkIC *ic, GdkWindow* window)
164 {
165   GdkICPrivate *private;
166   GdkICAttr attr;
167   
168   g_return_if_fail (ic != NULL);
169   
170   private = (GdkICPrivate *) ic;
171   
172   attr.focus_window = window;
173   gdk_ic_set_attr (ic, &attr, GDK_IC_FOCUS_WINDOW);
174
175   if (private != gdk_xim_ic)
176     {
177       gdk_im_end();
178       if (private->xic)
179         {
180           XSetICFocus (private->xic);
181           GDK_NOTE (XIM, g_print ("im_begin icfocus : %p(%ld)\n",
182                                   private->xic,
183                                   GDK_WINDOW_XWINDOW(private->attr->focus_window)));
184         }
185     }
186   gdk_xim_ic = private;
187   gdk_xim_window = window;
188 }
189
190 /*
191  *--------------------------------------------------------------
192  * gdk_im_end
193  *
194  *   End using input method with XIM Protocol(X11R6 standard)
195  *
196  * Arguments:
197  *
198  * Results:
199  *   The gdk's event handling routine is switched to normal routine.
200  *   User should call this function before ic and window will be destroyed.
201  *
202  * Side effects:
203  *
204  *--------------------------------------------------------------
205  */
206
207 void 
208 gdk_im_end (void)
209 {
210   if (gdk_xim_ic && gdk_xim_ic->xic)
211     {
212       XUnsetICFocus (gdk_xim_ic->xic);
213       GDK_NOTE (XIM, g_print ("im_end unfocus : %p\n", gdk_xim_ic->xic));
214     }
215   gdk_xim_ic = NULL;
216   gdk_xim_window = NULL;
217 }
218
219 static GdkIMStyle 
220 gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) 
221 {
222   GdkIMStyle s1, s2, u;
223   
224   if (style1 == 0) return style2;
225   if (style2 == 0) return style1;
226   if ((style1 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK))
227         == (style2 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK)))
228     return style1;
229
230   s1 = style1 & GDK_IM_PREEDIT_MASK;
231   s2 = style2 & GDK_IM_PREEDIT_MASK;
232   u = s1 | s2;
233   if (s1 != s2) {
234     if (u & GDK_IM_PREEDIT_CALLBACKS)
235       return (s1 == GDK_IM_PREEDIT_CALLBACKS)? style1:style2;
236     else if (u & GDK_IM_PREEDIT_POSITION)
237       return (s1 == GDK_IM_PREEDIT_POSITION)? style1:style2;
238     else if (u & GDK_IM_PREEDIT_AREA)
239       return (s1 == GDK_IM_PREEDIT_AREA)? style1:style2;
240     else if (u & GDK_IM_PREEDIT_NOTHING)
241       return (s1 == GDK_IM_PREEDIT_NOTHING)? style1:style2;
242   } else {
243     s1 = style1 & GDK_IM_STATUS_MASK;
244     s2 = style2 & GDK_IM_STATUS_MASK;
245     u = s1 | s2;
246     if ( u & GDK_IM_STATUS_CALLBACKS)
247       return (s1 == GDK_IM_STATUS_CALLBACKS)? style1:style2;
248     else if ( u & GDK_IM_STATUS_AREA)
249       return (s1 == GDK_IM_STATUS_AREA)? style1:style2;
250     else if ( u & GDK_IM_STATUS_NOTHING)
251       return (s1 == GDK_IM_STATUS_NOTHING)? style1:style2;
252     else if ( u & GDK_IM_STATUS_NONE)
253       return (s1 == GDK_IM_STATUS_NONE)? style1:style2;
254   }
255   return 0; /* Get rid of stupid warning */
256 }
257
258 GdkIMStyle
259 gdk_im_decide_style (GdkIMStyle supported_style)
260 {
261   gint i;
262   GdkIMStyle style, tmp;
263   
264   g_return_val_if_fail (xim_styles != NULL, 0);
265   
266   style = 0;
267   for (i=0; i<xim_styles->count_styles; i++)
268     {
269       tmp = xim_styles->supported_styles[i];
270       if (tmp == (tmp & supported_style & xim_best_allowed_style))
271         style = gdk_im_choose_better_style (style, tmp);
272     }
273   return style;
274 }
275
276 GdkIMStyle
277 gdk_im_set_best_style (GdkIMStyle style)
278 {
279   if (style & GDK_IM_PREEDIT_MASK)
280     {
281       xim_best_allowed_style &= ~GDK_IM_PREEDIT_MASK;
282
283       xim_best_allowed_style |= GDK_IM_PREEDIT_NONE;
284       if (!(style & GDK_IM_PREEDIT_NONE))
285         {
286           xim_best_allowed_style |= GDK_IM_PREEDIT_NOTHING;
287           if (!(style & GDK_IM_PREEDIT_NOTHING))
288             {
289               xim_best_allowed_style |= GDK_IM_PREEDIT_AREA;
290               if (!(style & GDK_IM_PREEDIT_AREA))
291                 {
292                   xim_best_allowed_style |= GDK_IM_PREEDIT_POSITION;
293                   if (!(style & GDK_IM_PREEDIT_POSITION))
294                     xim_best_allowed_style |= GDK_IM_PREEDIT_CALLBACKS;
295                 }
296             }
297         }
298     }
299   if (style & GDK_IM_STATUS_MASK)
300     {
301       xim_best_allowed_style &= ~GDK_IM_STATUS_MASK;
302
303       xim_best_allowed_style |= GDK_IM_STATUS_NONE;
304       if (!(style & GDK_IM_STATUS_NONE))
305         {
306           xim_best_allowed_style |= GDK_IM_STATUS_NOTHING;
307           if (!(style & GDK_IM_STATUS_NOTHING))
308             {
309               xim_best_allowed_style |= GDK_IM_STATUS_AREA;
310               if (!(style & GDK_IM_STATUS_AREA))
311                 xim_best_allowed_style |= GDK_IM_STATUS_CALLBACKS;
312             }
313         }
314     }
315   
316   return xim_best_allowed_style;
317 }
318
319 static void
320 gdk_im_destroy_cb (XIM im, XPointer client_data, XPointer call_data)
321 {
322   GList *node;
323   GdkICPrivate *private;
324
325   GDK_NOTE (XIM, g_message ("Ouch, Input Method is destroyed!!\n"));
326
327   xim_im = NULL;
328
329   if (xim_styles)
330     {
331       XFree (xim_styles);
332       xim_styles = NULL;
333     }
334
335   for (node = xim_ic_list; node != NULL; node = g_list_next(node))
336     {
337       private = (GdkICPrivate *) (node->data);
338       private->xic = NULL;
339     }
340
341   XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL,
342                                   gdk_im_instantiate_cb, NULL);
343 }
344
345 static void
346 gdk_im_instantiate_cb (Display *display,
347                        XPointer client_data, XPointer call_data)
348 {
349   XIMCallback destroy_cb;
350   GList *node;
351
352   GDK_NOTE (XIM, g_message ("New IM is instantiated."));
353   if (display != gdk_display)
354     return;
355
356   XUnregisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL,
357                                     gdk_im_instantiate_cb, NULL);
358
359   xim_im = XOpenIM (GDK_DISPLAY(), NULL, NULL, NULL);
360   if (xim_im == NULL)
361     GDK_NOTE (XIM, g_warning ("Unable to open open IM."));
362
363   destroy_cb.callback = gdk_im_destroy_cb;
364   destroy_cb.client_data = NULL;
365   XSetIMValues (xim_im, XNDestroyCallback, &destroy_cb, NULL);
366
367   XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL);
368
369   for (node = xim_ic_list; node != NULL; node = g_list_next(node))
370     {
371       GdkICPrivate *private = (GdkICPrivate *) (node->data);
372       if (private->xic == NULL)
373         gdk_ic_real_new ((GdkIC *)private);
374     }
375 }
376
377 gint 
378 gdk_im_open (void)
379 {
380   gdk_xim_ic = NULL;
381   gdk_xim_window = (GdkWindow*)NULL;
382   xim_im = NULL;
383   xim_styles = NULL;
384
385   /* initialize XIM Protocol variables */
386   if (!(xim_best_allowed_style & GDK_IM_PREEDIT_MASK))
387     gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
388   if (!(xim_best_allowed_style & GDK_IM_STATUS_MASK))
389     gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
390
391   XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL,
392                                   gdk_im_instantiate_cb, NULL);
393
394   return (xim_im != NULL);
395 }
396
397 void 
398 gdk_im_close (void)
399 {
400   if (xim_im)
401     {
402       XCloseIM (xim_im);
403       xim_im = NULL;
404     }
405   if (xim_styles)
406     {
407       XFree (xim_styles);
408       xim_styles = NULL;
409     }
410 }
411
412 gint 
413 gdk_im_ready (void)
414 {
415   return (xim_im != NULL);
416 }
417
418 static void
419 gdk_ic_real_new (GdkIC *ic)
420 {
421   XPoint spot_location;
422   XRectangle preedit_area;
423   XRectangle status_area;
424   XVaNestedList *preedit_attr = NULL;
425   XVaNestedList *status_attr = NULL;
426   GdkICAttr *attr;
427   GdkICPrivate *private;
428   GdkICAttributesType mask = GDK_IC_ALL_REQ;
429
430   private = (GdkICPrivate *) ic;
431   attr = private->attr;
432
433   switch (attr->style & GDK_IM_PREEDIT_MASK)
434     {
435     case GDK_IM_PREEDIT_AREA:
436       mask |= GDK_IC_PREEDIT_AREA_REQ;
437
438       preedit_area.x = attr->preedit_area.x;
439       preedit_area.y = attr->preedit_area.x;
440       preedit_area.width = attr->preedit_area.width;
441       preedit_area.height = attr->preedit_area.height;
442
443       preedit_attr = XVaCreateNestedList (0,
444                                           XNArea, &preedit_area,
445                                           XNFontSet,
446                                           GDK_FONT_XFONT(attr->preedit_fontset),
447                                           NULL);
448       break;
449
450     case GDK_IM_PREEDIT_POSITION:
451       mask |= GDK_IC_PREEDIT_POSITION_REQ;
452
453       preedit_area.x = attr->preedit_area.x;
454       preedit_area.y = attr->preedit_area.x;
455       preedit_area.width = attr->preedit_area.width;
456       preedit_area.height = attr->preedit_area.height;
457
458       spot_location.x = attr->spot_location.x;
459       spot_location.y = attr->spot_location.y;
460
461       preedit_attr = XVaCreateNestedList (0,
462                                           XNArea, &preedit_area,
463                                           XNFontSet,
464                                           GDK_FONT_XFONT(attr->preedit_fontset),
465                                           XNSpotLocation, &spot_location,
466                                           NULL);
467       break;
468     }
469
470   switch (attr->style & GDK_IM_STATUS_MASK)
471     {
472     case GDK_IM_STATUS_AREA:
473       mask |= GDK_IC_STATUS_AREA_REQ;
474
475       status_area.x = attr->status_area.x;
476       status_area.y = attr->status_area.x;
477       status_area.width = attr->status_area.width;
478       status_area.height = attr->status_area.height;
479
480       status_attr = XVaCreateNestedList (0,
481                                          XNArea, &status_area,
482                                          XNFontSet,
483                                          GDK_FONT_XFONT(attr->status_fontset),
484                                          NULL);
485       break;
486     }
487
488   if (preedit_attr != NULL && status_attr != NULL)
489     private->xic = XCreateIC (xim_im,
490                               XNInputStyle,
491                               attr->style,
492                               XNClientWindow,
493                               GDK_WINDOW_XWINDOW(attr->client_window),
494                               XNPreeditAttributes,
495                               preedit_attr,
496                               XNStatusAttributes,
497                               status_attr,
498                               NULL);
499   else if (preedit_attr != NULL)
500     private->xic = XCreateIC (xim_im,
501                               XNInputStyle,
502                               attr->style,
503                               XNClientWindow,
504                               GDK_WINDOW_XWINDOW(attr->client_window),
505                               XNPreeditAttributes,
506                               preedit_attr,
507                               NULL);
508   else if (status_attr != NULL)
509     private->xic = XCreateIC (xim_im,
510                               XNInputStyle,
511                               attr->style,
512                               XNClientWindow,
513                               GDK_WINDOW_XWINDOW(attr->client_window),
514                               XNStatusAttributes,
515                               status_attr,
516                               NULL);
517   else
518     private->xic = XCreateIC (xim_im,
519                               XNInputStyle,
520                               attr->style,
521                               XNClientWindow,
522                               GDK_WINDOW_XWINDOW(attr->client_window),
523                               NULL);
524
525   if (preedit_attr)
526     XFree (preedit_attr);
527   if (status_attr)
528     XFree (status_attr);
529
530   if (private->xic == NULL)
531     g_warning ("can not create input context with specified input style.");
532   else
533     gdk_ic_real_set_attr (ic, private->attr, private->mask & ~mask);
534 }
535
536 GdkIC *
537 gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
538 {
539   GdkICPrivate *private;
540   gboolean error = 0;
541   GdkICAttributesType invalid_mask;
542   GdkICAttr *pattr;
543
544   g_return_val_if_fail (attr != NULL, NULL);
545   g_return_val_if_fail ((mask & GDK_IC_ALL_REQ) == GDK_IC_ALL_REQ, NULL);
546
547   switch (attr->style & GDK_IM_PREEDIT_MASK)
548     {
549     case 0:
550       g_warning ("preedit style is not specified.\n");
551       error = 1;
552       break;
553
554     case GDK_IM_PREEDIT_AREA:
555       if ((mask & GDK_IC_PREEDIT_AREA_REQ) != GDK_IC_PREEDIT_AREA_REQ)
556         error = 4;
557       break;
558
559     case GDK_IM_PREEDIT_POSITION:
560       if ((mask & GDK_IC_PREEDIT_POSITION_REQ) != GDK_IC_PREEDIT_POSITION_REQ)
561         error = 4;
562       break;
563     }
564
565   switch (attr->style & GDK_IM_STATUS_MASK)
566     {
567     case 0:
568       g_warning ("status style is not specified.\n");
569       error = 2;
570       break;
571
572     case GDK_IM_STATUS_AREA:
573       if ((mask & GDK_IC_STATUS_AREA_REQ) != GDK_IC_STATUS_AREA_REQ)
574         error = 8;
575       break;
576     }
577
578   if (error)
579     {
580       if (error & 12)
581         g_warning ("IC attribute is not enough to required input style.\n");
582       return NULL;
583     }
584
585   if (attr->client_window == NULL ||
586       ((GdkWindowPrivate *)attr->client_window)->destroyed)
587     {
588       g_warning ("Client_window is null or already destroyed.\n");
589       return NULL;
590     }
591
592   private = g_new0 (GdkICPrivate, 1);
593   private->attr = pattr = gdk_ic_attr_new ();
594
595   gdk_window_ref (attr->client_window);
596   pattr->client_window = attr->client_window;
597   pattr->style = attr->style;
598   private->mask = GDK_IC_STYLE | GDK_IC_CLIENT_WINDOW;
599   
600   /* XIC is still not created, so following call only copies attributes */
601   invalid_mask = gdk_ic_set_attr ((GdkIC *)private, attr, mask & ~GDK_IC_ALL_REQ);
602
603   switch (attr->style & GDK_IM_PREEDIT_MASK)
604     {
605     case GDK_IM_PREEDIT_AREA:
606       if (invalid_mask & GDK_IC_PREEDIT_AREA_REQ)
607         error = TRUE;
608       break;
609
610     case GDK_IM_PREEDIT_POSITION:
611       if (invalid_mask & GDK_IC_PREEDIT_POSITION_REQ)
612         error = TRUE;
613       break;
614     }
615
616   switch (attr->style & GDK_IM_STATUS_MASK)
617     {
618     case GDK_IM_STATUS_AREA:
619       if (invalid_mask & GDK_IC_STATUS_AREA_REQ)
620         error = TRUE;
621       break;
622     }
623
624   if (error == TRUE)
625     {
626       g_warning ("Essential attributes for required style are invalid.\n");
627       gdk_ic_destroy ((GdkIC *)private);
628       return NULL;
629     }
630
631   if (gdk_im_ready ())
632     gdk_ic_real_new ((GdkIC *)private);
633
634   xim_ic_list = g_list_append (xim_ic_list, private);
635   
636   return (GdkIC *)private;
637 }
638
639 void 
640 gdk_ic_destroy (GdkIC *ic)
641 {
642   GdkICPrivate *private;
643   
644   g_return_if_fail (ic != NULL);
645   
646   private = (GdkICPrivate *) ic;
647   
648   if (gdk_xim_ic == private)
649     gdk_im_end ();
650   
651   GDK_NOTE (XIM, g_print("ic_destroy %p\n", private->xic));
652   if (private->xic != NULL)
653     XDestroyIC (private->xic);
654
655   if (private->mask & GDK_IC_CLIENT_WINDOW)
656     gdk_window_unref (private->attr->client_window);
657   if (private->mask & GDK_IC_FOCUS_WINDOW)
658     gdk_window_unref (private->attr->focus_window);
659
660   if (private->mask & GDK_IC_PREEDIT_FONTSET)
661     gdk_font_unref (private->attr->preedit_fontset);
662   if (private->mask & GDK_IC_PREEDIT_PIXMAP)
663     gdk_pixmap_unref (private->attr->preedit_pixmap);
664   if (private->mask & GDK_IC_PREEDIT_COLORMAP)
665     gdk_colormap_unref (private->attr->preedit_colormap);
666
667   if (private->mask & GDK_IC_STATUS_FONTSET)
668     gdk_font_unref (private->attr->status_fontset);
669   if (private->mask & GDK_IC_STATUS_PIXMAP)
670     gdk_pixmap_unref (private->attr->status_pixmap);
671   if (private->mask & GDK_IC_STATUS_COLORMAP)
672     gdk_colormap_unref (private->attr->status_colormap);
673
674   xim_ic_list = g_list_remove (xim_ic_list, private);
675   gdk_ic_attr_destroy (private->attr);
676   g_free (private);
677 }
678
679 GdkIMStyle
680 gdk_ic_get_style (GdkIC *ic)
681 {
682   GdkICPrivate *private;
683   
684   g_return_val_if_fail (ic != NULL, 0);
685   
686   private = (GdkICPrivate *) ic;
687   
688   return private->attr->style;
689 }
690
691 /*
692  * for keeping binary compatibility if member of ic attributes is added.
693  */
694 GdkICAttr *
695 gdk_ic_attr_new (void)
696 {
697   return g_new0 (GdkICAttr, 1);
698 }
699
700 void
701 gdk_ic_attr_destroy (GdkICAttr *attr)
702 {
703   g_return_if_fail (attr != NULL);
704
705   g_free (attr);
706 }
707
708 static GdkICAttributesType
709 gdk_ic_real_set_attr (GdkIC *ic,
710                       GdkICAttr *attr,
711                       GdkICAttributesType mask)
712 {
713   GdkICPrivate *private = (GdkICPrivate *)ic;
714   XIC xic = private->xic;
715   GdkICAttributesType error = 0;
716   GdkImArg arg[2] = {{NULL, NULL}, {NULL, NULL}};
717
718   if (mask & GDK_IC_FOCUS_WINDOW)
719     {
720       if (XSetICValues (xic, XNFocusWindow,
721                         GDK_WINDOW_XWINDOW(attr->focus_window), NULL) != NULL)
722         error |= GDK_IC_FOCUS_WINDOW;
723     }
724
725   if (mask & GDK_IC_SPOT_LOCATION)
726     {
727       XPoint point;
728
729       point.x = attr->spot_location.x;
730       point.y = attr->spot_location.y;
731
732       arg->name = XNSpotLocation;
733       arg->value = (gpointer) &point;
734
735       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
736         error |= GDK_IC_SPOT_LOCATION;
737     }
738
739   if (mask & GDK_IC_LINE_SPACING)
740     {
741       arg->name = XNLineSpace;
742       arg->value = GINT_TO_POINTER( attr->line_spacing );
743
744       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
745         error |= GDK_IC_LINE_SPACING;
746     }
747
748   if (mask & GDK_IC_CURSOR)
749     {
750       GdkCursorPrivate *cursor = (GdkCursorPrivate *) attr->cursor;
751
752       if (XSetICValues (xic, XNCursor, cursor->xcursor, NULL))
753         error |= GDK_IC_CURSOR;
754     }
755
756   if (mask & GDK_IC_PREEDIT_FONTSET)
757     {
758       arg->name = XNFontSet;
759       arg->value = (gpointer) GDK_FONT_XFONT(attr->preedit_fontset);
760
761       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
762         error |= GDK_IC_PREEDIT_FONTSET;
763     }
764
765   if (mask & GDK_IC_PREEDIT_AREA)
766     {
767       XRectangle rect;
768
769       rect.x = attr->preedit_area.x;
770       rect.y = attr->preedit_area.y;
771       rect.width = attr->preedit_area.width;
772       rect.height = attr->preedit_area.height;
773
774       arg->name = XNArea;
775       arg->value = (gpointer) &rect;
776
777       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
778         error |= GDK_IC_PREEDIT_AREA;
779     }
780
781   if (mask & GDK_IC_PREEDIT_AREA_NEEDED)
782     {
783       XRectangle rect;
784
785       rect.x = attr->preedit_area_needed.x;
786       rect.y = attr->preedit_area_needed.y;
787       rect.width = attr->preedit_area_needed.width;
788       rect.height = attr->preedit_area_needed.height;
789
790       arg->name = XNArea;
791       arg->value = (gpointer) &rect;
792
793       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
794         error |= GDK_IC_PREEDIT_AREA_NEEDED;
795       else
796         private->mask &= ~GDK_IC_PREEDIT_AREA_NEEDED;
797     }
798
799   if (mask & GDK_IC_PREEDIT_FOREGROUND)
800     {
801       arg->name = XNForeground;
802       arg->value = (gpointer) attr->preedit_foreground.pixel;
803
804       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
805         error |= GDK_IC_PREEDIT_FOREGROUND;
806     }
807
808   if (mask & GDK_IC_PREEDIT_BACKGROUND)
809     {
810       arg->name = XNBackground;
811       arg->value = (gpointer) attr->preedit_background.pixel;
812
813       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
814         error |= GDK_IC_PREEDIT_BACKGROUND;
815     }
816
817   if (mask & GDK_IC_PREEDIT_PIXMAP)
818     {
819       arg->name = XNBackgroundPixmap;
820       arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->preedit_pixmap);
821
822       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
823         error |= GDK_IC_PREEDIT_PIXMAP;
824     }
825
826   if (mask & GDK_IC_PREEDIT_COLORMAP)
827     {
828       arg->name = XNColormap;
829       arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->preedit_colormap);
830
831       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
832         error |= GDK_IC_PREEDIT_COLORMAP;
833     }
834
835
836   if (mask & GDK_IC_STATUS_FONTSET)
837     {
838       arg->name = XNFontSet;
839       arg->value = (gpointer) GDK_FONT_XFONT(attr->status_fontset);
840
841       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
842         error |= GDK_IC_STATUS_FONTSET;
843     }
844
845   if (mask & GDK_IC_STATUS_AREA)
846     {
847       XRectangle rect;
848
849       rect.x = attr->status_area.x;
850       rect.y = attr->status_area.y;
851       rect.width = attr->status_area.width;
852       rect.height = attr->status_area.height;
853
854       arg->name = XNArea;
855       arg->value = (gpointer) &rect;
856
857       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
858         error |= GDK_IC_STATUS_AREA;
859     }
860
861   if (mask & GDK_IC_STATUS_AREA_NEEDED)
862     {
863       XRectangle rect;
864
865       rect.x = attr->status_area_needed.x;
866       rect.y = attr->status_area_needed.y;
867       rect.width = attr->status_area_needed.width;
868       rect.height = attr->status_area_needed.height;
869
870       arg->name = XNArea;
871       arg->value = (gpointer) &rect;
872
873       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
874         error |= GDK_IC_STATUS_AREA_NEEDED;
875       else
876         private->mask &= ~GDK_IC_STATUS_AREA_NEEDED;
877     }
878
879   if (mask & GDK_IC_STATUS_FOREGROUND)
880     {
881       arg->name = XNForeground;
882       arg->value = (gpointer) attr->status_foreground.pixel;
883
884       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
885         error |= GDK_IC_STATUS_FOREGROUND;
886     }
887
888   if (mask & GDK_IC_STATUS_BACKGROUND)
889     {
890       arg->name = XNBackground;
891       arg->value = (gpointer) attr->status_background.pixel;
892
893       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
894         error |= GDK_IC_STATUS_BACKGROUND;
895     }
896
897   if (mask & GDK_IC_STATUS_PIXMAP)
898     {
899       arg->name = XNBackgroundPixmap;
900       arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->status_pixmap);
901
902       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
903         error |= GDK_IC_STATUS_PIXMAP;
904     }
905
906   if (mask & GDK_IC_STATUS_COLORMAP)
907     {
908       arg->name = XNColormap;
909       arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->status_colormap);
910
911       if (XSetICValues (xic, XNPreeditAttributes, arg, NULL))
912         error |= GDK_IC_STATUS_COLORMAP;
913     }
914
915   return error;
916 }
917
918 GdkICAttributesType
919 gdk_ic_set_attr (GdkIC *ic,
920                  GdkICAttr *attr,
921                  GdkICAttributesType mask)
922 {
923   GdkICPrivate *private;
924   GdkICAttr *pattr;
925   GdkICAttributesType error = 0;
926   GdkICAttributesType newattr = 0;
927
928   g_return_val_if_fail (ic != NULL, 0);
929   g_return_val_if_fail (attr != NULL, 0);
930
931   private = (GdkICPrivate *) ic;
932   pattr = private->attr;
933
934   /* Check and copy new attributes */
935
936   if (mask & GDK_IC_STYLE)
937     {
938       g_warning ("input style can be specified only when creating new ic.\n");
939       error |= GDK_IC_STYLE;
940     }
941
942   if (mask & GDK_IC_FILTER_EVENTS)
943     {
944       g_warning ("filter events is read only attributes.\n");
945       error |= GDK_IC_FILTER_EVENTS;
946     }
947
948   if (mask & GDK_IC_CLIENT_WINDOW)
949     {
950       g_warning ("client window can be specified only when creating new ic.\n");
951       error |= GDK_IC_CLIENT_WINDOW;
952     }
953
954   if (mask & GDK_IC_FOCUS_WINDOW)
955     {
956       if (attr->focus_window == NULL)
957         {
958           g_warning ("specified focus_window is invalid.\n");
959           error |= GDK_IC_FOCUS_WINDOW;
960         }
961       else if (pattr->focus_window != attr->focus_window)
962         {
963           if (pattr->focus_window != NULL)
964             gdk_window_unref (pattr->focus_window);
965           if (attr->focus_window != NULL)
966             gdk_window_ref (attr->focus_window);
967           pattr->focus_window = attr->focus_window;
968           newattr |= GDK_IC_FOCUS_WINDOW;
969         }
970     }
971
972   if (mask & GDK_IC_SPOT_LOCATION)
973     {
974       pattr->spot_location = attr->spot_location;
975       newattr |= GDK_IC_SPOT_LOCATION;
976     }
977
978   if (mask & GDK_IC_LINE_SPACING)
979     {
980       pattr->line_spacing = attr->line_spacing;
981       newattr |= GDK_IC_LINE_SPACING;
982     }
983
984   if (mask & GDK_IC_CURSOR)
985     {
986       pattr->cursor = attr->cursor;
987       newattr |= GDK_IC_CURSOR;
988     }
989
990   if (mask & GDK_IC_PREEDIT_FONTSET)
991     {
992       if (attr->preedit_fontset == NULL ||
993           attr->preedit_fontset->type != GDK_FONT_FONTSET)
994         {
995           g_warning ("gdk_font is NULL or not a fontset.\n");
996           error |= GDK_IC_PREEDIT_FONTSET;
997         }
998       else if (pattr->preedit_fontset != attr->preedit_fontset)
999         {
1000           if (pattr->preedit_fontset != NULL)
1001             gdk_font_unref (pattr->preedit_fontset);
1002           if (attr->preedit_fontset != NULL)
1003             gdk_font_ref (attr->preedit_fontset);
1004           pattr->preedit_fontset = attr->preedit_fontset;
1005           newattr |= GDK_IC_PREEDIT_FONTSET;
1006         }
1007     }
1008
1009   if (mask & GDK_IC_PREEDIT_AREA)
1010     {
1011       pattr->preedit_area = attr->preedit_area;
1012       newattr |= GDK_IC_PREEDIT_AREA;
1013     }
1014
1015   if (mask & GDK_IC_PREEDIT_AREA_NEEDED)
1016     {
1017       if (attr->preedit_area_needed.width == 0 ||
1018           attr->preedit_area_needed.height == 0)
1019         {
1020           g_warning ("width and height of preedit_area_needed must be non 0.\n");
1021           error |= GDK_IC_PREEDIT_AREA_NEEDED;
1022         }
1023       else
1024         {
1025           pattr->preedit_area_needed = attr->preedit_area_needed;
1026           newattr |= GDK_IC_PREEDIT_AREA_NEEDED;
1027         }
1028     }
1029
1030   if (mask & GDK_IC_PREEDIT_FOREGROUND)
1031     {
1032       pattr->preedit_foreground = attr->preedit_foreground;
1033       newattr |= GDK_IC_PREEDIT_FOREGROUND;
1034     }
1035
1036   if (mask & GDK_IC_PREEDIT_BACKGROUND)
1037     {
1038       pattr->preedit_background = attr->preedit_background;
1039       newattr |= GDK_IC_PREEDIT_BACKGROUND;
1040     }
1041
1042   if (mask & GDK_IC_PREEDIT_PIXMAP)
1043     {
1044       if (attr->preedit_pixmap != NULL &&
1045           ((GdkPixmapPrivate *)attr->preedit_pixmap)->destroyed)
1046         {
1047           g_warning ("Preedit pixmap is already destroyed.\n");
1048           error |= GDK_IC_PREEDIT_PIXMAP;
1049         }
1050       else
1051         {
1052           if (pattr->preedit_pixmap != attr->preedit_pixmap)
1053             {
1054               if (pattr->preedit_pixmap != NULL)
1055                 gdk_pixmap_unref (pattr->preedit_pixmap);
1056               if (attr->preedit_pixmap)
1057                 gdk_pixmap_ref (attr->preedit_pixmap);
1058               pattr->preedit_pixmap = attr->preedit_pixmap;
1059               newattr |= GDK_IC_PREEDIT_PIXMAP;
1060             }
1061         }
1062     }
1063
1064   if (mask & GDK_IC_PREEDIT_COLORMAP)
1065     {
1066       if (pattr->preedit_colormap != attr->preedit_colormap)
1067         {
1068           if (pattr->preedit_colormap != NULL)
1069             gdk_colormap_unref (pattr->preedit_colormap);
1070           if (attr->preedit_colormap != NULL)
1071             gdk_colormap_ref (attr->preedit_colormap);
1072           pattr->preedit_colormap = attr->preedit_colormap;
1073           newattr |= GDK_IC_PREEDIT_COLORMAP;
1074         }
1075     }
1076
1077   if (mask & GDK_IC_STATUS_FONTSET)
1078     {
1079       if (attr->status_fontset == NULL ||
1080           attr->status_fontset->type != GDK_FONT_FONTSET)
1081         {
1082           g_warning ("gdk_font is NULL or not a fontset.\n");
1083           error |= GDK_IC_STATUS_FONTSET;
1084         }
1085       else if (pattr->status_fontset != attr->status_fontset)
1086         {
1087           if (pattr->status_fontset != NULL)
1088             gdk_font_unref (pattr->status_fontset);
1089           if (attr->status_fontset != NULL)
1090             gdk_font_ref (attr->status_fontset);
1091           pattr->status_fontset = attr->status_fontset;
1092           newattr |= GDK_IC_STATUS_FONTSET;
1093         }
1094     }
1095
1096   if (mask & GDK_IC_STATUS_AREA)
1097     {
1098       pattr->status_area = attr->status_area;
1099       newattr |= GDK_IC_STATUS_AREA;
1100     }
1101
1102   if (mask & GDK_IC_STATUS_AREA_NEEDED)
1103     {
1104       if (attr->status_area_needed.width == 0 ||
1105           attr->status_area_needed.height == 0)
1106         {
1107           g_warning ("width and height of status_area_needed must be non 0.\n");
1108           error |= GDK_IC_STATUS_AREA_NEEDED;
1109         }
1110       else
1111         {
1112           pattr->status_area_needed = attr->status_area_needed;
1113           newattr |= GDK_IC_STATUS_AREA_NEEDED;
1114         }
1115     }
1116
1117   if (mask & GDK_IC_STATUS_FOREGROUND)
1118     {
1119       pattr->status_foreground = attr->status_foreground;
1120       newattr |= GDK_IC_STATUS_FOREGROUND;
1121     }
1122
1123   if (mask & GDK_IC_STATUS_BACKGROUND)
1124     {
1125       pattr->status_background = attr->status_background;
1126       newattr |= GDK_IC_STATUS_BACKGROUND;
1127     }
1128
1129   if (mask & GDK_IC_STATUS_PIXMAP)
1130     {
1131       if (attr->status_pixmap != NULL &&
1132           ((GdkPixmapPrivate *)attr->status_pixmap)->destroyed)
1133         {
1134           g_warning ("Preedit pixmap is already destroyed.\n");
1135           error |= GDK_IC_STATUS_PIXMAP;
1136         }
1137       else
1138         {
1139           if (pattr->status_pixmap != attr->status_pixmap)
1140             {
1141               if (pattr->status_pixmap != NULL)
1142                 gdk_pixmap_unref (pattr->status_pixmap);
1143               if (attr->status_pixmap)
1144                 gdk_pixmap_ref (attr->status_pixmap);
1145               pattr->status_pixmap = attr->status_pixmap;
1146               newattr |= GDK_IC_STATUS_PIXMAP;
1147             }
1148         }
1149     }
1150
1151   if (mask & GDK_IC_STATUS_COLORMAP)
1152     {
1153       if (pattr->status_colormap != attr->status_colormap)
1154         {
1155           if (pattr->status_colormap != NULL)
1156             gdk_colormap_unref (pattr->status_colormap);
1157           if (attr->status_colormap != NULL)
1158             gdk_colormap_ref (attr->status_colormap);
1159           pattr->status_colormap = attr->status_colormap;
1160           newattr |= GDK_IC_STATUS_COLORMAP;
1161         }
1162     }
1163
1164   if (private->xic == NULL)
1165     return error;
1166
1167   error |= gdk_ic_real_set_attr (ic, pattr, newattr);
1168
1169   return error;
1170 }
1171
1172 GdkICAttributesType
1173 gdk_ic_get_attr (GdkIC *ic,
1174                  GdkICAttr *attr,
1175                  GdkICAttributesType mask)
1176 {
1177   GdkICPrivate *private;
1178   GdkICAttr *pattr;
1179   GdkICAttributesType known, unknown = 0;
1180
1181   g_return_val_if_fail (ic != NULL, -1);
1182   g_return_val_if_fail (attr != NULL, -1);
1183
1184   private = (GdkICPrivate *) ic;
1185   pattr = private->attr;
1186
1187   known = mask & private->mask;
1188
1189   if (known & GDK_IC_STYLE)
1190     attr->style = pattr->style;
1191   if (known & GDK_IC_CLIENT_WINDOW)
1192     attr->client_window = pattr->client_window;
1193   if (known & GDK_IC_FOCUS_WINDOW)
1194     attr->focus_window = pattr->focus_window;
1195   if (known & GDK_IC_FILTER_EVENTS)
1196     attr->filter_events = pattr->filter_events;
1197   if (known & GDK_IC_LINE_SPACING)
1198     attr->line_spacing = pattr->line_spacing;
1199   if (known & GDK_IC_CURSOR)
1200     attr->cursor = pattr->cursor;
1201
1202   if (known & GDK_IC_PREEDIT_FONTSET)
1203     attr->preedit_fontset = pattr->preedit_fontset;
1204   if (known & GDK_IC_PREEDIT_AREA)
1205     attr->preedit_area = pattr->preedit_area;
1206   if (known & GDK_IC_PREEDIT_AREA_NEEDED)
1207     attr->preedit_area_needed = pattr->preedit_area_needed;
1208   if (known & GDK_IC_PREEDIT_FOREGROUND)
1209     attr->preedit_foreground = pattr->preedit_foreground;
1210   if (known & GDK_IC_PREEDIT_BACKGROUND)
1211     attr->preedit_background = pattr->preedit_background;
1212   if (known & GDK_IC_PREEDIT_PIXMAP)
1213     attr->preedit_pixmap = pattr->preedit_pixmap;
1214   if (known & GDK_IC_PREEDIT_COLORMAP)
1215     attr->preedit_colormap = pattr->preedit_colormap;
1216
1217   if (known & GDK_IC_STATUS_FONTSET)
1218     attr->status_fontset = pattr->status_fontset;
1219   if (known & GDK_IC_STATUS_AREA)
1220     attr->status_area = pattr->status_area;
1221   if (known & GDK_IC_STATUS_AREA_NEEDED)
1222     attr->status_area_needed = pattr->status_area_needed;
1223   if (known & GDK_IC_STATUS_FOREGROUND)
1224     attr->status_foreground = pattr->status_foreground;
1225   if (known & GDK_IC_STATUS_BACKGROUND)
1226     attr->status_background = pattr->status_background;
1227   if (known & GDK_IC_STATUS_PIXMAP)
1228     attr->status_pixmap = pattr->status_pixmap;
1229   if (known & GDK_IC_STATUS_COLORMAP)
1230     attr->status_colormap = pattr->status_colormap;
1231
1232   if (private->xic)
1233     {
1234       unknown = mask & ~(private->mask);
1235
1236       if (unknown & GDK_IC_FOCUS_WINDOW)
1237         attr->focus_window = pattr->client_window;
1238       if (unknown & GDK_IC_FILTER_EVENTS)
1239         {
1240           gdk_ic_get_events (ic);
1241           attr->filter_events = pattr->filter_events;
1242         }
1243       if (mask & GDK_IC_SPOT_LOCATION)
1244         {
1245           XPoint point;
1246           XVaNestedList *list;
1247           
1248           list = XVaCreateNestedList (0, XNSpotLocation, &point, NULL);
1249           if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL))
1250             unknown &= ~GDK_IC_SPOT_LOCATION;
1251           else
1252             {
1253               pattr->spot_location.x = point.x;
1254               pattr->spot_location.y = point.y;
1255               private->mask |= GDK_IC_SPOT_LOCATION;
1256
1257               attr->spot_location = pattr->spot_location;
1258             }
1259           XFree (list);
1260         }
1261       if (unknown & GDK_IC_PREEDIT_AREA_NEEDED)
1262         {
1263           XRectangle rect;
1264           XVaNestedList *list;
1265
1266           list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL);
1267           if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL))
1268             unknown &= ~GDK_IC_PREEDIT_AREA_NEEDED;
1269           else
1270             {
1271               pattr->preedit_area_needed.x = rect.x;
1272               pattr->preedit_area_needed.y = rect.y;
1273               pattr->preedit_area_needed.width = rect.width;
1274               pattr->preedit_area_needed.height = rect.height;
1275               private->mask |= GDK_IC_PREEDIT_AREA_NEEDED;
1276
1277               attr->preedit_area = pattr->preedit_area;
1278             }
1279           XFree (list);
1280         }
1281       if (unknown & GDK_IC_STATUS_AREA_NEEDED)
1282         {
1283           XRectangle rect;
1284           XVaNestedList *list;
1285
1286           list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL);
1287           if (XGetICValues (private->xic, XNStatusAttributes, list, NULL))
1288             unknown &= ~GDK_IC_STATUS_AREA_NEEDED;
1289           else
1290             {
1291               pattr->status_area_needed.x = rect.x;
1292               pattr->status_area_needed.y = rect.y;
1293               pattr->status_area_needed.width = rect.width;
1294               pattr->status_area_needed.height = rect.height;
1295               private->mask |= GDK_IC_STATUS_AREA_NEEDED;
1296
1297               attr->status_area = pattr->status_area;
1298             }
1299           XFree (list);
1300         }
1301     }
1302
1303   return mask & ~known & ~unknown;
1304 }
1305
1306 GdkEventMask 
1307 gdk_ic_get_events (GdkIC *ic)
1308 {
1309   GdkEventMask mask;
1310   glong xmask;
1311   glong bit;
1312   GdkICPrivate *private;
1313   gint i;
1314   
1315   /*  From gdkwindow.c  */
1316   
1317   g_return_val_if_fail (ic != NULL, 0);
1318   
1319   private = (GdkICPrivate *) ic;
1320
1321   if (private->mask & GDK_IC_FILTER_EVENTS)
1322     return private->attr->filter_events;
1323   
1324   if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL)
1325     {
1326       GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents));
1327       return 0;
1328     }
1329   
1330   mask = 0;
1331   for (i=0, bit=2; i < gdk_nevent_masks; i++, bit <<= 1)
1332     if (xmask & gdk_event_mask_table [i])
1333       {
1334         mask |= bit;
1335         xmask &= ~ gdk_event_mask_table [i];
1336       }
1337   
1338   if (xmask)
1339     g_warning ("ic requires events not supported by the application (%#04lx)", xmask);
1340   
1341   private->attr->filter_events = mask;
1342   private->mask |= GDK_IC_FILTER_EVENTS;
1343
1344   return mask;
1345 }
1346
1347 void 
1348 gdk_ic_cleanup (void)
1349 {
1350   gint destroyed;
1351   
1352   destroyed = 0;
1353   while (xim_ic_list != NULL)
1354     {
1355       gdk_ic_destroy ((GdkIC *) xim_ic_list->data);
1356       destroyed ++;
1357     }
1358 #ifdef G_ENABLE_DEBUG
1359   if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0)
1360     {
1361       g_warning ("Cleaned up %i IC(s)\n", destroyed);
1362     }
1363 #endif /* G_ENABLE_DEBUG */
1364 }
1365
1366 #else /* !USE_XIM */
1367
1368 void 
1369 gdk_im_begin (GdkIC *ic, GdkWindow* window)
1370 {
1371 }
1372
1373 void 
1374 gdk_im_end (void)
1375 {
1376 }
1377
1378 GdkIMStyle
1379 gdk_im_decide_style (GdkIMStyle supported_style)
1380 {
1381   return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1382 }
1383
1384 GdkIMStyle
1385 gdk_im_set_best_style (GdkIMStyle style)
1386 {
1387   return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1388 }
1389
1390 gint 
1391 gdk_im_ready (void)
1392 {
1393   return FALSE;
1394 }
1395
1396 GdkIC * 
1397 gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
1398 {
1399   return NULL;
1400 }
1401
1402 void 
1403 gdk_ic_destroy (GdkIC *ic)
1404 {
1405 }
1406
1407 GdkIMStyle
1408 gdk_ic_get_style (GdkIC *ic)
1409 {
1410   return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1411 }
1412
1413 void 
1414 gdk_ic_set_values (GdkIC *ic, ...)
1415 {
1416 }
1417
1418 void 
1419 gdk_ic_get_values (GdkIC *ic, ...)
1420 {
1421 }
1422
1423 GdkICAttributesType 
1424 gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
1425 {
1426   return 0;
1427 }
1428
1429 GdkICAttributesType 
1430 gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
1431 {
1432   return 0;
1433 }
1434
1435 GdkEventMask 
1436 gdk_ic_get_events (GdkIC *ic)
1437 {
1438   return 0;
1439 }
1440
1441 #endif /* USE_XIM */
1442
1443 /*
1444  * gdk_wcstombs 
1445  *
1446  * Returns a multi-byte string converted from the specified array
1447  * of wide characters. The string is newly allocated. The array of
1448  * wide characters must be null-terminated. If the conversion is
1449  * failed, it returns NULL.
1450  */
1451 gchar *
1452 gdk_wcstombs (const GdkWChar *src)
1453 {
1454   gchar *mbstr;
1455
1456   if (gdk_use_mb)
1457     {
1458       XTextProperty tpr;
1459
1460       if (sizeof(wchar_t) != sizeof(GdkWChar))
1461         {
1462           gint i;
1463           wchar_t *src_alt;
1464           for (i=0; src[i]; i++);
1465           src_alt = g_new (wchar_t, i+1);
1466           for (; i>=0; i--)
1467             src_alt[i] = src[i];
1468           if (XwcTextListToTextProperty (gdk_display, &src_alt, 1, XTextStyle, &tpr)
1469               != Success)
1470             {
1471               g_free (src_alt);
1472               return NULL;
1473             }
1474           g_free (src_alt);
1475         }
1476       else
1477         {
1478           if (XwcTextListToTextProperty (gdk_display, (wchar_t**)&src, 1,
1479                                          XTextStyle, &tpr) != Success)
1480             {
1481               return NULL;
1482             }
1483         }
1484       /*
1485        * We must copy the string into an area allocated by glib, because
1486        * the string 'tpr.value' must be freed by XFree().
1487        */
1488       mbstr = g_strdup(tpr.value);
1489       XFree (tpr.value);
1490     }
1491   else
1492     {
1493       gint length = 0;
1494       gint i;
1495
1496       while (src[length] != 0)
1497         length++;
1498       
1499       mbstr = g_new (gchar, length + 1);
1500
1501       for (i=0; i<length+1; i++)
1502         mbstr[i] = src[i];
1503     }
1504
1505   return mbstr;
1506 }
1507   
1508 /*
1509  * gdk_mbstowcs
1510  *
1511  * Converts the specified string into wide characters, and, returns the
1512  * number of wide characters written. The string 'src' must be
1513  * null-terminated. If the conversion is failed, it returns -1.
1514  */
1515 gint
1516 gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
1517 {
1518   if (gdk_use_mb)
1519     {
1520       XTextProperty tpr;
1521       wchar_t **wstrs, *wstr_src;
1522       gint num_wstrs;
1523       gint len_cpy;
1524       if (XmbTextListToTextProperty (gdk_display, (char **)&src, 1, XTextStyle,
1525                                      &tpr)
1526           != Success)
1527         {
1528           /* NoMem or LocaleNotSupp */
1529           return -1;
1530         }
1531       if (XwcTextPropertyToTextList (gdk_display, &tpr, &wstrs, &num_wstrs)
1532           != Success)
1533         {
1534           /* InvalidChar */
1535           return -1;
1536         }
1537       if (num_wstrs == 0)
1538         return 0;
1539       wstr_src = wstrs[0];
1540       for (len_cpy=0; len_cpy<dest_max && wstr_src[len_cpy]; len_cpy++)
1541         dest[len_cpy] = wstr_src[len_cpy];
1542       XwcFreeStringList (wstrs);
1543       return len_cpy;
1544     }
1545   else
1546     {
1547       gint i;
1548
1549       for (i=0; i<dest_max && src[i]; i++)
1550         dest[i] = src[i];
1551
1552       return i;
1553     }
1554 }