/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
/* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
/* |                                                                   | */
/* | Permission to use, copy, modify, and to distribute this software  | */
/* | and its documentation for any purpose is hereby granted without   | */
/* | fee, provided that the above copyright notice appear in all       | */
/* | copies and that both that copyright notice and this permission    | */
/* | notice appear in supporting documentation.  There is no           | */
/* | representations about the suitability of this software for        | */
/* | any purpose.  this software is provided "as is" without express   | */
/* | or implied warranty.                                              | */
/* |                                                                   | */
/* +-------------------------------------------------------------------+ */

/* $Id: print.c,v 1.9 2000/09/02 08:26:20 torsten Exp $ */

#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Text.h>
#include <X11/CoreP.h>
#include <X11/Xaw/ToggleP.h>
#include <X11/cursorfont.h>
#include <ctype.h>
#include <stdio.h>
#include <math.h>
#include "Colormap.h"
#include "Paint.h"
#include "PaintP.h"
#include "palette.h"
#include "xpaint.h"
#include "menu.h"
#include "image.h"
#include "messages.h"
#include "misc.h"
#include "region.h"
#include "text.h"
#include "graphic.h"
#include "operation.h"
#include "color.h"
#include "protocol.h"

#ifndef NOSTDHDRS
#include <stdlib.h>
#include <unistd.h>
#endif

#define PAGEWIDTH 200
#define PAGEHEIGHT 283

#ifdef XAW95
#define EXTRASPACE 15
#else
#define EXTRASPACE 10
#endif

extern int WriteGIF(char *file, Image * outImage);
extern int WritePNGn(char *file, Image * outImage);
extern int WritePNM(char *file, Image * outImage);
extern int WriteXPM(char *file, Image * outImage);
extern int WriteResizedPS(char *file, Image * image, void *data);

extern Image *outputImage;


static String textTranslations =
    "#override\n\
<Key>Return: print-text-ok()\n\
<Key>Linefeed: print-text-ok()\n\
Ctrl<Key>M: print-text-ok()\n\
Ctrl<Key>J: print-text-ok()\n";

static XtTranslations translations = None;

static PaintMenuItem fileMenu[] =
{
    MI_SIMPLE("print"),
    MI_SIMPLE("preview"),
    MI_SIMPLE("close"),
};
static PaintMenuItem formatMenu[] =
{
    MI_FLAG("Letter", MF_CHECK | MF_GROUP1),
    MI_FLAG("Legal", MF_CHECK | MF_GROUP1),
    MI_FLAG("Statement", MF_CHECK | MF_GROUP1),
    MI_FLAG("Tabloid", MF_CHECK | MF_GROUP1),
    MI_FLAG("Ledger", MF_CHECK | MF_GROUP1),
    MI_FLAG("Folio", MF_CHECK | MF_GROUP1),
    MI_FLAG("Quarto", MF_CHECK | MF_GROUP1),
    MI_FLAG("Executive", MF_CHECK | MF_GROUP1),
    MI_FLAG("10x14", MF_CHECK | MF_GROUP1),
    MI_FLAG("A2", MF_CHECK | MF_GROUP1),
    MI_FLAG("A3", MF_CHECK | MF_GROUP1),
    MI_FLAG("A4", MF_CHECK | MF_GROUP1),
    MI_FLAG("A5", MF_CHECK | MF_GROUP1),
    MI_FLAG("B4", MF_CHECK | MF_GROUP1),
    MI_FLAG("B5", MF_CHECK | MF_GROUP1),
};

static int paper_sizes[XtNumber(formatMenu)][2] = {
      {/* Letter */           612,  792},
      {/* Legal */            612, 1008},
      {/* Statement */        396,  612},
      {/* Tabloid */          792, 1224},
      {/* Ledger */          1224,  792},
      {/* Folio */            612,  936},
      {/* Quarto */           610,  780},
      {/* Executive */        540,  720},
      {/* 10x14 */            720, 1008},
      {/* A2 */              1191, 1684},
      {/* A3 */               842, 1191},
      {/* A4 */               595,  842},
      {/* A5 */               420,  595},
      {/* B4 */               729, 1032},
      {/* B5 */               516,  729}
    };

static PaintMenuItem helpMenu[] =
{
    MI_SIMPLECB("help", HelpDialog, "printMenu"),
};

static PaintMenuBar printMenuBar[] =
{
    {None, "file", XtNumber(fileMenu), fileMenu},
    {None, "format", XtNumber(formatMenu), formatMenu},
    {None, "help", XtNumber(helpMenu), helpMenu},
};

static PaintMenuItem externMenu[] =
{
    MI_FLAG("GIF", MF_CHECK | MF_GROUP1),
    MI_FLAG("PNG", MF_CHECK | MF_GROUP1),
    MI_FLAG("PPM", MF_CHECK | MF_GROUP1),
    MI_FLAG("XPM", MF_CHECK | MF_GROUP1),
};

static PaintMenuBar externMenuBar[] =
{
    {None, "format", XtNumber(externMenu), externMenu},
};

typedef struct {
    float wpercent, hpercent;
    int pwidth, pheight, width, height, rx, ry, wsubdiv, hsubdiv;
    int papertype, dwidth, dheight, x, y;
    Boolean tied, orient, output;
    Colormap cmap;
    GC gc1, gc2;
    char *tmpfile;
    PaintWidget paintwidget;
    Widget shell, topf, page, format, size, sampling, position;
    Widget printcmd, filename, psviewer;
    Widget portraittoggle, landscapetoggle, printtoggle, filetoggle, equal;
    Widget formatChecks[XtNumber(formatMenu)];
} PrintInfo;

typedef struct {
    int mode;
    char *cmd;
    Colormap cmap;
    PaintWidget paintwidget;
    Widget shell, format, viewer;
    Widget formatChecks[XtNumber(externMenu)];
} ExternInfo;

typedef struct {
    float wpercent, hpercent;
    int wbbox, hbbox, width, height, rx, ry, wsubdiv, hsubdiv, orient;
} PageInfo;

static PrintInfo *printinfo = NULL;
static ExternInfo *externinfo = NULL;

static void
showDrawing(PrintInfo * l)
{
    Display *dpy = XtDisplay(l->page);
    Window win = XtWindow(l->page);
    int i, x, y;

    i = l->papertype;
    x = l->x*l->pwidth/paper_sizes[i][0] - l->dwidth/2;
    y = l->y*l->pheight/paper_sizes[i][1] - l->dheight/2;

    if (x>=0)
        XClearArea(dpy, win, 0, 0, x, l->pheight+1, False);
    if (x+l->dwidth<l->pwidth)
        XClearArea(dpy, win, x+l->dwidth+1, 0, 
              l->pwidth-x-l->dwidth-1, l->pheight+1, False);
    if (y>=0) 
        XClearArea(dpy, win, 0, 0, l->pwidth+1, y, False);
    if (y+l->dheight<l->pheight)
        XClearArea(dpy, win, 0, y+l->dheight+1, l->pwidth+1, 
              l->pheight-y-l->dheight, False);
    XFillRectangle(dpy, win, l->gc1, x, y, l->dwidth, l->dheight);
    XDrawRectangle(dpy, win, l->gc2, x, y, l->dwidth, l->dheight);
    XDrawLine(dpy, win, l->gc2, x, y, x+l->dwidth, y+l->dheight);
    XDrawLine(dpy, win, l->gc2, x+l->dwidth, y, x, y+l->dheight);

    if (l->orient && l->dheight>4) {
        y = y+l->dheight/2;
        for (i=1; i<=3; i++) 
            XDrawLine(dpy, win, l->gc2, x+i, y-3+i, x+i, y+3-i);
    }
    if (!l->orient && l->dwidth>4) {
        x = x+l->dwidth/2;
        for (i=1; i<=3; i++) 
            XDrawLine(dpy, win, l->gc2, x-3+i, y+i, x+3-i, y+i);
    }
}

static void
drawArrows(Widget w, PrintInfo * l, XEvent * event, Boolean * flg)
{
    Display *dpy = XtDisplay(l->topf);
    Window win = XtWindow(l->topf);
    int i, j;

    i = 120;
    j = PAGEHEIGHT+EXTRASPACE+47;
    XDrawLine(dpy, win, l->gc2, i, j-2, PAGEWIDTH+EXTRASPACE, j-2);
    XDrawLine(dpy, win, l->gc2, i, j+2, PAGEWIDTH+EXTRASPACE, j+2);
    XDrawLine(dpy, win, l->gc2, i-6, j, i+4, j+5);
    XDrawLine(dpy, win, l->gc2, i-6, j, i+4, j-5);

    i = PAGEWIDTH+EXTRASPACE+17;
    j = PAGEHEIGHT+EXTRASPACE+30;
    XDrawLine(dpy, win, l->gc2, i-2, 172, i-2, j);
    XDrawLine(dpy, win, l->gc2, i+2, 172, i+2, j);
    XDrawLine(dpy, win, l->gc2, i, 166, i+5, 176);
    XDrawLine(dpy, win, l->gc2, i, 166, i-5, 176);
}

static void
setPosition(PrintInfo *l)
{
    char val[120];
    l->rx = l->x - (int)((l->orient?l->height:l->width)*l->wpercent*0.005);
    l->ry = paper_sizes[l->papertype][1] - l->y -
            (int)((l->orient?l->width:l->height)*l->hpercent*0.005);
    sprintf(val, "%d pt ; %d pt", l->rx, l->ry);
    XtVaSetValues(l->position, XtNstring, val, NULL);
}

static void 
setDrawingPosition(Widget w, PrintInfo * l, XEvent * event, Boolean * flg)
{
    while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
				  MotionNotify, (XEvent *) event));

    if (event->type == ButtonPress || event->type == MotionNotify) {
	l->x = event->xbutton.x * paper_sizes[l->papertype][0] / l->pwidth;
	l->y = event->xbutton.y * paper_sizes[l->papertype][1] / l->pheight;
	setPosition(l);
    }
    showDrawing(l);
}

static void 
doWritePS(PrintInfo *info, char *filename)
{
    Image * image;
    PageInfo pageinfo;

    image = PixmapToImage((Widget)info->paintwidget, 
			  info->paintwidget->paint.current, info->cmap);

    memcpy(&pageinfo, info, sizeof(PageInfo));
    pageinfo.wbbox = paper_sizes[info->papertype][0];
    pageinfo.hbbox = paper_sizes[info->papertype][1];
    if ((pageinfo.orient = info->orient)) {
        int exch = pageinfo.hsubdiv;
	pageinfo.hsubdiv = pageinfo.wsubdiv;
	pageinfo.wsubdiv = exch;
    }
    WriteResizedPS(filename, image, &pageinfo);
    ImageDelete(image);
}

static void 
printCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    char cmd[512];

    if (info->output) {
        char *ptr;
        XtVaGetValues(printinfo->filename, XtNstring, &ptr, NULL);
        doWritePS(info, ptr);
	Notice(w, msgText[FILE_WRITTEN], ptr);
    } else {
        char *ptr;
	XtVaGetValues(info->printcmd, XtNstring, &ptr, NULL);
        doWritePS(info, info->tmpfile);
        sprintf(cmd, "( %s %s ; rm -f %s ) &", 
            ptr, info->tmpfile, info->tmpfile);
        system(cmd);
	Notice(w, msgText[FILE_SENT_TO_PRINTER]);
    }
}

static void 
previewCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    char cmd[512];
    char *ps_viewer = NULL;

    XtVaGetValues(info->psviewer, XtNstring, &ps_viewer, NULL);

    if (!ps_viewer) return;

    doWritePS(info, info->tmpfile);
    sprintf(cmd, "( %s %s ; rm -f %s ) &", 
	    ps_viewer, info->tmpfile, info->tmpfile);
    system(cmd);
}

static void 
closePrintCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    Display *dpy;

    dpy = XtDisplay(info->shell);
    XFreeGC(dpy, info->gc1);
    XFreeGC(dpy, info->gc2);
    XtDestroyWidget(info->shell);
    info->shell = 0;
}

static void
findDrawSize(PrintInfo *l)
{
    int i;

    i = l->papertype;
    l->pwidth = PAGEWIDTH;
    l->pheight = paper_sizes[i][1]*PAGEWIDTH/paper_sizes[i][0];
    if (l->pheight>PAGEHEIGHT) {
        l->pheight = PAGEHEIGHT;
	l->pwidth = paper_sizes[i][0]*PAGEHEIGHT/paper_sizes[i][1];
    }
    if (l->orient) {
        l->dwidth = (int)((float)(l->height*l->pwidth)*l->wpercent*0.01/
                      (float)(paper_sizes[i][0])+0.5);
        l->dheight = (int)((float)(l->width*l->pheight)*l->hpercent*0.01/
                      (float)(paper_sizes[i][1])+0.5);
    } else {
        l->dwidth = (int)((float)(l->width*l->pwidth)*l->wpercent*0.01/
                      (float)(paper_sizes[i][0])+0.5);
        l->dheight = (int)((float)(l->height*l->pheight)*l->hpercent*0.01/
                      (float)(paper_sizes[i][1])+0.5);
    }
    XtVaSetValues(l->page, XtNwidth, l->pwidth, XtNheight, l->pheight, NULL);
}

static void 
setPapertype(char * str)
{
    char *ptr;
    int i;

    printinfo->papertype = i = 0;
    if (!str || !*str) {
        XtVaGetValues(printinfo->format, XtNstring, &str, NULL);
    }
    if (str) {
        while (isspace(*str)) ++str;
	if (*str)
        for (i=0; i<XtNumber(formatMenu); i++) {
	    XtVaGetValues(printinfo->formatChecks[i], XtNlabel, &ptr, NULL);
	    if (!strcasecmp(str, ptr)) {
	        printinfo->papertype = i;
                break;
	    }
	}
    }
    findDrawSize(printinfo);
    i = printinfo->papertype;
    printinfo->x = paper_sizes[i][0]/2;
    printinfo->y = paper_sizes[i][1]/2;
    XtVaGetValues(printinfo->formatChecks[i], XtNlabel, &ptr, NULL);
    XtVaSetValues(printinfo->format, XtNstring, ptr, NULL);
    MenuCheckItem(printinfo->formatChecks[i], True);
}

static void 
formatCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    int i;
    char *str;

    if (l->formatChecks[l->papertype] == w) return;
    MenuCheckItem(w, True);

    for (i=0; i<XtNumber(formatMenu); i++)
        if (l->formatChecks[i] == w) {
            XtVaGetValues(w, XtNlabel, &str, NULL);
            setPapertype(str);
	    setPosition(l);
	    showDrawing(l);
	    return;
	}
}

static void 
setPercent(PrintInfo * l)
{
    char str[80];
    char *ptr;
    int u, v;

    if (l->wpercent<0.5) l->wpercent =0.5;
    if (l->hpercent<0.5) l->hpercent =0.5;
    if (l->tied)
        sprintf(str, "%g%%", l->wpercent);
    else
        sprintf(str, "%g%% x %g%%", l->wpercent, l->hpercent);
    XtVaSetValues(l->size, XtNstring, str, NULL);

    XtVaGetValues(l->sampling, XtNstring, &ptr, NULL);
    if (sscanf(ptr, "%d x %d", &u, &v)==2) {
        if (u>=1 && v>=1) {
	    if (u>255) u = 255;
	    if (v>255) v = 255;
	    printinfo->wsubdiv = u;
            printinfo->hsubdiv = v;
	}
    }
    sprintf(str, "%d x %d (%d x %d dpi)", 
	    l->wsubdiv, l->hsubdiv,
            (int)(0.5 + 7200.0*l->wsubdiv / l->wpercent),
            (int)(0.5 + 7200.0*l->hsubdiv / l->hpercent));
    XtVaSetValues(l->sampling, XtNstring, str, NULL);

    findDrawSize(l);
    setPosition(l);
    showDrawing(l);
}

static void 
findPercent(char *str)
{
    if (!str || !*str) return;
    if (printinfo->tied) {
        sscanf(str, "%g%%", &printinfo->wpercent);
        printinfo->hpercent = printinfo->wpercent;
    } else
        sscanf(str, "%g%% x %g%%", &printinfo->wpercent, &printinfo->hpercent);
    setPercent(printinfo);
}

static void 
viewExternCallback(Widget w, XtPointer infoArg, XtPointer junk2);

static void 
textAction(Widget w, XEvent * event, String * prms,  Cardinal * nprms)
{
    char *str;
    int u, v;

    if (externinfo && w == externinfo->viewer)
       viewExternCallback(w, (XtPointer) externinfo, NULL);

    if (!printinfo) return;

    if (w == printinfo->size) {
       XtVaGetValues(w, XtNstring, &str, NULL);
       findPercent(str);
       setPosition(printinfo);
       showDrawing(printinfo);
    }
    else
    if (w == printinfo->sampling) {
       setPercent(printinfo);
    }
    else
    if (w == printinfo->position) {
       char *ptr, val[120];
       XtVaGetValues(printinfo->position, XtNstring, &ptr, NULL);
       if (sscanf(ptr, "%d pt ; %d", &u, &v)==2) {
	   printinfo->rx = u;
           printinfo->ry = v;
	   printinfo->x = u + (int)((printinfo->orient?printinfo->height:printinfo->width) *
              printinfo->wpercent*0.005);
	   printinfo->y = paper_sizes[printinfo->papertype][1] - v -
              (int)((printinfo->orient?printinfo->width:printinfo->height) * 
              printinfo->hpercent*0.005);
	   showDrawing(printinfo);
       }
       sprintf(val, "%d pt ; %d pt", printinfo->rx, printinfo->ry);
       XtVaSetValues(printinfo->position, XtNstring, val, NULL);
    }
    else
    if (w == printinfo->format) {
       XtVaGetValues(w, XtNstring, &str, NULL);
       setPapertype(str);
       setPosition(printinfo);
       showDrawing(printinfo);
    }
}

static void 
switchCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    Boolean state;

    XtVaGetValues(w, XtNstate, &state, NULL);

    if (w == info->portraittoggle) {
       XtVaSetValues(info->landscapetoggle, XtNstate, !state, NULL);
       info->orient = !state;
       findDrawSize(info);       
       setPosition(info);
       showDrawing(info);
    }
    if (w == info->landscapetoggle) {
       XtVaSetValues(info->portraittoggle, XtNstate, !state, NULL);
       info->orient = state;
       findDrawSize(info);
       setPosition(info);
       showDrawing(info);
    }
    if (w == info->printtoggle) {
       XtVaSetValues(info->filetoggle, XtNstate, !state, NULL);
       info->output = !state;
    }
    if (w == info->filetoggle) {
       XtVaSetValues(info->printtoggle, XtNstate, !state, NULL);
       info->orient = state;
    }
    if (w == info->equal) {
       info->tied = state;
       if (state) {
	   if (info->hpercent > info->wpercent) 
               info->wpercent = info->hpercent;
	   if (info->wpercent > info->hpercent) 
               info->hpercent = info->wpercent;
       }
       setPercent(info);
    }
}

static void 
wcenterCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    int i = l->papertype;
    l->x = paper_sizes[i][0]/2;
    setPosition(l);
    showDrawing(l);
}

static void 
wplusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->wpercent += 0.5;
    if (l->tied) l->hpercent = l->wpercent;
    setPercent(l);
}

static void 
wpplusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->wpercent += 5.0;
    if (l->tied) l->hpercent = l->wpercent;
    setPercent(l);
}

static void 
wminusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->wpercent -= 0.5;
    if (l->tied) l->hpercent = l->wpercent;
    setPercent(l);
}

static void 
wmminusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->wpercent -= 5.0;
    if (l->tied) l->hpercent = l->wpercent;
    setPercent(l);
}

static void 
hcenterCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    int i = l->papertype;
    l->y = paper_sizes[i][1]/2;
    setPosition(l);
    showDrawing(l);
}

static void 
hplusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->hpercent += 0.5;
    if (l->tied) l->wpercent = l->hpercent;
    setPercent(l);
}

static void 
hpplusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->hpercent += 5.0;
    if (l->tied) l->wpercent = l->hpercent;
    setPercent(l);
}

static void 
hminusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->hpercent -= 0.5;
    if (l->tied) l->wpercent = l->hpercent;
    setPercent(l);
}

static void 
hmminusCallback(Widget w, XtPointer larg, XtPointer junk)
{
    PrintInfo *l = (PrintInfo *) larg;
    l->hpercent -= 5.0;
    if (l->tied) l->wpercent = l->hpercent;
    setPercent(l);
}

void createPrintData() 
{
    int fd;
    char *tmp;
    char buf[256];

    printinfo = (PrintInfo *) XtMalloc(sizeof(PrintInfo));
    printinfo->tied = True;
    printinfo->orient = False;
    printinfo->output = False;
    printinfo->page = 0;

    if ((tmp = getenv("TMPDIR")) == NULL)
       tmp = P_tmpdir;

    strncpy(buf, tmp, 220);
    buf[220] = '\0';
    strcat(buf, "/XPaint-XXXXXX");
    fd = mkstemp(buf);
    if (fd == -1) return;
    close(fd);
    unlink(buf);
    strcat(buf, ".ps");
    printinfo->tmpfile = XtNewString(buf);
}

void 
PrintPopup(Widget w, XtPointer paintArg)
{
    static Cursor pageCursor = None;
    static XGCValues gcv;
    static XtTranslations paint_trans = None;

    Widget shell, topf, page, box, vp;
    Widget bar, printButton, previewButton, cancelButton;
    Widget wplus, wpplus, wminus, wmminus, wcenter;
    Widget hplus, hpplus, hminus, hmminus, hcenter;
    Widget equal;
    Widget paperlabel, papervalue;
    Widget portraitlabel, portraittoggle;
    Widget landscapelabel, landscapetoggle;
    Widget sizelabel, sizevalue;
    Widget positionlabel, positionvalue;
    Widget samplinglabel, samplingvalue;
    Widget printlabel, printcmd, printtoggle;
    Widget filelabel, filename, filetoggle;
    Widget psviewerlabel, psviewercmd;
    Display *dpy;
    Window root;
    char *defname = "yellow", *canvasfile;
    XColor scol, ecol;
    Pixel white, black, defpix;
    int i;
    Position x, y;
    Arg args[6];
    int nargs = 0, new = 0;

    dpy = XtDisplay(GetShell(w));
    root = RootWindowOfScreen(XtScreen(GetShell(w)));

    if (!printinfo) {
        new = 1;
	createPrintData();
	printinfo->shell = 0;
    }

    if (printinfo->shell) {
        if (printinfo->paintwidget == (PaintWidget)paintArg) {
            XMapRaised(dpy, XtWindow(printinfo->shell));
            return;
	} else
	    XtDestroyWidget(printinfo->shell);
    }
    printinfo->paintwidget = (PaintWidget)paintArg;

    canvasfile = printinfo->paintwidget->paint.filename;

    if (canvasfile) {
        char *ptr;
        canvasfile = malloc(strlen(canvasfile)+4);
	strcpy(canvasfile, ((PaintWidget) paintArg)->paint.filename);
	ptr = rindex(canvasfile, '.');
	if (ptr) 
           strcpy(ptr, ".ps");
	else
           strcat(canvasfile, ".ps");
    }

    XtVaGetValues(GetShell(w), XtNcolormap, &printinfo->cmap, 
                  XtNx, &x, XtNy, &y, NULL);
    XtSetArg(args[nargs], XtNcolormap, printinfo->cmap); nargs++; 
    XtSetArg(args[nargs], XtNx,  x+24);  nargs++;
    XtSetArg(args[nargs], XtNy,  y+24);  nargs++;
    
    XtVaGetValues((Widget)printinfo->paintwidget, XtNdrawWidth, 
                  &printinfo->width, XtNdrawHeight, &printinfo->height, NULL);

    shell = XtVisCreatePopupShell("print", topLevelShellWidgetClass,
				  GetShell(w), args, nargs);
    white = WhitePixelOfScreen(XtScreen(shell));
    black = BlackPixelOfScreen(XtScreen(shell));
    printinfo->shell = shell;

    if (XAllocNamedColor(dpy, printinfo->cmap, defname, &scol, &ecol) != 0)
        defpix = scol.pixel;
    else 
    if (XLookupColor(dpy, printinfo->cmap, defname, &scol, &ecol) != 0)
        defpix = scol.pixel;
    else 
        defpix = black;

    gcv.foreground = defpix;
    printinfo->gc1 = XCreateGC(dpy, root, GCForeground, &gcv);
    gcv.foreground = black;
    printinfo->gc2 = XCreateGC(dpy, root, GCForeground, &gcv);

    XtVaSetValues(shell, XtNallowResize, False, NULL);
    topf = XtVaCreateManagedWidget("form", formWidgetClass, shell, NULL);
    printinfo->topf = topf;

    bar = MenuBarCreate(topf, XtNumber(printMenuBar), printMenuBar);

    vp = XtVaCreateManagedWidget("viewport", viewportWidgetClass, topf,
				 XtNfromVert, bar,
				 XtNvertDistance, 2,
				 XtNallowVert, False,
				 XtNallowHoriz, False,
				 XtNleft, XtChainLeft,
				 XtNright, XtChainRight,
				 XtNwidth, PAGEWIDTH+EXTRASPACE, 
				 XtNheight, PAGEHEIGHT+EXTRASPACE,
			         XtNbackground, white,
				 NULL);

    box = XtVaCreateManagedWidget("printBox", boxWidgetClass, vp,
			    XtNbackgroundPixmap, GetBackgroundPixmap(vp),
			    NULL);

    page = XtVaCreateManagedWidget("page", paintWidgetClass, box,
                                   XtNfromHoriz, box,
				   XtNfillRule, FillSolid,
				   XtNzoom, 1,
				   XtNbackground, white,
			           XtNwidth, PAGEWIDTH, XtNheight, PAGEHEIGHT,
				   NULL);
    if (paint_trans == None) {
	paint_trans = XtParseTranslationTable(
	   "#override\n\t<BtnDown>,<BtnUp>,<BtnMotion>: \n");
    }
    XtVaSetValues(page, XtNtranslations, paint_trans, NULL);

    printinfo->page = page;
    if (pageCursor == None)
        pageCursor = XCreateFontCursor(dpy, XC_crosshair);


    wpplus = XtVaCreateManagedWidget("wpplus",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       NULL);

    wplus = XtVaCreateManagedWidget("wplus",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, wpplus,
				       NULL);

    wminus = XtVaCreateManagedWidget("wminus",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, wplus,
				       NULL);

    wmminus = XtVaCreateManagedWidget("wmminus",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, wminus,
				       NULL);

    wcenter = XtVaCreateManagedWidget("wcenter",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, wmminus,
				       NULL);

    hpplus = XtVaCreateManagedWidget("hpplus",
				       commandWidgetClass, topf,
				       XtNfromHoriz, vp,
				       XtNfromVert, bar,
				       XtNvertDistance, 2,
				       NULL);

    hplus = XtVaCreateManagedWidget("hplus",
				       commandWidgetClass, topf,
				       XtNfromHoriz, vp,
				       XtNfromVert, hpplus,
				       NULL);

    hminus = XtVaCreateManagedWidget("hminus",
				       commandWidgetClass, topf,
				       XtNfromHoriz, vp,
				       XtNfromVert, hplus,
				       NULL);

    hmminus = XtVaCreateManagedWidget("hmminus",
				       commandWidgetClass, topf,
				       XtNfromHoriz, vp,
				       XtNfromVert, hminus,
				       NULL);

    hcenter = XtVaCreateManagedWidget("hcenter",
				       commandWidgetClass, topf,
				       XtNfromHoriz, vp,
				       XtNfromVert, hmminus,
				       NULL);

    equal = XtVaCreateManagedWidget("equal",
				       toggleWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, vp,
				       XtNstate, printinfo->tied,
				       NULL);
    printinfo->equal = equal;

    if (translations == None) {
	static XtActionsRec act =
	{"print-text-ok", (XtActionProc) textAction};

	XtAppAddActions(XtWidgetToApplicationContext(w), &act, 1);

	translations = XtParseTranslationTable(textTranslations);
    }

    portraitlabel = XtVaCreateManagedWidget("portraitlabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromHoriz, hpplus,
				       XtNhorizDistance, 30,
				       XtNfromVert, bar,
				       XtNvertDistance, 2,
				       NULL);

    portraittoggle = XtVaCreateManagedWidget("portraittoggle",
				       toggleWidgetClass, topf,
                                       XtNstate, !printinfo->orient,
				       XtNfromHoriz, portraitlabel,
				       XtNfromVert, bar,
				       XtNvertDistance, 2,
				       NULL);
    printinfo->portraittoggle = portraittoggle;

    landscapelabel = XtVaCreateManagedWidget("landscapelabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromHoriz, portraittoggle,
				       XtNhorizDistance, 50,
				       XtNfromVert, bar,
				       XtNvertDistance, 2,
				       NULL);

    landscapetoggle = XtVaCreateManagedWidget("landscapetoggle",
				       toggleWidgetClass, topf,
                                       XtNstate, printinfo->orient,
				       XtNfromHoriz, landscapelabel,
                                       XtNradioGroup, portraittoggle,
				       XtNfromVert, bar,
				       XtNvertDistance, 2,
				       NULL);
    printinfo->landscapetoggle = landscapetoggle;

    paperlabel = XtVaCreateManagedWidget("paperlabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromVert, portraittoggle,
				       XtNfromHoriz, hpplus,
				       XtNhorizDistance, 30,
				       NULL);

    papervalue = XtVaCreateManagedWidget("papertype",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, portraittoggle,
				       XtNwidth, 100,
				       NULL);
    printinfo->format = papervalue;

    sizelabel = XtVaCreateManagedWidget("sizelabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, papervalue,
				       XtNhorizDistance, 30,
				       XtNvertDistance, 16,
				       NULL);

    sizevalue = XtVaCreateManagedWidget("sizevalue",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, papervalue,
				       XtNwidth, 150,
				       XtNvertDistance, 16,
				       NULL);
    printinfo->size = sizevalue;

    positionlabel = XtVaCreateManagedWidget("positionlabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, sizevalue,
				       XtNhorizDistance, 30,
				       NULL);

    positionvalue = XtVaCreateManagedWidget("positionvalue",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, sizevalue,
				       XtNwidth, 150,
				       NULL);
    printinfo->position = positionvalue;

    samplinglabel = XtVaCreateManagedWidget("samplinglabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromHoriz, hpplus,
				       XtNfromVert, positionvalue,
				       XtNhorizDistance, 30,
				       NULL);

    samplingvalue = XtVaCreateManagedWidget("samplingvalue",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromVert, positionvalue,
				       XtNfromHoriz, hpplus,
				       XtNwidth, 150,
				       NULL);
    printinfo->sampling = samplingvalue;

    printlabel = XtVaCreateManagedWidget("printlabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromVert, samplingvalue,
				       XtNfromHoriz, hpplus,
				       XtNhorizDistance, 30,
				       XtNvertDistance, 20,
				       NULL);

    printcmd = XtVaCreateManagedWidget("printcmd",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, samplingvalue,
				       XtNfromHoriz, hpplus,
				       XtNvertDistance, 20,
				       XtNwidth, 150, XtNheight, 40,
				       NULL);
    printinfo->printcmd = printcmd;

    printtoggle = XtVaCreateManagedWidget("printtoggle",
				       toggleWidgetClass, topf,
                                       XtNstate, !printinfo->output,
				       XtNfromVert, samplingvalue,
				       XtNfromHoriz, printcmd,
				       XtNvertDistance, 20,
				       NULL);
    printinfo->printtoggle = printtoggle;

    filelabel = XtVaCreateManagedWidget("filelabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromVert, printcmd,
				       XtNfromHoriz, hpplus,
				       XtNhorizDistance, 30,
				       NULL);

    filename = XtVaCreateManagedWidget("filename",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, printcmd,
				       XtNfromHoriz, hpplus,
				       XtNwidth, 150, XtNheight, 40,
				       NULL);
    if (canvasfile) {
        XtVaSetValues(filename, XtNstring, canvasfile, NULL);
	free(canvasfile);
    }
    printinfo->filename = filename;

    filetoggle = XtVaCreateManagedWidget("filetoggle",
				       toggleWidgetClass, topf,
                                       XtNstate, printinfo->output,
				       XtNfromVert, printcmd,
				       XtNfromHoriz, filename,
				       XtNradioGroup, printtoggle,
				       NULL);
    printinfo->filetoggle = filetoggle;

    psviewerlabel = XtVaCreateManagedWidget("psviewerlabel",
				       labelWidgetClass, topf,
				       XtNborderWidth, 0,
				       XtNfromVert, filename,
				       XtNfromHoriz, hpplus,
				       XtNhorizDistance, 30,
				       NULL);

    psviewercmd = XtVaCreateManagedWidget("psviewer",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, filename,
				       XtNfromHoriz, hpplus,
				       XtNwidth, 150, XtNheight, 40,
				       NULL);
    printinfo->psviewer = psviewercmd;

    printButton = XtVaCreateManagedWidget("print",
				       commandWidgetClass, topf,
				       XtNfromVert, vp,
				       XtNfromHoriz, hpplus,
				       NULL);

    previewButton = XtVaCreateManagedWidget("preview",
					 commandWidgetClass, topf,
                                         XtNfromVert, vp,
				         XtNfromHoriz, printButton,
				         XtNhorizDistance, 9,
					 NULL);

    cancelButton = XtVaCreateManagedWidget("cancel",
					   commandWidgetClass, topf,
					   XtNfromVert, vp,
				           XtNfromHoriz, previewButton,
				           XtNhorizDistance, 9,
					   NULL);

    XtAddEventHandler(topf, ExposureMask,
		  False, (XtEventHandler) drawArrows, (XtPointer) printinfo);

    XtAddEventHandler(page, ButtonPressMask | ButtonMotionMask | ExposureMask,
		  False, (XtEventHandler)setDrawingPosition, (XtPointer) printinfo);

    XtAddCallback(XtNameToWidget(bar, "file.fileMenu.print"),
		  XtNcallback, printCallback, (XtPointer) printinfo);

    XtAddCallback(XtNameToWidget(bar, "file.fileMenu.preview"),
		  XtNcallback, previewCallback, (XtPointer) printinfo);

    XtAddCallback(XtNameToWidget(bar, "file.fileMenu.close"),
		  XtNcallback, closePrintCallback, (XtPointer) printinfo);

    for (i=0; i<XtNumber(formatMenu); i++) {
        XtAddCallback(formatMenu[i].widget,
		  XtNcallback, formatCallback, (XtPointer) printinfo);
        printinfo->formatChecks[i] = formatMenu[i].widget;
    }

    XtAddCallback(wcenter, XtNcallback,
		  (XtCallbackProc) wcenterCallback, (XtPointer) printinfo);
    XtAddCallback(wplus, XtNcallback,
		  (XtCallbackProc) wplusCallback, (XtPointer) printinfo);
    XtAddCallback(wpplus, XtNcallback,
		  (XtCallbackProc) wpplusCallback, (XtPointer) printinfo);
    XtAddCallback(wminus, XtNcallback,
		  (XtCallbackProc) wminusCallback, (XtPointer) printinfo);
    XtAddCallback(wmminus, XtNcallback,
		  (XtCallbackProc) wmminusCallback, (XtPointer) printinfo);

    XtAddCallback(hcenter, XtNcallback,
		  (XtCallbackProc) hcenterCallback, (XtPointer) printinfo);
    XtAddCallback(hplus, XtNcallback,
		  (XtCallbackProc) hplusCallback, (XtPointer) printinfo);
    XtAddCallback(hpplus, XtNcallback,
		  (XtCallbackProc) hpplusCallback, (XtPointer) printinfo);
    XtAddCallback(hminus, XtNcallback,
		  (XtCallbackProc) hminusCallback, (XtPointer) printinfo);
    XtAddCallback(hmminus, XtNcallback,
		  (XtCallbackProc) hmminusCallback, (XtPointer) printinfo);

    XtAddCallback(portraittoggle, XtNcallback,
		  (XtCallbackProc) switchCallback, (XtPointer) printinfo);
    XtAddCallback(landscapetoggle, XtNcallback,
		  (XtCallbackProc) switchCallback, (XtPointer) printinfo);
    XtAddCallback(printtoggle, XtNcallback,
		  (XtCallbackProc) switchCallback, (XtPointer) printinfo);
    XtAddCallback(filetoggle, XtNcallback,
		  (XtCallbackProc) switchCallback, (XtPointer) printinfo);
    XtAddCallback(equal, XtNcallback,
		  (XtCallbackProc) switchCallback, (XtPointer) printinfo);

    XtAddCallback(printButton, XtNcallback,
		  (XtCallbackProc) printCallback, (XtPointer) printinfo);
    XtAddCallback(previewButton, XtNcallback,
		  (XtCallbackProc) previewCallback, (XtPointer) printinfo);
    XtAddCallback(cancelButton, XtNcallback,
		  (XtCallbackProc) closePrintCallback, (XtPointer) printinfo);
    AddDestroyCallback(shell, (DestroyCallbackFunc) closePrintCallback, printinfo);

    XtPopup(shell, XtGrabNone);

    if (new) {
        char *ptr;
	int u, v;
        XtVaGetValues(papervalue, XtNstring, &ptr, NULL);
        setPapertype(ptr);
	XtVaGetValues(samplingvalue, XtNstring, &ptr, NULL);
	printinfo->wsubdiv = 1;
	printinfo->hsubdiv = 1;
        if (sscanf(ptr, "%d x %d", &u, &v)==2) {
            if (u>=1 && v>=1) {
	        if (u>255) u = 255;
	        if (v>255) v = 255;
	        printinfo->wsubdiv = u;
                printinfo->hsubdiv = v;
	    }
        }
        XtVaGetValues(sizevalue, XtNstring, &ptr, NULL);
        findPercent(ptr);
    } else {
        char *ptr;
        /* recover values from previous printing session */
        int x = printinfo->x, y = printinfo->y;
        XtVaGetValues(printinfo->formatChecks[printinfo->papertype],
            XtNlabel, &ptr, NULL);
	setPapertype(ptr);
	printinfo->x = x;
	printinfo->y = y;
	setPercent(printinfo);
    }

    XDefineCursor(dpy, XtWindow(page), pageCursor);
}

static void 
selectCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    ExternInfo *l = (ExternInfo *) infoArg;
    int i;
    char *str;

    for (i=0; i<XtNumber(externMenu); i++)
        if (l->formatChecks[i] == w) {
            XtVaGetValues(w, XtNlabel, &str, NULL);
            XtVaSetValues(l->format, XtNlabel, str, NULL);
	    MenuCheckItem(w, True);
	    l->mode = i;
	    break;
	}
}
   
static void 
closeExternCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    ExternInfo *info = (ExternInfo *) infoArg;
    XtDestroyWidget(info->shell);
    info->shell = 0;
}

static void 
viewExternCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    ExternInfo *info = (ExternInfo *) infoArg;
    Image *image;
    static char suffix[8];
    char cmd[512], buf[256];
    char *viewer, *tmp, *sep, *file = NULL;
    int i, del, fd;

    XtVaGetValues(info->viewer, XtNstring, &viewer, NULL);
    if (!viewer || !*viewer) return;
    info->cmd = (char *)realloc(info->cmd, strlen(viewer)+1);
    strcpy(info->cmd, viewer);

    XtVaGetValues(info->formatChecks[info->mode], XtNlabel, &tmp, NULL);
    strcpy(suffix, tmp);
    i = 0;
    while (suffix[i]) {
       suffix[i] = tolower(suffix[i]);
       i++;
    }
    del = 1;
    sep = rindex(info->cmd, ' ');
    if (sep) {
        ++sep;
	sprintf(cmd, ".%s", suffix);
	if (strstr(sep, cmd)) {
	file = strdup(sep);
	*sep = '\0';
        del = 0;
	}
    }

    if (!file) {
       if ((tmp = getenv("TMPDIR")) == NULL)
          tmp = P_tmpdir;
        strncpy(buf, tmp, 220);
        buf[220] = '\0';
        strcat(buf, "/XPaint-XXXXXX");
        fd = mkstemp(buf);
        if (fd == -1) return;
        close(fd);
        unlink(buf);
        strcat(buf, ".");
	strcat(buf, suffix);
        file = XtNewString(buf);
    }
    if (del)
        sprintf(cmd, "(%s %s ; rm -f %s) &", info->cmd, file, file);
    else {
        sprintf(cmd, "%s %s &", info->cmd, file);
        *sep = ' ';
    }

    StateSetBusy(True);    
    image = PixmapToImage((Widget)info->paintwidget, 
        info->paintwidget->paint.current, info->cmap);
    if (!image) {
        StateSetBusy(False);
	free(file);
	return;
    }

    outputImage = NULL;
    if (info->mode == 0)
        WriteGIF(file, image);
    if (info->mode == 1)
        WritePNGn(file, image);
    if (info->mode == 2)
        WritePNM(file, image);
    if (info->mode == 3)
        WriteXPM(file, image);
    if (info->mode > 0) {
        if (outputImage)
            ImageDelete(outputImage);
        else
            ImageDelete(image);
    }
    StateSetBusy(False);

    system(cmd);
    free(file);
}

void 
ExternPopup(Widget w, XtPointer paintArg)
{
    Widget shell, topf, bar;
    Widget formatlabel, viewerlabel, viewercmd;
    Widget viewButton, cancelButton;
    Display *dpy;
    Window root;
    Colormap cmap;
    Position x, y;
    Arg args[6];
    int i, nargs = 0;
    char *str;

    dpy = XtDisplay(w);
    root = RootWindowOfScreen(XtScreen(w));

    if (!externinfo) {
        externinfo = (ExternInfo *) XtMalloc(sizeof(ExternInfo));
	externinfo->mode = -1;
	externinfo->cmd = NULL;
	externinfo->shell = 0;
    }
    if (externinfo->shell) {
        if (externinfo->paintwidget == (PaintWidget)paintArg) {
            XMapRaised(dpy, XtWindow(externinfo->shell));
            return;
	} else
	    XtDestroyWidget(externinfo->shell);
    }
    externinfo->paintwidget = (PaintWidget)paintArg;

    XtVaGetValues(w, XtNcolormap, &cmap, 
                  XtNx, &x, XtNy, &y, NULL);
    XtSetArg(args[nargs], XtNcolormap, cmap); nargs++; 
    externinfo->cmap = cmap;

    XtSetArg(args[nargs], XtNx,  x+24);  nargs++;
    XtSetArg(args[nargs], XtNy,  y+24);  nargs++;

    shell = XtVisCreatePopupShell("extern", topLevelShellWidgetClass,
			      GetShell(w), args, nargs);
    externinfo->shell = shell;

    topf = XtVaCreateManagedWidget("form", formWidgetClass, shell, NULL);

    bar = MenuBarCreate(topf, XtNumber(externMenuBar), externMenuBar);

    formatlabel = XtVaCreateManagedWidget("formatlabel",
				       labelWidgetClass, topf,
				       XtNfromHoriz, bar,
				       XtNborderWidth, 0,
				       NULL);
    externinfo->format = formatlabel;

    viewerlabel = XtVaCreateManagedWidget("viewerlabel",
				       labelWidgetClass, topf,
				       XtNfromVert, bar,
				       XtNvertDistance, 10,
				       XtNborderWidth, 0,
				       NULL);

    if (translations == None) {
	static XtActionsRec act =
	{"print-text-ok", (XtActionProc) textAction};

	XtAppAddActions(XtWidgetToApplicationContext(w), &act, 1);

	translations = XtParseTranslationTable(textTranslations);
    }

    viewercmd = XtVaCreateManagedWidget("viewercmd",
				       asciiTextWidgetClass, topf,
				       XtNtranslations, translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNwidth, 150, XtNheight, 40,
				       XtNfromVert, bar,
				       XtNvertDistance, 10,
				       XtNfromHoriz, viewerlabel,
				       NULL);
    externinfo->viewer = viewercmd;
    if (externinfo->cmd)
        XtVaSetValues(viewercmd, XtNstring, externinfo->cmd, NULL);

    viewButton = XtVaCreateManagedWidget("view",
				       commandWidgetClass, topf,
				       XtNfromVert, viewercmd,
				       NULL);

    cancelButton = XtVaCreateManagedWidget("cancel",
				       commandWidgetClass, topf,
				       XtNfromVert, viewercmd,
				       XtNfromHoriz, viewButton,
				       NULL);

    for (i=0; i<XtNumber(externMenu); i++) {
        XtAddCallback(externMenu[i].widget,
		  XtNcallback, selectCallback, (XtPointer) externinfo);
        externinfo->formatChecks[i] = externMenu[i].widget;
    }

    if (externinfo->mode == -1) {
        externinfo->mode = 2;
        XtVaGetValues(formatlabel, XtNlabel, &str, NULL);
        if (str && *str) {
            char *ptr;
            for (i=0; i<XtNumber(externMenu); i++) {
	        XtVaGetValues(externinfo->formatChecks[i], XtNlabel,&ptr,NULL);
	        if (!strcasecmp(str, ptr)) {
	            externinfo->mode = i;
                    break;
		}
	    }
	}
    }
    XtVaGetValues(externinfo->formatChecks[externinfo->mode], 
                  XtNlabel, &str, NULL);
    XtVaSetValues(formatlabel, XtNlabel, str, NULL);
    MenuCheckItem(externinfo->formatChecks[externinfo->mode], True);

    XtAddCallback(viewButton, XtNcallback,
		  (XtCallbackProc) viewExternCallback, (XtPointer) externinfo);

    XtAddCallback(cancelButton, XtNcallback,
		  (XtCallbackProc)closeExternCallback, (XtPointer) externinfo);

    AddDestroyCallback(shell, (DestroyCallbackFunc) closeExternCallback, 
                  externinfo);

    XtPopup(shell, XtGrabNone);
}

void
checkExternalLink(Widget paint)
{
    PaintWidget pw = (PaintWidget) paint;

    if (printinfo && printinfo->shell && printinfo->paintwidget == pw) {
         XtDestroyWidget(printinfo->shell);
	 printinfo->shell = 0;
    }
    if (externinfo && externinfo->shell && externinfo->paintwidget == pw) {
         XtDestroyWidget(externinfo->shell);
	 externinfo->shell = 0;
    }
}
