source: trunk/third/gtk/gdk/gdkim.c @ 17241

Revision 17241, 40.2 KB checked in by ghudson, 23 years ago (diff)
Fill in missing bits of interface for when USE_XIM isn't defined.
Line 
1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22 * file for a list of people on the GTK+ Team.  See the ChangeLog
23 * files for a list of changes.  These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27#include <X11/Xlocale.h>
28#include "gdk.h"
29#include "gdkprivate.h"
30#include "gdki18n.h"
31#include "gdkx.h"
32
33#if HAVE_CONFIG_H
34#  include <config.h>
35#  if STDC_HEADERS
36#    include <string.h>
37#  endif
38#endif
39
40#ifdef USE_NATIVE_LOCALE
41#include <stdlib.h>
42#endif
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 */
48static 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
62typedef struct {
63  gchar   *name;
64  gpointer value;
65} GdkImArg;
66
67#ifdef USE_X11R6_XIM
68static void   gdk_im_instantiate_cb      (Display *display,
69                                          XPointer client_data,
70                                          XPointer call_data);
71#endif
72static void   gdk_im_destroy_cb          (XIM im,
73                                          XPointer client_data,
74                                          XPointer call_data);
75static gint   gdk_im_real_open           (void);
76static void   gdk_ic_real_new            (GdkIC *ic);
77
78static GdkICAttributesType gdk_ic_real_set_attr (GdkIC *ic,
79                                                 GdkICAttr           *attr,
80                                                 GdkICAttributesType  mask);
81
82static XIM        xim_im;                       /* global IM */
83static XIMStyles* xim_styles;                   /* im supports these styles */
84static XIMStyle xim_best_allowed_style;
85static 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
102gchar*
103gdk_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
174void
175gdk_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
219void
220gdk_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
231static GdkIMStyle
232gdk_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
270GdkIMStyle
271gdk_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
288GdkIMStyle
289gdk_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
332static void
333gdk_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
358static void
359gdk_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
374static gint
375gdk_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
408gint
409gdk_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
433void
434gdk_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
448gboolean
449gdk_im_ready (void)
450{
451  return (xim_im != NULL);
452}
453
454static void
455gdk_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
578GdkIC *
579gdk_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      ((GdkWindowPrivate *)attr->client_window)->destroyed)
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
681void
682gdk_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->attr->client_window)
698    gdk_window_unref (private->attr->client_window);
699  if (private->attr->focus_window)
700    gdk_window_unref (private->attr->focus_window);
701
702  if (private->attr->preedit_fontset)
703    gdk_font_unref (private->attr->preedit_fontset);
704  if (private->attr->preedit_pixmap)
705    gdk_pixmap_unref (private->attr->preedit_pixmap);
706  if (private->attr->preedit_colormap)
707    gdk_colormap_unref (private->attr->preedit_colormap);
708
709  if (private->attr->status_fontset)
710    gdk_font_unref (private->attr->status_fontset);
711  if (private->attr->status_pixmap)
712    gdk_pixmap_unref (private->attr->status_pixmap);
713  if (private->attr->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
721GdkIMStyle
722gdk_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 */
736GdkICAttr *
737gdk_ic_attr_new (void)
738{
739  return g_new0 (GdkICAttr, 1);
740}
741
742void
743gdk_ic_attr_destroy (GdkICAttr *attr)
744{
745  g_return_if_fail (attr != NULL);
746
747  g_free (attr);
748}
749
750static GdkICAttributesType
751gdk_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
960GdkICAttributesType
961gdk_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          ((GdkPixmapPrivate *)attr->preedit_pixmap)->destroyed)
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          ((GdkPixmapPrivate *)attr->status_pixmap)->destroyed)
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
1214GdkICAttributesType
1215gdk_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
1348GdkEventMask
1349gdk_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
1389void
1390gdk_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
1410void
1411gdk_im_begin (GdkIC *ic, GdkWindow* window)
1412{
1413}
1414
1415void
1416gdk_im_end (void)
1417{
1418}
1419
1420GdkIMStyle
1421gdk_im_decide_style (GdkIMStyle supported_style)
1422{
1423  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1424}
1425
1426GdkIMStyle
1427gdk_im_set_best_style (GdkIMStyle style)
1428{
1429  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1430}
1431
1432gint
1433gdk_im_ready (void)
1434{
1435  return FALSE;
1436}
1437
1438GdkIC *
1439gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
1440{
1441  return NULL;
1442}
1443
1444void
1445gdk_ic_destroy (GdkIC *ic)
1446{
1447}
1448
1449GdkIMStyle
1450gdk_ic_get_style (GdkIC *ic)
1451{
1452  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
1453}
1454
1455GdkICAttr *
1456gdk_ic_attr_new (void)
1457{
1458  return NULL;
1459}
1460
1461void
1462gdk_ic_attr_destroy (GdkICAttr *attr)
1463{
1464}
1465
1466void
1467gdk_ic_set_values (GdkIC *ic, ...)
1468{
1469}
1470
1471void
1472gdk_ic_get_values (GdkIC *ic, ...)
1473{
1474}
1475
1476GdkICAttributesType
1477gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
1478{
1479  return 0;
1480}
1481
1482GdkICAttributesType
1483gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
1484{
1485  return 0;
1486}
1487
1488GdkEventMask
1489gdk_ic_get_events (GdkIC *ic)
1490{
1491  return 0;
1492}
1493
1494#endif /* USE_XIM */
1495
1496/*
1497 * gdk_wcstombs_len
1498 *
1499 * Returns a multi-byte string converted from the specified array
1500 * of wide characters. The string is newly allocated. The array of
1501 * wide characters is nul-terminated, if len < 0
1502 */
1503
1504#ifdef USE_NATIVE_LOCALE
1505gchar *
1506_gdk_wcstombs_len (const GdkWChar *src,
1507                   gint            src_len)
1508{
1509  gint len = 0;
1510  gint i;
1511  gchar *result = NULL;
1512  gchar buf[16];
1513  gchar *p;
1514
1515  if (MB_CUR_MAX <= 16)
1516    p = buf;
1517  else
1518    p = g_malloc (MB_CUR_MAX);  /* Presumably never hit */
1519
1520  wctomb (NULL, 0);
1521
1522  for (i=0; (src_len < 0 || i < src_len) && src[i]; i++)
1523    {
1524      gint charlen = wctomb (p, src[i]);
1525      if (charlen < 0)
1526        goto out;
1527     
1528      len += charlen;
1529    }
1530
1531  result = g_malloc (len + 1);
1532
1533  /* Old versions of GNU libc apparently can't handle a max of 0 here
1534   */
1535  if (len > 0)
1536    wcstombs (result, (wchar_t *)src, len);
1537 
1538  result[len] = '\0';
1539
1540 out:
1541  if (p != buf)
1542    g_free (p);
1543
1544  return result;
1545}
1546#else /* !USE_NATIVE_LOCALE */
1547
1548gchar *
1549_gdk_wcstombs_len (const GdkWChar *src,
1550                   int             len)
1551{
1552  gchar *mbstr = NULL;
1553  gint length;
1554 
1555  if (len < 0)
1556    {
1557      length = 0;
1558
1559      while (src[length] != 0)
1560        length++;
1561    }
1562  else
1563    length = len;
1564
1565  if (gdk_use_mb)
1566    {
1567      XTextProperty tpr;
1568      wchar_t *src_wc;
1569
1570      /* The len < 0 part is to ensure nul termination
1571       */
1572      if (len < 0 && sizeof(wchar_t) == sizeof(GdkWChar))
1573        {
1574          src_wc = (wchar_t *)src;
1575        }
1576      else
1577        {
1578          gint i;
1579
1580          src_wc = g_new (wchar_t, length + 1);
1581
1582          for (i = 0; i < length; i++)
1583            src_wc[i] = src[i];
1584
1585          src_wc[i] = 0;
1586        }
1587     
1588      if (XwcTextListToTextProperty (gdk_display, &src_wc, 1,
1589                                     XTextStyle, &tpr) == Success)
1590        {
1591          /*
1592           * We must copy the string into an area allocated by glib, because
1593           * the string 'tpr.value' must be freed by XFree().
1594           */
1595          mbstr = g_strdup(tpr.value);
1596          XFree (tpr.value);
1597        }
1598
1599      if (src_wc != (wchar_t *)src)
1600        g_free (src_wc);
1601    }
1602  else
1603    {
1604      gint i;
1605
1606      mbstr = g_new (gchar, length + 1);
1607
1608      for (i=0; i < length; i++)
1609        mbstr[i] = src[i];
1610
1611      mbstr[i] = '\0';
1612    }
1613
1614  return mbstr;
1615}
1616#endif /* !USE_NATIVE_LOCALE */
1617 
1618/*
1619 * gdk_wcstombs
1620 *
1621 * Returns a multi-byte string converted from the specified array
1622 * of wide characters. The string is newly allocated. The array of
1623 * wide characters must be null-terminated. If the conversion is
1624 * failed, it returns NULL.
1625 */
1626gchar *
1627gdk_wcstombs (const GdkWChar *src)
1628{
1629  return _gdk_wcstombs_len (src, -1);
1630}
1631 
1632/*
1633 * gdk_mbstowcs
1634 *
1635 * Converts the specified string into wide characters, and, returns the
1636 * number of wide characters written. The string 'src' must be
1637 * null-terminated. If the conversion is failed, it returns -1.
1638 */
1639gint
1640gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
1641{
1642#ifdef USE_NATIVE_LOCALE
1643  return mbstowcs ((wchar_t *)dest, src, dest_max);
1644#else
1645  if (gdk_use_mb)
1646    {
1647      XTextProperty tpr;
1648      wchar_t **wstrs, *wstr_src;
1649      gint num_wstrs;
1650      gint len_cpy;
1651      if (XmbTextListToTextProperty (gdk_display, (char **)&src, 1, XTextStyle,
1652                                     &tpr)
1653          != Success)
1654        {
1655          /* NoMem or LocaleNotSupp */
1656          return -1;
1657        }
1658      if (XwcTextPropertyToTextList (gdk_display, &tpr, &wstrs, &num_wstrs)
1659          != Success)
1660        {
1661          /* InvalidChar */
1662          XFree(tpr.value);
1663          return -1;
1664        }
1665      XFree(tpr.value);
1666      if (num_wstrs == 0)
1667        return 0;
1668      wstr_src = wstrs[0];
1669      for (len_cpy=0; len_cpy<dest_max && wstr_src[len_cpy]; len_cpy++)
1670        dest[len_cpy] = wstr_src[len_cpy];
1671      XwcFreeStringList (wstrs);
1672      return len_cpy;
1673    }
1674  else
1675    {
1676      gint i;
1677     
1678      for (i=0; i<dest_max && src[i]; i++)
1679        dest[i] = (guchar)src[i];
1680     
1681      return i;
1682    }
1683#endif
1684}
Note: See TracBrowser for help on using the repository browser.