(config_command): Set NAME before using it.
[m17n/m17n-lib.git] / example / mview.c
1 /* mview.c -- File viewer                               -*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004, 2005, 2006, 2007
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
104 #ifdef HAVE_X11_XAW_COMMAND_H
105
106 #include <X11/Intrinsic.h>
107 #include <X11/StringDefs.h>
108 #include <X11/Shell.h>
109
110 #include <m17n-gui.h>
111 #include <m17n-misc.h>
112 #include <m17n-X.h>
113
114 #include <X11/Xaw/Form.h>
115 #include <X11/Xaw/Command.h>
116 #include <X11/Xaw/Viewport.h>
117
118 /* Global m17n variables.  */
119 MFrame *frame;
120 MText *mt;
121 MDrawMetric metric;
122 MDrawControl control;
123
124
125 /* Callback procedure for "quit".  */
126
127 void
128 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
129 {
130   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
131 }
132
133
134 /* Move POS to the next line head in M-text MT whose length is LEN.
135    If POS is already on the last line, set POS to LEN.  */
136
137 #define NEXTLINE(pos, len)                      \
138   do {                                          \
139     pos = mtext_character (mt, pos, len, '\n'); \
140     if (pos < 0)                                \
141       pos = len;                                \
142     else                                        \
143       pos++;                                    \
144   } while (0)
145
146
147 /* Action procedure for expose event.  Redraw partial area of the
148    widget W.  The area is specified in EVENT.  */
149
150 static void
151 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
152 {
153   XExposeEvent *expose = (XExposeEvent *) event;
154   int len = mtext_len (mt);
155   int pos, from, to;
156   int y = 0, yoff = 0;
157   MDrawMetric rect;
158
159   /* We must update the area between the Y-positions expose->y and
160      (expose->y + expose->height).  We ignore X-positions.  */
161
162   /* At first, find the line that occupies the Y-position expose->y.
163      That is the first line to draw.  */
164   to = 0;
165   while (1)
166     {
167       from = to;
168       NEXTLINE (to, len);
169       mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, &rect);
170       if (to == len || y + rect.height > expose->y)
171         break;
172       y += rect.height;
173     }
174   /* The first character to draw is at position FROM.  Remeber the
175      Y-position to start drawing.  */
176   yoff = y - rect.y;
177
178   /* Next, find the line that occupies the Y-position (expose->y +
179      expose->height).  That is the last line to draw.  This time, we
180      enable caching to utilize it in the later drawing.  */
181   y += rect.height;
182   control.disable_caching = 0;
183   while (to < len && y < expose->y + expose->height)
184     {
185       pos = to;
186       NEXTLINE (to, len);
187       mdraw_text_extents (frame, mt, pos, to, &control, NULL, NULL, &rect);
188       y += rect.height;
189     }
190
191   /* It is decided that we must draw from FROM to the previous
192      character of TO.  */
193   mdraw_text_with_control (frame, (MDrawWindow) XtWindow (w),
194                            0, yoff, mt, from, to, &control);
195
196   /* Disable caching again.  */
197   control.disable_caching = 1;
198
199   /* If the widget was vertically enlarged too much, shrink it.  */
200   if (metric.height < expose->y + expose->height)
201     {
202       Arg arg;
203
204       XtSetArg (arg, XtNheight, metric.height);
205       XtSetValues (w, &arg, 0);
206     }
207 }
208
209
210 /* Print the usage of this program (the name is PROG), and exit with
211    EXIT_CODE.  */
212
213 void
214 help_exit (char *prog, int exit_code)
215 {
216   char *p = prog;
217
218   while (*p)
219     if (*p++ == '/')
220       prog = p;
221
222   printf ("Usage: %s [ XT-OPTION ...] [ OPTION ...] [ FILE ]\n", prog);
223   printf ("Display FILE on a window.\n");
224   printf ("  If FILE is omitted, the input is taken from standard input.\n");
225   printf ("  XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
226   printf ("The following OPTIONs are available.\n");
227   printf ("  %-13s %s", "-e ENCODING",
228           "ENCODING is the encoding of FILE (defaults to UTF-8).\n");
229   printf ("  %-13s %s", "-s FONTSIZE",
230           "FONTSIZE is the fontsize in point.\n");
231   printf ("\t\tIf omitted, it defaults to the size\n");
232   printf ("\t\tof the default font defined in X resource.\n");
233   printf ("  %-13s %s", "--version", "print version number\n");
234   printf ("  %-13s %s", "-h, --help", "print this message\n");
235   exit (exit_code);
236 }
237
238
239 /* Format MSG by FMT and print the result to the stderr, and exit.  */
240
241 #define FATAL_ERROR(fmt, arg)   \
242   do {                          \
243     fprintf (stderr, fmt, arg); \
244     exit (1);                   \
245   } while (0)
246
247
248 /* Adjust FONTSIZE for the resolution of the screen of widget W.  */
249
250 int
251 adjust_fontsize (Widget w, int fontsize)
252 {
253   Display *display = XtDisplay (w);
254   int screen_number = XScreenNumberOfScreen (XtScreen (w));
255   double pixels = DisplayHeight (display, screen_number);
256   double mm = DisplayHeightMM (display, screen_number);
257
258   return (fontsize * pixels * 25.4 / mm / 100);
259 }
260
261
262 int
263 main (int argc, char **argv)
264 {
265   XtAppContext context;
266   Widget shell, form, quit, viewport, text;
267   String quit_action = "<KeyPress>q: set() notify() unset()";
268   XtActionsRec actions[] = { {"Expose", ExposeProc} };
269   Arg arg[10];
270   int i;
271   int viewport_width, viewport_height;
272   char *coding_name = NULL;
273   FILE *fp = stdin;
274   MSymbol coding;
275   int fontsize = 0;
276
277   /* Open an application context.  */
278   XtSetLanguageProc (NULL, NULL, NULL);
279   shell = XtOpenApplication (&context, "M17NView", NULL, 0, &argc, argv, NULL,
280                              sessionShellWidgetClass, NULL, 0);
281   XtAppAddActions (context, actions, XtNumber (actions));
282
283   /* Parse the remaining command line arguments.  */
284   for (i = 1; i < argc; i++)
285     {
286       if (! strcmp (argv[i], "--help")
287           || ! strcmp (argv[i], "-h"))
288         help_exit (argv[0], 0);
289       else if (! strcmp (argv[i], "--version"))
290         {
291           printf ("m17n-view (m17n library) %s\n", M17NLIB_VERSION_NAME);
292           printf ("Copyright (C) 2003, 2004, 2005, 2006, 2007 AIST, JAPAN\n");
293           exit (0);
294         }
295       else if (! strcmp (argv[i], "-e"))
296         {
297           i++;
298           coding_name = argv[i];
299         }
300       else if (! strcmp (argv[i], "-s"))
301         {
302           double n;
303           i++;
304           n = atof (argv[i]);
305           if (n <= 0)
306             FATAL_ERROR ("Invalid fontsize %s!\n", argv[i]);
307           fontsize = adjust_fontsize (shell, (int) (n * 10));
308         }
309       else if (argv[i][0] != '-')
310         {
311           fp = fopen (argv[i], "r");
312           if (! fp)
313             FATAL_ERROR ("Fail to open the file %s!\n", argv[i]);
314         }
315       else
316         {
317           printf ("Unknown option: %s", argv[i]);
318           help_exit (argv[0], 1);
319         }
320     }
321
322   /* Initialize the m17n library.  */
323   M17N_INIT ();
324   if (merror_code != MERROR_NONE)
325     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library.");
326
327   /* Decide how to decode the input stream.  */
328   if (coding_name)
329     {
330       coding = mconv_resolve_coding (msymbol (coding_name));
331       if (coding == Mnil)
332         FATAL_ERROR ("Invalid coding: %s\n", coding_name);
333     }
334   else
335     coding = Mcoding_utf_8;
336
337   mt = mconv_decode_stream (coding, fp);
338   fclose (fp);
339   if (! mt)
340     FATAL_ERROR ("%s\n", "Fail to decode the input file or stream!");
341
342   {
343     MPlist *param = mplist ();
344     MFace *face = mface ();
345
346     if (fontsize)
347       mface_put_prop (face, Msize, (void *) fontsize);
348     mplist_put (param, Mwidget, shell);
349     mplist_put (param, Mface, face);
350     frame = mframe (param);
351     m17n_object_unref (param);
352     m17n_object_unref (face);
353   }
354
355   /* Create this widget hierarchy.
356      Shell - form -+- quit
357                    |
358                    +- viewport - text  */
359
360   form = XtCreateManagedWidget ("form", formWidgetClass, shell, NULL, 0);
361   XtSetArg (arg[0], XtNleft, XawChainLeft);
362   XtSetArg (arg[1], XtNright, XawChainLeft);
363   XtSetArg (arg[2], XtNtop, XawChainTop);
364   XtSetArg (arg[3], XtNbottom, XawChainTop);
365   XtSetArg (arg[4], XtNaccelerators, XtParseAcceleratorTable (quit_action));
366   quit = XtCreateManagedWidget ("quit", commandWidgetClass, form, arg, 5);
367   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
368
369   viewport_width = (int) mframe_get_prop (frame, Mfont_width) * 80;
370   viewport_height
371     = ((int) mframe_get_prop (frame, Mfont_ascent)
372        + (int) mframe_get_prop (frame, Mfont_descent)) * 24;
373   XtSetArg (arg[0], XtNallowVert, True);
374   XtSetArg (arg[1], XtNforceBars, False);
375   XtSetArg (arg[2], XtNfromVert, quit);
376   XtSetArg (arg[3], XtNtop, XawChainTop);
377   XtSetArg (arg[4], XtNbottom, XawChainBottom);
378   XtSetArg (arg[5], XtNright, XawChainRight);
379   XtSetArg (arg[6], XtNwidth, viewport_width);
380   XtSetArg (arg[7], XtNheight, viewport_height);
381   viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, form,
382                                     arg, 8);
383
384   /* Before creating the text widget, we must calculate the height of
385      the M-text to draw.  */
386   control.two_dimensional = 1;
387   control.enable_bidi = 1;
388   control.disable_caching = 1;
389   control.max_line_width = viewport_width;
390   mdraw_text_extents (frame, mt, 0, mtext_len (mt), &control,
391                       NULL, NULL, &metric);
392
393   {
394     /* Decide the size of the text widget.  */
395     XtSetArg (arg[0], XtNwidth, viewport_width);
396     if (viewport_height > metric.height)
397       /* The outer viewport is tall enough.  */
398       XtSetArg (arg[1], XtNheight, viewport_height);
399     else if (metric.height < 0x8000)
400       /* The M-text height is within the limit of X.  */
401       XtSetArg (arg[1], XtNheight, metric.height);
402     else
403       /* We can't make such a tall widget.  Truncate it.  */
404       XtSetArg (arg[1], XtNheight, 0x7FFF);
405
406     /* We must provide our own expose event handler.  */
407     XtSetArg (arg[2], XtNtranslations,
408               XtParseTranslationTable ((String) "<Expose>: Expose()"));
409     text = XtCreateManagedWidget ("text", simpleWidgetClass, viewport, arg, 3);
410   }
411
412   /* Realize the top widget, and dive into an even loop.  */
413   XtInstallAllAccelerators (form, form);
414   XtRealizeWidget (shell);
415   XtAppMainLoop (context);
416
417   /* Clear away.  */
418   m17n_object_unref (mt);
419   m17n_object_unref (frame);
420   M17N_FINI ();
421
422   exit (0);
423 }
424
425 #else  /* not HAVE_X11_XAW_COMMAND_H */
426
427 int
428 main (int argc, char **argv)
429 {
430   fprintf (stderr,
431            "Building of this program failed (lack of some header files)\n");
432   exit (1);
433 }
434
435 #endif /* not HAVE_X11_XAW_COMMAND_H */
436
437 #endif /* not FOR_DOXYGEN */