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