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