plug-in-message.c 47.1 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

Elliot Lee's avatar
Elliot Lee committed
19
#include "config.h"
Tor Lillqvist's avatar
Tor Lillqvist committed
20

Manish Singh's avatar
Manish Singh committed
21
22
23
24
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

25
#include <gtk/gtk.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
26

Elliot Lee's avatar
Elliot Lee committed
27
28
29
#include <signal.h>
#include <stdlib.h>
#include <string.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
30
#ifdef HAVE_SYS_WAIT_H
Elliot Lee's avatar
Elliot Lee committed
31
#include <sys/wait.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
32
33
#endif
#ifdef HAVE_SYS_TIME_H
Elliot Lee's avatar
Elliot Lee committed
34
#include <sys/time.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
35
#endif
36

Elliot Lee's avatar
Elliot Lee committed
37
#include <time.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
38
#ifdef HAVE_UNISTD_H
Elliot Lee's avatar
Elliot Lee committed
39
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
40
41
#endif

Manish Singh's avatar
Manish Singh committed
42
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
43
44
45
46
#define STRICT
#include <windows.h>
#include <process.h>

47
#ifdef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
48
49
50
51
#include <fcntl.h>
#include <io.h>
#endif

Manish Singh's avatar
Manish Singh committed
52
#ifdef G_WITH_CYGWIN
Tor Lillqvist's avatar
Tor Lillqvist committed
53
54
55
56
57
58
59
60
#define O_TEXT		0x0100	/* text file */
#define _O_TEXT		0x0100	/* text file */
#define O_BINARY	0x0200	/* binary file */
#define _O_BINARY	0x0200	/* binary file */
#endif

#endif

Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
61
62
63
64
65
66
67
#ifdef __EMX__
#include <fcntl.h>
#include <process.h>
#define _O_BINARY O_BINARY
#define _P_NOWAIT P_NOWAIT
#endif

68
69
70
71
72
73
74
75
#ifdef HAVE_IPC_H
#include <sys/ipc.h>
#endif

#ifdef HAVE_SHM_H
#include <sys/shm.h>
#endif

76
77
78
#include "libgimpbase/gimpbase.h"
#include "libgimpbase/gimpprotocol.h"
#include "libgimpbase/gimpwire.h"
79

Michael Natterer's avatar
Michael Natterer committed
80
#include "plug-in-types.h"
81

Michael Natterer's avatar
Michael Natterer committed
82
83
84
#include "base/tile.h"
#include "base/tile-manager.h"

85
86
#include "config/gimpcoreconfig.h"

87
#include "core/gimp.h"
88
#include "core/gimpcontext.h"
89
#include "core/gimpdrawable.h"
90
#include "core/gimpenvirontable.h"
91
#include "core/gimpimage.h"
92

93
#include "gui/plug-in-menus.h"
94
95
#include "gui/brush-select.h"
#include "gui/gradient-select.h"
96
#include "gui/palette-select.h"
97
98
#include "gui/pattern-select.h"

Michael Natterer's avatar
Michael Natterer committed
99
#include "plug-in.h"
100
101
102
#include "plug-ins.h"
#include "plug-in-def.h"
#include "plug-in-params.h"
103
#include "plug-in-proc.h"
104
#include "plug-in-progress.h"
105
#include "plug-in-rc.h"
Michael Natterer's avatar
Michael Natterer committed
106

107
#include "appenv.h"
108
#include "app_procs.h"
Elliot Lee's avatar
Elliot Lee committed
109

110
111
#include "libgimp/gimpintl.h"

112

113
typedef struct _PlugInBlocked PlugInBlocked;
Elliot Lee's avatar
Elliot Lee committed
114
115
116
117

struct _PlugInBlocked
{
  PlugIn *plug_in;
118
  gchar  *proc_name;
Elliot Lee's avatar
Elliot Lee committed
119
120
121
};


122
123
124
125
126
127
typedef struct _PlugInHelpPathDef PlugInHelpPathDef;

struct _PlugInHelpPathDef
{
  gchar *prog_name;
  gchar *help_path;
128
129
130
};


131
static gboolean plug_in_write             (GIOChannel	     *channel,
Elliot Lee's avatar
Elliot Lee committed
132
					   guint8            *buf,
133
134
135
136
				           gulong             count,
                                           gpointer           user_data);
static gboolean plug_in_flush             (GIOChannel        *channel,
                                           gpointer           user_data);
137
138
static void     plug_in_push              (PlugIn            *plug_in);
static void     plug_in_pop               (void);
Tor Lillqvist's avatar
Tor Lillqvist committed
139
140
141
static gboolean plug_in_recv_message	  (GIOChannel	     *channel,
					   GIOCondition	      cond,
					   gpointer	      data);
142
143
144
145
146
static void plug_in_handle_message        (PlugIn            *plug_in,
                                           WireMessage       *msg);
static void plug_in_handle_quit           (PlugIn            *plug_in);
static void plug_in_handle_tile_req       (PlugIn            *plug_in,
                                           GPTileReq         *tile_req);
147
static void plug_in_handle_proc_run       (PlugIn            *plug_in,
148
                                           GPProcRun         *proc_run);
149
static void plug_in_handle_proc_return    (PlugIn            *plug_in,
150
                                           GPProcReturn      *proc_return);
151
static void plug_in_handle_proc_install   (PlugIn            *plug_in,
152
                                           GPProcInstall     *proc_install);
153
static void plug_in_handle_proc_uninstall (PlugIn            *plug_in,
154
                                           GPProcUninstall   *proc_uninstall);
Michael Natterer's avatar
Michael Natterer committed
155
static void plug_in_handle_extension_ack  (PlugIn            *plug_in);
156
static void plug_in_handle_has_init       (PlugIn            *plug_in);
Elliot Lee's avatar
Elliot Lee committed
157

158
159
160
static Argument * plug_in_temp_run       (ProcRecord         *proc_rec,
					  Argument           *args,
					  gint                argc);
161
162
static void       plug_in_init_shm       (void);

163
164
165
166
static gchar    * plug_in_search_in_path (gchar              *search_path,
					  gchar              *filename);

static void       plug_in_prep_for_exec  (gpointer            data);
167

168

169
170
PlugIn     *current_plug_in    = NULL;
ProcRecord *last_plug_in       = NULL;
Elliot Lee's avatar
Elliot Lee committed
171

172
173
static GSList     *open_plug_ins    = NULL;
static GSList     *blocked_plug_ins = NULL;
174
175
176
177

static GSList     *plug_in_stack              = NULL;
static Argument   *current_return_vals        = NULL;
static gint        current_return_nvals       = 0;
Elliot Lee's avatar
Elliot Lee committed
178

179
static gint    shm_ID   = -1;
Elliot Lee's avatar
Elliot Lee committed
180
181
static guchar *shm_addr = NULL;

Manish Singh's avatar
Manish Singh committed
182
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
183
184
185
static HANDLE shm_handle;
#endif

186
187
188
189
190
191
192
193
194
195

static void
plug_in_init_shm (void)
{
  /* allocate a piece of shared memory for use in transporting tiles
   *  to plug-ins. if we can't allocate a piece of shared memory then
   *  we'll fall back on sending the data over the pipe.
   */
  
#ifdef HAVE_SHM_H
196
197
198
199
  shm_ID = shmget (IPC_PRIVATE,
                   TILE_WIDTH * TILE_HEIGHT * 4,
                   IPC_CREAT | 0600);

200
  if (shm_ID == -1)
201
    g_message ("shmget() failed: Disabling shared memory tile transport.");
202
203
  else
    {
204
205
      shm_addr = (guchar *) shmat (shm_ID, NULL, 0);
      if (shm_addr == (guchar *) -1)
206
	{
207
	  g_message ("shmat() failed: Disabling shared memory tile transport.");
208
	  shmctl (shm_ID, IPC_RMID, NULL);
209
210
211
212
	  shm_ID = -1;
	}
      
#ifdef	IPC_RMID_DEFERRED_RELEASE
213
214
      if (shm_addr != (guchar *) -1)
	shmctl (shm_ID, IPC_RMID, NULL);
215
216
217
#endif
    }
#else
Manish Singh's avatar
Manish Singh committed
218
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
219
220
221
  /* Use Win32 shared memory mechanisms for
   * transfering tile data.
   */
222
223
224
  gint  pid;
  gchar fileMapName[MAX_PATH];
  gint  tileByteSize = TILE_WIDTH * TILE_HEIGHT * 4;
225
226
227
228
229
  
  /* Our shared memory id will be our process ID */
  pid = GetCurrentProcessId ();
  
  /* From the id, derive the file map name */
230
231
  g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", pid);

232
233
234
235
236
237
238
239
240
  /* Create the file mapping into paging space */
  shm_handle = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL,
				  PAGE_READWRITE, 0,
				  tileByteSize, fileMapName);
  
  if (shm_handle)
    {
      /* Map the shared memory into our address space for use */
      shm_addr = (guchar *) MapViewOfFile(shm_handle,
241
					  FILE_MAP_ALL_ACCESS,
242
243
244
245
246
					  0, 0, tileByteSize);
      
      /* Verify that we mapped our view */
      if (shm_addr)
	shm_ID = pid;
247
248
249
250
      else
	{
	  g_warning ("MapViewOfFile error: %d... disabling shared memory transport\n", GetLastError());
	}
251
252
253
254
255
256
257
258
259
    }
  else
    {
      g_warning ("CreateFileMapping error: %d... disabling shared memory transport\n", GetLastError());
    }
#endif
#endif
}

Elliot Lee's avatar
Elliot Lee committed
260
void
261
plug_in_init (Gimp *gimp)
Elliot Lee's avatar
Elliot Lee committed
262
{
263
264
  g_return_if_fail (GIMP_IS_GIMP (gimp));

Elliot Lee's avatar
Elliot Lee committed
265
266
267
268
269
270
271
272
273
274
275
276
  /* initialize the gimp protocol library and set the read and
   *  write handlers.
   */
  gp_init ();
  wire_set_writer (plug_in_write);
  wire_set_flusher (plug_in_flush);

  /* allocate a piece of shared memory for use in transporting tiles
   *  to plug-ins. if we can't allocate a piece of shared memory then
   *  we'll fall back on sending the data over the pipe.
   */
  if (use_shm)
277
    plug_in_init_shm ();
Elliot Lee's avatar
Elliot Lee committed
278
279
280
}

void
281
plug_in_kill (Gimp *gimp)
Elliot Lee's avatar
Elliot Lee committed
282
283
284
285
{
  GSList *tmp;
  PlugIn *plug_in;
  
Manish Singh's avatar
Manish Singh committed
286
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
287
288
  CloseHandle (shm_handle);
#else
289
#ifdef HAVE_SHM_H
Elliot Lee's avatar
Elliot Lee committed
290
291
292
#ifndef	IPC_RMID_DEFERRED_RELEASE
  if (shm_ID != -1)
    {
293
294
      shmdt ((gchar *) shm_addr);
      shmctl (shm_ID, IPC_RMID, NULL);
Elliot Lee's avatar
Elliot Lee committed
295
296
297
    }
#else	/* IPC_RMID_DEFERRED_RELEASE */
  if (shm_ID != -1)
298
    shmdt ((gchar *) shm_addr);
Elliot Lee's avatar
Elliot Lee committed
299
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
300
#endif
301
302
#endif
 
Elliot Lee's avatar
Elliot Lee committed
303
304
305
306
307
308
309
310
311
312
313
  tmp = open_plug_ins;
  while (tmp)
    {
      plug_in = tmp->data;
      tmp = tmp->next;

      plug_in_destroy (plug_in);
    }
}

void
314
315
plug_in_call_query (Gimp      *gimp,
                    PlugInDef *plug_in_def)
Elliot Lee's avatar
Elliot Lee committed
316
{
317
318
  PlugIn      *plug_in;
  WireMessage  msg;
Sven Neumann's avatar
Sven Neumann committed
319

320
  plug_in = plug_in_new (gimp, plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
321

322
  if (plug_in)
Elliot Lee's avatar
Elliot Lee committed
323
    {
324
325
326
      plug_in->query       = TRUE;
      plug_in->synchronous = TRUE;
      plug_in->user_data   = plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
327

328
      if (plug_in_open (plug_in))
Elliot Lee's avatar
Elliot Lee committed
329
	{
330
	  plug_in_push (plug_in);
Elliot Lee's avatar
Elliot Lee committed
331

332
	  while (plug_in->open)
Elliot Lee's avatar
Elliot Lee committed
333
	    {
334
	      if (! wire_read_msg (plug_in->my_read, &msg, plug_in))
335
                {
336
                  plug_in_close (plug_in, TRUE);
337
338
339
                }
	      else 
		{
340
		  plug_in_handle_message (plug_in, &msg);
341
342
		  wire_destroy (&msg);
		}
Elliot Lee's avatar
Elliot Lee committed
343
344
	    }

345
346
	  plug_in_pop ();
	  plug_in_destroy (plug_in);
Elliot Lee's avatar
Elliot Lee committed
347
348
	}
    }
349
}
350

Elliot Lee's avatar
Elliot Lee committed
351
void
352
353
plug_in_call_init (Gimp      *gimp,
                   PlugInDef *plug_in_def)
Elliot Lee's avatar
Elliot Lee committed
354
{
355
356
  PlugIn      *plug_in;
  WireMessage  msg;
Elliot Lee's avatar
Elliot Lee committed
357

358
  plug_in = plug_in_new (gimp, plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
359

360
  if (plug_in)
361
    {
362
363
364
      plug_in->init        = TRUE;
      plug_in->synchronous = TRUE;
      plug_in->user_data   = plug_in_def;
365

366
      if (plug_in_open (plug_in))
367
	{
368
	  plug_in_push (plug_in);
Elliot Lee's avatar
Elliot Lee committed
369

370
	  while (plug_in->open)
Elliot Lee's avatar
Elliot Lee committed
371
	    {
372
	      if (! wire_read_msg (plug_in->my_read, &msg, plug_in))
373
                {
374
                  plug_in_close (plug_in, TRUE);
375
376
377
                }
	      else 
		{
378
		  plug_in_handle_message (plug_in, &msg);
379
380
		  wire_destroy (&msg);
		}
Elliot Lee's avatar
Elliot Lee committed
381
	    }
382

383
384
	  plug_in_pop ();
	  plug_in_destroy (plug_in);
Elliot Lee's avatar
Elliot Lee committed
385
386
	}
    }
387
388
}

389
PlugIn *
390
391
plug_in_new (Gimp  *gimp,
             gchar *name)
Elliot Lee's avatar
Elliot Lee committed
392
393
{
  PlugIn *plug_in;
394
  gchar  *path;
Elliot Lee's avatar
Elliot Lee committed
395

396
397
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);

398
  if (! g_path_is_absolute (name))
Elliot Lee's avatar
Elliot Lee committed
399
    {
400
      path = plug_in_search_in_path (gimp->config->plug_in_path, name);
401
402

      if (! path)
Elliot Lee's avatar
Elliot Lee committed
403
	{
404
	  g_message (_("Unable to locate Plug-In: \"%s\""), name);
Elliot Lee's avatar
Elliot Lee committed
405
406
407
408
409
410
411
412
	  return NULL;
	}
    }
  else
    {
      path = name;
    }

413
414
415
  plug_in = g_new0 (PlugIn, 1);

  plug_in->gimp               = gimp;
Elliot Lee's avatar
Elliot Lee committed
416

417
418
  plug_in->open               = FALSE;
  plug_in->query              = FALSE;
419
  plug_in->init               = FALSE;
420
421
422
423
424
425
  plug_in->synchronous        = FALSE;
  plug_in->recurse            = FALSE;
  plug_in->busy               = FALSE;
  plug_in->pid                = 0;
  plug_in->args[0]            = g_strdup (path);
  plug_in->args[1]            = g_strdup ("-gimp");
426
427
  plug_in->args[2]            = NULL;
  plug_in->args[3]            = NULL;
428
429
430
431
432
433
434
435
  plug_in->args[4]            = NULL;
  plug_in->args[5]            = NULL;
  plug_in->args[6]            = NULL;
  plug_in->my_read            = NULL;
  plug_in->my_write           = NULL;
  plug_in->his_read           = NULL;
  plug_in->his_write          = NULL;
  plug_in->input_id           = 0;
Elliot Lee's avatar
Elliot Lee committed
436
  plug_in->write_buffer_index = 0;
437
438
439
  plug_in->temp_proc_defs     = NULL;
  plug_in->progress           = NULL;
  plug_in->user_data          = NULL;
Elliot Lee's avatar
Elliot Lee committed
440
441
442
443
444
445
446
447
448

  return plug_in;
}

void
plug_in_destroy (PlugIn *plug_in)
{
  if (plug_in)
    {
449
450
      if (plug_in->open)
	plug_in_close (plug_in, TRUE);
Elliot Lee's avatar
Elliot Lee committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464

      if (plug_in->args[0])
	g_free (plug_in->args[0]);
      if (plug_in->args[1])
	g_free (plug_in->args[1]);
      if (plug_in->args[2])
	g_free (plug_in->args[2]);
      if (plug_in->args[3])
	g_free (plug_in->args[3]);
      if (plug_in->args[4])
	g_free (plug_in->args[4]);
      if (plug_in->args[5])
	g_free (plug_in->args[5]);

465
      if (plug_in->progress)
466
	plug_in_progress_end (plug_in);
467

Elliot Lee's avatar
Elliot Lee committed
468
469
470
      if (plug_in == current_plug_in)
	plug_in_pop ();

471
      g_free (plug_in);
Elliot Lee's avatar
Elliot Lee committed
472
473
474
    }
}

475
476
static void
plug_in_prep_for_exec (gpointer data)
Tor Lillqvist's avatar
Tor Lillqvist committed
477
{
478
479
#if !defined(G_OS_WIN32) && !defined (G_WITH_CYGWIN) && !defined(__EMX__)
  PlugIn *plug_in = data;
Tor Lillqvist's avatar
Tor Lillqvist committed
480

481
482
  g_io_channel_unref (plug_in->my_read);
  plug_in->my_read  = NULL;
Tor Lillqvist's avatar
Tor Lillqvist committed
483

484
485
486
487
  g_io_channel_unref (plug_in->my_write);
  plug_in->my_write  = NULL;
#endif
}
Tor Lillqvist's avatar
Tor Lillqvist committed
488

489
gboolean
Elliot Lee's avatar
Elliot Lee committed
490
491
plug_in_open (PlugIn *plug_in)
{
492
493
  gint my_read[2];
  gint my_write[2];
494
495
  gchar **envp;
  GError *error = NULL;
Elliot Lee's avatar
Elliot Lee committed
496

497
498
  g_return_val_if_fail (plug_in != NULL, FALSE);

Elliot Lee's avatar
Elliot Lee committed
499
500
501
502
503
504
  if (plug_in)
    {
      /* Open two pipes. (Bidirectional communication).
       */
      if ((pipe (my_read) == -1) || (pipe (my_write) == -1))
	{
505
	  g_message ("pipe() failed: Unable to start Plug-In \"%s\"\n(%s)",
506
507
		     g_path_get_basename (plug_in->args[0]),
		     plug_in->args[0]);
508
	  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
509
510
	}

Manish Singh's avatar
Manish Singh committed
511
#if defined(G_WITH_CYGWIN) || defined(__EMX__)
Tor Lillqvist's avatar
Tor Lillqvist committed
512
      /* Set to binary mode */
513
514
515
516
      setmode (my_read[0], _O_BINARY);
      setmode (my_write[0], _O_BINARY);
      setmode (my_read[1], _O_BINARY);
      setmode (my_write[1], _O_BINARY);
Tor Lillqvist's avatar
Tor Lillqvist committed
517
518
#endif

519
520
521
      plug_in->my_read   = g_io_channel_unix_new (my_read[0]);
      plug_in->my_write  = g_io_channel_unix_new (my_write[1]);
      plug_in->his_read  = g_io_channel_unix_new (my_write[0]);
Tor Lillqvist's avatar
Tor Lillqvist committed
522
      plug_in->his_write = g_io_channel_unix_new (my_read[1]);
Elliot Lee's avatar
Elliot Lee committed
523

524
525
526
527
528
      g_io_channel_set_encoding (plug_in->my_read, NULL, NULL);
      g_io_channel_set_encoding (plug_in->my_write, NULL, NULL);
      g_io_channel_set_encoding (plug_in->his_read, NULL, NULL);
      g_io_channel_set_encoding (plug_in->his_write, NULL, NULL);

529
530
531
532
533
      g_io_channel_set_buffered (plug_in->my_read, FALSE);
      g_io_channel_set_buffered (plug_in->my_write, FALSE);
      g_io_channel_set_buffered (plug_in->his_read, FALSE);
      g_io_channel_set_buffered (plug_in->his_write, FALSE);

534
535
536
537
538
      g_io_channel_set_close_on_unref (plug_in->my_read, TRUE);
      g_io_channel_set_close_on_unref (plug_in->my_write, TRUE);
      g_io_channel_set_close_on_unref (plug_in->his_read, TRUE);
      g_io_channel_set_close_on_unref (plug_in->his_write, TRUE);

Elliot Lee's avatar
Elliot Lee committed
539
540
      /* Remember the file descriptors for the pipes.
       */
541
542
543
544
      plug_in->args[2] =
	g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_read));
      plug_in->args[3] =
	g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_write));
Elliot Lee's avatar
Elliot Lee committed
545
546

      /* Set the rest of the command line arguments.
547
       * FIXME: this is ugly.  Pass in the mode as a separate argument?
Elliot Lee's avatar
Elliot Lee committed
548
549
550
551
552
       */
      if (plug_in->query)
	{
	  plug_in->args[4] = g_strdup ("-query");
	}
553
554
555
556
557
      else if (plug_in->init)
	{
	  plug_in->args[4] = g_strdup ("-init");
	}
      else  
Elliot Lee's avatar
Elliot Lee committed
558
	{
559
	  plug_in->args[4] = g_strdup ("-run");
Elliot Lee's avatar
Elliot Lee committed
560
561
	}

562
      plug_in->args[5] = g_strdup_printf ("%d", plug_in->gimp->stack_trace_mode);
563

Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
564
#ifdef __EMX__
565
566
      fcntl (my_read[0], F_SETFD, 1);
      fcntl (my_write[1], F_SETFD, 1);
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
567
#endif
Elliot Lee's avatar
Elliot Lee committed
568

569
570
571
572
573
574
575
576
577
578
579
      /* Fork another process. We'll remember the process id
       *  so that we can later use it to kill the filter if
       *  necessary.
       */
      envp = gimp_environ_table_get_envp (plug_in->gimp->environ_table);
      if (! g_spawn_async (NULL, plug_in->args, envp,
                           G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
                           G_SPAWN_DO_NOT_REAP_CHILD,
                           plug_in_prep_for_exec, plug_in,
                           &plug_in->pid,
                           &error))
Elliot Lee's avatar
Elliot Lee committed
580
	{
581
          g_message ("Unable to run Plug-In: \"%s\"\n(%s)\n%s",
582
		     g_path_get_basename (plug_in->args[0]),
583
584
585
586
		     plug_in->args[0],
		     error->message);
          g_error_free (error);

Elliot Lee's avatar
Elliot Lee committed
587
          plug_in_destroy (plug_in);
588
          return FALSE;
Elliot Lee's avatar
Elliot Lee committed
589
590
	}

Tor Lillqvist's avatar
Tor Lillqvist committed
591
592
      g_io_channel_unref (plug_in->his_read);
      plug_in->his_read  = NULL;
593

Tor Lillqvist's avatar
Tor Lillqvist committed
594
595
596
      g_io_channel_unref (plug_in->his_write);
      plug_in->his_write = NULL;

Elliot Lee's avatar
Elliot Lee committed
597
598
      if (!plug_in->synchronous)
	{
599
600
601
602
603
	  plug_in->input_id =
	    g_io_add_watch (plug_in->my_read,
			    G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
			    plug_in_recv_message,
			    plug_in);
Elliot Lee's avatar
Elliot Lee committed
604
605
606
607
608

	  open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
	}

      plug_in->open = TRUE;
609
      return TRUE;
Elliot Lee's avatar
Elliot Lee committed
610
611
    }

612
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
613
614
615
}

void
616
617
plug_in_close (PlugIn   *plug_in,
	       gboolean  kill_it)
Elliot Lee's avatar
Elliot Lee committed
618
{
619
  gint status;
620
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
621
  struct timeval tv;
Tor Lillqvist's avatar
Tor Lillqvist committed
622
#endif
Elliot Lee's avatar
Elliot Lee committed
623

624
625
  g_return_if_fail (plug_in != NULL);
  g_return_if_fail (plug_in->open == TRUE);
Elliot Lee's avatar
Elliot Lee committed
626

627
628
629
630
  if (! plug_in->open)
    return;

  plug_in->open = FALSE;
Elliot Lee's avatar
Elliot Lee committed
631

632
633
634
635
  /*  Ask the filter to exit gracefully  */
  if (kill_it && plug_in->pid)
    {
      plug_in_push (plug_in);
636
      gp_quit_write (plug_in->my_write, plug_in);
637
638
639
      plug_in_pop ();

      /*  give the plug-in some time (10 ms)  */
640
#ifndef G_OS_WIN32
641
642
643
      tv.tv_sec  = 0;
      tv.tv_usec = 100;	/* But this is 0.1 ms? */
      select (0, NULL, NULL, NULL, &tv);
Tor Lillqvist's avatar
Tor Lillqvist committed
644
#else
645
      Sleep (10);
Tor Lillqvist's avatar
Tor Lillqvist committed
646
#endif
647
    }
Elliot Lee's avatar
Elliot Lee committed
648

649
  /* If necessary, kill the filter. */
650
#ifndef G_OS_WIN32
651
652
  if (kill_it && plug_in->pid)
    status = kill (plug_in->pid, SIGKILL);
Elliot Lee's avatar
Elliot Lee committed
653

654
655
656
657
658
  /* Wait for the process to exit. This will happen
   *  immediately if it was just killed.
   */
  if (plug_in->pid)
    waitpid (plug_in->pid, &status, 0);
Tor Lillqvist's avatar
Tor Lillqvist committed
659
#else
660
661
662
663
664
665
666
667
668
669
670
  if (kill_it && plug_in->pid)
    {
      /* Trying to avoid TerminateProcess (does mostly work).
       * Otherwise some of our needed DLLs may get into an unstable state
       * (see Win32 API docs).
       */
      DWORD dwExitCode = STILL_ACTIVE;
      DWORD dwTries  = 10;
      while ((STILL_ACTIVE == dwExitCode)
	     && GetExitCodeProcess((HANDLE) plug_in->pid, &dwExitCode)
	     && (dwTries > 0))
Tor Lillqvist's avatar
Tor Lillqvist committed
671
	{
672
673
	  Sleep(10);
	  dwTries--;
Tor Lillqvist's avatar
Tor Lillqvist committed
674
	}
675
      if (STILL_ACTIVE == dwExitCode)
Tor Lillqvist's avatar
Tor Lillqvist committed
676
	{
677
678
	  g_warning("Terminating %s ...", plug_in->args[0]);
	  TerminateProcess ((HANDLE) plug_in->pid, 0);
Tor Lillqvist's avatar
Tor Lillqvist committed
679
	}
680
681
    }
#endif
Elliot Lee's avatar
Elliot Lee committed
682

683
  plug_in->pid = 0;
Elliot Lee's avatar
Elliot Lee committed
684

685
686
687
688
  /* Remove the input handler. */
  if (plug_in->input_id)
    {
      g_source_remove (plug_in->input_id);
Elliot Lee's avatar
Elliot Lee committed
689
      plug_in->input_id = 0;
690
691
692
693
694
695
    }

  /* Close the pipes. */
  if (plug_in->my_read != NULL)
    {
      g_io_channel_unref (plug_in->my_read);
Tor Lillqvist's avatar
Tor Lillqvist committed
696
      plug_in->my_read = NULL;
697
698
699
700
    }
  if (plug_in->my_write != NULL)
    {
      g_io_channel_unref (plug_in->my_write);
Tor Lillqvist's avatar
Tor Lillqvist committed
701
      plug_in->my_write = NULL;
702
703
704
705
    }
  if (plug_in->his_read != NULL)
    {
      g_io_channel_unref (plug_in->his_read);
Tor Lillqvist's avatar
Tor Lillqvist committed
706
      plug_in->his_read = NULL;
707
708
709
710
    }
  if (plug_in->his_write != NULL)
    {
      g_io_channel_unref (plug_in->his_write);
Tor Lillqvist's avatar
Tor Lillqvist committed
711
      plug_in->his_write = NULL;
712
    }
Elliot Lee's avatar
Elliot Lee committed
713

714
  wire_clear_error ();
Elliot Lee's avatar
Elliot Lee committed
715

716
  if (plug_in->progress)
717
    plug_in_progress_end (plug_in);
Elliot Lee's avatar
Elliot Lee committed
718

719
720
  if (plug_in->recurse)
    {
721
      gimp_main_loop_quit (plug_in->gimp);
722

723
724
      plug_in->recurse = FALSE;
    }
Elliot Lee's avatar
Elliot Lee committed
725

726
  plug_in->synchronous = FALSE;
Elliot Lee's avatar
Elliot Lee committed
727

728
729
730
731
  /* Unregister any temporary procedures. */
  if (plug_in->temp_proc_defs)
    {
      g_slist_foreach (plug_in->temp_proc_defs,
732
733
		       (GFunc) plug_ins_proc_def_remove,
		       plug_in->gimp);
734
735
736
      g_slist_foreach (plug_in->temp_proc_defs,
                       (GFunc) g_free,
                       NULL);
737
738
739
      g_slist_free (plug_in->temp_proc_defs);
      plug_in->temp_proc_defs = NULL;
    }
Elliot Lee's avatar
Elliot Lee committed
740

741
742
743
  /* Close any dialogs that this plugin might have opened */
  brush_select_dialogs_check ();
  gradient_select_dialogs_check ();
744
745
  palette_select_dialogs_check ();
  pattern_select_dialogs_check ();
746

747
  open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
Elliot Lee's avatar
Elliot Lee committed
748
749
750
751
752
753
}

static Argument *
plug_in_get_current_return_vals (ProcRecord *proc_rec)
{
  Argument *return_vals;
754
  gint      nargs;
Elliot Lee's avatar
Elliot Lee committed
755
756
757
758

  /* Return the status code plus the current return values. */
  nargs = proc_rec->num_values + 1;
  if (current_return_vals && current_return_nvals == nargs)
759
760
761
    {
      return_vals = current_return_vals;
    }
Elliot Lee's avatar
Elliot Lee committed
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  else if (current_return_vals)
    {
      /* Allocate new return values of the correct size. */
      return_vals = procedural_db_return_args (proc_rec, FALSE);

      /* Copy all of the arguments we can. */
      memcpy (return_vals, current_return_vals,
	      sizeof (Argument) * MIN (current_return_nvals, nargs));

      /* Free the old argument pointer.  This will cause a memory leak
	 only if there were more values returned than we need (which
	 shouldn't ever happen). */
      g_free (current_return_vals);
    }
  else
    {
      /* Just return a dummy set of values. */
      return_vals = procedural_db_return_args (proc_rec, FALSE);
    }

  /* We have consumed any saved values, so clear them. */
  current_return_nvals = 0;
784
  current_return_vals  = NULL;
Elliot Lee's avatar
Elliot Lee committed
785
786
787
788

  return return_vals;
}

789
Argument *
790
791
plug_in_run (Gimp       *gimp,
             ProcRecord *proc_rec,
Elliot Lee's avatar
Elliot Lee committed
792
	     Argument   *args,
793
794
795
796
	     gint        argc,
	     gboolean    synchronous,   
	     gboolean    destroy_values,
	     gint        gdisp_ID)
Elliot Lee's avatar
Elliot Lee committed
797
{
798
799
800
801
  GPConfig   config;
  GPProcRun  proc_run;
  Argument  *return_vals;
  PlugIn    *plug_in;
Elliot Lee's avatar
Elliot Lee committed
802
803
804

  return_vals = NULL;

805
  if (proc_rec->proc_type == GIMP_TEMPORARY)
Elliot Lee's avatar
Elliot Lee committed
806
    {
807
      return_vals = plug_in_temp_run (proc_rec, args, argc);
Elliot Lee's avatar
Elliot Lee committed
808
809
810
      goto done;
    }

811
  plug_in = plug_in_new (gimp, proc_rec->exec_method.plug_in.filename);
Elliot Lee's avatar
Elliot Lee committed
812
813
814
815
816
817
818
819
820

  if (plug_in)
    {
      if (plug_in_open (plug_in))
	{
	  plug_in->recurse = synchronous;

	  plug_in_push (plug_in);

821
822
823
824
	  config.version      = GP_VERSION;
	  config.tile_width   = TILE_WIDTH;
	  config.tile_height  = TILE_HEIGHT;
	  config.shm_ID       = shm_ID;
825
826
	  config.gamma        = gimp->config->gamma_val;
	  config.install_cmap = gimp->config->install_cmap;
827
          config.unused       = 0;
828
          config.min_colors   = CLAMP (gimp->config->min_colors, 27, 256);
829
830
831
	  config.gdisp_ID     = gdisp_ID;

	  proc_run.name    = proc_rec->name;
832
	  proc_run.nparams = argc;
833
	  proc_run.params  = plug_in_args_to_params (args, argc, FALSE);
Elliot Lee's avatar
Elliot Lee committed
834

835
836
837
	  if (! gp_config_write (plug_in->my_write, &config, plug_in)     ||
	      ! gp_proc_run_write (plug_in->my_write, &proc_run, plug_in) ||
	      ! wire_flush (plug_in->my_write, plug_in))
Elliot Lee's avatar
Elliot Lee committed
838
839
840
841
842
843
844
845
846
	    {
	      return_vals = procedural_db_return_args (proc_rec, FALSE);
	      goto done;
	    }

	  plug_in_pop ();

	  plug_in_params_destroy (proc_run.params, proc_run.nparams, FALSE);

847
848
	  /*  If this is an automatically installed extension, wait for an
	   *  installation-confirmation message
Elliot Lee's avatar
Elliot Lee committed
849
	   */
850
	  if ((proc_rec->proc_type == GIMP_EXTENSION) &&
851
	      (proc_rec->num_args == 0))
852
            {
853
              gimp_main_loop (gimp);
854
            }
Elliot Lee's avatar
Elliot Lee committed
855
856
857

	  if (plug_in->recurse)
	    {
858
              gimp_main_loop (gimp);
859

Elliot Lee's avatar
Elliot Lee committed
860
861
862
863
	      return_vals = plug_in_get_current_return_vals (proc_rec);
	    }
	}
    }
864

865
 done:
Elliot Lee's avatar
Elliot Lee committed
866
867
868
869
870
871
872
873
874
  if (return_vals && destroy_values)
    {
      procedural_db_destroy_args (return_vals, proc_rec->num_values);
      return_vals = NULL;
    }
  return return_vals;
}

void
875
876
877
878
879
plug_in_repeat (Gimp    *gimp,
                gint     display_ID,
                gint     image_ID,
                gint     drawable_ID,
                gboolean with_interface)
Elliot Lee's avatar
Elliot Lee committed
880
{
881
882
  Argument    *args;
  gint         i;
Elliot Lee's avatar
Elliot Lee committed
883
884
885
886

  if (last_plug_in)
    {
      /* construct the procedures arguments */
887
      args = g_new (Argument, 3);
Elliot Lee's avatar
Elliot Lee committed
888

889
890
      /* initialize the first three argument types */
      for (i = 0; i < 3; i++)
Elliot Lee's avatar
Elliot Lee committed
891
892
	args[i].arg_type = last_plug_in->args[i].arg_type;

893
      /* initialize the first three plug-in arguments  */
894
895
      args[0].value.pdb_int = (with_interface ? 
                               GIMP_RUN_INTERACTIVE : GIMP_RUN_WITH_LAST_VALS);
896
897
      args[1].value.pdb_int = image_ID;
      args[2].value.pdb_int = drawable_ID;
Elliot Lee's avatar
Elliot Lee committed
898
899

      /* run the plug-in procedure */
900
      plug_in_run (gimp, last_plug_in, args, 3, FALSE, TRUE, display_ID);
Elliot Lee's avatar
Elliot Lee committed
901
902
903
904
905

      g_free (args);
    }
}

Tor Lillqvist's avatar
Tor Lillqvist committed
906
static gboolean
907
908
909
plug_in_recv_message (GIOChannel   *channel,
		      GIOCondition  cond,
		      gpointer	    data)
Elliot Lee's avatar
Elliot Lee committed
910
{
911
912
  PlugIn   *plug_in;
  gboolean  got_message = FALSE;
913

914
915
916
917
  plug_in = (PlugIn *) data;

  if (plug_in != current_plug_in)
    plug_in_push (plug_in);
Elliot Lee's avatar
Elliot Lee committed
918

919
  if (plug_in->my_read == NULL)
Tor Lillqvist's avatar
Tor Lillqvist committed
920
    return TRUE;
Elliot Lee's avatar
Elliot Lee committed
921

922
923
924
925
926
927
  if (cond & (G_IO_IN | G_IO_PRI))
    {
      WireMessage msg;

      memset (&msg, 0, sizeof (WireMessage));

928
      if (! wire_read_msg (plug_in->my_read, &msg, plug_in))
929
	{
930
	  plug_in_close (plug_in, TRUE);
931
	}
932
      else
933
	{
934
	  plug_in_handle_message (plug_in, &msg);
935
936
937
938
939
940
	  wire_destroy (&msg);
	  got_message = TRUE;
	}
    }

  if (cond & (G_IO_ERR | G_IO_HUP))
Elliot Lee's avatar
Elliot Lee committed
941
    {
942
      if (plug_in->open)
943
	{
944
	  plug_in_close (plug_in, TRUE);
945
	}
Elliot Lee's avatar
Elliot Lee committed
946
947
    }

948
  if (! got_message)
949
950
951
952
    g_message (_("Plug-In crashed: \"%s\"\n(%s)\n\n"
		 "The dying Plug-In may have messed up GIMP's internal state.\n"
		 "You may want to save your images and restart GIMP\n"
		 "to be on the safe side."),
953
954
	       g_path_get_basename (plug_in->args[0]),
	       plug_in->args[0]);
955

956
957
  if (! plug_in->open)
    plug_in_destroy (plug_in);
Elliot Lee's avatar
Elliot Lee committed
958
959
  else
    plug_in_pop ();
960

Tor Lillqvist's avatar
Tor Lillqvist committed
961
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
962
963
964
}

static void
965
966
plug_in_handle_message (PlugIn      *plug_in,
                        WireMessage *msg)
Elliot Lee's avatar
Elliot Lee committed
967
968
969
970
{
  switch (msg->type)
    {
    case GP_QUIT:
971
      plug_in_handle_quit (plug_in);
Elliot Lee's avatar
Elliot Lee committed
972
      break;
Michael Natterer's avatar
Michael Natterer committed
973

Elliot Lee's avatar
Elliot Lee committed
974
    case GP_CONFIG:
975
976
      g_warning ("plug_in_handle_message(): "
		 "received a config message (should not happen)");
977
      plug_in_close (plug_in, TRUE);
Elliot Lee's avatar
Elliot Lee committed
978
      break;
Michael Natterer's avatar
Michael Natterer committed
979

Elliot Lee's avatar
Elliot Lee committed
980
    case GP_TILE_REQ:
981
      plug_in_handle_tile_req (plug_in, msg->data);
Elliot Lee's avatar
Elliot Lee committed
982
      break;
Michael Natterer's avatar
Michael Natterer committed
983

Elliot Lee's avatar
Elliot Lee committed
984
    case GP_TILE_ACK:
985
986
      g_warning ("plug_in_handle_message(): "
		 "received a tile ack message (should not happen)");
987
      plug_in_close (plug_in, TRUE);
Elliot Lee's avatar
Elliot Lee committed
988
      break;
Michael Natterer's avatar
Michael Natterer committed
989

Elliot Lee's avatar
Elliot Lee committed
990
    case GP_TILE_DATA:
991
992
      g_warning ("plug_in_handle_message(): "
		 "received a tile data message (should not happen)");
993
      plug_in_close (plug_in, TRUE);
Elliot Lee's avatar
Elliot Lee committed
994
      break;
Michael Natterer's avatar
Michael Natterer committed
995

Elliot Lee's avatar
Elliot Lee committed
996
    case GP_PROC_RUN:
997
      plug_in_handle_proc_run (plug_in, msg->data);
Elliot Lee's avatar
Elliot Lee committed
998
      break;
Michael Natterer's avatar
Michael Natterer committed
999