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