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
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., 59 Temple Place, Suite 330, Boston, MA
24 @enpage medit edit multilingual text
26 @section medit-synopsis SYNOPSIS
28 medit [ XT-OPTION ...] [ OPTION ... ] FILE
30 @section medit-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 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.
56 @japage medit ¿¸À¸ì¥Æ¥¥¹¥È¤ÎÊÔ½¸
58 @section medit-synopsis SYNOPSIS
60 medit [ XT-OPTION ...] [ OPTION ... ] FILE
62 @section medit-description DESCRIPTION
64 FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤·¡¢¥æ¡¼¥¶¤¬ÊÔ½¸¤Ç¤¤ë¤è¤¦¤Ë¤¹¤ë¡£
66 XT-OPTIONs ¤Ï Xt ¤Îɸ½à¤Î°ú¿ô¤Ç¤¢¤ë¡£ (e.g. -fn, -fg).
68 °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ¤ë¡£
74 ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£
78 ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£
82 ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£medit ¤Ïľ
83 ÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥¥Ã¥È¥é¥¤¥Ö¥é¥ê¤ä
84 XOM (X Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é ¥à
85 ¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
92 #include <sys/types.h>
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>
115 #include <m17n-gui.h>
116 #include <m17n-misc.h>
119 #define VERSION "1.2.0"
121 /* Global variables. */
126 /* For the X Window System. */
129 /* GCs for normal drawing, filling by background color, normal drawing
130 on bitmap (i.e. pixmap of depth 1), filling bitmap by background
132 GC gc, gc_inv, mono_gc, mono_gc_inv;
134 Atom XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING; /* X Selection types. */
135 XtAppContext context;
136 int default_font_size;
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
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;
154 int win_width, win_height; /* Size of TextWidget. */
157 Pixmap input_status_pixmap;
158 int input_status_width, input_status_height;
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 };
168 /* For the m17n library. */
171 int nchars; /* == mtext_len (mt) */
172 MDrawControl control, input_status_control;
173 MTextProperty *selection;
176 MFace *face_xxx_large;
178 MFace *face_courier, *face_helvetica, *face_times;
179 MFace *face_dv_ttyogesh, *face_freesans, *face_freeserif, *face_freemono;
180 MFace *face_default_fontset, *face_no_ctl_fontset;
181 MFace *face_input_status;
183 MSymbol Mcoding_compound_text;
185 int logical_move = 1; /* If 0, move cursor visually. */
189 MSymbol language, name;
193 InputMethodInfo *input_method_table;
195 int num_input_methods;
196 int current_input_method = -1; /* i.e. none */
197 int auto_input_method = 0;
198 MInputContext *current_input_context;
205 { {"Menu Size", NULL},
206 {"xx-small", &mface_xx_small},
207 {"x-small", &mface_x_small},
208 {"small", &mface_small},
209 {"normalsize", &mface_normalsize},
210 {"large", &mface_large},
211 {"x-large", &mface_x_large},
212 {"xx-large", &mface_xx_large},
213 {"xxx-large", &face_xxx_large},
215 {"Menu Family", NULL},
216 {"courier", &face_courier},
217 {"helvetica", &face_helvetica},
218 {"times", &face_times},
219 {"dv-ttyogesh", &face_dv_ttyogesh},
220 {"freesans", &face_freesans},
221 {"freeserif", &face_freeserif},
222 {"freemono", &face_freemono},
224 {"Menu Style", NULL},
225 {"medium", &mface_medium},
226 {"bold", &mface_bold},
227 {"italic", &mface_italic},
229 {"Menu Color", NULL},
230 {"black", &mface_black},
231 {"white", &mface_white},
233 {"green", &mface_green},
234 {"blue", &mface_blue},
235 {"cyan", &mface_cyan},
236 {"yello", &mface_yellow},
237 {"magenta", &mface_magenta},
240 {"normal", &mface_normal_video},
241 {"reverse", &mface_reverse_video},
242 {"underline", &mface_underline},
244 {"No CTL", &face_no_ctl_fontset} };
247 int num_faces = sizeof (face_table) / sizeof (struct FaceRec);
249 /* Information about a physical line metric. */
252 int from; /* BOL position of the line. */
253 int to; /* BOL position of the next line. */
254 int y0, y1; /* Top and bottom Y position of the line. */
255 int ascent; /* Height of the top Y position. */
258 struct LineInfo top; /* Topmost line. */
259 struct LineInfo cur; /* Line containing cursor. */
260 struct LineInfo sel_start; /* Line containing selection start. */
261 struct LineInfo sel_end; /* Line containing selection end. */
263 MDrawGlyphInfo cursor; /* Information about the cursor glyph. */
265 /* X position to keep on vertical (up and down) cursor motion. */
266 int target_x_position;
268 /* Interface macros for m17n-lib drawing routines. */
270 /* Draw a text in the range $FROM to $TO of the M-text #MT at the
271 coordinate ($X, $Y) */
272 #define DRAW_TEXT(x, y, from, to) \
273 mdraw_text_with_control \
274 (frame, (MDrawWindow) win, \
275 control.orientation_reversed ? x + win_width : x, y, \
276 mt, from, to, &control)
278 /* Store the extents of a text in the range $FROM to $TO in the
279 structure $RECT (type MDrawMetric). */
280 #define TEXT_EXTENTS(from, to, rect) \
281 mdraw_text_extents (frame, mt, from, (to), &control, NULL, NULL, &(rect))
283 /* Store the glyph information of a character at the position $POS in
284 the struct $INFO (type MDrawGlyphInfo) assuming that the text from
285 $FROM is written at the coordinate (0, 0). */
286 #define GLYPH_INFO(from, pos, info) \
287 mdraw_glyph_info (frame, mt, from, (pos), &control, &(info))
289 /* Set $X and $Y to the coordinate of character at position $POS
290 assuming that the text from $FROM is written at the coordinate (0,
292 #define COORDINATES_POSITION(from, pos, x, y) \
293 mdraw_coordinates_position (frame, mt, (from), (pos), (x), (y), &control)
295 /* Interface macros for X library. */
296 #define COPY_AREA(y0, y1, to) \
297 XCopyArea (display, win, win, gc, 0, (y0), win_width, (y1) - (y0), 0, (to))
299 #define CLEAR_AREA(x, y, w, h) \
300 XClearArea (display, win, (x), (y), (w), (h), False)
302 #define SELECTEDP() \
303 mtext_property_mtext (selection)
305 /* Format MSG by FMT and print the result to the stderr, and exit. */
306 #define FATAL_ERROR(fmt, arg) \
308 fprintf (stderr, fmt, arg); \
313 /* If POS is greater than zero, move POS back to the beginning of line
314 (BOL) position. If FORWARD is nonzero, move POS forward instead.
315 Return the new position. */
317 bol (int pos, int forward)
319 int limit = forward ? nchars : 0;
321 pos = mtext_character (mt, pos, limit, '\n');
322 return (pos < 0 ? limit : pos + 1);
325 /* Update the structure #TOP (struct LineInfo) to make $POS the first
326 character position of the screen. */
330 int from = bol (pos, 0);
333 GLYPH_INFO (from, pos, info);
334 top.from = info.line_from;
335 top.to = info.line_to;
337 top.y1 = info.metrics.height;
338 top.ascent = - info.metrics.y;
342 /* Update the scroll bar so that the text of the range $FROM to $TO
343 are shown on the window. */
345 update_scroll_bar (int from, int to)
347 float top = (float) from / nchars;
348 float shown = (float) (to - from) / nchars;
349 XtArgVal *l_top = (XtArgVal *) ⊤
350 XtArgVal *l_shown = (XtArgVal *) &shown;
352 XtSetArg (arg[0], XtNtopOfThumb, *l_top);
353 XtSetArg (arg[1], XtNshown, *l_shown);
354 XtSetValues (SbarWidget, arg, 2);
358 /* Redraw the window area between $Y0 and $Y1 (both Y-codinates). If
359 $CLEAR is nonzero, clear the area before drawing. If $SCROLL_BAR
360 is nonzero, update the scoll bar. */
362 redraw (int y0, int y1, int clear, int scroll_bar)
367 int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
368 struct LineInfo *line;
370 if (clear || control.anti_alias)
371 CLEAR_AREA (0, y0, win_width, y1 - y0);
373 /* Find a line closest to y0. It is a cursor line if the cursor is
374 Y0, otherwise the top line. */
379 /* If there exists a selected region, check it too. */
380 if (sel_y0 > line->y0 && y0 >= sel_y0)
385 info.metrics.height = line->y1 - y;
386 info.metrics.y = - line->ascent;
387 info.line_to = line->to;
388 while (from < nchars && y + info.metrics.height <= y0)
390 y += info.metrics.height;
392 GLYPH_INFO (from, from, info);
394 y0 = y - info.metrics.y;
396 while (to < nchars && y < y1)
398 GLYPH_INFO (to, to, info);
399 y += info.metrics.height;
405 DRAW_TEXT (0, y0, from, to);
410 GLYPH_INFO (to, to, info);
411 if (y + info.metrics.height >= win_height)
414 y += info.metrics.height;
416 update_scroll_bar (top.from, to);
421 /* Set the current input method spot to the correct position. */
423 set_input_method_spot ()
425 int x = cursor.x + (control.orientation_reversed ? win_width : 0);
426 int pos = cursor.from > 0 ? cursor.from - 1 : 0;
429 int size = 0, ratio = 0, i;
432 n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
434 for (i = n - 1; i >= 0; i--)
437 size = (int) mface_get_prop (faces[i], Msize);
439 ratio = (int) mface_get_prop (faces[i], Mratio);
442 size = default_font_size;
444 size = size * ratio / 100;
445 minput_set_spot (current_input_context, x, cur.y0 + cur.ascent,
446 cur.ascent, cur.y1 - (cur.y0 + cur.ascent), size,
451 /* Redraw the cursor. If $CLEAR is nonzero, clear the cursor area
454 redraw_cursor (int clear)
456 if (control.cursor_bidi)
458 /* We must update the whole line of the cursor. */
459 int beg = bol (cur.from, 0);
460 int end = bol (cur.to - 1, 1);
462 int y0 = cur.y0, y1 = cur.y1;
466 TEXT_EXTENTS (beg, cur.from, rect);
471 TEXT_EXTENTS (cur.to, end, rect);
474 redraw (y0, y1, clear, 0);
482 if (control.orientation_reversed)
483 x += win_width - cursor.logical_width;
484 CLEAR_AREA (x, cur.y0, cursor.logical_width, cursor.metrics.height);
486 DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
491 /* Update the information about the location of cursor to the position
492 $POS. If $FULL is nonzero, update the information fully only from
493 the information about the top line. Otherwise, truct the current
494 information in the structure $CUR. */
496 update_cursor (int pos, int full)
502 /* CUR is inaccurate. We can trust only TOP. */
503 GLYPH_INFO (top.from, pos, cursor);
504 cur.y0 = top.ascent + cursor.y + cursor.metrics.y;
506 else if (pos < cur.from)
508 int from = bol (pos, 0);
510 TEXT_EXTENTS (from, cur.from, rect);
511 GLYPH_INFO (from, pos, cursor);
512 cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.metrics.y);
514 else if (pos < cur.to)
516 GLYPH_INFO (cur.from, pos, cursor);
520 GLYPH_INFO (cur.from, pos, cursor);
521 cur.y0 += cur.ascent + cursor.y + cursor.metrics.y;
524 cur.from = cursor.line_from;
525 cur.to = cursor.line_to;
526 cur.y1 = cur.y0 + cursor.metrics.height;
527 cur.ascent = - cursor.metrics.y;
531 /* Update the information about the selected region. */
541 from = mtext_property_start (selection);
542 to = mtext_property_end (selection);
546 int pos = bol (from, 0);
548 TEXT_EXTENTS (pos, top.from, rect);
549 sel_start.y0 = top.y0 - rect.height;
550 sel_start.ascent = - rect.y;
551 GLYPH_INFO (pos, from, info);
552 if (pos < info.line_from)
553 sel_start.y0 += - rect.y + info.y + info.metrics.y;
557 GLYPH_INFO (top.from, from, info);
558 sel_start.y0 = top.ascent + info.y + info.metrics.y;
560 sel_start.ascent = -info.metrics.y;
561 sel_start.y1 = sel_start.y0 + info.metrics.height;
562 sel_start.from = info.line_from;
563 sel_start.to = info.line_to;
565 if (to <= sel_start.to)
571 GLYPH_INFO (sel_start.from, to, info);
572 sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.metrics.y;
573 sel_end.y1 = sel_end.y0 + info.metrics.height;
574 sel_end.ascent = - info.metrics.y;
575 sel_end.from = info.line_from;
576 sel_end.to = info.line_to;
581 /* Select the text in the region from $FROM to $TO. */
583 select_region (int from, int to)
588 pos = from, from = to, to = pos;
589 mtext_push_property (mt, from, to, selection);
594 /* Setup the window to display the character of $POS at the top left
600 /* Top and bottom Y positions to redraw. */
603 if (pos + 1000 < top.from)
604 y0 = 0, y1 = win_height;
605 else if (pos < top.from)
608 TEXT_EXTENTS (pos, top.from, rect);
609 if (rect.height >= win_height * 0.9)
614 COPY_AREA (0, win_height - y1, y1);
617 else if (pos < top.to)
619 /* No need of redrawing. */
622 else if (pos < top.from + 1000)
624 TEXT_EXTENTS (top.from, pos, rect);
625 if (rect.height >= win_height * 0.9)
629 y0 = win_height - rect.height;
630 COPY_AREA (rect.height, win_height, 0);
635 y0 = 0, y1 = win_height;
641 update_cursor (pos, 1);
643 update_cursor (cursor.from, 1);
645 redraw (y0, y1, 1, 1);
649 static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
652 /* Select an input method accoding to $IDX. If $IDX is negative, turn
653 off the current input method, otherwide turn on the input method
654 input_method_table[$IDX]. */
656 select_input_method (idx)
658 if (idx == current_input_method)
660 if (current_input_context)
662 minput_destroy_ic (current_input_context);
663 current_input_context = NULL;
664 current_input_method = -1;
668 InputMethodInfo *im = input_method_table + idx;
670 if (im->language == Mnil)
672 MInputXIMArgIC arg_xic;
673 Window win = XtWindow (TextWidget);
675 arg_xic.input_style = 0;
676 arg_xic.client_win = arg_xic.focus_win = win;
677 arg_xic.preedit_attrs = arg_xic.status_attrs = NULL;
678 current_input_context = minput_create_ic (im->im, &arg_xic);
682 MInputGUIArgIC arg_ic;
684 arg_ic.frame = frame;
685 arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
686 arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
687 current_input_context = minput_create_ic (im->im, &arg_ic);
690 if (current_input_context)
692 set_input_method_spot ();
693 current_input_method = idx;
696 if (current_input_method >= 0)
699 XtSetArg (arg[0], XtNlabel, &label);
700 XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
701 XtSetArg (arg[0], XtNlabel, label);
704 XtSetArg (arg[0], XtNlabel, "");
705 XtSetValues (CurIMLang, arg, 1);
708 static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
711 /* Display cursor according to the current information of #CUR.
712 $CLIENT_DATA is ignore. Most callback functions add this function
713 as a background processing procedure the current application (by
714 XtAppAddWorkProc) via the function hide_cursor. */
716 show_cursor (XtPointer client_data)
718 MFaceHLineProp *hline;
724 update_cursor (cursor.from, 1);
726 while (cur.y1 > win_height)
729 update_cursor (cursor.from, 1);
732 control.cursor_pos = cursor.from;
735 control.with_cursor = 1;
738 if (current_input_context)
739 set_input_method_spot ();
743 int pos = (SELECTEDP () ? mtext_property_start (selection)
744 : cursor.from > 0 ? cursor.from - 1
746 MFace *face = mface ();
747 MTextProperty *props[256];
748 int n = mtext_get_properties (mt, pos, Mface, props, 256);
750 char buf[256], *p = buf;
756 int size = (int) mfont_get_prop (cursor.font, Msize);
757 MSymbol family = mfont_get_prop (cursor.font, Mfamily);
758 MSymbol weight = mfont_get_prop (cursor.font, Mweight);
759 MSymbol style = mfont_get_prop (cursor.font, Mstyle);
760 MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
762 sprintf (p, "%dpt", size / 10), p += strlen (p);
764 strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
766 strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
768 strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
770 strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
774 mface_merge (face, face_default);
775 for (i = 0; i < n; i++)
776 if (props[i] != selection)
777 mface_merge (face, (MFace *) mtext_property_value (props[i]));
778 sym = (MSymbol) mface_get_prop (face, Mforeground);
780 strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
781 if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
782 strcat (p, ",rev"), p += strlen (p);
783 hline = mface_get_prop (face, Mhline);
784 if (hline && hline->width > 0)
785 strcat (p, ",ul"), p += strlen (p);
786 box = mface_get_prop (face, Mbox);
787 if (box && box->width > 0)
788 strcat (p, ",box"), p += strlen (p);
789 m17n_object_unref (face);
791 XtSetArg (arg[0], XtNborderWidth, 1);
792 XtSetArg (arg[1], XtNlabel, buf);
793 XtSetValues (CurFaceWidget, arg, 2);
796 if (control.cursor_pos < nchars)
800 if (control.cursor_pos > 0
801 && mtext_ref_char (mt, control.cursor_pos - 1) != '\n')
802 sym = mtext_get_prop (mt, control.cursor_pos - 1, Mlanguage);
804 sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
808 XtSetArg (arg[0], XtNborderWidth, 0);
809 XtSetArg (arg[1], XtNlabel, "");
813 XtSetArg (arg[0], XtNborderWidth, 1);
814 XtSetArg (arg[1], XtNlabel,
815 msymbol_name (msymbol_get (sym, Mlanguage)));
816 XtSetValues (CurLangWidget, arg, 2);
818 XtSetValues (CurLangWidget, arg, 2);
820 if (auto_input_method)
823 select_input_method (-1);
828 for (i = 0; i < num_input_methods; i++)
829 if (input_method_table[i].language == sym)
831 if (i < num_input_methods
832 && input_method_table[i].available >= 0)
834 if (! input_method_table[i].im)
836 input_method_table[i].im =
837 minput_open_im (input_method_table[i].language,
838 input_method_table[i].name, NULL);
839 if (! input_method_table[i].im)
840 input_method_table[i].available = -1;
842 if (input_method_table[i].im)
843 select_input_method (i);
845 select_input_method (-1);
848 select_input_method (-1);
853 MenuHelpProc (MessageWidget, NULL, NULL, NULL);
859 /* Hide the cursor. */
863 control.with_cursor = 0;
865 XtAppAddWorkProc (context, show_cursor, NULL);
869 /* Update the window area between the Y-positions $Y0 and $OLD_Y1 to
870 $Y1 and $NEW_Y1 assuming that the text in the other area is not
873 update_region (int y0, int old_y1, int new_y1)
879 if (old_y1 < win_height)
881 COPY_AREA (old_y1, win_height, new_y1);
882 redraw (win_height - (old_y1 - new_y1), win_height, 1, 0);
885 redraw (new_y1, win_height, 1, 0);
887 else if (new_y1 > old_y1)
889 if (new_y1 < win_height)
890 COPY_AREA (old_y1, win_height, new_y1);
892 if (new_y1 > win_height)
894 redraw (y0, new_y1, 1, 1);
898 /* Delete the next $N characters. If $N is negative delete the
899 precious (- $N) characters. */
909 from = cursor.from, to = from + n;
912 if (cursor.from == cur.from)
914 /* We are at the beginning of line. */
915 int pos = cursor.prev_from;
917 if (cursor.from == top.from)
919 /* We are at the beginning of screen. We must scroll
921 GLYPH_INFO (bol (top.from - 1, 0), top.from - 1, info);
922 reseat (info.line_from);
924 update_cursor (pos, 1);
930 from = cursor.from - 1;
935 TEXT_EXTENTS (cur.from, bol (to + 1, 1), rect);
936 old_y1 = cur.y0 + rect.height;
938 /* Now delete a character. */
939 mtext_del (mt, from, to);
941 if (from >= top.from && from < top.to)
942 update_top (top.from);
943 update_cursor (from, 1);
945 TEXT_EXTENTS (cur.from, bol (to, 1), rect);
946 new_y1 = cur.y0 + rect.height;
948 update_region (cur.y0, old_y1, new_y1);
952 /* Insert M-text $NEWTEXT at the current cursor position. */
954 insert_chars (MText *newtext)
956 int n = mtext_len (newtext);
958 int y0, old_y1, new_y1;
962 int n = (mtext_property_end (selection)
963 - mtext_property_start (selection));
964 mtext_detach_property (selection);
969 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
970 old_y1 = y0 + rect.height;
972 /* Now insert chars. */
973 mtext_ins (mt, cursor.from, newtext);
975 if (cur.from == top.from)
976 update_top (top.from);
977 update_cursor (cursor.from + n, 1);
979 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
980 new_y1 = cur.y0 + rect.height;
982 update_region (y0, old_y1, new_y1);
987 /* Convert the currently selected text to UTF8-STRING or
988 COMPOUND-TEXT. It is called when someone requests the current
989 value of the selection. */
991 covert_selection (Widget w, Atom *selection_atom,
992 Atom *target, Atom *return_type,
993 XtPointer *value, unsigned long *length, int *format)
995 unsigned char *buf = (unsigned char *) XtMalloc (4096);
996 MText *this_mt = mtext ();
997 int from = mtext_property_start (selection);
998 int to = mtext_property_end (selection);
1002 mtext_copy (this_mt, 0, mt, from, to);
1003 if (*target == XA_TEXT)
1005 #ifdef X_HAVE_UTF8_STRING
1006 coding = Mcoding_utf_8;
1007 *return_type = XA_UTF8_STRING;
1009 coding = Mcoding_compound_text;
1010 *return_type = XA_COMPOUND_TEXT;
1013 else if (*target == XA_UTF8_STRING)
1015 coding = Mcoding_utf_8;
1016 *return_type = XA_UTF8_STRING;
1018 else if (*target == XA_STRING)
1023 for (i = 0; i < len; i++)
1024 if (mtext_ref_char (this_mt, i) >= 0x100)
1025 /* Can't encode in XA_STRING */
1027 coding = Mcoding_iso_8859_1;
1028 *return_type = XA_STRING;
1030 else if (*target == XA_COMPOUND_TEXT)
1032 coding = Mcoding_compound_text;
1033 *return_type = XA_COMPOUND_TEXT;
1038 len = mconv_encode_buffer (coding, this_mt, buf, 4096);
1039 m17n_object_unref (this_mt);
1043 *value = (XtPointer) buf;
1049 /* Unselect the text. It is called when we loose the selection. */
1051 lose_selection (Widget w, Atom *selection_atom)
1055 mtext_detach_property (selection);
1056 redraw (sel_start.y0, sel_end.y1, 1, 0);
1061 get_selection (Widget w, XtPointer cliend_data, Atom *selection, Atom *type,
1062 XtPointer value, unsigned long *length, int *format)
1067 if (*type == XT_CONVERT_FAIL || ! value)
1069 if (*type == XA_STRING)
1071 else if (*type == XA_COMPOUND_TEXT)
1072 coding = msymbol ("compound-text");
1073 #ifdef X_HAVE_UTF8_STRING
1074 else if (*type == XA_UTF8_STRING)
1075 coding = msymbol ("utf-8");
1080 this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
1081 if (! this_mt && *type != XA_UTF8_STRING)
1083 XtGetSelectionValue (w, XA_PRIMARY, XA_UTF8_STRING, get_selection, NULL,
1090 insert_chars (this_mt);
1091 m17n_object_unref (this_mt);
1100 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1102 XExposeEvent *expose = (XExposeEvent *) event;
1106 Dimension width_max, width;
1108 XtSetArg (arg[0], XtNwidth, &width);
1109 XtGetValues (XtParent (w), arg, 1);
1111 XtGetValues (HeadWidget, arg, 1);
1112 if (width_max < width)
1114 XtGetValues (FaceWidget, arg, 1);
1115 if (width_max < width)
1117 XtGetValues (LangWidget, arg, 1);
1118 if (width_max < width)
1120 XtSetArg (arg[0], XtNwidth, width_max);
1121 XtSetValues (HeadWidget, arg, 1);
1122 XtSetValues (FaceWidget, arg, 1);
1123 XtSetValues (LangWidget, arg, 1);
1124 XtSetValues (XtParent (w), arg, 1);
1125 XtSetValues (TailWidget, arg, 1);
1128 update_cursor (0, 1);
1129 redraw (0, win_height, 0, 1);
1130 if (current_input_method >= 0)
1132 int idx = current_input_method;
1134 current_input_method = -1;
1135 input_method_table[idx].im =
1136 minput_open_im (input_method_table[idx].language,
1137 input_method_table[idx].name, NULL);
1138 if (input_method_table[idx].im)
1139 select_input_method (idx);
1141 input_method_table[idx].available = -1;
1147 redraw (expose->y, expose->y + expose->height, 0, 0);
1148 if (current_input_context
1149 && expose->y < cur.y0 && expose->y + expose->height < cur.y1)
1150 set_input_method_spot ();
1155 ConfigureProc (Widget w, XEvent *event, String *str, Cardinal *num)
1157 XConfigureEvent *configure = (XConfigureEvent *) event;
1160 control.max_line_width = win_width = configure->width;
1161 win_height = configure->height;
1162 mdraw_clear_cache (mt);
1164 update_cursor (0, 1);
1165 redraw (0, win_height, 1, 1);
1166 if (current_input_context)
1167 set_input_method_spot ();
1171 ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
1174 int x = event->xbutton.x;
1175 int y = event->xbutton.y - top.ascent;
1177 if (control.orientation_reversed)
1179 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1182 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1183 mtext_detach_property (selection);
1184 redraw (sel_start.y0, sel_end.y1, 1, 0);
1187 if (current_input_context)
1189 MText *produced = mtext ();
1191 minput_reset_ic (current_input_context);
1192 minput_lookup (current_input_context, Mnil, NULL, produced);
1193 if (mtext_len (produced) > 0)
1195 insert_chars (produced);
1196 if (pos >= cursor.from)
1197 pos += mtext_len (produced);
1199 m17n_object_unref (produced);
1201 update_cursor (pos, 0);
1206 ButtonReleaseProc (Widget w, XEvent *event, String *str, Cardinal *num)
1211 XtOwnSelection (w, XA_PRIMARY, CurrentTime,
1212 covert_selection, lose_selection, NULL);
1213 update_cursor (mtext_property_start (selection), 0);
1218 Button2Proc (Widget w, XEvent *event, String *str, Cardinal *num)
1222 /* We don't have a local selection. */
1223 XtGetSelectionValue (w, XA_PRIMARY, XA_TEXT, get_selection, NULL,
1228 int from = mtext_property_start (selection);
1229 int to = mtext_property_end (selection);
1232 int x = event->xbutton.x;
1233 int y = event->xbutton.y - top.ascent;
1235 if (control.orientation_reversed)
1237 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1239 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1240 mtext_detach_property (selection);
1242 this_mt = mtext_copy (mtext (), 0, mt, from, to);
1243 update_cursor (pos, 0);
1244 insert_chars (this_mt);
1245 m17n_object_unref (this_mt);
1250 ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
1253 int x = event->xbutton.x;
1254 int y = event->xbutton.y;
1256 if (control.orientation_reversed)
1259 pos = top.from, y -= top.ascent;
1261 pos = cur.from, y -= cur.y0 + cur.ascent;
1262 pos = COORDINATES_POSITION (pos, nchars + 1, x, y);
1264 if (pos == cursor.from)
1270 /* Selection range changed. */
1271 int from = mtext_property_start (selection);
1272 int to = mtext_property_end (selection);
1273 int start_y0 = sel_start.y0, start_y1 = sel_start.y1;
1274 int end_y0 = sel_end.y0, end_y1 = sel_end.y1;
1276 if (cursor.from == from)
1278 /* Starting position changed. */
1281 /* Enlarged. We can simply overdraw. */
1282 select_region (pos, to);
1283 redraw (sel_start.y0, start_y1, 0, 0);
1287 /* Shrunken. Previous selection face must be cleared. */
1288 select_region (pos, to);
1289 redraw (start_y0, sel_start.y1, 1, 0);
1293 /* Shrunken to zero. */
1294 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1295 mtext_detach_property (selection);
1296 redraw (start_y0, end_y1, 1, 0);
1300 /* Full update is necessary. */
1301 select_region (to, pos);
1302 redraw (start_y0, sel_end.y1, 1, 0);
1307 /* Ending position changed. */
1310 /* Full update is necessary. */
1311 select_region (pos, from);
1312 redraw (sel_start.y0, end_y1, 1, 0);
1314 else if (pos == from)
1316 /* Shrunken to zero. */
1317 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1318 mtext_detach_property (selection);
1319 redraw (start_y0, end_y1, 1, 0);
1323 /* Shrunken. Previous selection face must be cleared. */
1324 select_region (from, pos);
1325 redraw (sel_end.y0, end_y1, 1, 0);
1329 /* Enlarged. We can simply overdraw. */
1330 select_region (from, pos);
1331 redraw (end_y0, sel_end.y1, 0, 0);
1337 /* Newly selected. */
1338 select_region (pos, cursor.from);
1339 redraw (sel_start.y0, sel_end.y1, 0, 0);
1341 update_cursor (pos, 1);
1345 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1348 MDrawGlyphInfo info;
1350 int cursor_pos = cursor.from;
1352 if (((int) position) < 0)
1358 height = top.y1 - top.y0;
1361 pos = bol (from - 1, 0);
1362 GLYPH_INFO (pos, from - 1, info);
1363 if (height + info.metrics.height > win_height)
1365 height += info.metrics.height;
1366 from = info.line_from;
1368 if (cursor_pos >= top.to)
1370 cursor_pos = top.from;
1372 while (cursor_pos < nchars)
1374 GLYPH_INFO (pos, pos, info);
1375 if (height + info.metrics.height > win_height)
1377 height += info.metrics.height;
1383 else if (cur.to < nchars)
1385 /* Scroll up, but leave at least one line. */
1388 while (from < nchars)
1390 GLYPH_INFO (from, from, info);
1391 if (height + info.metrics.height > win_height
1392 || info.line_to >= nchars)
1394 height += info.metrics.height;
1395 from = info.line_to;
1398 from = info.line_from;
1399 if (cursor_pos < from)
1403 /* Scroll up to make the cursor line top. */
1407 update_cursor (cursor_pos, 1);
1411 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1413 float persent = *(float *) persent_ptr;
1414 int pos1, pos2 = nchars * persent;
1415 MDrawGlyphInfo info;
1418 pos1 = bol (pos2, 0);
1419 GLYPH_INFO (pos1, pos2, info);
1420 pos1 = info.line_from;
1422 update_cursor (pos1, 1);
1427 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1429 XKeyEvent *key_event = (XKeyEvent *) event;
1431 KeySym keysym = NoSymbol;
1433 /* If set to 1, do not update target_x_position. */
1434 int keep_target_x_position = 0;
1437 if (current_input_context
1438 && minput_filter (current_input_context, Mnil, event))
1440 if (event->type == KeyRelease)
1445 produced = mtext ();
1446 ret = minput_lookup (current_input_context, Mnil, event, produced);
1447 if (mtext_len (produced) > 0)
1448 insert_chars (produced);
1450 ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1451 m17n_object_unref (produced);
1461 n = (mtext_property_end (selection)
1462 - mtext_property_start (selection));
1463 mtext_detach_property (selection);
1465 else if (cursor.from < nchars)
1467 /* Delete the following grapheme cluster. */
1468 n = cursor.to - cursor.from;
1481 /* Delete selected region. */
1482 n = (mtext_property_end (selection)
1483 - mtext_property_start (selection));
1484 mtext_detach_property (selection);
1486 else if (cursor.from > 0)
1488 /* Delete the preceding character. */
1499 mtext_detach_property (selection);
1500 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1504 if (cursor.prev_from >= 0)
1505 update_cursor (cursor.prev_from, 0);
1509 if (cursor.left_from >= 0)
1510 update_cursor (cursor.left_from, 0);
1517 mtext_detach_property (selection);
1518 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1522 if (cursor.next_to >= 0)
1523 update_cursor (cursor.to, 0);
1527 if (cursor.right_from >= 0)
1528 update_cursor (cursor.right_from, 0);
1535 mtext_detach_property (selection);
1536 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1538 if (cur.to <= nchars)
1540 MDrawGlyphInfo info;
1543 GLYPH_INFO (cur.from, cur.to, info);
1544 pos = COORDINATES_POSITION (cur.from, nchars + 1,
1545 target_x_position, info.y);
1546 keep_target_x_position = 1;
1547 update_cursor (pos, 0);
1554 mtext_detach_property (selection);
1555 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1561 int pos = bol (cur.from - 1, 0);
1563 TEXT_EXTENTS (pos, cur.from - 1, rect);
1564 y = rect.height + rect.y - 1;
1565 pos = COORDINATES_POSITION (pos, nchars,
1566 target_x_position, y);
1567 keep_target_x_position = 1;
1568 update_cursor (pos, 0);
1575 mtext_detach_property (selection);
1576 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1578 if (top.from < nchars)
1579 ScrollProc (w, NULL, (XtPointer) 1);
1585 mtext_detach_property (selection);
1586 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1589 ScrollProc (w, NULL, (XtPointer) -1);
1595 if (buf[0] == 17) /* C-q */
1597 XtAppSetExitFlag (context);
1600 else if (buf[0] == 12) /* C-l */
1602 redraw (0, win_height, 1, 1);
1607 MText *temp = mtext ();
1609 mtext_cat_char (temp, buf[0] == '\r' ? '\n'
1610 : ((unsigned char *) buf)[0]);
1611 if (current_input_context)
1612 mtext_put_prop (temp, 0, 1, Mlanguage,
1613 current_input_context->im->language);
1614 insert_chars (temp);
1615 m17n_object_unref (temp);
1620 if (! keep_target_x_position)
1621 target_x_position = cursor.x;
1625 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1627 char *name = (char *) client_data;
1629 int from = -1, to = 0;
1634 filename = strdup (name);
1637 fp = fopen (filename, "w");
1640 fprintf (stderr, "Open for write fail: %s", filename);
1646 from = mtext_property_start (selection);
1647 to = mtext_property_end (selection);
1648 mtext_detach_property (selection);
1651 mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
1654 select_region (from, to);
1658 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1664 mtext_detach_property (selection);
1665 serialized = (int) client_data;
1667 new = mtext_deserialize (mt);
1670 MPlist *plist = mplist ();
1672 mplist_push (plist, Mt, Mface);
1673 mplist_push (plist, Mt, Mlanguage);
1674 new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1675 m17n_object_unref (plist);
1679 m17n_object_unref (mt);
1681 serialized = ! serialized;
1682 nchars = mtext_len (mt);
1685 update_cursor (0, 1);
1686 redraw (0, win_height, 1, 1);
1690 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1692 XtAppSetExitFlag (context);
1698 FILE *fp = fopen (filename, "r");
1701 FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1702 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
1705 FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1710 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1712 int data = (int) client_data;
1717 control.enable_bidi = 0;
1718 control.orientation_reversed = 0;
1722 control.enable_bidi = 1;
1723 control.orientation_reversed = data == 2;
1725 for (i = 0; i < 3; i++)
1728 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1730 XtSetArg (arg[0], XtNleftBitmap, None);
1731 XtSetValues (BidiMenus[i], arg, 1);
1734 update_cursor (cursor.from, 1);
1735 redraw (0, win_height, 1, 0);
1738 extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
1741 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1743 int data = (int) client_data;
1747 control.max_line_width = 0;
1750 control.max_line_width = win_width;
1751 control.line_break = (data == 1 ? NULL : line_break);
1753 for (i = 0; i < 3; i++)
1756 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1758 XtSetArg (arg[0], XtNleftBitmap, None);
1759 XtSetValues (LineBreakMenus[i], arg, 1);
1762 update_cursor (cursor.from, 1);
1763 redraw (0, win_height, 1, 0);
1767 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1769 int data = (int) client_data;
1783 control.cursor_bidi = 0, control.cursor_width = -1;
1787 control.cursor_bidi = 0, control.cursor_width = 2;
1791 control.cursor_bidi = 1;
1796 for (i = from; i < to; i++)
1799 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1801 XtSetArg (arg[0], XtNleftBitmap, None);
1802 XtSetValues (CursorMenus[i], arg, 1);
1805 update_cursor (cursor.from, 0);
1806 redraw (0, win_height, 1, 0);
1810 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
1812 int idx = (int) client_data;
1814 if (idx == -2 ? current_input_method < 0
1815 : idx == -1 ? auto_input_method
1816 : idx == current_input_method)
1819 XtSetArg (arg[0], XtNleftBitmap, None);
1820 if (auto_input_method)
1822 XtSetValues (InputMethodMenus[1], arg, 1);
1823 auto_input_method = 0;
1825 else if (current_input_method < 0)
1826 XtSetValues (InputMethodMenus[0], arg, 1);
1828 XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
1832 auto_input_method = 1;
1835 else if (input_method_table[idx].available >= 0)
1837 if (! input_method_table[idx].im)
1839 input_method_table[idx].im =
1840 minput_open_im (input_method_table[idx].language,
1841 input_method_table[idx].name, NULL);
1842 if (! input_method_table[idx].im)
1843 input_method_table[idx].available = -1;
1845 if (input_method_table[idx].im)
1846 select_input_method (idx);
1848 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1849 XtSetValues (InputMethodMenus[idx + 2], arg, 1);
1852 MPlist *default_face_list;
1855 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
1857 int idx = (int) client_data;
1868 MFace *face = mframe_get_prop (frame, Mface);
1870 for (plist = default_face_list; mplist_key (plist) != Mnil;
1871 plist = mplist_next (plist))
1872 mface_merge (face, mplist_value (plist));
1873 mplist_add (plist, Mt, *face_table[idx].face);
1874 mface_merge (face, *face_table[idx].face);
1876 else if (mplist_key (mplist_next (default_face_list)) != Mnil)
1878 MFace *face = mframe_get_prop (frame, Mface);
1880 for (plist = default_face_list;
1881 mplist_key (mplist_next (plist)) != Mnil;
1882 plist = mplist_next (plist))
1883 mface_merge (face, mplist_value (plist));
1887 update_cursor (0, 1);
1888 redraw (0, win_height, 1, 1);
1893 XtAppAddWorkProc (context, show_cursor, NULL);
1894 from = mtext_property_start (selection);
1895 to = mtext_property_end (selection);
1896 old_y1 = sel_end.y1;
1898 mtext_detach_property (selection);
1901 MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
1902 MTEXTPROP_REAR_STICKY);
1903 mtext_push_property (mt, from, to, prop);
1904 m17n_object_unref (prop);
1907 mtext_pop_prop (mt, from, to, Mface);
1909 update_top (top.from);
1910 update_cursor (cursor.from, 1);
1911 select_region (from, to);
1912 update_region (sel_start.y0, old_y1, sel_end.y1);
1913 if (cur.y1 > win_height)
1915 while (cur.y1 > win_height)
1918 update_cursor (cursor.from, 1);
1924 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
1926 MSymbol sym = (MSymbol) client_data;
1933 XtAppAddWorkProc (context, show_cursor, NULL);
1934 from = mtext_property_start (selection);
1935 to = mtext_property_end (selection);
1936 old_y1 = sel_end.y1;
1938 mtext_detach_property (selection);
1940 mtext_put_prop (mt, from, to, Mlanguage, sym);
1942 mtext_pop_prop (mt, from, to, Mlanguage);
1945 update_top (top.from);
1946 update_cursor (cursor.from, 1);
1947 select_region (from, to);
1948 update_region (sel_start.y0, old_y1, sel_end.y1);
1949 if (cur.y1 > win_height)
1951 while (cur.y1 > win_height)
1954 update_cursor (cursor.from, 1);
1960 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
1962 int narrowed = (int) client_data;
1965 MConverter *converter;
1971 from = mtext_property_start (selection);
1972 to = mtext_property_end (selection);
1981 mdump = popen ("mdump -q -p a4", "w");
1983 mdump = popen ("mdump -q", "w");
1986 converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
1987 mconv_encode_range (converter, mt, from, to);
1988 mconv_free_converter (converter);
1993 input_status (MInputContext *ic, MSymbol command)
1995 XFillRectangle (display, input_status_pixmap, gc_inv,
1996 0, 0, input_status_width, input_status_height);
1997 if (command == Minput_status_draw)
2001 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2002 Mface, face_input_status);
2003 if (ic->im->language != Mnil)
2004 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2005 Mlanguage, ic->im->language);
2006 mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
2007 &input_status_control, NULL, NULL, &rect);
2008 mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
2009 input_status_width - rect.width - 2, - rect.y,
2010 ic->status, 0, mtext_len (ic->status),
2011 &input_status_control);
2013 XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
2014 XtSetValues (CurIMStatus, arg, 1);
2018 compare_input_method (const void *elt1, const void *elt2)
2020 const InputMethodInfo *im1 = elt1;
2021 const InputMethodInfo *im2 = elt2;
2022 MSymbol lang1, lang2;
2024 if (im1->language == Mnil)
2026 if (im1->language == im2->language)
2027 return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
2028 if (im1->language == Mt)
2030 if (im2->language == Mt)
2032 lang1 = msymbol_get (im1->language, Mlanguage);
2033 lang2 = msymbol_get (im2->language, Mlanguage);
2034 return strcmp (msymbol_name (lang1), msymbol_name (lang2));
2038 setup_input_methods (int with_xim, char *initial_input_method)
2040 MInputMethod *im = NULL;
2041 MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
2044 char *lang_name = NULL, *method_name = NULL;
2046 if (initial_input_method)
2048 char *p = strchr (initial_input_method, '-');
2050 lang_name = initial_input_method, method_name = p + 1, *p = '\0';
2052 method_name = initial_input_method;
2055 num_input_methods = mplist_length (plist);
2059 MInputXIMArgIM arg_xim;
2061 arg_xim.display = display;
2063 arg_xim.res_name = arg_xim.res_class = NULL;
2064 arg_xim.locale = NULL;
2065 arg_xim.modifier_list = NULL;
2066 im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
2068 num_input_methods++;
2070 input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
2073 input_method_table[i].available = 1;
2074 input_method_table[i].language = Mnil;
2075 input_method_table[i].name = im->name;
2076 input_method_table[i].im = im;
2080 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
2082 MDatabase *mdb = mplist_value (pl);
2083 MSymbol *tag = mdatabase_tag (mdb);
2087 input_method_table[i].language = tag[1];
2088 input_method_table[i].name = tag[2];
2093 m17n_object_unref (plist);
2094 num_input_methods = i;
2095 qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
2096 compare_input_method);
2097 current_input_context = NULL;
2099 mplist_put (minput_driver->callback_list, Minput_status_start,
2100 (void *) input_status);
2101 mplist_put (minput_driver->callback_list, Minput_status_draw,
2102 (void *) input_status);
2103 mplist_put (minput_driver->callback_list, Minput_status_done,
2104 (void *) input_status);
2107 for (i = 0; i < num_input_methods; i++)
2108 if (strcmp (method_name, msymbol_name (input_method_table[i].name)) == 0
2110 ? strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0
2111 : input_method_table[i].language == Mt))
2113 current_input_method = i;
2120 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
2124 if (num && *num > 0)
2128 for (i = 0; i < *num; i++)
2129 bytes += strlen (str[i]) + 1;
2130 msg = alloca (bytes);
2131 strcpy (msg, str[0]);
2132 for (i = 1; i < *num; i++)
2133 strcat (msg, " "), strcat (msg, str[i]);
2135 else if (cursor.from < nchars)
2137 int c = mtext_ref_char (mt, cursor.from);
2138 char *name = mchar_get_prop (c, Mname);
2142 msg = alloca (10 + strlen (name));
2143 sprintf (msg, "U+%04X %s", c, name);
2149 XtSetArg (arg[0], XtNlabel, msg);
2150 XtSetValues (MessageWidget, arg, 1);
2156 char *name1, *name2;
2157 XtCallbackProc proc;
2158 XtPointer client_data;
2163 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
2165 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
2167 MenuRec FileMenu[] =
2168 { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
2169 { 0, "Save", NULL, SaveProc, NULL, -1 },
2170 { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
2172 { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2173 { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2175 { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2176 { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2178 { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2181 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2183 MenuRec *rec = (MenuRec *) client_data;
2186 XtSetArg (arg[0], XtNvalue, "");
2187 XtSetArg (arg[1], XtNlabel, rec->name1);
2188 XtSetValues (FileDialogWidget, arg, 2);
2189 XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2190 XtSetArg (arg[0], XtNx, x + 20);
2191 XtSetArg (arg[1], XtNy, y + 10);
2192 XtSetValues (FileShellWidget, arg, 2);
2193 XtPopup (FileShellWidget, XtGrabExclusive);
2197 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2202 XtPopdown (FileShellWidget);
2203 if ((int) client_data == 1)
2205 XtSetArg (arg[0], XtNlabel, &label);
2206 XtGetValues (FileDialogWidget, arg, 1);
2207 if (strcmp (label, FileMenu[0].name1) == 0)
2211 filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2212 fp = fopen (filename, "r");
2214 m17n_object_unref (mt);
2217 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
2225 nchars = mtext_len (mt);
2227 update_cursor (0, 1);
2228 redraw (0, win_height, 1, 1);
2230 else if (strcmp (label, FileMenu[2].name1) == 0)
2231 SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2233 fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2236 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS) \
2237 ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2238 (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA), \
2239 (MENU).status = (STATUS))
2243 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2244 char *menu_name, MenuRec *menus, int num_menus, char *help)
2246 Widget button, menu;
2247 char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2248 <LeaveWindow>: reset() MenuHelp()\n\
2249 <BtnDown>: reset() PopupMenu()\n\
2250 <BtnUp>: highlight()";
2256 menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2257 for (i = 0; i < num_menus; i++)
2268 XtSetArg (arg[n], XtNleftMargin, 20), n++;
2270 XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2272 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2274 XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2278 XtSetArg (arg[0], XtNsensitive, False);
2279 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2285 XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2290 trans = alloca (strlen (fmt) + strlen (help));
2291 sprintf (trans, fmt, help);
2292 XtSetArg (arg[0], XtNmenuName, menu_name);
2293 XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2294 XtSetArg (arg[2], XtNinternalWidth, 2);
2295 XtSetArg (arg[3], XtNhighlightThickness, 1);
2296 XtSetArg (arg[4], XtNleft, XawChainLeft);
2297 XtSetArg (arg[5], XtNright, XawChainLeft);
2300 XtSetArg (arg[i], XtNfromHoriz, left), i++;
2301 button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2306 int height, ascent, *width = alloca (sizeof (int) * num_menus);
2307 int *len = alloca (sizeof (int) * num_menus);
2310 XFontSetExtents *fontset_extents;
2312 XtSetArg (arg[0], XtNfontSet, &font_set);
2313 XtGetValues (button, arg, 1);
2315 fontset_extents = XExtentsOfFontSet (font_set);
2316 height = fontset_extents->max_logical_extent.height;
2317 ascent = - fontset_extents->max_logical_extent.y;
2319 for (i = 0; i < num_menus; i++)
2322 len[i] = strlen (menus[i].name2);
2323 width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2324 if (max_width < width[i])
2325 max_width = width[i];
2327 for (i = 0; i < num_menus; i++)
2330 Pixmap pixmap = XCreatePixmap (display,
2331 RootWindow (display, screen),
2332 max_width, height, 1);
2333 XFillRectangle (display, pixmap, mono_gc_inv,
2334 0, 0, max_width, height);
2335 XmbDrawString (display, pixmap, font_set, mono_gc,
2336 max_width - width[i], ascent,
2337 menus[i].name2, len[i]);
2338 XtSetArg (arg[0], XtNrightBitmap, pixmap);
2339 XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2340 XtSetValues (menus[i].w, arg, 2);
2348 XtActionsRec actions[] = {
2349 {"Expose", ExposeProc},
2350 {"Configure", ConfigureProc},
2352 {"ButtonPress", ButtonProc},
2353 {"ButtonRelease", ButtonReleaseProc},
2354 {"ButtonMotion", ButtonMoveProc},
2355 {"Button2Press", Button2Proc},
2356 {"MenuHelp", MenuHelpProc}
2360 /* Print the usage of this program (the name is PROG), and exit with
2364 help_exit (char *prog, int exit_code)
2372 printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2373 printf ("Display FILE on a window and allow users to edit it.\n");
2374 printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2375 printf ("The following OPTIONs are available.\n");
2376 printf (" %-13s\n\t\t%s", "--fontset FONTSET",
2377 "Use the specified fontset\n");
2378 printf (" %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
2379 printf (" %-13s\n\t\t%s", "--im INPUT-METHOD",
2380 "Input method activated initially.\n");
2381 printf (" %-13s %s", "--version", "print version number\n");
2382 printf (" %-13s %s", "-h, --help", "print this message\n");
2388 main (int argc, char **argv)
2390 Widget form, BodyWidget, w;
2391 char *fontset_name = NULL;
2393 char *initial_input_method = NULL;
2394 int col = 80, row = 32;
2395 /* Translation table for TextWidget. */
2396 String trans = "<Expose>: Expose()\n\
2397 <Configure>: Configure()\n\
2400 <Btn1Down>: ButtonPress()\n\
2401 <Btn1Up>: ButtonRelease()\n\
2402 <Btn1Motion>: ButtonMotion()\n\
2403 <Btn2Down>: Button2Press()";
2404 /* Translation table for the top form widget. */
2405 String trans2 = "<Key>: Key()\n\
2407 String pop_face_trans
2408 = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2409 <LeaveWindow>: MenuHelp() reset()\n\
2410 <Btn1Down>: set()\n\
2411 <Btn1Up>: notify() unset()";
2412 String pop_lang_trans
2413 = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2414 <LeaveWindow>: MenuHelp() reset()\n\
2415 <Btn1Down>: set()\n\
2416 <Btn1Up>: notify() unset()";
2417 int font_width, font_ascent, font_descent;
2421 setlocale (LC_ALL, "");
2422 /* Create the top shell. */
2423 XtSetLanguageProc (NULL, NULL, NULL);
2424 ShellWidget = XtOpenApplication (&context, "MEdit", NULL, 0, &argc, argv,
2425 NULL, sessionShellWidgetClass, NULL, 0);
2426 display = XtDisplay (ShellWidget);
2427 screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2429 /* Parse the remaining command line arguments. */
2430 for (i = 1; i < argc; i++)
2432 if (! strcmp (argv[i], "--help")
2433 || ! strcmp (argv[i], "-h"))
2434 help_exit (argv[0], 0);
2435 else if (! strcmp (argv[i], "--version"))
2437 printf ("medit (m17n library) %s\n", VERSION);
2438 printf ("Copyright (C) 2003 AIST, JAPAN\n");
2441 else if (! strcmp (argv[i], "--geometry"))
2444 if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2445 help_exit (argv[0], 1);
2447 else if (! strcmp (argv[i], "-s"))
2450 fontsize = atoi (argv[i]);
2454 else if (! strcmp (argv[i], "--fontset"))
2457 fontset_name = strdup (argv[i]);
2459 else if (! strcmp (argv[i], "--im"))
2462 initial_input_method = strdup (argv[i]);
2464 else if (! strcmp (argv[i], "--with-xim"))
2468 else if (argv[i][0] != '-')
2470 filename = strdup (argv[i]);
2474 fprintf (stderr, "Unknown option: %s\n", argv[i]);
2475 help_exit (argv[0], 1);
2479 filename = strdup ("/dev/null");
2481 mdatabase_dir = ".";
2482 /* Initialize the m17n library. */
2484 if (merror_code != MERROR_NONE)
2485 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2487 mt = read_file (filename);
2490 nchars = mtext_len (mt);
2493 MFace *face = mface ();
2495 mface_put_prop (face, Mforeground, msymbol ("blue"));
2496 mface_put_prop (face, Mbackground, msymbol ("yellow"));
2497 mface_put_prop (face, Mvideomode, Mreverse);
2498 selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2499 m17n_object_unref (face);
2502 /* This tells ExposeProc to initialize everything. */
2505 XA_TEXT = XInternAtom (display, "TEXT", False);
2506 XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2507 XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2508 Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
2509 if (Mcoding_compound_text == Mnil)
2510 FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
2513 MPlist *plist = mplist ();
2517 mplist_put (plist, msymbol ("widget"), ShellWidget);
2518 if (fontset_name || fontsize > 0)
2520 MFontset *fontset = mfontset (fontset_name);
2523 mface_put_prop (face, Mfontset, fontset);
2524 mface_put_prop (face, Msize, (void *) fontsize);
2525 m17n_object_unref (fontset);
2526 mplist_add (plist, Mface, face);
2527 m17n_object_unref (face);
2529 frame = mframe (plist);
2531 FATAL_ERROR ("%s\n", "Fail to create a frame!");
2532 m17n_object_unref (plist);
2533 face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
2534 default_face_list = mplist ();
2535 mplist_add (default_face_list, Mt, face_default);
2536 face_default_fontset = mface ();
2537 mface_put_prop (face_default_fontset, Mfontset,
2538 mface_get_prop (face_default, Mfontset));
2540 font = (MFont *) mframe_get_prop (frame, Mfont);
2541 default_font_size = (int) mfont_get_prop (font, Msize);
2544 font_width = (int) mframe_get_prop (frame, Mfont_width);
2545 font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2546 font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2547 win_width = font_width * col;
2548 win_height = (font_ascent + font_descent) * row;
2554 prop.color_top = prop.color_left = msymbol ("magenta");
2555 prop.color_bottom = prop.color_right = msymbol ("red");
2556 prop.inner_hmargin = prop.inner_vmargin = 1;
2557 prop.outer_hmargin = prop.outer_vmargin = 2;
2559 face_box = mface ();
2560 mface_put_prop (face_box, Mbox, &prop);
2563 face_courier = mface ();
2564 mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2565 face_helvetica = mface ();
2566 mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2567 face_times = mface ();
2568 mface_put_prop (face_times, Mfamily, msymbol ("times"));
2569 face_dv_ttyogesh = mface ();
2570 mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2571 face_freesans = mface ();
2572 mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2573 face_freeserif = mface ();
2574 mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
2575 face_freemono = mface ();
2576 mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2578 face_xxx_large = mface ();
2579 mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2581 MFont *latin_font = mframe_get_prop (frame, Mfont);
2582 MFont *dev_font = mfont ();
2583 MFont *thai_font = mfont ();
2584 MFont *tib_font = mfont ();
2586 MSymbol unicode_bmp = msymbol ("unicode-bmp");
2587 MSymbol no_ctl = msymbol ("no-ctl");
2589 mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2590 mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2591 mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2592 mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2593 mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2594 mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2596 fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
2597 mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
2598 latin_font, Mnil, 0);
2599 mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
2600 dev_font, no_ctl, 0);
2601 mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
2602 thai_font, no_ctl, 0);
2603 mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
2604 tib_font, no_ctl, 0);
2605 face_no_ctl_fontset = mface ();
2606 mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
2607 m17n_object_unref (fontset);
2614 setup_input_methods (with_xim, initial_input_method);
2616 gc = DefaultGC (display, screen);
2618 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2619 XtSetArg (arg[1], XtNdefaultDistance, 2);
2620 form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2622 XtSetArg (arg[0], XtNborderWidth, 0);
2623 XtSetArg (arg[1], XtNdefaultDistance, 2);
2624 XtSetArg (arg[2], XtNtop, XawChainTop);
2625 XtSetArg (arg[3], XtNbottom, XawChainTop);
2626 XtSetArg (arg[4], XtNleft, XawChainLeft);
2627 XtSetArg (arg[5], XtNright, XawChainRight);
2628 XtSetArg (arg[6], XtNresizable, True);
2629 HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2630 XtSetArg (arg[7], XtNfromVert, HeadWidget);
2631 FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2632 XtSetArg (arg[7], XtNfromVert, FaceWidget);
2633 LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2634 XtSetArg (arg[3], XtNbottom, XawChainBottom);
2635 XtSetArg (arg[7], XtNfromVert, LangWidget);
2636 BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2637 XtSetArg (arg[2], XtNtop, XawChainBottom);
2638 XtSetArg (arg[7], XtNfromVert, BodyWidget);
2639 TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2641 FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2642 HeadWidget, NULL, 0);
2643 XtSetArg (arg[0], XtNvalue, "");
2644 FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2645 FileShellWidget, arg, 1);
2646 XawDialogAddButton (FileDialogWidget, "OK",
2647 FileDialogProc, (XtPointer) 0);
2648 XawDialogAddButton (FileDialogWidget, "CANCEL",
2649 FileDialogProc, (XtPointer) 1);
2651 CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2652 (char *) check_bits,
2653 check_width, check_height);
2655 unsigned long valuemask = GCForeground;
2658 values.foreground = 1;
2659 mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2660 values.foreground = 0;
2661 mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2668 if (num_menus < num_input_methods + 2)
2669 num_menus = num_input_methods + 2;
2670 if (num_menus < num_faces + 1)
2671 num_menus = num_faces + 1;
2672 menus = alloca (sizeof (MenuRec) * num_menus);
2674 w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2675 FileMenu, sizeof FileMenu / sizeof (MenuRec),
2676 "File I/O, Serialization, Image, Quit");
2678 SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2679 SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2680 SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2681 SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2682 SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2683 SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2684 w = create_menu_button (ShellWidget, HeadWidget, w,
2685 "Cursor", "Cursor Menu",
2686 menus, 6, "Cursor Movement Mode, Cursor Shape");
2687 CursorMenus[0] = menus[0].w;
2688 CursorMenus[1] = menus[1].w;
2689 CursorMenus[2] = menus[3].w;
2690 CursorMenus[3] = menus[4].w;
2691 CursorMenus[4] = menus[5].w;
2693 SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2694 SetMenu (menus[1], 0, "Left (|--> |)", NULL, BidiProc, 1, 1);
2695 SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2696 w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2697 menus, 3, "BIDI Processing Mode");
2698 for (i = 0; i < 3; i++)
2699 BidiMenus[i] = menus[i].w;
2701 SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2702 SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2703 SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2704 w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2706 menus, 3, "How to break lines");
2707 for (i = 0; i < 3; i++)
2708 LineBreakMenus[i] = menus[i].w;
2710 SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2711 SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2712 for (i = 0; i < num_input_methods; i++)
2714 InputMethodInfo *im = input_method_table + i;
2715 char *name1, *name2;
2717 if (im->language != Mnil && im->language != Mt)
2719 MSymbol sym = msymbol_get (im->language, Mlanguage);
2721 name1 = msymbol_name (im->language);
2723 name1 = msymbol_name (sym);
2724 name2 = msymbol_name (im->name);
2727 name1 = msymbol_name (im->name), name2 = NULL;
2729 SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
2731 w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
2732 "Input Method Menu", menus, i + 2,
2733 "Select input method");
2736 unsigned long valuemask = GCForeground;
2739 XtSetArg (arg[0], XtNbackground, &values.foreground);
2740 XtGetValues (w, arg, 1);
2741 gc_inv = XCreateGC (display, RootWindow (display, screen),
2742 valuemask, &values);
2745 InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
2746 for (i = 0; i < num_input_methods + 2; i++)
2747 InputMethodMenus[i] = menus[i].w;
2749 input_status_width = font_width * 8;
2750 input_status_height = (font_ascent + font_descent) * 2.4;
2751 input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
2753 input_status_height,
2754 DefaultDepth (display, screen));
2759 prop.color_top = prop.color_bottom
2760 = prop.color_left = prop.color_right = Mnil;
2761 prop.inner_hmargin = prop.inner_vmargin = 1;
2762 prop.outer_hmargin = prop.outer_vmargin = 0;
2763 face_input_status = mface_copy (face_default);
2764 mface_put_prop (face_input_status, Mbox, &prop);
2767 XFillRectangle (display, input_status_pixmap, gc_inv,
2768 0, 0, input_status_width, input_status_height);
2769 XtSetArg (arg[0], XtNfromHoriz, w);
2770 XtSetArg (arg[1], XtNleft, XawRubber);
2771 XtSetArg (arg[2], XtNright, XawChainRight);
2772 XtSetArg (arg[3], XtNborderWidth, 0);
2773 XtSetArg (arg[4], XtNlabel, " ");
2774 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2775 CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
2776 HeadWidget, arg, 6);
2777 XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
2778 XtSetArg (arg[1], XtNleft, XawChainRight);
2779 XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
2780 CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
2781 HeadWidget, arg, 5);
2783 XtSetArg (arg[0], XtNborderWidth, 0);
2784 XtSetArg (arg[1], XtNleft, XawChainLeft);
2785 XtSetArg (arg[2], XtNright, XawChainLeft);
2786 w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
2787 for (i = 0; i < num_faces;)
2789 char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
2790 char *label = label_menu + 5; /* "Xxxx" */
2792 for (j = i; j < num_faces && face_table[j].face; j++)
2793 SetMenu (menus[j - i], 0, face_table[j].name, NULL,
2795 w = create_menu_button (ShellWidget, FaceWidget, w,
2797 menus, j - i, "Push face property");
2801 XtSetArg (arg[0], XtNfromHoriz, w);
2802 XtSetArg (arg[1], XtNleft, XawChainLeft);
2803 XtSetArg (arg[2], XtNright, XawChainLeft);
2804 XtSetArg (arg[3], XtNhorizDistance, 10);
2805 XtSetArg (arg[4], XtNlabel, "Pop");
2806 XtSetArg (arg[5], XtNtranslations,
2807 XtParseTranslationTable (pop_face_trans));
2808 w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
2809 FaceWidget, arg, 6);
2810 XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
2812 XtSetArg (arg[0], XtNfromHoriz, w);
2813 XtSetArg (arg[1], XtNleft, XawChainLeft);
2814 XtSetArg (arg[2], XtNright, XawChainRight);
2815 XtSetArg (arg[3], XtNlabel, "");
2816 XtSetArg (arg[4], XtNborderWidth, 0);
2817 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2818 CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
2819 FaceWidget, arg, 6);
2821 XtSetArg (arg[0], XtNborderWidth, 0);
2822 XtSetArg (arg[1], XtNleft, XawChainLeft);
2823 XtSetArg (arg[2], XtNright, XawChainLeft);
2824 w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
2826 MPlist *plist[11], *pl;
2829 for (i = 0; i < 11; i++) plist[i] = NULL;
2831 for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
2832 for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
2834 MSymbol sym = msymbol_exist (langname);
2838 && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
2840 char *name = msymbol_name (fullname);
2843 if (c >= 'A' && c <= 'Z')
2845 int idx = (c < 'U') ? (c - 'A') / 2 : 10;
2849 pl = plist[idx] = mplist ();
2850 for (; mplist_next (pl); pl = mplist_next (pl))
2851 if (strcmp (name, (char *) mplist_value (pl)) < 0)
2853 mplist_push (pl, sym, fullname);
2858 for (i = 0; i < 11; i++)
2861 char *name = alloca (9);
2863 sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
2866 for (j = 0, pl = plist[i]; mplist_next (pl);
2867 j++, pl = mplist_next (pl))
2868 SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
2869 msymbol_name (mplist_key (pl)),
2870 LangProc, mplist_key (pl), -1);
2871 w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
2872 menus, j, "Push language property");
2874 for (i = 0; i < 11; i++)
2876 m17n_object_unref (plist[i]);
2878 XtSetArg (arg[0], XtNfromHoriz, w);
2879 XtSetArg (arg[1], XtNleft, XawChainLeft);
2880 XtSetArg (arg[2], XtNright, XawChainLeft);
2881 XtSetArg (arg[3], XtNhorizDistance, 10);
2882 XtSetArg (arg[4], XtNlabel, "Pop");
2883 XtSetArg (arg[5], XtNtranslations,
2884 XtParseTranslationTable (pop_lang_trans));
2885 w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
2886 LangWidget, arg, 6);
2887 XtAddCallback (w, XtNcallback, LangProc, Mnil);
2889 XtSetArg (arg[0], XtNfromHoriz, w);
2890 XtSetArg (arg[1], XtNleft, XawChainLeft);
2891 XtSetArg (arg[2], XtNright, XawChainRight);
2892 XtSetArg (arg[3], XtNlabel, "");
2893 XtSetArg (arg[4], XtNborderWidth, 0);
2894 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2895 CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
2896 LangWidget, arg, 6);
2899 XtSetArg (arg[0], XtNheight, win_height);
2900 XtSetArg (arg[1], XtNwidth, 10);
2901 XtSetArg (arg[2], XtNleft, XawChainLeft);
2902 XtSetArg (arg[3], XtNright, XawChainLeft);
2903 SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
2905 XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
2906 XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
2908 XtSetArg (arg[0], XtNheight, win_height);
2909 XtSetArg (arg[1], XtNwidth, win_width);
2910 XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
2911 XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
2912 XtSetArg (arg[4], XtNleft, XawChainLeft);
2913 XtSetArg (arg[5], XtNright, XawChainRight);
2914 TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
2917 XtSetArg (arg[0], XtNborderWidth, 0);
2918 XtSetArg (arg[1], XtNleft, XawChainLeft);
2919 XtSetArg (arg[2], XtNright, XawChainRight);
2920 XtSetArg (arg[3], XtNresizable, True);
2921 XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
2922 MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
2923 TailWidget, arg, 5);
2925 memset (&control, 0, sizeof control);
2926 control.two_dimensional = 1;
2927 control.enable_bidi = 1;
2928 control.anti_alias = 1;
2929 control.min_line_ascent = font_ascent;
2930 control.min_line_descent = font_descent;
2931 control.max_line_width = win_width;
2932 control.with_cursor = 1;
2933 control.cursor_width = 2;
2934 control.partial_update = 1;
2935 control.ignore_formatting_char = 1;
2937 memset (&input_status_control, 0, sizeof input_status_control);
2938 input_status_control.enable_bidi = 1;
2940 XtAppAddActions (context, actions, XtNumber (actions));
2941 XtRealizeWidget (ShellWidget);
2943 win = XtWindow (TextWidget);
2945 XtAppMainLoop (context);
2947 if (current_input_context)
2948 minput_destroy_ic (current_input_context);
2949 for (i = 0; i < num_input_methods; i++)
2950 if (input_method_table[i].im)
2951 minput_close_im (input_method_table[i].im);
2952 m17n_object_unref (frame);
2953 m17n_object_unref (mt);
2954 m17n_object_unref (face_xxx_large);
2955 m17n_object_unref (face_box);
2956 m17n_object_unref (face_courier);
2957 m17n_object_unref (face_helvetica);
2958 m17n_object_unref (face_times);
2959 m17n_object_unref (face_dv_ttyogesh);
2960 m17n_object_unref (face_freesans);
2961 m17n_object_unref (face_freeserif);
2962 m17n_object_unref (face_freemono);
2963 m17n_object_unref (face_default_fontset);
2964 m17n_object_unref (face_no_ctl_fontset);
2965 m17n_object_unref (face_input_status);
2966 m17n_object_unref (face_default);
2967 m17n_object_unref (default_face_list);
2968 m17n_object_unref (selection);
2970 XFreeGC (display, mono_gc);
2971 XFreeGC (display, mono_gc_inv);
2972 XFreeGC (display, gc_inv);
2973 XtUninstallTranslations (form);
2974 XtUninstallTranslations (TextWidget);
2975 XtDestroyWidget (ShellWidget);
2976 XtDestroyApplicationContext (context);
2980 free (fontset_name);
2982 free (input_method_table);
2983 free (InputMethodMenus);
2987 #endif /* not FOR_DOXYGEN */