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 #ifdef HAVE_X11_XAW_COMMAND_H
102 #include <X11/keysym.h>
103 #include <X11/Xatom.h>
104 #include <X11/Intrinsic.h>
105 #include <X11/StringDefs.h>
106 #include <X11/Shell.h>
108 #include <m17n-gui.h>
109 #include <m17n-misc.h>
112 #include <X11/Xaw/Command.h>
113 #include <X11/Xaw/Box.h>
114 #include <X11/Xaw/Form.h>
115 #include <X11/Xaw/Dialog.h>
116 #include <X11/Xaw/Scrollbar.h>
117 #include <X11/Xaw/Toggle.h>
118 #include <X11/Xaw/SimpleMenu.h>
119 #include <X11/Xaw/SmeBSB.h>
120 #include <X11/Xaw/SmeLine.h>
121 #include <X11/Xaw/MenuButton.h>
123 #define VERSION "1.2.0"
125 /* Global variables. */
130 /* For the X Window System. */
133 /* GCs for normal drawing, filling by background color, normal drawing
134 on bitmap (i.e. pixmap of depth 1), filling bitmap by background
136 GC gc, gc_inv, mono_gc, mono_gc_inv;
138 Atom XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING; /* X Selection types. */
139 XtAppContext context;
140 int default_font_size;
144 Shell - Form -+- Head -- File, Cursor, Bidi, LineBreak, InputMethod, CurIM;
145 +- Face -- Size, Family, Style, Color, Misc, Pop, CurFace
146 +- Lang -- A-B, C-D, ..., U-Z, Pop, CurLang
147 +- Body -- Sbar, Text
151 Widget ShellWidget, HeadWidget, TailWidget, MessageWidget;
152 Widget CursorMenus[5], BidiMenus[3], LineBreakMenus[3], *InputMethodMenus;
153 Widget SbarWidget, TextWidget;
154 Widget FileShellWidget, FileDialogWidget;
155 Widget FaceWidget, CurFaceWidget, LangWidget, CurLangWidget;
156 Widget CurIMLang, CurIMStatus;
158 int win_width, win_height; /* Size of TextWidget. */
161 Pixmap input_status_pixmap;
162 int input_status_width, input_status_height;
164 /* Bitmap for "check" glyph. */
165 #define check_width 9
166 #define check_height 8
167 static unsigned char check_bits[] = {
168 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
169 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 };
172 /* For the m17n library. */
175 int nchars; /* == mtext_len (mt) */
176 MDrawControl control, input_status_control;
177 MTextProperty *selection;
182 MFace *face_xxx_large;
184 MFace *face_courier, *face_helvetica, *face_times;
185 MFace *face_dv_ttyogesh, *face_freesans, *face_freeserif, *face_freemono;
186 MFace *face_default_fontset, *face_no_ctl_fontset;
187 MFace *face_input_status;
189 MSymbol Mcoding_compound_text;
191 int logical_move = 1; /* If 0, move cursor visually. */
195 MSymbol language, name;
199 InputMethodInfo *input_method_table;
201 int num_input_methods;
202 int current_input_method = -1; /* i.e. none */
203 int auto_input_method = 0;
204 MInputContext *current_input_context;
211 { {"Menu Size", NULL},
212 {"xx-small", &mface_xx_small},
213 {"x-small", &mface_x_small},
214 {"small", &mface_small},
215 {"normalsize", &mface_normalsize},
216 {"large", &mface_large},
217 {"x-large", &mface_x_large},
218 {"xx-large", &mface_xx_large},
219 {"xxx-large", &face_xxx_large},
221 {"Menu Family", NULL},
222 {"courier", &face_courier},
223 {"helvetica", &face_helvetica},
224 {"times", &face_times},
225 {"dv-ttyogesh", &face_dv_ttyogesh},
226 {"freesans", &face_freesans},
227 {"freeserif", &face_freeserif},
228 {"freemono", &face_freemono},
230 {"Menu Style", NULL},
231 {"medium", &mface_medium},
232 {"bold", &mface_bold},
233 {"italic", &mface_italic},
235 {"Menu Color", NULL},
236 {"black", &mface_black},
237 {"white", &mface_white},
239 {"green", &mface_green},
240 {"blue", &mface_blue},
241 {"cyan", &mface_cyan},
242 {"yello", &mface_yellow},
243 {"magenta", &mface_magenta},
246 {"normal", &mface_normal_video},
247 {"reverse", &mface_reverse_video},
248 {"underline", &mface_underline},
250 {"No CTL", &face_no_ctl_fontset} };
253 int num_faces = sizeof (face_table) / sizeof (struct FaceRec);
255 /* Information about a physical line metric. */
258 int from; /* BOL position of the line. */
259 int to; /* BOL position of the next line. */
260 int y0, y1; /* Top and bottom Y position of the line. */
261 int ascent; /* Height of the top Y position. */
264 struct LineInfo top; /* Topmost line. */
265 struct LineInfo cur; /* Line containing cursor. */
266 struct LineInfo sel_start; /* Line containing selection start. */
267 struct LineInfo sel_end; /* Line containing selection end. */
269 MDrawGlyphInfo cursor; /* Information about the cursor glyph. */
271 /* X position to keep on vertical (up and down) cursor motion. */
272 int target_x_position;
274 /* Interface macros for m17n-lib drawing routines. */
276 /* Draw a text in the range $FROM to $TO of the M-text #MT at the
277 coordinate ($X, $Y) */
278 #define DRAW_TEXT(x, y, from, to) \
279 mdraw_text_with_control \
280 (frame, (MDrawWindow) win, \
281 control.orientation_reversed ? x + win_width : x, y, \
282 mt, from, to, &control)
284 /* Store the extents of a text in the range $FROM to $TO in the
285 structure $RECT (type MDrawMetric). */
286 #define TEXT_EXTENTS(from, to, rect) \
287 mdraw_text_extents (frame, mt, from, (to), &control, NULL, NULL, &(rect))
289 /* Store the glyph information of a character at the position $POS in
290 the struct $INFO (type MDrawGlyphInfo) assuming that the text from
291 $FROM is written at the coordinate (0, 0). */
292 #define GLYPH_INFO(from, pos, info) \
293 mdraw_glyph_info (frame, mt, from, (pos), &control, &(info))
295 /* Set $X and $Y to the coordinate of character at position $POS
296 assuming that the text from $FROM is written at the coordinate (0,
298 #define COORDINATES_POSITION(from, pos, x, y) \
299 mdraw_coordinates_position (frame, mt, (from), (pos), (x), (y), &control)
301 /* Interface macros for X library. */
302 #define COPY_AREA(y0, y1, to) \
303 XCopyArea (display, win, win, gc, 0, (y0), win_width, (y1) - (y0), 0, (to))
305 #define CLEAR_AREA(x, y, w, h) \
306 XClearArea (display, win, (x), (y), (w), (h), False)
308 #define SELECTEDP() \
309 mtext_property_mtext (selection)
311 /* Format MSG by FMT and print the result to the stderr, and exit. */
312 #define FATAL_ERROR(fmt, arg) \
314 fprintf (stderr, fmt, arg); \
319 /* If POS is greater than zero, move POS back to the beginning of line
320 (BOL) position. If FORWARD is nonzero, move POS forward instead.
321 Return the new position. */
323 bol (int pos, int forward)
325 int limit = forward ? nchars : 0;
327 pos = mtext_character (mt, pos, limit, '\n');
328 return (pos < 0 ? limit : pos + 1);
331 /* Update the structure #TOP (struct LineInfo) to make $POS the first
332 character position of the screen. */
336 int from = bol (pos, 0);
339 GLYPH_INFO (from, pos, info);
340 top.from = info.line_from;
341 top.to = info.line_to;
343 top.y1 = info.metrics.height;
344 top.ascent = - info.metrics.y;
348 /* Update the scroll bar so that the text of the range $FROM to $TO
349 are shown on the window. */
351 update_scroll_bar (int from, int to)
353 float top = (float) from / nchars;
354 float shown = (float) (to - from) / nchars;
355 XtArgVal *l_top = (XtArgVal *) ⊤
356 XtArgVal *l_shown = (XtArgVal *) &shown;
358 XtSetArg (arg[0], XtNtopOfThumb, *l_top);
359 XtSetArg (arg[1], XtNshown, *l_shown);
360 XtSetValues (SbarWidget, arg, 2);
364 /* Redraw the window area between $Y0 and $Y1 (both Y-codinates). If
365 $CLEAR is nonzero, clear the area before drawing. If $SCROLL_BAR
366 is nonzero, update the scoll bar. */
368 redraw (int y0, int y1, int clear, int scroll_bar)
373 int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
374 struct LineInfo *line;
376 if (clear || control.anti_alias)
377 CLEAR_AREA (0, y0, win_width, y1 - y0);
379 /* Find a line closest to y0. It is a cursor line if the cursor is
380 Y0, otherwise the top line. */
385 /* If there exists a selected region, check it too. */
386 if (sel_y0 > line->y0 && y0 >= sel_y0)
391 info.metrics.height = line->y1 - y;
392 info.metrics.y = - line->ascent;
393 info.line_to = line->to;
394 while (y + info.metrics.height <= y0)
396 y += info.metrics.height;
400 GLYPH_INFO (from, from, info);
402 if (y + info.metrics.height <= y0)
405 y0 = y - info.metrics.y;
407 while (to < nchars && y < y1)
409 GLYPH_INFO (to, to, info);
410 y += info.metrics.height;
416 DRAW_TEXT (0, y0, from, to);
421 GLYPH_INFO (to, to, info);
422 if (y + info.metrics.height >= win_height)
425 y += info.metrics.height;
427 update_scroll_bar (top.from, to);
432 /* Set the current input method spot to the correct position. */
434 set_input_method_spot ()
436 int x = cursor.x + (control.orientation_reversed ? win_width : 0);
437 int pos = cursor.from > 0 ? cursor.from - 1 : 0;
440 int size = 0, ratio = 0, i;
443 n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
445 for (i = n - 1; i >= 0; i--)
448 size = (int) mface_get_prop (faces[i], Msize);
450 ratio = (int) mface_get_prop (faces[i], Mratio);
453 size = default_font_size;
455 size = size * ratio / 100;
456 minput_set_spot (current_input_context, x, cur.y0 + cur.ascent,
457 cur.ascent, cur.y1 - (cur.y0 + cur.ascent), size,
462 /* Redraw the cursor. If $CLEAR is nonzero, clear the cursor area
465 redraw_cursor (int clear)
467 if (control.cursor_bidi)
469 /* We must update the whole line of the cursor. */
470 int beg = bol (cur.from, 0);
471 int end = bol (cur.to - 1, 1);
473 int y0 = cur.y0, y1 = cur.y1;
477 TEXT_EXTENTS (beg, cur.from, rect);
482 TEXT_EXTENTS (cur.to, end, rect);
485 redraw (y0, y1, clear, 0);
493 if (control.orientation_reversed)
494 x += win_width - cursor.logical_width;
495 CLEAR_AREA (x, cur.y0, cursor.logical_width, cursor.metrics.height);
497 DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
502 /* Update the information about the location of cursor to the position
503 $POS. If $FULL is nonzero, update the information fully only from
504 the information about the top line. Otherwise, trust the current
505 information in the structure $CUR. */
507 update_cursor (int pos, int full)
513 /* CUR is inaccurate. We can trust only TOP. */
514 GLYPH_INFO (top.from, pos, cursor);
515 cur.y0 = top.ascent + cursor.y + cursor.metrics.y;
517 else if (pos < cur.from)
519 int from = bol (pos, 0);
521 TEXT_EXTENTS (from, cur.from, rect);
522 GLYPH_INFO (from, pos, cursor);
523 cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.metrics.y);
525 else if (pos < cur.to)
527 GLYPH_INFO (cur.from, pos, cursor);
531 GLYPH_INFO (cur.from, pos, cursor);
532 cur.y0 += cur.ascent + cursor.y + cursor.metrics.y;
535 cur.from = cursor.line_from;
536 cur.to = cursor.line_to;
537 cur.y1 = cur.y0 + cursor.metrics.height;
538 cur.ascent = - cursor.metrics.y;
542 /* Update the information about the selected region. */
552 from = mtext_property_start (selection);
553 to = mtext_property_end (selection);
557 int pos = bol (from, 0);
559 TEXT_EXTENTS (pos, top.from, rect);
560 sel_start.y0 = top.y0 - rect.height;
561 sel_start.ascent = - rect.y;
562 GLYPH_INFO (pos, from, info);
563 if (pos < info.line_from)
564 sel_start.y0 += - rect.y + info.y + info.metrics.y;
568 GLYPH_INFO (top.from, from, info);
569 sel_start.y0 = top.ascent + info.y + info.metrics.y;
571 sel_start.ascent = -info.metrics.y;
572 sel_start.y1 = sel_start.y0 + info.metrics.height;
573 sel_start.from = info.line_from;
574 sel_start.to = info.line_to;
576 if (to <= sel_start.to)
582 GLYPH_INFO (sel_start.from, to, info);
583 sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.metrics.y;
584 sel_end.y1 = sel_end.y0 + info.metrics.height;
585 sel_end.ascent = - info.metrics.y;
586 sel_end.from = info.line_from;
587 sel_end.to = info.line_to;
592 /* Select the text in the region from $FROM to $TO. */
594 select_region (int from, int to)
599 pos = from, from = to, to = pos;
600 mtext_push_property (mt, from, to, selection);
605 /* Setup the window to display the character of $POS at the top left
611 /* Top and bottom Y positions to redraw. */
614 if (pos + 1000 < top.from)
615 y0 = 0, y1 = win_height;
616 else if (pos < top.from)
619 TEXT_EXTENTS (pos, top.from, rect);
620 if (rect.height >= win_height * 0.9)
625 COPY_AREA (0, win_height - y1, y1);
628 else if (pos < top.to)
630 /* No need of redrawing. */
633 else if (pos < top.from + 1000)
635 TEXT_EXTENTS (top.from, pos, rect);
636 if (rect.height >= win_height * 0.9)
640 y0 = win_height - rect.height;
641 COPY_AREA (rect.height, win_height, 0);
646 y0 = 0, y1 = win_height;
652 update_cursor (pos, 1);
654 update_cursor (cursor.from, 1);
656 redraw (y0, y1, 1, 1);
660 static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
663 /* Select an input method accoding to $IDX. If $IDX is negative, turn
664 off the current input method, otherwide turn on the input method
665 input_method_table[$IDX]. */
667 select_input_method (idx)
669 if (idx == current_input_method)
671 if (current_input_context)
673 minput_destroy_ic (current_input_context);
674 current_input_context = NULL;
675 current_input_method = -1;
679 InputMethodInfo *im = input_method_table + idx;
681 if (im->language == Mnil)
683 MInputXIMArgIC arg_xic;
684 Window win = XtWindow (TextWidget);
686 arg_xic.input_style = 0;
687 arg_xic.client_win = arg_xic.focus_win = win;
688 arg_xic.preedit_attrs = arg_xic.status_attrs = NULL;
689 current_input_context = minput_create_ic (im->im, &arg_xic);
693 MInputGUIArgIC arg_ic;
695 arg_ic.frame = frame;
696 arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
697 arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
698 current_input_context = minput_create_ic (im->im, &arg_ic);
701 if (current_input_context)
703 set_input_method_spot ();
704 current_input_method = idx;
707 if (current_input_method >= 0)
710 XtSetArg (arg[0], XtNlabel, &label);
711 XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
712 XtSetArg (arg[0], XtNlabel, label);
715 XtSetArg (arg[0], XtNlabel, "");
716 XtSetValues (CurIMLang, arg, 1);
719 static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
722 /* Display cursor according to the current information of #CUR.
723 $CLIENT_DATA is ignore. Most callback functions add this function
724 as a background processing procedure the current application (by
725 XtAppAddWorkProc) via the function hide_cursor. */
727 show_cursor (XtPointer client_data)
729 MFaceHLineProp *hline;
735 update_cursor (cursor.from, 1);
737 while (cur.y1 > win_height)
740 update_cursor (cursor.from, 1);
743 control.cursor_pos = cursor.from;
746 control.with_cursor = 1;
749 if (current_input_context)
750 set_input_method_spot ();
754 int pos = (SELECTEDP () ? mtext_property_start (selection)
755 : cursor.from > 0 ? cursor.from - 1
757 MFace *face = mface ();
758 MTextProperty *props[256];
759 int n = mtext_get_properties (mt, pos, Mface, props, 256);
761 char buf[256], *p = buf;
767 int size = (int) mfont_get_prop (cursor.font, Msize);
768 MSymbol family = mfont_get_prop (cursor.font, Mfamily);
769 MSymbol weight = mfont_get_prop (cursor.font, Mweight);
770 MSymbol style = mfont_get_prop (cursor.font, Mstyle);
771 MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
773 sprintf (p, "%dpt", size / 10), p += strlen (p);
775 strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
777 strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
779 strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
781 strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
785 mface_merge (face, face_default);
786 for (i = 0; i < n; i++)
787 if (props[i] != selection)
788 mface_merge (face, (MFace *) mtext_property_value (props[i]));
789 sym = (MSymbol) mface_get_prop (face, Mforeground);
791 strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
792 if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
793 strcat (p, ",rev"), p += strlen (p);
794 hline = mface_get_prop (face, Mhline);
795 if (hline && hline->width > 0)
796 strcat (p, ",ul"), p += strlen (p);
797 box = mface_get_prop (face, Mbox);
798 if (box && box->width > 0)
799 strcat (p, ",box"), p += strlen (p);
800 m17n_object_unref (face);
802 XtSetArg (arg[0], XtNborderWidth, 1);
803 XtSetArg (arg[1], XtNlabel, buf);
804 XtSetValues (CurFaceWidget, arg, 2);
807 if (control.cursor_pos < nchars)
809 MSymbol sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
813 XtSetArg (arg[0], XtNborderWidth, 0);
814 XtSetArg (arg[1], XtNlabel, "");
818 XtSetArg (arg[0], XtNborderWidth, 1);
819 XtSetArg (arg[1], XtNlabel,
820 msymbol_name (msymbol_get (sym, Mlanguage)));
821 XtSetValues (CurLangWidget, arg, 2);
823 XtSetValues (CurLangWidget, arg, 2);
825 if (auto_input_method)
828 select_input_method (-1);
833 for (i = 0; i < num_input_methods; i++)
834 if (input_method_table[i].language == sym)
836 if (i < num_input_methods
837 && input_method_table[i].available >= 0)
839 if (! input_method_table[i].im)
841 input_method_table[i].im =
842 minput_open_im (input_method_table[i].language,
843 input_method_table[i].name, NULL);
844 if (! input_method_table[i].im)
845 input_method_table[i].available = -1;
847 if (input_method_table[i].im)
848 select_input_method (i);
850 select_input_method (-1);
853 select_input_method (-1);
858 MenuHelpProc (MessageWidget, NULL, NULL, NULL);
864 /* Hide the cursor. */
868 control.with_cursor = 0;
870 XtAppAddWorkProc (context, show_cursor, NULL);
874 /* Update the window area between the Y-positions $Y0 and $OLD_Y1 to
875 $Y1 and $NEW_Y1 assuming that the text in the other area is not
878 update_region (int y0, int old_y1, int new_y1)
884 if (old_y1 < win_height)
886 COPY_AREA (old_y1, win_height, new_y1);
887 redraw (win_height - (old_y1 - new_y1), win_height, 1, 0);
890 redraw (new_y1, win_height, 1, 0);
892 else if (new_y1 > old_y1)
894 if (new_y1 < win_height)
895 COPY_AREA (old_y1, win_height, new_y1);
897 if (new_y1 > win_height)
899 redraw (y0, new_y1, 1, 1);
903 /* Delete the next $N characters. If $N is negative delete the
904 precious (- $N) characters. */
910 int y0, old_y1, new_y1;
912 int line_from = cursor.line_from;
915 from = cursor.from, to = from + n;
918 if (cursor.from == cur.from)
920 /* We are at the beginning of line. */
921 int pos = cursor.prev_from;
923 if (cursor.from == top.from)
925 /* We are at the beginning of screen. We must scroll
927 GLYPH_INFO (bol (top.from - 1, 0), top.from - 1, info);
928 reseat (info.line_from);
930 update_cursor (pos, 1);
936 from = cursor.from - 1;
941 TEXT_EXTENTS (cur.from, bol (to + 1, 1), rect);
942 old_y1 = cur.y0 + rect.height;
944 /* Now delete a character. */
945 mtext_del (mt, from, to);
947 if (from >= top.from && from < top.to)
948 update_top (top.from);
949 update_cursor (from, 1);
952 if (line_from != cursor.line_from)
955 TEXT_EXTENTS (cur.from, bol (to, 1), rect);
956 new_y1 = cur.y0 + rect.height;
958 update_region (cur.y0, old_y1, new_y1);
962 /* Insert M-text $NEWTEXT at the current cursor position. */
964 insert_chars (MText *newtext)
966 int n = mtext_len (newtext);
968 int y0, old_y1, new_y1;
973 int n = (mtext_property_end (selection)
974 - mtext_property_start (selection));
975 mtext_detach_property (selection);
980 if (cursor.line_from > 0
981 && mtext_ref_char (mt, cursor.line_from - 1) != '\n')
982 y0 -= control.min_line_descent;
984 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
985 old_y1 = y0 + rect.height;
987 line_from = cursor.line_from;
989 /* Now insert chars. */
990 mtext_ins (mt, cursor.from, newtext);
992 if (cur.from == top.from)
993 update_top (top.from);
994 update_cursor (cursor.from + n, 1);
996 TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
997 new_y1 = cur.y0 + rect.height;
999 update_region (y0, old_y1, new_y1);
1000 update_selection ();
1005 word_constituent_p (int c)
1007 MSymbol category = (MSymbol) mchar_get_prop (c, Mcategory);
1008 char *name = category != Mnil ? msymbol_name (category) : NULL;
1010 return (name && (name[0] == 'L' || name[0] == 'M'));
1017 int pos = cursor.from;
1019 while (pos < nchars && ! word_constituent_p (mtext_ref_char (mt, pos)))
1023 MTextProperty *prop = mtext_get_property (mt, pos, Mword);
1026 pos = mtext_property_end (prop);
1028 while (pos < nchars && word_constituent_p (mtext_ref_char (mt, pos)))
1031 update_cursor (pos, 0);
1037 int pos = cursor.from;
1039 while (pos > 0 && ! word_constituent_p (mtext_ref_char (mt, pos - 1)))
1043 MTextProperty *prop = mtext_get_property (mt, pos - 1, Mword);
1046 pos = mtext_property_start (prop);
1048 while (pos > 0 && word_constituent_p (mtext_ref_char (mt, pos - 1)))
1051 update_cursor (pos, 0);
1055 /* Convert the currently selected text to UTF8-STRING or
1056 COMPOUND-TEXT. It is called when someone requests the current
1057 value of the selection. */
1059 covert_selection (Widget w, Atom *selection_atom,
1060 Atom *target, Atom *return_type,
1061 XtPointer *value, unsigned long *length, int *format)
1063 unsigned char *buf = (unsigned char *) XtMalloc (4096);
1064 MText *this_mt = mtext ();
1065 int from = mtext_property_start (selection);
1066 int to = mtext_property_end (selection);
1070 mtext_copy (this_mt, 0, mt, from, to);
1071 if (*target == XA_TEXT)
1073 #ifdef X_HAVE_UTF8_STRING
1074 coding = Mcoding_utf_8;
1075 *return_type = XA_UTF8_STRING;
1077 coding = Mcoding_compound_text;
1078 *return_type = XA_COMPOUND_TEXT;
1081 else if (*target == XA_UTF8_STRING)
1083 coding = Mcoding_utf_8;
1084 *return_type = XA_UTF8_STRING;
1086 else if (*target == XA_STRING)
1091 for (i = 0; i < len; i++)
1092 if (mtext_ref_char (this_mt, i) >= 0x100)
1093 /* Can't encode in XA_STRING */
1095 coding = Mcoding_iso_8859_1;
1096 *return_type = XA_STRING;
1098 else if (*target == XA_COMPOUND_TEXT)
1100 coding = Mcoding_compound_text;
1101 *return_type = XA_COMPOUND_TEXT;
1106 len = mconv_encode_buffer (coding, this_mt, buf, 4096);
1107 m17n_object_unref (this_mt);
1111 *value = (XtPointer) buf;
1117 /* Unselect the text. It is called when we loose the selection. */
1119 lose_selection (Widget w, Atom *selection_atom)
1123 mtext_detach_property (selection);
1124 redraw (sel_start.y0, sel_end.y1, 1, 0);
1129 get_selection (Widget w, XtPointer cliend_data, Atom *selection, Atom *type,
1130 XtPointer value, unsigned long *length, int *format)
1135 if (*type == XT_CONVERT_FAIL || ! value)
1137 if (*type == XA_STRING)
1139 else if (*type == XA_COMPOUND_TEXT)
1140 coding = msymbol ("compound-text");
1141 #ifdef X_HAVE_UTF8_STRING
1142 else if (*type == XA_UTF8_STRING)
1143 coding = msymbol ("utf-8");
1148 this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
1149 if (! this_mt && *type != XA_UTF8_STRING)
1151 XtGetSelectionValue (w, XA_PRIMARY, XA_UTF8_STRING, get_selection, NULL,
1158 insert_chars (this_mt);
1159 m17n_object_unref (this_mt);
1168 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1170 XExposeEvent *expose = (XExposeEvent *) event;
1174 Dimension width_max, width;
1176 XtSetArg (arg[0], XtNwidth, &width);
1177 XtGetValues (XtParent (w), arg, 1);
1179 XtGetValues (HeadWidget, arg, 1);
1180 if (width_max < width)
1182 XtGetValues (FaceWidget, arg, 1);
1183 if (width_max < width)
1185 XtGetValues (LangWidget, arg, 1);
1186 if (width_max < width)
1188 XtSetArg (arg[0], XtNwidth, width_max);
1189 XtSetValues (HeadWidget, arg, 1);
1190 XtSetValues (FaceWidget, arg, 1);
1191 XtSetValues (LangWidget, arg, 1);
1192 XtSetValues (XtParent (w), arg, 1);
1193 XtSetValues (TailWidget, arg, 1);
1196 update_cursor (0, 1);
1197 redraw (0, win_height, 0, 1);
1198 if (current_input_method >= 0)
1200 int idx = current_input_method;
1202 current_input_method = -1;
1203 input_method_table[idx].im =
1204 minput_open_im (input_method_table[idx].language,
1205 input_method_table[idx].name, NULL);
1206 if (input_method_table[idx].im)
1207 select_input_method (idx);
1209 input_method_table[idx].available = -1;
1215 redraw (expose->y, expose->y + expose->height, 0, 0);
1216 if (current_input_context
1217 && expose->y < cur.y0 && expose->y + expose->height < cur.y1)
1218 set_input_method_spot ();
1223 ConfigureProc (Widget w, XEvent *event, String *str, Cardinal *num)
1225 XConfigureEvent *configure = (XConfigureEvent *) event;
1228 control.max_line_width = win_width = configure->width;
1229 win_height = configure->height;
1230 mdraw_clear_cache (mt);
1232 update_cursor (0, 1);
1233 redraw (0, win_height, 1, 1);
1234 if (current_input_context)
1235 set_input_method_spot ();
1239 ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
1242 int x = event->xbutton.x;
1243 int y = event->xbutton.y - top.ascent;
1245 if (control.orientation_reversed)
1247 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1250 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1251 mtext_detach_property (selection);
1252 redraw (sel_start.y0, sel_end.y1, 1, 0);
1255 if (current_input_context)
1257 MText *produced = mtext ();
1259 minput_reset_ic (current_input_context);
1260 minput_lookup (current_input_context, Mnil, NULL, produced);
1261 if (mtext_len (produced) > 0)
1263 insert_chars (produced);
1264 if (pos >= cursor.from)
1265 pos += mtext_len (produced);
1267 m17n_object_unref (produced);
1269 update_cursor (pos, 0);
1274 ButtonReleaseProc (Widget w, XEvent *event, String *str, Cardinal *num)
1279 XtOwnSelection (w, XA_PRIMARY, CurrentTime,
1280 covert_selection, lose_selection, NULL);
1281 update_cursor (mtext_property_start (selection), 0);
1286 Button2Proc (Widget w, XEvent *event, String *str, Cardinal *num)
1290 /* We don't have a local selection. */
1291 XtGetSelectionValue (w, XA_PRIMARY, XA_TEXT, get_selection, NULL,
1296 int from = mtext_property_start (selection);
1297 int to = mtext_property_end (selection);
1300 int x = event->xbutton.x;
1301 int y = event->xbutton.y - top.ascent;
1303 if (control.orientation_reversed)
1305 pos = COORDINATES_POSITION (top.from, nchars + 1, x, y);
1307 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1308 mtext_detach_property (selection);
1310 this_mt = mtext_copy (mtext (), 0, mt, from, to);
1311 update_cursor (pos, 0);
1312 insert_chars (this_mt);
1313 m17n_object_unref (this_mt);
1318 ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
1321 int x = event->xbutton.x;
1322 int y = event->xbutton.y;
1324 if (control.orientation_reversed)
1327 pos = top.from, y -= top.ascent;
1329 pos = cur.from, y -= cur.y0 + cur.ascent;
1330 pos = COORDINATES_POSITION (pos, nchars + 1, x, y);
1332 if (pos == cursor.from)
1338 /* Selection range changed. */
1339 int from = mtext_property_start (selection);
1340 int to = mtext_property_end (selection);
1341 int start_y0 = sel_start.y0, start_y1 = sel_start.y1;
1342 int end_y0 = sel_end.y0, end_y1 = sel_end.y1;
1344 if (cursor.from == from)
1346 /* Starting position changed. */
1349 /* Enlarged. We can simply overdraw. */
1350 select_region (pos, to);
1351 redraw (sel_start.y0, start_y1, 0, 0);
1355 /* Shrunken. Previous selection face must be cleared. */
1356 select_region (pos, to);
1357 redraw (start_y0, sel_start.y1, 1, 0);
1361 /* Shrunken to zero. */
1362 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1363 mtext_detach_property (selection);
1364 redraw (start_y0, end_y1, 1, 0);
1368 /* Full update is necessary. */
1369 select_region (to, pos);
1370 redraw (start_y0, sel_end.y1, 1, 0);
1375 /* Ending position changed. */
1378 /* Full update is necessary. */
1379 select_region (pos, from);
1380 redraw (sel_start.y0, end_y1, 1, 0);
1382 else if (pos == from)
1384 /* Shrunken to zero. */
1385 XtDisownSelection (w, XA_PRIMARY, CurrentTime);
1386 mtext_detach_property (selection);
1387 redraw (start_y0, end_y1, 1, 0);
1391 /* Shrunken. Previous selection face must be cleared. */
1392 select_region (from, pos);
1393 redraw (sel_end.y0, end_y1, 1, 0);
1397 /* Enlarged. We can simply overdraw. */
1398 select_region (from, pos);
1399 redraw (end_y0, sel_end.y1, 0, 0);
1405 /* Newly selected. */
1406 select_region (pos, cursor.from);
1407 redraw (sel_start.y0, sel_end.y1, 0, 0);
1409 update_cursor (pos, 1);
1413 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1416 MDrawGlyphInfo info;
1418 int cursor_pos = cursor.from;
1420 if (((int) position) < 0)
1426 height = top.y1 - top.y0;
1429 pos = bol (from - 1, 0);
1430 GLYPH_INFO (pos, from - 1, info);
1431 if (height + info.metrics.height > win_height)
1433 height += info.metrics.height;
1434 from = info.line_from;
1436 if (cursor_pos >= top.to)
1438 cursor_pos = top.from;
1440 while (cursor_pos < nchars)
1442 GLYPH_INFO (pos, pos, info);
1443 if (height + info.metrics.height > win_height)
1445 height += info.metrics.height;
1451 else if (cur.to < nchars)
1453 /* Scroll up, but leave at least one line. */
1456 while (from < nchars)
1458 GLYPH_INFO (from, from, info);
1459 if (height + info.metrics.height > win_height
1460 || info.line_to >= nchars)
1462 height += info.metrics.height;
1463 from = info.line_to;
1466 from = info.line_from;
1467 if (cursor_pos < from)
1471 /* Scroll up to make the cursor line top. */
1475 update_cursor (cursor_pos, 1);
1479 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1481 float persent = *(float *) persent_ptr;
1482 int pos1, pos2 = nchars * persent;
1483 MDrawGlyphInfo info;
1486 pos1 = bol (pos2, 0);
1487 GLYPH_INFO (pos1, pos2, info);
1488 pos1 = info.line_from;
1490 update_cursor (pos1, 1);
1495 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1497 XKeyEvent *key_event = (XKeyEvent *) event;
1499 KeySym keysym = NoSymbol;
1501 /* If set to 1, do not update target_x_position. */
1502 int keep_target_x_position = 0;
1505 if (current_input_context
1506 && minput_filter (current_input_context, Mnil, event))
1508 if (event->type == KeyRelease)
1513 produced = mtext ();
1514 ret = minput_lookup (current_input_context, Mnil, event, produced);
1515 if (mtext_len (produced) > 0)
1516 insert_chars (produced);
1518 ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1519 m17n_object_unref (produced);
1529 n = (mtext_property_end (selection)
1530 - mtext_property_start (selection));
1531 mtext_detach_property (selection);
1533 else if (cursor.from < nchars)
1535 /* Delete the following grapheme cluster. */
1536 n = cursor.to - cursor.from;
1549 /* Delete selected region. */
1550 n = (mtext_property_end (selection)
1551 - mtext_property_start (selection));
1552 mtext_detach_property (selection);
1554 else if (cursor.from > 0)
1556 /* Delete the preceding character. */
1567 mtext_detach_property (selection);
1568 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1572 if (cursor.prev_from >= 0)
1573 update_cursor (cursor.prev_from, 0);
1577 if (cursor.left_from >= 0)
1578 update_cursor (cursor.left_from, 0);
1585 mtext_detach_property (selection);
1586 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1590 if (cursor.next_to >= 0)
1591 update_cursor (cursor.to, 0);
1595 if (cursor.right_from >= 0)
1596 update_cursor (cursor.right_from, 0);
1603 mtext_detach_property (selection);
1604 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1606 if (cur.to <= nchars)
1608 MDrawGlyphInfo info;
1611 GLYPH_INFO (cur.from, cur.to, info);
1612 pos = COORDINATES_POSITION (cur.from, nchars + 1,
1613 target_x_position, info.y);
1614 keep_target_x_position = 1;
1615 update_cursor (pos, 0);
1622 mtext_detach_property (selection);
1623 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1629 int pos = bol (cur.from - 1, 0);
1631 TEXT_EXTENTS (pos, cur.from - 1, rect);
1632 y = rect.height + rect.y - 1;
1633 pos = COORDINATES_POSITION (pos, nchars,
1634 target_x_position, y);
1635 keep_target_x_position = 1;
1636 update_cursor (pos, 0);
1643 mtext_detach_property (selection);
1644 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1646 if (top.from < nchars)
1647 ScrollProc (w, NULL, (XtPointer) 1);
1653 mtext_detach_property (selection);
1654 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1657 ScrollProc (w, NULL, (XtPointer) -1);
1661 if (key_event->state >= Mod1Mask)
1663 lose_selection (NULL, NULL);
1669 if (key_event->state >= Mod1Mask)
1671 lose_selection (NULL, NULL);
1679 if (buf[0] == 17) /* C-q */
1681 XtAppSetExitFlag (context);
1684 else if (buf[0] == 12) /* C-l */
1686 redraw (0, win_height, 1, 1);
1691 MText *temp = mtext ();
1693 mtext_cat_char (temp, buf[0] == '\r' ? '\n'
1694 : ((unsigned char *) buf)[0]);
1695 if (current_input_context)
1696 mtext_put_prop (temp, 0, 1, Mlanguage,
1697 current_input_context->im->language);
1698 insert_chars (temp);
1699 m17n_object_unref (temp);
1704 if (! keep_target_x_position)
1705 target_x_position = cursor.x;
1709 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1711 char *name = (char *) client_data;
1713 int from = -1, to = 0;
1718 filename = strdup (name);
1721 fp = fopen (filename, "w");
1724 fprintf (stderr, "Open for write fail: %s", filename);
1730 from = mtext_property_start (selection);
1731 to = mtext_property_end (selection);
1732 mtext_detach_property (selection);
1735 mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
1738 select_region (from, to);
1742 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1748 mtext_detach_property (selection);
1749 serialized = (int) client_data;
1751 new = mtext_deserialize (mt);
1754 MPlist *plist = mplist ();
1756 mplist_push (plist, Mt, Mface);
1757 mplist_push (plist, Mt, Mlanguage);
1758 new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1759 m17n_object_unref (plist);
1763 m17n_object_unref (mt);
1765 serialized = ! serialized;
1766 nchars = mtext_len (mt);
1769 update_cursor (0, 1);
1770 redraw (0, win_height, 1, 1);
1774 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1776 XtAppSetExitFlag (context);
1782 FILE *fp = fopen (filename, "r");
1785 FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1786 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
1789 FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1794 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1796 int data = (int) client_data;
1801 control.enable_bidi = 0;
1802 control.orientation_reversed = 0;
1806 control.enable_bidi = 1;
1807 control.orientation_reversed = data == 2;
1809 for (i = 0; i < 3; i++)
1812 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1814 XtSetArg (arg[0], XtNleftBitmap, None);
1815 XtSetValues (BidiMenus[i], arg, 1);
1818 update_cursor (cursor.from, 1);
1819 redraw (0, win_height, 1, 0);
1823 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1825 int data = (int) client_data;
1829 control.max_line_width = 0;
1832 control.max_line_width = win_width;
1833 control.line_break = (data == 1 ? NULL : mdraw_default_line_break);
1835 for (i = 0; i < 3; i++)
1838 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1840 XtSetArg (arg[0], XtNleftBitmap, None);
1841 XtSetValues (LineBreakMenus[i], arg, 1);
1844 update_cursor (cursor.from, 1);
1845 redraw (0, win_height, 1, 0);
1849 FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
1851 char *filter_module = (char *) client_data;
1853 void (*func) (MText *, int, int);
1857 handle = dlopen (filter_module, RTLD_NOW);
1860 *(void **) (&func) = dlsym (handle, "filter");
1862 (*func) (mt, mtext_property_start (selection),
1863 mtext_property_end (selection));
1868 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1870 int data = (int) client_data;
1884 control.cursor_bidi = 0, control.cursor_width = -1;
1888 control.cursor_bidi = 0, control.cursor_width = 2;
1892 control.cursor_bidi = 1;
1897 for (i = from; i < to; i++)
1900 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1902 XtSetArg (arg[0], XtNleftBitmap, None);
1903 XtSetValues (CursorMenus[i], arg, 1);
1906 update_cursor (cursor.from, 0);
1907 redraw (0, win_height, 1, 0);
1911 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
1913 int idx = (int) client_data;
1915 if (idx == -2 ? current_input_method < 0
1916 : idx == -1 ? auto_input_method
1917 : idx == current_input_method)
1920 XtSetArg (arg[0], XtNleftBitmap, None);
1921 if (auto_input_method)
1923 XtSetValues (InputMethodMenus[1], arg, 1);
1924 auto_input_method = 0;
1926 else if (current_input_method < 0)
1927 XtSetValues (InputMethodMenus[0], arg, 1);
1929 XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
1933 auto_input_method = 1;
1936 else if (input_method_table[idx].available >= 0)
1938 if (! input_method_table[idx].im)
1940 input_method_table[idx].im =
1941 minput_open_im (input_method_table[idx].language,
1942 input_method_table[idx].name, NULL);
1943 if (! input_method_table[idx].im)
1944 input_method_table[idx].available = -1;
1946 if (input_method_table[idx].im)
1947 select_input_method (idx);
1949 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1950 XtSetValues (InputMethodMenus[idx + 2], arg, 1);
1953 MPlist *default_face_list;
1956 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
1958 int idx = (int) client_data;
1969 MFace *face = mframe_get_prop (frame, Mface);
1971 for (plist = default_face_list; mplist_key (plist) != Mnil;
1972 plist = mplist_next (plist))
1973 mface_merge (face, mplist_value (plist));
1974 mplist_add (plist, Mt, *face_table[idx].face);
1975 mface_merge (face, *face_table[idx].face);
1977 else if (mplist_key (mplist_next (default_face_list)) != Mnil)
1979 MFace *face = mframe_get_prop (frame, Mface);
1981 for (plist = default_face_list;
1982 mplist_key (mplist_next (plist)) != Mnil;
1983 plist = mplist_next (plist))
1984 mface_merge (face, mplist_value (plist));
1988 update_cursor (0, 1);
1989 redraw (0, win_height, 1, 1);
1994 XtAppAddWorkProc (context, show_cursor, NULL);
1995 from = mtext_property_start (selection);
1996 to = mtext_property_end (selection);
1997 old_y1 = sel_end.y1;
1999 mtext_detach_property (selection);
2002 MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
2003 MTEXTPROP_REAR_STICKY);
2004 mtext_push_property (mt, from, to, prop);
2005 m17n_object_unref (prop);
2008 mtext_pop_prop (mt, from, to, Mface);
2010 update_top (top.from);
2011 update_cursor (cursor.from, 1);
2012 select_region (from, to);
2013 update_region (sel_start.y0, old_y1, sel_end.y1);
2014 if (cur.y1 > win_height)
2016 while (cur.y1 > win_height)
2019 update_cursor (cursor.from, 1);
2025 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
2027 MSymbol sym = (MSymbol) client_data;
2034 XtAppAddWorkProc (context, show_cursor, NULL);
2035 from = mtext_property_start (selection);
2036 to = mtext_property_end (selection);
2037 old_y1 = sel_end.y1;
2039 mtext_detach_property (selection);
2041 mtext_put_prop (mt, from, to, Mlanguage, sym);
2043 mtext_pop_prop (mt, from, to, Mlanguage);
2046 update_top (top.from);
2047 update_cursor (cursor.from, 1);
2048 select_region (from, to);
2049 update_region (sel_start.y0, old_y1, sel_end.y1);
2050 if (cur.y1 > win_height)
2052 while (cur.y1 > win_height)
2055 update_cursor (cursor.from, 1);
2061 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
2063 int narrowed = (int) client_data;
2066 MConverter *converter;
2072 from = mtext_property_start (selection);
2073 to = mtext_property_end (selection);
2082 mdump = popen ("mdump -q -p a4", "w");
2084 mdump = popen ("mdump -q", "w");
2087 converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
2088 mconv_encode_range (converter, mt, from, to);
2089 mconv_free_converter (converter);
2094 input_status (MInputContext *ic, MSymbol command)
2096 XFillRectangle (display, input_status_pixmap, gc_inv,
2097 0, 0, input_status_width, input_status_height);
2098 if (command == Minput_status_draw)
2102 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2103 Mface, face_input_status);
2104 if (ic->im->language != Mnil)
2105 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2106 Mlanguage, ic->im->language);
2107 mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
2108 &input_status_control, NULL, NULL, &rect);
2109 mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
2110 input_status_width - rect.width - 2, - rect.y,
2111 ic->status, 0, mtext_len (ic->status),
2112 &input_status_control);
2114 XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
2115 XtSetValues (CurIMStatus, arg, 1);
2119 compare_input_method (const void *elt1, const void *elt2)
2121 const InputMethodInfo *im1 = elt1;
2122 const InputMethodInfo *im2 = elt2;
2123 MSymbol lang1, lang2;
2125 if (im1->language == Mnil)
2127 if (im1->language == im2->language)
2128 return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
2129 if (im1->language == Mt)
2131 if (im2->language == Mt)
2133 lang1 = msymbol_get (im1->language, Mlanguage);
2134 lang2 = msymbol_get (im2->language, Mlanguage);
2135 return strcmp (msymbol_name (lang1), msymbol_name (lang2));
2139 setup_input_methods (int with_xim, char *initial_input_method)
2141 MInputMethod *im = NULL;
2142 MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
2145 char *lang_name = NULL, *method_name = NULL;
2147 if (initial_input_method)
2149 char *p = strchr (initial_input_method, '-');
2151 lang_name = initial_input_method, method_name = p + 1, *p = '\0';
2153 method_name = initial_input_method;
2156 num_input_methods = plist ? mplist_length (plist) : 0;
2160 MInputXIMArgIM arg_xim;
2162 arg_xim.display = display;
2164 arg_xim.res_name = arg_xim.res_class = NULL;
2165 arg_xim.locale = NULL;
2166 arg_xim.modifier_list = NULL;
2167 im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
2169 num_input_methods++;
2171 input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
2174 input_method_table[i].available = 1;
2175 input_method_table[i].language = Mnil;
2176 input_method_table[i].name = im->name;
2177 input_method_table[i].im = im;
2183 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
2185 MDatabase *mdb = mplist_value (pl);
2186 MSymbol *tag = mdatabase_tag (mdb);
2190 input_method_table[i].language = tag[1];
2191 input_method_table[i].name = tag[2];
2196 m17n_object_unref (plist);
2198 num_input_methods = i;
2199 qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
2200 compare_input_method);
2201 current_input_context = NULL;
2203 mplist_put (minput_driver->callback_list, Minput_status_start,
2204 (void *) input_status);
2205 mplist_put (minput_driver->callback_list, Minput_status_draw,
2206 (void *) input_status);
2207 mplist_put (minput_driver->callback_list, Minput_status_done,
2208 (void *) input_status);
2211 for (i = 0; i < num_input_methods; i++)
2212 if (strcmp (method_name, msymbol_name (input_method_table[i].name)) == 0
2214 ? strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0
2215 : input_method_table[i].language == Mt))
2217 current_input_method = i;
2224 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
2228 if (num && *num > 0)
2232 for (i = 0; i < *num; i++)
2233 bytes += strlen (str[i]) + 1;
2234 msg = alloca (bytes);
2235 strcpy (msg, str[0]);
2236 for (i = 1; i < *num; i++)
2237 strcat (msg, " "), strcat (msg, str[i]);
2239 else if (cursor.from < nchars)
2241 int c = mtext_ref_char (mt, cursor.from);
2242 char *name = mchar_get_prop (c, Mname);
2246 msg = alloca (10 + strlen (name));
2247 sprintf (msg, "U+%04X %s", c, name);
2253 XtSetArg (arg[0], XtNlabel, msg);
2254 XtSetValues (MessageWidget, arg, 1);
2260 char *name1, *name2;
2261 XtCallbackProc proc;
2262 XtPointer client_data;
2267 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
2269 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
2271 MenuRec FileMenu[] =
2272 { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
2273 { 0, "Save", NULL, SaveProc, NULL, -1 },
2274 { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
2276 { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2277 { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2279 { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2280 { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2282 { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2285 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2287 MenuRec *rec = (MenuRec *) client_data;
2290 XtSetArg (arg[0], XtNvalue, "");
2291 XtSetArg (arg[1], XtNlabel, rec->name1);
2292 XtSetValues (FileDialogWidget, arg, 2);
2293 XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2294 XtSetArg (arg[0], XtNx, x + 20);
2295 XtSetArg (arg[1], XtNy, y + 10);
2296 XtSetValues (FileShellWidget, arg, 2);
2297 XtPopup (FileShellWidget, XtGrabExclusive);
2301 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2306 XtPopdown (FileShellWidget);
2307 if ((int) client_data == 1)
2309 XtSetArg (arg[0], XtNlabel, &label);
2310 XtGetValues (FileDialogWidget, arg, 1);
2311 if (strcmp (label, FileMenu[0].name1) == 0)
2315 filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2316 fp = fopen (filename, "r");
2318 m17n_object_unref (mt);
2321 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
2329 nchars = mtext_len (mt);
2331 update_cursor (0, 1);
2332 redraw (0, win_height, 1, 1);
2334 else if (strcmp (label, FileMenu[2].name1) == 0)
2335 SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2337 fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2340 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS) \
2341 ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2342 (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA), \
2343 (MENU).status = (STATUS))
2347 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2348 char *menu_name, MenuRec *menus, int num_menus, char *help)
2350 Widget button, menu;
2351 char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2352 <LeaveWindow>: reset() MenuHelp()\n\
2353 <BtnDown>: reset() PopupMenu()\n\
2354 <BtnUp>: highlight()";
2360 menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2361 for (i = 0; i < num_menus; i++)
2372 XtSetArg (arg[n], XtNleftMargin, 20), n++;
2374 XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2376 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2378 XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2382 XtSetArg (arg[0], XtNsensitive, False);
2383 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2389 XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2394 trans = alloca (strlen (fmt) + strlen (help));
2395 sprintf (trans, fmt, help);
2396 XtSetArg (arg[0], XtNmenuName, menu_name);
2397 XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2398 XtSetArg (arg[2], XtNinternalWidth, 2);
2399 XtSetArg (arg[3], XtNhighlightThickness, 1);
2400 XtSetArg (arg[4], XtNleft, XawChainLeft);
2401 XtSetArg (arg[5], XtNright, XawChainLeft);
2404 XtSetArg (arg[i], XtNfromHoriz, left), i++;
2405 button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2410 int height, ascent, *width = alloca (sizeof (int) * num_menus);
2411 int *len = alloca (sizeof (int) * num_menus);
2414 XFontSetExtents *fontset_extents;
2416 XtSetArg (arg[0], XtNfontSet, &font_set);
2417 XtGetValues (button, arg, 1);
2419 fontset_extents = XExtentsOfFontSet (font_set);
2420 height = fontset_extents->max_logical_extent.height;
2421 ascent = - fontset_extents->max_logical_extent.y;
2423 for (i = 0; i < num_menus; i++)
2426 len[i] = strlen (menus[i].name2);
2427 width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2428 if (max_width < width[i])
2429 max_width = width[i];
2431 for (i = 0; i < num_menus; i++)
2434 Pixmap pixmap = XCreatePixmap (display,
2435 RootWindow (display, screen),
2436 max_width, height, 1);
2437 XFillRectangle (display, pixmap, mono_gc_inv,
2438 0, 0, max_width, height);
2439 XmbDrawString (display, pixmap, font_set, mono_gc,
2440 max_width - width[i], ascent,
2441 menus[i].name2, len[i]);
2442 XtSetArg (arg[0], XtNrightBitmap, pixmap);
2443 XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2444 XtSetValues (menus[i].w, arg, 2);
2452 XtActionsRec actions[] = {
2453 {"Expose", ExposeProc},
2454 {"Configure", ConfigureProc},
2456 {"ButtonPress", ButtonProc},
2457 {"ButtonRelease", ButtonReleaseProc},
2458 {"ButtonMotion", ButtonMoveProc},
2459 {"Button2Press", Button2Proc},
2460 {"MenuHelp", MenuHelpProc}
2464 /* Print the usage of this program (the name is PROG), and exit with
2468 help_exit (char *prog, int exit_code)
2476 printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2477 printf ("Display FILE on a window and allow users to edit it.\n");
2478 printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2479 printf ("The following OPTIONs are available.\n");
2480 printf (" %-13s\n\t\t%s", "--fontset FONTSET",
2481 "Use the specified fontset\n");
2482 printf (" %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
2483 printf (" %-13s\n\t\t%s", "--im INPUT-METHOD",
2484 "Input method activated initially.\n");
2485 printf (" %-13s %s", "--version", "print version number\n");
2486 printf (" %-13s %s", "-h, --help", "print this message\n");
2492 main (int argc, char **argv)
2494 Widget form, BodyWidget, w;
2495 char *fontset_name = NULL;
2497 char *initial_input_method = NULL;
2498 int col = 80, row = 32;
2499 /* Translation table for TextWidget. */
2500 String trans = "<Expose>: Expose()\n\
2501 <Configure>: Configure()\n\
2504 <Btn1Down>: ButtonPress()\n\
2505 <Btn1Up>: ButtonRelease()\n\
2506 <Btn1Motion>: ButtonMotion()\n\
2507 <Btn2Down>: Button2Press()";
2508 /* Translation table for the top form widget. */
2509 String trans2 = "<Key>: Key()\n\
2511 String pop_face_trans
2512 = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2513 <LeaveWindow>: MenuHelp() reset()\n\
2514 <Btn1Down>: set()\n\
2515 <Btn1Up>: notify() unset()";
2516 String pop_lang_trans
2517 = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2518 <LeaveWindow>: MenuHelp() reset()\n\
2519 <Btn1Down>: set()\n\
2520 <Btn1Up>: notify() unset()";
2521 int font_width, font_ascent, font_descent;
2524 char *filter = NULL;
2526 setlocale (LC_ALL, "");
2527 /* Create the top shell. */
2528 XtSetLanguageProc (NULL, NULL, NULL);
2529 ShellWidget = XtOpenApplication (&context, "M17NEdit", NULL, 0, &argc, argv,
2530 NULL, sessionShellWidgetClass, NULL, 0);
2531 display = XtDisplay (ShellWidget);
2532 screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2534 /* Parse the remaining command line arguments. */
2535 for (i = 1; i < argc; i++)
2537 if (! strcmp (argv[i], "--help")
2538 || ! strcmp (argv[i], "-h"))
2539 help_exit (argv[0], 0);
2540 else if (! strcmp (argv[i], "--version"))
2542 printf ("m17n-edit (m17n library) %s\n", VERSION);
2543 printf ("Copyright (C) 2003 AIST, JAPAN\n");
2546 else if (! strcmp (argv[i], "--geometry"))
2549 if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2550 help_exit (argv[0], 1);
2552 else if (! strcmp (argv[i], "-s"))
2555 fontsize = atoi (argv[i]);
2559 else if (! strcmp (argv[i], "--fontset"))
2562 fontset_name = strdup (argv[i]);
2564 else if (! strcmp (argv[i], "--im"))
2567 initial_input_method = strdup (argv[i]);
2569 else if (! strcmp (argv[i], "--with-xim"))
2573 else if (! strcmp (argv[i], "--filter"))
2578 else if (argv[i][0] != '-')
2580 filename = strdup (argv[i]);
2584 fprintf (stderr, "Unknown option: %s\n", argv[i]);
2585 help_exit (argv[0], 1);
2589 filename = strdup ("/dev/null");
2591 mdatabase_dir = ".";
2592 /* Initialize the m17n library. */
2594 if (merror_code != MERROR_NONE)
2595 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2596 minput_driver = &minput_gui_driver;
2598 mt = read_file (filename);
2601 nchars = mtext_len (mt);
2603 Mword = msymbol ("word");
2606 MFace *face = mface ();
2608 mface_put_prop (face, Mforeground, msymbol ("blue"));
2609 mface_put_prop (face, Mbackground, msymbol ("yellow"));
2610 mface_put_prop (face, Mvideomode, Mreverse);
2611 selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2612 m17n_object_unref (face);
2615 /* This tells ExposeProc to initialize everything. */
2618 XA_TEXT = XInternAtom (display, "TEXT", False);
2619 XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2620 XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2621 Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
2622 if (Mcoding_compound_text == Mnil)
2623 FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
2626 MPlist *plist = mplist ();
2630 mplist_put (plist, msymbol ("widget"), ShellWidget);
2631 if (fontset_name || fontsize > 0)
2633 MFontset *fontset = mfontset (fontset_name);
2636 mface_put_prop (face, Mfontset, fontset);
2637 mface_put_prop (face, Msize, (void *) fontsize);
2638 m17n_object_unref (fontset);
2639 mplist_add (plist, Mface, face);
2640 m17n_object_unref (face);
2642 frame = mframe (plist);
2644 FATAL_ERROR ("%s\n", "Fail to create a frame!");
2645 m17n_object_unref (plist);
2646 face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
2647 default_face_list = mplist ();
2648 mplist_add (default_face_list, Mt, face_default);
2649 face_default_fontset = mface ();
2650 mface_put_prop (face_default_fontset, Mfontset,
2651 mface_get_prop (face_default, Mfontset));
2653 font = (MFont *) mframe_get_prop (frame, Mfont);
2654 default_font_size = (int) mfont_get_prop (font, Msize);
2657 font_width = (int) mframe_get_prop (frame, Mfont_width);
2658 font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2659 font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2660 win_width = font_width * col;
2661 win_height = (font_ascent + font_descent) * row;
2667 prop.color_top = prop.color_left = msymbol ("magenta");
2668 prop.color_bottom = prop.color_right = msymbol ("red");
2669 prop.inner_hmargin = prop.inner_vmargin = 1;
2670 prop.outer_hmargin = prop.outer_vmargin = 2;
2672 face_box = mface ();
2673 mface_put_prop (face_box, Mbox, &prop);
2676 face_courier = mface ();
2677 mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2678 face_helvetica = mface ();
2679 mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2680 face_times = mface ();
2681 mface_put_prop (face_times, Mfamily, msymbol ("times"));
2682 face_dv_ttyogesh = mface ();
2683 mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2684 face_freesans = mface ();
2685 mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2686 face_freeserif = mface ();
2687 mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
2688 face_freemono = mface ();
2689 mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2691 face_xxx_large = mface ();
2692 mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2694 MFont *latin_font = mframe_get_prop (frame, Mfont);
2695 MFont *dev_font = mfont ();
2696 MFont *thai_font = mfont ();
2697 MFont *tib_font = mfont ();
2699 MSymbol unicode_bmp = msymbol ("unicode-bmp");
2700 MSymbol no_ctl = msymbol ("no-ctl");
2702 mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2703 mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2704 mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2705 mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2706 mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2707 mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2709 fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
2710 mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
2711 latin_font, Mnil, 0);
2712 mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
2713 dev_font, no_ctl, 0);
2714 mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
2715 thai_font, no_ctl, 0);
2716 mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
2717 tib_font, no_ctl, 0);
2718 face_no_ctl_fontset = mface ();
2719 mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
2720 m17n_object_unref (fontset);
2727 setup_input_methods (with_xim, initial_input_method);
2729 gc = DefaultGC (display, screen);
2731 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2732 XtSetArg (arg[1], XtNdefaultDistance, 2);
2733 form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2735 XtSetArg (arg[0], XtNborderWidth, 0);
2736 XtSetArg (arg[1], XtNdefaultDistance, 2);
2737 XtSetArg (arg[2], XtNtop, XawChainTop);
2738 XtSetArg (arg[3], XtNbottom, XawChainTop);
2739 XtSetArg (arg[4], XtNleft, XawChainLeft);
2740 XtSetArg (arg[5], XtNright, XawChainRight);
2741 XtSetArg (arg[6], XtNresizable, True);
2742 HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2743 XtSetArg (arg[7], XtNfromVert, HeadWidget);
2744 FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2745 XtSetArg (arg[7], XtNfromVert, FaceWidget);
2746 LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2747 XtSetArg (arg[3], XtNbottom, XawChainBottom);
2748 XtSetArg (arg[7], XtNfromVert, LangWidget);
2749 BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2750 XtSetArg (arg[2], XtNtop, XawChainBottom);
2751 XtSetArg (arg[7], XtNfromVert, BodyWidget);
2752 TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2754 FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2755 HeadWidget, NULL, 0);
2756 XtSetArg (arg[0], XtNvalue, "");
2757 FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2758 FileShellWidget, arg, 1);
2759 XawDialogAddButton (FileDialogWidget, "OK",
2760 FileDialogProc, (XtPointer) 0);
2761 XawDialogAddButton (FileDialogWidget, "CANCEL",
2762 FileDialogProc, (XtPointer) 1);
2764 CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2765 (char *) check_bits,
2766 check_width, check_height);
2768 unsigned long valuemask = GCForeground;
2771 values.foreground = 1;
2772 mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2773 values.foreground = 0;
2774 mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2781 if (num_menus < num_input_methods + 2)
2782 num_menus = num_input_methods + 2;
2783 if (num_menus < num_faces + 1)
2784 num_menus = num_faces + 1;
2785 menus = alloca (sizeof (MenuRec) * num_menus);
2787 w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2788 FileMenu, sizeof FileMenu / sizeof (MenuRec),
2789 "File I/O, Serialization, Image, Quit");
2791 SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2792 SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2793 SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2794 SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2795 SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2796 SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2797 w = create_menu_button (ShellWidget, HeadWidget, w,
2798 "Cursor", "Cursor Menu",
2799 menus, 6, "Cursor Movement Mode, Cursor Shape");
2800 CursorMenus[0] = menus[0].w;
2801 CursorMenus[1] = menus[1].w;
2802 CursorMenus[2] = menus[3].w;
2803 CursorMenus[3] = menus[4].w;
2804 CursorMenus[4] = menus[5].w;
2806 SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2807 SetMenu (menus[1], 0, "Left (|--> |)", NULL, BidiProc, 1, 1);
2808 SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2809 w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2810 menus, 3, "BIDI Processing Mode");
2811 for (i = 0; i < 3; i++)
2812 BidiMenus[i] = menus[i].w;
2814 SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2815 SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2816 SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2817 w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2819 menus, 3, "How to break lines");
2820 for (i = 0; i < 3; i++)
2821 LineBreakMenus[i] = menus[i].w;
2823 SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2824 SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2825 for (i = 0; i < num_input_methods; i++)
2827 InputMethodInfo *im = input_method_table + i;
2828 char *name1, *name2;
2830 if (im->language != Mnil && im->language != Mt)
2832 MSymbol sym = msymbol_get (im->language, Mlanguage);
2834 name1 = msymbol_name (im->language);
2836 name1 = msymbol_name (sym);
2837 name2 = msymbol_name (im->name);
2840 name1 = msymbol_name (im->name), name2 = NULL;
2842 SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
2844 w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
2845 "Input Method Menu", menus, i + 2,
2846 "Select input method");
2849 unsigned long valuemask = GCForeground;
2852 XtSetArg (arg[0], XtNbackground, &values.foreground);
2853 XtGetValues (w, arg, 1);
2854 gc_inv = XCreateGC (display, RootWindow (display, screen),
2855 valuemask, &values);
2858 InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
2859 for (i = 0; i < num_input_methods + 2; i++)
2860 InputMethodMenus[i] = menus[i].w;
2864 SetMenu (menus[0], 0, filter, NULL, FilterProc, filter, 0);
2865 w = create_menu_button (ShellWidget, HeadWidget, w, "Filter",
2866 "Filter Menu", menus, 1,
2867 "Select filter to run");
2870 input_status_width = font_width * 8;
2871 input_status_height = (font_ascent + font_descent) * 2.4;
2872 input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
2874 input_status_height,
2875 DefaultDepth (display, screen));
2880 prop.color_top = prop.color_bottom
2881 = prop.color_left = prop.color_right = Mnil;
2882 prop.inner_hmargin = prop.inner_vmargin = 1;
2883 prop.outer_hmargin = prop.outer_vmargin = 0;
2884 face_input_status = mface_copy (face_default);
2885 mface_put_prop (face_input_status, Mbox, &prop);
2888 XFillRectangle (display, input_status_pixmap, gc_inv,
2889 0, 0, input_status_width, input_status_height);
2890 XtSetArg (arg[0], XtNfromHoriz, w);
2891 XtSetArg (arg[1], XtNleft, XawRubber);
2892 XtSetArg (arg[2], XtNright, XawChainRight);
2893 XtSetArg (arg[3], XtNborderWidth, 0);
2894 XtSetArg (arg[4], XtNlabel, " ");
2895 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2896 CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
2897 HeadWidget, arg, 6);
2898 XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
2899 XtSetArg (arg[1], XtNleft, XawChainRight);
2900 XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
2901 CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
2902 HeadWidget, arg, 5);
2904 XtSetArg (arg[0], XtNborderWidth, 0);
2905 XtSetArg (arg[1], XtNleft, XawChainLeft);
2906 XtSetArg (arg[2], XtNright, XawChainLeft);
2907 w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
2908 for (i = 0; i < num_faces;)
2910 char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
2911 char *label = label_menu + 5; /* "Xxxx" */
2913 for (j = i; j < num_faces && face_table[j].face; j++)
2914 SetMenu (menus[j - i], 0, face_table[j].name, NULL,
2916 w = create_menu_button (ShellWidget, FaceWidget, w,
2918 menus, j - i, "Push face property");
2922 XtSetArg (arg[0], XtNfromHoriz, w);
2923 XtSetArg (arg[1], XtNleft, XawChainLeft);
2924 XtSetArg (arg[2], XtNright, XawChainLeft);
2925 XtSetArg (arg[3], XtNhorizDistance, 10);
2926 XtSetArg (arg[4], XtNlabel, "Pop");
2927 XtSetArg (arg[5], XtNtranslations,
2928 XtParseTranslationTable (pop_face_trans));
2929 w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
2930 FaceWidget, arg, 6);
2931 XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
2933 XtSetArg (arg[0], XtNfromHoriz, w);
2934 XtSetArg (arg[1], XtNleft, XawChainLeft);
2935 XtSetArg (arg[2], XtNright, XawChainRight);
2936 XtSetArg (arg[3], XtNlabel, "");
2937 XtSetArg (arg[4], XtNborderWidth, 0);
2938 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2939 CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
2940 FaceWidget, arg, 6);
2942 XtSetArg (arg[0], XtNborderWidth, 0);
2943 XtSetArg (arg[1], XtNleft, XawChainLeft);
2944 XtSetArg (arg[2], XtNright, XawChainLeft);
2945 w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
2947 MPlist *plist[11], *pl;
2950 for (i = 0; i < 11; i++) plist[i] = NULL;
2952 for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
2953 for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
2955 MSymbol sym = msymbol_exist (langname);
2959 && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
2961 char *name = msymbol_name (fullname);
2964 if (c >= 'a' && c <= 'z')
2966 int idx = (c < 'u') ? (c - 'a') / 2 : 10;
2970 pl = plist[idx] = mplist ();
2971 for (; mplist_next (pl); pl = mplist_next (pl))
2972 if (strcmp (name, (char *) mplist_value (pl)) < 0)
2974 mplist_push (pl, sym, fullname);
2979 for (i = 0; i < 11; i++)
2982 char *name = alloca (9);
2984 sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
2987 for (j = 0, pl = plist[i]; mplist_next (pl);
2988 j++, pl = mplist_next (pl))
2989 SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
2990 msymbol_name (mplist_key (pl)),
2991 LangProc, mplist_key (pl), -1);
2992 w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
2993 menus, j, "Push language property");
2995 for (i = 0; i < 11; i++)
2997 m17n_object_unref (plist[i]);
2999 XtSetArg (arg[0], XtNfromHoriz, w);
3000 XtSetArg (arg[1], XtNleft, XawChainLeft);
3001 XtSetArg (arg[2], XtNright, XawChainLeft);
3002 XtSetArg (arg[3], XtNhorizDistance, 10);
3003 XtSetArg (arg[4], XtNlabel, "Pop");
3004 XtSetArg (arg[5], XtNtranslations,
3005 XtParseTranslationTable (pop_lang_trans));
3006 w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
3007 LangWidget, arg, 6);
3008 XtAddCallback (w, XtNcallback, LangProc, Mnil);
3010 XtSetArg (arg[0], XtNfromHoriz, w);
3011 XtSetArg (arg[1], XtNleft, XawChainLeft);
3012 XtSetArg (arg[2], XtNright, XawChainRight);
3013 XtSetArg (arg[3], XtNlabel, "");
3014 XtSetArg (arg[4], XtNborderWidth, 0);
3015 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3016 CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
3017 LangWidget, arg, 6);
3020 XtSetArg (arg[0], XtNheight, win_height);
3021 XtSetArg (arg[1], XtNwidth, 10);
3022 XtSetArg (arg[2], XtNleft, XawChainLeft);
3023 XtSetArg (arg[3], XtNright, XawChainLeft);
3024 SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
3026 XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
3027 XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
3029 XtSetArg (arg[0], XtNheight, win_height);
3030 XtSetArg (arg[1], XtNwidth, win_width);
3031 XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
3032 XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
3033 XtSetArg (arg[4], XtNleft, XawChainLeft);
3034 XtSetArg (arg[5], XtNright, XawChainRight);
3035 TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
3038 XtSetArg (arg[0], XtNborderWidth, 0);
3039 XtSetArg (arg[1], XtNleft, XawChainLeft);
3040 XtSetArg (arg[2], XtNright, XawChainRight);
3041 XtSetArg (arg[3], XtNresizable, True);
3042 XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
3043 MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
3044 TailWidget, arg, 5);
3046 memset (&control, 0, sizeof control);
3047 control.two_dimensional = 1;
3048 control.enable_bidi = 1;
3049 control.anti_alias = 1;
3050 control.min_line_ascent = font_ascent;
3051 control.min_line_descent = font_descent;
3052 control.max_line_width = win_width;
3053 control.with_cursor = 1;
3054 control.cursor_width = 2;
3055 control.partial_update = 1;
3056 control.ignore_formatting_char = 1;
3058 memset (&input_status_control, 0, sizeof input_status_control);
3059 input_status_control.enable_bidi = 1;
3061 XtAppAddActions (context, actions, XtNumber (actions));
3062 XtRealizeWidget (ShellWidget);
3064 win = XtWindow (TextWidget);
3066 XtAppMainLoop (context);
3068 if (current_input_context)
3069 minput_destroy_ic (current_input_context);
3070 for (i = 0; i < num_input_methods; i++)
3071 if (input_method_table[i].im)
3072 minput_close_im (input_method_table[i].im);
3073 m17n_object_unref (frame);
3074 m17n_object_unref (mt);
3075 m17n_object_unref (face_xxx_large);
3076 m17n_object_unref (face_box);
3077 m17n_object_unref (face_courier);
3078 m17n_object_unref (face_helvetica);
3079 m17n_object_unref (face_times);
3080 m17n_object_unref (face_dv_ttyogesh);
3081 m17n_object_unref (face_freesans);
3082 m17n_object_unref (face_freeserif);
3083 m17n_object_unref (face_freemono);
3084 m17n_object_unref (face_default_fontset);
3085 m17n_object_unref (face_no_ctl_fontset);
3086 m17n_object_unref (face_input_status);
3087 m17n_object_unref (face_default);
3088 m17n_object_unref (default_face_list);
3089 m17n_object_unref (selection);
3091 XFreeGC (display, mono_gc);
3092 XFreeGC (display, mono_gc_inv);
3093 XFreeGC (display, gc_inv);
3094 XtUninstallTranslations (form);
3095 XtUninstallTranslations (TextWidget);
3096 XtDestroyWidget (ShellWidget);
3097 XtDestroyApplicationContext (context);
3101 free (fontset_name);
3103 free (input_method_table);
3104 free (InputMethodMenus);
3109 #else /* not HAVE_X11_XAW_COMMAND_H */
3112 main (int argc, char **argv)
3115 "Building of this program failed (lack of some header files)\n");
3119 #endif /* not HAVE_X11_XAW_COMMAND_H */
3121 #endif /* not FOR_DOXYGEN */