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