From a309b7dd121980d3b90541bbdada40aaf32c8b27 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Wed, 9 Dec 1998 09:19:36 +0000 Subject: [PATCH] New file that holds code for dealing with X Input Methods. (Missing from last big commit) --- gdk/gdkim.c | 1447 +++++++++++++++++++++++++++++++++++++++++++ gdk/x11/gdkim-x11.c | 1447 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2894 insertions(+) create mode 100644 gdk/gdkim.c create mode 100644 gdk/x11/gdkim-x11.c diff --git a/gdk/gdkim.c b/gdk/gdkim.c new file mode 100644 index 0000000000..235cc5e8d2 --- /dev/null +++ b/gdk/gdkim.c @@ -0,0 +1,1447 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdki18n.h" +#include "gdkx.h" + +#ifdef USE_XIM + +#include +#include + +/* The following routines duplicate functionality in Xlib to + * translate from varargs to X's internal opaque XVaNestedList. + * + * If all vendors have stuck close to the reference implementation, + * then we should hopefully be OK. + */ + +typedef struct { + gchar *name; + gpointer value; +} GdkImArg; + +#ifdef USE_XIM + +static void gdk_im_instantiate_cb (Display *display, + XPointer client_data, + XPointer call_data); +static void gdk_im_destroy_cb (XIM im, + XPointer client_data, + XPointer call_data); + +static void gdk_ic_real_new (GdkIC *ic); + +static GdkICAttributesType gdk_ic_real_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask); + +static XIM xim_im; /* global IM */ +static XIMStyles* xim_styles; /* im supports these styles */ +static XIMStyle xim_best_allowed_style; +static GList* xim_ic_list; + +#endif /* USE_XIM */ + +/* + *-------------------------------------------------------------- + * gdk_im_begin + * + * Begin using input method with XIM Protocol(X11R6 standard) + * + * Arguments: + * "ic" is the "Input Context" which is created by gtk_ic_new. + * The input area is specified with "window". + * + * Results: + * The gdk's event handling routine is switched to XIM based routine. + * XIM based routine uses XFilterEvent to get rid of events used by IM, + * and uses XmbLookupString instead of XLookupString. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ + GdkICPrivate *private; + GdkICAttr attr; + + g_return_if_fail (ic != NULL); + + private = (GdkICPrivate *) ic; + + attr.focus_window = window; + gdk_ic_set_attr (ic, &attr, GDK_IC_FOCUS_WINDOW); + + if (private != gdk_xim_ic) + { + gdk_im_end(); + if (private->xic) + { + XSetICFocus (private->xic); + GDK_NOTE (XIM, g_print ("im_begin icfocus : %p(%ld)\n", + private->xic, + GDK_WINDOW_XWINDOW(private->attr->focus_window))); + } + } + gdk_xim_ic = private; + gdk_xim_window = window; +} + +/* + *-------------------------------------------------------------- + * gdk_im_end + * + * End using input method with XIM Protocol(X11R6 standard) + * + * Arguments: + * + * Results: + * The gdk's event handling routine is switched to normal routine. + * User should call this function before ic and window will be destroyed. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_im_end (void) +{ + if (gdk_xim_ic && gdk_xim_ic->xic) + { + XUnsetICFocus (gdk_xim_ic->xic); + GDK_NOTE (XIM, g_print ("im_end unfocus : %p\n", gdk_xim_ic->xic)); + } + gdk_xim_ic = NULL; + gdk_xim_window = NULL; +} + +static GdkIMStyle +gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) +{ + GdkIMStyle s1, s2, u; + + if (style1 == 0) return style2; + if (style2 == 0) return style1; + if ((style1 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK)) + == (style2 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK))) + return style1; + + s1 = style1 & GDK_IM_PREEDIT_MASK; + s2 = style2 & GDK_IM_PREEDIT_MASK; + u = s1 | s2; + if (s1 != s2) { + if (u & GDK_IM_PREEDIT_CALLBACKS) + return (s1 == GDK_IM_PREEDIT_CALLBACKS)? style1:style2; + else if (u & GDK_IM_PREEDIT_POSITION) + return (s1 == GDK_IM_PREEDIT_POSITION)? style1:style2; + else if (u & GDK_IM_PREEDIT_AREA) + return (s1 == GDK_IM_PREEDIT_AREA)? style1:style2; + else if (u & GDK_IM_PREEDIT_NOTHING) + return (s1 == GDK_IM_PREEDIT_NOTHING)? style1:style2; + } else { + s1 = style1 & GDK_IM_STATUS_MASK; + s2 = style2 & GDK_IM_STATUS_MASK; + u = s1 | s2; + if ( u & GDK_IM_STATUS_CALLBACKS) + return (s1 == GDK_IM_STATUS_CALLBACKS)? style1:style2; + else if ( u & GDK_IM_STATUS_AREA) + return (s1 == GDK_IM_STATUS_AREA)? style1:style2; + else if ( u & GDK_IM_STATUS_NOTHING) + return (s1 == GDK_IM_STATUS_NOTHING)? style1:style2; + else if ( u & GDK_IM_STATUS_NONE) + return (s1 == GDK_IM_STATUS_NONE)? style1:style2; + } + return 0; /* Get rid of stupid warning */ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + gint i; + GdkIMStyle style, tmp; + + g_return_val_if_fail (xim_styles != NULL, 0); + + style = 0; + for (i=0; icount_styles; i++) + { + tmp = xim_styles->supported_styles[i]; + if (tmp == (tmp & supported_style & xim_best_allowed_style)) + style = gdk_im_choose_better_style (style, tmp); + } + return style; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + if (style & GDK_IM_PREEDIT_MASK) + { + xim_best_allowed_style &= ~GDK_IM_PREEDIT_MASK; + + xim_best_allowed_style |= GDK_IM_PREEDIT_NONE; + if (!(style & GDK_IM_PREEDIT_NONE)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_NOTHING; + if (!(style & GDK_IM_PREEDIT_NOTHING)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_AREA; + if (!(style & GDK_IM_PREEDIT_AREA)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_POSITION; + if (!(style & GDK_IM_PREEDIT_POSITION)) + xim_best_allowed_style |= GDK_IM_PREEDIT_CALLBACKS; + } + } + } + } + if (style & GDK_IM_STATUS_MASK) + { + xim_best_allowed_style &= ~GDK_IM_STATUS_MASK; + + xim_best_allowed_style |= GDK_IM_STATUS_NONE; + if (!(style & GDK_IM_STATUS_NONE)) + { + xim_best_allowed_style |= GDK_IM_STATUS_NOTHING; + if (!(style & GDK_IM_STATUS_NOTHING)) + { + xim_best_allowed_style |= GDK_IM_STATUS_AREA; + if (!(style & GDK_IM_STATUS_AREA)) + xim_best_allowed_style |= GDK_IM_STATUS_CALLBACKS; + } + } + } + + return xim_best_allowed_style; +} + +static void +gdk_im_destroy_cb (XIM im, XPointer client_data, XPointer call_data) +{ + GList *node; + GdkICPrivate *private; + + GDK_NOTE (XIM, g_message ("Ouch, Input Method is destroyed!!\n")); + + xim_im = NULL; + + if (xim_styles) + { + XFree (xim_styles); + xim_styles = NULL; + } + + for (node = xim_ic_list; node != NULL; node = g_list_next(node)) + { + private = (GdkICPrivate *) (node->data); + private->xic = NULL; + } + + XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); +} + +static void +gdk_im_instantiate_cb (Display *display, + XPointer client_data, XPointer call_data) +{ + XIMCallback destroy_cb; + GList *node; + + GDK_NOTE (XIM, g_message ("New IM is instantiated.")); + if (display != gdk_display) + return; + + XUnregisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); + + xim_im = XOpenIM (GDK_DISPLAY(), NULL, NULL, NULL); + if (xim_im == NULL) + GDK_NOTE (XIM, g_warning ("Unable to open open IM.")); + + destroy_cb.callback = gdk_im_destroy_cb; + destroy_cb.client_data = NULL; + XSetIMValues (xim_im, XNDestroyCallback, &destroy_cb, NULL); + + XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL); + + for (node = xim_ic_list; node != NULL; node = g_list_next(node)) + { + GdkICPrivate *private = (GdkICPrivate *) (node->data); + if (private->xic == NULL) + gdk_ic_real_new ((GdkIC *)private); + } +} + +gint +gdk_im_open (void) +{ + gdk_xim_ic = NULL; + gdk_xim_window = (GdkWindow*)NULL; + xim_im = NULL; + xim_styles = NULL; + + /* initialize XIM Protocol variables */ + if (!(xim_best_allowed_style & GDK_IM_PREEDIT_MASK)) + gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS); + if (!(xim_best_allowed_style & GDK_IM_STATUS_MASK)) + gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS); + + XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); + + return (xim_im != NULL); +} + +void +gdk_im_close (void) +{ + if (xim_im) + { + XCloseIM (xim_im); + xim_im = NULL; + } + if (xim_styles) + { + XFree (xim_styles); + xim_styles = NULL; + } +} + +gint +gdk_im_ready (void) +{ + return (xim_im != NULL); +} + +static void +gdk_ic_real_new (GdkIC *ic) +{ + XPoint spot_location; + XRectangle preedit_area; + XRectangle status_area; + XVaNestedList *preedit_attr = NULL; + XVaNestedList *status_attr = NULL; + GdkICAttr *attr; + GdkICPrivate *private; + GdkICAttributesType mask = GDK_IC_ALL_REQ; + + private = (GdkICPrivate *) ic; + attr = private->attr; + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case GDK_IM_PREEDIT_AREA: + mask |= GDK_IC_PREEDIT_AREA_REQ; + + preedit_area.x = attr->preedit_area.x; + preedit_area.y = attr->preedit_area.x; + preedit_area.width = attr->preedit_area.width; + preedit_area.height = attr->preedit_area.height; + + preedit_attr = XVaCreateNestedList (0, + XNArea, &preedit_area, + XNFontSet, + GDK_FONT_XFONT(attr->preedit_fontset), + NULL); + break; + + case GDK_IM_PREEDIT_POSITION: + mask |= GDK_IC_PREEDIT_POSITION_REQ; + + preedit_area.x = attr->preedit_area.x; + preedit_area.y = attr->preedit_area.x; + preedit_area.width = attr->preedit_area.width; + preedit_area.height = attr->preedit_area.height; + + spot_location.x = attr->spot_location.x; + spot_location.y = attr->spot_location.y; + + preedit_attr = XVaCreateNestedList (0, + XNArea, &preedit_area, + XNFontSet, + GDK_FONT_XFONT(attr->preedit_fontset), + XNSpotLocation, &spot_location, + NULL); + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case GDK_IM_STATUS_AREA: + mask |= GDK_IC_STATUS_AREA_REQ; + + status_area.x = attr->status_area.x; + status_area.y = attr->status_area.x; + status_area.width = attr->status_area.width; + status_area.height = attr->status_area.height; + + status_attr = XVaCreateNestedList (0, + XNArea, &status_area, + XNFontSet, + GDK_FONT_XFONT(attr->status_fontset), + NULL); + break; + } + + if (preedit_attr != NULL && status_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNPreeditAttributes, + preedit_attr, + XNStatusAttributes, + status_attr, + NULL); + else if (preedit_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNPreeditAttributes, + preedit_attr, + NULL); + else if (status_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNStatusAttributes, + status_attr, + NULL); + else + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + NULL); + + if (preedit_attr) + XFree (preedit_attr); + if (status_attr) + XFree (status_attr); + + if (private->xic == NULL) + g_warning ("can not create input context with specified input style."); + else + gdk_ic_real_set_attr (ic, private->attr, private->mask & ~mask); +} + +GdkIC * +gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask) +{ + GdkICPrivate *private; + gboolean error = 0; + GdkICAttributesType invalid_mask; + GdkICAttr *pattr; + + g_return_val_if_fail (attr != NULL, NULL); + g_return_val_if_fail ((mask & GDK_IC_ALL_REQ) == GDK_IC_ALL_REQ, NULL); + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case 0: + g_warning ("preedit style is not specified.\n"); + error = 1; + break; + + case GDK_IM_PREEDIT_AREA: + if ((mask & GDK_IC_PREEDIT_AREA_REQ) != GDK_IC_PREEDIT_AREA_REQ) + error = 4; + break; + + case GDK_IM_PREEDIT_POSITION: + if ((mask & GDK_IC_PREEDIT_POSITION_REQ) != GDK_IC_PREEDIT_POSITION_REQ) + error = 4; + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case 0: + g_warning ("status style is not specified.\n"); + error = 2; + break; + + case GDK_IM_STATUS_AREA: + if ((mask & GDK_IC_STATUS_AREA_REQ) != GDK_IC_STATUS_AREA_REQ) + error = 8; + break; + } + + if (error) + { + if (error & 12) + g_warning ("IC attribute is not enough to required input style.\n"); + return NULL; + } + + if (attr->client_window == NULL || + ((GdkWindowPrivate *)attr->client_window)->destroyed) + { + g_warning ("Client_window is null or already destroyed.\n"); + return NULL; + } + + private = g_new0 (GdkICPrivate, 1); + private->attr = pattr = gdk_ic_attr_new (); + + gdk_window_ref (attr->client_window); + pattr->client_window = attr->client_window; + pattr->style = attr->style; + private->mask = GDK_IC_STYLE | GDK_IC_CLIENT_WINDOW; + + /* XIC is still not created, so following call only copies attributes */ + invalid_mask = gdk_ic_set_attr ((GdkIC *)private, attr, mask & ~GDK_IC_ALL_REQ); + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case GDK_IM_PREEDIT_AREA: + if (invalid_mask & GDK_IC_PREEDIT_AREA_REQ) + error = TRUE; + break; + + case GDK_IM_PREEDIT_POSITION: + if (invalid_mask & GDK_IC_PREEDIT_POSITION_REQ) + error = TRUE; + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case GDK_IM_STATUS_AREA: + if (invalid_mask & GDK_IC_STATUS_AREA_REQ) + error = TRUE; + break; + } + + if (error == TRUE) + { + g_warning ("Essential attributes for required style are invalid.\n"); + gdk_ic_destroy ((GdkIC *)private); + return NULL; + } + + if (gdk_im_ready ()) + gdk_ic_real_new ((GdkIC *)private); + + xim_ic_list = g_list_append (xim_ic_list, private); + + return (GdkIC *)private; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ + GdkICPrivate *private; + + g_return_if_fail (ic != NULL); + + private = (GdkICPrivate *) ic; + + if (gdk_xim_ic == private) + gdk_im_end (); + + GDK_NOTE (XIM, g_print("ic_destroy %p\n", private->xic)); + if (private->xic != NULL) + XDestroyIC (private->xic); + + if (private->mask & GDK_IC_CLIENT_WINDOW) + gdk_window_unref (private->attr->client_window); + if (private->mask & GDK_IC_FOCUS_WINDOW) + gdk_window_unref (private->attr->focus_window); + + if (private->mask & GDK_IC_PREEDIT_FONTSET) + gdk_font_unref (private->attr->preedit_fontset); + if (private->mask & GDK_IC_PREEDIT_PIXMAP) + gdk_pixmap_unref (private->attr->preedit_pixmap); + if (private->mask & GDK_IC_PREEDIT_COLORMAP) + gdk_colormap_unref (private->attr->preedit_colormap); + + if (private->mask & GDK_IC_STATUS_FONTSET) + gdk_font_unref (private->attr->status_fontset); + if (private->mask & GDK_IC_STATUS_PIXMAP) + gdk_pixmap_unref (private->attr->status_pixmap); + if (private->mask & GDK_IC_STATUS_COLORMAP) + gdk_colormap_unref (private->attr->status_colormap); + + xim_ic_list = g_list_remove (xim_ic_list, private); + gdk_ic_attr_destroy (private->attr); + g_free (private); +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + GdkICPrivate *private; + + g_return_val_if_fail (ic != NULL, 0); + + private = (GdkICPrivate *) ic; + + return private->attr->style; +} + +/* + * for keeping binary compatibility if member of ic attributes is added. + */ +GdkICAttr * +gdk_ic_attr_new (void) +{ + return g_new0 (GdkICAttr, 1); +} + +void +gdk_ic_attr_destroy (GdkICAttr *attr) +{ + g_return_if_fail (attr != NULL); + + g_free (attr); +} + +static GdkICAttributesType +gdk_ic_real_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private = (GdkICPrivate *)ic; + XIC xic = private->xic; + GdkICAttributesType error = 0; + GdkImArg arg[2] = {{NULL, NULL}, {NULL, NULL}}; + + if (mask & GDK_IC_FOCUS_WINDOW) + { + if (XSetICValues (xic, XNFocusWindow, + GDK_WINDOW_XWINDOW(attr->focus_window), NULL) != NULL) + error |= GDK_IC_FOCUS_WINDOW; + } + + if (mask & GDK_IC_SPOT_LOCATION) + { + XPoint point; + + point.x = attr->spot_location.x; + point.y = attr->spot_location.y; + + arg->name = XNSpotLocation; + arg->value = (gpointer) &point; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_SPOT_LOCATION; + } + + if (mask & GDK_IC_LINE_SPACING) + { + arg->name = XNLineSpace; + arg->value = (gpointer) attr->line_spacing; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_LINE_SPACING; + } + + if (mask & GDK_IC_CURSOR) + { + GdkCursorPrivate *cursor = (GdkCursorPrivate *) attr->cursor; + + if (XSetICValues (xic, XNCursor, cursor->xcursor, NULL)) + error |= GDK_IC_CURSOR; + } + + if (mask & GDK_IC_PREEDIT_FONTSET) + { + arg->name = XNFontSet; + arg->value = (gpointer) GDK_FONT_XFONT(attr->preedit_fontset); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_FONTSET; + } + + if (mask & GDK_IC_PREEDIT_AREA) + { + XRectangle rect; + + rect.x = attr->preedit_area.x; + rect.y = attr->preedit_area.y; + rect.width = attr->preedit_area.width; + rect.height = attr->preedit_area.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_AREA; + } + + if (mask & GDK_IC_PREEDIT_AREA_NEEDED) + { + XRectangle rect; + + rect.x = attr->preedit_area_needed.x; + rect.y = attr->preedit_area_needed.y; + rect.width = attr->preedit_area_needed.width; + rect.height = attr->preedit_area_needed.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_AREA_NEEDED; + else + private->mask &= ~GDK_IC_PREEDIT_AREA_NEEDED; + } + + if (mask & GDK_IC_PREEDIT_FOREGROUND) + { + arg->name = XNForeground; + arg->value = (gpointer) attr->preedit_foreground.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_FOREGROUND; + } + + if (mask & GDK_IC_PREEDIT_BACKGROUND) + { + arg->name = XNBackground; + arg->value = (gpointer) attr->preedit_background.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_BACKGROUND; + } + + if (mask & GDK_IC_PREEDIT_PIXMAP) + { + arg->name = XNBackgroundPixmap; + arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->preedit_pixmap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_PIXMAP; + } + + if (mask & GDK_IC_PREEDIT_COLORMAP) + { + arg->name = XNColormap; + arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->preedit_colormap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_COLORMAP; + } + + + if (mask & GDK_IC_STATUS_FONTSET) + { + arg->name = XNFontSet; + arg->value = (gpointer) GDK_FONT_XFONT(attr->status_fontset); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_FONTSET; + } + + if (mask & GDK_IC_STATUS_AREA) + { + XRectangle rect; + + rect.x = attr->status_area.x; + rect.y = attr->status_area.y; + rect.width = attr->status_area.width; + rect.height = attr->status_area.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_AREA; + } + + if (mask & GDK_IC_STATUS_AREA_NEEDED) + { + XRectangle rect; + + rect.x = attr->status_area_needed.x; + rect.y = attr->status_area_needed.y; + rect.width = attr->status_area_needed.width; + rect.height = attr->status_area_needed.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_AREA_NEEDED; + else + private->mask &= ~GDK_IC_STATUS_AREA_NEEDED; + } + + if (mask & GDK_IC_STATUS_FOREGROUND) + { + arg->name = XNForeground; + arg->value = (gpointer) attr->status_foreground.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_FOREGROUND; + } + + if (mask & GDK_IC_STATUS_BACKGROUND) + { + arg->name = XNBackground; + arg->value = (gpointer) attr->status_background.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_BACKGROUND; + } + + if (mask & GDK_IC_STATUS_PIXMAP) + { + arg->name = XNBackgroundPixmap; + arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->status_pixmap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_PIXMAP; + } + + if (mask & GDK_IC_STATUS_COLORMAP) + { + arg->name = XNColormap; + arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->status_colormap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_COLORMAP; + } + + return error; +} + +GdkICAttributesType +gdk_ic_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private; + GdkICAttr *pattr; + GdkICAttributesType error = 0; + GdkICAttributesType newattr = 0; + + g_return_val_if_fail (ic != NULL, 0); + g_return_val_if_fail (attr != NULL, 0); + + private = (GdkICPrivate *) ic; + pattr = private->attr; + + /* Check and copy new attributes */ + + if (mask & GDK_IC_STYLE) + { + g_warning ("input style can be specified only when creating new ic.\n"); + error |= GDK_IC_STYLE; + } + + if (mask & GDK_IC_FILTER_EVENTS) + { + g_warning ("filter events is read only attributes.\n"); + error |= GDK_IC_FILTER_EVENTS; + } + + if (mask & GDK_IC_CLIENT_WINDOW) + { + g_warning ("client window can be specified only when creating new ic.\n"); + error |= GDK_IC_CLIENT_WINDOW; + } + + if (mask & GDK_IC_FOCUS_WINDOW) + { + if (attr->focus_window == NULL) + { + g_warning ("specified focus_window is invalid.\n"); + error |= GDK_IC_FOCUS_WINDOW; + } + else if (pattr->focus_window != attr->focus_window) + { + if (pattr->focus_window != NULL) + gdk_window_unref (pattr->focus_window); + if (attr->focus_window != NULL) + gdk_window_ref (attr->focus_window); + pattr->focus_window = attr->focus_window; + newattr |= GDK_IC_FOCUS_WINDOW; + } + } + + if (mask & GDK_IC_SPOT_LOCATION) + { + pattr->spot_location = attr->spot_location; + newattr |= GDK_IC_SPOT_LOCATION; + } + + if (mask & GDK_IC_LINE_SPACING) + { + pattr->line_spacing = attr->line_spacing; + newattr |= GDK_IC_LINE_SPACING; + } + + if (mask & GDK_IC_CURSOR) + { + pattr->cursor = attr->cursor; + newattr |= GDK_IC_CURSOR; + } + + if (mask & GDK_IC_PREEDIT_FONTSET) + { + if (attr->preedit_fontset == NULL || + attr->preedit_fontset->type != GDK_FONT_FONTSET) + { + g_warning ("gdk_font is NULL or not a fontset.\n"); + error |= GDK_IC_PREEDIT_FONTSET; + } + else if (pattr->preedit_fontset != attr->preedit_fontset) + { + if (pattr->preedit_fontset != NULL) + gdk_font_unref (pattr->preedit_fontset); + if (attr->preedit_fontset != NULL) + gdk_font_ref (attr->preedit_fontset); + pattr->preedit_fontset = attr->preedit_fontset; + newattr |= GDK_IC_PREEDIT_FONTSET; + } + } + + if (mask & GDK_IC_PREEDIT_AREA) + { + pattr->preedit_area = attr->preedit_area; + newattr |= GDK_IC_PREEDIT_AREA; + } + + if (mask & GDK_IC_PREEDIT_AREA_NEEDED) + { + if (attr->preedit_area_needed.width == 0 || + attr->preedit_area_needed.height == 0) + { + g_warning ("width and height of preedit_area_needed must be non 0.\n"); + error |= GDK_IC_PREEDIT_AREA_NEEDED; + } + else + { + pattr->preedit_area_needed = attr->preedit_area_needed; + newattr |= GDK_IC_PREEDIT_AREA_NEEDED; + } + } + + if (mask & GDK_IC_PREEDIT_FOREGROUND) + { + pattr->preedit_foreground = attr->preedit_foreground; + newattr |= GDK_IC_PREEDIT_FOREGROUND; + } + + if (mask & GDK_IC_PREEDIT_BACKGROUND) + { + pattr->preedit_background = attr->preedit_background; + newattr |= GDK_IC_PREEDIT_BACKGROUND; + } + + if (mask & GDK_IC_PREEDIT_PIXMAP) + { + if (attr->preedit_pixmap != NULL && + ((GdkPixmapPrivate *)attr->preedit_pixmap)->destroyed) + { + g_warning ("Preedit pixmap is already destroyed.\n"); + error |= GDK_IC_PREEDIT_PIXMAP; + } + else + { + if (pattr->preedit_pixmap != attr->preedit_pixmap) + { + if (pattr->preedit_pixmap != NULL) + gdk_pixmap_unref (pattr->preedit_pixmap); + if (attr->preedit_pixmap) + gdk_pixmap_ref (attr->preedit_pixmap); + pattr->preedit_pixmap = attr->preedit_pixmap; + newattr |= GDK_IC_PREEDIT_PIXMAP; + } + } + } + + if (mask & GDK_IC_PREEDIT_COLORMAP) + { + if (pattr->preedit_colormap != attr->preedit_colormap) + { + if (pattr->preedit_colormap != NULL) + gdk_colormap_unref (pattr->preedit_colormap); + if (attr->preedit_colormap != NULL) + gdk_colormap_ref (attr->preedit_colormap); + pattr->preedit_colormap = attr->preedit_colormap; + newattr |= GDK_IC_PREEDIT_COLORMAP; + } + } + + if (mask & GDK_IC_STATUS_FONTSET) + { + if (attr->status_fontset == NULL || + attr->status_fontset->type != GDK_FONT_FONTSET) + { + g_warning ("gdk_font is NULL or not a fontset.\n"); + error |= GDK_IC_STATUS_FONTSET; + } + else if (pattr->status_fontset != attr->status_fontset) + { + if (pattr->status_fontset != NULL) + gdk_font_unref (pattr->status_fontset); + if (attr->status_fontset != NULL) + gdk_font_ref (attr->status_fontset); + pattr->status_fontset = attr->status_fontset; + newattr |= GDK_IC_STATUS_FONTSET; + } + } + + if (mask & GDK_IC_STATUS_AREA) + { + pattr->status_area = attr->status_area; + newattr |= GDK_IC_STATUS_AREA; + } + + if (mask & GDK_IC_STATUS_AREA_NEEDED) + { + if (attr->status_area_needed.width == 0 || + attr->status_area_needed.height == 0) + { + g_warning ("width and height of status_area_needed must be non 0.\n"); + error |= GDK_IC_STATUS_AREA_NEEDED; + } + else + { + pattr->status_area_needed = attr->status_area_needed; + newattr |= GDK_IC_STATUS_AREA_NEEDED; + } + } + + if (mask & GDK_IC_STATUS_FOREGROUND) + { + pattr->status_foreground = attr->status_foreground; + newattr |= GDK_IC_STATUS_FOREGROUND; + } + + if (mask & GDK_IC_STATUS_BACKGROUND) + { + pattr->status_background = attr->status_background; + newattr |= GDK_IC_STATUS_BACKGROUND; + } + + if (mask & GDK_IC_STATUS_PIXMAP) + { + if (attr->status_pixmap != NULL && + ((GdkPixmapPrivate *)attr->status_pixmap)->destroyed) + { + g_warning ("Preedit pixmap is already destroyed.\n"); + error |= GDK_IC_STATUS_PIXMAP; + } + else + { + if (pattr->status_pixmap != attr->status_pixmap) + { + if (pattr->status_pixmap != NULL) + gdk_pixmap_unref (pattr->status_pixmap); + if (attr->status_pixmap) + gdk_pixmap_ref (attr->status_pixmap); + pattr->status_pixmap = attr->status_pixmap; + newattr |= GDK_IC_STATUS_PIXMAP; + } + } + } + + if (mask & GDK_IC_STATUS_COLORMAP) + { + if (pattr->status_colormap != attr->status_colormap) + { + if (pattr->status_colormap != NULL) + gdk_colormap_unref (pattr->status_colormap); + if (attr->status_colormap != NULL) + gdk_colormap_ref (attr->status_colormap); + pattr->status_colormap = attr->status_colormap; + newattr |= GDK_IC_STATUS_COLORMAP; + } + } + + if (private->xic == NULL) + return error; + + error |= gdk_ic_real_set_attr (ic, pattr, newattr); + + return error; +} + +GdkICAttributesType +gdk_ic_get_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private; + GdkICAttr *pattr; + GdkICAttributesType known, unknown = 0; + + g_return_val_if_fail (ic != NULL, -1); + g_return_val_if_fail (attr != NULL, -1); + + private = (GdkICPrivate *) ic; + pattr = private->attr; + + known = mask & private->mask; + + if (known & GDK_IC_STYLE) + attr->style = pattr->style; + if (known & GDK_IC_CLIENT_WINDOW) + attr->client_window = pattr->client_window; + if (known & GDK_IC_FOCUS_WINDOW) + attr->focus_window = pattr->focus_window; + if (known & GDK_IC_FILTER_EVENTS) + attr->filter_events = pattr->filter_events; + if (known & GDK_IC_LINE_SPACING) + attr->line_spacing = pattr->line_spacing; + if (known & GDK_IC_CURSOR) + attr->cursor = pattr->cursor; + + if (known & GDK_IC_PREEDIT_FONTSET) + attr->preedit_fontset = pattr->preedit_fontset; + if (known & GDK_IC_PREEDIT_AREA) + attr->preedit_area = pattr->preedit_area; + if (known & GDK_IC_PREEDIT_AREA_NEEDED) + attr->preedit_area_needed = pattr->preedit_area_needed; + if (known & GDK_IC_PREEDIT_FOREGROUND) + attr->preedit_foreground = pattr->preedit_foreground; + if (known & GDK_IC_PREEDIT_BACKGROUND) + attr->preedit_background = pattr->preedit_background; + if (known & GDK_IC_PREEDIT_PIXMAP) + attr->preedit_pixmap = pattr->preedit_pixmap; + if (known & GDK_IC_PREEDIT_COLORMAP) + attr->preedit_colormap = pattr->preedit_colormap; + + if (known & GDK_IC_STATUS_FONTSET) + attr->status_fontset = pattr->status_fontset; + if (known & GDK_IC_STATUS_AREA) + attr->status_area = pattr->status_area; + if (known & GDK_IC_STATUS_AREA_NEEDED) + attr->status_area_needed = pattr->status_area_needed; + if (known & GDK_IC_STATUS_FOREGROUND) + attr->status_foreground = pattr->status_foreground; + if (known & GDK_IC_STATUS_BACKGROUND) + attr->status_background = pattr->status_background; + if (known & GDK_IC_STATUS_PIXMAP) + attr->status_pixmap = pattr->status_pixmap; + if (known & GDK_IC_STATUS_COLORMAP) + attr->status_colormap = pattr->status_colormap; + + if (private->xic) + { + unknown = mask & ~(private->mask); + + if (unknown & GDK_IC_FOCUS_WINDOW) + attr->focus_window = pattr->client_window; + if (unknown & GDK_IC_FILTER_EVENTS) + { + gdk_ic_get_events (ic); + attr->filter_events = pattr->filter_events; + } + if (mask & GDK_IC_SPOT_LOCATION) + { + XPoint point; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNSpotLocation, &point, NULL); + if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL)) + unknown &= ~GDK_IC_SPOT_LOCATION; + else + { + pattr->spot_location.x = point.x; + pattr->spot_location.y = point.y; + private->mask |= GDK_IC_SPOT_LOCATION; + + attr->spot_location = pattr->spot_location; + } + XFree (list); + } + if (unknown & GDK_IC_PREEDIT_AREA_NEEDED) + { + XRectangle rect; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL); + if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL)) + unknown &= ~GDK_IC_PREEDIT_AREA_NEEDED; + else + { + pattr->preedit_area_needed.x = rect.x; + pattr->preedit_area_needed.y = rect.y; + pattr->preedit_area_needed.width = rect.width; + pattr->preedit_area_needed.height = rect.height; + private->mask |= GDK_IC_PREEDIT_AREA_NEEDED; + + attr->preedit_area = pattr->preedit_area; + } + XFree (list); + } + if (unknown & GDK_IC_STATUS_AREA_NEEDED) + { + XRectangle rect; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL); + if (XGetICValues (private->xic, XNStatusAttributes, list, NULL)) + unknown &= ~GDK_IC_STATUS_AREA_NEEDED; + else + { + pattr->status_area_needed.x = rect.x; + pattr->status_area_needed.y = rect.y; + pattr->status_area_needed.width = rect.width; + pattr->status_area_needed.height = rect.height; + private->mask |= GDK_IC_STATUS_AREA_NEEDED; + + attr->status_area = pattr->status_area; + } + XFree (list); + } + } + + return mask & ~known & ~unknown; +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + GdkEventMask mask; + glong xmask; + glong bit; + GdkICPrivate *private; + gint i; + + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + g_return_val_if_fail (ic != NULL, 0); + + private = (GdkICPrivate *) ic; + + if (private->mask & GDK_IC_FILTER_EVENTS) + return private->attr->filter_events; + + if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL) + { + GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents)); + return 0; + } + + mask = 0; + for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1) + if (xmask & event_mask_table [i]) + { + mask |= bit; + xmask &= ~ event_mask_table [i]; + } + + if (xmask) + g_warning ("ic requires events not supported by the application (%#04lx)", xmask); + + private->attr->filter_events = mask; + private->mask |= GDK_IC_FILTER_EVENTS; + + return mask; +} + +void +gdk_ic_cleanup (void) +{ + gint destroyed; + + destroyed = 0; + while (xim_ic_list != NULL) + { + gdk_ic_destroy ((GdkIC *) xim_ic_list->data); + destroyed ++; + } +#ifdef G_ENABLE_DEBUG + if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0) + { + g_warning ("Cleaned up %i IC(s)\n", destroyed); + } +#endif /* G_ENABLE_DEBUG */ +} + +#else /* !USE_XIM */ + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ +} + +void +gdk_im_end (void) +{ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +gint +gdk_im_ready (void) +{ + return FALSE; +} + +GdkIC +gdk_ic_new (GdkWindow* client_window, + GdkWindow* focus_window, + GdkIMStyle style, ...) +{ + return NULL; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +void +gdk_ic_set_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_get_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_set_attr (GdkIC *ic, const char *target, ...) +{ +} + +void +gdk_ic_get_attr (GdkIC *ic, const char *target, ...) +{ +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + return 0; +} + +#endif /* USE_XIM */ + +/* + * gdk_wcstombs + * + * Returns a multi-byte string converted from the specified array + * of wide characters. The string is newly allocated. The array of + * wide characters must be null-terminated. If the conversion is + * failed, it returns NULL. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gchar *mbstr; + XTextProperty tpr; + if (sizeof(wchar_t) != sizeof(GdkWChar)) + { + gint i; + wchar_t *src_alt; + for (i=0; src[i]; i++); + src_alt = g_new (wchar_t, i+1); + for (; i>=0; i--) + src_alt[i] = src[i]; + if (XwcTextListToTextProperty (gdk_display, &src_alt, 1, XTextStyle, &tpr) + != Success) + { + g_free (src_alt); + return NULL; + } + g_free (src_alt); + } + else + { + if (XwcTextListToTextProperty (gdk_display, (wchar_t**)&src, 1, + XTextStyle, &tpr) != Success) + { + return NULL; + } + } + /* + * We must copy the string into an area allocated by glib, because + * the string 'tpr.value' must be freed by XFree(). + */ + mbstr = g_strdup(tpr.value); + XFree (tpr.value); + return mbstr; +} + +/* + * gdk_mbstowcs + * + * Converts the specified string into wide characters, and, returns the + * number of wide characters written. The string 'src' must be + * null-terminated. If the conversion is failed, it returns -1. + */ +gint +gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max) +{ + XTextProperty tpr; + wchar_t **wstrs, *wstr_src; + gint num_wstrs; + gint len_cpy; + if (XmbTextListToTextProperty (gdk_display, (char **)&src, 1, XTextStyle, + &tpr) + != Success) + { + /* NoMem or LocaleNotSupp */ + return -1; + } + if (XwcTextPropertyToTextList (gdk_display, &tpr, &wstrs, &num_wstrs) + != Success) + { + /* InvalidChar */ + return -1; + } + if (num_wstrs == 0) + return 0; + wstr_src = wstrs[0]; + for (len_cpy=0; len_cpy +#include + +/* The following routines duplicate functionality in Xlib to + * translate from varargs to X's internal opaque XVaNestedList. + * + * If all vendors have stuck close to the reference implementation, + * then we should hopefully be OK. + */ + +typedef struct { + gchar *name; + gpointer value; +} GdkImArg; + +#ifdef USE_XIM + +static void gdk_im_instantiate_cb (Display *display, + XPointer client_data, + XPointer call_data); +static void gdk_im_destroy_cb (XIM im, + XPointer client_data, + XPointer call_data); + +static void gdk_ic_real_new (GdkIC *ic); + +static GdkICAttributesType gdk_ic_real_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask); + +static XIM xim_im; /* global IM */ +static XIMStyles* xim_styles; /* im supports these styles */ +static XIMStyle xim_best_allowed_style; +static GList* xim_ic_list; + +#endif /* USE_XIM */ + +/* + *-------------------------------------------------------------- + * gdk_im_begin + * + * Begin using input method with XIM Protocol(X11R6 standard) + * + * Arguments: + * "ic" is the "Input Context" which is created by gtk_ic_new. + * The input area is specified with "window". + * + * Results: + * The gdk's event handling routine is switched to XIM based routine. + * XIM based routine uses XFilterEvent to get rid of events used by IM, + * and uses XmbLookupString instead of XLookupString. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ + GdkICPrivate *private; + GdkICAttr attr; + + g_return_if_fail (ic != NULL); + + private = (GdkICPrivate *) ic; + + attr.focus_window = window; + gdk_ic_set_attr (ic, &attr, GDK_IC_FOCUS_WINDOW); + + if (private != gdk_xim_ic) + { + gdk_im_end(); + if (private->xic) + { + XSetICFocus (private->xic); + GDK_NOTE (XIM, g_print ("im_begin icfocus : %p(%ld)\n", + private->xic, + GDK_WINDOW_XWINDOW(private->attr->focus_window))); + } + } + gdk_xim_ic = private; + gdk_xim_window = window; +} + +/* + *-------------------------------------------------------------- + * gdk_im_end + * + * End using input method with XIM Protocol(X11R6 standard) + * + * Arguments: + * + * Results: + * The gdk's event handling routine is switched to normal routine. + * User should call this function before ic and window will be destroyed. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_im_end (void) +{ + if (gdk_xim_ic && gdk_xim_ic->xic) + { + XUnsetICFocus (gdk_xim_ic->xic); + GDK_NOTE (XIM, g_print ("im_end unfocus : %p\n", gdk_xim_ic->xic)); + } + gdk_xim_ic = NULL; + gdk_xim_window = NULL; +} + +static GdkIMStyle +gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) +{ + GdkIMStyle s1, s2, u; + + if (style1 == 0) return style2; + if (style2 == 0) return style1; + if ((style1 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK)) + == (style2 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK))) + return style1; + + s1 = style1 & GDK_IM_PREEDIT_MASK; + s2 = style2 & GDK_IM_PREEDIT_MASK; + u = s1 | s2; + if (s1 != s2) { + if (u & GDK_IM_PREEDIT_CALLBACKS) + return (s1 == GDK_IM_PREEDIT_CALLBACKS)? style1:style2; + else if (u & GDK_IM_PREEDIT_POSITION) + return (s1 == GDK_IM_PREEDIT_POSITION)? style1:style2; + else if (u & GDK_IM_PREEDIT_AREA) + return (s1 == GDK_IM_PREEDIT_AREA)? style1:style2; + else if (u & GDK_IM_PREEDIT_NOTHING) + return (s1 == GDK_IM_PREEDIT_NOTHING)? style1:style2; + } else { + s1 = style1 & GDK_IM_STATUS_MASK; + s2 = style2 & GDK_IM_STATUS_MASK; + u = s1 | s2; + if ( u & GDK_IM_STATUS_CALLBACKS) + return (s1 == GDK_IM_STATUS_CALLBACKS)? style1:style2; + else if ( u & GDK_IM_STATUS_AREA) + return (s1 == GDK_IM_STATUS_AREA)? style1:style2; + else if ( u & GDK_IM_STATUS_NOTHING) + return (s1 == GDK_IM_STATUS_NOTHING)? style1:style2; + else if ( u & GDK_IM_STATUS_NONE) + return (s1 == GDK_IM_STATUS_NONE)? style1:style2; + } + return 0; /* Get rid of stupid warning */ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + gint i; + GdkIMStyle style, tmp; + + g_return_val_if_fail (xim_styles != NULL, 0); + + style = 0; + for (i=0; icount_styles; i++) + { + tmp = xim_styles->supported_styles[i]; + if (tmp == (tmp & supported_style & xim_best_allowed_style)) + style = gdk_im_choose_better_style (style, tmp); + } + return style; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + if (style & GDK_IM_PREEDIT_MASK) + { + xim_best_allowed_style &= ~GDK_IM_PREEDIT_MASK; + + xim_best_allowed_style |= GDK_IM_PREEDIT_NONE; + if (!(style & GDK_IM_PREEDIT_NONE)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_NOTHING; + if (!(style & GDK_IM_PREEDIT_NOTHING)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_AREA; + if (!(style & GDK_IM_PREEDIT_AREA)) + { + xim_best_allowed_style |= GDK_IM_PREEDIT_POSITION; + if (!(style & GDK_IM_PREEDIT_POSITION)) + xim_best_allowed_style |= GDK_IM_PREEDIT_CALLBACKS; + } + } + } + } + if (style & GDK_IM_STATUS_MASK) + { + xim_best_allowed_style &= ~GDK_IM_STATUS_MASK; + + xim_best_allowed_style |= GDK_IM_STATUS_NONE; + if (!(style & GDK_IM_STATUS_NONE)) + { + xim_best_allowed_style |= GDK_IM_STATUS_NOTHING; + if (!(style & GDK_IM_STATUS_NOTHING)) + { + xim_best_allowed_style |= GDK_IM_STATUS_AREA; + if (!(style & GDK_IM_STATUS_AREA)) + xim_best_allowed_style |= GDK_IM_STATUS_CALLBACKS; + } + } + } + + return xim_best_allowed_style; +} + +static void +gdk_im_destroy_cb (XIM im, XPointer client_data, XPointer call_data) +{ + GList *node; + GdkICPrivate *private; + + GDK_NOTE (XIM, g_message ("Ouch, Input Method is destroyed!!\n")); + + xim_im = NULL; + + if (xim_styles) + { + XFree (xim_styles); + xim_styles = NULL; + } + + for (node = xim_ic_list; node != NULL; node = g_list_next(node)) + { + private = (GdkICPrivate *) (node->data); + private->xic = NULL; + } + + XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); +} + +static void +gdk_im_instantiate_cb (Display *display, + XPointer client_data, XPointer call_data) +{ + XIMCallback destroy_cb; + GList *node; + + GDK_NOTE (XIM, g_message ("New IM is instantiated.")); + if (display != gdk_display) + return; + + XUnregisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); + + xim_im = XOpenIM (GDK_DISPLAY(), NULL, NULL, NULL); + if (xim_im == NULL) + GDK_NOTE (XIM, g_warning ("Unable to open open IM.")); + + destroy_cb.callback = gdk_im_destroy_cb; + destroy_cb.client_data = NULL; + XSetIMValues (xim_im, XNDestroyCallback, &destroy_cb, NULL); + + XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL); + + for (node = xim_ic_list; node != NULL; node = g_list_next(node)) + { + GdkICPrivate *private = (GdkICPrivate *) (node->data); + if (private->xic == NULL) + gdk_ic_real_new ((GdkIC *)private); + } +} + +gint +gdk_im_open (void) +{ + gdk_xim_ic = NULL; + gdk_xim_window = (GdkWindow*)NULL; + xim_im = NULL; + xim_styles = NULL; + + /* initialize XIM Protocol variables */ + if (!(xim_best_allowed_style & GDK_IM_PREEDIT_MASK)) + gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS); + if (!(xim_best_allowed_style & GDK_IM_STATUS_MASK)) + gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS); + + XRegisterIMInstantiateCallback (gdk_display, NULL, NULL, NULL, + gdk_im_instantiate_cb, NULL); + + return (xim_im != NULL); +} + +void +gdk_im_close (void) +{ + if (xim_im) + { + XCloseIM (xim_im); + xim_im = NULL; + } + if (xim_styles) + { + XFree (xim_styles); + xim_styles = NULL; + } +} + +gint +gdk_im_ready (void) +{ + return (xim_im != NULL); +} + +static void +gdk_ic_real_new (GdkIC *ic) +{ + XPoint spot_location; + XRectangle preedit_area; + XRectangle status_area; + XVaNestedList *preedit_attr = NULL; + XVaNestedList *status_attr = NULL; + GdkICAttr *attr; + GdkICPrivate *private; + GdkICAttributesType mask = GDK_IC_ALL_REQ; + + private = (GdkICPrivate *) ic; + attr = private->attr; + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case GDK_IM_PREEDIT_AREA: + mask |= GDK_IC_PREEDIT_AREA_REQ; + + preedit_area.x = attr->preedit_area.x; + preedit_area.y = attr->preedit_area.x; + preedit_area.width = attr->preedit_area.width; + preedit_area.height = attr->preedit_area.height; + + preedit_attr = XVaCreateNestedList (0, + XNArea, &preedit_area, + XNFontSet, + GDK_FONT_XFONT(attr->preedit_fontset), + NULL); + break; + + case GDK_IM_PREEDIT_POSITION: + mask |= GDK_IC_PREEDIT_POSITION_REQ; + + preedit_area.x = attr->preedit_area.x; + preedit_area.y = attr->preedit_area.x; + preedit_area.width = attr->preedit_area.width; + preedit_area.height = attr->preedit_area.height; + + spot_location.x = attr->spot_location.x; + spot_location.y = attr->spot_location.y; + + preedit_attr = XVaCreateNestedList (0, + XNArea, &preedit_area, + XNFontSet, + GDK_FONT_XFONT(attr->preedit_fontset), + XNSpotLocation, &spot_location, + NULL); + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case GDK_IM_STATUS_AREA: + mask |= GDK_IC_STATUS_AREA_REQ; + + status_area.x = attr->status_area.x; + status_area.y = attr->status_area.x; + status_area.width = attr->status_area.width; + status_area.height = attr->status_area.height; + + status_attr = XVaCreateNestedList (0, + XNArea, &status_area, + XNFontSet, + GDK_FONT_XFONT(attr->status_fontset), + NULL); + break; + } + + if (preedit_attr != NULL && status_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNPreeditAttributes, + preedit_attr, + XNStatusAttributes, + status_attr, + NULL); + else if (preedit_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNPreeditAttributes, + preedit_attr, + NULL); + else if (status_attr != NULL) + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + XNStatusAttributes, + status_attr, + NULL); + else + private->xic = XCreateIC (xim_im, + XNInputStyle, + attr->style, + XNClientWindow, + GDK_WINDOW_XWINDOW(attr->client_window), + NULL); + + if (preedit_attr) + XFree (preedit_attr); + if (status_attr) + XFree (status_attr); + + if (private->xic == NULL) + g_warning ("can not create input context with specified input style."); + else + gdk_ic_real_set_attr (ic, private->attr, private->mask & ~mask); +} + +GdkIC * +gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask) +{ + GdkICPrivate *private; + gboolean error = 0; + GdkICAttributesType invalid_mask; + GdkICAttr *pattr; + + g_return_val_if_fail (attr != NULL, NULL); + g_return_val_if_fail ((mask & GDK_IC_ALL_REQ) == GDK_IC_ALL_REQ, NULL); + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case 0: + g_warning ("preedit style is not specified.\n"); + error = 1; + break; + + case GDK_IM_PREEDIT_AREA: + if ((mask & GDK_IC_PREEDIT_AREA_REQ) != GDK_IC_PREEDIT_AREA_REQ) + error = 4; + break; + + case GDK_IM_PREEDIT_POSITION: + if ((mask & GDK_IC_PREEDIT_POSITION_REQ) != GDK_IC_PREEDIT_POSITION_REQ) + error = 4; + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case 0: + g_warning ("status style is not specified.\n"); + error = 2; + break; + + case GDK_IM_STATUS_AREA: + if ((mask & GDK_IC_STATUS_AREA_REQ) != GDK_IC_STATUS_AREA_REQ) + error = 8; + break; + } + + if (error) + { + if (error & 12) + g_warning ("IC attribute is not enough to required input style.\n"); + return NULL; + } + + if (attr->client_window == NULL || + ((GdkWindowPrivate *)attr->client_window)->destroyed) + { + g_warning ("Client_window is null or already destroyed.\n"); + return NULL; + } + + private = g_new0 (GdkICPrivate, 1); + private->attr = pattr = gdk_ic_attr_new (); + + gdk_window_ref (attr->client_window); + pattr->client_window = attr->client_window; + pattr->style = attr->style; + private->mask = GDK_IC_STYLE | GDK_IC_CLIENT_WINDOW; + + /* XIC is still not created, so following call only copies attributes */ + invalid_mask = gdk_ic_set_attr ((GdkIC *)private, attr, mask & ~GDK_IC_ALL_REQ); + + switch (attr->style & GDK_IM_PREEDIT_MASK) + { + case GDK_IM_PREEDIT_AREA: + if (invalid_mask & GDK_IC_PREEDIT_AREA_REQ) + error = TRUE; + break; + + case GDK_IM_PREEDIT_POSITION: + if (invalid_mask & GDK_IC_PREEDIT_POSITION_REQ) + error = TRUE; + break; + } + + switch (attr->style & GDK_IM_STATUS_MASK) + { + case GDK_IM_STATUS_AREA: + if (invalid_mask & GDK_IC_STATUS_AREA_REQ) + error = TRUE; + break; + } + + if (error == TRUE) + { + g_warning ("Essential attributes for required style are invalid.\n"); + gdk_ic_destroy ((GdkIC *)private); + return NULL; + } + + if (gdk_im_ready ()) + gdk_ic_real_new ((GdkIC *)private); + + xim_ic_list = g_list_append (xim_ic_list, private); + + return (GdkIC *)private; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ + GdkICPrivate *private; + + g_return_if_fail (ic != NULL); + + private = (GdkICPrivate *) ic; + + if (gdk_xim_ic == private) + gdk_im_end (); + + GDK_NOTE (XIM, g_print("ic_destroy %p\n", private->xic)); + if (private->xic != NULL) + XDestroyIC (private->xic); + + if (private->mask & GDK_IC_CLIENT_WINDOW) + gdk_window_unref (private->attr->client_window); + if (private->mask & GDK_IC_FOCUS_WINDOW) + gdk_window_unref (private->attr->focus_window); + + if (private->mask & GDK_IC_PREEDIT_FONTSET) + gdk_font_unref (private->attr->preedit_fontset); + if (private->mask & GDK_IC_PREEDIT_PIXMAP) + gdk_pixmap_unref (private->attr->preedit_pixmap); + if (private->mask & GDK_IC_PREEDIT_COLORMAP) + gdk_colormap_unref (private->attr->preedit_colormap); + + if (private->mask & GDK_IC_STATUS_FONTSET) + gdk_font_unref (private->attr->status_fontset); + if (private->mask & GDK_IC_STATUS_PIXMAP) + gdk_pixmap_unref (private->attr->status_pixmap); + if (private->mask & GDK_IC_STATUS_COLORMAP) + gdk_colormap_unref (private->attr->status_colormap); + + xim_ic_list = g_list_remove (xim_ic_list, private); + gdk_ic_attr_destroy (private->attr); + g_free (private); +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + GdkICPrivate *private; + + g_return_val_if_fail (ic != NULL, 0); + + private = (GdkICPrivate *) ic; + + return private->attr->style; +} + +/* + * for keeping binary compatibility if member of ic attributes is added. + */ +GdkICAttr * +gdk_ic_attr_new (void) +{ + return g_new0 (GdkICAttr, 1); +} + +void +gdk_ic_attr_destroy (GdkICAttr *attr) +{ + g_return_if_fail (attr != NULL); + + g_free (attr); +} + +static GdkICAttributesType +gdk_ic_real_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private = (GdkICPrivate *)ic; + XIC xic = private->xic; + GdkICAttributesType error = 0; + GdkImArg arg[2] = {{NULL, NULL}, {NULL, NULL}}; + + if (mask & GDK_IC_FOCUS_WINDOW) + { + if (XSetICValues (xic, XNFocusWindow, + GDK_WINDOW_XWINDOW(attr->focus_window), NULL) != NULL) + error |= GDK_IC_FOCUS_WINDOW; + } + + if (mask & GDK_IC_SPOT_LOCATION) + { + XPoint point; + + point.x = attr->spot_location.x; + point.y = attr->spot_location.y; + + arg->name = XNSpotLocation; + arg->value = (gpointer) &point; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_SPOT_LOCATION; + } + + if (mask & GDK_IC_LINE_SPACING) + { + arg->name = XNLineSpace; + arg->value = (gpointer) attr->line_spacing; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_LINE_SPACING; + } + + if (mask & GDK_IC_CURSOR) + { + GdkCursorPrivate *cursor = (GdkCursorPrivate *) attr->cursor; + + if (XSetICValues (xic, XNCursor, cursor->xcursor, NULL)) + error |= GDK_IC_CURSOR; + } + + if (mask & GDK_IC_PREEDIT_FONTSET) + { + arg->name = XNFontSet; + arg->value = (gpointer) GDK_FONT_XFONT(attr->preedit_fontset); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_FONTSET; + } + + if (mask & GDK_IC_PREEDIT_AREA) + { + XRectangle rect; + + rect.x = attr->preedit_area.x; + rect.y = attr->preedit_area.y; + rect.width = attr->preedit_area.width; + rect.height = attr->preedit_area.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_AREA; + } + + if (mask & GDK_IC_PREEDIT_AREA_NEEDED) + { + XRectangle rect; + + rect.x = attr->preedit_area_needed.x; + rect.y = attr->preedit_area_needed.y; + rect.width = attr->preedit_area_needed.width; + rect.height = attr->preedit_area_needed.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_AREA_NEEDED; + else + private->mask &= ~GDK_IC_PREEDIT_AREA_NEEDED; + } + + if (mask & GDK_IC_PREEDIT_FOREGROUND) + { + arg->name = XNForeground; + arg->value = (gpointer) attr->preedit_foreground.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_FOREGROUND; + } + + if (mask & GDK_IC_PREEDIT_BACKGROUND) + { + arg->name = XNBackground; + arg->value = (gpointer) attr->preedit_background.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_BACKGROUND; + } + + if (mask & GDK_IC_PREEDIT_PIXMAP) + { + arg->name = XNBackgroundPixmap; + arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->preedit_pixmap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_PIXMAP; + } + + if (mask & GDK_IC_PREEDIT_COLORMAP) + { + arg->name = XNColormap; + arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->preedit_colormap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_PREEDIT_COLORMAP; + } + + + if (mask & GDK_IC_STATUS_FONTSET) + { + arg->name = XNFontSet; + arg->value = (gpointer) GDK_FONT_XFONT(attr->status_fontset); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_FONTSET; + } + + if (mask & GDK_IC_STATUS_AREA) + { + XRectangle rect; + + rect.x = attr->status_area.x; + rect.y = attr->status_area.y; + rect.width = attr->status_area.width; + rect.height = attr->status_area.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_AREA; + } + + if (mask & GDK_IC_STATUS_AREA_NEEDED) + { + XRectangle rect; + + rect.x = attr->status_area_needed.x; + rect.y = attr->status_area_needed.y; + rect.width = attr->status_area_needed.width; + rect.height = attr->status_area_needed.height; + + arg->name = XNArea; + arg->value = (gpointer) ▭ + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_AREA_NEEDED; + else + private->mask &= ~GDK_IC_STATUS_AREA_NEEDED; + } + + if (mask & GDK_IC_STATUS_FOREGROUND) + { + arg->name = XNForeground; + arg->value = (gpointer) attr->status_foreground.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_FOREGROUND; + } + + if (mask & GDK_IC_STATUS_BACKGROUND) + { + arg->name = XNBackground; + arg->value = (gpointer) attr->status_background.pixel; + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_BACKGROUND; + } + + if (mask & GDK_IC_STATUS_PIXMAP) + { + arg->name = XNBackgroundPixmap; + arg->value = (gpointer) GDK_WINDOW_XWINDOW(attr->status_pixmap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_PIXMAP; + } + + if (mask & GDK_IC_STATUS_COLORMAP) + { + arg->name = XNColormap; + arg->value = (gpointer) GDK_COLORMAP_XCOLORMAP(attr->status_colormap); + + if (XSetICValues (xic, XNPreeditAttributes, arg, NULL)) + error |= GDK_IC_STATUS_COLORMAP; + } + + return error; +} + +GdkICAttributesType +gdk_ic_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private; + GdkICAttr *pattr; + GdkICAttributesType error = 0; + GdkICAttributesType newattr = 0; + + g_return_val_if_fail (ic != NULL, 0); + g_return_val_if_fail (attr != NULL, 0); + + private = (GdkICPrivate *) ic; + pattr = private->attr; + + /* Check and copy new attributes */ + + if (mask & GDK_IC_STYLE) + { + g_warning ("input style can be specified only when creating new ic.\n"); + error |= GDK_IC_STYLE; + } + + if (mask & GDK_IC_FILTER_EVENTS) + { + g_warning ("filter events is read only attributes.\n"); + error |= GDK_IC_FILTER_EVENTS; + } + + if (mask & GDK_IC_CLIENT_WINDOW) + { + g_warning ("client window can be specified only when creating new ic.\n"); + error |= GDK_IC_CLIENT_WINDOW; + } + + if (mask & GDK_IC_FOCUS_WINDOW) + { + if (attr->focus_window == NULL) + { + g_warning ("specified focus_window is invalid.\n"); + error |= GDK_IC_FOCUS_WINDOW; + } + else if (pattr->focus_window != attr->focus_window) + { + if (pattr->focus_window != NULL) + gdk_window_unref (pattr->focus_window); + if (attr->focus_window != NULL) + gdk_window_ref (attr->focus_window); + pattr->focus_window = attr->focus_window; + newattr |= GDK_IC_FOCUS_WINDOW; + } + } + + if (mask & GDK_IC_SPOT_LOCATION) + { + pattr->spot_location = attr->spot_location; + newattr |= GDK_IC_SPOT_LOCATION; + } + + if (mask & GDK_IC_LINE_SPACING) + { + pattr->line_spacing = attr->line_spacing; + newattr |= GDK_IC_LINE_SPACING; + } + + if (mask & GDK_IC_CURSOR) + { + pattr->cursor = attr->cursor; + newattr |= GDK_IC_CURSOR; + } + + if (mask & GDK_IC_PREEDIT_FONTSET) + { + if (attr->preedit_fontset == NULL || + attr->preedit_fontset->type != GDK_FONT_FONTSET) + { + g_warning ("gdk_font is NULL or not a fontset.\n"); + error |= GDK_IC_PREEDIT_FONTSET; + } + else if (pattr->preedit_fontset != attr->preedit_fontset) + { + if (pattr->preedit_fontset != NULL) + gdk_font_unref (pattr->preedit_fontset); + if (attr->preedit_fontset != NULL) + gdk_font_ref (attr->preedit_fontset); + pattr->preedit_fontset = attr->preedit_fontset; + newattr |= GDK_IC_PREEDIT_FONTSET; + } + } + + if (mask & GDK_IC_PREEDIT_AREA) + { + pattr->preedit_area = attr->preedit_area; + newattr |= GDK_IC_PREEDIT_AREA; + } + + if (mask & GDK_IC_PREEDIT_AREA_NEEDED) + { + if (attr->preedit_area_needed.width == 0 || + attr->preedit_area_needed.height == 0) + { + g_warning ("width and height of preedit_area_needed must be non 0.\n"); + error |= GDK_IC_PREEDIT_AREA_NEEDED; + } + else + { + pattr->preedit_area_needed = attr->preedit_area_needed; + newattr |= GDK_IC_PREEDIT_AREA_NEEDED; + } + } + + if (mask & GDK_IC_PREEDIT_FOREGROUND) + { + pattr->preedit_foreground = attr->preedit_foreground; + newattr |= GDK_IC_PREEDIT_FOREGROUND; + } + + if (mask & GDK_IC_PREEDIT_BACKGROUND) + { + pattr->preedit_background = attr->preedit_background; + newattr |= GDK_IC_PREEDIT_BACKGROUND; + } + + if (mask & GDK_IC_PREEDIT_PIXMAP) + { + if (attr->preedit_pixmap != NULL && + ((GdkPixmapPrivate *)attr->preedit_pixmap)->destroyed) + { + g_warning ("Preedit pixmap is already destroyed.\n"); + error |= GDK_IC_PREEDIT_PIXMAP; + } + else + { + if (pattr->preedit_pixmap != attr->preedit_pixmap) + { + if (pattr->preedit_pixmap != NULL) + gdk_pixmap_unref (pattr->preedit_pixmap); + if (attr->preedit_pixmap) + gdk_pixmap_ref (attr->preedit_pixmap); + pattr->preedit_pixmap = attr->preedit_pixmap; + newattr |= GDK_IC_PREEDIT_PIXMAP; + } + } + } + + if (mask & GDK_IC_PREEDIT_COLORMAP) + { + if (pattr->preedit_colormap != attr->preedit_colormap) + { + if (pattr->preedit_colormap != NULL) + gdk_colormap_unref (pattr->preedit_colormap); + if (attr->preedit_colormap != NULL) + gdk_colormap_ref (attr->preedit_colormap); + pattr->preedit_colormap = attr->preedit_colormap; + newattr |= GDK_IC_PREEDIT_COLORMAP; + } + } + + if (mask & GDK_IC_STATUS_FONTSET) + { + if (attr->status_fontset == NULL || + attr->status_fontset->type != GDK_FONT_FONTSET) + { + g_warning ("gdk_font is NULL or not a fontset.\n"); + error |= GDK_IC_STATUS_FONTSET; + } + else if (pattr->status_fontset != attr->status_fontset) + { + if (pattr->status_fontset != NULL) + gdk_font_unref (pattr->status_fontset); + if (attr->status_fontset != NULL) + gdk_font_ref (attr->status_fontset); + pattr->status_fontset = attr->status_fontset; + newattr |= GDK_IC_STATUS_FONTSET; + } + } + + if (mask & GDK_IC_STATUS_AREA) + { + pattr->status_area = attr->status_area; + newattr |= GDK_IC_STATUS_AREA; + } + + if (mask & GDK_IC_STATUS_AREA_NEEDED) + { + if (attr->status_area_needed.width == 0 || + attr->status_area_needed.height == 0) + { + g_warning ("width and height of status_area_needed must be non 0.\n"); + error |= GDK_IC_STATUS_AREA_NEEDED; + } + else + { + pattr->status_area_needed = attr->status_area_needed; + newattr |= GDK_IC_STATUS_AREA_NEEDED; + } + } + + if (mask & GDK_IC_STATUS_FOREGROUND) + { + pattr->status_foreground = attr->status_foreground; + newattr |= GDK_IC_STATUS_FOREGROUND; + } + + if (mask & GDK_IC_STATUS_BACKGROUND) + { + pattr->status_background = attr->status_background; + newattr |= GDK_IC_STATUS_BACKGROUND; + } + + if (mask & GDK_IC_STATUS_PIXMAP) + { + if (attr->status_pixmap != NULL && + ((GdkPixmapPrivate *)attr->status_pixmap)->destroyed) + { + g_warning ("Preedit pixmap is already destroyed.\n"); + error |= GDK_IC_STATUS_PIXMAP; + } + else + { + if (pattr->status_pixmap != attr->status_pixmap) + { + if (pattr->status_pixmap != NULL) + gdk_pixmap_unref (pattr->status_pixmap); + if (attr->status_pixmap) + gdk_pixmap_ref (attr->status_pixmap); + pattr->status_pixmap = attr->status_pixmap; + newattr |= GDK_IC_STATUS_PIXMAP; + } + } + } + + if (mask & GDK_IC_STATUS_COLORMAP) + { + if (pattr->status_colormap != attr->status_colormap) + { + if (pattr->status_colormap != NULL) + gdk_colormap_unref (pattr->status_colormap); + if (attr->status_colormap != NULL) + gdk_colormap_ref (attr->status_colormap); + pattr->status_colormap = attr->status_colormap; + newattr |= GDK_IC_STATUS_COLORMAP; + } + } + + if (private->xic == NULL) + return error; + + error |= gdk_ic_real_set_attr (ic, pattr, newattr); + + return error; +} + +GdkICAttributesType +gdk_ic_get_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask) +{ + GdkICPrivate *private; + GdkICAttr *pattr; + GdkICAttributesType known, unknown = 0; + + g_return_val_if_fail (ic != NULL, -1); + g_return_val_if_fail (attr != NULL, -1); + + private = (GdkICPrivate *) ic; + pattr = private->attr; + + known = mask & private->mask; + + if (known & GDK_IC_STYLE) + attr->style = pattr->style; + if (known & GDK_IC_CLIENT_WINDOW) + attr->client_window = pattr->client_window; + if (known & GDK_IC_FOCUS_WINDOW) + attr->focus_window = pattr->focus_window; + if (known & GDK_IC_FILTER_EVENTS) + attr->filter_events = pattr->filter_events; + if (known & GDK_IC_LINE_SPACING) + attr->line_spacing = pattr->line_spacing; + if (known & GDK_IC_CURSOR) + attr->cursor = pattr->cursor; + + if (known & GDK_IC_PREEDIT_FONTSET) + attr->preedit_fontset = pattr->preedit_fontset; + if (known & GDK_IC_PREEDIT_AREA) + attr->preedit_area = pattr->preedit_area; + if (known & GDK_IC_PREEDIT_AREA_NEEDED) + attr->preedit_area_needed = pattr->preedit_area_needed; + if (known & GDK_IC_PREEDIT_FOREGROUND) + attr->preedit_foreground = pattr->preedit_foreground; + if (known & GDK_IC_PREEDIT_BACKGROUND) + attr->preedit_background = pattr->preedit_background; + if (known & GDK_IC_PREEDIT_PIXMAP) + attr->preedit_pixmap = pattr->preedit_pixmap; + if (known & GDK_IC_PREEDIT_COLORMAP) + attr->preedit_colormap = pattr->preedit_colormap; + + if (known & GDK_IC_STATUS_FONTSET) + attr->status_fontset = pattr->status_fontset; + if (known & GDK_IC_STATUS_AREA) + attr->status_area = pattr->status_area; + if (known & GDK_IC_STATUS_AREA_NEEDED) + attr->status_area_needed = pattr->status_area_needed; + if (known & GDK_IC_STATUS_FOREGROUND) + attr->status_foreground = pattr->status_foreground; + if (known & GDK_IC_STATUS_BACKGROUND) + attr->status_background = pattr->status_background; + if (known & GDK_IC_STATUS_PIXMAP) + attr->status_pixmap = pattr->status_pixmap; + if (known & GDK_IC_STATUS_COLORMAP) + attr->status_colormap = pattr->status_colormap; + + if (private->xic) + { + unknown = mask & ~(private->mask); + + if (unknown & GDK_IC_FOCUS_WINDOW) + attr->focus_window = pattr->client_window; + if (unknown & GDK_IC_FILTER_EVENTS) + { + gdk_ic_get_events (ic); + attr->filter_events = pattr->filter_events; + } + if (mask & GDK_IC_SPOT_LOCATION) + { + XPoint point; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNSpotLocation, &point, NULL); + if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL)) + unknown &= ~GDK_IC_SPOT_LOCATION; + else + { + pattr->spot_location.x = point.x; + pattr->spot_location.y = point.y; + private->mask |= GDK_IC_SPOT_LOCATION; + + attr->spot_location = pattr->spot_location; + } + XFree (list); + } + if (unknown & GDK_IC_PREEDIT_AREA_NEEDED) + { + XRectangle rect; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL); + if (XGetICValues (private->xic, XNPreeditAttributes, list, NULL)) + unknown &= ~GDK_IC_PREEDIT_AREA_NEEDED; + else + { + pattr->preedit_area_needed.x = rect.x; + pattr->preedit_area_needed.y = rect.y; + pattr->preedit_area_needed.width = rect.width; + pattr->preedit_area_needed.height = rect.height; + private->mask |= GDK_IC_PREEDIT_AREA_NEEDED; + + attr->preedit_area = pattr->preedit_area; + } + XFree (list); + } + if (unknown & GDK_IC_STATUS_AREA_NEEDED) + { + XRectangle rect; + XVaNestedList *list; + + list = XVaCreateNestedList (0, XNAreaNeeded, &rect, NULL); + if (XGetICValues (private->xic, XNStatusAttributes, list, NULL)) + unknown &= ~GDK_IC_STATUS_AREA_NEEDED; + else + { + pattr->status_area_needed.x = rect.x; + pattr->status_area_needed.y = rect.y; + pattr->status_area_needed.width = rect.width; + pattr->status_area_needed.height = rect.height; + private->mask |= GDK_IC_STATUS_AREA_NEEDED; + + attr->status_area = pattr->status_area; + } + XFree (list); + } + } + + return mask & ~known & ~unknown; +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + GdkEventMask mask; + glong xmask; + glong bit; + GdkICPrivate *private; + gint i; + + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + g_return_val_if_fail (ic != NULL, 0); + + private = (GdkICPrivate *) ic; + + if (private->mask & GDK_IC_FILTER_EVENTS) + return private->attr->filter_events; + + if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL) + { + GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents)); + return 0; + } + + mask = 0; + for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1) + if (xmask & event_mask_table [i]) + { + mask |= bit; + xmask &= ~ event_mask_table [i]; + } + + if (xmask) + g_warning ("ic requires events not supported by the application (%#04lx)", xmask); + + private->attr->filter_events = mask; + private->mask |= GDK_IC_FILTER_EVENTS; + + return mask; +} + +void +gdk_ic_cleanup (void) +{ + gint destroyed; + + destroyed = 0; + while (xim_ic_list != NULL) + { + gdk_ic_destroy ((GdkIC *) xim_ic_list->data); + destroyed ++; + } +#ifdef G_ENABLE_DEBUG + if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0) + { + g_warning ("Cleaned up %i IC(s)\n", destroyed); + } +#endif /* G_ENABLE_DEBUG */ +} + +#else /* !USE_XIM */ + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ +} + +void +gdk_im_end (void) +{ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +gint +gdk_im_ready (void) +{ + return FALSE; +} + +GdkIC +gdk_ic_new (GdkWindow* client_window, + GdkWindow* focus_window, + GdkIMStyle style, ...) +{ + return NULL; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +void +gdk_ic_set_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_get_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_set_attr (GdkIC *ic, const char *target, ...) +{ +} + +void +gdk_ic_get_attr (GdkIC *ic, const char *target, ...) +{ +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + return 0; +} + +#endif /* USE_XIM */ + +/* + * gdk_wcstombs + * + * Returns a multi-byte string converted from the specified array + * of wide characters. The string is newly allocated. The array of + * wide characters must be null-terminated. If the conversion is + * failed, it returns NULL. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gchar *mbstr; + XTextProperty tpr; + if (sizeof(wchar_t) != sizeof(GdkWChar)) + { + gint i; + wchar_t *src_alt; + for (i=0; src[i]; i++); + src_alt = g_new (wchar_t, i+1); + for (; i>=0; i--) + src_alt[i] = src[i]; + if (XwcTextListToTextProperty (gdk_display, &src_alt, 1, XTextStyle, &tpr) + != Success) + { + g_free (src_alt); + return NULL; + } + g_free (src_alt); + } + else + { + if (XwcTextListToTextProperty (gdk_display, (wchar_t**)&src, 1, + XTextStyle, &tpr) != Success) + { + return NULL; + } + } + /* + * We must copy the string into an area allocated by glib, because + * the string 'tpr.value' must be freed by XFree(). + */ + mbstr = g_strdup(tpr.value); + XFree (tpr.value); + return mbstr; +} + +/* + * gdk_mbstowcs + * + * Converts the specified string into wide characters, and, returns the + * number of wide characters written. The string 'src' must be + * null-terminated. If the conversion is failed, it returns -1. + */ +gint +gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max) +{ + XTextProperty tpr; + wchar_t **wstrs, *wstr_src; + gint num_wstrs; + gint len_cpy; + if (XmbTextListToTextProperty (gdk_display, (char **)&src, 1, XTextStyle, + &tpr) + != Success) + { + /* NoMem or LocaleNotSupp */ + return -1; + } + if (XwcTextPropertyToTextList (gdk_display, &tpr, &wstrs, &num_wstrs) + != Success) + { + /* InvalidChar */ + return -1; + } + if (num_wstrs == 0) + return 0; + wstr_src = wstrs[0]; + for (len_cpy=0; len_cpy