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