1 /* mview.c -- File viewer				-*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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    Boston, MA 02110-1301 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
QuitProc(Widget w,XtPointer client_data,XtPointer call_data)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
ExposeProc(Widget w,XEvent * event,String * str,Cardinal * num)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
help_exit(char * prog,int exit_code)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
adjust_fontsize(Widget w,int fontsize)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
main(int argc,char ** argv)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, 2009, 2010, 2011, 2012 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
main(int argc,char ** argv)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 */
439