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