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