(device_open): Try at most 32 fonts to find a
[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, i;
2147     /* Try at least 32 fonts to obtain a non-autoscaled font.  */
2148     char **names = XListFonts (display, app_data.font, 32, &nfonts);
2149     MFont *font = NULL;
2150
2151     for (i = 0; ! font && i < nfonts; i++)
2152       {
2153         font = mfont_parse_name (names[i], Mx);
2154         if (!font)
2155           {
2156             /* The font name does not conform to XLFD.  Try to open the
2157                font and get XA_FONT property.  */
2158             XFontStruct *xfont = XLoadQueryFont (display, names[i]);
2159
2160             if (xfont)
2161               {
2162                 unsigned long value;
2163                 char *name;
2164
2165                 if (XGetFontProperty (xfont, XA_FONT, &value)
2166                     && (name = ((char *)
2167                                 XGetAtomName (display, (Atom) value))))
2168                   font = mfont_parse_name (name, Mx);
2169                 XFreeFont (display, xfont);
2170               }
2171           }
2172         if (font &&
2173             font->property[MFONT_SIZE] == 0 && font->property[MFONT_RESY] > 0)
2174           {
2175             free (font);
2176             font = NULL;
2177           }
2178       }
2179     if (nfonts)
2180       XFreeFontNames (names);
2181     frame->font = font ? font : mfont_parse_name (FALLBACK_FONT, Mx);
2182   }
2183
2184   face = mface_from_font (frame->font);
2185   face->property[MFACE_FONTSET] = mfontset (NULL);
2186   face->property[MFACE_FOREGROUND] = frame->foreground;
2187   face->property[MFACE_BACKGROUND] = frame->background;
2188   mface_put_prop (face, Mhline, mface_get_prop (mface__default, Mhline));
2189   mface_put_prop (face, Mbox, mface_get_prop (mface__default, Mbox));
2190   face->property[MFACE_VIDEOMODE] = frame->videomode;
2191   mface_put_prop (face, Mhook_func, 
2192                   mface_get_prop (mface__default, Mhook_func));
2193   face->property[MFACE_RATIO] = (void *) 100;
2194   mplist_push (param, Mface, face);
2195   M17N_OBJECT_UNREF (face);
2196
2197 #ifdef X_SET_ERROR_HANDLER
2198   XSetErrorHandler (x_error_handler);
2199   XSetIOErrorHandler (x_io_error_handler);
2200 #endif
2201
2202   return 0;
2203 }
2204
2205 \f
2206
2207 /* XIM (X Input Method) handler */
2208
2209 typedef struct MInputXIMMethodInfo
2210 {
2211   Display *display;
2212   XIM xim;
2213   MSymbol language;
2214   MSymbol coding;
2215 } MInputXIMMethodInfo;
2216
2217 typedef struct MInputXIMContextInfo
2218 {
2219   XIC xic;
2220   Window win;
2221   MConverter *converter;
2222 } MInputXIMContextInfo;
2223
2224 static int
2225 xim_open_im (MInputMethod *im)
2226 {
2227   MInputXIMArgIM *arg = (MInputXIMArgIM *) im->arg;
2228   MLocale *saved, *this;
2229   char *save_modifier_list;
2230   XIM xim;
2231   MInputXIMMethodInfo *im_info;
2232
2233   saved = mlocale_set (LC_CTYPE, NULL);
2234   this = mlocale_set (LC_CTYPE, arg->locale ? arg->locale : "");
2235   if (! this)
2236     /* The specified locale is not supported.  */
2237     MERROR (MERROR_LOCALE, -1);
2238   if (mlocale_get_prop (this, Mcoding) == Mnil)
2239     {
2240       /* Unable to decode the output of XIM.  */
2241       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2242       MERROR (MERROR_LOCALE, -1);
2243     }
2244
2245   if (arg->modifier_list)
2246     save_modifier_list = XSetLocaleModifiers (arg->modifier_list);
2247   else
2248     save_modifier_list = XSetLocaleModifiers ("");
2249   if (! save_modifier_list)
2250     {
2251       /* The specified locale is not supported by X.  */
2252       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2253       MERROR (MERROR_LOCALE, -1);
2254     }
2255
2256   xim = XOpenIM (arg->display, arg->db, arg->res_name, arg->res_class);
2257   if (! xim)
2258     {
2259       /* No input method is available in the current locale.  */
2260       XSetLocaleModifiers (save_modifier_list);
2261       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2262       MERROR (MERROR_WIN, -1);
2263     }
2264
2265   MSTRUCT_MALLOC (im_info, MERROR_WIN);
2266   im_info->display = arg->display;
2267   im_info->xim = xim;
2268   im_info->language = mlocale_get_prop (this, Mlanguage);
2269   im_info->coding = mlocale_get_prop (this, Mcoding);
2270   im->info = im_info;
2271
2272   XSetLocaleModifiers (save_modifier_list);
2273   mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2274
2275   return 0;
2276 }
2277
2278 static void
2279 xim_close_im (MInputMethod *im)
2280 {
2281   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) im->info;
2282
2283   XCloseIM (im_info->xim);
2284   free (im_info);
2285 }
2286
2287 static int
2288 xim_create_ic (MInputContext *ic)
2289 {
2290   MInputXIMArgIC *arg = (MInputXIMArgIC *) ic->arg;
2291   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2292   MInputXIMContextInfo *ic_info;
2293   XIC xic;
2294
2295   if (! arg->input_style)
2296     {
2297       /* By default, use Root style.  */
2298       arg->input_style = XIMPreeditNothing | XIMStatusNothing;
2299       arg->preedit_attrs = NULL;
2300       arg->status_attrs = NULL;
2301     }
2302
2303   if (! arg->preedit_attrs && ! arg->status_attrs)
2304     xic = XCreateIC (im_info->xim,
2305                      XNInputStyle, arg->input_style,
2306                      XNClientWindow, arg->client_win,
2307                      XNFocusWindow, arg->focus_win,
2308                      NULL);
2309   else if (arg->preedit_attrs && ! arg->status_attrs)
2310     xic = XCreateIC (im_info->xim,
2311                      XNInputStyle, arg->input_style,
2312                      XNClientWindow, arg->client_win,
2313                      XNFocusWindow, arg->focus_win,
2314                      XNPreeditAttributes, arg->preedit_attrs,
2315                      NULL);
2316   else if (! arg->preedit_attrs && arg->status_attrs)
2317     xic = XCreateIC (im_info->xim,
2318                      XNInputStyle, arg->input_style,
2319                      XNClientWindow, arg->client_win,
2320                      XNFocusWindow, arg->focus_win,
2321                      XNStatusAttributes, arg->status_attrs,
2322                      NULL);
2323   else
2324     xic = XCreateIC (im_info->xim,
2325                      XNInputStyle, arg->input_style,
2326                      XNClientWindow, arg->client_win,
2327                      XNFocusWindow, arg->focus_win,
2328                      XNPreeditAttributes, arg->preedit_attrs,
2329                      XNStatusAttributes, arg->status_attrs,
2330                      NULL);
2331   if (! xic)
2332     MERROR (MERROR_WIN, -1);
2333
2334   MSTRUCT_MALLOC (ic_info, MERROR_WIN);
2335   ic_info->xic = xic;
2336   ic_info->win = arg->focus_win;
2337   ic_info->converter = mconv_buffer_converter (im_info->coding, NULL, 0);
2338   ic->info = ic_info;
2339   return 0;
2340 }
2341
2342 static void
2343 xim_destroy_ic (MInputContext *ic)
2344 {
2345   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2346
2347   XDestroyIC (ic_info->xic);
2348   mconv_free_converter (ic_info->converter);
2349   free (ic_info);
2350   ic->info = NULL;
2351 }
2352
2353 static int
2354 xim_filter (MInputContext *ic, MSymbol key, void *event)
2355 {
2356   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2357
2358   return (XFilterEvent ((XEvent *) event, ic_info->win) == True);
2359 }
2360
2361
2362 static int
2363 xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2364 {
2365   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2366   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2367   XKeyPressedEvent *ev = (XKeyPressedEvent *) arg;
2368   KeySym keysym;
2369   Status status;
2370   char *buf;
2371   int len;
2372
2373   buf = (char *) alloca (512);
2374   len = XmbLookupString (ic_info->xic, ev, buf, 512, &keysym, &status);
2375   if (status == XBufferOverflow)
2376     {
2377       buf = (char *) alloca (len);
2378       len = XmbLookupString (ic_info->xic, ev, buf, len, &keysym, &status);
2379     }
2380
2381   mtext_reset (ic->produced);
2382   if (len == 0)
2383     return 1;
2384
2385   mconv_reset_converter (ic_info->converter);
2386   mconv_rebind_buffer (ic_info->converter, (unsigned char *) buf, len);
2387   mconv_decode (ic_info->converter, ic->produced);
2388   mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2389                   Mlanguage, (void *) im_info->language);
2390   mtext_cpy (mt, ic->produced);
2391   mtext_reset (ic->produced);  
2392   return 0;
2393 }
2394
2395 \f
2396
2397 #ifdef X_SET_ERROR_HANDLER
2398 static int
2399 x_error_handler (Display *display, XErrorEvent *error)
2400 {
2401   mdebug_hook ();
2402   return 0;
2403 }
2404
2405 static int
2406 x_io_error_handler (Display *display)
2407 {
2408   mdebug_hook ();
2409   return 0;
2410 }
2411 #endif
2412
2413 /*=*/
2414
2415 /*** @} */
2416 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2417 \f
2418 /* External API */
2419
2420 /*** @addtogroup m17nInputMethodWin */
2421 /*=*/
2422 /*** @{ */
2423
2424 /***en
2425     @brief Input method driver for XIM.
2426
2427     The driver #minput_xim_driver is for the foreign input method of
2428     name #Mxim.  It uses XIM (X Input Methods) as a background input
2429     engine.
2430
2431     As the symbol #Mxim has property #Minput_driver whose value is
2432     a pointer to this driver, the input method of language #Mnil
2433     and name #Mxim uses this driver.
2434
2435     Therefore, for such input methods, the driver dependent arguments
2436     to the functions whose name begin with minput_ must be as follows.
2437
2438     The argument $ARG of the function minput_open_im () must be a
2439     pointer to the structure #MInputXIMArgIM.  See the documentation
2440     of #MInputXIMArgIM for more details.
2441
2442     The argument $ARG of the function minput_create_ic () must be a
2443     pointer to the structure #MInputXIMArgIC. See the documentation
2444     of #MInputXIMArgIC for more details.
2445
2446     The argument $ARG of the function minput_filter () must be a
2447     pointer to the structure @c XEvent.  The argument $KEY is ignored.
2448
2449     The argument $ARG of the function minput_lookup () must be the
2450     same one as that of the function minput_filter ().  The argument
2451     $KEY is ignored.  */
2452
2453 /***ja
2454     @brief XIMÍÑÆþÎϥɥ饤¥Ð.
2455
2456     ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã
2457     ¥ÉÍѤǤ¢¤ê¡¢ XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸
2458     ¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
2459
2460     ¥·¥ó¥Ü¥ë #Mxim ¤Ï¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥×¥í¥Ñ¥Æ¥£
2461     #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim ¤Ç¤¢¤ëÆþÎÏ
2462     ¥á¥½¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
2463
2464     ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø
2465     ¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2466
2467     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM ¤Ø¤Î¥Ý
2468     ¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò
2469     »²¾È¡£
2470
2471     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC ¤Ø¤Î
2472     ¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ
2473     ¤ò»²¾È¡£
2474
2475     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent ¤Ø¤Î¥Ý¥¤¥ó¥¿
2476     ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
2477
2478     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô function minput_filter () 
2479     ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì
2480     ¤ë¡£  */
2481
2482 MInputDriver minput_xim_driver =
2483   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
2484     xim_filter, xim_lookup, NULL };
2485
2486 /*** @} */ 
2487
2488 /*
2489   Local Variables:
2490   coding: euc-japan
2491   End:
2492 */