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 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 Outout 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 Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
85 ¥à¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
92 #include <sys/types.h>
100 #include <X11/keysym.h>
101 #include <X11/Xatom.h>
102 #include <X11/Intrinsic.h>
103 #include <X11/StringDefs.h>
104 #include <X11/Shell.h>
105 #include <X11/Xaw/Command.h>
106 #include <X11/Xaw/Box.h>
107 #include <X11/Xaw/Form.h>
108 #include <X11/Xaw/Dialog.h>
109 #include <X11/Xaw/Scrollbar.h>
110 #include <X11/Xaw/Toggle.h>
111 #include <X11/Xaw/SimpleMenu.h>
112 #include <X11/Xaw/SmeBSB.h>
113 #include <X11/Xaw/SmeLine.h>
114 #include <X11/Xaw/MenuButton.h>
116 #include <m17n-gui.h>
117 #include <m17n-misc.h>
120 #define VERSION "1.2.0"
122 /* Global variables. */
127 /* For the X Window System. */
130 /* GCs for normal drawing, filling by background color, normal drawing
131 on bitmap (i.e. pixmap of depth 1), filling bitmap by background
133 GC gc, gc_inv, mono_gc, mono_gc_inv;
135 Atom XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING; /* X Selection types. */
136 XtAppContext context;
137 int default_font_size;
141 Shell - Form -+- Head -- File, Cursor, Bidi, LineBreak, InputMethod, CurIM;
142 +- Face -- Size, Family, Style, Color, Misc, Pop, CurFace
143 +- Lang -- A-B, C-D, ..., U-Z, Pop, CurLang
144 +- Body -- Sbar, Text
148 Widget ShellWidget, HeadWidget, TailWidget, MessageWidget;
149 Widget CursorMenus[5], BidiMenus[3], LineBreakMenus[3], *InputMethodMenus;
150 Widget SbarWidget, TextWidget;
151 Widget FileShellWidget, FileDialogWidget;
152 Widget FaceWidget, CurFaceWidget, LangWidget, CurLangWidget;
153 Widget CurIMLang, CurIMStatus;
155 int win_width, win_height; /* Size of TextWidget. */
158 Pixmap input_status_pixmap;
159 int input_status_width, input_status_height;
161 /* Bitmap for "check" glyph. */
162 #define check_width 9
163 #define check_height 8
164 static unsigned char check_bits[] = {
165 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
166 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 };
169 /* For the m17n library. */
172 int nchars; /* == mtext_len (mt) */
173 MDrawControl control, input_status_control;
174 MTextProperty *selection;
179 MFace *face_xxx_large;
181 MFace *face_courier, *face_helvetica, *face_times;
182 MFace *face_dv_ttyogesh, *face_freesans, *face_freeserif, *face_freemono;
183 MFace *face_default_fontset, *face_no_ctl_fontset;
184 MFace *face_input_status;
186 MSymbol Mcoding_compound_text;
188 int logical_move = 1; /* If 0, move cursor visually. */
192 MSymbol language, name;
196 InputMethodInfo *input_method_table;
198 int num_input_methods;
199 int current_input_method = -1; /* i.e. none */
200 int auto_input_method = 0;
201 MInputContext *current_input_context;
208 { {"Menu Size", NULL},
209 {"xx-small", &mface_xx_small},
210 {"x-small", &mface_x_small},
211 {"small", &mface_small},
212 {"normalsize", &mface_normalsize},
213 {"large", &mface_large},
214 {"x-large", &mface_x_large},
215 {"xx-large", &mface_xx_large},
216 {"xxx-large", &face_xxx_large},
218 {"Menu Family", NULL},
219 {"courier", &face_courier},
220 {"helvetica", &face_helvetica},
221 {"times", &face_times},
222 {"dv-ttyogesh", &face_dv_ttyogesh},
223 {"freesans", &face_freesans},
224 {"freeserif", &face_freeserif},
225 {"freemono", &face_freemono},
227 {"Menu Style", NULL},
228 {"medium", &mface_medium},
229 {"bold", &mface_bold},
230 {"italic", &mface_italic},
232 {"Menu Color", NULL},
233 {"black", &mface_black},
234 {"white", &mface_white},
236 {"green", &mface_green},
237 {"blue", &mface_blue},
238 {"cyan", &mface_cyan},
239 {"yello", &mface_yellow},
240 {"magenta", &mface_magenta},
243 {"normal", &mface_normal_video},
244 {"reverse", &mface_reverse_video},
245 {"underline", &mface_underline},
247 {"No CTL", &face_no_ctl_fontset} };
250 int num_faces = sizeof (face_table) / sizeof (struct FaceRec);
252 /* Information about a physical line metric. */
255 int from; /* BOL position of the line. */
256 int to; /* BOL position of the next line. */
257 int y0, y1; /* Top and bottom Y position of the line. */
258 int ascent; /* Height of the top Y position. */
261 struct LineInfo top; /* Topmost line. */
262 struct LineInfo cur; /* Line containing cursor. */
263 struct LineInfo sel_start; /* Line containing selection start. */
264 struct LineInfo sel_end; /* Line containing selection end. */
266 MDrawGlyphInfo cursor; /* Information about the cursor glyph. */
268 /* X position to keep on vertical (up and down) cursor motion. */
269 int target_x_position;
271 /* Interface macros for m17n-lib drawing routines. */
273 /* Draw a text in the range $FROM to $TO of the M-text #MT at the
274 coordinate ($X, $Y) */
275 #define DRAW_TEXT(x, y, from, to) \
276 mdraw_text_with_control \
277 (frame, (MDrawWindow) win, \
278 control.orientation_reversed ? x + win_width : x, y, \
279 mt, from, to, &control)
281 /* Store the extents of a text in the range $FROM to $TO in the
282 structure $RECT (type MDrawMetric). */
283 #define TEXT_EXTENTS(from, to, rect) \
284 mdraw_text_extents (frame, mt, from, (to), &control, NULL, NULL, &(rect))
286 /* Store the glyph information of a character at the position $POS in
287 the struct $INFO (type MDrawGlyphInfo) assuming that the text from
288 $FROM is written at the coordinate (0, 0). */
289 #define GLYPH_INFO(from, pos, info) \
290 mdraw_glyph_info (frame, mt, from, (pos), &control, &(info))
292 /* Set $X and $Y to the coordinate of character at position $POS
293 assuming that the text from $FROM is written at the coordinate (0,
295 #define COORDINATES_POSITION(from, pos, x, y) \
296 mdraw_coordinates_position (frame, mt, (from), (pos), (x), (y), &control)
298 /* Interface macros for X library. */
299 #define COPY_AREA(y0, y1, to) \
300 XCopyArea (display, win, win, gc, 0, (y0), win_width, (y1) - (y0), 0, (to))
302 #define CLEAR_AREA(x, y, w, h) \
303 XClearArea (display, win, (x), (y), (w), (h), False)
305 #define SELECTEDP() \
306 mtext_property_mtext (selection)
308 /* Format MSG by FMT and print the result to the stderr, and exit. */
309 #define FATAL_ERROR(fmt, arg) \
311 fprintf (stderr, fmt, arg); \
316 /* If POS is greater than zero, move POS back to the beginning of line
317 (BOL) position. If FORWARD is nonzero, move POS forward instead.
318 Return the new position. */
320 bol (int pos, int forward)
322 int limit = forward ? nchars : 0;
324 pos = mtext_character (mt, pos, limit, '\n');
325 return (pos < 0 ? limit : pos + 1);
328 /* Update the structure #TOP (struct LineInfo) to make $POS the first
329 character position of the screen. */
333 int from = bol (pos, 0);
336 GLYPH_INFO (from, pos, info);
337 top.from = info.line_from;
338 top.to = info.line_to;
340 top.y1 = info.metrics.height;
341 top.ascent = - info.metrics.y;
345 /* Update the scroll bar so that the text of the range $FROM to $TO
346 are shown on the window. */
348 update_scroll_bar (int from, int to)
350 float top = (float) from / nchars;
351 float shown = (float) (to - from) / nchars;
352 XtArgVal *l_top = (XtArgVal *) ⊤
353 XtArgVal *l_shown = (XtArgVal *) &shown;
355 XtSetArg (arg[0], XtNtopOfThumb, *l_top);
356 XtSetArg (arg[1], XtNshown, *l_shown);
357 XtSetValues (SbarWidget, arg, 2);
361 /* Redraw the window area between $Y0 and $Y1 (both Y-codinates). If
362 $CLEAR is nonzero, clear the area before drawing. If $SCROLL_BAR
363 is nonzero, update the scoll bar. */
365 redraw (int y0, int y1, int clear, int scroll_bar)
370 int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
371 struct LineInfo *line;
373 if (clear || control.anti_alias)
374 CLEAR_AREA (0, y0, win_width, y1 - y0);
376 /* Find a line closest to y0. It is a cursor line if the cursor is
377 Y0, otherwise the top line. */
382 /* If there exists a selected region, check it too. */
383 if (sel_y0 > line->y0 && y0 >= sel_y0)
388 info.metrics.height = line->y1 - y;
389 info.metrics.y = - line->ascent;
390 info.line_to = line->to;
391 while (from < nchars && y + info.metrics.height <= y0)
393 y += info.metrics.height;
395 GLYPH_INFO (from, from, info);
397 y0 = y - info.metrics.y;
399 while (to < nchars && y < y1)
401 GLYPH_INFO (to, to, info);
402 y += info.metrics.height;
408 DRAW_TEXT (0, y0, from, to);
413 GLYPH_INFO (to, to, info);
414 if (y + info.metrics.height >= win_height)
417 y += info.metrics.height;
419 update_scroll_bar (top.from, to);
424 /* Set the current input method spot to the correct position. */
426 set_input_method_spot ()
428 int x = cursor.x + (control.orientation_reversed ? win_width : 0);
429 int pos = cursor.from > 0 ? cursor.from - 1 : 0;
432 int size = 0, ratio = 0, i;
435 n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
437 for (i = n - 1; i >= 0; i--)
440 size = (int) mface_get_prop (faces[i], Msize);
442 ratio = (int) mface_get_prop (faces[i], Mratio);
445 size = default_font_size;
447 size = size * ratio / 100;
448 minput_set_spot (current_input_context, x, cur.y0 + cur.ascent,
449 cur.ascent, cur.y1 - (cur.y0 + cur.ascent), size,
454 /* Redraw the cursor. If $CLEAR is nonzero, clear the cursor area
457 redraw_cursor (int clear)
459 if (control.cursor_bidi)
461 /* We must update the whole line of the cursor. */
462 int beg = bol (cur.from, 0);
463 int end = bol (cur.to - 1, 1);
465 int y0 = cur.y0, y1 = cur.y1;
469 TEXT_EXTENTS (beg, cur.from, rect);
474 TEXT_EXTENTS (cur.to, end, rect);
477 redraw (y0, y1, clear, 0);
485 if (control.orientation_reversed)
486 x += win_width - cursor.logical_width;
487 CLEAR_AREA (x, cur.y0, cursor.logical_width, cursor.metrics.height);
489 DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
494 /* Update the information about the location of cursor to the position
495 $POS. If $FULL is nonzero, update the information fully only from
496 the information about the top line. Otherwise, trust the current
497 information in the structure $CUR. */
499 update_cursor (int pos, int full)
505 /* CUR is inaccurate. We can trust only TOP. */
506 GLYPH_INFO (top.from, pos, cursor);
507 cur.y0 = top.ascent + cursor.y + cursor.metrics.y;
509 else if (pos < cur.from)
511 int from = bol (pos, 0);
513 TEXT_EXTENTS (from, cur.from, rect);
514 GLYPH_INFO (from, pos, cursor);
515 cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.metrics.y);
517 else if (pos < cur.to)
519 GLYPH_INFO (cur.from, pos, cursor);
523 GLYPH_INFO (cur.from, pos, cursor);
524 cur.y0 += cur.ascent + cursor.y + cursor.metrics.y;
527 cur.from = cursor.line_from;
528 cur.to = cursor.line_to;
529 cur.y1 = cur.y0 + cursor.metrics.height;
530 cur.ascent = - cursor.metrics.y;
534 /* Update the information about the selected region. */
544 from = mtext_property_start (selection);
545 to = mtext_property_end (selection);
549 int pos = bol (from, 0);
551 TEXT_EXTENTS (pos, top.from, rect);
552 sel_start.y0 = top.y0 - rect.height;
553 sel_start.ascent = - rect.y;
554 GLYPH_INFO (pos, from, info);
555 if (pos < info.line_from)
556 sel_start.y0 += - rect.y + info.y + info.metrics.y;
560 GLYPH_INFO (top.from, from, info);
561 sel_start.y0 = top.ascent + info.y + info.metrics.y;
563 sel_start.ascent = -info.metrics.y;
564 sel_start.y1 = sel_start.y0 + info.metrics.height;
565 sel_start.from = info.line_from;
566 sel_start.to = info.line_to;
568 if (to <= sel_start.to)
574 GLYPH_INFO (sel_start.from, to, info);
575 sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.metrics.y;
576 sel_end.y1 = sel_end.y0 + info.metrics.height;
577 sel_end.ascent = - info.metrics.y;
578 sel_end.from = info.line_from;
579 sel_end.to = info.line_to;
584 /* Select the text in the region from $FROM to $TO. */
586 select_region (int from, int to)
591 pos = from, from = to, to = pos;
592 mtext_push_property (mt, from, to, selection);
597 /* Setup the window to display the character of $POS at the top left
603 /* Top and bottom Y positions to redraw. */
606 if (pos + 1000 < top.from)
607 y0 = 0, y1 = win_height;
608 else if (pos < top.from)
611 TEXT_EXTENTS (pos, top.from, rect);
612 if (rect.height >= win_height * 0.9)
617 COPY_AREA (0, win_height - y1, y1);
620 else if (pos < top.to)
622 /* No need of redrawing. */
625 else if (pos < top.from + 1000)
627 TEXT_EXTENTS (top.from, pos, rect);
628 if (rect.height >= win_height * 0.9)
632 y0 = win_height - rect.height;
633 COPY_AREA (rect.height, win_height, 0);
638 y0 = 0, y1 = win_height;
644 update_cursor (pos, 1);
646 update_cursor (cursor.from, 1);
648 redraw (y0, y1, 1, 1);
652 static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
655 /* Select an input method accoding to $IDX. If $IDX is negative, turn
656 off the current input method, otherwide turn on the input method
657 input_method_table[$IDX]. */
659 select_input_method (idx)
661 if (idx == current_input_method)
663 if (current_input_context)
665 minput_destroy_ic (current_input_context);
666 current_input_context = NULL;
667 current_input_method = -1;
671 InputMethodInfo *im = input_method_table + idx;
673 if (im->language == Mnil)
675 MInputXIMArgIC arg_xic;
676 Window win = XtWindow (TextWidget);
678 arg_xic.input_style = 0;
679 arg_xic.client_win = arg_xic.focus_win = win;
680 arg_xic.preedit_attrs = arg_xic.status_attrs = NULL;
681 current_input_context = minput_create_ic (im->im, &arg_xic);
685 MInputGUIArgIC arg_ic;
687 arg_ic.frame = frame;
688 arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
689 arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
690 current_input_context = minput_create_ic (im->im, &arg_ic);
693 if (current_input_context)
695 set_input_method_spot ();
696 current_input_method = idx;
699 if (current_input_method >= 0)
702 XtSetArg (arg[0], XtNlabel, &label);
703 XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
704 XtSetArg (arg[0], XtNlabel, label);
707 XtSetArg (arg[0], XtNlabel, "");
708 XtSetValues (CurIMLang, arg, 1);
711 static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
714 /* Display cursor according to the current information of #CUR.
715 $CLIENT_DATA is ignore. Most callback functions add this function
716 as a background processing procedure the current application (by
717 XtAppAddWorkProc) via the function hide_cursor. */
719 show_cursor (XtPointer client_data)
721 MFaceHLineProp *hline;
727 update_cursor (cursor.from, 1);
729 while (cur.y1 > win_height)
732 update_cursor (cursor.from, 1);
735 control.cursor_pos = cursor.from;
738 control.with_cursor = 1;
741 if (current_input_context)
742 set_input_method_spot ();
746 int pos = (SELECTEDP () ? mtext_property_start (selection)
747 : cursor.from > 0 ? cursor.from - 1
749 MFace *face = mface ();
750 MTextProperty *props[256];
751 int n = mtext_get_properties (mt, pos, Mface, props, 256);
753 char buf[256], *p = buf;
759 int size = (int) mfont_get_prop (cursor.font, Msize);
760 MSymbol family = mfont_get_prop (cursor.font, Mfamily);
761 MSymbol weight = mfont_get_prop (cursor.font, Mweight);
762 MSymbol style = mfont_get_prop (cursor.font, Mstyle);
763 MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
765 sprintf (p, "%dpt", size / 10), p += strlen (p);
767 strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
769 strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
771 strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
773 strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
777 mface_merge (face, face_default);
778 for (i = 0; i < n; i++)
779 if (props[i] != selection)
780 mface_merge (face, (MFace *) mtext_property_value (props[i]));
781 sym = (MSymbol) mface_get_prop (face, Mforeground);
783 strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
784 if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
785 strcat (p, ",rev"), p += strlen (p);
786 hline = mface_get_prop (face, Mhline);
787 if (hline && hline->width > 0)
788 strcat (p, ",ul"), p += strlen (p);
789 box = mface_get_prop (face, Mbox);
790 if (box && box->width > 0)
791 strcat (p, ",box"), p += strlen (p);
792 m17n_object_unref (face);
794 XtSetArg (arg[0], XtNborderWidth, 1);
795 XtSetArg (arg[1], XtNlabel, buf);
796 XtSetValues (CurFaceWidget, arg, 2);
799 if (control.cursor_pos < nchars)
801 MSymbol sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
805 XtSetArg (arg[0], XtNborderWidth, 0);
806 XtSetArg (arg[1], XtNlabel, "");
810 XtSetArg (arg[0], XtNborderWidth, 1);
811 XtSetArg (arg[1], XtNlabel,
812 msymbol_name (msymbol_get (sym, Mlanguage)));
813 XtSetValues (CurLangWidget, arg, 2);
815 XtSetValues (CurLangWidget, arg, 2);
817 if (auto_input_method)
820 select_input_method (-1);
825 for (i = 0; i < num_input_methods; i++)
826 if (input_method_table[i].language == sym)
828 if (i < num_input_methods
829 && input_method_table[i].available >= 0)
831 if (! input_method_table[i].im)
833 input_method_table[i].im =
834 minput_open_im (input_method_table[i].language,
835 input_method_table[i].name, NULL);
836 if (! input_method_table[i].im)
837 input_method_table[i].available = -1;
839 if (input_method_table[i].im)
840 select_input_method (i);
842 select_input_method (-1);
845 select_input_method (-1);
850 MenuHelpProc (MessageWidget, NULL, NULL, NULL);
856 /* Hide the cursor. */
860 control.with_cursor = 0;
862 XtAppAddWorkProc (context, show_cursor, NULL);
866 /* Update the window area between the Y-positions $Y0 and $OLD_Y1 to
867 $Y1 and $NEW_Y1 assuming that the text in the other area is not
870 update_region (int y0, int old_y1, int new_y1)
876 if (old_y1 < win_height)
878 COPY_AREA (old_y1, win_height, new_y1);
879 redraw (win_height - (old_y1 - new_y1), win_height, 1, 0);
882 redraw (new_y1, win_height, 1, 0);
884 else if (new_y1 > old_y1)
886 if (new_y1 < win_height)
887 COPY_AREA (old_y1, win_height, new_y1);
889 if (new_y1 > win_height)
891 redraw (y0, new_y1, 1, 1);
895 /* Delete the next $N characters. If $N is negative delete the
896 precious (- $N) characters. */
902 int y0, old_y1, new_y1;
904 int line_from = cursor.line_from;
907 from = cursor.from, to = from + n;
910 if (cursor.from == cur.from)
912 /* We are at the beginning of line. */
913 int pos = cursor.prev_from;
915 if (cursor.from == top.from)
917 /* We are at the beginning of screen. We must scroll
919 GLYPH_INFO (bol (top.from - 1, 0), top.from - 1, info);
920 reseat (info.line_from);
922 update_cursor (pos, 1);
928 from = cursor.from - 1;
933 TEXT_EXTENTS (cur.from, bol (to + 1, 1), rect);
934 old_y1 = cur.y0 + rect.height;
936 /* Now delete a character. */
937 mtext_del (mt, from, to);
939 if (from >= top.from && from < top.to)
940 update_top (top.from);
941 update_cursor (from, 1);
944 if (line_from != cursor.line_from)
947 TEXT_EXTENTS (cur.from, bol (to, 1), rect);
948 new_y1 = cur.y0 + rect.height;
950 update_region (cur.y0, old_y1, new_y1);
954 /* Insert M-text $NEWTEXT at the current cursor position. */
956 insert_chars (MText *newtext)
958 int n = mtext_len (newtext);
960 int y0, old_y1, new_y1;
965 int n = (mtext_property_end (selection)
966 - mtext_property_start (selection));
967 mtext_detach_property (selection);
972 if (cursor.line_from > 0
973 && mtext_ref_char (mt, cursor.line_from - 1) != '\n')
974 y0 -= control.min_line_descent;
976 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
977 old_y1 = y0 + rect.height;
979 line_from = cursor.line_from;
981 /* Now insert chars. */
982 mtext_ins (mt, cursor.from, newtext);
984 if (cur.from == top.from)
985 update_top (top.from);
986 update_cursor (cursor.from + n, 1);
988 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
989 new_y1 = cur.y0 + rect.height;
991 update_region (y0, old_y1, new_y1);
997 word_constituent_p (int c)
999 MSymbol category = (MSymbol) mchar_get_prop (c, Mcategory);
1000 char *name = category != Mnil ? msymbol_name (category) : NULL;
1002 return (name && (name[0] == 'L' || name[0] == 'M'));
1009 int pos = cursor.from;
1011 while (pos < nchars && ! word_constituent_p (mtext_ref_char (mt, pos)))
1015 MTextProperty *prop = mtext_get_property (mt, pos, Mword);
1018 pos = mtext_property_end (prop);
1020 while (pos < nchars && word_constituent_p (mtext_ref_char (mt, pos)))
1023 update_cursor (pos, 0);
1029 int pos = cursor.from;
1031 while (pos > 0 && ! word_constituent_p (mtext_ref_char (mt, pos - 1)))
1035 MTextProperty *prop = mtext_get_property (mt, pos - 1, Mword);
1038 pos = mtext_property_start (prop);
1040 while (pos > 0 && word_constituent_p (mtext_ref_char (mt, pos - 1)))
1043 update_cursor (pos, 0);
1047 /* Convert the currently selected text to UTF8-STRING or
1048 COMPOUND-TEXT. It is called when someone requests the current
1049 value of the selection. */
1051 covert_selection (Widget w, Atom *selection_atom,
1052 Atom *target, Atom *return_type,
1053 XtPointer *value, unsigned long *length, int *format)
1055 unsigned char *buf = (unsigned char *) XtMalloc (4096);
1056 MText *this_mt = mtext ();
1057 int from = mtext_property_start (selection);
1058 int to = mtext_property_end (selection);
1062 mtext_copy (this_mt, 0, mt, from, to);
1063 if (*target == XA_TEXT)
1065 #ifdef X_HAVE_UTF8_STRING
1066 coding = Mcoding_utf_8;
1067 *return_type = XA_UTF8_STRING;
1069 coding = Mcoding_compound_text;
1070 *return_type = XA_COMPOUND_TEXT;
1073 else if (*target == XA_UTF8_STRING)
1075 coding = Mcoding_utf_8;
1076 *return_type = XA_UTF8_STRING;
1078 else if (*target == XA_STRING)
1083 for (i = 0; i < len; i++)
1084 if (mtext_ref_char (this_mt, i) >= 0x100)
1085 /* Can't encode in XA_STRING */
1087 coding = Mcoding_iso_8859_1;
1088 *return_type = XA_STRING;
1090 else if (*target == XA_COMPOUND_TEXT)
1092 coding = Mcoding_compound_text;
1093 *return_type = XA_COMPOUND_TEXT;
1098 len = mconv_encode_buffer (coding, this_mt, buf, 4096);
1099 m17n_object_unref (this_mt);
1103 *value = (XtPointer) buf;
1109 /* Unselect the text. It is called when we loose the selection. */
1111 lose_selection (Widget w, Atom *selection_atom)
1115 mtext_detach_property (selection);
1116 redraw (sel_start.y0, sel_end.y1, 1, 0);
1121 get_selection (Widget w, XtPointer cliend_data, Atom *selection, Atom *type,
1122 XtPointer value, unsigned long *length, int *format)
1127 if (*type == XT_CONVERT_FAIL || ! value)
1129 if (*type == XA_STRING)
1131 else if (*type == XA_COMPOUND_TEXT)
1132 coding = msymbol ("compound-text");
1133 #ifdef X_HAVE_UTF8_STRING
1134 else if (*type == XA_UTF8_STRING)
1135 coding = msymbol ("utf-8");
1140 this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
1141 if (! this_mt && *type != XA_UTF8_STRING)
1143 XtGetSelectionValue (w, XA_PRIMARY, XA_UTF8_STRING, get_selection, NULL,
1150 insert_chars (this_mt);
1151 m17n_object_unref (this_mt);
1160 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1162 XExposeEvent *expose = (XExposeEvent *) event;
1166 Dimension width_max, width;
1168 XtSetArg (arg[0], XtNwidth, &width);
1169 XtGetValues (XtParent (w), arg, 1);
1171 XtGetValues (HeadWidget, arg, 1);
1172 if (width_max < width)
1174 XtGetValues (FaceWidget, arg, 1);
1175 if (width_max < width)
1177 XtGetValues (LangWidget, arg, 1);
1178 if (width_max < width)
1180 XtSetArg (arg[0], XtNwidth, width_max);
1181 XtSetValues (HeadWidget, arg, 1);
1182 XtSetValues (FaceWidget, arg, 1);
1183 XtSetValues (LangWidget, arg, 1);
1184 XtSetValues (XtParent (w), arg, 1);
1185 XtSetValues (TailWidget, arg, 1);
1188 update_cursor (0, 1);
1189 redraw (0, win_height, 0, 1);
1190 if (current_input_method >= 0)
1192 int idx = current_input_method;
1194 current_input_method = -1;
1195 input_method_table[idx].im =
1196 minput_open_im (input_method_table[idx].language,
1197 input_method_table[idx].name, NULL);
1198 if (input_method_table[idx].im)
1199 select_input_method (idx);
1201 input_method_table[idx].available = -1;
1207 redraw (expose->y, expose->y + expose->height, 0, 0);
1208 if (current_input_context
1209 && expose->y < cur.y0 && expose->y + expose->height < cur.y1)
1210 set_input_method_spot ();
1215 ConfigureProc (Widget w, XEvent *event, String *str, Cardinal *num)
1217 XConfigureEvent *configure = (XConfigureEvent *) event;
1220 control.max_line_width = win_width = configure->width;
1221 win_height = configure->height;
1222 mdraw_clear_cache (mt);
1224 update_cursor (0, 1);
1225 redraw (0, win_height, 1, 1);
1226 if (current_input_context)
1227 set_input_method_spot ();
1231 ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
1234 int x = event->xbutton.x;
1235 int y = event->xbutton.y - top.ascent;
1237 if (control.orientation_reversed)
1239 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1242 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1243 mtext_detach_property (selection);
1244 redraw (sel_start.y0, sel_end.y1, 1, 0);
1247 if (current_input_context)
1249 MText *produced = mtext ();
1251 minput_reset_ic (current_input_context);
1252 minput_lookup (current_input_context, Mnil, NULL, produced);
1253 if (mtext_len (produced) > 0)
1255 insert_chars (produced);
1256 if (pos >= cursor.from)
1257 pos += mtext_len (produced);
1259 m17n_object_unref (produced);
1261 update_cursor (pos, 0);
1266 ButtonReleaseProc (Widget w, XEvent *event, String *str, Cardinal *num)
1271 XtOwnSelection (w, XA_PRIMARY, CurrentTime,
1272 covert_selection, lose_selection, NULL);
1273 update_cursor (mtext_property_start (selection), 0);
1278 Button2Proc (Widget w, XEvent *event, String *str, Cardinal *num)
1282 /* We don't have a local selection. */
1283 XtGetSelectionValue (w, XA_PRIMARY, XA_TEXT, get_selection, NULL,
1288 int from = mtext_property_start (selection);
1289 int to = mtext_property_end (selection);
1292 int x = event->xbutton.x;
1293 int y = event->xbutton.y - top.ascent;
1295 if (control.orientation_reversed)
1297 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1299 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1300 mtext_detach_property (selection);
1302 this_mt = mtext_copy (mtext (), 0, mt, from, to);
1303 update_cursor (pos, 0);
1304 insert_chars (this_mt);
1305 m17n_object_unref (this_mt);
1310 ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
1313 int x = event->xbutton.x;
1314 int y = event->xbutton.y;
1316 if (control.orientation_reversed)
1319 pos = top.from, y -= top.ascent;
1321 pos = cur.from, y -= cur.y0 + cur.ascent;
1322 pos = COORDINATES_POSITION (pos, nchars + 1, x, y);
1324 if (pos == cursor.from)
1330 /* Selection range changed. */
1331 int from = mtext_property_start (selection);
1332 int to = mtext_property_end (selection);
1333 int start_y0 = sel_start.y0, start_y1 = sel_start.y1;
1334 int end_y0 = sel_end.y0, end_y1 = sel_end.y1;
1336 if (cursor.from == from)
1338 /* Starting position changed. */
1341 /* Enlarged. We can simply overdraw. */
1342 select_region (pos, to);
1343 redraw (sel_start.y0, start_y1, 0, 0);
1347 /* Shrunken. Previous selection face must be cleared. */
1348 select_region (pos, to);
1349 redraw (start_y0, sel_start.y1, 1, 0);
1353 /* Shrunken to zero. */
1354 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1355 mtext_detach_property (selection);
1356 redraw (start_y0, end_y1, 1, 0);
1360 /* Full update is necessary. */
1361 select_region (to, pos);
1362 redraw (start_y0, sel_end.y1, 1, 0);
1367 /* Ending position changed. */
1370 /* Full update is necessary. */
1371 select_region (pos, from);
1372 redraw (sel_start.y0, end_y1, 1, 0);
1374 else if (pos == from)
1376 /* Shrunken to zero. */
1377 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1378 mtext_detach_property (selection);
1379 redraw (start_y0, end_y1, 1, 0);
1383 /* Shrunken. Previous selection face must be cleared. */
1384 select_region (from, pos);
1385 redraw (sel_end.y0, end_y1, 1, 0);
1389 /* Enlarged. We can simply overdraw. */
1390 select_region (from, pos);
1391 redraw (end_y0, sel_end.y1, 0, 0);
1397 /* Newly selected. */
1398 select_region (pos, cursor.from);
1399 redraw (sel_start.y0, sel_end.y1, 0, 0);
1401 update_cursor (pos, 1);
1405 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1408 MDrawGlyphInfo info;
1410 int cursor_pos = cursor.from;
1412 if (((int) position) < 0)
1418 height = top.y1 - top.y0;
1421 pos = bol (from - 1, 0);
1422 GLYPH_INFO (pos, from - 1, info);
1423 if (height + info.metrics.height > win_height)
1425 height += info.metrics.height;
1426 from = info.line_from;
1428 if (cursor_pos >= top.to)
1430 cursor_pos = top.from;
1432 while (cursor_pos < nchars)
1434 GLYPH_INFO (pos, pos, info);
1435 if (height + info.metrics.height > win_height)
1437 height += info.metrics.height;
1443 else if (cur.to < nchars)
1445 /* Scroll up, but leave at least one line. */
1448 while (from < nchars)
1450 GLYPH_INFO (from, from, info);
1451 if (height + info.metrics.height > win_height
1452 || info.line_to >= nchars)
1454 height += info.metrics.height;
1455 from = info.line_to;
1458 from = info.line_from;
1459 if (cursor_pos < from)
1463 /* Scroll up to make the cursor line top. */
1467 update_cursor (cursor_pos, 1);
1471 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1473 float persent = *(float *) persent_ptr;
1474 int pos1, pos2 = nchars * persent;
1475 MDrawGlyphInfo info;
1478 pos1 = bol (pos2, 0);
1479 GLYPH_INFO (pos1, pos2, info);
1480 pos1 = info.line_from;
1482 update_cursor (pos1, 1);
1487 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1489 XKeyEvent *key_event = (XKeyEvent *) event;
1491 KeySym keysym = NoSymbol;
1493 /* If set to 1, do not update target_x_position. */
1494 int keep_target_x_position = 0;
1497 if (current_input_context
1498 && minput_filter (current_input_context, Mnil, event))
1500 if (event->type == KeyRelease)
1505 produced = mtext ();
1506 ret = minput_lookup (current_input_context, Mnil, event, produced);
1507 if (mtext_len (produced) > 0)
1508 insert_chars (produced);
1510 ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1511 m17n_object_unref (produced);
1521 n = (mtext_property_end (selection)
1522 - mtext_property_start (selection));
1523 mtext_detach_property (selection);
1525 else if (cursor.from < nchars)
1527 /* Delete the following grapheme cluster. */
1528 n = cursor.to - cursor.from;
1541 /* Delete selected region. */
1542 n = (mtext_property_end (selection)
1543 - mtext_property_start (selection));
1544 mtext_detach_property (selection);
1546 else if (cursor.from > 0)
1548 /* Delete the preceding character. */
1559 mtext_detach_property (selection);
1560 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1564 if (cursor.prev_from >= 0)
1565 update_cursor (cursor.prev_from, 0);
1569 if (cursor.left_from >= 0)
1570 update_cursor (cursor.left_from, 0);
1577 mtext_detach_property (selection);
1578 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1582 if (cursor.next_to >= 0)
1583 update_cursor (cursor.to, 0);
1587 if (cursor.right_from >= 0)
1588 update_cursor (cursor.right_from, 0);
1595 mtext_detach_property (selection);
1596 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1598 if (cur.to <= nchars)
1600 MDrawGlyphInfo info;
1603 GLYPH_INFO (cur.from, cur.to, info);
1604 pos = COORDINATES_POSITION (cur.from, nchars + 1,
1605 target_x_position, info.y);
1606 keep_target_x_position = 1;
1607 update_cursor (pos, 0);
1614 mtext_detach_property (selection);
1615 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1621 int pos = bol (cur.from - 1, 0);
1623 TEXT_EXTENTS (pos, cur.from - 1, rect);
1624 y = rect.height + rect.y - 1;
1625 pos = COORDINATES_POSITION (pos, nchars,
1626 target_x_position, y);
1627 keep_target_x_position = 1;
1628 update_cursor (pos, 0);
1635 mtext_detach_property (selection);
1636 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1638 if (top.from < nchars)
1639 ScrollProc (w, NULL, (XtPointer) 1);
1645 mtext_detach_property (selection);
1646 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1649 ScrollProc (w, NULL, (XtPointer) -1);
1653 if (key_event->state >= Mod1Mask)
1655 lose_selection (NULL, NULL);
1661 if (key_event->state >= Mod1Mask)
1663 lose_selection (NULL, NULL);
1671 if (buf[0] == 17) /* C-q */
1673 XtAppSetExitFlag (context);
1676 else if (buf[0] == 12) /* C-l */
1678 redraw (0, win_height, 1, 1);
1683 MText *temp = mtext ();
1685 mtext_cat_char (temp, buf[0] == '\r' ? '\n'
1686 : ((unsigned char *) buf)[0]);
1687 if (current_input_context)
1688 mtext_put_prop (temp, 0, 1, Mlanguage,
1689 current_input_context->im->language);
1690 insert_chars (temp);
1691 m17n_object_unref (temp);
1696 if (! keep_target_x_position)
1697 target_x_position = cursor.x;
1701 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1703 char *name = (char *) client_data;
1705 int from = -1, to = 0;
1710 filename = strdup (name);
1713 fp = fopen (filename, "w");
1716 fprintf (stderr, "Open for write fail: %s", filename);
1722 from = mtext_property_start (selection);
1723 to = mtext_property_end (selection);
1724 mtext_detach_property (selection);
1727 mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
1730 select_region (from, to);
1734 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1740 mtext_detach_property (selection);
1741 serialized = (int) client_data;
1743 new = mtext_deserialize (mt);
1746 MPlist *plist = mplist ();
1748 mplist_push (plist, Mt, Mface);
1749 mplist_push (plist, Mt, Mlanguage);
1750 new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1751 m17n_object_unref (plist);
1755 m17n_object_unref (mt);
1757 serialized = ! serialized;
1758 nchars = mtext_len (mt);
1761 update_cursor (0, 1);
1762 redraw (0, win_height, 1, 1);
1766 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1768 XtAppSetExitFlag (context);
1774 FILE *fp = fopen (filename, "r");
1777 FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1778 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
1781 FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1786 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1788 int data = (int) client_data;
1793 control.enable_bidi = 0;
1794 control.orientation_reversed = 0;
1798 control.enable_bidi = 1;
1799 control.orientation_reversed = data == 2;
1801 for (i = 0; i < 3; i++)
1804 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1806 XtSetArg (arg[0], XtNleftBitmap, None);
1807 XtSetValues (BidiMenus[i], arg, 1);
1810 update_cursor (cursor.from, 1);
1811 redraw (0, win_height, 1, 0);
1815 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1817 int data = (int) client_data;
1821 control.max_line_width = 0;
1824 control.max_line_width = win_width;
1825 control.line_break = (data == 1 ? NULL : mdraw_default_line_break);
1827 for (i = 0; i < 3; i++)
1830 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1832 XtSetArg (arg[0], XtNleftBitmap, None);
1833 XtSetValues (LineBreakMenus[i], arg, 1);
1836 update_cursor (cursor.from, 1);
1837 redraw (0, win_height, 1, 0);
1841 FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
1843 char *filter_module = (char *) client_data;
1845 void (*func) (MText *, int, int);
1849 handle = dlopen (filter_module, RTLD_NOW);
1852 *(void **) (&func) = dlsym (handle, "filter");
1854 (*func) (mt, mtext_property_start (selection),
1855 mtext_property_end (selection));
1860 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1862 int data = (int) client_data;
1876 control.cursor_bidi = 0, control.cursor_width = -1;
1880 control.cursor_bidi = 0, control.cursor_width = 2;
1884 control.cursor_bidi = 1;
1889 for (i = from; i < to; i++)
1892 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1894 XtSetArg (arg[0], XtNleftBitmap, None);
1895 XtSetValues (CursorMenus[i], arg, 1);
1898 update_cursor (cursor.from, 0);
1899 redraw (0, win_height, 1, 0);
1903 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
1905 int idx = (int) client_data;
1907 if (idx == -2 ? current_input_method < 0
1908 : idx == -1 ? auto_input_method
1909 : idx == current_input_method)
1912 XtSetArg (arg[0], XtNleftBitmap, None);
1913 if (auto_input_method)
1915 XtSetValues (InputMethodMenus[1], arg, 1);
1916 auto_input_method = 0;
1918 else if (current_input_method < 0)
1919 XtSetValues (InputMethodMenus[0], arg, 1);
1921 XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
1925 auto_input_method = 1;
1928 else if (input_method_table[idx].available >= 0)
1930 if (! input_method_table[idx].im)
1932 input_method_table[idx].im =
1933 minput_open_im (input_method_table[idx].language,
1934 input_method_table[idx].name, NULL);
1935 if (! input_method_table[idx].im)
1936 input_method_table[idx].available = -1;
1938 if (input_method_table[idx].im)
1939 select_input_method (idx);
1941 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1942 XtSetValues (InputMethodMenus[idx + 2], arg, 1);
1945 MPlist *default_face_list;
1948 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
1950 int idx = (int) client_data;
1961 MFace *face = mframe_get_prop (frame, Mface);
1963 for (plist = default_face_list; mplist_key (plist) != Mnil;
1964 plist = mplist_next (plist))
1965 mface_merge (face, mplist_value (plist));
1966 mplist_add (plist, Mt, *face_table[idx].face);
1967 mface_merge (face, *face_table[idx].face);
1969 else if (mplist_key (mplist_next (default_face_list)) != Mnil)
1971 MFace *face = mframe_get_prop (frame, Mface);
1973 for (plist = default_face_list;
1974 mplist_key (mplist_next (plist)) != Mnil;
1975 plist = mplist_next (plist))
1976 mface_merge (face, mplist_value (plist));
1980 update_cursor (0, 1);
1981 redraw (0, win_height, 1, 1);
1986 XtAppAddWorkProc (context, show_cursor, NULL);
1987 from = mtext_property_start (selection);
1988 to = mtext_property_end (selection);
1989 old_y1 = sel_end.y1;
1991 mtext_detach_property (selection);
1994 MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
1995 MTEXTPROP_REAR_STICKY);
1996 mtext_push_property (mt, from, to, prop);
1997 m17n_object_unref (prop);
2000 mtext_pop_prop (mt, from, to, Mface);
2002 update_top (top.from);
2003 update_cursor (cursor.from, 1);
2004 select_region (from, to);
2005 update_region (sel_start.y0, old_y1, sel_end.y1);
2006 if (cur.y1 > win_height)
2008 while (cur.y1 > win_height)
2011 update_cursor (cursor.from, 1);
2017 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
2019 MSymbol sym = (MSymbol) client_data;
2026 XtAppAddWorkProc (context, show_cursor, NULL);
2027 from = mtext_property_start (selection);
2028 to = mtext_property_end (selection);
2029 old_y1 = sel_end.y1;
2031 mtext_detach_property (selection);
2033 mtext_put_prop (mt, from, to, Mlanguage, sym);
2035 mtext_pop_prop (mt, from, to, Mlanguage);
2038 update_top (top.from);
2039 update_cursor (cursor.from, 1);
2040 select_region (from, to);
2041 update_region (sel_start.y0, old_y1, sel_end.y1);
2042 if (cur.y1 > win_height)
2044 while (cur.y1 > win_height)
2047 update_cursor (cursor.from, 1);
2053 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
2055 int narrowed = (int) client_data;
2058 MConverter *converter;
2064 from = mtext_property_start (selection);
2065 to = mtext_property_end (selection);
2074 mdump = popen ("mdump -q -p a4", "w");
2076 mdump = popen ("mdump -q", "w");
2079 converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
2080 mconv_encode_range (converter, mt, from, to);
2081 mconv_free_converter (converter);
2086 input_status (MInputContext *ic, MSymbol command)
2088 XFillRectangle (display, input_status_pixmap, gc_inv,
2089 0, 0, input_status_width, input_status_height);
2090 if (command == Minput_status_draw)
2094 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2095 Mface, face_input_status);
2096 if (ic->im->language != Mnil)
2097 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2098 Mlanguage, ic->im->language);
2099 mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
2100 &input_status_control, NULL, NULL, &rect);
2101 mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
2102 input_status_width - rect.width - 2, - rect.y,
2103 ic->status, 0, mtext_len (ic->status),
2104 &input_status_control);
2106 XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
2107 XtSetValues (CurIMStatus, arg, 1);
2111 compare_input_method (const void *elt1, const void *elt2)
2113 const InputMethodInfo *im1 = elt1;
2114 const InputMethodInfo *im2 = elt2;
2115 MSymbol lang1, lang2;
2117 if (im1->language == Mnil)
2119 if (im1->language == im2->language)
2120 return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
2121 if (im1->language == Mt)
2123 if (im2->language == Mt)
2125 lang1 = msymbol_get (im1->language, Mlanguage);
2126 lang2 = msymbol_get (im2->language, Mlanguage);
2127 return strcmp (msymbol_name (lang1), msymbol_name (lang2));
2131 setup_input_methods (int with_xim, char *initial_input_method)
2133 MInputMethod *im = NULL;
2134 MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
2137 char *lang_name = NULL, *method_name = NULL;
2139 if (initial_input_method)
2141 char *p = strchr (initial_input_method, '-');
2143 lang_name = initial_input_method, method_name = p + 1, *p = '\0';
2145 method_name = initial_input_method;
2148 num_input_methods = plist ? mplist_length (plist) : 0;
2152 MInputXIMArgIM arg_xim;
2154 arg_xim.display = display;
2156 arg_xim.res_name = arg_xim.res_class = NULL;
2157 arg_xim.locale = NULL;
2158 arg_xim.modifier_list = NULL;
2159 im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
2161 num_input_methods++;
2163 input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
2166 input_method_table[i].available = 1;
2167 input_method_table[i].language = Mnil;
2168 input_method_table[i].name = im->name;
2169 input_method_table[i].im = im;
2175 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
2177 MDatabase *mdb = mplist_value (pl);
2178 MSymbol *tag = mdatabase_tag (mdb);
2182 input_method_table[i].language = tag[1];
2183 input_method_table[i].name = tag[2];
2188 m17n_object_unref (plist);
2190 num_input_methods = i;
2191 qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
2192 compare_input_method);
2193 current_input_context = NULL;
2195 mplist_put (minput_driver->callback_list, Minput_status_start,
2196 (void *) input_status);
2197 mplist_put (minput_driver->callback_list, Minput_status_draw,
2198 (void *) input_status);
2199 mplist_put (minput_driver->callback_list, Minput_status_done,
2200 (void *) input_status);
2203 for (i = 0; i < num_input_methods; i++)
2204 if (strcmp (method_name, msymbol_name (input_method_table[i].name)) == 0
2206 ? strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0
2207 : input_method_table[i].language == Mt))
2209 current_input_method = i;
2216 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
2220 if (num && *num > 0)
2224 for (i = 0; i < *num; i++)
2225 bytes += strlen (str[i]) + 1;
2226 msg = alloca (bytes);
2227 strcpy (msg, str[0]);
2228 for (i = 1; i < *num; i++)
2229 strcat (msg, " "), strcat (msg, str[i]);
2231 else if (cursor.from < nchars)
2233 int c = mtext_ref_char (mt, cursor.from);
2234 char *name = mchar_get_prop (c, Mname);
2238 msg = alloca (10 + strlen (name));
2239 sprintf (msg, "U+%04X %s", c, name);
2245 XtSetArg (arg[0], XtNlabel, msg);
2246 XtSetValues (MessageWidget, arg, 1);
2252 char *name1, *name2;
2253 XtCallbackProc proc;
2254 XtPointer client_data;
2259 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
2261 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
2263 MenuRec FileMenu[] =
2264 { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
2265 { 0, "Save", NULL, SaveProc, NULL, -1 },
2266 { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
2268 { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2269 { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2271 { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2272 { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2274 { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2277 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2279 MenuRec *rec = (MenuRec *) client_data;
2282 XtSetArg (arg[0], XtNvalue, "");
2283 XtSetArg (arg[1], XtNlabel, rec->name1);
2284 XtSetValues (FileDialogWidget, arg, 2);
2285 XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2286 XtSetArg (arg[0], XtNx, x + 20);
2287 XtSetArg (arg[1], XtNy, y + 10);
2288 XtSetValues (FileShellWidget, arg, 2);
2289 XtPopup (FileShellWidget, XtGrabExclusive);
2293 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2298 XtPopdown (FileShellWidget);
2299 if ((int) client_data == 1)
2301 XtSetArg (arg[0], XtNlabel, &label);
2302 XtGetValues (FileDialogWidget, arg, 1);
2303 if (strcmp (label, FileMenu[0].name1) == 0)
2307 filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2308 fp = fopen (filename, "r");
2310 m17n_object_unref (mt);
2313 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
2321 nchars = mtext_len (mt);
2323 update_cursor (0, 1);
2324 redraw (0, win_height, 1, 1);
2326 else if (strcmp (label, FileMenu[2].name1) == 0)
2327 SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2329 fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2332 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS) \
2333 ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2334 (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA), \
2335 (MENU).status = (STATUS))
2339 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2340 char *menu_name, MenuRec *menus, int num_menus, char *help)
2342 Widget button, menu;
2343 char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2344 <LeaveWindow>: reset() MenuHelp()\n\
2345 <BtnDown>: reset() PopupMenu()\n\
2346 <BtnUp>: highlight()";
2352 menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2353 for (i = 0; i < num_menus; i++)
2364 XtSetArg (arg[n], XtNleftMargin, 20), n++;
2366 XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2368 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2370 XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2374 XtSetArg (arg[0], XtNsensitive, False);
2375 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2381 XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2386 trans = alloca (strlen (fmt) + strlen (help));
2387 sprintf (trans, fmt, help);
2388 XtSetArg (arg[0], XtNmenuName, menu_name);
2389 XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2390 XtSetArg (arg[2], XtNinternalWidth, 2);
2391 XtSetArg (arg[3], XtNhighlightThickness, 1);
2392 XtSetArg (arg[4], XtNleft, XawChainLeft);
2393 XtSetArg (arg[5], XtNright, XawChainLeft);
2396 XtSetArg (arg[i], XtNfromHoriz, left), i++;
2397 button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2402 int height, ascent, *width = alloca (sizeof (int) * num_menus);
2403 int *len = alloca (sizeof (int) * num_menus);
2406 XFontSetExtents *fontset_extents;
2408 XtSetArg (arg[0], XtNfontSet, &font_set);
2409 XtGetValues (button, arg, 1);
2411 fontset_extents = XExtentsOfFontSet (font_set);
2412 height = fontset_extents->max_logical_extent.height;
2413 ascent = - fontset_extents->max_logical_extent.y;
2415 for (i = 0; i < num_menus; i++)
2418 len[i] = strlen (menus[i].name2);
2419 width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2420 if (max_width < width[i])
2421 max_width = width[i];
2423 for (i = 0; i < num_menus; i++)
2426 Pixmap pixmap = XCreatePixmap (display,
2427 RootWindow (display, screen),
2428 max_width, height, 1);
2429 XFillRectangle (display, pixmap, mono_gc_inv,
2430 0, 0, max_width, height);
2431 XmbDrawString (display, pixmap, font_set, mono_gc,
2432 max_width - width[i], ascent,
2433 menus[i].name2, len[i]);
2434 XtSetArg (arg[0], XtNrightBitmap, pixmap);
2435 XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2436 XtSetValues (menus[i].w, arg, 2);
2444 XtActionsRec actions[] = {
2445 {"Expose", ExposeProc},
2446 {"Configure", ConfigureProc},
2448 {"ButtonPress", ButtonProc},
2449 {"ButtonRelease", ButtonReleaseProc},
2450 {"ButtonMotion", ButtonMoveProc},
2451 {"Button2Press", Button2Proc},
2452 {"MenuHelp", MenuHelpProc}
2456 /* Print the usage of this program (the name is PROG), and exit with
2460 help_exit (char *prog, int exit_code)
2468 printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2469 printf ("Display FILE on a window and allow users to edit it.\n");
2470 printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2471 printf ("The following OPTIONs are available.\n");
2472 printf (" %-13s\n\t\t%s", "--fontset FONTSET",
2473 "Use the specified fontset\n");
2474 printf (" %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
2475 printf (" %-13s\n\t\t%s", "--im INPUT-METHOD",
2476 "Input method activated initially.\n");
2477 printf (" %-13s %s", "--version", "print version number\n");
2478 printf (" %-13s %s", "-h, --help", "print this message\n");
2484 main (int argc, char **argv)
2486 Widget form, BodyWidget, w;
2487 char *fontset_name = NULL;
2489 char *initial_input_method = NULL;
2490 int col = 80, row = 32;
2491 /* Translation table for TextWidget. */
2492 String trans = "<Expose>: Expose()\n\
2493 <Configure>: Configure()\n\
2496 <Btn1Down>: ButtonPress()\n\
2497 <Btn1Up>: ButtonRelease()\n\
2498 <Btn1Motion>: ButtonMotion()\n\
2499 <Btn2Down>: Button2Press()";
2500 /* Translation table for the top form widget. */
2501 String trans2 = "<Key>: Key()\n\
2503 String pop_face_trans
2504 = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2505 <LeaveWindow>: MenuHelp() reset()\n\
2506 <Btn1Down>: set()\n\
2507 <Btn1Up>: notify() unset()";
2508 String pop_lang_trans
2509 = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2510 <LeaveWindow>: MenuHelp() reset()\n\
2511 <Btn1Down>: set()\n\
2512 <Btn1Up>: notify() unset()";
2513 int font_width, font_ascent, font_descent;
2516 char *filter = NULL;
2518 setlocale (LC_ALL, "");
2519 /* Create the top shell. */
2520 XtSetLanguageProc (NULL, NULL, NULL);
2521 ShellWidget = XtOpenApplication (&context, "M17NEdit", NULL, 0, &argc, argv,
2522 NULL, sessionShellWidgetClass, NULL, 0);
2523 display = XtDisplay (ShellWidget);
2524 screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2526 /* Parse the remaining command line arguments. */
2527 for (i = 1; i < argc; i++)
2529 if (! strcmp (argv[i], "--help")
2530 || ! strcmp (argv[i], "-h"))
2531 help_exit (argv[0], 0);
2532 else if (! strcmp (argv[i], "--version"))
2534 printf ("m17n-edit (m17n library) %s\n", VERSION);
2535 printf ("Copyright (C) 2003 AIST, JAPAN\n");
2538 else if (! strcmp (argv[i], "--geometry"))
2541 if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2542 help_exit (argv[0], 1);
2544 else if (! strcmp (argv[i], "-s"))
2547 fontsize = atoi (argv[i]);
2551 else if (! strcmp (argv[i], "--fontset"))
2554 fontset_name = strdup (argv[i]);
2556 else if (! strcmp (argv[i], "--im"))
2559 initial_input_method = strdup (argv[i]);
2561 else if (! strcmp (argv[i], "--with-xim"))
2565 else if (! strcmp (argv[i], "--filter"))
2570 else if (argv[i][0] != '-')
2572 filename = strdup (argv[i]);
2576 fprintf (stderr, "Unknown option: %s\n", argv[i]);
2577 help_exit (argv[0], 1);
2581 filename = strdup ("/dev/null");
2583 mdatabase_dir = ".";
2584 /* Initialize the m17n library. */
2586 if (merror_code != MERROR_NONE)
2587 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2589 mt = read_file (filename);
2592 nchars = mtext_len (mt);
2594 Mword = msymbol ("word");
2597 MFace *face = mface ();
2599 mface_put_prop (face, Mforeground, msymbol ("blue"));
2600 mface_put_prop (face, Mbackground, msymbol ("yellow"));
2601 mface_put_prop (face, Mvideomode, Mreverse);
2602 selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2603 m17n_object_unref (face);
2606 /* This tells ExposeProc to initialize everything. */
2609 XA_TEXT = XInternAtom (display, "TEXT", False);
2610 XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2611 XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2612 Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
2613 if (Mcoding_compound_text == Mnil)
2614 FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
2617 MPlist *plist = mplist ();
2621 mplist_put (plist, msymbol ("widget"), ShellWidget);
2622 if (fontset_name || fontsize > 0)
2624 MFontset *fontset = mfontset (fontset_name);
2627 mface_put_prop (face, Mfontset, fontset);
2628 mface_put_prop (face, Msize, (void *) fontsize);
2629 m17n_object_unref (fontset);
2630 mplist_add (plist, Mface, face);
2631 m17n_object_unref (face);
2633 frame = mframe (plist);
2635 FATAL_ERROR ("%s\n", "Fail to create a frame!");
2636 m17n_object_unref (plist);
2637 face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
2638 default_face_list = mplist ();
2639 mplist_add (default_face_list, Mt, face_default);
2640 face_default_fontset = mface ();
2641 mface_put_prop (face_default_fontset, Mfontset,
2642 mface_get_prop (face_default, Mfontset));
2644 font = (MFont *) mframe_get_prop (frame, Mfont);
2645 default_font_size = (int) mfont_get_prop (font, Msize);
2648 font_width = (int) mframe_get_prop (frame, Mfont_width);
2649 font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2650 font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2651 win_width = font_width * col;
2652 win_height = (font_ascent + font_descent) * row;
2658 prop.color_top = prop.color_left = msymbol ("magenta");
2659 prop.color_bottom = prop.color_right = msymbol ("red");
2660 prop.inner_hmargin = prop.inner_vmargin = 1;
2661 prop.outer_hmargin = prop.outer_vmargin = 2;
2663 face_box = mface ();
2664 mface_put_prop (face_box, Mbox, &prop);
2667 face_courier = mface ();
2668 mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2669 face_helvetica = mface ();
2670 mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2671 face_times = mface ();
2672 mface_put_prop (face_times, Mfamily, msymbol ("times"));
2673 face_dv_ttyogesh = mface ();
2674 mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2675 face_freesans = mface ();
2676 mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2677 face_freeserif = mface ();
2678 mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
2679 face_freemono = mface ();
2680 mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2682 face_xxx_large = mface ();
2683 mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2685 MFont *latin_font = mframe_get_prop (frame, Mfont);
2686 MFont *dev_font = mfont ();
2687 MFont *thai_font = mfont ();
2688 MFont *tib_font = mfont ();
2690 MSymbol unicode_bmp = msymbol ("unicode-bmp");
2691 MSymbol no_ctl = msymbol ("no-ctl");
2693 mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2694 mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2695 mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2696 mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2697 mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2698 mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2700 fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
2701 mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
2702 latin_font, Mnil, 0);
2703 mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
2704 dev_font, no_ctl, 0);
2705 mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
2706 thai_font, no_ctl, 0);
2707 mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
2708 tib_font, no_ctl, 0);
2709 face_no_ctl_fontset = mface ();
2710 mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
2711 m17n_object_unref (fontset);
2718 setup_input_methods (with_xim, initial_input_method);
2720 gc = DefaultGC (display, screen);
2722 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2723 XtSetArg (arg[1], XtNdefaultDistance, 2);
2724 form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2726 XtSetArg (arg[0], XtNborderWidth, 0);
2727 XtSetArg (arg[1], XtNdefaultDistance, 2);
2728 XtSetArg (arg[2], XtNtop, XawChainTop);
2729 XtSetArg (arg[3], XtNbottom, XawChainTop);
2730 XtSetArg (arg[4], XtNleft, XawChainLeft);
2731 XtSetArg (arg[5], XtNright, XawChainRight);
2732 XtSetArg (arg[6], XtNresizable, True);
2733 HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2734 XtSetArg (arg[7], XtNfromVert, HeadWidget);
2735 FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2736 XtSetArg (arg[7], XtNfromVert, FaceWidget);
2737 LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2738 XtSetArg (arg[3], XtNbottom, XawChainBottom);
2739 XtSetArg (arg[7], XtNfromVert, LangWidget);
2740 BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2741 XtSetArg (arg[2], XtNtop, XawChainBottom);
2742 XtSetArg (arg[7], XtNfromVert, BodyWidget);
2743 TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2745 FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2746 HeadWidget, NULL, 0);
2747 XtSetArg (arg[0], XtNvalue, "");
2748 FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2749 FileShellWidget, arg, 1);
2750 XawDialogAddButton (FileDialogWidget, "OK",
2751 FileDialogProc, (XtPointer) 0);
2752 XawDialogAddButton (FileDialogWidget, "CANCEL",
2753 FileDialogProc, (XtPointer) 1);
2755 CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2756 (char *) check_bits,
2757 check_width, check_height);
2759 unsigned long valuemask = GCForeground;
2762 values.foreground = 1;
2763 mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2764 values.foreground = 0;
2765 mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2772 if (num_menus < num_input_methods + 2)
2773 num_menus = num_input_methods + 2;
2774 if (num_menus < num_faces + 1)
2775 num_menus = num_faces + 1;
2776 menus = alloca (sizeof (MenuRec) * num_menus);
2778 w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2779 FileMenu, sizeof FileMenu / sizeof (MenuRec),
2780 "File I/O, Serialization, Image, Quit");
2782 SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2783 SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2784 SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2785 SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2786 SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2787 SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2788 w = create_menu_button (ShellWidget, HeadWidget, w,
2789 "Cursor", "Cursor Menu",
2790 menus, 6, "Cursor Movement Mode, Cursor Shape");
2791 CursorMenus[0] = menus[0].w;
2792 CursorMenus[1] = menus[1].w;
2793 CursorMenus[2] = menus[3].w;
2794 CursorMenus[3] = menus[4].w;
2795 CursorMenus[4] = menus[5].w;
2797 SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2798 SetMenu (menus[1], 0, "Left (|--> |)", NULL, BidiProc, 1, 1);
2799 SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2800 w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2801 menus, 3, "BIDI Processing Mode");
2802 for (i = 0; i < 3; i++)
2803 BidiMenus[i] = menus[i].w;
2805 SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2806 SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2807 SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2808 w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2810 menus, 3, "How to break lines");
2811 for (i = 0; i < 3; i++)
2812 LineBreakMenus[i] = menus[i].w;
2814 SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2815 SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2816 for (i = 0; i < num_input_methods; i++)
2818 InputMethodInfo *im = input_method_table + i;
2819 char *name1, *name2;
2821 if (im->language != Mnil && im->language != Mt)
2823 MSymbol sym = msymbol_get (im->language, Mlanguage);
2825 name1 = msymbol_name (im->language);
2827 name1 = msymbol_name (sym);
2828 name2 = msymbol_name (im->name);
2831 name1 = msymbol_name (im->name), name2 = NULL;
2833 SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
2835 w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
2836 "Input Method Menu", menus, i + 2,
2837 "Select input method");
2840 unsigned long valuemask = GCForeground;
2843 XtSetArg (arg[0], XtNbackground, &values.foreground);
2844 XtGetValues (w, arg, 1);
2845 gc_inv = XCreateGC (display, RootWindow (display, screen),
2846 valuemask, &values);
2849 InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
2850 for (i = 0; i < num_input_methods + 2; i++)
2851 InputMethodMenus[i] = menus[i].w;
2855 SetMenu (menus[0], 0, filter, NULL, FilterProc, filter, 0);
2856 w = create_menu_button (ShellWidget, HeadWidget, w, "Filter",
2857 "Filter Menu", menus, 1,
2858 "Select filter to run");
2861 input_status_width = font_width * 8;
2862 input_status_height = (font_ascent + font_descent) * 2.4;
2863 input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
2865 input_status_height,
2866 DefaultDepth (display, screen));
2871 prop.color_top = prop.color_bottom
2872 = prop.color_left = prop.color_right = Mnil;
2873 prop.inner_hmargin = prop.inner_vmargin = 1;
2874 prop.outer_hmargin = prop.outer_vmargin = 0;
2875 face_input_status = mface_copy (face_default);
2876 mface_put_prop (face_input_status, Mbox, &prop);
2879 XFillRectangle (display, input_status_pixmap, gc_inv,
2880 0, 0, input_status_width, input_status_height);
2881 XtSetArg (arg[0], XtNfromHoriz, w);
2882 XtSetArg (arg[1], XtNleft, XawRubber);
2883 XtSetArg (arg[2], XtNright, XawChainRight);
2884 XtSetArg (arg[3], XtNborderWidth, 0);
2885 XtSetArg (arg[4], XtNlabel, " ");
2886 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2887 CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
2888 HeadWidget, arg, 6);
2889 XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
2890 XtSetArg (arg[1], XtNleft, XawChainRight);
2891 XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
2892 CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
2893 HeadWidget, arg, 5);
2895 XtSetArg (arg[0], XtNborderWidth, 0);
2896 XtSetArg (arg[1], XtNleft, XawChainLeft);
2897 XtSetArg (arg[2], XtNright, XawChainLeft);
2898 w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
2899 for (i = 0; i < num_faces;)
2901 char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
2902 char *label = label_menu + 5; /* "Xxxx" */
2904 for (j = i; j < num_faces && face_table[j].face; j++)
2905 SetMenu (menus[j - i], 0, face_table[j].name, NULL,
2907 w = create_menu_button (ShellWidget, FaceWidget, w,
2909 menus, j - i, "Push face property");
2913 XtSetArg (arg[0], XtNfromHoriz, w);
2914 XtSetArg (arg[1], XtNleft, XawChainLeft);
2915 XtSetArg (arg[2], XtNright, XawChainLeft);
2916 XtSetArg (arg[3], XtNhorizDistance, 10);
2917 XtSetArg (arg[4], XtNlabel, "Pop");
2918 XtSetArg (arg[5], XtNtranslations,
2919 XtParseTranslationTable (pop_face_trans));
2920 w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
2921 FaceWidget, arg, 6);
2922 XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
2924 XtSetArg (arg[0], XtNfromHoriz, w);
2925 XtSetArg (arg[1], XtNleft, XawChainLeft);
2926 XtSetArg (arg[2], XtNright, XawChainRight);
2927 XtSetArg (arg[3], XtNlabel, "");
2928 XtSetArg (arg[4], XtNborderWidth, 0);
2929 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2930 CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
2931 FaceWidget, arg, 6);
2933 XtSetArg (arg[0], XtNborderWidth, 0);
2934 XtSetArg (arg[1], XtNleft, XawChainLeft);
2935 XtSetArg (arg[2], XtNright, XawChainLeft);
2936 w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
2938 MPlist *plist[11], *pl;
2941 for (i = 0; i < 11; i++) plist[i] = NULL;
2943 for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
2944 for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
2946 MSymbol sym = msymbol_exist (langname);
2950 && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
2952 char *name = msymbol_name (fullname);
2955 if (c >= 'A' && c <= 'Z')
2957 int idx = (c < 'U') ? (c - 'A') / 2 : 10;
2961 pl = plist[idx] = mplist ();
2962 for (; mplist_next (pl); pl = mplist_next (pl))
2963 if (strcmp (name, (char *) mplist_value (pl)) < 0)
2965 mplist_push (pl, sym, fullname);
2970 for (i = 0; i < 11; i++)
2973 char *name = alloca (9);
2975 sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
2978 for (j = 0, pl = plist[i]; mplist_next (pl);
2979 j++, pl = mplist_next (pl))
2980 SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
2981 msymbol_name (mplist_key (pl)),
2982 LangProc, mplist_key (pl), -1);
2983 w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
2984 menus, j, "Push language property");
2986 for (i = 0; i < 11; i++)
2988 m17n_object_unref (plist[i]);
2990 XtSetArg (arg[0], XtNfromHoriz, w);
2991 XtSetArg (arg[1], XtNleft, XawChainLeft);
2992 XtSetArg (arg[2], XtNright, XawChainLeft);
2993 XtSetArg (arg[3], XtNhorizDistance, 10);
2994 XtSetArg (arg[4], XtNlabel, "Pop");
2995 XtSetArg (arg[5], XtNtranslations,
2996 XtParseTranslationTable (pop_lang_trans));
2997 w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
2998 LangWidget, arg, 6);
2999 XtAddCallback (w, XtNcallback, LangProc, Mnil);
3001 XtSetArg (arg[0], XtNfromHoriz, w);
3002 XtSetArg (arg[1], XtNleft, XawChainLeft);
3003 XtSetArg (arg[2], XtNright, XawChainRight);
3004 XtSetArg (arg[3], XtNlabel, "");
3005 XtSetArg (arg[4], XtNborderWidth, 0);
3006 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3007 CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
3008 LangWidget, arg, 6);
3011 XtSetArg (arg[0], XtNheight, win_height);
3012 XtSetArg (arg[1], XtNwidth, 10);
3013 XtSetArg (arg[2], XtNleft, XawChainLeft);
3014 XtSetArg (arg[3], XtNright, XawChainLeft);
3015 SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
3017 XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
3018 XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
3020 XtSetArg (arg[0], XtNheight, win_height);
3021 XtSetArg (arg[1], XtNwidth, win_width);
3022 XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
3023 XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
3024 XtSetArg (arg[4], XtNleft, XawChainLeft);
3025 XtSetArg (arg[5], XtNright, XawChainRight);
3026 TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
3029 XtSetArg (arg[0], XtNborderWidth, 0);
3030 XtSetArg (arg[1], XtNleft, XawChainLeft);
3031 XtSetArg (arg[2], XtNright, XawChainRight);
3032 XtSetArg (arg[3], XtNresizable, True);
3033 XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
3034 MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
3035 TailWidget, arg, 5);
3037 memset (&control, 0, sizeof control);
3038 control.two_dimensional = 1;
3039 control.enable_bidi = 1;
3040 control.anti_alias = 1;
3041 control.min_line_ascent = font_ascent;
3042 control.min_line_descent = font_descent;
3043 control.max_line_width = win_width;
3044 control.with_cursor = 1;
3045 control.cursor_width = 2;
3046 control.partial_update = 1;
3047 control.ignore_formatting_char = 1;
3049 memset (&input_status_control, 0, sizeof input_status_control);
3050 input_status_control.enable_bidi = 1;
3052 XtAppAddActions (context, actions, XtNumber (actions));
3053 XtRealizeWidget (ShellWidget);
3055 win = XtWindow (TextWidget);
3057 XtAppMainLoop (context);
3059 if (current_input_context)
3060 minput_destroy_ic (current_input_context);
3061 for (i = 0; i < num_input_methods; i++)
3062 if (input_method_table[i].im)
3063 minput_close_im (input_method_table[i].im);
3064 m17n_object_unref (frame);
3065 m17n_object_unref (mt);
3066 m17n_object_unref (face_xxx_large);
3067 m17n_object_unref (face_box);
3068 m17n_object_unref (face_courier);
3069 m17n_object_unref (face_helvetica);
3070 m17n_object_unref (face_times);
3071 m17n_object_unref (face_dv_ttyogesh);
3072 m17n_object_unref (face_freesans);
3073 m17n_object_unref (face_freeserif);
3074 m17n_object_unref (face_freemono);
3075 m17n_object_unref (face_default_fontset);
3076 m17n_object_unref (face_no_ctl_fontset);
3077 m17n_object_unref (face_input_status);
3078 m17n_object_unref (face_default);
3079 m17n_object_unref (default_face_list);
3080 m17n_object_unref (selection);
3082 XFreeGC (display, mono_gc);
3083 XFreeGC (display, mono_gc_inv);
3084 XFreeGC (display, gc_inv);
3085 XtUninstallTranslations (form);
3086 XtUninstallTranslations (TextWidget);
3087 XtDestroyWidget (ShellWidget);
3088 XtDestroyApplicationContext (context);
3092 free (fontset_name);
3094 free (input_method_table);
3095 free (InputMethodMenus);
3099 #endif /* not FOR_DOXYGEN */