(xft_render): Check xft_draw's drawable before changing
[m17n/m17n-lib.git] / src / m17n-X.c
1 /* m17n-X.c -- implementation of the GUI API on X Windows.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 #include "config.h"
24
25 #ifdef HAVE_X11
26
27 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
28 /*** @addtogroup m17nInternal
29      @{ */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <locale.h>
36
37 #include <X11/Xlib.h>
38 #include <X11/keysym.h>
39 #include <X11/Xlocale.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xresource.h>
42 #include <X11/Xatom.h>
43 #include <X11/StringDefs.h>
44 #include <X11/Intrinsic.h>
45
46 #ifdef HAVE_XFT2
47 #include <X11/Xft/Xft.h>
48 #include <fontconfig/fcfreetype.h>
49 #endif  /* HAVE_XFT2 */
50
51 #include "m17n-gui.h"
52 #include "m17n-X.h"
53 #include "m17n-misc.h"
54 #include "internal.h"
55 #include "internal-gui.h"
56 #include "symbol.h"
57 #include "input.h"
58 #include "font.h"
59 #include "fontset.h"
60 #include "face.h"
61
62 typedef struct _MFontX MFontX;
63
64 struct _MFontX 
65 {
66   /* Record a font of the smallest pixel size.  */
67   MFont core;
68   /* Nth bit tells the existence of a font of size N + 5.  So this is
69      for 5..36 pixel size fonts.  Usually this covers all sizes.  */
70   unsigned int size5_36;
71   /* Fonts of (size < 5 || size > 36) are listed here (except for a
72      scalable whose size is 0).  */
73   MFontX *next;
74 };
75
76 /* S must satisfy the condition (S >= 5 && S < 36).  */
77
78 #define SET_SIZE(FONTX, S) ((FONTX)->size5_36 |= (1 << ((S) - 5)))
79
80 #define HAVE_SIZE(FONTX, S) ((FONTX)->size5_36 & (1 << ((S) - 5)))
81
82 typedef struct
83 {
84   /* Common header for the m17n object.  */
85   M17NObject control;
86
87   Display *display;
88
89   /* If nonzero, <display> is opened by this library.  Thus it should
90      be closed on freeing this structure.  */
91   int auto_display;
92
93   /** List of available X-core fonts on the display.  Keys are
94       registries and values are plists whose keys are families and
95       values are pointers to MFontX.  */
96   MPlist *font_list;
97
98   /** Nonzero means that <font_list> already contains all available
99       fonts on the display.  */
100   int all_fonts_scaned;
101
102  /** Modifier bit masks of the display.  */
103   int meta_mask;
104   int alt_mask;
105   int super_mask;
106   int hyper_mask;
107
108   Atom MULE_BASELINE_OFFSET;
109   Atom AVERAGE_WIDTH;
110 } MDisplayInfo;
111
112 /* Anchor of the chain of MDisplayInfo objects.  */
113 static MPlist *display_info_list;
114
115
116 /* Color value and the corresponding GC.  */
117 typedef struct
118 {
119   unsigned int rgb;            /* (red << 16) | (green << 8) | blue */
120   GC gc;
121 } RGB_GC;
122
123 enum gc_index
124   {
125     GC_INVERSE,
126     GC_NORMAL = GC_INVERSE + 7,
127     GC_HLINE,
128     GC_BOX_TOP,
129     GC_BOX_BOTTOM,
130     GC_BOX_LEFT,
131     GC_BOX_RIGHT,
132     GC_MAX
133   };
134
135 typedef struct
136 {
137   int rgb_fore;
138   int rgb_back;
139   /* The first 8 elements are indexed by an intensity for
140      anti-aliasing.  The 2nd to 7th are created on demand.  */
141   GC gc[GC_MAX];
142 #ifdef HAVE_XFT2
143   XftColor xft_color_fore, xft_color_back;
144 #endif
145 } GCInfo;
146
147 typedef struct
148 {
149   /* Common header for the m17n object.  */
150   M17NObject control;
151
152   MDisplayInfo *display_info;
153
154   int screen_num;
155
156   Drawable drawable;
157
158   unsigned depth;
159
160   Colormap cmap;
161
162   GC scratch_gc;
163
164   int resy;
165
166 #ifdef HAVE_XFT2
167   XftDraw *xft_draw;
168 #endif
169
170   /** List of pointers to realized faces on the frame.  */
171   MPlist *realized_face_list;
172
173   /* List of single element whose value is a root of chain of realized
174      fonts.  */
175   MPlist *realized_font_list;
176
177   /** List of pointers to realized fontsets on the frame.  */
178   MPlist *realized_fontset_list;
179
180   /** List of XColors vs GCs on the frame.  */
181   MPlist *gc_list;
182 } MWDevice;
183
184 static MPlist *device_list;
185
186 static MSymbol M_iso8859_1, M_iso10646_1;
187
188 #define FRAME_DEVICE(frame) ((MWDevice *) (frame)->device)
189 #define FRAME_DISPLAY(frame) (FRAME_DEVICE (frame)->display_info->display)
190 #define FRAME_SCREEN(frame) (FRAME_DEVICE (frame)->screen_num)
191 #define FRAME_CMAP(frame) (FRAME_DEVICE (frame)->cmap)
192 #define FRAME_VISUAL(frame) DefaultVisual (FRAME_DISPLAY (frame), \
193                                            FRAME_SCREEN (frame))
194
195 #define DEFAULT_FONT "-*-*-medium-r-normal--13-*-*-*-c-*-iso8859-1"
196
197 typedef struct
198 {
199   String font;
200   String foreground;
201   String background;
202   Boolean reverse_video;
203 } AppData, *AppDataPtr;
204
205 static void
206 free_display_info (void *object)
207 {
208   MDisplayInfo *disp_info = (MDisplayInfo *) object;
209   MPlist *plist, *pl;
210
211   MPLIST_DO (plist, disp_info->font_list)
212     {
213       MPLIST_DO (pl, MPLIST_VAL (plist))
214         {
215           MFontX *fontx, *next;
216
217           for (fontx = MPLIST_VAL (pl); fontx; fontx = next)
218             {
219               next = fontx->next;
220               free (fontx);
221             }
222         }
223       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
224     }
225   M17N_OBJECT_UNREF (disp_info->font_list);
226
227   if (disp_info->auto_display)
228     XCloseDisplay (disp_info->display);
229
230   free (object);
231 }
232
233 static void
234 free_device (void *object)
235 {
236   MWDevice *device = object;
237   MPlist *plist;
238
239   for (plist = device->realized_fontset_list;
240        mplist_key (plist) != Mnil; plist = mplist_next (plist))
241     mfont__free_realized_fontset ((MRealizedFontset *) mplist_value (plist));
242   M17N_OBJECT_UNREF (device->realized_fontset_list);
243
244   if (MPLIST_VAL (device->realized_font_list))
245     mfont__free_realized (MPLIST_VAL (device->realized_font_list));
246   M17N_OBJECT_UNREF (device->realized_font_list);
247
248   MPLIST_DO (plist, device->realized_face_list)
249     {
250       MRealizedFace *rface = MPLIST_VAL (plist);
251
252       free (rface->info);
253       mface__free_realized (rface);
254     }
255   M17N_OBJECT_UNREF (device->realized_face_list);
256
257   MPLIST_DO (plist, device->gc_list)
258     {
259       XFreeGC (device->display_info->display,
260                ((RGB_GC *) MPLIST_VAL (plist))->gc);
261       free (MPLIST_VAL (plist));
262     }
263   M17N_OBJECT_UNREF (device->gc_list);
264   XFreeGC (device->display_info->display, device->scratch_gc);
265
266 #ifdef HAVE_XFT2
267   XftDrawDestroy (device->xft_draw);
268 #endif
269
270   XFreePixmap (device->display_info->display, device->drawable);
271   M17N_OBJECT_UNREF (device->display_info);
272   free (object);
273 }
274
275
276 static void
277 find_modifier_bits (MDisplayInfo *disp_info)
278 {
279   Display *display = disp_info->display;
280   XModifierKeymap *mods;
281   KeyCode meta_l = XKeysymToKeycode (display, XK_Meta_L);
282   KeyCode meta_r = XKeysymToKeycode (display, XK_Meta_R);
283   KeyCode alt_l = XKeysymToKeycode (display, XK_Alt_L);
284   KeyCode alt_r = XKeysymToKeycode (display, XK_Alt_R);
285   KeyCode super_l = XKeysymToKeycode (display, XK_Super_L);
286   KeyCode super_r = XKeysymToKeycode (display, XK_Super_R);
287   KeyCode hyper_l = XKeysymToKeycode (display, XK_Hyper_L);
288   KeyCode hyper_r = XKeysymToKeycode (display, XK_Hyper_R);
289   int i, j;
290
291   mods = XGetModifierMapping (display);
292   /* We skip the first three sets for Shift, Lock, and Control.  The
293      remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5.  */
294   for (i = 3; i < 8; i++)
295     for (j = 0; j < mods->max_keypermod; j++)
296       {
297         KeyCode code = mods->modifiermap[i * mods->max_keypermod + j];
298
299         if (! code)
300           continue;
301         if (code == meta_l || code == meta_r)
302           disp_info->meta_mask |= (1 << i);
303         else if (code == alt_l || code == alt_r)
304           disp_info->alt_mask |= (1 << i);
305         else if (code == super_l || code == super_r)
306           disp_info->super_mask |= (1 << i);
307         else if (code == hyper_l || code == hyper_r)
308           disp_info->hyper_mask |= (1 << i);
309       }
310
311   /* If meta keys are not in any modifier, use alt keys as meta
312      keys.  */
313   if (! disp_info->meta_mask)
314     {
315       disp_info->meta_mask = disp_info->alt_mask;
316       disp_info->alt_mask = 0;
317     }
318   /* If both meta and alt are assigned to the same modifier, give meta
319      keys priority.  */
320   if (disp_info->meta_mask & disp_info->alt_mask)
321     disp_info->alt_mask &= ~disp_info->meta_mask;
322
323   XFreeModifiermap (mods);
324 }
325
326 static RGB_GC *
327 get_rgb_gc (MWDevice *device, XColor *xcolor)
328 {
329   int rgb = (((xcolor->red >> 8) << 16) | ((xcolor->green >> 8) << 8)
330              | (xcolor->blue >> 8));
331   MPlist *plist;
332   RGB_GC *rgb_gc;
333   unsigned long valuemask = GCForeground;
334   XGCValues values;
335
336   MPLIST_DO (plist, device->gc_list)
337     {
338       rgb_gc = MPLIST_VAL (plist);
339
340       if (rgb_gc->rgb == rgb)
341         return rgb_gc;
342       if (rgb_gc->rgb > rgb)
343         break;
344     }
345
346   if (! XAllocColor (device->display_info->display, device->cmap, xcolor))
347     return NULL;
348
349   rgb_gc = malloc (sizeof (RGB_GC));
350   rgb_gc->rgb = rgb;
351   values.foreground = xcolor->pixel;
352   rgb_gc->gc = XCreateGC (device->display_info->display,
353                           device->drawable, valuemask, &values);
354   mplist_push (plist, Mt, rgb_gc);
355   return rgb_gc;
356 }
357
358 static GC
359 get_gc (MFrame *frame, MSymbol color, int for_foreground, int *rgb_ret)
360 {
361   MWDevice *device = FRAME_DEVICE (frame);
362   XColor xcolor;
363   RGB_GC *rgb_gc;
364
365   if (color == Mnil)
366     {
367       if (frame->rface)
368         goto no_color;
369       color = for_foreground ? frame->foreground : frame->background;
370     }
371   if (! XParseColor (FRAME_DISPLAY (frame), device->cmap,
372                      msymbol_name (color), &xcolor))
373     goto no_color;
374   rgb_gc = get_rgb_gc (device, &xcolor);
375   if (! rgb_gc)
376     goto no_color;
377   if (rgb_ret)
378     *rgb_ret = rgb_gc->rgb;
379   return rgb_gc->gc;
380
381  no_color:
382   {
383     GCInfo *info = frame->rface->info;
384     GC gc;
385     int rgb;
386
387     if (for_foreground)
388       rgb = info->rgb_fore, gc = info->gc[GC_NORMAL];
389     else
390       rgb = info->rgb_back, gc = info->gc[GC_INVERSE];
391     if (rgb_ret)
392       *rgb_ret = rgb;
393     return gc;
394   }
395 }
396
397 static GC
398 get_gc_for_anti_alias (MWDevice *device, GCInfo *info, int intensity)
399 {
400   int rgb_fore, rgb_back;
401   XColor xcolor;
402   RGB_GC *rgb_gc;
403   GC gc;
404
405   if (info->gc[intensity])
406     return info->gc[intensity];
407
408   rgb_fore = info->rgb_fore, rgb_back = info->rgb_back;
409   xcolor.red = ((((rgb_fore & 0xFF0000) >> 16) * intensity
410                  + ((rgb_back & 0xFF0000) >> 16) * (7 - intensity)) / 7) << 8;
411   xcolor.green = ((((rgb_fore & 0xFF00) >> 8) * intensity
412                    + ((rgb_back & 0xFF00) >> 8) * (7 - intensity)) / 7) << 8;
413   xcolor.blue = (((rgb_fore & 0xFF) * intensity
414                   + (rgb_back & 0xFF) * (7 - intensity)) / 7) << 8;
415   rgb_gc = get_rgb_gc (device, &xcolor);
416   if (rgb_gc)
417     gc = rgb_gc->gc;
418   else
419     gc =get_gc_for_anti_alias (device, info,
420                                intensity < 4 ? intensity - 1 : intensity + 1);
421   return (info->gc[intensity] = gc);
422 }
423
424 static GC
425 set_region (MFrame *frame, GC gc, MDrawRegion region)
426 {
427   unsigned long valuemask = GCForeground;
428
429   XCopyGC (FRAME_DISPLAY (frame), gc, valuemask,
430            FRAME_DEVICE (frame)->scratch_gc);
431   XSetRegion (FRAME_DISPLAY (frame), FRAME_DEVICE (frame)->scratch_gc, region);
432   return FRAME_DEVICE (frame)->scratch_gc;
433 }
434
435 \f
436 /** X font handler */
437
438 static MFont *xfont_select (MFrame *, MFont *, int);
439 static MRealizedFont *xfont_open (MFrame *, MFont *, MFont *, MRealizedFont *);
440 static void xfont_find_metric (MRealizedFont *, MGlyphString *, int, int);
441 static int xfont_has_char (MFrame *, MFont *, MFont *, int, unsigned);
442 static unsigned xfont_encode_char (MFrame *, MFont *, MFont *, unsigned);
443 static void xfont_render (MDrawWindow, int, int, MGlyphString *,
444                           MGlyph *, MGlyph *, int, MDrawRegion);
445 static int xfont_list (MFrame *, MPlist *, MFont *, int);
446
447
448 static MFontDriver xfont_driver =
449   { xfont_select, xfont_open,
450     xfont_find_metric, xfont_has_char, xfont_encode_char,
451     xfont_render, xfont_list };
452
453 static int
454 font_compare (const void *p1, const void *p2)
455 {
456   return strcmp (*(char **) p1, *(char **) p2);
457 }
458
459 static MPlist *
460 xfont_registry_list (MFrame *frame, MSymbol registry)
461 {
462   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
463   MPlist *font_list = disp_info->font_list;
464   MPlist *plist, *p;
465   char pattern[1024];
466   char **font_names, **names;
467   int nfonts;
468   int i, j;
469   MFont font;
470   int for_full_width;
471
472   plist = mplist_get (font_list, registry);
473   if (plist)
474     return plist;
475   plist = mplist ();
476   mplist_add (font_list, registry, plist);
477   sprintf (pattern, "-*-*-*-*-*-*-*-*-*-*-*-*-%s", msymbol_name (registry));
478   font_names = XListFonts (disp_info->display, pattern, 0x8000, &nfonts);
479   if (nfonts == 0)
480     return plist;
481   {
482     char *reg_name = msymbol_name (registry);
483
484     for_full_width = (strncmp (reg_name, "jis", 3) == 0
485                       || strncmp (reg_name, "gb", 2) == 0
486                       || strncmp (reg_name, "big5", 4) == 0
487                       || strncmp (reg_name, "ksc", 3) == 0);
488   }
489   names = alloca (sizeof (char *) * nfonts);
490   memcpy (names, font_names, sizeof (char *) * nfonts);
491   qsort (names, nfonts, sizeof (char *), font_compare);
492   MFONT_INIT (&font);
493   for (i = 0, p = NULL; i < nfonts; i++)
494     if (mfont__parse_name_into_font (names[i], Mx, &font) == 0
495         && (font.size >= 50 || font.property[MFONT_RESY] == 0))
496       {
497         MSymbol family = FONT_PROPERTY (&font, MFONT_FAMILY);
498         MFontX *fontx, *fontx2;
499         unsigned sizes[256];
500         int nsizes = 0;
501         int size, smallest;
502         char *base_end;
503         int base_len;
504         int fields;
505         
506         if (p && MPLIST_KEY (p) != family)
507           p = mplist_find_by_key (plist, family);
508         if (! p)
509           p = mplist_push (plist, family, NULL);
510
511         /* Calculate how many bytes to compare to detect fonts of the
512            same base name.  */
513         for (base_end = names[i], fields = 0; *base_end; base_end++)
514           if (*base_end == '-'
515               && ++fields == 7  /* PIXEL_SIZE */)
516             break;
517         base_len = base_end - names[i] + 1;
518
519         size = smallest = font.size / 10;
520         sizes[nsizes++] = size;
521         for (j = i + 1; j < nfonts && ! strncmp (names[i], names[j], base_len);
522              i = j++)
523           if (mfont__parse_name_into_font (names[j], Mx, &font) == 0
524               && (font.size >= 50 || font.property[MFONT_RESY] == 0))
525             {
526               size = font.size / 10;
527               if (size < smallest)
528                 smallest = size;
529               if (nsizes < 256)
530                 sizes[nsizes++] = size;
531             }
532
533         font.for_full_width = for_full_width;
534         font.type = MFONT_TYPE_OBJECT;
535         font.source = MFONT_SOURCE_X;
536         MSTRUCT_CALLOC (fontx, MERROR_WIN);
537         fontx->core = font;
538         fontx->core.size = smallest * 10;
539         fontx->next = MPLIST_VAL (p);
540         MPLIST_VAL (p) = fontx;
541         if (smallest > 0)
542           for (j = 0; j < nsizes; j++)
543             {
544               if (sizes[j] <= 36)
545                 {
546                   if (sizes[j] != smallest)
547                     SET_SIZE (fontx, sizes[j]);
548                 }
549               else
550                 {
551                   MSTRUCT_CALLOC (fontx2, MERROR_WIN);
552                   fontx2->core = font;
553                   fontx2->core.size = sizes[j] * 10;
554                   fontx2->next = MPLIST_VAL (p);
555                   MPLIST_VAL (p) = fontx2;
556                 }
557             }
558       }
559   XFreeFontNames (font_names);
560   return plist;
561 }
562
563 static void
564 xfont_list_all (MFrame *frame)
565 {
566   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
567   MPlist *font_encoding_list, *p;
568
569   if (disp_info->all_fonts_scaned)
570     return;
571   disp_info->all_fonts_scaned = 1;
572   font_encoding_list = mfont__encoding_list ();
573   if (! font_encoding_list)
574     return;
575   MPLIST_DO (p, font_encoding_list)
576     xfont_registry_list (frame, MPLIST_KEY (p));
577 }
578
579 typedef struct
580 {
581   M17NObject control;
582   Display *display;
583   XFontStruct *xfont;
584 } MRealizedFontX;
585
586 /* The X font driver function SELECT.  */
587
588 static MFont *
589 xfont_select (MFrame *frame, MFont *font, int limited_size)
590 {
591   MPlist *plist = mplist (), *pl;
592   int num = xfont_list (frame, plist, font, 0);
593   MFont *found = NULL;
594
595   if (num > 0)
596     MPLIST_DO (pl, plist)
597       {
598         font = MPLIST_VAL (pl);
599         if (limited_size == 0
600             || font->size == 0
601             || font->size <= limited_size)
602           {
603             found = font;
604             break;
605           }
606       }
607   M17N_OBJECT_UNREF (plist);
608   return found;
609 }
610
611 /* The X font driver function CLOSE.  */
612
613 static void
614 close_xfont (void *object)
615 {
616   MRealizedFontX *x_rfont = object;
617
618   XFreeFont (x_rfont->display, x_rfont->xfont);
619   free (x_rfont);
620 }
621
622 /* The X font driver function OPEN.  */
623
624 static MRealizedFont *
625 xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
626 {
627   int size = spec->size;
628   MRealizedFontX *x_rfont;
629   char *name;
630   Display *display = FRAME_DISPLAY (frame);
631   XFontStruct *xfont;
632   int mdebug_mask = MDEBUG_FONT;
633   MFont this;
634
635   if (rfont)
636     {
637       for (; rfont; rfont = rfont->next)
638         if (rfont->font == font && rfont->spec.size == size)
639           return rfont;
640     }
641
642   this = *font;
643   this.size = size;
644   /* This never fail to generate a valid fontname.  */
645   name = mfont_unparse_name (&this, Mx);
646   xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
647   if (! xfont)
648     {
649       MDEBUG_PRINT1 (" [XFONT] x %s\n", name);
650       free (name);
651       font->type = MFONT_TYPE_FAILURE;
652       return NULL;
653     }
654   MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
655   free (name);
656   M17N_OBJECT (x_rfont, close_xfont, MERROR_FONT_X);
657   x_rfont->display = display;
658   x_rfont->xfont = xfont;
659   MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
660   rfont->spec = this;
661   rfont->spec.type = MFONT_TYPE_REALIZED;
662   rfont->spec.source = MFONT_SOURCE_X;
663   rfont->frame = frame;
664   rfont->font = font;
665   rfont->driver = &xfont_driver;
666   rfont->info = x_rfont;
667   {
668     MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
669     unsigned long value;
670
671     rfont->baseline_offset
672       = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
673          ? (int) value : 0);
674     rfont->average_width
675       = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
676          ? (int) value / 10 : 0);
677   }
678   rfont->ascent = xfont->ascent + rfont->baseline_offset;
679   rfont->descent = xfont->descent - rfont->baseline_offset;
680   rfont->max_advance = xfont->max_bounds.width;
681   rfont->fontp = xfont;
682   rfont->next = MPLIST_VAL (frame->realized_font_list);
683   MPLIST_VAL (frame->realized_font_list) = rfont;
684   return rfont;
685 }
686
687
688 /* The X font driver function FIND_METRIC.  */
689
690 static void
691 xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
692                    int from, int to)
693 {
694   XFontStruct *xfont = rfont->fontp;
695   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
696
697   for (; g != gend; g++)
698     {
699       if (g->code == MCHAR_INVALID_CODE)
700         {
701           g->lbearing = xfont->max_bounds.lbearing;
702           g->rbearing = xfont->max_bounds.rbearing;
703           g->width = xfont->max_bounds.width;
704           g->ascent = xfont->ascent;
705           g->descent = xfont->descent;
706         }
707       else
708         {
709           int byte1 = g->code >> 8, byte2 = g->code & 0xFF;
710           XCharStruct *pcm = NULL;
711
712           if (xfont->per_char != NULL)
713             {
714               if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
715                 {
716                   if (byte1 == 0
717                       && byte2 >= xfont->min_char_or_byte2
718                       && byte2 <= xfont->max_char_or_byte2)
719                     pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
720                 }
721               else
722                 {
723                   if (byte1 >= xfont->min_byte1
724                       && byte1 <= xfont->max_byte1
725                       && byte2 >= xfont->min_char_or_byte2
726                       && byte2 <= xfont->max_char_or_byte2)
727                     {
728                       pcm = (xfont->per_char
729                              + ((xfont->max_char_or_byte2
730                                  - xfont->min_char_or_byte2 + 1)
731                                 * (byte1 - xfont->min_byte1))
732                              + (byte2 - xfont->min_char_or_byte2));
733                     }
734                 }
735             }
736
737           if (pcm)
738             {
739               g->lbearing = pcm->lbearing;
740               g->rbearing = pcm->rbearing;
741               g->width = pcm->width;
742               g->ascent = pcm->ascent;
743               g->descent = pcm->descent;
744             }
745           else
746             {
747               /* If the per_char pointer is null, all glyphs between
748                  the first and last character indexes inclusive have
749                  the same information, as given by both min_bounds and
750                  max_bounds.  */
751               g->lbearing = 0;
752               g->rbearing = xfont->max_bounds.width;
753               g->width = xfont->max_bounds.width;
754               g->ascent = xfont->ascent;
755               g->descent = xfont->descent;
756             }
757         }
758       g->ascent += rfont->baseline_offset;
759       g->descent -= rfont->baseline_offset;
760     }
761 }
762
763
764 static int
765 xfont_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
766 {
767   return (xfont_encode_char (frame, font, spec, code) != MCHAR_INVALID_CODE);
768 }
769
770 /* The X font driver function GET_GLYPH_ID.  */
771
772 static unsigned
773 xfont_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
774 {
775   MRealizedFont *rfont;
776   XFontStruct *xfont;
777   unsigned min_byte1, max_byte1, min_byte2, max_byte2;
778   int all_chars_exist;
779
780   if (font->type == MFONT_TYPE_REALIZED)
781     rfont = (MRealizedFont *) font;
782   else if (font->type == MFONT_TYPE_OBJECT)
783     {
784       int size = spec->size;
785
786       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
787            rfont = rfont->next)
788         if (rfont->font == font && rfont->spec.size == size)
789           break;
790       if (! rfont)
791         {
792           rfont = xfont_open (frame, font, spec, NULL);
793           if (! rfont)
794             return MCHAR_INVALID_CODE;
795         }
796     }
797   else
798     MFATAL (MERROR_FONT_X);
799   xfont = rfont->fontp;
800   all_chars_exist = (! xfont->per_char || xfont->all_chars_exist == True);
801   min_byte1 = xfont->min_byte1;
802   max_byte1 = xfont->max_byte1;
803   min_byte2 = xfont->min_char_or_byte2;
804   max_byte2 = xfont->max_char_or_byte2;
805
806   if (min_byte1 == 0 && max_byte1 == 0)
807     {
808       XCharStruct *pcm;
809
810       if (code < min_byte2 || code > max_byte2)
811         return MCHAR_INVALID_CODE;
812       if (all_chars_exist)
813         return code;
814       pcm = xfont->per_char + (code - min_byte2);
815       return ((pcm->width > 0 || pcm->rbearing != pcm->lbearing)
816               ? code : MCHAR_INVALID_CODE);
817     }
818   else
819     {
820       unsigned byte1 = code >> 8, byte2 = code & 0xFF;
821       XCharStruct *pcm;
822
823       if (byte1 < min_byte1 || byte1 > max_byte1
824           || byte2 < min_byte2 || byte2 > max_byte2)
825         return MCHAR_INVALID_CODE;
826
827       if (all_chars_exist)
828         return code;
829       pcm = xfont->per_char + ((byte1 - min_byte1) * (max_byte2 - min_byte2 + 1)
830                            + (byte2 - min_byte2));
831       return ((pcm->width > 0 || pcm->rbearing != pcm->lbearing)
832               ? code : MCHAR_INVALID_CODE);
833     }
834 }
835
836 /* The X font driver function RENDER.  */
837
838 static void
839 xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
840               MGlyph *from, MGlyph *to, int reverse, MDrawRegion region)
841 {
842   MRealizedFace *rface = from->rface;
843   Display *display = FRAME_DISPLAY (rface->frame);
844   XChar2b *code;
845   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
846   MGlyph *g;
847   int i;
848   int baseline_offset;
849
850   if (from == to)
851     return;
852
853   baseline_offset = rface->rfont->baseline_offset;
854   if (region)
855     gc = set_region (rface->frame, gc, region);
856   XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
857   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
858   for (i = 0, g = from; g < to; i++, g++)
859     {
860       code[i].byte1 = g->code >> 8;
861       code[i].byte2 = g->code & 0xFF;
862     }
863
864   g = from;
865   while (g < to)
866     {
867       if (g->type == GLYPH_PAD)
868         x += g++->width;
869       else if (g->type == GLYPH_SPACE)
870         for (; g < to && g->type == GLYPH_SPACE; g++)
871           x += g->width;
872       else if (! g->rface->rfont)
873         {
874           if ((g->c >= 0x200B && g->c <= 0x200F)
875               || (g->c >= 0x202A && g->c <= 0x202E))
876             x += g++->width;
877           else
878             {
879               /* As a font is not found for this character, draw an
880                  empty box.  */
881               int box_width = g->width;
882               int box_height = gstring->ascent + gstring->descent;
883
884               if (box_width > 4)
885                 box_width -= 2;
886               if (box_height > 4)
887                 box_height -= 2;
888               XDrawRectangle (display, (Window) win, gc,
889                               x, y - gstring->ascent, box_width, box_height);
890               x += g++->width;
891             }
892         }
893       else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
894         {
895           XDrawString16 (display, (Window) win, gc,
896                          x + g->xoff, y + g->yoff - baseline_offset,
897                          code + (g - from), 1);
898           x += g->width;
899           g++;
900         }
901       else
902         {
903           int orig_x = x;
904           int code_idx = g - from;
905
906           for (i = 0;
907                g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
908                i++, g++)
909               x += g->width;
910           XDrawString16 (display, (Window) win, gc,
911                          orig_x, y - baseline_offset, code + code_idx, i);
912         }
913     }
914 }
915
916 static int
917 xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
918 {
919   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
920   MSymbol registry = font ? FONT_PROPERTY (font, MFONT_REGISTRY) : Mnil;
921   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
922   int size = font ? font->size : 0;
923   MPlist *pl, *p;
924   int num = 0;
925   int mdebug_mask = MDEBUG_FONT;
926
927   MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
928                  family ? msymbol_name (family) : "*",
929                  registry ? msymbol_name (registry) : "*");
930
931   if (registry == Mnil)
932     xfont_list_all (frame);
933   else
934     xfont_registry_list (frame, registry);
935
936   MPLIST_DO (pl, disp_info->font_list)
937     {
938       if (registry != Mnil && registry != MPLIST_KEY (pl))
939         continue;
940       MPLIST_DO (p, MPLIST_VAL (pl))
941         {
942           MFontX *fontx;
943
944           if (family != Mnil && family != MPLIST_KEY (p))
945             continue;
946           for (fontx = MPLIST_VAL (p); fontx; fontx = fontx->next)
947             if (! font
948                 || (mfont__match_p (&fontx->core, font, MFONT_REGISTRY)))
949               {
950                 if (fontx->core.size == size
951                     || fontx->core.size == 0)
952                   {
953                     mplist_push (plist, MPLIST_KEY (p), fontx);
954                     num++;
955                   }
956                 else if (size == 0
957                          || (size <= 360 && HAVE_SIZE (fontx, (size / 10))))
958                   {
959                     unsigned size5_36 = fontx->size5_36;
960                     MFontX *fontx2;
961                     int i;
962
963                     fontx->size5_36 = 0;
964                     for (i = fontx->core.size / 10; i <= 36; i++)
965                       if (size5_36 & (1 << (i - 5)))
966                         {
967                           MSTRUCT_CALLOC (fontx2, MERROR_WIN);
968                           fontx2->core = fontx->core;
969                           fontx2->core.size = i * 10;
970                           fontx2->next = fontx->next;
971                           fontx->next = fontx2;
972                           fontx = fontx2;
973                           if ((size == 0 || size == fontx->core.size)
974                               && (maxnum == 0 || num < maxnum))
975                             {
976                               mplist_push (plist, MPLIST_KEY (p), fontx);
977                               num++;
978                             }
979                         }
980                   }
981                 if (maxnum > 0 && maxnum == num)
982                   break;
983               }
984           if (maxnum > 0 && maxnum == num)
985             break;
986         }
987       if (maxnum > 0 && maxnum == num)
988         break;
989     }
990
991   MDEBUG_PRINT1 (" %d found\n", num);
992   return num;
993 }
994
995 \f
996 /* Xft Handler */
997
998 #ifdef HAVE_XFT2
999
1000 typedef struct
1001 {
1002   M17NObject control;
1003   Display *display;
1004   XftFont *font_aa;
1005   XftFont *font_no_aa;
1006   FT_Face ft_face;
1007   /* Pointer to MRealizedFontFT */
1008   void *info;
1009 } MRealizedFontXft;
1010
1011 static MRealizedFont *xft_open (MFrame *frame, MFont *font, MFont *spec,
1012                                 MRealizedFont *);
1013 static int xft_has_char (MFrame *frame, MFont *font, MFont *spec,
1014                          int c, unsigned code);
1015 static unsigned xft_encode_char (MFrame *frame, MFont *font, MFont *spec,
1016                                  unsigned code);
1017 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
1018 static void xft_render (MDrawWindow, int, int, MGlyphString *,
1019                         MGlyph *, MGlyph *, int, MDrawRegion);
1020
1021 MFontDriver xft_driver =
1022   { NULL, xft_open,
1023     xft_find_metric, xft_has_char, xft_encode_char, xft_render, NULL };
1024
1025 static void
1026 close_xft (void *object)
1027 {
1028   MRealizedFontXft *rfont_xft = object;
1029
1030   if (rfont_xft->font_aa)
1031     XftFontClose (rfont_xft->display, rfont_xft->font_aa);
1032   if (rfont_xft->font_no_aa)
1033     XftFontClose (rfont_xft->display, rfont_xft->font_no_aa);
1034   M17N_OBJECT_UNREF (rfont_xft->info);
1035   free (rfont_xft);
1036 }
1037
1038
1039 static XftFont *
1040 xft_open_font (Display *display, MSymbol file, double size,
1041                FcBool anti_alias)
1042 {
1043   FcPattern *pattern;
1044   XftFont *font;
1045
1046   pattern = FcPatternCreate ();
1047   FcPatternAddString (pattern, FC_FILE, (FcChar8 *) msymbol_name (file));
1048   FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
1049   FcPatternAddBool (pattern, FC_ANTIALIAS, anti_alias);
1050   font = XftFontOpenPattern (display, pattern);
1051   return font;
1052 }
1053
1054
1055 static MRealizedFont *
1056 xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1057 {
1058   Display *display = FRAME_DISPLAY (frame);
1059   int reg = spec->property[MFONT_REGISTRY];
1060   FT_Face ft_face;
1061   MRealizedFontXft *rfont_xft;
1062   FcBool anti_alias = FRAME_DEVICE (frame)->depth > 1 ? FcTrue : FcFalse;
1063   double size = font->size ? font->size : spec->size;
1064   XftFont *xft_font;
1065   int ascent, descent, max_advance, average_width, baseline_offset;
1066
1067   if (rfont)
1068     {
1069       MRealizedFont *save = NULL;
1070
1071       for (; rfont; rfont = rfont->next)
1072         if (rfont->font == font
1073             && (rfont->font->size ? rfont->font->size == size
1074                 : rfont->spec.size == size)
1075             && rfont->spec.property[MFONT_REGISTRY] == reg)
1076           {
1077             if (! save)
1078               save = rfont;
1079             if (rfont->driver == &xft_driver)
1080               return rfont;
1081           }
1082       rfont = save;
1083     }
1084   rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
1085   if (! rfont)
1086     return NULL;
1087   ascent = rfont->ascent;
1088   descent = rfont->descent;
1089   max_advance = rfont->max_advance;
1090   average_width = rfont->average_width;
1091   baseline_offset = rfont->baseline_offset;
1092   spec = &rfont->spec;
1093   ft_face = rfont->fontp;
1094   xft_font = xft_open_font (display, font->file, size / 10, anti_alias);
1095   if (! xft_font)
1096     return NULL;
1097   M17N_OBJECT (rfont_xft, close_xft, MERROR_WIN);
1098   rfont_xft->display = display;
1099   if (anti_alias == FcTrue)
1100     rfont_xft->font_aa = xft_font;
1101   else
1102     rfont_xft->font_no_aa = xft_font;
1103   rfont_xft->ft_face = ft_face;
1104   rfont_xft->info = rfont->info;
1105   M17N_OBJECT_REF (rfont->info);
1106   MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
1107   rfont->spec = *spec;
1108   rfont->frame = frame;
1109   rfont->font = font;
1110   rfont->driver = &xft_driver;
1111   rfont->info = rfont_xft;
1112   rfont->ascent = ascent;
1113   rfont->descent = descent;
1114   rfont->max_advance = max_advance;
1115   rfont->average_width = average_width;
1116   rfont->baseline_offset = baseline_offset;
1117   rfont->fontp = xft_font;
1118   rfont->next = MPLIST_VAL (frame->realized_font_list);
1119   MPLIST_VAL (frame->realized_font_list) = rfont;
1120   return rfont;
1121 }
1122
1123 static void
1124 xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1125                 int from, int to)
1126 {
1127   Display *display = FRAME_DISPLAY (rfont->frame);
1128   XftFont *xft_font = rfont->fontp;
1129   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1130
1131   for (; g != gend; g++)
1132     {
1133       if (g->code == MCHAR_INVALID_CODE)
1134         {
1135           g->lbearing = 0;
1136           g->rbearing = xft_font->max_advance_width;
1137           g->width = g->rbearing;
1138           g->ascent = xft_font->ascent;
1139           g->descent = xft_font->descent;
1140         }
1141       else
1142         {
1143           XGlyphInfo extents;
1144
1145           XftGlyphExtents (display, xft_font, &g->code, 1, &extents);
1146           g->lbearing = - extents.x;
1147           g->rbearing = extents.width - extents.x;
1148           g->width = extents.xOff;
1149           g->ascent = extents.y;
1150           g->descent = extents.height - extents.y;
1151         }
1152     }
1153 }
1154
1155 static int
1156 xft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1157 {
1158   int result;
1159
1160   if (font->type == MFONT_TYPE_REALIZED)
1161     {
1162       MRealizedFont *rfont = (MRealizedFont *) font;
1163       MRealizedFontXft *rfont_xft = rfont->info;
1164       
1165       rfont->info = rfont_xft->info;
1166       result = mfont__ft_driver.has_char (frame, font, spec, c, code);
1167       rfont->info = rfont_xft;
1168     }
1169   else
1170     result = mfont__ft_driver.has_char (frame, font, spec, c, code);
1171   return result;
1172 }
1173
1174 static unsigned
1175 xft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1176 {
1177   if (font->type == MFONT_TYPE_REALIZED)
1178     {
1179       MRealizedFont *rfont = (MRealizedFont *) font;
1180       MRealizedFontXft *rfont_xft = rfont->info;
1181       
1182       rfont->info = rfont_xft->info;
1183       code = mfont__ft_driver.encode_char (frame, font, spec, code);
1184       rfont->info = rfont_xft;
1185     }
1186   else
1187     code = mfont__ft_driver.encode_char (frame, font, spec, code);
1188   return code;
1189 }
1190
1191 static void 
1192 xft_render (MDrawWindow win, int x, int y,
1193             MGlyphString *gstring, MGlyph *from, MGlyph *to,
1194             int reverse, MDrawRegion region)
1195 {
1196   MRealizedFace *rface = from->rface;
1197   MFrame *frame = rface->frame;
1198   Display *display = FRAME_DISPLAY (frame);
1199   MRealizedFont *rfont = rface->rfont;
1200   MRealizedFontXft *rfont_xft = rfont->info;
1201   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
1202   XftColor *xft_color = (! reverse
1203                          ? &((GCInfo *) rface->info)->xft_color_fore
1204                          : &((GCInfo *) rface->info)->xft_color_back);
1205   int anti_alias = (gstring->control.anti_alias
1206                     && FRAME_DEVICE (frame)->depth > 1);
1207   XftFont *xft_font;
1208   MGlyph *g;
1209   FT_UInt *glyphs;
1210   int last_x;
1211   int nglyphs;
1212
1213   if (from == to)
1214     return;
1215
1216   if (anti_alias)
1217     {
1218       if (rfont_xft->font_aa)
1219         xft_font = rfont_xft->font_aa;
1220       else
1221         {
1222           double size = rfont->spec.size;
1223
1224           xft_font = xft_open_font (display, rfont->spec.file, size / 10,
1225                                     FcTrue);
1226           if (xft_font)
1227             rfont_xft->font_aa = xft_font;
1228           else
1229             xft_font = rfont->fontp;
1230         }
1231     }
1232   else
1233     {
1234       if (rfont_xft->font_no_aa)
1235         xft_font = rfont_xft->font_no_aa;
1236       else
1237         {
1238           double size = rfont->spec.size;
1239
1240           xft_font = xft_open_font (display, rfont->spec.file, size / 10,
1241                                     FcTrue);
1242           if (xft_font)
1243             rfont_xft->font_no_aa = xft_font;
1244           else
1245             xft_font = rfont->fontp;
1246         }
1247     }
1248
1249   if (XftDrawDrawable (xft_draw) != (Drawable) win)
1250     XftDrawChange (xft_draw, (Drawable) win);
1251   XftDrawSetClip (xft_draw, (Region) region);
1252       
1253   y -= rfont->baseline_offset;
1254   glyphs = alloca (sizeof (FT_UInt) * (to - from));
1255   for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
1256     {
1257       if (g->xoff == 0 && g->yoff == 0 && !g->left_padding && !g->right_padding)
1258         glyphs[nglyphs++] = g->code;
1259       else
1260         {
1261           if (nglyphs > 0)
1262             XftDrawGlyphs (xft_draw, xft_color, xft_font,
1263                            last_x, y, glyphs, nglyphs);
1264           nglyphs = 0;
1265           XftDrawGlyphs (xft_draw, xft_color, xft_font,
1266                          x + g->xoff, y + g->yoff, (FT_UInt *) &g->code, 1);
1267           last_x = x + g->width;
1268         }
1269     }
1270   if (nglyphs > 0)
1271     XftDrawGlyphs (xft_draw, xft_color, xft_font, last_x, y, glyphs, nglyphs);
1272 }
1273
1274 #endif  /* HAVE_XFT2 */
1275
1276 \f
1277 /* Functions for the device driver.  */
1278
1279 static void
1280 mwin__close_device (MFrame *frame)
1281 {
1282   MWDevice *device = FRAME_DEVICE (frame);
1283
1284   M17N_OBJECT_UNREF (device);
1285 }
1286
1287 static void *
1288 mwin__device_get_prop (MFrame *frame, MSymbol key)
1289 {
1290   MWDevice *device = FRAME_DEVICE (frame);
1291
1292   if (key == Mdisplay)
1293     return (void *) device->display_info->display;
1294   if (key == Mscreen)
1295     return (void *) ScreenOfDisplay(device->display_info->display,
1296                                     device->screen_num);
1297   if (key == Mcolormap)
1298     return (void *) device->cmap;
1299   if (key == Mdepth)
1300     return (void *) device->depth;
1301   return NULL;
1302 }
1303
1304 static void
1305 mwin__realize_face (MRealizedFace *rface)
1306 {
1307   MFrame *frame;
1308   MSymbol foreground, background, videomode;
1309   MFaceHLineProp *hline;
1310   MFaceBoxProp *box;
1311   GCInfo *info;
1312
1313   if (rface != rface->ascii_rface)
1314     {
1315       rface->info = rface->ascii_rface->info;
1316       return;
1317     }
1318
1319   frame = rface->frame;
1320   MSTRUCT_CALLOC (info, MERROR_WIN);
1321
1322   foreground = rface->face.property[MFACE_FOREGROUND];
1323   background = rface->face.property[MFACE_BACKGROUND];
1324   videomode = rface->face.property[MFACE_VIDEOMODE];
1325   if (! videomode)
1326     videomode = frame->videomode;
1327   if (videomode != Mreverse)
1328     {
1329       info->gc[GC_NORMAL] = get_gc (frame, foreground, 1, &info->rgb_fore);
1330       info->gc[GC_INVERSE] = get_gc (frame, background, 0, &info->rgb_back);
1331     }
1332   else
1333     {
1334       info->gc[GC_NORMAL] = get_gc (frame, background, 0, &info->rgb_fore);
1335       info->gc[GC_INVERSE] = get_gc (frame, foreground, 1, &info->rgb_back);
1336     }
1337 #ifdef HAVE_XFT2
1338   if (foreground == Mnil)
1339     foreground = frame->foreground;
1340   if (background == Mnil)
1341     background = frame->background;
1342   if (videomode == Mreverse)
1343     {
1344       MSymbol temp = foreground;
1345       foreground = background;
1346       background = temp;
1347     }
1348   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1349                            FRAME_VISUAL (frame),
1350                            FRAME_CMAP (frame),
1351                            MSYMBOL_NAME (foreground),
1352                            &info->xft_color_fore))
1353     mdebug_hook ();
1354   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1355                            FRAME_VISUAL (frame),
1356                            FRAME_CMAP (frame),
1357                            MSYMBOL_NAME (background),
1358                            &info->xft_color_back))
1359     mdebug_hook ();
1360 #endif  /* HAVE_XFT2 */
1361
1362   hline = rface->hline;
1363   if (hline)
1364     {
1365       if (hline->color)
1366         info->gc[GC_HLINE] = get_gc (frame, hline->color, 1, NULL);
1367       else
1368         info->gc[GC_HLINE] = info->gc[GC_NORMAL];
1369     }
1370
1371   box = rface->box;
1372   if (box)
1373     {
1374       if (box->color_top)
1375         info->gc[GC_BOX_TOP] = get_gc (frame, box->color_top, 1, NULL);
1376       else
1377         info->gc[GC_BOX_TOP] = info->gc[GC_NORMAL];
1378
1379       if (box->color_left && box->color_left != box->color_top)
1380         info->gc[GC_BOX_LEFT] = get_gc (frame, box->color_left, 1, NULL);
1381       else
1382         info->gc[GC_BOX_LEFT] = info->gc[GC_BOX_TOP];
1383
1384       if (box->color_bottom && box->color_bottom != box->color_top)
1385         info->gc[GC_BOX_BOTTOM] = get_gc (frame, box->color_bottom, 1, NULL);
1386       else
1387         info->gc[GC_BOX_BOTTOM] = info->gc[GC_BOX_TOP];
1388
1389       if (box->color_right && box->color_right != box->color_bottom)
1390         info->gc[GC_BOX_RIGHT] = get_gc (frame, box->color_right, 1, NULL);
1391       else
1392         info->gc[GC_BOX_RIGHT] = info->gc[GC_BOX_BOTTOM];
1393     }
1394
1395   rface->info = info;
1396 }
1397
1398
1399 static void
1400 mwin__free_realized_face (MRealizedFace *rface)
1401 {
1402   if (rface == rface->ascii_rface)
1403     free (rface->info);
1404 }
1405
1406
1407 static void
1408 mwin__fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1409                   int reverse,
1410                   int x, int y, int width, int height, MDrawRegion region)
1411 {
1412   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_NORMAL : GC_INVERSE];
1413
1414   if (region)
1415     gc = set_region (frame, gc, region);
1416
1417   XFillRectangle (FRAME_DISPLAY (frame), (Window) win, gc,
1418                   x, y, width, height);
1419 }
1420
1421
1422 static void
1423 mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
1424                         MGlyphString *gstring, MGlyph *from, MGlyph *to,
1425                         int reverse, MDrawRegion region)
1426 {
1427   MRealizedFace *rface = from->rface;
1428   Display *display = FRAME_DISPLAY (rface->frame);
1429   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1430
1431   if (from == to)
1432     return;
1433
1434   if (region)
1435     gc = set_region (rface->frame, gc, region);
1436   for (; from < to; from++)
1437     {
1438       XDrawRectangle (display, (Window) win, gc,
1439                       x, y - gstring->ascent + 1, from->width - 1,
1440                       gstring->ascent + gstring->descent - 2);
1441       x += from->width;
1442     }
1443 }
1444
1445
1446 static void
1447 mwin__draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1448                  MRealizedFace *rface, int reverse,
1449                  int x, int y, int width, MDrawRegion region)
1450 {
1451   enum MFaceHLineType type = rface->hline->type;
1452   GCInfo *info = rface->info;
1453   GC gc = gc = info->gc[GC_HLINE];
1454   int i;
1455
1456   y = (type == MFACE_HLINE_BOTTOM
1457        ? y + gstring->text_descent - rface->hline->width
1458        : type == MFACE_HLINE_UNDER
1459        ? y + 1
1460        : type == MFACE_HLINE_STRIKE_THROUGH
1461        ? y - ((gstring->ascent + gstring->descent) / 2)
1462        : y - gstring->text_ascent);
1463   if (region)
1464     gc = set_region (frame, gc, region);
1465
1466   for (i = 0; i < rface->hline->width; i++)
1467     XDrawLine (FRAME_DISPLAY (frame), (Window) win, gc,
1468                x, y + i, x + width - 1, y + i);
1469 }
1470
1471
1472 static void
1473 mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1474                 MGlyph *g, int x, int y, int width, MDrawRegion region)
1475 {
1476   Display *display = FRAME_DISPLAY (frame);
1477   MRealizedFace *rface = g->rface;
1478   MFaceBoxProp *box = rface->box;
1479   GCInfo *info = rface->info;
1480   GC gc_top, gc_left, gc_right, gc_btm;
1481   int y0, y1;
1482   int i;
1483
1484   y0 = y - (gstring->text_ascent
1485             + rface->box->inner_vmargin + rface->box->width);
1486   y1 = y + (gstring->text_descent
1487             + rface->box->inner_vmargin + rface->box->width - 1);
1488
1489   gc_top = info->gc[GC_BOX_TOP];
1490   if (region)
1491     gc_top = set_region (frame, gc_top, region);
1492   if (info->gc[GC_BOX_TOP] == info->gc[GC_BOX_BOTTOM])
1493     gc_btm = gc_top;
1494   else
1495     gc_btm = info->gc[GC_BOX_BOTTOM];
1496
1497   if (g->type == GLYPH_BOX)
1498     {
1499       int x0, x1;
1500
1501       if (g->left_padding)
1502         x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
1503       else
1504         x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
1505
1506       /* Draw the top side.  */
1507       for (i = 0; i < box->width; i++)
1508         XDrawLine (display, (Window) win, gc_top, x0, y0 + i, x1, y0 + i);
1509
1510       /* Draw the bottom side.  */
1511       if (region && gc_btm != gc_top)
1512         gc_btm = set_region (frame, gc_btm, region);
1513       for (i = 0; i < box->width; i++)
1514         XDrawLine (display, (Window) win, gc_btm, x0, y1 - i, x1, y1 - i);
1515
1516       if (g->left_padding > 0)
1517         {
1518           /* Draw the left side.  */
1519           if (info->gc[GC_BOX_LEFT] == info->gc[GC_BOX_TOP])
1520             gc_left = gc_top;
1521           else
1522             {
1523               gc_left = info->gc[GC_BOX_LEFT];
1524               if (region)
1525                 gc_left = set_region (frame, gc_left, region);
1526             }
1527           for (i = 0; i < rface->box->width; i++)
1528             XDrawLine (display, (Window) win, gc_left,
1529                        x0 + i, y0 + i, x0 + i, y1 - i);
1530         }
1531       else
1532         {
1533           /* Draw the right side.  */
1534           if (info->gc[GC_BOX_RIGHT] == info->gc[GC_BOX_TOP])
1535             gc_right = gc_top;
1536           else
1537             {
1538               gc_right = info->gc[GC_BOX_RIGHT];
1539               if (region)
1540                 gc_right = set_region (frame, gc_right, region);
1541             }
1542           for (i = 0; i < rface->box->width; i++)
1543             XDrawLine (display, (Window) win, gc_right,
1544                        x1 - i, y0 + i, x1 - i, y1 - i);
1545         }
1546     }
1547   else
1548     {
1549       /* Draw the top side.  */
1550       for (i = 0; i < box->width; i++)
1551         XDrawLine (display, (Window) win, gc_top,
1552                    x, y0 + i, x + width - 1, y0 + i);
1553
1554       /* Draw the bottom side.  */
1555       if (region && gc_btm != gc_top)
1556         gc_btm = set_region (frame, gc_btm, region);
1557       for (i = 0; i < box->width; i++)
1558         XDrawLine (display, (Window) win, gc_btm,
1559                    x, y1 - i, x + width - 1, y1 - i);
1560     }
1561 }
1562
1563
1564 #if 0
1565 static void
1566 mwin__draw_bitmap (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1567                    int reverse, int x, int y,
1568                    int width, int height, int row_bytes, unsigned char *bmp,
1569                    MDrawRegion region)
1570 {
1571   Display *display = FRAME_DISPLAY (frame);
1572   int i, j;
1573   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1574
1575   if (region)
1576     gc = set_region (frame, gc, region);
1577
1578   for (i = 0; i < height; i++, bmp += row_bytes)
1579     for (j = 0; j < width; j++)
1580       if (bmp[j / 8] & (1 << (7 - (j % 8))))
1581         XDrawPoint (display, (Window) win, gc, x + j, y + i);
1582 }
1583 #endif
1584
1585 static void
1586 mwin__draw_points (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1587                    int intensity, MDrawPoint *points, int num,
1588                    MDrawRegion region)
1589 {
1590   GCInfo *info = rface->info;
1591   GC gc;
1592
1593   if (! (gc = info->gc[intensity]))
1594     gc = info->gc[intensity] = get_gc_for_anti_alias (FRAME_DEVICE (frame),
1595                                                       info, intensity);
1596   if (region)
1597     gc = set_region (frame, gc, region);
1598
1599   XDrawPoints (FRAME_DISPLAY (frame), (Window) win, gc,
1600                (XPoint *) points, num, CoordModeOrigin);
1601 }
1602
1603
1604 static MDrawRegion
1605 mwin__region_from_rect (MDrawMetric *rect)
1606 {
1607   MDrawRegion region1 = XCreateRegion ();
1608   MDrawRegion region2 = XCreateRegion ();
1609   XRectangle xrect;
1610
1611   xrect.x = rect->x;
1612   xrect.y = rect->y;
1613   xrect.width = rect->width;
1614   xrect.height = rect->height;
1615   XUnionRectWithRegion (&xrect, region1, region2);
1616   XDestroyRegion (region1);
1617   return region2;
1618 }
1619
1620 static void
1621 mwin__union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
1622 {
1623   MDrawRegion region1 = XCreateRegion ();
1624   XRectangle xrect;
1625
1626   xrect.x = rect->x;
1627   xrect.y = rect->y;
1628   xrect.width = rect->width;
1629   xrect.height = rect->height;
1630
1631   XUnionRegion (region, region, region1);
1632   XUnionRectWithRegion (&xrect, region1, region);
1633   XDestroyRegion (region1);
1634 }
1635
1636 static void
1637 mwin__intersect_region (MDrawRegion region1, MDrawRegion region2)
1638 {
1639   MDrawRegion region = XCreateRegion ();
1640
1641   XUnionRegion (region1, region1, region);
1642   XIntersectRegion (region, region2, region1);
1643   XDestroyRegion (region);
1644 }
1645
1646 static void
1647 mwin__region_add_rect (MDrawRegion region, MDrawMetric *rect)
1648 {
1649   MDrawRegion region1 = XCreateRegion ();
1650   XRectangle xrect;
1651
1652   xrect.x = rect->x;
1653   xrect.y = rect->y;
1654   xrect.width = rect->width;
1655   xrect.height = rect->height;
1656   XUnionRectWithRegion (&xrect, region1, region);
1657   XDestroyRegion (region1);
1658 }
1659
1660 static void
1661 mwin__region_to_rect (MDrawRegion region, MDrawMetric *rect)
1662 {
1663   XRectangle xrect;
1664
1665   XClipBox (region, &xrect);
1666   rect->x = xrect.x;
1667   rect->y = xrect.y;
1668   rect->width = xrect.width;
1669   rect->height = xrect.height;
1670 }
1671
1672 static void
1673 mwin__free_region (MDrawRegion region)
1674 {
1675   XDestroyRegion (region);
1676 }
1677
1678 static void
1679 mwin__dump_region (MDrawRegion region)
1680 {
1681   XRectangle rect;
1682   XClipBox (region, &rect);
1683   fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
1684 }
1685
1686
1687 static MDrawWindow
1688 mwin__create_window (MFrame *frame, MDrawWindow parent)
1689 {
1690   Display *display = FRAME_DISPLAY (frame);
1691   Window win;
1692   XWMHints wm_hints = { InputHint, False };
1693   XClassHint class_hints = { "M17N-IM", "m17n-im" };
1694   XSetWindowAttributes set_attrs;
1695   unsigned long mask;
1696   XGCValues values;
1697   GCInfo *info = frame->rface->info;
1698
1699   if (! parent)
1700     parent = (MDrawWindow) RootWindow (display, FRAME_SCREEN (frame));
1701   mask = GCForeground;
1702   XGetGCValues (display, info->gc[GC_INVERSE], mask, &values);
1703   set_attrs.background_pixel = values.foreground;
1704   set_attrs.backing_store = Always;
1705   set_attrs.override_redirect = True;
1706   set_attrs.save_under = True;
1707   mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWSaveUnder;
1708   win = XCreateWindow (display, (Window) parent, 0, 0, 1, 1, 0,
1709                        CopyFromParent, InputOutput, CopyFromParent,
1710                        mask, &set_attrs);
1711   XSetWMProperties (display, (Window) win, NULL, NULL, NULL, 0,
1712                     NULL, &wm_hints, &class_hints);
1713   XSelectInput (display, (Window) win, StructureNotifyMask | ExposureMask);
1714   return (MDrawWindow) win;
1715 }
1716
1717 static void
1718 mwin__destroy_window (MFrame *frame, MDrawWindow win)
1719 {
1720 #ifdef HAVE_XFT2
1721   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
1722
1723   if (XftDrawDrawable (xft_draw) == (Drawable) win)
1724     XftDrawChange (xft_draw, FRAME_DEVICE (frame)->drawable);
1725 #endif  /* HAVE_XFT2 */
1726   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
1727 }
1728
1729 #if 0
1730 static MDrawWindow
1731 mwin__event_window (void *event)
1732 {
1733   return ((MDrawWindow) ((XEvent *) event)->xany.window);
1734 }
1735
1736 static void
1737 mwin__print_event (void *arg, char *win_name)
1738 {
1739   char *event_name;
1740   XEvent *event = (XEvent *) arg;
1741
1742   switch (event->xany.type)
1743     {
1744     case 2: event_name = "KeyPress"; break;
1745     case 3: event_name = "KeyRelease"; break;
1746     case 4: event_name = "ButtonPress"; break;
1747     case 5: event_name = "ButtonRelease"; break;
1748     case 6: event_name = "MotionNotify"; break;
1749     case 7: event_name = "EnterNotify"; break;
1750     case 8: event_name = "LeaveNotify"; break;
1751     case 9: event_name = "FocusIn"; break;
1752     case 10: event_name = "FocusOut"; break;
1753     case 11: event_name = "KeymapNotify"; break;
1754     case 12: event_name = "Expose"; break;
1755     case 13: event_name = "GraphicsExpose"; break;
1756     case 14: event_name = "NoExpose"; break;
1757     case 15: event_name = "VisibilityNotify"; break;
1758     case 16: event_name = "CreateNotify"; break;
1759     case 17: event_name = "DestroyNotify"; break;
1760     case 18: event_name = "UnmapNotify"; break;
1761     case 19: event_name = "MapNotify"; break;
1762     case 20: event_name = "MapRequest"; break;
1763     case 21: event_name = "ReparentNotify"; break;
1764     case 22: event_name = "ConfigureNotify"; break;
1765     case 23: event_name = "ConfigureRequest"; break;
1766     case 24: event_name = "GravityNotify"; break;
1767     case 25: event_name = "ResizeRequest"; break;
1768     case 26: event_name = "CirculateNotify"; break;
1769     case 27: event_name = "CirculateRequest"; break;
1770     case 28: event_name = "PropertyNotify"; break;
1771     case 29: event_name = "SelectionClear"; break;
1772     case 30: event_name = "SelectionRequest"; break;
1773     case 31: event_name = "SelectionNotify"; break;
1774     case 32: event_name = "ColormapNotify"; break;
1775     case 33: event_name = "ClientMessage"; break;
1776     case 34: event_name = "MappingNotify"; break;
1777     default: event_name = "unknown";
1778     }
1779
1780   fprintf (stderr, "%s: %s\n", win_name, event_name);
1781 }
1782 #endif
1783
1784 static void
1785 mwin__map_window (MFrame *frame, MDrawWindow win)
1786 {
1787   XMapRaised (FRAME_DISPLAY (frame), (Window) win);
1788 }
1789
1790 static void
1791 mwin__unmap_window (MFrame *frame, MDrawWindow win)
1792 {
1793   XUnmapWindow (FRAME_DISPLAY (frame), (Window) win);
1794 }
1795
1796 static void
1797 mwin__window_geometry (MFrame *frame, MDrawWindow win, MDrawWindow parent_win,
1798                        MDrawMetric *geometry)
1799 {
1800   Display *display = FRAME_DISPLAY (frame);
1801   XWindowAttributes attr;
1802   Window parent = (Window) parent_win, root;
1803
1804   XGetWindowAttributes (display, (Window) win, &attr);
1805   geometry->x = attr.x + attr.border_width;
1806   geometry->y = attr.y + attr.border_width;
1807   geometry->width = attr.width;
1808   geometry->height = attr.height; 
1809
1810   if (! parent)
1811     parent = RootWindow (display, FRAME_SCREEN (frame));
1812   while (1)
1813     {
1814       Window this_parent, *children;
1815       unsigned n;
1816
1817       XQueryTree (display, (Window) win, &root, &this_parent, &children, &n);
1818       if (children)
1819         XFree (children);
1820       if (this_parent == parent || this_parent == root)
1821         break;
1822       win = (MDrawWindow) this_parent;
1823       XGetWindowAttributes (display, (Window) win, &attr);
1824       geometry->x += attr.x + attr.border_width;
1825       geometry->y += attr.y + attr.border_width;
1826     }
1827 }
1828
1829 static void
1830 mwin__adjust_window (MFrame *frame, MDrawWindow win,
1831                      MDrawMetric *current, MDrawMetric *new)
1832 {
1833   Display *display = FRAME_DISPLAY (frame);
1834   unsigned int mask = 0;
1835   XWindowChanges values;
1836
1837   if (current->width != new->width)
1838     {
1839       mask |= CWWidth;
1840       if (new->width <= 0)
1841         new->width = 1;
1842       values.width = current->width = new->width;
1843     }
1844   if (current->height != new->height)
1845     {
1846       mask |= CWHeight;
1847       if (new->height <= 0)
1848         new->height = 1;
1849       values.height = current->height = new->height;
1850     }
1851   if (current->x != new->x)
1852     {
1853       mask |= CWX;
1854       values.x = current->x = new->x;
1855     }
1856   if (current->y != new->y)
1857     {
1858       mask |= CWY;
1859       current->y = new->y;
1860       values.y = current->y = new->y;
1861     }
1862   if (mask)
1863     XConfigureWindow (display, (Window) win, mask, &values);
1864   XClearWindow (display, (Window) win);
1865 }
1866
1867 static MSymbol
1868 mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
1869 {
1870   XEvent *event = (XEvent *) arg;
1871   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
1872   int len;
1873   char buf[512];
1874   KeySym keysym;
1875   MSymbol key = Mnil;
1876
1877   *modifiers = 0;
1878   if (event->xany.type != KeyPress
1879       /* && event->xany.type != KeyRelease */
1880       )
1881     return Mnil;
1882   len = XLookupString ((XKeyEvent *) event, (char *) buf, 512, &keysym, NULL);
1883   if (len > 1)
1884     return Mnil;
1885   if (len == 1)
1886     {
1887       int c = keysym;
1888
1889       if (c < XK_space || c > XK_asciitilde)
1890         c = buf[0];
1891       if ((c == ' ' || c == 127) && ((XKeyEvent *) event)->state & ShiftMask)
1892         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1893       if (((XKeyEvent *) event)->state & ControlMask)
1894         {
1895           if (c >= 'a' && c <= 'z')
1896             c += 'A' - 'a';
1897           if (c >= ' ' && c < 127)
1898             *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1899         }
1900       key = minput__char_to_key (c);
1901     }
1902   else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
1903     return Mnil;
1904   if (key == Mnil)
1905     {
1906       char *str = XKeysymToString (keysym);
1907
1908       if (! str)
1909         return Mnil;
1910       key = msymbol (str);
1911       if (((XKeyEvent *) event)->state & ShiftMask)
1912         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1913       if (((XKeyEvent *) event)->state & ControlMask)
1914         *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1915     }
1916   if (((XKeyEvent *) event)->state & disp_info->meta_mask)
1917     *modifiers |= MINPUT_KEY_META_MODIFIER;
1918   if (((XKeyEvent *) event)->state & disp_info->alt_mask)
1919     *modifiers |= MINPUT_KEY_ALT_MODIFIER;
1920   if (((XKeyEvent *) event)->state & disp_info->super_mask)
1921     *modifiers |= MINPUT_KEY_SUPER_MODIFIER;
1922   if (((XKeyEvent *) event)->state & disp_info->hyper_mask)
1923     *modifiers |= MINPUT_KEY_HYPER_MODIFIER;
1924
1925   return key;
1926 }
1927
1928
1929 void
1930 mwin__dump_gc (MFrame *frame, MRealizedFace *rface)
1931 {
1932   unsigned long valuemask = GCForeground | GCBackground | GCClipMask;
1933   XGCValues values;
1934   Display *display = FRAME_DISPLAY (frame);
1935   GCInfo *info = rface->info;
1936   int i;
1937
1938   for (i = 0; i <= GC_INVERSE; i++)
1939     {
1940       XGetGCValues (display, info->gc[i], valuemask, &values);
1941       fprintf (stderr, "GC%d: fore/#%lX back/#%lX", i,
1942                values.foreground, values.background);
1943       fprintf (stderr, "\n");
1944     }
1945 }
1946
1947 static MDeviceDriver x_driver =
1948   {
1949     mwin__close_device,
1950     mwin__device_get_prop,
1951     mwin__realize_face,
1952     mwin__free_realized_face,
1953     mwin__fill_space,
1954     mwin__draw_empty_boxes,
1955     mwin__draw_hline,
1956     mwin__draw_box,
1957     mwin__draw_points,
1958     mwin__region_from_rect,
1959     mwin__union_rect_with_region,
1960     mwin__intersect_region,
1961     mwin__region_add_rect,
1962     mwin__region_to_rect,
1963     mwin__free_region,
1964     mwin__dump_region,
1965     mwin__create_window,
1966     mwin__destroy_window,
1967     mwin__map_window,
1968     mwin__unmap_window,
1969     mwin__window_geometry,
1970     mwin__adjust_window,
1971     mwin__parse_event
1972   };
1973
1974 /* Functions to be stored in MDeviceLibraryInterface by dlsym ().  */
1975
1976 int
1977 device_init ()
1978 {
1979   M_iso8859_1 = msymbol ("iso8859-1");
1980   M_iso10646_1 = msymbol ("iso10646-1");
1981
1982   display_info_list = mplist ();
1983   device_list = mplist ();
1984
1985 #ifdef HAVE_XFT2
1986   xft_driver.select = mfont__ft_driver.select;
1987   xft_driver.list = mfont__ft_driver.list;
1988 #endif
1989
1990   Mxim = msymbol ("xim");
1991   msymbol_put (Mxim, Minput_driver, &minput_xim_driver);
1992
1993   return 0;
1994 }
1995
1996 int
1997 device_fini ()
1998 {
1999   M17N_OBJECT_UNREF (display_info_list);
2000   M17N_OBJECT_UNREF (device_list);
2001   return 0;
2002 }
2003
2004
2005 #ifdef X_SET_ERROR_HANDLER
2006 static int
2007 x_error_handler (Display *display, XErrorEvent *error)
2008 {
2009   mdebug_hook ();
2010   return 0;
2011 }
2012
2013 static int
2014 x_io_error_handler (Display *display)
2015 {
2016   mdebug_hook ();
2017   return 0;
2018 }
2019 #endif
2020
2021 /** Return an MWDevice object corresponding to a display specified in
2022     PLIST.
2023
2024     It searches device_list for a device matching the display.  If
2025     found, return the found object.  Otherwise, return a newly created
2026     object.  */
2027
2028 int
2029 device_open (MFrame *frame, MPlist *param)
2030 {
2031   Display *display = NULL;
2032   Screen *screen = NULL;
2033   int screen_num;
2034   Drawable drawable = 0;
2035   Widget widget = NULL;
2036   Colormap cmap = 0;
2037   int auto_display = 0;
2038   MDisplayInfo *disp_info = NULL;
2039   MWDevice *device = NULL;
2040   MSymbol key;
2041   XWindowAttributes attr;
2042   unsigned depth = 0;
2043   MPlist *plist;
2044   AppData app_data;
2045   MFont *font = NULL;
2046   MFace *face;
2047   int use_xfont = 0, use_freetype = 0, use_xft = 0;
2048
2049   for (plist = param; (key = mplist_key (plist)) != Mnil;
2050        plist = mplist_next (plist))
2051     {
2052       if (key == Mdisplay)
2053         display = (Display *) mplist_value (plist);
2054       else if (key == Mscreen)
2055         screen = mplist_value (plist);
2056       else if (key == Mdrawable)
2057         drawable = (Drawable) mplist_value (plist);
2058       else if (key == Mdepth)
2059         depth = (unsigned) mplist_value (plist);
2060       else if (key == Mwidget)
2061         widget = (Widget) mplist_value (plist);
2062       else if (key == Mcolormap)
2063         cmap = (Colormap) mplist_value (plist);
2064       else if (key == Mfont)
2065         {
2066           MSymbol val = MPLIST_SYMBOL (plist);
2067
2068           if (val == Mx)
2069             use_xfont = 1;
2070 #ifdef HAVE_FREETYPE
2071           else if (val == Mfreetype)
2072             use_freetype = 1;
2073 #ifdef HAVE_XFT2
2074           else if (val == Mxft)
2075             use_xft = 1;
2076 #endif
2077 #endif
2078         }
2079     }
2080
2081   /* If none of them is specified, use all of them.  */
2082   if (! use_xfont && ! use_freetype && ! use_xft)
2083     use_xfont = use_freetype = use_xft = 1;
2084
2085   if (widget)
2086     {
2087       display = XtDisplay (widget);
2088       screen_num = XScreenNumberOfScreen (XtScreen (widget));
2089       depth = DefaultDepth (display, screen_num);
2090     }
2091   else if (drawable)
2092     {
2093       Window root_window;
2094       int x, y;
2095       unsigned width, height, border_width;
2096
2097       if (! display)
2098         MERROR (MERROR_WIN, -1);
2099       XGetGeometry (display, drawable, &root_window,
2100                     &x, &y, &width, &height, &border_width, &depth);
2101       XGetWindowAttributes (display, root_window, &attr);
2102       screen_num = XScreenNumberOfScreen (attr.screen);
2103     }
2104   else
2105     {
2106       if (screen)
2107         display = DisplayOfScreen (screen);
2108       else
2109         {
2110           if (! display)
2111             {
2112               display = XOpenDisplay (NULL);
2113               if (! display)
2114                 MERROR (MERROR_WIN, -1);
2115               auto_display = 1;
2116             }
2117           screen = DefaultScreenOfDisplay (display);
2118         }
2119       screen_num = XScreenNumberOfScreen (screen);
2120       if (! depth)
2121         depth = DefaultDepth (display, screen_num);
2122     }
2123
2124   if (! cmap)
2125     cmap = DefaultColormap (display, screen_num);
2126
2127   for (plist = display_info_list; mplist_key (plist) != Mnil;
2128        plist = mplist_next (plist))
2129     {
2130       disp_info = (MDisplayInfo *) mplist_value (plist);
2131       if (disp_info->display == display)
2132         break;
2133     }
2134
2135   if (mplist_key (plist) != Mnil)
2136     M17N_OBJECT_REF (disp_info);
2137   else
2138     {
2139       M17N_OBJECT (disp_info, free_display_info, MERROR_WIN);
2140       disp_info->display = display;
2141       disp_info->auto_display = auto_display;
2142       disp_info->font_list = mplist ();
2143       find_modifier_bits (disp_info);
2144       disp_info->MULE_BASELINE_OFFSET
2145         = XInternAtom (display, "_MULE_BASELINE_OFFSET", False);
2146       disp_info->AVERAGE_WIDTH
2147         = XInternAtom (display, "AVERAGE_WIDTH", False);
2148       mplist_add (display_info_list, Mt, disp_info);
2149     }  
2150
2151   for (plist = device_list; mplist_key (plist) != Mnil;
2152        plist = mplist_next (plist))
2153     {
2154       device = (MWDevice *) mplist_value (plist);
2155       if (device->display_info == disp_info
2156           && device->depth == depth
2157           && device->cmap == cmap
2158           && device->screen_num == screen_num)
2159         break;
2160     }
2161
2162   if (mplist_key (plist) != Mnil)
2163     M17N_OBJECT_REF (device);
2164   else
2165     {
2166       unsigned long valuemask = GCForeground;
2167       XGCValues values;
2168       double pixels, mm;
2169
2170       M17N_OBJECT (device, free_device, MERROR_WIN);
2171       device->display_info = disp_info;
2172       device->screen_num = screen_num;
2173       /* A drawable on which to create GCs.  */
2174       device->drawable = XCreatePixmap (display,
2175                                         RootWindow (display, screen_num),
2176                                         1, 1, depth);
2177       device->depth = depth;
2178       device->cmap = cmap;
2179       pixels = DisplayHeight (display, screen_num);
2180       mm = DisplayHeightMM (display, screen_num);
2181       device->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
2182       device->realized_face_list = mplist ();
2183       device->realized_font_list = mplist ();
2184       mplist_add (device->realized_font_list, Mt, NULL);
2185       device->realized_fontset_list = mplist ();
2186       device->gc_list = mplist ();
2187       values.foreground = BlackPixel (display, screen_num);
2188       device->scratch_gc = XCreateGC (display, device->drawable,
2189                                       valuemask, &values);
2190 #ifdef HAVE_XFT2
2191       device->xft_draw = XftDrawCreate (display, device->drawable,
2192                                         DefaultVisual (display, screen_num),
2193                                         cmap);
2194 #endif
2195     }
2196
2197   frame->device = device;
2198   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
2199   frame->dpi = device->resy;
2200   frame->driver = &x_driver;
2201   frame->font_driver_list = mplist ();
2202 #ifdef HAVE_XFT2
2203   if (use_xft)
2204     {
2205       mplist_add (frame->font_driver_list, Mfreetype, &xft_driver);
2206       use_freetype = 0;
2207     }
2208 #endif  /* HAVE_XFT2 */
2209 #ifdef HAVE_FREETYPE
2210   if (use_freetype)
2211     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
2212 #endif  /* HAVE_FREETYPE */
2213   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
2214     mplist_push (frame->font_driver_list, Mx, &xfont_driver);
2215
2216   frame->realized_font_list = device->realized_font_list;
2217   frame->realized_face_list = device->realized_face_list;
2218   frame->realized_fontset_list = device->realized_fontset_list;
2219
2220   if (widget)
2221     {
2222       XtResource resources[] = {
2223         { XtNfont, XtCFont, XtRString, sizeof (String),
2224           XtOffset (AppDataPtr, font), XtRString, DEFAULT_FONT },
2225         { XtNforeground, XtCForeground, XtRString, sizeof (String),
2226           XtOffset (AppDataPtr, foreground), XtRString, "black" },
2227         { XtNbackground, XtCBackground, XtRString, sizeof (String),
2228           XtOffset (AppDataPtr, background), XtRString, "white" },
2229         { XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
2230           XtOffset (AppDataPtr, reverse_video), XtRImmediate, (caddr_t) FALSE }
2231       };
2232
2233       XtGetApplicationResources (widget, &app_data,
2234                                  resources, XtNumber (resources), NULL, 0);
2235       frame->foreground = msymbol (app_data.foreground);
2236       frame->background = msymbol (app_data.background);
2237       frame->videomode = app_data.reverse_video == True ? Mreverse : Mnormal;
2238     }
2239   else
2240     {
2241       app_data.font = DEFAULT_FONT;
2242       frame->foreground = msymbol ("black");
2243       frame->background = msymbol ("white");
2244       frame->videomode = Mnormal;
2245     }
2246
2247   if (strcmp (app_data.font, DEFAULT_FONT) != 0)
2248     {
2249       XFontStruct *xfont = XLoadQueryFont (display, app_data.font);
2250       unsigned long value;
2251       char *name;
2252
2253       if (xfont)
2254         {
2255           font = mfont_parse_name (app_data.font, Mx);
2256           if (! font
2257               && XGetFontProperty (xfont, XA_FONT, &value)
2258               && (name = ((char *) XGetAtomName (display, (Atom) value))))
2259             font = mfont_parse_name (name, Mx);
2260           XFreeFont (display, xfont);
2261         }
2262     }
2263   if (! font)
2264       font = mfont_parse_name (DEFAULT_FONT, Mx);
2265   else if (! font->size)
2266     font->size = 130;
2267   face = mface_from_font (font);
2268   free (font);
2269   face->property[MFACE_FONTSET] = mfontset (NULL);
2270   face->property[MFACE_FOREGROUND] = frame->foreground;
2271   face->property[MFACE_BACKGROUND] = frame->background;
2272   mface_put_prop (face, Mhline, mface_get_prop (mface__default, Mhline));
2273   mface_put_prop (face, Mbox, mface_get_prop (mface__default, Mbox));
2274   face->property[MFACE_VIDEOMODE] = frame->videomode;
2275   mface_put_prop (face, Mhook_func, 
2276                   mface_get_prop (mface__default, Mhook_func));
2277   face->property[MFACE_RATIO] = (void *) 100;
2278   mplist_push (param, Mface, face);
2279   M17N_OBJECT_UNREF (face);
2280
2281 #ifdef X_SET_ERROR_HANDLER
2282   XSetErrorHandler (x_error_handler);
2283   XSetIOErrorHandler (x_io_error_handler);
2284 #endif
2285   return 0;
2286 }
2287
2288 \f
2289
2290 /* XIM (X Input Method) handler */
2291
2292 typedef struct MInputXIMMethodInfo
2293 {
2294   Display *display;
2295   XIM xim;
2296   MSymbol language;
2297   MSymbol coding;
2298 } MInputXIMMethodInfo;
2299
2300 typedef struct MInputXIMContextInfo
2301 {
2302   XIC xic;
2303   Window win;
2304   MConverter *converter;
2305 } MInputXIMContextInfo;
2306
2307 static int
2308 xim_open_im (MInputMethod *im)
2309 {
2310   MInputXIMArgIM *arg = (MInputXIMArgIM *) im->arg;
2311   MLocale *saved, *this;
2312   char *save_modifier_list;
2313   XIM xim;
2314   MInputXIMMethodInfo *im_info;
2315
2316   saved = mlocale_set (LC_CTYPE, NULL);
2317   this = mlocale_set (LC_CTYPE, arg->locale ? arg->locale : "");
2318   if (! this)
2319     /* The specified locale is not supported.  */
2320     MERROR (MERROR_LOCALE, -1);
2321   if (mlocale_get_prop (this, Mcoding) == Mnil)
2322     {
2323       /* Unable to decode the output of XIM.  */
2324       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2325       MERROR (MERROR_LOCALE, -1);
2326     }
2327
2328   if (arg->modifier_list)
2329     save_modifier_list = XSetLocaleModifiers (arg->modifier_list);
2330   else
2331     save_modifier_list = XSetLocaleModifiers ("");
2332   if (! save_modifier_list)
2333     {
2334       /* The specified locale is not supported by X.  */
2335       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2336       MERROR (MERROR_LOCALE, -1);
2337     }
2338
2339   xim = XOpenIM (arg->display, arg->db, arg->res_name, arg->res_class);
2340   if (! xim)
2341     {
2342       /* No input method is available in the current locale.  */
2343       XSetLocaleModifiers (save_modifier_list);
2344       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2345       MERROR (MERROR_WIN, -1);
2346     }
2347
2348   MSTRUCT_MALLOC (im_info, MERROR_WIN);
2349   im_info->display = arg->display;
2350   im_info->xim = xim;
2351   im_info->language = mlocale_get_prop (this, Mlanguage);
2352   im_info->coding = mlocale_get_prop (this, Mcoding);
2353   im->info = im_info;
2354
2355   XSetLocaleModifiers (save_modifier_list);
2356   mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2357
2358   return 0;
2359 }
2360
2361 static void
2362 xim_close_im (MInputMethod *im)
2363 {
2364   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) im->info;
2365
2366   XCloseIM (im_info->xim);
2367   free (im_info);
2368 }
2369
2370 static int
2371 xim_create_ic (MInputContext *ic)
2372 {
2373   MInputXIMArgIC *arg = (MInputXIMArgIC *) ic->arg;
2374   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2375   MInputXIMContextInfo *ic_info;
2376   XIC xic;
2377
2378   if (! arg->input_style)
2379     {
2380       /* By default, use Root style.  */
2381       arg->input_style = XIMPreeditNothing | XIMStatusNothing;
2382       arg->preedit_attrs = NULL;
2383       arg->status_attrs = NULL;
2384     }
2385
2386   if (! arg->preedit_attrs && ! arg->status_attrs)
2387     xic = XCreateIC (im_info->xim,
2388                      XNInputStyle, arg->input_style,
2389                      XNClientWindow, arg->client_win,
2390                      XNFocusWindow, arg->focus_win,
2391                      NULL);
2392   else if (arg->preedit_attrs && ! arg->status_attrs)
2393     xic = XCreateIC (im_info->xim,
2394                      XNInputStyle, arg->input_style,
2395                      XNClientWindow, arg->client_win,
2396                      XNFocusWindow, arg->focus_win,
2397                      XNPreeditAttributes, arg->preedit_attrs,
2398                      NULL);
2399   else if (! arg->preedit_attrs && arg->status_attrs)
2400     xic = XCreateIC (im_info->xim,
2401                      XNInputStyle, arg->input_style,
2402                      XNClientWindow, arg->client_win,
2403                      XNFocusWindow, arg->focus_win,
2404                      XNStatusAttributes, arg->status_attrs,
2405                      NULL);
2406   else
2407     xic = XCreateIC (im_info->xim,
2408                      XNInputStyle, arg->input_style,
2409                      XNClientWindow, arg->client_win,
2410                      XNFocusWindow, arg->focus_win,
2411                      XNPreeditAttributes, arg->preedit_attrs,
2412                      XNStatusAttributes, arg->status_attrs,
2413                      NULL);
2414   if (! xic)
2415     MERROR (MERROR_WIN, -1);
2416
2417   MSTRUCT_MALLOC (ic_info, MERROR_WIN);
2418   ic_info->xic = xic;
2419   ic_info->win = arg->focus_win;
2420   ic_info->converter = mconv_buffer_converter (im_info->coding, NULL, 0);
2421   ic->info = ic_info;
2422   return 0;
2423 }
2424
2425 static void
2426 xim_destroy_ic (MInputContext *ic)
2427 {
2428   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2429
2430   XDestroyIC (ic_info->xic);
2431   mconv_free_converter (ic_info->converter);
2432   free (ic_info);
2433   ic->info = NULL;
2434 }
2435
2436 static int
2437 xim_filter (MInputContext *ic, MSymbol key, void *event)
2438 {
2439   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2440
2441   return (XFilterEvent ((XEvent *) event, ic_info->win) == True);
2442 }
2443
2444
2445 static int
2446 xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2447 {
2448   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2449   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2450   XKeyPressedEvent *ev = (XKeyPressedEvent *) arg;
2451   KeySym keysym;
2452   Status status;
2453   char *buf;
2454   int len;
2455
2456   buf = (char *) alloca (512);
2457   len = XmbLookupString (ic_info->xic, ev, buf, 512, &keysym, &status);
2458   if (status == XBufferOverflow)
2459     {
2460       buf = (char *) alloca (len);
2461       len = XmbLookupString (ic_info->xic, ev, buf, len, &keysym, &status);
2462     }
2463
2464   mtext_reset (ic->produced);
2465   if (len == 0)
2466     return 1;
2467
2468   mconv_reset_converter (ic_info->converter);
2469   mconv_rebind_buffer (ic_info->converter, (unsigned char *) buf, len);
2470   mconv_decode (ic_info->converter, ic->produced);
2471   mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2472                   Mlanguage, (void *) im_info->language);
2473   mtext_cpy (mt, ic->produced);
2474   mtext_reset (ic->produced);  
2475   return 0;
2476 }
2477
2478 \f
2479 /*=*/
2480
2481 /*** @} */
2482 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2483 \f
2484 /* External API */
2485
2486 /*** @addtogroup m17nInputMethodWin */
2487
2488 /*** @{ */
2489
2490 /***en
2491     @brief Input method driver for XIM.
2492
2493     The driver #minput_xim_driver is for the foreign input method of
2494     name #Mxim.  It uses XIM (X Input Methods) as a background input
2495     engine.
2496
2497     As the symbol #Mxim has property #Minput_driver whose value is
2498     a pointer to this driver, the input method of language #Mnil
2499     and name #Mxim uses this driver.
2500
2501     Therefore, for such input methods, the driver dependent arguments
2502     to the functions whose name begin with minput_ must be as follows.
2503
2504     The argument $ARG of the function minput_open_im () must be a
2505     pointer to the structure #MInputXIMArgIM.  See the documentation
2506     of #MInputXIMArgIM for more details.
2507
2508     The argument $ARG of the function minput_create_ic () must be a
2509     pointer to the structure #MInputXIMArgIC. See the documentation
2510     of #MInputXIMArgIC for more details.
2511
2512     The argument $ARG of the function minput_filter () must be a
2513     pointer to the structure @c XEvent.  The argument $KEY is ignored.
2514
2515     The argument $ARG of the function minput_lookup () must be the
2516     same one as that of the function minput_filter ().  The argument
2517     $KEY is ignored.  */
2518
2519 /***ja
2520     @brief XIMÍÑÆþÎϥɥ饤¥Ð.
2521
2522     ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã¥ÉÍѤǤ¢¤ê¡¢
2523     XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
2524
2525     ¥·¥ó¥Ü¥ë #Mxim ¤Ï¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥×¥í¥Ñ¥Æ¥£
2526     #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim 
2527     ¤Ç¤¢¤ëÆþÎϥ᥽¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
2528
2529     ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ 
2530     ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2531
2532     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM 
2533     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò»²¾È¡£
2534
2535     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC 
2536     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ¤ò»²¾È¡£
2537
2538     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent 
2539     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
2540
2541     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô function minput_filter () 
2542     ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì¤ë¡£  */
2543
2544 MInputDriver minput_xim_driver =
2545   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
2546     xim_filter, xim_lookup, NULL };
2547
2548 /*** @} */ 
2549
2550 #else  /* not HAVE_X11 */
2551
2552 int device_open () { return -1; }
2553
2554 #endif  /* not HAVE_X11 */
2555
2556 /*
2557   Local Variables:
2558   coding: euc-japan
2559   End:
2560 */