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