Dvi.c revision f80a6dcd
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	0,				/* 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(request, new, args, num_args)
219	Widget request, new;
220	ArgList args;
221	Cardinal *num_args;
222{
223    DviWidget	dw = (DviWidget) new;
224
225    dw->dvi.tmpFile = 0;
226    dw->dvi.readingTmp = 0;
227    dw->dvi.ungot = 0;
228    dw->dvi.normal_GC = 0;
229    dw->dvi.file_map = 0;
230    dw->dvi.fonts = 0;
231    dw->dvi.font_map = 0;
232    dw->dvi.current_page = 0;
233    dw->dvi.font_size = 0;
234    dw->dvi.font_number = 0;
235    dw->dvi.device_resolution = 0;
236    dw->dvi.line_width = 0;
237    dw->dvi.line_style = 0;
238    dw->dvi.font = 0;
239    dw->dvi.display_enable = 0;
240    dw->dvi.scale = 0.0;
241    dw->dvi.state = 0;
242    dw->dvi.cache.index = 0;
243    dw->dvi.cache.font = 0;
244    dw->dvi.size_scale = 0;
245    dw->dvi.size_scale_set = 0;
246    RequestDesiredSize (dw);
247}
248
249static void
250Realize(w, valueMask, attrs)
251	Widget			w;
252	XtValueMask		*valueMask;
253	XSetWindowAttributes	*attrs;
254{
255    DviWidget	dw = (DviWidget) w;
256    XGCValues	values;
257
258    if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) {
259	attrs->backing_store = dw->dvi.backing_store;
260	*valueMask |= CWBackingStore;
261    }
262    XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent,
263		    *valueMask, attrs);
264    values.foreground = dw->dvi.foreground;
265    dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w),
266				    GCForeground, &values);
267#ifdef USE_XFT
268    {
269	int		scr;
270	Visual		*visual;
271	Colormap	cmap;
272	XRenderColor	black;
273
274	scr = XScreenNumberOfScreen (dw->core.screen);
275	visual = DefaultVisual (XtDisplay (w), scr);
276	cmap = DefaultColormap (XtDisplay (w), scr);
277	dw->dvi.draw = XftDrawCreate (XtDisplay (w), XtWindow (w),
278				      visual, cmap);
279
280	black.red = black.green = black.blue = 0;
281	black.alpha = 0xffff;
282	XftColorAllocValue (XtDisplay (w), visual, cmap,
283			    &black, &dw->dvi.black);
284	dw->dvi.default_font = XftFontOpenName (XtDisplay (w),
285						scr,
286						"serif-12");
287    }
288#endif
289    if (dw->dvi.file)
290	OpenFile (dw);
291    ParseFontMap (dw);
292}
293
294static void
295Destroy(w)
296	Widget w;
297{
298	DviWidget	dw = (DviWidget) w;
299
300	XFreeGC (XtDisplay (w), dw->dvi.normal_GC);
301	DestroyFontMap (dw->dvi.font_map);
302	DestroyFileMap (dw->dvi.file_map);
303}
304
305/*
306 * Repaint the widget window
307 */
308
309/* ARGSUSED */
310static void
311Redisplay(w, event, region)
312	Widget w;
313	XEvent *event;
314	Region region;
315{
316	DviWidget	dw = (DviWidget) w;
317#ifndef USE_XFT
318	XRectangle	extents;
319#endif
320
321#ifdef USE_XFT
322	XClearArea (XtDisplay (dw),
323		    XtWindow (dw),
324		    0, 0, 0, 0, False);
325	dw->dvi.extents.x1 = 0;
326	dw->dvi.extents.y1 = 0;
327	dw->dvi.extents.x2 = dw->core.width;
328	dw->dvi.extents.y2 = dw->core.height;
329#else
330	XClipBox (region, &extents);
331	dw->dvi.extents.x1 = extents.x;
332	dw->dvi.extents.y1 = extents.y;
333	dw->dvi.extents.x2 = extents.x + extents.width;
334	dw->dvi.extents.y2 = extents.y + extents.height;
335#endif
336	ShowDvi (dw);
337}
338
339static void
340RequestDesiredSize (dw)
341    DviWidget	dw;
342{
343    XtWidgetGeometry	req, rep;
344
345    dw->dvi.desired_width = dw->dvi.page_width *
346				 dw->dvi.screen_resolution;
347    dw->dvi.desired_height = dw->dvi.page_height *
348				  dw->dvi.screen_resolution;
349    req.request_mode = CWWidth|CWHeight;
350    req.width = dw->dvi.desired_width;
351    req.height = dw->dvi.desired_height;
352    XtMakeGeometryRequest ((Widget) dw, &req, &rep);
353}
354
355/*
356 * Set specified arguments into widget
357 */
358/* ARGSUSED */
359static Boolean
360SetValues (wcurrent, wrequest, wnew, args, num_args)
361	Widget wcurrent, wrequest, wnew;
362	ArgList args;
363	Cardinal *num_args;
364{
365    DviWidget	current = (DviWidget) wcurrent;
366    DviWidget	request = (DviWidget) wrequest;
367    DviWidget	new     = (DviWidget) wnew;
368    Boolean	redisplay = FALSE;
369    char	*new_map;
370    int		cur, req;
371
372    req = request->dvi.requested_page;
373    cur = current->dvi.requested_page;
374    if (cur != req) {
375	    if (req < 1)
376		req = 1;
377	    if (request->dvi.file)
378	    {
379		if (current->dvi.last_page != 0 &&
380		    req > current->dvi.last_page)
381			req = current->dvi.last_page;
382	    }
383	    if (cur != req)
384		redisplay = TRUE;
385	    new->dvi.requested_page = req;
386    }
387
388    if (current->dvi.font_map_string != request->dvi.font_map_string) {
389	    new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1);
390	    if (new_map) {
391		    redisplay = TRUE;
392		    strcpy (new_map, request->dvi.font_map_string);
393		    new->dvi.font_map_string = new_map;
394		    if (current->dvi.font_map_string)
395			    XtFree (current->dvi.font_map_string);
396		    current->dvi.font_map_string = 0;
397		    ParseFontMap (new);
398	    }
399    }
400    if (current->dvi.screen_resolution != request->dvi.screen_resolution)
401    {
402	ResetFonts (new);
403	new->dvi.line_width = -1;
404    }
405    if (request->dvi.device_resolution)
406	new->dvi.scale = ((double) request->dvi.screen_resolution) /
407			     ((double) request->dvi.device_resolution);
408    if (current->dvi.page_width !=  request->dvi.page_width ||
409	current->dvi.page_height != request->dvi.page_height ||
410	current->dvi.screen_resolution != request->dvi.screen_resolution)
411    {
412	RequestDesiredSize (new);
413	redisplay = TRUE;
414    }
415    return redisplay;
416}
417
418/*
419 * use the set_values_hook entry to check when
420 * the file is set
421 */
422
423static Boolean
424SetValuesHook (widget, args, num_argsp)
425	Widget		widget;
426	ArgList		args;
427	Cardinal	*num_argsp;
428{
429	DviWidget	dw = (DviWidget) widget;
430	Cardinal	i;
431
432	for (i = 0; i < *num_argsp; i++) {
433		if (!strcmp (args[i].name, XtNfile)) {
434			CloseFile (dw);
435			OpenFile (dw);
436			return TRUE;
437		}
438	}
439	return FALSE;
440}
441
442static void
443CloseFile (dw)
444	DviWidget	dw;
445{
446    if (dw->dvi.tmpFile)
447	fclose (dw->dvi.tmpFile);
448    ForgetPagePositions (dw);
449}
450
451static void
452OpenFile (dw)
453	DviWidget	dw;
454{
455    char	tmpName[sizeof ("/tmp/dviXXXXXX")];
456#ifdef HAS_MKSTEMP
457    int fd;
458#endif
459
460    dw->dvi.tmpFile = 0;
461    if (!dw->dvi.seek) {
462	strcpy (tmpName, "/tmp/dviXXXXXX");
463#ifndef HAS_MKSTEMP
464	mktemp (tmpName);
465	dw->dvi.tmpFile = fopen (tmpName, "w+");
466#else
467	fd = mkstemp(tmpName);
468	dw->dvi.tmpFile = fdopen(fd, "w+");
469#endif
470	unlink (tmpName);
471    }
472    if (dw->dvi.requested_page < 1)
473	dw->dvi.requested_page = 1;
474    dw->dvi.last_page = 0;
475}
476
477static XtGeometryResult
478QueryGeometry (w, request, geometry_return)
479	Widget			w;
480	XtWidgetGeometry	*request, *geometry_return;
481{
482	XtGeometryResult	ret;
483	DviWidget		dw = (DviWidget) w;
484
485	ret = XtGeometryYes;
486	if ((int)request->width < dw->dvi.desired_width
487	    || (int)request->height < dw->dvi.desired_height)
488		ret = XtGeometryAlmost;
489	geometry_return->width = dw->dvi.desired_width;
490	geometry_return->height = dw->dvi.desired_height;
491	geometry_return->request_mode = CWWidth|CWHeight;
492	return ret;
493}
494
495void
496SetDeviceResolution (dw, resolution)
497	DviWidget   dw;
498	int	    resolution;
499{
500    if (resolution != dw->dvi.device_resolution) {
501	dw->dvi.device_resolution = resolution;
502	dw->dvi.scale = ((double)  dw->dvi.screen_resolution) /
503			((double) resolution);
504    }
505}
506
507static void
508ShowDvi (dw)
509	DviWidget	dw;
510{
511	int	i;
512	long	file_position;
513
514	if (!dw->dvi.file)
515	  return;
516
517	if (dw->dvi.requested_page < 1)
518		dw->dvi.requested_page = 1;
519
520	if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page)
521		dw->dvi.requested_page = dw->dvi.last_page;
522
523	file_position = SearchPagePosition (dw, dw->dvi.requested_page);
524	if (file_position != -1) {
525		FileSeek(dw, file_position);
526		dw->dvi.current_page = dw->dvi.requested_page;
527	} else {
528		for (i=dw->dvi.requested_page; i > 0; i--) {
529			file_position = SearchPagePosition (dw, i);
530			if (file_position != -1)
531				break;
532		}
533		if (file_position == -1)
534			file_position = 0;
535		FileSeek (dw, file_position);
536
537		dw->dvi.current_page = i;
538
539		dw->dvi.display_enable = 0;
540		while (dw->dvi.current_page != dw->dvi.requested_page) {
541			dw->dvi.current_page = ParseInput (dw);
542			/*
543			 * at EOF, seek back to the begining of this page.
544			 */
545			if (feof (dw->dvi.file)) {
546				file_position = SearchPagePosition (dw,
547						dw->dvi.current_page);
548				if (file_position != -1)
549					FileSeek (dw, file_position);
550				break;
551			}
552		}
553	}
554
555	dw->dvi.display_enable = 1;
556	ParseInput (dw);
557	if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page)
558		dw->dvi.requested_page = dw->dvi.last_page;
559}
560