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