(xfont_open): Check resize ratio.
[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 static int xfont_check_capability (MRealizedFont *rfont, MSymbol capability);
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, xfont_check_capability };
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;
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 (font->size)
636     /* non-scalable font */
637     size = font->size;
638   else if (spec->size)
639     {
640       int ratio = mfont_resize_ratio (font);
641
642       size = ratio == 100 ? spec->size : spec->size * ratio / 100;
643     }
644   else
645     size = 120;
646
647   if (rfont)
648     {
649       for (; rfont; rfont = rfont->next)
650         if (rfont->font == font && rfont->spec.size == size)
651           return rfont;
652     }
653
654   this = *font;
655   this.size = size;
656   /* This never fail to generate a valid fontname.  */
657   name = mfont_unparse_name (&this, Mx);
658   xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
659   if (! xfont)
660     {
661       MDEBUG_PRINT1 (" [XFONT] x %s\n", name);
662       free (name);
663       font->type = MFONT_TYPE_FAILURE;
664       return NULL;
665     }
666   MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
667   free (name);
668   M17N_OBJECT (x_rfont, close_xfont, MERROR_FONT_X);
669   x_rfont->display = display;
670   x_rfont->xfont = xfont;
671   MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
672   rfont->spec = this;
673   rfont->spec.type = MFONT_TYPE_REALIZED;
674   rfont->spec.source = MFONT_SOURCE_X;
675   rfont->frame = frame;
676   rfont->font = font;
677   rfont->driver = &xfont_driver;
678   rfont->info = x_rfont;
679   {
680     MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
681     unsigned long value;
682
683     rfont->baseline_offset
684       = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
685          ? (int) value : 0);
686     rfont->average_width
687       = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
688          ? (int) value / 10 : 0);
689   }
690   rfont->ascent = xfont->ascent + rfont->baseline_offset;
691   rfont->descent = xfont->descent - rfont->baseline_offset;
692   rfont->max_advance = xfont->max_bounds.width;
693   rfont->fontp = xfont;
694   rfont->next = MPLIST_VAL (frame->realized_font_list);
695   MPLIST_VAL (frame->realized_font_list) = rfont;
696   return rfont;
697 }
698
699
700 /* The X font driver function FIND_METRIC.  */
701
702 static void
703 xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
704                    int from, int to)
705 {
706   XFontStruct *xfont = rfont->fontp;
707   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
708
709   for (; g != gend; g++)
710     {
711       if (g->code == MCHAR_INVALID_CODE)
712         {
713           g->lbearing = xfont->max_bounds.lbearing;
714           g->rbearing = xfont->max_bounds.rbearing;
715           g->width = xfont->max_bounds.width;
716           g->ascent = xfont->ascent;
717           g->descent = xfont->descent;
718         }
719       else
720         {
721           int byte1 = g->code >> 8, byte2 = g->code & 0xFF;
722           XCharStruct *pcm = NULL;
723
724           if (xfont->per_char != NULL)
725             {
726               if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
727                 {
728                   if (byte1 == 0
729                       && byte2 >= xfont->min_char_or_byte2
730                       && byte2 <= xfont->max_char_or_byte2)
731                     pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
732                 }
733               else
734                 {
735                   if (byte1 >= xfont->min_byte1
736                       && byte1 <= xfont->max_byte1
737                       && byte2 >= xfont->min_char_or_byte2
738                       && byte2 <= xfont->max_char_or_byte2)
739                     {
740                       pcm = (xfont->per_char
741                              + ((xfont->max_char_or_byte2
742                                  - xfont->min_char_or_byte2 + 1)
743                                 * (byte1 - xfont->min_byte1))
744                              + (byte2 - xfont->min_char_or_byte2));
745                     }
746                 }
747             }
748
749           if (pcm)
750             {
751               g->lbearing = pcm->lbearing;
752               g->rbearing = pcm->rbearing;
753               g->width = pcm->width;
754               g->ascent = pcm->ascent;
755               g->descent = pcm->descent;
756             }
757           else
758             {
759               /* If the per_char pointer is null, all glyphs between
760                  the first and last character indexes inclusive have
761                  the same information, as given by both min_bounds and
762                  max_bounds.  */
763               g->lbearing = 0;
764               g->rbearing = xfont->max_bounds.width;
765               g->width = xfont->max_bounds.width;
766               g->ascent = xfont->ascent;
767               g->descent = xfont->descent;
768             }
769         }
770       g->ascent += rfont->baseline_offset;
771       g->descent -= rfont->baseline_offset;
772     }
773 }
774
775
776 static int
777 xfont_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
778 {
779   return (xfont_encode_char (frame, font, spec, code) != MCHAR_INVALID_CODE);
780 }
781
782 /* The X font driver function GET_GLYPH_ID.  */
783
784 static unsigned
785 xfont_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
786 {
787   MRealizedFont *rfont;
788   XFontStruct *xfont;
789   unsigned min_byte1, max_byte1, min_byte2, max_byte2;
790   int all_chars_exist;
791
792   if (font->type == MFONT_TYPE_REALIZED)
793     rfont = (MRealizedFont *) font;
794   else if (font->type == MFONT_TYPE_OBJECT)
795     {
796       int size = spec->size;
797
798       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
799            rfont = rfont->next)
800         if (rfont->font == font && rfont->spec.size == size)
801           break;
802       if (! rfont)
803         {
804           rfont = xfont_open (frame, font, spec, NULL);
805           if (! rfont)
806             return MCHAR_INVALID_CODE;
807         }
808     }
809   else
810     MFATAL (MERROR_FONT_X);
811   xfont = rfont->fontp;
812   all_chars_exist = (! xfont->per_char || xfont->all_chars_exist == True);
813   min_byte1 = xfont->min_byte1;
814   max_byte1 = xfont->max_byte1;
815   min_byte2 = xfont->min_char_or_byte2;
816   max_byte2 = xfont->max_char_or_byte2;
817
818   if (min_byte1 == 0 && max_byte1 == 0)
819     {
820       XCharStruct *pcm;
821
822       if (code < min_byte2 || code > max_byte2)
823         return MCHAR_INVALID_CODE;
824       if (all_chars_exist)
825         return code;
826       pcm = xfont->per_char + (code - min_byte2);
827       return ((pcm->width > 0 || pcm->rbearing != pcm->lbearing)
828               ? code : MCHAR_INVALID_CODE);
829     }
830   else
831     {
832       unsigned byte1 = code >> 8, byte2 = code & 0xFF;
833       XCharStruct *pcm;
834
835       if (byte1 < min_byte1 || byte1 > max_byte1
836           || byte2 < min_byte2 || byte2 > max_byte2)
837         return MCHAR_INVALID_CODE;
838
839       if (all_chars_exist)
840         return code;
841       pcm = xfont->per_char + ((byte1 - min_byte1) * (max_byte2 - min_byte2 + 1)
842                            + (byte2 - min_byte2));
843       return ((pcm->width > 0 || pcm->rbearing != pcm->lbearing)
844               ? code : MCHAR_INVALID_CODE);
845     }
846 }
847
848 /* The X font driver function RENDER.  */
849
850 static void
851 xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
852               MGlyph *from, MGlyph *to, int reverse, MDrawRegion region)
853 {
854   MRealizedFace *rface = from->rface;
855   Display *display = FRAME_DISPLAY (rface->frame);
856   XChar2b *code;
857   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
858   MGlyph *g;
859   int i;
860   int baseline_offset;
861
862   if (from == to)
863     return;
864
865   baseline_offset = rface->rfont->baseline_offset;
866   if (region)
867     gc = set_region (rface->frame, gc, region);
868   XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
869   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
870   for (i = 0, g = from; g < to; i++, g++)
871     {
872       code[i].byte1 = g->code >> 8;
873       code[i].byte2 = g->code & 0xFF;
874     }
875
876   g = from;
877   while (g < to)
878     {
879       if (g->type == GLYPH_PAD)
880         x += g++->width;
881       else if (g->type == GLYPH_SPACE)
882         for (; g < to && g->type == GLYPH_SPACE; g++)
883           x += g->width;
884       else if (! g->rface->rfont)
885         {
886           if ((g->c >= 0x200B && g->c <= 0x200F)
887               || (g->c >= 0x202A && g->c <= 0x202E))
888             x += g++->width;
889           else
890             {
891               /* As a font is not found for this character, draw an
892                  empty box.  */
893               int box_width = g->width;
894               int box_height = gstring->ascent + gstring->descent;
895
896               if (box_width > 4)
897                 box_width -= 2;
898               if (box_height > 4)
899                 box_height -= 2;
900               XDrawRectangle (display, (Window) win, gc,
901                               x, y - gstring->ascent, box_width, box_height);
902               x += g++->width;
903             }
904         }
905       else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
906         {
907           XDrawString16 (display, (Window) win, gc,
908                          x + g->xoff, y + g->yoff - baseline_offset,
909                          code + (g - from), 1);
910           x += g->width;
911           g++;
912         }
913       else
914         {
915           int orig_x = x;
916           int code_idx = g - from;
917
918           for (i = 0;
919                g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
920                i++, g++)
921               x += g->width;
922           XDrawString16 (display, (Window) win, gc,
923                          orig_x, y - baseline_offset, code + code_idx, i);
924         }
925     }
926 }
927
928 static int
929 xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
930 {
931   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
932   MSymbol registry = font ? FONT_PROPERTY (font, MFONT_REGISTRY) : Mnil;
933   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
934   int size = font ? font->size : 0;
935   MPlist *pl, *p;
936   int num = 0;
937   int mdebug_mask = MDEBUG_FONT;
938
939   MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
940                  family ? msymbol_name (family) : "*",
941                  registry ? msymbol_name (registry) : "*");
942
943   if (registry == Mnil)
944     xfont_list_all (frame);
945   else
946     xfont_registry_list (frame, registry);
947
948   MPLIST_DO (pl, disp_info->font_list)
949     {
950       if (registry != Mnil && registry != MPLIST_KEY (pl))
951         continue;
952       MPLIST_DO (p, MPLIST_VAL (pl))
953         {
954           MFontX *fontx;
955
956           if (family != Mnil && family != MPLIST_KEY (p))
957             continue;
958           for (fontx = MPLIST_VAL (p); fontx; fontx = fontx->next)
959             if (! font
960                 || (mfont__match_p (&fontx->core, font, MFONT_REGISTRY)))
961               {
962                 if (fontx->core.size == size
963                     || fontx->core.size == 0)
964                   {
965                     mplist_push (plist, MPLIST_KEY (p), fontx);
966                     num++;
967                   }
968                 else if (size == 0
969                          || (size <= 360 && HAVE_SIZE (fontx, (size / 10))))
970                   {
971                     unsigned size5_36 = fontx->size5_36;
972                     MFontX *fontx2;
973                     int i;
974
975                     fontx->size5_36 = 0;
976                     for (i = fontx->core.size / 10; i <= 36; i++)
977                       if (size5_36 & (1 << (i - 5)))
978                         {
979                           MSTRUCT_CALLOC (fontx2, MERROR_WIN);
980                           fontx2->core = fontx->core;
981                           fontx2->core.size = i * 10;
982                           fontx2->next = fontx->next;
983                           fontx->next = fontx2;
984                           fontx = fontx2;
985                           if ((size == 0 || size == fontx->core.size)
986                               && (maxnum == 0 || num < maxnum))
987                             {
988                               mplist_push (plist, MPLIST_KEY (p), fontx);
989                               num++;
990                             }
991                         }
992                   }
993                 if (maxnum > 0 && maxnum == num)
994                   break;
995               }
996           if (maxnum > 0 && maxnum == num)
997             break;
998         }
999       if (maxnum > 0 && maxnum == num)
1000         break;
1001     }
1002
1003   MDEBUG_PRINT1 (" %d found\n", num);
1004   return num;
1005 }
1006
1007 static int 
1008 xfont_check_capability (MRealizedFont *rfont, MSymbol capability)
1009 {
1010   /* Currently X font driver doesn't support any capability.  */
1011   return -1;
1012 }
1013
1014 \f
1015 /* Xft Handler */
1016
1017 #ifdef HAVE_XFT2
1018
1019 typedef struct
1020 {
1021   M17NObject control;
1022   Display *display;
1023   XftFont *font_aa;
1024   XftFont *font_no_aa;
1025   FT_Face ft_face;
1026   /* Pointer to MRealizedFontFT */
1027   void *info;
1028 } MRealizedFontXft;
1029
1030 static MRealizedFont *xft_open (MFrame *frame, MFont *font, MFont *spec,
1031                                 MRealizedFont *);
1032 static int xft_has_char (MFrame *frame, MFont *font, MFont *spec,
1033                          int c, unsigned code);
1034 static unsigned xft_encode_char (MFrame *frame, MFont *font, MFont *spec,
1035                                  unsigned code);
1036 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
1037 static void xft_render (MDrawWindow, int, int, MGlyphString *,
1038                         MGlyph *, MGlyph *, int, MDrawRegion);
1039 static int xft_check_capability (MRealizedFont *rfont, MSymbol capability);
1040
1041 MFontDriver xft_driver =
1042   { NULL, xft_open,
1043     xft_find_metric, xft_has_char, xft_encode_char, xft_render, NULL,
1044     xft_check_capability
1045   };
1046
1047 static void
1048 close_xft (void *object)
1049 {
1050   MRealizedFontXft *rfont_xft = object;
1051
1052   if (rfont_xft->font_aa)
1053     XftFontClose (rfont_xft->display, rfont_xft->font_aa);
1054   if (rfont_xft->font_no_aa)
1055     XftFontClose (rfont_xft->display, rfont_xft->font_no_aa);
1056   M17N_OBJECT_UNREF (rfont_xft->info);
1057   free (rfont_xft);
1058 }
1059
1060
1061 static XftFont *
1062 xft_open_font (Display *display, MSymbol file, double size,
1063                FcBool anti_alias)
1064 {
1065   FcPattern *pattern;
1066   XftFont *font;
1067
1068   pattern = FcPatternCreate ();
1069   FcPatternAddString (pattern, FC_FILE, (FcChar8 *) msymbol_name (file));
1070   FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
1071   FcPatternAddBool (pattern, FC_ANTIALIAS, anti_alias);
1072   font = XftFontOpenPattern (display, pattern);
1073   return font;
1074 }
1075
1076
1077 static MRealizedFont *
1078 xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1079 {
1080   Display *display = FRAME_DISPLAY (frame);
1081   int reg = spec->property[MFONT_REGISTRY];
1082   FT_Face ft_face;
1083   MRealizedFontXft *rfont_xft;
1084   FcBool anti_alias = FRAME_DEVICE (frame)->depth > 1 ? FcTrue : FcFalse;
1085   int size;
1086   XftFont *xft_font;
1087   int ascent, descent, max_advance, average_width, baseline_offset;
1088
1089   if (font->size)
1090     /* non-scalable font */
1091     size = font->size;
1092   else if (spec->size)
1093     {
1094       int ratio = mfont_resize_ratio (font);
1095
1096       size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1097     }
1098   else
1099     size = 120;
1100
1101   if (rfont)
1102     {
1103       MRealizedFont *save = NULL;
1104
1105       for (; rfont; rfont = rfont->next)
1106         if (rfont->font == font
1107             && (rfont->font->size ? rfont->font->size == size
1108                 : rfont->spec.size == size)
1109             && rfont->spec.property[MFONT_REGISTRY] == reg)
1110           {
1111             if (! save)
1112               save = rfont;
1113             if (rfont->driver == &xft_driver)
1114               return rfont;
1115           }
1116       rfont = save;
1117     }
1118   rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
1119   if (! rfont)
1120     return NULL;
1121   ascent = rfont->ascent;
1122   descent = rfont->descent;
1123   max_advance = rfont->max_advance;
1124   average_width = rfont->average_width;
1125   baseline_offset = rfont->baseline_offset;
1126   spec = &rfont->spec;
1127   ft_face = rfont->fontp;
1128   xft_font = xft_open_font (display, font->file, size / 10, anti_alias);
1129   if (! xft_font)
1130     return NULL;
1131   M17N_OBJECT (rfont_xft, close_xft, MERROR_WIN);
1132   rfont_xft->display = display;
1133   if (anti_alias == FcTrue)
1134     rfont_xft->font_aa = xft_font;
1135   else
1136     rfont_xft->font_no_aa = xft_font;
1137   rfont_xft->ft_face = ft_face;
1138   rfont_xft->info = rfont->info;
1139   M17N_OBJECT_REF (rfont->info);
1140   MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
1141   rfont->spec = *spec;
1142   rfont->spec.size = size;
1143   rfont->frame = frame;
1144   rfont->font = font;
1145   rfont->driver = &xft_driver;
1146   rfont->info = rfont_xft;
1147   rfont->ascent = ascent;
1148   rfont->descent = descent;
1149   rfont->max_advance = max_advance;
1150   rfont->average_width = average_width;
1151   rfont->baseline_offset = baseline_offset;
1152   rfont->fontp = xft_font;
1153   rfont->next = MPLIST_VAL (frame->realized_font_list);
1154   MPLIST_VAL (frame->realized_font_list) = rfont;
1155   return rfont;
1156 }
1157
1158 static void
1159 xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1160                 int from, int to)
1161 {
1162   Display *display = FRAME_DISPLAY (rfont->frame);
1163   XftFont *xft_font = rfont->fontp;
1164   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1165
1166   for (; g != gend; g++)
1167     {
1168       if (g->code == MCHAR_INVALID_CODE)
1169         {
1170           g->lbearing = 0;
1171           g->rbearing = xft_font->max_advance_width;
1172           g->width = g->rbearing;
1173           g->ascent = xft_font->ascent;
1174           g->descent = xft_font->descent;
1175         }
1176       else
1177         {
1178           XGlyphInfo extents;
1179
1180           XftGlyphExtents (display, xft_font, &g->code, 1, &extents);
1181           g->lbearing = - extents.x;
1182           g->rbearing = extents.width - extents.x;
1183           g->width = extents.xOff;
1184           g->ascent = extents.y;
1185           g->descent = extents.height - extents.y;
1186         }
1187     }
1188 }
1189
1190 static int
1191 xft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1192 {
1193   int result;
1194
1195   if (font->type == MFONT_TYPE_REALIZED)
1196     {
1197       MRealizedFont *rfont = (MRealizedFont *) font;
1198       MRealizedFontXft *rfont_xft = rfont->info;
1199       
1200       rfont->info = rfont_xft->info;
1201       result = mfont__ft_driver.has_char (frame, font, spec, c, code);
1202       rfont->info = rfont_xft;
1203     }
1204   else
1205     result = mfont__ft_driver.has_char (frame, font, spec, c, code);
1206   return result;
1207 }
1208
1209 static unsigned
1210 xft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1211 {
1212   if (font->type == MFONT_TYPE_REALIZED)
1213     {
1214       MRealizedFont *rfont = (MRealizedFont *) font;
1215       MRealizedFontXft *rfont_xft = rfont->info;
1216       
1217       rfont->info = rfont_xft->info;
1218       code = mfont__ft_driver.encode_char (frame, font, spec, code);
1219       rfont->info = rfont_xft;
1220     }
1221   else
1222     code = mfont__ft_driver.encode_char (frame, font, spec, code);
1223   return code;
1224 }
1225
1226 static void 
1227 xft_render (MDrawWindow win, int x, int y,
1228             MGlyphString *gstring, MGlyph *from, MGlyph *to,
1229             int reverse, MDrawRegion region)
1230 {
1231   MRealizedFace *rface = from->rface;
1232   MFrame *frame = rface->frame;
1233   Display *display = FRAME_DISPLAY (frame);
1234   MRealizedFont *rfont = rface->rfont;
1235   MRealizedFontXft *rfont_xft = rfont->info;
1236   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
1237   XftColor *xft_color = (! reverse
1238                          ? &((GCInfo *) rface->info)->xft_color_fore
1239                          : &((GCInfo *) rface->info)->xft_color_back);
1240   int anti_alias = (gstring->control.anti_alias
1241                     && FRAME_DEVICE (frame)->depth > 1);
1242   XftFont *xft_font;
1243   MGlyph *g;
1244   FT_UInt *glyphs;
1245   int last_x;
1246   int nglyphs;
1247
1248   if (from == to)
1249     return;
1250
1251   if (anti_alias)
1252     {
1253       if (rfont_xft->font_aa)
1254         xft_font = rfont_xft->font_aa;
1255       else
1256         {
1257           double size = rfont->spec.size;
1258
1259           xft_font = xft_open_font (display, rfont->spec.file, size / 10,
1260                                     FcTrue);
1261           if (xft_font)
1262             rfont_xft->font_aa = xft_font;
1263           else
1264             xft_font = rfont->fontp;
1265         }
1266     }
1267   else
1268     {
1269       if (rfont_xft->font_no_aa)
1270         xft_font = rfont_xft->font_no_aa;
1271       else
1272         {
1273           double size = rfont->spec.size;
1274
1275           xft_font = xft_open_font (display, rfont->spec.file, size / 10,
1276                                     FcTrue);
1277           if (xft_font)
1278             rfont_xft->font_no_aa = xft_font;
1279           else
1280             xft_font = rfont->fontp;
1281         }
1282     }
1283
1284   XftDrawChange (xft_draw, (Drawable) win);
1285   XftDrawSetClip (xft_draw, (Region) region);
1286       
1287   y -= rfont->baseline_offset;
1288   glyphs = alloca (sizeof (FT_UInt) * (to - from));
1289   for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
1290     {
1291       if (g->xoff == 0 && g->yoff == 0 && !g->left_padding && !g->right_padding)
1292         glyphs[nglyphs++] = g->code;
1293       else
1294         {
1295           if (nglyphs > 0)
1296             XftDrawGlyphs (xft_draw, xft_color, xft_font,
1297                            last_x, y, glyphs, nglyphs);
1298           nglyphs = 0;
1299           XftDrawGlyphs (xft_draw, xft_color, xft_font,
1300                          x + g->xoff, y + g->yoff, (FT_UInt *) &g->code, 1);
1301           last_x = x + g->width;
1302         }
1303     }
1304   if (nglyphs > 0)
1305     XftDrawGlyphs (xft_draw, xft_color, xft_font, last_x, y, glyphs, nglyphs);
1306 }
1307
1308 static int
1309 xft_check_capability (MRealizedFont *rfont, MSymbol capability)
1310 {
1311   MRealizedFontXft *rfont_xft = rfont->info;
1312   int result;
1313       
1314   rfont->info = rfont_xft->info;
1315   result = mfont__ft_driver.check_capability (rfont, capability);
1316   rfont->info = rfont_xft;
1317   return result;
1318 }
1319
1320 #endif  /* HAVE_XFT2 */
1321
1322 \f
1323 /* Functions for the device driver.  */
1324
1325 static void
1326 mwin__close_device (MFrame *frame)
1327 {
1328   MWDevice *device = FRAME_DEVICE (frame);
1329
1330   M17N_OBJECT_UNREF (device);
1331 }
1332
1333 static void *
1334 mwin__device_get_prop (MFrame *frame, MSymbol key)
1335 {
1336   MWDevice *device = FRAME_DEVICE (frame);
1337
1338   if (key == Mdisplay)
1339     return (void *) device->display_info->display;
1340   if (key == Mscreen)
1341     return (void *) ScreenOfDisplay(device->display_info->display,
1342                                     device->screen_num);
1343   if (key == Mcolormap)
1344     return (void *) device->cmap;
1345   if (key == Mdepth)
1346     return (void *) device->depth;
1347   return NULL;
1348 }
1349
1350 static void
1351 mwin__realize_face (MRealizedFace *rface)
1352 {
1353   MFrame *frame;
1354   MSymbol foreground, background, videomode;
1355   MFaceHLineProp *hline;
1356   MFaceBoxProp *box;
1357   GCInfo *info;
1358
1359   if (rface != rface->ascii_rface)
1360     {
1361       rface->info = rface->ascii_rface->info;
1362       return;
1363     }
1364
1365   frame = rface->frame;
1366   MSTRUCT_CALLOC (info, MERROR_WIN);
1367
1368   foreground = rface->face.property[MFACE_FOREGROUND];
1369   background = rface->face.property[MFACE_BACKGROUND];
1370   videomode = rface->face.property[MFACE_VIDEOMODE];
1371   if (! videomode)
1372     videomode = frame->videomode;
1373   if (videomode != Mreverse)
1374     {
1375       info->gc[GC_NORMAL] = get_gc (frame, foreground, 1, &info->rgb_fore);
1376       info->gc[GC_INVERSE] = get_gc (frame, background, 0, &info->rgb_back);
1377     }
1378   else
1379     {
1380       info->gc[GC_NORMAL] = get_gc (frame, background, 0, &info->rgb_fore);
1381       info->gc[GC_INVERSE] = get_gc (frame, foreground, 1, &info->rgb_back);
1382     }
1383 #ifdef HAVE_XFT2
1384   if (foreground == Mnil)
1385     foreground = frame->foreground;
1386   if (background == Mnil)
1387     background = frame->background;
1388   if (videomode == Mreverse)
1389     {
1390       MSymbol temp = foreground;
1391       foreground = background;
1392       background = temp;
1393     }
1394   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1395                            FRAME_VISUAL (frame),
1396                            FRAME_CMAP (frame),
1397                            MSYMBOL_NAME (foreground),
1398                            &info->xft_color_fore))
1399     mdebug_hook ();
1400   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1401                            FRAME_VISUAL (frame),
1402                            FRAME_CMAP (frame),
1403                            MSYMBOL_NAME (background),
1404                            &info->xft_color_back))
1405     mdebug_hook ();
1406 #endif  /* HAVE_XFT2 */
1407
1408   hline = rface->hline;
1409   if (hline)
1410     {
1411       if (hline->color)
1412         info->gc[GC_HLINE] = get_gc (frame, hline->color, 1, NULL);
1413       else
1414         info->gc[GC_HLINE] = info->gc[GC_NORMAL];
1415     }
1416
1417   box = rface->box;
1418   if (box)
1419     {
1420       if (box->color_top)
1421         info->gc[GC_BOX_TOP] = get_gc (frame, box->color_top, 1, NULL);
1422       else
1423         info->gc[GC_BOX_TOP] = info->gc[GC_NORMAL];
1424
1425       if (box->color_left && box->color_left != box->color_top)
1426         info->gc[GC_BOX_LEFT] = get_gc (frame, box->color_left, 1, NULL);
1427       else
1428         info->gc[GC_BOX_LEFT] = info->gc[GC_BOX_TOP];
1429
1430       if (box->color_bottom && box->color_bottom != box->color_top)
1431         info->gc[GC_BOX_BOTTOM] = get_gc (frame, box->color_bottom, 1, NULL);
1432       else
1433         info->gc[GC_BOX_BOTTOM] = info->gc[GC_BOX_TOP];
1434
1435       if (box->color_right && box->color_right != box->color_bottom)
1436         info->gc[GC_BOX_RIGHT] = get_gc (frame, box->color_right, 1, NULL);
1437       else
1438         info->gc[GC_BOX_RIGHT] = info->gc[GC_BOX_BOTTOM];
1439     }
1440
1441   rface->info = info;
1442 }
1443
1444
1445 static void
1446 mwin__free_realized_face (MRealizedFace *rface)
1447 {
1448   if (rface == rface->ascii_rface)
1449     free (rface->info);
1450 }
1451
1452
1453 static void
1454 mwin__fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1455                   int reverse,
1456                   int x, int y, int width, int height, MDrawRegion region)
1457 {
1458   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_NORMAL : GC_INVERSE];
1459
1460   if (region)
1461     gc = set_region (frame, gc, region);
1462
1463   XFillRectangle (FRAME_DISPLAY (frame), (Window) win, gc,
1464                   x, y, width, height);
1465 }
1466
1467
1468 static void
1469 mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
1470                         MGlyphString *gstring, MGlyph *from, MGlyph *to,
1471                         int reverse, MDrawRegion region)
1472 {
1473   MRealizedFace *rface = from->rface;
1474   Display *display = FRAME_DISPLAY (rface->frame);
1475   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1476
1477   if (from == to)
1478     return;
1479
1480   if (region)
1481     gc = set_region (rface->frame, gc, region);
1482   for (; from < to; from++)
1483     {
1484       XDrawRectangle (display, (Window) win, gc,
1485                       x, y - gstring->ascent + 1, from->width - 1,
1486                       gstring->ascent + gstring->descent - 2);
1487       x += from->width;
1488     }
1489 }
1490
1491
1492 static void
1493 mwin__draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1494                  MRealizedFace *rface, int reverse,
1495                  int x, int y, int width, MDrawRegion region)
1496 {
1497   enum MFaceHLineType type = rface->hline->type;
1498   GCInfo *info = rface->info;
1499   GC gc = gc = info->gc[GC_HLINE];
1500   int i;
1501
1502   y = (type == MFACE_HLINE_BOTTOM
1503        ? y + gstring->text_descent - rface->hline->width
1504        : type == MFACE_HLINE_UNDER
1505        ? y + 1
1506        : type == MFACE_HLINE_STRIKE_THROUGH
1507        ? y - ((gstring->ascent + gstring->descent) / 2)
1508        : y - gstring->text_ascent);
1509   if (region)
1510     gc = set_region (frame, gc, region);
1511
1512   for (i = 0; i < rface->hline->width; i++)
1513     XDrawLine (FRAME_DISPLAY (frame), (Window) win, gc,
1514                x, y + i, x + width - 1, y + i);
1515 }
1516
1517
1518 static void
1519 mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1520                 MGlyph *g, int x, int y, int width, MDrawRegion region)
1521 {
1522   Display *display = FRAME_DISPLAY (frame);
1523   MRealizedFace *rface = g->rface;
1524   MFaceBoxProp *box = rface->box;
1525   GCInfo *info = rface->info;
1526   GC gc_top, gc_left, gc_right, gc_btm;
1527   int y0, y1;
1528   int i;
1529
1530   y0 = y - (gstring->text_ascent
1531             + rface->box->inner_vmargin + rface->box->width);
1532   y1 = y + (gstring->text_descent
1533             + rface->box->inner_vmargin + rface->box->width - 1);
1534
1535   gc_top = info->gc[GC_BOX_TOP];
1536   if (region)
1537     gc_top = set_region (frame, gc_top, region);
1538   if (info->gc[GC_BOX_TOP] == info->gc[GC_BOX_BOTTOM])
1539     gc_btm = gc_top;
1540   else
1541     gc_btm = info->gc[GC_BOX_BOTTOM];
1542
1543   if (g->type == GLYPH_BOX)
1544     {
1545       int x0, x1;
1546
1547       if (g->left_padding)
1548         x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
1549       else
1550         x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
1551
1552       /* Draw the top side.  */
1553       for (i = 0; i < box->width; i++)
1554         XDrawLine (display, (Window) win, gc_top, x0, y0 + i, x1, y0 + i);
1555
1556       /* Draw the bottom side.  */
1557       if (region && gc_btm != gc_top)
1558         gc_btm = set_region (frame, gc_btm, region);
1559       for (i = 0; i < box->width; i++)
1560         XDrawLine (display, (Window) win, gc_btm, x0, y1 - i, x1, y1 - i);
1561
1562       if (g->left_padding > 0)
1563         {
1564           /* Draw the left side.  */
1565           if (info->gc[GC_BOX_LEFT] == info->gc[GC_BOX_TOP])
1566             gc_left = gc_top;
1567           else
1568             {
1569               gc_left = info->gc[GC_BOX_LEFT];
1570               if (region)
1571                 gc_left = set_region (frame, gc_left, region);
1572             }
1573           for (i = 0; i < rface->box->width; i++)
1574             XDrawLine (display, (Window) win, gc_left,
1575                        x0 + i, y0 + i, x0 + i, y1 - i);
1576         }
1577       else
1578         {
1579           /* Draw the right side.  */
1580           if (info->gc[GC_BOX_RIGHT] == info->gc[GC_BOX_TOP])
1581             gc_right = gc_top;
1582           else
1583             {
1584               gc_right = info->gc[GC_BOX_RIGHT];
1585               if (region)
1586                 gc_right = set_region (frame, gc_right, region);
1587             }
1588           for (i = 0; i < rface->box->width; i++)
1589             XDrawLine (display, (Window) win, gc_right,
1590                        x1 - i, y0 + i, x1 - i, y1 - i);
1591         }
1592     }
1593   else
1594     {
1595       /* Draw the top side.  */
1596       for (i = 0; i < box->width; i++)
1597         XDrawLine (display, (Window) win, gc_top,
1598                    x, y0 + i, x + width - 1, y0 + i);
1599
1600       /* Draw the bottom side.  */
1601       if (region && gc_btm != gc_top)
1602         gc_btm = set_region (frame, gc_btm, region);
1603       for (i = 0; i < box->width; i++)
1604         XDrawLine (display, (Window) win, gc_btm,
1605                    x, y1 - i, x + width - 1, y1 - i);
1606     }
1607 }
1608
1609
1610 #if 0
1611 static void
1612 mwin__draw_bitmap (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1613                    int reverse, int x, int y,
1614                    int width, int height, int row_bytes, unsigned char *bmp,
1615                    MDrawRegion region)
1616 {
1617   Display *display = FRAME_DISPLAY (frame);
1618   int i, j;
1619   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1620
1621   if (region)
1622     gc = set_region (frame, gc, region);
1623
1624   for (i = 0; i < height; i++, bmp += row_bytes)
1625     for (j = 0; j < width; j++)
1626       if (bmp[j / 8] & (1 << (7 - (j % 8))))
1627         XDrawPoint (display, (Window) win, gc, x + j, y + i);
1628 }
1629 #endif
1630
1631 static void
1632 mwin__draw_points (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1633                    int intensity, MDrawPoint *points, int num,
1634                    MDrawRegion region)
1635 {
1636   GCInfo *info = rface->info;
1637   GC gc;
1638
1639   if (! (gc = info->gc[intensity]))
1640     gc = info->gc[intensity] = get_gc_for_anti_alias (FRAME_DEVICE (frame),
1641                                                       info, intensity);
1642   if (region)
1643     gc = set_region (frame, gc, region);
1644
1645   XDrawPoints (FRAME_DISPLAY (frame), (Window) win, gc,
1646                (XPoint *) points, num, CoordModeOrigin);
1647 }
1648
1649
1650 static MDrawRegion
1651 mwin__region_from_rect (MDrawMetric *rect)
1652 {
1653   MDrawRegion region1 = XCreateRegion ();
1654   MDrawRegion region2 = XCreateRegion ();
1655   XRectangle xrect;
1656
1657   xrect.x = rect->x;
1658   xrect.y = rect->y;
1659   xrect.width = rect->width;
1660   xrect.height = rect->height;
1661   XUnionRectWithRegion (&xrect, region1, region2);
1662   XDestroyRegion (region1);
1663   return region2;
1664 }
1665
1666 static void
1667 mwin__union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
1668 {
1669   MDrawRegion region1 = XCreateRegion ();
1670   XRectangle xrect;
1671
1672   xrect.x = rect->x;
1673   xrect.y = rect->y;
1674   xrect.width = rect->width;
1675   xrect.height = rect->height;
1676
1677   XUnionRegion (region, region, region1);
1678   XUnionRectWithRegion (&xrect, region1, region);
1679   XDestroyRegion (region1);
1680 }
1681
1682 static void
1683 mwin__intersect_region (MDrawRegion region1, MDrawRegion region2)
1684 {
1685   MDrawRegion region = XCreateRegion ();
1686
1687   XUnionRegion (region1, region1, region);
1688   XIntersectRegion (region, region2, region1);
1689   XDestroyRegion (region);
1690 }
1691
1692 static void
1693 mwin__region_add_rect (MDrawRegion region, MDrawMetric *rect)
1694 {
1695   MDrawRegion region1 = XCreateRegion ();
1696   XRectangle xrect;
1697
1698   xrect.x = rect->x;
1699   xrect.y = rect->y;
1700   xrect.width = rect->width;
1701   xrect.height = rect->height;
1702   XUnionRectWithRegion (&xrect, region1, region);
1703   XDestroyRegion (region1);
1704 }
1705
1706 static void
1707 mwin__region_to_rect (MDrawRegion region, MDrawMetric *rect)
1708 {
1709   XRectangle xrect;
1710
1711   XClipBox (region, &xrect);
1712   rect->x = xrect.x;
1713   rect->y = xrect.y;
1714   rect->width = xrect.width;
1715   rect->height = xrect.height;
1716 }
1717
1718 static void
1719 mwin__free_region (MDrawRegion region)
1720 {
1721   XDestroyRegion (region);
1722 }
1723
1724 static void
1725 mwin__dump_region (MDrawRegion region)
1726 {
1727   XRectangle rect;
1728   XClipBox (region, &rect);
1729   fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
1730 }
1731
1732
1733 static MDrawWindow
1734 mwin__create_window (MFrame *frame, MDrawWindow parent)
1735 {
1736   Display *display = FRAME_DISPLAY (frame);
1737   Window win;
1738   XWMHints wm_hints = { InputHint, False };
1739   XClassHint class_hints = { "M17N-IM", "m17n-im" };
1740   XSetWindowAttributes set_attrs;
1741   unsigned long mask;
1742   XGCValues values;
1743   GCInfo *info = frame->rface->info;
1744
1745   if (! parent)
1746     parent = (MDrawWindow) RootWindow (display, FRAME_SCREEN (frame));
1747   mask = GCForeground;
1748   XGetGCValues (display, info->gc[GC_INVERSE], mask, &values);
1749   set_attrs.background_pixel = values.foreground;
1750   set_attrs.backing_store = Always;
1751   set_attrs.override_redirect = True;
1752   set_attrs.save_under = True;
1753   mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWSaveUnder;
1754   win = XCreateWindow (display, (Window) parent, 0, 0, 1, 1, 0,
1755                        CopyFromParent, InputOutput, CopyFromParent,
1756                        mask, &set_attrs);
1757   XSetWMProperties (display, (Window) win, NULL, NULL, NULL, 0,
1758                     NULL, &wm_hints, &class_hints);
1759   XSelectInput (display, (Window) win, StructureNotifyMask | ExposureMask);
1760   return (MDrawWindow) win;
1761 }
1762
1763 static void
1764 mwin__destroy_window (MFrame *frame, MDrawWindow win)
1765 {
1766 #ifdef HAVE_XFT2
1767   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
1768
1769   if (XftDrawDrawable (xft_draw) == (Drawable) win)
1770     XftDrawChange (xft_draw, FRAME_DEVICE (frame)->drawable);
1771 #endif  /* HAVE_XFT2 */
1772   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
1773 }
1774
1775 #if 0
1776 static MDrawWindow
1777 mwin__event_window (void *event)
1778 {
1779   return ((MDrawWindow) ((XEvent *) event)->xany.window);
1780 }
1781
1782 static void
1783 mwin__print_event (void *arg, char *win_name)
1784 {
1785   char *event_name;
1786   XEvent *event = (XEvent *) arg;
1787
1788   switch (event->xany.type)
1789     {
1790     case 2: event_name = "KeyPress"; break;
1791     case 3: event_name = "KeyRelease"; break;
1792     case 4: event_name = "ButtonPress"; break;
1793     case 5: event_name = "ButtonRelease"; break;
1794     case 6: event_name = "MotionNotify"; break;
1795     case 7: event_name = "EnterNotify"; break;
1796     case 8: event_name = "LeaveNotify"; break;
1797     case 9: event_name = "FocusIn"; break;
1798     case 10: event_name = "FocusOut"; break;
1799     case 11: event_name = "KeymapNotify"; break;
1800     case 12: event_name = "Expose"; break;
1801     case 13: event_name = "GraphicsExpose"; break;
1802     case 14: event_name = "NoExpose"; break;
1803     case 15: event_name = "VisibilityNotify"; break;
1804     case 16: event_name = "CreateNotify"; break;
1805     case 17: event_name = "DestroyNotify"; break;
1806     case 18: event_name = "UnmapNotify"; break;
1807     case 19: event_name = "MapNotify"; break;
1808     case 20: event_name = "MapRequest"; break;
1809     case 21: event_name = "ReparentNotify"; break;
1810     case 22: event_name = "ConfigureNotify"; break;
1811     case 23: event_name = "ConfigureRequest"; break;
1812     case 24: event_name = "GravityNotify"; break;
1813     case 25: event_name = "ResizeRequest"; break;
1814     case 26: event_name = "CirculateNotify"; break;
1815     case 27: event_name = "CirculateRequest"; break;
1816     case 28: event_name = "PropertyNotify"; break;
1817     case 29: event_name = "SelectionClear"; break;
1818     case 30: event_name = "SelectionRequest"; break;
1819     case 31: event_name = "SelectionNotify"; break;
1820     case 32: event_name = "ColormapNotify"; break;
1821     case 33: event_name = "ClientMessage"; break;
1822     case 34: event_name = "MappingNotify"; break;
1823     default: event_name = "unknown";
1824     }
1825
1826   fprintf (stderr, "%s: %s\n", win_name, event_name);
1827 }
1828 #endif
1829
1830 static void
1831 mwin__map_window (MFrame *frame, MDrawWindow win)
1832 {
1833   XMapRaised (FRAME_DISPLAY (frame), (Window) win);
1834 }
1835
1836 static void
1837 mwin__unmap_window (MFrame *frame, MDrawWindow win)
1838 {
1839   XUnmapWindow (FRAME_DISPLAY (frame), (Window) win);
1840 }
1841
1842 static void
1843 mwin__window_geometry (MFrame *frame, MDrawWindow win, MDrawWindow parent_win,
1844                        MDrawMetric *geometry)
1845 {
1846   Display *display = FRAME_DISPLAY (frame);
1847   XWindowAttributes attr;
1848   Window parent = (Window) parent_win, root;
1849
1850   XGetWindowAttributes (display, (Window) win, &attr);
1851   geometry->x = attr.x + attr.border_width;
1852   geometry->y = attr.y + attr.border_width;
1853   geometry->width = attr.width;
1854   geometry->height = attr.height; 
1855
1856   if (! parent)
1857     parent = RootWindow (display, FRAME_SCREEN (frame));
1858   while (1)
1859     {
1860       Window this_parent, *children;
1861       unsigned n;
1862
1863       XQueryTree (display, (Window) win, &root, &this_parent, &children, &n);
1864       if (children)
1865         XFree (children);
1866       if (this_parent == parent || this_parent == root)
1867         break;
1868       win = (MDrawWindow) this_parent;
1869       XGetWindowAttributes (display, (Window) win, &attr);
1870       geometry->x += attr.x + attr.border_width;
1871       geometry->y += attr.y + attr.border_width;
1872     }
1873 }
1874
1875 static void
1876 mwin__adjust_window (MFrame *frame, MDrawWindow win,
1877                      MDrawMetric *current, MDrawMetric *new)
1878 {
1879   Display *display = FRAME_DISPLAY (frame);
1880   unsigned int mask = 0;
1881   XWindowChanges values;
1882
1883   if (current->width != new->width)
1884     {
1885       mask |= CWWidth;
1886       if (new->width <= 0)
1887         new->width = 1;
1888       values.width = current->width = new->width;
1889     }
1890   if (current->height != new->height)
1891     {
1892       mask |= CWHeight;
1893       if (new->height <= 0)
1894         new->height = 1;
1895       values.height = current->height = new->height;
1896     }
1897   if (current->x != new->x)
1898     {
1899       mask |= CWX;
1900       values.x = current->x = new->x;
1901     }
1902   if (current->y != new->y)
1903     {
1904       mask |= CWY;
1905       current->y = new->y;
1906       values.y = current->y = new->y;
1907     }
1908   if (mask)
1909     XConfigureWindow (display, (Window) win, mask, &values);
1910   XClearWindow (display, (Window) win);
1911 }
1912
1913 static MSymbol
1914 mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
1915 {
1916   XEvent *event = (XEvent *) arg;
1917   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
1918   int len;
1919   char buf[512];
1920   KeySym keysym;
1921   MSymbol key = Mnil;
1922
1923   *modifiers = 0;
1924   if (event->xany.type != KeyPress
1925       /* && event->xany.type != KeyRelease */
1926       )
1927     return Mnil;
1928   len = XLookupString ((XKeyEvent *) event, (char *) buf, 512, &keysym, NULL);
1929   if (len > 1)
1930     return Mnil;
1931   if (len == 1)
1932     {
1933       int c = keysym;
1934
1935       if (c < XK_space || c > XK_asciitilde)
1936         c = buf[0];
1937       if ((c == ' ' || c == 127) && ((XKeyEvent *) event)->state & ShiftMask)
1938         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1939       if (((XKeyEvent *) event)->state & ControlMask)
1940         {
1941           if (c >= 'a' && c <= 'z')
1942             c += 'A' - 'a';
1943           if (c >= ' ' && c < 127)
1944             *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1945         }
1946       key = minput__char_to_key (c);
1947     }
1948   else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
1949     return Mnil;
1950   if (key == Mnil)
1951     {
1952       char *str = XKeysymToString (keysym);
1953
1954       if (! str)
1955         return Mnil;
1956       key = msymbol (str);
1957       if (((XKeyEvent *) event)->state & ShiftMask)
1958         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1959       if (((XKeyEvent *) event)->state & ControlMask)
1960         *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1961     }
1962   if (((XKeyEvent *) event)->state & disp_info->meta_mask)
1963     *modifiers |= MINPUT_KEY_META_MODIFIER;
1964   if (((XKeyEvent *) event)->state & disp_info->alt_mask)
1965     *modifiers |= MINPUT_KEY_ALT_MODIFIER;
1966   if (((XKeyEvent *) event)->state & disp_info->super_mask)
1967     *modifiers |= MINPUT_KEY_SUPER_MODIFIER;
1968   if (((XKeyEvent *) event)->state & disp_info->hyper_mask)
1969     *modifiers |= MINPUT_KEY_HYPER_MODIFIER;
1970
1971   return key;
1972 }
1973
1974
1975 void
1976 mwin__dump_gc (MFrame *frame, MRealizedFace *rface)
1977 {
1978   unsigned long valuemask = GCForeground | GCBackground | GCClipMask;
1979   XGCValues values;
1980   Display *display = FRAME_DISPLAY (frame);
1981   GCInfo *info = rface->info;
1982   int i;
1983
1984   for (i = 0; i <= GC_INVERSE; i++)
1985     {
1986       XGetGCValues (display, info->gc[i], valuemask, &values);
1987       fprintf (stderr, "GC%d: fore/#%lX back/#%lX", i,
1988                values.foreground, values.background);
1989       fprintf (stderr, "\n");
1990     }
1991 }
1992
1993 static MDeviceDriver x_driver =
1994   {
1995     mwin__close_device,
1996     mwin__device_get_prop,
1997     mwin__realize_face,
1998     mwin__free_realized_face,
1999     mwin__fill_space,
2000     mwin__draw_empty_boxes,
2001     mwin__draw_hline,
2002     mwin__draw_box,
2003     mwin__draw_points,
2004     mwin__region_from_rect,
2005     mwin__union_rect_with_region,
2006     mwin__intersect_region,
2007     mwin__region_add_rect,
2008     mwin__region_to_rect,
2009     mwin__free_region,
2010     mwin__dump_region,
2011     mwin__create_window,
2012     mwin__destroy_window,
2013     mwin__map_window,
2014     mwin__unmap_window,
2015     mwin__window_geometry,
2016     mwin__adjust_window,
2017     mwin__parse_event
2018   };
2019
2020 /* Functions to be stored in MDeviceLibraryInterface by dlsym ().  */
2021
2022 int
2023 device_init ()
2024 {
2025   M_iso8859_1 = msymbol ("iso8859-1");
2026   M_iso10646_1 = msymbol ("iso10646-1");
2027
2028   display_info_list = mplist ();
2029   device_list = mplist ();
2030
2031 #ifdef HAVE_XFT2
2032   xft_driver.select = mfont__ft_driver.select;
2033   xft_driver.list = mfont__ft_driver.list;
2034 #endif
2035
2036   Mxim = msymbol ("xim");
2037   msymbol_put (Mxim, Minput_driver, &minput_xim_driver);
2038
2039   return 0;
2040 }
2041
2042 int
2043 device_fini ()
2044 {
2045   M17N_OBJECT_UNREF (display_info_list);
2046   M17N_OBJECT_UNREF (device_list);
2047   return 0;
2048 }
2049
2050
2051 #ifdef X_SET_ERROR_HANDLER
2052 static int
2053 x_error_handler (Display *display, XErrorEvent *error)
2054 {
2055   mdebug_hook ();
2056   return 0;
2057 }
2058
2059 static int
2060 x_io_error_handler (Display *display)
2061 {
2062   mdebug_hook ();
2063   return 0;
2064 }
2065 #endif
2066
2067 /** Return an MWDevice object corresponding to a display specified in
2068     PLIST.
2069
2070     It searches device_list for a device matching the display.  If
2071     found, return the found object.  Otherwise, return a newly created
2072     object.  */
2073
2074 int
2075 device_open (MFrame *frame, MPlist *param)
2076 {
2077   Display *display = NULL;
2078   Screen *screen = NULL;
2079   int screen_num;
2080   Drawable drawable = 0;
2081   Widget widget = NULL;
2082   Colormap cmap = 0;
2083   int auto_display = 0;
2084   MDisplayInfo *disp_info = NULL;
2085   MWDevice *device = NULL;
2086   MSymbol key;
2087   XWindowAttributes attr;
2088   unsigned depth = 0;
2089   MPlist *plist;
2090   AppData app_data;
2091   MFont *font = NULL;
2092   MFace *face;
2093   int use_xfont = 0, use_freetype = 0, use_xft = 0;
2094
2095   for (plist = param; (key = mplist_key (plist)) != Mnil;
2096        plist = mplist_next (plist))
2097     {
2098       if (key == Mdisplay)
2099         display = (Display *) mplist_value (plist);
2100       else if (key == Mscreen)
2101         screen = mplist_value (plist);
2102       else if (key == Mdrawable)
2103         drawable = (Drawable) mplist_value (plist);
2104       else if (key == Mdepth)
2105         depth = (unsigned) mplist_value (plist);
2106       else if (key == Mwidget)
2107         widget = (Widget) mplist_value (plist);
2108       else if (key == Mcolormap)
2109         cmap = (Colormap) mplist_value (plist);
2110       else if (key == Mfont)
2111         {
2112           MSymbol val = MPLIST_SYMBOL (plist);
2113
2114           if (val == Mx)
2115             use_xfont = 1;
2116 #ifdef HAVE_FREETYPE
2117           else if (val == Mfreetype)
2118             use_freetype = 1;
2119 #ifdef HAVE_XFT2
2120           else if (val == Mxft)
2121             use_xft = 1;
2122 #endif
2123 #endif
2124         }
2125     }
2126
2127   /* If none of them is specified, use all of them.  */
2128   if (! use_xfont && ! use_freetype && ! use_xft)
2129     use_xfont = use_freetype = use_xft = 1;
2130
2131   if (widget)
2132     {
2133       display = XtDisplay (widget);
2134       screen_num = XScreenNumberOfScreen (XtScreen (widget));
2135       depth = DefaultDepth (display, screen_num);
2136     }
2137   else if (drawable)
2138     {
2139       Window root_window;
2140       int x, y;
2141       unsigned width, height, border_width;
2142
2143       if (! display)
2144         MERROR (MERROR_WIN, -1);
2145       XGetGeometry (display, drawable, &root_window,
2146                     &x, &y, &width, &height, &border_width, &depth);
2147       XGetWindowAttributes (display, root_window, &attr);
2148       screen_num = XScreenNumberOfScreen (attr.screen);
2149     }
2150   else
2151     {
2152       if (screen)
2153         display = DisplayOfScreen (screen);
2154       else
2155         {
2156           if (! display)
2157             {
2158               display = XOpenDisplay (NULL);
2159               if (! display)
2160                 MERROR (MERROR_WIN, -1);
2161               auto_display = 1;
2162             }
2163           screen = DefaultScreenOfDisplay (display);
2164         }
2165       screen_num = XScreenNumberOfScreen (screen);
2166       if (! depth)
2167         depth = DefaultDepth (display, screen_num);
2168     }
2169
2170   if (! cmap)
2171     cmap = DefaultColormap (display, screen_num);
2172
2173   for (plist = display_info_list; mplist_key (plist) != Mnil;
2174        plist = mplist_next (plist))
2175     {
2176       disp_info = (MDisplayInfo *) mplist_value (plist);
2177       if (disp_info->display == display)
2178         break;
2179     }
2180
2181   if (mplist_key (plist) != Mnil)
2182     M17N_OBJECT_REF (disp_info);
2183   else
2184     {
2185       M17N_OBJECT (disp_info, free_display_info, MERROR_WIN);
2186       disp_info->display = display;
2187       disp_info->auto_display = auto_display;
2188       disp_info->font_list = mplist ();
2189       find_modifier_bits (disp_info);
2190       disp_info->MULE_BASELINE_OFFSET
2191         = XInternAtom (display, "_MULE_BASELINE_OFFSET", False);
2192       disp_info->AVERAGE_WIDTH
2193         = XInternAtom (display, "AVERAGE_WIDTH", False);
2194       mplist_add (display_info_list, Mt, disp_info);
2195     }  
2196
2197   for (plist = device_list; mplist_key (plist) != Mnil;
2198        plist = mplist_next (plist))
2199     {
2200       device = (MWDevice *) mplist_value (plist);
2201       if (device->display_info == disp_info
2202           && device->depth == depth
2203           && device->cmap == cmap
2204           && device->screen_num == screen_num)
2205         break;
2206     }
2207
2208   if (mplist_key (plist) != Mnil)
2209     M17N_OBJECT_REF (device);
2210   else
2211     {
2212       unsigned long valuemask = GCForeground;
2213       XGCValues values;
2214       double pixels, mm;
2215
2216       M17N_OBJECT (device, free_device, MERROR_WIN);
2217       device->display_info = disp_info;
2218       device->screen_num = screen_num;
2219       /* A drawable on which to create GCs.  */
2220       device->drawable = XCreatePixmap (display,
2221                                         RootWindow (display, screen_num),
2222                                         1, 1, depth);
2223       device->depth = depth;
2224       device->cmap = cmap;
2225       pixels = DisplayHeight (display, screen_num);
2226       mm = DisplayHeightMM (display, screen_num);
2227       device->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
2228       device->realized_face_list = mplist ();
2229       device->realized_font_list = mplist ();
2230       mplist_add (device->realized_font_list, Mt, NULL);
2231       device->realized_fontset_list = mplist ();
2232       device->gc_list = mplist ();
2233       values.foreground = BlackPixel (display, screen_num);
2234       device->scratch_gc = XCreateGC (display, device->drawable,
2235                                       valuemask, &values);
2236 #ifdef HAVE_XFT2
2237       device->xft_draw = XftDrawCreate (display, device->drawable,
2238                                         DefaultVisual (display, screen_num),
2239                                         cmap);
2240 #endif
2241     }
2242
2243   frame->device = device;
2244   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
2245   frame->dpi = device->resy;
2246   frame->driver = &x_driver;
2247   frame->font_driver_list = mplist ();
2248 #ifdef HAVE_XFT2
2249   if (use_xft)
2250     {
2251       mplist_add (frame->font_driver_list, Mfreetype, &xft_driver);
2252       use_freetype = 0;
2253     }
2254 #endif  /* HAVE_XFT2 */
2255 #ifdef HAVE_FREETYPE
2256   if (use_freetype)
2257     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
2258 #endif  /* HAVE_FREETYPE */
2259   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
2260     mplist_push (frame->font_driver_list, Mx, &xfont_driver);
2261
2262   frame->realized_font_list = device->realized_font_list;
2263   frame->realized_face_list = device->realized_face_list;
2264   frame->realized_fontset_list = device->realized_fontset_list;
2265
2266   if (widget)
2267     {
2268       XtResource resources[] = {
2269         { XtNfont, XtCFont, XtRString, sizeof (String),
2270           XtOffset (AppDataPtr, font), XtRString, DEFAULT_FONT },
2271         { XtNforeground, XtCForeground, XtRString, sizeof (String),
2272           XtOffset (AppDataPtr, foreground), XtRString, "black" },
2273         { XtNbackground, XtCBackground, XtRString, sizeof (String),
2274           XtOffset (AppDataPtr, background), XtRString, "white" },
2275         { XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
2276           XtOffset (AppDataPtr, reverse_video), XtRImmediate, (caddr_t) FALSE }
2277       };
2278
2279       XtGetApplicationResources (widget, &app_data,
2280                                  resources, XtNumber (resources), NULL, 0);
2281       frame->foreground = msymbol (app_data.foreground);
2282       frame->background = msymbol (app_data.background);
2283       frame->videomode = app_data.reverse_video == True ? Mreverse : Mnormal;
2284     }
2285   else
2286     {
2287       app_data.font = DEFAULT_FONT;
2288       frame->foreground = msymbol ("black");
2289       frame->background = msymbol ("white");
2290       frame->videomode = Mnormal;
2291     }
2292
2293   if (strcmp (app_data.font, DEFAULT_FONT) != 0)
2294     {
2295       XFontStruct *xfont = XLoadQueryFont (display, app_data.font);
2296       unsigned long value;
2297       char *name;
2298
2299       if (xfont)
2300         {
2301           font = mfont_parse_name (app_data.font, Mx);
2302           if (! font
2303               && XGetFontProperty (xfont, XA_FONT, &value)
2304               && (name = ((char *) XGetAtomName (display, (Atom) value))))
2305             font = mfont_parse_name (name, Mx);
2306           XFreeFont (display, xfont);
2307         }
2308     }
2309   if (! font)
2310       font = mfont_parse_name (DEFAULT_FONT, Mx);
2311   else if (! font->size)
2312     font->size = 130;
2313   face = mface_from_font (font);
2314   free (font);
2315   face->property[MFACE_FONTSET] = mfontset (NULL);
2316   face->property[MFACE_FOREGROUND] = frame->foreground;
2317   face->property[MFACE_BACKGROUND] = frame->background;
2318   mface_put_prop (face, Mhline, mface_get_prop (mface__default, Mhline));
2319   mface_put_prop (face, Mbox, mface_get_prop (mface__default, Mbox));
2320   face->property[MFACE_VIDEOMODE] = frame->videomode;
2321   mface_put_prop (face, Mhook_func, 
2322                   mface_get_prop (mface__default, Mhook_func));
2323   face->property[MFACE_RATIO] = (void *) 100;
2324   mplist_push (param, Mface, face);
2325   M17N_OBJECT_UNREF (face);
2326
2327 #ifdef X_SET_ERROR_HANDLER
2328   XSetErrorHandler (x_error_handler);
2329   XSetIOErrorHandler (x_io_error_handler);
2330 #endif
2331   return 0;
2332 }
2333
2334 \f
2335
2336 /* XIM (X Input Method) handler */
2337
2338 typedef struct MInputXIMMethodInfo
2339 {
2340   Display *display;
2341   XIM xim;
2342   MSymbol language;
2343   MSymbol coding;
2344 } MInputXIMMethodInfo;
2345
2346 typedef struct MInputXIMContextInfo
2347 {
2348   XIC xic;
2349   Window win;
2350   MConverter *converter;
2351 } MInputXIMContextInfo;
2352
2353 static int
2354 xim_open_im (MInputMethod *im)
2355 {
2356   MInputXIMArgIM *arg = (MInputXIMArgIM *) im->arg;
2357   MLocale *saved, *this;
2358   char *save_modifier_list;
2359   XIM xim;
2360   MInputXIMMethodInfo *im_info;
2361
2362   saved = mlocale_set (LC_CTYPE, NULL);
2363   this = mlocale_set (LC_CTYPE, arg->locale ? arg->locale : "");
2364   if (! this)
2365     /* The specified locale is not supported.  */
2366     MERROR (MERROR_LOCALE, -1);
2367   if (mlocale_get_prop (this, Mcoding) == Mnil)
2368     {
2369       /* Unable to decode the output of XIM.  */
2370       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2371       MERROR (MERROR_LOCALE, -1);
2372     }
2373
2374   if (arg->modifier_list)
2375     save_modifier_list = XSetLocaleModifiers (arg->modifier_list);
2376   else
2377     save_modifier_list = XSetLocaleModifiers ("");
2378   if (! save_modifier_list)
2379     {
2380       /* The specified locale is not supported by X.  */
2381       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2382       MERROR (MERROR_LOCALE, -1);
2383     }
2384
2385   xim = XOpenIM (arg->display, arg->db, arg->res_name, arg->res_class);
2386   if (! xim)
2387     {
2388       /* No input method is available in the current locale.  */
2389       XSetLocaleModifiers (save_modifier_list);
2390       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2391       MERROR (MERROR_WIN, -1);
2392     }
2393
2394   MSTRUCT_MALLOC (im_info, MERROR_WIN);
2395   im_info->display = arg->display;
2396   im_info->xim = xim;
2397   im_info->language = mlocale_get_prop (this, Mlanguage);
2398   im_info->coding = mlocale_get_prop (this, Mcoding);
2399   im->info = im_info;
2400
2401   XSetLocaleModifiers (save_modifier_list);
2402   mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2403
2404   return 0;
2405 }
2406
2407 static void
2408 xim_close_im (MInputMethod *im)
2409 {
2410   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) im->info;
2411
2412   XCloseIM (im_info->xim);
2413   free (im_info);
2414 }
2415
2416 static int
2417 xim_create_ic (MInputContext *ic)
2418 {
2419   MInputXIMArgIC *arg = (MInputXIMArgIC *) ic->arg;
2420   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2421   MInputXIMContextInfo *ic_info;
2422   XIC xic;
2423
2424   if (! arg->input_style)
2425     {
2426       /* By default, use Root style.  */
2427       arg->input_style = XIMPreeditNothing | XIMStatusNothing;
2428       arg->preedit_attrs = NULL;
2429       arg->status_attrs = NULL;
2430     }
2431
2432   if (! arg->preedit_attrs && ! arg->status_attrs)
2433     xic = XCreateIC (im_info->xim,
2434                      XNInputStyle, arg->input_style,
2435                      XNClientWindow, arg->client_win,
2436                      XNFocusWindow, arg->focus_win,
2437                      NULL);
2438   else if (arg->preedit_attrs && ! arg->status_attrs)
2439     xic = XCreateIC (im_info->xim,
2440                      XNInputStyle, arg->input_style,
2441                      XNClientWindow, arg->client_win,
2442                      XNFocusWindow, arg->focus_win,
2443                      XNPreeditAttributes, arg->preedit_attrs,
2444                      NULL);
2445   else if (! arg->preedit_attrs && arg->status_attrs)
2446     xic = XCreateIC (im_info->xim,
2447                      XNInputStyle, arg->input_style,
2448                      XNClientWindow, arg->client_win,
2449                      XNFocusWindow, arg->focus_win,
2450                      XNStatusAttributes, arg->status_attrs,
2451                      NULL);
2452   else
2453     xic = XCreateIC (im_info->xim,
2454                      XNInputStyle, arg->input_style,
2455                      XNClientWindow, arg->client_win,
2456                      XNFocusWindow, arg->focus_win,
2457                      XNPreeditAttributes, arg->preedit_attrs,
2458                      XNStatusAttributes, arg->status_attrs,
2459                      NULL);
2460   if (! xic)
2461     MERROR (MERROR_WIN, -1);
2462
2463   MSTRUCT_MALLOC (ic_info, MERROR_WIN);
2464   ic_info->xic = xic;
2465   ic_info->win = arg->focus_win;
2466   ic_info->converter = mconv_buffer_converter (im_info->coding, NULL, 0);
2467   ic->info = ic_info;
2468   return 0;
2469 }
2470
2471 static void
2472 xim_destroy_ic (MInputContext *ic)
2473 {
2474   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2475
2476   XDestroyIC (ic_info->xic);
2477   mconv_free_converter (ic_info->converter);
2478   free (ic_info);
2479   ic->info = NULL;
2480 }
2481
2482 static int
2483 xim_filter (MInputContext *ic, MSymbol key, void *event)
2484 {
2485   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2486
2487   return (XFilterEvent ((XEvent *) event, ic_info->win) == True);
2488 }
2489
2490
2491 static int
2492 xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2493 {
2494   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2495   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2496   XKeyPressedEvent *ev = (XKeyPressedEvent *) arg;
2497   KeySym keysym;
2498   Status status;
2499   char *buf;
2500   int len;
2501
2502   buf = (char *) alloca (512);
2503   len = XmbLookupString (ic_info->xic, ev, buf, 512, &keysym, &status);
2504   if (status == XBufferOverflow)
2505     {
2506       buf = (char *) alloca (len);
2507       len = XmbLookupString (ic_info->xic, ev, buf, len, &keysym, &status);
2508     }
2509
2510   mtext_reset (ic->produced);
2511   if (len == 0)
2512     return 1;
2513
2514   mconv_reset_converter (ic_info->converter);
2515   mconv_rebind_buffer (ic_info->converter, (unsigned char *) buf, len);
2516   mconv_decode (ic_info->converter, ic->produced);
2517   mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2518                   Mlanguage, (void *) im_info->language);
2519   mtext_cpy (mt, ic->produced);
2520   mtext_reset (ic->produced);  
2521   return 0;
2522 }
2523
2524 \f
2525 /*=*/
2526
2527 /*** @} */
2528 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2529 \f
2530 /* External API */
2531
2532 /*** @addtogroup m17nInputMethodWin */
2533
2534 /*** @{ */
2535
2536 /***en
2537     @brief Input method driver for XIM.
2538
2539     The driver #minput_xim_driver is for the foreign input method of
2540     name #Mxim.  It uses XIM (X Input Methods) as a background input
2541     engine.
2542
2543     As the symbol #Mxim has property #Minput_driver whose value is
2544     a pointer to this driver, the input method of language #Mnil
2545     and name #Mxim uses this driver.
2546
2547     Therefore, for such input methods, the driver dependent arguments
2548     to the functions whose name begin with minput_ must be as follows.
2549
2550     The argument $ARG of the function minput_open_im () must be a
2551     pointer to the structure #MInputXIMArgIM.  See the documentation
2552     of #MInputXIMArgIM for more details.
2553
2554     The argument $ARG of the function minput_create_ic () must be a
2555     pointer to the structure #MInputXIMArgIC. See the documentation
2556     of #MInputXIMArgIC for more details.
2557
2558     The argument $ARG of the function minput_filter () must be a
2559     pointer to the structure @c XEvent.  The argument $KEY is ignored.
2560
2561     The argument $ARG of the function minput_lookup () must be the
2562     same one as that of the function minput_filter ().  The argument
2563     $KEY is ignored.  */
2564
2565 /***ja
2566     @brief XIMÍÑÆþÎϥɥ饤¥Ð.
2567
2568     ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã¥ÉÍѤǤ¢¤ê¡¢
2569     XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
2570
2571     ¥·¥ó¥Ü¥ë #Mxim ¤Ï¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥×¥í¥Ñ¥Æ¥£
2572     #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim 
2573     ¤Ç¤¢¤ëÆþÎϥ᥽¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
2574
2575     ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ 
2576     ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2577
2578     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM 
2579     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò»²¾È¡£
2580
2581     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC 
2582     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ¤ò»²¾È¡£
2583
2584     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent 
2585     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
2586
2587     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô function minput_filter () 
2588     ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì¤ë¡£  */
2589
2590 MInputDriver minput_xim_driver =
2591   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
2592     xim_filter, xim_lookup, NULL };
2593
2594 /*** @} */ 
2595
2596 #else  /* not HAVE_X11 */
2597
2598 int device_open () { return -1; }
2599
2600 #endif  /* not HAVE_X11 */
2601
2602 /*
2603   Local Variables:
2604   coding: euc-japan
2605   End:
2606 */