*** empty log message ***
[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   MWDevice *device = FRAME_DEVICE (frame);
1216
1217   M17N_OBJECT_UNREF (device);
1218 }
1219
1220 static void *
1221 mwin__device_get_prop (MFrame *frame, MSymbol key)
1222 {
1223   MWDevice *device = FRAME_DEVICE (frame);
1224
1225   if (key == Mdisplay)
1226     return (void *) device->display_info->display;
1227   if (key == Mscreen)
1228     return (void *) ScreenOfDisplay(device->display_info->display,
1229                                     device->screen_num);
1230   if (key == Mcolormap)
1231     return (void *) device->cmap;
1232   if (key == Mdepth)
1233     return (void *) device->depth;
1234   return NULL;
1235 }
1236
1237 static void
1238 mwin__realize_face (MRealizedFace *rface)
1239 {
1240   MFrame *frame;
1241   MSymbol foreground, background, videomode;
1242   MFaceHLineProp *hline;
1243   MFaceBoxProp *box;
1244   GCInfo *info;
1245
1246   if (rface != rface->ascii_rface)
1247     {
1248       rface->info = rface->ascii_rface->info;
1249       return;
1250     }
1251
1252   frame = rface->frame;
1253   MSTRUCT_CALLOC (info, MERROR_WIN);
1254
1255   foreground = rface->face.property[MFACE_FOREGROUND];
1256   background = rface->face.property[MFACE_BACKGROUND];
1257   videomode = rface->face.property[MFACE_VIDEOMODE];
1258   if (! videomode)
1259     videomode = frame->videomode;
1260   if (videomode != Mreverse)
1261     {
1262       info->gc[GC_NORMAL] = get_gc (frame, foreground, 1, &info->rgb_fore);
1263       info->gc[GC_INVERSE] = get_gc (frame, background, 0, &info->rgb_back);
1264     }
1265   else
1266     {
1267       info->gc[GC_NORMAL] = get_gc (frame, background, 0, &info->rgb_fore);
1268       info->gc[GC_INVERSE] = get_gc (frame, foreground, 1, &info->rgb_back);
1269     }
1270 #ifdef HAVE_XFT2
1271   if (foreground == Mnil)
1272     foreground = frame->foreground;
1273   if (background == Mnil)
1274     background = frame->background;
1275   if (videomode == Mreverse)
1276     {
1277       MSymbol temp = foreground;
1278       foreground = background;
1279       background = temp;
1280     }
1281   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1282                            FRAME_VISUAL (frame),
1283                            FRAME_CMAP (frame),
1284                            MSYMBOL_NAME (foreground),
1285                            &info->xft_color_fore))
1286     mdebug_hook ();
1287   if (! XftColorAllocName (FRAME_DISPLAY (frame),
1288                            FRAME_VISUAL (frame),
1289                            FRAME_CMAP (frame),
1290                            MSYMBOL_NAME (background),
1291                            &info->xft_color_back))
1292     mdebug_hook ();
1293 #endif
1294
1295   hline = rface->hline;
1296   if (hline)
1297     {
1298       if (hline->color)
1299         info->gc[GC_HLINE] = get_gc (frame, hline->color, 1, NULL);
1300       else
1301         info->gc[GC_HLINE] = info->gc[GC_NORMAL];
1302     }
1303
1304   box = rface->box;
1305   if (box)
1306     {
1307       if (box->color_top)
1308         info->gc[GC_BOX_TOP] = get_gc (frame, box->color_top, 1, NULL);
1309       else
1310         info->gc[GC_BOX_TOP] = info->gc[GC_NORMAL];
1311
1312       if (box->color_left && box->color_left != box->color_top)
1313         info->gc[GC_BOX_LEFT] = get_gc (frame, box->color_left, 1, NULL);
1314       else
1315         info->gc[GC_BOX_LEFT] = info->gc[GC_BOX_TOP];
1316
1317       if (box->color_bottom && box->color_bottom != box->color_top)
1318         info->gc[GC_BOX_BOTTOM] = get_gc (frame, box->color_bottom, 1, NULL);
1319       else
1320         info->gc[GC_BOX_BOTTOM] = info->gc[GC_BOX_TOP];
1321
1322       if (box->color_right && box->color_right != box->color_bottom)
1323         info->gc[GC_BOX_RIGHT] = get_gc (frame, box->color_right, 1, NULL);
1324       else
1325         info->gc[GC_BOX_RIGHT] = info->gc[GC_BOX_BOTTOM];
1326     }
1327
1328   rface->info = info;
1329 }
1330
1331
1332 static void
1333 mwin__free_realized_face (MRealizedFace *rface)
1334 {
1335   if (rface == rface->ascii_rface)
1336     free (rface->info);
1337 }
1338
1339
1340 static void
1341 mwin__fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1342                   int reverse,
1343                   int x, int y, int width, int height, MDrawRegion region)
1344 {
1345   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_NORMAL : GC_INVERSE];
1346
1347   if (region)
1348     gc = set_region (frame, gc, region);
1349
1350   XFillRectangle (FRAME_DISPLAY (frame), (Window) win, gc,
1351                   x, y, width, height);
1352 }
1353
1354
1355 static void
1356 mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
1357                         MGlyphString *gstring, MGlyph *from, MGlyph *to,
1358                         int reverse, MDrawRegion region)
1359 {
1360   MRealizedFace *rface = from->rface;
1361   Display *display = FRAME_DISPLAY (rface->frame);
1362   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1363
1364   if (from == to)
1365     return;
1366
1367   if (region)
1368     gc = set_region (rface->frame, gc, region);
1369   for (; from < to; from++)
1370     {
1371       XDrawRectangle (display, (Window) win, gc,
1372                       x, y - gstring->ascent + 1, from->width - 1,
1373                       gstring->ascent + gstring->descent - 2);
1374       x += from->width;
1375     }
1376 }
1377
1378
1379 static void
1380 mwin__draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1381                  MRealizedFace *rface, int reverse,
1382                  int x, int y, int width, MDrawRegion region)
1383 {
1384   enum MFaceHLineType type = rface->hline->type;
1385   GCInfo *info = rface->info;
1386   GC gc = gc = info->gc[GC_HLINE];
1387   int i;
1388
1389   y = (type == MFACE_HLINE_BOTTOM
1390        ? y + gstring->text_descent - rface->hline->width
1391        : type == MFACE_HLINE_UNDER
1392        ? y + 1
1393        : type == MFACE_HLINE_STRIKE_THROUGH
1394        ? y - ((gstring->ascent + gstring->descent) / 2)
1395        : y - gstring->text_ascent);
1396   if (region)
1397     gc = set_region (frame, gc, region);
1398
1399   for (i = 0; i < rface->hline->width; i++)
1400     XDrawLine (FRAME_DISPLAY (frame), (Window) win, gc,
1401                x, y + i, x + width - 1, y + i);
1402 }
1403
1404
1405 static void
1406 mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
1407                 MGlyph *g, int x, int y, int width, MDrawRegion region)
1408 {
1409   Display *display = FRAME_DISPLAY (frame);
1410   MRealizedFace *rface = g->rface;
1411   MFaceBoxProp *box = rface->box;
1412   GCInfo *info = rface->info;
1413   GC gc_top, gc_left, gc_right, gc_btm;
1414   int y0, y1;
1415   int i;
1416
1417   y0 = y - (gstring->text_ascent
1418             + rface->box->inner_vmargin + rface->box->width);
1419   y1 = y + (gstring->text_descent
1420             + rface->box->inner_vmargin + rface->box->width - 1);
1421
1422   gc_top = info->gc[GC_BOX_TOP];
1423   if (region)
1424     gc_top = set_region (frame, gc_top, region);
1425   if (info->gc[GC_BOX_TOP] == info->gc[GC_BOX_BOTTOM])
1426     gc_btm = gc_top;
1427   else
1428     gc_btm = info->gc[GC_BOX_BOTTOM];
1429
1430   if (g->type == GLYPH_BOX)
1431     {
1432       int x0, x1;
1433
1434       if (g->left_padding)
1435         x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
1436       else
1437         x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
1438
1439       /* Draw the top side.  */
1440       for (i = 0; i < box->width; i++)
1441         XDrawLine (display, (Window) win, gc_top, x0, y0 + i, x1, y0 + i);
1442
1443       /* Draw the bottom side.  */
1444       if (region && gc_btm != gc_top)
1445         gc_btm = set_region (frame, gc_btm, region);
1446       for (i = 0; i < box->width; i++)
1447         XDrawLine (display, (Window) win, gc_btm, x0, y1 - i, x1, y1 - i);
1448
1449       if (g->left_padding > 0)
1450         {
1451           /* Draw the left side.  */
1452           if (info->gc[GC_BOX_LEFT] == info->gc[GC_BOX_TOP])
1453             gc_left = gc_top;
1454           else
1455             {
1456               gc_left = info->gc[GC_BOX_LEFT];
1457               if (region)
1458                 gc_left = set_region (frame, gc_left, region);
1459             }
1460           for (i = 0; i < rface->box->width; i++)
1461             XDrawLine (display, (Window) win, gc_left,
1462                        x0 + i, y0 + i, x0 + i, y1 - i);
1463         }
1464       else
1465         {
1466           /* Draw the right side.  */
1467           if (info->gc[GC_BOX_RIGHT] == info->gc[GC_BOX_TOP])
1468             gc_right = gc_top;
1469           else
1470             {
1471               gc_right = info->gc[GC_BOX_RIGHT];
1472               if (region)
1473                 gc_right = set_region (frame, gc_right, region);
1474             }
1475           for (i = 0; i < rface->box->width; i++)
1476             XDrawLine (display, (Window) win, gc_right,
1477                        x1 - i, y0 + i, x1 - i, y1 - i);
1478         }
1479     }
1480   else
1481     {
1482       /* Draw the top side.  */
1483       for (i = 0; i < box->width; i++)
1484         XDrawLine (display, (Window) win, gc_top,
1485                    x, y0 + i, x + width - 1, y0 + i);
1486
1487       /* Draw the bottom side.  */
1488       if (region && gc_btm != gc_top)
1489         gc_btm = set_region (frame, gc_btm, region);
1490       for (i = 0; i < box->width; i++)
1491         XDrawLine (display, (Window) win, gc_btm,
1492                    x, y1 - i, x + width - 1, y1 - i);
1493     }
1494 }
1495
1496
1497 #if 0
1498 static void
1499 mwin__draw_bitmap (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1500                    int reverse, int x, int y,
1501                    int width, int height, int row_bytes, unsigned char *bmp,
1502                    MDrawRegion region)
1503 {
1504   Display *display = FRAME_DISPLAY (frame);
1505   int i, j;
1506   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
1507
1508   if (region)
1509     gc = set_region (frame, gc, region);
1510
1511   for (i = 0; i < height; i++, bmp += row_bytes)
1512     for (j = 0; j < width; j++)
1513       if (bmp[j / 8] & (1 << (7 - (j % 8))))
1514         XDrawPoint (display, (Window) win, gc, x + j, y + i);
1515 }
1516 #endif
1517
1518 static void
1519 mwin__draw_points (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
1520                    int intensity, MDrawPoint *points, int num,
1521                    MDrawRegion region)
1522 {
1523   GCInfo *info = rface->info;
1524   GC gc;
1525
1526   if (! (gc = info->gc[intensity]))
1527     gc = info->gc[intensity] = get_gc_for_anti_alias (FRAME_DEVICE (frame),
1528                                                       info, intensity);
1529   if (region)
1530     gc = set_region (frame, gc, region);
1531
1532   XDrawPoints (FRAME_DISPLAY (frame), (Window) win, gc,
1533                (XPoint *) points, num, CoordModeOrigin);
1534 }
1535
1536
1537 static MDrawRegion
1538 mwin__region_from_rect (MDrawMetric *rect)
1539 {
1540   MDrawRegion region1 = XCreateRegion ();
1541   MDrawRegion region2 = XCreateRegion ();
1542   XRectangle xrect;
1543
1544   xrect.x = rect->x;
1545   xrect.y = rect->y;
1546   xrect.width = rect->width;
1547   xrect.height = rect->height;
1548   XUnionRectWithRegion (&xrect, region1, region2);
1549   XDestroyRegion (region1);
1550   return region2;
1551 }
1552
1553 static void
1554 mwin__union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
1555 {
1556   MDrawRegion region1 = XCreateRegion ();
1557   XRectangle xrect;
1558
1559   xrect.x = rect->x;
1560   xrect.y = rect->y;
1561   xrect.width = rect->width;
1562   xrect.height = rect->height;
1563
1564   XUnionRegion (region, region, region1);
1565   XUnionRectWithRegion (&xrect, region1, region);
1566   XDestroyRegion (region1);
1567 }
1568
1569 static void
1570 mwin__intersect_region (MDrawRegion region1, MDrawRegion region2)
1571 {
1572   MDrawRegion region = XCreateRegion ();
1573
1574   XUnionRegion (region1, region1, region);
1575   XIntersectRegion (region, region2, region1);
1576   XDestroyRegion (region);
1577 }
1578
1579 static void
1580 mwin__region_add_rect (MDrawRegion region, MDrawMetric *rect)
1581 {
1582   MDrawRegion region1 = XCreateRegion ();
1583   XRectangle xrect;
1584
1585   xrect.x = rect->x;
1586   xrect.y = rect->y;
1587   xrect.width = rect->width;
1588   xrect.height = rect->height;
1589   XUnionRectWithRegion (&xrect, region1, region);
1590   XDestroyRegion (region1);
1591 }
1592
1593 static void
1594 mwin__region_to_rect (MDrawRegion region, MDrawMetric *rect)
1595 {
1596   XRectangle xrect;
1597
1598   XClipBox (region, &xrect);
1599   rect->x = xrect.x;
1600   rect->y = xrect.y;
1601   rect->width = xrect.width;
1602   rect->height = xrect.height;
1603 }
1604
1605 static void
1606 mwin__free_region (MDrawRegion region)
1607 {
1608   XDestroyRegion (region);
1609 }
1610
1611 static void
1612 mwin__dump_region (MDrawRegion region)
1613 {
1614   XRectangle rect;
1615   XClipBox (region, &rect);
1616   fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
1617 }
1618
1619
1620 static MDrawWindow
1621 mwin__create_window (MFrame *frame, MDrawWindow parent)
1622 {
1623   Display *display = FRAME_DISPLAY (frame);
1624   Window win;
1625   XWMHints wm_hints = { InputHint, False };
1626   XClassHint class_hints = { "M17N-IM", "m17n-im" };
1627   XSetWindowAttributes set_attrs;
1628   unsigned long mask;
1629   XGCValues values;
1630   GCInfo *info = frame->rface->info;
1631
1632   if (! parent)
1633     parent = (MDrawWindow) RootWindow (display, FRAME_SCREEN (frame));
1634   mask = GCForeground;
1635   XGetGCValues (display, info->gc[GC_INVERSE], mask, &values);
1636   set_attrs.background_pixel = values.foreground;
1637   set_attrs.backing_store = Always;
1638   set_attrs.override_redirect = True;
1639   set_attrs.save_under = True;
1640   mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWSaveUnder;
1641   win = XCreateWindow (display, (Window) parent, 0, 0, 1, 1, 0,
1642                        CopyFromParent, InputOutput, CopyFromParent,
1643                        mask, &set_attrs);
1644   XSetWMProperties (display, (Window) win, NULL, NULL, NULL, 0,
1645                     NULL, &wm_hints, &class_hints);
1646   XSelectInput (display, (Window) win, StructureNotifyMask | ExposureMask);
1647   return (MDrawWindow) win;
1648 }
1649
1650 static void
1651 mwin__destroy_window (MFrame *frame, MDrawWindow win)
1652 {
1653   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
1654 }
1655
1656 #if 0
1657 static MDrawWindow
1658 mwin__event_window (void *event)
1659 {
1660   return ((MDrawWindow) ((XEvent *) event)->xany.window);
1661 }
1662
1663 static void
1664 mwin__print_event (void *arg, char *win_name)
1665 {
1666   char *event_name;
1667   XEvent *event = (XEvent *) arg;
1668
1669   switch (event->xany.type)
1670     {
1671     case 2: event_name = "KeyPress"; break;
1672     case 3: event_name = "KeyRelease"; break;
1673     case 4: event_name = "ButtonPress"; break;
1674     case 5: event_name = "ButtonRelease"; break;
1675     case 6: event_name = "MotionNotify"; break;
1676     case 7: event_name = "EnterNotify"; break;
1677     case 8: event_name = "LeaveNotify"; break;
1678     case 9: event_name = "FocusIn"; break;
1679     case 10: event_name = "FocusOut"; break;
1680     case 11: event_name = "KeymapNotify"; break;
1681     case 12: event_name = "Expose"; break;
1682     case 13: event_name = "GraphicsExpose"; break;
1683     case 14: event_name = "NoExpose"; break;
1684     case 15: event_name = "VisibilityNotify"; break;
1685     case 16: event_name = "CreateNotify"; break;
1686     case 17: event_name = "DestroyNotify"; break;
1687     case 18: event_name = "UnmapNotify"; break;
1688     case 19: event_name = "MapNotify"; break;
1689     case 20: event_name = "MapRequest"; break;
1690     case 21: event_name = "ReparentNotify"; break;
1691     case 22: event_name = "ConfigureNotify"; break;
1692     case 23: event_name = "ConfigureRequest"; break;
1693     case 24: event_name = "GravityNotify"; break;
1694     case 25: event_name = "ResizeRequest"; break;
1695     case 26: event_name = "CirculateNotify"; break;
1696     case 27: event_name = "CirculateRequest"; break;
1697     case 28: event_name = "PropertyNotify"; break;
1698     case 29: event_name = "SelectionClear"; break;
1699     case 30: event_name = "SelectionRequest"; break;
1700     case 31: event_name = "SelectionNotify"; break;
1701     case 32: event_name = "ColormapNotify"; break;
1702     case 33: event_name = "ClientMessage"; break;
1703     case 34: event_name = "MappingNotify"; break;
1704     default: event_name = "unknown";
1705     }
1706
1707   fprintf (stderr, "%s: %s\n", win_name, event_name);
1708 }
1709 #endif
1710
1711 static void
1712 mwin__map_window (MFrame *frame, MDrawWindow win)
1713 {
1714   XMapRaised (FRAME_DISPLAY (frame), (Window) win);
1715 }
1716
1717 static void
1718 mwin__unmap_window (MFrame *frame, MDrawWindow win)
1719 {
1720   XUnmapWindow (FRAME_DISPLAY (frame), (Window) win);
1721 }
1722
1723 static void
1724 mwin__window_geometry (MFrame *frame, MDrawWindow win, MDrawWindow parent_win,
1725                        MDrawMetric *geometry)
1726 {
1727   Display *display = FRAME_DISPLAY (frame);
1728   XWindowAttributes attr;
1729   Window parent = (Window) parent_win, root;
1730
1731   XGetWindowAttributes (display, (Window) win, &attr);
1732   geometry->x = attr.x + attr.border_width;
1733   geometry->y = attr.y + attr.border_width;
1734   geometry->width = attr.width;
1735   geometry->height = attr.height; 
1736
1737   if (! parent)
1738     parent = RootWindow (display, FRAME_SCREEN (frame));
1739   while (1)
1740     {
1741       Window this_parent, *children;
1742       unsigned n;
1743
1744       XQueryTree (display, (Window) win, &root, &this_parent, &children, &n);
1745       if (children)
1746         XFree (children);
1747       if (this_parent == parent || this_parent == root)
1748         break;
1749       win = (MDrawWindow) this_parent;
1750       XGetWindowAttributes (display, (Window) win, &attr);
1751       geometry->x += attr.x + attr.border_width;
1752       geometry->y += attr.y + attr.border_width;
1753     }
1754 }
1755
1756 static void
1757 mwin__adjust_window (MFrame *frame, MDrawWindow win,
1758                      MDrawMetric *current, MDrawMetric *new)
1759 {
1760   Display *display = FRAME_DISPLAY (frame);
1761   unsigned int mask = 0;
1762   XWindowChanges values;
1763
1764   if (current->width != new->width)
1765     {
1766       mask |= CWWidth;
1767       if (new->width <= 0)
1768         new->width = 1;
1769       values.width = current->width = new->width;
1770     }
1771   if (current->height != new->height)
1772     {
1773       mask |= CWHeight;
1774       if (new->height <= 0)
1775         new->height = 1;
1776       values.height = current->height = new->height;
1777     }
1778   if (current->x != new->x)
1779     {
1780       mask |= CWX;
1781       values.x = current->x = new->x;
1782     }
1783   if (current->y != new->y)
1784     {
1785       mask |= CWY;
1786       current->y = new->y;
1787       values.y = current->y = new->y;
1788     }
1789   if (mask)
1790     XConfigureWindow (display, (Window) win, mask, &values);
1791   XClearWindow (display, (Window) win);
1792 }
1793
1794 static MSymbol
1795 mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
1796 {
1797   XEvent *event = (XEvent *) arg;
1798   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
1799   int len;
1800   char buf[512];
1801   KeySym keysym;
1802   MSymbol key = Mnil;
1803
1804   *modifiers = 0;
1805   if (event->xany.type != KeyPress
1806       /* && event->xany.type != KeyRelease */
1807       )
1808     return Mnil;
1809   len = XLookupString ((XKeyEvent *) event, (char *) buf, 512, &keysym, NULL);
1810   if (len > 1)
1811     return Mnil;
1812   if (len == 1)
1813     {
1814       int c = keysym;
1815
1816       if (c < XK_space || c > XK_asciitilde)
1817         c = buf[0];
1818       if ((c == ' ' || c == 127) && ((XKeyEvent *) event)->state & ShiftMask)
1819         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1820       if (((XKeyEvent *) event)->state & ControlMask)
1821         {
1822           if (c >= 'a' && c <= 'z')
1823             c += 'A' - 'a';
1824           if (c >= ' ' && c < 127)
1825             *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1826         }
1827       key = minput__char_to_key (c);
1828     }
1829   else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
1830     return Mnil;
1831   if (key == Mnil)
1832     {
1833       char *str = XKeysymToString (keysym);
1834
1835       if (! str)
1836         return Mnil;
1837       key = msymbol (str);
1838       if (((XKeyEvent *) event)->state & ShiftMask)
1839         *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
1840       if (((XKeyEvent *) event)->state & ControlMask)
1841         *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
1842     }
1843   if (((XKeyEvent *) event)->state & disp_info->meta_mask)
1844     *modifiers |= MINPUT_KEY_META_MODIFIER;
1845   if (((XKeyEvent *) event)->state & disp_info->alt_mask)
1846     *modifiers |= MINPUT_KEY_ALT_MODIFIER;
1847   if (((XKeyEvent *) event)->state & disp_info->super_mask)
1848     *modifiers |= MINPUT_KEY_SUPER_MODIFIER;
1849   if (((XKeyEvent *) event)->state & disp_info->hyper_mask)
1850     *modifiers |= MINPUT_KEY_HYPER_MODIFIER;
1851
1852   return key;
1853 }
1854
1855
1856 void
1857 mwin__dump_gc (MFrame *frame, MRealizedFace *rface)
1858 {
1859   unsigned long valuemask = GCForeground | GCBackground | GCClipMask;
1860   XGCValues values;
1861   Display *display = FRAME_DISPLAY (frame);
1862   GCInfo *info = rface->info;
1863   int i;
1864
1865   for (i = 0; i <= GC_INVERSE; i++)
1866     {
1867       XGetGCValues (display, info->gc[i], valuemask, &values);
1868       fprintf (stderr, "GC%d: fore/#%lX back/#%lX", i,
1869                values.foreground, values.background);
1870       fprintf (stderr, "\n");
1871     }
1872 }
1873
1874 static MDeviceDriver x_driver =
1875   {
1876     mwin__close_device,
1877     mwin__device_get_prop,
1878     mwin__realize_face,
1879     mwin__free_realized_face,
1880     mwin__fill_space,
1881     mwin__draw_empty_boxes,
1882     mwin__draw_hline,
1883     mwin__draw_box,
1884     mwin__draw_points,
1885     mwin__region_from_rect,
1886     mwin__union_rect_with_region,
1887     mwin__intersect_region,
1888     mwin__region_add_rect,
1889     mwin__region_to_rect,
1890     mwin__free_region,
1891     mwin__dump_region,
1892     mwin__create_window,
1893     mwin__destroy_window,
1894     mwin__map_window,
1895     mwin__unmap_window,
1896     mwin__window_geometry,
1897     mwin__adjust_window,
1898     mwin__parse_event
1899   };
1900
1901 /* Functions to be stored in MDeviceLibraryInterface by dlsym ().  */
1902
1903 int
1904 device_init ()
1905 {
1906   M_iso8859_1 = msymbol ("iso8859-1");
1907   M_iso10646_1 = msymbol ("iso10646-1");
1908
1909   display_info_list = mplist ();
1910   device_list = mplist ();
1911
1912 #ifdef HAVE_XFT2
1913   xft_driver.select = mfont__ft_driver.select;
1914   xft_driver.encode_char = mfont__ft_driver.encode_char;
1915   xft_driver.list = mfont__ft_driver.list;
1916 #endif
1917
1918   Mxim = msymbol ("xim");
1919   msymbol_put (Mxim, Minput_driver, &minput_xim_driver);
1920
1921   return 0;
1922 }
1923
1924 int
1925 device_fini ()
1926 {
1927   M17N_OBJECT_UNREF (display_info_list);
1928   M17N_OBJECT_UNREF (device_list);
1929   return 0;
1930 }
1931
1932 /** Return an MWDevice object corresponding to a display specified in
1933     PLIST.
1934
1935     It searches device_list for a device matching the display.  If
1936     found, return the found object.  Otherwise, return a newly created
1937     object.  */
1938
1939 int
1940 device_open (MFrame *frame, MPlist *param)
1941 {
1942   Display *display = NULL;
1943   Screen *screen = NULL;
1944   int screen_num;
1945   Drawable drawable = 0;
1946   Widget widget = NULL;
1947   Colormap cmap = 0;
1948   int auto_display = 0;
1949   MDisplayInfo *disp_info = NULL;
1950   MWDevice *device = NULL;
1951   MSymbol key;
1952   XWindowAttributes attr;
1953   unsigned depth = 0;
1954   MPlist *plist;
1955   AppData app_data;
1956   MFace *face;
1957   int use_xfont = 0, use_freetype = 0, use_xft = 0;
1958
1959   for (plist = param; (key = mplist_key (plist)) != Mnil;
1960        plist = mplist_next (plist))
1961     {
1962       if (key == Mdisplay)
1963         display = (Display *) mplist_value (plist);
1964       else if (key == Mscreen)
1965         screen = mplist_value (plist);
1966       else if (key == Mdrawable)
1967         drawable = (Drawable) mplist_value (plist);
1968       else if (key == Mdepth)
1969         depth = (unsigned) mplist_value (plist);
1970       else if (key == Mwidget)
1971         widget = (Widget) mplist_value (plist);
1972       else if (key == Mcolormap)
1973         cmap = (Colormap) mplist_value (plist);
1974       else if (key == Mfont)
1975         {
1976           MSymbol val = MPLIST_SYMBOL (plist);
1977
1978           if (val == Mx)
1979             use_xfont = 1;
1980 #ifdef HAVE_FREETYPE
1981           else if (val == Mfreetype)
1982             use_freetype = 1;
1983 #ifdef HAVE_XFT2
1984           else if (val == Mxft)
1985             use_xft = 1;
1986 #endif
1987 #endif
1988         }
1989     }
1990
1991   /* If none of them is specified, use all of them.  */
1992   if (! use_xfont && ! use_freetype && ! use_xft)
1993     use_xfont = use_freetype = use_xft = 1;
1994
1995   if (widget)
1996     {
1997       display = XtDisplay (widget);
1998       screen_num = XScreenNumberOfScreen (XtScreen (widget));
1999       depth = DefaultDepth (display, screen_num);
2000     }
2001   else if (drawable)
2002     {
2003       Window root_window;
2004       int x, y;
2005       unsigned width, height, border_width;
2006
2007       if (! display)
2008         MERROR (MERROR_WIN, -1);
2009       XGetGeometry (display, drawable, &root_window,
2010                     &x, &y, &width, &height, &border_width, &depth);
2011       XGetWindowAttributes (display, root_window, &attr);
2012       screen_num = XScreenNumberOfScreen (attr.screen);
2013     }
2014   else
2015     {
2016       if (screen)
2017         display = DisplayOfScreen (screen);
2018       else
2019         {
2020           if (! display)
2021             {
2022               display = XOpenDisplay (NULL);
2023               if (! display)
2024                 MERROR (MERROR_WIN, -1);
2025               auto_display = 1;
2026             }
2027           screen = DefaultScreenOfDisplay (display);
2028         }
2029       screen_num = XScreenNumberOfScreen (screen);
2030       if (! depth)
2031         depth = DefaultDepth (display, screen_num);
2032     }
2033
2034   if (! cmap)
2035     cmap = DefaultColormap (display, screen_num);
2036
2037   for (plist = display_info_list; mplist_key (plist) != Mnil;
2038        plist = mplist_next (plist))
2039     {
2040       disp_info = (MDisplayInfo *) mplist_value (plist);
2041       if (disp_info->display == display)
2042         break;
2043     }
2044
2045   if (mplist_key (plist) != Mnil)
2046     M17N_OBJECT_REF (disp_info);
2047   else
2048     {
2049       M17N_OBJECT (disp_info, free_display_info, MERROR_WIN);
2050       disp_info->display = display;
2051       disp_info->auto_display = auto_display;
2052       disp_info->font_list = mplist ();
2053       disp_info->base_font_list = mplist ();
2054       find_modifier_bits (disp_info);
2055       mplist_add (display_info_list, Mt, disp_info);
2056     }  
2057
2058   for (plist = device_list; mplist_key (plist) != Mnil;
2059        plist = mplist_next (plist))
2060     {
2061       device = (MWDevice *) mplist_value (plist);
2062       if (device->display_info == disp_info
2063           && device->depth == depth
2064           && device->cmap == cmap)
2065         break;
2066     }
2067
2068   if (mplist_key (plist) != Mnil)
2069     M17N_OBJECT_REF (device);
2070   else
2071     {
2072       unsigned long valuemask = GCForeground;
2073       XGCValues values;
2074
2075       M17N_OBJECT (device, free_device, MERROR_WIN);
2076       device->display_info = disp_info;
2077       device->screen_num = screen_num;
2078       /* A drawable on which to create GCs.  */
2079       device->drawable = XCreatePixmap (display,
2080                                         RootWindow (display, screen_num),
2081                                         1, 1, depth);
2082       device->depth = depth;
2083       device->cmap = cmap;
2084       device->realized_face_list = mplist ();
2085       device->realized_font_list = mplist ();
2086       device->realized_fontset_list = mplist ();
2087       device->gc_list = mplist ();
2088       values.foreground = BlackPixel (display, screen_num);
2089       device->scratch_gc = XCreateGC (display, device->drawable,
2090                                       valuemask, &values);
2091 #ifdef HAVE_XFT2
2092       device->xft_draw = XftDrawCreate (display, device->drawable,
2093                                         DefaultVisual (display, screen_num),
2094                                         cmap);
2095 #endif
2096     }
2097
2098   frame->device = device;
2099   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
2100   frame->driver = &x_driver;
2101   frame->font_driver_list = mplist ();
2102 #ifdef HAVE_XFT2
2103   if (use_xft)
2104     {
2105       mplist_add (frame->font_driver_list, Mfreetype, &xft_driver);
2106       use_freetype = 0;
2107     }
2108 #endif  /* HAVE_XFT2 */
2109 #ifdef HAVE_FREETYPE
2110   if (use_freetype)
2111     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
2112 #endif  /* HAVE_FREETYPE */
2113   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
2114     mplist_push (frame->font_driver_list, Mx, &xfont_driver);
2115
2116   frame->realized_font_list = device->realized_font_list;
2117   frame->realized_face_list = device->realized_face_list;
2118   frame->realized_fontset_list = device->realized_fontset_list;
2119
2120   if (widget)
2121     {
2122       XtResource resources[] = {
2123         { XtNfont, XtCFont, XtRString, sizeof (String),
2124           XtOffset (AppDataPtr, font), XtRString, DEFAULT_FONT },
2125         { XtNforeground, XtCForeground, XtRString, sizeof (String),
2126           XtOffset (AppDataPtr, foreground), XtRString, "black" },
2127         { XtNbackground, XtCBackground, XtRString, sizeof (String),
2128           XtOffset (AppDataPtr, background), XtRString, "white" },
2129         { XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
2130           XtOffset (AppDataPtr, reverse_video), XtRImmediate, (caddr_t) FALSE }
2131       };
2132
2133       XtGetApplicationResources (widget, &app_data,
2134                                  resources, XtNumber (resources), NULL, 0);
2135       frame->foreground = msymbol (app_data.foreground);
2136       frame->background = msymbol (app_data.background);
2137       frame->videomode = app_data.reverse_video == True ? Mreverse : Mnormal;
2138     }
2139   else
2140     {
2141       app_data.font = DEFAULT_FONT;
2142       frame->foreground = msymbol ("black");
2143       frame->background = msymbol ("white");
2144       frame->videomode = Mnormal;
2145     }
2146
2147   {
2148     int nfonts, i;
2149     /* Try at least 32 fonts to obtain a non-autoscaled font.  */
2150     char **names = XListFonts (display, app_data.font, 32, &nfonts);
2151     MFont *font = NULL;
2152
2153     for (i = 0; ! font && i < nfonts; i++)
2154       {
2155         font = mfont_parse_name (names[i], Mx);
2156         if (!font)
2157           {
2158             /* The font name does not conform to XLFD.  Try to open the
2159                font and get XA_FONT property.  */
2160             XFontStruct *xfont = XLoadQueryFont (display, names[i]);
2161
2162             if (xfont)
2163               {
2164                 unsigned long value;
2165                 char *name;
2166
2167                 if (XGetFontProperty (xfont, XA_FONT, &value)
2168                     && (name = ((char *)
2169                                 XGetAtomName (display, (Atom) value))))
2170                   font = mfont_parse_name (name, Mx);
2171                 XFreeFont (display, xfont);
2172               }
2173           }
2174         if (font &&
2175             font->property[MFONT_SIZE] == 0 && font->property[MFONT_RESY] > 0)
2176           {
2177             free (font);
2178             font = NULL;
2179           }
2180       }
2181     if (nfonts)
2182       XFreeFontNames (names);
2183     frame->font = font ? font : mfont_parse_name (FALLBACK_FONT, Mx);
2184   }
2185
2186   face = mface_from_font (frame->font);
2187   face->property[MFACE_FONTSET] = mfontset (NULL);
2188   face->property[MFACE_FOREGROUND] = frame->foreground;
2189   face->property[MFACE_BACKGROUND] = frame->background;
2190   mface_put_prop (face, Mhline, mface_get_prop (mface__default, Mhline));
2191   mface_put_prop (face, Mbox, mface_get_prop (mface__default, Mbox));
2192   face->property[MFACE_VIDEOMODE] = frame->videomode;
2193   mface_put_prop (face, Mhook_func, 
2194                   mface_get_prop (mface__default, Mhook_func));
2195   face->property[MFACE_RATIO] = (void *) 100;
2196   mplist_push (param, Mface, face);
2197   M17N_OBJECT_UNREF (face);
2198
2199 #ifdef X_SET_ERROR_HANDLER
2200   XSetErrorHandler (x_error_handler);
2201   XSetIOErrorHandler (x_io_error_handler);
2202 #endif
2203
2204   return 0;
2205 }
2206
2207 \f
2208
2209 /* XIM (X Input Method) handler */
2210
2211 typedef struct MInputXIMMethodInfo
2212 {
2213   Display *display;
2214   XIM xim;
2215   MSymbol language;
2216   MSymbol coding;
2217 } MInputXIMMethodInfo;
2218
2219 typedef struct MInputXIMContextInfo
2220 {
2221   XIC xic;
2222   Window win;
2223   MConverter *converter;
2224 } MInputXIMContextInfo;
2225
2226 static int
2227 xim_open_im (MInputMethod *im)
2228 {
2229   MInputXIMArgIM *arg = (MInputXIMArgIM *) im->arg;
2230   MLocale *saved, *this;
2231   char *save_modifier_list;
2232   XIM xim;
2233   MInputXIMMethodInfo *im_info;
2234
2235   saved = mlocale_set (LC_CTYPE, NULL);
2236   this = mlocale_set (LC_CTYPE, arg->locale ? arg->locale : "");
2237   if (! this)
2238     /* The specified locale is not supported.  */
2239     MERROR (MERROR_LOCALE, -1);
2240   if (mlocale_get_prop (this, Mcoding) == Mnil)
2241     {
2242       /* Unable to decode the output of XIM.  */
2243       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2244       MERROR (MERROR_LOCALE, -1);
2245     }
2246
2247   if (arg->modifier_list)
2248     save_modifier_list = XSetLocaleModifiers (arg->modifier_list);
2249   else
2250     save_modifier_list = XSetLocaleModifiers ("");
2251   if (! save_modifier_list)
2252     {
2253       /* The specified locale is not supported by X.  */
2254       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2255       MERROR (MERROR_LOCALE, -1);
2256     }
2257
2258   xim = XOpenIM (arg->display, arg->db, arg->res_name, arg->res_class);
2259   if (! xim)
2260     {
2261       /* No input method is available in the current locale.  */
2262       XSetLocaleModifiers (save_modifier_list);
2263       mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2264       MERROR (MERROR_WIN, -1);
2265     }
2266
2267   MSTRUCT_MALLOC (im_info, MERROR_WIN);
2268   im_info->display = arg->display;
2269   im_info->xim = xim;
2270   im_info->language = mlocale_get_prop (this, Mlanguage);
2271   im_info->coding = mlocale_get_prop (this, Mcoding);
2272   im->info = im_info;
2273
2274   XSetLocaleModifiers (save_modifier_list);
2275   mlocale_set (LC_CTYPE, msymbol_name (mlocale_get_prop (saved, Mname)));
2276
2277   return 0;
2278 }
2279
2280 static void
2281 xim_close_im (MInputMethod *im)
2282 {
2283   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) im->info;
2284
2285   XCloseIM (im_info->xim);
2286   free (im_info);
2287 }
2288
2289 static int
2290 xim_create_ic (MInputContext *ic)
2291 {
2292   MInputXIMArgIC *arg = (MInputXIMArgIC *) ic->arg;
2293   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2294   MInputXIMContextInfo *ic_info;
2295   XIC xic;
2296
2297   if (! arg->input_style)
2298     {
2299       /* By default, use Root style.  */
2300       arg->input_style = XIMPreeditNothing | XIMStatusNothing;
2301       arg->preedit_attrs = NULL;
2302       arg->status_attrs = NULL;
2303     }
2304
2305   if (! arg->preedit_attrs && ! arg->status_attrs)
2306     xic = XCreateIC (im_info->xim,
2307                      XNInputStyle, arg->input_style,
2308                      XNClientWindow, arg->client_win,
2309                      XNFocusWindow, arg->focus_win,
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                      XNPreeditAttributes, arg->preedit_attrs,
2317                      NULL);
2318   else if (! arg->preedit_attrs && arg->status_attrs)
2319     xic = XCreateIC (im_info->xim,
2320                      XNInputStyle, arg->input_style,
2321                      XNClientWindow, arg->client_win,
2322                      XNFocusWindow, arg->focus_win,
2323                      XNStatusAttributes, arg->status_attrs,
2324                      NULL);
2325   else
2326     xic = XCreateIC (im_info->xim,
2327                      XNInputStyle, arg->input_style,
2328                      XNClientWindow, arg->client_win,
2329                      XNFocusWindow, arg->focus_win,
2330                      XNPreeditAttributes, arg->preedit_attrs,
2331                      XNStatusAttributes, arg->status_attrs,
2332                      NULL);
2333   if (! xic)
2334     MERROR (MERROR_WIN, -1);
2335
2336   MSTRUCT_MALLOC (ic_info, MERROR_WIN);
2337   ic_info->xic = xic;
2338   ic_info->win = arg->focus_win;
2339   ic_info->converter = mconv_buffer_converter (im_info->coding, NULL, 0);
2340   ic->info = ic_info;
2341   return 0;
2342 }
2343
2344 static void
2345 xim_destroy_ic (MInputContext *ic)
2346 {
2347   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2348
2349   XDestroyIC (ic_info->xic);
2350   mconv_free_converter (ic_info->converter);
2351   free (ic_info);
2352   ic->info = NULL;
2353 }
2354
2355 static int
2356 xim_filter (MInputContext *ic, MSymbol key, void *event)
2357 {
2358   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2359
2360   return (XFilterEvent ((XEvent *) event, ic_info->win) == True);
2361 }
2362
2363
2364 static int
2365 xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2366 {
2367   MInputXIMMethodInfo *im_info = (MInputXIMMethodInfo *) ic->im->info;
2368   MInputXIMContextInfo *ic_info = (MInputXIMContextInfo *) ic->info;
2369   XKeyPressedEvent *ev = (XKeyPressedEvent *) arg;
2370   KeySym keysym;
2371   Status status;
2372   char *buf;
2373   int len;
2374
2375   buf = (char *) alloca (512);
2376   len = XmbLookupString (ic_info->xic, ev, buf, 512, &keysym, &status);
2377   if (status == XBufferOverflow)
2378     {
2379       buf = (char *) alloca (len);
2380       len = XmbLookupString (ic_info->xic, ev, buf, len, &keysym, &status);
2381     }
2382
2383   mtext_reset (ic->produced);
2384   if (len == 0)
2385     return 1;
2386
2387   mconv_reset_converter (ic_info->converter);
2388   mconv_rebind_buffer (ic_info->converter, (unsigned char *) buf, len);
2389   mconv_decode (ic_info->converter, ic->produced);
2390   mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2391                   Mlanguage, (void *) im_info->language);
2392   mtext_cpy (mt, ic->produced);
2393   mtext_reset (ic->produced);  
2394   return 0;
2395 }
2396
2397 \f
2398
2399 #ifdef X_SET_ERROR_HANDLER
2400 static int
2401 x_error_handler (Display *display, XErrorEvent *error)
2402 {
2403   mdebug_hook ();
2404   return 0;
2405 }
2406
2407 static int
2408 x_io_error_handler (Display *display)
2409 {
2410   mdebug_hook ();
2411   return 0;
2412 }
2413 #endif
2414
2415 /*=*/
2416
2417 /*** @} */
2418 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2419 \f
2420 /* External API */
2421
2422 /*** @addtogroup m17nInputMethodWin */
2423 /*=*/
2424 /*** @{ */
2425
2426 /***en
2427     @brief Input method driver for XIM.
2428
2429     The driver #minput_xim_driver is for the foreign input method of
2430     name #Mxim.  It uses XIM (X Input Methods) as a background input
2431     engine.
2432
2433     As the symbol #Mxim has property #Minput_driver whose value is
2434     a pointer to this driver, the input method of language #Mnil
2435     and name #Mxim uses this driver.
2436
2437     Therefore, for such input methods, the driver dependent arguments
2438     to the functions whose name begin with minput_ must be as follows.
2439
2440     The argument $ARG of the function minput_open_im () must be a
2441     pointer to the structure #MInputXIMArgIM.  See the documentation
2442     of #MInputXIMArgIM for more details.
2443
2444     The argument $ARG of the function minput_create_ic () must be a
2445     pointer to the structure #MInputXIMArgIC. See the documentation
2446     of #MInputXIMArgIC for more details.
2447
2448     The argument $ARG of the function minput_filter () must be a
2449     pointer to the structure @c XEvent.  The argument $KEY is ignored.
2450
2451     The argument $ARG of the function minput_lookup () must be the
2452     same one as that of the function minput_filter ().  The argument
2453     $KEY is ignored.  */
2454
2455 /***ja
2456     @brief XIMÍÑÆþÎϥɥ饤¥Ð.
2457
2458     ¥É¥é¥¤¥Ð #minput_xim_driver ¤Ï #Mxim ¤ò̾Á°¤È¤·¤Æ»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã¥ÉÍѤǤ¢¤ê¡¢
2459     XIM (X Input Methods) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸¥ó¤È¤·¤Æ»ÈÍѤ¹¤ë¡£
2460
2461     ¥·¥ó¥Ü¥ë #Mxim ¤Ï¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥×¥í¥Ñ¥Æ¥£
2462     #Minput_driver ¤ò»ý¤Á¡¢LANGUAGE ¤¬ #Mnil ¤Ç̾Á°¤¬ #Mxim 
2463     ¤Ç¤¢¤ëÆþÎϥ᥽¥Ã¥É¤Ï¤³¤Î¥É¥é¥¤¥Ð¤òÍøÍѤ¹¤ë¡£
2464
2465     ¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢minput_ 
2466     ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô¤Ï¼¡¤Î¤è¤¦¤Ê¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2467
2468     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIM 
2469     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIM ¤ÎÀâÌÀ¤ò»²¾È¡£
2470
2471     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ#MInputXIMArgIC 
2472     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï #MInputXIMArgIC ¤ÎÀâÌÀ¤ò»²¾È¡£
2473
2474     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c XEvent 
2475     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£°ú¿ô $KEY ¤Ï̵»ë¤µ¤ì¤ë¡£
2476
2477     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô function minput_filter () 
2478     ¤Î°ú¿ô $ARG ¤ÈƱ¤¸¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ °ú¿ô $KEY ¤Ï¡¢Ìµ»ë¤µ¤ì¤ë¡£  */
2479
2480 MInputDriver minput_xim_driver =
2481   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
2482     xim_filter, xim_lookup, NULL };
2483
2484 /*** @} */ 
2485
2486 /*
2487   Local Variables:
2488   coding: euc-japan
2489   End:
2490 */