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