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