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
1256 && minput_filter (current_input_context, Minput_focus_move, NULL) == 0)
1258 MText *produced = mtext ();
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 FocusInProc (Widget w, XEvent *event, String *str, Cardinal *num)
1415 if (current_input_context
1416 && minput_filter (current_input_context, Minput_focus_out, NULL) == 0)
1418 MText *produced = mtext ();
1420 minput_lookup (current_input_context, Mnil, NULL, produced);
1421 if (mtext_len (produced) > 0)
1424 insert_chars (produced);
1426 m17n_object_unref (produced);
1431 FocusOutProc (Widget w, XEvent *event, String *str, Cardinal *num)
1433 if (current_input_context
1434 && minput_filter (current_input_context, Minput_focus_out, NULL) == 0)
1436 MText *produced = mtext ();
1438 minput_lookup (current_input_context, Mnil, NULL, produced);
1439 if (mtext_len (produced) > 0)
1442 insert_chars (produced);
1444 m17n_object_unref (produced);
1449 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
1452 MDrawGlyphInfo info;
1454 int cursor_pos = cursor.from;
1456 if (((int) position) < 0)
1462 height = top.y1 - top.y0;
1465 pos = bol (from - 1, 0);
1466 GLYPH_INFO (pos, from - 1, info);
1467 if (height + info.metrics.height > win_height)
1469 height += info.metrics.height;
1470 from = info.line_from;
1472 if (cursor_pos >= top.to)
1474 cursor_pos = top.from;
1476 while (cursor_pos < nchars)
1478 GLYPH_INFO (pos, pos, info);
1479 if (height + info.metrics.height > win_height)
1481 height += info.metrics.height;
1487 else if (cur.to < nchars)
1489 /* Scroll up, but leave at least one line. */
1492 while (from < nchars)
1494 GLYPH_INFO (from, from, info);
1495 if (height + info.metrics.height > win_height
1496 || info.line_to >= nchars)
1498 height += info.metrics.height;
1499 from = info.line_to;
1502 from = info.line_from;
1503 if (cursor_pos < from)
1507 /* Scroll up to make the cursor line top. */
1511 update_cursor (cursor_pos, 1);
1515 JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
1517 float persent = *(float *) persent_ptr;
1518 int pos1, pos2 = nchars * persent;
1519 MDrawGlyphInfo info;
1522 pos1 = bol (pos2, 0);
1523 GLYPH_INFO (pos1, pos2, info);
1524 pos1 = info.line_from;
1526 update_cursor (pos1, 1);
1531 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
1533 XKeyEvent *key_event = (XKeyEvent *) event;
1535 KeySym keysym = NoSymbol;
1537 /* If set to 1, do not update target_x_position. */
1538 int keep_target_x_position = 0;
1541 if (current_input_context
1542 && minput_filter (current_input_context, Mnil, event))
1544 if (event->type == KeyRelease)
1549 produced = mtext ();
1550 ret = minput_lookup (current_input_context, Mnil, event, produced);
1551 if (mtext_len (produced) > 0)
1552 insert_chars (produced);
1554 ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
1555 m17n_object_unref (produced);
1565 n = (mtext_property_end (selection)
1566 - mtext_property_start (selection));
1567 mtext_detach_property (selection);
1569 else if (cursor.from < nchars)
1571 /* Delete the following grapheme cluster. */
1572 n = cursor.to - cursor.from;
1585 /* Delete selected region. */
1586 n = (mtext_property_end (selection)
1587 - mtext_property_start (selection));
1588 mtext_detach_property (selection);
1590 else if (cursor.from > 0)
1592 /* Delete the preceding character. */
1603 mtext_detach_property (selection);
1604 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1608 if (cursor.prev_from >= 0)
1609 update_cursor (cursor.prev_from, 0);
1613 if (cursor.left_from >= 0)
1614 update_cursor (cursor.left_from, 0);
1621 mtext_detach_property (selection);
1622 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1626 if (cursor.next_to >= 0)
1627 update_cursor (cursor.to, 0);
1631 if (cursor.right_from >= 0)
1632 update_cursor (cursor.right_from, 0);
1639 mtext_detach_property (selection);
1640 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1642 if (cur.to <= nchars)
1644 MDrawGlyphInfo info;
1647 GLYPH_INFO (cur.from, cur.to, info);
1648 pos = COORDINATES_POSITION (cur.from, nchars + 1,
1649 target_x_position, info.y);
1650 keep_target_x_position = 1;
1651 update_cursor (pos, 0);
1658 mtext_detach_property (selection);
1659 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1665 int pos = bol (cur.from - 1, 0);
1667 TEXT_EXTENTS (pos, cur.from - 1, rect);
1668 y = rect.height + rect.y - 1;
1669 pos = COORDINATES_POSITION (pos, nchars,
1670 target_x_position, y);
1671 keep_target_x_position = 1;
1672 update_cursor (pos, 0);
1679 mtext_detach_property (selection);
1680 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1682 if (top.from < nchars)
1683 ScrollProc (w, NULL, (XtPointer) 1);
1689 mtext_detach_property (selection);
1690 redraw (sel_start.y0, sel_end.y1, 1, 0);;
1693 ScrollProc (w, NULL, (XtPointer) -1);
1697 if (key_event->state >= Mod1Mask)
1699 lose_selection (NULL, NULL);
1705 if (key_event->state >= Mod1Mask)
1707 lose_selection (NULL, NULL);
1715 if (buf[0] == 17) /* C-q */
1717 XtAppSetExitFlag (context);
1720 else if (buf[0] == 12) /* C-l */
1722 redraw (0, win_height, 1, 1);
1727 MText *temp = mtext ();
1729 mtext_cat_char (temp, buf[0] == '\r' ? '\n'
1730 : ((unsigned char *) buf)[0]);
1731 if (current_input_context)
1732 mtext_put_prop (temp, 0, 1, Mlanguage,
1733 current_input_context->im->language);
1734 insert_chars (temp);
1735 m17n_object_unref (temp);
1740 if (! keep_target_x_position)
1741 target_x_position = cursor.x;
1745 SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
1747 char *name = (char *) client_data;
1749 int from = -1, to = 0;
1754 filename = strdup (name);
1757 fp = fopen (filename, "w");
1760 fprintf (stderr, "Open for write fail: %s", filename);
1766 from = mtext_property_start (selection);
1767 to = mtext_property_end (selection);
1768 mtext_detach_property (selection);
1771 mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
1774 select_region (from, to);
1778 SerializeProc (Widget w, XtPointer client_data, XtPointer call_data)
1784 mtext_detach_property (selection);
1785 serialized = (int) client_data;
1787 new = mtext_deserialize (mt);
1790 MPlist *plist = mplist ();
1792 mplist_push (plist, Mt, Mface);
1793 mplist_push (plist, Mt, Mlanguage);
1794 new = mtext_serialize (mt, 0, mtext_len (mt), plist);
1795 m17n_object_unref (plist);
1799 m17n_object_unref (mt);
1801 serialized = ! serialized;
1802 nchars = mtext_len (mt);
1805 update_cursor (0, 1);
1806 redraw (0, win_height, 1, 1);
1810 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
1812 XtAppSetExitFlag (context);
1818 FILE *fp = fopen (filename, "r");
1821 FATAL_ERROR ("Can't read \"%s\"!\n", filename);
1822 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
1825 FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
1830 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
1832 int data = (int) client_data;
1837 control.enable_bidi = 0;
1838 control.orientation_reversed = 0;
1842 control.enable_bidi = 1;
1843 control.orientation_reversed = data == 2;
1845 for (i = 0; i < 3; i++)
1848 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1850 XtSetArg (arg[0], XtNleftBitmap, None);
1851 XtSetValues (BidiMenus[i], arg, 1);
1854 update_cursor (cursor.from, 1);
1855 redraw (0, win_height, 1, 0);
1859 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
1861 int data = (int) client_data;
1865 control.max_line_width = 0;
1868 control.max_line_width = win_width;
1869 control.line_break = (data == 1 ? NULL : mdraw_default_line_break);
1871 for (i = 0; i < 3; i++)
1874 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1876 XtSetArg (arg[0], XtNleftBitmap, None);
1877 XtSetValues (LineBreakMenus[i], arg, 1);
1880 update_cursor (cursor.from, 1);
1881 redraw (0, win_height, 1, 0);
1885 FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
1887 char *filter_module = (char *) client_data;
1889 void (*func) (MText *, int, int);
1893 handle = dlopen (filter_module, RTLD_NOW);
1896 *(void **) (&func) = dlsym (handle, "filter");
1898 (*func) (mt, mtext_property_start (selection),
1899 mtext_property_end (selection));
1904 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
1906 int data = (int) client_data;
1920 control.cursor_bidi = 0, control.cursor_width = -1;
1924 control.cursor_bidi = 0, control.cursor_width = 2;
1928 control.cursor_bidi = 1;
1933 for (i = from; i < to; i++)
1936 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1938 XtSetArg (arg[0], XtNleftBitmap, None);
1939 XtSetValues (CursorMenus[i], arg, 1);
1942 update_cursor (cursor.from, 0);
1943 redraw (0, win_height, 1, 0);
1947 InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
1949 int idx = (int) client_data;
1951 if (idx == -2 ? current_input_method < 0
1952 : idx == -1 ? auto_input_method
1953 : idx == current_input_method)
1956 XtSetArg (arg[0], XtNleftBitmap, None);
1957 if (auto_input_method)
1959 XtSetValues (InputMethodMenus[1], arg, 1);
1960 auto_input_method = 0;
1962 else if (current_input_method < 0)
1963 XtSetValues (InputMethodMenus[0], arg, 1);
1965 XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
1969 auto_input_method = 1;
1972 else if (input_method_table[idx].available >= 0)
1974 if (! input_method_table[idx].im)
1976 input_method_table[idx].im =
1977 minput_open_im (input_method_table[idx].language,
1978 input_method_table[idx].name, NULL);
1979 if (! input_method_table[idx].im)
1980 input_method_table[idx].available = -1;
1982 if (input_method_table[idx].im)
1983 select_input_method (idx);
1985 XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
1986 XtSetValues (InputMethodMenus[idx + 2], arg, 1);
1989 MPlist *default_face_list;
1992 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
1994 int idx = (int) client_data;
2005 MFace *face = mframe_get_prop (frame, Mface);
2007 for (plist = default_face_list; mplist_key (plist) != Mnil;
2008 plist = mplist_next (plist))
2009 mface_merge (face, mplist_value (plist));
2010 mplist_add (plist, Mt, *face_table[idx].face);
2011 mface_merge (face, *face_table[idx].face);
2013 else if (mplist_key (mplist_next (default_face_list)) != Mnil)
2015 MFace *face = mframe_get_prop (frame, Mface);
2017 for (plist = default_face_list;
2018 mplist_key (mplist_next (plist)) != Mnil;
2019 plist = mplist_next (plist))
2020 mface_merge (face, mplist_value (plist));
2024 update_cursor (0, 1);
2025 redraw (0, win_height, 1, 1);
2030 XtAppAddWorkProc (context, show_cursor, NULL);
2031 from = mtext_property_start (selection);
2032 to = mtext_property_end (selection);
2033 old_y1 = sel_end.y1;
2035 mtext_detach_property (selection);
2038 MTextProperty *prop = mtext_property (Mface, *face_table[idx].face,
2039 MTEXTPROP_REAR_STICKY);
2040 mtext_push_property (mt, from, to, prop);
2041 m17n_object_unref (prop);
2044 mtext_pop_prop (mt, from, to, Mface);
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 LangProc (Widget w, XtPointer client_data, XtPointer call_data)
2063 MSymbol sym = (MSymbol) client_data;
2070 XtAppAddWorkProc (context, show_cursor, NULL);
2071 from = mtext_property_start (selection);
2072 to = mtext_property_end (selection);
2073 old_y1 = sel_end.y1;
2075 mtext_detach_property (selection);
2077 mtext_put_prop (mt, from, to, Mlanguage, sym);
2079 mtext_pop_prop (mt, from, to, Mlanguage);
2082 update_top (top.from);
2083 update_cursor (cursor.from, 1);
2084 select_region (from, to);
2085 update_region (sel_start.y0, old_y1, sel_end.y1);
2086 if (cur.y1 > win_height)
2088 while (cur.y1 > win_height)
2091 update_cursor (cursor.from, 1);
2097 DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
2099 int narrowed = (int) client_data;
2102 MConverter *converter;
2108 from = mtext_property_start (selection);
2109 to = mtext_property_end (selection);
2118 mdump = popen ("mdump -q -p a4", "w");
2120 mdump = popen ("mdump -q", "w");
2123 converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
2124 mconv_encode_range (converter, mt, from, to);
2125 mconv_free_converter (converter);
2130 input_status (MInputContext *ic, MSymbol command)
2132 XFillRectangle (display, input_status_pixmap, gc_inv,
2133 0, 0, input_status_width, input_status_height);
2134 if (command == Minput_status_draw)
2138 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2139 Mface, face_input_status);
2140 if (ic->im->language != Mnil)
2141 mtext_put_prop (ic->status, 0, mtext_len (ic->status),
2142 Mlanguage, ic->im->language);
2143 mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
2144 &input_status_control, NULL, NULL, &rect);
2145 mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
2146 input_status_width - rect.width - 2, - rect.y,
2147 ic->status, 0, mtext_len (ic->status),
2148 &input_status_control);
2150 XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
2151 XtSetValues (CurIMStatus, arg, 1);
2155 compare_input_method (const void *elt1, const void *elt2)
2157 const InputMethodInfo *im1 = elt1;
2158 const InputMethodInfo *im2 = elt2;
2159 MSymbol lang1, lang2;
2161 if (im1->language == Mnil)
2163 if (im1->language == im2->language)
2164 return strcmp (msymbol_name (im1->name), msymbol_name (im2->name));
2165 if (im1->language == Mt)
2167 if (im2->language == Mt)
2169 lang1 = msymbol_get (im1->language, Mlanguage);
2170 lang2 = msymbol_get (im2->language, Mlanguage);
2171 return strcmp (msymbol_name (lang1), msymbol_name (lang2));
2175 setup_input_methods (int with_xim, char *initial_input_method)
2177 MInputMethod *im = NULL;
2178 MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
2181 char *lang_name = NULL, *method_name = NULL;
2183 if (initial_input_method)
2185 char *p = strchr (initial_input_method, '-');
2187 lang_name = initial_input_method, method_name = p + 1, *p = '\0';
2189 method_name = initial_input_method;
2192 num_input_methods = plist ? mplist_length (plist) : 0;
2196 MInputXIMArgIM arg_xim;
2198 arg_xim.display = display;
2200 arg_xim.res_name = arg_xim.res_class = NULL;
2201 arg_xim.locale = NULL;
2202 arg_xim.modifier_list = NULL;
2203 im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
2205 num_input_methods++;
2207 input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
2210 input_method_table[i].available = 1;
2211 input_method_table[i].language = Mnil;
2212 input_method_table[i].name = im->name;
2213 input_method_table[i].im = im;
2219 for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
2221 MDatabase *mdb = mplist_value (pl);
2222 MSymbol *tag = mdatabase_tag (mdb);
2226 input_method_table[i].language = tag[1];
2227 input_method_table[i].name = tag[2];
2232 m17n_object_unref (plist);
2234 num_input_methods = i;
2235 qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
2236 compare_input_method);
2237 current_input_context = NULL;
2239 mplist_put (minput_driver->callback_list, Minput_status_start,
2240 (void *) input_status);
2241 mplist_put (minput_driver->callback_list, Minput_status_draw,
2242 (void *) input_status);
2243 mplist_put (minput_driver->callback_list, Minput_status_done,
2244 (void *) input_status);
2247 for (i = 0; i < num_input_methods; i++)
2248 if (strcmp (method_name, msymbol_name (input_method_table[i].name)) == 0
2250 ? strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0
2251 : input_method_table[i].language == Mt))
2253 current_input_method = i;
2260 MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num)
2264 if (num && *num > 0)
2268 for (i = 0; i < *num; i++)
2269 bytes += strlen (str[i]) + 1;
2270 msg = alloca (bytes);
2271 strcpy (msg, str[0]);
2272 for (i = 1; i < *num; i++)
2273 strcat (msg, " "), strcat (msg, str[i]);
2275 else if (cursor.from < nchars)
2277 int c = mtext_ref_char (mt, cursor.from);
2278 char *name = mchar_get_prop (c, Mname);
2282 msg = alloca (10 + strlen (name));
2283 sprintf (msg, "U+%04X %s", c, name);
2289 XtSetArg (arg[0], XtNlabel, msg);
2290 XtSetValues (MessageWidget, arg, 1);
2296 char *name1, *name2;
2297 XtCallbackProc proc;
2298 XtPointer client_data;
2303 void PopupProc (Widget w, XtPointer client_data, XtPointer call_data);
2305 void SaveProc (Widget w, XtPointer client_data, XtPointer call_data);
2307 MenuRec FileMenu[] =
2308 { { 0, "Open", NULL, PopupProc, FileMenu + 0, -1 },
2309 { 0, "Save", NULL, SaveProc, NULL, -1 },
2310 { 0, "Save as", NULL, PopupProc, FileMenu + 2, -1 },
2312 { 0, "Serialize", NULL, SerializeProc, (void *) 1, -1 },
2313 { 0, "Deserialize", NULL, SerializeProc, (void *) 0, -1 },
2315 { 0, "Dump Image Buffer", NULL, DumpImageProc, (void *) 0, -1 },
2316 { 0, "Dump Image Region", NULL, DumpImageProc, (void *) 1, -1 },
2318 { 0, "Quit", NULL, QuitProc, NULL, -1 } };
2321 PopupProc (Widget w, XtPointer client_data, XtPointer call_data)
2323 MenuRec *rec = (MenuRec *) client_data;
2326 XtSetArg (arg[0], XtNvalue, "");
2327 XtSetArg (arg[1], XtNlabel, rec->name1);
2328 XtSetValues (FileDialogWidget, arg, 2);
2329 XtTranslateCoords (w, (Position) 0, (Position) 0, &x, &y);
2330 XtSetArg (arg[0], XtNx, x + 20);
2331 XtSetArg (arg[1], XtNy, y + 10);
2332 XtSetValues (FileShellWidget, arg, 2);
2333 XtPopup (FileShellWidget, XtGrabExclusive);
2337 FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
2342 XtPopdown (FileShellWidget);
2343 if ((int) client_data == 1)
2345 XtSetArg (arg[0], XtNlabel, &label);
2346 XtGetValues (FileDialogWidget, arg, 1);
2347 if (strcmp (label, FileMenu[0].name1) == 0)
2351 filename = strdup ((char *) XawDialogGetValueString (FileDialogWidget));
2352 fp = fopen (filename, "r");
2354 m17n_object_unref (mt);
2357 mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
2365 nchars = mtext_len (mt);
2367 update_cursor (0, 1);
2368 redraw (0, win_height, 1, 1);
2370 else if (strcmp (label, FileMenu[2].name1) == 0)
2371 SaveProc (w, (XtPointer) XawDialogGetValueString (FileDialogWidget), NULL);
2373 fprintf (stderr, "Invalid calling sequence: FileDialogProc\n");
2376 #define SetMenu(MENU, TYPE, NAME1, NAME2, PROC, DATA, STATUS) \
2377 ((MENU).type = (TYPE), (MENU).name1 = (NAME1), (MENU).name2 = (NAME2), \
2378 (MENU).proc = (PROC), (MENU).client_data = (XtPointer) (DATA), \
2379 (MENU).status = (STATUS))
2383 create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
2384 char *menu_name, MenuRec *menus, int num_menus, char *help)
2386 Widget button, menu;
2387 char *fmt = "<EnterWindow>: highlight() MenuHelp(%s)\n\
2388 <LeaveWindow>: reset() MenuHelp()\n\
2389 <BtnDown>: reset() PopupMenu()\n\
2390 <BtnUp>: highlight()";
2396 menu = XtCreatePopupShell (menu_name, simpleMenuWidgetClass, top, NULL, 0);
2397 for (i = 0; i < num_menus; i++)
2408 XtSetArg (arg[n], XtNleftMargin, 20), n++;
2410 XtSetArg (arg[n], XtNleftBitmap, CheckPixmap), n++;
2412 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2414 XtAddCallback (m->w, XtNcallback, m->proc, m->client_data);
2418 XtSetArg (arg[0], XtNsensitive, False);
2419 m->w = XtCreateManagedWidget (m->name1, smeBSBObjectClass,
2425 XtCreateManagedWidget (m->name1, smeLineObjectClass, menu, NULL, 0);
2430 trans = alloca (strlen (fmt) + strlen (help));
2431 sprintf (trans, fmt, help);
2432 XtSetArg (arg[0], XtNmenuName, menu_name);
2433 XtSetArg (arg[1], XtNtranslations, XtParseTranslationTable ((String) trans));
2434 XtSetArg (arg[2], XtNinternalWidth, 2);
2435 XtSetArg (arg[3], XtNhighlightThickness, 1);
2436 XtSetArg (arg[4], XtNleft, XawChainLeft);
2437 XtSetArg (arg[5], XtNright, XawChainLeft);
2440 XtSetArg (arg[i], XtNfromHoriz, left), i++;
2441 button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
2446 int height, ascent, *width = alloca (sizeof (int) * num_menus);
2447 int *len = alloca (sizeof (int) * num_menus);
2450 XFontSetExtents *fontset_extents;
2452 XtSetArg (arg[0], XtNfontSet, &font_set);
2453 XtGetValues (button, arg, 1);
2455 fontset_extents = XExtentsOfFontSet (font_set);
2456 height = fontset_extents->max_logical_extent.height;
2457 ascent = - fontset_extents->max_logical_extent.y;
2459 for (i = 0; i < num_menus; i++)
2462 len[i] = strlen (menus[i].name2);
2463 width[i] = XmbTextEscapement (font_set, menus[i].name2, len[i]);
2464 if (max_width < width[i])
2465 max_width = width[i];
2467 for (i = 0; i < num_menus; i++)
2470 Pixmap pixmap = XCreatePixmap (display,
2471 RootWindow (display, screen),
2472 max_width, height, 1);
2473 XFillRectangle (display, pixmap, mono_gc_inv,
2474 0, 0, max_width, height);
2475 XmbDrawString (display, pixmap, font_set, mono_gc,
2476 max_width - width[i], ascent,
2477 menus[i].name2, len[i]);
2478 XtSetArg (arg[0], XtNrightBitmap, pixmap);
2479 XtSetArg (arg[1], XtNrightMargin, max_width + 20);
2480 XtSetValues (menus[i].w, arg, 2);
2488 XtActionsRec actions[] = {
2489 {"Expose", ExposeProc},
2490 {"Configure", ConfigureProc},
2492 {"ButtonPress", ButtonProc},
2493 {"ButtonRelease", ButtonReleaseProc},
2494 {"ButtonMotion", ButtonMoveProc},
2495 {"Button2Press", Button2Proc},
2496 {"MenuHelp", MenuHelpProc},
2497 {"FocusIn", FocusInProc},
2498 {"FocusOut", FocusOutProc}
2502 /* Print the usage of this program (the name is PROG), and exit with
2506 help_exit (char *prog, int exit_code)
2514 printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] FILE\n", prog);
2515 printf ("Display FILE on a window and allow users to edit it.\n");
2516 printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
2517 printf ("The following OPTIONs are available.\n");
2518 printf (" %-13s\n\t\t%s", "--fontset FONTSET",
2519 "Use the specified fontset\n");
2520 printf (" %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
2521 printf (" %-13s\n\t\t%s", "--im INPUT-METHOD",
2522 "Input method activated initially.\n");
2523 printf (" %-13s %s", "--version", "print version number\n");
2524 printf (" %-13s %s", "-h, --help", "print this message\n");
2530 main (int argc, char **argv)
2532 Widget form, BodyWidget, w;
2533 char *fontset_name = NULL;
2535 char *initial_input_method = NULL;
2536 int col = 80, row = 32;
2537 /* Translation table for TextWidget. */
2538 String trans = "<Expose>: Expose()\n\
2539 <Configure>: Configure()\n\
2542 <Btn1Down>: ButtonPress()\n\
2543 <Btn1Up>: ButtonRelease()\n\
2544 <Btn1Motion>: ButtonMotion()\n\
2545 <Btn2Down>: Button2Press()";
2546 /* Translation table for the top form widget. */
2547 String trans2 = "<Key>: Key()\n\
2549 <FocusIn>: FocusIn()\n\
2550 <FocusOut>: FocusOut()";
2551 String pop_face_trans
2552 = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
2553 <LeaveWindow>: MenuHelp() reset()\n\
2554 <Btn1Down>: set()\n\
2555 <Btn1Up>: notify() unset()";
2556 String pop_lang_trans
2557 = "<EnterWindow>: MenuHelp(Pop language property) highlight()\n\
2558 <LeaveWindow>: MenuHelp() reset()\n\
2559 <Btn1Down>: set()\n\
2560 <Btn1Up>: notify() unset()";
2561 int font_width, font_ascent, font_descent;
2564 char *filter = NULL;
2566 setlocale (LC_ALL, "");
2567 /* Create the top shell. */
2568 XtSetLanguageProc (NULL, NULL, NULL);
2569 ShellWidget = XtOpenApplication (&context, "M17NEdit", NULL, 0, &argc, argv,
2570 NULL, sessionShellWidgetClass, NULL, 0);
2571 display = XtDisplay (ShellWidget);
2572 screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
2574 /* Parse the remaining command line arguments. */
2575 for (i = 1; i < argc; i++)
2577 if (! strcmp (argv[i], "--help")
2578 || ! strcmp (argv[i], "-h"))
2579 help_exit (argv[0], 0);
2580 else if (! strcmp (argv[i], "--version"))
2582 printf ("m17n-edit (m17n library) %s\n", VERSION);
2583 printf ("Copyright (C) 2003 AIST, JAPAN\n");
2586 else if (! strcmp (argv[i], "--geometry"))
2589 if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
2590 help_exit (argv[0], 1);
2592 else if (! strcmp (argv[i], "-s"))
2595 fontsize = atoi (argv[i]);
2599 else if (! strcmp (argv[i], "--fontset"))
2602 fontset_name = strdup (argv[i]);
2604 else if (! strcmp (argv[i], "--im"))
2607 initial_input_method = strdup (argv[i]);
2609 else if (! strcmp (argv[i], "--with-xim"))
2613 else if (! strcmp (argv[i], "--filter"))
2618 else if (argv[i][0] != '-')
2620 filename = strdup (argv[i]);
2624 fprintf (stderr, "Unknown option: %s\n", argv[i]);
2625 help_exit (argv[0], 1);
2629 filename = strdup ("/dev/null");
2631 mdatabase_dir = ".";
2632 /* Initialize the m17n library. */
2634 if (merror_code != MERROR_NONE)
2635 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
2636 minput_driver = &minput_gui_driver;
2638 mt = read_file (filename);
2641 nchars = mtext_len (mt);
2643 Mword = msymbol ("word");
2646 MFace *face = mface ();
2648 mface_put_prop (face, Mforeground, msymbol ("blue"));
2649 mface_put_prop (face, Mbackground, msymbol ("yellow"));
2650 mface_put_prop (face, Mvideomode, Mreverse);
2651 selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
2652 m17n_object_unref (face);
2655 /* This tells ExposeProc to initialize everything. */
2658 XA_TEXT = XInternAtom (display, "TEXT", False);
2659 XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
2660 XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
2661 Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
2662 if (Mcoding_compound_text == Mnil)
2663 FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
2666 MPlist *plist = mplist ();
2670 mplist_put (plist, msymbol ("widget"), ShellWidget);
2671 if (fontset_name || fontsize > 0)
2673 MFontset *fontset = mfontset (fontset_name);
2676 mface_put_prop (face, Mfontset, fontset);
2677 mface_put_prop (face, Msize, (void *) fontsize);
2678 m17n_object_unref (fontset);
2679 mplist_add (plist, Mface, face);
2680 m17n_object_unref (face);
2682 frame = mframe (plist);
2684 FATAL_ERROR ("%s\n", "Fail to create a frame!");
2685 m17n_object_unref (plist);
2686 face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
2687 default_face_list = mplist ();
2688 mplist_add (default_face_list, Mt, face_default);
2689 face_default_fontset = mface ();
2690 mface_put_prop (face_default_fontset, Mfontset,
2691 mface_get_prop (face_default, Mfontset));
2693 font = (MFont *) mframe_get_prop (frame, Mfont);
2694 default_font_size = (int) mfont_get_prop (font, Msize);
2697 font_width = (int) mframe_get_prop (frame, Mfont_width);
2698 font_ascent = (int) mframe_get_prop (frame, Mfont_ascent);
2699 font_descent = (int) mframe_get_prop (frame, Mfont_descent);
2700 win_width = font_width * col;
2701 win_height = (font_ascent + font_descent) * row;
2707 prop.color_top = prop.color_left = msymbol ("magenta");
2708 prop.color_bottom = prop.color_right = msymbol ("red");
2709 prop.inner_hmargin = prop.inner_vmargin = 1;
2710 prop.outer_hmargin = prop.outer_vmargin = 2;
2712 face_box = mface ();
2713 mface_put_prop (face_box, Mbox, &prop);
2716 face_courier = mface ();
2717 mface_put_prop (face_courier, Mfamily, msymbol ("courier"));
2718 face_helvetica = mface ();
2719 mface_put_prop (face_helvetica, Mfamily, msymbol ("helvetica"));
2720 face_times = mface ();
2721 mface_put_prop (face_times, Mfamily, msymbol ("times"));
2722 face_dv_ttyogesh = mface ();
2723 mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
2724 face_freesans = mface ();
2725 mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
2726 face_freeserif = mface ();
2727 mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
2728 face_freemono = mface ();
2729 mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
2731 face_xxx_large = mface ();
2732 mface_put_prop (face_xxx_large, Mratio, (void *) 300);
2734 MFont *latin_font = mframe_get_prop (frame, Mfont);
2735 MFont *dev_font = mfont ();
2736 MFont *thai_font = mfont ();
2737 MFont *tib_font = mfont ();
2739 MSymbol unicode_bmp = msymbol ("unicode-bmp");
2740 MSymbol no_ctl = msymbol ("no-ctl");
2742 mfont_put_prop (dev_font, Mfamily, msymbol ("raghindi"));
2743 mfont_put_prop (dev_font, Mregistry, unicode_bmp);
2744 mfont_put_prop (thai_font, Mfamily, msymbol ("norasi"));
2745 mfont_put_prop (thai_font, Mregistry, unicode_bmp);
2746 mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
2747 mfont_put_prop (tib_font, Mregistry, unicode_bmp);
2749 fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
2750 mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
2751 latin_font, Mnil, 0);
2752 mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
2753 dev_font, no_ctl, 0);
2754 mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
2755 thai_font, no_ctl, 0);
2756 mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
2757 tib_font, no_ctl, 0);
2758 face_no_ctl_fontset = mface ();
2759 mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
2760 m17n_object_unref (fontset);
2767 setup_input_methods (with_xim, initial_input_method);
2769 gc = DefaultGC (display, screen);
2771 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans2));
2772 XtSetArg (arg[1], XtNdefaultDistance, 2);
2773 form = XtCreateManagedWidget ("form", formWidgetClass, ShellWidget, arg, 2);
2775 XtSetArg (arg[0], XtNborderWidth, 0);
2776 XtSetArg (arg[1], XtNdefaultDistance, 2);
2777 XtSetArg (arg[2], XtNtop, XawChainTop);
2778 XtSetArg (arg[3], XtNbottom, XawChainTop);
2779 XtSetArg (arg[4], XtNleft, XawChainLeft);
2780 XtSetArg (arg[5], XtNright, XawChainRight);
2781 XtSetArg (arg[6], XtNresizable, True);
2782 HeadWidget = XtCreateManagedWidget ("head", formWidgetClass, form, arg, 7);
2783 XtSetArg (arg[7], XtNfromVert, HeadWidget);
2784 FaceWidget = XtCreateManagedWidget ("face", formWidgetClass, form, arg, 8);
2785 XtSetArg (arg[7], XtNfromVert, FaceWidget);
2786 LangWidget = XtCreateManagedWidget ("lang", formWidgetClass, form, arg, 8);
2787 XtSetArg (arg[3], XtNbottom, XawChainBottom);
2788 XtSetArg (arg[7], XtNfromVert, LangWidget);
2789 BodyWidget = XtCreateManagedWidget ("body", formWidgetClass, form, arg, 8);
2790 XtSetArg (arg[2], XtNtop, XawChainBottom);
2791 XtSetArg (arg[7], XtNfromVert, BodyWidget);
2792 TailWidget = XtCreateManagedWidget ("tail", formWidgetClass, form, arg, 8);
2794 FileShellWidget = XtCreatePopupShell ("FileShell", transientShellWidgetClass,
2795 HeadWidget, NULL, 0);
2796 XtSetArg (arg[0], XtNvalue, "");
2797 FileDialogWidget = XtCreateManagedWidget ("File", dialogWidgetClass,
2798 FileShellWidget, arg, 1);
2799 XawDialogAddButton (FileDialogWidget, "OK",
2800 FileDialogProc, (XtPointer) 0);
2801 XawDialogAddButton (FileDialogWidget, "CANCEL",
2802 FileDialogProc, (XtPointer) 1);
2804 CheckPixmap = XCreateBitmapFromData (display, RootWindow (display, screen),
2805 (char *) check_bits,
2806 check_width, check_height);
2808 unsigned long valuemask = GCForeground;
2811 values.foreground = 1;
2812 mono_gc = XCreateGC (display, CheckPixmap, valuemask, &values);
2813 values.foreground = 0;
2814 mono_gc_inv = XCreateGC (display, CheckPixmap, valuemask, &values);
2821 if (num_menus < num_input_methods + 2)
2822 num_menus = num_input_methods + 2;
2823 if (num_menus < num_faces + 1)
2824 num_menus = num_faces + 1;
2825 menus = alloca (sizeof (MenuRec) * num_menus);
2827 w = create_menu_button (ShellWidget, HeadWidget, NULL, "File", "File Menu",
2828 FileMenu, sizeof FileMenu / sizeof (MenuRec),
2829 "File I/O, Serialization, Image, Quit");
2831 SetMenu (menus[0], 0, "Logical Move", NULL, CursorProc, 0, 1);
2832 SetMenu (menus[1], 0, "Visual Move", NULL, CursorProc, 1, 0);
2833 SetMenu (menus[2], 1, "", NULL, NULL, NULL, 0);
2834 SetMenu (menus[3], 0, "Box type", NULL, CursorProc, 2, 0);
2835 SetMenu (menus[4], 0, "Bar type", NULL, CursorProc, 3, 1);
2836 SetMenu (menus[5], 0, "Bidi type", NULL, CursorProc, 4, 0);
2837 w = create_menu_button (ShellWidget, HeadWidget, w,
2838 "Cursor", "Cursor Menu",
2839 menus, 6, "Cursor Movement Mode, Cursor Shape");
2840 CursorMenus[0] = menus[0].w;
2841 CursorMenus[1] = menus[1].w;
2842 CursorMenus[2] = menus[3].w;
2843 CursorMenus[3] = menus[4].w;
2844 CursorMenus[4] = menus[5].w;
2846 SetMenu (menus[0], 0, "disable", NULL, BidiProc, 0, 0);
2847 SetMenu (menus[1], 0, "Left (|--> |)", NULL, BidiProc, 1, 1);
2848 SetMenu (menus[2], 0, "Right (| <--|)", NULL, BidiProc, 2, 0);
2849 w = create_menu_button (ShellWidget, HeadWidget, w, "Bidi", "Bidi Menu",
2850 menus, 3, "BIDI Processing Mode");
2851 for (i = 0; i < 3; i++)
2852 BidiMenus[i] = menus[i].w;
2854 SetMenu (menus[0], 0, "truncate", NULL, LineBreakProc, 0, 0);
2855 SetMenu (menus[1], 0, "break at edge", NULL, LineBreakProc, 1, 1);
2856 SetMenu (menus[2], 0, "break at word boundary", NULL, LineBreakProc, 2, 0);
2857 w = create_menu_button (ShellWidget, HeadWidget, w, "LineBreak",
2859 menus, 3, "How to break lines");
2860 for (i = 0; i < 3; i++)
2861 LineBreakMenus[i] = menus[i].w;
2863 SetMenu (menus[0], 0, "none", NULL, InputMethodProc, -2, 1);
2864 SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
2865 for (i = 0; i < num_input_methods; i++)
2867 InputMethodInfo *im = input_method_table + i;
2868 char *name1, *name2;
2870 if (im->language != Mnil && im->language != Mt)
2872 MSymbol sym = msymbol_get (im->language, Mlanguage);
2874 name1 = msymbol_name (im->language);
2876 name1 = msymbol_name (sym);
2877 name2 = msymbol_name (im->name);
2880 name1 = msymbol_name (im->name), name2 = NULL;
2882 SetMenu (menus[i + 2], 0, name1, name2, InputMethodProc, i, 0);
2884 w = create_menu_button (ShellWidget, HeadWidget, w, "InputMethod",
2885 "Input Method Menu", menus, i + 2,
2886 "Select input method");
2889 unsigned long valuemask = GCForeground;
2892 XtSetArg (arg[0], XtNbackground, &values.foreground);
2893 XtGetValues (w, arg, 1);
2894 gc_inv = XCreateGC (display, RootWindow (display, screen),
2895 valuemask, &values);
2898 InputMethodMenus = malloc (sizeof (Widget) * (num_input_methods + 2));
2899 for (i = 0; i < num_input_methods + 2; i++)
2900 InputMethodMenus[i] = menus[i].w;
2904 SetMenu (menus[0], 0, filter, NULL, FilterProc, filter, 0);
2905 w = create_menu_button (ShellWidget, HeadWidget, w, "Filter",
2906 "Filter Menu", menus, 1,
2907 "Select filter to run");
2910 input_status_width = font_width * 8;
2911 input_status_height = (font_ascent + font_descent) * 2.4;
2912 input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
2914 input_status_height,
2915 DefaultDepth (display, screen));
2920 prop.color_top = prop.color_bottom
2921 = prop.color_left = prop.color_right = Mnil;
2922 prop.inner_hmargin = prop.inner_vmargin = 1;
2923 prop.outer_hmargin = prop.outer_vmargin = 0;
2924 face_input_status = mface_copy (face_default);
2925 mface_put_prop (face_input_status, Mbox, &prop);
2928 XFillRectangle (display, input_status_pixmap, gc_inv,
2929 0, 0, input_status_width, input_status_height);
2930 XtSetArg (arg[0], XtNfromHoriz, w);
2931 XtSetArg (arg[1], XtNleft, XawRubber);
2932 XtSetArg (arg[2], XtNright, XawChainRight);
2933 XtSetArg (arg[3], XtNborderWidth, 0);
2934 XtSetArg (arg[4], XtNlabel, " ");
2935 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2936 CurIMLang = XtCreateManagedWidget ("CurIMLang", labelWidgetClass,
2937 HeadWidget, arg, 6);
2938 XtSetArg (arg[0], XtNfromHoriz, CurIMLang);
2939 XtSetArg (arg[1], XtNleft, XawChainRight);
2940 XtSetArg (arg[4], XtNbitmap, input_status_pixmap);
2941 CurIMStatus = XtCreateManagedWidget ("CurIMStatus", labelWidgetClass,
2942 HeadWidget, arg, 5);
2944 XtSetArg (arg[0], XtNborderWidth, 0);
2945 XtSetArg (arg[1], XtNleft, XawChainLeft);
2946 XtSetArg (arg[2], XtNright, XawChainLeft);
2947 w = XtCreateManagedWidget ("Face", labelWidgetClass, FaceWidget, arg, 3);
2948 for (i = 0; i < num_faces;)
2950 char *label_menu = face_table[i++].name; /* "Menu Xxxx" */
2951 char *label = label_menu + 5; /* "Xxxx" */
2953 for (j = i; j < num_faces && face_table[j].face; j++)
2954 SetMenu (menus[j - i], 0, face_table[j].name, NULL,
2956 w = create_menu_button (ShellWidget, FaceWidget, w,
2958 menus, j - i, "Push face property");
2962 XtSetArg (arg[0], XtNfromHoriz, w);
2963 XtSetArg (arg[1], XtNleft, XawChainLeft);
2964 XtSetArg (arg[2], XtNright, XawChainLeft);
2965 XtSetArg (arg[3], XtNhorizDistance, 10);
2966 XtSetArg (arg[4], XtNlabel, "Pop");
2967 XtSetArg (arg[5], XtNtranslations,
2968 XtParseTranslationTable (pop_face_trans));
2969 w = XtCreateManagedWidget ("Pop Face", commandWidgetClass,
2970 FaceWidget, arg, 6);
2971 XtAddCallback (w, XtNcallback, FaceProc, (void *) -1);
2973 XtSetArg (arg[0], XtNfromHoriz, w);
2974 XtSetArg (arg[1], XtNleft, XawChainLeft);
2975 XtSetArg (arg[2], XtNright, XawChainRight);
2976 XtSetArg (arg[3], XtNlabel, "");
2977 XtSetArg (arg[4], XtNborderWidth, 0);
2978 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
2979 CurFaceWidget = XtCreateManagedWidget ("Current Face", labelWidgetClass,
2980 FaceWidget, arg, 6);
2982 XtSetArg (arg[0], XtNborderWidth, 0);
2983 XtSetArg (arg[1], XtNleft, XawChainLeft);
2984 XtSetArg (arg[2], XtNright, XawChainLeft);
2985 w = XtCreateManagedWidget ("Lang", labelWidgetClass, LangWidget, arg, 3);
2987 MPlist *plist[11], *pl;
2990 for (i = 0; i < 11; i++) plist[i] = NULL;
2992 for (langname[0] = 'a'; langname[0] <= 'z'; langname[0]++)
2993 for (langname[1] = 'a'; langname[1] <= 'z'; langname[1]++)
2995 MSymbol sym = msymbol_exist (langname);
2999 && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
3001 char *name = msymbol_name (fullname);
3004 if (c >= 'a' && c <= 'z')
3006 int idx = (c < 'u') ? (c - 'a') / 2 : 10;
3010 pl = plist[idx] = mplist ();
3011 for (; mplist_next (pl); pl = mplist_next (pl))
3012 if (strcmp (name, (char *) mplist_value (pl)) < 0)
3014 mplist_push (pl, sym, fullname);
3019 for (i = 0; i < 11; i++)
3022 char *name = alloca (9);
3024 sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
3027 for (j = 0, pl = plist[i]; mplist_next (pl);
3028 j++, pl = mplist_next (pl))
3029 SetMenu (menus[j], 0, msymbol_name ((MSymbol) mplist_value (pl)),
3030 msymbol_name (mplist_key (pl)),
3031 LangProc, mplist_key (pl), -1);
3032 w = create_menu_button (ShellWidget, LangWidget, w, name + 5, name,
3033 menus, j, "Push language property");
3035 for (i = 0; i < 11; i++)
3037 m17n_object_unref (plist[i]);
3039 XtSetArg (arg[0], XtNfromHoriz, w);
3040 XtSetArg (arg[1], XtNleft, XawChainLeft);
3041 XtSetArg (arg[2], XtNright, XawChainLeft);
3042 XtSetArg (arg[3], XtNhorizDistance, 10);
3043 XtSetArg (arg[4], XtNlabel, "Pop");
3044 XtSetArg (arg[5], XtNtranslations,
3045 XtParseTranslationTable (pop_lang_trans));
3046 w = XtCreateManagedWidget ("Pop Lang", commandWidgetClass,
3047 LangWidget, arg, 6);
3048 XtAddCallback (w, XtNcallback, LangProc, Mnil);
3050 XtSetArg (arg[0], XtNfromHoriz, w);
3051 XtSetArg (arg[1], XtNleft, XawChainLeft);
3052 XtSetArg (arg[2], XtNright, XawChainRight);
3053 XtSetArg (arg[3], XtNlabel, "");
3054 XtSetArg (arg[4], XtNborderWidth, 0);
3055 XtSetArg (arg[5], XtNjustify, XtJustifyRight);
3056 CurLangWidget = XtCreateManagedWidget ("Current Lang", labelWidgetClass,
3057 LangWidget, arg, 6);
3060 XtSetArg (arg[0], XtNheight, win_height);
3061 XtSetArg (arg[1], XtNwidth, 10);
3062 XtSetArg (arg[2], XtNleft, XawChainLeft);
3063 XtSetArg (arg[3], XtNright, XawChainLeft);
3064 SbarWidget = XtCreateManagedWidget ("sbar", scrollbarWidgetClass, BodyWidget,
3066 XtAddCallback (SbarWidget, XtNscrollProc, ScrollProc, NULL);
3067 XtAddCallback (SbarWidget, XtNjumpProc, JumpProc, NULL);
3069 XtSetArg (arg[0], XtNheight, win_height);
3070 XtSetArg (arg[1], XtNwidth, win_width);
3071 XtSetArg (arg[2], XtNtranslations, XtParseTranslationTable (trans));
3072 XtSetArg (arg[3], XtNfromHoriz, SbarWidget);
3073 XtSetArg (arg[4], XtNleft, XawChainLeft);
3074 XtSetArg (arg[5], XtNright, XawChainRight);
3075 TextWidget = XtCreateManagedWidget ("text", simpleWidgetClass, BodyWidget,
3078 XtSetArg (arg[0], XtNborderWidth, 0);
3079 XtSetArg (arg[1], XtNleft, XawChainLeft);
3080 XtSetArg (arg[2], XtNright, XawChainRight);
3081 XtSetArg (arg[3], XtNresizable, True);
3082 XtSetArg (arg[4], XtNjustify, XtJustifyLeft);
3083 MessageWidget = XtCreateManagedWidget ("message", labelWidgetClass,
3084 TailWidget, arg, 5);
3086 memset (&control, 0, sizeof control);
3087 control.two_dimensional = 1;
3088 control.enable_bidi = 1;
3089 control.anti_alias = 1;
3090 control.min_line_ascent = font_ascent;
3091 control.min_line_descent = font_descent;
3092 control.max_line_width = win_width;
3093 control.with_cursor = 1;
3094 control.cursor_width = 2;
3095 control.partial_update = 1;
3096 control.ignore_formatting_char = 1;
3098 memset (&input_status_control, 0, sizeof input_status_control);
3099 input_status_control.enable_bidi = 1;
3101 XtAppAddActions (context, actions, XtNumber (actions));
3102 XtRealizeWidget (ShellWidget);
3104 win = XtWindow (TextWidget);
3106 XtAppMainLoop (context);
3108 if (current_input_context)
3109 minput_destroy_ic (current_input_context);
3110 for (i = 0; i < num_input_methods; i++)
3111 if (input_method_table[i].im)
3112 minput_close_im (input_method_table[i].im);
3113 m17n_object_unref (frame);
3114 m17n_object_unref (mt);
3115 m17n_object_unref (face_xxx_large);
3116 m17n_object_unref (face_box);
3117 m17n_object_unref (face_courier);
3118 m17n_object_unref (face_helvetica);
3119 m17n_object_unref (face_times);
3120 m17n_object_unref (face_dv_ttyogesh);
3121 m17n_object_unref (face_freesans);
3122 m17n_object_unref (face_freeserif);
3123 m17n_object_unref (face_freemono);
3124 m17n_object_unref (face_default_fontset);
3125 m17n_object_unref (face_no_ctl_fontset);
3126 m17n_object_unref (face_input_status);
3127 m17n_object_unref (face_default);
3128 m17n_object_unref (default_face_list);
3129 m17n_object_unref (selection);
3131 XFreeGC (display, mono_gc);
3132 XFreeGC (display, mono_gc_inv);
3133 XFreeGC (display, gc_inv);
3134 XtUninstallTranslations (form);
3135 XtUninstallTranslations (TextWidget);
3136 XtDestroyWidget (ShellWidget);
3137 XtDestroyApplicationContext (context);
3141 free (fontset_name);
3143 free (input_method_table);
3144 free (InputMethodMenus);
3149 #else /* not HAVE_X11_XAW_COMMAND_H */
3152 main (int argc, char **argv)
3155 "Building of this program failed (lack of some header files)\n");
3159 #endif /* not HAVE_X11_XAW_COMMAND_H */
3161 #endif /* not FOR_DOXYGEN */