1 /* medit.c -- simple multilingual editor. -*- coding: euc-jp; -*-
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 @enpage m17n-edit edit multilingual text
26 @section m17n-edit-synopsis SYNOPSIS
28 m17n-edit [ XT-OPTION ...] [ OPTION ... ] FILE
30 @section m17n-edit-description DESCRIPTION
32 Display FILE on a window and allow users to edit it.
34 XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).
36 The following OPTIONs are available.
50 This program is to demonstrate how to use the m17n GUI API.
51 Although m17n-edit directly uses the GUI API, the API is mainly
52 for toolkit libraries or to implement XOM (X Output Method), not
53 for direct use from application programs.
56 @japage m17n-edit ¿¸À¸ì¥Æ¥¥¹¥È¤ÎÊÔ½¸
58 @section m17n-edit-synopsis SYNOPSIS
60 m17n-edit [ XT-OPTION ...] [ OPTION ... ] FILE
62 @section m17n-edit-description DESCRIPTION
64 FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤·¡¢¥æ¡¼¥¶¤¬ÊÔ½¸¤Ç¤¤ë¤è¤¦¤Ë¤¹¤ë¡£
66 XT-OPTIONs ¤Ï Xt ¤Îɸ½à¤Î°ú¿ô¤Ç¤¢¤ë¡£ (e.g. -fn, -fg).
68 °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ¤ë¡£
74 ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£
78 ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£
82 ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£m17n-edit
83 ¤ÏľÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥¥Ã¥È¥é¥¤¥Ö¥é
84 ¥ê¤äXOM (X Output Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
85 ¥à¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
92 #include <sys/types.h>
100 #ifdef HAVE_X11_XAW_COMMAND_H
102 #include <X11/keysym.h>
103 #include <X11/Xatom.h>
104 #include <X11/Intrinsic.h>
105 #include <X11/StringDefs.h>
106 #include <X11/Shell.h>
108 #include <m17n-gui.h>
109 #include <m17n-misc.h>
112 #include <X11/Xaw/Command.h>
113 #include <X11/Xaw/Box.h>
114 #include <X11/Xaw/Form.h>
115 #include <X11/Xaw/Dialog.h>
116 #include <X11/Xaw/Scrollbar.h>
117 #include <X11/Xaw/Toggle.h>
118 #include <X11/Xaw/SimpleMenu.h>
119 #include <X11/Xaw/SmeBSB.h>
120 #include <X11/Xaw/SmeLine.h>
121 #include <X11/Xaw/MenuButton.h>
123 /* Global variables. */
128 /* For the X Window System. */
131 /* GCs for normal drawing, filling by background color, normal drawing
132 on bitmap (i.e. pixmap of depth 1), filling bitmap by background
134 GC gc, gc_inv, mono_gc, mono_gc_inv;
136 Atom XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING; /* X Selection types. */
137 XtAppContext context;
138 int default_font_size;
142 Shell - Form -+- Head -- File, Cursor, Bidi, LineBreak, InputMethod, CurIM;
143 +- Face -- Size, Family, Style, Color, Misc, Pop, CurFace
144 +- Lang -- A-B, C-D, ..., U-Z, Pop, CurLang
145 +- Body -- Sbar, Text
149 Widget ShellWidget, HeadWidget, TailWidget, MessageWidget;
150 Widget CursorMenus[5], BidiMenus[3], LineBreakMenus[3], *InputMethodMenus;
151 Widget SbarWidget, TextWidget;
152 Widget FileShellWidget, FileDialogWidget;
153 Widget FaceWidget, CurFaceWidget, LangWidget, CurLangWidget;
154 Widget CurIMLang, CurIMStatus;
156 int win_width, win_height; /* Size of TextWidget. */
159 Pixmap input_status_pixmap;
160 int input_status_width, input_status_height;
162 /* Bitmap for "check" glyph. */
163 #define check_width 9
164 #define check_height 8
165 static unsigned char check_bits[] = {
166 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
167 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 };
170 /* For the m17n library. */
173 int nchars; /* == mtext_len (mt) */
175 MDrawControl control, input_status_control;
176 MTextProperty *selection;
181 MFace *face_xxx_large;
183 MFace *face_courier, *face_helvetica, *face_times;
184 MFace *face_dv_ttyogesh, *face_freesans, *face_freeserif, *face_freemono;
185 MFace *face_default_fontset, *face_no_ctl_fontset;
186 MFace *face_input_status;
188 MSymbol Mcoding_compound_text;
190 int logical_move = 1; /* If 0, move cursor visually. */
194 MSymbol language, name;
198 InputMethodInfo *input_method_table;
200 int num_input_methods;
201 int current_input_method = -1; /* i.e. none */
202 int unicode_input_method = -1;
203 int auto_input_method = 0;
204 int saved_input_method = -3;
205 MInputContext *current_input_context;
212 { {"Menu Size", NULL},
213 {"xx-small", &mface_xx_small},
214 {"x-small", &mface_x_small},
215 {"small", &mface_small},
216 {"normalsize", &mface_normalsize},
217 {"large", &mface_large},
218 {"x-large", &mface_x_large},
219 {"xx-large", &mface_xx_large},
220 {"xxx-large", &face_xxx_large},
222 {"Menu Family", NULL},
223 {"courier", &face_courier},
224 {"helvetica", &face_helvetica},
225 {"times", &face_times},
226 {"dv-ttyogesh", &face_dv_ttyogesh},
227 {"freesans", &face_freesans},
228 {"freeserif", &face_freeserif},
229 {"freemono", &face_freemono},
231 {"Menu Style", NULL},
232 {"medium", &mface_medium},
233 {"bold", &mface_bold},
234 {"italic", &mface_italic},
236 {"Menu Color", NULL},
237 {"black", &mface_black},
238 {"white", &mface_white},
240 {"green", &mface_green},
241 {"blue", &mface_blue},
242 {"cyan", &mface_cyan},
243 {"yello", &mface_yellow},
244 {"magenta", &mface_magenta},
247 {"normal", &mface_normal_video},
248 {"reverse", &mface_reverse_video},
249 {"underline", &mface_underline},
251 {"No CTL", &face_no_ctl_fontset} };
254 int num_faces = sizeof (face_table) / sizeof (struct FaceRec);
256 /* Information about a physical line metric. */
259 int from; /* BOL position of the line. */
260 int to; /* BOL position of the next line. */
261 int y0, y1; /* Top and bottom Y position of the line. */
262 int ascent; /* Height of the top Y position. */
265 struct LineInfo top; /* Topmost line. */
266 struct LineInfo cur; /* Line containing cursor. */
267 struct LineInfo sel_start; /* Line containing selection start. */
268 struct LineInfo sel_end; /* Line containing selection end. */
270 MDrawGlyphInfo cursor; /* Information about the cursor glyph. */
272 /* X position to keep on vertical (up and down) cursor motion. */
273 int target_x_position;
275 /* Interface macros for m17n-lib drawing routines. */
277 /* Draw a text in the range $FROM to $TO of the M-text #MT at the
278 coordinate ($X, $Y) */
279 #define DRAW_TEXT(x, y, from, to) \
280 mdraw_text_with_control \
281 (frame, (MDrawWindow) win, \
282 control.orientation_reversed ? x + win_width : x, y, \
283 mt, from, to, &control)
285 /* Store the extents of a text in the range $FROM to $TO in the
286 structure $RECT (type MDrawMetric). */
287 #define TEXT_EXTENTS(from, to, rect) \
288 mdraw_text_extents (frame, mt, from, (to), &control, NULL, NULL, &(rect))
290 /* Store the glyph information of a character at the position $POS in
291 the struct $INFO (type MDrawGlyphInfo) assuming that the text from
292 $FROM is written at the coordinate (0, 0). */
293 #define GLYPH_INFO(from, pos, info) \
294 mdraw_glyph_info (frame, mt, from, (pos), &control, &(info))
296 /* Set $X and $Y to the coordinate of character at position $POS
297 assuming that the text from $FROM is written at the coordinate (0,
299 #define COORDINATES_POSITION(from, pos, x, y) \
300 mdraw_coordinates_position (frame, mt, (from), (pos), (x), (y), &control)
302 /* Interface macros for X library. */
303 #define COPY_AREA(y0, y1, to) \
304 XCopyArea (display, win, win, gc, 0, (y0), win_width, (y1) - (y0), 0, (to))
306 #define CLEAR_AREA(x, y, w, h) \
307 XClearArea (display, win, (x), (y), (w), (h), False)
309 #define SELECTEDP() \
310 mtext_property_mtext (selection)
312 /* Format MSG by FMT and print the result to the stderr, and exit. */
313 #define FATAL_ERROR(fmt, arg) \
315 fprintf (stderr, fmt, arg); \
320 /* If POS is greater than zero, move POS back to the beginning of line
321 (BOL) position. If FORWARD is nonzero, move POS forward instead.
322 Return the new position. */
324 bol (int pos, int forward)
326 int limit = forward ? nchars : 0;
328 pos = mtext_character (mt, pos, limit, '\n');
329 return (pos < 0 ? limit : pos + 1);
332 /* Update the structure #TOP (struct LineInfo) to make $POS the first
333 character position of the screen. */
337 int from = bol (pos, 0);
340 GLYPH_INFO (from, pos, info);
341 top.from = info.line_from;
342 top.to = info.line_to;
344 top.y1 = info.metrics.height;
345 top.ascent = - info.metrics.y;
349 /* Update the scroll bar so that the text of the range $FROM to $TO
350 are shown on the window. */
352 update_scroll_bar (int from, int to)
354 float top = (float) from / nchars;
355 float shown = (float) (to - from) / nchars;
356 XtArgVal *l_top = (XtArgVal *) ⊤
357 XtArgVal *l_shown = (XtArgVal *) &shown;
359 XtSetArg (arg[0], XtNtopOfThumb, *l_top);
360 XtSetArg (arg[1], XtNshown, *l_shown);
361 XtSetValues (SbarWidget, arg, 2);
365 /* Redraw the window area between $Y0 and $Y1 (both Y-codinates). If
366 $CLEAR is nonzero, clear the area before drawing. If $SCROLL_BAR
367 is nonzero, update the scoll bar. */
369 redraw (int y0, int y1, int clear, int scroll_bar)
374 int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
375 struct LineInfo *line;
377 if (clear || control.anti_alias)
378 CLEAR_AREA (0, y0, win_width, y1 - y0);
380 /* Find a line closest to y0. It is a cursor line if the cursor is
381 Y0, otherwise the top line. */
386 /* If there exists a selected region, check it too. */
387 if (sel_y0 > line->y0 && y0 >= sel_y0)
392 info.metrics.height = line->y1 - y;
393 info.metrics.y = - line->ascent;
394 info.line_to = line->to;
395 while (y + info.metrics.height <= y0)
397 y += info.metrics.height;
401 GLYPH_INFO (from, from, info);
403 if (y + info.metrics.height <= y0)
406 y0 = y - info.metrics.y;
408 while (to < nchars && y < y1)
410 GLYPH_INFO (to, to, info);
411 y += info.metrics.height;
417 DRAW_TEXT (0, y0, from, to);
422 GLYPH_INFO (to, to, info);
423 if (y + info.metrics.height >= win_height)
426 y += info.metrics.height;
428 update_scroll_bar (top.from, to);
433 /* Set the current input method spot to the correct position. */
435 set_input_method_spot ()
437 int x = cursor.x + (control.orientation_reversed ? win_width : 0);
438 int pos = cursor.from > 0 ? cursor.from - 1 : 0;
441 int size = 0, ratio = 0, i;
444 n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
446 for (i = n - 1; i >= 0; i--)
449 size = (int) mface_get_prop (faces[i], Msize);
451 ratio = (int) mface_get_prop (faces[i], Mratio);
454 size = default_font_size;
456 size = size * ratio / 100;
457 minput_set_spot (current_input_context, x, cur.y0 + cur.ascent,
458 cur.ascent, cur.y1 - (cur.y0 + cur.ascent), size,
463 /* Redraw the cursor. If $CLEAR is nonzero, clear the cursor area
466 redraw_cursor (int clear)
468 if (control.cursor_bidi)
470 /* We must update the whole line of the cursor. */
471 int beg = bol (cur.from, 0);
472 int end = bol (cur.to - 1, 1);
474 int y0 = cur.y0, y1 = cur.y1;
478 TEXT_EXTENTS (beg, cur.from, rect);
483 TEXT_EXTENTS (cur.to, end, rect);
486 redraw (y0, y1, clear, 0);
494 if (control.orientation_reversed)
495 x += win_width - cursor.logical_width;
496 CLEAR_AREA (x, cur.y0, cursor.logical_width, cursor.metrics.height);
498 DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
503 /* Update the information about the location of cursor to the position
504 $POS. If $FULL is nonzero, update the information fully only from
505 the information about the top line. Otherwise, trust the current
506 information in the structure $CUR. */
508 update_cursor (int pos, int full)
512 control.cursor_pos = pos;
515 /* CUR is inaccurate. We can trust only TOP. */
516 GLYPH_INFO (top.from, pos, cursor);
517 cur.y0 = top.ascent + cursor.y + cursor.metrics.y;
519 else if (pos < cur.from)
521 int from = bol (pos, 0);
523 TEXT_EXTENTS (from, cur.from, rect);
524 GLYPH_INFO (from, pos, cursor);
525 cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.metrics.y);
527 else if (pos < cur.to)
529 GLYPH_INFO (cur.from, pos, cursor);
533 GLYPH_INFO (cur.from, pos, cursor);
534 cur.y0 += cur.ascent + cursor.y + cursor.metrics.y;
537 cur.from = cursor.line_from;
538 cur.to = cursor.line_to;
539 cur.y1 = cur.y0 + cursor.metrics.height;
540 cur.ascent = - cursor.metrics.y;
544 /* Update the information about the selected region. */
554 from = mtext_property_start (selection);
555 to = mtext_property_end (selection);
559 int pos = bol (from, 0);
561 TEXT_EXTENTS (pos, top.from, rect);
562 sel_start.y0 = top.y0 - rect.height;
563 sel_start.ascent = - rect.y;
564 GLYPH_INFO (pos, from, info);
565 if (pos < info.line_from)
566 sel_start.y0 += - rect.y + info.y + info.metrics.y;
570 GLYPH_INFO (top.from, from, info);
571 sel_start.y0 = top.ascent + info.y + info.metrics.y;
573 sel_start.ascent = -info.metrics.y;
574 sel_start.y1 = sel_start.y0 + info.metrics.height;
575 sel_start.from = info.line_from;
576 sel_start.to = info.line_to;
578 if (to <= sel_start.to)
584 GLYPH_INFO (sel_start.from, to, info);
585 sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.metrics.y;
586 sel_end.y1 = sel_end.y0 + info.metrics.height;
587 sel_end.ascent = - info.metrics.y;
588 sel_end.from = info.line_from;
589 sel_end.to = info.line_to;
594 /* Select the text in the region from $FROM to $TO. */
596 select_region (int from, int to)
601 pos = from, from = to, to = pos;
602 mtext_push_property (mt, from, to, selection);
607 /* Setup the window to display the character of $POS at the top left
613 /* Top and bottom Y positions to redraw. */
616 if (pos + 1000 < top.from)
617 y0 = 0, y1 = win_height;
618 else if (pos < top.from)
621 TEXT_EXTENTS (pos, top.from, rect);
622 if (rect.height >= win_height * 0.9)
627 COPY_AREA (0, win_height - y1, y1);
630 else if (pos < top.to)
632 /* No need of redrawing. */
635 else if (pos < top.from + 1000)
637 TEXT_EXTENTS (top.from, pos, rect);
638 if (rect.height >= win_height * 0.9)
642 y0 = win_height - rect.height;
643 COPY_AREA (rect.height, win_height, 0);
648 y0 = 0, y1 = win_height;
654 update_cursor (pos, 1);
656 update_cursor (cursor.from, 1);
658 redraw (y0, y1, 1, 1);
662 static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
665 /* Select an input method accoding to $IDX. If $IDX is negative, turn
666 off the current input method, otherwide turn on the input method
667 input_method_table[$IDX]. */
669 select_input_method (idx)
671 int previous_input_method = current_input_method;
673 if (idx == current_input_method)
675 if (current_input_method >= 0)
677 minput_destroy_ic (current_input_context);
678 current_input_context = NULL;
679 current_input_method = -1;
683 && input_method_table[idx].available >= 0)
685 InputMethodInfo *im = input_method_table + idx;
687 if (im->available == 0)
690 im->im = minput_open_im (im->language, im->name, NULL);
693 MInputXIMArgIM arg_xim;
695 arg_xim.display = display;
697 arg_xim.res_name = arg_xim.res_class = NULL;
698 arg_xim.locale = NULL;
699 arg_xim.modifier_list = NULL;
700 im->im = minput_open_im (Mnil, im->name, &arg_xim);
702 im->available = im->im ? 1 : -1;
706 if (im->language == Mnil)
708 MInputXIMArgIC arg_xic;
709 Window win = XtWindow (TextWidget);
711 arg_xic.input_style = 0;
712 arg_xic.client_win = arg_xic.focus_win = win;
713 arg_xic.preedit_attrs = arg_xic.status_attrs = NULL;
714 current_input_context = minput_create_ic (im->im, &arg_xic);
718 MInputGUIArgIC arg_ic;
720 arg_ic.frame = frame;
721 arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
722 arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
723 current_input_context = minput_create_ic (im->im, &arg_ic);
726 if (current_input_context)
728 current_input_method = idx;
729 set_input_method_spot ();
733 minput_close_im (im->im);
736 current_input_method = -1;
740 if (! auto_input_method)
742 XtSetArg (arg[0], XtNleftBitmap, None);
743 if (previous_input_method >= 0)
744 XtSetValues (InputMethodMenus[previous_input_method + 2], arg, 1);
746 XtSetValues (InputMethodMenus[0], arg, 1);
747 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
748 if (current_input_method >= 0)
749 XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
751 XtSetValues (InputMethodMenus[0], arg, 1);
754 if (current_input_method >= 0)
758 XtSetArg (arg[0], XtNlabel, &label);
759 XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
760 XtSetArg (arg[0], XtNlabel, label);
764 XtSetArg (arg[0], XtNlabel, "");
766 XtSetValues (CurIMLang, arg, 1);
769 static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
772 /* Display cursor according to the current information of #CUR.
773 $CLIENT_DATA is ignore. Most callback functions add this function
774 as a background processing procedure the current application (by
775 XtAppAddWorkProc) via the function hide_cursor. */
777 show_cursor (XtPointer client_data)
779 MFaceHLineProp *hline;
785 update_cursor (cursor.from, 1);
787 while (cur.y1 > win_height)
790 update_cursor (cursor.from, 1);
793 control.cursor_pos = cursor.from;
796 control.with_cursor = 1;
799 if (current_input_context)
800 set_input_method_spot ();
804 int pos = (SELECTEDP () ? mtext_property_start (selection)
805 : cursor.from > 0 ? cursor.from - 1
807 MFace *face = mface ();
808 MTextProperty *props[256];
809 int n = mtext_get_properties (mt, pos, Mface, props, 256);
811 char buf[256], *p = buf;
817 int size = (int) mfont_get_prop (cursor.font, Msize);
818 MSymbol family = mfont_get_prop (cursor.font, Mfamily);
819 MSymbol weight = mfont_get_prop (cursor.font, Mweight);
820 MSymbol style = mfont_get_prop (cursor.font, Mstyle);
821 MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
823 sprintf (p, "%dpt", size / 10), p += strlen (p);
825 strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
827 strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
829 strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
831 strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
835 mface_merge (face, face_default);
836 for (i = 0; i < n; i++)
837 if (props[i] != selection)
838 mface_merge (face, (MFace *) mtext_property_value (props[i]));
839 sym = (MSymbol) mface_get_prop (face, Mforeground);
841 strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
842 if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
843 strcat (p, ",rev"), p += strlen (p);
844 hline = mface_get_prop (face, Mhline);
845 if (hline && hline->width > 0)
846 strcat (p, ",ul"), p += strlen (p);
847 box = mface_get_prop (face, Mbox);
848 if (box && box->width > 0)
849 strcat (p, ",box"), p += strlen (p);
850 m17n_object_unref (face);
852 XtSetArg (arg[0], XtNborderWidth, 1);
853 XtSetArg (arg[1], XtNlabel, buf);
854 XtSetValues (CurFaceWidget, arg, 2);
857 if (control.cursor_pos < nchars)
859 MSymbol sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
863 XtSetArg (arg[0], XtNborderWidth, 0);
864 XtSetArg (arg[1], XtNlabel, "");
868 XtSetArg (arg[0], XtNborderWidth, 1);
869 sym = mlanguage_name (sym);
870 XtSetArg (arg[1], XtNlabel, msymbol_name (sym));
871 XtSetValues (CurLangWidget, arg, 2);
873 XtSetValues (CurLangWidget, arg, 2);
875 if (auto_input_method)
878 select_input_method (-1);
883 for (i = 0; i < num_input_methods; i++)
884 if (input_method_table[i].language == sym
885 && input_method_table[i].available >= 0)
887 if (i < num_input_methods)
888 select_input_method (i);
890 select_input_method (-1);
895 MenuHelpProc (MessageWidget, NULL, NULL, NULL);
901 /* Hide the cursor. */
905 control.with_cursor = 0;
907 XtAppAddWorkProc (context, show_cursor, NULL);
911 /* Update the window area between the Y-positions $Y0 and $OLD_Y1 to
912 $Y1 and $NEW_Y1 assuming that the text in the other area is not
915 update_region (int y0, int old_y1, int new_y1)
921 if (old_y1 < win_height)
923 COPY_AREA (old_y1, win_height, new_y1);
924 redraw (win_height - (old_y1 - new_y1), win_height, 1, 0);
927 redraw (new_y1, win_height, 1, 0);
929 else if (new_y1 > old_y1)
931 if (new_y1 < win_height)
932 COPY_AREA (old_y1, win_height, new_y1);
934 if (new_y1 > win_height)
936 redraw (y0, new_y1, 1, 1);
940 /* Delete the next $N characters. If $N is negative delete the
941 precious (- $N) characters. */
947 int y0, old_y1, new_y1;
949 int line_from = cursor.line_from;
952 from = cursor.from, to = from + n;
955 from = cursor.from + n;
957 if (cursor.from == cur.from)
959 /* We are at the beginning of line. */
960 int pos = cursor.prev_from;
962 if (cursor.from == top.from)
964 /* We are at the beginning of screen. We must scroll
966 GLYPH_INFO (bol (top.from - 1, 0), top.from - 1, info);
967 reseat (info.line_from);
969 update_cursor (pos, 1);
973 TEXT_EXTENTS (cur.from, bol (to + 1, 1), rect);
974 old_y1 = cur.y0 + rect.height;
976 /* Now delete a character. */
977 mtext_del (mt, from, to);
979 if (from >= top.from && from < top.to)
980 update_top (top.from);
981 update_cursor (from, 1);
984 if (line_from != cursor.line_from)
987 TEXT_EXTENTS (cur.from, bol (to, 1), rect);
988 new_y1 = cur.y0 + rect.height;
990 update_region (cur.y0, old_y1, new_y1);
994 /* Insert M-text $NEWTEXT at the current cursor position. */
996 insert_chars (MText *newtext)
998 int n = mtext_len (newtext);
1000 int y0, old_y1, new_y1;
1005 int n = (mtext_property_end (selection)
1006 - mtext_property_start (selection));
1007 mtext_detach_property (selection);
1012 if (cursor.line_from > 0
1013 && mtext_ref_char (mt, cursor.line_from - 1) != '\n')
1014 y0 -= control.min_line_descent;
1016 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
1017 old_y1 = y0 + rect.height;
1019 line_from = cursor.line_from;
1021 /* Now insert chars. */
1022 mtext_ins (mt, cursor.from, newtext);
1024 if (cur.from == top.from)
1025 update_top (top.from);
1026 update_cursor (cursor.from + n, 1);
1028 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
1029 new_y1 = cur.y0 + rect.height;
1031 update_region (y0, old_y1, new_y1);
1032 update_selection ();
1037 word_constituent_p (int c)
1039 MSymbol category = (MSymbol) mchar_get_prop (c, Mcategory);
1040 char *name = category != Mnil ? msymbol_name (category) : NULL;
1042 return (name && (name[0] == 'L' || name[0] == 'M'));
1049 int pos = cursor.from;
1051 while (pos < nchars && ! word_constituent_p (mtext_ref_char (mt, pos)))
1055 MTextProperty *prop = mtext_get_property (mt, pos, Mword);
1058 pos = mtext_property_end (prop);
1060 while (pos < nchars && word_constituent_p (mtext_ref_char (mt, pos)))
1063 update_cursor (pos, 0);
1069 int pos = cursor.from;
1071 while (pos > 0 && ! word_constituent_p (mtext_ref_char (mt, pos - 1)))
1075 MTextProperty *prop = mtext_get_property (mt, pos - 1, Mword);
1078 pos = mtext_property_start (prop);
1080 while (pos > 0 && word_constituent_p (mtext_ref_char (mt, pos - 1)))
1083 update_cursor (pos, 0);
1087 /* Convert the currently selected text to UTF8-STRING or
1088 COMPOUND-TEXT. It is called when someone requests the current
1089 value of the selection. */
1091 covert_selection (Widget w, Atom *selection_atom,
1092 Atom *target, Atom *return_type,
1093 XtPointer *value, unsigned long *length, int *format)
1095 unsigned char *buf = (unsigned char *) XtMalloc (4096);
1096 MText *this_mt = mtext ();
1097 int from = mtext_property_start (selection);
1098 int to = mtext_property_end (selection);
1102 mtext_copy (this_mt, 0, mt, from, to);
1103 if (*target == XA_TEXT)
1105 #ifdef X_HAVE_UTF8_STRING
1106 coding = Mcoding_utf_8;
1107 *return_type = XA_UTF8_STRING;
1109 coding = Mcoding_compound_text;
1110 *return_type = XA_COMPOUND_TEXT;
1113 else if (*target == XA_UTF8_STRING)
1115 coding = Mcoding_utf_8;
1116 *return_type = XA_UTF8_STRING;
1118 else if (*target == XA_STRING)
1123 for (i = 0; i < len; i++)
1124 if (mtext_ref_char (this_mt, i) >= 0x100)
1125 /* Can't encode in XA_STRING */
1127 coding = Mcoding_iso_8859_1;
1128 *return_type = XA_STRING;
1130 else if (*target == XA_COMPOUND_TEXT)
1132 coding = Mcoding_compound_text;
1133 *return_type = XA_COMPOUND_TEXT;
1138 len = mconv_encode_buffer (coding, this_mt, buf, 4096);
1139 m17n_object_unref (this_mt);
1143 *value = (XtPointer) buf;
1149 /* Unselect the text. It is called when we loose the selection. */
1151 lose_selection (Widget w, Atom *selection_atom)
1155 mtext_detach_property (selection);
1156 redraw (sel_start.y0, sel_end.y1, 1, 0);
1161 get_selection (Widget w, XtPointer cliend_data, Atom *selection, Atom *type,
1162 XtPointer value, unsigned long *length, int *format)
1167 if (*type == XT_CONVERT_FAIL || ! value)
1169 if (*type == XA_STRING)
1171 else if (*type == XA_COMPOUND_TEXT)
1172 coding = msymbol ("compound-text");
1173 #ifdef X_HAVE_UTF8_STRING
1174 else if (*type == XA_UTF8_STRING)
1175 coding = msymbol ("utf-8");
1180 this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
1181 if (! this_mt && *type != XA_UTF8_STRING)
1183 XtGetSelectionValue (w, XA_PRIMARY, XA_UTF8_STRING, get_selection, NULL,
1190 insert_chars (this_mt);
1191 m17n_object_unref (this_mt);
1200 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1202 XExposeEvent *expose = (XExposeEvent *) event;
1206 Dimension width_max, width;
1208 XtSetArg (arg[0], XtNwidth, &width);
1209 XtGetValues (XtParent (w), arg, 1);
1211 XtGetValues (HeadWidget, arg, 1);
1212 if (width_max < width)
1214 XtGetValues (FaceWidget, arg, 1);
1215 if (width_max < width)
1217 XtGetValues (LangWidget, arg, 1);
1218 if (width_max < width)
1220 XtSetArg (arg[0], XtNwidth, width_max);
1221 XtSetValues (HeadWidget, arg, 1);
1222 XtSetValues (FaceWidget, arg, 1);
1223 XtSetValues (LangWidget, arg, 1);
1224 XtSetValues (XtParent (w), arg, 1);
1225 XtSetValues (TailWidget, arg, 1);
1228 update_cursor (0, 1);
1229 redraw (0, win_height, 0, 1);
1230 if (current_input_method >= 0)
1232 int idx = current_input_method;
1234 current_input_method = -1;
1235 select_input_method (idx);
1241 redraw (expose->y, expose->y + expose->height, 0, 0);
1242 if (current_input_context
1243 && expose->y < cur.y0 && expose->y + expose->height < cur.y1)
1244 set_input_method_spot ();
1249 ConfigureProc (Widget w, XEvent *event, String *str, Cardinal *num)
1251 XConfigureEvent *configure = (XConfigureEvent *) event;
1254 control.max_line_width = win_width = configure->width;
1255 win_height = configure->height;
1256 mdraw_clear_cache (mt);
1258 update_cursor (0, 1);
1259 redraw (0, win_height, 1, 1);
1260 if (current_input_context)
1261 set_input_method_spot ();
1265 ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
1268 int x = event->xbutton.x;
1269 int y = event->xbutton.y - top.ascent;
1271 if (control.orientation_reversed)
1273 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1276 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1277 mtext_detach_property (selection);
1278 redraw (sel_start.y0, sel_end.y1, 1, 0);
1281 if (current_input_context
1282 && minput_filter (current_input_context, Minput_focus_move, NULL) == 0)
1284 MText *produced = mtext ();
1286 minput_lookup (current_input_context, Mnil, NULL, produced);
1287 if (mtext_len (produced) > 0)
1289 insert_chars (produced);
1290 if (pos >= cursor.from)
1291 pos += mtext_len (produced);
1293 m17n_object_unref (produced);
1295 update_cursor (pos, 0);
1300 ButtonReleaseProc (Widget w, XEvent *event, String *str, Cardinal *num)
1305 XtOwnSelection (w, XA_PRIMARY, CurrentTime,
1306 covert_selection, lose_selection, NULL);
1307 update_cursor (mtext_property_start (selection), 0);
1312 Button2Proc (Widget w, XEvent *event, String *str, Cardinal *num)
1316 /* We don't have a local selection. */
1317 XtGetSelectionValue (w, XA_PRIMARY, XA_TEXT, get_selection, NULL,
1322 int from = mtext_property_start (selection);
1323 int to = mtext_property_end (selection);
1326 int x = event->xbutton.x;
1327 int y = event->xbutton.y - top.ascent;
1329 if (control.orientation_reversed)
1331 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1333 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1334 mtext_detach_property (selection);
1336 this_mt = mtext_copy (mtext (), 0, mt, from, to);
1337 update_cursor (pos, 0);
1338 insert_chars (this_mt);
1339 m17n_object_unref (this_mt);
1344 ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
1347 int x = event->xbutton.x;
1348 int y = event->xbutton.y;
1350 if (control.orientation_reversed)
1353 pos = top.from, y -= top.ascent;
1355 pos = cur.from, y -= cur.y0 + cur.ascent;
1356 pos = COORDINATES_POSITION (pos, nchars + 1, x, y);
1358 if (pos == cursor.from)
1364 /* Selection range changed. */
1365 int from = mtext_property_start (selection);
1366 int to = mtext_property_end (selection);
1367 int start_y0 = sel_start.y0, start_y1 = sel_start.y1;
1368 int end_y0 = sel_end.y0, end_y1 = sel_end.y1;
1370 if (cursor.from == from)
1372 /* Starting position changed. */
1375 /* Enlarged. We can simply overdraw. */
1376 select_region (pos, to);
1377 redraw (sel_start.y0, start_y1, 0, 0);
1381 /* Shrunken. Previous selection face must be cleared. */
1382 select_region (pos, to);
1383 redraw (start_y0, sel_start.y1, 1, 0);
1387 /* Shrunken to zero. */
1388 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1389 mtext_detach_property (selection);
1390 redraw (start_y0, end_y1, 1, 0);
1394 /* Full update is necessary. */
1395 select_region (to, pos);
1396 redraw (start_y0, sel_end.y1, 1, 0);
1401 /* Ending position changed. */
1404 /* Full update is necessary. */
1405 select_region (pos, from);
1406 redraw (sel_start.y0, end_y1, 1, 0);
1408 else if (pos == from)
1410 /* Shrunken to zero. */
1411 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1412 mtext_detach_property (selection);
1413 redraw (start_y0, end_y1, 1, 0);
1417 /* Shrunken. Previous selection face must be cleared. */
1418 select_region (from, pos);
1419 redraw (sel_end.y0, end_y1, 1, 0);
1423 /* Enlarged. We can simply overdraw. */
1424 select_region (from, pos);
1425 redraw (end_y0, sel_end.y1, 0, 0);
1431 /* Newly selected. */
1432 select_region (pos, cursor.from);
1433 redraw (sel_start.y0, sel_end.y1, 0, 0);
1435 update_cursor (pos, 1);
1439 FocusInProc (Widget w, XEvent *event, String *str, Cardinal *num)
1441 if (current_input_context
1442 && minput_filter (current_input_context, Minput_focus_in, NULL) == 0)
1444 MText *produced = mtext ();
1446 minput_lookup (current_input_context, Mnil, NULL, produced);
1447 if (mtext_len (produced) > 0)
1450 insert_chars (produced);
1452 m17n_object_unref (produced);
1457 FocusOutProc (Widget w, XEvent *event, String *str, Cardinal *num)
1459 if (current_input_context
1460 && minput_filter (current_input_context, Minput_focus_out, NULL) == 0)
1462 MText *produced = mtext ();
1464 minput_lookup (current_input_context, Mnil, NULL, produced);
1465 if (mtext_len (produced) > 0)
1468 insert_chars (produced);
1470 m17n_object_unref (produced);
1475 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1478 MDrawGlyphInfo info;
1480 int cursor_pos = cursor.from;
1482 if (((int) position) < 0)
1488 height = top.y1 - top.y0;
1491 pos = bol (from - 1, 0);
1492 GLYPH_INFO (pos, from - 1, info);
1493 if (height + info.metrics.height > win_height)
1495 height += info.metrics.height;
1496 from = info.line_from;
1498 if (cursor_pos >= top.to)
1500 cursor_pos = top.from;
1502 while (cursor_pos < nchars)
1504 GLYPH_INFO (pos, pos, info);
1505 if (height + info.metrics.height > win_height)
1507 height += info.metrics.height;
1513 else if (cur.to < nchars)
1515 /* Scroll up, but leave at least one line. */
1518 while (from < nchars)
1520 GLYPH_INFO (from, from, info);
1521 if (height + info.metrics.height > win_height
1522 || info.line_to >= nchars)
1524 height += info.metrics.height;
1525 from = info.line_to;
1528 from = info.line_from;
1529 if (cursor_pos < from)
1533 /* Scroll up to make the cursor line top. */
1537 update_cursor (cursor_pos, 1);
1541 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1543 float persent = *(float *) persent_ptr;
1544 int pos1, pos2 = nchars * persent;
1545 MDrawGlyphInfo info;
1548 pos1 = bol (pos2, 0);
1549 GLYPH_INFO (pos1, pos2, info);
1550 pos1 = info.line_from;
1552 update_cursor (pos1, 1);
1555 static void InputMethodProc (Widget, XtPointer, XtPointer);
1558 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1560 XKeyEvent *key_event = (XKeyEvent *) event;
1562 KeySym keysym = NoSymbol;
1564 /* If set to 1, do not update target_x_position. */
1565 int keep_target_x_position = 0;
1567 int y0, old_y1, new_y1;
1574 if (current_input_context
1575 && minput_filter (current_input_context, Mnil, event))
1580 update_region (y0, old_y1, new_y1);
1584 if (event->type == KeyRelease)
1587 produced = mtext ();
1588 ret = minput_lookup (current_input_context, Mnil, event, produced);
1589 if (mtext_len (produced) > 0)
1590 insert_chars (produced);
1592 ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1593 m17n_object_unref (produced);
1595 if (saved_input_method > -3)
1597 InputMethodProc (w, (XtPointer) saved_input_method, NULL);
1598 saved_input_method = -3;
1609 n = (mtext_property_end (selection)
1610 - mtext_property_start (selection));
1611 mtext_detach_property (selection);
1613 else if (cursor.from < nchars)
1615 /* Delete the following grapheme cluster. */
1616 n = cursor.to - cursor.from;
1629 /* Delete selected region. */
1630 n = (mtext_property_end (selection)
1631 - mtext_property_start (selection));
1632 mtext_detach_property (selection);
1634 else if (cursor.from > 0)
1636 /* Delete the preceding character. */
1647 mtext_detach_property (selection);
1648 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1652 if (cursor.prev_from >= 0)
1653 update_cursor (cursor.prev_from, 0);
1657 if (cursor.left_from >= 0)
1658 update_cursor (cursor.left_from, 0);
1665 mtext_detach_property (selection);
1666 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1670 if (cursor.next_to >= 0)
1671 update_cursor (cursor.to, 0);
1675 if (cursor.right_from >= 0)
1676 update_cursor (cursor.right_from, 0);
1683 mtext_detach_property (selection);
1684 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1686 if (cur.to <= nchars)
1688 MDrawGlyphInfo info;
1691 GLYPH_INFO (cur.from, cur.to, info);
1692 pos = COORDINATES_POSITION (cur.from, nchars + 1,
1693 target_x_position, info.y);
1694 keep_target_x_position = 1;
1695 update_cursor (pos, 0);
1702 mtext_detach_property (selection);
1703 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1709 int pos = bol (cur.from - 1, 0);
1711 TEXT_EXTENTS (pos, cur.from - 1, rect);
1712 y = rect.height + rect.y - 1;
1713 pos = COORDINATES_POSITION (pos, nchars,
1714 target_x_position, y);
1715 keep_target_x_position = 1;
1716 update_cursor (pos, 0);
1723 mtext_detach_property (selection);
1724 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1726 if (top.from < nchars)
1727 ScrollProc (w, NULL, (XtPointer) 1);
1733 mtext_detach_property (selection);
1734 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1737 ScrollProc (w, NULL, (XtPointer) -1);
1741 if (key_event->state >= Mod1Mask)
1743 lose_selection (NULL, NULL);
1749 if (key_event->state >= Mod1Mask)
1751 lose_selection (NULL, NULL);
1759 if (buf[0] == 17) /* C-q */
1761 XtAppSetExitFlag (context);
1764 else if (buf[0] == 12) /* C-l */
1766 redraw (0, win_height, 1, 1);
1769 else if (buf[0] == '='
1770 && (event->xkey.state & ControlMask)
1771 && unicode_input_method >= 0)
1773 saved_input_method = current_input_method;
1774 InputMethodProc (w, (XtPointer) unicode_input_method, NULL);
1775 minput_filter (current_input_context, msymbol ("C-u"), NULL);
1779 MText *temp = mtext ();
1781 mtext_cat_char (temp, buf[0] == '\r' ? '\n'
1782 : ((unsigned char *) buf)[0]);
1783 if (current_input_context)
1784 mtext_put_prop (temp, 0, 1, Mlanguage,
1785 current_input_context->im->language);
1786 insert_chars (temp);
1787 m17n_object_unref (temp);
1792 if (! keep_target_x_position)
1793 target_x_position = cursor.x;
1797 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1799 char *name = (char *) client_data;
1801 int from = -1, to = 0;
1806 filename = strdup (name);
1809 fp = fopen (filename, "w");
1812 fprintf (stderr, "Open for write fail: %s", filename);
1818 from = mtext_property_start (selection);
1819 to = mtext_property_end (selection);
1820 mtext_detach_property (selection);
1823 mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
1826 select_region (from, to);
1830 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1836 mtext_detach_property (selection);
1837 serialized = (int) client_data;
1839 new = mtext_deserialize (mt);
1842 MPlist *plist = mplist ();
1844 mplist_push (plist, Mt, Mface);
1845 mplist_push (plist, Mt, Mlanguage);
1846 new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1847 m17n_object_unref (plist);
1851 m17n_object_unref (mt);
1853 serialized = ! serialized;
1854 nchars = mtext_len (mt);
1857 update_cursor (0, 1);
1858 redraw (0, win_height, 1, 1);
1862 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1864 XtAppSetExitFlag (context);
1870 FILE *fp = fopen (filename, "r");
1873 FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1874 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
1877 FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1882 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1884 int data = (int) client_data;
1889 control.enable_bidi = 0;
1890 control.orientation_reversed = 0;
1894 control.enable_bidi = 1;
1895 control.orientation_reversed = data == 2;
1897 for (i = 0; i < 3; i++)
1900 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1902 XtSetArg (arg[0], XtNleftBitmap, None);
1903 XtSetValues (BidiMenus[i], arg, 1);
1906 update_cursor (cursor.from, 1);
1907 redraw (0, win_height, 1, 0);
1911 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1913 int data = (int) client_data;
1917 control.max_line_width = 0;
1920 control.max_line_width = win_width;
1921 control.line_break = (data == 1 ? NULL : mdraw_default_line_break);
1923 for (i = 0; i < 3; i++)
1926 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1928 XtSetArg (arg[0], XtNleftBitmap, None);
1929 XtSetValues (LineBreakMenus[i], arg, 1);
1932 update_cursor (cursor.from, 1);
1933 redraw (0, win_height, 1, 0);
1937 FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
1939 char *filter_module = (char *) client_data;
1941 void (*func) (MText *, int, int);
1945 handle = dlopen (filter_module, RTLD_NOW);
1948 *(void **) (&func) = dlsym (handle, "filter");
1950 (*func) (mt, mtext_property_start (selection),
1951 mtext_property_end (selection));
1956 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1958 int data = (int) client_data;
1972 control.cursor_bidi = 0, control.cursor_width = -1;
1976 control.cursor_bidi = 0, control.cursor_width = 2;
1980 control.cursor_bidi = 1;
1985 for (i = from; i < to; i++)
1988 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1990 XtSetArg (arg[0], XtNleftBitmap, None);
1991 XtSetValues (CursorMenus[i], arg, 1);
1994 update_cursor (cursor.from, 0);
1995 redraw (0, win_height, 1, 0);
1999 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
2001 int idx = (int) client_data;
2003 if (idx == -2 ? (! auto_input_method && current_input_method < 0)
2004 : idx == -1 ? auto_input_method
2005 : idx == current_input_method)
2008 if (auto_input_method)
2010 select_input_method (-1);
2011 XtSetArg (arg[0], XtNleftBitmap, None);
2012 XtSetValues (InputMethodMenus[1], arg, 1);
2013 auto_input_method = 0;
2018 select_input_method (-1);
2019 XtSetArg (arg[0], XtNleftBitmap, None);
2020 XtSetValues (InputMethodMenus[0], arg, 1);
2021 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
2022 XtSetValues (InputMethodMenus[1], arg, 1);
2023 auto_input_method = 1;
2028 select_input_method (idx);
2032 MPlist *default_face_list;
2035 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
2037 int idx = (int) client_data;
2048 MFace *face = mframe_get_prop (frame, Mface);
2050 for (plist = default_face_list; mplist_key (plist) != Mnil;
2051 plist = mplist_next (plist))
2052 mface_merge (face, mplist_value (plist));
2053 mplist_add (plist, Mt, *face_table[idx].face);
2054 mface_merge (face, *face_table[idx].face);
2056 else if (mplist_key (mplist_next (default_face_list)) != Mnil)
2058 MFace *face = mframe_get_prop (frame, Mface);
2060 for (plist = default_face_list;
2061 mplist_key (mplist_next (plist)) != Mnil;
2062 plist = mplist_next (plist))
2063 mface_merge (face, mplist_value (plist));
2067 update_cursor (0, 1);
2068 redraw (0, win_height, 1, 1);
2073 XtAppAddWorkProc (context, show_cursor, NULL);
2074 from = mtext_property_start (selection);
2075 to = mtext_property_end (selection);
2076 old_y1 = sel_end.y1;
2078 mtext_detach_property (selection);
2081 MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
2082 MTEXTPROP_REAR_STICKY);
2083 mtext_push_property (mt, from, to, prop);
2084 m17n_object_unref (prop);
2087 mtext_pop_prop (mt, from, to, Mface);
2089 update_top (top.from);
2090 update_cursor (cursor.from, 1);
2091 select_region (from, to);
2092 update_region (sel_start.y0, old_y1, sel_end.y1);
2093 if (cur.y1 > win_height)
2095 while (cur.y1 > win_height)
2098 update_cursor (cursor.from, 1);
2104 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
2106 MSymbol sym = (MSymbol) client_data;
2113 XtAppAddWorkProc (context, show_cursor, NULL);
2114 from = mtext_property_start (selection);
2115 to = mtext_property_end (selection);
2116 old_y1 = sel_end.y1;
2118 mtext_detach_property (selection);
2120 mtext_put_prop (mt, from, to, Mlanguage, sym);
2122 mtext_pop_prop (mt, from, to, Mlanguage);
2125 update_top (top.from);
2126 update_cursor (cursor.from, 1);
2127 select_region (from, to);
2128 update_region (sel_start.y0, old_y1, sel_end.y1);
2129 if (cur.y1 > win_height)
2131 while (cur.y1 > win_height)
2134 update_cursor (cursor.from, 1);
2140 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
2142 int narrowed = (int) client_data;
2145 MConverter *converter;
2151 from = mtext_property_start (selection);
2152 to = mtext_property_end (selection);
2161 mdump = popen ("mdump -q -p a4", "w");
2163 mdump = popen ("mdump -q", "w");
2166 converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
2167 mconv_encode_range (converter, mt, from, to);
2168 mconv_free_converter (converter);
2173 input_status (MInputContext *ic, MSymbol command)
2175 XFillRectangle (display, input_status_pixmap, gc_inv,
2176 0, 0, input_status_width, input_status_height);
2177 if (command == Minput_status_draw)
2181 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2182 Mface, face_input_status);
2183 if (ic->im->language != Mnil)
2184 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2185 Mlanguage, ic->im->language);
2186 mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
2187 &input_status_control, NULL, NULL, &rect);
2188 mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
2189 input_status_width - rect.width - 2, - rect.y,
2190 ic->status, 0, mtext_len (ic->status),
2191 &input_status_control);
2193 XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
2194 XtSetValues (CurIMStatus, arg, 1);
2198 surrounding_text_handler (MInputContext *ic, MSymbol command)
2200 if (command == Minput_get_surrounding_text)
2202 int len = (int) mplist_value (ic->plist);
2208 pos = cursor.from + len;
2211 surround = mtext_duplicate (mt, pos, cursor.from);
2215 pos = cursor.from + len;
2218 surround = mtext_duplicate (mt, cursor.from, pos);
2221 surround = mtext ();
2222 mplist_set (ic->plist, Mtext, surround);
2223 m17n_object_unref (surround);
2225 else if (command == Minput_delete_surrounding_text)
2227 int len = (int) mplist_value (ic->plist);
2231 if (cursor.from + len < 0)
2232 len = - cursor.from;
2233 mtext_del (mt, cursor.from + len, cursor.from);
2235 update_cursor (cursor.from + len, 1);
2239 if (cursor.from + len > nchars)
2240 len = nchars - cursor.from;
2241 mtext_del (mt, cursor.from, cursor.from + len);
2243 update_cursor (cursor.from, 1);
2251 compare_input_method (const void *elt1, const void *elt2)
2253 const InputMethodInfo *im1 = elt1;
2254 const InputMethodInfo *im2 = elt2;
2255 MSymbol lang1, lang2;
2257 if (im1->language == Mnil)
2259 if (im1->language == im2->language)
2260 return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
2261 if (im1->language == Mt)
2263 if (im2->language == Mt)
2265 lang1 = mlanguage_name (im1->language);
2266 lang2 = mlanguage_name (im2->language);
2267 return strcmp (msymbol_name (lang1), msymbol_name (lang2));
2271 setup_input_methods (int with_xim, char *initial_input_method)
2273 MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
2276 MSymbol Municode = msymbol ("unicode");
2278 num_input_methods = plist ? mplist_length (plist) : 0;
2280 num_input_methods++;
2281 input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
2286 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl), i++)
2288 MDatabase *mdb = mplist_value (pl);
2289 MSymbol *tag = mdatabase_tag (mdb);
2292 i--, num_input_methods--;
2295 input_method_table[i].language = tag[1];
2296 input_method_table[i].name = tag[2];
2299 m17n_object_unref (plist);
2303 input_method_table[i].language = Mnil;
2304 input_method_table[i].name = msymbol ("xim");
2308 qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
2309 compare_input_method);
2310 for (i = 0; i < num_input_methods; i++)
2311 if (input_method_table[i].language == Mt
2312 && input_method_table[i].name == Municode)
2314 unicode_input_method = i;
2317 mplist_put_func (minput_driver->callback_list, Minput_status_start,
2318 M17N_FUNC (input_status));
2319 mplist_put_func (minput_driver->callback_list, Minput_status_draw,
2320 M17N_FUNC (input_status));
2321 mplist_put_func (minput_driver->callback_list, Minput_status_done,
2322 M17N_FUNC (input_status));
2323 mplist_put_func (minput_driver->callback_list, Minput_get_surrounding_text,
2324 M17N_FUNC (surrounding_text_handler));
2325 mplist_put_func (minput_driver->callback_list, Minput_delete_surrounding_text,
2326 M17N_FUNC (surrounding_text_handler));
2328 current_input_context = NULL;
2329 current_input_method = -1;
2331 if (initial_input_method)
2333 char *lang_name, *method_name;
2334 char *p = strchr (initial_input_method, '-');
2337 lang_name = initial_input_method, *p = '\0', method_name = p + 1;
2339 lang_name = "t", method_name = initial_input_method;
2341 for (i = 0; i < num_input_methods; i++)
2342 if ((strcmp (method_name, msymbol_name (input_method_table[i].name))
2344 && (strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0))
2346 current_input_method = i;
2354 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
2358 if (num && *num > 0)
2362 for (i = 0; i < *num; i++)
2363 bytes += strlen (str[i]) + 1;
2364 msg = alloca (bytes);
2365 strcpy (msg, str[0]);
2366 for (i = 1; i < *num; i++)
2367 strcat (msg, " "), strcat (msg, str[i]);
2369 else if (cursor.from < nchars)
2371 int c = mtext_ref_char (mt, cursor.from);
2372 char *name = mchar_get_prop (c, Mname);
2376 msg = alloca (10 + strlen (name));
2377 sprintf (msg, "U+%04X %s", c, name);
2383 XtSetArg (arg[0], XtNlabel, msg);
2384 XtSetValues (MessageWidget, arg, 1);
2390 char *name1, *name2;
2391 XtCallbackProc proc;
2392 XtPointer client_data;
2397 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
2399 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
2401 MenuRec FileMenu[] =
2402 { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
2403 { 0, "Save", NULL, SaveProc, NULL, -1 },
2404 { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
2406 { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2407 { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2409 { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2410 { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2412 { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2415 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2417 MenuRec *rec = (MenuRec *) client_data;
2420 XtSetArg (arg[0], XtNvalue, "");
2421 XtSetArg (arg[1], XtNlabel, rec->name1);
2422 XtSetValues (FileDialogWidget, arg, 2);
2423 XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2424 XtSetArg (arg[0], XtNx, x + 20);
2425 XtSetArg (arg[1], XtNy, y + 10);
2426 XtSetValues (FileShellWidget, arg, 2);
2427 XtPopup (FileShellWidget, XtGrabExclusive);
2431 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2436 XtPopdown (FileShellWidget);
2437 if ((int) client_data == 1)
2439 XtSetArg (arg[0], XtNlabel, &label);
2440 XtGetValues (FileDialogWidget, arg, 1);
2441 if (strcmp (label, FileMenu[0].name1) == 0)
2445 filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2446 fp = fopen (filename, "r");
2448 m17n_object_unref (mt);
2451 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
2459 nchars = mtext_len (mt);
2461 update_cursor (0, 1);
2462 redraw (0, win_height, 1, 1);
2464 else if (strcmp (label, FileMenu[2].name1) == 0)
2465 SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2467 fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2470 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS) \
2471 ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2472 (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA), \
2473 (MENU).status = (STATUS))
2477 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2478 char *menu_name, MenuRec *menus, int num_menus, char *help)
2480 Widget button, menu;
2481 char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2482 <LeaveWindow>: reset() MenuHelp()\n\
2483 <BtnDown>: reset() PopupMenu()\n\
2484 <BtnUp>: highlight()";
2490 menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2491 for (i = 0; i < num_menus; i++)
2502 XtSetArg (arg[n], XtNleftMargin, 20), n++;
2504 XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2506 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2508 XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2512 XtSetArg (arg[0], XtNsensitive, False);
2513 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2519 XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2524 trans = alloca (strlen (fmt) + strlen (help));
2525 sprintf (trans, fmt, help);
2526 XtSetArg (arg[0], XtNmenuName, menu_name);
2527 XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2528 XtSetArg (arg[2], XtNinternalWidth, 2);
2529 XtSetArg (arg[3], XtNhighlightThickness, 1);
2530 XtSetArg (arg[4], XtNleft, XawChainLeft);
2531 XtSetArg (arg[5], XtNright, XawChainLeft);
2532 XtSetArg (arg[6], XtNinternational, True);
2535 XtSetArg (arg[i], XtNfromHoriz, left), i++;
2536 button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2541 int height, ascent, *width = alloca (sizeof (int) * num_menus);
2542 int *len = alloca (sizeof (int) * num_menus);
2545 XFontSetExtents *fontset_extents;
2547 XtSetArg (arg[0], XtNfontSet, &font_set);
2548 XtGetValues (button, arg, 1);
2550 fontset_extents = XExtentsOfFontSet (font_set);
2551 height = fontset_extents->max_logical_extent.height;
2552 ascent = - fontset_extents->max_logical_extent.y;
2554 for (i = 0; i < num_menus; i++)
2557 len[i] = strlen (menus[i].name2);
2558 width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2559 if (max_width < width[i])
2560 max_width = width[i];
2562 for (i = 0; i < num_menus; i++)
2565 Pixmap pixmap = XCreatePixmap (display,
2566 RootWindow (display, screen),
2567 max_width, height, 1);
2568 XFillRectangle (display, pixmap, mono_gc_inv,
2569 0, 0, max_width, height);
2570 XmbDrawString (display, pixmap, font_set, mono_gc,
2571 max_width - width[i], ascent,
2572 menus[i].name2, len[i]);
2573 XtSetArg (arg[0], XtNrightBitmap, pixmap);
2574 XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2575 XtSetValues (menus[i].w, arg, 2);
2583 XtActionsRec actions[] = {
2584 {"Expose", ExposeProc},
2585 {"Configure", ConfigureProc},
2587 {"ButtonPress", ButtonProc},
2588 {"ButtonRelease", ButtonReleaseProc},
2589 {"ButtonMotion", ButtonMoveProc},
2590 {"Button2Press", Button2Proc},
2591 {"MenuHelp", MenuHelpProc},
2592 {"FocusIn", FocusInProc},
2593 {"FocusOut", FocusOutProc}
2597 /* Print the usage of this program (the name is PROG), and exit with
2601 help_exit (char *prog, int exit_code)
2609 printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2610 printf ("Display FILE on a window and allow users to edit it.\n");
2611 printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2612 printf ("The following OPTIONs are available.\n");
2613 printf (" %-13s\n\t\t%s", "--fontset FONTSET",
2614 "Use the specified fontset\n");
2615 printf (" %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
2616 printf (" %-13s\n\t\t%s", "--im INPUT-METHOD",
2617 "Input method activated initially.\n");
2618 printf (" %-13s %s", "--version", "print version number\n");
2619 printf (" %-13s %s", "-h, --help", "print this message\n");
2625 main (int argc, char **argv)
2627 Widget form, BodyWidget, w;
2628 char *fontset_name = NULL;
2629 char *font_name = NULL;
2631 char *initial_input_method = NULL;
2632 int col = 80, row = 32;
2633 /* Translation table for TextWidget. */
2634 String trans = "<Expose>: Expose()\n\
2635 <Configure>: Configure()\n\
2638 <Btn1Down>: ButtonPress()\n\
2639 <Btn1Up>: ButtonRelease()\n\
2640 <Btn1Motion>: ButtonMotion()\n\
2641 <Btn2Down>: Button2Press()";
2642 /* Translation table for the top form widget. */
2643 String trans2 = "<Key>: Key()\n\
2645 <FocusIn>: FocusIn()\n\
2646 <FocusOut>: FocusOut()";
2647 String pop_face_trans
2648 = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2649 <LeaveWindow>: MenuHelp() reset()\n\
2650 <Btn1Down>: set()\n\
2651 <Btn1Up>: notify() unset()";
2652 String pop_lang_trans
2653 = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2654 <LeaveWindow>: MenuHelp() reset()\n\
2655 <Btn1Down>: set()\n\
2656 <Btn1Up>: notify() unset()";
2657 int font_width, font_ascent, font_descent;
2660 char *filter = NULL;
2663 setlocale (LC_ALL, "");
2664 /* Create the top shell. */
2665 XtSetLanguageProc (NULL, NULL, NULL);
2666 ShellWidget = XtOpenApplication (&context, "M17NEdit", NULL, 0, &argc, argv,
2667 NULL, sessionShellWidgetClass, NULL, 0);
2668 display = XtDisplay (ShellWidget);
2669 screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2671 /* Parse the remaining command line arguments. */
2672 for (i = 1; i < argc; i++)
2674 if (! strcmp (argv[i], "--help")
2675 || ! strcmp (argv[i], "-h"))
2676 help_exit (argv[0], 0);
2677 else if (! strcmp (argv[i], "--version"))
2679 printf ("m17n-edit (m17n library) %s\n", M17NLIB_VERSION_NAME);
2680 printf ("Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 AIST, JAPAN\n");
2683 else if (! strcmp (argv[i], "--geometry"))
2686 if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2687 help_exit (argv[0], 1);
2689 else if (! strcmp (argv[i], "-s"))
2692 fontsize = atoi (argv[i]);
2696 else if (! strcmp (argv[i], "--fontset"))
2699 fontset_name = strdup (argv[i]);
2701 else if (! strcmp (argv[i], "--font"))
2704 font_name = strdup (argv[i]);
2706 else if (! strcmp (argv[i], "--im"))
2709 initial_input_method = strdup (argv[i]);
2711 else if (! strcmp (argv[i], "--with-xim"))
2715 else if (! strcmp (argv[i], "--filter"))
2720 else if (argv[i][0] != '-')
2722 filename = strdup (argv[i]);
2726 fprintf (stderr, "Unknown option: %s\n", argv[i]);
2727 help_exit (argv[0], 1);
2731 filename = strdup ("/dev/null");
2733 mdatabase_dir = ".";
2734 /* Initialize the m17n library. */
2736 if (merror_code != MERROR_NONE)
2737 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2738 minput_driver = &minput_gui_driver;
2740 mt = read_file (filename);
2743 nchars = mtext_len (mt);
2745 Mword = msymbol ("word");
2748 MFace *face = mface ();
2750 mface_put_prop (face, Mforeground, msymbol ("blue"));
2751 mface_put_prop (face, Mbackground, msymbol ("yellow"));
2752 mface_put_prop (face, Mvideomode, Mreverse);
2753 selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2754 m17n_object_unref (face);
2757 /* This tells ExposeProc to initialize everything. */
2760 XA_TEXT = XInternAtom (display, "TEXT", False);
2761 XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2762 XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2763 Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
2764 if (Mcoding_compound_text == Mnil)
2765 FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
2768 MPlist *plist = mplist ();
2771 mplist_put (plist, msymbol ("widget"), ShellWidget);
2772 if (fontset_name || font_name || fontsize > 0)
2778 font = mfont_parse_name (font_name, Mnil);
2780 face = mface_from_font (font);
2788 MFontset *fontset = mfontset (fontset_name);
2790 mface_put_prop (face, Mfontset, fontset);
2791 m17n_object_unref (fontset);
2794 mface_put_prop (face, Msize, (void *) fontsize);
2795 mplist_add (plist, Mface, face);
2796 m17n_object_unref (face);
2798 frame = mframe (plist);
2800 FATAL_ERROR ("%s\n", "Fail to create a frame!");
2801 m17n_object_unref (plist);
2802 face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
2803 default_face_list = mplist ();
2804 mplist_add (default_face_list, Mt, face_default);
2805 face_default_fontset = mface ();
2806 mface_put_prop (face_default_fontset, Mfontset,
2807 mface_get_prop (face_default, Mfontset));
2809 font = (MFont *) mframe_get_prop (frame, Mfont);
2810 default_font_size = (int) mfont_get_prop (font, Msize);
2813 font_width = (int) mframe_get_prop (frame, Mfont_width);
2814 font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2815 font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2816 win_width = font_width * col;
2817 win_height = (font_ascent + font_descent) * row;
2823 prop.color_top = prop.color_left = msymbol ("magenta");
2824 prop.color_bottom = prop.color_right = msymbol ("red");
2825 prop.inner_hmargin = prop.inner_vmargin = 1;
2826 prop.outer_hmargin = prop.outer_vmargin = 2;
2828 face_box = mface ();
2829 mface_put_prop (face_box, Mbox, &prop);
2832 face_courier = mface ();
2833 mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2834 face_helvetica = mface ();
2835 mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2836 face_times = mface ();
2837 mface_put_prop (face_times, Mfamily, msymbol ("times"));
2838 face_dv_ttyogesh = mface ();
2839 mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2840 face_freesans = mface ();
2841 mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2842 face_freeserif = mface ();
2843 mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
2844 face_freemono = mface ();
2845 mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2847 face_xxx_large = mface ();
2848 mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2850 MFont *latin_font = mframe_get_prop (frame, Mfont);
2851 MFont *dev_font = mfont ();
2852 MFont *thai_font = mfont ();
2853 MFont *tib_font = mfont ();
2854 MFontset *fontset, *fontset_no_ctl;
2855 MSymbol unicode_bmp = msymbol ("unicode-bmp");
2856 MSymbol no_ctl = msymbol ("no-ctl");
2858 mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2859 mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2860 mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2861 mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2862 mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2863 mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2865 fontset = mfontset (fontset_name);
2866 fontset_no_ctl = mfontset_copy (fontset, "no-ctl");
2867 m17n_object_unref (fontset);
2868 mfontset_modify_entry (fontset_no_ctl, msymbol ("latin"), Mnil, Mnil,
2869 latin_font, Mnil, 0);
2870 mfontset_modify_entry (fontset_no_ctl, msymbol ("devanagari"), Mnil, Mnil,
2871 dev_font, no_ctl, 0);
2872 mfontset_modify_entry (fontset_no_ctl, msymbol ("thai"), Mnil, Mnil,
2873 thai_font, no_ctl, 0);
2874 mfontset_modify_entry (fontset_no_ctl, msymbol ("tibetan"), Mnil, Mnil,
2875 tib_font, no_ctl, 0);
2876 face_no_ctl_fontset = mface ();
2877 mface_put_prop (face_no_ctl_fontset, Mfontset, fontset_no_ctl);
2878 m17n_object_unref (fontset_no_ctl);
2885 setup_input_methods (with_xim, initial_input_method);
2887 gc = DefaultGC (display, screen);
2889 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2890 XtSetArg (arg[1], XtNdefaultDistance, 2);
2891 form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2893 XtSetArg (arg[0], XtNborderWidth, 0);
2894 XtSetArg (arg[1], XtNdefaultDistance, 2);
2895 XtSetArg (arg[2], XtNtop, XawChainTop);
2896 XtSetArg (arg[3], XtNbottom, XawChainTop);
2897 XtSetArg (arg[4], XtNleft, XawChainLeft);
2898 XtSetArg (arg[5], XtNright, XawChainRight);
2899 XtSetArg (arg[6], XtNresizable, True);
2900 HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2901 XtSetArg (arg[7], XtNfromVert, HeadWidget);
2902 FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2903 XtSetArg (arg[7], XtNfromVert, FaceWidget);
2904 LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2905 XtSetArg (arg[3], XtNbottom, XawChainBottom);
2906 XtSetArg (arg[7], XtNfromVert, LangWidget);
2907 BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2908 XtSetArg (arg[2], XtNtop, XawChainBottom);
2909 XtSetArg (arg[7], XtNfromVert, BodyWidget);
2910 TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2912 FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2913 HeadWidget, NULL, 0);
2914 XtSetArg (arg[0], XtNvalue, "");
2915 FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2916 FileShellWidget, arg, 1);
2917 XawDialogAddButton (FileDialogWidget, "OK",
2918 FileDialogProc, (XtPointer) 0);
2919 XawDialogAddButton (FileDialogWidget, "CANCEL",
2920 FileDialogProc, (XtPointer) 1);
2922 CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2923 (char *) check_bits,
2924 check_width, check_height);
2926 unsigned long valuemask = GCForeground;
2929 values.foreground = 1;
2930 mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2931 values.foreground = 0;
2932 mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2939 if (num_menus < num_input_methods + 2)
2940 num_menus = num_input_methods + 2;
2941 if (num_menus < num_faces + 1)
2942 num_menus = num_faces + 1;
2943 menus = alloca (sizeof (MenuRec) * num_menus);
2945 w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2946 FileMenu, sizeof FileMenu / sizeof (MenuRec),
2947 "File I/O, Serialization, Image, Quit");
2949 SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2950 SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2951 SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2952 SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2953 SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2954 SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2955 w = create_menu_button (ShellWidget, HeadWidget, w,
2956 "Cursor", "Cursor Menu",
2957 menus, 6, "Cursor Movement Mode, Cursor Shape");
2958 CursorMenus[0] = menus[0].w;
2959 CursorMenus[1] = menus[1].w;
2960 CursorMenus[2] = menus[3].w;
2961 CursorMenus[3] = menus[4].w;
2962 CursorMenus[4] = menus[5].w;
2964 SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2965 SetMenu (menus[1], 0, "Left (|--> |)", NULL, BidiProc, 1, 1);
2966 SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2967 w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2968 menus, 3, "BIDI Processing Mode");
2969 for (i = 0; i < 3; i++)
2970 BidiMenus[i] = menus[i].w;
2972 SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2973 SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2974 SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2975 w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2977 menus, 3, "How to break lines");
2978 for (i = 0; i < 3; i++)
2979 LineBreakMenus[i] = menus[i].w;
2981 SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2982 SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2983 for (i = 0; i < num_input_methods; i++)
2985 InputMethodInfo *im = input_method_table + i;
2986 char *name1, *name2;
2988 if (im->language != Mnil && im->language != Mt)
2990 MSymbol sym = mlanguage_name (im->language);
2992 name1 = msymbol_name (im->language);
2994 name1 = msymbol_name (sym);
2995 name2 = msymbol_name (im->name);
2998 name1 = msymbol_name (im->name), name2 = NULL;
3000 SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
3002 w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
3003 "Input Method Menu", menus, i + 2,
3004 "Select input method");
3007 unsigned long valuemask = GCForeground;
3010 XtSetArg (arg[0], XtNbackground, &values.foreground);
3011 XtGetValues (w, arg, 1);
3012 gc_inv = XCreateGC (display, RootWindow (display, screen),
3013 valuemask, &values);
3016 InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
3017 for (i = 0; i < num_input_methods + 2; i++)
3018 InputMethodMenus[i] = menus[i].w;
3022 SetMenu (menus[0], 0, filter, NULL, FilterProc, filter, 0);
3023 w = create_menu_button (ShellWidget, HeadWidget, w, "Filter",
3024 "Filter Menu", menus, 1,
3025 "Select filter to run");
3028 input_status_width = font_width * 8;
3029 input_status_height = (font_ascent + font_descent) * 2.4;
3030 input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
3032 input_status_height,
3033 DefaultDepth (display, screen));
3038 prop.color_top = prop.color_bottom
3039 = prop.color_left = prop.color_right = Mnil;
3040 prop.inner_hmargin = prop.inner_vmargin = 1;
3041 prop.outer_hmargin = prop.outer_vmargin = 0;
3042 face_input_status = mface_copy (face_default);
3043 mface_put_prop (face_input_status, Mbox, &prop);
3046 XFillRectangle (display, input_status_pixmap, gc_inv,
3047 0, 0, input_status_width, input_status_height);
3048 XtSetArg (arg[0], XtNfromHoriz, w);
3049 XtSetArg (arg[1], XtNleft, XawRubber);
3050 XtSetArg (arg[2], XtNright, XawChainRight);
3051 XtSetArg (arg[3], XtNborderWidth, 0);
3052 XtSetArg (arg[4], XtNlabel, " ");
3053 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3054 CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
3055 HeadWidget, arg, 6);
3056 XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
3057 XtSetArg (arg[1], XtNleft, XawChainRight);
3058 XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
3059 CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
3060 HeadWidget, arg, 5);
3062 XtSetArg (arg[0], XtNborderWidth, 0);
3063 XtSetArg (arg[1], XtNleft, XawChainLeft);
3064 XtSetArg (arg[2], XtNright, XawChainLeft);
3065 w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
3066 for (i = 0; i < num_faces;)
3068 char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
3069 char *label = label_menu + 5; /* "Xxxx" */
3071 for (j = i; j < num_faces && face_table[j].face; j++)
3072 SetMenu (menus[j - i], 0, face_table[j].name, NULL,
3074 w = create_menu_button (ShellWidget, FaceWidget, w,
3076 menus, j - i, "Push face property");
3080 XtSetArg (arg[0], XtNfromHoriz, w);
3081 XtSetArg (arg[1], XtNleft, XawChainLeft);
3082 XtSetArg (arg[2], XtNright, XawChainLeft);
3083 XtSetArg (arg[3], XtNhorizDistance, 10);
3084 XtSetArg (arg[4], XtNlabel, "Pop");
3085 XtSetArg (arg[5], XtNtranslations,
3086 XtParseTranslationTable (pop_face_trans));
3087 w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
3088 FaceWidget, arg, 6);
3089 XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
3091 XtSetArg (arg[0], XtNfromHoriz, w);
3092 XtSetArg (arg[1], XtNleft, XawChainLeft);
3093 XtSetArg (arg[2], XtNright, XawChainRight);
3094 XtSetArg (arg[3], XtNlabel, "");
3095 XtSetArg (arg[4], XtNborderWidth, 0);
3096 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3097 CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
3098 FaceWidget, arg, 6);
3100 XtSetArg (arg[0], XtNborderWidth, 0);
3101 XtSetArg (arg[1], XtNleft, XawChainLeft);
3102 XtSetArg (arg[2], XtNright, XawChainLeft);
3103 w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
3105 MPlist *plist[11], *pl;
3108 for (i = 0; i < 11; i++) plist[i] = NULL;
3110 for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
3111 for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
3113 MSymbol sym = msymbol_exist (langname);
3117 && ((fullname = mlanguage_name (sym)) != Mnil))
3119 char *name = msymbol_name (fullname);
3122 if (c >= 'a' && c <= 'z')
3124 int idx = (c < 'u') ? (c - 'a') / 2 : 10;
3128 pl = plist[idx] = mplist ();
3129 for (; mplist_next (pl); pl = mplist_next (pl))
3130 if (strcmp (name, (char *) mplist_value (pl)) < 0)
3132 mplist_push (pl, sym, fullname);
3137 for (i = 0; i < 11; i++)
3140 char *name = alloca (9);
3142 sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
3145 for (j = 0, pl = plist[i]; mplist_next (pl);
3146 j++, pl = mplist_next (pl))
3147 SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
3148 msymbol_name (mplist_key (pl)),
3149 LangProc, mplist_key (pl), -1);
3150 w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
3151 menus, j, "Push language property");
3153 for (i = 0; i < 11; i++)
3155 m17n_object_unref (plist[i]);
3157 XtSetArg (arg[0], XtNfromHoriz, w);
3158 XtSetArg (arg[1], XtNleft, XawChainLeft);
3159 XtSetArg (arg[2], XtNright, XawChainLeft);
3160 XtSetArg (arg[3], XtNhorizDistance, 10);
3161 XtSetArg (arg[4], XtNlabel, "Pop");
3162 XtSetArg (arg[5], XtNtranslations,
3163 XtParseTranslationTable (pop_lang_trans));
3164 w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
3165 LangWidget, arg, 6);
3166 XtAddCallback (w, XtNcallback, LangProc, Mnil);
3168 XtSetArg (arg[0], XtNfromHoriz, w);
3169 XtSetArg (arg[1], XtNleft, XawChainLeft);
3170 XtSetArg (arg[2], XtNright, XawChainRight);
3171 XtSetArg (arg[3], XtNlabel, "");
3172 XtSetArg (arg[4], XtNborderWidth, 0);
3173 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3174 CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
3175 LangWidget, arg, 6);
3178 XtSetArg (arg[0], XtNheight, win_height);
3179 XtSetArg (arg[1], XtNwidth, 10);
3180 XtSetArg (arg[2], XtNleft, XawChainLeft);
3181 XtSetArg (arg[3], XtNright, XawChainLeft);
3182 SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
3184 XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
3185 XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
3187 XtSetArg (arg[0], XtNheight, win_height);
3188 XtSetArg (arg[1], XtNwidth, win_width);
3189 XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
3190 XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
3191 XtSetArg (arg[4], XtNleft, XawChainLeft);
3192 XtSetArg (arg[5], XtNright, XawChainRight);
3193 TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
3196 XtSetArg (arg[0], XtNborderWidth, 0);
3197 XtSetArg (arg[1], XtNleft, XawChainLeft);
3198 XtSetArg (arg[2], XtNright, XawChainRight);
3199 XtSetArg (arg[3], XtNresizable, True);
3200 XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
3201 MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
3202 TailWidget, arg, 5);
3204 memset (&control, 0, sizeof control);
3205 control.two_dimensional = 1;
3206 control.enable_bidi = 1;
3207 control.anti_alias = 1;
3208 control.min_line_ascent = font_ascent;
3209 control.min_line_descent = font_descent;
3210 control.max_line_width = win_width;
3211 control.with_cursor = 1;
3212 control.cursor_width = 2;
3213 control.partial_update = 1;
3214 control.ignore_formatting_char = 1;
3216 memset (&input_status_control, 0, sizeof input_status_control);
3217 input_status_control.enable_bidi = 1;
3219 XtAppAddActions (context, actions, XtNumber (actions));
3220 XtRealizeWidget (ShellWidget);
3222 win = XtWindow (TextWidget);
3224 XtAppMainLoop (context);
3226 if (current_input_context)
3227 minput_destroy_ic (current_input_context);
3228 for (i = 0; i < num_input_methods; i++)
3229 if (input_method_table[i].im)
3230 minput_close_im (input_method_table[i].im);
3231 m17n_object_unref (frame);
3232 m17n_object_unref (mt);
3233 m17n_object_unref (face_xxx_large);
3234 m17n_object_unref (face_box);
3235 m17n_object_unref (face_courier);
3236 m17n_object_unref (face_helvetica);
3237 m17n_object_unref (face_times);
3238 m17n_object_unref (face_dv_ttyogesh);
3239 m17n_object_unref (face_freesans);
3240 m17n_object_unref (face_freeserif);
3241 m17n_object_unref (face_freemono);
3242 m17n_object_unref (face_default_fontset);
3243 m17n_object_unref (face_no_ctl_fontset);
3244 m17n_object_unref (face_input_status);
3245 m17n_object_unref (face_default);
3246 m17n_object_unref (default_face_list);
3247 m17n_object_unref (selection);
3251 XFreeGC (display, mono_gc);
3252 XFreeGC (display, mono_gc_inv);
3253 XFreeGC (display, gc_inv);
3254 XtUninstallTranslations (form);
3255 XtUninstallTranslations (TextWidget);
3256 XtDestroyWidget (ShellWidget);
3257 XtDestroyApplicationContext (context);
3262 free (fontset_name);
3264 free (input_method_table);
3265 free (InputMethodMenus);
3270 #else /* not HAVE_X11_XAW_COMMAND_H */
3273 main (int argc, char **argv)
3276 "Building of this program failed (lack of some header files)\n");
3280 #endif /* not HAVE_X11_XAW_COMMAND_H */
3282 #endif /* not FOR_DOXYGEN */