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