"Fossies" - the Fresh Open Source Software Archive

Member "ghostview-1.4.1/misc.c" (27 Oct 1992, 41873 Bytes) of package /linux/misc/old/ghost/gnu/ghostview/ghostview-1.4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * misc.c -- Everything that isn't a callback or action.
    3  * Copyright (C) 1992  Timothy O. Theisen
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  *
   19  *   Author: Tim Theisen           Systems Programmer
   20  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
   21  *     UUCP: uwvax!tim             University of Wisconsin-Madison
   22  *    Phone: (608)262-0438         1210 West Dayton Street
   23  *      FAX: (608)262-9777         Madison, WI   53706
   24  */
   25 
   26 #include <stdio.h>
   27 #ifndef SEEK_SET
   28 #define SEEK_SET 0
   29 #endif
   30 
   31 #include <X11/Xos.h>
   32 #include <signal.h>
   33 #ifdef SIGNALRETURNSINT
   34 #define SIGVAL int
   35 #else
   36 #define SIGVAL void
   37 #endif
   38 
   39 #include <math.h>
   40 
   41 #include <X11/Xatom.h>
   42 #include <X11/Intrinsic.h>
   43 #include <X11/StringDefs.h>
   44 #include <X11/Shell.h>
   45 #include <X11/Xaw/Cardinals.h>
   46 #include <X11/Xaw/Form.h>
   47 #include <X11/Xaw/SimpleMenu.h>
   48 #include <X11/Xaw/SmeBSB.h>
   49 #include <X11/Xaw/SmeLine.h>
   50 #include <X11/Xaw/Scrollbar.h>
   51 #include <X11/Xaw/AsciiText.h>
   52 /* Yuck, cannot get vScrollbar via the usual methods */
   53 #include <X11/IntrinsicP.h>
   54 #include <X11/Xaw/TextP.h>
   55 #include <X11/Xmu/StdCmap.h>
   56 
   57 #include <errno.h>
   58 /* BSD 4.3 errno.h does not declare errno */
   59 extern int errno;
   60 #ifdef VMS
   61 #include <perror.h>
   62 #else
   63 extern int sys_nerr;
   64 extern char *sys_errlist[];
   65 #endif
   66 
   67 #include "Ghostview.h"
   68 #include "gv.h"
   69 #include "ps.h"
   70 
   71 #ifndef max
   72 #define max(a, b)   ((a) > (b) ? (a) : (b))
   73 #endif
   74 
   75 /* Translate orientations defined by the enum in "ps.h" to
   76  * XtPageOrientations defined in "Ghostview.h".
   77  */
   78 static XtPageOrientation
   79 xorient(psorient)
   80     int psorient;
   81 {
   82     switch (psorient) {
   83     case PORTRAIT: return XtPageOrientationPortrait;
   84     case LANDSCAPE:
   85     if (app_res.swap_landscape) {
   86         return XtPageOrientationSeascape;
   87     } else {
   88         return XtPageOrientationLandscape;
   89     }
   90     }
   91 }
   92 
   93 static void
   94 break_chains()
   95 {
   96     Arg args[2];
   97     XtSetArg(args[0], XtNbottom, XtChainTop);
   98     XtSetArg(args[1], XtNright, XtChainLeft);
   99     XtSetValues(toc, args, ONE);
  100     XtSetValues(pageview, args, TWO);
  101 }
  102 
  103 static void
  104 set_chains()
  105 {
  106     Arg args[2];
  107 
  108     XtSetArg(args[0], XtNbottom, XtChainBottom);
  109     XtSetArg(args[1], XtNright, XtChainRight);
  110     XtSetValues(toc, args, ONE);
  111     XtSetValues(pageview, args, TWO);
  112 }
  113 
  114 static void
  115 reset_size_hints()
  116 {
  117     Arg args[4];
  118     if (app_res.ncdwm) return;
  119     XtSetArg(args[0], XtNmaxWidth, XtUnspecifiedShellInt);
  120     XtSetArg(args[1], XtNmaxHeight, XtUnspecifiedShellInt);
  121     XtSetArg(args[2], XtNminWidth, XtUnspecifiedShellInt);
  122     XtSetArg(args[3], XtNminHeight, XtUnspecifiedShellInt);
  123     XtSetValues(toplevel, args, FOUR);
  124 }
  125 
  126 static void
  127 set_size_hints(minw, minh, maxw, maxh)
  128     Dimension minw, minh, maxw, maxh;
  129 {
  130     Arg args[4];
  131 
  132     XtSetArg(args[0], XtNminWidth, minw);
  133     XtSetArg(args[1], XtNminHeight, minh);
  134     XtSetArg(args[2], XtNmaxWidth, maxw);
  135     XtSetArg(args[3], XtNmaxHeight, maxh);
  136     XtSetValues(toplevel, args, FOUR);
  137 }
  138 
  139 static Boolean horiz_scroll_saved = False;
  140 static Boolean vert_scroll_saved = False;
  141 static float horiz_top;
  142 static float vert_top;
  143 
  144 static void
  145 reset_scroll_bars()
  146 {
  147     Arg args[1];
  148     Widget scroll;
  149     float zero = 0.0;
  150     
  151     if (horiz_scroll_saved || vert_scroll_saved) return;
  152 
  153     scroll = XtNameToWidget(pageview, "horizontal");
  154     if (scroll) {
  155     XtSetArg(args[0], XtNtopOfThumb, &horiz_top);
  156     XtGetValues(scroll, args, ONE);
  157     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  158     horiz_scroll_saved = True;
  159     }
  160 
  161     scroll = XtNameToWidget(pageview, "vertical");
  162     if (scroll) {
  163     XtSetArg(args[0], XtNtopOfThumb, &vert_top);
  164     XtGetValues(scroll, args, ONE);
  165     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  166     vert_scroll_saved = True;
  167     }
  168 }
  169 
  170 static void
  171 set_scroll_bars()
  172 {
  173     Arg args[1];
  174     Widget scroll;
  175     float shown;
  176 
  177     if (horiz_scroll_saved) {
  178     scroll = XtNameToWidget(pageview, "horizontal");
  179     if (scroll) {
  180         XtSetArg(args[0], XtNshown, &shown);
  181         XtGetValues(scroll, args, ONE);
  182         if (horiz_top > (1.0 - shown)) horiz_top = (1.0 - shown);
  183         XtCallCallbacks(scroll, XtNjumpProc, &horiz_top);
  184     }
  185     }
  186 
  187     if (vert_scroll_saved) {
  188     scroll = XtNameToWidget(pageview, "vertical");
  189     if (scroll) {
  190         XtSetArg(args[0], XtNshown, &shown);
  191         XtGetValues(scroll, args, ONE);
  192         if (vert_top > (1.0 - shown)) vert_top = (1.0 - shown);
  193         XtCallCallbacks(scroll, XtNjumpProc, &vert_top);
  194     }
  195     }
  196 
  197     horiz_scroll_saved = vert_scroll_saved = False;
  198 }
  199 
  200 /* Start rendering a new page */
  201 void
  202 show_page(number)
  203     int number;
  204 {
  205     struct stat sbuf;
  206     int i;
  207 
  208     if (!filename) return;
  209 
  210     /* Unmark current_page as current */
  211     if (toc_text && (current_page >= 0)) {
  212     int marker = current_page*toc_entry_length + toc_entry_length-2;
  213     toc_text[marker] = ' ';
  214     XawTextInvalidate(toc, marker, marker+1);
  215     }
  216 
  217     /* If the file has changed, rescan it so that offsets into the file
  218      * are still correct.  If the file is rescanned, we must setup ghostview
  219      * again.  Also, force a new copy of ghostscript to start. */
  220     if (psfile) {
  221     if (!stat(filename, &sbuf) && mtime != sbuf.st_mtime) {
  222         fclose(psfile);
  223         psfile = fopen(filename, "r");
  224         mtime = sbuf.st_mtime;
  225         if (oldfilename) XtFree(oldfilename);
  226         oldfilename = XtNewString(filename);
  227         new_file(number);
  228     }
  229     }
  230 
  231     /* Coerce page number to fall in range */
  232     if (toc_text) {
  233     if (number >= doc->numpages) number = doc->numpages - 1;
  234     if (number < 0) number = 0;
  235     }
  236 
  237     if (set_new_orientation(number) || set_new_pagemedia(number))
  238     layout_ghostview();
  239 
  240     if (toc_text) {
  241     int marker;
  242     current_page = number;
  243     XawTextUnsetSelection(toc);
  244     XawTextSetInsertionPoint(toc, current_page * toc_entry_length);
  245     marker = current_page*toc_entry_length + toc_entry_length-2;
  246     toc_text[marker] = '<';
  247     XawTextInvalidate(toc, marker, marker+1);
  248     if (GhostviewIsInterpreterReady(page)) {
  249         GhostviewNextPage(page);
  250     } else {
  251         GhostviewEnableInterpreter(page);
  252         GhostviewSendPS(page, psfile, doc->beginprolog,
  253                 doc->lenprolog, False);
  254         GhostviewSendPS(page, psfile, doc->beginsetup,
  255                 doc->lensetup, False);
  256     }
  257     if (doc->pageorder == DESCEND)
  258         i = (doc->numpages - 1) - current_page;
  259     else
  260         i = current_page;
  261     GhostviewSendPS(page, psfile, doc->pages[i].begin,
  262             doc->pages[i].len, False);
  263     } else {
  264     if (!GhostviewIsInterpreterRunning(page))
  265         GhostviewEnableInterpreter(page);
  266     else if (GhostviewIsInterpreterReady(page))
  267         GhostviewNextPage(page);
  268     else
  269         XBell(XtDisplay(page), 0);
  270     }
  271 
  272     if (toc_text) {
  273     XtSetSensitive(prevbutton, current_page != 0);
  274     XtSetSensitive(nextbutton, current_page != doc->numpages-1);
  275     XtSetSensitive(showbutton, True);
  276     }
  277 }
  278 
  279 /* setup ghostview.  This includes:
  280  *  scanning the PostScript file,
  281  *  setting the title and date labels,
  282  *  building the pagemedia menu,
  283  *  building the toc (table of contents)
  284  *  sensitizing the appropriate menu buttons,
  285  *  popping down and erasing the infotext popup.
  286  */
  287 
  288 static Boolean useful_page_labels;
  289 Boolean
  290 setup_ghostview()
  291 {
  292     Arg args[20];
  293     Cardinal num_args;
  294     int oldtoc_entry_length;
  295     char *tocp;
  296     XawTextBlock message_block;
  297     static String nothing = "";
  298     String label;
  299     Pixmap bitmap;
  300 
  301     /* Reset to a known state. */
  302     psfree(olddoc);
  303     olddoc = doc;
  304     doc = NULL;
  305     current_page = -1;
  306     if (toc_text) XtFree(toc_text);
  307     oldtoc_entry_length = toc_entry_length;
  308     toc_text = NULL;
  309 
  310     /* Scan document and start setting things up */
  311     if (psfile) doc = psscan(psfile);
  312 
  313     if (app_res.show_title) {
  314     if (doc && doc->title) {
  315         label = doc->title;
  316         bitmap = menu16_bitmap;
  317     } else {
  318         if (filename) {
  319         label = filename;
  320         } else {
  321         label = "";
  322         }
  323         bitmap = None;
  324     }
  325     XtSetArg(args[0], XtNlabel, label);
  326     XtSetValues(titlebutton, args, ONE);
  327     if (titlemenu) XtDestroyWidget(titlemenu);
  328     titlemenu = build_label_menu(titlebutton, "title", label, bitmap);
  329     }
  330 
  331     if (app_res.show_date) {
  332     if (doc && doc->date) {
  333         label = doc->date;
  334         bitmap = menu16_bitmap;
  335     } else {
  336         if (psfile) {
  337         label = ctime(&mtime);
  338         } else {
  339         label = "";
  340         }
  341         bitmap = None;
  342     }
  343     XtSetArg(args[0], XtNlabel, label);
  344     XtSetValues(datebutton, args, ONE);
  345     if (datemenu) XtDestroyWidget(datemenu);
  346     datemenu = build_label_menu(datebutton, "date", label, bitmap);
  347     }
  348 
  349     build_pagemedia_menu();
  350 
  351     /* Reset ghostscript and output messages popup */
  352     if (!doc || !olddoc ||
  353     strcmp(oldfilename, filename) ||
  354     olddoc->beginprolog != doc->beginprolog ||
  355     olddoc->endprolog != doc->endprolog ||
  356     olddoc->beginsetup != doc->beginsetup ||
  357     olddoc->endsetup != doc->endsetup) {
  358 
  359     GhostviewDisableInterpreter(page);
  360     XtPopdown(infopopup);
  361     info_up = False;
  362     XtSetArg(args[0], XtNeditType, XawtextEdit);
  363     XtSetArg(args[1], XtNinsertPosition, 0);
  364     XtSetValues(infotext, args, TWO);
  365     message_block.length = 0;
  366     XawTextReplace(infotext, 0, info_length, &message_block);
  367     info_length = 0;
  368     XtSetArg(args[0], XtNeditType, XawtextRead);
  369     XtSetValues(infotext, args, ONE);
  370     }
  371 
  372     /* Build table of contents */
  373     if (doc && (!doc->epsf && doc->numpages > 0 ||
  374          doc->epsf && doc->numpages > 1)) {
  375     int maxlen = 0;
  376     int i, j;
  377     useful_page_labels = False;
  378 
  379     if (doc->numpages == 1) useful_page_labels = True;
  380     for (i = 1; i < doc->numpages; i++)
  381         if (useful_page_labels = (useful_page_labels ||
  382             strcmp(doc->pages[i-1].label, doc->pages[i].label))) break;
  383     if (useful_page_labels) {
  384         for (i = 0; i < doc->numpages; i++) 
  385         maxlen = max(maxlen, strlen(doc->pages[i].label));
  386     } else {
  387         double x;
  388         x = doc->numpages;
  389         maxlen = log10(x) + 1;
  390     }
  391     toc_entry_length = maxlen + 3;
  392     toc_length = doc->numpages * toc_entry_length - 1;
  393     toc_text = XtMalloc(toc_length + 2); /* include final NULL */
  394 
  395     for (i = 0, tocp = toc_text; i < doc->numpages;
  396          i++, tocp += toc_entry_length) {
  397         if (useful_page_labels) {
  398         if (doc->pageorder == DESCEND) {
  399             j = (doc->numpages - 1) - i;
  400         } else {
  401             j = i;
  402         }
  403         sprintf(tocp, " %*s \n", maxlen, doc->pages[j].label);
  404         } else {
  405         sprintf(tocp, " %*d \n", maxlen, i+1);
  406         }
  407     }
  408     toc_text[toc_length] = '\0';
  409                                     num_args = 0;
  410     XtSetArg(args[num_args], XtNfilename, NULL);        num_args++;
  411     XtSetValues(page, args, num_args);
  412     } else {
  413     toc_length = 0;
  414     toc_entry_length = 3;
  415                                     num_args = 0;
  416     XtSetArg(args[num_args], XtNfilename, filename);        num_args++;
  417     XtSetValues(page, args, num_args);
  418     }
  419                                 num_args = 0;
  420     XtSetArg(args[num_args], XtNlength, toc_length);        num_args++;
  421     if (toc_text) {
  422     XtSetArg(args[num_args], XtNstring, toc_text);      num_args++;
  423     } else {
  424     /* Text widget sometime blows up when given a NULL pointer */
  425     XtSetArg(args[num_args], XtNstring, nothing);       num_args++;
  426     }
  427     XtSetValues(toc, args, num_args);
  428 
  429     XtSetSensitive(reopenbutton, (psfile != NULL));
  430     XtSetSensitive(printwholebutton, (psfile != NULL));
  431     XtSetSensitive(printmarkedbutton, (psfile != NULL));
  432     XtSetSensitive(savebutton, (toc_text != NULL));
  433     XtSetSensitive(nextbutton, (filename != NULL));
  434     XtSetSensitive(showbutton, (filename != NULL));
  435     XtSetSensitive(prevbutton, (toc_text != NULL));
  436     XtSetSensitive(centerbutton, (filename != NULL));
  437     XtSetSensitive(markbutton, (toc_text != NULL));
  438     XtSetSensitive(unmarkbutton, (toc_text != NULL));
  439 
  440     return oldtoc_entry_length != toc_entry_length;
  441 }
  442 
  443 int
  444 find_page(label)
  445     String label;
  446 {
  447     int i, j;
  448 
  449     if (label == NULL || doc == NULL) return 0;
  450 
  451     if (useful_page_labels) {
  452     for (i = 0; i < doc->numpages; i++) {
  453         if (doc->pageorder == DESCEND) {
  454         j = (doc->numpages - 1) - i;
  455         } else {
  456         j = i;
  457         }
  458         if (!strcmp(label, doc->pages[j].label)) return i;
  459     }
  460     return 0;
  461     } else {
  462     return atoi(label) - 1;
  463     }
  464 }
  465 
  466 /* try_try_again sets the geometry of the form when the form failed
  467  * to do it earlier.  It uses activity check with exponential backoff
  468  * to make sure that the dust has settled before trying again.
  469  */
  470 static unsigned int delay = 125;    /* Start with 1/8 second delay */
  471 
  472 static void
  473 try_try_again(client_data, timer)
  474     XtPointer client_data;
  475     XtIntervalId *timer;
  476 {
  477     XSync(XtDisplay(toplevel), False);  /* Push everything out */
  478     if (XtAppPending(app_con)) {
  479     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  480     /* fprintf(stderr, "Delaying(%d)...\n",delay); */
  481     delay *= 2;
  482     } else {
  483     /* fprintf(stderr, "Trying again...\n"); */
  484     layout_ghostview();
  485     }
  486 }
  487 
  488 /* set the dimensions for items in the main form widget. */
  489 /* set foreground and background color in scrollbars. */
  490 /* (The scroll bars come and go as size changes.) */
  491 /* Set window manager hints to keep window manager from causing main */
  492 /* viewport from growing too large */
  493 void
  494 layout_ghostview()
  495 {
  496     Arg args[20];
  497     Cardinal num_args;
  498     Widget w;
  499     /* Yuck, cannot get vScrollbar via the usual methods */
  500     TextWidget tw;
  501     Dimension min_width, min_height;
  502     Dimension max_width, max_height;
  503     Dimension form_width, form_height;
  504     Dimension title_height, title_border;
  505     Dimension date_height, date_border;
  506     Dimension locator_height, locator_border;
  507     Dimension box_width, box_height, box_border;
  508     Dimension label_width;
  509     Dimension toc_width, toc_height, toc_border;
  510     Dimension view_width, view_height, view_border;
  511     Dimension page_width, page_height;
  512     Dimension leftMargin, rightMargin;
  513     Dimension width, height;
  514     Boolean correct = True;
  515     int distance;
  516     int a_label;
  517     XFontStruct *font;
  518 
  519     XawFormDoLayout(form, False);
  520     reset_size_hints();
  521     reset_scroll_bars();
  522     break_chains();
  523 
  524     XtSetArg(args[0], XtNdefaultDistance, &distance);
  525     XtGetValues(form, args, ONE);
  526 
  527     a_label = 0;
  528     if (app_res.show_title) {
  529     XtSetArg(args[0], XtNheight, &title_height);
  530     XtSetArg(args[1], XtNborderWidth, &title_border);
  531     XtGetValues(titlebutton, args, TWO);
  532     a_label = 1;
  533     } else {
  534     title_height = title_border = 0;
  535     }
  536 
  537     if (app_res.show_date) {
  538     XtSetArg(args[0], XtNheight, &date_height);
  539     XtSetArg(args[1], XtNborderWidth, &date_border);
  540     XtGetValues(datebutton, args, TWO);
  541     a_label = 1;
  542     } else {
  543     date_height = date_border = 0;
  544     }
  545 
  546     if (app_res.show_locator) {
  547     XtSetArg(args[0], XtNheight, &locator_height);
  548     XtSetArg(args[1], XtNborderWidth, &locator_border);
  549     XtGetValues(locator, args, TWO);
  550     a_label = 1;
  551     } else {
  552     locator_height = locator_border = 0;
  553     }
  554 
  555     XtSetArg(args[0], XtNwidth, &box_width);
  556     XtSetArg(args[1], XtNheight, &box_height);
  557     XtSetArg(args[2], XtNborderWidth, &box_border);
  558     XtGetValues(box, args, THREE);
  559 
  560     XtSetArg(args[0], XtNfont, &font);
  561     XtSetArg(args[1], XtNleftMargin, &leftMargin);
  562     XtSetArg(args[2], XtNrightMargin, &rightMargin);
  563     XtSetArg(args[3], XtNborderWidth, &toc_border);
  564     XtGetValues(toc, args, FOUR);
  565     toc_width = font->max_bounds.width * (toc_entry_length - 1) +
  566         leftMargin + rightMargin;
  567 
  568     XtSetArg(args[0], XtNwidth, &page_width);
  569     XtSetArg(args[1], XtNheight, &page_height);
  570     XtGetValues(page, args, TWO);
  571 
  572     XtSetArg(args[0], XtNborderWidth, &view_border);
  573     XtGetValues(pageview, args, ONE);
  574     view_width = page_width;
  575     view_height = page_height;
  576 
  577     min_width = box_width + 2*box_border + toc_width + 2*toc_border +
  578         2*view_border + 4*distance;
  579     min_height = title_height + 2*title_border + date_height + 2*date_border +
  580          locator_height + 2*locator_border + box_height + 2*box_border +
  581          (2+a_label)*distance;
  582 
  583     max_width = WidthOfScreen(XtScreen(toplevel)) - app_res.wm_horiz_margin;
  584     max_height = HeightOfScreen(XtScreen(toplevel)) - app_res.wm_vert_margin;
  585 
  586     if (min_width + view_width > max_width)
  587     view_width = max_width - min_width;
  588     if (2*(view_border + distance) + view_height > max_height)
  589     view_height = max_height - 2*(view_border + distance);
  590     form_width = view_width + min_width;
  591     form_height = max(view_height + 2*(view_border + distance), min_height);
  592     toc_height = view_height - (title_height + 2*title_border +
  593                 date_height + 2*date_border +
  594                 locator_height + 2*locator_border +
  595                 a_label*distance);
  596 
  597     label_width = box_width + 2*box_border + distance +
  598           toc_width + 2*toc_border;
  599 
  600     XtSetArg(args[0], XtNwidth, form_width);
  601     XtSetArg(args[1], XtNheight, form_height);
  602     XtSetValues(form, args, TWO);
  603 
  604     XtSetArg(args[0], XtNwidth, label_width);
  605     if (app_res.show_title) XtSetValues(titlebutton, args, ONE);
  606     if (app_res.show_date) XtSetValues(datebutton, args, ONE);
  607     if (app_res.show_locator) XtSetValues(locator, args, ONE);
  608 
  609     XtSetArg(args[0], XtNwidth, toc_width);
  610     XtSetArg(args[1], XtNheight, toc_height);
  611     XtSetValues(toc, args, TWO);
  612 
  613     XtSetArg(args[0], XtNwidth, view_width);
  614     XtSetArg(args[1], XtNheight, view_height);
  615     XtSetValues(pageview, args, TWO);
  616 
  617     XawFormDoLayout(form, True);
  618 
  619     /* Check to make sure everything was done as planned. */
  620     XtSetArg(args[0], XtNwidth, &width);
  621     XtSetArg(args[1], XtNheight, &height);
  622 
  623     XtGetValues(form, args, TWO);
  624     if (width != form_width || height != form_height) {
  625     correct = False;
  626     /* fprintf(stderr, "Oops, %dx%d form was supposed to be %dx%d.\n",
  627         width, height, form_width, form_height); */
  628     }
  629     if (app_res.show_title) {
  630     XtGetValues(titlebutton, args, ONE);
  631     if (width != label_width) {
  632         correct = False;
  633         /* fprintf(stderr,
  634         "Oops, %d wide title was supposed to be %d wide.\n",
  635         width, label_width); */
  636     }
  637     }
  638     if (app_res.show_date) {
  639     XtGetValues(datebutton, args, ONE);
  640     if (width != label_width) {
  641         correct = False;
  642         /* fprintf(stderr,
  643         "Oops, %d wide date was supposed to be %d wide.\n",
  644         width, label_width); */
  645     }
  646     }
  647     if (app_res.show_locator) {
  648     XtGetValues(locator, args, ONE);
  649     if (width != label_width) {
  650         correct = False;
  651         /* fprintf(stderr,
  652         "Oops, %d wide locator was supposed to be %d wide.\n",
  653         width, label_width); */
  654     }
  655     }
  656     XtGetValues(toc, args, TWO);
  657     if (width != toc_width || height != toc_height) {
  658     correct = False;
  659     /* fprintf(stderr, "Oops, %dx%d toc was supposed to be %dx%d.\n",
  660         width, height, toc_width, toc_height); */
  661     }
  662     XtGetValues(pageview, args, TWO);
  663     if (width != view_width || height != view_height) {
  664     correct = False;
  665     /* fprintf(stderr, "Oops, %dx%d pageview was supposed to be %dx%d.\n",
  666         width, height, view_width, view_height); */
  667     }
  668 
  669     if (correct) {
  670     if (special_cmap) {
  671         /* Yuck, cannot get vScrollbar via the usual methods */
  672         /* w = XtNameToWidget(toc, "*vScrollbar"); */
  673         tw = (TextWidget) toc;
  674         w = tw->text.vbar;
  675         if (w) {
  676         /* Double Yuck, have to set them twice to make them */
  677         /* get the right colors */
  678                                 num_args = 0;
  679         XtSetArg(args[num_args], XtNforeground, white); num_args++;
  680         XtSetArg(args[num_args], XtNbackground, black); num_args++;
  681         XtSetValues(w, args, num_args);
  682                                 num_args = 0;
  683         XtSetArg(args[num_args], XtNforeground, black); num_args++;
  684         XtSetArg(args[num_args], XtNbackground, white); num_args++;
  685         XtSetValues(w, args, num_args);
  686         }
  687 
  688         w = XtNameToWidget(pageview, "horizontal");
  689         if (w) {
  690                                 num_args = 0;
  691         XtSetArg(args[num_args], XtNforeground, black); num_args++;
  692         XtSetArg(args[num_args], XtNbackground, white); num_args++;
  693         XtSetValues(w, args, num_args);
  694         }
  695 
  696         w = XtNameToWidget(pageview, "vertical");
  697         if (w) {
  698                                 num_args = 0;
  699         XtSetArg(args[num_args], XtNforeground, black); num_args++;
  700         XtSetArg(args[num_args], XtNbackground, white); num_args++;
  701         XtSetValues(w, args, num_args);
  702         }
  703     }
  704 
  705     set_size_hints(min_width, min_height, min_width+page_width,
  706                max(form_height,
  707                page_height + 2*(view_border + distance)));
  708     if (app_res.auto_center) {
  709         horiz_scroll_saved = vert_scroll_saved = False;
  710         center_page(form, NULL, NULL);
  711     } else {
  712         set_scroll_bars();
  713     }
  714     set_chains();
  715     delay = 125;    /* Reset to 1/8 second delay */
  716     /* fprintf(stderr, "Layout correct.\n"); */
  717     } else {
  718     XSync(XtDisplay(toplevel), False);
  719     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  720     /* fprintf(stderr, "Didn't work, scheduling(%d)...\n",delay); */
  721     }
  722 
  723 }
  724 
  725 /* Create a Standard colormap for ghostscript to use. */
  726 void
  727 SetStandardColormap(w)
  728     Widget w;
  729 {
  730     XVisualInfo xvinfo;
  731     XVisualInfo *xvinfop;
  732     Atom prop;
  733     XStandardColormap *std_cmap = NULL;
  734     XStandardColormap *scmap, *sp;
  735     Screen *scr = DefaultScreenOfDisplay(XtDisplay(w));
  736     int nitems, i;
  737     Boolean has_color;
  738     Arg args[20];
  739     Cardinal num_args;
  740 
  741     XtSetArg(args[0], XtNvisual, &(xvinfo.visual));
  742     XtGetValues(w, args, ONE);
  743     if (xvinfo.visual == CopyFromParent)
  744     xvinfo.visual = DefaultVisualOfScreen(scr);
  745     xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
  746     xvinfop = XGetVisualInfo(XtDisplay(w), VisualIDMask, &xvinfo, &nitems);
  747     if (xvinfop == NULL) {
  748         fprintf(stderr, "Bad visual class.\n");
  749     exit(1);
  750     }
  751     xvinfo = *xvinfop;
  752     XtFree((char *)xvinfop);
  753 
  754     has_color = (xvinfo.class != StaticGray) && (xvinfo.class != GrayScale);
  755 
  756     if (has_color) {
  757     if (xvinfo.visual == DefaultVisualOfScreen(scr)) {
  758         prop = XA_RGB_DEFAULT_MAP;
  759     } else {
  760         prop = XA_RGB_BEST_MAP;
  761     }
  762     } else {
  763     prop = XA_RGB_GRAY_MAP;
  764     }
  765 
  766     if (XGetRGBColormaps(XtDisplay(w), RootWindowOfScreen(scr),
  767              &scmap, &nitems, prop)) {
  768     for (i = 0, sp = scmap; i < nitems; i++, sp++) {
  769         if (xvinfo.visualid == sp->visualid) {
  770         std_cmap = sp;
  771         break;
  772         }
  773     }
  774     }
  775 
  776     if (!std_cmap && app_res.install_std_cmap) {
  777     if (XmuLookupStandardColormap(XtDisplay(w),
  778                       DefaultScreen(XtDisplay(w)),
  779                       xvinfo.visualid, xvinfo.depth,
  780                       prop, False, app_res.retain_std_cmap)) {
  781         if (XGetRGBColormaps(XtDisplay(w), RootWindowOfScreen(scr),
  782                  &scmap, &nitems, prop)) {
  783         for (i = 0, sp = scmap; i < nitems; i++, sp++) {
  784             if (xvinfo.visualid == sp->visualid) {
  785             std_cmap = sp;
  786             }
  787         }
  788         }
  789     }
  790     }
  791 
  792     if (std_cmap && xvinfo.visual == DefaultVisualOfScreen(scr) &&
  793     std_cmap->colormap != DefaultColormapOfScreen(scr) &&
  794     !app_res.private_cmap) {
  795     std_cmap = NULL;
  796     }
  797     if (std_cmap) {
  798     cmap = std_cmap->colormap;
  799     if (std_cmap->colormap != DefaultColormapOfScreen(scr)) {
  800         black = std_cmap->base_pixel;
  801         white = std_cmap->red_max * std_cmap->red_mult +
  802             std_cmap->green_max * std_cmap->green_mult +
  803             std_cmap->blue_max * std_cmap->blue_mult +
  804             std_cmap->base_pixel;
  805     } else {
  806         white = WhitePixelOfScreen(scr);
  807         black = BlackPixelOfScreen(scr);
  808     }
  809     } else {
  810     if (xvinfo.visual == DefaultVisualOfScreen(scr)) {
  811         cmap = DefaultColormapOfScreen(scr);
  812         white = WhitePixelOfScreen(scr);
  813         black = BlackPixelOfScreen(scr);
  814     } else {
  815         XColor c;
  816         cmap = XCreateColormap(XtDisplay(w), RootWindowOfScreen(scr),
  817                    xvinfo.visual, AllocNone);
  818         c.red = c.green = c.blue = ~(unsigned short)0;
  819         XAllocColor(XtDisplay(w), cmap, &c);
  820         white = c.pixel;
  821         c.red = c.green = c.blue = 0;
  822         XAllocColor(XtDisplay(w), cmap, &c);
  823         black = c.pixel;
  824     }
  825     }
  826     special_cmap = cmap != DefaultColormapOfScreen(scr);
  827 
  828                             num_args = 0;
  829     XtSetArg(args[num_args], XtNcolormap, cmap);    num_args++;
  830     if (special_cmap) {
  831     XtSetArg(args[num_args], XtNforeground, black); num_args++;
  832     XtSetArg(args[num_args], XtNbackground, white); num_args++;
  833     }
  834     XtSetValues(w, args, num_args);
  835 }
  836 
  837 /* Compute new dpi from magstep */
  838 void
  839 magnify(dpi, magstep)
  840     float *dpi;
  841     int    magstep;
  842 {
  843     if (magstep < 0) {
  844     while (magstep++) *dpi /= 1.2;
  845     } else {
  846     while (magstep--) *dpi *= 1.2;
  847     }
  848 }
  849 
  850 /* Attempt to open file, return error message string on failure */
  851 String
  852 open_file(name)
  853     String name;
  854 {
  855     FILE *fp;
  856     struct stat sbuf;
  857 
  858     if (*name == '\0') {    /* Null filename */
  859     return(NULL);
  860     }
  861     if (strcmp(name, "-")) {
  862     if ((fp = fopen(name, "r")) == NULL) {
  863         String buf = XtMalloc(strlen(app_res.open_fail) +
  864                   strlen(sys_errlist[errno]) + 1);
  865         strcpy(buf, app_res.open_fail);
  866         if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  867         return buf;
  868     } else {
  869         if (oldfilename) XtFree(oldfilename);
  870         oldfilename = filename;
  871         filename = XtNewString(name);
  872         if (psfile) fclose(psfile);
  873         psfile = fp;
  874         stat(filename, &sbuf);
  875         mtime = sbuf.st_mtime;
  876         new_file(0);
  877         show_page(0);
  878         return(NULL);
  879     }
  880     } else {
  881     if (oldfilename) XtFree(oldfilename);
  882     oldfilename = filename;
  883     filename = XtNewString(name);
  884     if (psfile) fclose(psfile);
  885     psfile = NULL;
  886     new_file(0);
  887     show_page(0);
  888     return(NULL);
  889     }
  890 }
  891 
  892 /* Attempt to save file, return error message string on failure */
  893 String
  894 save_file(name)
  895     String name;
  896 {
  897     FILE *pswrite;
  898 
  899     if (*name == '\0') {    /* Null filename */
  900     return(NULL);
  901     }
  902     if ((pswrite = fopen(name, "w")) == NULL) {
  903     String buf = XtMalloc(strlen(app_res.save_fail) +
  904                   strlen(sys_errlist[errno]) + 1);
  905     strcpy(buf, app_res.save_fail);
  906     if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  907     return buf;
  908     } else {
  909     pscopydoc(pswrite);
  910     fclose(pswrite);
  911     return(NULL);
  912     }
  913 }
  914 
  915 /* Attempt to print file.  Return error string on failure */ 
  916 String
  917 print_file(name, whole_mode)
  918     String name;
  919     Boolean whole_mode;
  920 {
  921     FILE *printer;
  922     SIGVAL (*oldsig)();
  923     int bytes;
  924     char buf[BUFSIZ];
  925 #ifdef VMS
  926     char fnam[64], *p;
  927 #endif
  928     Boolean failed;
  929     String ret_val;
  930 
  931 #ifdef VMS
  932     sprintf(fnam, "sys$scratch:%s.tmp", tmpnam(NULL));
  933     printer = fopen(fnam, "w");
  934 #else /* VMS */
  935     if (*name != '\0') {
  936     setenv(app_res.printer_variable, name, True);
  937     }
  938     oldsig = signal(SIGPIPE, SIG_IGN);
  939     printer = popen(app_res.print_command, "w");
  940 #endif /* VMS */
  941     if (toc_text && !whole_mode) {
  942     pscopydoc(printer);
  943     } else {
  944     FILE *psfile = fopen(filename, "r");
  945     while (bytes = read(fileno(psfile), buf, BUFSIZ))
  946         bytes = write(fileno(printer), buf, bytes);
  947     fclose(psfile);
  948     }
  949 #ifdef VMS
  950     sprintf(buf, "%s %s %s", app_res.print_command, name, fnam);
  951     failed = fclose(printer) != 0 || system(buf) != 1;
  952 #else /* VMS */
  953     failed = pclose(printer) != 0;
  954 #endif /* VMS */
  955     if (failed) {
  956     sprintf(buf, app_res.print_fail, app_res.print_command);
  957     ret_val = XtNewString(buf);
  958     } else {
  959     ret_val = NULL;
  960     }
  961 #ifndef VMS
  962     signal(SIGPIPE, oldsig);
  963 #endif /* VMS */
  964     return(ret_val);
  965 }
  966 
  967 /* length calculates string length at compile time */
  968 /* can only be used with character constants */
  969 #define length(a) (sizeof(a)-1)
  970 
  971 /* Copy the headers, marked pages, and trailer to fp */
  972 void
  973 pscopydoc(fp)
  974     FILE *fp;
  975 {
  976     FILE *psfile;
  977     char text[PSLINELENGTH];
  978     char *comment;
  979     Boolean pages_written = False;
  980     Boolean pages_atend = False;
  981     Boolean marked_pages = False;
  982     int pages = 0;
  983     int page = 1;
  984     int i, j;
  985     long here;
  986 
  987     psfile = fopen(filename, "r");
  988 
  989     for (i = 0; i < doc->numpages; i++) {
  990     if (toc_text[toc_entry_length * i] == '*') pages++;
  991     }
  992 
  993     if (pages == 0) {   /* User forgot to mark the pages */
  994     mark_page(form, NULL, NULL);
  995     marked_pages = True;
  996     for (i = 0; i < doc->numpages; i++) {
  997         if (toc_text[toc_entry_length * i] == '*') pages++;
  998     }
  999     }
 1000 
 1001     here = doc->beginheader;
 1002     while (comment = pscopyuntil(psfile, fp, here,
 1003                  doc->endheader, "%%Pages:")) {
 1004     here = ftell(psfile);
 1005     if (pages_written || pages_atend) {
 1006         free(comment);
 1007         continue;
 1008     }
 1009     sscanf(comment+length("%%Pages:"), "%s", text);
 1010     if (strcmp(text, "(atend)") == 0) {
 1011         fputs(comment, fp);
 1012         pages_atend = True;
 1013     } else {
 1014         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
 1015         case 1:
 1016             fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
 1017             break;
 1018         default:
 1019             fprintf(fp, "%%%%Pages: %d\n", pages);
 1020             break;
 1021         }
 1022         pages_written = True;
 1023     }
 1024     free(comment);
 1025     }
 1026     pscopy(psfile, fp, doc->beginpreview, doc->endpreview);
 1027     pscopy(psfile, fp, doc->begindefaults, doc->enddefaults);
 1028     pscopy(psfile, fp, doc->beginprolog, doc->endprolog);
 1029     pscopy(psfile, fp, doc->beginsetup, doc->endsetup);
 1030 
 1031     for (i = 0; i < doc->numpages; i++) {
 1032     if (doc->pageorder == DESCEND) 
 1033         j = (doc->numpages - 1) - i;
 1034     else
 1035         j = i;
 1036     if (toc_text[toc_entry_length * j] == '*') {
 1037         comment = pscopyuntil(psfile, fp, doc->pages[i].begin,
 1038                   doc->pages[i].end, "%%Page:");
 1039         fprintf(fp, "%%%%Page: %s %d\n",
 1040             doc->pages[i].label, page++);
 1041         free(comment);
 1042         pscopy(psfile, fp, -1, doc->pages[i].end);
 1043     }
 1044     }
 1045 
 1046     here = doc->begintrailer;
 1047     while (comment = pscopyuntil(psfile, fp, here,
 1048                  doc->endtrailer, "%%Pages:")) {
 1049     here = ftell(psfile);
 1050     if (pages_written) {
 1051         free(comment);
 1052         continue;
 1053     }
 1054     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
 1055         case 1:
 1056         fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
 1057         break;
 1058         default:
 1059         fprintf(fp, "%%%%Pages: %d\n", pages);
 1060         break;
 1061     }
 1062     pages_written = True;
 1063     free(comment);
 1064     }
 1065     fclose(psfile);
 1066 
 1067     if (marked_pages) unmark_page(form, NULL, NULL);
 1068 }
 1069 #undef length
 1070 
 1071 /* position popup window under the cursor */
 1072 void
 1073 positionpopup(w)
 1074     Widget w;
 1075 {
 1076     Arg args[3];
 1077     Cardinal num_args;
 1078     Dimension width, height, b_width;
 1079     int x, y, max_x, max_y;
 1080     Window root, child;
 1081     int dummyx, dummyy;
 1082     unsigned int dummymask;
 1083     
 1084     XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
 1085           &dummyx, &dummyy, &dummymask);
 1086     num_args = 0;
 1087     XtSetArg(args[num_args], XtNwidth, &width); num_args++;
 1088     XtSetArg(args[num_args], XtNheight, &height); num_args++;
 1089     XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
 1090     XtGetValues(w, args, num_args);
 1091 
 1092     width += 2 * b_width;
 1093     height += 2 * b_width;
 1094 
 1095     x -= ( (Position) width/2 );
 1096     if (x < 0) x = 0;
 1097     if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
 1098 
 1099     y -= ( (Position) height/2 );
 1100     if (y < 0) y = 0;
 1101     if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
 1102     
 1103     num_args = 0;
 1104     XtSetArg(args[num_args], XtNx, x); num_args++;
 1105     XtSetArg(args[num_args], XtNy, y); num_args++;
 1106     XtSetValues(w, args, num_args);
 1107 }
 1108 
 1109 /* Set new magstep */
 1110 Boolean
 1111 set_new_magstep()
 1112 {
 1113     int new_magstep;
 1114     Boolean changed = False;
 1115     Arg args[20];
 1116     Cardinal num_args;
 1117     float xdpi, ydpi;
 1118 
 1119     new_magstep = app_res.magstep;
 1120     /* If magstep changed, stop interpreter and setup for new dpi. */
 1121     if (new_magstep != current_magstep) {
 1122     GhostviewDisableInterpreter(page);
 1123     XawFormDoLayout(form, False);
 1124     reset_size_hints();
 1125     reset_scroll_bars();
 1126     break_chains();
 1127     changed = True;
 1128     xdpi = default_xdpi;
 1129     ydpi = default_ydpi;
 1130     magnify(&xdpi, new_magstep);
 1131     magnify(&ydpi, new_magstep);
 1132                             num_args = 0;
 1133     XtSetFloatArg(args[num_args], XtNxdpi, xdpi);   num_args++;
 1134     XtSetFloatArg(args[num_args], XtNydpi, ydpi);   num_args++;
 1135     XtSetValues(page, args, num_args);
 1136 
 1137     XtSetArg(args[0], XtNleftBitmap, None);
 1138     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
 1139             args, ONE);
 1140     current_magstep = new_magstep;
 1141     }
 1142     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
 1143     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
 1144         args, ONE);
 1145 
 1146     return changed;
 1147 }
 1148 
 1149 /* Set new orientation */
 1150 Boolean
 1151 set_new_orientation(number)
 1152     int number;
 1153 {
 1154     Boolean changed = False;
 1155     Boolean from_doc = False;
 1156     Arg args[1];
 1157     XtPageOrientation new_orientation;
 1158 
 1159     if (app_res.force_orientation) {
 1160     new_orientation = app_res.orientation;
 1161     } else {
 1162     if (doc) {
 1163         if (toc_text && doc->pages[number].orientation != NONE) {
 1164         new_orientation = xorient(doc->pages[number].orientation);
 1165         from_doc = True;
 1166         } else if (doc->default_page_orientation != NONE) {
 1167         new_orientation = xorient(doc->default_page_orientation);
 1168         from_doc = True;
 1169         } else if (doc->orientation != NONE) {
 1170         new_orientation = xorient(doc->orientation);
 1171         from_doc = True;
 1172         } else {
 1173         new_orientation = app_res.orientation;
 1174         }
 1175     } else {
 1176         new_orientation = app_res.orientation;
 1177     }
 1178     }
 1179 
 1180     /* If orientation changed,
 1181      * stop interpreter and setup for new orientation. */
 1182     if (new_orientation != current_orientation) {
 1183     GhostviewDisableInterpreter(page);
 1184     XawFormDoLayout(form, False);
 1185     reset_size_hints();
 1186     reset_scroll_bars();
 1187     break_chains();
 1188     changed = True;
 1189     XtSetArg(args[0], XtNorientation, new_orientation);
 1190     XtSetValues(page, args, ONE);
 1191     XtSetArg(args[0], XtNleftBitmap, None);
 1192     if (current_orientation == XtPageOrientationPortrait) 
 1193         XtSetValues(portraitbutton, args, ONE);
 1194     else if (current_orientation == XtPageOrientationLandscape)
 1195             XtSetValues(landscapebutton, args, ONE);
 1196         else if (current_orientation == XtPageOrientationUpsideDown)
 1197             XtSetValues(upsidedownbutton, args, ONE);
 1198         else if (current_orientation == XtPageOrientationSeascape)
 1199             XtSetValues(seascapebutton, args, ONE);
 1200     current_orientation = new_orientation;
 1201     }
 1202 
 1203     /* mark forced orientation with tie fighter. ("Use the force, Luke") */
 1204     if (app_res.force_orientation) {
 1205     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
 1206     } else if (from_doc) {
 1207     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
 1208     } else {
 1209     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
 1210     }
 1211     if (current_orientation == XtPageOrientationPortrait) 
 1212     XtSetValues(portraitbutton, args, ONE);
 1213     else if (current_orientation == XtPageOrientationLandscape)
 1214     XtSetValues(landscapebutton, args, ONE);
 1215     else if (current_orientation == XtPageOrientationUpsideDown)
 1216     XtSetValues(upsidedownbutton, args, ONE);
 1217     else if (current_orientation == XtPageOrientationSeascape)
 1218     XtSetValues(seascapebutton, args, ONE);
 1219     
 1220     return changed;
 1221 }
 1222 
 1223 /* Set new pagemedia */
 1224 Boolean
 1225 set_new_pagemedia(number)
 1226     int number;
 1227 {
 1228     int new_pagemedia;
 1229     int new_llx;
 1230     int new_lly;
 1231     int new_urx;
 1232     int new_ury;
 1233     Boolean changed = False;
 1234     Boolean from_doc = False;
 1235     Arg args[4];
 1236 
 1237     if (force_document_media) {
 1238     new_pagemedia = document_media;
 1239     } else if (app_res.force_pagemedia) {
 1240     new_pagemedia = default_pagemedia;
 1241     } else {
 1242     if (doc) {
 1243         if (toc_text && doc->pages[number].media != NULL) {
 1244         new_pagemedia = doc->pages[number].media - doc->media;
 1245         from_doc = True;
 1246         } else if (doc->default_page_media != NULL) {
 1247         new_pagemedia = doc->default_page_media - doc->media;
 1248         from_doc = True;
 1249         } else {
 1250         new_pagemedia = default_pagemedia;
 1251         }
 1252     } else {
 1253         new_pagemedia = default_pagemedia;
 1254     }
 1255     }
 1256 
 1257     /* If pagemedia changed, remove the old marker. */
 1258     if (new_pagemedia != current_pagemedia) {
 1259     XtSetArg(args[0], XtNleftBitmap, None);
 1260     if (pagemediaentry[current_pagemedia])
 1261         XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
 1262     else
 1263         XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
 1264 
 1265     current_pagemedia = new_pagemedia;
 1266     }
 1267 
 1268     /* mark forced page media with tie fighter. ("Use the force, Luke") */
 1269     if (force_document_media || app_res.force_pagemedia) {
 1270     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
 1271     } else if (from_doc) {
 1272     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
 1273     } else {
 1274     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
 1275     }
 1276     if (pagemediaentry[current_pagemedia])
 1277     XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
 1278     else
 1279     XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
 1280 
 1281     /* Compute bounding box */
 1282     if (!force_document_media && !app_res.force_pagemedia &&
 1283     doc && doc->epsf &&
 1284     /* Ignore malformed bounding boxes */
 1285     (doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
 1286     (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
 1287     new_llx = doc->boundingbox[LLX];
 1288     new_lly = doc->boundingbox[LLY];
 1289     new_urx = doc->boundingbox[URX];
 1290     new_ury = doc->boundingbox[URY];
 1291     } else {
 1292     new_llx = new_lly = 0;
 1293     if (new_pagemedia < base_papersize) {
 1294         new_urx = doc->media[new_pagemedia].width;
 1295         new_ury = doc->media[new_pagemedia].height;
 1296     } else {
 1297         new_urx = papersizes[new_pagemedia-base_papersize].width;
 1298         new_ury = papersizes[new_pagemedia-base_papersize].height;
 1299     }
 1300     }
 1301 
 1302     /* If bounding box changed, setup for new size. */
 1303     if ((new_llx != current_llx) || (new_lly != current_lly) ||
 1304     (new_urx != current_urx) || (new_ury != current_ury)) {
 1305     GhostviewDisableInterpreter(page);
 1306     XawFormDoLayout(form, False);
 1307     reset_size_hints();
 1308     reset_scroll_bars();
 1309     break_chains();
 1310     changed = True;
 1311     current_llx = new_llx;
 1312     current_lly = new_lly;
 1313     current_urx = new_urx;
 1314     current_ury = new_ury;
 1315     XtSetArg(args[0], XtNllx, current_llx);
 1316     XtSetArg(args[1], XtNlly, current_lly);
 1317     XtSetArg(args[2], XtNurx, current_urx);
 1318     XtSetArg(args[3], XtNury, current_ury);
 1319     XtSetValues(page, args, FOUR);
 1320     }
 1321 
 1322     return changed;
 1323 }
 1324 
 1325 static Boolean
 1326 same_document_media()
 1327 {
 1328     int i;
 1329 
 1330     if (olddoc == NULL && doc == NULL) return True;
 1331     if (olddoc == NULL || doc == NULL) return False;
 1332     if (olddoc->nummedia != doc->nummedia) return False;
 1333     for (i = 0; i < doc->nummedia; i++)
 1334     if (strcmp(olddoc->media[i].name, doc->media[i].name)) return False;
 1335     return True;
 1336 }
 1337 
 1338 void
 1339 build_pagemedia_menu()
 1340 {
 1341     Arg args[20];
 1342     Cardinal num_args;
 1343     Widget w;
 1344     int i;
 1345 
 1346     if (pagemediamenu && same_document_media()) return;
 1347     if (pagemediamenu) XtDestroyWidget(pagemediamenu);
 1348     force_document_media = False;
 1349 
 1350                             num_args = 0;
 1351     XtSetArg(args[num_args], XtNcolormap, cmap);    num_args++;
 1352     if (special_cmap) {
 1353     XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1354     }
 1355     pagemediamenu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
 1356                        pagemediabutton, args, num_args);
 1357 
 1358     /* Build the Page Media menu */
 1359     /* the Page media menu has two parts.
 1360      *  - the document defined page medias
 1361      *  - the standard page media defined from Adobe's PPD
 1362      */
 1363     base_papersize = 0;
 1364     if (doc) base_papersize = doc->nummedia;
 1365     for (i = 0; papersizes[i].name; i++) {} /* Count the standard entries */
 1366     i += base_papersize;
 1367     pagemediaentry = (Widget *) XtMalloc(i * sizeof(Widget));
 1368 
 1369     if (doc && doc->nummedia) {
 1370     for (i = 0; i < doc->nummedia; i++) {
 1371                                 num_args = 0;
 1372         if (special_cmap) {
 1373         XtSetArg(args[num_args], XtNforeground, black); num_args++;
 1374         XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1375         }
 1376         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
 1377         pagemediaentry[i] = XtCreateManagedWidget(doc->media[i].name,
 1378                 smeBSBObjectClass, pagemediamenu,
 1379                 args, num_args);
 1380         XtAddCallback(pagemediaentry[i], XtNcallback,
 1381               set_pagemedia, (XtPointer)i);
 1382     }
 1383 
 1384                             num_args = 0;
 1385     if (special_cmap) {
 1386         XtSetArg(args[num_args], XtNforeground, black); num_args++;
 1387         XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1388     }
 1389     w = XtCreateManagedWidget("line", smeLineObjectClass, pagemediamenu,
 1390                   args, num_args);
 1391     }
 1392 
 1393     for (i = 0; papersizes[i].name; i++) {
 1394     pagemediaentry[i+base_papersize] = NULL;
 1395     if (i > 0) {
 1396         /* Skip over same paper size with small imageable area */
 1397         if ((papersizes[i].width == papersizes[i-1].width) &&
 1398         (papersizes[i].height == papersizes[i-1].height)) {
 1399         continue;
 1400         }
 1401     }
 1402                             num_args = 0;
 1403     if (special_cmap) {
 1404         XtSetArg(args[num_args], XtNforeground, black); num_args++;
 1405         XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1406     }
 1407     XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
 1408     pagemediaentry[i+base_papersize] = XtCreateManagedWidget(
 1409                         papersizes[i].name,
 1410                         smeBSBObjectClass, pagemediamenu,
 1411                         args, num_args);
 1412     XtAddCallback(pagemediaentry[i+base_papersize], XtNcallback,
 1413               set_pagemedia, (XtPointer)(i+base_papersize));
 1414     }
 1415 }
 1416 
 1417 Widget
 1418 build_label_menu(parent, name, label, bitmap)
 1419     Widget parent;
 1420     String name, label;
 1421     Pixmap bitmap;
 1422 {
 1423     Arg args[20];
 1424     Cardinal num_args;
 1425     Widget menu, entry;
 1426                                 num_args = 0;
 1427     XtSetArg(args[num_args], XtNcolormap, cmap);        num_args++;
 1428     if (special_cmap) {
 1429         XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1430     }
 1431     menu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
 1432                   parent, args, num_args);
 1433 
 1434                                 num_args = 0;
 1435     if (special_cmap) {
 1436         XtSetArg(args[num_args], XtNforeground, black); num_args++;
 1437         XtSetArg(args[num_args], XtNbackground, white); num_args++;
 1438     }
 1439     XtSetArg(args[num_args], XtNlabel, label);      num_args++;
 1440     if (bitmap) {
 1441         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
 1442         XtSetArg(args[num_args], XtNleftBitmap, bitmap);    num_args++;
 1443     }
 1444     entry = XtCreateManagedWidget(name, smeBSBObjectClass,
 1445                       menu, args, num_args);
 1446     return menu;
 1447 }
 1448 
 1449 void
 1450 new_file(number)
 1451     int number;
 1452 {
 1453     Boolean layout_changed = False;
 1454 
 1455     if (setup_ghostview()) layout_changed = True;
 1456 
 1457     /* Coerce page number to fall in range */
 1458     if (toc_text) {
 1459     if (number >= doc->numpages) number = doc->numpages - 1;
 1460     if (number < 0) number = 0;
 1461     }
 1462 
 1463     if (set_new_orientation(number)) layout_changed = True;
 1464     if (set_new_pagemedia(number)) layout_changed = True;
 1465     if (layout_changed) layout_ghostview();
 1466 }
 1467 
 1468 /* Catch X errors die gracefully if one occurs */
 1469 int
 1470 catch_Xerror(dpy, err)
 1471     Display *dpy;
 1472     XErrorEvent *err;
 1473 {
 1474     if (err->error_code == BadImplementation) {
 1475     old_Xerror(dpy, err);
 1476     return 0;
 1477     }
 1478     if (dying) return 0;
 1479     dying = True;
 1480     bomb = *err;
 1481     XtDestroyWidget(toplevel);
 1482     return 0;
 1483 }