1 /*
2 **
3 ** misc.c
4 **
5 ** Copyright (C) 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING.  If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author:   Johannes Plass (plass@thep.physik.uni-mainz.de)
24 **           Department of Physics
25 **           Johannes Gutenberg-University
26 **           Mainz, Germany
27 **
28 **           Jose E. Marchesi (jemarch@gnu.org)
29 **           GNU Project
30 **
31 */
32 /* for canonicalize_file_name: */
33 #define _GNU_SOURCE 1
34 #include "ac_config.h"
35 
36 /*
37  * This code is derived from:
38 */
39 
40 /*
41  * misc.c -- Everything that isn't a callback or action.
42  * Copyright (C) 1992  Timothy O. Theisen
43  *   Author: Tim Theisen           Systems Programmer
44  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
45  *     UUCP: uwvax!tim             University of Wisconsin-Madison
46  *    Phone: (608)262-0438         1210 West Dayton Street
47  *      FAX: (608)262-9777         Madison, WI   53706
48  *
49  * This program is free software; you can redistribute it and/or modify
50  * it under the terms of the GNU General Public License as published by
51  * the Free Software Foundation; either version 3 of the License, or
52  * (at your option) any later version.
53  *
54  * This program is distributed in the hope that it will be useful,
55  * but WITHOUT ANY WARRANTY; without even the implied warranty of
56  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
57  * GNU General Public License for more details.
58  *
59 */
60 
61 /*
62 #define MESSAGES
63 */
64 #include "message.h"
65 
66 #include "config.h"
67 
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <ctype.h>
71 
72 #include "ac_config.h"
73 #include <inttypes.h>
74 
75 #ifndef SEEK_SET
76 #   define SEEK_SET 0
77 #endif
78 
79 #include <gv_signal.h>
80 #ifdef SIGNALRETURNSINT
81 #   define SIGVAL int
82 #else
83 #   define SIGVAL void
84 #endif
85 
86 #define GV_MAXLENGTH 512
87 
88 
89 #   include <sys/types.h>
90 #   include <sys/stat.h>
91 #   include <unistd.h>
92 
93 
94 #include <math.h>
95 
96 #include "paths.h"
97 #include INC_X11(Xos.h)
98 #include INC_X11(Xatom.h)
99 #include INC_X11(Intrinsic.h)
100 #include INC_X11(StringDefs.h)
101 #include INC_X11(Shell.h)
102 #include INC_XAW(Cardinals.h)
103 #include INC_XAW(SimpleMenu.h)
104 #include INC_XAW(SmeBSB.h)
105 #include INC_XAW(SmeLine.h)
106 #include INC_X11(IntrinsicP.h)
107 #include INC_XAW(TextP.h)
108 #include INC_XAW(Scrollbar.h)
109 #include INC_XMU(StdCmap.h)
110 #include "Aaa.h"
111 #include "Button.h"
112 #include "Clip.h"
113 #include "Frame.h"
114 #include "Ghostview.h"
115 #include "Vlist.h"
116 
117 
118 #include "types.h"
119 #include "actions.h"
120 #include "callbacks.h"
121 #include "file.h"
122 #include "ps.h"
123 #include "doc_misc.h"
124 #include "info.h"
125 #include "main_resources.h"
126 #include "main_globals.h"
127 #include "misc.h"
128 #include "note.h"
129 #include "error.h"
130 #include "save.h"
131 #include "widgets_misc.h"
132 
133 #ifndef max
134 #   define max(a, b)	((a) > (b) ? (a) : (b))
135 #endif
136 #ifndef min
137 #   define min(a, b)	((a) < (b) ? (a) : (b))
138 #endif
139 
140 #define UNMAP_CONTROL	(1<<0)
141 #define UNMAP_PAGEVIEW	(1<<1)
142 #define UNMAP_PAGE	(1<<2)
143 #define MAP_CONTROL	(1<<3)
144 #define MAP_PAGEVIEW	(1<<4)
145 #define MAP_PAGE	(1<<5)
146 
147 static Boolean set_new_scale        (void);
148 static Boolean set_new_orientation  (int);
149 static Boolean set_new_pagemedia    (int);
150 static void    layout_ghostview     (void);
151 
152 /*############################################################*/
153 /* misc_drawEyeGuide */
154 /*############################################################*/
155 
156 typedef struct
157 {
158   Widget w;
159   int drawn;
160   int x,y,width,height;
161   XtIntervalId timer;
162 } EyeGuideDataStruct,*EyeGuideData;
163 
164 static void
misc_catchEyeGuideTimer(XtPointer client_data,XtIntervalId * idp _GL_UNUSED)165 misc_catchEyeGuideTimer(XtPointer client_data, XtIntervalId *idp _GL_UNUSED)
166 {
167   EyeGuideData egd = (EyeGuideData) client_data;
168 
169   BEGINMESSAGE(misc_catchEyeGuideTimer)
170   if (egd->timer) misc_drawEyeGuide(egd->w,EYEGUIDE_REMOVE,0,0);
171   ENDMESSAGE(misc_catchEyeGuideTimer)
172 }
173 
174 void
misc_drawEyeGuide(Widget w,int d,int x,int y)175 misc_drawEyeGuide(Widget w, int d, int x, int y)
176 {
177   unsigned long t = (unsigned long) 1000;
178   static EyeGuideData egd = NULL;
179 
180   BEGINMESSAGE(misc_drawEyeGuide)
181   if (!app_res.scrolling_eye_guide) {
182     ENDMESSAGE(misc_drawEyeGuide)
183     return;
184   }
185   if (!egd) {
186     egd = (EyeGuideData) XtMalloc(sizeof(EyeGuideDataStruct));
187     egd->w = w;
188     egd->drawn = 0;
189     egd->timer = (XtIntervalId) 0;
190   }
191   if (d & EYEGUIDE_DRAW) {
192     if (egd->timer) XtRemoveTimeOut(egd->timer);
193     egd->timer = XtAppAddTimeOut(app_con,t,misc_catchEyeGuideTimer,(XtPointer)egd);
194     if (!egd->drawn) {
195       int x_1,y_1,x_2,y_2,nx,ny;
196       Widget clip = XtParent(XtParent(w));
197       INFMESSAGE(drawing)
198       nx = (int)w->core.x + (int) w->core.border_width;
199       ny = (int)w->core.y + (int) w->core.border_width;
200       if (-x>nx) x_1 = -x - nx; else x_1=0;
201       if (-y>ny) y_1 = -y - ny; else y_1=0;
202       x_2 = x_1 + (int)clip->core.width -1;
203       if (-x<nx) x_2 -= nx;
204       if (x_2 > w->core.width) x_2 = w->core.width;
205       y_2 = y_1 + (int)clip->core.height - 1;
206       if (-y<ny) y_2 -= ny;
207       if (y_2 > w->core.height) y_2 = w->core.height;
208       if (x_1==0) x_1 = -1;
209       if (y_1==0) y_1 = -1;
210       egd->x = x_1;
211       egd->y = y_1;
212       egd->width = x_2-x_1;
213       egd->height = y_2-y_1;
214       GhostviewDrawRectangle(w,egd->x,egd->y,egd->width,egd->height);
215       egd->drawn=1;
216     }
217   }
218   if (d & EYEGUIDE_REMOVE) {
219     if (egd->drawn) {
220       INFMESSAGE(removing)
221       GhostviewDrawRectangle(w,egd->x,egd->y,egd->width,egd->height);
222     }
223   }
224   if (d & (EYEGUIDE_REMOVE|EYEGUIDE_RESET)) {
225     if (egd->timer) XtRemoveTimeOut(egd->timer);
226     XtFree((char*)egd);
227     egd = NULL;
228   }
229   ENDMESSAGE(misc_drawEyeGuide)
230 }
231 
232 /*############################################################*/
233 /* misc_savePagePosition */
234 /*############################################################*/
235 
236 static int pagepos_x,pagepos_y,pagepos_saved=0;
237 
238 void
misc_savePagePosition(void)239 misc_savePagePosition(void)
240 {
241   int x,y,psx,psy;
242   BEGINMESSAGE(misc_savePagePosition)
243   x = ((int)viewClip->core.width)/2  - viewControl->core.x - page->core.x;
244   y = ((int)viewClip->core.height)/2 - viewControl->core.y - page->core.y;
245   GhostviewCoordsXtoPS(page,x,y,&psx,&psy);
246   pagepos_x = psx;
247   pagepos_y = psy;
248   pagepos_saved = 1;
249   ENDMESSAGE(misc_savePagePosition)
250 }
251 
252 /*############################################################*/
253 /* misc_restorePagePosition */
254 /*############################################################*/
255 
256 int
misc_restorePagePosition(int * xP,int * yP)257 misc_restorePagePosition(int *xP, int *yP)
258 {
259   BEGINMESSAGE(misc_restorePagePosition)
260   if (pagepos_saved) {
261     *xP = pagepos_x;
262     *yP = pagepos_y;
263     ENDMESSAGE(misc_restorePagePosition)
264     return(1);
265   }
266   ENDMESSAGE(misc_restorePagePosition)
267   return(0);
268 }
269 
270 /*############################################################*/
271 /* misc_restorePagePosition */
272 /*############################################################*/
273 
274 void
misc_resetPagePosition(void)275 misc_resetPagePosition(void)
276 {
277   BEGINMESSAGE(misc_resetPagePosition)
278   pagepos_saved = 0;
279   ENDMESSAGE(misc_resetPagePosition)
280 }
281 
282 /*############################################################*/
283 /* misc_setPageMarker */
284 /*############################################################*/
285 
286 void
misc_setPageMarker(int entry,int kind,XEvent * event,Boolean check_toc)287 misc_setPageMarker(int entry, int kind, XEvent *event, Boolean check_toc)
288   /* kind: 0 = selected, 1 = highlighted , 2 = bring selected in sight*/
289 {
290   int firstvisible, lastvisible;
291   int maxvisible, numentries;
292   Boolean b = False;
293   INFMESSAGE(misc_setPageMarker)
294   if (toc_text && (entry >= 0)) {
295     if (kind == 0 && VlistSelected(newtoc) != entry)
296       VlistChangeSelected(newtoc,entry,XawVlistSet);
297     else if (kind == 1 && VlistHighlighted(newtoc) != entry)
298       VlistChangeHighlighted(newtoc,entry,XawVlistSet);
299     else if (kind == 2) {
300       entry=VlistSelected(newtoc);
301       if (entry<0) return;
302     }
303     firstvisible = VlistGetFirstVisible(newtoc);
304     maxvisible = VlistMaxEntriesVisible(newtoc, newtocClip->core.height);
305     numentries = VlistEntries(newtoc);
306     IIMESSAGE(entry,firstvisible)
307     IIMESSAGE(maxvisible,numentries)
308     if (numentries < maxvisible) {
309       /* check if everything fits */
310       /* this can happen if the window size is increased */
311       if (entry != 0) {
312         VlistSetFirstVisible(newtoc, 0);
313         b = True;
314       }
315     } else if (firstvisible > entry || (entry > 0 && firstvisible >= entry)) {
316       if (entry > 0)
317 	VlistSetFirstVisible(newtoc, entry - 1);
318       else
319 	VlistSetFirstVisible(newtoc, entry);
320       b = True;
321     } else {
322       /* sadly newtoc does not know it's height, so it cannot be told
323        * to made an item visible and we need to trick: */
324       lastvisible = VlistEntryOfPosition(newtoc, newtocClip->core.height);
325       IIMESSAGE(lastvisible,maxvisible)
326       if (entry > firstvisible && entry >= lastvisible) {
327 	int firstentry;
328 	firstentry = entry - (lastvisible - firstvisible - 1); /* make the entry second last */
329 	if (firstentry > numentries - maxvisible) firstentry = numentries - maxvisible; /* avoid empty holes at the end */
330 	if (firstentry < 0) firstentry = 0; /* keep in range */
331 	VlistSetFirstVisible(newtoc, firstentry);
332 	b = True;
333       }
334     }
335     /* if this happened by mouse, we have the information to get the
336      * highlight up to date again: */
337     if (b) {
338       if (event)
339 	{
340 	  entry = VlistEntryOfPosition(newtoc, (int)event->xbutton.y);
341 	  if (entry != VlistHighlighted(newtoc) && check_toc)
342 	    VlistChangeHighlighted(newtoc,entry,XawVlistSet);
343 	}
344     }
345   }
346 }
347 
348 /*------------------------------------------------------------*/
349 /* misc_openFile */
350 /*------------------------------------------------------------*/
351 
352 static String
misc_openFile(String name,FILE ** fpP)353 misc_openFile(String name, FILE **fpP)
354 {
355    char *str,*error=NULL;
356    FILE *fp=NULL;
357 
358    BEGINMESSAGE(misc_openFile)
359 
360    if (!name) name = "";
361    if (strcmp(name, "-")) {
362       INFSMESSAGE(trying to open,name)
363       if (file_fileIsNotUseful(name)) {
364          size_t l;
365          INFMESSAGE(file is not useful)
366          str="Invalid file: %s";
367          l = strlen(str) + strlen(name) + 1;
368          error = XtMalloc(l*sizeof(char));
369          sprintf(error,str,name);
370       }
371       else if ((fp = fopen(name, "r")) == NULL) {
372          INFMESSAGE(failed to open)
373          INFIMESSAGE(error number,errno)
374          error = open_fail_error(errno,GV_ERROR_OPEN_FAIL,name,0);
375       }
376    }
377    if (fpP) *fpP=fp;
378    else if (fp) fclose(fp);
379 
380    ENDMESSAGE(misc_openFile)
381    return(error);
382 }
383 
384 /*############################################################*/
385 /* misc_testFile */
386 /*############################################################*/
387 
388 String
misc_testFile(String name)389 misc_testFile(String name)
390 {
391    char *error;
392    BEGINMESSAGE(misc_testFile)
393    error = misc_openFile(name,NULL);
394    ENDMESSAGE(misc_testFile)
395    return(error);
396 }
397 
398 /*############################################################*/
399 /* misc_changeFile */
400 /*############################################################*/
401 
misc_changeFile(String name)402 String misc_changeFile(String name)
403 {
404   FILE *fp=NULL;
405   String error=NULL;
406   char *p;
407   Boolean b = False;
408 
409   BEGINMESSAGE(misc_changeFile)
410 
411   if (!name) name="";
412   p = XtMalloc((strlen(name)+5)*sizeof(char));
413   strcpy(p,name);
414   if (strcmp(name,"-")) {
415     if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.ps",name);  else b = True;
416     if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.pdf",name); else b = True;
417     if (!b)                            strcpy(p,name);
418     name = canonicalize_file_name(p);
419     if (name)
420 	    p = name;
421   }
422   name = p;
423   INFSMESSAGE(trying to open,name)
424   error = misc_openFile(name,&fp);
425   if (error) {
426     ENDMESSAGE(misc_changeFile)
427     XtFree(name);
428     return(error);
429   }
430 
431   XtFree(gv_filename_old);
432   XtFree(gv_filename_raw);
433   gv_filename_old = gv_filename;
434   if (gv_filename_dsc) {
435     unlink(gv_filename_dsc);
436     XtFree(gv_filename_dsc);
437     gv_filename_dsc=NULL;
438   }
439   if (gv_filename_unc) {
440     unlink(gv_filename_unc);
441     XtFree(gv_filename_unc);
442     gv_filename_unc=NULL;
443   }
444   if (gv_psfile) fclose(gv_psfile);
445 
446   gv_filename = XtNewString(name);
447   gv_filename_raw = XtNewString(name);
448   gv_filename_raw = file_getUsefulName(gv_filename_raw);
449   gv_psfile = fp;
450   if (strcmp(name,"-")) {
451     struct stat sbuf;
452     stat(gv_filename, &sbuf);
453     mtime = sbuf.st_mtime;
454     INFSMESSAGE(new,gv_filename)
455   }
456   XtFree(name);
457   ENDMESSAGE(misc_changeFile)
458   return(error);
459 }
460 
461 /*############################################################*/
462 /* close_file */
463 /*############################################################*/
464 
close_file(FILE * file,String name)465 String close_file(FILE *file, String name)
466 {
467   char *error=NULL;
468 
469   BEGINMESSAGE(close_file)
470   if (file && fclose(file)!=0) {
471     char *error_close_fail     = "Cannot close file %s\n";
472     size_t l;
473     l = strlen(error_close_fail) + strlen(name) + 1;
474     error = XtMalloc(l*sizeof(char));
475     sprintf(error,error_close_fail,name);
476   }
477   ENDMESSAGE(close_file)
478   return(error);
479 }
480 
481 /*############################################################*/
482 /* check_file */
483 /* check if there is a new version of the file */
484 /* returns -1 if no filename or error in checking file */
485 /*          0 if no new version exists */
486 /*          1 if new version exists */
487 /*############################################################*/
488 
489 int
check_file(int mode)490 check_file(int mode)
491 {
492    int status=0;
493    struct stat sbuf;
494    char *tmpname;
495    int  r = -1;
496 
497    BEGINMESSAGE(check_file)
498 
499    if (!gv_filename) {
500       INFMESSAGE(file not useful)
501       ENDMESSAGE(check_file)
502       return(r);
503    }
504    if (!strcmp(gv_filename,"-")) {
505       INFMESSAGE(reading from stdin; nothing to update)
506       ENDMESSAGE(check_file)
507       return(0);
508    }
509 
510 
511    if (1) {
512 
513       INFMESSAGE(checking file date)
514       status = stat(gv_filename, &sbuf);
515       if (!status && mtime != sbuf.st_mtime) {
516          INFMESSAGE(file has changed)
517          ENDMESSAGE(check_file)
518          return(1);
519       }
520    }
521 
522    tmpname=gv_filename;
523    r=status;
524 
525 
526 
527    if (r<0) {
528      char message[GV_MAXLENGTH];
529      if (r != -2) {
530         INFSMESSAGE(cannot access file:,tmpname)
531         sprintf(message,"Unable to access file '%s'\n",tmpname);
532      } else { /* privilege violation */
533         INFSMESSAGE(user not authorized to access file:,tmpname)
534         sprintf(message,"User is not authorized to access file '%s'\n",tmpname);
535      }
536      NotePopupShowMessage(message);
537    }
538    if (gv_filename!=tmpname) XtFree(tmpname);
539    ENDMESSAGE(check_file)
540    return(r);
541 }
542 
543 /*------------------------------------------------------------*/
544 /* render_page */
545 /* Start rendering a new page */
546 /*------------------------------------------------------------*/
547 
548 static void
render_page(Widget gvw)549 render_page(Widget gvw)
550 {
551     int i;
552 
553     BEGINMESSAGE(render_page)
554 
555     if (!gv_filename) { INFMESSAGE(no file) ENDMESSAGE(render_page) return; }
556 
557     INFIMESSAGE(displaying page,current_page)
558 
559     if (toc_text) {
560        Boolean processflag;
561        Boolean idleflag;
562        Boolean noinputflag;
563        INFMESSAGE(toc available)
564        GhostviewState(gvw,&processflag,&idleflag,&noinputflag);
565 #      ifdef MESSAGES
566           if (processflag) {INFMESSAGE(interpreter running)}
567           else             {INFMESSAGE(no interpreter running)}
568           if (idleflag)    {INFMESSAGE(widget is idle)}
569           else             {INFMESSAGE(widget is busy)}
570           if (noinputflag) {INFMESSAGE(interpreter has no input)}
571           else             {INFMESSAGE(interpreter has input)}
572 #      endif
573        /* Check first what the state of the ghostview widget is.
574           Some documents show additional lines between
575           the 'showpage' and the next '%%Page' comment.
576           In this case the 'noinputflag' is 'False' but the additional
577           lines are not really of significance (at least in no document I have
578           encountered).
579           So we ignore this flag and start from scratch only if the widget is
580           busy or if no interpreter is running.
581           Only if 'GV_RESTART_IF_CBUSY' is defined the noinputflag will be
582           considered.
583        */
584 #ifdef GV_RESTART_IF_BUSY /* ###jp### added 1.2.95 */
585        if (processflag && idleflag && noinputflag) {
586 #else
587        if (processflag && idleflag) {
588 #endif
589           INFMESSAGE(displaying next page)
590  	  GhostviewNextPage(gvw);
591        } else {
592           INFMESSAGE(starting new interpreter)
593  	  GhostviewEnableInterpreter(gvw);
594 	  GhostviewSendPS(gvw, gv_psfile, doc->beginprolog,
595 			  doc->lenprolog, False);
596 	  GhostviewSendPS(gvw, gv_psfile, doc->beginsetup,
597 			  doc->lensetup, False);
598        }
599        if (doc->pageorder == DESCEND) i = (doc->numpages - 1) - current_page;
600        else                           i = current_page;
601        GhostviewSendPS(gvw, gv_psfile, doc->pages[i].begin,doc->pages[i].len, False);
602     } else {
603        INFMESSAGE(no toc available)
604        if (!GhostviewIsInterpreterRunning(gvw)) {
605           INFMESSAGE(enabling interpreter for unstructured document)
606           GhostviewEnableInterpreter(gvw);
607        }
608        else if (GhostviewIsInterpreterReady(gvw)) {
609           INFMESSAGE(displaying page of unstructured document)
610           GhostviewNextPage(gvw);
611        }
612        else {
613           INFMESSAGE(interpreter running but not ready)
614           XBell(XtDisplay(gvw), 0);
615        }
616     }
617 
618     if (gvw == page) {
619        if (toc_text) {
620 	 if (show_prevPage) {
621 	   if (current_page == 0) ButtonReset(w_prevPage,NULL,NULL,NULL);
622 	   XtSetSensitive(w_prevPage, current_page != 0);
623 	 }
624 	 if (show_nextPage) {
625 	   if (current_page == doc->numpages-1) ButtonReset(w_nextPage,NULL,NULL,NULL);
626 	   XtSetSensitive(w_nextPage, current_page != doc->numpages-1);
627 	 }
628 	 XtSetSensitive(prevEntry, current_page != 0);
629 	 XtSetSensitive(nextEntry, current_page != doc->numpages-1);
630        }
631        {
632          int n = doc ? doc->nummedia : 0;
633 	 Boolean b = (doc_mediaIsOk(doc,current_page,n) ? True : False);
634 	 XtSetSensitive(pagemediaEntry[n],b);
635        }
636        if (toc_text) {
637 	 INFMESSAGE(marking current_page as current)
638          misc_setPageMarker(current_page,0,NULL,True);
639        }
640     }
641 
642     ENDMESSAGE(render_page)
643 }
644 
645 /*############################################################*/
646 /* show_page */
647 /* This routine is probably the heart of GV */
648 /* It receives requests from the various callbacks and actions, */
649 /* maps them onto three flags (need_layout, need_setup, need_render) */
650 /* and calls the necessary subroutines */
651 /*############################################################*/
652 
653 void
654 show_page(int number, XtPointer data1)
655 {
656    Bool need_layout = False;
657    Bool need_setup  = False;
658    Bool need_render = False;
659    int request=number;
660    int ori_request=number;
661 
662    BEGINMESSAGE(show_page)
663    INFIMESSAGE(received,request)
664 
665    if ( /* check if file has changed */
666         gv_filename &&
667         (request != REQUEST_NEW_FILE) &&
668         (request != REQUEST_REOPEN) &&
669         (request != REQUEST_TOGGLE_RESIZE) &&
670         (request != REQUEST_SETUP)
671       ) {
672       int changed = check_file(CHECK_FILE_DATE);
673       if (changed==1) {
674          INFMESSAGE(file has changed; requesting new file)
675          request = REQUEST_NEW_FILE;
676 	 if (number < NO_CURRENT_PAGE) number = current_page;
677       } else if (changed == -1) {
678          INFMESSAGE(file is not accessible)
679          ENDMESSAGE(show_page)
680          return;
681       }
682    }
683 
684    if (!toc_text && (request==REQUEST_REDISPLAY)) {
685       INFMESSAGE(request to redisplay non DSC file; changing to request for new file)
686       request=REQUEST_NEW_FILE;
687    }
688 
689    if (request >= NO_CURRENT_PAGE) {
690       INFMESSAGE(request for new page)
691       if (GhostviewIsBusy(page)) {
692          INFMESSAGE(busy state)
693          if (toc_text) {
694             number = doc_putPageInRange(doc,number);
695             gv_pending_page_request=number;
696             INFIMESSAGE(will remember,gv_pending_page_request)
697          }
698          ENDMESSAGE(show_page)
699          return;
700       }
701       need_layout = need_setup =
702           set_new_orientation(number)|set_new_pagemedia(number);
703       if (need_layout && !app_res.auto_resize && gv_scales[gv_scale]->scale <= 0)
704           set_new_scale();
705       need_render = True;
706    } else if (request<NO_CURRENT_PAGE) {
707       INFIMESSAGE(analyzing,request)
708       switch (request) {
709       case REQUEST_TOGGLE_RESIZE:
710 		INFMESSAGE(### request for change of resize behaviour)
711 		number=current_page;
712 		need_layout = True;
713 		need_setup  = False;
714 		need_render = False;
715 		break;
716       case REQUEST_REDISPLAY:
717 		INFMESSAGE(### request for redisplay)
718 		number=current_page;
719 		need_layout = False;
720 		need_setup  = False;
721 		need_render = True;
722 		break;
723       case REQUEST_SETUP:
724 		INFMESSAGE(### request for setup)
725 		number=current_page;
726 		need_layout =	set_new_orientation(number)
727 				|set_new_pagemedia(number)
728 				|set_new_scale();
729                 need_setup  = True;
730 		need_render = True;
731 		break;
732       case REQUEST_NEW_SCALE:
733 		INFMESSAGE(### request for new scale)
734 		number=current_page;
735 		need_layout = need_setup = need_render =
736 				set_new_scale();
737                 if (!need_layout) {ENDMESSAGE(show_page) return;}
738                 break;
739       case REQUEST_NEW_PAGEMEDIA:
740 		INFMESSAGE(### request for new pagemedia)
741 		number=current_page;
742 		need_layout = need_setup = need_render =
743 				set_new_pagemedia(number);
744                 if (!need_layout) {ENDMESSAGE(show_page) return;}
745                 break;
746       case REQUEST_NEW_ORIENTATION:
747 		INFMESSAGE(### request for new orientation)
748 		number=current_page;
749 		need_layout = need_setup = need_render =
750 				set_new_orientation(number);
751                 if (!need_layout) {ENDMESSAGE(show_page) return;}
752 		break;
753       case REQUEST_OPTION_CHANGE:
754         {
755 		INFMESSAGE(### request by options menu)
756 		cb_popdownNotePopup((Widget)NULL,(XtPointer)NULL,NULL);
757 		number=current_page;
758 		number = doc_putPageInRange(doc,number);
759 		need_setup = need_layout = need_render =
760 		                set_new_orientation(number) |
761 		                set_new_pagemedia(number)   |
762 		                set_new_scale();
763 		        }
764 		break;
765       case REQUEST_REOPEN:
766       case REQUEST_NEW_FILE:
767 	{
768                 String filename;
769                 String error = NULL;
770                 if (data1) filename = (String) data1;
771                 else       filename = gv_filename;
772 		INFMESSAGE(### request to open or reopen file)
773                 error = misc_changeFile(filename);
774                 if (error) {
775 		   NotePopupShowMessage(error);
776 		   XtFree(error);
777  		   ENDMESSAGE(show_page)
778                    return;
779                 }
780 		if (request==REQUEST_REOPEN) {
781 		   INFMESSAGE(request to reopen file)
782 		   number=current_page;
783 		}
784 		need_layout = setup_ghostview();
785 		number = doc_putPageInRange(doc,number);
786 		need_layout = need_layout
787 				|set_new_orientation(number)
788 				|set_new_pagemedia(number)
789 				|set_new_scale();
790                 need_setup  = True;
791                 need_render = True;
792 		break;
793 	}
794       default:
795 		INFMESSAGE(### unknown request)
796 		fprintf(stderr,"  %s: Unknown request in show_page\n",gv_name);
797 		ENDMESSAGE(show_page)
798 		return;
799       }
800    }
801 
802    if (!gv_psfile && need_render) {
803       INFMESSAGE(no gv_psfile; forcing setup and layout)
804       need_setup=True;
805       need_layout=True;
806    }
807 
808 #  ifdef MESSAGES
809       if (need_layout) {INFMESSAGE(### need layout)} else {INFMESSAGE(### do not layout)}
810       if (need_setup)  {INFMESSAGE(### need setup)}  else {INFMESSAGE(### do not setup)}
811       if (need_render) {INFMESSAGE(### need render)} else {INFMESSAGE(### do not render)}
812 #  endif
813 
814    if (need_layout) layout_ghostview();
815 
816    if (need_setup)  GhostviewSetup(page);
817    if (!gv_filename) {
818       need_render=False;
819       INFMESSAGE(no filename; forcing no render)
820    }
821    if (toc_text) {
822       number = doc_putPageInRange(doc,number);
823       current_page = number;
824    }
825    if (need_render) {
826      render_page(page);
827      misc_drawEyeGuide(page,EYEGUIDE_RESET,0,0);
828      if (ori_request == REQUEST_NEW_FILE && !need_layout)
829        cb_positionPage(page,(XtPointer)NULL,(XtPointer)NULL);
830    }
831 
832    gv_pending_page_request=NO_CURRENT_PAGE; /* eliminate any pending requests now */
833 
834    ENDMESSAGE(show_page)
835 }
836 
837 /*############################################################*/
838 /* setup_ghostview */
839 /* This includes:
840  *  scanning the PostScript file,
841  *  setting the title and date labels,
842  *  building the pagemedia menu,
843  *  building the toc (table of contents)
844  *  sensitizing the appropriate menu buttons,
845  *  popping down and erasing the infotext popup.
846  */
847 /*############################################################*/
848 
849 static void misc_setSensitive(Widget w, Boolean s, Boolean b)
850 {
851   if (s) {
852     if (!b) ButtonReset(w,NULL,NULL,NULL);
853     XtSetSensitive(w,b);
854   }
855 }
856 
857 static void misc_setBitmap(Widget w, Boolean s, Pixmap b)
858 {
859   Arg args[1];
860   if (s) {
861     if (b != None) {
862       XtSetArg(args[0],XtNbitmap,(toc_text ? b :app_res.mark_empty_bitmap));
863       XtSetValues(w,args,(Cardinal)1);
864     }
865   }
866 }
867 
868 Boolean
869 setup_ghostview(void)
870 {
871     Arg args[10];
872     Cardinal n;
873     int oldtoc_entry_length;
874     int toc_length;
875     char *tocp;
876     Pixmap bitmap;
877     String label;
878 
879     BEGINMESSAGE(setup_ghostview)
880     /* Reset to a known state. */
881     psfree(olddoc);
882     olddoc = doc;
883     doc = NULL;
884     current_page = NO_CURRENT_PAGE;
885     XtFree(toc_text);
886     oldtoc_entry_length = toc_entry_length;
887     toc_text = NULL;
888 
889     INFMESSAGE(scanning file for structure information)
890     gv_filename_dsc = gv_filename_unc = NULL;
891     {
892        char* tmp = malloc(1512);
893        char* src = gv_gs_cmd_scan_pdf;
894        char* dest = tmp;
895        int spaceFound = 0;
896 
897        if (strstr(gv_gs_cmd_scan_pdf, "-P") || !gv_gs_safer)
898           strcpy(tmp, gv_gs_cmd_scan_pdf);
899        else
900        {
901           while (*src)
902           {
903              int isSpace = *src == ' ';
904              *(dest++) = *(src++);
905 	     if (!spaceFound && isSpace)
906 	     {
907 	        strcpy(dest, "-P- -dSAFER -dDELAYSAFER ");
908 	        dest+=25;
909 		spaceFound = 1;
910 	     }
911           }
912 	  *dest = 0;
913        }
914 
915        doc_scanFile( &gv_psfile,&doc,
916 		  gv_filename,
917 		  gv_filename_raw,
918 		  &gv_filename_dsc,tmp,
919 		  &gv_filename_unc,gv_uncompress_command,
920 		  gv_scanstyle, gv_gs_safeDir);
921 
922        free(tmp);
923     }
924     {
925       int m;
926       m = gv_pagemedia;
927       if (olddoc && olddoc->nummedia && m >= 0) {
928 	if (m >= olddoc->nummedia) m = m - olddoc->nummedia;
929 	else                       m = MEDIA_ID_INVALID;
930       }
931       if (doc && doc->nummedia && m >= 0) {
932          m = m + doc->nummedia;
933       }
934       if (m != gv_pagemedia) gv_pagemedia = gv_pagemedia_old = m;
935     }
936     if (gv_pagemedia == MEDIA_ID_INVALID) {
937        int m;
938        gv_pagemedia_old         = MEDIA_ID_INVALID;
939        m = doc_convStringToPageMedia(doc,app_res.default_pagemedia);
940        if (m== MEDIA_ID_AUTO) {
941           gv_pagemedia_auto     = 1;
942           gv_pagemedia_auto_old = 0;
943           gv_pagemedia          = MEDIA_ID_INVALID;
944        } else {
945           gv_pagemedia_auto     = 0;
946           gv_pagemedia_auto_old = 1;
947           gv_pagemedia          = m;
948        }
949     }
950     cb_showTitle(toplevel,NULL,NULL);
951 
952     if (show_date) {
953        if (doc && doc->date) {
954           label = doc->date;
955           bitmap = app_res.document_bitmap;
956        }
957        else {
958           if (gv_psfile) { label = ctime(&mtime); }
959           else { label = ""; }
960           bitmap = None;
961        }
962 
963                                                   n=0;
964        XtSetArg(args[n], XtNlabel, label);        n++;
965        XtSetValues(datebutton, args, n);
966        if (datemenu) XtDestroyWidget(datemenu);
967        datemenu = build_label_menu(datebutton, "date", label, bitmap);
968     }
969 
970     misc_buildPagemediaMenu();
971     {
972       int media_bbox = doc ? doc->nummedia : 0;
973       Boolean b = (doc_mediaIsOk(doc,current_page,media_bbox) ? True : False);
974       XtSetSensitive(pagemediaEntry[media_bbox], b);
975     }
976 
977     /* Reset ghostscript and output messages popup */
978 
979     if (!doc || !olddoc ||
980 	strcmp(gv_filename_old, gv_filename) ||
981 	olddoc->beginprolog != doc->beginprolog ||
982 	olddoc->endprolog != doc->endprolog ||
983 	olddoc->beginsetup != doc->beginsetup ||
984 	olddoc->endsetup != doc->endsetup) {
985         INFMESSAGE(disabling interpreter)
986 	GhostviewDisableInterpreter(page);
987         cb_popdownInfoPopup((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
988         cb_resetInfoPopup((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
989     }
990 
991     /* Build table of contents */
992     if (doc && doc->structured) {
993 	int maxlen = 0;
994 	int i, j;
995 
996         INFMESSAGE(toc available)
997 	if (doc->labels_useful) {
998 	    for (i = 0; i < doc->numpages; i++)
999 		maxlen = max(maxlen, (int)strlen(doc->pages[i].label));
1000 	} else {
1001 	    double x;
1002 	    x = doc->numpages;
1003 	    maxlen = log10(x) + 1;
1004 	}
1005 	toc_entry_length = maxlen + 1;
1006 	toc_length = doc->numpages * toc_entry_length - 1;
1007 	toc_text = XtMalloc(toc_length + 2); /* include final NULL */
1008 
1009 	for (i = 0, tocp = toc_text; i < doc->numpages;
1010 	     i++, tocp += toc_entry_length) {
1011 	    if (doc->labels_useful) {
1012 		if (doc->pageorder == DESCEND) {
1013 		    j = (doc->numpages - 1) - i;
1014 		} else {
1015 		    j = i;
1016 		}
1017 		sprintf(tocp, "%*s\n", maxlen, doc->pages[j].label);
1018 	    } else {
1019 		sprintf(tocp, "%*d\n", maxlen, i+1);
1020 	    }
1021 	}
1022 	toc_text[toc_length] = '\0';
1023 							n=0;
1024 	XtSetArg(args[n], XtNfilename, NULL);      	n++;
1025 	XtSetValues(page, args, n);
1026     } else {
1027         String fn;
1028         fn = gv_filename_unc ? gv_filename_unc : gv_filename;
1029         INFMESSAGE(toc not available)
1030 	toc_length = 0;
1031 	toc_entry_length = 1;
1032 				       	        n=0;
1033 	XtSetArg(args[n], XtNfilename, fn);     n++;
1034 	XtSetValues(page, args, n);
1035     }
1036 
1037     {
1038       String s;
1039       int i=0;
1040       if (toc_text) {
1041 	s = (char*)XtMalloc((doc->numpages+1)*sizeof(char));
1042 	while (i < doc->numpages) {
1043 	  s[i] = 'p';
1044 	  i++;
1045 	}
1046 	s[i] = '\0';
1047 							n=0;
1048 	if (	(!gv_filename_old)			||
1049 		(!olddoc)				||
1050 		(strcmp(gv_filename_old, gv_filename))	||
1051 		(doc->numpages != olddoc->numpages)	)
1052 		  XtSetArg(args[n], XtNvlist, s);	n++;
1053 	XtSetArg(args[n], XtNlabel, toc_text);		n++;
1054       } else {
1055 	s = NULL;
1056 	XtSetArg(args[n], XtNvlist, "");		n++;
1057 	XtSetArg(args[n], XtNlabel, "");		n++;
1058       }
1059       XtSetValues(newtoc, args, n);
1060       ClipWidgetSetCoordinates(newtocClip,0,0);
1061       INFMESSAGE(setup_ghostview calling XawScrollbarSetThumb)
1062       XawScrollbarSetThumb(newtocScroll,
1063 		      VlistScrollPosition(newtoc),
1064 		      VlistVisibleLength(newtoc,newtocClip->core.height));
1065       XtFree(s);
1066     }
1067 
1068     misc_setBitmap(w_toggleCurrentPage , show_toggleCurrentPage , app_res.mark_current_bitmap);
1069     misc_setBitmap(w_toggleEvenPages   , show_toggleEvenPages   , app_res.mark_even_bitmap);
1070     misc_setBitmap(w_toggleOddPages    , show_toggleOddPages    , app_res.mark_odd_bitmap);
1071     misc_setBitmap(w_unmarkAllPages    , show_unmarkAllPages    , app_res.mark_unmark_bitmap);
1072 
1073     misc_setSensitive(w_saveMarkedPages   , show_saveMarkedPages   , (toc_text    != NULL));
1074     misc_setSensitive(w_saveAllPages      , show_saveAllPages      , (gv_psfile   != NULL));
1075     misc_setSensitive(w_printMarkedPages  , show_printMarkedPages  , (toc_text    != NULL));
1076     misc_setSensitive(w_printAllPages     , show_printAllPages     , (gv_psfile   != NULL));
1077     misc_setSensitive(w_checkFile         , show_checkFile         , (gv_filename != NULL));
1078     misc_setSensitive(w_updateFile        , show_updateFile        , (gv_filename != NULL));
1079     misc_setSensitive(w_showThisPage      , show_showThisPage      , (gv_psfile   != NULL || (gv_gs_arguments && *gv_gs_arguments)));
1080     misc_setSensitive(w_prevPage          , show_prevPage          , (toc_text    != NULL));
1081     misc_setSensitive(w_nextPage          , show_nextPage          , (gv_filename != NULL));
1082     misc_setSensitive(w_toggleCurrentPage , show_toggleCurrentPage , (toc_text    != NULL));
1083     misc_setSensitive(w_toggleEvenPages   , show_toggleEvenPages   , (toc_text    != NULL));
1084     misc_setSensitive(w_toggleOddPages    , show_toggleOddPages    , (toc_text    != NULL));
1085     misc_setSensitive(w_unmarkAllPages    , show_unmarkAllPages    , (toc_text    != NULL));
1086 
1087     XtSetSensitive(reopenEntry,      (gv_psfile   != NULL));
1088     XtSetSensitive(saveposEntry,      (gv_psfile   != NULL));
1089     XtSetSensitive(presentationEntry,      (gv_psfile   != NULL));
1090     XtSetSensitive(printAllEntry,    (gv_psfile   != NULL));
1091     XtSetSensitive(printMarkedEntry, (toc_text    != NULL));
1092     XtSetSensitive(saveAllEntry,     (gv_psfile   != NULL));
1093     XtSetSensitive(saveMarkedEntry,  (toc_text    != NULL));
1094     XtSetSensitive(nextEntry,        (gv_filename != NULL));
1095     XtSetSensitive(redisplayEntry,   (gv_psfile   != NULL || (gv_gs_arguments && *gv_gs_arguments)));
1096     XtSetSensitive(prevEntry,        (toc_text    != NULL));
1097     XtSetSensitive(currentEntry,     (toc_text    != NULL));
1098     XtSetSensitive(oddEntry,         (toc_text    != NULL));
1099     XtSetSensitive(evenEntry,        (toc_text    != NULL));
1100     XtSetSensitive(unmarkEntry,      (toc_text    != NULL));
1101 
1102     ENDMESSAGE(setup_ghostview)
1103     return oldtoc_entry_length != toc_entry_length;
1104 }
1105 
1106 Dimension view_width, view_height, view_border;
1107 Dimension control_width, control_height;
1108 
1109 /*------------------------------------------------------------*/
1110 /* layout_ghostview */
1111 /*------------------------------------------------------------*/
1112 
1113 static void
1114 layout_ghostview(void)
1115 {
1116    Arg       args[10];
1117    Cardinal  n;
1118    Dimension page_prefWidth, page_prefHeight;
1119    Dimension page_width, page_height;
1120    static Boolean firsttime=True;
1121    Boolean auto_resize;
1122 
1123    BEGINMESSAGE(layout_ghostview)
1124 
1125    if (!firsttime) {
1126       XtSetArg(args[0], XtNallowShellResize,&auto_resize);
1127       XtGetValues(toplevel, args,ONE);
1128       if (auto_resize != app_res.auto_resize) {
1129          INFMESSAGE(######## changing resize behaviour)
1130 #        ifdef MESSAGES
1131             if (app_res.auto_resize) {INFMESSAGE(shell is allowed to resize)}
1132             else                     {INFMESSAGE(shell must not resize)}
1133 #        endif
1134          XtSetArg(args[0], XtNallowShellResize,app_res.auto_resize);
1135          XtSetValues(toplevel, args,ONE);
1136 	 if (app_res.auto_resize==False) {
1137 	   ENDMESSAGE(layout_ghostview)
1138 	   return;
1139          }
1140 	 INFIMESSAGE(setting tocFrame height:,TOC3D_INITIAL_HEIGHT)
1141          XtSetArg(args[0], XtNheight,TOC3D_INITIAL_HEIGHT);
1142 	 XtSetValues(newtocFrame, args, ONE);
1143       }
1144    }
1145 
1146    INFMESSAGE(#### retrieving dimensions)
1147    XtSetArg(args[0], XtNpreferredWidth, &page_prefWidth);
1148    XtSetArg(args[1], XtNpreferredHeight, &page_prefHeight);
1149    XtSetArg(args[2], XtNwidth, &page_width);
1150    XtSetArg(args[3], XtNheight, &page_height);
1151    XtGetValues(page, args, FOUR);
1152    INFIIMESSAGE(## preferred,page_prefWidth,page_prefHeight)
1153    INFIIMESSAGE(## actual,page_width,page_height)
1154 
1155    if (page_prefWidth != page_width || page_prefHeight != page_height) {
1156       INFMESSAGE(#### setting ghostview widget size to its preferred size)
1157       XtSetArg(args[0], XtNwidth,           page_prefWidth);
1158       XtSetArg(args[1], XtNheight,          page_prefHeight);
1159       XtSetValues(page, args, TWO);
1160    }
1161    cb_positionPage(page,(XtPointer)NULL,(XtPointer)NULL);
1162 
1163    if (firsttime) {
1164 						            n=0;
1165      XtSetArg(args[n], XtNminWidth, (Dimension)app_res.minimum_width);  n++;
1166      XtSetArg(args[n], XtNminHeight,(Dimension)app_res.minimum_height);n++;
1167      if (app_res.auto_resize==False) {
1168         INFMESSAGE(switching to No-Resize mode)
1169         XtSetArg(args[n], XtNallowShellResize,app_res.auto_resize); n++;
1170      }
1171      XtSetValues(toplevel, args,n);
1172      firsttime=False;
1173    }
1174 
1175   ENDMESSAGE(layout_ghostview)
1176 }
1177 
1178 /*############################################################*/
1179 /* setup_layout_ghostview */
1180 /*############################################################*/
1181 
1182 void
1183 setup_layout_ghostview(void)
1184 {
1185   BEGINMESSAGE(setup_layout_ghostview )
1186   ENDMESSAGE(setup_layout_ghostview)
1187 }
1188 
1189 /*------------------------------------------------------------*/
1190 /* set_new_scale */
1191 /*------------------------------------------------------------*/
1192 
1193 static Boolean
1194 set_new_scale(void)
1195 {
1196   int new_scale,new_scale_base;
1197   Boolean changed = False;
1198   Arg args[2];
1199   Cardinal n;
1200   Scale scale;
1201   float ascale;
1202 
1203   BEGINMESSAGE(set_new_scale)
1204 
1205   new_scale_base = gv_scale_base;
1206   if (!default_xdpi || !default_ydpi || new_scale_base != gv_scale_base_current) {
1207     scale = gv_scales[new_scale_base];
1208     ascale = scale->scale;
1209     if ((scale->is_base)&SCALE_IS_REAL_BASED) {
1210       default_xdpi = gv_real_xdpi;
1211       default_ydpi = gv_real_ydpi;
1212     } else {
1213       default_xdpi = gv_pixel_xdpi;
1214       default_ydpi = gv_pixel_ydpi;
1215     }
1216     default_xdpi *= ascale;
1217     default_ydpi *= ascale;
1218     INFIMESSAGE(old scale base,gv_scale_base_current);
1219     INFIMESSAGE(new scale base,new_scale_base);
1220     XtSetArg(args[0], XtNleftBitmap, None);
1221     if (gv_scale_base_current >=0) XtSetValues(scaleEntry[gv_scale_base_current],args, ONE);
1222     XtSetArg(args[0], XtNleftBitmap, app_res.selected_bitmap);
1223     XtSetValues(scaleEntry[new_scale_base],args, ONE);
1224     gv_scale_base_current = new_scale_base;
1225     changed=True;
1226   }
1227 
1228   new_scale = gv_scale;
1229   if (changed || new_scale != gv_scale_current || gv_scales[new_scale]->scale <=0) {
1230     float xdpi, ydpi;
1231     GhostviewDisableInterpreter(page);
1232     scale = gv_scales[new_scale];
1233     ascale = scale->scale;
1234 
1235     if (!ascale)
1236     {
1237        int dx = current_urx - current_llx + 1;
1238        int dy = current_ury - current_lly + 1;
1239        float ascale1;
1240        float ascale2;
1241 
1242        if (gv_orientation == 2 || gv_orientation == 3)
1243        {
1244           int hlp = dx;
1245 	  dx = dy;
1246 	  dy = hlp;
1247        }
1248 
1249        ascale1 = (float)viewClip->core.width / dx / 72.0 * default_xdpi;
1250        ascale2 = (float)viewClip->core.height / dy / 72.0 * default_ydpi;
1251 
1252        ascale = ascale1 < ascale2 ? ascale1 : ascale2;
1253     }
1254     else if (fabs(ascale+1) <= 0.001)
1255     {
1256        int dx = current_urx - current_llx + 1;
1257        int dy = current_ury - current_lly + 1;
1258 
1259        if (gv_orientation == 2 || gv_orientation == 3)
1260        {
1261           int hlp = dx;
1262 	  dx = dy;
1263 	  dy = hlp;
1264        }
1265 
1266        ascale = (float)viewClip->core.width / dx / 72.0 * default_xdpi;
1267     }
1268     else if (fabs(ascale+3) <= 0.001)
1269     {
1270        int dx = current_urx - current_llx + 1;
1271        int dy = current_ury - current_lly + 1;
1272 
1273        if (gv_orientation == 2 || gv_orientation == 3)
1274        {
1275           int hlp = dx;
1276          dx = dy;
1277          dy = hlp;
1278        }
1279 
1280        ascale = (float)viewClip->core.height / dy / 72.0 * default_xdpi;
1281     }
1282     else if (fabs(ascale+2) <= 0.001)
1283     {
1284        ascale = gv_ascale;
1285     }
1286 
1287     xdpi = default_xdpi / ascale;
1288     ydpi = default_ydpi / ascale;
1289                                               n=0;
1290     XtSetArg(args[n], XtNlabel, scale->name); n++;
1291     XtSetValues(scaleButton, args, n);
1292 			            	      n=0;
1293     XtSetArg(args[n], XtNlxdpi, (1000*xdpi)); n++;
1294     XtSetArg(args[n], XtNlydpi, (1000*ydpi)); n++;
1295     XtSetValues(page, args, n);
1296 			            	      n=0;
1297     XtSetArg(args[n], XtNleftBitmap, None);   n++;
1298     if (gv_scale_current >=0) XtSetValues(scaleEntry[gv_scale_current],args, n);
1299 			            	      n=0;
1300     XtSetArg(args[n], XtNleftBitmap, app_res.selected_bitmap); n++;
1301     XtSetValues(scaleEntry[new_scale],args, n);
1302     gv_scale_current = new_scale;
1303     changed=True;
1304   }
1305   ENDMESSAGE(set_new_scale)
1306   return changed;
1307 }
1308 
1309 /*------------------------------------------------------------*/
1310 /* set_orientationButton_label */
1311 /*------------------------------------------------------------*/
1312 
1313 static void
1314 set_orientationButton_label(int orientation)
1315 {
1316    Arg args[1];
1317    Widget w = portraitEntry;
1318    String label;
1319 
1320    BEGINMESSAGE(set_orientationButton_label)
1321    if (orientation == O_LANDSCAPE)       w = landscapeEntry;
1322    else if (orientation == O_UPSIDEDOWN) w = upsidedownEntry;
1323    else if (orientation == O_SEASCAPE)   w = seascapeEntry;
1324    XtSetArg(args[0], XtNlabel,&label);
1325    XtGetValues(w, args, ONE);
1326    XtSetArg(args[0], XtNlabel,label);
1327    XtSetValues(orientationButton, args, ONE);
1328    ENDMESSAGE(set_orientationButton_label)
1329 }
1330 
1331 /*------------------------------------------------------------*/
1332 /* set_newBitmapIfChanged */
1333 /*------------------------------------------------------------*/
1334 
1335 static void
1336 set_newBitmapIfChanged(Widget w, Pixmap new_bitmap)
1337 {
1338    Arg args[1];
1339    Pixmap old_bitmap;
1340 
1341    BEGINMESSAGE(set_newBitmapIfChanged)
1342    if (!w) return;  /* continuing will eventually cause a core dump */
1343    XtSetArg(args[0], XtNleftBitmap, &old_bitmap);
1344    XtGetValues(w, args, ONE);
1345    if (new_bitmap != old_bitmap) {
1346       XtSetArg(args[0], XtNleftBitmap, new_bitmap);
1347       XtSetValues(w, args, ONE);
1348    }
1349    ENDMESSAGE(set_newBitmapIfChanged)
1350 }
1351 
1352 /*------------------------------------------------------------*/
1353 /* set_new_orientation */
1354 /*------------------------------------------------------------*/
1355 
1356 static Boolean
1357 set_new_orientation(int pagenumber)
1358 {
1359    Boolean changed  = False;
1360    int from_doc = 0;
1361    int no;
1362    Widget w;
1363    Pixmap bitmap;
1364    XtPageOrientation xto,xto_old;
1365 
1366    BEGINMESSAGE(set_new_orientation)
1367 
1368    no = O_UNSPECIFIED;
1369    if (no == O_UNSPECIFIED && gv_orientation != gv_orientation_old) {
1370       INFIMESSAGE(forcing new orientation to be,no)
1371       no = gv_orientation;
1372       INFMESSAGE(disabling automatic orientation)
1373       gv_orientation_auto = 0;
1374    }
1375    if (no == O_UNSPECIFIED && gv_orientation_auto) {
1376       int po;
1377       po = doc_preferredOrientationOfPage(doc,pagenumber);
1378       INFIMESSAGE(using orientation from doc, po)
1379       if (po != O_UNSPECIFIED) {
1380          INFIMESSAGE(using orientation from doc, po)
1381          no = po;
1382          from_doc = 1;
1383       }
1384    }
1385    if (no==O_UNSPECIFIED) no = gv_orientation_old;
1386    if (no!=O_PORTRAIT && no!=O_LANDSCAPE && no!=O_SEASCAPE && no!=O_UPSIDEDOWN)
1387       no = gv_fallback_orientation;
1388    gv_orientation = no;
1389 
1390    xto     = doc_convDocOrientToXtOrient(gv_orientation,    gv_swap_landscape    );
1391    xto_old = doc_convDocOrientToXtOrient(gv_orientation_old,gv_swap_landscape_old);
1392    IIMESSAGE(xto,xto_old)
1393 
1394    if (xto != xto_old) {
1395       Arg args[1];
1396       if      (gv_orientation_old == O_PORTRAIT)   w = portraitEntry;
1397       else if (gv_orientation_old == O_LANDSCAPE)  w = landscapeEntry;
1398       else if (gv_orientation_old == O_UPSIDEDOWN) w = upsidedownEntry;
1399       else                                         w = seascapeEntry;
1400       widgets_setSelectedBitmap(w,0);
1401 
1402       INFIMESSAGE(changing orientation for page to be,xto)
1403       GhostviewDisableInterpreter(page);
1404       XtSetArg(args[0], XtNorientation, xto);
1405       XtSetValues(page, args, ONE);
1406       changed = True;
1407       set_orientationButton_label(gv_orientation);
1408    }
1409 
1410    if (from_doc) bitmap = app_res.document_bitmap;
1411    else          bitmap = app_res.selected_bitmap;
1412    if      ( no == O_PORTRAIT)   w = portraitEntry;
1413    else if ( no == O_LANDSCAPE)  w = landscapeEntry;
1414    else if ( no == O_UPSIDEDOWN) w = upsidedownEntry;
1415    else                          w = seascapeEntry;
1416       if (w)
1417          set_newBitmapIfChanged(w,bitmap);
1418 
1419    if (gv_swap_landscape != gv_swap_landscape_old)
1420       widgets_setSelectedBitmap(swapEntry,gv_swap_landscape);
1421    if (gv_orientation_auto != gv_orientation_auto_old)
1422       widgets_setSelectedBitmap(autoOrientEntry,gv_orientation_auto);
1423 
1424    gv_orientation_old       = gv_orientation;
1425    gv_orientation_auto_old  = gv_orientation_auto;
1426    gv_swap_landscape_old    = gv_swap_landscape;
1427 
1428    ENDMESSAGE(set_new_orientation)
1429    return(changed);
1430 
1431 }
1432 
1433 /*------------------------------------------------------------*/
1434 /* set_pagemediaButton */
1435 /*------------------------------------------------------------*/
1436 
1437 static void
1438 set_pagemediaButton_label(int media_id)
1439 {
1440    String s = NULL;
1441    Arg args[1];
1442 
1443    BEGINMESSAGE(set_pagemediaButton_label)
1444    if (media_id>=0) {
1445       Widget w;
1446       if (pagemediaEntry[media_id]) w = pagemediaEntry[media_id];
1447       else if (media_id <= 0)       w = NULL;
1448       else                          w = pagemediaEntry[media_id-1];
1449       if (!w)
1450 	  goto out;
1451       XtSetArg(args[0], XtNlabel, &s);
1452       XtGetValues(w, args, ONE);
1453    }
1454    else s = "?";
1455    XtSetArg(args[0], XtNlabel, s);
1456    XtSetValues(pagemediaButton, args, ONE);
1457 out:
1458    ENDMESSAGE(set_pagemediaButton_label)
1459    return;
1460 }
1461 
1462 /*------------------------------------------------------------*/
1463 /* set_new_pagemedia */
1464 /*------------------------------------------------------------*/
1465 
1466 static Boolean
1467 set_new_pagemedia(int pagenumber)
1468 {
1469    int new_llx,new_lly,new_urx,new_ury;
1470    Boolean changed = False;
1471    int from_doc = 0;
1472    Arg args[4];
1473    Widget w = NULL;
1474    Pixmap bitmap;
1475    int num_doc_media;
1476    int nm;
1477    int media_bbox;
1478 
1479    BEGINMESSAGE(set_new_pagemedia)
1480 
1481    num_doc_media=0;
1482    if (doc) num_doc_media = doc->nummedia;
1483    media_bbox = num_doc_media;
1484 
1485    nm = MEDIA_ID_INVALID;
1486    if (gv_pagemedia != gv_pagemedia_old) {
1487      if (doc_mediaIsOk(doc,pagenumber,gv_pagemedia)) {
1488        nm = gv_pagemedia;
1489        INFIMESSAGE(forcing new pagemedia to be,nm)
1490        INFMESSAGE(disabling automatic pagemedia)
1491        gv_pagemedia_auto = 0;
1492      }
1493    }
1494    else if (gv_pagemedia==media_bbox && !gv_pagemedia_auto) {
1495      if (doc_mediaIsOk(doc,pagenumber,gv_pagemedia))
1496        nm = gv_pagemedia;
1497    }
1498    else if (gv_pagemedia_auto) {
1499      nm = doc_preferredMediaOfPage(doc,pagenumber,&new_llx,&new_lly,&new_urx,&new_ury);
1500      if (nm != MEDIA_ID_INVALID) {
1501        INFIMESSAGE(using pagemedia preferred from doc, nm)
1502        from_doc = 1;
1503      }
1504    }
1505    if (nm==MEDIA_ID_INVALID && doc_mediaIsOk(doc,pagenumber,gv_pagemedia_old))
1506      nm = gv_pagemedia_old;
1507    if (nm==MEDIA_ID_INVALID) nm = gv_fallback_pagemedia;
1508    gv_pagemedia = nm;
1509 
1510    /* If pagemedia changed, remove the old marker. */
1511    IIMESSAGE(gv_pagemedia,gv_pagemedia_old)
1512    if (gv_pagemedia != gv_pagemedia_old) {
1513       if (gv_pagemedia_old>=0) {
1514          if (pagemediaEntry[gv_pagemedia_old]) w = pagemediaEntry[gv_pagemedia_old];
1515          else                                  w = pagemediaEntry[gv_pagemedia_old-1];
1516          widgets_setSelectedBitmap(w,0);
1517       }
1518       set_pagemediaButton_label(gv_pagemedia);
1519    }
1520 
1521    if (gv_pagemedia >= 0) {
1522       if (from_doc) bitmap = app_res.document_bitmap;
1523       else          bitmap = app_res.selected_bitmap;
1524       if (pagemediaEntry[gv_pagemedia]) w = pagemediaEntry[gv_pagemedia];
1525       else                              w = pagemediaEntry[gv_pagemedia-1];
1526          if (w)
1527           set_newBitmapIfChanged(w,bitmap);
1528    }
1529 
1530    if (gv_pagemedia_auto != gv_pagemedia_auto_old) widgets_setSelectedBitmap(autoMediaEntry,gv_pagemedia_auto);
1531 
1532    if (gv_pagemedia == num_doc_media) {
1533       doc_boundingBoxOfPage(doc,pagenumber,&new_llx,&new_lly,&new_urx,&new_ury);
1534    } else {
1535       new_llx = new_lly = 0;
1536       if (gv_pagemedia < num_doc_media) {
1537          new_urx = doc->media[gv_pagemedia].width-1;
1538 	 new_ury = doc->media[gv_pagemedia].height-1;
1539       } else {
1540          new_urx = gv_medias[gv_pagemedia-num_doc_media]->width-1;
1541          new_ury = gv_medias[gv_pagemedia-num_doc_media]->height-1;
1542       }
1543    }
1544 
1545    /* If bounding box changed, setup for new size. */
1546    if ((new_llx != current_llx) || (new_lly != current_lly) ||
1547       (new_urx != current_urx) || (new_ury != current_ury)) {
1548       INFMESSAGE(bounding box changed)
1549       INFIIMESSAGE(lower left:,new_llx,new_lly)
1550       INFIIMESSAGE(upper right:,new_urx,new_ury)
1551       GhostviewDisableInterpreter(page);
1552       changed = True;
1553       current_llx = new_llx;
1554       current_lly = new_lly;
1555       current_urx = new_urx;
1556       current_ury = new_ury;
1557       XtSetArg(args[0], XtNllx, current_llx);
1558       XtSetArg(args[1], XtNlly, current_lly);
1559       XtSetArg(args[2], XtNurx, current_urx);
1560       XtSetArg(args[3], XtNury, current_ury);
1561       XtSetValues(page, args, FOUR);
1562    }
1563 
1564    gv_pagemedia_old = gv_pagemedia;
1565    gv_pagemedia_auto_old = gv_pagemedia_auto;
1566 
1567    ENDMESSAGE(set_new_pagemedia)
1568    return changed;
1569 }
1570 
1571 /*------------------------------------------------------------*/
1572 /* same_document_media */
1573 /*------------------------------------------------------------*/
1574 
1575 static Boolean
1576 same_document_media(void)
1577 {
1578    int i;
1579    Boolean same = True;
1580 
1581    BEGINMESSAGE(same_document_media)
1582    if (olddoc == NULL && doc == NULL)          same=True;
1583    else if (olddoc == NULL || doc == NULL)     same=False;
1584    else if (olddoc->nummedia != doc->nummedia) same=False;
1585    else for (i = 0; i < doc->nummedia; i++) {
1586        if (strcmp(olddoc->media[i].name, doc->media[i].name)) {
1587           same=False;
1588           break;
1589        }
1590    }
1591    ENDMESSAGE(same_document_media)
1592    return(same);
1593 }
1594 
1595 /*############################################################*/
1596 /* misc_buildPagemediaMenu */
1597 /*############################################################*/
1598 
1599 void misc_buildPagemediaMenu(void)
1600 {
1601   Widget w;
1602   int i,num_doc_media;
1603 
1604   BEGINMESSAGE(misc_buildPagemediaMenu)
1605   if (pagemediaMenu && same_document_media()) {
1606     ENDMESSAGE(misc_buildPagemediaMenu)
1607     return;
1608   }
1609   if (pagemediaMenu) XtDestroyWidget(pagemediaMenu);
1610   pagemediaMenu = XtCreatePopupShell("menu", simpleMenuWidgetClass,pagemediaButton, NULL,(Cardinal)0);
1611 
1612   autoMediaEntry = XtCreateManagedWidget("automatic",smeBSBObjectClass,pagemediaMenu,NULL,(Cardinal)0);
1613   XtAddCallback(autoMediaEntry,XtNcallback,cb_setPagemedia,(XtPointer)MEDIA_ID_AUTO);
1614   widgets_setSelectedBitmap(autoMediaEntry,gv_pagemedia_auto);
1615   XtCreateManagedWidget("line",smeLineObjectClass,pagemediaMenu,NULL,(Cardinal)0);
1616 
1617   /* Build the Page Media menu */
1618   /* the Page media menu has three parts.
1619    *  - the automatic media detection entry.
1620    *  - the document defined page medias
1621    *  - the standard page medias
1622    */
1623   num_doc_media = 0;
1624   if (doc) num_doc_media = doc->nummedia;
1625 
1626   i = gv_num_std_pagemedia + num_doc_media;
1627   XtFree((XtPointer)pagemediaEntry);
1628   pagemediaEntry = (Widget *) XtMalloc(i * sizeof(Widget));
1629 
1630   if (doc && doc->nummedia) {
1631     for (i = 0; i < doc->nummedia; i++) {
1632       pagemediaEntry[i] = XtCreateManagedWidget(doc->media[i].name,smeBSBObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1633       XtAddCallback(pagemediaEntry[i], XtNcallback,cb_setPagemedia, (XtPointer)(intptr_t)i);
1634     }
1635     w = XtCreateManagedWidget("line", smeLineObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1636   }
1637 
1638   for (i = 0; gv_medias[i]; i++) {
1639     pagemediaEntry[i+num_doc_media] = NULL;
1640     if (!(gv_medias[i]->used)) continue;
1641     pagemediaEntry[i+num_doc_media] =
1642       XtCreateManagedWidget(gv_medias[i]->name,smeBSBObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1643     XtAddCallback(pagemediaEntry[i+num_doc_media], XtNcallback,cb_setPagemedia, (XtPointer)(intptr_t)(i+num_doc_media));
1644   }
1645   {
1646     Boolean b = (doc_mediaIsOk(doc,current_page,num_doc_media) ? True : False);
1647     XtSetSensitive(pagemediaEntry[num_doc_media],b);
1648   }
1649 
1650   ENDMESSAGE(misc_buildPagemediaMenu)
1651 }
1652 
1653 /*------------------------------------------------------------*/
1654 /* build_label_menu */
1655 /*------------------------------------------------------------*/
1656 
1657 Widget
1658 build_label_menu(Widget parent, String name, String label, Pixmap bitmap)
1659 {
1660     Arg args[5];
1661     Cardinal n;
1662     Widget menu, entry;
1663 
1664     BEGINMESSAGE(build_label_menu)
1665 								n=0;
1666     menu = XtCreatePopupShell("menu", simpleMenuWidgetClass,parent, args, n);
1667 								n=0;
1668     XtSetArg(args[n], XtNlabel, label);			        n++;
1669     if (bitmap) {
1670        XtSetArg(args[n], XtNleftMargin, 20);			n++;
1671        XtSetArg(args[n], XtNleftBitmap, bitmap);		n++;
1672     }
1673     XtSetArg(args[n], XtNjustify, XtJustifyCenter);	        n++;
1674     entry = XtCreateManagedWidget(name, smeBSBObjectClass,menu, args, n);
1675     ENDMESSAGE(build_label_menu)
1676     return menu;
1677 }
1678 
1679 /*############################################################*/
1680 /* catch_Xerror */
1681 /* Catch X errors die gracefully if one occurs */
1682 /*############################################################*/
1683 
1684 int
1685 catch_Xerror(Display *dpy, XErrorEvent *err)
1686 {
1687     BEGINMESSAGE(catch_Xerror)
1688     if (err->error_code == BadImplementation) {
1689 	old_Xerror(dpy, err);
1690 	return 0;
1691     }
1692     if (dying) return 0;
1693     dying = True;
1694     bomb = *err;
1695     XtDestroyWidget(toplevel);
1696     ENDMESSAGE(catch_Xerror)
1697     return 0;
1698 }
1699 
1700 /*############################################################*/
1701 /* quote_filename */
1702 /* Quotes special characters in filenames */
1703 /* (taken from bash sources) */
1704 /*############################################################*/
1705 
1706 char *
1707 quote_filename (char *string)
1708 {
1709     int c;
1710     char *result, *r, *s;
1711 
1712     BEGINMESSAGE(quote_filename)
1713 
1714     result = (char*) XtMalloc((2 * strlen (string) + 1) * sizeof(char));
1715 
1716     for (r = result, s = string; s && (c = *s); s++)
1717     {
1718       switch (c)
1719 	{
1720 	case ' ': case '\t': case '\n':		/* IFS white space */
1721 	case '\'': case '"': case '\\':		/* quoting chars */
1722 	case '|': case '&': case ';':		/* shell metacharacters */
1723 	case '(': case ')': case '<': case '>':
1724 	case '!': case '{': case '}':		/* reserved words */
1725 	case '*': case '[': case '?': case ']':	/* globbing chars */
1726 	case '^':
1727 	case '$': case '`':			/* expansion chars */
1728 	  *r++ = '\\';
1729 	  *r++ = c;
1730 	  break;
1731 	case '#':				/* comment char */
1732 	  if (s == string)
1733 	    *r++ = '\\';
1734 	  /* FALLTHROUGH */
1735 	default:
1736 	  *r++ = c;
1737 	  break;
1738 	}
1739     }
1740     *r = '\0';
1741 
1742     ENDMESSAGE(quote_filename)
1743 
1744     return (result);
1745 }
1746