Call AC_GNU_SOURCE and AM_GNU_GETTEXT_VERSION. Call AC_PROG_LIBTOOL
[m17n/m17n-lib.git] / example / mview.c
1 /* mview.c -- File viewer                               -*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
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.
12
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.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @enpage m17n-view view file
25
26     @section m17n-view-synopsis SYNOPSIS
27
28     m17n-view [ XT-OPTION ...] [ OPTION ... ] [ FILE ]
29
30     @section m17n-view-description DESCRIPTION
31
32     Display FILE on a window.
33
34     If FILE is omitted, the input is taken from standard input.
35
36     XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).
37
38     The following OPTIONs are available.
39
40     <ul>
41
42     <li> -e ENCODING
43
44     ENCODING is the encoding of FILE (defaults to UTF-8).
45
46     <li> -s FONTSIZE
47
48     FONTSIZE is the fontsize in point.  If omitted, it defaults to the
49     size of the default font defined in X resource.
50
51     <li> --version
52
53     Print version number.
54
55     <li> -h, --help
56
57     Print this message.
58
59     </ul>
60 */
61 /***ja
62     @japage m17n-view ¥Õ¥¡¥¤¥ë¤ò¸«¤ë
63
64     @section m17n-view-synopsis SYNOPSIS
65
66     m17n-view [ XT-OPTION ...] [ OPTION ... ] [ FILE ]
67
68     @section m17n-view-description DESCRIPTION
69
70     FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤¹¤ë¡£ 
71
72     FILE ¤¬¾Êά¤µ¤ì¤¿¾ì¹ç¤Ï¡¢É¸½àÆþÎϤ«¤é¤È¤ë¡£ 
73
74     XT-OPTIONs ¤Ï Xt ¤Îɸ½à¤Î°ú¿ô¤Ç¤¢¤ë¡£ (e.g. -fn, -fg). 
75
76     °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ­¤ë¡£ 
77
78     <ul>
79
80     <li> -e ENCODING
81
82     ENCODING ¤Ï FILE ¤Î¥³¡¼¥É·Ï¤Ç¤¢¤ë¡£(¥Ç¥Õ¥©¥ë¥È¤Ï UTF-8) 
83
84     <li> -s FONTSIZE
85
86     FONTSIZE ¤Ï¥Õ¥©¥ó¥È¤ÎÂ礭¤µ¤ò¥Ý¥¤¥ó¥Èñ°Ì¤Ç¼¨¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£¾Êά 
87     ¤µ¤ì¤¿¾ì¹ç¤Ï¡¢X ¤Î¥ê¥½¡¼¥¹¤ÇÄêµÁ¤µ¤ì¤¿¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¤ÎÂ礭¤µ¤È 
88     ¤Ê¤ë¡£
89
90     <li> --version
91
92     ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£
93
94     <li> -h, --help
95
96    ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£ 
97
98     </ul>
99 */
100 #ifndef FOR_DOXYGEN
101
102 #include <stdio.h>
103 #include <stdlib.h>
104
105 #ifdef HAVE_X11_XAW_COMMAND_H
106
107 #include <X11/Intrinsic.h>
108 #include <X11/StringDefs.h>
109 #include <X11/Shell.h>
110
111 #include <m17n-gui.h>
112 #include <m17n-misc.h>
113 #include <m17n-X.h>
114
115 #include <X11/Xaw/Form.h>
116 #include <X11/Xaw/Command.h>
117 #include <X11/Xaw/Viewport.h>
118
119 /* Global m17n variables.  */
120 MFrame *frame;
121 MText *mt;
122 MDrawMetric metric;
123 MDrawControl control;
124
125
126 /* Callback procedure for "quit".  */
127
128 void
129 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
130 {
131   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
132 }
133
134
135 /* Move POS to the next line head in M-text MT whose length is LEN.
136    If POS is already on the last line, set POS to LEN.  */
137
138 #define NEXTLINE(pos, len)                      \
139   do {                                          \
140     pos = mtext_character (mt, pos, len, '\n'); \
141     if (pos < 0)                                \
142       pos = len;                                \
143     else                                        \
144       pos++;                                    \
145   } while (0)
146
147
148 /* Action procedure for expose event.  Redraw partial area of the
149    widget W.  The area is specified in EVENT.  */
150
151 static void
152 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
153 {
154   XExposeEvent *expose = (XExposeEvent *) event;
155   int len = mtext_len (mt);
156   int pos, from, to;
157   int y = 0, yoff = 0;
158   MDrawMetric rect;
159
160   /* We must update the area between the Y-positions expose->y and
161      (expose->y + expose->height).  We ignore X-positions.  */
162
163   /* At first, find the line that occupies the Y-position expose->y.
164      That is the first line to draw.  */
165   to = 0;
166   while (1)
167     {
168       from = to;
169       NEXTLINE (to, len);
170       mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, &rect);
171       if (to == len || y + rect.height > expose->y)
172         break;
173       y += rect.height;
174     }
175   /* The first character to draw is at position FROM.  Remeber the
176      Y-position to start drawing.  */
177   yoff = y - rect.y;
178
179   /* Next, find the line that occupies the Y-position (expose->y +
180      expose->height).  That is the last line to draw.  This time, we
181      enable caching to utilize it in the later drawing.  */
182   y += rect.height;
183   control.disable_caching = 0;
184   while (to < len && y < expose->y + expose->height)
185     {
186       pos = to;
187       NEXTLINE (to, len);
188       mdraw_text_extents (frame, mt, pos, to, &control, NULL, NULL, &rect);
189       y += rect.height;
190     }
191
192   /* It is decided that we must draw from FROM to the previous
193      character of TO.  */
194   mdraw_text_with_control (frame, (MDrawWindow) XtWindow (w),
195                            0, yoff, mt, from, to, &control);
196
197   /* Disable caching again.  */
198   control.disable_caching = 1;
199
200   /* If the widget was vertically enlarged too much, shrink it.  */
201   if (metric.height < expose->y + expose->height)
202     {
203       Arg arg;
204
205       XtSetArg (arg, XtNheight, metric.height);
206       XtSetValues (w, &arg, 0);
207     }
208 }
209
210
211 /* Print the usage of this program (the name is PROG), and exit with
212    EXIT_CODE.  */
213
214 void
215 help_exit (char *prog, int exit_code)
216 {
217   char *p = prog;
218
219   while (*p)
220     if (*p++ == '/')
221       prog = p;
222
223   printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] [ FILE ]\n", prog);
224   printf ("Display FILE on a window.\n");
225   printf ("  If FILE is omitted, the input is taken from standard input.\n");
226   printf ("  XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
227   printf ("The following OPTIONs are available.\n");
228   printf ("  %-13s %s", "-e ENCODING",
229           "ENCODING is the encoding of FILE (defaults to UTF-8).\n");
230   printf ("  %-13s %s", "-s FONTSIZE",
231           "FONTSIZE is the fontsize in point.\n");
232   printf ("\t\tIf omitted, it defaults to the size\n");
233   printf ("\t\tof the default font defined in X resource.\n");
234   printf ("  %-13s %s", "--version", "print version number\n");
235   printf ("  %-13s %s", "-h, --help", "print this message\n");
236   exit (exit_code);
237 }
238
239
240 /* Format MSG by FMT and print the result to the stderr, and exit.  */
241
242 #define FATAL_ERROR(fmt, arg)   \
243   do {                          \
244     fprintf (stderr, fmt, arg); \
245     exit (1);                   \
246   } while (0)
247
248
249 /* Adjust FONTSIZE for the resolution of the screen of widget W.  */
250
251 int
252 adjust_fontsize (Widget w, int fontsize)
253 {
254   Display *display = XtDisplay (w);
255   int screen_number = XScreenNumberOfScreen (XtScreen (w));
256   double pixels = DisplayHeight (display, screen_number);
257   double mm = DisplayHeightMM (display, screen_number);
258
259   return (fontsize * pixels * 25.4 / mm / 100);
260 }
261
262
263 int
264 main (int argc, char **argv)
265 {
266   XtAppContext context;
267   Widget shell, form, quit, viewport, text;
268   String quit_action = "<KeyPress>q: set() notify() unset()";
269   XtActionsRec actions[] = { {"Expose", ExposeProc} };
270   Arg arg[10];
271   int i;
272   int viewport_width, viewport_height;
273   char *coding_name = NULL;
274   FILE *fp = stdin;
275   MSymbol coding;
276   int fontsize = 0;
277
278   /* Open an application context.  */
279   XtSetLanguageProc (NULL, NULL, NULL);
280   shell = XtOpenApplication (&context, "M17NView", NULL, 0, &argc, argv, NULL,
281                              sessionShellWidgetClass, NULL, 0);
282   XtAppAddActions (context, actions, XtNumber (actions));
283
284   /* Parse the remaining command line arguments.  */
285   for (i = 1; i < argc; i++)
286     {
287       if (! strcmp (argv[i], "--help")
288           || ! strcmp (argv[i], "-h"))
289         help_exit (argv[0], 0);
290       else if (! strcmp (argv[i], "--version"))
291         {
292           printf ("m17n-view (m17n library) %s\n", M17NLIB_VERSION_NAME);
293           printf ("Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 AIST, JAPAN\n");
294           exit (0);
295         }
296       else if (! strcmp (argv[i], "-e"))
297         {
298           i++;
299           coding_name = argv[i];
300         }
301       else if (! strcmp (argv[i], "-s"))
302         {
303           double n;
304           i++;
305           n = atof (argv[i]);
306           if (n <= 0)
307             FATAL_ERROR ("Invalid fontsize %s!\n", argv[i]);
308           fontsize = adjust_fontsize (shell, (int) (n * 10));
309         }
310       else if (argv[i][0] != '-')
311         {
312           fp = fopen (argv[i], "r");
313           if (! fp)
314             FATAL_ERROR ("Fail to open the file %s!\n", argv[i]);
315         }
316       else
317         {
318           printf ("Unknown option: %s", argv[i]);
319           help_exit (argv[0], 1);
320         }
321     }
322
323   /* Initialize the m17n library.  */
324   M17N_INIT ();
325   if (merror_code != MERROR_NONE)
326     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library.");
327
328   /* Decide how to decode the input stream.  */
329   if (coding_name)
330     {
331       coding = mconv_resolve_coding (msymbol (coding_name));
332       if (coding == Mnil)
333         FATAL_ERROR ("Invalid coding: %s\n", coding_name);
334     }
335   else
336     coding = Mcoding_utf_8;
337
338   mt = mconv_decode_stream (coding, fp);
339   fclose (fp);
340   if (! mt)
341     FATAL_ERROR ("%s\n", "Fail to decode the input file or stream!");
342
343   {
344     MPlist *param = mplist ();
345     MFace *face = mface ();
346
347     if (fontsize)
348       mface_put_prop (face, Msize, (void *) fontsize);
349     mplist_put (param, Mwidget, shell);
350     mplist_put (param, Mface, face);
351     frame = mframe (param);
352     m17n_object_unref (param);
353     m17n_object_unref (face);
354   }
355
356   /* Create this widget hierarchy.
357      Shell - form -+- quit
358                    |
359                    +- viewport - text  */
360
361   form = XtCreateManagedWidget ("form", formWidgetClass, shell, NULL, 0);
362   XtSetArg (arg[0], XtNleft, XawChainLeft);
363   XtSetArg (arg[1], XtNright, XawChainLeft);
364   XtSetArg (arg[2], XtNtop, XawChainTop);
365   XtSetArg (arg[3], XtNbottom, XawChainTop);
366   XtSetArg (arg[4], XtNaccelerators, XtParseAcceleratorTable (quit_action));
367   quit = XtCreateManagedWidget ("quit", commandWidgetClass, form, arg, 5);
368   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
369
370   viewport_width = (int) mframe_get_prop (frame, Mfont_width) * 80;
371   viewport_height
372     = ((int) mframe_get_prop (frame, Mfont_ascent)
373        + (int) mframe_get_prop (frame, Mfont_descent)) * 24;
374   XtSetArg (arg[0], XtNallowVert, True);
375   XtSetArg (arg[1], XtNforceBars, False);
376   XtSetArg (arg[2], XtNfromVert, quit);
377   XtSetArg (arg[3], XtNtop, XawChainTop);
378   XtSetArg (arg[4], XtNbottom, XawChainBottom);
379   XtSetArg (arg[5], XtNright, XawChainRight);
380   XtSetArg (arg[6], XtNwidth, viewport_width);
381   XtSetArg (arg[7], XtNheight, viewport_height);
382   viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, form,
383                                     arg, 8);
384
385   /* Before creating the text widget, we must calculate the height of
386      the M-text to draw.  */
387   control.two_dimensional = 1;
388   control.enable_bidi = 1;
389   control.disable_caching = 1;
390   control.max_line_width = viewport_width;
391   mdraw_text_extents (frame, mt, 0, mtext_len (mt), &control,
392                       NULL, NULL, &metric);
393
394   {
395     /* Decide the size of the text widget.  */
396     XtSetArg (arg[0], XtNwidth, viewport_width);
397     if (viewport_height > metric.height)
398       /* The outer viewport is tall enough.  */
399       XtSetArg (arg[1], XtNheight, viewport_height);
400     else if (metric.height < 0x8000)
401       /* The M-text height is within the limit of X.  */
402       XtSetArg (arg[1], XtNheight, metric.height);
403     else
404       /* We can't make such a tall widget.  Truncate it.  */
405       XtSetArg (arg[1], XtNheight, 0x7FFF);
406
407     /* We must provide our own expose event handler.  */
408     XtSetArg (arg[2], XtNtranslations,
409               XtParseTranslationTable ((String) "<Expose>: Expose()"));
410     text = XtCreateManagedWidget ("text", simpleWidgetClass, viewport, arg, 3);
411   }
412
413   /* Realize the top widget, and dive into an even loop.  */
414   XtInstallAllAccelerators (form, form);
415   XtRealizeWidget (shell);
416   XtAppMainLoop (context);
417
418   /* Clear away.  */
419   m17n_object_unref (mt);
420   m17n_object_unref (frame);
421   M17N_FINI ();
422
423   exit (0);
424 }
425
426 #else  /* not HAVE_X11_XAW_COMMAND_H */
427
428 int
429 main (int argc, char **argv)
430 {
431   fprintf (stderr,
432            "Building of this program failed (lack of some header files)\n");
433   exit (1);
434 }
435
436 #endif /* not HAVE_X11_XAW_COMMAND_H */
437
438 #endif /* not FOR_DOXYGEN */