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