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