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