/* +-------------------------------------------------------------------+ */
/* | 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: main.c,v 1.18 2000/09/11 18:42:58 torsten Exp $ */

#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#ifndef NOSTDHDRS
#include <stdlib.h>
#include <unistd.h>
#endif

#include <xpm.h>

#define DEFINE_GLOBAL
#include "xpaint.h"
#include "Paint.h"
#include "misc.h"
#include "operation.h"
#include "graphic.h"
#include "messages.h"
#include "protocol.h"
#include "rw/rwTable.h"

#include "XPaintIcon.xpm"

String *helpText;
int helpNum;
String *msgText;
int msgNum;

char lang[10];

extern void BrushInit(Widget toplevel);

static char *appDefaults[] =
{
#include "XPaint.ad.h"
    NULL
};

typedef struct {
    String visualType;
    String lang;
    String size;
    String winsize;
    String help;
    String rcFile;
    String helpFile;
    String msgFile;
    int zoom;
    Boolean fullpopup;
    Boolean nomenubar;
    Boolean popped;
    Boolean snapshot;
    Boolean horizontal;
    Boolean nowarn;
} AppInfo;

static AppInfo appInfo;

static XtResource resources[] =
{
    {"visualType", "VisualType", XtRString, sizeof(String),
   XtOffset(AppInfo *, visualType), XtRImmediate, (XtPointer) "default"},
    {"lang", "Lang", XtRString, sizeof(String),
     XtOffset(AppInfo *, lang), XtRImmediate, (XtPointer) NULL},
    {"size", "Size", XtRString, sizeof(String),
     XtOffset(AppInfo *, size), XtRImmediate, (XtPointer) "640x480"},
    {"winsize", "WinSize", XtRString, sizeof(String),
     XtOffset(AppInfo *, winsize), XtRImmediate, (XtPointer) "0x0"},
    {"rcFile", "RcFile", XtRString, sizeof(String),
     XtOffset(AppInfo *, rcFile), XtRImmediate, (XtPointer) NULL},
    {"help", "Help", XtRString, sizeof(String),
     XtOffset(AppInfo *, help), XtRImmediate, (XtPointer) NULL},
    {"helpFile", "HelpFile", XtRString, sizeof(String),
     XtOffset(AppInfo *, helpFile), XtRImmediate, (XtPointer) NULL},
    {"msgFile", "MsgFile", XtRString, sizeof(String),
     XtOffset(AppInfo *, msgFile), XtRImmediate, (XtPointer) NULL},
    {"zoom", "Zoom", XtRInt, sizeof(int),
     XtOffset(AppInfo *, zoom), XtRImmediate, (XtPointer) 1},
    {"fullpopup", "FullPopup", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, fullpopup), XtRImmediate, (XtPointer) True},
    {"nomenubar", "NoMenubar", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, nomenubar), XtRImmediate, (XtPointer) False},
    {"popped", "Popped", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, popped), XtRImmediate, (XtPointer) False},
    {"snapshot", "Snapshot", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, snapshot), XtRImmediate, (XtPointer) False},
    {"horizontal", "Horizontal", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, horizontal), XtRImmediate, (XtPointer) False},
    {"nowarn", "NoWarn", XtRBoolean, sizeof(Boolean),
     XtOffset(AppInfo *, nowarn), XtRImmediate, (XtPointer) False},
};

static XrmOptionDescRec options[] =
{
    {"-24", ".visualType", XrmoptionNoArg, (XtPointer) "true24"},
    {"-12", ".visualType", XrmoptionNoArg, (XtPointer) "cmap12"},
    {"-language", ".lang", XrmoptionSepArg, (XtPointer) NULL},
    {"-size", ".size", XrmoptionSepArg, (XtPointer) NULL},
    {"-winsize", ".winsize", XrmoptionSepArg, (XtPointer) "0x0"},
    {"-rcFile", ".rcFile", XrmoptionSepArg, (XtPointer) NULL},
    {"-helpFile", ".helpFile", XrmoptionSepArg, (XtPointer) NULL},
    {"-msgFile", ".msgFile", XrmoptionSepArg, (XtPointer) NULL},
    {"-zoom", ".zoom", XrmoptionSepArg, (XtPointer) "-1"},
    {"-simplepopup", ".fullpopup", XrmoptionNoArg, (XtPointer) "False"},
    {"-fullpopup", ".fullpopup", XrmoptionNoArg, (XtPointer) "True"},
    {"-nomenubar", ".nomenubar", XrmoptionNoArg, (XtPointer) "True"},
    {"-popped", ".popped", XrmoptionNoArg, (XtPointer) "True"},
    {"-snapshot", ".snapshot", XrmoptionNoArg, (XtPointer) "True"},
    {"-horizontal", ".horizontal", XrmoptionNoArg, (XtPointer) "True"},
    {"-nowarn", ".nowarn", XrmoptionNoArg, (XtPointer) "True"},
    {"-help", ".help", XrmoptionNoArg, (XtPointer) "command"},
    {"+help", ".help", XrmoptionSepArg, (XtPointer) NULL},
    {"-8", ".visualType", XrmoptionNoArg, (XtPointer) "cmap8"},
    {"-visual", ".visualType", XrmoptionSepArg, (XtPointer) NULL},
};


/*
**  Public query functions for application defaults
 */

void 
SetDefaultWHZ(int w, int h, int zoom)
{
    char str[40];
    if (w<=0) w = 1;
    if (h<=0) h = 1;
    if (zoom<=0) zoom = -1;
    if (zoom>32) zoom = 32;
    sprintf(str, "%dx%d", w, h);
    appInfo.size = strdup(str);
    appInfo.zoom = zoom;
}

void 
GetDefaultWH(int *w, int *h)
{
    int x, y;
    unsigned int width, height;

    XParseGeometry(appInfo.size, &x, &y, &width, &height);
    *w = width;
    *h = height;
}

void 
GetPaintWH(int *w, int *h)
{
    int x, y;
    unsigned int width, height;

    XParseGeometry(appInfo.winsize, &x, &y, &width, &height);
    *w = width;
    *h = height;
}

void 
GetInitZoom(int *z)
{
    *z = appInfo.zoom;
    if (*z<=0) *z = -1;
    if (*z>32) *z = 32;
}

void 
SetMenuBarHidden(Boolean flag)
{
    appInfo.nomenubar = flag;
}

Boolean
ThereIsNoMenuBar()
{
    return appInfo.nomenubar;
}

void 
SetFullMenuPopup(Boolean flag)
{
    appInfo.fullpopup = flag;
}

Boolean
IsFullPopup()
{
    return appInfo.fullpopup;
}

Boolean
ToolsAreHorizontal()
{
    return appInfo.horizontal;
}

char *
GetDefaultRC(void)
{
    return appInfo.rcFile;
}

/*
**  Create a nice icon image for XPaint...
 */
void 
SetIconImage(Widget w)
{
    static Pixmap icon = None;
    static int iconW = 1, iconH = 1;
    Window iconWindow;
    Screen *screen = XtScreen(w);
    Display *dpy = XtDisplay(w);
    XpmAttributes myattributes;

    /*
    **  Build the XPaint icon
     */
    iconWindow = XCreateSimpleWindow(dpy, RootWindowOfScreen(screen),
				     0, 0,	/* x, y */
				     iconW, iconH, 0,
				     BlackPixelOfScreen(screen),
				     BlackPixelOfScreen(screen));
    if (icon == None) {
 	myattributes.valuemask = XpmCloseness;
 	myattributes.closeness = 65535;
 	if (XpmCreatePixmapFromData(dpy, iconWindow,
				    XPaintIcon_xpm, &icon, NULL, &myattributes)) {
	    fprintf(stderr, msgText[CANNOT_INSTALL_XPM_ICON]);
	    exit(1);
 	}
	GetPixmapWHD(dpy, icon, &iconW, &iconH, NULL);
	XResizeWindow(dpy, iconWindow, iconW, iconH);
    }
    XSetWindowBackgroundPixmap(dpy, iconWindow, icon);

    XtVaSetValues(w, XtNiconWindow, iconWindow, NULL);
}


/*
**  The rest of main
 */
static void 
usage(char *prog, char *msg)
{
    if (msg)
	fprintf(stderr, "%s\n", msg);
    fprintf(stderr, "%s %s (XPaint %s):\n", 
            msgText[USAGE_FOR], prog, XPAINT_VERSION);
    HelpTextOutput(stderr, appInfo.help == NULL ? "command" : appInfo.help);
    exit(1);
}

typedef struct {
    XtWorkProcId id;
    Widget toplevel;
    int nfiles;
    int pos;
    char **files;
} LocalInfo;

static Boolean
workProc(LocalInfo * l)
{
    char *file;
    void *v;

    if ((l == NULL) || (l->id == None))
	return TRUE;

    file = l->files[l->pos];

    StateSetBusy(True);

    if ((v = ReadMagic(file)) != NULL)
	GraphicOpenFile(l->toplevel, file, v);
    else
	Notice(l->toplevel, msgText[UNABLE_TO_OPEN_INPUT_FILE],
	       file, RWGetMsg());

    StateSetBusy(False);

    if (++l->pos == l->nfiles) {
	XtFree((XtPointer) l->files);
	XtFree((XtPointer) l);
	return TRUE;
    } else
	return FALSE;
}

/*
 * You can specify:
 * the visual
 * the visual and the depth
 * the visualID
 * Any other combinations may not generate the results that you expect
 * Also note that the visualID is strongly dependent on the platform
 * being used.  We will let the user specify any visualID that they want.
 */
XVisualInfo
GetFutureVisual(Widget *toplevel, int desiredDepth, int desiredVisual,
		int desiredVisualID, Boolean *valid)
{
    Display *display = XtDisplay(*toplevel);
    int i, visnum = 0;
	
    XVisualInfo rtnval;
	
    int visualsMatched;    
     
    XVisualInfo vTemplate;   
    XVisualInfo visual[50]; /* If a machine has more than 50 visuals then this will fail. Higher end SGI's have 20 so this is probably OK */
    XVisualInfo *visualList = visual;
	

    *valid=FALSE;
      
    vTemplate.screen = DefaultScreen(display);

    if (desiredVisualID >= 0)
        visualList = XGetVisualInfo (display, VisualScreenMask, &vTemplate, &visualsMatched);
    else {
        vTemplate.class = desiredVisual;
	if (desiredDepth > 0) {
	    vTemplate.depth = desiredDepth;
	    visualList = XGetVisualInfo(display,
					VisualClassMask | VisualScreenMask |
					VisualDepthMask, &vTemplate,
					&visualsMatched);
	}
	else {
  	    visualList = XGetVisualInfo(display,
					VisualClassMask | VisualScreenMask,
					&vTemplate, &visualsMatched);
	}
    }

    if (visualsMatched && desiredVisualID >= 0) {
        visnum = -1;
	/* look through the entire list for our visual ID */
	for (i = 0; i < visualsMatched; i++) {
  	    if (XVisualIDFromVisual(visualList[i].visual) == desiredVisualID)
	        visnum = i;
	}
	if (visnum < 0)
	    visualsMatched=0;
    }
	
    if (visualsMatched == 0) {
        fprintf(stderr, msgText[NO_MATCH_FOUND_FOR_VISUAL]);
	exit(1);
    }
	
    rtnval = visualList[visnum];
    *valid = TRUE;
	  
    XFree(visualList);
	
    return rtnval;
}

void
LoadMessages()
{
    FILE *fd;
    int i, j;
    char buf[256];
    static char alert[] = "!! No messages found !!";
    static char failure[] = "Memory allocation failure\n";

    helpNum = 0; 
    fd = fopen(appInfo.helpFile, "r");
    if (!fd) {
        sprintf(buf, "%s/help/Help", SHAREDIR);
	fd = fopen(buf, "r");
    }
    if (fd) {
        while (!feof(fd)) {
            ++helpNum;
            helpText = (String *)realloc(helpText, helpNum*sizeof(String));
            fgets(buf, 250, fd);
            i = strlen(buf)-1;
            if (i>0 && buf[i] == '\n') buf[i] = '\0';
            helpText[helpNum-1] = strdup(buf);
        }
        fclose(fd);
    } else {
        fprintf(stderr, "No help file found !!\n");
    }

    msgNum = 0; 
    fd = fopen(appInfo.msgFile, "r");
    if (!fd) {
        sprintf(buf, "%s/messages/Messages", SHAREDIR);
	fd = fopen(buf, "r");
    }
    if (fd) {
        while (!feof(fd)) {
            fgets(buf, 250, fd);
	    if (*buf == '#') {
	         if (!strncmp(buf+1, "END_MESSAGES", 12)) break;
	         continue;
	    }
            ++msgNum;
            msgText = (String *)realloc(msgText, msgNum*sizeof(String));
	    if (!msgText) {
	        fprintf(stderr, failure);
	        exit(1);
	    }
            i = 0;
            j = 0;
            while (buf[i]) {
	        if (buf[i] == '\n') break;
	        if (buf[i] == '\\' && buf[i+1] == 'n') {
                     ++i;
		     buf[j] = '\n';
		} else
		if (j<i)
		     buf[j] = buf[i];
                ++i;
                ++j;
	    }
	    buf[j] = '\0';
            msgText[msgNum-1] = strdup(buf);
	    if (!msgText[msgNum-1]) {
	        fprintf(stderr, failure);
	        exit(1);
	    }
        }
        fclose(fd);
    } else {
        msgNum = END_MESSAGES;
        msgText = (String *)realloc(msgText, msgNum*sizeof(String));
        for (i=0; i<msgNum; i++) msgText[i] = alert;
	fprintf(stderr, "%s\n\n", msgText[0]);
    }
}

String GetAppDefaultFile()
{
    char *lg;
    char name[256];
    int i;
    FILE *fd = NULL;

    if (!*lang && (lg = getenv("LANG"))) strncpy(lang, lg, 8);
    if (*lang) {
        for (i=0; i<=8 ; i++) lang[i] = tolower(lang[i]);
    }
    else
        strcpy(lang, "en");
    sprintf(name, "%s/XPaint_%s", XAPPLOADDIR, lang);
    fd = fopen(name, "r");
    if (*lang && !fd) {
        lang[2] = '\0';
        sprintf(name, "%s/XPaint_%s", XAPPLOADDIR, lang);
	fd = fopen(name, "r");
    }   
    if (fd) {
        fclose(fd);
	sprintf(name, "XPaint_%s", lang);
	return strdup(name);
    } else
        return strdup("XPaint");
}


static void
checkRCsize()
{
    FILE *fd;
    char buf[256];
    char *ptr;
    int w, h, i;
    if (!strcmp(appInfo.size, "640x480")) {
        if (appInfo.rcFile)
	    strcpy(buf, appInfo.rcFile);
	else
	    strcpy(buf, ".XPaintrc");
	if ((fd = fopen(buf, "r"))) {
	    i = 0;
            while (!feof(fd)) {
                fgets(buf, 250, fd);
		if (*buf && isspace(*buf)) ++i;
		if (!strncasecmp(buf, "defaultsize", 11)) {
		    ptr = buf + 12;
		    while (isspace(*ptr)) ++ptr;
	            if (sscanf(ptr, "%dx%d", &w, &h) == 2) {
	                 SetDefaultWHZ(w, h, appInfo.zoom);
		    }
		    break;
		}
		if (i >= 4) break;
	    }
	    fclose(fd);
	}
    }
}

int
main(int argc, char *argv[])
{
    Display *dpy;
    Widget toplevel;
    XtAppContext app;
    char xpTitle[20];
    int i;
    XEvent event;
    Arg args[5];
    int nargs = 0;
    XrmDatabase rdb;
    Boolean isIcon;

    Widget temp;
    int desiredVisual = -1;
    XVisualInfo vis;
    Boolean valid;
    int depth;
    int desiredDepth;
    int tempargc;
    char **tempargv;
    char phrase[128];
    String app_def_file;
    int desiredVisualID = -1;	 

    InitTypeConverters();
	 
    msgText = NULL;
    helpText = NULL;
    tempargc = argc;
    tempargv = xmalloc(argc * sizeof(char *));
    
    *lang = '\0';
    for (i = 0; i < argc; i++) {
        tempargv[i] = xmalloc(strlen(argv[i])+1);
	if (i < argc-1 && !strncasecmp(argv[i], "-language", strlen(argv[i])))
	   strncpy(lang, argv[i+1], 8);
	strcpy(tempargv[i], argv[i]);
    }

    app_def_file = GetAppDefaultFile();
    if (!app_def_file) {
        fprintf(stderr, "%s : %s\n",
            msgText[CANT_FIND_APP_DEFAULTS_FILE], app_def_file);
        exit(1);
    }

    /*
     * Create a temp widget that we can interrogate.
     * This widget will not be realized. 
     * There should be a better way to do this...
     */
    temp = XtAppInitialize(&Global.appContext, app_def_file,
			   options, XtNumber(options), &tempargc, tempargv,
			   appDefaults, args, nargs);
    XtGetApplicationResources(temp, (XtPointer) & appInfo,
			      resources, XtNumber(resources), NULL, 0);

   /*
    **  Load help and messages files
     */
    LoadMessages();

    rdb = XtDatabase(XtDisplay(temp));
    for (i = 0; i < tempargc; i++)
        free(tempargv[i]);
	 
    if (appInfo.help != NULL)
	usage(argv[0], NULL);

    desiredDepth = 0;
    if (strcmp(appInfo.visualType, "default") != 0) {
        char *cp = appInfo.visualType;
	char *vp = phrase;

	/* this includes the terminating null character */
	for (i = 0; i <= strlen(cp); i++)
	    phrase[i] = tolower(cp[i]);
		 
	if (strncmp(vp, "cmap", 4) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "PseudoColor");
	    desiredVisual = PseudoColor;
	    vp += 4;
	} else if (strncmp(vp, "directcolor", 11) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "DirectColor");
	    desiredVisual = DirectColor;
	    desiredDepth = 24;
	    vp += 11;
	} else if (strncmp(vp, "truecolor", 9) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "TrueColor");
	    desiredVisual = TrueColor;
	    desiredDepth = 24;
	    vp += 9;
	} else if (strncmp(vp, "grayscale", 9) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "GrayScale");
	    desiredVisual = GrayScale;
	    desiredDepth = 8;
	    vp += 9;
	} else if (strncmp(vp, "pseudocolor", 11) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "PseudoColor");
	    desiredVisual = PseudoColor;
	    vp += 11;
	} else if (strncmp(vp, "staticgray", 10) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "StaticGray");
	    desiredVisual = StaticGray;
	    desiredDepth = 8;
	    vp += 10;
	} else if (strncmp(vp, "staticcolor", 11) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "StaticColor");
	    desiredVisual = StaticColor;
	    desiredDepth = 8;
	    vp += 11;
	} else if (strncmp(vp, "true", 4) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "TrueColor");
	    desiredVisual = TrueColor;
	    vp += 4;
	} else if (strncmp(vp, "gray", 4) == 0) {
	    XrmPutStringResource(&rdb, "Canvas*visual", "StaticGray");
	    desiredVisual = StaticGray;
	    vp += 4;
	} else if (atoi(vp)>0 || (vp[0]=='0' && vp[1]=='\0')) {
 	    desiredVisualID = atoi(vp);
	    *vp = '\0';
	} else {
	    fprintf(stderr, msgText[BAD_VISUAL_TYPE_SPECIFICATION],
		    argv[0], vp);
	    exit(1);
	}
	if (*vp != '\0') {
	    desiredDepth=atoi(vp);
	    if (desiredDepth > 0) 
	        XrmPutStringResource(&rdb, "Canvas*depth", vp);
	    else
	        desiredDepth = 0;
	}
    }
    else {
        /* go find out what the default visual is and get its parameters */
        Global.vis.depth = DefaultDepth(XtDisplay(temp),
					DefaultScreen(XtDisplay(temp)));
	Global.vis.visual = DefaultVisual(XtDisplay(temp),
					  DefaultScreen(XtDisplay(temp)));
    }

    if (desiredVisual >= 0 || desiredVisualID >= 0) {
        vis = GetFutureVisual(&temp, desiredDepth,
			      desiredVisual, desiredVisualID, &valid);
		 
	if (valid) {
	    depth = vis.depth;
	    Global.vis = vis;
	}
	else {
	    fprintf(stderr, msgText[NO_MATCH_FOUND_FOR_VISUAL]);
	    exit(1);
	}
    }
    else {
        Global.vis.depth = DefaultDepth(XtDisplay(temp),
					DefaultScreen(XtDisplay(temp)));
	Global.vis.visual = DefaultVisual(XtDisplay(temp),
					  DefaultScreen(XtDisplay(temp)));
    }
	 
    sprintf(phrase, "%d", Global.vis.depth);
    XrmPutStringResource(&rdb, "Canvas*depth", phrase);

    /* destroy our temporary widget */
    XtDestroyWidget(temp);

    /*
    **  Create the application context
     */

    toplevel = XtAppInitialize(&Global.appContext, app_def_file,
			       options, XtNumber(options), &argc, argv,
			       appDefaults, args, nargs);

    XtGetApplicationResources(toplevel, (XtPointer) & appInfo,
			      resources, XtNumber(resources), NULL, 0);

    if (argc != 1 && argv[1][0] == '-')
	usage(argv[0], "Invalid option");

    checkRCsize();

    /*
    **  A little initialization
     */
    Global.toplevel = toplevel;
    Global.canvas = None;
    Global.back = None;
    Global.patternshell = None;
    Global.patterninfo = NULL;
    Global.region.image = NULL;
    Global.region.cmap = None;
    Global.region.width = 0;
    Global.region.height = 0;
    Global.region.pix = None;
    Global.region.mask = None;
    Global.nbrushes = 0;
    Global.brushes = NULL;
    Global.join = JoinMiter;
    Global.dashlist[0] = '\0';
    Global.dashnumber = 0;
    Global.dashoffset = 0;
    Global.numregions = 0;
    Global.regiondata = NULL;

    /*
    **
     */
    XtVaGetValues(toplevel, XtNiconic, &isIcon, NULL);
    if (isIcon)
	XrmPutStringResource(&rdb, "Canvas.iconic", "on");

	 
    /*
    **  GRR 960525:  check depth and warn user (use AlertBox() instead?)
     */
    if (!appInfo.nowarn && !appInfo.snapshot) {
	int depth = Global.vis.depth;

	/* XtVaGetValues(toplevel, XtNdepth, &depth, NULL); */
	HelpTextOutput(stderr, "data_loss");
	fprintf(stderr, msgText[YOUR_CANVAS_DEPTH_IS_THAT_MANY_BITS], depth);
	switch (depth) {
	    case 8:
	    case 12:
		fprintf(stderr, msgText[SEPARATOR_STRIP_ONE]);
		fprintf(stderr, msgText[WARNING_ONE]);
		fprintf(stderr, msgText[SEPARATOR_STRIP_ONE]);
		fprintf(stderr, "\n");
		break;
	    case 1:
	    case 2:
	    case 4:
	    case 6:
	    case 15:
	    case 16:
		fprintf(stderr, msgText[SEPARATOR_STRIP_TWO]);
		fprintf(stderr, msgText[WARNING_TWO_A]);
		fprintf(stderr, msgText[WARNING_TWO_B]);
		fprintf(stderr, msgText[SEPARATOR_STRIP_TWO]);
		fprintf(stderr, "\n");
		break;
	    case 24:
	    case 32:
		fprintf(stderr, msgText[WARNING_THREE_A]);
		fprintf(stderr, msgText[WARNING_THREE_B]);
		fprintf(stderr, msgText[WARNING_THREE_C]);
		break;
	    default:
		break;
	}
    }

    /*
    **  Now build and construct the widgets
     */
    Global.timeToDie = False;
    Global.explore = False;
    app = XtWidgetToApplicationContext(toplevel);
    dpy = Global.display = XtDisplay(toplevel);

    /*
    **  Call the initializers
     */

    OperationInit(toplevel);

    /*
    **  A few rogue initializers
     */
    BrushInit(toplevel);
    HelpInit(toplevel);

    SRANDOM(time(0));

    SetIconImage(toplevel);

    /*
    **  GRR 960526:  put version number in title string (and icon name?)
     */
    sprintf(xpTitle, "XPaint %s", XPAINT_VERSION);
    XtVaSetValues(toplevel, XtNtitle, xpTitle, NULL);
 /* XtVaSetValues(toplevel, XtNiconName, xpTitle, XtNtitle, xpTitle, NULL); */

    if (appInfo.snapshot) {
        SnapshotImage(toplevel, NULL, 0);
    }
    /*
    **  Realize it (doesn't hurt)
     */
    XtRealizeWidget(toplevel);

    /*
    **  Now open any file on the command line
     */
    if (argc != 1) {
	LocalInfo *l = XtNew(LocalInfo);
	l->pos = 0;
	l->toplevel = toplevel;
	l->nfiles = argc - 1;
	l->files = (char **) XtCalloc(argc, sizeof(char *));
	for (i = 1; i < argc; i++)
	    l->files[i - 1] = argv[i];
	l->id = XtAppAddWorkProc(app, (XtWorkProc) workProc, (XtPointer) l);
    } else if (appInfo.popped) {
	/*
	**  If nothing is coming up, bring up a blank canvas
	 */
	GraphicCreate(toplevel, 0);
    }
    /*
    **  MainLoop
     */
    do {
	XtAppNextEvent(app, &event);
	if (event.type == ButtonPress || event.type == ButtonRelease)
	    Global.currentTime = event.xbutton.time;
	XtDispatchEvent(&event);
    }
    while (!Global.timeToDie);
    return 0;
}

