]> git.lyx.org Git - lyx.git/blob - src/insets/figinset.C
1e884f179822eabdf9b868d87597a43887631e2d
[lyx.git] / src / insets / figinset.C
1 /*
2  *      figinset.C - part of LyX project
3  */
4
5 extern int      reverse_video;
6 extern long int background_pixels;
7
8 /*  Rework of path-handling (Matthias 04.07.1996 )
9  * ------------------------------------------------
10  *   figinsets keep an absolute path to the eps-file.
11  *   For the user alway a relative path appears
12  *   (in lyx-file, latex-file and edit-popup).
13  *   To calculate this relative path the path to the
14  *   document where the figinset is in is needed. 
15  *   This is done by a reference to the buffer, called
16  *   figinset::cbuffer. To be up to date the cbuffer
17  *   is sometimes set to the current buffer 
18  *   bufferlist.current(), when it can be assumed that
19  *   this operation happens in the current buffer. 
20  *   This is true for InsetFig::Edit(...), 
21  *   InsetFig::InsetFig(...), InsetFig::Read(...),
22  *   InsetFig::Write and InsetFig::Latex(...).
23  *   Therefore the bufferlist has to make sure that
24  *   during these operations bufferlist.current() 
25  *   returns the buffer where the figinsets are in.
26  *   This made few changes in buffer.C necessary.
27  *
28  * The above is not totally valid anymore. (Lgb)
29  */
30
31
32 #include <config.h>
33
34 #include <unistd.h>
35 #include <signal.h>
36 #include <sys/wait.h>
37
38 #include FORMS_H_LOCATION
39 #include <stdlib.h>
40 #include <ctype.h>
41 #include <math.h>
42
43 #include "form1.h"
44 #include "figinset.h"
45 #include "lyx.h"
46 #include "lyx_main.h"
47 #include "buffer.h"
48 #include "filedlg.h"
49 #include "filetools.h"
50 #include "LyXView.h" // just because of form_main
51 #include "error.h"
52 #include "lyxdraw.h"
53 #include "LaTeXFeatures.h"
54 #include "lyxrc.h"
55 #include "gettext.h"
56 #include "lyx_gui_misc.h" // CancelCloseBoxCB
57 #include "FileInfo.h"
58
59 //      $Id: figinset.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $  
60
61 #if !defined(lint) && !defined(WITH_WARNINGS)
62 static char vcid[] = "$Id: figinset.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $";
63 #endif /* lint */
64
65 extern BufferView *current_view;
66 static volatile bool alarmed;
67
68 extern FL_OBJECT *figinset_canvas;
69 inline
70 void waitalarm(int)
71 {
72         alarmed = true;
73 }
74
75 extern char **environ; // is this only redundtant on linux systems? Lgb.
76 extern void UpdateInset(Inset* inset, bool mark_dirty = true);
77 // better for asyncron updating:
78 void PutInsetIntoInsetUpdateList(Inset* inset);
79 extern void ProhibitInput();
80 extern void AllowInput();
81
82 #define DEG2PI 57.295779513
83 #define figallocchunk 32
84
85 static int figinsref = 0;       /* number of figures */
86 static int figarrsize = 0;      /* current max number of figures */
87 static int bmpinsref = 0;       /* number of bitmaps */
88 static int bmparrsize = 0;      /* current max number of bitmaps */
89
90 struct queue {
91         float rx, ry;           /* resolution x and y */
92         int ofsx, ofsy;         /* x and y translation */
93         figdata *data;          /* we are doing it for this data */
94         queue *next;            /* next item in queue */
95 };
96
97 struct pidwait {
98         int pid;                /* pid to wait for */
99         pidwait *next;  /* next */
100 };
101
102 #define MAXGS 3                 /* maximum 3 gs's at a time */
103
104 static Figref **figures;        /* all the figures */
105 static figdata **bitmaps;       /* all the bitmaps */
106 static queue *gsqueue = NULL;   /* queue for ghostscripting */
107 static int gsrunning = 0;       /* currently so many gs's are running */
108 static bool bitmap_waiting = false; /* bitmaps are waiting finished */
109 static char bittable[256];      /* bit reversion table */
110
111 static bool gs_color;                   // do we allocate colors for gs?
112 static bool color_visual;               // is the visual color?
113 static bool gs_xcolor = false;          // allocated extended colors
114 static unsigned long gs_pixels[128];    // allocated pixels
115 static int gs_num_pixels;               // number of pixels allocated
116 static int gs_spc;                      // shades per color
117 static bool gs_gray;                    // is grayscale?
118 static int gs_allcolors;                // number of all colors
119
120 static pidwait *pw = NULL;              // pid wait list
121
122
123 extern FD_form_main *fd_form_main;
124 extern Colormap color_map;
125
126 void addpidwait(int pid)
127 {
128         // adds pid to pid wait list
129         register pidwait *p = new pidwait;
130
131         p->pid = pid;
132         p->next = pw;
133         pw = p;
134
135         if (lyxerr.debugging()) {
136                 lyxerr.print(LString("Pids to wait for: ") + int(p->pid));
137                 while (p->next) {
138                         p = p->next;
139                         lyxerr.print(LString() + int(p->pid));
140                 }
141         }
142 }
143
144
145 int GhostscriptMsg(FL_OBJECT *, Window, int, int,
146                    XEvent *ev, void *)
147 {
148         int i;
149         char tmp[128];
150
151         XClientMessageEvent *e = (XClientMessageEvent*) ev;
152
153         if(lyxerr.debugging()) {
154                 fprintf(stderr,
155                         "ClientMessage, win:[xx] gs:[%ld] pm:[%ld]\n",
156                         e->data.l[0], e->data.l[1]);
157         }
158
159         // just kill gs, that way it will work for sure
160         for (i = 0; i < bmpinsref; ++i)
161                 if ((long)bitmaps[i]->bitmap == (long)e->data.l[1]) {
162                         // found the one
163                         figdata *p = bitmaps[i];
164                         p->gsdone = true;
165
166                         // first update p->bitmap, if necessary
167                         if (p->bitmap != None && p->flags > (1|8) && gs_color && p->wid) {
168                                 // query current colormap and re-render
169                                 // the pixmap with proper colors
170                                 XColor *cmap;
171                                 XWindowAttributes wa;
172                                 register XImage *im;
173                                 int i, y, wid1, spc1 = gs_spc-1,
174                                         spc2 = gs_spc*gs_spc, wid = p->wid,
175                                         forkstat;
176                                 Display *tmpdisp;
177                                 GC gc = getGC(gc_copy);
178
179                                 XGetWindowAttributes(fl_display, fl_get_canvas_id(
180                                         figinset_canvas), &wa);
181                                 XFlush(fl_display);
182                                 if (lyxerr.debugging()) {
183                                         fprintf(stderr,
184                                                 "Starting image translation %ld %d %dx%d %d %d\n",
185                                                p->bitmap, p->flags, p->wid, p->hgh, wa.depth,
186                                                XYPixmap);
187                                 }
188                                 // now fork rendering process
189                                 forkstat = fork();
190                                 if (forkstat == -1) {
191                                         lyxerr.debug("Cannot fork, using slow "
192                                                       "method for pixmap translation.");
193                                         tmpdisp = fl_display;
194                                 } else if (forkstat > 0) {
195                                         // register child
196                                         if (lyxerr.debugging()) {
197                                                 lyxerr.print(
198                                                         LString("Spawned child ")
199                                                         + int(forkstat));
200                                         }
201                                         addpidwait(forkstat);
202                                         break; // in parent process
203                                 } else {
204                                         tmpdisp = XOpenDisplay(XDisplayName(NULL));
205                                         XFlush(tmpdisp);
206                                 }
207                                 im = XGetImage(tmpdisp, p->bitmap, 0, 0,
208                                                p->wid, p->hgh, (1<<wa.depth)-1, XYPixmap);
209                                 XFlush(tmpdisp);
210                                 if (lyxerr.debugging()) {
211                                         lyxerr.print("Got the image");
212                                 }
213                                 if (!im) {
214                                         if (lyxerr.debugging()) {
215                                                 lyxerr.print("Error getting the image");
216                                         }
217                                         goto noim;
218                                 }
219                                 // query current colormap
220                                 cmap = (XColor *) malloc(gs_allcolors*sizeof(XColor));
221                                 for (i = 0; i < gs_allcolors; ++i) cmap[i].pixel = i;
222                                 XQueryColors(tmpdisp, color_map, cmap, gs_allcolors);
223                                 XFlush(tmpdisp);
224                                 wid1 = p->wid - 1;
225                                 // now we process all the image
226                                 for (y = 0; y < p->hgh; ++y) {
227                                         register int x;
228                                         for (x = 0; x < wid; ++x) {
229                                                 register XColor* pc;
230                                                 pc = cmap + XGetPixel(im, x, y);
231                                                 XFlush(tmpdisp);
232                                                 XPutPixel(im, x, y, gs_pixels[((pc->red+6553)*
233                                                                                spc1/65535)*spc2+((pc->green+6553)*
234                                                                                                  spc1/65535)*gs_spc+((pc->blue+6553)*
235                                                                                                                      spc1/65535)]);
236                                                 XFlush(tmpdisp);
237                                         }
238                                 }
239                                 if (lyxerr.debugging()) {
240                                         lyxerr.print("Putting image back");
241                                 }
242                                 XPutImage(tmpdisp, p->bitmap, gc, im, 0, 0,
243                                           0, 0, p->wid, p->hgh);
244                                 XDestroyImage(im);
245                                 if (lyxerr.debugging()) {
246                                         lyxerr.print("Done translation");
247                                 }
248                           noim:
249                                 if (lyxerr.debugging()) {
250                                         lyxerr.print(LString("Killing gs ") 
251                                                      + int(p->gspid));
252                                 }
253                                 kill(p->gspid, SIGHUP);
254
255                                 sprintf(tmp, "%s/~lyxgs%d.ps",
256                                         system_tempdir.c_str(), 
257                                         p->gspid);
258                                 unlink(tmp);
259                                 if (forkstat == 0) {
260                                         XCloseDisplay(tmpdisp);
261                                         _exit(0);
262                                 }
263                         } else {
264                                 if (lyxerr.debugging()) {
265                                         lyxerr.print(LString("Killing gs ") 
266                                                      +int(p->gspid));
267                                 }
268                                 kill(p->gspid, SIGHUP);
269
270                                 sprintf(tmp, "%s/~lyxgs%d.ps", 
271                                         system_tempdir.c_str(),
272                                         p->gspid);
273                                 unlink(tmp);
274                         }
275                         break;
276                 }
277         return 0;
278 }
279
280
281 static void AllocColors(int num)
282 // allocate color cube numxnumxnum, if possible
283 {
284         XColor xcol;
285         int i;
286
287         if (lyxerr.debugging()) {
288                 printf("Allocating color cube %dx%dx%d\n", num, num, num);
289         }
290
291         if (num <= 1) {
292                 lyxerr.print("Error allocating color colormap.");
293                 gs_color = false;
294                 return;
295         }
296         if (num > 5) num = 5;
297         for (i = 0; i < num*num*num; ++i) {
298                 xcol.red = 65535*(i/(num*num))/(num-1);
299                 xcol.green = 65535*((i/num) % num)/(num-1);
300                 xcol.blue = 65535*(i % num)/(num-1);
301                 xcol.flags = DoRed | DoGreen | DoBlue;
302                 if (!XAllocColor(fl_display, color_map, &xcol)) {
303                         if (i) XFreeColors(fl_display, color_map,
304                                            gs_pixels, i, 0);
305                         if(lyxerr.debugging()) {
306                                 lyxerr.print(LString("Cannot allocate color cube " )
307                                              + int(num));
308                         }
309                         AllocColors(num-1);
310                         return;
311                 }
312                 gs_pixels[i] = xcol.pixel;
313         }
314         gs_color = true;
315         gs_gray = false;
316         gs_spc = num;
317         gs_num_pixels = num*num*num;
318 }
319
320
321 static void AllocGrays(int num)
322 // allocate grayscale ramp
323 {
324         XColor xcol;
325         int i;
326
327         if (lyxerr.debugging()) {
328                 lyxerr.print(LString("Allocating grayscale ramp ") 
329                              + int(num));
330         }
331
332         if (num < 4) {
333                 lyxerr.print("Error allocating grayscale colormap.");
334                 gs_color = false;
335                 return;
336         }
337         if (num > 128) num = 128;
338         for (i = 0; i < num; ++i) {
339                 xcol.red = xcol.green = xcol.blue = 65535*i/(num-1);
340                 xcol.flags = DoRed | DoGreen | DoBlue;
341                 if (!XAllocColor(fl_display, color_map, &xcol)) {
342                         if (i) XFreeColors(fl_display, color_map,
343                                            gs_pixels, i, 0);
344                         if (lyxerr.debugging()) {
345                                 lyxerr.print(LString("Cannot allocate grayscale ") 
346                                              + int(num));
347                         }
348                         AllocGrays(num/2);
349                         return;
350                 }
351                 gs_pixels[i] = xcol.pixel;
352         }
353         gs_color = true;
354         gs_gray = false;
355         gs_num_pixels = num;
356 }
357
358
359 void InitFigures()
360 {
361         unsigned int i, j, k;
362         Visual *vi;
363
364         bmparrsize = figarrsize = figallocchunk;
365         figures = (Figref**) malloc(sizeof(Figref*)*figallocchunk);
366         bitmaps = (figdata**) malloc(sizeof(figdata*)*figallocchunk);
367
368         for (i = 0; i < 256; ++i) {
369                 k = 0;
370                 for (j = 0; j < 8; ++j)
371                         if (i & (1 << (7-j))) k |= 1 << j;
372                 bittable[i] = (char) ~k;
373         }
374
375         fl_add_canvas_handler(figinset_canvas, ClientMessage,
376                               GhostscriptMsg, fd_form_main);
377
378         // now we have to init color_map
379         if (!color_map) color_map = DefaultColormap(fl_display,
380                                                     DefaultScreen(fl_display));
381         // allocate color cube on pseudo-color display
382         // first get visual
383         gs_color = false;
384
385         vi = DefaultVisual(fl_display, DefaultScreen(fl_display));
386         if (lyxerr.debugging()) {
387                 printf("Visual ID: %ld, class: %d, bprgb: %d, mapsz: %d\n", 
388                        vi->visualid, vi->c_class, 
389                        vi->bits_per_rgb, vi->map_entries);
390         }
391         color_visual = ( (vi->c_class == StaticColor) ||
392                 (vi->c_class == PseudoColor) ||
393                 (vi->c_class == TrueColor) ||
394                 (vi->c_class == DirectColor) );
395         if ((vi->c_class & 1) == 0) return;
396         // now allocate colors
397         if (vi->c_class == GrayScale) {
398                 // allocate grayscale
399                 AllocGrays(vi->map_entries/2);
400         } else {
401                 // allocate normal color
402                 int i = 5;
403                 while (i*i*i*2 > vi->map_entries) --i;
404                 AllocColors(i);
405         }
406         gs_allcolors = vi->map_entries;
407 }
408
409
410 void DoneFigures()
411 {
412         free(figures);
413         free(bitmaps);
414         figarrsize = 0;
415         bmparrsize = 0;
416
417         lyxerr.debug("Unregistering figures...");
418
419         fl_remove_canvas_handler(figinset_canvas, ClientMessage,
420                                  GhostscriptMsg);
421
422         if (gs_color) {
423                 lyxerr.debug("Freeing up the colors...");
424                 XFreeColors(fl_display, color_map, gs_pixels,
425                             gs_num_pixels, 0);
426                 /******????????????????? what's planes in this case ??????***/
427         }
428 }
429
430
431 int FindBmpIndex(figdata *tmpdata)
432 {
433         int i = 0;
434         while (i < bmpinsref) {
435                 if (bitmaps[i] == tmpdata) return i;
436                 ++i;
437         }
438         return i;
439 }
440
441
442 static void chpixmap(Pixmap, int, int)
443 {
444         Display* tempdisp = XOpenDisplay(XDisplayName(NULL));
445
446         // here read the pixmap and change all colors to those we
447         // have allocated
448
449         XCloseDisplay(tempdisp);
450 }
451
452
453 static void freefigdata(figdata *tmpdata)
454 {
455         int i;
456
457         tmpdata->ref--;
458         if (tmpdata->ref) return;
459
460         if (tmpdata->gspid > 0) {
461                 int pid = tmpdata->gspid;
462                 char buf[128];
463                 // change Pixmap according to our allocated colormap
464                 chpixmap(tmpdata->bitmap, tmpdata->wid, tmpdata->hgh);
465                 // kill ghostscript and unlink it's files
466                 tmpdata->gspid = -1;
467                 kill(pid, SIGKILL);
468                 sprintf(buf, "%s/~lyxgs%d.ps", system_tempdir.c_str(), pid);
469                 unlink(buf);
470         }
471
472         if (tmpdata->bitmap) XFreePixmap(fl_display, tmpdata->bitmap);
473         delete tmpdata;
474         i = FindBmpIndex(tmpdata);
475         --bmpinsref;
476         while (i < bmpinsref) {
477                 bitmaps[i] = bitmaps[i+1];
478                 ++i;
479         }
480 }
481
482
483 static void runqueue()
484 {
485         // run queued requests for ghostscript, if any
486         if (!gsrunning && gs_color && !gs_xcolor) {
487                 // here alloc all colors, so that gs will use only
488                 // those we allocated for it
489                 // *****
490                 gs_xcolor = true;
491         }
492         
493         while (gsrunning < MAXGS) {
494                 queue *p;
495                 int pid;
496                 char tbuf[384], tbuf2[80];
497                 Atom *prop;
498                 int nprop, i;
499
500                 if (!gsqueue) {
501                         if (!gsrunning && gs_xcolor) {
502                                 // de-allocate rest of colors
503                                 // *****
504                                 gs_xcolor = false;
505                         }
506                         return;
507                 }
508                 p = gsqueue;
509
510                 if (!p->data) {
511                         delete p;
512                         continue;
513                 }
514
515                 pid = fork();
516                 
517                 if (pid == -1) {
518                         if (lyxerr.debugging()) {
519                                 lyxerr.print("GS start error! Cannot fork.");
520                         }
521                         p->data->broken = true;
522                         p->data->reading = false;
523                         return;
524                 }
525                 if (pid == 0) { // child
526                         char **env, rbuf[80], gbuf[40];
527                         int ne = 0;
528                         Display* tempdisp = XOpenDisplay(XDisplayName(NULL));
529
530                         // create translation file
531                         sprintf(tbuf, "%s/~lyxgs%d.ps", system_tempdir.c_str(),
532                                 int(getpid()));
533                         
534                         FilePtr f(tbuf, FilePtr::write);
535                         fprintf(f, "gsave clippath pathbbox grestore\n"
536                                 "4 dict begin\n"
537                                 "/ury exch def /urx exch def /lly exch def " 
538                                 "/llx exch def\n"
539                                 "%g %g translate\n"
540                                 "%g rotate\n"
541                                 "%g %g translate\n"
542                                 "%g %g scale\n"
543                                 "%d %d translate\nend\n",
544                                 p->data->wid / 2.0, p->data->hgh / 2.0,
545                                 p->data->angle,
546                                 - (p->data->raw_wid / 2.0), -(p->data->raw_hgh / 2.0),
547                                 p->rx / 72.0, p->ry / 72.0,
548                                 -p->ofsx, -p->ofsy
549                                 );
550
551                         // DON'T EVER remove this!!
552                         f.close(); // was this all? (Lgb)
553                         
554                         // gs process - set ghostview environment first
555                         sprintf(tbuf2, "GHOSTVIEW=%ld %ld", fl_get_canvas_id(
556                                 figinset_canvas), p->data->bitmap);
557
558                         // now set up ghostview property on a window
559                         sprintf(tbuf, "0 0 0 0 %d %d 72 72 0 0 0 0",
560                                 p->data->wid, p->data->hgh);
561 //#warning BUG seems that the only bug here might be the hardcoded dpi.. Bummer!
562                         
563                         if (lyxerr.debugging()) {
564                                 lyxerr.print(LString("Will set GHOSTVIEW"
565                                                      " property to [") +
566                                              tbuf + "]");
567                         }
568                         // wait until property is deleted if executing multiple
569                         // ghostscripts
570                         for (;;) {
571                                 // grab server to prevent other child interfering
572                                 // with setting GHOSTVIEW property
573                                 if (lyxerr.debugging()) {
574                                         lyxerr.print("Grabbing the server");
575                                 }
576                                 XGrabServer(tempdisp);
577                                 prop = XListProperties(tempdisp, fl_get_canvas_id(
578                                         figinset_canvas), &nprop);
579                                 if (!prop) break;
580
581                                 bool err = true;
582                                 for (i = 0; i < nprop; ++i) {
583                                         char *p = XGetAtomName(tempdisp, prop[i]);
584                                         if (strcmp(p, "GHOSTVIEW") == 0) {
585                                                 err = false;
586                                                 break;
587                                         }
588                                         XFree(p);
589                                 }
590                                 XFree((char *)prop);    /* jc: */
591                                 if (err) break;
592                                 // release the server
593                                 XUngrabServer(tempdisp);
594                                 XFlush(tempdisp);
595                                 // ok, property found, we must wait until ghostscript
596                                 // deletes it
597                                 if (lyxerr.debugging()) {
598                                         lyxerr.print("Releasing the server");
599                                         lyxerr.print(LString('[') +
600                                                       int(getpid()) +
601                                                       "] GHOSTVIEW property"
602                                                       " found. Waiting.");
603                                 }
604 #ifdef WITH_WARNINGS
605 #warning What is this doing? (wouldn't a sleep(1); work too?')
606 #endif
607                                 alarm(1);
608                                 alarmed = false;
609                                 signal(SIGALRM, waitalarm);
610                                 while (!alarmed) pause();
611                         }
612
613                         XChangeProperty(tempdisp, 
614                                         fl_get_canvas_id(figinset_canvas),
615                                         XInternAtom(tempdisp, "GHOSTVIEW", false),
616                                         XInternAtom(tempdisp, "STRING", false),
617                                         8, PropModeAppend, 
618                                         (unsigned char *) tbuf,
619                                         strlen(tbuf));
620                         
621                         switch (p->data->flags & 3) {
622                         case 0: tbuf[0] = 'H'; break; // Hidden
623                         case 1: tbuf[0] = 'M'; break; // Mono
624                         case 2: tbuf[0] = 'G'; break; // Gray
625                         case 3:
626                                 if (color_visual) 
627                                         tbuf[0] = 'C'; // Color
628                                 else 
629                                         tbuf[0] = 'G'; // Gray
630                                 break;
631                         }
632
633                         if (reverse_video) {
634                                 sprintf(tbuf+1, " %ld %ld", WhitePixelOfScreen(
635                                         DefaultScreenOfDisplay(fl_display)),
636                                         background_pixels);
637                         } else {
638                                 sprintf(tbuf+1, " %ld %ld", BlackPixelOfScreen(
639                                         DefaultScreenOfDisplay(fl_display)),
640                                         background_pixels);
641                         }
642
643                         XChangeProperty(tempdisp, 
644                                         fl_get_canvas_id(figinset_canvas),
645                                         XInternAtom(tempdisp, "GHOSTVIEW_COLORS", false),
646                                         XInternAtom(tempdisp, "STRING", false),
647                                         8, PropModeReplace, 
648                                         (unsigned char *) tbuf,
649                                         strlen(tbuf));
650                         XUngrabServer(tempdisp);
651                         XFlush(tempdisp);
652                         if (lyxerr.debugging()) {
653                                 lyxerr.print("Releasing the server");
654                         }
655                         XCloseDisplay(tempdisp);
656
657                         // set up environment
658                         while (environ[ne]) ++ne;
659                         env = (char **) malloc(sizeof(char*)*(ne+2));
660                         env[0] = tbuf2;
661                         memcpy(&env[1], environ, sizeof(char*)*(ne+1));
662                         environ = env;
663
664                         // now make gs command
665                         // close(0);
666                         // close(1); do NOT close. If GS writes out
667                         // errors it would hang. (Matthias 290596) 
668                         sprintf(rbuf, "-r%gx%g", p->rx, p->ry);
669                         sprintf(gbuf, "-g%dx%d", p->data->wid, p->data->hgh);
670                         // now chdir into dir with .eps file, to be on the safe
671                         // side
672                         chdir(OnlyPath(p->data->fname).c_str());
673                         // make temp file name
674                         sprintf(tbuf, "%s/~lyxgs%d.ps", system_tempdir.c_str(),
675                                 int(getpid()));
676                         if (lyxerr.debugging()) {
677                                 printf("starting gs %s %s, pid: %d\n", tbuf,
678                                        p->data->fname.c_str(), int(getpid()));
679                         }
680
681                         int err = execlp(lyxrc->ps_command.c_str(), 
682                                          lyxrc->ps_command.c_str(), 
683                                          "-sDEVICE=x11",
684                                          "-dNOPAUSE", "-dQUIET",
685                                          "-dSAFER", 
686                                          rbuf, gbuf, tbuf, 
687                                          p->data->fname.c_str(), 
688                                          "showpage.ps", "quit.ps", "-", NULL);
689                         // if we are still there, an error occurred.
690                         lyxerr.print(LString("Error executing ghostscript. ")
691                                      +"Code: "+err);
692                         lyxerr.debug("Cmd: " 
693                                      + lyxrc->ps_command
694                                      +" -sDEVICE=x11 "
695                                      + tbuf + LString(' ')
696                                      + p->data->fname);
697                         _exit(0);       // no gs?
698                 }
699                 // normal process (parent)
700                 if (lyxerr.debugging()) {
701                         lyxerr.print(LString("GS [") + int(pid) + "] started");
702                 }
703                 gsqueue = gsqueue->next;
704                 gsrunning++;
705                 p->data->gspid = pid;
706                 delete p;
707         }
708 }
709
710
711 static void addwait(int psx, int psy, int pswid, int pshgh, figdata *data)
712 {
713         // recompute the stuff and put in the queue
714         queue *p, *p2;
715         p = new queue;
716         p->ofsx = psx;
717         p->ofsy = psy;
718         p->rx = ((float)data->raw_wid*72)/pswid;
719         p->ry = ((float)data->raw_hgh*72)/pshgh;
720
721         p->data = data;
722         p->next = NULL;
723
724         // now put into queue
725         p2 = gsqueue;
726         if (!gsqueue) gsqueue = p;
727         else {
728                 while (p2->next) p2 = p2->next;
729                 p2->next = p;
730         }
731
732         // if possible, run the queue
733         runqueue();
734 }
735
736
737 static figdata *getfigdata(int wid, int hgh, LString const & fname, 
738                            int psx, int psy, int pswid, int pshgh, 
739                            int raw_wid, int raw_hgh, float angle, char flags)
740 {
741         /* first search for an exact match with fname and width/height */
742         int i = 0;
743         figdata *p;
744         XWindowAttributes wa;
745
746         if (fname.empty()) return NULL;
747
748         while (i < bmpinsref) {
749                 if (bitmaps[i]->wid == wid && bitmaps[i]->hgh == hgh &&
750                     bitmaps[i]->flags == flags && bitmaps[i]->fname==fname &&
751                     bitmaps[i]->angle == angle) {
752                         bitmaps[i]->ref++;
753                         return bitmaps[i];
754                 }
755                 ++i;
756         }
757         /* not found -> create new record or return NULL if no record */
758         ++bmpinsref;
759         if (bmpinsref > bmparrsize) {
760                 // allocate more space
761                 bmparrsize += figallocchunk;
762                 figdata **tmp = (figdata**) malloc(sizeof(figdata*)*bmparrsize);
763                 memcpy(tmp, bitmaps, sizeof(figdata*)*(bmparrsize-figallocchunk));
764                 free(bitmaps);
765                 bitmaps = tmp;
766         }
767         p = new figdata;
768         bitmaps[bmpinsref-1] = p;
769         p->wid = wid;
770         p->hgh = hgh;
771         p->raw_wid = raw_wid;
772         p->raw_hgh = raw_hgh;
773         p->angle = angle;
774         p->fname = fname;
775         p->flags = flags;
776         XGetWindowAttributes(fl_display, fl_get_canvas_id(
777                 figinset_canvas), &wa);
778
779         if (lyxerr.debugging()) {
780                 printf("Create pixmap disp:%d scr:%d w:%d h:%d depth:%d\n",
781                        PTR_AS_INT(fl_display), DefaultScreen(fl_display), 
782                        wid, hgh, wa.depth);
783         }
784         
785         p->ref = 1;
786         p->reading = false;
787         p->broken = false;
788         p->gspid = -1;
789         if (flags) {
790                 p->bitmap = XCreatePixmap(fl_display, fl_get_canvas_id(
791                         figinset_canvas), wid, hgh, wa.depth);
792                 p->gsdone = false;
793                 // initialize reading of .eps file with correct sizes and stuff
794                 addwait(psx, psy, pswid, pshgh, p);
795                 p->reading = true;
796         } else {
797                 p->bitmap = None;
798                 p->gsdone = true;
799         }
800
801         return p;
802 }
803
804
805 static void getbitmap(figdata *p)
806 {
807         p->gspid = -1;
808 }
809
810
811 static void makeupdatelist(figdata *p)
812 {
813         int i;
814
815         for (i = 0; i < figinsref; ++i) if (figures[i]->data == p) {
816                 if (lyxerr.debugging()) {
817                         printf("Updating inset %d\n", 
818                                PTR_AS_INT(figures[i]->inset));
819                 }
820                 //UpdateInset(figures[i]->inset);
821                 // add inset figures[i]->inset into to_update list
822                 PutInsetIntoInsetUpdateList(figures[i]->inset);
823         }
824 }
825
826
827 void sigchldchecker(pid_t pid, int *status)
828 {
829         int i;
830         figdata *p;
831
832         bool pid_handled = false;
833         
834         lyxerr.debug(LString("Got pid = ") + long (pid));
835         pid_handled = false;
836         for (i = bmpinsref - 1; i >= 0; --i) {
837                 if (bitmaps[i]->reading && pid == bitmaps[i]->gspid) {
838                         lyxerr.debug("Found pid in bitmaps");
839                         // now read the file and remove it from disk
840                         p = bitmaps[i];
841                         p->reading = false;
842                         if (bitmaps[i]->gsdone) *status = 0;
843                         if (*status == 0) {
844                                 lyxerr.debug(LString("GS [") + int(pid) +
845                                              "] exit OK.");
846                         } else {
847                                 fprintf(stderr, "GS [%ld] error %d E:%d %d S:%d %d\n", long(pid),
848                                         *status, WIFEXITED(*status), WEXITSTATUS(*status),
849                                         WIFSIGNALED(*status), WTERMSIG(*status));
850                         }
851                         if (*status == 0) {
852                                 bitmap_waiting = true;
853                                 p->broken = false;
854                         } else {
855                                 // remove temporary files
856                                 char tmp[128];
857                                 sprintf(tmp, "%s/~lyxgs%d.ps", 
858                                         system_tempdir.c_str(),
859                                         p->gspid);
860                                 unlink(tmp);
861                                 p->gspid = -1;
862                                 p->broken = true;
863                         }
864                         makeupdatelist(bitmaps[i]);
865                         gsrunning--;
866                         runqueue();
867                         pid_handled = true;
868                 }
869         }
870         if (!pid_handled) {
871                 lyxerr.debug("Checking pid in pidwait");
872                 pidwait *p = pw, *prev = NULL;
873                 while (p) {
874                         if (pid == p->pid) {
875                                 lyxerr.debug("Found pid in pidwait");
876                                 lyxerr.debug(LString("Caught child pid of recompute routine ") + int(pid));
877                                 if (prev)
878                                         prev->next = p->next;
879                                 else
880                                         pw = p->next;
881                                 free(p);
882                                 break;
883                         }
884                         prev = p;
885                         p = p->next;
886                 }
887         }
888
889         if (pid == -1) {
890                 lyxerr.debug("waitpid error");
891                 switch (errno) {
892                 case ECHILD:
893                         lyxerr.print(
894                                 "The process or process group specified by pid "
895                                 "does  not exist or is not a child of the cal-"
896                                 "ling process or can never be  in  the  states "
897                                 "specified by options.");
898                         break;
899                 case EINTR:
900                         lyxerr.print(
901                                 "waitpid() was interrupted due to the  receipt "
902                                 "of a signal sent by the calling process.");
903                         break;
904                 case EINVAL:
905                         lyxerr.print(
906                                 "An invalid value was specified for options.");
907                         break;
908                 default:
909                         lyxerr.print("Unknown error from waitpid");
910                         break;
911                 }
912         } else if (pid == 0) {
913                 lyxerr.print("waitpid nohang");
914         } else {
915                 lyxerr.debug("normal exit from childhandler");
916         }
917 }
918
919
920 static void getbitmaps()
921 {
922         int i;
923         bitmap_waiting = false;
924         for (i = 0; i < bmpinsref; ++i)
925                 if (bitmaps[i]->gspid > 0 && !bitmaps[i]->reading)
926                         getbitmap(bitmaps[i]);
927 }
928
929
930 static void RegisterFigure(InsetFig *fi)
931 {
932         Figref *tmpfig;
933
934         if (figinsref == 0) InitFigures();
935         fi->form = NULL;
936         ++figinsref;
937         if (figinsref > figarrsize) {
938                 // allocate more space
939                 figarrsize += figallocchunk;
940                 Figref **tmp = (Figref**) malloc(sizeof(Figref*)*figarrsize);
941                 memcpy(tmp, figures, sizeof(Figref*)*(figarrsize-figallocchunk));
942                 free(figures);
943                 figures = tmp;
944         }
945         tmpfig = new Figref;
946         tmpfig->data = NULL;
947         tmpfig->inset = fi;
948         figures[figinsref-1] = tmpfig;
949         fi->figure = tmpfig;
950
951         if (lyxerr.debugging()) {
952                 lyxerr.print(LString("Register Figure: buffer:[") +
953                              long(current_view->currentBuffer()) + "]");
954         }
955 }
956
957
958 int FindFigIndex(Figref *tmpfig)
959 {
960         int i = 0;
961         while (i < figinsref) {
962                 if (figures[i] == tmpfig) return i;
963                 ++i;
964         }
965         return i;
966 }
967
968
969 static void UnregisterFigure(InsetFig *fi)
970 {
971         Figref *tmpfig = fi->figure;
972         int i;
973
974         if (tmpfig->data) freefigdata(tmpfig->data);
975         if (tmpfig->inset->form) {
976                 if (tmpfig->inset->form->Figure->visible)
977                         fl_hide_form(tmpfig->inset->form->Figure);
978                 fl_free_form(tmpfig->inset->form->Figure);
979                 free(tmpfig->inset->form);
980                 tmpfig->inset->form = NULL;
981         }
982         i = FindFigIndex(tmpfig);
983         --figinsref;
984         while (i < figinsref) {
985                 figures[i] = figures[i+1];
986                 ++i;
987         }
988         delete tmpfig;
989
990         if (figinsref == 0) DoneFigures();
991 }
992
993
994 static char* NextToken(FILE *myfile)
995 {
996         char* token = NULL;
997         char c;
998         int i = 0;
999    
1000         if (!feof(myfile)) {
1001                 token = new char[256];
1002                 do {
1003                         c = fgetc(myfile);
1004                         token[i++]=c;
1005                 } while (!feof(myfile) && !isspace(c));
1006       
1007                 token[i-1]='\0';         /* just the end of a command  */
1008         }
1009         return token;
1010 }
1011
1012
1013 InsetFig::InsetFig(int tmpx, int tmpy, Buffer *o)
1014         : owner(o)
1015 {
1016         wid = tmpx;
1017         hgh = tmpy;
1018         wtype = DEF;
1019         htype = DEF;
1020         twtype = DEF;
1021         thtype = DEF;
1022         pflags = flags = 9;
1023         psubfigure = subfigure = false;
1024         xwid = xhgh = angle = 0;
1025         raw_wid = raw_hgh = 0;
1026         changedfname = false;
1027         RegisterFigure(this);
1028 }
1029
1030
1031 InsetFig::~InsetFig()
1032 {
1033         if (lyxerr.debugging()) {
1034                 lyxerr.print("Figure destructor called");
1035         }
1036         UnregisterFigure(this);
1037 }
1038
1039
1040 int InsetFig::Ascent(LyXFont const&) const
1041 {
1042         return hgh + 3;
1043 }
1044
1045
1046 int InsetFig::Descent(LyXFont const&) const
1047 {
1048         return 1;
1049 }
1050
1051
1052 int InsetFig::Width(LyXFont const&) const
1053 {
1054         return wid + 2;
1055 }
1056
1057
1058 void InsetFig::Draw(LyXFont font, LyXScreen &scr, int baseline, float &x)
1059 {
1060         if (bitmap_waiting) getbitmaps();
1061
1062         // I wish that I didn't have to use this
1063         // but the figinset code is so complicated so
1064         // I don't want to fiddle with it now.
1065         unsigned long pm = scr.getForeground();
1066         
1067         if (figure && figure->data && figure->data->bitmap &&
1068             !figure->data->reading && !figure->data->broken) {
1069                 // draw the bitmap
1070                 XCopyArea(fl_display, figure->data->bitmap, pm, getGC(gc_copy),
1071                           0, 0, wid, hgh, int(x+1), baseline-hgh);
1072                 XFlush(fl_display);
1073                 if (flags & 4) XDrawRectangle(fl_display, pm, getGC(gc_copy),
1074                                               int(x), baseline - hgh - 1,
1075                                               wid+1, hgh+1);
1076         } else {
1077                 char * msg = 0;
1078                 // draw frame
1079                 XDrawRectangle(fl_display, pm, getGC(gc_copy),
1080                                (int) x,
1081                                baseline - hgh - 1, wid+1, hgh+1);
1082                 if (figure && figure->data) {
1083                   if (figure->data->broken)  msg = _("[render error]");
1084                   else if (figure->data->reading) msg = _("[rendering ... ]");
1085                 } else 
1086                   if (fname.empty()) msg = _("[no file]");
1087                   else if ((flags & 3) == 0) msg = _("[not displayed]");
1088                   else if (lyxrc->ps_command.empty()) msg = _("[no ghostscript]");
1089
1090                 if (!msg) msg = _("[unknown error]");
1091                 
1092                 font.setFamily (LyXFont::SANS_FAMILY);
1093                 font.setSize (LyXFont::SIZE_FOOTNOTE);
1094                 LString justname = OnlyFilename (fname);
1095                 font.drawString(justname,pm,
1096                                baseline - font.maxAscent() - 4,
1097                                (int) x + 8);
1098                 font.setSize (LyXFont::SIZE_TINY);
1099                 font.drawText (msg, strlen(msg),pm,
1100                                baseline - 4,
1101                                (int) x + 8);
1102
1103         }
1104         x += Width(font);    // ?
1105 }
1106
1107
1108 void InsetFig::Write(FILE *file)
1109 {
1110         Regenerate();
1111         fprintf(file, "Figure size %d %d\n", wid, hgh);
1112         if (!fname.empty()) {
1113           LString buf1 = OnlyPath(owner->getFileName());
1114           LString fname2 = MakeRelPath(fname, buf1);
1115           fprintf(file, "file %s\n", fname2.c_str());
1116         }
1117         if (!subcaption.empty())
1118           fprintf(file, "subcaption %s\n", subcaption.c_str());
1119         if (wtype) fprintf(file, "width %d %g\n", wtype, xwid);
1120         if (htype) fprintf(file, "height %d %g\n", htype, xhgh);
1121         if (angle != 0) fprintf(file, "angle %g\n", angle);
1122         fprintf(file, "flags %d\n", flags);
1123         if (subfigure) fprintf(file, "subfigure\n");
1124 }
1125
1126
1127 void InsetFig::Read(LyXLex &lex)
1128 {
1129         LString buf;
1130         bool finished = false;
1131         
1132         while (lex.IsOK() && !finished) {
1133                 lex.next();
1134
1135                 LString const token = lex.GetString();
1136                 lyxerr.debug("Token: " + token);
1137                 
1138                 if (token.empty())
1139                         continue;
1140                 else if (token == "\\end_inset") {
1141                         finished = true;
1142                 } else if (token == "file") {
1143                         if (lex.next()) {
1144                                 buf = lex.GetString();
1145                                 LString buf1 = OnlyPath(owner->getFileName());
1146                                 fname = MakeAbsPath(buf, buf1);
1147                                 changedfname = true;
1148                         }
1149                 } else if (token == "extra") {
1150                         if (lex.next());
1151                         // kept for backwards compability. Delete in 0.13.x
1152                 } else if (token == "subcaption") {
1153                         if (lex.EatLine())
1154                                 subcaption = lex.GetString();
1155                 } else if (token == "label") {
1156                         if (lex.next());
1157                         // kept for backwards compability. Delete in 0.13.x
1158                 } else if (token == "angle") {
1159                         if (lex.next())
1160                                 angle = lex.GetFloat();
1161                 } else if (token == "size") {
1162                         if (lex.next())
1163                                 wid = lex.GetInteger();
1164                         if (lex.next())
1165                                 hgh = lex.GetInteger();
1166                 } else if (token == "flags") {
1167                         if (lex.next())
1168                                 flags = pflags = lex.GetInteger();
1169                 } else if (token == "subfigure") {
1170                         subfigure = psubfigure = true;
1171                 } else if (token == "width") {
1172                         int typ = 0;
1173                         if (lex.next())
1174                                 typ = lex.GetInteger();
1175                         if (lex.next())
1176                                 xwid = lex.GetFloat();
1177                         switch (typ) {
1178                         case DEF: wtype = DEF; break;
1179                         case CM: wtype = CM; break;
1180                         case IN: wtype = IN; break;
1181                         case PER_PAGE: wtype = PER_PAGE; break;
1182                         case PER_COL: wtype = PER_COL; break;
1183                         default:
1184                                 lyxerr.debug("Unknown type!");
1185                                 break;
1186                         }
1187                         twtype = wtype;
1188                 } else if (token == "height") {
1189                         int typ = 0;
1190                         if (lex.next())
1191                                 typ = lex.GetInteger();
1192                         if (lex.next())
1193                                 xhgh = lex.GetFloat();
1194                         switch (typ) {
1195                         case DEF: htype = DEF; break;
1196                         case CM: htype = CM; break;
1197                         case IN: htype = IN; break;
1198                         case PER_PAGE: htype = PER_PAGE; break;
1199                         default:
1200                                 lyxerr.debug("Unknown type!");
1201                                 break;
1202                         }
1203                         thtype = htype;
1204                 }
1205         }
1206         Regenerate();
1207         Recompute();
1208 }
1209
1210
1211 int InsetFig::Latex(FILE *file, signed char /* fragile*/ )
1212 {
1213         Regenerate();
1214         if (!cmd.empty()) fprintf(file, "%s ", cmd.c_str());
1215         return 0;
1216 }
1217
1218
1219 int InsetFig::Latex(LString &file, signed char /* fragile*/ )
1220 {
1221         Regenerate();
1222         file += cmd + ' ';
1223         return 0;
1224 }
1225
1226
1227 int InsetFig::Linuxdoc(LString &/*file*/)
1228 {
1229         return 0;
1230 }
1231
1232
1233 int InsetFig::DocBook(LString &file)
1234 {
1235         LString figurename=fname;
1236
1237         if(figurename.suffixIs(".eps"))
1238                 figurename=figurename.substring(0,fname.length()-5);
1239
1240         file += "@<graphic fileref=\"" + figurename + "\"></graphic>";
1241         return 0;
1242 }
1243
1244
1245 void InsetFig::Validate(LaTeXFeatures &features) const
1246 {
1247         features.graphics = true;
1248         if (subfigure) features.subfigure = true;
1249 }
1250
1251
1252 unsigned char InsetFig::Editable() const
1253 {
1254         return 1;
1255 }
1256
1257
1258 bool InsetFig::Deletable() const
1259 {
1260         return false;
1261 }
1262
1263
1264 void InsetFig::Edit(int, int)
1265 {
1266         lyxerr.debug("Editing InsetFig.");
1267         Regenerate();
1268
1269         // We should have RO-versions of the form instead.
1270         // The actual prevention of altering a readonly doc
1271         // is done in CallbackFig()
1272         if(current_view->currentBuffer()->isReadonly()) 
1273                 WarnReadonly();
1274
1275         if (!form) {
1276                 form = create_form_Figure();
1277                 fl_set_form_atclose(form->Figure, CancelCloseBoxCB, NULL);
1278                 fl_set_object_return(form->Angle,FL_RETURN_ALWAYS);
1279                 fl_set_object_return(form->Width,FL_RETURN_ALWAYS);
1280                 fl_set_object_return(form->Height,FL_RETURN_ALWAYS);
1281         }
1282         RestoreForm();
1283         if (form->Figure->visible) {
1284                 fl_raise_form(form->Figure);
1285         } else {
1286                 fl_show_form(form->Figure, FL_PLACE_MOUSE | FL_PLACE_SIZE,
1287                              FL_FULLBORDER, _("Figure"));
1288         }
1289 }
1290
1291
1292 Inset *InsetFig::Clone()
1293 {
1294         InsetFig *tmp = new InsetFig(100, 100, owner);
1295
1296         if (lyxerr.debugging()) {
1297                 fprintf(stderr, "Clone Figure: buffer:[%d], cbuffer:[xx]\n",
1298                        PTR_AS_INT(current_view->currentBuffer()));
1299         }
1300
1301         tmp->wid = wid;
1302         tmp->hgh = hgh;
1303         tmp->raw_wid = raw_wid;
1304         tmp->raw_hgh = raw_hgh;
1305         tmp->angle = angle;
1306         tmp->xwid = xwid;
1307         tmp->xhgh = xhgh;
1308         tmp->flags = flags;
1309         tmp->pflags = pflags;
1310         tmp->subfigure = subfigure;
1311         tmp->psubfigure = psubfigure;
1312         tmp->wtype = wtype;
1313         tmp->htype = htype;
1314         tmp->psx = psx;
1315         tmp->psy = psy;
1316         tmp->pswid = pswid;
1317         tmp->pshgh = pshgh;
1318         tmp->fname = fname;
1319         if (!fname.empty() && (flags & 3) && !lyxrc->ps_command.empty()) { 
1320           // do not display if there is "do not display" chosen (Matthias 260696)
1321                 tmp->figure->data = getfigdata(wid, hgh, fname, psx, psy,
1322                                                pswid, pshgh, raw_wid, raw_hgh,
1323                                                angle, flags & (3|8));
1324         } else tmp->figure->data = NULL;
1325         tmp->subcaption = subcaption;
1326         tmp->changedfname = false;
1327         tmp->owner = owner;
1328         tmp->Regenerate();
1329         return tmp;
1330 }
1331
1332
1333 Inset::Code InsetFig::LyxCode() const
1334 {
1335         return Inset::GRAPHICS_CODE;
1336 }
1337
1338
1339 void InsetFig::Regenerate()
1340 {
1341         LString cmdbuf;
1342         LString gcmd;
1343         LString resizeW, resizeH;
1344         LString rotate, recmd;
1345
1346         if (fname.empty()) {
1347                 cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}";
1348                 cmd += _("empty figure path");
1349                 cmd += '}';
1350                 //if (form) fl_set_object_label(form->cmd, "");
1351                 return;
1352         }
1353
1354         LString buf1 = OnlyPath(owner->getFileName());
1355         LString fname2 = MakeRelPath(fname, buf1);
1356
1357         gcmd = "\\includegraphics{" + fname2 + '}';
1358         
1359         switch (wtype) {
1360         case DEF:
1361                 break;
1362         case CM:{// \resizebox*{h-length}{v-length}{text}
1363                 char buf[10];
1364                 sprintf(buf, "%g", xwid); // should find better
1365                 resizeW = buf;
1366                 resizeW += "cm";
1367                 break;
1368         }
1369         case IN: {
1370                 char buf[10];
1371                 sprintf(buf, "%g", xwid);
1372                 resizeW = buf;
1373                 resizeW += "in";
1374                 break;
1375         }
1376         case PER_PAGE:{
1377                 char buf[10];
1378                 sprintf(buf, "%g", xwid/100);
1379                 resizeW = buf;
1380                 resizeW += "\\textwidth";
1381                 break;
1382         }
1383         case PER_COL:{
1384                 char buf[10];
1385                 sprintf(buf, "%g", xwid/100);
1386                 resizeW = buf;
1387                 resizeW += "\\columnwidth";
1388                 break;
1389         }
1390         }
1391
1392         switch (htype) {
1393         case DEF:
1394                 break;
1395         case CM: {
1396                 char buf[10];
1397                 sprintf(buf, "%g", xhgh);
1398                 resizeH = buf;
1399                 resizeH += "cm";
1400                 break;
1401         }
1402         case IN:{
1403                 char buf[10];
1404                 sprintf(buf, "%g", xhgh);
1405                 resizeH = buf;
1406                 resizeH += "in";
1407                 break;
1408         }
1409         case PER_PAGE: {
1410                 char buf[10];
1411                 sprintf(buf, "%g", xhgh/100);
1412                 resizeH = buf;
1413                 resizeH += "\\textheight";
1414                 break;
1415         }
1416         case PER_COL: {
1417                 // Doesn't occur; case exists to suppress compiler warnings.
1418                 break;
1419         }
1420         }
1421
1422         if (!resizeW.empty() || !resizeH.empty()) {
1423                 recmd = "\\resizebox*{";
1424                 if (!resizeW.empty())
1425                         recmd += resizeW;
1426                 else
1427                         recmd += '!';
1428                 recmd += "}{";
1429                 if (!resizeH.empty())
1430                         recmd += resizeH;
1431                 else
1432                         recmd += '!';
1433                 recmd += "}{";
1434         }
1435         
1436         
1437         if (angle != 0) {
1438                 char buf[10];
1439                 sprintf(buf, "%g", angle);
1440                 // \rotatebox{angle}{text}
1441                 rotate = "\\rotatebox{";
1442                 rotate += buf;
1443                 rotate += "}{";
1444         }
1445
1446         cmdbuf = recmd;
1447         cmdbuf += rotate;
1448         cmdbuf += gcmd;
1449         if (!rotate.empty()) cmdbuf += '}';
1450         if (!recmd.empty()) cmdbuf += '}';
1451         if (subfigure) {
1452                 if (!subcaption.empty())
1453                         cmdbuf = "\\subfigure[" + subcaption +
1454                           "]{" + cmdbuf + "}";
1455                 else
1456                         cmdbuf = "\\subfigure{" + cmdbuf + "}";
1457         }
1458         
1459         cmd = cmdbuf;
1460
1461         //if (form) fl_set_object_label(form->cmd, cmd.c_str());
1462 }
1463
1464
1465 void InsetFig::TempRegenerate()
1466 {
1467         LString gcmd;
1468         LString cmdbuf;
1469         LString resizeW, resizeH;
1470         LString rotate, recmd;
1471         LString tsubcap;
1472         
1473         char const *tfname; // *textra;
1474         float tangle, txwid, txhgh;
1475
1476         tfname = fl_get_input(form->EpsFile);
1477         tsubcap = fl_get_input(form->Subcaption);
1478         tangle = atof(fl_get_input(form->Angle));
1479         txwid = atof(fl_get_input(form->Width));
1480         txhgh = atof(fl_get_input(form->Height));
1481
1482         if (!tfname || !*tfname) {
1483                 //fl_set_object_label(form->cmd, "");
1484                 //fl_redraw_object(form->cmd);
1485                 cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}";
1486                 cmd += _("empty figure path");
1487                 cmd += '}';
1488                 return;
1489         }
1490
1491         LString buf1 = OnlyPath(owner->getFileName());
1492         LString fname2 = MakeRelPath(tfname, buf1);
1493         // \includegraphics*[<llx,lly>][<urx,ury>]{file}
1494         gcmd = "\\includegraphics{" + fname2 + '}';
1495         
1496         switch (twtype) {
1497         case DEF:
1498                 break;
1499         case CM: {// \resizebox*{h-length}{v-length}{text}
1500                 char buf[10];
1501                 sprintf(buf, "%g", txwid); // should find better
1502                 resizeW = buf;
1503                 resizeW += "cm";
1504                 break;
1505         }
1506         case IN: {
1507                 char buf[10];
1508                 sprintf(buf, "%g", txwid);
1509                 resizeW = buf;
1510                 resizeW += "in";
1511                 break;
1512         }
1513         case PER_PAGE: {
1514                 char buf[10];
1515                 sprintf(buf, "%g", txwid/100);
1516                 resizeW = buf;
1517                 resizeW += "\\textwidth";
1518                 break;
1519         }
1520         case PER_COL: {
1521                 char buf[10];
1522                 sprintf(buf, "%g", txwid/100);
1523                 resizeW = buf;
1524                 resizeW += "\\columnwidth";
1525                 break;
1526         }
1527         }
1528
1529         switch (thtype) {
1530         case DEF:
1531                 break;
1532         case CM: {
1533                 char buf[10];
1534                 sprintf(buf, "%g", txhgh);
1535                 resizeH = buf;
1536                 resizeH += "cm";
1537                 break;
1538         }
1539         case IN: {
1540                 char buf[10];
1541                 sprintf(buf, "%g", txhgh);
1542                 resizeH = buf;
1543                 resizeH += "in";
1544                 break;
1545         }
1546         case PER_PAGE: {
1547                 char buf[10];
1548                 sprintf(buf, "%g", txhgh/100);
1549                 resizeH = buf;
1550                 resizeH += "\\textheight";
1551                 break;
1552         }
1553         case PER_COL: {
1554                 // Doesn't occur; case exists to suppress compiler warnings.
1555                 break;
1556         }
1557         }
1558
1559         // \resizebox*{h-length}{v-length}{text}
1560         if (!resizeW.empty() || !resizeH.empty()) {
1561                 recmd = "\\resizebox*{";
1562                 if (!resizeW.empty())
1563                         recmd += resizeW;
1564                 else
1565                         recmd += '!';
1566                 recmd += "}{";
1567                 if (!resizeH.empty())
1568                         recmd += resizeH;
1569                 else
1570                         recmd += '!';
1571                 recmd += "}{";
1572         }
1573         
1574         if (tangle != 0) {
1575                 char buf[10];
1576                 sprintf(buf, "%g", tangle);
1577                 // \rotatebox{angle}{text}
1578                 rotate = "\\rotatebox{";
1579                 rotate += buf;
1580                 rotate += "}{";
1581         }
1582
1583         cmdbuf = recmd;
1584         cmdbuf += rotate;
1585         cmdbuf += gcmd;
1586         if (!rotate.empty()) cmdbuf += '}';
1587         if (!recmd.empty()) cmdbuf += '}';
1588         if (psubfigure && !tsubcap.empty()) {
1589                 cmdbuf = LString("\\subfigure{") + tsubcap
1590                   + LString("}{") + cmdbuf + "}";
1591         }
1592
1593         
1594         //fl_set_object_label(form->cmd, cmdbuf.c_str());
1595         //fl_redraw_object(form->cmd);
1596 }
1597
1598
1599 void InsetFig::Recompute()
1600 {
1601         bool changed = changedfname;
1602         int newx, newy, nraw_x, nraw_y, frame_wid, frame_hgh;
1603         float sin_a, cos_a;
1604
1605         if (changed) GetPSSizes();
1606
1607         sin_a = sin (angle / DEG2PI);        /* rotation; H. Zeller 021296 */
1608         cos_a = cos (angle / DEG2PI);
1609         frame_wid = (int) ceil (fabs(cos_a * pswid) + fabs(sin_a * pshgh));
1610         frame_hgh= (int) ceil (fabs(cos_a * pshgh) + fabs(sin_a * pswid));
1611
1612         /* now recompute wid and hgh, and if that is changed, set changed */
1613         /* this depends on chosen size of the picture and its bbox */
1614         // This will be redone in 0.13 ... (hen)
1615         if (!fname.empty()) {
1616                 // say, total width is 595 pts, as A4 in TeX, thats in 1/72" */
1617
1618                 newx = frame_wid;
1619                 newy = frame_hgh;
1620                 switch (wtype) {
1621                 case DEF:
1622                         break;
1623                 case CM:        /* cm */
1624                         newx = (int) (28.346*xwid);
1625                         break;
1626                 case IN: /* in */
1627                         newx = (int) (72*xwid);
1628                         break;
1629                 case PER_PAGE:  /* % of page */
1630                         newx = (int) (5.95*xwid);
1631                         break;
1632                 case PER_COL:   /* % of col */
1633                         newx = (int) (2.975*xwid);
1634                         break;
1635                 }
1636                 
1637                 if (wtype && frame_wid) newy = newx*frame_hgh/frame_wid;
1638                 
1639                 switch (htype) {
1640                 case DEF:
1641                         //fprintf(stderr, "This should not happen!\n");
1642                         break;
1643                 case CM:        /* cm */
1644                         newy = (int) (28.346*xhgh);
1645                         break;
1646                 case IN: /* in */
1647                         newy = (int) (72*xhgh);
1648                         break;
1649                 case PER_PAGE:  /* % of page */
1650                         newy = (int) (8.42*xhgh);
1651                         break;
1652                 case PER_COL: 
1653                         // Doesn't occur; case exists to suppress
1654                         // compiler warnings.  
1655                         break;
1656                 }
1657                 if (htype && !wtype && frame_hgh) newx = newy*frame_wid/frame_hgh;
1658         } else {
1659                 newx = wid;
1660                 newy = hgh;
1661         }
1662
1663         if (frame_wid == 0)
1664                 nraw_x = 5;
1665         else
1666                 nraw_x = (int) ((1.0 * pswid * newx)/frame_wid);
1667
1668         if (frame_hgh == 0)
1669                 nraw_y = 5;
1670         else
1671                 nraw_y = (int) ((1.0 * pshgh * newy)/frame_hgh);
1672
1673         // cannot be zero, actually, set it to some minimum, so its clickable
1674         if (newx < 5) newx = 5;
1675         if (newy < 5) newy = 5;
1676
1677         if (newx   != wid     || newy   != hgh     || 
1678             nraw_x != raw_wid || nraw_y != raw_hgh ||
1679             flags  != pflags  || subfigure != psubfigure) 
1680                 changed = true;
1681        
1682         raw_wid = nraw_x;
1683         raw_hgh = nraw_y;
1684         wid = newx;
1685         hgh = newy;
1686         flags = pflags;
1687         subfigure = psubfigure;
1688
1689         if (changed) {
1690                 figdata *pf = figure->data;
1691
1692                 // get new data
1693                 if (!fname.empty() && (flags & 3) && !lyxrc->ps_command.empty()) {
1694                         // do not display if there is "do not display"
1695                         // chosen (Matthias 260696)
1696                         figure->data = getfigdata(wid, hgh, fname,
1697                                                   psx, psy, pswid, pshgh,
1698                                                   raw_wid, raw_hgh,
1699                                                   angle, flags & (3|8));
1700                 } else figure->data = NULL;
1701
1702                 // free the old data
1703                 if (pf) freefigdata(pf);
1704         }
1705
1706         changedfname = false;
1707 }
1708
1709
1710 void InsetFig::GetPSSizes()
1711 {
1712         /* get %%BoundingBox: from postscript file */
1713         int lastchar, c;
1714         char *p = NULL;
1715         
1716         /* defaults to associated size
1717          * ..just in case the PS-file is not readable (Henner,24-Aug-97) 
1718          */
1719         psx = 0;
1720         psy = 0;
1721         pswid = wid;
1722         pshgh = hgh;
1723
1724         if (fname.empty()) return;
1725         
1726         FilePtr f(fname, FilePtr::read);
1727
1728         if (!f()) return;       // file not found !!!!
1729
1730         /* defaults to A4 page */
1731         psx = 0;
1732         psy = 0;
1733         pswid = 595;
1734         pshgh = 842;
1735
1736         lastchar = fgetc(f);
1737         for (;;) {
1738                 c = fgetc(f);
1739                 if (c == EOF) {
1740                         lyxerr.debug("End of (E)PS file reached and"
1741                                       " no BoundingBox!");
1742                         break;
1743                 }
1744                 if (c == '%' && lastchar == '%') {
1745                         p = NextToken(f);
1746                         if (!p) break;
1747                         if (strcmp(p, "EndComments") == 0) break;
1748                         if (strcmp(p, "BoundingBox:") == 0) {
1749                                 float fpsx, fpsy, fpswid, fpshgh;
1750                                 if (fscanf(f, "%f %f %f %f", &fpsx, &fpsy,
1751                                            &fpswid, &fpshgh) == 4) {
1752                                         psx = (int) fpsx;
1753                                         psy = (int) fpsy;
1754                                         pswid = (int) fpswid;
1755                                         pshgh = (int) fpshgh;
1756                                 } 
1757
1758                                 if (lyxerr.debugging()) {
1759                                         fprintf(stderr, "%%%%BoundingBox:"
1760                                                 " %d %d %d %d\n",
1761                                                 psx, psy, pswid, pshgh);
1762                                         break;
1763                                 }
1764                         }
1765                         c = 0;
1766                         delete[] p;
1767                         p = NULL;
1768                 }
1769                 lastchar = c;
1770         }
1771         if (p) delete[] p;
1772         pswid -= psx;
1773         pshgh -= psy;
1774
1775 }
1776
1777
1778 void InsetFig::CallbackFig(long arg)
1779 {
1780         bool regen = false;
1781         char const *p;
1782
1783         if (lyxerr.debugging()) {
1784                 printf("Figure callback, arg %ld\n", arg);
1785         }
1786
1787         switch (arg) {
1788         case 10:
1789         case 11:
1790         case 12:        /* width type */
1791         case 13:
1792         case 14:
1793                 switch (arg - 10) {
1794                 case DEF:
1795                         twtype = DEF;
1796                         // put disable here
1797                         fl_deactivate_object(form->Width);
1798                         break;
1799                 case CM:
1800                         twtype = CM;
1801                         // put enable here
1802                         fl_activate_object(form->Width);
1803                         break;
1804                 case IN:
1805                         twtype = IN;
1806                         // put enable here
1807                         fl_activate_object(form->Width);
1808                         break;
1809                 case PER_PAGE:
1810                         twtype = PER_PAGE;
1811                         // put enable here
1812                         fl_activate_object(form->Width);
1813                         break;
1814                 case PER_COL:
1815                         twtype = PER_COL;
1816                         // put enable here
1817                         fl_activate_object(form->Width);
1818                         break;
1819                 default:
1820                         lyxerr.debug("Unknown type!");
1821                         break;
1822                 }
1823                 regen = true;
1824                 break;
1825         case 20:
1826         case 21:
1827         case 22:        /* height type */
1828         case 23:
1829                 switch (arg - 20) {
1830                 case DEF:
1831                         thtype = DEF;
1832                         // put disable here
1833                         fl_deactivate_object(form->Height);
1834                         break;
1835                 case CM:
1836                         thtype = CM;
1837                         // put enable here
1838                         fl_activate_object(form->Height);
1839                         break;
1840                 case IN:
1841                         thtype = IN;
1842                         // put enable here
1843                         fl_activate_object(form->Height);
1844                         break;
1845                 case PER_PAGE:
1846                         thtype = PER_PAGE;
1847                         // put enable here
1848                         fl_activate_object(form->Height);
1849                         break;
1850                 default:
1851                         lyxerr.debug("Unknown type!");
1852                         break;
1853                 }
1854                 regen = true;
1855                 break;
1856         case 3:
1857                 pflags = pflags & ~3;           /* wysiwyg0 */
1858                 break;
1859         case 33:
1860                 pflags = (pflags & ~3) | 1;     /* wysiwyg1 */
1861                 break;
1862         case 43:
1863                 pflags = (pflags & ~3) | 2;     /* wysiwyg2 */
1864                 break;
1865         case 63:
1866                 pflags = (pflags & ~3) | 3;     /* wysiwyg3 */
1867                 break;
1868         case 53:
1869                 pflags ^= 4;    /* frame */
1870                 break;
1871         case 54:
1872                 pflags ^= 8;    /* do translations */
1873                 break;
1874         case 70:
1875                 psubfigure = !psubfigure;       /* This is a subfigure */
1876                 break;
1877         case 2:
1878                 regen = true;           /* regenerate command */
1879                 break;
1880         case 0:                         /* browse file */
1881                 BrowseFile();
1882                 regen = true;
1883                 break;
1884         case 1:                         /* preview */
1885                 p = fl_get_input(form->EpsFile);
1886                 Preview(p);
1887                 break;
1888         case 7:                         /* apply */
1889         case 8:                         /* ok (apply and close) */
1890                 if(!current_view->currentBuffer()->isReadonly())
1891                 {
1892                         wtype = twtype;
1893                         htype = thtype;
1894                         xwid = atof(fl_get_input(form->Width));
1895                         xhgh = atof(fl_get_input(form->Height));
1896                         angle = atof(fl_get_input(form->Angle));
1897                         p = fl_get_input(form->EpsFile);
1898                         if (p && *p) {
1899                                 LString buf1 = OnlyPath(owner->getFileName());
1900                                 fname = MakeAbsPath(p, buf1);
1901                                 changedfname = true;
1902                         } else {
1903                                 if (!fname.empty()) {
1904                                         changedfname = true;
1905                                         fname.clean();
1906                                 }
1907                         }
1908                         subcaption = fl_get_input(form->Subcaption);
1909         
1910                         Regenerate();
1911                         Recompute();
1912                         /* now update inset */
1913                         if (lyxerr.debugging()) {
1914                                 fprintf(stderr, "Update: [%dx%d]\n", wid, hgh);
1915                         }
1916                         UpdateInset(this);
1917                         if (arg == 8) {
1918                                 fl_hide_form(form->Figure);
1919                                 fl_free_form(form->Figure);
1920                                 free(form);
1921                                 form = NULL;
1922                         }
1923                         break;
1924                 } //if not readonly
1925                 //  The user has already been informed about RO in ::Edit
1926                 if(arg == 7) // if 'Apply'
1927                         break;
1928                 // fall through
1929         case 9:                         /* cancel = restore and close */
1930                 fl_hide_form(form->Figure);
1931                 fl_free_form(form->Figure);
1932                 free(form);
1933                 form = NULL;
1934                 break;
1935         }
1936
1937         if (regen) TempRegenerate();
1938 }
1939
1940 inline void DisableFigurePanel(FD_Figure * const form)
1941 {
1942         fl_deactivate_object(form->EpsFile);
1943         fl_deactivate_object(form->Browse);
1944         fl_deactivate_object(form->Width);
1945         fl_deactivate_object(form->Height);
1946         fl_deactivate_object(form->Frame);
1947         fl_deactivate_object(form->Translations);
1948         fl_deactivate_object(form->Angle);
1949         fl_deactivate_object(form->HeightGrp);
1950         fl_deactivate_object(form->page2);
1951         fl_deactivate_object(form->Default2);
1952         fl_deactivate_object(form->cm2);
1953         fl_deactivate_object(form->in2);
1954         fl_deactivate_object(form->HeightLabel);
1955         fl_deactivate_object(form->WidthLabel);
1956         fl_deactivate_object(form->DisplayGrp);
1957         fl_deactivate_object(form->Wysiwyg3);
1958         fl_deactivate_object(form->Wysiwyg0);
1959         fl_deactivate_object(form->Wysiwyg2);
1960         fl_deactivate_object(form->Wysiwyg1);
1961         fl_deactivate_object(form->WidthGrp);
1962         fl_deactivate_object(form->Default1);
1963         fl_deactivate_object(form->cm1);
1964         fl_deactivate_object(form->in1);
1965         fl_deactivate_object(form->page1);
1966         fl_deactivate_object(form->column1);
1967         fl_deactivate_object(form->Subcaption);
1968         fl_deactivate_object(form->Subfigure);
1969         fl_deactivate_object (form->OkBtn);
1970         fl_deactivate_object (form->ApplyBtn);
1971         fl_set_object_lcol (form->OkBtn, FL_INACTIVE);
1972         fl_set_object_lcol (form->ApplyBtn, FL_INACTIVE);
1973 }
1974
1975 inline void EnableFigurePanel(FD_Figure * const form)
1976 {
1977         fl_activate_object(form->EpsFile);
1978         fl_activate_object(form->Browse);
1979         fl_activate_object(form->Width);
1980         fl_activate_object(form->Height);
1981         fl_activate_object(form->Frame);
1982         fl_activate_object(form->Translations);
1983         fl_activate_object(form->Angle);
1984         fl_activate_object(form->HeightGrp);
1985         fl_activate_object(form->page2);
1986         fl_activate_object(form->Default2);
1987         fl_activate_object(form->cm2);
1988         fl_activate_object(form->in2);
1989         fl_activate_object(form->HeightLabel);
1990         fl_activate_object(form->WidthLabel);
1991         fl_activate_object(form->DisplayGrp);
1992         fl_activate_object(form->Wysiwyg3);
1993         fl_activate_object(form->Wysiwyg0);
1994         fl_activate_object(form->Wysiwyg2);
1995         fl_activate_object(form->Wysiwyg1);
1996         fl_activate_object(form->WidthGrp);
1997         fl_activate_object(form->Default1);
1998         fl_activate_object(form->cm1);
1999         fl_activate_object(form->in1);
2000         fl_activate_object(form->page1);
2001         fl_activate_object(form->column1);
2002         fl_activate_object(form->Subcaption);
2003         fl_activate_object(form->Subfigure);
2004         fl_activate_object (form->OkBtn);
2005         fl_activate_object (form->ApplyBtn);
2006         fl_set_object_lcol (form->OkBtn, FL_BLACK);
2007         fl_set_object_lcol (form->ApplyBtn, FL_BLACK);
2008 }
2009
2010 void InsetFig::RestoreForm()
2011 {
2012         char buf[32];
2013         int pflags;
2014
2015         EnableFigurePanel(form);
2016
2017         twtype = wtype;
2018         fl_set_button(form->Default1, (wtype == 0));
2019         fl_set_button(form->cm1, (wtype == 1));
2020         fl_set_button(form->in1, (wtype == 2));
2021         fl_set_button(form->page1, (wtype == 3));
2022         fl_set_button(form->column1, (wtype == 4));
2023         if (wtype == 0) {
2024                 fl_deactivate_object(form->Width);
2025         } else {
2026                 fl_activate_object(form->Width);
2027         }
2028                 
2029         // enable and disable should be put here.
2030         thtype = htype;
2031         fl_set_button(form->Default2, (htype == 0));
2032         fl_set_button(form->cm2, (htype == 1));
2033         fl_set_button(form->in2, (htype == 2));
2034         fl_set_button(form->page2, (htype == 3));
2035         // enable and disable should be put here.
2036         if (htype == 0) {
2037                 fl_deactivate_object(form->Height);
2038         } else {
2039                 fl_activate_object(form->Height);
2040         }
2041
2042         pflags = flags & 3;
2043         fl_set_button(form->Wysiwyg0, (pflags == 0));
2044         fl_set_button(form->Wysiwyg1, (pflags == 1));
2045         fl_set_button(form->Wysiwyg2, (pflags == 2));
2046         fl_set_button(form->Wysiwyg3, (pflags == 3));
2047         fl_set_button(form->Frame, ((flags & 4) != 0));
2048         fl_set_button(form->Translations, ((flags & 8) != 0));
2049         fl_set_button(form->Subfigure, (subfigure != 0));
2050         pflags = flags;
2051         psubfigure = subfigure;
2052         sprintf(buf, "%g", xwid);
2053         fl_set_input(form->Width, buf);
2054         sprintf(buf, "%g", xhgh);
2055         fl_set_input(form->Height, buf);
2056         sprintf(buf, "%g", angle);
2057         fl_set_input(form->Angle, buf);
2058         if (!fname.empty()){
2059                 LString buf1 = OnlyPath(owner->getFileName());
2060                 LString fname2 = MakeRelPath(fname, buf1);
2061                 fl_set_input(form->EpsFile, fname2.c_str());
2062         }
2063         else fl_set_input(form->EpsFile, "");
2064         fl_set_input(form->Subcaption, subcaption.c_str());
2065         if(current_view->currentBuffer()->isReadonly()) 
2066                 DisableFigurePanel(form);
2067
2068         TempRegenerate();
2069 }
2070
2071
2072 void InsetFig::Preview(char const *p)
2073 {
2074         int pid;
2075
2076         pid = fork();
2077
2078         if (pid == -1) {
2079                 lyxerr.print("Cannot fork process!");
2080                 return;         // error
2081         }
2082         if (pid > 0) {
2083                 addpidwait(pid);
2084                 return;         // parent process
2085         }
2086
2087         LString buf1 = OnlyPath(owner->getFileName());
2088         LString buf2 = MakeAbsPath(p, buf1);
2089         
2090         lyxerr.print(LString("Error during rendering ") +
2091                       int(execlp(lyxrc->view_pspic_command.c_str(),
2092                                  lyxrc->view_pspic_command.c_str(),
2093                                  buf2.c_str(), 
2094                                  NULL)));
2095         _exit(0);
2096 }
2097
2098
2099 void InsetFig::BrowseFile()
2100 {
2101         LString buf, buf2, bufclip;
2102         static LString current_figure_path;
2103         static int once = 0;
2104         LyXFileDlg fileDlg;
2105
2106         if (lyxerr.debugging()) {
2107                 fprintf(stderr, "Filename: %s\n", owner->getFileName().c_str());
2108         }
2109         LString p = fl_get_input(form->EpsFile);
2110
2111         buf = MakeAbsPath(owner->getFileName());
2112         buf2 = OnlyPath(buf);
2113         if (!p.empty()) {
2114                 buf = MakeAbsPath(p, buf2);
2115                 buf = OnlyPath(buf);
2116         } else {
2117           buf = OnlyPath(owner->getFileName().c_str());
2118         }
2119         
2120         // Does user clipart directory exist?
2121         bufclip = AddName (user_lyxdir, "clipart");     
2122         FileInfo fileInfo(bufclip);
2123         if (!(fileInfo.isOK() && fileInfo.isDir()))
2124           // No - bail out to system clipart directory
2125           bufclip = AddName (system_lyxdir, "clipart"); 
2126
2127
2128         fileDlg.SetButton(0, _("Clipart"), bufclip); 
2129         fileDlg.SetButton(1, _("Document"), buf); 
2130
2131         bool error = false;
2132         do {
2133                 ProhibitInput();
2134                 if (once) {
2135                         p =fileDlg.Select(_("EPS Figure"), current_figure_path,
2136                                            "*ps", LString());
2137                 } else {
2138                         p = fileDlg.Select(_("EPS Figure"), buf,
2139                                            "*ps", LString());
2140                 }
2141                 AllowInput();
2142
2143                 if (p.empty()) return;
2144
2145                 buf = MakeRelPath(p, buf2);
2146                 current_figure_path = OnlyPath(p);
2147                 once = 1;
2148                 
2149                 if (p.contains("#") || p.contains("~") || p.contains("$")
2150                     || p.contains("%") || p.contains(" ")) 
2151                 {
2152                         WriteAlert(_("Filename can't contain any of these characters:"), // xgettext:no-c-format
2153                                    _("space, '#', '~', '$' or '%'.")); 
2154                         error = true;
2155                 }
2156         } while (error);
2157
2158         if (form) fl_set_input(form->EpsFile, buf.c_str());
2159 }
2160
2161
2162 void GraphicsCB(FL_OBJECT *obj, long arg)
2163 {
2164         /* obj->form contains the form */
2165
2166         if (lyxerr.debugging()) {
2167                 lyxerr.print(LString("GraphicsCB callback: ") + long(arg));
2168         }
2169
2170         /* find inset we were reacting to */
2171         for (int i = 0; i < figinsref; ++i)
2172                 if (figures[i]->inset->form && figures[i]->inset->form->Figure
2173                     == obj->form) {
2174             
2175                         if (lyxerr.debugging()) {
2176                                 lyxerr.print(LString("Calling back figure ")
2177                                              +int(i));
2178                         }
2179                         figures[i]->inset->CallbackFig(arg);
2180                         return;
2181                 }
2182 }
2183
2184
2185 void HideFiguresPopups()
2186 {
2187         for (int i = 0; i < figinsref; ++i)
2188                 if (figures[i]->inset->form 
2189                     && figures[i]->inset->form->Figure->visible) {
2190                         if (lyxerr.debugging()) {
2191                                 lyxerr.print(LString("Hiding figure ")
2192                                              +int(i));
2193                         }
2194                         // hide and free the form
2195                         figures[i]->inset->CallbackFig(9);
2196                 }
2197 }