*** empty log message ***
[m17n/m17n-lib.git] / src / m17n-X.c
index 376b12a..3bb06f4 100644 (file)
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307, USA.  */
 
+#include "config.h"
+
+#ifdef HAVE_X11
+
 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
 /*** @addtogroup m17nInternal
      @{ */
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -43,6 +45,7 @@
 
 #ifdef HAVE_XFT2
 #include <X11/Xft/Xft.h>
+#include <fontconfig/fcfreetype.h>
 #endif /* HAVE_XFT2 */
 
 #include "m17n-gui.h"
 #include "fontset.h"
 #include "face.h"
 
-typedef struct {
+typedef struct _MFontX MFontX;
+
+struct _MFontX 
+{
+  /* Record a font of the smallest pixel size.  */
   MFont core;
-  unsigned int sizes[2];
-} MXFont;
+  /* Nth bit tells the existence of a font of size N + 5.  So this is
+     for 5..36 pixel size fonts.  Usually this covers all sizes.  */
+  unsigned int size5_36;
+  /* Fonts of (size < 5 || size > 36) are listed here (except for a
+     scalable whose size is 0).  */
+  MFontX *next;
+};
+
+/* S must satisfy the condition (S >= 5 && S < 36).  */
 
-#define SET_SIZE(xfont, s) ((xfont)->sizes[(s) / 32] |= (1 << ((s) & 0x1F)))
-#define HAVE_SIZE(xfont, s) ((xfont)->sizes[(s) / 32] & (1 << ((s) & 0x1F)))
+#define SET_SIZE(FONTX, S) ((FONTX)->size5_36 |= (1 << ((S) - 5)))
 
-typedef struct {
-  int size, inc, used;
-  MXFont *fonts;
-} MXFontList;
+#define HAVE_SIZE(FONTX, S) ((FONTX)->size5_36 & (1 << ((S) - 5)))
 
 typedef struct
 {
@@ -82,14 +92,9 @@ typedef struct
 
   /** List of available X-core fonts on the display.  Keys are
       registries and values are plists whose keys are families and
-      values are pointers to MXFontList.  */
+      values are pointers to MFontX.  */
   MPlist *font_list;
 
-  /** List of available X-core fonts on the display.  Keys are
-      families and values are pointers to MFont.  For each MFont, only
-      these properties are important; FOUNDRY, FAMILY, REGISTRY.  */
-  MPlist *base_font_list;
-
   /** Nonzero means that <font_list> already contains all available
       fonts on the display.  */
   int all_fonts_scaned;
@@ -99,6 +104,9 @@ typedef struct
   int alt_mask;
   int super_mask;
   int hyper_mask;
+
+  Atom MULE_BASELINE_OFFSET;
+  Atom AVERAGE_WIDTH;
 } MDisplayInfo;
 
 /* Anchor of the chain of MDisplayInfo objects.  */
@@ -153,6 +161,8 @@ typedef struct
 
   GC scratch_gc;
 
+  int resy;
+
 #ifdef HAVE_XFT2
   XftDraw *xft_draw;
 #endif
@@ -160,8 +170,8 @@ typedef struct
   /** List of pointers to realized faces on the frame.  */
   MPlist *realized_face_list;
 
-  /* List of information about each font.  Keys are font registries,
-     values are (MFontInfo *).  */
+  /* List of single element whose value is a root of chain of realized
+     fonts.  */
   MPlist *realized_font_list;
 
   /** List of pointers to realized fontsets on the frame.  */
@@ -182,8 +192,7 @@ static MSymbol M_iso8859_1, M_iso10646_1;
 #define FRAME_VISUAL(frame) DefaultVisual (FRAME_DISPLAY (frame), \
                                           FRAME_SCREEN (frame))
 
-#define DEFAULT_FONT "-misc-fixed-medium-r-normal--*-120-*-*-*-*-iso8859-1"
-#define FALLBACK_FONT "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1"
+#define DEFAULT_FONT "-*-*-medium-r-normal--13-*-*-*-c-*-iso8859-1"
 
 typedef struct
 {
@@ -197,18 +206,23 @@ static void
 free_display_info (void *object)
 {
   MDisplayInfo *disp_info = (MDisplayInfo *) object;
-  MPlist *plist, *p;
+  MPlist *plist, *pl;
 
   MPLIST_DO (plist, disp_info->font_list)
     {
-      MPLIST_DO (p, MPLIST_VAL (plist))
-       free (MPLIST_VAL (p));
+      MPLIST_DO (pl, MPLIST_VAL (plist))
+       {
+         MFontX *fontx, *next;
+
+         for (fontx = MPLIST_VAL (pl); fontx; fontx = next)
+           {
+             next = fontx->next;
+             free (fontx);
+           }
+       }
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     }
   M17N_OBJECT_UNREF (disp_info->font_list);
-  MPLIST_DO (plist, disp_info->base_font_list)
-    free (MPLIST_VAL (plist));
-  M17N_OBJECT_UNREF (disp_info->base_font_list);
 
   if (disp_info->auto_display)
     XCloseDisplay (disp_info->display);
@@ -227,8 +241,8 @@ free_device (void *object)
     mfont__free_realized_fontset ((MRealizedFontset *) mplist_value (plist));
   M17N_OBJECT_UNREF (device->realized_fontset_list);
 
-  MPLIST_DO (plist, device->realized_font_list)
-    mfont__free_realized ((MRealizedFont *) MPLIST_VAL (plist));
+  if (MPLIST_VAL (device->realized_font_list))
+    mfont__free_realized (MPLIST_VAL (device->realized_font_list));
   M17N_OBJECT_UNREF (device->realized_font_list);
 
   MPLIST_DO (plist, device->realized_face_list)
@@ -421,19 +435,21 @@ set_region (MFrame *frame, GC gc, MDrawRegion region)
 \f
 /** X font handler */
 
-static MRealizedFont *xfont_select (MFrame *, MFont *, MFont *, int);
-static int xfont_open (MRealizedFont *);
+static MFont *xfont_select (MFrame *, MFont *, int);
+static MRealizedFont *xfont_open (MFrame *, MFont *, MFont *, MRealizedFont *);
 static void xfont_find_metric (MRealizedFont *, MGlyphString *, int, int);
-static unsigned xfont_encode_char (MRealizedFont *, unsigned);
+static int xfont_has_char (MFrame *, MFont *, MFont *, int, unsigned);
+static unsigned xfont_encode_char (MFrame *, MFont *, MFont *, unsigned);
 static void xfont_render (MDrawWindow, int, int, MGlyphString *,
                          MGlyph *, MGlyph *, int, MDrawRegion);
-static int xfont_list (MFrame *frame, MPlist *plist,
-                       MFont *font, MSymbol language, int maxnum);
-
+static int xfont_list (MFrame *, MPlist *, MFont *, int);
+static void xfont_list_family_names (MFrame *, MPlist *);
+static int xfont_check_capability (MRealizedFont *rfont, MSymbol capability);
 
 static MFontDriver xfont_driver =
   { xfont_select, xfont_open,
-    xfont_find_metric, xfont_encode_char, xfont_render, xfont_list };
+    xfont_find_metric, xfont_has_char, xfont_encode_char,
+    xfont_render, xfont_list, xfont_list_family_names, xfont_check_capability };
 
 static int
 font_compare (const void *p1, const void *p2)
@@ -446,15 +462,13 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MPlist *font_list = disp_info->font_list;
-  MPlist *base_font_list = disp_info->base_font_list;
   MPlist *plist, *p;
   char pattern[1024];
   char **font_names, **names;
   int nfonts;
   int i, j;
-  MXFont font;
-  MXFontList *xfont_table;
-  MFont *bfont = NULL;
+  MFont font;
+  int for_full_width;
 
   plist = mplist_get (font_list, registry);
   if (plist)
@@ -465,64 +479,83 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
   font_names = XListFonts (disp_info->display, pattern, 0x8000, &nfonts);
   if (nfonts == 0)
     return plist;
+  {
+    char *reg_name = msymbol_name (registry);
+
+    for_full_width = (strncmp (reg_name, "jis", 3) == 0
+                     || strncmp (reg_name, "gb", 2) == 0
+                     || strncmp (reg_name, "big5", 4) == 0
+                     || strncmp (reg_name, "ksc", 3) == 0);
+  }
   names = alloca (sizeof (char *) * nfonts);
   memcpy (names, font_names, sizeof (char *) * nfonts);
   qsort (names, nfonts, sizeof (char *), font_compare);
+  MFONT_INIT (&font);
   for (i = 0, p = NULL; i < nfonts; i++)
-    if (mfont__parse_name_into_font (names[i], Mx, (MFont *) &font) == 0
-       && (font.core.property[MFONT_SIZE] > 0
-           || font.core.property[MFONT_RESY] == 0))
+    if (mfont__parse_name_into_font (names[i], Mx, &font) == 0
+       && (font.size >= 50 || font.property[MFONT_RESY] == 0))
       {
-       MSymbol family = FONT_PROPERTY ((MFont *) &font, MFONT_FAMILY);
-       int size = font.core.property[MFONT_SIZE] / 10;
+       MSymbol family = FONT_PROPERTY (&font, MFONT_FAMILY);
+       MFontX *fontx, *fontx2;
+       unsigned sizes[256];
+       int nsizes = 0;
+       int size, smallest;
        char *base_end;
        int base_len;
        int fields;
        
-       font.sizes[0] = font.sizes[1] = 0;
-       SET_SIZE (&font, size);
-           
-       /* Handle fonts of the same base.  */
+       if (p && MPLIST_KEY (p) != family)
+         p = mplist_find_by_key (plist, family);
+       if (! p)
+         p = mplist_push (plist, family, NULL);
+
+       /* Calculate how many bytes to compare to detect fonts of the
+          same base name.  */
        for (base_end = names[i], fields = 0; *base_end; base_end++)
          if (*base_end == '-'
              && ++fields == 7  /* PIXEL_SIZE */)
            break;
-       base_len = base_end - names[i];
+       base_len = base_end - names[i] + 1;
+
+       size = smallest = font.size / 10;
+       sizes[nsizes++] = size;
        for (j = i + 1; j < nfonts && ! strncmp (names[i], names[j], base_len);
             i = j++)
-         if (mfont__parse_name_into_font (names[j], Mx, (MFont *) &font) == 0
-             && (font.core.property[MFONT_SIZE] > 0
-                 || font.core.property[MFONT_RESY] == 0))
+         if (mfont__parse_name_into_font (names[j], Mx, &font) == 0
+             && (font.size >= 50 || font.property[MFONT_RESY] == 0))
            {
-             size = font.core.property[MFONT_SIZE] / 10;
-             SET_SIZE (&font, size);
+             size = font.size / 10;
+             if (size < smallest)
+               smallest = size;
+             if (nsizes < 256)
+               sizes[nsizes++] = size;
            }
 
-       if (p && MPLIST_KEY (p) != family)
-         p = mplist_find_by_key (plist, family);
-       if (p)
-         xfont_table = MPLIST_VAL (p);
-       else
-         {
-           p = plist;
-           MSTRUCT_MALLOC (xfont_table, MERROR_WIN);
-           MLIST_INIT1 (xfont_table, fonts, 4);
-           mplist_push (p, family, xfont_table);
-         }
-       MLIST_APPEND1 (xfont_table, fonts, font, MERROR_WIN);
-       if (! bfont
-           || (font.core.property[MFONT_FOUNDRY]
-               != bfont->property[MFONT_FOUNDRY])
-           || (font.core.property[MFONT_FAMILY]
-               != bfont->property[MFONT_FAMILY]))
-         {
-           MSTRUCT_MALLOC (bfont, MERROR_WIN);
-           *bfont = font.core;
-           for (j = MFONT_WEIGHT; j <= MFONT_ADSTYLE; j++)
-             bfont->property[j] = 0;
-           bfont->property[MFONT_SIZE] = bfont->property[MFONT_RESY] = 0;
-           mplist_push (base_font_list, family, bfont);
-         }
+       font.for_full_width = for_full_width;
+       font.type = MFONT_TYPE_OBJECT;
+       font.source = MFONT_SOURCE_X;
+       MSTRUCT_CALLOC (fontx, MERROR_WIN);
+       fontx->core = font;
+       fontx->core.size = smallest * 10;
+       fontx->next = MPLIST_VAL (p);
+       MPLIST_VAL (p) = fontx;
+       if (smallest > 0)
+         for (j = 0; j < nsizes; j++)
+           {
+             if (sizes[j] <= 36)
+               {
+                 if (sizes[j] != smallest)
+                   SET_SIZE (fontx, sizes[j]);
+               }
+             else
+               {
+                 MSTRUCT_CALLOC (fontx2, MERROR_WIN);
+                 fontx2->core = font;
+                 fontx2->core.size = sizes[j] * 10;
+                 fontx2->next = MPLIST_VAL (p);
+                 MPLIST_VAL (p) = fontx2;
+               }
+           }
       }
   XFreeFontNames (font_names);
   return plist;
@@ -544,149 +577,124 @@ xfont_list_all (MFrame *frame)
     xfont_registry_list (frame, MPLIST_KEY (p));
 }
 
-
 typedef struct
 {
   M17NObject control;
   Display *display;
   XFontStruct *xfont;
-} MXFontInfo;
+} MRealizedFontX;
 
 /* The X font driver function SELECT.  */
 
-static MRealizedFont *
-xfont_select (MFrame *frame, MFont *spec, MFont *request, int limited_size){
-
-  MSymbol family = FONT_PROPERTY (spec, MFONT_FAMILY);
-  MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
-  int requested_size = request->property[MFONT_SIZE];
-  MRealizedFont *rfont;
-  MPlist *plist;
-  int i;
-  MFont *best_font;
-  int best_score, score;
-
-  if (registry == Mnil
-      || ! strchr (MSYMBOL_NAME (registry), '-'))
-    return NULL;
-
-  plist = xfont_registry_list (frame, registry);
-  if (MPLIST_TAIL_P (plist))
-    return NULL;
-  best_score = -1, best_font = NULL;
-  if (family == Mnil)
-    family = FONT_PROPERTY (request, MFONT_FAMILY);
-  MPLIST_DO (plist, plist)
-    {
-      if (family == Mnil || family == MPLIST_KEY (plist))
-       {
-         MXFontList *xfont_table = MPLIST_VAL (plist);
-
-         for (i = 0; i < xfont_table->used; i++)
-           {
-             MXFont *xfont = xfont_table->fonts + i;
-             MFont *font = (MFont *) xfont;
-             int size = requested_size / 10, s0, s1;
-             
-             for (s0 = size; s0 > 0 && ! HAVE_SIZE (xfont, s0); s0--);
-             if (s0 * 10 == requested_size)
-               /* Exact size match.  */
-               ;
-             else if (xfont->sizes[0] & 1)
-               /* Scalable font.  */
-               size = 0;
-             else if (limited_size)
-               /* We can't use a larger font.  */
-               continue;
-             else if (s0 == 0)
-               {
-                 for (s0 = size + 1; s0 < 64 && ! HAVE_SIZE (xfont, s0); s0++);
-                 if (s0 == 64)
-                   continue;
-                 size = s0;
-               }
-             else
-               {
-                 for (s1 = size + (size - s0) - 1;
-                      s1 > size && HAVE_SIZE (xfont, s1); s1++);
-                 size = (s1 > size ? s1 : s0);
-               }
-             font->property[MFONT_SIZE] = size * 10;
+static MFont *
+xfont_select (MFrame *frame, MFont *font, int limited_size)
+{
+  MPlist *plist = mplist (), *pl;
+  int num = xfont_list (frame, plist, font, 0);
+  MFont *found = NULL;
 
-             if ((score = mfont__score (font, spec, request,
-                                        limited_size)) >= 0
-                 && (best_score < 0 || score < best_score))
-             {
-               best_score = score;
-               best_font = (MFont *) (xfont_table->fonts + i);
-               if (best_score == 0)
-                 break;
-             }
-           }
-         if (best_score == 0)
+  if (num > 0)
+    MPLIST_DO (pl, plist)
+      {
+       font = MPLIST_VAL (pl);
+       if (limited_size == 0
+           || font->size == 0
+           || font->size <= limited_size)
+         {
+           found = font;
            break;
-       }
-    }
-  if (! best_font)
-    return NULL;
-
-  MSTRUCT_CALLOC (rfont, MERROR_WIN);
-  rfont->frame = frame;
-  rfont->spec = *spec;
-  rfont->request = *request;
-  rfont->font = *best_font;
-  if (best_font->property[MFONT_SIZE] == 0)
-    rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
-  rfont->score = best_score;
-  return rfont;
+         }
+      }
+  M17N_OBJECT_UNREF (plist);
+  return found;
 }
 
-
 /* The X font driver function CLOSE.  */
 
 static void
 close_xfont (void *object)
 {
-  MXFontInfo *xfont_info = object;
+  MRealizedFontX *x_rfont = object;
 
-  XFreeFont (xfont_info->display, xfont_info->xfont);
-  free (object);
+  XFreeFont (x_rfont->display, x_rfont->xfont);
+  free (x_rfont);
 }
 
-
 /* The X font driver function OPEN.  */
 
-static int
-xfont_open (MRealizedFont *rfont)
+static MRealizedFont *
+xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 {
+  int size;
+  MRealizedFontX *x_rfont;
   char *name;
-  MXFontInfo *xfont_info;
-  MFrame *frame = rfont->frame;
+  Display *display = FRAME_DISPLAY (frame);
+  XFontStruct *xfont;
   int mdebug_mask = MDEBUG_FONT;
+  MFont this;
 
-  /* This never fail to generate a valid fontname because open_spec
-     should correspond to a font available on the system.  */
-  name = mfont_unparse_name (&rfont->font, Mx);
-  M17N_OBJECT (xfont_info, close_xfont, MERROR_WIN);
-  xfont_info->display = FRAME_DISPLAY (frame);
-  xfont_info->xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
-  if (! xfont_info->xfont)
+  if (font->size)
+    /* non-scalable font */
+    size = font->size;
+  else if (spec->size)
+    {
+      int ratio = mfont_resize_ratio (font);
+
+      size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+    }
+  else
+    size = 120;
+
+  if (rfont)
+    {
+      for (; rfont; rfont = rfont->next)
+       if (rfont->font == font && rfont->spec.size == size)
+         return rfont;
+    }
+
+  this = *font;
+  this.size = size;
+  /* This never fail to generate a valid fontname.  */
+  name = mfont_unparse_name (&this, Mx);
+  xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
+  if (! xfont)
     {
-      rfont->status = -1;
-      free (xfont_info);
       MDEBUG_PRINT1 (" [XFONT] x %s\n", name);
       free (name);
-      return -1;
+      font->type = MFONT_TYPE_FAILURE;
+      return NULL;
     }
-  rfont->info = xfont_info;
   MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
   free (name);
-  rfont->status = 1;
-  rfont->ascent = xfont_info->xfont->ascent;
-  rfont->descent = xfont_info->xfont->descent;
-  rfont->type = Mx;
-  rfont->fontp = xfont_info->xfont;
-  return 0;
+  M17N_OBJECT (x_rfont, close_xfont, MERROR_FONT_X);
+  x_rfont->display = display;
+  x_rfont->xfont = xfont;
+  MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
+  rfont->spec = this;
+  rfont->spec.type = MFONT_TYPE_REALIZED;
+  rfont->spec.source = MFONT_SOURCE_X;
+  rfont->frame = frame;
+  rfont->font = font;
+  rfont->driver = &xfont_driver;
+  rfont->info = x_rfont;
+  {
+    MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
+    unsigned long value;
+
+    rfont->baseline_offset
+      = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
+        ? (int) value : 0);
+    rfont->average_width
+      = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
+        ? (int) value / 10 : 0);
+  }
+  rfont->ascent = xfont->ascent + rfont->baseline_offset;
+  rfont->descent = xfont->descent - rfont->baseline_offset;
+  rfont->max_advance = xfont->max_bounds.width;
+  rfont->fontp = xfont;
+  rfont->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = rfont;
+  return rfont;
 }
 
 
@@ -696,8 +704,7 @@ static void
 xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                   int from, int to)
 {
-  MXFontInfo *xfont_info = rfont->info;
-  XFontStruct *xfont = xfont_info->xfont;
+  XFontStruct *xfont = rfont->fontp;
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
@@ -761,29 +768,48 @@ xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
              g->descent = xfont->descent;
            }
        }
+      g->ascent += rfont->baseline_offset;
+      g->descent -= rfont->baseline_offset;
     }
 }
 
 
+static int
+xfont_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
+{
+  return (xfont_encode_char (frame, font, spec, code) != MCHAR_INVALID_CODE);
+}
+
 /* The X font driver function GET_GLYPH_ID.  */
 
 static unsigned
-xfont_encode_char (MRealizedFont *rfont, unsigned code)
+xfont_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
 {
-  MXFontInfo *xfont_info;
+  MRealizedFont *rfont;
   XFontStruct *xfont;
   unsigned min_byte1, max_byte1, min_byte2, max_byte2;
   int all_chars_exist;
 
-  if (rfont->status < 0 || code >= 0x10000)
-    return MCHAR_INVALID_CODE;
-  if (rfont->status == 0)
+  if (font->type == MFONT_TYPE_REALIZED)
+    rfont = (MRealizedFont *) font;
+  else if (font->type == MFONT_TYPE_OBJECT)
     {
-      if (xfont_open (rfont) < 0)
-       return MCHAR_INVALID_CODE;
+      int size = spec->size;
+
+      for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
+          rfont = rfont->next)
+       if (rfont->font == font && rfont->spec.size == size)
+         break;
+      if (! rfont)
+       {
+         rfont = xfont_open (frame, font, spec, NULL);
+         if (! rfont)
+           return MCHAR_INVALID_CODE;
+       }
     }
-  xfont_info = rfont->info;
-  xfont = xfont_info->xfont;
+  else
+    MFATAL (MERROR_FONT_X);
+  xfont = rfont->fontp;
   all_chars_exist = (! xfont->per_char || xfont->all_chars_exist == True);
   min_byte1 = xfont->min_byte1;
   max_byte1 = xfont->max_byte1;
@@ -827,23 +853,20 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
              MGlyph *from, MGlyph *to, int reverse, MDrawRegion region)
 {
   MRealizedFace *rface = from->rface;
-  MXFontInfo *xfont_info = rface->rfont->info;
-  Display *display;
+  Display *display = FRAME_DISPLAY (rface->frame);
   XChar2b *code;
   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
   MGlyph *g;
   int i;
+  int baseline_offset;
 
   if (from == to)
     return;
 
-  /* It is assured that the all glyphs in the current range use the
-     same realized face.  */
-  display = FRAME_DISPLAY (rface->frame);
-
+  baseline_offset = rface->rfont->baseline_offset;
   if (region)
     gc = set_region (rface->frame, gc, region);
-  XSetFont (display, gc, xfont_info->xfont->fid);
+  XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
   for (i = 0, g = from; g < to; i++, g++)
     {
@@ -883,7 +906,8 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
       else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
        {
          XDrawString16 (display, (Window) win, gc,
-                        x + g->xoff, y + g->yoff, code + (g - from), 1);
+                        x + g->xoff, y + g->yoff - baseline_offset,
+                        code + (g - from), 1);
          x += g->width;
          g++;
        }
@@ -896,82 +920,138 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
               g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
               i++, g++)
              x += g->width;
-         XDrawString16 (display, (Window) win, gc, orig_x, y,
-                        code + code_idx, i);
+         XDrawString16 (display, (Window) win, gc,
+                        orig_x, y - baseline_offset, code + code_idx, i);
        }
     }
 }
 
 static int
-xfont_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
-           int maxnum)
+xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MSymbol registry = font ? FONT_PROPERTY (font, MFONT_REGISTRY) : Mnil;
   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
-  MPlist *p, *pl;
+  int size = font ? font->size : 0;
+  MPlist *pl, *p;
   int num = 0;
+  int mdebug_mask = MDEBUG_FONT;
 
-  if (registry != Mnil)
-    xfont_registry_list (frame, registry);
-  else
-    xfont_list_all (frame);
+  MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
+                family ? msymbol_name (family) : "*",
+                registry ? msymbol_name (registry) : "*");
 
-  /* As we have not yet implemented the language check, return all
-     base fonts.  */
-  if (! font)
-    MPLIST_DO (p, disp_info->base_font_list)
-      {
-       mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
-       num++;
-       if (num == maxnum)
-         return num;
-      }
+  if (registry == Mnil)
+    xfont_list_all (frame);
   else
-    {
-      MXFontList *xfontlist;
-      MXFont *xfont;
-      int i;
+    xfont_registry_list (frame, registry);
 
-      pl = disp_info->font_list;
-      if (registry != Mnil)
+  MPLIST_DO (pl, disp_info->font_list)
+    {
+      if (registry != Mnil && registry != MPLIST_KEY (pl))
+       continue;
+      MPLIST_DO (p, MPLIST_VAL (pl))
        {
-         pl = mplist_find_by_key (pl, registry);
-         if (! pl)
-           return 0;
+         MFontX *fontx;
+
+         if (family != Mnil && family != MPLIST_KEY (p))
+           continue;
+         for (fontx = MPLIST_VAL (p); fontx; fontx = fontx->next)
+           if (! font
+               || (mfont__match_p (&fontx->core, font, MFONT_REGISTRY)))
+             {
+               if (fontx->core.size == size
+                   || fontx->core.size == 0)
+                 {
+                   mplist_push (plist, MPLIST_KEY (p), fontx);
+                   num++;
+                 }
+               else if (size == 0
+                        || (size <= 360 && HAVE_SIZE (fontx, (size / 10))))
+                 {
+                   unsigned size5_36 = fontx->size5_36;
+                   MFontX *fontx2;
+                   int i;
+
+                   fontx->size5_36 = 0;
+                   for (i = fontx->core.size / 10; i <= 36; i++)
+                     if (size5_36 & (1 << (i - 5)))
+                       {
+                         MSTRUCT_CALLOC (fontx2, MERROR_WIN);
+                         fontx2->core = fontx->core;
+                         fontx2->core.size = i * 10;
+                         fontx2->next = fontx->next;
+                         fontx->next = fontx2;
+                         fontx = fontx2;
+                         if ((size == 0 || size == fontx->core.size)
+                             && (maxnum == 0 || num < maxnum))
+                           {
+                             mplist_push (plist, MPLIST_KEY (p), fontx);
+                             num++;
+                           }
+                       }
+                 }
+               if (maxnum > 0 && maxnum == num)
+                 break;
+             }
+         if (maxnum > 0 && maxnum == num)
+           break;
        }
+      if (maxnum > 0 && maxnum == num)
+       break;
+    }
 
-      MPLIST_DO (pl, pl)
+  MDEBUG_PRINT1 (" %d found\n", num);
+  return num;
+}
+
+static void
+xfont_list_family_names (MFrame *frame, MPlist *plist)
+{
+  MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
+  char **font_names;
+  int i, nfonts;
+  MSymbol last_family = Mnil;
+
+  font_names = XListFonts (disp_info->display,
+                          "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", 0x8000, &nfonts);
+  for (i = 0; i < nfonts; i++)
+    {
+      MSymbol family;
+      char foundry[256], fam[256];
+      MPlist *p;
+      
+      if (sscanf (font_names[i], "-%s-%s-", foundry, fam) < 2)
+       continue;
+      family = msymbol (fam);
+      if (family == last_family)
+       continue;
+      last_family = family;
+
+      MPLIST_DO (p, plist)
        {
-         p = MPLIST_VAL (pl);
-         if (family != Mnil)
-           {
-             p = mplist_find_by_key (p, family);
-             if (! p)
-               return 0;
-           }
-         MPLIST_DO (p, p)
+         MSymbol sym = MPLIST_SYMBOL (p);
+
+         if (sym == family)
+           break;
+         if (strcmp (MSYMBOL_NAME (sym), fam) > 0)
            {
-             xfontlist = MPLIST_VAL (p);
-             for (i = 0; i < xfontlist->used; i++)
-               {
-                 xfont = xfontlist->fonts + i;
-                 if (mfont__match_p (&xfont->core, font, MFONT_REGISTRY))
-                   {
-                     mplist_add (plist, MPLIST_KEY (p), &xfont->core);
-                     num++;
-                     if (num == maxnum)
-                       return num;
-                   }
-               }
-             if (family != Mnil)
-               break;
+             mplist_push (p, Msymbol, family);
+             break;
            }
-         if (registry != Mnil)
-           break;
        }
+      if (MPLIST_TAIL_P (p))
+       mplist_push (p, Msymbol, family);
     }
-  return num;
+  if (font_names)
+    XFreeFontNames (font_names);
+}
+
+static int 
+xfont_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  /* Currently X font driver doesn't support any capability.  */
+  return -1;
 }
 
 \f
@@ -985,115 +1065,162 @@ typedef struct
   Display *display;
   XftFont *font_aa;
   XftFont *font_no_aa;
-} MXftFontInfo;
-
-static int xft_open (MRealizedFont *);
+  FT_Face ft_face;
+  /* Pointer to MRealizedFontFT */
+  void *info;
+} MRealizedFontXft;
+
+static MRealizedFont *xft_open (MFrame *frame, MFont *font, MFont *spec,
+                               MRealizedFont *);
+static int xft_has_char (MFrame *frame, MFont *font, MFont *spec,
+                        int c, unsigned code);
+static unsigned xft_encode_char (MFrame *frame, MFont *font, MFont *spec,
+                                unsigned code);
 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xft_render (MDrawWindow, int, int, MGlyphString *,
                        MGlyph *, MGlyph *, int, MDrawRegion);
+static int xft_check_capability (MRealizedFont *rfont, MSymbol capability);
 
-MFontDriver xft_driver =
-  { NULL,                      /* Set to ft_select in device_init (). */
-    xft_open, xft_find_metric,
-    NULL,                      /* Set to ft_encode_char in device_init (). */
-    xft_render,
-    NULL                       /* Set to ft_list in device_init (). */
+static MFontDriver xft_driver =
+  { NULL, xft_open,
+    xft_find_metric, xft_has_char, xft_encode_char, xft_render, NULL, NULL,
+    xft_check_capability
   };
 
-
 static void
 close_xft (void *object)
 {
-  MXftFontInfo *font_info = object;
+  MRealizedFontXft *rfont_xft = object;
 
-  XftFontClose (font_info->display, font_info->font_aa);
-  XftFontClose (font_info->display, font_info->font_no_aa);
-  free (font_info);
+  if (rfont_xft->font_aa)
+    XftFontClose (rfont_xft->display, rfont_xft->font_aa);
+  if (rfont_xft->font_no_aa)
+    XftFontClose (rfont_xft->display, rfont_xft->font_no_aa);
+  M17N_OBJECT_UNREF (rfont_xft->info);
+  free (rfont_xft);
 }
 
 
 static XftFont *
-xft_open_font (MFrame *frame, MFTInfo *ft_info, int size, int anti_alias)
+xft_open_font (Display *display, MSymbol file, double size,
+              FcBool anti_alias)
 {
-  XftPattern *pattern;
-  XftFontInfo *xft_font_info;
+  FcPattern *pattern;
   XftFont *font;
 
-  pattern = XftPatternCreate ();
-  XftPatternAddString (pattern, XFT_FILE, ft_info->filename);
-  XftPatternAddDouble (pattern, XFT_PIXEL_SIZE, (double) size);
-  XftPatternAddBool (pattern, XFT_ANTIALIAS, anti_alias);
-  xft_font_info = XftFontInfoCreate (FRAME_DISPLAY (frame), pattern);
-  if (! xft_font_info)
-    return NULL;
-  font = XftFontOpenInfo (FRAME_DISPLAY (frame), pattern, xft_font_info);
-  XftFontInfoDestroy (FRAME_DISPLAY (frame), xft_font_info);
+  pattern = FcPatternCreate ();
+  FcPatternAddString (pattern, FC_FILE, (FcChar8 *) msymbol_name (file));
+  FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
+  FcPatternAddBool (pattern, FC_ANTIALIAS, anti_alias);
+  font = XftFontOpenPattern (display, pattern);
   return font;
 }
 
 
-static int
-xft_open (MRealizedFont *rfont)
+static MRealizedFont *
+xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 {
-  MFrame *frame;
-  MFTInfo *ft_info;
-  MXftFontInfo *font_info;
+  Display *display = FRAME_DISPLAY (frame);
+  int reg = spec->property[MFONT_REGISTRY];
+  FT_Face ft_face;
+  MRealizedFontXft *rfont_xft;
+  FcBool anti_alias = FRAME_DEVICE (frame)->depth > 1 ? FcTrue : FcFalse;
   int size;
+  XftFont *xft_font;
+  int ascent, descent, max_advance, average_width, baseline_offset;
 
-  if ((mfont__ft_driver.open) (rfont) < 0)
-    return -1;
+  if (font->size)
+    /* non-scalable font */
+    size = font->size;
+  else if (spec->size)
+    {
+      int ratio = mfont_resize_ratio (font);
 
-  size = rfont->font.property[MFONT_SIZE] / 10;
-  frame = rfont->frame;
+      size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+    }
+  else
+    size = 120;
 
-  ft_info = rfont->info;
-  M17N_OBJECT (font_info, close_xft, MERROR_WIN);
-  ft_info->extra_info = font_info;
-  font_info->display = FRAME_DISPLAY (frame);
-  font_info->font_aa = xft_open_font (frame, ft_info, size, 1);
-  if (font_info->font_aa)
+  if (rfont)
     {
-      font_info->font_no_aa = xft_open_font (frame, ft_info, size, 0);
-      if (font_info->font_no_aa)
-       {
-         rfont->type = Mxft;
-         rfont->fontp = font_info->font_no_aa;
-         return 0;
-       }
-      XftFontClose (FRAME_DISPLAY (rfont->frame), font_info->font_aa);
+      MRealizedFont *save = NULL;
+
+      for (; rfont; rfont = rfont->next)
+       if (rfont->font == font
+           && (rfont->font->size ? rfont->font->size == size
+               : rfont->spec.size == size)
+           && rfont->spec.property[MFONT_REGISTRY] == reg)
+         {
+           if (! save)
+             save = rfont;
+           if (rfont->driver == &xft_driver)
+             return rfont;
+         }
+      rfont = save;
     }
-  free (font_info);  
-  ft_info->extra_info = NULL;
-  rfont->status = -1;
-  return -1;
+  rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
+  if (! rfont)
+    return NULL;
+  ascent = rfont->ascent;
+  descent = rfont->descent;
+  max_advance = rfont->max_advance;
+  average_width = rfont->average_width;
+  baseline_offset = rfont->baseline_offset;
+  spec = &rfont->spec;
+  ft_face = rfont->fontp;
+  xft_font = xft_open_font (display, font->file, size / 10, anti_alias);
+  if (! xft_font)
+    return NULL;
+  M17N_OBJECT (rfont_xft, close_xft, MERROR_WIN);
+  rfont_xft->display = display;
+  if (anti_alias == FcTrue)
+    rfont_xft->font_aa = xft_font;
+  else
+    rfont_xft->font_no_aa = xft_font;
+  rfont_xft->ft_face = ft_face;
+  rfont_xft->info = rfont->info;
+  M17N_OBJECT_REF (rfont->info);
+  MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
+  rfont->spec = *spec;
+  rfont->spec.size = size;
+  rfont->frame = frame;
+  rfont->font = font;
+  rfont->driver = &xft_driver;
+  rfont->info = rfont_xft;
+  rfont->ascent = ascent;
+  rfont->descent = descent;
+  rfont->max_advance = max_advance;
+  rfont->average_width = average_width;
+  rfont->baseline_offset = baseline_offset;
+  rfont->fontp = xft_font;
+  rfont->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = rfont;
+  return rfont;
 }
 
-
 static void
 xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                int from, int to)
 {
-  MFTInfo *ft_info = rfont->info;
-  MXftFontInfo *font_info = ft_info->extra_info;
+  Display *display = FRAME_DISPLAY (rfont->frame);
+  XftFont *xft_font = rfont->fontp;
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
     {
       if (g->code == MCHAR_INVALID_CODE)
        {
-         MGlyph *start = g++;
-
-         while (g != gend && g->code == MCHAR_INVALID_CODE) g++;
-         (mfont__ft_driver.find_metric) (rfont, gstring, GLYPH_INDEX (start),
-                                         GLYPH_INDEX (g));
-         g--;
+         g->lbearing = 0;
+         g->rbearing = xft_font->max_advance_width;
+         g->width = g->rbearing;
+         g->ascent = xft_font->ascent;
+         g->descent = xft_font->descent;
        }
       else
        {
          XGlyphInfo extents;
 
-         XftGlyphExtents (FRAME_DISPLAY (gstring->frame),
-                          font_info->font_aa, &g->code, 1, &extents);
+         XftGlyphExtents (display, xft_font, &g->code, 1, &extents);
          g->lbearing = - extents.x;
          g->rbearing = extents.width - extents.x;
          g->width = extents.xOff;
@@ -1103,6 +1230,41 @@ xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
     }
 }
 
+static int
+xft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
+{
+  int result;
+
+  if (font->type == MFONT_TYPE_REALIZED)
+    {
+      MRealizedFont *rfont = (MRealizedFont *) font;
+      MRealizedFontXft *rfont_xft = rfont->info;
+      
+      rfont->info = rfont_xft->info;
+      result = mfont__ft_driver.has_char (frame, font, spec, c, code);
+      rfont->info = rfont_xft;
+    }
+  else
+    result = mfont__ft_driver.has_char (frame, font, spec, c, code);
+  return result;
+}
+
+static unsigned
+xft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
+{
+  if (font->type == MFONT_TYPE_REALIZED)
+    {
+      MRealizedFont *rfont = (MRealizedFont *) font;
+      MRealizedFontXft *rfont_xft = rfont->info;
+      
+      rfont->info = rfont_xft->info;
+      code = mfont__ft_driver.encode_char (frame, font, spec, code);
+      rfont->info = rfont_xft;
+    }
+  else
+    code = mfont__ft_driver.encode_char (frame, font, spec, code);
+  return code;
+}
 
 static void 
 xft_render (MDrawWindow win, int x, int y,
@@ -1111,15 +1273,16 @@ xft_render (MDrawWindow win, int x, int y,
 {
   MRealizedFace *rface = from->rface;
   MFrame *frame = rface->frame;
-  MFTInfo *ft_info = rface->rfont->info;
-  MXftFontInfo *font_info = ft_info->extra_info;
+  Display *display = FRAME_DISPLAY (frame);
+  MRealizedFont *rfont = rface->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
   XftColor *xft_color = (! reverse
                         ? &((GCInfo *) rface->info)->xft_color_fore
                         : &((GCInfo *) rface->info)->xft_color_back);
-  XftFont *xft_font = (gstring->control.anti_alias
-                      && FRAME_DEVICE (frame)->depth > 1
-                      ? font_info->font_aa : font_info->font_no_aa);
+  int anti_alias = (gstring->control.anti_alias
+                   && FRAME_DEVICE (frame)->depth > 1);
+  XftFont *xft_font;
   MGlyph *g;
   FT_UInt *glyphs;
   int last_x;
@@ -1128,9 +1291,43 @@ xft_render (MDrawWindow win, int x, int y,
   if (from == to)
     return;
 
+  if (anti_alias)
+    {
+      if (rfont_xft->font_aa)
+       xft_font = rfont_xft->font_aa;
+      else
+       {
+         double size = rfont->spec.size;
+
+         xft_font = xft_open_font (display, rfont->spec.file, size / 10,
+                                   FcTrue);
+         if (xft_font)
+           rfont_xft->font_aa = xft_font;
+         else
+           xft_font = rfont->fontp;
+       }
+    }
+  else
+    {
+      if (rfont_xft->font_no_aa)
+       xft_font = rfont_xft->font_no_aa;
+      else
+       {
+         double size = rfont->spec.size;
+
+         xft_font = xft_open_font (display, rfont->spec.file, size / 10,
+                                   FcTrue);
+         if (xft_font)
+           rfont_xft->font_no_aa = xft_font;
+         else
+           xft_font = rfont->fontp;
+       }
+    }
+
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
+  y -= rfont->baseline_offset;
   glyphs = alloca (sizeof (FT_UInt) * (to - from));
   for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
     {
@@ -1151,7 +1348,19 @@ xft_render (MDrawWindow win, int x, int y,
     XftDrawGlyphs (xft_draw, xft_color, xft_font, last_x, y, glyphs, nglyphs);
 }
 
-#endif
+static int
+xft_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.check_capability (rfont, capability);
+  rfont->info = rfont_xft;
+  return result;
+}
+
+#endif /* HAVE_XFT2 */
 
 \f
 /* Functions for the device driver.  */
@@ -1159,7 +1368,9 @@ xft_render (MDrawWindow win, int x, int y,
 static void
 mwin__close_device (MFrame *frame)
 {
-  M17N_OBJECT_UNREF (FRAME_DEVICE (frame));
+  MWDevice *device = FRAME_DEVICE (frame);
+
+  M17N_OBJECT_UNREF (device);
 }
 
 static void *
@@ -1235,7 +1446,7 @@ mwin__realize_face (MRealizedFace *rface)
                           MSYMBOL_NAME (background),
                           &info->xft_color_back))
     mdebug_hook ();
-#endif
+#endif /* HAVE_XFT2 */
 
   hline = rface->hline;
   if (hline)
@@ -1595,6 +1806,12 @@ mwin__create_window (MFrame *frame, MDrawWindow parent)
 static void
 mwin__destroy_window (MFrame *frame, MDrawWindow win)
 {
+#ifdef HAVE_XFT2
+  XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
+
+  if (XftDrawDrawable (xft_draw) == (Drawable) win)
+    XftDrawChange (xft_draw, FRAME_DEVICE (frame)->drawable);
+#endif /* HAVE_XFT2 */
   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
 }
 
@@ -1744,7 +1961,7 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
   int len;
   char buf[512];
   KeySym keysym;
-  MSymbol key;
+  MSymbol key = Mnil;
 
   *modifiers = 0;
   if (event->xany.type != KeyPress
@@ -1773,7 +1990,7 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
     }
   else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
     return Mnil;
-  else
+  if (key == Mnil)
     {
       char *str = XKeysymToString (keysym);
 
@@ -1856,8 +2073,8 @@ device_init ()
 
 #ifdef HAVE_XFT2
   xft_driver.select = mfont__ft_driver.select;
-  xft_driver.encode_char = mfont__ft_driver.encode_char;
   xft_driver.list = mfont__ft_driver.list;
+  xft_driver.list_family_names = mfont__ft_driver.list_family_names;
 #endif
 
   Mxim = msymbol ("xim");
@@ -1874,6 +2091,23 @@ device_fini ()
   return 0;
 }
 
+
+#ifdef X_SET_ERROR_HANDLER
+static int
+x_error_handler (Display *display, XErrorEvent *error)
+{
+  mdebug_hook ();
+  return 0;
+}
+
+static int
+x_io_error_handler (Display *display)
+{
+  mdebug_hook ();
+  return 0;
+}
+#endif
+
 /** Return an MWDevice object corresponding to a display specified in
     PLIST.
 
@@ -1898,8 +2132,9 @@ device_open (MFrame *frame, MPlist *param)
   unsigned depth = 0;
   MPlist *plist;
   AppData app_data;
+  MFont *font = NULL;
   MFace *face;
-  int use_xfont = 1, use_freetype = 1;
+  int use_xfont = 0, use_freetype = 0, use_xft = 0;
 
   for (plist = param; (key = mplist_key (plist)) != Mnil;
        plist = mplist_next (plist))
@@ -1921,14 +2156,22 @@ device_open (MFrame *frame, MPlist *param)
          MSymbol val = MPLIST_SYMBOL (plist);
 
          if (val == Mx)
-           use_freetype = 0;
+           use_xfont = 1;
 #ifdef HAVE_FREETYPE
          else if (val == Mfreetype)
-           use_xfont = 0;
+           use_freetype = 1;
+#ifdef HAVE_XFT2
+         else if (val == Mxft)
+           use_xft = 1;
+#endif
 #endif
        }
     }
 
+  /* If none of them is specified, use all of them.  */
+  if (! use_xfont && ! use_freetype && ! use_xft)
+    use_xfont = use_freetype = use_xft = 1;
+
   if (widget)
     {
       display = XtDisplay (widget);
@@ -1987,8 +2230,11 @@ device_open (MFrame *frame, MPlist *param)
       disp_info->display = display;
       disp_info->auto_display = auto_display;
       disp_info->font_list = mplist ();
-      disp_info->base_font_list = mplist ();
       find_modifier_bits (disp_info);
+      disp_info->MULE_BASELINE_OFFSET
+       = XInternAtom (display, "_MULE_BASELINE_OFFSET", False);
+      disp_info->AVERAGE_WIDTH
+       = XInternAtom (display, "AVERAGE_WIDTH", False);
       mplist_add (display_info_list, Mt, disp_info);
     }  
 
@@ -1998,7 +2244,8 @@ device_open (MFrame *frame, MPlist *param)
       device = (MWDevice *) mplist_value (plist);
       if (device->display_info == disp_info
          && device->depth == depth
-         && device->cmap == cmap)
+         && device->cmap == cmap
+         && device->screen_num == screen_num)
        break;
     }
 
@@ -2008,6 +2255,7 @@ device_open (MFrame *frame, MPlist *param)
     {
       unsigned long valuemask = GCForeground;
       XGCValues values;
+      double pixels, mm;
 
       M17N_OBJECT (device, free_device, MERROR_WIN);
       device->display_info = disp_info;
@@ -2018,8 +2266,12 @@ device_open (MFrame *frame, MPlist *param)
                                        1, 1, depth);
       device->depth = depth;
       device->cmap = cmap;
+      pixels = DisplayHeight (display, screen_num);
+      mm = DisplayHeightMM (display, screen_num);
+      device->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
       device->realized_face_list = mplist ();
       device->realized_font_list = mplist ();
+      mplist_add (device->realized_font_list, Mt, NULL);
       device->realized_fontset_list = mplist ();
       device->gc_list = mplist ();
       values.foreground = BlackPixel (display, screen_num);
@@ -2034,17 +2286,23 @@ device_open (MFrame *frame, MPlist *param)
 
   frame->device = device;
   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
+  frame->dpi = device->resy;
   frame->driver = &x_driver;
   frame->font_driver_list = mplist ();
-  if (use_xfont)
-    mplist_add (frame->font_driver_list, Mx, &xfont_driver);
 #ifdef HAVE_XFT2
-  if (use_freetype)
-    mplist_add (frame->font_driver_list, Mfreetype, &xft_driver);
-#elif HAVE_FREETYPE
+  if (use_xft)
+    {
+      mplist_add (frame->font_driver_list, Mfreetype, &xft_driver);
+      use_freetype = 0;
+    }
+#endif /* HAVE_XFT2 */
+#ifdef HAVE_FREETYPE
   if (use_freetype)
     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
-#endif
+#endif /* HAVE_FREETYPE */
+  if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
+    mplist_push (frame->font_driver_list, Mx, &xfont_driver);
+
   frame->realized_font_list = device->realized_font_list;
   frame->realized_face_list = device->realized_face_list;
   frame->realized_fontset_list = device->realized_fontset_list;
@@ -2076,41 +2334,28 @@ device_open (MFrame *frame, MPlist *param)
       frame->videomode = Mnormal;
     }
 
-  {
-    int nfonts;
-    char **names = XListFonts (display, app_data.font, 1, &nfonts);
-
-    if (nfonts > 0)
-      {
-       if (! (frame->font = mfont_parse_name (names[0], Mx)))
-         {
-           /* The font name does not conform to XLFD.  Try to open the
-              font and get XA_FONT property.  */
-           XFontStruct *xfont = XLoadQueryFont (display, names[0]);
-
-           nfonts = 0;
-           if (xfont)
-             {
-               unsigned long value;
-               char *name;
-
-               if (XGetFontProperty (xfont, XA_FONT, &value)
-                   && (name = ((char *)
-                               XGetAtomName (display, (Atom) value))))
-                 {
-                   if ((frame->font = mfont_parse_name (name, Mx)))
-                     nfonts = 1;
-                 }
-               XFreeFont (display, xfont);
-             }
-         }
-       XFreeFontNames (names);
-      }
-    if (! nfonts)
-      frame->font = mfont_parse_name (FALLBACK_FONT, Mx);
-  }
+  if (strcmp (app_data.font, DEFAULT_FONT) != 0)
+    {
+      XFontStruct *xfont = XLoadQueryFont (display, app_data.font);
+      unsigned long value;
+      char *name;
 
-  face = mface_from_font (frame->font);
+      if (xfont)
+       {
+         font = mfont_parse_name (app_data.font, Mx);
+         if (! font
+             && XGetFontProperty (xfont, XA_FONT, &value)
+             && (name = ((char *) XGetAtomName (display, (Atom) value))))
+           font = mfont_parse_name (name, Mx);
+         XFreeFont (display, xfont);
+       }
+    }
+  if (! font)
+      font = mfont_parse_name (DEFAULT_FONT, Mx);
+  else if (! font->size)
+    font->size = 130;
+  face = mface_from_font (font);
+  free (font);
   face->property[MFACE_FONTSET] = mfontset (NULL);
   face->property[MFACE_FOREGROUND] = frame->foreground;
   face->property[MFACE_BACKGROUND] = frame->background;
@@ -2127,7 +2372,6 @@ device_open (MFrame *frame, MPlist *param)
   XSetErrorHandler (x_error_handler);
   XSetIOErrorHandler (x_io_error_handler);
 #endif
-
   return 0;
 }
 
@@ -2322,23 +2566,6 @@ xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
 }
 
 \f
-
-#ifdef X_SET_ERROR_HANDLER
-static int
-x_error_handler (Display *display, XErrorEvent *error)
-{
-  mdebug_hook ();
-  return 0;
-}
-
-static int
-x_io_error_handler (Display *display)
-{
-  mdebug_hook ();
-  return 0;
-}
-#endif
-
 /*=*/
 
 /*** @} */
@@ -2347,7 +2574,7 @@ x_io_error_handler (Display *display)
 /* External API */
 
 /*** @addtogroup m17nInputMethodWin */
-/*=*/
+
 /*** @{ */
 
 /***en
@@ -2382,31 +2609,27 @@ x_io_error_handler (Display *display)
 /***ja
     @brief XIMÍÑÆþÎϥɥ饤¥Ð.
 
-    ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã
-    ¥ÉÍѤǤ¢¤ê¡¢ XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸
-    ¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
+    ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã¥ÉÍѤǤ¢¤ê¡¢
+    XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
 
     ¥·¥ó¥Ü¥ë #Mxim ¤Ï¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥×¥í¥Ñ¥Æ¥£
-    #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim ¤Ç¤¢¤ëÆþÎÏ
-    ¥á¥½¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
+    #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim 
+    ¤Ç¤¢¤ëÆþÎϥ᥽¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
 
-    ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø
-    ¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ 
+    ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
-    ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM ¤Ø¤Î¥Ý
-    ¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò
-    »²¾È¡£
+    ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM 
+    ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò»²¾È¡£
 
-    ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC ¤Ø¤Î
-    ¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ
-    ¤ò»²¾È¡£
+    ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC 
+    ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ¤ò»²¾È¡£
 
-    ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent ¤Ø¤Î¥Ý¥¤¥ó¥¿
-    ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
+    ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent 
+    ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
 
     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô function minput_filter () 
-    ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì
-    ¤ë¡£  */
+    ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì¤ë¡£  */
 
 MInputDriver minput_xim_driver =
   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
@@ -2414,6 +2637,12 @@ MInputDriver minput_xim_driver =
 
 /*** @} */ 
 
+#else  /* not HAVE_X11 */
+
+int device_open () { return -1; }
+
+#endif /* not HAVE_X11 */
+
 /*
   Local Variables:
   coding: euc-japan