Dvi.c revision 8c7c3c7e
1/*
2
3Copyright (c) 1991  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be included
14in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall
25not be used in advertising or otherwise to promote the sale, use or
26other dealings in this Software without prior written authorization
27from the X Consortium.
28
29*/
30
31
32/*
33 * Dvi.c - Dvi display widget
34 */
35
36#ifdef HAVE_CONFIG_H
37# include "config.h"
38#endif
39
40#define XtStrlen(s)	((s) ? strlen(s) : 0)
41
42  /* The following are defined for the reader's convenience.  Any
43     Xt..Field macro in this code just refers to some field in
44     one of the substructures of the WidgetRec.  */
45
46#include <X11/IntrinsicP.h>
47#include <X11/StringDefs.h>
48#include <X11/Xmu/Converters.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <unistd.h>
52#include <ctype.h>
53#include "DviP.h"
54
55/****************************************************************
56 *
57 * Full class record constant
58 *
59 ****************************************************************/
60
61/* Private Data */
62/* Note: default_font_map was too long a token for some machines...
63 *       therefore it has been split in two and assigned to resources
64 *       in the ClassInitialize routine.
65 */
66static const char *default_font_map_1 =  "\
67R	-*-times-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
68I	-*-times-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\
69B	-*-times-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
70F	-*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\
71TR	-*-times-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
72TI	-*-times-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\
73TB	-*-times-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
74TF	-*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\
75BI	-*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\
76C	-*-courier-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
77CO	-*-courier-medium-o-normal--*-*-*-*-*-*-iso8859-1\n\
78CB	-*-courier-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
79CF	-*-courier-bold-o-normal--*-*-*-*-*-*-iso8859-1\n\
80H	-*-helvetica-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
81HO	-*-helvetica-medium-o-normal--*-*-*-*-*-*-iso8859-1\n\
82HB	-*-helvetica-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
83HF	-*-helvetica-bold-o-normal--*-*-*-*-*-*-iso8859-1\n\
84";
85static const char *default_font_map_2 =  "\
86N	-*-new century schoolbook-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
87NI	-*-new century schoolbook-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\
88NB	-*-new century schoolbook-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
89NF	-*-new century schoolbook-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\
90A	-*-charter-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\
91AI	-*-charter-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\
92AB	-*-charter-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\
93AF	-*-charter-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\
94S	-*-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific\n\
95S2	-*-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific\n\
96";
97
98#define offset(field) XtOffsetOf(DviRec, field)
99
100static XtResource resources[] = {
101	{XtNfontMap, XtCFontMap, XtRString, sizeof (char *),
102	 offset(dvi.font_map_string), XtRString, NULL /* set in code */},
103	{XtNforeground, XtCForeground, XtRPixel, sizeof (unsigned long),
104	 offset(dvi.foreground), XtRString, XtDefaultForeground},
105	{XtNpageNumber, XtCPageNumber, XtRInt, sizeof (int),
106	 offset(dvi.requested_page), XtRImmediate, (XtPointer) 1},
107	{XtNlastPageNumber, XtCLastPageNumber, XtRInt, sizeof (int),
108	 offset (dvi.last_page), XtRImmediate, (XtPointer) 0},
109	{XtNfile, XtCFile, XtRFile, sizeof (FILE *),
110	 offset (dvi.file), XtRFile, (char *) 0},
111	{XtNseek, XtCSeek, XtRBoolean, sizeof (Boolean),
112	 offset(dvi.seek), XtRImmediate, (XtPointer) False},
113	{XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
114	 offset(dvi.default_font), XtRString, XtDefaultFont},
115	{XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
116	 offset(dvi.backing_store), XtRString, "default"},
117	{XtNnoPolyText, XtCNoPolyText, XtRBoolean, sizeof (Boolean),
118	 offset(dvi.noPolyText), XtRImmediate, (XtPointer) False},
119	{XtNscreenResolution, XtCScreenResolution, XtRInt, sizeof (int),
120	 offset(dvi.screen_resolution), XtRImmediate, (XtPointer) 75},
121	{XtNpageWidth, XtCPageWidth, XtRFloat, sizeof (float),
122	 offset(dvi.page_width), XtRString, "8.5"},
123	{XtNpageHeight, XtCPageHeight, XtRFloat, sizeof (float),
124	 offset(dvi.page_height), XtRString, "11"},
125	{XtNsizeScale, XtCSizeScale, XtRInt, sizeof (int),
126	 offset(dvi.size_scale_set), XtRImmediate, (XtPointer) 0},
127};
128
129#undef offset
130
131static void		ClassInitialize(void);
132static void		Initialize(Widget, Widget, ArgList, Cardinal *);
133static void		Realize(Widget, XtValueMask *, XSetWindowAttributes *);
134static void		Destroy(Widget);
135static void		Redisplay(Widget, XEvent *, Region);
136static Boolean		SetValues(Widget, Widget, Widget, ArgList , Cardinal *);
137static Boolean		SetValuesHook(Widget, ArgList, Cardinal	*);
138static XtGeometryResult	QueryGeometry(Widget,
139				      XtWidgetGeometry *, XtWidgetGeometry *);
140static void		RequestDesiredSize(DviWidget);
141static void		ShowDvi(DviWidget);
142static void		CloseFile(DviWidget);
143static void		OpenFile(DviWidget);
144
145#define SuperClass ((SimpleWidgetClass)&simpleClassRec)
146
147DviClassRec dviClassRec = {
148{
149	(WidgetClass) SuperClass,	/* superclass		  */
150	"Dvi",				/* class_name		  */
151	sizeof(DviRec),			/* size			  */
152	ClassInitialize,		/* class_initialize	  */
153	NULL,				/* class_part_initialize  */
154	FALSE,				/* class_inited		  */
155	Initialize,			/* initialize		  */
156	NULL,				/* initialize_hook	  */
157	Realize,			/* realize		  */
158	NULL,				/* actions		  */
159	0,				/* num_actions		  */
160	resources,			/* resources		  */
161	XtNumber(resources),		/* resource_count	  */
162	NULLQUARK,			/* xrm_class		  */
163	FALSE,				/* compress_motion	  */
164	XtExposeCompressMaximal,    	/* compress_exposure	  */
165	TRUE,				/* compress_enterleave    */
166	FALSE,				/* visible_interest	  */
167	Destroy,			/* destroy		  */
168	NULL,				/* resize		  */
169	Redisplay,			/* expose		  */
170	SetValues,			/* set_values		  */
171	SetValuesHook,			/* set_values_hook	  */
172	XtInheritSetValuesAlmost,	/* set_values_almost	  */
173	NULL,				/* get_values_hook	  */
174	NULL,				/* accept_focus		  */
175	XtVersion,			/* version		  */
176	NULL,				/* callback_private	  */
177	NULL,				/* tm_table		  */
178	QueryGeometry,			/* query_geometry	  */
179	XtInheritDisplayAccelerator,	/* display_accelerator	  */
180	NULL,				/* extension		  */
181},  /* CoreClass fields initialization */
182{
183    XtInheritChangeSensitive		/* change_sensitive	*/
184},  /* SimpleClass fields initialization */
185{
186    0,                                     /* field not used    */
187},  /* DviClass fields initialization */
188};
189
190WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec;
191
192static void
193ClassInitialize (void)
194{
195  int len1 = strlen(default_font_map_1);
196  int len2 = strlen(default_font_map_2);
197  char *dfm = XtMalloc(len1 + len2 + 1);
198  char *ptr = dfm;
199  strcpy(ptr, default_font_map_1); ptr += len1;
200  strcpy(ptr, default_font_map_2);
201  resources[0].default_addr = dfm;
202
203  XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
204		 NULL, 0 );
205}
206
207/****************************************************************
208 *
209 * Private Procedures
210 *
211 ****************************************************************/
212
213/* ARGSUSED */
214static void
215Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
216{
217    DviWidget	dw = (DviWidget) new;
218
219    dw->dvi.tmpFile = NULL;
220    dw->dvi.readingTmp = 0;
221    dw->dvi.ungot = 0;
222    dw->dvi.normal_GC = NULL;
223    dw->dvi.file_map = NULL;
224    dw->dvi.fonts = NULL;
225    dw->dvi.font_map = NULL;
226    dw->dvi.current_page = 0;
227    dw->dvi.font_size = 0;
228    dw->dvi.font_number = 0;
229    dw->dvi.device_resolution = 0;
230    dw->dvi.line_width = 0;
231    dw->dvi.line_style = 0;
232    dw->dvi.font = NULL;
233    dw->dvi.display_enable = 0;
234    dw->dvi.scale = 0.0;
235    dw->dvi.state = NULL;
236    dw->dvi.cache.index = 0;
237    dw->dvi.cache.font = NULL;
238    dw->dvi.size_scale = 0;
239    dw->dvi.size_scale_set = 0;
240    RequestDesiredSize (dw);
241}
242
243static void
244Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
245{
246    DviWidget	dw = (DviWidget) w;
247    XGCValues	values;
248
249    if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) {
250	attrs->backing_store = dw->dvi.backing_store;
251	*valueMask |= CWBackingStore;
252    }
253    XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent,
254		    *valueMask, attrs);
255    values.foreground = dw->dvi.foreground;
256    dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w),
257				    GCForeground, &values);
258#ifdef USE_XFT
259    {
260	int		scr;
261	Visual		*visual;
262	Colormap	cmap;
263	XRenderColor	black;
264
265	scr = XScreenNumberOfScreen (dw->core.screen);
266	visual = DefaultVisual (XtDisplay (w), scr);
267	cmap = DefaultColormap (XtDisplay (w), scr);
268	dw->dvi.draw = XftDrawCreate (XtDisplay (w), XtWindow (w),
269				      visual, cmap);
270
271	black.red = black.green = black.blue = 0;
272	black.alpha = 0xffff;
273	XftColorAllocValue (XtDisplay (w), visual, cmap,
274			    &black, &dw->dvi.black);
275	dw->dvi.default_font = XftFontOpenName (XtDisplay (w),
276						scr,
277						"serif-12");
278    }
279#endif
280    if (dw->dvi.file)
281	OpenFile (dw);
282    ParseFontMap (dw);
283}
284
285static void
286Destroy(Widget w)
287{
288	DviWidget	dw = (DviWidget) w;
289
290	XFreeGC (XtDisplay (w), dw->dvi.normal_GC);
291	DestroyFontMap (dw->dvi.font_map);
292	DestroyFileMap (dw->dvi.file_map);
293}
294
295/*
296 * Repaint the widget window
297 */
298
299/* ARGSUSED */
300static void
301Redisplay(Widget w, XEvent *event, Region region)
302{
303	DviWidget	dw = (DviWidget) w;
304#ifndef USE_XFT
305	XRectangle	extents;
306#endif
307
308#ifdef USE_XFT
309	XClearArea (XtDisplay (dw),
310		    XtWindow (dw),
311		    0, 0, 0, 0, False);
312	dw->dvi.extents.x1 = 0;
313	dw->dvi.extents.y1 = 0;
314	dw->dvi.extents.x2 = dw->core.width;
315	dw->dvi.extents.y2 = dw->core.height;
316#else
317	XClipBox (region, &extents);
318	dw->dvi.extents.x1 = extents.x;
319	dw->dvi.extents.y1 = extents.y;
320	dw->dvi.extents.x2 = extents.x + extents.width;
321	dw->dvi.extents.y2 = extents.y + extents.height;
322#endif
323	ShowDvi (dw);
324}
325
326static void
327RequestDesiredSize (DviWidget dw)
328{
329    XtWidgetGeometry	req, rep;
330
331    dw->dvi.desired_width = dw->dvi.page_width *
332				 dw->dvi.screen_resolution;
333    dw->dvi.desired_height = dw->dvi.page_height *
334				  dw->dvi.screen_resolution;
335    req.request_mode = CWWidth|CWHeight;
336    req.width = dw->dvi.desired_width;
337    req.height = dw->dvi.desired_height;
338    XtMakeGeometryRequest ((Widget) dw, &req, &rep);
339}
340
341/*
342 * Set specified arguments into widget
343 */
344/* ARGSUSED */
345static Boolean
346SetValues (Widget wcurrent, Widget wrequest, Widget wnew,
347	   ArgList args, Cardinal *num_args)
348{
349    DviWidget	current = (DviWidget) wcurrent;
350    DviWidget	request = (DviWidget) wrequest;
351    DviWidget	new     = (DviWidget) wnew;
352    Boolean	redisplay = FALSE;
353    char	*new_map;
354    int		cur, req;
355
356    req = request->dvi.requested_page;
357    cur = current->dvi.requested_page;
358    if (cur != req) {
359	    if (req < 1)
360		req = 1;
361	    if (request->dvi.file)
362	    {
363		if (current->dvi.last_page != 0 &&
364		    req > current->dvi.last_page)
365			req = current->dvi.last_page;
366	    }
367	    if (cur != req)
368		redisplay = TRUE;
369	    new->dvi.requested_page = req;
370    }
371
372    if (current->dvi.font_map_string != request->dvi.font_map_string) {
373	    new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1);
374	    if (new_map) {
375		    redisplay = TRUE;
376		    strcpy (new_map, request->dvi.font_map_string);
377		    new->dvi.font_map_string = new_map;
378		    if (current->dvi.font_map_string)
379			    XtFree (current->dvi.font_map_string);
380		    current->dvi.font_map_string = NULL;
381		    ParseFontMap (new);
382	    }
383    }
384    if (current->dvi.screen_resolution != request->dvi.screen_resolution)
385    {
386	ResetFonts (new);
387	new->dvi.line_width = -1;
388    }
389    if (request->dvi.device_resolution)
390	new->dvi.scale = ((double) request->dvi.screen_resolution) /
391			     ((double) request->dvi.device_resolution);
392    if (current->dvi.page_width !=  request->dvi.page_width ||
393	current->dvi.page_height != request->dvi.page_height ||
394	current->dvi.screen_resolution != request->dvi.screen_resolution)
395    {
396	RequestDesiredSize (new);
397	redisplay = TRUE;
398    }
399    return redisplay;
400}
401
402/*
403 * use the set_values_hook entry to check when
404 * the file is set
405 */
406
407static Boolean
408SetValuesHook (Widget widget, ArgList args, Cardinal *num_argsp)
409{
410	DviWidget	dw = (DviWidget) widget;
411	Cardinal	i;
412
413	for (i = 0; i < *num_argsp; i++) {
414		if (!strcmp (args[i].name, XtNfile)) {
415			CloseFile (dw);
416			OpenFile (dw);
417			return TRUE;
418		}
419	}
420	return FALSE;
421}
422
423static void
424CloseFile (DviWidget dw)
425{
426    if (dw->dvi.tmpFile)
427	fclose (dw->dvi.tmpFile);
428    ForgetPagePositions (dw);
429}
430
431static void
432OpenFile (DviWidget dw)
433{
434    dw->dvi.tmpFile = NULL;
435    if (!dw->dvi.seek) {
436	char	tmpName[] = "/tmp/dviXXXXXX";
437
438#ifndef HAS_MKSTEMP
439	mktemp (tmpName);
440	dw->dvi.tmpFile = fopen (tmpName, "w+");
441#else
442	int fd = mkstemp(tmpName);
443	if (fd != -1) {
444	    dw->dvi.tmpFile = fdopen(fd, "w+");
445	    if (dw->dvi.tmpFile == NULL)
446		close(fd);
447	}
448#endif
449	remove (tmpName);
450    }
451    if (dw->dvi.requested_page < 1)
452	dw->dvi.requested_page = 1;
453    dw->dvi.last_page = 0;
454}
455
456static XtGeometryResult
457QueryGeometry (Widget w, XtWidgetGeometry *request,
458	       XtWidgetGeometry *geometry_return)
459{
460	XtGeometryResult	ret;
461	DviWidget		dw = (DviWidget) w;
462
463	ret = XtGeometryYes;
464	if ((int)request->width < dw->dvi.desired_width
465	    || (int)request->height < dw->dvi.desired_height)
466		ret = XtGeometryAlmost;
467	geometry_return->width = dw->dvi.desired_width;
468	geometry_return->height = dw->dvi.desired_height;
469	geometry_return->request_mode = CWWidth|CWHeight;
470	return ret;
471}
472
473void
474SetDeviceResolution (DviWidget dw, int resolution)
475{
476    if (resolution != dw->dvi.device_resolution) {
477	dw->dvi.device_resolution = resolution;
478	dw->dvi.scale = ((double)  dw->dvi.screen_resolution) /
479			((double) resolution);
480    }
481}
482
483static void
484ShowDvi (DviWidget dw)
485{
486	long	file_position;
487
488	if (!dw->dvi.file)
489	  return;
490
491	if (dw->dvi.requested_page < 1)
492		dw->dvi.requested_page = 1;
493
494	if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page)
495		dw->dvi.requested_page = dw->dvi.last_page;
496
497	file_position = SearchPagePosition (dw, dw->dvi.requested_page);
498	if (file_position != -1) {
499		FileSeek(dw, file_position);
500		dw->dvi.current_page = dw->dvi.requested_page;
501	} else {
502		int	i;
503
504		for (i = dw->dvi.requested_page; i > 0; i--) {
505			file_position = SearchPagePosition (dw, i);
506			if (file_position != -1)
507				break;
508		}
509		if (file_position == -1)
510			file_position = 0;
511		FileSeek (dw, file_position);
512
513		dw->dvi.current_page = i;
514
515		dw->dvi.display_enable = 0;
516		while (dw->dvi.current_page != dw->dvi.requested_page) {
517			dw->dvi.current_page = ParseInput (dw);
518			/*
519			 * at EOF, seek back to the beginning of this page.
520			 */
521			if (feof (dw->dvi.file)) {
522				file_position = SearchPagePosition (dw,
523						dw->dvi.current_page);
524				if (file_position != -1)
525					FileSeek (dw, file_position);
526				break;
527			}
528		}
529	}
530
531	dw->dvi.display_enable = 1;
532	ParseInput (dw);
533	if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page)
534		dw->dvi.requested_page = dw->dvi.last_page;
535}
536