diff src/xfns.c @ 27502:52e8cb1333f2

(xic_set_preeditarea): Take window parameter and window-relative pixel-positions. (x_create_im): Removed. (DEFAULT_STYLE, DEFAULT_FONT): Removed. (supported_xim_styles): Renamed from supported_styles. (best_xim_style): Renamed from best_style. (create_frame_xic): Renamed from xic_create_frame. (free_frame_xic): Renamed from xic_destroy_frame. (supported_styles): New variable. (DEFAULT_STYLE, DEFAULT_FONT): New macros (xic_create_xfontset, best_style, xic_create_frame) (xic_destroy_frame, xic_set_preeditarea, xic_set_statusarea) (xic_set_xfontset): New functions.
author Gerd Moellmann <gerd@gnu.org>
date Sat, 29 Jan 2000 23:17:49 +0000
parents 43230463dfcf
children 4137c807296b
line wrap: on
line diff
--- a/src/xfns.c	Sat Jan 29 23:17:15 2000 +0000
+++ b/src/xfns.c	Sat Jan 29 23:17:49 2000 +0000
@@ -3046,69 +3046,288 @@
 #endif
 
 
-/* Create input method and input context for frame F.  Set FRAME_XIM
-   (F) and FRAME_XIC (F).  */
-
-static void
-x_create_im (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;
-{
-  FRAME_XIM (f) = 0;
-  FRAME_XIC (f) = 0;
-  
-#ifdef HAVE_X_I18N
+     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;
+{
 #ifndef X_I18N_INHIBITED
-  { 
-    XIM xim;
-    XIC xic = NULL;
-    XIMStyles *styles;
-    XIMStyle input_style = XIMPreeditNothing | XIMStatusNothing;
-    int i, n;
-
-    xim = XOpenIM (FRAME_X_DISPLAY(f), NULL, NULL, NULL);
-    if (!xim)
-      return;
-    
-    if (XGetIMValues (xim, XNQueryInputStyle, &styles, NULL)
-	|| !styles)
-      {
-	/* Input method doesn't support any input style.  */
-	XCloseIM (xim);
-	return;
-      }
-
-    /* See if input_style is supported.  Give up if it isn't.  */
-    n = styles->count_styles;
-    for (i = 0; i < n; ++i)
-      if (styles->supported_styles[i] == input_style)
-	break;
-    
-    XFree (styles);
-    if (i == n)
-      {
-	XCloseIM (xim);
-	return;
-      }
-
-    /* Create the input context.  */
-    xic = XCreateIC (xim,  
-		     XNInputStyle,   input_style,
-		     XNClientWindow, FRAME_X_WINDOW(f),
-		     XNFocusWindow,  FRAME_X_WINDOW(f),
-		     NULL);
-    
-    if (!xic)
-      {
-	XCloseIM (xim);
-	return;
-      }
-
-    FRAME_XIM (f) = xim;
-    FRAME_XIC (f) = xic;
-  }
+  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 = {0, 0, 1, 1};
+      XPoint spot = {0, 1};
+      XVaNestedList preedit_attr;
+      XVaNestedList status_attr;
+      char *base_fontname;
+      int fontset;
+
+      /* Create X fontset. */
+      fontset = FRAME_FONTSET (f);
+      if (fontset < 0)
+	base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+      else
+	{
+	  struct fontset_info *fontsetp;
+	  int len = 0;
+	  int i;
+	  
+	  fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
+	  for (i = 0; i <= MAX_CHARSET; i++)
+	    if (fontsetp->fontname[i])
+	      len += strlen (fontsetp->fontname[i]) + 1;
+	  base_fontname = alloca (len);
+	  strcpy (base_fontname, fontsetp->fontname[CHARSET_ASCII]);
+	  for (i = MIN_CHARSET_OFFICIAL_DIMENSION1; i <= MAX_CHARSET; i++)
+	    if (fontsetp->fontname[i])
+	      {
+		strcat (base_fontname, ",");
+		strcat (base_fontname, fontsetp->fontname[i]);
+	      }
+	}
+      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;
+#else /* X_I18N_INHIBITED */
+  FRAME_XIC (f) = NULL;
+  FRAME_XIC_STYLE (f) = 0;
+  FRAME_XIC_FONTSET (f) = NULL;
 #endif /* X_I18N_INHIBITED */
+}
+
+
+/* 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 */
-}
+
 
 
 #ifdef USE_X_TOOLKIT
@@ -3266,7 +3485,11 @@
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
   class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
   XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
-  x_create_im (f);
+
+#ifdef HAVE_X_I18N
+  FRAME_XIC (f) = NULL;
+  create_frame_xic (f);
+#endif
 
   f->output_data.x->wm_hints.input = True;
   f->output_data.x->wm_hints.flags |= InputHint;
@@ -3288,8 +3511,19 @@
 		   XA_ATOM, 32, PropModeAppend,
 		   (unsigned char*) NULL, 0);
 
- /* Make all the standard events reach the Emacs frame.  */
+  /* Make all the standard events reach the Emacs frame.  */
   attributes.event_mask = STANDARD_EVENT_SET;
+
+#ifdef HAVE_X_I18N
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+    }
+#endif /* HAVE_X_I18N */
+  
   attribute_mask = CWEventMask;
   XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
 			   attribute_mask, &attributes);
@@ -3357,7 +3591,21 @@
 		     InputOutput, /* class */
 		     FRAME_X_DISPLAY_INFO (f)->visual,
 		     attribute_mask, &attributes);
-  x_create_im (f);
+
+#ifdef HAVE_X_I18N
+  create_frame_xic (f);
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+      attribute_mask = CWEventMask;
+      XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+			       attribute_mask, &attributes);
+    }
+#endif /* HAVE_X_I18N */
+  
   validate_x_resource_name ();
 
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;