1 /*
2  * Copyright 1991 Massachusetts Institute of Technology
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  M.I.T. makes no representations about the
11  * suitability of this software for any purpose.  It is provided "as is"
12  * without express or implied warranty.
13  *
14  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
16  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  */
22 /*
23  * xditview --
24  *
25  *   Display ditroff output in an X window
26  */
27 
28 #ifndef SABER
29 #ifndef lint
30 static char rcsid[] = "$XConsortium: xditview.c,v 1.17 89/12/10 17:05:08 rws Exp $";
31 #endif /* lint */
32 #endif /* SABER */
33 
34 #include <X11/Xatom.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xos.h>
37 #include <X11/Intrinsic.h>
38 #include <X11/StringDefs.h>
39 #include <X11/Shell.h>
40 #include <X11/Xaw/Paned.h>
41 #include <X11/Xaw/Viewport.h>
42 #include <X11/Xaw/Box.h>
43 #include <X11/Xaw/Command.h>
44 #include <X11/Xaw/Dialog.h>
45 #include <X11/Xaw/Label.h>
46 #include <X11/Xaw/SimpleMenu.h>
47 #include <X11/Xaw/SmeBSB.h>
48 
49 #include <stdlib.h>
50 #include <signal.h>
51 
52 #include "Dvi.h"
53 
54 #include "xdit.bm"
55 #include "xdit_mask.bm"
56 #include "stdio.h"
57 
58 extern FILE *popen();
59 extern void exit();
60 
61 static String fallback_resources[] = {
62 #include "GXditview-ad.h"
63     NULL
64 };
65 
66 static struct app_resources {
67     char *print_command;
68     char *filename;
69 } app_resources;
70 
71 #define offset(field) XtOffset(struct app_resources *, field)
72 
73 /* Application resources. */
74 
75 static XtResource resources[] = {
76   {"printCommand", "PrintCommand", XtRString, sizeof(char*),
77        offset(print_command), XtRString, NULL},
78   {"filename", "Filename", XtRString, sizeof(char*),
79        offset(filename), XtRString, NULL},
80 };
81 
82 #undef offset
83 
84 /* Command line options table.  Only resources are entered here...there is a
85    pass over the remaining options after XtParseCommand is let loose. */
86 
87 static XrmOptionDescRec options[] = {
88 {"-page",	    "*dvi.pageNumber",	    XrmoptionSepArg,	NULL},
89 {"-backingStore",   "*dvi.backingStore",    XrmoptionSepArg,	NULL},
90 {"-resolution",	    "*dvi.resolution",      XrmoptionSepArg,	NULL},
91 {"-printCommand",   ".printCommand",        XrmoptionSepArg,	NULL},
92 {"-filename",       ".filename",            XrmoptionSepArg,	NULL},
93 {"-noPolyText",	    "*dvi.noPolyText",	    XrmoptionNoArg,	"TRUE"},
94 };
95 
96 static char current_print_command[1024];
97 
98 static char	current_file_name[1024];
99 static FILE	*current_file;
100 
101 /*
102  * Report the syntax for calling xditview.
103  */
104 
105 static void
Syntax(call)106 Syntax(call)
107 	char *call;
108 {
109 	(void) printf ("Usage: %s [-fg <color>] [-bg <color>]\n", call);
110 	(void) printf ("       [-bd <color>] [-bw <pixels>] [-help]\n");
111 	(void) printf ("       [-display displayname] [-geometry geom]\n");
112 	(void) printf ("       [-page <page-number>] [-backing <backing-store>]\n");
113 	(void) printf ("       [-resolution <res>] [-print <command>]\n");
114 	(void) printf ("       [-filename <file>] [filename]\n\n");
115 	exit(1);
116 }
117 
118 static void	NewFile (), SetPageNumber ();
119 static Widget	toplevel, paned, viewport, dvi;
120 static Widget	page;
121 static Widget	simpleMenu;
122 
123 static void	NextPage(), PreviousPage(), SelectPage(), OpenFile(), Quit();
124 static void	Print();
125 
126 static struct menuEntry {
127     char    *name;
128     void    (*function)();
129 } menuEntries[] = {
130     {"nextPage",    NextPage},
131     {"previousPage",PreviousPage},
132     {"selectPage",  SelectPage},
133     {"print",	    Print},
134     {"openFile",    OpenFile},
135     {"quit",	    Quit},
136 };
137 
138 static void	NextPageAction(), PreviousPageAction(), SelectPageAction();
139 static void	OpenFileAction(), QuitAction();
140 static void	AcceptAction(), CancelAction();
141 static void	PrintAction();
142 static void	RerasterizeAction();
143 static void     MakePrompt();
144 
145 XtActionsRec xditview_actions[] = {
146     {"NextPage",     NextPageAction},
147     {"PreviousPage", PreviousPageAction},
148     {"SelectPage",   SelectPageAction},
149     {"Print",	     PrintAction},
150     {"OpenFile",     OpenFileAction},
151     {"Rerasterize",  RerasterizeAction},
152     {"Quit",	     QuitAction},
153     {"Accept",	     AcceptAction},
154     {"Cancel",	     CancelAction},
155 };
156 
157 #define MenuNextPage		0
158 #define MenuPreviousPage	1
159 #define MenuSelectPage		2
160 #define MenuPrint		3
161 #define MenuOpenFile		4
162 #define	MenuQuit		5
163 
164 static char	pageLabel[256] = "Page <none>";
165 
main(argc,argv)166 int main(argc, argv)
167     int argc;
168     char **argv;
169 {
170     char	    *file_name = 0;
171     int		    i;
172     static Arg	    labelArgs[] = {
173 			{XtNlabel, (XtArgVal) pageLabel},
174     };
175     XtAppContext    xtcontext;
176     Arg		    topLevelArgs[2];
177     Widget          entry;
178     Arg		    pageNumberArgs[1];
179     int		    page_number;
180 
181     toplevel = XtAppInitialize(&xtcontext, "GXditview",
182 			    options, XtNumber (options),
183  			    &argc, argv, fallback_resources, NULL, 0);
184     if (argc > 2
185 	|| (argc == 2 && (!strcmp(argv[1], "-help")
186 			  || !strcmp(argv[1], "--help"))))
187 	Syntax(argv[0]);
188 
189     XtGetApplicationResources(toplevel, (XtPointer)&app_resources,
190 			      resources, XtNumber(resources),
191 			      NULL, (Cardinal) 0);
192     if (app_resources.print_command)
193 	strcpy(current_print_command, app_resources.print_command);
194 
195     XtAppAddActions(xtcontext, xditview_actions, XtNumber (xditview_actions));
196 
197     XtSetArg (topLevelArgs[0], XtNiconPixmap,
198 	      XCreateBitmapFromData (XtDisplay (toplevel),
199 				     XtScreen(toplevel)->root,
200 				     xdit_bits, xdit_width, xdit_height));
201 
202     XtSetArg (topLevelArgs[1], XtNiconMask,
203 	      XCreateBitmapFromData (XtDisplay (toplevel),
204 				     XtScreen(toplevel)->root,
205 				     xdit_mask_bits,
206 				     xdit_mask_width, xdit_mask_height));
207     XtSetValues (toplevel, topLevelArgs, 2);
208     if (argc > 1)
209 	file_name = argv[1];
210 
211     /*
212      * create the menu and insert the entries
213      */
214     simpleMenu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, toplevel,
215 				    NULL, 0);
216     for (i = 0; i < XtNumber (menuEntries); i++) {
217 	entry = XtCreateManagedWidget(menuEntries[i].name,
218 				      smeBSBObjectClass, simpleMenu,
219 				      NULL, (Cardinal) 0);
220 	XtAddCallback(entry, XtNcallback, menuEntries[i].function, NULL);
221     }
222 
223     paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel,
224 				    NULL, (Cardinal) 0);
225     viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, paned,
226 				     NULL, (Cardinal) 0);
227     dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, viewport, NULL, 0);
228     page = XtCreateManagedWidget ("label", labelWidgetClass, paned,
229 					labelArgs, XtNumber (labelArgs));
230     XtSetArg (pageNumberArgs[0], XtNpageNumber, &page_number);
231     XtGetValues (dvi, pageNumberArgs, 1);
232     if (file_name)
233 	NewFile (file_name);
234     /* NewFile modifies current_file_name, so do this here. */
235     if (app_resources.filename)
236 	strcpy(current_file_name, app_resources.filename);
237     XtRealizeWidget (toplevel);
238     if (file_name)
239 	SetPageNumber (page_number);
240     XtAppMainLoop(xtcontext);
241     return 0;
242 }
243 
244 static void
SetPageNumber(number)245 SetPageNumber (number)
246 {
247     Arg	arg[2];
248     int	actual_number, last_page;
249 
250     XtSetArg (arg[0], XtNpageNumber, number);
251     XtSetValues (dvi, arg, 1);
252     XtSetArg (arg[0], XtNpageNumber, &actual_number);
253     XtSetArg (arg[1], XtNlastPageNumber, &last_page);
254     XtGetValues (dvi, arg, 2);
255     if (actual_number == 0)
256 	sprintf (pageLabel, "Page <none>");
257     else if (last_page > 0)
258 	sprintf (pageLabel, "Page %d of %d", actual_number, last_page);
259     else
260 	sprintf (pageLabel, "Page %d", actual_number);
261     XtSetArg (arg[0], XtNlabel, pageLabel);
262     XtSetValues (page, arg, 1);
263 }
264 
265 static void
SelectPageNumber(number_string)266 SelectPageNumber (number_string)
267 char	*number_string;
268 {
269 	SetPageNumber (atoi(number_string));
270 }
271 
272 static int hadFile = 0;
273 
274 static void
NewFile(name)275 NewFile (name)
276 char	*name;
277 {
278     Arg	    arg[2];
279     char    *n;
280     FILE    *new_file;
281     Boolean seek = 0;
282 
283     if (current_file) {
284 	if (!strcmp (current_file_name, "-"))
285 	    ;
286 	else if (current_file_name[0] == '|')
287 	    pclose (current_file);
288 	else
289 	    fclose (current_file);
290     }
291     if (!strcmp (name, "-"))
292 	new_file = stdin;
293     else if (name[0] == '|')
294 	new_file = popen (name+1, "r");
295     else {
296 	new_file = fopen (name, "r");
297 	seek = 1;
298     }
299     if (!new_file) {
300 	/* XXX display error message */
301 	return;
302     }
303     XtSetArg (arg[0], XtNfile, new_file);
304     XtSetArg (arg[1], XtNseek, seek);
305     XtSetValues (dvi, arg, 2);
306     if (hadFile || name[0] != '-' || name[1] != '\0') {
307 	XtSetArg (arg[0], XtNtitle, name);
308 	if (name[0] != '/' && (n = strrchr (name, '/')))
309 	    n = n + 1;
310 	else
311 	    n = name;
312 	XtSetArg (arg[1], XtNiconName, n);
313 	XtSetValues (toplevel, arg, 2);
314     }
315     hadFile = 1;
316     SelectPageNumber ("1");
317     strcpy (current_file_name, name);
318     current_file = new_file;
319 }
320 
321 static char fileBuf[1024];
322 
323 static void
ResetMenuEntry(entry)324 ResetMenuEntry (entry)
325     Widget  entry;
326 {
327     Arg	arg[1];
328 
329     XtSetArg (arg[0], XtNpopupOnEntry, entry);
330     XtSetValues (XtParent(entry) , arg, (Cardinal) 1);
331 }
332 
333 /*ARGSUSED*/
334 
335 static void
NextPage(entry,name,data)336 NextPage (entry, name, data)
337     Widget  entry;
338     caddr_t name, data;
339 {
340     NextPageAction();
341     ResetMenuEntry (entry);
342 }
343 
344 static void
NextPageAction()345 NextPageAction ()
346 {
347     Arg	args[1];
348     int	number;
349 
350     XtSetArg (args[0], XtNpageNumber, &number);
351     XtGetValues (dvi, args, 1);
352     SetPageNumber (number+1);
353 }
354 
355 /*ARGSUSED*/
356 
357 static void
PreviousPage(entry,name,data)358 PreviousPage (entry, name, data)
359     Widget  entry;
360     caddr_t name, data;
361 {
362     PreviousPageAction ();
363     ResetMenuEntry (entry);
364 }
365 
366 static void
PreviousPageAction()367 PreviousPageAction ()
368 {
369     Arg	args[1];
370     int	number;
371 
372     XtSetArg (args[0], XtNpageNumber, &number);
373     XtGetValues (dvi, args, 1);
374     SetPageNumber (number-1);
375 }
376 
377 /* ARGSUSED */
378 
379 static void
SelectPage(entry,name,data)380 SelectPage (entry, name, data)
381     Widget  entry;
382     caddr_t name, data;
383 {
384     SelectPageAction ();
385     ResetMenuEntry (entry);
386 }
387 
388 static void
SelectPageAction()389 SelectPageAction ()
390 {
391     MakePrompt (toplevel, "Page number", SelectPageNumber, "");
392 }
393 
394 
395 static void
DoPrint(name)396 DoPrint (name)
397     char *name;
398 {
399     FILE *print_file;
400 #ifdef SIGNALRETURNSINT
401     int (*handler)();
402 #else
403     void (*handler)();
404 #endif
405     /* Avoid dieing because of an invalid command. */
406     handler = signal(SIGPIPE, SIG_IGN);
407 
408     print_file = popen(name, "w");
409     if (!print_file)
410 	/* XXX print error message */
411 	return;
412     DviSaveToFile(dvi, print_file);
413     pclose(print_file);
414     signal(SIGPIPE, handler);
415     strcpy(current_print_command, name);
416 }
417 
418 static void
RerasterizeAction()419 RerasterizeAction()
420 {
421     Arg	args[1];
422     int	number;
423 
424     if (current_file_name[0] == 0) {
425 	/* XXX display an error message */
426 	return;
427     }
428     XtSetArg (args[0], XtNpageNumber, &number);
429     XtGetValues (dvi, args, 1);
430     NewFile(current_file_name);
431     SetPageNumber (number);
432 }
433 
434 /* ARGSUSED */
435 
436 static void
Print(entry,name,data)437 Print (entry, name, data)
438     Widget  entry;
439     caddr_t name, data;
440 {
441     PrintAction ();
442     ResetMenuEntry (entry);
443 }
444 
445 static void
PrintAction()446 PrintAction ()
447 {
448     if (current_print_command[0])
449 	strcpy (fileBuf, current_print_command);
450     else
451 	fileBuf[0] = '\0';
452     MakePrompt (toplevel, "Print command:", DoPrint, fileBuf);
453 }
454 
455 
456 /* ARGSUSED */
457 
458 static void
OpenFile(entry,name,data)459 OpenFile (entry, name, data)
460     Widget  entry;
461     caddr_t name, data;
462 {
463     OpenFileAction ();
464     ResetMenuEntry (entry);
465 }
466 
467 static void
OpenFileAction()468 OpenFileAction ()
469 {
470     if (current_file_name[0])
471 	strcpy (fileBuf, current_file_name);
472     else
473 	fileBuf[0] = '\0';
474     MakePrompt (toplevel, "File to open:", NewFile, fileBuf);
475 }
476 
477 /* ARGSUSED */
478 
479 static void
Quit(entry,closure,data)480 Quit (entry, closure, data)
481     Widget  entry;
482     caddr_t closure, data;
483 {
484     QuitAction ();
485 }
486 
487 static void
QuitAction()488 QuitAction ()
489 {
490     exit (0);
491 }
492 
493 Widget	promptShell, promptDialog;
494 void	(*promptfunction)();
495 
496 /* ARGSUSED */
497 static
CancelAction(widget,event,params,num_params)498 void CancelAction (widget, event, params, num_params)
499     Widget	widget;
500     XEvent	*event;
501     String	*params;
502     Cardinal	*num_params;
503 {
504     if (promptShell) {
505 	XtSetKeyboardFocus(toplevel, (Widget) None);
506 	XtDestroyWidget(promptShell);
507 	promptShell = (Widget) 0;
508     }
509 }
510 
511 static
AcceptAction(widget,event,params,num_params)512 void AcceptAction (widget, event, params, num_params)
513     Widget	widget;
514     XEvent	*event;
515     String	*params;
516     Cardinal	*num_params;
517 {
518     (*promptfunction)(XawDialogGetValueString(promptDialog));
519     CancelAction (widget, event, params, num_params);
520 }
521 
522 static void
MakePrompt(centerw,prompt,func,def)523 MakePrompt(centerw, prompt, func, def)
524 Widget	centerw;
525 char *prompt;
526 void (*func)();
527 char	*def;
528 {
529     static Arg dialogArgs[] = {
530 	{XtNlabel, 0},
531 	{XtNvalue, 0},
532     };
533     Arg valueArgs[1];
534     Arg centerArgs[2];
535     Position	source_x, source_y;
536     Position	dest_x, dest_y;
537     Dimension center_width, center_height;
538     Dimension prompt_width, prompt_height;
539     Widget  valueWidget;
540 
541     CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
542     promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass,
543 				      toplevel, NULL, (Cardinal) 0);
544     dialogArgs[0].value = (XtArgVal)prompt;
545     dialogArgs[1].value = (XtArgVal)def;
546     promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass,
547 		    promptShell, dialogArgs, XtNumber (dialogArgs));
548     XawDialogAddButton(promptDialog, "accept", NULL, (caddr_t) 0);
549     XawDialogAddButton(promptDialog, "cancel", NULL, (caddr_t) 0);
550     valueWidget = XtNameToWidget (promptDialog, "value");
551     if (valueWidget) {
552     	XtSetArg (valueArgs[0], XtNresizable, TRUE);
553     	XtSetValues (valueWidget, valueArgs, 1);
554 	/*
555 	 * as resizable isn't set until just above, the
556 	 * default value will be displayed incorrectly.
557 	 * rectify the situation by resetting the values
558 	 */
559         XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs));
560     }
561     XtSetKeyboardFocus (promptDialog, valueWidget);
562     XtSetKeyboardFocus (toplevel, valueWidget);
563     XtRealizeWidget (promptShell);
564     /*
565      * place the widget in the center of the "parent"
566      */
567     XtSetArg (centerArgs[0], XtNwidth, &center_width);
568     XtSetArg (centerArgs[1], XtNheight, &center_height);
569     XtGetValues (centerw, centerArgs, 2);
570     XtSetArg (centerArgs[0], XtNwidth, &prompt_width);
571     XtSetArg (centerArgs[1], XtNheight, &prompt_height);
572     XtGetValues (promptShell, centerArgs, 2);
573     source_x = (center_width - prompt_width) / 2;
574     source_y = (center_height - prompt_height) / 3;
575     XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y);
576     XtSetArg (centerArgs[0], XtNx, dest_x);
577     XtSetArg (centerArgs[1], XtNy, dest_y);
578     XtSetValues (promptShell, centerArgs, 2);
579     XtMapWidget(promptShell);
580     promptfunction = func;
581 }
582 
583 /* For DviChar.c */
584 
xmalloc(n)585 char *xmalloc(n)
586     int n;
587 {
588     return XtMalloc(n);
589 }
590 
591 /*
592 Local Variables:
593 c-indent-level: 4
594 c-continued-statement-offset: 4
595 c-brace-offset: -4
596 c-argdecl-indent: 4
597 c-label-offset: -4
598 c-tab-always-indent: nil
599 End:
600 */
601