1/*	$NetBSD$	*/
2
3#ifndef SABER
4#ifndef lint
5static char Xrcsid[] = "$XConsortium: Dvi.c,v 1.9 89/12/10 16:12:25 rws Exp $";
6#endif /* lint */
7#endif /* SABER */
8
9/*
10 * Dvi.c - Dvi display widget
11 *
12 */
13
14#define XtStrlen(s)	((s) ? strlen(s) : 0)
15
16  /* The following are defined for the reader's convenience.  Any
17     Xt..Field macro in this code just refers to some field in
18     one of the substructures of the WidgetRec.  */
19
20#include <X11/IntrinsicP.h>
21#include <X11/StringDefs.h>
22#include <X11/Xmu/Converters.h>
23#include <stdio.h>
24#include <ctype.h>
25#include "DviP.h"
26
27/****************************************************************
28 *
29 * Full class record constant
30 *
31 ****************************************************************/
32
33/* Private Data */
34
35static char default_font_map_1[] = "\
36TR	-adobe-times-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
37TI	-adobe-times-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
38TB	-adobe-times-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
39TBI	-adobe-times-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
40CR	-adobe-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
41CI	-adobe-courier-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
42CB	-adobe-courier-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
43CBI	-adobe-courier-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
44";
45static char default_font_map_2[] = "\
46HR	-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
47HI	-adobe-helvetica-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
48HB	-adobe-helvetica-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
49HBI	-adobe-helvetica-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
50";
51static char default_font_map_3[] = "\
52NR	-adobe-new century schoolbook-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
53NI	-adobe-new century schoolbook-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
54NB	-adobe-new century schoolbook-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
55NBI	-adobe-new century schoolbook-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
56S	-adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
57SS	-adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
58";
59
60#define offset(field) XtOffset(DviWidget, field)
61
62#define MY_WIDTH(dw) ((int)(dw->dvi.paperwidth * dw->dvi.scale_factor + .5))
63#define MY_HEIGHT(dw) ((int)(dw->dvi.paperlength * dw->dvi.scale_factor + .5))
64
65static XtResource resources[] = {
66	{(String)XtNfontMap, (String)XtCFontMap, (String)XtRString,
67	 sizeof (char *), offset(dvi.font_map_string),
68	 (String)XtRString, NULL /* set in code */},
69	{(String)XtNforeground, (String)XtCForeground, (String)XtRPixel,
70	 sizeof (unsigned long), offset(dvi.foreground),
71	 (String)XtRString, (XtPointer)"XtDefaultForeground"},
72	{(String)XtNbackground, (String)XtCBackground, (String)XtRPixel,
73	 sizeof (unsigned long), offset(dvi.background),
74	 (String)XtRString, (XtPointer)"XtDefaultBackground"},
75	{(String)XtNpageNumber, (String)XtCPageNumber, (String)XtRInt,
76	 sizeof (int), offset(dvi.requested_page),
77	 (String)XtRString, (XtPointer)"1"},
78	{(String)XtNlastPageNumber, (String)XtCLastPageNumber, (String)XtRInt,
79	 sizeof (int), offset (dvi.last_page),
80	 (String)XtRString, (XtPointer)"0"},
81	{(String)XtNfile, (String)XtCFile, (String)XtRFile,
82	 sizeof (FILE *), offset (dvi.file),
83	 (String)XtRFile, (XtPointer)0},
84	{(String)XtNseek, (String)XtCSeek, (String)XtRBoolean,
85	 sizeof (Boolean), offset(dvi.seek),
86	 (String)XtRString, (XtPointer)"false"},
87	{(String)XtNfont, (String)XtCFont, (String)XtRFontStruct,
88	 sizeof (XFontStruct *), offset(dvi.default_font),
89	 (String)XtRString, (XtPointer)"xtdefaultfont"},
90	{(String)XtNbackingStore, (String)XtCBackingStore, (String)XtRBackingStore,
91	 sizeof (int), offset(dvi.backing_store),
92	 (String)XtRString, (XtPointer)"default"},
93	{(String)XtNnoPolyText, (String)XtCNoPolyText, (String)XtRBoolean,
94	 sizeof (Boolean), offset(dvi.noPolyText),
95	 (String)XtRString, (XtPointer)"false"},
96	{(String)XtNresolution, (String)XtCResolution, (String)XtRInt,
97	 sizeof(int), offset(dvi.default_resolution),
98	 (String)XtRString, (XtPointer)"75"},
99};
100
101#undef offset
102
103static void		ClassInitialize (void);
104static void		ClassPartInitialize(WidgetClass);
105static void		Initialize(Widget, Widget, ArgList, Cardinal *);
106static void		Realize (Widget, XtValueMask *, XSetWindowAttributes *);
107static void		Destroy (Widget);
108static void		Redisplay (Widget, XEvent *, Region);
109static Boolean		SetValues (Widget, Widget, Widget,
110				   ArgList, Cardinal *);
111static Boolean		SetValuesHook (Widget, ArgList, Cardinal *);
112static XtGeometryResult	QueryGeometry (Widget, XtWidgetGeometry *,
113				       XtWidgetGeometry *);
114static void		ShowDvi (DviWidget);
115static void		CloseFile (DviWidget);
116static void		OpenFile (DviWidget);
117static void		FindPage (DviWidget);
118
119static void		SaveToFile (Widget, FILE *);
120
121/* font.c */
122extern void ParseFontMap(DviWidget);
123extern void DestroyFontMap(DviFontMap *);
124extern void ForgetFonts(DviWidget);
125
126/* page.c */
127extern void DestroyFileMap(DviFileMap *);
128extern long SearchPagePosition(DviWidget, int);
129extern void FileSeek(DviWidget, long);
130extern void ForgetPagePositions(DviWidget);
131
132/* parse.c */
133extern int ParseInput(register DviWidget);
134
135DviClassRec dviClassRec = {
136{
137	&widgetClassRec,		/* superclass		  */
138	(String)"Dvi",			/* class_name		  */
139	sizeof(DviRec),			/* size			  */
140	ClassInitialize,		/* class_initialize	  */
141	ClassPartInitialize,		/* class_part_initialize  */
142	FALSE,				/* class_inited		  */
143	Initialize,			/* initialize		  */
144	NULL,				/* initialize_hook	  */
145	Realize,			/* realize		  */
146	NULL,				/* actions		  */
147	0,				/* num_actions		  */
148	resources,			/* resources		  */
149	XtNumber(resources),		/* resource_count	  */
150	NULLQUARK,			/* xrm_class		  */
151	FALSE,				/* compress_motion	  */
152	TRUE,				/* compress_exposure	  */
153	TRUE,				/* compress_enterleave    */
154	FALSE,				/* visible_interest	  */
155	Destroy,			/* destroy		  */
156	NULL,				/* resize		  */
157	Redisplay,			/* expose		  */
158	SetValues,			/* set_values		  */
159	SetValuesHook,			/* set_values_hook	  */
160	NULL,				/* set_values_almost	  */
161	NULL,				/* get_values_hook	  */
162	NULL,				/* accept_focus		  */
163	XtVersion,			/* version		  */
164	NULL,				/* callback_private	  */
165	0,				/* tm_table		  */
166	QueryGeometry,			/* query_geometry	  */
167	NULL,				/* display_accelerator	  */
168	NULL				/* extension		  */
169},{
170	SaveToFile,			/* save    */
171},
172};
173
174WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec;
175
176static void ClassInitialize (void)
177{
178	int len1 = strlen(default_font_map_1);
179	int len2 = strlen(default_font_map_2);
180	int len3 = strlen(default_font_map_3);
181	char *dfm = XtMalloc(len1 + len2 + len3 + 1);
182	char *ptr = dfm;
183	strcpy(ptr, default_font_map_1); ptr += len1;
184	strcpy(ptr, default_font_map_2); ptr += len2;
185	strcpy(ptr, default_font_map_3);
186	resources[0].default_addr = dfm;
187
188	XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
189			NULL, 0 );
190}
191
192/****************************************************************
193 *
194 * Private Procedures
195 *
196 ****************************************************************/
197
198/* ARGSUSED */
199static void Initialize(Widget request, Widget new_wd,
200		       ArgList args, Cardinal *num_args)
201{
202	DviWidget	dw = (DviWidget) new_wd;
203
204	dw->dvi.current_page = 0;
205	dw->dvi.font_map = 0;
206	dw->dvi.cache.index = 0;
207	dw->dvi.text_x_width = 0;
208	dw->dvi.text_device_width = 0;
209	dw->dvi.word_flag = 0;
210	dw->dvi.file = 0;
211	dw->dvi.tmpFile = 0;
212	dw->dvi.state = 0;
213	dw->dvi.readingTmp = 0;
214	dw->dvi.cache.char_index = 0;
215	dw->dvi.cache.font_size = -1;
216	dw->dvi.cache.font_number = -1;
217	dw->dvi.cache.adjustable[0] = 0;
218	dw->dvi.file_map = 0;
219	dw->dvi.fonts = 0;
220	dw->dvi.seek = False;
221	dw->dvi.device_resolution = dw->dvi.default_resolution;
222	dw->dvi.display_resolution = dw->dvi.default_resolution;
223	dw->dvi.paperlength = dw->dvi.default_resolution*11;
224	dw->dvi.paperwidth = (dw->dvi.default_resolution*8
225			      + dw->dvi.default_resolution/2);
226	dw->dvi.scale_factor = 1.0;
227	dw->dvi.sizescale = 1;
228	dw->dvi.line_thickness = -1;
229	dw->dvi.line_width = 1;
230	dw->dvi.fill = DVI_FILL_MAX;
231	dw->dvi.device_font = 0;
232	dw->dvi.device_font_number = -1;
233	dw->dvi.device = 0;
234	dw->dvi.native = 0;
235
236	request = request;	/* unused; suppress compiler warning */
237	args = args;
238	num_args = num_args;
239}
240
241#include "gray1.bm"
242#include "gray2.bm"
243#include "gray3.bm"
244#include "gray4.bm"
245#include "gray5.bm"
246#include "gray6.bm"
247#include "gray7.bm"
248#include "gray8.bm"
249
250static void
251Realize (Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
252{
253	DviWidget	dw = (DviWidget) w;
254	XGCValues	values;
255
256	if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) {
257		attrs->backing_store = dw->dvi.backing_store;
258		*valueMask |= CWBackingStore;
259	}
260	XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent,
261			*valueMask, attrs);
262	values.foreground = dw->dvi.foreground;
263	values.cap_style = CapRound;
264	values.join_style = JoinRound;
265	values.line_width = dw->dvi.line_width;
266	dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w),
267				       GCForeground|GCCapStyle|GCJoinStyle
268				       |GCLineWidth,
269				       &values);
270	dw->dvi.gray[0] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
271					     gray1_bits,
272					     gray1_width, gray1_height);
273	dw->dvi.gray[1] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
274					     gray2_bits,
275					     gray2_width, gray2_height);
276	dw->dvi.gray[2] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
277					     gray3_bits,
278					     gray3_width, gray3_height);
279	dw->dvi.gray[3] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
280					     gray4_bits,
281					     gray4_width, gray4_height);
282	dw->dvi.gray[4] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
283					     gray5_bits,
284					     gray5_width, gray5_height);
285	dw->dvi.gray[5] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
286					     gray6_bits,
287					     gray6_width, gray6_height);
288	dw->dvi.gray[6] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
289					     gray7_bits,
290					     gray7_width, gray7_height);
291	dw->dvi.gray[7] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
292					     gray8_bits,
293					     gray8_width, gray8_height);
294	values.background = dw->dvi.background;
295	values.stipple = dw->dvi.gray[5];
296	dw->dvi.fill_GC = XCreateGC (XtDisplay (w), XtWindow (w),
297				     GCForeground|GCBackground|GCStipple,
298				     &values);
299
300	dw->dvi.fill_type = 9;
301
302	if (dw->dvi.file)
303		OpenFile (dw);
304	ParseFontMap (dw);
305}
306
307static void
308Destroy(Widget w)
309{
310	DviWidget	dw = (DviWidget) w;
311
312	XFreeGC (XtDisplay (w), dw->dvi.normal_GC);
313	XFreeGC (XtDisplay (w), dw->dvi.fill_GC);
314	XFreePixmap (XtDisplay (w), dw->dvi.gray[0]);
315	XFreePixmap (XtDisplay (w), dw->dvi.gray[1]);
316	XFreePixmap (XtDisplay (w), dw->dvi.gray[2]);
317	XFreePixmap (XtDisplay (w), dw->dvi.gray[3]);
318	XFreePixmap (XtDisplay (w), dw->dvi.gray[4]);
319	XFreePixmap (XtDisplay (w), dw->dvi.gray[5]);
320	XFreePixmap (XtDisplay (w), dw->dvi.gray[6]);
321	XFreePixmap (XtDisplay (w), dw->dvi.gray[7]);
322	DestroyFontMap (dw->dvi.font_map);
323	DestroyFileMap (dw->dvi.file_map);
324	device_destroy (dw->dvi.device);
325}
326
327/*
328 * Repaint the widget window
329 */
330
331/* ARGSUSED */
332static void
333Redisplay(Widget w, XEvent *event, Region region)
334{
335	DviWidget	dw = (DviWidget) w;
336	XRectangle	extents;
337
338	XClipBox (region, &extents);
339	dw->dvi.extents.x1 = extents.x;
340	dw->dvi.extents.y1 = extents.y;
341	dw->dvi.extents.x2 = extents.x + extents.width;
342	dw->dvi.extents.y2 = extents.y + extents.height;
343	ShowDvi (dw);
344
345	event = event;		/* unused; suppress compiler warning */
346}
347
348/*
349 * Set specified arguments into widget
350 */
351/* ARGSUSED */
352static Boolean
353SetValues (Widget wcurrent, Widget wrequest, Widget wnew,
354	   ArgList args, Cardinal *num_args)
355{
356	Boolean		redisplay = FALSE;
357	char		*new_map;
358	int		cur, req;
359	DviWidget	current = (DviWidget)wcurrent;
360	DviWidget	request = (DviWidget)wrequest;
361	DviWidget	new_wd = (DviWidget)wnew;
362
363	if (current->dvi.font_map_string != request->dvi.font_map_string) {
364		new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1);
365		if (new_map) {
366			redisplay = TRUE;
367			strcpy (new_map, request->dvi.font_map_string);
368			new_wd->dvi.font_map_string = new_map;
369			if (current->dvi.font_map_string)
370				XtFree (current->dvi.font_map_string);
371			current->dvi.font_map_string = 0;
372			ParseFontMap (new_wd);
373		}
374	}
375
376	req = request->dvi.requested_page;
377	cur = current->dvi.requested_page;
378	if (cur != req) {
379		if (!request->dvi.file)
380		    req = 0;
381		else {
382		    if (req < 1)
383			    req = 1;
384		    if (current->dvi.last_page != 0 &&
385			req > current->dvi.last_page)
386			    req = current->dvi.last_page;
387		}
388		if (cur != req)
389	    	    redisplay = TRUE;
390		new_wd->dvi.requested_page = req;
391		if (current->dvi.last_page == 0 && req > cur)
392			FindPage (new_wd);
393	}
394
395	args = args;		/* unused; suppress compiler warning */
396	num_args = num_args;
397
398	return redisplay;
399}
400
401/*
402 * use the set_values_hook entry to check when
403 * the file is set
404 */
405
406static Boolean
407SetValuesHook (Widget wdw, ArgList args, Cardinal *num_argsp)
408{
409	Cardinal	i;
410	DviWidget	dw = (DviWidget)wdw;
411
412	for (i = 0; i < *num_argsp; i++) {
413		if (!strcmp (args[i].name, XtNfile)) {
414			CloseFile (dw);
415			OpenFile (dw);
416			return TRUE;
417		}
418	}
419	return FALSE;
420}
421
422static void CloseFile (DviWidget dw)
423{
424	if (dw->dvi.tmpFile)
425		fclose (dw->dvi.tmpFile);
426	ForgetPagePositions (dw);
427}
428
429static void OpenFile (DviWidget dw)
430{
431	dw->dvi.tmpFile = 0;
432	if (!dw->dvi.seek)
433		dw->dvi.tmpFile = tmpfile();
434	dw->dvi.requested_page = 1;
435	dw->dvi.last_page = 0;
436}
437
438static XtGeometryResult
439QueryGeometry (Widget w, XtWidgetGeometry *request,
440	       XtWidgetGeometry *geometry_return)
441{
442	XtGeometryResult	ret;
443	DviWidget		dw = (DviWidget) w;
444
445	ret = XtGeometryYes;
446	if (((request->request_mode & CWWidth)
447	     && request->width < MY_WIDTH(dw))
448	    || ((request->request_mode & CWHeight)
449		&& request->height < MY_HEIGHT(dw)))
450		ret = XtGeometryAlmost;
451	geometry_return->width = MY_WIDTH(dw);
452	geometry_return->height = MY_HEIGHT(dw);
453	geometry_return->request_mode = CWWidth|CWHeight;
454	return ret;
455}
456
457void
458SetDevice (DviWidget dw, const char *name)
459{
460	XtWidgetGeometry	request, reply;
461	XtGeometryResult ret;
462
463	ForgetFonts (dw);
464	dw->dvi.device = device_load (name);
465	if (!dw->dvi.device)
466		return;
467	dw->dvi.sizescale = dw->dvi.device->sizescale;
468	dw->dvi.device_resolution = dw->dvi.device->res;
469	dw->dvi.native = dw->dvi.device->X11;
470	dw->dvi.paperlength = dw->dvi.device->paperlength;
471	dw->dvi.paperwidth = dw->dvi.device->paperwidth;
472	if (dw->dvi.native) {
473		dw->dvi.display_resolution = dw->dvi.device_resolution;
474		dw->dvi.scale_factor = 1.0;
475	}
476	else {
477		dw->dvi.display_resolution = dw->dvi.default_resolution;
478		dw->dvi.scale_factor = ((double)dw->dvi.display_resolution
479					/ dw->dvi.device_resolution);
480	}
481	request.request_mode = CWWidth|CWHeight;
482	request.width = MY_WIDTH(dw);
483	request.height = MY_HEIGHT(dw);
484	ret = XtMakeGeometryRequest ((Widget)dw, &request, &reply);
485	if (ret == XtGeometryAlmost
486	    && reply.height >= request.height
487	    && reply.width >= request.width) {
488		request.width = reply.width;
489		request.height = reply.height;
490		XtMakeGeometryRequest ((Widget)dw, &request, &reply);
491	}
492}
493
494static void
495ShowDvi (DviWidget dw)
496{
497	if (!dw->dvi.file) {
498		static char Error[] = "No file selected";
499
500		XSetFont (XtDisplay(dw), dw->dvi.normal_GC,
501			  dw->dvi.default_font->fid);
502		XDrawString (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
503			     20, 20, Error, strlen (Error));
504		return;
505	}
506
507	FindPage (dw);
508
509	dw->dvi.display_enable = 1;
510	ParseInput (dw);
511	if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page)
512		dw->dvi.requested_page = dw->dvi.last_page;
513}
514
515static void
516FindPage (DviWidget dw)
517{
518	int	i;
519	long	file_position;
520
521	if (dw->dvi.requested_page < 1)
522		dw->dvi.requested_page = 1;
523
524	if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page)
525		dw->dvi.requested_page = dw->dvi.last_page;
526
527	file_position = SearchPagePosition (dw, dw->dvi.requested_page);
528	if (file_position != -1) {
529		FileSeek(dw, file_position);
530		dw->dvi.current_page = dw->dvi.requested_page;
531	} else {
532		for (i=dw->dvi.requested_page; i > 0; i--) {
533			file_position = SearchPagePosition (dw, i);
534			if (file_position != -1)
535				break;
536		}
537		if (file_position == -1)
538			file_position = 0;
539		FileSeek (dw, file_position);
540
541		dw->dvi.current_page = i;
542
543		dw->dvi.display_enable = 0;
544		while (dw->dvi.current_page != dw->dvi.requested_page) {
545			dw->dvi.current_page = ParseInput (dw);
546			/*
547			 * at EOF, seek back to the beginning of this page.
548			 */
549			if (!dw->dvi.readingTmp && feof (dw->dvi.file)) {
550				file_position = SearchPagePosition (dw,
551						dw->dvi.current_page);
552				if (file_position != -1)
553					FileSeek (dw, file_position);
554				dw->dvi.requested_page = dw->dvi.current_page;
555				break;
556			}
557		}
558	}
559}
560
561void DviSaveToFile(Widget w, FILE *fp)
562{
563	XtCheckSubclass(w, dviWidgetClass, NULL);
564	(*((DviWidgetClass) XtClass(w))->command_class.save)(w, fp);
565}
566
567static
568void SaveToFile(Widget w, FILE *fp)
569{
570	DviWidget dw = (DviWidget)w;
571	long pos;
572	int c;
573
574	if (dw->dvi.tmpFile) {
575		pos = ftell(dw->dvi.tmpFile);
576		if (dw->dvi.ungot) {
577			pos--;
578			dw->dvi.ungot = 0;
579			/* The ungot character is in the tmpFile, so we don't
580			   want to read it from file. */
581			(void)getc(dw->dvi.file);
582		}
583	}
584	else
585		pos = ftell(dw->dvi.file);
586	FileSeek(dw, 0L);
587	while (DviGetC(dw, &c) != EOF)
588		if (putc(c, fp) == EOF) {
589			/* XXX print error message */
590			break;
591		}
592	FileSeek(dw, pos);
593}
594
595static
596void ClassPartInitialize(WidgetClass widget_class)
597{
598	DviWidgetClass wc = (DviWidgetClass)widget_class;
599	DviWidgetClass super = (DviWidgetClass) wc->core_class.superclass;
600	if (wc->command_class.save == InheritSaveToFile)
601		wc->command_class.save = super->command_class.save;
602}
603
604/*
605Local Variables:
606c-indent-level: 8
607c-continued-statement-offset: 8
608c-brace-offset: -8
609c-argdecl-indent: 8
610c-label-offset: -8
611c-tab-always-indent: nil
612End:
613*/
614