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