xditview.c revision 65912f00
1/* $XConsortium: xditview.c,v 1.32 94/04/17 20:43:36 eswu Exp $ */
2/*
3
4Copyright (c) 1991  X Consortium
5
6Permission is hereby granted, free of charge, to any person obtaining
7a copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sublicense, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice shall be included
15in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
21OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of the X Consortium shall
26not be used in advertising or otherwise to promote the sale, use or
27other dealings in this Software without prior written authorization
28from the X Consortium.
29
30*/
31/* $XFree86: xc/programs/xditview/xditview.c,v 1.4tsi Exp $ */
32/*
33 * xditview --
34 *
35 *   Display ditroff output in an X window
36 */
37
38#include <X11/Intrinsic.h>
39#include <X11/StringDefs.h>
40#include <X11/Xatom.h>
41#include <X11/Shell.h>
42#include <X11/Xos.h>		/* rindex declaration */
43#include <X11/Xaw/Paned.h>
44#include <X11/Xaw/Panner.h>
45#include <X11/Xaw/Porthole.h>
46#include <X11/Xaw/Viewport.h>
47#include <X11/Xaw/Box.h>
48#include <X11/Xaw/Command.h>
49#include <X11/Xaw/Dialog.h>
50#include <X11/Xaw/Label.h>
51#include <X11/Xaw/MenuButton.h>
52#include <X11/Xaw/SimpleMenu.h>
53#include <X11/Xaw/SmeBSB.h>
54#include <X11/Xaw/AsciiText.h>
55
56#include "Dvi.h"
57
58#include "xdit.bm"
59#include "xdit_mask.bm"
60#include <stdio.h>
61#include <stdlib.h>
62
63/* Command line options table.  Only resources are entered here...there is a
64   pass over the remaining options after XtParseCommand is let loose. */
65
66static XrmOptionDescRec options[] = {
67{"-page",	    "*dvi.pageNumber",	    XrmoptionSepArg,	NULL},
68{"-backingStore",   "*dvi.backingStore",    XrmoptionSepArg,	NULL},
69{"-noPolyText",	    "*dvi.noPolyText",	    XrmoptionNoArg,	"TRUE"},
70{"-resolution",	    "*dvi.screenResolution",XrmoptionSepArg,    NULL},
71};
72
73static char	current_file_name[1024];
74static FILE	*current_file;
75
76static void MakePrompt(Widget, char *, void (*)(char *), char *);
77
78/*
79 * Report the syntax for calling xditview.
80 */
81
82static void
83Syntax(char *call)
84{
85	(void) printf ("Usage: %s [-fg <color>] [-bg <color>]\n", call);
86	(void) printf ("       [-bd <color>] [-bw <pixels>] [-help]\n");
87	(void) printf ("       [-display displayname] [-geometry geom]\n");
88	(void) printf ("       [-page <page-number>] [-backing <backing-store>]\n");
89	(void) printf ("       [-resolution <screen-resolution>]\n\n");
90	exit(1);
91}
92
93static void	NewResolution (char *resString);
94static void	NewFile (char *name);
95static void	DisplayPageNumber (void);
96static void	VisitFile (char *name, Boolean resetPage);
97static Widget	toplevel, paned, porthole, dvi;
98#ifdef NOTDEF
99static Widget	form, panner;
100#endif
101static Widget	popupMenu;
102static Widget	menuBar;
103static Widget	fileMenuButton, fileMenu;
104static Widget	pageNumber;
105
106static void	NextPage(Widget entry, XtPointer name, XtPointer data);
107static void	PreviousPage(Widget entry, XtPointer name, XtPointer data);
108static void	SetResolution(Widget entry, XtPointer name, XtPointer data);
109static void	OpenFile(Widget entry, XtPointer name, XtPointer data);
110static void	RevisitFile(Widget entry, XtPointer name, XtPointer data);
111static void	Quit(Widget entry, XtPointer closure, XtPointer data);
112
113struct menuEntry {
114    char    *name;
115    void    (*function)(Widget entry, XtPointer name, XtPointer data);
116};
117
118static struct menuEntry popupMenuEntries[] = {
119    { "nextPage",	    NextPage },
120    { "previousPage",	    PreviousPage },
121    { "setResolution",	    SetResolution },
122    { "openFile",	    OpenFile },
123    { "revisitFile",	    RevisitFile },
124    { "quit",		    Quit }
125};
126
127static struct menuEntry fileMenuEntries[] = {
128    { "openFile",	    OpenFile },
129    { "revisitFile",	    RevisitFile },
130    { "setResolution",	    SetResolution },
131    { "quit",		    Quit }
132};
133
134static void	NextPageAction(Widget, XEvent *, String *, Cardinal *);
135static void	PreviousPageAction(Widget, XEvent *, String *, Cardinal *);
136static void	SetResolutionAction(Widget, XEvent *, String *, Cardinal *);
137static void	OpenFileAction(Widget, XEvent *, String *, Cardinal *);
138static void	RevisitFileAction(Widget, XEvent *, String *, Cardinal *);
139static void	QuitAction(Widget, XEvent *, String *, Cardinal *);
140static void	AcceptAction(Widget, XEvent *, String *, Cardinal *);
141static void	CancelAction(Widget, XEvent *, String *, Cardinal *);
142static void	UpdatePageNumber(Widget, XEvent *, String *, Cardinal *);
143static void	Noop(Widget, XEvent *, String *, Cardinal *);
144
145static XtActionsRec xditview_actions[] = {
146    { "NextPage",	    NextPageAction },
147    { "PreviousPage",	    PreviousPageAction },
148    { "SetResolution",	    SetResolutionAction },
149    { "OpenFile",	    OpenFileAction },
150    { "Quit",		    QuitAction },
151    { "Accept",		    AcceptAction },
152    { "Cancel",		    CancelAction },
153    { "SetPageNumber",	    UpdatePageNumber },
154    { "Noop",		    Noop }
155};
156
157static Atom wm_delete_window;
158
159#ifdef NOTDEF
160/*	Function Name: PannerCallback
161 *	Description: called when the panner has moved.
162 *	Arguments: panner - the panner widget.
163 *                 closure - *** NOT USED ***.
164 *                 report_ptr - the panner record.
165 *	Returns: none.
166 */
167
168/* ARGSUSED */
169static void
170PannerCallback(Widget w, XtPointer closure, XtPointer report_ptr)
171{
172    Arg args[2];
173    XawPannerReport *report = (XawPannerReport *) report_ptr;
174
175    if (!dvi)
176	return;
177    XtSetArg (args[0], XtNx, -report->slider_x);
178    XtSetArg (args[1], XtNy, -report->slider_y);
179
180    XtSetValues(dvi, args, 2);
181}
182
183/*	Function Name: PortholeCallback
184 *	Description: called when the porthole or its child has
185 *                   changed
186 *	Arguments: porthole - the porthole widget.
187 *                 panner_ptr - the panner widget.
188 *                 report_ptr - the porthole record.
189 *	Returns: none.
190 */
191
192/* ARGSUSED */
193static void
194PortholeCallback(Widget w, XtPointer panner_ptr, XtPointer report_ptr)
195{
196    Arg args[10];
197    Cardinal n = 0;
198    XawPannerReport *report = (XawPannerReport *) report_ptr;
199    Widget panner = (Widget) panner_ptr;
200
201    XtSetArg (args[n], XtNsliderX, report->slider_x); n++;
202    XtSetArg (args[n], XtNsliderY, report->slider_y); n++;
203    if (report->changed != (XawPRSliderX | XawPRSliderY)) {
204	XtSetArg (args[n], XtNsliderWidth, report->slider_width); n++;
205	XtSetArg (args[n], XtNsliderHeight, report->slider_height); n++;
206	XtSetArg (args[n], XtNcanvasWidth, report->canvas_width); n++;
207	XtSetArg (args[n], XtNcanvasHeight, report->canvas_height); n++;
208    }
209    XtSetValues (panner, args, n);
210}
211#endif
212
213int
214main(int argc, char **argv)
215{
216    char	    *file_name = NULL;
217    int		    i;
218    XtAppContext    xtcontext;
219    Arg		    topLevelArgs[2];
220    Widget          entry;
221
222    XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
223
224    toplevel = XtAppInitialize(&xtcontext, "Xditview",
225			       options, XtNumber (options),
226			       &argc, argv, NULL, NULL, 0);
227    if (argc > 2)
228	Syntax(argv[0]);
229
230    XtAppAddActions(xtcontext, xditview_actions, XtNumber (xditview_actions));
231    XtOverrideTranslations
232	(toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
233
234    XtSetArg (topLevelArgs[0], XtNiconPixmap,
235	      XCreateBitmapFromData (XtDisplay (toplevel),
236				     XtScreen(toplevel)->root,
237				     (char *) xdit_bits,
238				     xdit_width, xdit_height));
239
240    XtSetArg (topLevelArgs[1], XtNiconMask,
241	      XCreateBitmapFromData (XtDisplay (toplevel),
242				     XtScreen(toplevel)->root,
243				     (char *) xdit_mask_bits,
244				     xdit_mask_width, xdit_mask_height));
245    XtSetValues (toplevel, topLevelArgs, 2);
246    if (argc > 1)
247	file_name = argv[1];
248
249    /*
250     * create the popup menu and insert the entries
251     */
252    popupMenu = XtCreatePopupShell ("popupMenu", simpleMenuWidgetClass, toplevel,
253				    NULL, 0);
254    for (i = 0; i < XtNumber (popupMenuEntries); i++) {
255	entry = XtCreateManagedWidget(popupMenuEntries[i].name,
256				      smeBSBObjectClass, popupMenu,
257				      NULL, (Cardinal) 0);
258	XtAddCallback(entry, XtNcallback, popupMenuEntries[i].function, NULL);
259    }
260
261    paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel,
262				    NULL, (Cardinal) 0);
263    menuBar = XtCreateManagedWidget ("menuBar", boxWidgetClass, paned, NULL, 0);
264
265    fileMenuButton = XtCreateManagedWidget ("fileMenuButton", menuButtonWidgetClass,
266				    menuBar, NULL, (Cardinal) 0);
267    fileMenu = XtCreatePopupShell ("fileMenu", simpleMenuWidgetClass,
268				    fileMenuButton, NULL, (Cardinal) 0);
269    for (i = 0; i < XtNumber (fileMenuEntries); i++) {
270	entry = XtCreateManagedWidget(fileMenuEntries[i].name,
271				      smeBSBObjectClass, fileMenu,
272				      NULL, (Cardinal) 0);
273	XtAddCallback (entry, XtNcallback, fileMenuEntries[i].function, NULL);
274    }
275
276    (void) XtCreateManagedWidget ("prevButton", commandWidgetClass,
277				  menuBar, NULL, (Cardinal) 0);
278
279    pageNumber = XtCreateManagedWidget("pageNumber", asciiTextWidgetClass,
280					menuBar, NULL, (Cardinal) 0);
281
282    (void) XtCreateManagedWidget ("nextButton", commandWidgetClass,
283				  menuBar, NULL, (Cardinal) 0);
284
285#ifdef NOTDEF
286    form = XtCreateManagedWidget ("form", formWidgetClass, paned,
287				    NULL, (Cardinal) 0);
288    panner = XtCreateManagedWidget ("panner", pannerWidgetClass,
289				    form, NULL, 0);
290    porthole = XtCreateManagedWidget ("porthole", portholeWidgetClass,
291				      form, NULL, 0);
292    XtAddCallback(porthole,
293		  XtNreportCallback, PortholeCallback, (XtPointer) panner);
294    XtAddCallback(panner,
295		  XtNreportCallback, PannerCallback, (XtPointer) porthole);
296#else
297    porthole = XtCreateManagedWidget ("viewport", viewportWidgetClass,
298				      paned, NULL, 0);
299#endif
300    dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, porthole, NULL, 0);
301    if (file_name)
302	VisitFile (file_name, FALSE);
303    XtRealizeWidget (toplevel);
304    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
305				   False);
306    (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
307                            &wm_delete_window, 1);
308    XtAppMainLoop(xtcontext);
309
310    return 0;
311}
312
313static void
314DisplayPageNumber (void)
315{
316    Arg	arg[2];
317    int	actual_number, last_page;
318    XawTextBlock    text;
319    int		    length;
320    char	    value[128];
321    char	    *cur;
322
323    XtSetArg (arg[0], XtNpageNumber, &actual_number);
324    XtSetArg (arg[1], XtNlastPageNumber, &last_page);
325    XtGetValues (dvi, arg, 2);
326    if (actual_number == 0)
327	sprintf (value, "<none>");
328    else if (last_page > 0)
329	sprintf (value, "%d of %d", actual_number, last_page);
330    else
331	sprintf (value, "%d", actual_number);
332    text.firstPos = 0;
333    text.length = strlen (value);
334    text.ptr = value;
335    text.format = FMT8BIT;
336    XtSetArg (arg[0], XtNstring, &cur);
337    XtGetValues (XawTextGetSource (pageNumber), arg, 1);
338    length = strlen (cur);
339    XawTextReplace (pageNumber, 0, length, &text);
340}
341
342static void
343SetPageNumber (int number)
344{
345    Arg	arg[1];
346
347    XtSetArg (arg[0], XtNpageNumber, number);
348    XtSetValues (dvi, arg, 1);
349    DisplayPageNumber ();
350}
351
352static void
353UpdatePageNumber (Widget w, XEvent *xev, String *s, Cardinal *c)
354{
355    char    *string;
356    Arg	    arg[1];
357
358    XtSetArg (arg[0], XtNstring, &string);
359    XtGetValues (XawTextGetSource(pageNumber), arg, 1);
360    SetPageNumber (atoi(string));
361}
362
363static void
364NewResolution(char *resString)
365{
366    int	res;
367    Arg	arg[1];
368
369    res = atoi (resString);
370    if (res <= 0)
371	return;
372    XtSetArg (arg[0], XtNscreenResolution, res);
373    XtSetValues (dvi, arg, 1);
374}
375
376static void
377VisitFile (char *name, Boolean resetPage)
378{
379    Arg	    arg[3];
380    char    *n;
381    FILE    *new_file;
382    Boolean seek = 0;
383    int	    i;
384
385    if (current_file) {
386	if (!strcmp (current_file_name, "-"))
387	    ;
388	else if (current_file_name[0] == '|')
389	    pclose (current_file);
390	else
391	    fclose (current_file);
392    }
393    if (!strcmp (name, "-"))
394	new_file = stdin;
395    else if (name[0] == '|')
396	new_file = popen (name+1, "r");
397    else {
398	new_file = fopen (name, "r");
399	seek = 1;
400    }
401    if (!new_file) {
402	/* XXX display error message */
403	return;
404    }
405    i = 0;
406    XtSetArg (arg[i], XtNfile, new_file); i++;
407    XtSetArg (arg[i], XtNseek, seek); i++;
408    if (resetPage) {
409	XtSetArg (arg[i], XtNpageNumber, 1); i++;
410    }
411    XtSetValues (dvi, arg, i);
412    XtSetArg (arg[0], XtNtitle, name);
413    if (name[0] != '/' && (n = rindex (name, '/')))
414	n = n + 1;
415    else
416	n = name;
417    XtSetArg (arg[1], XtNiconName, n);
418    XtSetValues (toplevel, arg, 2);
419    strcpy (current_file_name, name);
420    current_file = new_file;
421    DisplayPageNumber ();
422}
423
424static void
425NewFile (char *name)
426{
427    VisitFile (name, TRUE);
428}
429
430static char fileBuf[1024];
431static char resolutionBuf[1024];
432
433static void
434ResetMenuEntry (Widget entry)
435{
436    Arg	arg[1];
437
438    XtSetArg (arg[0], XtNpopupOnEntry, entry);
439    XtSetValues (XtParent(entry) , arg, (Cardinal) 1);
440}
441
442/*ARGSUSED*/
443static void
444NextPage (Widget entry, XtPointer name, XtPointer data)
445{
446    NextPageAction(entry, NULL, NULL, NULL);
447    ResetMenuEntry (entry);
448}
449
450static void
451NextPageAction (Widget w, XEvent *xev, String *s, Cardinal *c)
452{
453    Arg	args[1];
454    int	number;
455
456    XtSetArg (args[0], XtNpageNumber, &number);
457    XtGetValues (dvi, args, 1);
458    SetPageNumber (number+1);
459}
460
461/*ARGSUSED*/
462static void
463PreviousPage (Widget entry, XtPointer name, XtPointer data)
464{
465    PreviousPageAction (entry, NULL, NULL, NULL);
466    ResetMenuEntry (entry);
467}
468
469static void
470PreviousPageAction (Widget w, XEvent *xev, String *s, Cardinal *c)
471{
472    Arg	args[1];
473    int	number;
474
475    XtSetArg (args[0], XtNpageNumber, &number);
476    XtGetValues (dvi, args, 1);
477    SetPageNumber (number-1);
478}
479
480/*ARGSUSED*/
481static void
482SetResolution (Widget entry, XtPointer name, XtPointer data)
483{
484    SetResolutionAction (entry, NULL, NULL, NULL);
485    ResetMenuEntry (entry);
486}
487
488static void
489SetResolutionAction (Widget w, XEvent *xev, String *s, Cardinal *c)
490{
491    Arg	    args[1];
492    int	    cur;
493
494    XtSetArg (args[0], XtNscreenResolution, &cur);
495    XtGetValues (dvi, args, 1);
496    sprintf (resolutionBuf, "%d", cur);
497    MakePrompt (toplevel, "Screen resolution:", NewResolution, resolutionBuf);
498}
499
500/*ARGSUSED*/
501static void
502OpenFile (Widget entry, XtPointer name, XtPointer data)
503{
504    OpenFileAction (entry, NULL, NULL, NULL);
505    ResetMenuEntry (entry);
506}
507
508static void
509OpenFileAction (Widget w, XEvent *xev, String *s, Cardinal *c)
510{
511    if (current_file_name[0])
512	strcpy (fileBuf, current_file_name);
513    else
514	fileBuf[0] = '\0';
515    MakePrompt (toplevel, "File to open:", NewFile, fileBuf);
516}
517
518/*ARGSUSED*/
519static void
520RevisitFile (Widget entry, XtPointer name, XtPointer data)
521{
522    RevisitFileAction (entry, NULL, NULL, NULL);
523    ResetMenuEntry (entry);
524}
525
526static void
527RevisitFileAction (Widget w, XEvent *xev, String *s, Cardinal *c)
528{
529    if (current_file_name[0])
530	VisitFile (current_file_name, FALSE);
531}
532
533/*ARGSUSED*/
534static void
535Quit (Widget entry, XtPointer closure, XtPointer data)
536{
537    QuitAction (entry, NULL, NULL, NULL);
538}
539
540static void
541QuitAction (Widget w, XEvent *xev, String *s, Cardinal *c)
542{
543    exit (0);
544}
545
546static Widget promptShell, promptDialog;
547static void (*promptfunction)(char *);
548
549/* ARGSUSED */
550static
551void CancelAction (Widget widget, XEvent *event,
552		   String *params, Cardinal *num_params)
553{
554    if (promptShell) {
555	XtSetKeyboardFocus(toplevel, (Widget) None);
556	XtDestroyWidget(promptShell);
557	promptShell = (Widget) 0;
558    }
559}
560
561
562/* ARGSUSED */
563static
564void AcceptAction (Widget widget, XEvent *event,
565		   String *params, Cardinal *num_params)
566{
567    (*promptfunction)(XawDialogGetValueString(promptDialog));
568    CancelAction (widget, event, params, num_params);
569}
570
571static
572void Noop (Widget w, XEvent *xev, String *s, Cardinal *c)
573{
574}
575
576static void
577MakePrompt(Widget centerw, char *prompt, void (*func)(char *), char *def)
578{
579    static Arg dialogArgs[] = {
580	{XtNlabel, (XtArgVal) 0},
581	{XtNvalue, (XtArgVal) 0},
582    };
583    Arg valueArgs[1];
584    Arg centerArgs[2];
585    Position	source_x, source_y;
586    Position	dest_x, dest_y;
587    Dimension center_width, center_height;
588    Dimension prompt_width, prompt_height;
589    Widget  valueWidget;
590
591    CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
592    promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass,
593				      toplevel, NULL, (Cardinal) 0);
594    dialogArgs[0].value = (XtArgVal)prompt;
595    dialogArgs[1].value = (XtArgVal)def;
596    promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass,
597		    promptShell, dialogArgs, XtNumber (dialogArgs));
598    XawDialogAddButton(promptDialog, "accept", NULL, NULL);
599    XawDialogAddButton(promptDialog, "cancel", NULL, NULL);
600    valueWidget = XtNameToWidget (promptDialog, "value");
601    if (valueWidget) {
602    	XtSetArg (valueArgs[0], XtNresizable, TRUE);
603    	XtSetValues (valueWidget, valueArgs, 1);
604	/*
605	 * as resizable isn't set until just above, the
606	 * default value will be displayed incorrectly.
607	 * rectify the situation by resetting the values
608	 */
609        XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs));
610    }
611    XtSetKeyboardFocus (promptDialog, valueWidget);
612    XtSetKeyboardFocus (toplevel, valueWidget);
613    XtRealizeWidget (promptShell);
614    /*
615     * place the widget in the center of the "parent"
616     */
617    XtSetArg (centerArgs[0], XtNwidth, &center_width);
618    XtSetArg (centerArgs[1], XtNheight, &center_height);
619    XtGetValues (centerw, centerArgs, 2);
620    XtSetArg (centerArgs[0], XtNwidth, &prompt_width);
621    XtSetArg (centerArgs[1], XtNheight, &prompt_height);
622    XtGetValues (promptShell, centerArgs, 2);
623    source_x = (int)(center_width - prompt_width) / 2;
624    source_y = (int)(center_height - prompt_height) / 3;
625    XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y);
626    XtSetArg (centerArgs[0], XtNx, dest_x);
627    XtSetArg (centerArgs[1], XtNy, dest_y);
628    XtSetValues (promptShell, centerArgs, 2);
629    XtMapWidget(promptShell);
630    promptfunction = func;
631}
632