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