/* +-------------------------------------------------------------------+ */
/* | 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.12 2005/03/20 20:15:32 demailly Exp $ */

#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <math.h>

#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <X11/cursorfont.h>

#include "xaw_incdir/Box.h"
#include "xaw_incdir/Form.h"
#include "xaw_incdir/Scrollbar.h"
#include "xaw_incdir/Viewport.h"
#include "xaw_incdir/Command.h"
#include "xaw_incdir/Paned.h"
#include "xaw_incdir/AsciiText.h"
#include "xaw_incdir/Text.h"
#include "xaw_incdir/MenuButton.h"
#include "xaw_incdir/SimpleMenu.h"
#include "xaw_incdir/SmeBSB.h"
#include "xaw_incdir/ToggleP.h"

#include "Colormap.h"
#include "Paint.h"
#include "PaintP.h"
#include "palette.h"
#include "print.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

extern void openTempDir(char *buf);
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 int PAGEWIDTH;
static int PAGEHEIGHT;
#if defined(XAW95) || defined(XAW3DG)
#define EXTRAWIDTH 15
#define EXTRAHEIGHT 13
#else
#define EXTRAWIDTH 10
#define EXTRAHEIGHT 10
#endif

static int oldw = -1, oldh = -1;

static XtTranslations text_translations = None;

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 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),
};

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, "help", XtNumber(helpMenu), helpMenu},
    {None, "format", XtNumber(formatMenu), formatMenu}
};

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, form, bar;
    Widget format, print, preview, cancel;
    Widget page, box, vp;
    Widget wplus, wpplus, wminus, wmminus, wcenter, equal;
    Widget hplus, hpplus, hminus, hmminus, hcenter;
    Widget portraitlabel, portraittoggle;
    Widget landscapelabel, landscapetoggle;
    Widget graylabel, graytoggle;
    Widget compresslabel, compresstoggle, pdflabel, pdftoggle;
    Widget sizelabel, positionlabel, samplinglabel, 
           printlabel, filelabel, psviewlabel, resultlabel;
    Widget size, position, sampling, printcmd, filename, psviewcmd, printresult;
    Widget printerlist, printtoggle, fileselect, filetoggle;
    Widget printentry, printermenu;
    Widget formatChecks[XtNumber(formatMenu)];
} PrintInfo;

typedef struct {
    int mode;
    char *cmd;
    Colormap cmap;
    PaintWidget paintwidget;
    Widget shell, form, bar;
    Widget formatlabel, extviewlabel;
    Widget extview, viewbut, cancel;
    Widget formatChecks[XtNumber(externMenu)];
} ExternInfo;

static PrintInfo *printinfo = NULL;
static ExternInfo *externinfo = NULL;
static char *printerlist_env = NULL;
static char *printcmd_str = NULL;
static char *printcmd_ini = NULL;
static char *printcmd_short = NULL;
static char *psviewcmd_str = NULL;
static char **printer_names = NULL;
static int num_printers = 0;

#ifdef PRINTCAP
static void
parsePrintcap(char *env)
{
    FILE *fd;
    int jumpnext;
    char *printcap, *ptr0, *ptr1;
    char *pline;
    char line[1024];
   
    if (strlen(env)<=1) return;

    printcap = strdup(env);
    ptr0 = printcap;
    ptr1 = index(ptr0, ':');
    if (ptr1) *ptr1 = '\0';
   
    while((fd=fopen(ptr0,"r"))==NULL) {
	    if (ptr1) {
	       ptr0 = ptr1+1;
               ptr1 = index(ptr0, ':');
	       if (ptr1) *ptr1 = '\0';
	    }
	    else {
	       fprintf(stderr, msgText[CANT_FIND_PRINTCAP_FILE], printcap);
	       return;
	    }
    }

    num_printers = 0;   
    jumpnext = 0;
    while ((pline=fgets(line,1020,fd))!=NULL) {
            while(isspace(*pline) && *pline!='\0') ++pline;
            if (*pline=='\0' || *pline=='#') { 
	       jumpnext=0; 
	       continue;
	    }
	    pline=pline+strlen(pline)-1;
            if (*pline=='\n') {
	       *pline = '\0';
	       --pline;
	    }
            if(*pline=='\\') 
	      ++jumpnext;
            if (jumpnext>1) continue;
            pline=line;
	    while(*pline!=':' && pline<line+strlen(line)) ++pline;
	    *pline='\0';	
	    pline=line;
	    while(*pline!='|' && *pline!='\0') ++pline;
	    *pline='\0';
	    pline=line;
	    while(isspace(*pline) && *pline!='\0') ++pline;
            ++num_printers;
            printer_names = realloc(printer_names, 
				    (num_printers+1)*sizeof(char *));
            printer_names[num_printers] = strdup(pline);
    }
   
    fclose(fd);
    free(printcap);
}
#endif

static void
printerMenuSelect(Widget w, XtPointer junk, XtPointer garbage)
{
    char *name, *ptr;
    XtVaGetValues(w, XtNlabel, &name, NULL);
    if (strcmp(name, "(-)")) {
       printcmd_str = realloc(printcmd_str,
                              strlen(printcmd_ini)+strlen(name)+4);
       sprintf(printcmd_str, "%s%s", printcmd_ini, name);
    } else {
       printcmd_str = realloc(printcmd_str, strlen(printcmd_short) + 1);
       strcpy(printcmd_str, printcmd_short);
    }
    XtVaSetValues(printinfo->printcmd, XtNstring, printcmd_str, NULL);
    XtVaSetValues(printinfo->printtoggle, XtNstate, True, NULL);   
    XtVaSetValues(printinfo->filetoggle, XtNstate, False, 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->form);
    Window win = XtWindow(l->form);
    int a, i, j, top;

#ifdef XAW3D
    a = 4 * Global.btn_height / 5 + 4;
    i = 5 * a + 31;
    j = PAGEHEIGHT+EXTRAHEIGHT+3*Global.btn_height/2+27;
#else
    i = 120;   
    j = PAGEHEIGHT+EXTRAHEIGHT+51;
#endif   
    XDrawLine(dpy, win, l->gc2, i, j-2, PAGEWIDTH+EXTRAWIDTH, j-2);
    XDrawLine(dpy, win, l->gc2, i, j+2, PAGEWIDTH+EXTRAWIDTH, 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);

#ifdef XAW3D 
    i = PAGEWIDTH+EXTRAWIDTH+ a/2 + 8;
    j = PAGEHEIGHT+EXTRAHEIGHT+Global.btn_height+ 18;
    top = Global.btn_height+ 5*a + 45;
#else
    i = PAGEWIDTH+EXTRAWIDTH+17;   
    j = PAGEHEIGHT+EXTRAHEIGHT+34;
    top = 172;
#endif   
    XDrawLine(dpy, win, l->gc2, i-2, top, i-2, j);
    XDrawLine(dpy, win, l->gc2, i+2, top, i+2, j);
    XDrawLine(dpy, win, l->gc2, i, top-6, i+5, top+4);
    XDrawLine(dpy, win, l->gc2, i, top-6, i-5, top+4);
}

static void
buttonPressed(Widget w, XtPointer arg, XConfigureEvent * event, 
              Boolean * flg)
{
    if (event->type == ButtonPress || event->type == ButtonRelease) {
        XtSetKeyboardFocus((Widget)arg, None);
        XtSetKeyboardFocus((Widget)arg, w);
    }
}

static void 
closeMenus(Widget w, PrintInfo * l, XEvent * event, Boolean * flg)
{
    PopdownMenusGlobal();
    if (event->type = LeaveNotify)
        XSetInputFocus(XtDisplay(l->form), XtWindow(l->form),
                       RevertToNone, CurrentTime);
}

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;
    char *title;

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

    memcpy(&pageinfo, info, sizeof(PageInfo));
    pageinfo.wbbox = paper_sizes[info->papertype][0];
    pageinfo.hbbox = paper_sizes[info->papertype][1];
    pageinfo.eps = False;

    XtVaGetValues(info->graytoggle, XtNstate, &pageinfo.gray, NULL);
    XtVaGetValues(info->compresstoggle, XtNstate, &pageinfo.compress, NULL);
    XtVaGetValues(info->pdftoggle, XtNstate, &pageinfo.pdf, NULL);
    XtVaGetValues(info->filename, XtNstring, &title, NULL);

    if (title && *title) 
        pageinfo.title = title;
    else
        pageinfo.title = filename;

    if ((pageinfo.orient = info->orient)) {
        int exch = pageinfo.hsubdiv;
	pageinfo.hsubdiv = pageinfo.wsubdiv;
	pageinfo.wsubdiv = exch;
    }
    pageinfo.page = 1;
    WriteResizedPS(filename, image, &pageinfo);
    ImageDelete(image);
}

static void FlashString(char *str)
{
    int i;
    for (i=1; i<=4; i++) {
	XtVaSetValues(printinfo->printresult, XtNstring, str, NULL);
        XFlush(XtDisplay(printinfo->printresult));
        if (i==4) return;
        usleep(300000);
	XtVaSetValues(printinfo->printresult, XtNstring, "", NULL);
        XFlush(XtDisplay(printinfo->printresult));
        usleep(100000);
    }
}

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

    PopdownMenusGlobal();

    if (info->output) {
        XtVaGetValues(printinfo->filename, XtNstring, &name, NULL);
        XtVaGetValues(info->pdftoggle, XtNstate, &dopdf, NULL);

        if (dopdf) {
            doWritePS(info, info->tmpfile);
            sprintf(cmd, "ps2pdf %s %s", info->tmpfile, name);
            if (system(cmd));
            unlink(info->tmpfile);
	} else
            doWritePS(info, name);
        sprintf(cmd, msgText[FILE_WRITTEN], name);
    } else {
        char *name;
	XtVaGetValues(info->printcmd, XtNstring, &name, NULL);
        doWritePS(info, info->tmpfile);
        sprintf(cmd, "( %s %s ; rm -f %s ) &", 
            name, info->tmpfile, info->tmpfile);
        if (system(cmd));
        sprintf(cmd, msgText[FILE_SENT_TO_PRINTER], name);
    }
    FlashString(cmd);
}

static void 
selectionOkCallback(Widget w, XtPointer infoArg, char* file)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    XtVaSetValues(info->filename, XtNstring, file, NULL);
    PopdownMenusGlobal();
}
 
static void 
fileselectCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    char *name;
    PopdownMenusGlobal();
    XtVaGetValues(info->filename, XtNstring, &name, NULL);
    XtVaSetValues(info->filetoggle, XtNstate, True, NULL);
    GetFileName(GetToplevel(w), BROWSER_SIMPLESAVE, name, 
                (XtCallbackProc) selectionOkCallback, (XtPointer)infoArg);
}

static void 
previewCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    PrintInfo *info = (PrintInfo *) infoArg;
    char cmd[2048];
    char *ps_viewer = NULL;
    char *name = NULL;
    Boolean dopdf, dofile;

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

    if (!ps_viewer) return;

    XtVaGetValues(info->filetoggle, XtNstate, &dofile, NULL);
    XtVaGetValues(info->pdftoggle, XtNstate, &dopdf, NULL);
    XtVaGetValues(info->filename, XtNstring, &name, NULL);

    doWritePS(info, info->tmpfile);

    if ((dofile && name && *name)) {
       if (dopdf) 
          sprintf(cmd, "( ps2pdf %s %s ; %s %s ; rm -f %s ) &", 
	          info->tmpfile, name, ps_viewer, name, info->tmpfile);
       else
          sprintf(cmd, "mv -f %s %s ; %s %s &", 
	          info->tmpfile, name, ps_viewer, name);
       if (system(cmd));
    } else {
       sprintf(cmd, "( %s %s ; rm -f %s ) &", 
	       ps_viewer, info->tmpfile, info->tmpfile);
       if (system(cmd));
    }
    sprintf(cmd, msgText[FILE_WRITTEN], (dofile)? name:info->tmpfile);
    FlashString(cmd);
}

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

    PopdownMenusGlobal();
    XtVaGetValues(info->printcmd, XtNstring, &ptr, NULL);
    if (ptr) {
       if (printcmd_str) free(printcmd_str);
       printcmd_str = strdup(ptr);
    }	
    XtVaGetValues(info->psviewcmd, XtNstring, &ptr, NULL);
    if (ptr) {
       if (psviewcmd_str) free(psviewcmd_str);
       psviewcmd_str = strdup(ptr);
    }	   
    dpy = XtDisplay(info->shell);
    XFreeGC(dpy, info->gc1);
    XFreeGC(dpy, info->gc2);
    XtDestroyWidget(info->shell);
    info->shell = 0;
    oldw = oldh = -1;
}

void
setPageSize(int *w, int *h)
{
    int i, j;
    if (!printinfo) {
       *w = 595;
       *h = 842;
       return;
    }
    i = printinfo->papertype;
    if (printinfo->orient) j = 1; else j = 0;
    if (i<0 || i>=XtNumber(formatMenu)) i = 11;
    *w = paper_sizes[i][j];
    *h = paper_sizes[i][1-j];
}

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;

    PopdownMenusGlobal();
    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->extview)
       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;
    char *name, *name1, *name2;
    struct stat buf;
    int i;
    Boolean state, statepdf;

    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->pdftoggle) {
       w = info->filetoggle;
       state = True;
       XtVaSetValues(info->filetoggle, XtNstate, state, NULL);
       
    }
    if (w == info->filetoggle || w == info->pdftoggle) {
       XtVaSetValues(info->printtoggle, XtNstate, !state, NULL);
       info->output = state;
       if (state) {
          XtVaGetValues(info->filename, XtNstring, &name, NULL);
          XtVaGetValues(info->pdftoggle, XtNstate, &statepdf, NULL);
	  if (!*name || !strncmp(name, "painting", 8)) {
	     name = xmalloc(20*sizeof(char));
	     i = 0;	     
	     incr1:
             sprintf(name, "painting-%d.%s", i, (statepdf)?"pdf":"ps");
	     if (stat(name, &buf)!=-1) {
	        ++i; 
		if (i<1000) goto incr1;
	     }
	     XtVaSetValues(info->filename, XtNstring, name, NULL);
	     free(name);
	  } else {
	     name1 = xmalloc(strlen(name)+8);
	     strcpy(name1, name);
	     name = rindex(name1, '.');
	     if (!strcasecmp(name, ".ps") || !strcasecmp(name, ".pdf"))
	        *name = '\0';
	     name = strdup(name1);
	     sprintf(name1, "%s.%s", name, (statepdf)?"pdf":"ps");
	     i = 0;	     
	     incr2:
	     if (stat(name1, &buf)!=-1) {
	        name2 = name + strlen(name) - 1;
	        while (name2 > name && isdigit(*name2)) --name2;
	        if (*name2 == '-') {
		   i = atoi(name2+1);
		   *name2 = '\0';
		}
	        ++i; 
		if (i<1000) {
                   sprintf(name1, "%s-%d.%s", name, i, (statepdf)?"pdf":"ps");
		   goto incr2;
		}
	     }
	     XtVaSetValues(info->filename, XtNstring, name1, NULL);
	     free(name);
	     free(name1);	     
	  }
       }
    }
    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 buf[256];

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

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

void
printpopupResized(Widget w, PrintInfo * l, XConfigureEvent * event, 
                  Boolean * flg)
{
    Dimension width, height;
    Widget *wg;
    Position x, y;
    int dx, dy, i, n;
    XtVaGetValues(l->shell, XtNwidth, &width, XtNheight, &height, NULL);
    if (width == oldw && height == oldh) return;
    if (oldw == -1) {
      x = 0;
      wg = &l->size;
      for (i=0; i<7; i++) {
        XtVaGetValues(wg[i], XtNx, &y, NULL);
        if (y > x) x = y;
      }
      XResizeWindow(XtDisplay(l->form), XtWindow(l->form), width, height);
      XMapWindow(XtDisplay(l->form), XtWindow(l->form));	      
      for (i=0; i<7; i++) {
        XtVaGetValues(wg[i], XtNy, &y, NULL);
        XtMoveWidget(wg[i], x, y);
	XMapWindow(XtDisplay(wg[i]), XtWindow(wg[i]));	
      }
      wg = &l->printerlist;
      for (i=0; i<4; i++) if (wg[i]) {
        XtVaGetValues(wg[i], XtNy, &y, NULL);
        XtMoveWidget(wg[i], x - Global.btn_height - 2, y);
	XMapWindow(XtDisplay(wg[i]), XtWindow(wg[i]));
      }
      oldw = width;
      oldh = height;
      wg = &l->wplus;
      for (i=0; i<6; i++) {
         XtVaGetValues(wg[i], XtNx, &x, NULL);      
#ifdef XAW3D       
         XtMoveWidget(wg[i], x, PAGEHEIGHT+EXTRAHEIGHT+Global.btn_height+28);
#else       
         XtMoveWidget(wg[i], x, PAGEHEIGHT+EXTRAHEIGHT+Global.btn_height+25);
#endif
	 XMapWindow(XtDisplay(wg[i]), XtWindow(wg[i]));	 
      }
      wg = &l->compresslabel;
      XtVaGetValues(wg[3], XtNx, &x, XtNy, &y, NULL);
      n = Global.btn_height * 4 / 5 + 8;
      n = width - n - x;
      for (i=3; i>=0; i--) {      
        if (i==1) n = n/2;
        XtVaGetValues(wg[i], XtNx, &x, XtNy, &y, NULL);
        XtMoveWidget(wg[i], x + n, y);
	XMapWindow(XtDisplay(wg[i]), XtWindow(wg[i]));	
      }
      drawArrows(l->shell, l, NULL, False);
      findDrawSize(l);
      showDrawing(l);
    } else {
      i = 4 * Global.btn_height / 5 + 4;
      x = 5 * i + 25;
      y = PAGEHEIGHT+Global.btn_height+8;
      XClearArea(XtDisplay(l->form), XtWindow(l->form),
	         x, y,  PAGEWIDTH+EXTRAWIDTH, y+2*Global.btn_height+10, True);
      x = PAGEWIDTH+EXTRAWIDTH + 4;
      y = PAGEHEIGHT+EXTRAHEIGHT+Global.btn_height+ 18;
      n = Global.btn_height+ 5*i + 39;
      XClearArea(XtDisplay(l->form), XtWindow(l->form),
	         x, n, x+18, y, True);
      dx = width - oldw;
      dy = height - oldh;
      PAGEWIDTH += dx;
      i = 0;
      n = 200;
      if (PAGEWIDTH<n) {
	i = n - PAGEWIDTH;
	dx += i;
	width += i;
	PAGEWIDTH = n;
      }
      PAGEHEIGHT += dy;
      /* n = Global.btn_height * 297 / 21; */
      n = 283;
      if (PAGEHEIGHT<n) {
	i = n - PAGEHEIGHT;
	dy += i;
	height += i;
	PAGEHEIGHT = n;
      }
      if (i) {
        XResizeWindow(XtDisplay(l->shell), XtWindow(l->shell), width, height);
        XResizeWindow(XtDisplay(l->form), XtWindow(l->form), width, height);	
      }
      oldw = width;
      oldh = height;
      XResizeWindow(XtDisplay(l->form), XtWindow(l->form), width, height);
      XtResizeWidget(l->vp, PAGEWIDTH+EXTRAWIDTH, PAGEHEIGHT+EXTRAHEIGHT, 0);
      XtResizeWidget(l->box, PAGEWIDTH+EXTRAWIDTH, PAGEHEIGHT+EXTRAHEIGHT, 0);
      XtResizeWidget(l->page, PAGEWIDTH, PAGEHEIGHT, 1);
      wg = &l->hplus;
      n = &l->printermenu - wg;
      if (dx) for (i=0; i<n; i++) {      
        XtVaGetValues(wg[i], XtNx, &x, XtNy, &y, NULL);
        XtMoveWidget(wg[i], x + dx, y);
      }
      XtVaGetValues(l->equal, XtNx, &x, XtNy, &y, NULL);
      XtMoveWidget(l->equal, x + dx, y + dy);
      wg = &l->wplus;
      if (dy) for (i=0; i<5; i++) {      
        XtVaGetValues(wg[i], XtNx, &x, XtNy, &y, NULL);
        XtMoveWidget(wg[i], x, y + dy);
      }      
      wg = &l->printerlist;
      for (i=0; i<4; i++) if (wg[i]) {
	XMapWindow(XtDisplay(wg[i]), XtWindow(wg[i]));
      }
      findDrawSize(l);
      showDrawing(l);
    }
}

static void 
CheckNotify(Widget w, XEvent * event, String * params, Cardinal * nparams)
{
    Position pos;
    XtVaGetValues(w, XtNy, &pos, NULL);
    XtCallActionProc(w, "notify", event, params, 0);
    if (event->xbutton.y_root > pos) XtPopdown(w);
} 

void 
PrintPopup(Widget w, XtPointer paintArg)
{
    static Cursor pageCursor = None;
    static XGCValues gcv;
    static XtTranslations paint_translations = None;
    static XtTranslations button_translations = None;
    static String buttonTranslations =
    "#override\n\
<BtnDown>: check-notify()";
    
    Display *dpy;
    Window root;
    char *defname = "yellow", *canvasfile, *ptr;
    char wname[8];
    XColor scol, ecol;
    Pixel white, black, defpix;
    int a, b, aw, bw, i;
    Position x, y;
    Arg args[6];
    int nargs = 0, new = 0;
    FILE *out;

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

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

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

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

    if (canvasfile) {
        char *ptr;
        canvasfile = xmalloc(strlen(canvasfile)+4);
	strcpy(canvasfile, ((PaintWidget) paintArg)->paint.filename);
	ptr = strrchr(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);

    PAGEWIDTH = 10 * Global.btn_height;
    PAGEHEIGHT = Global.btn_height * 297 / 21;
    printinfo->shell = XtVisCreatePopupShell("print", topLevelShellWidgetClass,
				  GetShell(w), args, nargs);
    white = WhitePixelOfScreen(XtScreen(printinfo->shell));
    black = BlackPixelOfScreen(XtScreen(printinfo->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);

    printinfo->form = XtVaCreateManagedWidget("form", formWidgetClass, printinfo->shell, NULL);

    XtAddEventHandler(printinfo->form, ButtonPressMask,
                  False, (XtEventHandler)closeMenus, (XtPointer) printinfo);

    printinfo->bar = MenuBarCreate(printinfo->form, XtNumber(printMenuBar), printMenuBar);

    printinfo->format = XtVaCreateManagedWidget("formattype",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, printinfo->bar,
				       XtNvertDistance, 7,
				       XtNwidth, 100,
				       NULL);

    XtAddEventHandler(printinfo->format, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    printinfo->print = XtVaCreateManagedWidget("print",
				       commandWidgetClass, printinfo->form,
				       XtNheight, Global.btn_height,
				       XtNfromHoriz, printinfo->format,
				       XtNvertDistance, 8,
				       NULL);

    printinfo->preview = XtVaCreateManagedWidget("preview",
					 commandWidgetClass, printinfo->form,
				         XtNheight, Global.btn_height,
				         XtNfromHoriz, printinfo->print,
				         XtNhorizDistance, 9,
				         XtNvertDistance, 8,
					 NULL);

    printinfo->cancel = XtVaCreateManagedWidget("cancel",
					   commandWidgetClass, printinfo->form,
					   XtNheight, Global.btn_height,	
				           XtNfromHoriz, printinfo->preview,
				           XtNhorizDistance, 9,
				           XtNvertDistance, 8,
					   NULL);

    printinfo->vp = XtVaCreateManagedWidget("viewport", viewportWidgetClass, 
                                 printinfo->form,
				 XtNfromVert, printinfo->bar,
				 XtNvertDistance, 8,
				 XtNallowVert, False,
				 XtNallowHoriz, False,
				 XtNleft, XtChainLeft,
				 XtNright, XtChainRight,
				 XtNwidth, PAGEWIDTH+EXTRAWIDTH,
				 XtNheight, PAGEHEIGHT+EXTRAHEIGHT,
			         XtNbackground, white,
				 NULL);

    printinfo->box = XtVaCreateManagedWidget("printBox", boxWidgetClass, 
                            printinfo->vp,
			    XtNbackgroundPixmap, GetBackgroundPixmap(printinfo->vp),
			    XtNwidth, PAGEWIDTH+EXTRAWIDTH,
			    XtNheight, PAGEHEIGHT+EXTRAHEIGHT,		     
			    NULL);

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

    if (pageCursor == None)
        pageCursor = XCreateFontCursor(dpy, XC_crosshair);


    a = Global.btn_height * 4 / 5 + 4;
    aw = 9 * Global.btn_height;
    bw = 2 * Global.btn_height;

    printinfo->wpplus = XtVaCreateManagedWidget("wpplus",
				       commandWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->wplus = XtVaCreateManagedWidget("wplus",
				       commandWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNfromHoriz, printinfo->wpplus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->wminus = XtVaCreateManagedWidget("wminus",
				       commandWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNfromHoriz, printinfo->wplus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->wmminus = XtVaCreateManagedWidget("wmminus",
				       commandWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNfromHoriz, printinfo->wminus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->wcenter = XtVaCreateManagedWidget("wcenter",
				       commandWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNfromHoriz, printinfo->wmminus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->hpplus = XtVaCreateManagedWidget("hpplus",
				       commandWidgetClass, printinfo->form,
				       XtNfromHoriz, printinfo->vp,
				       XtNfromVert, printinfo->bar,
				       XtNvertDistance, 6,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->hplus = XtVaCreateManagedWidget("hplus",
				       commandWidgetClass, printinfo->form,
				       XtNfromHoriz, printinfo->vp,
				       XtNfromVert, printinfo->hpplus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->hminus = XtVaCreateManagedWidget("hminus",
				       commandWidgetClass, printinfo->form,
				       XtNfromHoriz, printinfo->vp,
				       XtNfromVert, printinfo->hplus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->hmminus = XtVaCreateManagedWidget("hmminus",
				       commandWidgetClass, printinfo->form,
				       XtNfromHoriz, printinfo->vp,
				       XtNfromVert, printinfo->hminus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->hcenter = XtVaCreateManagedWidget("hcenter",
				       commandWidgetClass, printinfo->form,
				       XtNfromHoriz, printinfo->vp,
				       XtNfromVert, printinfo->hmminus,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->equal = XtVaCreateManagedWidget("equal",
				       toggleWidgetClass, printinfo->form,
				       XtNfromVert, printinfo->vp,
				       XtNfromHoriz, printinfo->vp,
				       XtNstate, printinfo->tied,
				       XtNvertDistance, 12,
				       XtNwidth, a, XtNheight, a,
				       NULL);

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

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

	text_translations = XtParseTranslationTable(textTranslations);
    }

    b = 2 * (Global.btn_height - 19);

    printinfo->portraitlabel = XtVaCreateManagedWidget("portraitlabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNfromVert, printinfo->bar,
				       XtNhorizDistance, 30,
				       XtNvertDistance, b,
				       NULL);

    printinfo->portraittoggle = XtVaCreateManagedWidget("portraittoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, !printinfo->orient,
				       XtNfromHoriz, printinfo->portraitlabel,
				       XtNfromVert, printinfo->bar,
				       XtNhorizDistance, 12,
				       XtNvertDistance, b,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->landscapelabel = XtVaCreateManagedWidget("landscapelabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->portraittoggle,
				       XtNfromVert, printinfo->bar,
				       XtNhorizDistance, 4*Global.btn_height,
				       XtNvertDistance, b,
				       NULL);

    printinfo->landscapetoggle = XtVaCreateManagedWidget("landscapetoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, printinfo->orient,
				       XtNfromHoriz, printinfo->landscapelabel,
                                       XtNradioGroup,printinfo->portraittoggle,
				       XtNfromVert, printinfo->bar,
				       XtNhorizDistance, 6,
				       XtNvertDistance, b,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->graylabel = XtVaCreateManagedWidget("graylabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, 30,
				       XtNvertDistance, 6,
				       NULL);

    printinfo->graytoggle = XtVaCreateManagedWidget("graytoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, 0,
				       XtNfromHoriz, printinfo->graylabel,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, 6,
				       XtNvertDistance, 6,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->compresslabel = XtVaCreateManagedWidget("compresslabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->graytoggle,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, Global.btn_height,
				       XtNvertDistance, 6,
				       NULL);

    printinfo->compresstoggle = XtVaCreateManagedWidget("compresstoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, 0,
				       XtNfromHoriz, printinfo->compresslabel,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, 12,
				       XtNvertDistance, 6,
				       XtNstate, True,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->pdflabel = XtVaCreateManagedWidget("pdflabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->compresstoggle,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, 4*Global.btn_height,
				       XtNvertDistance, 6,
				       NULL);

    printinfo->pdftoggle = XtVaCreateManagedWidget("pdftoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, 0,
				       XtNfromHoriz, printinfo->pdflabel,
				       XtNfromVert, printinfo->portraittoggle,
				       XtNhorizDistance, 6,
				       XtNvertDistance, 6,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->sizelabel = XtVaCreateManagedWidget("sizelabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNfromVert, printinfo->graytoggle,
				       XtNhorizDistance, 30,
				       XtNvertDistance, 12,
				       NULL);

    printinfo->size = XtVaCreateManagedWidget("sizevalue",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, printinfo->sizelabel,
				       XtNfromVert, printinfo->graytoggle,
				       XtNwidth, aw,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNvertDistance, 12,
				       NULL);
    XtAddEventHandler(printinfo->size, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    printinfo->positionlabel = XtVaCreateManagedWidget("positionlabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNfromVert, printinfo->size,
				       XtNhorizDistance, 30,
				       NULL);

    printinfo->position = XtVaCreateManagedWidget("positionvalue",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromHoriz, printinfo->positionlabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNfromVert, printinfo->size,
				       XtNwidth, aw,
				       NULL);
    XtAddEventHandler(printinfo->position, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    printinfo->samplinglabel = XtVaCreateManagedWidget("samplinglabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNfromVert, printinfo->position,
				       XtNhorizDistance, 30,
				       NULL);

    printinfo->sampling = XtVaCreateManagedWidget("samplingvalue",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNresize, XawtextResizeWidth,
				       XtNfromVert, printinfo->position,
				       XtNfromHoriz, printinfo->samplinglabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNwidth, aw,
				       NULL);
    XtAddEventHandler(printinfo->sampling, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    printinfo->printlabel = XtVaCreateManagedWidget("printlabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromVert, printinfo->sampling,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNhorizDistance, 30,
				       XtNvertDistance, 14,
				       NULL);

    printinfo->printcmd = XtVaCreateManagedWidget("printcmd",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, printinfo->sampling,
				       XtNfromHoriz, printinfo->printlabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNvertDistance, 14,
				       XtNwidth, aw, XtNheight, bw,
				       NULL);
    XtAddEventHandler(printinfo->printcmd, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    if (printcmd_str) 
       XtVaSetValues(printinfo->printcmd, XtNstring, printcmd_str, NULL);

    printinfo->printerlist = XtVaCreateManagedWidget("printerlist",
                                    menuButtonWidgetClass, printinfo->form,
				    XtNmenuName, "printermenu",
				    XtNborderWidth, 1,
				    XtNwidth, a, XtNheight, a,
				    XtNfromVert, printinfo->sampling,
				    XtNfromHoriz, printinfo->printlabel,
				    XtNvertDistance, 15,
#ifdef XAW3D
                                    XtNborderWidth, 0,							    
#endif							    
				    NULL);
    
    printinfo->printtoggle = XtVaCreateManagedWidget("printtoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, !printinfo->output,
				       XtNfromVert, printinfo->printerlist,
				       XtNfromHoriz, printinfo->printlabel,
				       XtNhorizDistance, 4,
				       XtNvertDistance, 4,
				       XtNwidth, a, XtNheight, a,
				       NULL);
   
    printinfo->filelabel = XtVaCreateManagedWidget("filelabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromVert, printinfo->printcmd,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNhorizDistance, 30,
				       NULL);

    printinfo->filename = XtVaCreateManagedWidget("filename",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, printinfo->printcmd,
				       XtNfromHoriz, printinfo->filelabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNvertDistance, 6,
				       XtNwidth, aw, XtNheight, bw,
				       NULL);
    XtAddEventHandler(printinfo->filename, ButtonPressMask | ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    if (canvasfile) {
        XtVaSetValues(printinfo->filename, XtNstring, canvasfile, NULL);
	free(canvasfile);
    }

    printinfo->fileselect = XtVaCreateManagedWidget("fileselect",
				       commandWidgetClass, printinfo->form,
				       XtNlabel, "?",
				       XtNwidth, a, XtNheight, a,
				       XtNfromVert, printinfo->printcmd,
				       XtNfromHoriz, printinfo->filelabel,
                                       XtNvertDistance, 6,
				       NULL);

    printinfo->filetoggle = XtVaCreateManagedWidget("filetoggle",
				       toggleWidgetClass, printinfo->form,
                                       XtNstate, printinfo->output,
				       XtNfromVert, printinfo->fileselect,
				       XtNfromHoriz, printinfo->filelabel,
				       XtNradioGroup, printinfo->printtoggle,
                                       XtNvertDistance, 4,
				       XtNwidth, a, XtNheight, a,
				       NULL);

    printinfo->psviewlabel = XtVaCreateManagedWidget("psviewlabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromVert, printinfo->filename,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNhorizDistance, 30,
				       NULL);

    printinfo->psviewcmd = XtVaCreateManagedWidget("psviewcmd",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, printinfo->filename,
				       XtNfromHoriz, printinfo->psviewlabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNvertDistance, 6,
				       XtNwidth, aw, XtNheight, bw,
				       NULL);
    XtAddEventHandler(printinfo->psviewcmd, ButtonPressMask| ButtonReleaseMask, 
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    printinfo->resultlabel = XtVaCreateManagedWidget("resultlabel",
				       labelWidgetClass, printinfo->form,
				       XtNborderWidth, 0,
				       XtNfromVert, printinfo->psviewcmd,
				       XtNfromHoriz, printinfo->hpplus,
				       XtNvertDistance, 6,
				       XtNhorizDistance, 30,
				       NULL);

    printinfo->printresult = XtVaCreateManagedWidget("printresult",
				       asciiTextWidgetClass, printinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNfromVert, printinfo->psviewcmd,
				       XtNfromHoriz, printinfo->resultlabel,
				       XtNhorizDistance, Global.btn_height+8,
				       XtNvertDistance, 6,
				       XtNwidth, aw, XtNheight, bw,
				       NULL);
    XtAddEventHandler(printinfo->printresult, ButtonPressMask|ButtonReleaseMask,
                                  False, (XtEventHandler) buttonPressed,
                                  (XtPointer) printinfo->form);

    if (psviewcmd_str) 
       XtVaSetValues(printinfo->psviewcmd, XtNstring, psviewcmd_str, NULL);

    XtAddEventHandler(printinfo->shell, StructureNotifyMask, False,
	      (XtEventHandler) printpopupResized, (XtPointer) printinfo);

    XtAddEventHandler(printinfo->form, ExposureMask,
		  False, (XtEventHandler) drawArrows, (XtPointer) printinfo);

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

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

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

    XtAddCallback(XtNameToWidget(printinfo->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(printinfo->wcenter, XtNcallback,
		  (XtCallbackProc) wcenterCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->wplus, XtNcallback,
		  (XtCallbackProc) wplusCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->wpplus, XtNcallback,
		  (XtCallbackProc) wpplusCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->wminus, XtNcallback,
		  (XtCallbackProc) wminusCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->wmminus, XtNcallback,
		  (XtCallbackProc) wmminusCallback, (XtPointer) printinfo);

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

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

    XtAddCallback(printinfo->print, XtNcallback,
		  (XtCallbackProc) printCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->preview, XtNcallback,
		  (XtCallbackProc) previewCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->fileselect, XtNcallback,
		  (XtCallbackProc) fileselectCallback, (XtPointer) printinfo);
    XtAddCallback(printinfo->cancel, XtNcallback,
		  (XtCallbackProc) closePrintCallback, (XtPointer) printinfo);
    AddDestroyCallback(printinfo->shell, (DestroyCallbackFunc) closePrintCallback, printinfo);

    XtPopup(printinfo->shell, XtGrabNone);
    XtVaGetValues(printinfo->printcmd, XtNstring, &ptr, NULL);
    
    if (ptr && *ptr && !printcmd_ini)
       printcmd_ini = strdup(ptr);
    
    if (!printcmd_ini) printcmd_ini = strdup(PRINTCMD);

    if (!printcmd_short) {
       printcmd_short = strdup(printcmd_ini);
       ptr = printcmd_short;
       while (*ptr && !isspace(*ptr)) ++ptr;
       if (isspace(*ptr)) *ptr = '\0';
    }
    XtVaGetValues(printinfo->printcmd, XtNstring, &ptr, NULL);
    if (!strcmp(ptr, printcmd_ini))
       XtVaSetValues(printinfo->printcmd, XtNstring, printcmd_short, NULL);

    if (!printerlist_env) {
       XtVaGetValues(printinfo->printerlist, XtNlabel, &ptr, NULL);
       if (ptr && *ptr)
	  printerlist_env = strdup(ptr);
       else
	  printerlist_env = strdup(PRINTERLIST);
    }

#ifdef PRINTCAP
    for(i=1; i<=num_printers; i++) free(printer_names[i]);
    parsePrintcap(printerlist_env);
#else
    for (i=1; i<=num_printers; i++) free(printer_names[i]);
    num_printers = 0;
    out = popen(printerlist_env, "r");
    ptr = NULL;
    i = 0;
    num_printers = 0;
    while (!feof(out)) {
       ptr = (char *)realloc(ptr, i+3);
       ptr[i] = fgetc(out);
       if (ptr[i] == '\n') {
	  ptr[i] = '\0';
          ++num_printers;	 
          printer_names = (char **)realloc(printer_names, 
	 		                  (num_printers+1)*sizeof(char *));
          printer_names[num_printers] = strdup(ptr);
          i = 0;	  
       } else
          ++i;
    }
    if (i != 0) {
       ++num_printers;	 
       printer_names = (char **)realloc(printer_names, 
	 		                  (num_printers+1)*sizeof(char *));
       printer_names[num_printers] = strdup(ptr);
    }
    pclose(out);
    printer_names[0] = "(-)";
    if (!isalnum(printer_names[num_printers][0])) {
       free(printer_names[num_printers]);
       --num_printers;
    }
#endif
    XtVaSetValues(printinfo->printerlist, XtNlabel, "?", NULL);
    if (!num_printers) {
       printer_names = (char **)realloc(printer_names, sizeof(char *));
       printer_names[0] = "(-)";
    }
      
    printinfo->printermenu = XtVaCreatePopupShell("printermenu",
				    simpleMenuWidgetClass, 
                                    printinfo->printerlist,
				    NULL);

    if (button_translations == None) {
        static XtActionsRec act[1] =
	      {"check-notify",  (XtActionProc) CheckNotify};

        XtAppAddActions(
                  XtWidgetToApplicationContext(printinfo->printermenu),
                  act, 1);
        button_translations = XtParseTranslationTable(buttonTranslations);
        XtOverrideTranslations(printinfo->printermenu, button_translations);
    }

    for (i = 0; i<=num_printers; i++) {
	sprintf(wname, "%d", i);
	printinfo->printentry = 
	XtVaCreateManagedWidget(wname, smeBSBObjectClass,
				printinfo->printermenu, 
				XtNlabel, printer_names[i], NULL);
	XtAddCallback(printinfo->printentry,
			 XtNcallback, printerMenuSelect, NULL);
    }
      
    SetWMInputHint(dpy, XtWindow(printinfo->shell));
    XtUnmanageChild(printinfo->form);
    XMapWindow(XtDisplay(printinfo->form), XtWindow(printinfo->form));

    if (new) {
        char *ptr;
	int u, v;
        XtVaGetValues(printinfo->format, XtNstring, &ptr, NULL);
        setPapertype(ptr);
	XtVaGetValues(printinfo->sampling, 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(printinfo->size, 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(printinfo->page), pageCursor);
    XFlush(XtDisplay(printinfo->form));
}

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->formatlabel, XtNlabel, str, NULL);
	    MenuCheckItem(w, True);
	    l->mode = i;
	    break;
	}
}
   
static void 
closeExternCallback(Widget w, XtPointer infoArg, XtPointer junk2)
{
    ExternInfo *info = (ExternInfo *) infoArg;
    PopdownMenusGlobal();    
    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 *extviewcmd, *tmp, *sep, *file = NULL;
    int i, del, fd;

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

    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 = strrchr(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.pixmap, 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);

    if (system(cmd));
    free(file);
}

void
externpopupResized(Widget w, ExternInfo * l, XConfigureEvent * event, 
                  Boolean * flg)
{
    Dimension width, height, width1, height1;
    int x;

    XtVaGetValues(l->shell, XtNwidth, &width, XtNheight, &height, NULL);
    XResizeWindow(XtDisplay(l->form), XtWindow(l->form), width, height);
    XtVaGetValues(l->extview, XtNx, &x, NULL);
    width1 = width - x - 8;
    if (width1 < 100) width1 = 100;
    height1 = height - 2 * Global.btn_height - 16;
    if (height1 < 40) height1 = 40;
    XtMoveWidget(l->extview, x, Global.btn_height + 8);
    XtResizeWidget(l->extview, width1, height1, 0);
    XtVaGetValues(l->viewbut, XtNx, &x, NULL);
    XtMoveWidget(l->viewbut, x, height - Global.btn_height - 3);
    XtVaGetValues(l->cancel, XtNx, &x, NULL);
    XtMoveWidget(l->cancel, x, height - Global.btn_height - 3);
}

void 
ExternPopup(Widget w, XtPointer paintArg)
{
    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) {
            RaiseWindow(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++;

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

    externinfo->form = 
        XtVaCreateManagedWidget("form", formWidgetClass, externinfo->shell, NULL);

    externinfo->bar = 
        MenuBarCreate(externinfo->form, XtNumber(externMenuBar), externMenuBar);

    externinfo->formatlabel = XtVaCreateManagedWidget("formatlabel",
				       labelWidgetClass, externinfo->form,
				       XtNfromHoriz, externinfo->bar,
				       XtNheight, Global.btn_height,
				       XtNborderWidth, 0,
				       NULL);

    externinfo->extviewlabel = XtVaCreateManagedWidget("extviewlabel",
				       labelWidgetClass, externinfo->form,
				       XtNfromVert, externinfo->bar,
				       XtNheight, Global.btn_height,
				       XtNvertDistance, 10,
				       XtNborderWidth, 0,
				       NULL);

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

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

	text_translations = XtParseTranslationTable(textTranslations);
    }

    externinfo->extview = XtVaCreateManagedWidget("extviewcmd",
				       asciiTextWidgetClass, externinfo->form,
				       XtNtranslations, text_translations,
 				       XtNeditType, XawtextEdit,
				       XtNwrap, XawtextWrapNever,
				       XtNscrollHorizontal, True,
				       XtNwidth, 450, XtNheight, 100,
				       XtNfromVert, externinfo->bar,
				       XtNvertDistance, 10,
				       XtNfromHoriz, externinfo->extviewlabel,
				       NULL);

    if (externinfo->cmd)
        XtVaSetValues(externinfo->extview, XtNstring, externinfo->cmd, NULL);

    externinfo->viewbut = XtVaCreateManagedWidget("view",
				       commandWidgetClass, externinfo->form,
				       XtNfromVert, externinfo->extview,
				       XtNheight, Global.btn_height,
				       NULL);

    externinfo->cancel = XtVaCreateManagedWidget("cancel",
				       commandWidgetClass, externinfo->form,
				       XtNfromVert, externinfo->extview,
				       XtNfromHoriz, externinfo->viewbut,
				       XtNheight, Global.btn_height,
				       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(externinfo->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(externinfo->formatlabel, XtNlabel, str, NULL);
    MenuCheckItem(externinfo->formatChecks[externinfo->mode], True);

    XtAddCallback(externinfo->viewbut, XtNcallback,
		  (XtCallbackProc) viewExternCallback, (XtPointer) externinfo);

    XtAddCallback(externinfo->cancel, XtNcallback,
		  (XtCallbackProc)closeExternCallback, (XtPointer) externinfo);

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

    XtPopup(externinfo->shell, XtGrabNone);
    XtSetKeyboardFocus(externinfo->form, externinfo->extview);
    SetWMInputHint(dpy, XtWindow(externinfo->shell));
    XtUnmanageChild(externinfo->form);
    XMapWindow(XtDisplay(externinfo->form), XtWindow(externinfo->form));

    XtAddEventHandler(externinfo->shell, StructureNotifyMask, False,
	      (XtEventHandler) externpopupResized, (XtPointer) externinfo);
}

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;
    }
}

