Add coding tag euc-jp.
[m17n/m17n-lib.git] / example / medit.c
1 /* medit.c -- simple multilingual editor.               -*- coding: euc-jp; -*-
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 /***en
24     @enpage medit edit multilingual text
25
26     @section medit-synopsis SYNOPSIS
27
28     medit [ XT-OPTION ...] [ OPTION ... ] FILE
29
30     @section medit-description DESCRIPTION
31
32     Display FILE on a window and allow users to edit it.
33
34     XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).
35
36     The following OPTIONs are available.
37
38     <ul>
39
40     <li> --version
41
42     Print version number.
43
44     <li> -h, --help
45
46     Print this message.
47
48     </ul>
49
50     This program is to demonstrate how to use the m17n GUI API.
51     Although medit directly uses the GUI API, the API is mainly for
52     toolkit libraries or to implement XOM (X Outout Method), not for
53     direct use from application programs.
54 */
55 /***ja
56     @japage medit Â¿¸À¸ì¥Æ¥­¥¹¥È¤ÎÊÔ½¸
57
58     @section medit-synopsis SYNOPSIS
59
60     medit [ XT-OPTION ...] [ OPTION ... ] FILE
61
62     @section medit-description DESCRIPTION
63
64     FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤·¡¢¥æ¡¼¥¶¤¬ÊÔ½¸¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡£
65
66     XT-OPTIONs ¤Ï Xt ¤Îɸ½à¤Î°ú¿ô¤Ç¤¢¤ë¡£ (e.g. -fn, -fg). 
67
68     °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ­¤ë¡£ 
69
70     <ul>
71
72     <li> --version
73
74     ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£ 
75
76     <li> -h, --help
77
78     ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£ 
79
80     </ul>
81
82     ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£medit ¤Ïľ 
83     ÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥­¥Ã¥È¥é¥¤¥Ö¥é¥ê¤ä
84     XOM (X Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é ¥à
85     ¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
86 */
87
88 #ifndef FOR_DOXYGEN
89
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <sys/types.h>
93 #include <sys/stat.h>
94 #include <fcntl.h>
95 #include <unistd.h>
96 #include <libgen.h>
97 #include <locale.h>
98
99 #include <X11/keysym.h>
100 #include <X11/Xatom.h>
101 #include <X11/Intrinsic.h>
102 #include <X11/StringDefs.h>
103 #include <X11/Shell.h>
104 #include <X11/Xaw/Command.h>
105 #include <X11/Xaw/Box.h>
106 #include <X11/Xaw/Form.h>
107 #include <X11/Xaw/Dialog.h>
108 #include <X11/Xaw/Scrollbar.h>
109 #include <X11/Xaw/Toggle.h>
110 #include <X11/Xaw/SimpleMenu.h>
111 #include <X11/Xaw/SmeBSB.h>
112 #include <X11/Xaw/SmeLine.h>
113 #include <X11/Xaw/MenuButton.h>
114
115 #include <m17n-gui.h>
116 #include <m17n-misc.h>
117 #include <m17n-X.h>
118
119 #define VERSION "1.0.1"
120
121 /* Global variables.  */
122
123 char *filename;
124 int serialized;
125
126 /* For the X Window System.  */
127 Display *display;
128 int screen;
129 /* GCs for normal drawing, filling by background color, normal drawing
130    on bitmap (i.e. pixmap of depth 1), filling bitmap by background
131    color. */
132 GC gc, gc_inv, mono_gc, mono_gc_inv;
133 Window win;
134 Atom XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING; /* X Selection types.  */
135 XtAppContext context;
136 int default_font_size;
137
138 /* Widget hierarchy
139
140 Shell - Form -+- Head -- File, Cursor, Bidi, LineBreak, InputMethod, CurIM;
141               +- Face -- Size, Family, Style, Color, Misc, Pop, CurFace
142               +- Lang -- A-B, C-D, ..., U-Z, Pop, CurLang
143               +- Body -- Sbar, Text
144               +- Tail -- Message
145 */
146
147 Widget ShellWidget, HeadWidget, TailWidget, MessageWidget;
148 Widget CursorMenus[5], BidiMenus[3], LineBreakMenus[3], *InputMethodMenus;
149 Widget SbarWidget, TextWidget;
150 Widget FileShellWidget, FileDialogWidget;
151 Widget FaceWidget, CurFaceWidget, LangWidget, CurLangWidget;
152 Widget CurIMLang, CurIMStatus;
153
154 int win_width, win_height;      /* Size of TextWidget.  */
155 Arg arg[10];
156
157 Pixmap input_status_pixmap;
158 int input_status_width, input_status_height;
159
160 /* Bitmap for "check" glyph.  */
161 #define check_width 9
162 #define check_height 8
163 static unsigned char check_bits[] = {
164    0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
165    0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 };
166 Pixmap CheckPixmap;
167
168 /* For the m17n library.  */
169 MFrame *frame;
170 MText *mt;
171 int nchars;                     /* == mtext_len (mt) */
172 MDrawControl control, input_status_control;
173 MTextProperty *selection;
174
175 MFace *face_default;
176 MFace *face_xxx_large;
177 MFace *face_box;
178 MFace *face_courier, *face_helvetica, *face_times;
179 MFace *face_dv_ttyogesh, *face_freesans, *face_freemono;
180 MFace *face_default_fontset, *face_no_ctl_fontset;
181 MFace *face_input_status;
182
183 int logical_move = 1;           /* If 0, move cursor visually.  */
184
185 MInputMethod **input_method_table;
186 int num_input_methods;
187 int current_input_method = -1;  /* i.e. none */
188 int auto_input_method = 0;
189 MInputContext *current_input_context;
190
191 struct FaceRec
192 {
193   char *name;
194   MFace **face;
195 } face_table[] =
196   { {"Menu Size", NULL},
197     {"xx-small", &mface_xx_small},
198     {"x-small", &mface_x_small},
199     {"small", &mface_small},
200     {"normalsize", &mface_normalsize},
201     {"large", &mface_large},
202     {"x-large", &mface_x_large},
203     {"xx-large", &mface_xx_large},
204     {"xxx-large", &face_xxx_large},
205
206     {"Menu Family", NULL},
207     {"courier", &face_courier},
208     {"helvetica", &face_helvetica},
209     {"times", &face_times},
210     {"dv-ttyogesh", &face_dv_ttyogesh},
211     {"freesans", &face_freesans},
212     {"freemono", &face_freemono},
213
214     {"Menu Style", NULL},
215     {"medium", &mface_medium},
216     {"bold", &mface_bold},
217     {"italic", &mface_italic},
218
219     {"Menu Color", NULL},
220     {"black", &mface_black},
221     {"white", &mface_white},
222     {"red", &mface_red},
223     {"green", &mface_green},
224     {"blue", &mface_blue},
225     {"cyan", &mface_cyan},
226     {"yello", &mface_yellow},
227     {"magenta", &mface_magenta},
228
229     {"Menu Misc", NULL},
230     {"normal", &mface_normal_video},
231     {"reverse", &mface_reverse_video},
232     {"underline", &mface_underline},
233     {"box", &face_box},
234     {"No CTL", &face_no_ctl_fontset} };
235
236
237 int num_faces = sizeof (face_table) / sizeof (struct FaceRec);
238
239 /* Information about a physical line metric.  */
240 struct LineInfo
241 {
242   int from;                     /* BOL position of the line.  */
243   int to;                       /* BOL position of the next line.  */
244   int y0, y1;            /* Top and bottom Y position of the line.  */
245   int ascent;                   /* Height of the top Y position.  */
246 };
247
248 struct LineInfo top;            /* Topmost line.  */
249 struct LineInfo cur;            /* Line containing cursor.  */
250 struct LineInfo sel_start;     /* Line containing selection start.  */
251 struct LineInfo sel_end;        /* Line containing selection end.  */
252
253 MDrawGlyphInfo cursor;      /* Information about the cursor glyph.  */
254
255 /* X position to keep on vertical (up and down) cursor motion. */
256 int target_x_position;
257
258 /* Interface macros for m17n-lib drawing routines. */
259
260 /* Draw a text in the range $FROM to $TO of the M-text #MT at the
261    coordinate ($X, $Y)  */
262 #define DRAW_TEXT(x, y, from, to)                               \
263     mdraw_text_with_control                                     \
264       (frame, (MDrawWindow) win,                                \
265        control.orientation_reversed ? x + win_width : x, y,     \
266        mt, from, to, &control)
267
268 /* Store the extents of a text in the range $FROM to $TO in the
269    structure $RECT (type MDrawMetric).  */
270 #define TEXT_EXTENTS(from, to, rect)    \
271   mdraw_text_extents (frame, mt, from, (to), &control, NULL, NULL, &(rect))
272
273 /* Store the glyph information of a character at the position $POS in
274    the struct $INFO (type MDrawGlyphInfo) assuming that the text from
275    $FROM is written at the coordinate (0, 0).  */
276 #define GLYPH_INFO(from, pos, info)     \
277   mdraw_glyph_info (frame, mt, from, (pos), &control, &(info))
278
279 /* Set $X and $Y to the coordinate of character at position $POS
280    assuming that the text from $FROM is written at the coordinate (0,
281    0).  */
282 #define COORDINATES_POSITION(from, pos, x, y)   \
283   mdraw_coordinates_position (frame, mt, (from), (pos), (x), (y), &control)
284
285 /* Interface macros for X library.  */
286 #define COPY_AREA(y0, y1, to)   \
287   XCopyArea (display, win, win, gc, 0, (y0), win_width, (y1) - (y0), 0, (to))
288
289 #define CLEAR_AREA(x, y, w, h)  \
290   XClearArea (display, win, (x), (y), (w), (h), False)
291
292 #define SELECTEDP() \
293   mtext_property_mtext (selection)
294
295 /* Format MSG by FMT and print the result to the stderr, and exit.  */
296 #define FATAL_ERROR(fmt, arg)   \
297   do {                          \
298     fprintf (stderr, fmt, arg); \
299     exit (1);                   \
300   } while (0)
301
302
303 /* If POS is greater than zero, move POS back to the beginning of line
304    (BOL) position.  If FORWARD is nonzero, move POS forward instead.
305    Return the new position.  */
306 int
307 bol (int pos, int forward)
308 {
309   int limit = forward ? nchars : 0;
310
311   pos = mtext_character (mt, pos, limit, '\n');
312   return (pos < 0 ? limit : pos + 1);
313 }
314
315 /* Update the structure #TOP (struct LineInfo) to make $POS the first
316    character position of the screen.  */
317 void
318 update_top (int pos)
319 {
320   int from = bol (pos, 0);
321   MDrawGlyphInfo info;
322
323   GLYPH_INFO (from, pos, info);
324   top.from = info.line_from;
325   top.to = info.line_to;
326   top.y0 = 0;
327   top.y1 = info.this.height;
328   top.ascent = - info.this.y;
329 }
330
331
332 /* Update the scroll bar so that the text of the range $FROM to $TO
333    are shown on the window.  */
334 void
335 update_scroll_bar (int from, int to)
336 {
337   float top = (float) from / nchars;
338   float shown = (float) (to - from) / nchars;
339   XtArgVal *l_top = (XtArgVal *) &top;
340   XtArgVal *l_shown = (XtArgVal *) &shown;
341
342   XtSetArg (arg[0], XtNtopOfThumb, *l_top);
343   XtSetArg (arg[1], XtNshown, *l_shown);
344   XtSetValues (SbarWidget, arg, 2);
345 }
346
347
348 /* Redraw the window area between $Y0 and $Y1 (both Y-codinates).  If
349    $CLEAR is nonzero, clear the area before drawing.  If $SCROLL_BAR
350    is nonzero, update the scoll bar.  */
351 void
352 redraw (int y0, int y1, int clear, int scroll_bar)
353 {
354   int from, to;
355   int y;
356   MDrawGlyphInfo info;
357   int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
358   struct LineInfo *line;
359   
360   if (clear)
361     CLEAR_AREA (0, y0, win_width, y1 - y0);
362
363   /* Find a line closest to y0.  It is a cursor line if the cursor is
364      Y0, otherwise the top line.  */
365   if (y0 >= cur.y0)
366     line = &cur;
367   else
368     line = &top;
369   /* If there exists a selected region, check it too.  */
370   if (sel_y0 > line->y0 && y0 >= sel_y0)
371     line = &sel_start;
372
373   from = line->from;
374   y = line->y0;
375   info.this.height = line->y1 - y;
376   info.this.y = - line->ascent;
377   info.line_to = line->to;
378   while (from < nchars && y + info.this.height <= y0)
379     {
380       y += info.this.height;
381       from = info.line_to;
382       GLYPH_INFO (from, from, info);
383     }
384   y0 = y - info.this.y;
385   to = from;
386   while (to < nchars && y < y1)
387     {
388       GLYPH_INFO (to, to, info);
389       y += info.this.height;
390       to = info.line_to;
391     }
392   if (to == nchars)
393     to++;
394   if (from < to)
395     DRAW_TEXT (0, y0, from, to);
396   if (scroll_bar)
397     {
398       while (to < nchars)
399         {
400           GLYPH_INFO (to, to, info);
401           if (y + info.this.height >= win_height)
402             break;
403           to = info.line_to;
404           y += info.this.height;
405         }
406       update_scroll_bar (top.from, to);
407     }
408 }
409      
410
411 /* Set the current input method spot to the correct position.  */
412 void
413 set_input_method_spot ()
414 {
415   int x = cursor.x + (control.orientation_reversed ? win_width : 0);
416   int pos = cursor.from > 0 ? cursor.from - 1 : 0;
417   MFace *faces[256];
418   int n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
419   int size = 0, ratio = 0, i;
420
421   for (i = n - 1; i >= 0; i--)
422     {
423       if (! size)
424         size = (int) mface_get_prop (faces[i], Msize);
425       if (! ratio)
426         ratio = (int) mface_get_prop (faces[i], Mratio);
427     }
428   if (! size)
429     size = default_font_size;
430   if (ratio)
431     size = size * ratio / 100;
432   minput_set_spot (current_input_context, x, cur.y0 + cur.ascent,
433                    cur.ascent, cur.y1 - (cur.y0 + cur.ascent), size,
434                    mt, cursor.from);
435 }
436
437
438 /* Redraw the cursor.  If $CLEAR is nonzero, clear the cursor area
439    before drawing.  */
440 void
441 redraw_cursor (int clear)
442 {
443   if (control.cursor_bidi)
444     {
445       /* We must update the whole line of the cursor.  */
446       int beg = bol (cur.from, 0);
447       int end = bol (cur.to - 1, 1);
448       MDrawMetric rect;
449       int y0 = cur.y0, y1 = cur.y1;
450
451       if (beg != cur.from)
452         {
453           TEXT_EXTENTS (beg, cur.from, rect);
454           y0 -= rect.height;
455         }
456       if (end != cur.to)
457         {
458           TEXT_EXTENTS (cur.to, end, rect);
459           y1 += rect.height; 
460         }
461       redraw (y0, y1, clear, 0);
462     }
463   else
464     {
465       if (clear)
466         {
467           int x = cursor.x;
468
469           if (control.orientation_reversed)
470             x += win_width - cursor.this.width;
471           CLEAR_AREA (x, cur.y0, cursor.this.width, cursor.this.height);
472         }
473       DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
474     }
475 }
476
477
478 /* Update the information about the location of cursor to the position
479    $POS.  If $FULL is nonzero, update the information fully only from
480    the information about the top line.  Otherwise, truct the current
481    information in the structure $CUR.  */
482 void
483 update_cursor (int pos, int full)
484 {
485   MDrawMetric rect;
486
487   if (full)
488     {
489       /* CUR is inaccurate.  We can trust only TOP.  */
490       GLYPH_INFO (top.from, pos, cursor);
491       cur.y0 = top.ascent + cursor.y + cursor.this.y;
492     }
493   else if (pos < cur.from)
494     {
495       int from = bol (pos, 0);
496
497       TEXT_EXTENTS (from, cur.from, rect);
498       GLYPH_INFO (from, pos, cursor);
499       cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.this.y);
500     }
501   else if (pos < cur.to)
502     {
503       GLYPH_INFO (cur.from, pos, cursor);
504     }
505   else
506     {
507       GLYPH_INFO (cur.from, pos, cursor);
508       cur.y0 += cur.ascent + cursor.y + cursor.this.y;
509     }
510
511   cur.from = cursor.line_from;
512   cur.to = cursor.line_to;
513   cur.y1 = cur.y0 + cursor.this.height;
514   cur.ascent = - cursor.this.y;
515 }
516
517
518 /* Update the information about the selected region.  */
519 void
520 update_selection ()
521 {
522   int from, to;
523   MDrawMetric rect;
524   MDrawGlyphInfo info;
525
526   if (! SELECTEDP ())
527     return;
528   from = mtext_property_start (selection);
529   to = mtext_property_end (selection);
530
531   if (from < top.from)
532     {
533       int pos = bol (from, 0);
534
535       TEXT_EXTENTS (pos, top.from, rect);
536       sel_start.y0 = top.y0 - rect.height;
537       sel_start.ascent = - rect.y;
538       GLYPH_INFO (pos, from, info);
539       if (pos < info.line_from)
540         sel_start.y0 += - rect.y + info.y + info.this.y;
541     }
542   else
543     {
544       GLYPH_INFO (top.from, from, info);
545       sel_start.y0 = top.ascent + info.y + info.this.y;
546     }
547   sel_start.ascent = -info.this.y;
548   sel_start.y1 = sel_start.y0 + info.this.height;
549   sel_start.from = info.line_from;
550   sel_start.to = info.line_to;
551
552   if (to <= sel_start.to)
553     {
554       sel_end = sel_start;
555       if (to >= sel_end.to)
556         {
557           GLYPH_INFO (sel_start.from, to, info);
558           sel_end.y1 = sel_end.y0 + info.y + info.this.height;
559           sel_end.to = info.line_to;
560         }
561     }
562   else
563     {
564       GLYPH_INFO (sel_start.from, to, info);
565       sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.this.y;
566       sel_end.y1 = sel_end.y0 + info.this.height;
567       sel_end.ascent = - info.this.y;
568       sel_end.from = info.line_from;
569       sel_end.to = info.line_to;
570     }
571 }
572
573
574 /* Select the text in the region from $FROM to $TO.  */
575 void
576 select_region (int from, int to)
577 {
578   int pos;
579
580   if (from > to)
581     pos = from, from = to, to = pos;
582   mtext_push_property (mt, from, to, selection);
583   update_selection ();
584 }
585
586
587 /* Setup the window to display the character of $POS at the top left
588    of the window.  */
589 void
590 reseat (int pos)
591 {
592   MDrawMetric rect;
593   /* Top and bottom Y positions to redraw.  */
594   int y0, y1;
595
596   if (pos + 1000 < top.from)
597     y0 = 0, y1 = win_height;
598   else if (pos < top.from)
599     {
600       y0 = 0;
601       TEXT_EXTENTS (pos, top.from, rect);
602       if (rect.height >= win_height * 0.9)
603         y1 = win_height;
604       else
605         {
606           y1 = rect.height;
607           COPY_AREA (0, win_height - y1, y1);
608         }
609     }
610   else if (pos < top.to)
611     {
612       /* No need of redrawing.  */
613       y0 = y1 = 0;
614     }
615   else if (pos < top.from + 1000)
616     {
617       TEXT_EXTENTS (top.from, pos, rect);
618       if (rect.height >= win_height * 0.9)
619         y0 = 0;
620       else
621         {
622           y0 = win_height - rect.height;
623           COPY_AREA (rect.height, win_height, 0);
624         }
625       y1 = win_height;
626     }
627   else
628     y0 = 0, y1 = win_height;
629
630   if (y0 < y1)
631     {
632       update_top (pos);
633       if (cur.to <= pos)
634         update_cursor (pos, 1);
635       else
636         update_cursor (cursor.from, 1);
637       update_selection ();
638       redraw (y0, y1, 1, 1);
639     }
640 }
641
642 static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
643
644
645 /* Select an input method accoding to $IDX.  If $IDX is negative, turn
646    off the current input method, otherwide turn on the input method
647    input_method_table[$IDX].  */
648 void
649 select_input_method (idx)
650 {
651   if (idx == current_input_method)
652     return;
653   if (current_input_context)
654     {
655       minput_destroy_ic (current_input_context);
656       current_input_context = NULL;
657       current_input_method = -1;
658     }
659   if (idx >= 0)
660     {
661       MInputMethod *im = input_method_table[idx];
662
663       if (im->language == Mnil)
664         {
665           MInputXIMArgIC arg_xic;
666           Window win = XtWindow (TextWidget);
667
668           arg_xic.input_style = 0;
669           arg_xic.client_win = arg_xic.focus_win = win;
670           arg_xic.preedit_attrs =  arg_xic.status_attrs = NULL;
671           current_input_context = minput_create_ic (im, &arg_xic);
672         }
673       else
674         {
675           MInputGUIArgIC arg_ic;
676
677           arg_ic.frame = frame;
678           arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
679           arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
680           current_input_context = minput_create_ic (im, &arg_ic);
681         }
682
683       if (current_input_context)
684         {
685           set_input_method_spot ();
686           current_input_method = idx;
687         }
688     }
689   if (current_input_method >= 0)
690     {
691       char *label;
692       XtSetArg (arg[0], XtNlabel, &label);
693       XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
694       XtSetArg (arg[0], XtNlabel, label);
695     }
696   else
697     XtSetArg (arg[0], XtNlabel, "");
698   XtSetValues (CurIMLang, arg, 1);
699 }
700
701 static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
702
703
704 /* Display cursor according to the current information of #CUR.
705    $CLIENT_DATA is ignore.  Most callback functions add this function
706    as a background processing procedure the current application (by
707    XtAppAddWorkProc) via the function hide_cursor.  */
708 Boolean
709 show_cursor (XtPointer client_data)
710 {
711   if (cur.y0 < 0)
712     {
713       reseat (cur.from);
714       update_cursor (cursor.from, 1);
715     }
716   while (cur.y1 > win_height)
717     {
718       reseat (top.to);
719       update_cursor (cursor.from, 1);
720     }
721
722   control.cursor_pos = cursor.from;
723   if (! SELECTEDP ())
724     {
725       control.with_cursor = 1;
726       redraw_cursor (0);
727     }
728   if (current_input_context)
729     set_input_method_spot ();
730
731   {
732     int pos = (SELECTEDP () ? mtext_property_start (selection)
733                : cursor.from > 0 ? cursor.from - 1
734                : cursor.from);
735     MFace *face = mface ();
736     MTextProperty *props[256];
737     int n = mtext_get_properties (mt, pos, Mface, props, 256);
738     int i;
739     char buf[256], *p = buf;
740     MSymbol sym;
741
742     buf[0] = '\0';
743     if (cursor.font)
744       {
745         int size = (int) mfont_get_prop (cursor.font, Msize);
746         MSymbol family = mfont_get_prop (cursor.font, Mfamily);
747         MSymbol weight = mfont_get_prop (cursor.font, Mweight);
748         MSymbol style = mfont_get_prop (cursor.font, Mstyle);
749         MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
750
751         sprintf (p, "%dpt", size / 10), p += strlen (p);
752         if (family)
753           strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
754         if (weight)
755           strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
756         if (style)
757           strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
758         if (registry)
759           strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
760         p += strlen (p);
761       }
762
763     mface_merge (face, face_default);
764     for (i = 0; i < n; i++)
765       if (props[i] != selection)
766         mface_merge (face, (MFace *) mtext_property_value (props[i]));
767     sym = (MSymbol) mface_get_prop (face, Mforeground);
768     if (sym != Mnil)
769       strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
770     if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
771       strcat (p, ",rev"), p += strlen (p);
772     if (mface_get_prop (face, Mhline))
773       strcat (p, ",ul"), p += strlen (p);
774     if (mface_get_prop (face, Mbox))
775       strcat (p, ",box"), p += strlen (p);
776     m17n_object_unref (face);
777
778     XtSetArg (arg[0], XtNborderWidth, 1);
779     XtSetArg (arg[1], XtNlabel, buf);
780     XtSetValues (CurFaceWidget, arg, 2);
781   }
782
783   if (control.cursor_pos < nchars)
784     {
785       MSymbol sym = Mnil;
786
787       if (control.cursor_pos > 0
788           && mtext_ref_char (mt, control.cursor_pos - 1) != '\n')
789         sym = mtext_get_prop (mt, control.cursor_pos - 1, Mlanguage);
790       if (sym == Mnil)
791         sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
792     
793       if (sym == Mnil)
794         {
795           XtSetArg (arg[0], XtNborderWidth, 0);
796           XtSetArg (arg[1], XtNlabel, "");
797         }
798       else
799         {
800           XtSetArg (arg[0], XtNborderWidth, 1);
801           XtSetArg (arg[1], XtNlabel,
802                     msymbol_name (msymbol_get (sym, Mlanguage)));
803           XtSetValues (CurLangWidget, arg, 2);
804         }
805       XtSetValues (CurLangWidget, arg, 2);
806
807       if (auto_input_method)
808         {
809           if (sym == Mnil)
810             select_input_method (-1);
811           else
812             {
813               int i;
814
815               for (i = 0; i < num_input_methods; i++)
816                 if (input_method_table[i]->language == sym)
817                   break;
818               if (i < num_input_methods)
819                 select_input_method (i);
820               else
821                 select_input_method (-1);
822             }
823         }
824     }
825
826   MenuHelpProc (MessageWidget, NULL, NULL, NULL);
827
828   return True;
829 }
830
831
832 /* Hide the cursor.  */
833 void
834 hide_cursor ()
835 {
836   control.with_cursor = 0;
837   redraw_cursor (1);
838   XtAppAddWorkProc (context, show_cursor, NULL);
839 }
840
841
842 /* Update the window area between the Y-positions $Y0 and $OLD_Y1 to
843    $Y1 and $NEW_Y1 assuming that the text in the other area is not
844    changed.  */
845 void
846 update_region (int y0, int old_y1, int new_y1)
847 {
848   if (y0 < 0)
849     y0 = 0;
850   if (new_y1 < old_y1)
851     {
852       if (old_y1 < win_height)
853         {
854           COPY_AREA (old_y1, win_height, new_y1);
855           redraw (win_height - (old_y1 - new_y1), win_height, 1, 0);
856         }
857       else
858         redraw (new_y1, win_height, 1, 0);
859     }
860   else if (new_y1 > old_y1)
861     {
862       if (new_y1 < win_height)
863         COPY_AREA (old_y1, win_height, new_y1);
864     }
865   if (new_y1 > win_height)
866     new_y1 = win_height;
867   redraw (y0, new_y1, 1, 1);
868 }
869
870
871 /* Delete the next $N characters.  If $N is negative delete the
872    precious (- $N) characters.  */
873 void
874 delete_char (int n)
875 {
876   MDrawMetric rect;
877   MDrawGlyphInfo info;
878   int old_y1, new_y1;
879   int from, to;
880
881   if (n > 0)
882     from = cursor.from, to = from + n;
883   else
884     {
885       if (cursor.from == cur.from)
886         {
887           /* We are at the beginning of line.  */
888           int pos = cursor.prev_from;
889           
890           if (cursor.from == top.from)
891             {
892               /* We are at the beginning of screen.  We must scroll
893                  down.  */
894               GLYPH_INFO (bol (top.from - 1, 0), top.from - 1, info);
895               reseat (info.line_from);
896             }
897           update_cursor (pos, 1);
898           from = cursor.from;
899           to = cursor.to;
900         }
901       else
902         {
903           from = cursor.from - 1;
904           to = cursor.from;
905         }
906     }
907
908   TEXT_EXTENTS (cur.from, bol (to + 1, 1), rect);
909   old_y1 = cur.y0 + rect.height;
910
911   /* Now delete a character.  */
912   mtext_del (mt, from, to);
913   nchars--;
914   if (from >= top.from && from < top.to)
915     update_top (top.from);
916   update_cursor (from, 1);
917
918   TEXT_EXTENTS (cur.from, bol (to, 1), rect);
919   new_y1 = cur.y0 + rect.height;
920
921   update_region (cur.y0, old_y1, new_y1);
922 }
923
924
925 /* Insert M-text $NEWTEXT at the current cursor position.  */
926 void
927 insert_chars (MText *newtext)
928 {
929   int n = mtext_len (newtext);
930   MDrawMetric rect;
931   int y0, old_y1, new_y1;
932
933   if (SELECTEDP ())
934     {
935       int n = (mtext_property_end (selection)
936                - mtext_property_start (selection));
937       mtext_detach_property (selection);
938       delete_char (n);
939     }
940
941   y0 = cur.y0;
942   TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
943   old_y1 = y0 + rect.height;
944
945   /* Now insert chars.  */
946   mtext_ins (mt, cursor.from, newtext);
947   nchars += n;
948   if (cur.from == top.from)
949     update_top (top.from);
950   update_cursor (cursor.from + n, 1);
951
952   TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
953   new_y1 = cur.y0 + rect.height;
954
955   update_region (y0, old_y1, new_y1);
956   update_selection ();
957 }
958
959
960 /* Convert the currently selected text to COMPOUND-TEXT.  It is called
961    when someone requests the current value of the selection.  */
962 Boolean
963 covert_selection (Widget w, Atom *selection_atom,
964                   Atom *target, Atom *return_type,
965                   XtPointer *value, unsigned long *length, int *format)
966 {
967   unsigned char *buf = (unsigned char *) XtMalloc (4096);
968   MText *this_mt = mtext ();
969   int from = mtext_property_start (selection);
970   int to = mtext_property_end (selection);
971
972   mtext_copy (this_mt, 0, mt, from, to);
973   *length = mconv_encode_buffer (msymbol ("compound-text"),
974                                  this_mt, buf, 4096);
975   *return_type = XA_COMPOUND_TEXT;
976   *value = (XtPointer) buf;
977   *format = 8;
978   m17n_object_unref (this_mt);
979   return True;
980 }
981
982
983 /* Unselect the text.  It is called when we loose the selection.  */
984 void
985 lose_selection (Widget w, Atom *selection_atom)
986 {
987   if (SELECTEDP ())
988     {
989       mtext_detach_property (selection);
990       redraw (sel_start.y0, sel_end.y1, 1, 0);
991     }
992 }
993
994 void
995 get_selection (Widget w, XtPointer cliend_data, Atom *selection,  Atom *type,
996                XtPointer value, unsigned long *length, int *format)
997 {
998   MText *this_mt;
999   MSymbol coding;
1000
1001   if (*type == XT_CONVERT_FAIL || ! value)
1002     goto err;
1003   if (*type == XA_STRING)
1004     coding = Mnil;
1005   else if (*type == XA_COMPOUND_TEXT)
1006     coding = msymbol ("compound-text");
1007   else if (*type == XA_UTF8_STRING)
1008     coding = msymbol ("utf-8");
1009   else
1010     goto err;
1011
1012   this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
1013   if (this_mt)
1014     {
1015       hide_cursor ();
1016       insert_chars (this_mt);
1017       m17n_object_unref (this_mt);
1018     }
1019
1020  err:
1021   if (value)
1022     XtFree (value);
1023 }
1024
1025 static void
1026 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1027 {
1028   XExposeEvent *expose = (XExposeEvent *) event;
1029
1030   if (top.from < 0)
1031     {
1032       Dimension width_max, width;
1033
1034       XtSetArg (arg[0], XtNwidth, &width);
1035       XtGetValues (XtParent (w), arg, 1);
1036       width_max = width;
1037       XtGetValues (HeadWidget, arg, 1);
1038       if (width_max < width)
1039         width_max = width;
1040       XtGetValues (FaceWidget, arg, 1);
1041       if (width_max < width)
1042         width_max = width;
1043       XtGetValues (LangWidget, arg, 1);
1044       if (width_max < width)
1045         width_max = width;
1046       XtSetArg (arg[0], XtNwidth, width_max);
1047       XtSetValues (HeadWidget, arg, 1);
1048       XtSetValues (FaceWidget, arg, 1);
1049       XtSetValues (LangWidget, arg, 1);
1050       XtSetValues (XtParent (w), arg, 1);
1051       XtSetValues (TailWidget, arg, 1);
1052
1053       update_top (0);
1054       update_cursor (0, 1);
1055       redraw (0, win_height, 0, 1);
1056       show_cursor (NULL);
1057     }
1058   else
1059     {
1060       redraw (expose->y, expose->y + expose->height, 0, 0);
1061       if (current_input_context
1062           && expose->y < cur.y0 && expose->y + expose->height < cur.y1)
1063         set_input_method_spot ();
1064     }
1065 }
1066
1067 static void
1068 ConfigureProc (Widget w, XEvent *event, String *str, Cardinal *num)
1069 {
1070   XConfigureEvent *configure = (XConfigureEvent *) event;
1071   
1072   hide_cursor ();
1073   control.max_line_width = win_width = configure->width;
1074   win_height = configure->height;
1075   mdraw_clear_cache (mt);
1076   update_top (0);
1077   update_cursor (0, 1);
1078   redraw (0, win_height, 1, 1);
1079   if (current_input_context)
1080     set_input_method_spot ();
1081 }
1082
1083 static void
1084 ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
1085 {
1086   int pos;
1087   int x = event->xbutton.x;
1088   int y = event->xbutton.y - top.ascent;
1089
1090   if (control.orientation_reversed)
1091     x -= win_width;
1092   pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1093   if (SELECTEDP ())
1094     {
1095       XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1096       mtext_detach_property (selection);
1097       redraw (sel_start.y0, sel_end.y1, 1, 0);
1098     }
1099   hide_cursor ();
1100   update_cursor (pos, 0);
1101 }
1102
1103
1104 static void
1105 ButtonReleaseProc (Widget w, XEvent *event, String *str, Cardinal *num)
1106 {
1107   if (! SELECTEDP ())
1108     return;
1109
1110   XtOwnSelection (w, XA_PRIMARY, CurrentTime,
1111                   covert_selection, lose_selection, NULL);
1112   update_cursor (mtext_property_start (selection), 0);
1113 }
1114
1115 static
1116 void
1117 Button2Proc (Widget w, XEvent *event, String *str, Cardinal *num)
1118 {
1119   if (! SELECTEDP ())
1120     {
1121       /* We don't have a local selection.  */
1122       XtGetSelectionValue (w, XA_PRIMARY, XA_TEXT, get_selection, NULL,
1123                            CurrentTime);
1124     }
1125   else
1126     {
1127       int from = mtext_property_start (selection);
1128       int to = mtext_property_end (selection);
1129       MText *this_mt;
1130       int pos;
1131       int x = event->xbutton.x;
1132       int y = event->xbutton.y - top.ascent;
1133
1134       if (control.orientation_reversed)
1135         x -= win_width;
1136       pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1137       
1138       XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1139       mtext_detach_property (selection);
1140       hide_cursor ();
1141       this_mt = mtext_copy (mtext (), 0, mt, from, to);
1142       update_cursor (pos, 0);
1143       insert_chars (this_mt);
1144       m17n_object_unref (this_mt);
1145     }
1146 }
1147
1148 static void
1149 ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
1150 {
1151   int pos;
1152   int x = event->xbutton.x;
1153   int y = event->xbutton.y;
1154
1155   if (control.orientation_reversed)
1156     x -= win_width;
1157   if (y < cur.y0)
1158     pos = top.from, y -= top.ascent;
1159   else
1160     pos = cur.from, y -= cur.y0 + cur.ascent;
1161   pos = COORDINATES_POSITION (pos, nchars + 1, x, y);
1162
1163   if (pos == cursor.from)
1164     return;
1165
1166   hide_cursor ();
1167   if (SELECTEDP ())
1168     {
1169       /* Selection range changed.  */
1170       int from = mtext_property_start (selection);
1171       int to = mtext_property_end (selection);
1172       int start_y0 = sel_start.y0, start_y1 = sel_start.y1;
1173       int end_y0 = sel_end.y0, end_y1 = sel_end.y1;
1174
1175       if (cursor.from == from)
1176         {
1177           /* Starting position changed.  */
1178           if (pos <= from)
1179             {
1180               /* Enlarged.  We can simply overdraw if not using
1181                  antialiased text.  */
1182               select_region (pos, to);
1183               redraw (sel_start.y0, start_y1, control.anti_alias, 0);
1184             }
1185           else if (pos < to)
1186             {
1187               /* Shrunken.  Previous selection face must be cleared.  */
1188               select_region (pos, to);
1189               redraw (start_y0, sel_start.y1, 1, 0);
1190             }
1191           else if (pos == to)
1192             {
1193               /* Shrunken to zero.  */
1194               XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1195               mtext_detach_property (selection);
1196               redraw (start_y0, end_y1, 1, 0);
1197             }
1198           else
1199             {
1200               /* Full update is necessary.  */
1201               select_region (to, pos);
1202               redraw (start_y0, sel_end.y1, 1, 0);
1203             }
1204         }
1205       else
1206         {
1207           /* Ending position changed.  */
1208           if (pos < from)
1209             {
1210               /* Full update is necessary.  */
1211               select_region (pos, from);
1212               redraw (sel_start.y0, end_y1, 1, 0);
1213             }
1214           else if (pos == from)
1215             {
1216               /* Shrunken to zero.  */
1217               XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1218               mtext_detach_property (selection);
1219               redraw (start_y0, end_y1, 1, 0);
1220             }
1221           else if (pos < to)
1222             {
1223               /* Shrunken.  Previous selection face must be cleared.  */
1224               select_region (from, pos);
1225               redraw (sel_end.y0, end_y1, 1, 0);
1226             }
1227           else
1228             {
1229               /* Enlarged.  We can simply overdraw if not using
1230                  antialiased text.  */
1231               select_region (from, pos);
1232               redraw (end_y0, sel_end.y1, control.anti_alias, 0);
1233             }
1234         }
1235     }
1236   else
1237     {
1238       /* Newly selected.  */
1239       select_region (pos, cursor.from);
1240       redraw (sel_start.y0, sel_end.y1, 0, 0);
1241     }
1242   update_cursor (pos, 1);
1243 }
1244
1245 void
1246 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1247 {
1248   int from;
1249   MDrawGlyphInfo info;
1250   int height;
1251   int cursor_pos = cursor.from;
1252
1253   if (((int) position) < 0)
1254     {
1255       /* Scroll down.  */
1256       int pos;
1257
1258       from = top.from;
1259       height = top.y1 - top.y0;
1260       while (from > 0)
1261         {
1262           pos = bol (from - 1, 0);
1263           GLYPH_INFO (pos, from - 1, info);
1264           if (height + info.this.height > win_height)
1265             break;
1266           height += info.this.height;
1267           from = info.line_from;
1268         }
1269       if (cursor_pos >= top.to)
1270         {
1271           cursor_pos = top.from;
1272           pos = top.to;
1273           while (cursor_pos < nchars)
1274             {
1275               GLYPH_INFO (pos, pos, info);
1276               if (height + info.this.height > win_height)
1277                 break;
1278               height += info.this.height;
1279               cursor_pos = pos;
1280               pos = info.line_to;
1281             }
1282         }
1283     }
1284   else if (cur.to < nchars)
1285     {
1286       /* Scroll up, but leave at least one line.  */
1287       from = cur.to;
1288       height = cur.y1;
1289       while (from < nchars)
1290         {
1291           GLYPH_INFO (from, from, info);
1292           if (height + info.this.height > win_height
1293               || info.line_to >= nchars)
1294             break;
1295           height += info.this.height;
1296           from = info.line_to;
1297         }
1298       if (from == nchars)
1299         from = info.line_from;
1300       if (cursor_pos < from)
1301         cursor_pos = from;
1302     }
1303   else
1304     /* Scroll up to make the cursor line top.  */
1305     from = cur.from;
1306   hide_cursor ();
1307   reseat (from);
1308   update_cursor (cursor_pos, 1);
1309 }
1310
1311 void
1312 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1313 {
1314   float persent = *(float *) persent_ptr;
1315   int pos1, pos2 = nchars * persent;
1316   MDrawGlyphInfo info;
1317
1318   hide_cursor ();
1319   pos1 = bol (pos2, 0);
1320   GLYPH_INFO (pos1, pos2, info);
1321   pos1 = info.line_from;
1322   reseat (pos1);
1323   update_cursor (pos1, 1);
1324 }
1325
1326
1327 static void
1328 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1329 {
1330   XKeyEvent *key_event = (XKeyEvent *) event;
1331   char buf[512];
1332   KeySym keysym = NoSymbol;
1333   int ret;
1334   /* If set to 1, do not update target_x_position.  */
1335   int keep_target_x_position = 0;
1336   MText *produced;
1337
1338   if (current_input_context
1339       && minput_filter (current_input_context, Mnil, event))
1340     return;
1341   if (event->type == KeyRelease)
1342     return;
1343
1344   hide_cursor ();
1345
1346   produced = mtext ();
1347   ret = minput_lookup (current_input_context, Mnil, event, produced);
1348   if (mtext_len (produced) > 0)
1349     insert_chars (produced);
1350   if (ret)
1351     ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1352   m17n_object_unref (produced);
1353
1354   switch (keysym)
1355     {
1356     case XK_Delete:
1357       {
1358         int n = 0;
1359
1360         if (SELECTEDP ())
1361           {
1362             n = (mtext_property_end (selection)
1363                  - mtext_property_start (selection));
1364             mtext_detach_property (selection);
1365           }
1366         else if (cursor.from < nchars)
1367           {
1368             /* Delete the following grapheme cluster.  */
1369             n = cursor.to - cursor.from;
1370           }
1371         if (n != 0)
1372           delete_char (n);
1373       }
1374       break;
1375
1376     case XK_BackSpace:
1377       {
1378         int n = 0;
1379
1380         if (SELECTEDP ())
1381           {
1382             /* Delete selected region.  */
1383             n = (mtext_property_end (selection)
1384                  - mtext_property_start (selection));
1385             mtext_detach_property (selection);
1386           }
1387         else if (cursor.from > 0)
1388           {
1389             /* Delete the preceding character.  */
1390             n = -1;
1391           }
1392         if (n != 0)
1393           delete_char (n);
1394       }
1395       break;
1396
1397     case XK_Left:
1398       if (SELECTEDP ())
1399         {
1400           mtext_detach_property (selection);
1401           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1402         }
1403       if (logical_move)
1404         {
1405           if (cursor.prev_from >= 0)
1406             update_cursor (cursor.prev_from, 0);
1407         }
1408       else
1409         {
1410           if (cursor.left_from >= 0)
1411             update_cursor (cursor.left_from, 0);
1412         }
1413       break;
1414
1415     case XK_Right:
1416       if (SELECTEDP ())
1417         {
1418           mtext_detach_property (selection);
1419           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1420         }
1421       if (logical_move)
1422         {
1423           if (cursor.next_to >= 0)
1424             update_cursor (cursor.to, 0);
1425         }
1426       else
1427         {
1428           if (cursor.right_from >= 0)
1429             update_cursor (cursor.right_from, 0);
1430         }
1431       break;
1432
1433     case XK_Down:
1434       if (SELECTEDP ())
1435         {
1436           mtext_detach_property (selection);
1437           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1438         }
1439       if (cur.to <= nchars)
1440         {
1441           MDrawGlyphInfo info;
1442           int pos;
1443
1444           GLYPH_INFO (cur.from, cur.to, info);
1445           pos = COORDINATES_POSITION (cur.from, nchars + 1,
1446                                       target_x_position, info.y);
1447           keep_target_x_position = 1;
1448           update_cursor (pos, 0);
1449         }
1450       break;
1451
1452     case XK_Up:
1453       if (SELECTEDP ())
1454         {
1455           mtext_detach_property (selection);
1456           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1457         }
1458       if (cur.from > 0)
1459         {
1460           MDrawMetric rect;
1461           int y;
1462           int pos = bol (cur.from - 1, 0);
1463
1464           TEXT_EXTENTS (pos, cur.from - 1, rect);
1465           y = rect.height + rect.y - 1;
1466           pos = COORDINATES_POSITION (pos, nchars,
1467                                       target_x_position, y);
1468           keep_target_x_position = 1;
1469           update_cursor (pos, 0);
1470         }
1471       break;
1472
1473     case XK_Page_Down:
1474       if (SELECTEDP ())
1475         {
1476           mtext_detach_property (selection);
1477           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1478         }
1479       if (top.from < nchars)
1480         ScrollProc (w, NULL, (XtPointer) 1);
1481       break;
1482
1483     case XK_Page_Up:
1484       if (SELECTEDP ())
1485         {
1486           mtext_detach_property (selection);
1487           redraw (sel_start.y0, sel_end.y1, 1, 0);;
1488         }
1489       if (top.from > 0)
1490         ScrollProc (w, NULL, (XtPointer) -1);
1491       break;
1492
1493     default:
1494       if (ret > 0)
1495         {
1496           if (buf[0] == 17) /* C-q */
1497             {
1498               XtAppSetExitFlag (context);
1499               return;
1500             }
1501           else if (buf[0] == 12) /* C-l */
1502             {
1503               redraw (0, win_height, 1, 1);
1504               return;
1505             }
1506           else
1507             {
1508               MText *temp = mtext ();
1509
1510               mtext_cat_char (temp, buf[0] == '\r' ? '\n' : buf[0]);
1511               if (current_input_context)
1512                 mtext_put_prop (temp, 0, 1, Mlanguage,
1513                                 current_input_context->im->language);
1514               insert_chars (temp);
1515               m17n_object_unref (temp);
1516             }
1517         }
1518     }
1519
1520   if (! keep_target_x_position)
1521     target_x_position = cursor.x;
1522 }
1523
1524 void
1525 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1526 {
1527   char *name = (char *) client_data;
1528   FILE *fp;
1529   int from = -1, to = 0;
1530   
1531   if (name)
1532     {
1533       free (filename);
1534       filename = strdup (name);
1535     }
1536
1537   fp = fopen (filename, "w");
1538   if (! fp)
1539     {
1540       fprintf (stderr, "Open for write fail: %s", filename);
1541       return;
1542     }
1543
1544   if (SELECTEDP ())
1545     {
1546       from = mtext_property_start (selection);
1547       to = mtext_property_end (selection);
1548       mtext_detach_property (selection);
1549     }
1550
1551   mconv_encode_stream (Mcoding_utf_8, mt, fp);
1552   fclose (fp);
1553   if (from >= 0)
1554     select_region (from, to);
1555 }
1556
1557 void
1558 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1559 {
1560   MText *new;
1561
1562   hide_cursor ();
1563   if (SELECTEDP ())
1564     mtext_detach_property (selection);
1565   serialized = (int) client_data;
1566   if (! serialized)
1567     new = mtext_deserialize (mt);
1568   else
1569     {
1570       MPlist *plist = mplist ();
1571
1572       mplist_push (plist, Mt, Mface);
1573       mplist_push (plist, Mt, Mlanguage);
1574       new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1575       m17n_object_unref (plist);
1576     }
1577   if (new)
1578     {
1579       m17n_object_unref (mt);
1580       mt = new;
1581       serialized = ! serialized;
1582       nchars = mtext_len (mt);
1583       update_top (0);
1584     }
1585   update_cursor (0, 1);
1586   redraw (0, win_height, 1, 1);
1587 }
1588
1589 void
1590 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1591 {
1592   XtAppSetExitFlag (context);
1593 }
1594
1595 MText *
1596 read_file ()
1597 {
1598   FILE *fp = fopen (filename, "r");
1599
1600   if (! fp)
1601     FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1602   mt = mconv_decode_stream (Mcoding_utf_8, fp);
1603   fclose (fp);
1604   if (! mt)
1605     FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1606   return mt;
1607 }
1608
1609 void
1610 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1611 {
1612   int data = (int) client_data;
1613   int i;
1614
1615   if (data == 0)
1616     {
1617       control.enable_bidi = 0;
1618       control.orientation_reversed = 0;
1619     }
1620   else
1621     {
1622       control.enable_bidi = 1;
1623       control.orientation_reversed = data == 2;
1624     }
1625   for (i = 0; i < 3; i++)
1626     {
1627       if (i == data)
1628         XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1629       else
1630         XtSetArg (arg[0], XtNleftBitmap, None);
1631       XtSetValues (BidiMenus[i], arg, 1);
1632     }
1633
1634   update_cursor (cursor.from, 1);
1635   redraw (0, win_height, 1, 0);
1636 }
1637
1638 extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
1639
1640 void
1641 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1642 {
1643   int data = (int) client_data;
1644   int i;
1645
1646   if (data == 0)
1647     control.max_line_width = 0;
1648   else
1649     {
1650       control.max_line_width = win_width;
1651       control.line_break = (data == 1 ? NULL : line_break);
1652     }
1653   for (i = 0; i < 3; i++)
1654     {
1655       if (i == data)
1656         XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1657       else
1658         XtSetArg (arg[0], XtNleftBitmap, None);
1659       XtSetValues (LineBreakMenus[i], arg, 1);
1660     }
1661
1662   update_cursor (cursor.from, 1);
1663   redraw (0, win_height, 1, 0);
1664 }
1665
1666 void
1667 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1668 {
1669   int data = (int) client_data;
1670   int i, from, to;
1671
1672   switch (data)
1673     {
1674     case 0:
1675       logical_move = 1;
1676       from = 0, to = 2;
1677       break;
1678     case 1:
1679       logical_move = 0;
1680       from = 0, to = 2;
1681       break;
1682     case 2:
1683       control.cursor_bidi = 0, control.cursor_width = -1;
1684       from = 2, to = 5;
1685       break;
1686     case 3:
1687       control.cursor_bidi = 0, control.cursor_width = 2;
1688       from = 2, to = 5;
1689       break;
1690     default:
1691       control.cursor_bidi = 1;
1692       from = 2, to = 5;
1693       break;
1694     }
1695
1696   for (i = from; i < to; i++)
1697     {
1698       if (i == data)
1699         XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1700       else
1701         XtSetArg (arg[0], XtNleftBitmap, None);
1702       XtSetValues (CursorMenus[i], arg, 1);
1703     }
1704
1705   redraw (0, win_height, 1, 0);
1706 }
1707
1708 static void
1709 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
1710 {
1711   int idx = (int) client_data;
1712
1713   if (idx == -2 ? current_input_method < 0
1714       : idx == -1 ? auto_input_method
1715       : idx == current_input_method)
1716     return;
1717
1718   XtSetArg (arg[0], XtNleftBitmap, None);
1719   if (auto_input_method)
1720     {
1721       XtSetValues (InputMethodMenus[1], arg, 1);
1722       auto_input_method = 0;
1723     }
1724   else if (current_input_method < 0)
1725     XtSetValues (InputMethodMenus[0], arg, 1);
1726   else
1727     XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
1728
1729   if (idx == -1)
1730     {
1731       auto_input_method = 1;
1732       hide_cursor ();
1733     }
1734   else
1735     select_input_method (idx);
1736   XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1737   XtSetValues (InputMethodMenus[idx + 2], arg, 1);
1738 }
1739
1740 void
1741 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
1742 {
1743   int idx = (int) client_data;
1744   int from, to;
1745   int old_y1;
1746
1747   if (! SELECTEDP ())
1748     return;
1749
1750   XtAppAddWorkProc (context, show_cursor, NULL);
1751   from = mtext_property_start (selection);
1752   to = mtext_property_end (selection);
1753   old_y1 = sel_end.y1;
1754
1755   mtext_detach_property (selection);
1756   if (idx >= 0)
1757     {
1758       MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
1759                                             MTEXTPROP_REAR_STICKY);
1760       mtext_push_property (mt, from, to, prop);
1761       m17n_object_unref (prop);
1762     }
1763   else
1764     mtext_pop_prop (mt, from, to, Mface);
1765   if (from < top.to)
1766     update_top (top.from);
1767   update_cursor (cursor.from, 1);
1768   select_region (from, to);
1769   update_region (sel_start.y0, old_y1, sel_end.y1);
1770   if (cur.y1 > win_height)
1771     {
1772       while (cur.y1 > win_height)
1773         {
1774           reseat (top.to);
1775           update_cursor (cursor.from, 1);
1776         }
1777     }
1778 }
1779
1780 void
1781 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
1782 {
1783   MSymbol sym = (MSymbol) client_data;
1784   int from, to;
1785   int old_y1;
1786
1787   if (! SELECTEDP ())
1788     return;
1789
1790   XtAppAddWorkProc (context, show_cursor, NULL);
1791   from = mtext_property_start (selection);
1792   to = mtext_property_end (selection);
1793   old_y1 = sel_end.y1;
1794
1795   mtext_detach_property (selection);
1796   if (sym != Mnil)
1797     mtext_put_prop (mt, from, to, Mlanguage, sym);
1798   else
1799     mtext_pop_prop (mt, from, to, Mlanguage);
1800
1801   if (from < top.to)
1802     update_top (top.from);
1803   update_cursor (cursor.from, 1);
1804   select_region (from, to);
1805   update_region (sel_start.y0, old_y1, sel_end.y1);
1806   if (cur.y1 > win_height)
1807     {
1808       while (cur.y1 > win_height)
1809         {
1810           reseat (top.to);
1811           update_cursor (cursor.from, 1);
1812         }
1813     }
1814 }
1815
1816 void
1817 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
1818 {
1819   int narrowed = (int) client_data;
1820   FILE *mdump;
1821   int from, to;
1822   MConverter *converter;
1823
1824   if (narrowed)
1825     {
1826       if (! SELECTEDP ())
1827         return;
1828       from = mtext_property_start (selection);
1829       to = mtext_property_end (selection);
1830     }
1831   else
1832     {
1833       from = 0;
1834       to = nchars;
1835     }
1836
1837   if (! narrowed)
1838     mdump = popen ("mdump -q -p a4", "w");
1839   else
1840     mdump = popen ("mdump -q", "w");
1841   if (! mdump)
1842     return;
1843   converter = mconv_stream_converter (Mcoding_utf_8, mdump);
1844   mconv_encode_range (converter, mt, from, to);
1845   mconv_free_converter (converter);
1846   fclose (mdump);
1847 }
1848
1849 void
1850 input_status (MInputContext *ic, MSymbol command)
1851 {
1852   XFillRectangle (display, input_status_pixmap, gc_inv,
1853                   0, 0, input_status_width, input_status_height);
1854   if (command == Minput_status_draw)
1855     {
1856       MDrawMetric rect;
1857
1858       mtext_put_prop (ic->status, 0, mtext_len (ic->status),
1859                       Mface, face_input_status);
1860       if (ic->im->language != Mnil)
1861         mtext_put_prop (ic->status, 0, mtext_len (ic->status),
1862                         Mlanguage, ic->im->language);
1863       mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
1864                           &input_status_control, NULL, NULL, &rect);
1865       mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
1866                                input_status_width - rect.width - 2, - rect.y,
1867                                ic->status, 0, mtext_len (ic->status),
1868                                &input_status_control);
1869     }
1870   XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
1871   XtSetValues (CurIMStatus, arg, 1);
1872 }
1873
1874 int
1875 compare_input_method (const void *elt1, const void *elt2)
1876 {
1877   const MInputMethod *im1 = *(MInputMethod **) elt1;
1878   const MInputMethod *im2 = *(MInputMethod **) elt2;
1879   MSymbol lang1, lang2;
1880
1881   if (im1->language == Mnil)
1882     return 1;
1883   if (im1->language == im2->language)
1884     return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
1885   if (im1->language == Mt)
1886     return 1;
1887   if (im2->language == Mt)
1888     return -1;
1889   lang1 = msymbol_get (im1->language, Mlanguage);
1890   lang2 = msymbol_get (im2->language, Mlanguage);
1891   return strcmp (msymbol_name (lang1), msymbol_name (lang2));
1892 }
1893
1894 void
1895 setup_input_methods (int with_xim)
1896 {
1897   MInputMethod *im = NULL;
1898   MInputXIMArgIM arg_xim;
1899   MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
1900   MPlist *pl;
1901   int i = 0;
1902
1903   num_input_methods = mplist_length (plist);
1904
1905   if (with_xim)
1906     {
1907       arg_xim.display = display;
1908       arg_xim.db = NULL;  
1909       arg_xim.res_name = arg_xim.res_class = NULL;
1910       arg_xim.locale = NULL;
1911       arg_xim.modifier_list = NULL;
1912       im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
1913       if (im)
1914         num_input_methods++;
1915     }
1916   input_method_table = calloc (num_input_methods, sizeof (MInputMethod *));
1917   if (im)
1918     input_method_table[i++] = im;
1919   for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
1920     {
1921       MDatabase *mdb = mplist_value (pl);
1922       MSymbol *tag = mdatabase_tag (mdb);
1923
1924       if (tag[1] != Mnil)
1925         {
1926           im = minput_open_im (tag[1], tag[2], NULL);
1927           if (im)
1928             input_method_table[i++] = im;
1929         }
1930     }
1931
1932   m17n_object_unref (plist);
1933   num_input_methods = i;
1934   qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
1935          compare_input_method);
1936   current_input_context = NULL;
1937
1938   mplist_put (minput_driver->callback_list, Minput_status_start,
1939               (void *) input_status);
1940   mplist_put (minput_driver->callback_list, Minput_status_draw,
1941               (void *) input_status);
1942   mplist_put (minput_driver->callback_list, Minput_status_done,
1943               (void *) input_status);
1944 }
1945
1946
1947 static void
1948 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
1949 {
1950   char *msg;
1951
1952   if (num && *num > 0)
1953     {
1954       int bytes = 0, i;
1955
1956       for (i = 0; i < *num; i++)
1957         bytes += strlen (str[i]) + 1;
1958       msg = alloca (bytes);
1959       strcpy (msg, str[0]);
1960       for (i = 1; i < *num; i++)
1961         strcat (msg, " "), strcat (msg, str[i]);
1962     }
1963   else if (cursor.from < nchars)
1964     {
1965       int c = mtext_ref_char (mt, cursor.from);
1966       char *name = mchar_get_prop (c, Mname);
1967
1968       if (! name)
1969         name = "";
1970       msg = alloca (10 + strlen (name));
1971       sprintf (msg, "U+%04X %s", c, name);
1972     }
1973   else
1974     {
1975       msg = "";
1976     }
1977   XtSetArg (arg[0], XtNlabel, msg);
1978   XtSetValues (MessageWidget, arg, 1);
1979 }
1980
1981 typedef struct
1982 {
1983   int type;
1984   char *name1, *name2;
1985   XtCallbackProc proc;
1986   XtPointer client_data;
1987   int status;
1988   Widget w;
1989 } MenuRec;
1990
1991 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
1992
1993 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
1994
1995 MenuRec FileMenu[] =
1996   { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
1997     { 0, "Save", NULL, SaveProc, NULL, -1 },
1998     { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
1999     { 1 },
2000     { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2001     { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2002     { 1 },
2003     { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2004     { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2005     { 1 },
2006     { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2007
2008 void
2009 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2010 {
2011   MenuRec *rec = (MenuRec *) client_data;
2012   Position x, y;
2013
2014   XtSetArg (arg[0], XtNvalue, "");
2015   XtSetArg (arg[1], XtNlabel, rec->name1);
2016   XtSetValues (FileDialogWidget, arg, 2);
2017   XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2018   XtSetArg (arg[0], XtNx, x + 20);
2019   XtSetArg (arg[1], XtNy, y + 10);
2020   XtSetValues (FileShellWidget, arg, 2);
2021   XtPopup (FileShellWidget, XtGrabExclusive);
2022 }
2023
2024 void
2025 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2026 {
2027   FILE *fp;
2028   char *label;
2029
2030   XtPopdown (FileShellWidget);
2031   if ((int) client_data == 1)
2032     return;
2033   XtSetArg (arg[0], XtNlabel, &label);
2034   XtGetValues (FileDialogWidget, arg, 1);
2035   if (strcmp (label, FileMenu[0].name1) == 0)
2036     {
2037       /* Open a file */
2038       free (filename);
2039       filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2040       fp = fopen (filename, "r");
2041       hide_cursor ();
2042       m17n_object_unref (mt);
2043       if (fp)
2044         {
2045           mt = mconv_decode_stream (Mcoding_utf_8, fp);
2046           fclose (fp);
2047           if (! mt)
2048             mt = mtext ();
2049         }
2050       else
2051         mt = mtext ();
2052       serialized = 0;
2053       nchars = mtext_len (mt);
2054       update_top (0);
2055       update_cursor (0, 1);
2056       redraw (0, win_height, 1, 1);
2057     }
2058   else if (strcmp (label, FileMenu[2].name1) == 0)
2059     SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2060   else
2061     fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2062 }
2063
2064 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS)            \
2065   ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2066    (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA),        \
2067    (MENU).status = (STATUS))
2068
2069
2070 Widget
2071 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2072                     char *menu_name, MenuRec *menus, int num_menus, char *help)
2073 {
2074   Widget button, menu;
2075   char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2076                <LeaveWindow>: reset() MenuHelp()\n\
2077                <BtnDown>: reset() PopupMenu()\n\
2078                <BtnUp>: highlight()"; 
2079   int i;
2080   MenuRec *m;
2081   char *trans;
2082   int max_width = 0;
2083
2084   menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2085   for (i = 0; i < num_menus; i++)
2086     {
2087       m = menus + i;
2088       if (m->type == 0)
2089         {
2090           if (m->proc)
2091             {
2092               int n = 0;
2093
2094               if (m->status >= 0)
2095                 {
2096                   XtSetArg (arg[n], XtNleftMargin, 20), n++;
2097                   if (m->status > 0)
2098                     XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2099                 }
2100               m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2101                                             menu, arg, n);
2102               XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2103             }
2104           else
2105             {
2106               XtSetArg (arg[0], XtNsensitive, False);
2107               m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2108                                             menu, arg, 2);
2109             }
2110         }
2111       else
2112         {
2113           XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2114         }
2115       if (m->name2)
2116         max_width = 1;
2117     }
2118   trans = alloca (strlen (fmt) + strlen (help));
2119   sprintf (trans, fmt, help);
2120   XtSetArg (arg[0], XtNmenuName, menu_name);
2121   XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2122   XtSetArg (arg[2], XtNinternalWidth, 2);
2123   XtSetArg (arg[3], XtNhighlightThickness, 1);
2124   XtSetArg (arg[4], XtNleft, XawChainLeft);
2125   XtSetArg (arg[5], XtNright, XawChainLeft);
2126   i = 6;
2127   if (left)
2128     XtSetArg (arg[i], XtNfromHoriz, left), i++;
2129   button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2130                                   arg, i);
2131
2132   if (max_width)
2133     {
2134       int height, ascent, *width = alloca (sizeof (int) * num_menus);
2135       int *len = alloca (sizeof (int) * num_menus);
2136
2137       XFontSet font_set;
2138       XFontSetExtents *fontset_extents;
2139
2140       XtSetArg (arg[0], XtNfontSet, &font_set);
2141       XtGetValues (button, arg, 1);
2142
2143       fontset_extents = XExtentsOfFontSet (font_set);
2144       height = fontset_extents->max_logical_extent.height;
2145       ascent = - fontset_extents->max_logical_extent.y;
2146
2147       for (i = 0; i < num_menus; i++)
2148         if (menus[i].name2)
2149           {
2150             len[i] = strlen (menus[i].name2);
2151             width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2152             if (max_width < width[i])
2153               max_width = width[i];
2154           }
2155       for (i = 0; i < num_menus; i++)
2156         if (menus[i].name2)
2157           {
2158             Pixmap pixmap = XCreatePixmap (display,
2159                                            RootWindow (display, screen),
2160                                            max_width, height, 1);
2161             XFillRectangle (display, pixmap, mono_gc_inv,
2162                             0, 0, max_width, height);
2163             XmbDrawString (display, pixmap, font_set, mono_gc,
2164                            max_width - width[i], ascent,
2165                            menus[i].name2, len[i]);
2166             XtSetArg (arg[0], XtNrightBitmap, pixmap);
2167             XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2168             XtSetValues (menus[i].w, arg, 2);
2169           }
2170     }
2171
2172   return button;
2173 }
2174
2175
2176 XtActionsRec actions[] = {
2177   {"Expose", ExposeProc},
2178   {"Configure", ConfigureProc},
2179   {"Key", KeyProc},
2180   {"ButtonPress", ButtonProc},
2181   {"ButtonRelease", ButtonReleaseProc},
2182   {"ButtonMotion", ButtonMoveProc},
2183   {"Button2Press", Button2Proc},
2184   {"MenuHelp", MenuHelpProc}
2185 };
2186
2187
2188 /* Print the usage of this program (the name is PROG), and exit with
2189    EXIT_CODE.  */
2190
2191 void
2192 help_exit (char *prog, int exit_code)
2193 {
2194   char *p = prog;
2195
2196   while (*p)
2197     if (*p++ == '/')
2198       prog = p;
2199
2200   printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2201   printf ("Display FILE on a window and allow users to edit it.\n");
2202   printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2203   printf ("The following OPTIONs are available.\n");
2204   printf ("  %-13s %s", "--version", "print version number\n");
2205   printf ("  %-13s %s", "-h, --help", "print this message\n");
2206   exit (exit_code);
2207 }
2208
2209 int
2210 main (int argc, char **argv)
2211 {
2212   Widget form, BodyWidget, w;
2213   char *fontset_name = NULL;
2214   int col = 80, row = 32;
2215   /* Translation table for TextWidget.  */
2216   String trans = "<Expose>: Expose()\n\
2217                   <Configure>: Configure()\n\
2218                   <Key>: Key()\n\
2219                   <KeyUp>: Key()\n\
2220                   <Btn1Down>: ButtonPress()\n\
2221                   <Btn1Up>: ButtonRelease()\n\
2222                   <Btn1Motion>: ButtonMotion()\n\
2223                   <Btn2Down>: Button2Press()";
2224   /* Translation table for the top form widget.  */
2225   String trans2 = "<Key>: Key()\n\
2226                    <KeyUp>: Key()";
2227   String pop_face_trans
2228     = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2229        <LeaveWindow>: MenuHelp() reset()\n\
2230        <Btn1Down>: set()\n\
2231        <Btn1Up>: notify() unset()"; 
2232   String pop_lang_trans
2233     = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2234        <LeaveWindow>: MenuHelp() reset()\n\
2235        <Btn1Down>: set()\n\
2236        <Btn1Up>: notify() unset()"; 
2237   int font_width, font_ascent, font_descent;
2238   int with_xim = 0;
2239   int i, j;
2240
2241   setlocale (LC_ALL, "");
2242   /* Create the top shell.  */
2243   XtSetLanguageProc (NULL, NULL, NULL);
2244   ShellWidget = XtOpenApplication (&context, "MEdit", NULL, 0, &argc, argv,
2245                                    NULL, sessionShellWidgetClass, NULL, 0);
2246   display = XtDisplay (ShellWidget);
2247   screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2248
2249   /* Parse the remaining command line arguments.  */
2250   for (i = 1; i < argc; i++)
2251     {
2252       if (! strcmp (argv[i], "--help")
2253           || ! strcmp (argv[i], "-h"))
2254         help_exit (argv[0], 0);
2255       else if (! strcmp (argv[i], "--version"))
2256         {
2257           printf ("medit (m17n library) %s\n", VERSION);
2258           printf ("Copyright (C) 2003 AIST, JAPAN\n");
2259           exit (0);
2260         }
2261       else if (! strcmp (argv[i], "--geometry"))
2262         {
2263           i++;
2264           if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2265             help_exit (argv[0], 1);
2266         }
2267       else if (! strcmp (argv[i], "--fontset"))
2268         {
2269           i++;
2270           fontset_name = strdup (argv[i]);
2271         }
2272       else if (! strcmp (argv[i], "--with-xim"))
2273         {
2274           with_xim = 1;
2275         }
2276       else if (argv[i][0] != '-')
2277         {
2278           filename = strdup (argv[i]);
2279         }
2280       else
2281         {
2282           fprintf (stderr, "Unknown option: %s", argv[i]);
2283           help_exit (argv[0], 1);
2284         }
2285     }
2286   if (! filename)
2287     help_exit (argv[0], 1);
2288
2289   mdatabase_dir = ".";
2290   /* Initialize the m17n library.  */
2291   M17N_INIT ();
2292   if (merror_code != MERROR_NONE)
2293     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2294
2295   mt = read_file (filename);
2296   serialized = 0;
2297
2298   nchars = mtext_len (mt);
2299
2300   {
2301     MFace *face = mface ();
2302
2303     mface_put_prop (face, Mbackground, msymbol ("blue"));
2304     mface_put_prop (face, Mforeground, msymbol ("yellow"));
2305     selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2306     m17n_object_unref (face);
2307   }
2308
2309   /* This tells ExposeProc to initialize everything.  */
2310   top.from = -1;
2311   
2312   XA_TEXT = XInternAtom (display, "TEXT", False);
2313   XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2314   XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2315   {
2316     MPlist *plist = mplist ();
2317     MFace *face;
2318     MFont *font;
2319
2320     mplist_put (plist, msymbol ("widget"), ShellWidget);
2321     if (fontset_name)
2322       {
2323         MFontset *fontset = mfontset (fontset_name);
2324         
2325         face = mface ();
2326         mface_put_prop (face, Mfontset, fontset);
2327         m17n_object_unref (fontset);
2328         mplist_add (plist, Mface, face);
2329         m17n_object_unref (face);
2330       }
2331     frame = mframe (plist);
2332     m17n_object_unref (plist);
2333     face_default = (MFace *) mframe_get_prop (frame, Mface);
2334     face_default_fontset = mface ();
2335     mface_put_prop (face_default_fontset, Mfontset,
2336                     mface_get_prop (face_default, Mfontset));
2337
2338     font = (MFont *) mframe_get_prop (frame, Mfont);
2339     default_font_size = (int) mfont_get_prop (font, Msize);
2340   }
2341
2342   font_width = (int) mframe_get_prop (frame, Mfont_width);
2343   font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2344   font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2345   win_width = font_width * col;
2346   win_height = (font_ascent + font_descent) * row;
2347
2348   {
2349     MFaceBoxProp prop;
2350
2351     prop.width = 4;
2352     prop.color_top = prop.color_left = msymbol ("magenta");
2353     prop.color_bottom = prop.color_right = msymbol ("red");
2354     prop.inner_hmargin = prop.inner_vmargin = 1;
2355     prop.outer_hmargin = prop.outer_vmargin = 2;
2356
2357     face_box = mface ();
2358     mface_put_prop (face_box, Mbox, &prop);
2359   }
2360
2361   face_courier = mface ();
2362   mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2363   face_helvetica = mface ();
2364   mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2365   face_times = mface ();
2366   mface_put_prop (face_times, Mfamily, msymbol ("times"));
2367   face_dv_ttyogesh = mface ();
2368   mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2369   face_freesans = mface ();
2370   mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2371   face_freemono = mface ();
2372   mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2373
2374   face_xxx_large = mface ();
2375   mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2376   {
2377     MFont *latin_font = mframe_get_prop (frame, Mfont);
2378     MFont *dev_font = mfont ();
2379     MFont *thai_font = mfont ();
2380     MFont *tib_font = mfont ();
2381     MFontset *fontset;
2382     MSymbol unicode_bmp = msymbol ("unicode-bmp");
2383     MSymbol no_ctl = msymbol ("no-ctl");
2384
2385     mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2386     mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2387     mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2388     mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2389     mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2390     mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2391
2392     fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
2393     mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
2394                            latin_font, Mnil, 0);
2395     mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
2396                            dev_font, no_ctl, 0);
2397     mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
2398                            thai_font, no_ctl, 0);
2399     mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
2400                            tib_font, no_ctl, 0);
2401     face_no_ctl_fontset = mface ();
2402     mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
2403     m17n_object_unref (fontset);
2404
2405     free (dev_font);
2406     free (thai_font);
2407     free (tib_font);
2408   }
2409
2410   setup_input_methods (with_xim);
2411
2412   gc = DefaultGC (display, screen);
2413
2414   XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2415   XtSetArg (arg[1], XtNdefaultDistance, 2);
2416   form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2417
2418   XtSetArg (arg[0], XtNborderWidth, 0);
2419   XtSetArg (arg[1], XtNdefaultDistance, 2);
2420   XtSetArg (arg[2], XtNtop, XawChainTop);
2421   XtSetArg (arg[3], XtNbottom, XawChainTop);
2422   XtSetArg (arg[4], XtNleft, XawChainLeft);
2423   XtSetArg (arg[5], XtNright, XawChainRight);
2424   XtSetArg (arg[6], XtNresizable, True);
2425   HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2426   XtSetArg (arg[7], XtNfromVert, HeadWidget);
2427   FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2428   XtSetArg (arg[7], XtNfromVert, FaceWidget);
2429   LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2430   XtSetArg (arg[3], XtNbottom, XawChainBottom);
2431   XtSetArg (arg[7], XtNfromVert, LangWidget);
2432   BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2433   XtSetArg (arg[2], XtNtop, XawChainBottom);
2434   XtSetArg (arg[7], XtNfromVert, BodyWidget);
2435   TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2436
2437   FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2438                                         HeadWidget, NULL, 0);
2439   XtSetArg (arg[0], XtNvalue, "");
2440   FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2441                                             FileShellWidget, arg, 1);
2442   XawDialogAddButton (FileDialogWidget, "OK",
2443                       FileDialogProc, (XtPointer) 0);
2444   XawDialogAddButton (FileDialogWidget, "CANCEL",
2445                       FileDialogProc, (XtPointer) 1);
2446
2447   CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2448                                        (char *) check_bits,
2449                                        check_width, check_height);
2450   {
2451     unsigned long valuemask = GCForeground;
2452     XGCValues values;
2453
2454     values.foreground = 1;
2455     mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2456     values.foreground = 0;
2457     mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2458   }
2459
2460   {
2461     MenuRec *menus;
2462     int num_menus = 10;
2463
2464     if (num_menus < num_input_methods + 2)
2465       num_menus = num_input_methods + 2;
2466     if (num_menus < num_faces + 1)
2467       num_menus = num_faces + 1;
2468     menus = alloca (sizeof (MenuRec) * num_menus);
2469
2470     w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2471                             FileMenu, sizeof FileMenu / sizeof (MenuRec),
2472                             "File I/O, Serialization, Image, Quit");
2473
2474     SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2475     SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2476     SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2477     SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2478     SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2479     SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2480     w = create_menu_button (ShellWidget, HeadWidget, w,
2481                             "Cursor", "Cursor Menu",
2482                             menus, 6, "Cursor Movement Mode, Cursor Shape");
2483     CursorMenus[0] = menus[0].w;
2484     CursorMenus[1] = menus[1].w;
2485     CursorMenus[2] = menus[3].w;
2486     CursorMenus[3] = menus[4].w;
2487     CursorMenus[4] = menus[5].w;
2488
2489     SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2490     SetMenu (menus[1], 0, "Left  (|--> |)", NULL, BidiProc, 1, 1);
2491     SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2492     w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2493                             menus, 3, "BIDI Processing Mode");
2494     for (i = 0; i < 3; i++)
2495       BidiMenus[i] = menus[i].w;
2496
2497     SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2498     SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2499     SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2500     w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2501                             "LineBreak Menu",
2502                             menus, 3, "How to break lines");
2503     for (i = 0; i < 3; i++)
2504       LineBreakMenus[i] = menus[i].w;
2505
2506     SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2507     SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2508     for (i = 0; i < num_input_methods; i++)
2509       {
2510         MInputMethod *im = input_method_table[i];
2511         char *name1, *name2;
2512
2513         if (im->language != Mnil && im->language != Mt)
2514           {
2515             MSymbol sym = msymbol_get (im->language, Mlanguage);
2516             if (sym == Mnil)
2517               name1 = msymbol_name (im->language);
2518             else
2519               name1 = msymbol_name (sym);
2520             name2 = msymbol_name (im->name);
2521           }
2522         else
2523           name1 = msymbol_name (im->name), name2 = NULL;
2524
2525         SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
2526       }
2527     w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
2528                             "Input Method Menu", menus, i + 2,
2529                             "Select input method");
2530
2531     {
2532       unsigned long valuemask = GCForeground;
2533       XGCValues values;
2534
2535       XtSetArg (arg[0], XtNbackground, &values.foreground);
2536       XtGetValues (w, arg, 1);
2537       gc_inv = XCreateGC (display, RootWindow (display, screen),
2538                           valuemask, &values);
2539     }
2540
2541     InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
2542     for (i = 0; i < num_input_methods + 2; i++)
2543       InputMethodMenus[i] = menus[i].w;
2544
2545     input_status_width = font_width * 8;
2546     input_status_height = (font_ascent + font_descent) * 2.4;
2547     input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
2548                                          input_status_width,
2549                                          input_status_height,
2550                                          DefaultDepth (display, screen));
2551     {
2552       MFaceBoxProp prop;
2553
2554       prop.width = 1;
2555       prop.color_top = prop.color_bottom
2556         = prop.color_left = prop.color_right = Mnil;
2557       prop.inner_hmargin = prop.inner_vmargin = 1;
2558       prop.outer_hmargin = prop.outer_vmargin = 0;
2559       face_input_status = mface ();
2560       mface_put_prop (face_input_status, Mbox, &prop);
2561     }
2562
2563     XFillRectangle (display, input_status_pixmap, gc_inv,
2564                     0, 0, input_status_width, input_status_height);
2565     XtSetArg (arg[0], XtNfromHoriz, w);
2566     XtSetArg (arg[1], XtNleft, XawRubber);
2567     XtSetArg (arg[2], XtNright, XawChainRight);
2568     XtSetArg (arg[3], XtNborderWidth, 0);
2569     XtSetArg (arg[4], XtNlabel, "          ");
2570     XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2571     CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
2572                                        HeadWidget, arg, 6);
2573     XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
2574     XtSetArg (arg[1], XtNleft, XawChainRight);
2575     XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
2576     CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
2577                                          HeadWidget, arg, 5);
2578
2579     XtSetArg (arg[0], XtNborderWidth, 0);
2580     XtSetArg (arg[1], XtNleft, XawChainLeft);
2581     XtSetArg (arg[2], XtNright, XawChainLeft);
2582     w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
2583     for (i = 0; i < num_faces;)
2584       {
2585         char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
2586         char *label = label_menu + 5;            /* "Xxxx" */
2587
2588         for (j = i; j < num_faces && face_table[j].face; j++)
2589           SetMenu (menus[j - i], 0, face_table[j].name, NULL,
2590                    FaceProc, j, -1);
2591         w = create_menu_button (ShellWidget, FaceWidget, w,
2592                                 label, label_menu,
2593                                 menus, j - i, "Push face property");
2594         i = j;
2595       }
2596
2597     XtSetArg (arg[0], XtNfromHoriz, w);
2598     XtSetArg (arg[1], XtNleft, XawChainLeft);
2599     XtSetArg (arg[2], XtNright, XawChainLeft);
2600     XtSetArg (arg[3], XtNhorizDistance, 10);
2601     XtSetArg (arg[4], XtNlabel, "Pop");
2602     XtSetArg (arg[5], XtNtranslations,
2603               XtParseTranslationTable (pop_face_trans));
2604     w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
2605                                FaceWidget, arg, 6);
2606     XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
2607
2608     XtSetArg (arg[0], XtNfromHoriz, w);
2609     XtSetArg (arg[1], XtNleft, XawChainLeft);
2610     XtSetArg (arg[2], XtNright, XawChainRight);
2611     XtSetArg (arg[3], XtNlabel, "");
2612     XtSetArg (arg[4], XtNborderWidth, 0);
2613     XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2614     CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
2615                                            FaceWidget, arg, 6);
2616
2617     XtSetArg (arg[0], XtNborderWidth, 0);
2618     XtSetArg (arg[1], XtNleft, XawChainLeft);
2619     XtSetArg (arg[2], XtNright, XawChainLeft);
2620     w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
2621     {
2622       MPlist *plist[11], *pl;
2623       char langname[3];
2624
2625       for (i = 0; i < 11; i++) plist[i] = NULL;
2626       langname[2] = '\0';
2627       for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
2628         for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
2629           {
2630             MSymbol sym = msymbol_exist (langname);
2631             MSymbol fullname;
2632
2633             if (sym != Mnil
2634                 && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
2635               {
2636                 char *name = msymbol_name (fullname);
2637                 char c = name[0];
2638
2639                 if (c >= 'A' && c <= 'Z')
2640                   {
2641                     int idx = (c < 'U') ? (c - 'A') / 2 : 10;
2642
2643                     pl = plist[idx];
2644                     if (! pl)
2645                       pl = plist[idx] = mplist ();
2646                     for (; mplist_next (pl); pl = mplist_next (pl))
2647                       if (strcmp (name, (char *) mplist_value (pl)) < 0)
2648                         break;
2649                     mplist_push (pl, sym, fullname);
2650                   }
2651               }
2652           }
2653
2654       for (i = 0; i < 11; i++)
2655         if (plist[i])
2656           {
2657             char *name = alloca (9);
2658
2659             sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
2660             if (i == 10)
2661               name[7] = 'Z';
2662             for (j = 0, pl = plist[i]; mplist_next (pl);
2663                  j++, pl = mplist_next (pl))
2664               SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
2665                        msymbol_name (mplist_key (pl)),
2666                        LangProc, mplist_key (pl), -1);
2667             w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
2668                                     menus, j, "Push language property");
2669           }
2670       for (i = 0; i < 11; i++)
2671         if (plist[i])
2672           m17n_object_unref (plist[i]);
2673     }
2674     XtSetArg (arg[0], XtNfromHoriz, w);
2675     XtSetArg (arg[1], XtNleft, XawChainLeft);
2676     XtSetArg (arg[2], XtNright, XawChainLeft);
2677     XtSetArg (arg[3], XtNhorizDistance, 10);
2678     XtSetArg (arg[4], XtNlabel, "Pop");
2679     XtSetArg (arg[5], XtNtranslations,
2680               XtParseTranslationTable (pop_lang_trans));
2681     w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
2682                                LangWidget, arg, 6);
2683     XtAddCallback (w, XtNcallback, LangProc, Mnil);
2684
2685     XtSetArg (arg[0], XtNfromHoriz, w);
2686     XtSetArg (arg[1], XtNleft, XawChainLeft);
2687     XtSetArg (arg[2], XtNright, XawChainRight);
2688     XtSetArg (arg[3], XtNlabel, "");
2689     XtSetArg (arg[4], XtNborderWidth, 0);
2690     XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2691     CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
2692                                            LangWidget, arg, 6);
2693   }
2694
2695   XtSetArg (arg[0], XtNheight, win_height);
2696   XtSetArg (arg[1], XtNwidth, 10);
2697   XtSetArg (arg[2], XtNleft, XawChainLeft);
2698   XtSetArg (arg[3], XtNright, XawChainLeft);
2699   SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
2700                                       arg, 4);
2701   XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
2702   XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
2703
2704   XtSetArg (arg[0], XtNheight, win_height);
2705   XtSetArg (arg[1], XtNwidth, win_width);
2706   XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
2707   XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
2708   XtSetArg (arg[4], XtNleft, XawChainLeft);
2709   XtSetArg (arg[5], XtNright, XawChainRight);
2710   TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
2711                                       arg, 5);
2712
2713   XtSetArg (arg[0], XtNborderWidth, 0);
2714   XtSetArg (arg[1], XtNleft, XawChainLeft);
2715   XtSetArg (arg[2], XtNright, XawChainRight);
2716   XtSetArg (arg[3], XtNresizable, True);
2717   XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
2718   MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
2719                                          TailWidget, arg, 5);
2720
2721   memset (&control, 0, sizeof control);
2722   control.two_dimensional = 1;
2723   control.enable_bidi = 1;
2724   control.anti_alias = 1;
2725   control.min_line_ascent = font_ascent;
2726   control.min_line_descent = font_descent;
2727   control.max_line_width = win_width;
2728   control.with_cursor = 1;
2729   control.cursor_width = 2;
2730   control.partial_update = 1;
2731   control.ignore_formatting_char = 1;
2732
2733   memset (&input_status_control, 0, sizeof input_status_control);
2734   input_status_control.enable_bidi = 1;
2735
2736   XtAppAddActions (context, actions, XtNumber (actions));
2737   XtRealizeWidget (ShellWidget);
2738
2739   win = XtWindow (TextWidget);
2740
2741   XtAppMainLoop (context);
2742
2743   if (current_input_context)
2744     minput_destroy_ic (current_input_context);
2745   for (i = 0; i < num_input_methods; i++)
2746     minput_close_im (input_method_table[i]);
2747   m17n_object_unref (frame);
2748   m17n_object_unref (mt);
2749   m17n_object_unref (face_xxx_large);
2750   m17n_object_unref (face_box);
2751   m17n_object_unref (face_courier);
2752   m17n_object_unref (face_helvetica);
2753   m17n_object_unref (face_times);
2754   m17n_object_unref (face_dv_ttyogesh);
2755   m17n_object_unref (face_freesans);
2756   m17n_object_unref (face_freemono);
2757   m17n_object_unref (face_default_fontset);
2758   m17n_object_unref (face_no_ctl_fontset);
2759   m17n_object_unref (face_input_status);
2760   m17n_object_unref (selection);
2761
2762   M17N_FINI ();
2763
2764   free (fontset_name);
2765   free (filename);
2766   free (input_method_table);
2767   free (InputMethodMenus);
2768
2769   XFreeGC (display, mono_gc);
2770   XFreeGC (display, mono_gc_inv);
2771   XFreeGC (display, gc_inv);
2772   XtUninstallTranslations (form);
2773   XtUninstallTranslations (TextWidget);
2774   XtDestroyWidget (ShellWidget);
2775   XtDestroyApplicationContext (context);
2776
2777   exit (0);
2778 }
2779 #endif /* not FOR_DOXYGEN */