+
+
+\f
+/* Support routines for XIC (X Input Context). */
+
+#ifdef HAVE_X_I18N
+
+static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
+static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
+
+
+/* Supported XIM styles, ordered by preferenc. */
+
+static XIMStyle supported_xim_styles[] =
+{
+ XIMPreeditPosition | XIMStatusArea,
+ XIMPreeditPosition | XIMStatusNothing,
+ XIMPreeditPosition | XIMStatusNone,
+ XIMPreeditNothing | XIMStatusArea,
+ XIMPreeditNothing | XIMStatusNothing,
+ XIMPreeditNothing | XIMStatusNone,
+ XIMPreeditNone | XIMStatusArea,
+ XIMPreeditNone | XIMStatusNothing,
+ XIMPreeditNone | XIMStatusNone,
+ 0,
+};
+
+
+/* Create an X fontset on frame F with base font name
+ BASE_FONTNAME.. */
+
+static XFontSet
+xic_create_xfontset (f, base_fontname)
+ struct frame *f;
+ char *base_fontname;
+{
+ XFontSet xfs;
+ char **missing_list;
+ int missing_count;
+ char *def_string;
+
+ xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
+ base_fontname, &missing_list,
+ &missing_count, &def_string);
+ if (missing_list)
+ XFreeStringList (missing_list);
+
+ /* No need to free def_string. */
+ return xfs;
+}
+
+
+/* Value is the best input style, given user preferences USER (already
+ checked to be supported by Emacs), and styles supported by the
+ input method XIM. */
+
+static XIMStyle
+best_xim_style (user, xim)
+ XIMStyles *user;
+ XIMStyles *xim;
+{
+ int i, j;
+
+ for (i = 0; i < user->count_styles; ++i)
+ for (j = 0; j < xim->count_styles; ++j)
+ if (user->supported_styles[i] == xim->supported_styles[j])
+ return user->supported_styles[i];
+
+ /* Return the default style. */
+ return XIMPreeditNothing | XIMStatusNothing;
+}
+
+/* Create XIC for frame F. */
+
+void
+create_frame_xic (f)
+ struct frame *f;
+{
+ XIM xim;
+ XIC xic = NULL;
+ XFontSet xfs = NULL;
+ static XIMStyle xic_style;
+
+ if (FRAME_XIC (f))
+ return;
+
+ xim = FRAME_X_XIM (f);
+ if (xim)
+ {
+ XRectangle s_area;
+ XPoint spot;
+ XVaNestedList preedit_attr;
+ XVaNestedList status_attr;
+ char *base_fontname;
+ int fontset;
+
+ s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
+ spot.x = 0; spot.y = 1;
+ /* Create X fontset. */
+ fontset = FRAME_FONTSET (f);
+ if (fontset < 0)
+ base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+ else
+ {
+ /* Determine the base fontname from the ASCII font name of
+ FONTSET. */
+ char *ascii_font = (char *) XSTRING (fontset_ascii (fontset))->data;
+ char *p = ascii_font;
+ int i;
+
+ for (i = 0; *p; p++)
+ if (*p == '-') i++;
+ if (i != 14)
+ /* As the font name doesn't conform to XLFD, we can't
+ modify it to get a suitable base fontname for the
+ frame. */
+ base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+ else
+ {
+ int len = strlen (ascii_font) + 1;
+ char *p1;
+
+ for (i = 0, p = ascii_font; i < 8; p++)
+ {
+ if (*p == '-')
+ {
+ i++;
+ if (i == 3)
+ p1 = p + 1;
+ }
+ }
+ base_fontname = (char *) alloca (len);
+ bzero (base_fontname, len);
+ strcpy (base_fontname, "-*-*-");
+ bcopy (p1, base_fontname + 5, p - p1);
+ strcat (base_fontname, "*-*-*-*-*-*-*");
+ }
+ }
+ xfs = xic_create_xfontset (f, base_fontname);
+
+ /* Determine XIC style. */
+ if (xic_style == 0)
+ {
+ XIMStyles supported_list;
+ supported_list.count_styles = (sizeof supported_xim_styles
+ / sizeof supported_xim_styles[0]);
+ supported_list.supported_styles = supported_xim_styles;
+ xic_style = best_xim_style (&supported_list,
+ FRAME_X_XIM_STYLES (f));
+ }
+
+ preedit_attr = XVaCreateNestedList (0,
+ XNFontSet, xfs,
+ XNForeground,
+ FRAME_FOREGROUND_PIXEL (f),
+ XNBackground,
+ FRAME_BACKGROUND_PIXEL (f),
+ (xic_style & XIMPreeditPosition
+ ? XNSpotLocation
+ : NULL),
+ &spot,
+ NULL);
+ status_attr = XVaCreateNestedList (0,
+ XNArea,
+ &s_area,
+ XNFontSet,
+ xfs,
+ XNForeground,
+ FRAME_FOREGROUND_PIXEL (f),
+ XNBackground,
+ FRAME_BACKGROUND_PIXEL (f),
+ NULL);
+
+ xic = XCreateIC (xim,
+ XNInputStyle, xic_style,
+ XNClientWindow, FRAME_X_WINDOW(f),
+ XNFocusWindow, FRAME_X_WINDOW(f),
+ XNStatusAttributes, status_attr,
+ XNPreeditAttributes, preedit_attr,
+ NULL);
+ XFree (preedit_attr);
+ XFree (status_attr);
+ }
+
+ FRAME_XIC (f) = xic;
+ FRAME_XIC_STYLE (f) = xic_style;
+ FRAME_XIC_FONTSET (f) = xfs;
+}
+
+
+/* Destroy XIC and free XIC fontset of frame F, if any. */
+
+void
+free_frame_xic (f)
+ struct frame *f;
+{
+ if (FRAME_XIC (f) == NULL)
+ return;
+
+ XDestroyIC (FRAME_XIC (f));
+ if (FRAME_XIC_FONTSET (f))
+ XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+
+ FRAME_XIC (f) = NULL;
+ FRAME_XIC_FONTSET (f) = NULL;
+}
+
+
+/* Place preedit area for XIC of window W's frame to specified
+ pixel position X/Y. X and Y are relative to window W. */
+
+void
+xic_set_preeditarea (w, x, y)
+ struct window *w;
+ int x, y;
+{
+ struct frame *f = XFRAME (w->frame);
+ XVaNestedList attr;
+ XPoint spot;
+
+ spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
+ spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
+ attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
+ XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+ XFree (attr);
+}
+
+
+/* Place status area for XIC in bottom right corner of frame F.. */
+
+void
+xic_set_statusarea (f)
+ struct frame *f;
+{
+ XIC xic = FRAME_XIC (f);
+ XVaNestedList attr;
+ XRectangle area;
+ XRectangle *needed;
+
+ /* Negotiate geometry of status area. If input method has existing
+ status area, use its current size. */
+ area.x = area.y = area.width = area.height = 0;
+ attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
+ XSetICValues (xic, XNStatusAttributes, attr, NULL);
+ XFree (attr);
+
+ attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
+ XGetICValues (xic, XNStatusAttributes, attr, NULL);
+ XFree (attr);
+
+ if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
+ {
+ attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
+ XGetICValues (xic, XNStatusAttributes, attr, NULL);
+ XFree (attr);
+ }
+
+ area.width = needed->width;
+ area.height = needed->height;
+ area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
+ area.y = (PIXEL_HEIGHT (f) - area.height
+ - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
+ XFree (needed);
+
+ attr = XVaCreateNestedList (0, XNArea, &area, NULL);
+ XSetICValues(xic, XNStatusAttributes, attr, NULL);
+ XFree (attr);
+}
+
+
+/* Set X fontset for XIC of frame F, using base font name
+ BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
+
+void
+xic_set_xfontset (f, base_fontname)
+ struct frame *f;
+ char *base_fontname;
+{
+ XVaNestedList attr;
+ XFontSet xfs;
+
+ xfs = xic_create_xfontset (f, base_fontname);
+
+ attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
+ if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
+ XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+ if (FRAME_XIC_STYLE (f) & XIMStatusArea)
+ XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
+ XFree (attr);
+
+ if (FRAME_XIC_FONTSET (f))
+ XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+ FRAME_XIC_FONTSET (f) = xfs;
+}
+
+#endif /* HAVE_X_I18N */
+
+