/*
 *	figinset.C - part of LyX project
 */

extern int	reverse_video;

/*  Rework of path-handling (Matthias 04.07.1996 )
 * ------------------------------------------------
 *   figinsets keep an absolute path to the eps-file.
 *   For the user alway a relative path appears
 *   (in lyx-file, latex-file and edit-popup).
 *   To calculate this relative path the path to the
 *   document where the figinset is in is needed. 
 *   This is done by a reference to the buffer, called
 *   figinset::cbuffer. To be up to date the cbuffer
 *   is sometimes set to the current buffer 
 *   bufferlist.current(), when it can be assumed that
 *   this operation happens in the current buffer. 
 *   This is true for InsetFig::Edit(...), 
 *   InsetFig::InsetFig(...), InsetFig::Read(...),
 *   InsetFig::Write and InsetFig::Latex(...).
 *   Therefore the bufferlist has to make sure that
 *   during these operations bufferlist.current() 
 *   returns the buffer where the figinsets are in.
 *   This made few changes in buffer.C necessary.
 * 
 */


#include "config.h"

#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#if defined(sgi) && !defined(__GNUC__)
#include <bstring.h>
#endif

#include "forms.h"
#include <stdlib.h>
#include <ctype.h>

#include "form1.h"
#include "figinset.h"
#include "lyx.h"
#include "buffer.h"
#include "paths.h"

//extern void sigchldhandler(int sig,...);//... added to please Sun's CC (JMarc)
extern void sigchldhandler(int sig);

static bool alarmed;

//static
inline
void waitalarm(int)
{
	alarmed = true;
}

extern char **environ; // is this only reductant on linux systems? Lgb.
extern void UpdateInset(Inset* inset, bool mark_dirty = true);
// better for asyncron updating:
void PutInsetIntoInsetUpdateList(Inset* inset);
extern void ProhibitInput();
extern void AllowInput();
extern char * system_lyxdir;

// // #undef FASTRECOLOR	// somewhat faster recoloring routine, but worse.
// // 			// quality. Not worth trying it, though

// //#define debug		// show some debugging info

// #ifdef debug
// #undef debug1		// show more debugging info
// #endif


// define FASTRECOLOR here since the other recoloring routine
// has a bug that at least I cannot fix :-( 
// Happens when using image translation on the platypus.eps => segfault
// Let's wait until Ivan has some time.... (Matthias 290596)
#define FASTRECOLOR


#define figallocchunk 32

static int figinsref = 0;	/* number of figures */
static int figarrsize = 0;	/* current max number of figures */
static int bmpinsref = 0;	/* number of bitmaps */
static int bmparrsize = 0;	/* current max number of bitmaps */

// typedef struct queue_ {
// 	float rx, ry;		/* resolution x and y */
// 	int gx, gy;		/* image size x and y */
// 	int ofsx, ofsy;		/* x and y translation */
// 	figdata *data;		/* we are doing it for this data */
// 	struct queue_ *next;	/* next item in queue */
// 	char flags;		/* color flags */
// } queue;
struct queue {
	float rx, ry;		/* resolution x and y */
	int gx, gy;		/* image size x and y */
	int ofsx, ofsy;		/* x and y translation */
	figdata *data;		/* we are doing it for this data */
	queue *next;	        /* next item in queue */
	char flags;		/* color flags */
};

// typedef struct pidwait_ {
// 	int pid;		/* pid to wait for */
// 	struct pidwait_ *next;	/* next */
// } pidwait;
struct pidwait {
	int pid;		/* pid to wait for */
	pidwait *next;	/* next */
};

#define MAXGS 3			/* maximum 3 gs's at a time */

static Figref **figures;	/* all the figures */
static figdata **bitmaps;	/* all the bitmaps */
static queue *gsqueue = NULL;	/* queue for ghostscripting */
static int gsrunning = 0;	/* currently so many gs's are running */
static bool bitmap_waiting = false; /* bitmaps are waiting finished */
static char bittable[256];	/* bit reversion table */

static bool gs_color;			// do we allocate colors for gs?
static bool gs_xcolor = false;		// allocated extended colors
static unsigned long gs_pixels[128];	// allocated pixels
static int gs_num_pixels;		// number of pixels allocated
static int gs_spc;			// shades per color
static bool gs_gray;			// is grayscale?
static int gs_allcolors;		// number of all colors

static pidwait *pw = NULL;		// pid wait list


extern FD_form_main *fd_form_main;
extern Colormap color_map;

void addpidwait(int pid)
{
	// adds pid to pid wait list
	register pidwait *p = new pidwait;

	p->pid = pid;
	p->next = pw;
	pw = p;

#ifdef debug1
	printf("Pids to wait for: %d", p->pid);
	while (p->next) {
		p = p->next;
		printf(", %d", p->pid);
	}
	printf("\n");
#endif
}

int GhostscriptMsg(FL_OBJECT *, Window, int, int,
	XEvent *ev, void *)
{
	// char *p; //unused
	int i;
	char tmp[128];

	XClientMessageEvent *e = (XClientMessageEvent*) ev;
#ifdef debug
	printf("ClientMessage, win:[%ld] gs:[%ld] pm:[%ld]\n", win,
		e->data.l[0], e->data.l[1]);
#endif
	// just kill gs, that way it will work for sure
	for (i = 0; i < bmpinsref; ++i)
		if ((long)bitmaps[i]->bitmap == (long)e->data.l[1])
		{
			// found the one
			figdata *p = bitmaps[i];
			p->gsdone = true;

			// first update p->bitmap, if necessary
			if (p->bitmap != None && p->flags > (1|8) && gs_color && p->wid) {
				// query current colormap and re-render the pixmap
				// with proper colors
				int *rdif, *gdif, *bdif;
				// int lbdif=0, lgdif=0, lrdif=0; //unused
				XColor *cmap;
				XWindowAttributes wa;
				register XImage *im;
				int i, y, wid1, spc1 = gs_spc-1,
					spc2 = gs_spc*gs_spc, wid = p->wid,
					forkstat;
				// int pp; // unused
				Display *tmpdisp;
				GC gc = LyXGetCopyGC();
				
				XGetWindowAttributes(fl_display, fl_get_canvas_id(
					fd_form_main->figinset_canvas), &wa);
#ifdef debug
				printf("Starting image translation %ld %d %dx%d %d %d\n",
				       p->bitmap, p->flags, p->wid, p->hgh, wa.depth,
				       XYPixmap);
#endif
				// now fork rendering process
				forkstat = fork();
				if (forkstat == -1) {
					fprintf(stderr, "Cannot fork, using slow "
						"method for pixmap translation.\n");
					tmpdisp = fl_display;
				} else if (forkstat > 0) {
					// register child
#ifdef debug1
					printf("Spawned child %d\n", forkstat);
#endif
					addpidwait(forkstat);
					break; // in parent process
				} else {
					tmpdisp = XOpenDisplay(XDisplayName(NULL));
				}
				im = XGetImage(tmpdisp, p->bitmap, 0, 0,
					       p->wid, p->hgh, (1<<wa.depth)-1, XYPixmap);
#ifdef debug1
				printf("Got the image\n");
#endif
				if (!im) {
#ifdef debug
					printf("Error getting the image\n");
#endif
					goto noim;
				}
				// query current colormap
				cmap = (XColor *) malloc(gs_allcolors*sizeof(XColor));
				for (i = 0; i < gs_allcolors; ++i) cmap[i].pixel = i;
				XQueryColors(tmpdisp, color_map, cmap, gs_allcolors);
				// allocate differences
				i = p->wid*sizeof(int);
				rdif = (int *) malloc(i);
				gdif = (int *) malloc(i);
				bdif = (int *) malloc(i);
				BZERO(rdif, i);
				BZERO(gdif, i);
				BZERO(bdif, i);
				wid1 = p->wid - 1;
				// now we process all the image
#ifdef FASTRECOLOR
				for (y = 0; y < p->hgh; ++y) {
					register int x;
					for (x = 0; x < wid; ++x) {
						register XColor* pc;
						pc = cmap + XGetPixel(im, x, y);
						XPutPixel(im, x, y, gs_pixels[((pc->red+6553)*
									       spc1/65535)*spc2+((pc->green+6553)*
												 spc1/65535)*gs_spc+((pc->blue+6553)*
														     spc1/65535)]);
					}
				}
#endif
#ifndef FASTRECOLOR
				for (y = 0; y < p->hgh; ++y) {
					register int x;
					lrdif = lgdif = lbdif = 0;
					for (x = 0; x < wid; ++x) {
						register XColor* pc;
						register int r, g, b;
						r = (pc = cmap + XGetPixel(im, x, y))->red +
							(lrdif+rdif[x])/2;
						g = pc->green + (lgdif+gdif[x])/2;
						b = pc->blue + (lbdif+bdif[x])/2;
						rdif[x] = lrdif = r-(pc = cmap + (pp = gs_pixels[((r+
												   6553)*spc1/65535)*spc2+((g+6553)*spc1/65535)*
												   gs_spc+((b+6553)*spc1/65535)]))->red;
						gdif[x] = lgdif = g-pc->green;
						bdif[x] = lbdif = b-pc->blue;
						XPutPixel(im, x, y, pp);
					}
				}
#endif
#ifdef debug1
				printf("Putting image back\n");
#endif
				XPutImage(tmpdisp, p->bitmap, gc, im, 0, 0,
					  0, 0, p->wid, p->hgh);
				free(rdif);
				free(gdif);
				free(bdif);
				XDestroyImage(im);
#ifdef debug1
				printf("Done translation\n");
#endif
			  noim:
#ifdef debug
				printf("Killing gs %d\n", p->gspid);
#endif
				kill(p->gspid, SIGHUP);
				
				sprintf(tmp, "/tmp/~lyxgs%d.ps", p->gspid);
				unlink(tmp);
				if (forkstat == 0) {
					XCloseDisplay(tmpdisp);
					_exit(0);
				}
			} else {
#ifdef debug
				printf("Killing gs %d\n", p->gspid);
#endif
				kill(p->gspid, SIGHUP);
				
				sprintf(tmp, "/tmp/~lyxgs%d.ps", p->gspid);
				unlink(tmp);
			}
			break;
		}
	return 0;
}

static void AllocColors(int num)
// allocate color cube numxnumxnum, if possible
{
	XColor xcol;
	int i;

#ifdef debug
	printf("Allocating color cube %dx%dx%d\n", num, num, num);
#endif

	if (num <= 1) {
		fprintf(stderr, "Error allocating color colormap\n");
		gs_color = false;
		return;
	}
	if (num > 5) num = 5;
	for (i = 0; i < num*num*num; ++i) {
		xcol.red = 65535*(i/(num*num))/(num-1);
		xcol.green = 65535*((i/num) % num)/(num-1);
		xcol.blue = 65535*(i % num)/(num-1);
		xcol.flags = DoRed | DoGreen | DoBlue;
		if (!XAllocColor(fl_display, color_map, &xcol)) {
			if (i) XFreeColors(fl_display, color_map,
				gs_pixels, i, 0);
#ifdef debug
			printf("Cannot allocate color cube %d\n", num);
#endif
			AllocColors(num-1);
			return;
		}
		gs_pixels[i] = xcol.pixel;
	}
	gs_color = true;
	gs_gray = false;
	gs_spc = num;
	gs_num_pixels = num*num*num;
}

static void AllocGrays(int num)
// allocate grayscale ramp
{
	XColor xcol;
	int i;

#ifdef debug
	printf("Allocating grayscale ramp %d\n", num);
#endif

	if (num < 4) {
		fprintf(stderr, "Error allocating grayscale colormap\n");
		gs_color = false;
		return;
	}
	if (num > 128) num = 128;
	for (i = 0; i < num; ++i) {
		xcol.red = xcol.green = xcol.blue = 65535*i/(num-1);
		xcol.flags = DoRed | DoGreen | DoBlue;
		if (!XAllocColor(fl_display, color_map, &xcol)) {
			if (i) XFreeColors(fl_display, color_map,
				gs_pixels, i, 0);
#ifdef debug
			printf("Cannot allocate grayscale %d\n", num);
#endif
			AllocGrays(num/2);
			return;
		}
		gs_pixels[i] = xcol.pixel;
	}
	gs_color = true;
	gs_gray = false;
	gs_num_pixels = num;
}

void InitFigures()
{
	unsigned int i, j, k;
	Visual *vi;

	bmparrsize = figarrsize = figallocchunk;
	figures = (Figref**) malloc(sizeof(Figref*)*figallocchunk);
	bitmaps = (figdata**) malloc(sizeof(figdata*)*figallocchunk);

	for (i = 0; i < 256; ++i) {
		k = 0;
		for (j = 0; j < 8; ++j)
			if (i & (1 << (7-j))) k |= 1 << j;
		bittable[i] = (char) ~k;
	}

	fl_add_canvas_handler(fd_form_main->figinset_canvas, ClientMessage,
		GhostscriptMsg, fd_form_main);

	// now we have to init color_map
	if (!color_map) color_map = DefaultColormap(fl_display,
		DefaultScreen(fl_display));
	// allocate color cube on pseudo-color display
	// first get visual
	gs_color = false;

	vi = DefaultVisual(fl_display, DefaultScreen(fl_display));
#ifdef debug
	printf("Visual ID: %ld, class: %d, bprgb: %d, mapsz: %d\n", vi->visualid,
		vi->c_class, vi->bits_per_rgb, vi->map_entries);
#endif
	if ((vi->c_class & 1) == 0) return;
	// now allocate colors
	if (vi->c_class == GrayScale) {
		// allocate grayscale
		AllocGrays(vi->map_entries/2);
	} else {
		// allocate normal color
		int i = 5;
		while (i*i*i*2 > vi->map_entries) --i;
		AllocColors(i);
	}
	gs_allcolors = vi->map_entries;
}

void DoneFigures()
{
	free(figures);
	free(bitmaps);
	figarrsize = 0;
	bmparrsize = 0;

#ifdef debug
	printf("Unregistering figures...\n");
#endif
	fl_remove_canvas_handler(fd_form_main->figinset_canvas, ClientMessage,
		GhostscriptMsg);

	if (gs_color) {
#ifdef debug
	printf("Freeing up the colors...\n");
#endif
		XFreeColors(fl_display, color_map, gs_pixels,
			gs_num_pixels, 0);
	/******????????????????? what's planes in this case ??????*********/
	}
}

int FindBmpIndex(figdata *tmpdata)
{
	int i = 0;
	while (i < bmpinsref) {
		if (bitmaps[i] == tmpdata) return i;
		++i;
	}
	return i;
}

static void chpixmap(Pixmap, int, int)
{
	Display* tempdisp = XOpenDisplay(XDisplayName(NULL));

	// here read the pixmap and change all colors to those we
	// have allocated

	XCloseDisplay(tempdisp);
}

static void freefigdata(figdata *tmpdata)
{
	int i;

	tmpdata->ref--;
	if (tmpdata->ref) return;

	if (tmpdata->gspid > 0) {
		int pid = tmpdata->gspid;
		char buf[128];
		// change Pixmap according to our allocated colormap
		chpixmap(tmpdata->bitmap, tmpdata->wid, tmpdata->hgh);
		// kill ghostscript and unlink it's files
		tmpdata->gspid = -1;
		kill(pid, SIGKILL);
		sprintf(buf, "/tmp/~lyxgs%d.ps", pid);
		unlink(buf);
	}

	if (tmpdata->bitmap) XFreePixmap(fl_display, tmpdata->bitmap);
	if (tmpdata->fname) delete [] tmpdata->fname;
	free(tmpdata);
	i = FindBmpIndex(tmpdata);
	--bmpinsref;
	while (i < bmpinsref) {
		bitmaps[i] = bitmaps[i+1];
		++i;
	}
}


static void runqueue()
{
    // run queued requests for ghostscript, if any
    if (!gsrunning && gs_color && !gs_xcolor) {
	// here alloc all colors, so that gs will use only those we allocated
	// for it
	// *****
	gs_xcolor = true;
    }

    while (gsrunning < MAXGS) {
	queue *p;
	int pid;
	char tbuf[384], tbuf2[80];
	FILE *f;
	Atom *prop;
	int nprop, i;

	if (!gsqueue) {
		if (!gsrunning && gs_xcolor) {
			// de-allocate rest of colors
			// *****
			gs_xcolor = false;
		}
		return;
	}
	p = gsqueue;

	if (!p->data) {
		free(p);
		continue;
	}

	pid = fork();

	if (pid == -1) {
#ifdef debug
		printf("GS start error!!! Cannot fork.\n");
#endif
		p->data->broken = true;
		p->data->reading = false;
		return;
	}
	if (pid == 0) {
		char **env, rbuf[80], gbuf[40];
		int ne = 0;
		Display* tempdisp = XOpenDisplay(XDisplayName(NULL));

		// create translation file
		sprintf(tbuf, "/tmp/~lyxgs%d.ps", (int)getpid());
		f = fopen(tbuf, "w");
		fprintf(f, "gsave clippath pathbbox grestore\n"
			"4 dict begin\n"
			"/ury exch def /urx exch def /lly exch def " 
			"/llx exch def\n"
			"%g %g scale\n"
			"-%d -%d translate\nend\n", p->rx / 72.0, p->ry / 72.0,
			p->ofsx, p->ofsy);
		fclose(f);

		// gs process - set ghostview environment first
		sprintf(tbuf2, "GHOSTVIEW=%ld %ld", fl_get_canvas_id(
			fd_form_main->figinset_canvas), p->data->bitmap);

		// now set up ghostview property on a window
		sprintf(tbuf, "0 0 0 0 %d %d 72 72 0 0 0 0",
			p->gx, p->gy);
#ifdef debug1
		printf("Will set GHOSTVIEW property to [%s]\n", tbuf);
#endif
		// wait until property is deleted if executing multiple
		// ghostscripts
		for (;;) {
			bool err;
			err = false;
			// grab server to prevent other child interfering
			// with setting GHOSTVIEW property
#ifdef debug1
			printf("Grabbing the server\n");
#endif
			XGrabServer(tempdisp);
			prop = XListProperties(tempdisp, fl_get_canvas_id(
				fd_form_main->figinset_canvas), &nprop);
			if (!prop) break;
			for (i = 0; i < nprop; ++i) {
				char *p = XGetAtomName(tempdisp, prop[i]);
				if (strcmp(p, "GHOSTVIEW") == 0) {
					err = true;
					break;
				}
				XFree(p);
			}
			XFree((char *)prop);    /* jc: */
			if (!err) break;
			// release the server
			XUngrabServer(tempdisp);
			XFlush(tempdisp);
			// ok, property found, we must wait until ghostscript
			// deletes it
#ifdef debug1
			printf("Releasing the server\n");
			printf("[%d] GHOSTVIEW property found. Waiting\n",
				getpid());
#endif
			alarm(1);
			alarmed = false;
			signal(SIGALRM, waitalarm);
			while (!alarmed) pause();
		}

		XChangeProperty(tempdisp, fl_get_canvas_id(fd_form_main->figinset_canvas),
			XInternAtom(tempdisp, "GHOSTVIEW", false),
			XInternAtom(tempdisp, "STRING", false),
			8, PropModeAppend, (unsigned char *) tbuf,
			strlen(tbuf));
		switch (p->flags & 3) {
			case 2:	tbuf[0] = 'G';
				break;
			case 3:	if (gs_color && !gs_gray) tbuf[0] = 'C';
					else tbuf[0] = 'G';
				break;
			default:
				tbuf[0] = 'M';
				break;
		}
		if (reverse_video) {
		    sprintf(tbuf+1, " %ld %ld", WhitePixelOfScreen(
			DefaultScreenOfDisplay(fl_display)),
			BlackPixelOfScreen(DefaultScreenOfDisplay(
			fl_display)));
		} else {
		    sprintf(tbuf+1, " %ld %ld", BlackPixelOfScreen(
			DefaultScreenOfDisplay(fl_display)),
			WhitePixelOfScreen(DefaultScreenOfDisplay(
			fl_display)));
		}
		XChangeProperty(tempdisp, fl_get_canvas_id(fd_form_main->figinset_canvas),
			XInternAtom(tempdisp, "GHOSTVIEW_COLORS", false),
			XInternAtom(tempdisp, "STRING", false),
			8, PropModeReplace, (unsigned char *) tbuf,
			strlen(tbuf));
		XUngrabServer(tempdisp);
		XFlush(tempdisp);
#ifdef debug1
		printf("Releasing the server\n");
#endif
		XCloseDisplay(tempdisp);

		// set up environment
		while (environ[ne]) ++ne;
		env = (char **) malloc(sizeof(char*)*(ne+2));
		env[0] = tbuf2;
		memcpy(&env[1], environ, sizeof(char*)*(ne+1));
		environ = env;

		// now make gs command
		// close(0);
		// close(1); do NOT close. If GS writes out errors it would hang. (Matthias 290596)
		sprintf(rbuf, "-r%gx%g", p->rx, p->ry);
		sprintf(gbuf, "-g%dx%d", p->gx, p->gy);
		// now chdir into dir with .eps file, to be on the safe
		// side
		MakePath(tbuf, p->data->fname, NULL);
		chdir(tbuf);
		// make temp file name
		sprintf(tbuf, "/tmp/~lyxgs%d.ps", (int)getpid());
#ifdef debug
		printf("starting gs %s %s, pid: %d\n", tbuf,
			p->data->fname, (int)getpid());
#endif
		fprintf(stderr, "Error executing ghostscript. Code: %d\n",
			execlp("gs", "gs", "-sDEVICE=x11", "-dNOPAUSE",
				"-dQUIET", "-dSAFER", rbuf, gbuf,
				tbuf, p->data->fname, "showpage.ps", NULL));
		fprintf(stderr, "Cmd: gs -sDEVICE=x11 %s %s\n",
			tbuf, p->data->fname);
		_exit(0);	// no gs?
	}
	// normal process
#ifdef debug1
	printf("GS [%d] started\n", pid);
#endif
	gsqueue = gsqueue->next;
	gsrunning++;
	p->data->gspid = pid;
	free(p);
	signal(SIGCHLD, sigchldhandler);
    }
}

static void addwait(char */*fname*/, int wid, int hgh, int psx, int psy,
		int pswid, int pshgh, figdata *data, char flags)
{
	// recompute the stuff and put in the queue
	queue *p, *p2;
	p = new queue;
	p->ofsx = psx;
	p->ofsy = psy;
	p->gx = wid;
	p->gy = hgh;
	p->rx = ((float)wid*72)/pswid;
	p->ry = ((float)hgh*72)/pshgh;
	p->data = data;
	p->flags = flags;
	p->next = NULL;

	// now put into queue
	p2 = gsqueue;
	if (!gsqueue) gsqueue = p;
	else {
		while (p2->next) p2 = p2->next;
		p2->next = p;
	}

	// if possible, run the queue
	runqueue();
}

static figdata *getfigdata(int wid, int hgh, char *fname, int psx, int psy,
	int pswid, int pshgh, char flags)
{
	/* first search for an exact match with fname and width/height */
	int i = 0;
	figdata *p;
	XWindowAttributes wa;

	if (!fname) return NULL;

	while (i < bmpinsref) {
		if (bitmaps[i]->wid == wid && bitmaps[i]->hgh == hgh &&
		    bitmaps[i]->flags == flags && strcmp(bitmaps[i]->fname,
		    fname) == 0) {
			bitmaps[i]->ref++;
			return bitmaps[i];
		    }
		++i;
	}
	/* not found -> create new record or return NULL if no record */
	++bmpinsref;
	if (bmpinsref > bmparrsize) {
		// allocate more space
		bmparrsize += figallocchunk;
		figdata **tmp = (figdata**) malloc(sizeof(figdata*)*bmparrsize);
		memcpy(tmp, bitmaps, sizeof(figdata*)*(bmparrsize-figallocchunk));
		free(bitmaps);
		bitmaps = tmp;
	}
	p = new figdata;
	bitmaps[bmpinsref-1] = p;
	p->wid = wid;
	p->hgh = hgh;
	p->fname = StringCopy(fname);
	p->flags = flags;
	XGetWindowAttributes(fl_display, fl_get_canvas_id(
		fd_form_main->figinset_canvas), &wa);
#ifdef debug1
	printf("Create pixmap disp:%d scr:%d w:%d h:%d depth:%d\n",
		(int)fl_display, DefaultScreen(fl_display), wid, hgh,
		wa.depth);
#endif
	p->ref = 1;
	p->reading = false;
	p->broken = false;
	p->gspid = -1;
	if (flags) {
		p->bitmap = XCreatePixmap(fl_display, fl_get_canvas_id(
			fd_form_main->figinset_canvas), wid, hgh, wa.depth);
		p->gsdone = false;
		// initialize reading of .eps file with correct sizes and stuff
		addwait(fname, wid, hgh, psx, psy, pswid, pshgh, p, flags);
		p->reading = true;
	} else {
		p->bitmap = None;
		p->gsdone = true;
	}

	return p;
}


static void getbitmap(figdata *p)
{
	p->gspid = -1;
}

static void makeupdatelist(figdata *p)
{
	int i;

	for (i = 0; i < figinsref; ++i) if (figures[i]->data == p) {
#ifdef debug
	  printf("Updating inset %d\n", (int)figures[i]->inset);
#endif
	  //UpdateInset(figures[i]->inset);
	  // add inset figures[i]->inset into to_update list
	  PutInsetIntoInsetUpdateList(figures[i]->inset);
	}
}

void sigchldchecker(int)
{
	int i, status;
	figdata *p;
	int pid = 0;

	for (i = bmpinsref - 1; i >= 0; --i)
	    if (bitmaps[i]->reading && bitmaps[i]->gspid > 0)
		if ((pid = waitpid(bitmaps[i]->gspid, &status, WNOHANG)) ==
		    bitmaps[i]->gspid) {
			// now read the file and remove it from disk
			p = bitmaps[i];
			p->reading = false;
			if (bitmaps[i]->gsdone) status = 0;
#ifdef debug
			if (status == 0) {
				printf("GS [%d] exit OK.\n", pid);
			} else {
				printf("GS [%d] error %d E:%d %d S:%d %d\n", pid,
					status, WIFEXITED(status), WEXITSTATUS(status),
					WIFSIGNALED(status), WTERMSIG(status));
			}
#endif
			if (status == 0) {
				bitmap_waiting = true;
				p->broken = false;
			} else {
				// remove temporary files
				char tmp[128];
				sprintf(tmp, "/tmp/~lyxgs%d.ps", p->gspid);
				unlink(tmp);
				p->gspid = -1;
				p->broken = true;
			}
			makeupdatelist(bitmaps[i]);
			gsrunning--;
			runqueue();
			break;
		}
	if (!pid) {
	    pidwait *p = pw, *prev = NULL;
	    while (p) {
		if ((pid = waitpid(p->pid, &status, WNOHANG)) == p->pid) {
			// got a pid we were waiting for
#ifdef debug1
			printf("Caught child pid of recompute routine %d\n",
				pid);
#endif
			if (prev) prev->next = p->next;
				else pw = p->next;
			free(p);
			break;
		}
		prev = p;
		p = p->next;
	    }
	}
#ifdef debug1
	if (pid) printf("Caught child pid: %d\n", pid);
	if (pid <= 0)   /* jc: catching non expected SIGCHLD */
	  fprintf(stderr,"Caught child pid: %d\n", wait(NULL));
#else
        if (pid <= 0)
          (void) wait(NULL);
#endif
 	// we must catch further signals, so set up the signal handler again
	signal(SIGCHLD, sigchldhandler);
}

static char chldcnt = 0;	// children counter

void checkchildren()
// if there are any children on wait list, hit with SIGCHLD
// this serves as cleanup in case some child signal gets lost
// also every 10-th time do it anyway, if some gs process has not
// been caught yet
{
  // commented out, since it causes forever hanging LyX. 
  // Waiting for some information from Ivan... (Matthias 290596)
 
// #ifdef debug1
// 	printf("Checking for children, cnt = %d\n", chldcnt);
// #endif
// 	if (pw || chldcnt == 0) kill(getpid(), SIGCHLD);
// 	chldcnt += 1;
// 	if (chldcnt == 10) chldcnt = 0;
}

static void getbitmaps()
{
	int i;
	bitmap_waiting = false;
	for (i = 0; i < bmpinsref; ++i)
	    if (bitmaps[i]->gspid > 0 && !bitmaps[i]->reading)
		getbitmap(bitmaps[i]);
}

static void RegisterFigure(InsetFig *fi)
{
	Figref *tmpfig;

	if (figinsref == 0) InitFigures();
	fi->form = NULL;
	++figinsref;
	if (figinsref > figarrsize) {
		// allocate more space
		figarrsize += figallocchunk;
		Figref **tmp = (Figref**) malloc(sizeof(Figref*)*figarrsize);
		memcpy(tmp, figures, sizeof(Figref*)*(figarrsize-figallocchunk));
		free(figures);
		figures = tmp;
	}
	//tmpfig = (figref*) malloc(sizeof(figref));
	tmpfig = new Figref;
	tmpfig->data = NULL;
	tmpfig->inset = fi;
	figures[figinsref-1] = tmpfig;
	fi->figure = tmpfig;

#ifdef debug1
	printf("Register Figure: buffer:[%d]\n", (int)bufferlist.current());
#endif
}

int FindFigIndex(Figref *tmpfig)
{
	int i = 0;
	while (i < figinsref) {
		if (figures[i] == tmpfig) return i;
		++i;
	}
	return i;
}

static void UnregisterFigure(InsetFig *fi)
{
	Figref *tmpfig = fi->figure;
	int i;

	if (tmpfig->data) freefigdata(tmpfig->data);
	if (tmpfig->inset->form) {
//		fl_remove_canvas_handler(tmpfig->inset->form->Prev,
//			Expose, ExposePreview);
		if (tmpfig->inset->form->Figure->visible)
			fl_hide_form(tmpfig->inset->form->Figure);
		fl_free_form(tmpfig->inset->form->Figure);
		free(tmpfig->inset->form);
		tmpfig->inset->form = NULL;
	}
	i = FindFigIndex(tmpfig);
	--figinsref;
	while (i < figinsref) {
		figures[i] = figures[i+1];
		++i;
	}
	free(tmpfig);

	if (figinsref == 0) DoneFigures();
}


static char* NextToken(FILE *myfile)
{
   char* token = NULL;
   char c;
   int i = 0;
   
   if (!feof(myfile)) {
      token = (char *) malloc(128);
      do {
         c = fgetc(myfile);
         token[i++]=c;
      } while (!feof(myfile) && !isspace(c));
      
      token[i-1]='\0';         /* just the end of a command  */
   }
   return token;
}


InsetFig::InsetFig(int tmpx, int tmpy)
{
	cmd = fname = extra = label = NULL;
	wid = tmpx;
	hgh = tmpy;
	wtype = htype = twtype = thtype = 0;
	pflags = flags = 9;
	xwid = xhgh = angle = 0;
	changedfname = false;
	cbuffer = bufferlist.current();
	RegisterFigure(this);
}


InsetFig::~InsetFig()
{
#ifdef debug
	printf("Figure destructor called\n");
#endif
	if (cmd) delete [] cmd;
	if (fname) delete [] fname;
	if (extra) delete [] extra;
	if (label) delete [] label;
	UnregisterFigure(this);
}


int InsetFig::Ascent(LyXFont)
{
	return hgh + 3;
}


int InsetFig::Descent(LyXFont)
{
	return 1;
}


int InsetFig::Width(LyXFont)
{
	return wid + 2;
}


void InsetFig::Draw(LyXFont font, unsigned long pm, int baseline, float &x)
{
	if (bitmap_waiting) getbitmaps();

	if (figure && figure->data && figure->data->bitmap &&
	    !figure->data->reading && !figure->data->broken) {
		// draw the bitmap
		XCopyArea(fl_display, figure->data->bitmap, pm, LyXGetCopyGC(),
			0, 0, wid, hgh, (int) x+1, baseline-hgh);
		if (flags & 4) XDrawRectangle(fl_display, pm, LyXGetCopyGC(),
			(int) x, baseline - hgh - 1, wid+1, hgh+1);
	} else {
		char c = 'F';
		if (figure && figure->data) {
			if (figure->data->reading) c = 'R';
			if (figure->data->broken) c = 'X';
		} else if (fname) c = 'X';
		XDrawRectangle(fl_display, pm, LyXGetCopyGC(), (int) x,
			baseline - hgh - 1, wid+1, hgh+1);
		XDrawString(fl_display, pm, LyXGetCopyGC(), (int) x + wid/2 -
			LyXTextWidth(font, &c, 1)/2,
			baseline - hgh/2 + LyXAscent(font, c)/2, &c, 1);
	}
	x += Width(font);
}


void InsetFig::Write(FILE *file)
{
	cbuffer = bufferlist.current();
	Regenerate();
	fprintf(file, "Figure size %d %d\n", wid, hgh);
	char* buf1 = NameToPath(NULL, cbuffer->filename);
	char* fname2 = MakeRelPath(NULL, fname, buf1);
	if (buf1) delete [] buf1;
	if (fname2) fprintf(file, "file %s\n", fname2);
	if (fname2) delete[] fname2;
	if (wtype) fprintf(file, "width %d %g\n", wtype, xwid);
	if (htype) fprintf(file, "height %d %g\n", htype, xhgh);
	if (angle != 0) fprintf(file, "angle %g\n", angle);
	fprintf(file, "flags %d\n", flags);
	if (extra) fprintf(file, "extra %s\n", extra);
	if (label) fprintf(file, "label %s\n", label);
}


void InsetFig::Read(FILE *file)
{
	cbuffer = bufferlist.current();
	char buf[512], *p;
	int i;

	for (;;) {
		p = NextToken(file);
		if (!p) break;
		if (strcmp(p, "\\end_inset") == 0) {
			delete [] p;
			break;
		}
		if (strcmp(p, "file") == 0) {
			fgets(buf, 384, file);
			if (buf[i = strlen(buf) - 1] == '\n') buf[i] = 0;
			if (fname) delete [] fname;
			char* buf1 = NameToPath(NULL, cbuffer->filename);
			fname = MakeAbsPath(NULL, buf, buf1);
			if (buf1) delete [] buf1;
			changedfname = true;
		} else
		if (strcmp(p, "extra") == 0) {
			fgets(buf, 512, file);
			if (buf[i = strlen(buf) - 1] == '\n') buf[i] = 0;
			if (extra) delete [] extra;
			extra = StringCopy(buf);
		} else
		if (strcmp(p, "label") == 0) {
			fgets(buf, 512, file);
			if (buf[i = strlen(buf) - 1] == '\n') buf[i] = 0;
			if (label) delete [] label;
			label = StringCopy(buf);
		} else
		if (strcmp(p, "angle") == 0) {
			fscanf(file, "%f", &angle);
			sprintf(buf, "%g", angle);
		} else
		if (strcmp(p, "size") == 0) {
			fscanf(file, "%d %d", &wid, &hgh);
		} else
		if (strcmp(p, "flags") == 0) {
			fscanf(file, "%d", &flags);
			pflags = flags;
		} else
		if (strcmp(p, "width") == 0) {
			fscanf(file, "%d %f", &wtype, &xwid);
			sprintf(buf, "%g", xwid);
			twtype = wtype;
		} else
		if (strcmp(p, "height") == 0) {
			fscanf(file, "%d %f", &htype, &xhgh);
			sprintf(buf, "%g", xhgh);
			// Ivan, what sense had this: ??? 
			// fl_set_input(form->Height, buf);
			thtype = htype;
		}
		delete [] p;
	}

	Regenerate();
	Recompute();
}


int InsetFig::Latex(FILE *file, char /* fragile*/ )
{
	cbuffer = bufferlist.current();
	Regenerate();
	if (cmd) fprintf(file, "%s ", cmd);
	return 0;
}


char InsetFig::Editable()
{
	return 1;
}


char InsetFig::Deletable()
{
	return 0;
}


void InsetFig::Edit(int, int)
{
#ifdef debug1
	printf("Editing InsetFig\n");
#endif
	cbuffer = bufferlist.current();
	Regenerate();
	if (!form) {
		form = create_form_Figure();
		RestoreForm();
	}
	if (form->Figure->visible) {
		fl_raise_form(form->Figure);
	} else {
		fl_show_form(form->Figure, FL_PLACE_MOUSE | FL_PLACE_SIZE,
			FL_FULLBORDER, "EPS Figure");
	}
}


Inset *InsetFig::Clone()
{
	InsetFig *tmp = new InsetFig(100, 100);
	char fbuf[256], fbuf2[256];

#ifdef debug
	printf("Clone Figure: buffer:[%d], cbuffer:[%d]\n",
	       (int)bufferlist.current(),
	       (int)cbuffer);
#endif

	tmp->wid = wid;
	tmp->hgh = hgh;
	tmp->angle = angle;
	tmp->xwid = xwid;
	tmp->xhgh = xhgh;
	tmp->flags = flags;
	tmp->pflags = pflags;
	tmp->wtype = wtype;
	tmp->htype = htype;
	tmp->psx = psx;
	tmp->psy = psy;
	tmp->pswid = pswid;
	tmp->pshgh = pshgh;
	if (fname) tmp->fname = StringCopy(fname);
		else tmp->fname = NULL;
	if (extra) tmp->extra = StringCopy(extra);
		else tmp->extra = NULL;
	if (label) tmp->label = StringCopy(label);
		else tmp->label = NULL;
	if (fname && (flags & 3) ) { // do not display if there is "do not display" chosen (Matthias 260696)
	  tmp->figure->data = getfigdata(wid, hgh, fname, psx, psy,
					 pswid, pshgh, flags & (3|8));
	} else tmp->figure->data = NULL;
	tmp->changedfname = false;
	tmp->cbuffer = cbuffer;
	tmp->Regenerate();
	return tmp;
}


char InsetFig::LyxCode()
{
	return LYX_NO_CODE;
}


void InsetFig::Regenerate()
{
	char cmdbuf[1024], buf[64];
	const char *p = NULL;
	const char *p2 = NULL;

	if (form) {
		p = fl_get_input(form->Extra);
		//		p2 = fl_get_input(form->Label);
	}

	if (!fname) {
		if (cmd) delete [] cmd;
		cmd = NULL;
		if (form) fl_set_input(form->Command, "");
		return;
	}

	char* buf1 = NameToPath(NULL, cbuffer->filename);
	char* fname2 = MakeRelPath(NULL, fname, buf1);
	if (buf1) delete [] buf1;

	sprintf(cmdbuf, "\\epsfig{file=%s", fname2);
	if (fname2) delete[] fname2;

	switch (wtype) {
		case 1:
			sprintf(buf, ", width=%gcm", xwid);
			break;
		case 2:
			sprintf(buf, ", width=%gin", xwid);
			break;
		case 3:
			sprintf(buf, ", width=%g\\textwidth", xwid/100);
			break;
		default:
			buf[0] = 0;
			break;
	}
	strcat(cmdbuf, buf);

	switch (htype) {
		case 1:
			sprintf(buf, ", height=%gcm", xhgh);
			break;
		case 2:
			sprintf(buf, ", height=%gin", xhgh);
			break;
		case 3:
			sprintf(buf, ", height=%g\\textheight", xhgh/100);
			break;
		default:
			buf[0] = 0;
			break;
	}
	strcat(cmdbuf, buf);

	if (angle != 0) {
		sprintf(buf, ", angle=%g", angle);
		strcat(cmdbuf, buf);
	}

	if (p) if (*p) {
		if (extra) delete [] extra;
		extra = StringCopy(p);
	} else {
		if (extra) delete [] extra;
		extra = NULL;
	}

	if (extra) {
		strcat(cmdbuf, ", ");
		strcat(cmdbuf, extra);
	}

	if (p2) if (*p2) {
		if (label) delete [] label;
		label = StringCopy(p2);
	} else {
		if (label) delete [] label;
		label = NULL;
	}

	if (label) {
		strcat(cmdbuf, "}\\label{");
		strcat(cmdbuf, label);
	}
	strcat(cmdbuf, "}");

	if (cmd) delete [] cmd;
	cmd = StringCopy(cmdbuf);

	if (form) fl_set_input(form->Command, cmd);
}


void InsetFig::TempRegenerate()
{
	char cmdbuf[1024], buf[64];
	const char *tfname, *textra;
	// const char *tlabel; // unused
	float tangle, txwid, txhgh;

	tfname = fl_get_input(form->EpsFile);
	textra = fl_get_input(form->Extra);
// 	tlabel = fl_get_input(form->Label);
	tangle = atof(fl_get_input(form->Angle));
	txwid = atof(fl_get_input(form->Width));
	txhgh = atof(fl_get_input(form->Height));

	if (!tfname || !*tfname) {
		fl_set_input(form->Command, "");
		return;
	}

	char* buf1 = NameToPath(NULL, cbuffer->filename);
	char* fname2 = MakeRelPath(NULL, tfname, buf1);
	if (buf1) delete [] buf1;
	sprintf(cmdbuf, "\\epsfig{file=%s", fname2);
	if (fname2) delete[] fname2;


	switch (twtype) {
		case 1:
			sprintf(buf, ", width=%gcm", txwid);
			break;
		case 2:
			sprintf(buf, ", width=%gin", txwid);
			break;
		case 3:
			sprintf(buf, ", width=%g\\textwidth", txwid/100);
			break;
		default:
			buf[0] = 0;
			break;
	}
	strcat(cmdbuf, buf);

	switch (thtype) {
		case 1:
			sprintf(buf, ", height=%gcm", txhgh);
			break;
		case 2:
			sprintf(buf, ", height=%gin", txhgh);
			break;
		case 3:
			sprintf(buf, ", height=%g\\textheight", txhgh/100);
			break;
		default:
			buf[0] = 0;
			break;
	}
	strcat(cmdbuf, buf);

	if (tangle != 0) {
		sprintf(buf, ", angle=%g", tangle);
		strcat(cmdbuf, buf);
	}

	if (textra && *textra) {
		strcat(cmdbuf, ", ");
		strcat(cmdbuf, textra);
	}

// 	if (tlabel && *tlabel) {
// 		strcat(cmdbuf, "}\\label{");
// 		strcat(cmdbuf, tlabel);
// 	}

	strcat(cmdbuf, "}");

	fl_set_input(form->Command, cmdbuf);
}


void InsetFig::Recompute()
{
	bool changed = changedfname;
	int newx, newy;

	if (changed) GetPSSizes();

	/* now recompute wid and hgh, and if that is changed, set changed */
	/* this depends on chosen size of the picture and it's bbox */
	if (fname) {
		// say, total width is 595 pts, as A4 in TeX, that's in 1/72" */
		newx = pswid;
		newy = pshgh;
		switch (wtype) {
			case 1:	/* cm */
				newx = (int) (28.346*xwid);
				break;
			case 2: /* in */
				newx = (int) (72*xwid);
				break;
			case 3:	/* % of page */
				newx = (int) (5.95*xwid);
				break;
		}
		if (wtype && pswid) newy = newx*pshgh/pswid;
		switch (htype) {
			case 1:	/* cm */
				newy = (int) (28.346*xhgh);
				break;
			case 2: /* in */
				newy = (int) (72*xhgh);
				break;
			case 3:	/* % of page */
				newy = (int) (8.42*xhgh);
				break;
		}
		if (htype && !wtype && pshgh) newx = newy*pswid/pshgh;
	} else {
		newx = wid;
		newy = hgh;
	}

	// cannot be zero, actually, set it to some minimum, so it's clickable
	if (newx < 5) newx = 5;
	if (newy < 5) newy = 5;

	if (newx != wid || newy != hgh || flags != pflags) changed = true;

	wid = newx;
	hgh = newy;
	flags = pflags;

	if (changed) {
		char fbuf[256], fbuf2[256];
		figdata *pf = figure->data;

		// get new data
		if (fname && (flags & 3) ) { // do not display if there is "do not display" chosen (Matthias 260696)
		  figure->data = getfigdata(wid, hgh, fname,
					    psx, psy, pswid, pshgh, flags & (3|8));
		} else figure->data = NULL;

		// free the old data
		if (pf) freefigdata(pf);
	}

	changedfname = false;
}


void InsetFig::GetPSSizes()
{
	/* get %%BoundingBox: from postscript file */
	FILE *f;
	int lastchar, c;
	char *p = NULL, fbuf[256], fbuf2[256];
	
	/* defaults to A4 page */
	psx = 0;
	psy = 0;
	pswid = 595;
	pshgh = 842;

	if (!fname) return;
	f = fopen(fname, "r");

	if (!f) return;	// file not found !!!!

	lastchar = fgetc(f);
	for (;;) {
		c = fgetc(f);
		if (c == EOF) break;	// eof and no BBox
		if (c == '%' && lastchar == '%') {
			p = NextToken(f);
			if (!p) break;
			if (strcmp(p, "EndComments") == 0) break;
			if (strcmp(p, "BoundingBox:") == 0) {
				fscanf(f, "%d %d %d %d", &psx, &psy,
					&pswid, &pshgh);
				break;
			}
			c = 0;
			delete [] p;
			p = NULL;
		}
		lastchar = c;
	}
	if (p) delete [] p;
	fclose(f);
	pswid -= psx;
	pshgh -= psy;

}


void InsetFig::CallbackFig(long arg)
{
	char* buf1;
	bool regen = false;
	// char buf[384]; // unused
	const char *p;

#ifdef debug
	printf("Figure callback, arg %ld\n", arg);
#endif

	switch (arg) {
		case 10:
		case 11:
		case 12:	/* width type */
		case 13:
			twtype = arg - 10;
			regen = true;
			break;
		case 20:
		case 21:
		case 22:	/* height type */
		case 23:
			thtype = arg - 20;
			regen = true;
			break;
		case 3:
			pflags = pflags & ~3;		/* wysiwyg0 */
			break;
		case 33:
			pflags = (pflags & ~3) | 1;	/* wysiwyg1 */
			break;
		case 43:
			pflags = (pflags & ~3) | 2;	/* wysiwyg2 */
			break;
		case 63:
			pflags = (pflags & ~3) | 3;	/* wysiwyg3 */
			break;
		case 53:
			pflags ^= 4;	/* frame */
			break;
		case 54:
			pflags ^= 8;	/* do translations */
			break;
		case 2:
			regen = true;		/* regenerate command */
			break;
		case 0:				/* browse file */
			BrowseFile();
			regen = true;
			break;
		case 1:				/* preview */
			p = fl_get_input(form->EpsFile);
			Preview(p);
			break;
		case 7:				/* apply */
		case 8:				/* apply and close */
			wtype = twtype;
			htype = thtype;
			xwid = atof(fl_get_input(form->Width));
			xhgh = atof(fl_get_input(form->Height));
			angle = atof(fl_get_input(form->Angle));
			p = fl_get_input(form->EpsFile);
			if (p && *p) {
				if (fname) 
				  delete [] fname;
				buf1 = NameToPath(NULL, cbuffer->filename);
				fname = MakeAbsPath(NULL, p, buf1);
				if (buf1) delete [] buf1;
				changedfname = true;
			} else {
				if (fname) {
					changedfname = true;
					delete [] fname;
					fname = NULL;
				}
			}
			p = fl_get_input(form->Extra);
			if (extra) delete [] extra;
			if (p && *p) {
				extra = StringCopy(p);
			} else {
				extra = NULL;
			}
// 			p = fl_get_input(form->Label);
// 			if (label) free(label);
// 			if (p && *p) {
// 				label = StringCopy(p);
// 			} else {
// 				label = NULL;
// 			}
			Regenerate();
			Recompute();
			/* now update inset */
#ifdef debug
			printf("Update: [%dx%d]\n", wid, hgh);
#endif
			UpdateInset(this);
			if (arg == 8) {
//				fl_remove_canvas_handler(form->Prev, Expose,
//					ExposePreview);
				fl_hide_form(form->Figure);
				fl_free_form(form->Figure);
				free(form);
				form = NULL;
			}
			break;
		case 9:				/* cancel = restore and close */
//			fl_remove_canvas_handler(form->Prev, Expose,
//				ExposePreview);
			fl_hide_form(form->Figure);
			fl_free_form(form->Figure);
			free(form);
			form = NULL;
			break;
	}

	if (regen) TempRegenerate();
}


void InsetFig::RestoreForm()
{
	char buf[32];
	int pflags;

	twtype = wtype;
	fl_set_button(form->Default1, (wtype == 0));
	fl_set_button(form->cm1, (wtype == 1));
	fl_set_button(form->in1, (wtype == 2));
	fl_set_button(form->page1, (wtype == 3));
	thtype = htype;
	fl_set_button(form->Default2, (htype == 0));
	fl_set_button(form->cm2, (htype == 1));
	fl_set_button(form->in2, (htype == 2));
	fl_set_button(form->page2, (htype == 3));
	pflags = flags & 3;
	fl_set_button(form->Wysiwyg0, (pflags == 0));
	fl_set_button(form->Wysiwyg1, (pflags == 1));
	fl_set_button(form->Wysiwyg2, (pflags == 2));
	fl_set_button(form->Wysiwyg3, (pflags == 3));
	fl_set_button(form->Frame, ((flags & 4) != 0));
	fl_set_button(form->Translations, ((flags & 8) != 0));
	pflags = flags;
	sprintf(buf, "%g", xwid);
	fl_set_input(form->Width, buf);
	sprintf(buf, "%g", xhgh);
	fl_set_input(form->Height, buf);
	sprintf(buf, "%g", angle);
	fl_set_input(form->Angle, buf);
	if (fname){
	  char* buf1 = NameToPath(NULL, cbuffer->filename);
	  char* fname2 = MakeRelPath(NULL, fname, buf1);
	  if (buf1) delete [] buf1;
	  fl_set_input(form->EpsFile, fname2);
	  delete [] fname2;
	}
	else fl_set_input(form->EpsFile, "");
	if (extra) fl_set_input(form->Extra, extra);
		else fl_set_input(form->Extra, "");
// 	if (label) fl_set_input(form->Label, label);
// 		else fl_set_input(form->Label, "");
	TempRegenerate();
}


void InsetFig::Preview(const char *p)
{
	int pid;

 	signal(SIGCHLD, sigchldhandler);
 	pid = fork();

  	if (pid == -1) {
  		fprintf(stderr, "Cannot fork process!!!\n");
  		return;		// error
  	}
  	if (pid > 0) {
  		addpidwait(pid);
  		return;		// parent process
  	}

	char* buf1 = NameToPath(NULL, cbuffer->filename);
	char* buf2 = MakeAbsPath(NULL, p, buf1);
	if (buf1) delete [] buf1;
	
	fprintf(stderr, "Error executing ghostview %d\n",
		execlp("ghostview", "ghostview", buf2, NULL));
	_exit(0);
}


void InsetFig::BrowseFile()
{
	char buf[256], buf2[256], buf3[256];
	//char buf4[256]; // unused
	static char current_figure_path[256];
	static int once = 0;

#ifdef debug1
	printf("Filename: %s\n", cbuffer->filename);
#endif
	const char *p = fl_get_input(form->EpsFile);

	MakeAbsPath2(buf2, cbuffer->filename);
	MakePath(buf3, buf2, NULL);
	if (p && *p) {
	  MakeAbsPath(buf2, (char *) p, buf3);
	  MakePath(buf, buf2, NULL);
	} else {
	  AddName (buf, system_lyxdir, "clipart");
	}
	
	SetFSelButton(0, "Clipart", buf);
	ProhibitInput();
	if (once) {
	  p = SelectFile("EPS Figure", current_figure_path,
		  "*ps", "");
	} else {
	  p = SelectFile("EPS Figure", buf,
		  "*ps", "");
	}
	AllowInput();
	SetFSelButton(0, NULL, NULL);

	if (!p) return;

	// got file name
#ifdef debug1
	printf("Got .ps file name: %s\n", p);
#endif
	MakeRelPath(buf, (char *) p, buf3);
	NameToPath(current_figure_path, p);
	once = 1;
#ifdef debug1
	printf("Relative path: %s\n", buf);
#endif
	if (form) fl_set_input(form->EpsFile, buf); 
}


void EpsFig(FL_OBJECT *obj, long arg)
{
	/* obj->form contains the form */
	int i;

#ifdef debug
	printf("EpsFig callback: %ld\n", arg);
#endif

	/* find inset we were reacting to */
	for (i = 0; i < figinsref; ++i)
	  if (figures[i]->inset->form && figures[i]->inset->form->Figure
	      == obj->form) {
	    
#ifdef debug
			printf("Calling back figure %d\n", i);
#endif
			figures[i]->inset->CallbackFig(arg);
			return;
		}
}
