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