plug-in.c 79.5 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
 */
Tor Lillqvist's avatar
Tor Lillqvist committed
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

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

Elliot Lee's avatar
Elliot Lee committed
27 28 29 30 31
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
32
#ifdef HAVE_SYS_WAIT_H
Elliot Lee's avatar
Elliot Lee committed
33
#include <sys/wait.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
34 35
#endif
#ifdef HAVE_SYS_TIME_H
Elliot Lee's avatar
Elliot Lee committed
36
#include <sys/time.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
37
#endif
Elliot Lee's avatar
Elliot Lee committed
38 39 40
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
41
#ifdef HAVE_UNISTD_H
Elliot Lee's avatar
Elliot Lee committed
42
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
43 44
#endif

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

50
#ifdef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
51 52 53 54
#include <fcntl.h>
#include <io.h>
#endif

Manish Singh's avatar
Manish Singh committed
55
#ifdef G_WITH_CYGWIN
Tor Lillqvist's avatar
Tor Lillqvist committed
56 57 58 59 60 61 62 63
#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
64 65 66 67 68 69 70
#ifdef __EMX__
#include <fcntl.h>
#include <process.h>
#define _O_BINARY O_BINARY
#define _P_NOWAIT P_NOWAIT
#endif

71 72
#include "libgimp/parasite.h"
#include "libgimp/parasiteP.h" /* ick */
Tor Lillqvist's avatar
Tor Lillqvist committed
73
#include "libgimp/gimpenv.h"
Elliot Lee's avatar
Elliot Lee committed
74

75 76 77 78 79 80 81 82
#ifdef HAVE_IPC_H
#include <sys/ipc.h>
#endif

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

Elliot Lee's avatar
Elliot Lee committed
83 84 85
#include "libgimp/gimpprotocol.h"
#include "libgimp/gimpwire.h"

86
#include "app_procs.h"
Elliot Lee's avatar
Elliot Lee committed
87
#include "appenv.h"
88
#include "brush_select.h"  /* Need for closing dialogs */
Elliot Lee's avatar
Elliot Lee committed
89 90 91 92 93 94 95
#include "drawable.h"
#include "datafiles.h"
#include "errors.h"
#include "gdisplay.h"
#include "general.h"
#include "gimage.h"
#include "gimprc.h"
Michael Natterer's avatar
Michael Natterer committed
96
#include "gradient_select.h"
Elliot Lee's avatar
Elliot Lee committed
97 98
#include "interface.h"
#include "menus.h"
99
#include "pattern_select.h"   /* Needed for closing pattern dialogs */
Elliot Lee's avatar
Elliot Lee committed
100 101
#include "plug_in.h"

scott's avatar
scott committed
102
#include "tile.h"			/* ick. */
Elliot Lee's avatar
Elliot Lee committed
103

104 105
#include "libgimp/gimpintl.h"

106

Elliot Lee's avatar
Elliot Lee committed
107 108 109 110 111 112 113 114 115
typedef struct _PlugInBlocked  PlugInBlocked;

struct _PlugInBlocked
{
  PlugIn *plug_in;
  char *proc_name;
};


Tor Lillqvist's avatar
Tor Lillqvist committed
116
static int  plug_in_write                 (GIOChannel	     *channel,
Elliot Lee's avatar
Elliot Lee committed
117 118
					   guint8            *buf,
				           gulong             count);
Tor Lillqvist's avatar
Tor Lillqvist committed
119
static int  plug_in_flush                 (GIOChannel        *channel);
Elliot Lee's avatar
Elliot Lee committed
120 121
static void plug_in_push                  (PlugIn            *plug_in);
static void plug_in_pop                   (void);
Tor Lillqvist's avatar
Tor Lillqvist committed
122 123 124
static gboolean plug_in_recv_message	  (GIOChannel	     *channel,
					   GIOCondition	      cond,
					   gpointer	      data);
Elliot Lee's avatar
Elliot Lee committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
static void plug_in_handle_message        (WireMessage       *msg);
static void plug_in_handle_quit           (void);
static void plug_in_handle_tile_req       (GPTileReq         *tile_req);
static void plug_in_handle_proc_run       (GPProcRun         *proc_run);
static void plug_in_handle_proc_return    (GPProcReturn      *proc_return);
static void plug_in_handle_proc_install   (GPProcInstall     *proc_install);
static void plug_in_handle_proc_uninstall (GPProcUninstall   *proc_uninstall);
static void plug_in_write_rc              (char              *filename);
static void plug_in_init_file             (char              *filename);
static void plug_in_query                 (char              *filename,
				           PlugInDef         *plug_in_def);
static void plug_in_add_to_db             (void);
static void plug_in_make_menu             (void);
static void plug_in_callback              (GtkWidget         *widget,
					   gpointer           client_data);
140 141 142
static void plug_in_proc_def_insert       (PlugInProcDef     *proc_def,
					   void (*superceed_fn)(void *));
static void plug_in_proc_def_dead         (void *freed_proc_def);
Elliot Lee's avatar
Elliot Lee committed
143 144 145 146 147
static void plug_in_proc_def_remove       (PlugInProcDef     *proc_def);
static void plug_in_proc_def_destroy      (PlugInProcDef     *proc_def,
					   int                data_only);

static Argument* plug_in_temp_run       (ProcRecord *proc_rec,
148 149
  					 Argument   *args,
  					 int         argc);
Elliot Lee's avatar
Elliot Lee committed
150 151 152 153 154 155 156 157 158 159 160 161
static Argument* plug_in_params_to_args (GPParam   *params,
  					 int        nparams,
  					 int        full_copy);
static GPParam*  plug_in_args_to_params (Argument  *args,
  					 int        nargs,
  					 int        full_copy);
static void      plug_in_params_destroy (GPParam   *params,
  					 int        nparams,
  					 int        full_destroy);
static void      plug_in_args_destroy   (Argument  *args,
  					 int        nargs,
  					 int        full_destroy);
162
static void      plug_in_init_shm (void);
163

164 165
PlugIn *current_plug_in = NULL;
GSList *proc_defs = NULL;
Elliot Lee's avatar
Elliot Lee committed
166 167 168 169 170 171 172

static GSList *plug_in_defs = NULL;
static GSList *gimprc_proc_defs = NULL;
static GSList *open_plug_ins = NULL;
static GSList *blocked_plug_ins = NULL;

static GSList *plug_in_stack = NULL;
Tor Lillqvist's avatar
Tor Lillqvist committed
173 174
static GIOChannel *current_readchannel = NULL;
static GIOChannel *current_writechannel = NULL;
Elliot Lee's avatar
Elliot Lee committed
175 176 177 178 179 180 181 182 183 184
static int current_write_buffer_index = 0;
static char *current_write_buffer = NULL;
static Argument *current_return_vals = NULL;
static int current_return_nvals = 0;

static ProcRecord *last_plug_in = NULL;

static int shm_ID = -1;
static guchar *shm_addr = NULL;

Manish Singh's avatar
Manish Singh committed
185
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
186 187 188
static HANDLE shm_handle;
#endif

Elliot Lee's avatar
Elliot Lee committed
189 190
static int write_pluginrc = FALSE;

191

192 193 194 195 196 197 198 199 200 201 202 203 204 205


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
  shm_ID = shmget (IPC_PRIVATE, TILE_WIDTH * TILE_HEIGHT * 4, IPC_CREAT | 0777);
  
  if (shm_ID == -1)
Sven Neumann's avatar
Sven Neumann committed
206
    g_message ("shmget failed...disabling shared memory tile transport");
207 208 209 210 211
  else
    {
      shm_addr = (guchar*) shmat (shm_ID, 0, 0);
      if (shm_addr == (guchar*) -1)
	{
Sven Neumann's avatar
Sven Neumann committed
212
	  g_message ("shmat failed...disabling shared memory tile transport");
213 214 215 216 217 218 219 220 221
	  shm_ID = -1;
	}
      
#ifdef	IPC_RMID_DEFERRED_RELEASE
      if (shm_addr != (guchar*) -1)
	shmctl (shm_ID, IPC_RMID, 0);
#endif
    }
#else
Manish Singh's avatar
Manish Singh committed
222
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
  /* Use Win32 shared memory mechanisms for
   * transfering tile data.
   */
  int pid;
  char fileMapName[MAX_PATH];
  int tileByteSize = TILE_WIDTH * TILE_HEIGHT * 4;
  
  /* Our shared memory id will be our process ID */
  pid = GetCurrentProcessId ();
  
  /* From the id, derive the file map name */
  sprintf (fileMapName, "GIMP%d.SHM", pid);
  
  /* 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,
					      FILE_MAP_ALL_ACCESS,
					  0, 0, tileByteSize);
      
      /* Verify that we mapped our view */
      if (shm_addr)
	shm_ID = pid;
      else {
	g_warning ("MapViewOfFile error: %d... disabling shared memory transport\n", GetLastError());
      }
    }
  else
    {
      g_warning ("CreateFileMapping error: %d... disabling shared memory transport\n", GetLastError());
    }
#endif
#endif
}

Elliot Lee's avatar
Elliot Lee committed
263
void
264
plug_in_init (void)
Elliot Lee's avatar
Elliot Lee committed
265 266
{
  extern int use_shm;
Tor Lillqvist's avatar
Tor Lillqvist committed
267
  char *filename;
Elliot Lee's avatar
Elliot Lee committed
268 269 270
  GSList *tmp, *tmp2;
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
271
  gfloat nplugins, nth;
Elliot Lee's avatar
Elliot Lee committed
272 273 274 275 276 277 278 279 280 281 282 283 284

  /* 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)
285 286 287
  {
      plug_in_init_shm();
  }
Elliot Lee's avatar
Elliot Lee committed
288 289 290 291
  /* search for binaries in the plug-in directory path */
  datafiles_read_directories (plug_in_path, plug_in_init_file, MODE_EXECUTABLE);

  /* read the pluginrc file for cached data */
Tor Lillqvist's avatar
Tor Lillqvist committed
292
  filename = NULL;
293 294
  if (pluginrc_path)
    {
Tor Lillqvist's avatar
Tor Lillqvist committed
295 296
      if (g_path_is_absolute (pluginrc_path))
        filename = g_strdup (pluginrc_path);
297
      else
Tor Lillqvist's avatar
Tor Lillqvist committed
298 299
        filename = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
				    gimp_directory (), pluginrc_path);
300 301
    }
  else
Tor Lillqvist's avatar
Tor Lillqvist committed
302
    filename = gimp_personal_rc_file ("pluginrc");
303

304
  app_init_update_status(_("Resource configuration"), filename, -1);
Elliot Lee's avatar
Elliot Lee committed
305 306 307 308 309 310
  parse_gimprc_file (filename);

  /* query any plug-ins that have changed since we last wrote out
   *  the pluginrc file.
   */
  tmp = plug_in_defs;
311
  app_init_update_status(_("Plug-ins"), "", 0);
312 313
  nplugins = g_slist_length(tmp);
  nth = 0;
Elliot Lee's avatar
Elliot Lee committed
314 315 316 317 318 319 320 321
  while (tmp)
    {
      plug_in_def = tmp->data;
      tmp = tmp->next;

      if (plug_in_def->query)
	{
	  write_pluginrc = TRUE;
322
	  if ((be_verbose == TRUE) || (no_splash == TRUE))
323
	    g_print (_("query plug-in: \"%s\"\n"), plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
324 325
	  plug_in_query (plug_in_def->prog, plug_in_def);
	}
326 327
      app_init_update_status(NULL, plug_in_def->prog, nth/nplugins);
      nth++;
Elliot Lee's avatar
Elliot Lee committed
328 329 330 331 332 333 334 335
    }

  /* insert the proc defs */
  tmp = gimprc_proc_defs;
  while (tmp)
    {
      proc_def = g_new (PlugInProcDef, 1);
      *proc_def = *((PlugInProcDef*) tmp->data);
336
      plug_in_proc_def_insert (proc_def, NULL);
Elliot Lee's avatar
Elliot Lee committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
      tmp = tmp->next;
    }

  tmp = plug_in_defs;
  while (tmp)
    {
      plug_in_def = tmp->data;
      tmp = tmp->next;

      tmp2 = plug_in_def->proc_defs;
      while (tmp2)
	{
	  proc_def = tmp2->data;
	  tmp2 = tmp2->next;

GMT 1999 Andy Thomas's avatar
GMT 1999 Andy Thomas committed
352
 	  proc_def->mtime = plug_in_def->mtime; 
353
	  plug_in_proc_def_insert (proc_def, plug_in_proc_def_dead);
Elliot Lee's avatar
Elliot Lee committed
354 355 356 357 358 359
	}
    }

  /* write the pluginrc file if necessary */
  if (write_pluginrc)
    {
360
      if ((be_verbose == TRUE) || (no_splash == TRUE))
361
	g_print (_("writing \"%s\"\n"), filename);
Elliot Lee's avatar
Elliot Lee committed
362 363 364
      plug_in_write_rc (filename);
    }

Tor Lillqvist's avatar
Tor Lillqvist committed
365 366
  g_free (filename);

Elliot Lee's avatar
Elliot Lee committed
367 368 369 370 371 372 373 374
  /* add the plug-in procs to the procedure database */
  plug_in_add_to_db ();

  /* make the menu */
  plug_in_make_menu ();

  /* run the available extensions */
  tmp = proc_defs;
375
  if ((be_verbose == TRUE) || (no_splash == TRUE))
376 377
    g_print (_("Starting extensions: "));
  app_init_update_status(_("Extensions"), "", 0);
378
  nplugins = g_slist_length(tmp); nth = 0;
379

Elliot Lee's avatar
Elliot Lee committed
380 381 382 383 384 385 386 387 388
  while (tmp)
    {
      proc_def = tmp->data;
      tmp = tmp->next;

      if (proc_def->prog &&
	  (proc_def->db_info.num_args == 0) &&
	  (proc_def->db_info.proc_type == PDB_EXTENSION))
	{
389 390
	  if ((be_verbose == TRUE) || (no_splash == TRUE))
	    g_print ("%s ", proc_def->db_info.name);
391 392
	  app_init_update_status(NULL, proc_def->db_info.name,
				 nth/nplugins);
393

394
	  plug_in_run (&proc_def->db_info, NULL, 0, FALSE, TRUE, -1);
Elliot Lee's avatar
Elliot Lee committed
395 396
	}
    }
397 398
  if ((be_verbose == TRUE) || (no_splash == TRUE))
    g_print ("\n");
Elliot Lee's avatar
Elliot Lee committed
399 400 401 402 403 404 405 406 407 408 409 410 411

  /* free up stuff */
  tmp = plug_in_defs;
  while (tmp)
    {
      plug_in_def = tmp->data;
      tmp = tmp->next;

      g_slist_free (plug_in_def->proc_defs);
      g_free (plug_in_def->prog);
      g_free (plug_in_def);
    }
  g_slist_free (plug_in_defs);
412 413


Elliot Lee's avatar
Elliot Lee committed
414 415
}

416

Elliot Lee's avatar
Elliot Lee committed
417
void
418
plug_in_kill (void)
Elliot Lee's avatar
Elliot Lee committed
419 420 421 422
{
  GSList *tmp;
  PlugIn *plug_in;
  
Manish Singh's avatar
Manish Singh committed
423
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
424 425
  CloseHandle (shm_handle);
#else
426
#ifdef HAVE_SHM_H
Elliot Lee's avatar
Elliot Lee committed
427 428 429 430 431 432 433 434 435 436
#ifndef	IPC_RMID_DEFERRED_RELEASE
  if (shm_ID != -1)
    {
      shmdt ((char*) shm_addr);
      shmctl (shm_ID, IPC_RMID, 0);
    }
#else	/* IPC_RMID_DEFERRED_RELEASE */
  if (shm_ID != -1)
    shmdt ((char*) shm_addr);
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
437
#endif
438 439
#endif
 
Elliot Lee's avatar
Elliot Lee committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
  tmp = open_plug_ins;
  while (tmp)
    {
      plug_in = tmp->data;
      tmp = tmp->next;

      plug_in_destroy (plug_in);
    }
}

void
plug_in_add (char *prog,
	     char *menu_path,
	     char *accelerator)
{
  PlugInProcDef *proc_def;
  GSList *tmp;

  if (strncmp ("plug_in_", prog, 8) != 0)
    {
460
      char *t = g_strdup_printf ("plug_in_%s", prog);
Elliot Lee's avatar
Elliot Lee committed
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
      g_free (prog);
      prog = t;
    }

  tmp = gimprc_proc_defs;
  while (tmp)
    {
      proc_def = tmp->data;
      tmp = tmp->next;

      if (strcmp (proc_def->db_info.name, prog) == 0)
	{
	  if (proc_def->db_info.name)
	    g_free (proc_def->db_info.name);
	  if (proc_def->menu_path)
	    g_free (proc_def->menu_path);
	  if (proc_def->accelerator)
	    g_free (proc_def->accelerator);
	  if (proc_def->extensions)
	    g_free (proc_def->extensions);
	  if (proc_def->prefixes)
	    g_free (proc_def->prefixes);
	  if (proc_def->magics)
	    g_free (proc_def->magics);
	  if (proc_def->image_types)
	    g_free (proc_def->image_types);

	  proc_def->db_info.name = prog;
	  proc_def->menu_path = menu_path;
	  proc_def->accelerator = accelerator;
	  proc_def->prefixes = NULL;
	  proc_def->extensions = NULL;
	  proc_def->magics = NULL;
	  proc_def->image_types = NULL;
	  return;
	}
    }

  proc_def = g_new0 (PlugInProcDef, 1);
  proc_def->db_info.name = prog;
  proc_def->menu_path = menu_path;
  proc_def->accelerator = accelerator;

  gimprc_proc_defs = g_slist_prepend (gimprc_proc_defs, proc_def);
}

char*
plug_in_image_types (char *name)
{
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
  GSList *tmp;

  if (current_plug_in)
    {
      plug_in_def = current_plug_in->user_data;
      tmp = plug_in_def->proc_defs;
    }
  else
    {
      tmp = proc_defs;
    }

  while (tmp)
    {
      proc_def = tmp->data;
      tmp = tmp->next;

      if (strcmp (proc_def->db_info.name, name) == 0)
	return proc_def->image_types;
    }

  return NULL;
}

GSList*
plug_in_extensions_parse (char *extensions)
{
  GSList *list;
540 541
  gchar *extension;
  gchar *next_token;
Elliot Lee's avatar
Elliot Lee committed
542 543 544 545 546
  list = NULL;
  /* EXTENSIONS can be NULL.  Avoid calling strtok if it is.  */
  if (extensions)
    {
      extensions = g_strdup (extensions);
547 548
      next_token = extensions;
      extension = strtok (next_token, " \t,");
Elliot Lee's avatar
Elliot Lee committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
      while (extension)
	{
	  list = g_slist_prepend (list, g_strdup (extension));
	  extension = strtok (NULL, " \t,");
	}
      g_free (extensions);
    }

  return g_slist_reverse (list);
}

void
plug_in_add_internal (PlugInProcDef *proc_def)
{
  proc_defs = g_slist_prepend (proc_defs, proc_def);
}

PlugInProcDef*
plug_in_file_handler (char *name,
		      char *extensions,
		      char *prefixes,
		      char *magics)
{
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
  GSList *tmp;

  if (current_plug_in)
    {
      plug_in_def = current_plug_in->user_data;
      tmp = plug_in_def->proc_defs;
    }
  else
    {
      tmp = proc_defs;
    }

  while (tmp)
    {
      proc_def = tmp->data;
      tmp = tmp->next;

      if (strcmp (proc_def->db_info.name, name) == 0)
	{
	  /* EXTENSIONS can be proc_def->extensions  */
	  if (proc_def->extensions != extensions)
	    {
	      if (proc_def->extensions)
		g_free (proc_def->extensions);
	      proc_def->extensions = g_strdup (extensions);
	    }
	  proc_def->extensions_list = plug_in_extensions_parse (proc_def->extensions);

	  /* PREFIXES can be proc_def->prefixes  */
	  if (proc_def->prefixes != prefixes)
	    {
	      if (proc_def->prefixes)
		g_free (proc_def->prefixes);
	      proc_def->prefixes = g_strdup (prefixes);
	    }
	  proc_def->prefixes_list = plug_in_extensions_parse (proc_def->prefixes);

611
	  /* MAGICS can be proc_def->magics  */
Elliot Lee's avatar
Elliot Lee committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
	  if (proc_def->magics != magics)
	    {
	      if (proc_def->magics)
		g_free (proc_def->magics);
	      proc_def->magics = g_strdup (magics);
	    }
	  proc_def->magics_list = plug_in_extensions_parse (proc_def->magics);
	  return proc_def;
	}
    }

  return NULL;
}

void
plug_in_def_add (PlugInDef *plug_in_def)
{
  GSList *tmp;
  PlugInDef *tplug_in_def;
631
  PlugInProcDef *proc_def;
Elliot Lee's avatar
Elliot Lee committed
632 633
  char *t1, *t2;

Tor Lillqvist's avatar
Tor Lillqvist committed
634
  t1 = strrchr (plug_in_def->prog, G_DIR_SEPARATOR);
Elliot Lee's avatar
Elliot Lee committed
635 636 637 638 639
  if (t1)
    t1 = t1 + 1;
  else
    t1 = plug_in_def->prog;

640 641 642 643 644 645
  /* If this is a file load or save plugin, make sure we have
   * something for one of the extensions, prefixes, or magic number.
   * Other bits of code rely on detecting file plugins by the presence
   * of one of these things, but Nick Lamb's alien/unknown format
   * loader needs to be able to register no extensions, prefixes or
   * magics. -- austin 13/Feb/99 */
646
  for (tmp = plug_in_def->proc_defs; tmp; tmp = g_slist_next (tmp))
647
    {
648
      proc_def = tmp->data;
649

650 651 652 653 654 655 656 657
      if (!proc_def->extensions && !proc_def->prefixes && !proc_def->magics &&
	  proc_def->menu_path &&
	  (!strncmp (proc_def->menu_path, "<Load>", 6) ||
	   !strncmp (proc_def->menu_path, "<Save>", 6)))
	{
	  proc_def->extensions = g_strdup("");
	}
    }
658

659
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
660 661 662
    {
      tplug_in_def = tmp->data;

Tor Lillqvist's avatar
Tor Lillqvist committed
663
      t2 = strrchr (tplug_in_def->prog, G_DIR_SEPARATOR);
Elliot Lee's avatar
Elliot Lee committed
664 665 666 667 668 669 670
      if (t2)
	t2 = t2 + 1;
      else
	t2 = tplug_in_def->prog;

      if (strcmp (t1, t2) == 0)
	{
Tor Lillqvist's avatar
Tor Lillqvist committed
671
	  if ((g_strcasecmp (plug_in_def->prog, tplug_in_def->prog) == 0) &&
Elliot Lee's avatar
Elliot Lee committed
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
	      (plug_in_def->mtime == tplug_in_def->mtime))
	    {
	      /* Use cached plug-in entry */
	      tmp->data = plug_in_def;
	      g_free (tplug_in_def->prog);
	      g_free (tplug_in_def);
	    }
	  else
	    {
	      g_free (plug_in_def->prog);
	      g_free (plug_in_def);
	    }
	  return;
	}
    }

  write_pluginrc = TRUE;
Sven Neumann's avatar
Sven Neumann committed
689
  g_print ("\"%s\" executable not found\n", plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
690 691 692 693
  g_free (plug_in_def->prog);
  g_free (plug_in_def);
}

694 695
gchar *
plug_in_menu_path (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
696 697 698 699 700
{
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
  GSList *tmp, *tmp2;

701
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
702 703 704
    {
      plug_in_def = tmp->data;

705
      for (tmp2 = plug_in_def->proc_defs; tmp2; tmp2 = g_slist_next (tmp2))
Elliot Lee's avatar
Elliot Lee committed
706 707 708 709 710 711 712 713
	{
	  proc_def = tmp2->data;

	  if (strcmp (proc_def->db_info.name, name) == 0)
	    return proc_def->menu_path;
	}
    }

714
  for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
715 716 717 718 719 720 721 722 723 724 725
    {
      proc_def = tmp->data;

      if (strcmp (proc_def->db_info.name, name) == 0)
	return proc_def->menu_path;
    }

  return NULL;
}

PlugIn*
726
plug_in_new (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
727 728
{
  PlugIn *plug_in;
729
  gchar *path;
Elliot Lee's avatar
Elliot Lee committed
730

Tor Lillqvist's avatar
Tor Lillqvist committed
731
  if (!g_path_is_absolute (name))
Elliot Lee's avatar
Elliot Lee committed
732 733 734 735
    {
      path = search_in_path (plug_in_path, name);
      if (!path)
	{
736
	  g_message (_("unable to locate plug-in: \"%s\""), name);
Elliot Lee's avatar
Elliot Lee committed
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
	  return NULL;
	}
    }
  else
    {
      path = name;
    }

  plug_in = g_new (PlugIn, 1);

  plug_in->open = FALSE;
  plug_in->destroy = FALSE;
  plug_in->query = FALSE;
  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");
Tor Lillqvist's avatar
Tor Lillqvist committed
756 757
  plug_in->args[2] = g_new (char, 32);
  plug_in->args[3] = g_new (char, 32);
Elliot Lee's avatar
Elliot Lee committed
758 759 760
  plug_in->args[4] = NULL;
  plug_in->args[5] = NULL;
  plug_in->args[6] = NULL;
Tor Lillqvist's avatar
Tor Lillqvist committed
761 762 763 764
  plug_in->my_read = NULL;
  plug_in->my_write = NULL;
  plug_in->his_read = NULL;
  plug_in->his_write = NULL;
765
  plug_in->input_id = 0;
Elliot Lee's avatar
Elliot Lee committed
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
  plug_in->write_buffer_index = 0;
  plug_in->temp_proc_defs = NULL;
  plug_in->progress = NULL;
  plug_in->user_data = NULL;

  return plug_in;
}

void
plug_in_destroy (PlugIn *plug_in)
{
  if (plug_in)
    {
      plug_in_close (plug_in, TRUE);

      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]);

794 795 796
      if (plug_in->progress)
	progress_end (plug_in->progress);
      plug_in->progress = NULL;
797

Elliot Lee's avatar
Elliot Lee committed
798 799 800 801 802 803 804 805
      if (plug_in == current_plug_in)
	plug_in_pop ();

      if (!plug_in->destroy)
	g_free (plug_in);
    }
}

Tor Lillqvist's avatar
Tor Lillqvist committed
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
#ifdef G_OS_WIN32
/* The Microsoft _spawnv() does not allow to run scripts. But
 * this is essential to get scripting extension up and running.
 * Following the replacement function xspawnv().
 */
int
xspawnv (int                mode,
	 const char        *cmdname,
	 const char *const *argv )
{
  char sExecutable[_MAX_PATH*2];
  char** sArgsList;
  char sCmndLine[1024];
  char* sPath;
  HINSTANCE hInst;
  int i;
  int pid;

  /* only use it if _spawnv fails */
  pid = _spawnv(mode, cmdname, argv);
  if (pid != -1) return pid;

  /* stuff parameters into one cmndline */
  sCmndLine[0] = 0;
  for (i = 1; argv[i] != NULL; i++)
    {
       strcat(sCmndLine, argv[i]);
       strcat(sCmndLine, " ");
    }
  /* remove last blank */
  sCmndLine[strlen(sCmndLine)-1] = 0;

  /* do we really need _spawnv (ShelExecute seems not to do it)*/
  if (32 <= (int)FindExecutable (cmdname, 
				 gimp_directory (),
				 sExecutable))
    {
      //g_print("_spawnlp %s %s %s", sExecutable, cmdname, sCmndLine);
      
      pid = _spawnlp(mode, sExecutable, "-c", cmdname, sCmndLine, NULL);
    }
  else
    {
      g_warning("Execution error for: %s", cmdname);
      return -1;
    }
  return pid;
}
#undef _spawnv
#define _spawnv xspawnv

#endif /* G_OS_WIN32 */

859
gint
Elliot Lee's avatar
Elliot Lee committed
860 861 862 863 864 865 866 867 868 869 870
plug_in_open (PlugIn *plug_in)
{
  int my_read[2];
  int my_write[2];

  if (plug_in)
    {
      /* Open two pipes. (Bidirectional communication).
       */
      if ((pipe (my_read) == -1) || (pipe (my_write) == -1))
	{
Sven Neumann's avatar
Sven Neumann committed
871
	  g_message ("unable to open pipe");
Elliot Lee's avatar
Elliot Lee committed
872 873 874
	  return 0;
	}

Manish Singh's avatar
Manish Singh committed
875
#if defined(G_WITH_CYGWIN) || defined(__EMX__)
Tor Lillqvist's avatar
Tor Lillqvist committed
876 877 878 879 880 881 882
      /* Set to binary mode */
      setmode(my_read[0], _O_BINARY);
      setmode(my_write[0], _O_BINARY);
      setmode(my_read[1], _O_BINARY);
      setmode(my_write[1], _O_BINARY);
#endif

883
#ifndef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
884 885 886 887 888 889 890 891 892 893 894
      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]);
      plug_in->his_write = g_io_channel_unix_new (my_read[1]);
#else
      plug_in->my_read = g_io_channel_win32_new_pipe (my_read[0]);
      plug_in->his_read = g_io_channel_win32_new_pipe (my_write[0]);
      plug_in->his_read_fd = my_write[0];
      plug_in->my_write = g_io_channel_win32_new_pipe (my_write[1]);
      plug_in->his_write = g_io_channel_win32_new_pipe (my_read[1]);
#endif
Elliot Lee's avatar
Elliot Lee committed
895 896 897

      /* Remember the file descriptors for the pipes.
       */
898
#ifndef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
899 900 901 902 903 904 905
      sprintf (plug_in->args[2], "%d",
	       g_io_channel_unix_get_fd (plug_in->his_read));
      sprintf (plug_in->args[3], "%d",
	       g_io_channel_unix_get_fd (plug_in->his_write));
#else
      sprintf (plug_in->args[2], "%d",
	       g_io_channel_win32_get_fd (plug_in->his_read));
906
      sprintf (plug_in->args[3], "%d:%u:%d",
Tor Lillqvist's avatar
Tor Lillqvist committed
907 908 909 910
	       g_io_channel_win32_get_fd (plug_in->his_write),
	       GetCurrentThreadId (),
	       g_io_channel_win32_get_fd (plug_in->my_read));
#endif
Elliot Lee's avatar
Elliot Lee committed
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930

      /* Set the rest of the command line arguments.
       */
      if (plug_in->query)
	{
	  plug_in->args[4] = g_strdup ("-query");
	}
      else
	{
	  plug_in->args[4] = g_new (char, 16);
	  plug_in->args[5] = g_new (char, 16);

	  sprintf (plug_in->args[4], "%d", TILE_WIDTH);
	  sprintf (plug_in->args[5], "%d", TILE_WIDTH);
	}

      /* Fork another process. We'll remember the process id
       *  so that we can later use it to kill the filter if
       *  necessary.
       */
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
931 932 933 934
#ifdef __EMX__
      fcntl(my_read[0], F_SETFD, 1);
      fcntl(my_write[1], F_SETFD, 1);
#endif
Manish Singh's avatar
Manish Singh committed
935
#if defined(G_OS_WIN32) || defined (G_WITH_CYGWIN) || defined(__EMX__)
Tor Lillqvist's avatar
Tor Lillqvist committed
936
      plug_in->pid = _spawnv (_P_NOWAIT, plug_in->args[0], plug_in->args);
Tor Lillqvist's avatar
Tor Lillqvist committed
937 938
      if (plug_in->pid == -1)
#else
Elliot Lee's avatar
Elliot Lee committed
939 940 941 942
      plug_in->pid = fork ();

      if (plug_in->pid == 0)
	{
943 944 945 946 947 948 949
	  g_io_channel_close (plug_in->my_read);
	  g_io_channel_unref (plug_in->my_read);
	  plug_in->my_read  = NULL;
	  g_io_channel_close (plug_in->my_write);
	  g_io_channel_unref (plug_in->my_write);
	  plug_in->my_write  = NULL;

Elliot Lee's avatar
Elliot Lee committed
950 951 952 953 954 955 956 957
          /* Execute the filter. The "_exit" call should never
           *  be reached, unless some strange error condition
           *  exists.
           */
          execvp (plug_in->args[0], plug_in->args);
          _exit (1);
	}
      else if (plug_in->pid == -1)
Tor Lillqvist's avatar
Tor Lillqvist committed
958
#endif
Elliot Lee's avatar
Elliot Lee committed
959
	{
Sven Neumann's avatar
Sven Neumann committed
960
          g_message ("unable to run plug-in: %s", plug_in->args[0]);
Elliot Lee's avatar
Elliot Lee committed
961 962 963 964
          plug_in_destroy (plug_in);
          return 0;
	}

Tor Lillqvist's avatar
Tor Lillqvist committed
965 966 967 968 969 970 971
      g_io_channel_close (plug_in->his_read);
      g_io_channel_unref (plug_in->his_read);
      plug_in->his_read  = NULL;
      g_io_channel_close (plug_in->his_write);
      g_io_channel_unref (plug_in->his_write);
      plug_in->his_write = NULL;

972
#ifdef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
973 974 975 976 977 978 979 980 981 982 983
      /* The plug-in tells us its thread id */
      if (!plug_in->query)
	{
	  if (!wire_read_int32 (plug_in->my_read, &plug_in->his_thread_id, 1))
	    {
	      g_message ("unable to read plug-ins's thread id");
	      plug_in_destroy (plug_in);
	      return 0;
	    }
	}
#endif
Elliot Lee's avatar
Elliot Lee committed
984 985 986

      if (!plug_in->synchronous)
	{
Tor Lillqvist's avatar
Tor Lillqvist committed
987 988
	  plug_in->input_id = g_io_add_watch (plug_in->my_read,
					      G_IO_IN | G_IO_PRI,
Elliot Lee's avatar
Elliot Lee committed
989 990 991 992 993 994 995
					     plug_in_recv_message,
					     plug_in);

	  open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
	}

      plug_in->open = TRUE;
996
      return TRUE;
Elliot Lee's avatar
Elliot Lee committed
997 998
    }

999
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1000 1001 1002 1003
}

void
plug_in_close (PlugIn *plug_in,
1004
	       gint    kill_it)
Elliot Lee's avatar
Elliot Lee committed
1005
{
1006
  gint status;
1007
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1008
  struct timeval tv;
Tor Lillqvist's avatar
Tor Lillqvist committed
1009
#endif
Elliot Lee's avatar
Elliot Lee committed
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

  if (plug_in && plug_in->open)
    {
      plug_in->open = FALSE;

      /* Ask the filter to exit gracefully
       */
      if (kill_it && plug_in->pid)
	{
	  plug_in_push (plug_in);
Tor Lillqvist's avatar
Tor Lillqvist committed
1020
	  gp_quit_write (current_writechannel);
Elliot Lee's avatar
Elliot Lee committed
1021 1022 1023
	  plug_in_pop ();

	  /*  give the plug-in some time (10 ms)  */
1024
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1025
	  tv.tv_sec = 0;
Tor Lillqvist's avatar
Tor Lillqvist committed
1026
	  tv.tv_usec = 100;	/* But this is 0.1 ms? */
Elliot Lee's avatar
Elliot Lee committed
1027
	  select (0, NULL, NULL, NULL, &tv);
Tor Lillqvist's avatar
Tor Lillqvist committed
1028 1029 1030
#else
	  Sleep (10);
#endif
Elliot Lee's avatar
Elliot Lee committed
1031 1032 1033 1034
	}

      /* If necessary, kill the filter.
       */
1035
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1036 1037 1038 1039 1040 1041 1042 1043
      if (kill_it && plug_in->pid)
	status = kill (plug_in->pid, SIGKILL);

      /* 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
1044 1045
#else
      if (kill_it && plug_in->pid)
Tor Lillqvist's avatar
Tor Lillqvist committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
	{
	  /* 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))
	    {
	      Sleep(10);
	      dwTries--;
	    }
	  if (STILL_ACTIVE == dwExitCode)
	    {
	      g_warning("Terminating %s ...", plug_in->args[0]);
	      TerminateProcess ((HANDLE) plug_in->pid, 0);
	    }
	}
Tor Lillqvist's avatar
Tor Lillqvist committed
1066
#endif
Elliot Lee's avatar
Elliot Lee committed
1067 1068 1069 1070 1071 1072 1073 1074

      /* Remove the input handler.
       */
      if (plug_in->input_id)
        gdk_input_remove (plug_in->input_id);

      /* Close the pipes.
       */
Tor Lillqvist's avatar
Tor Lillqvist committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
      if (plug_in->my_read != NULL)
	{
	  g_io_channel_close (plug_in->my_read);
	  g_io_channel_unref (plug_in->my_read);
	  plug_in->my_read = NULL;
	}
      if (plug_in->my_write != NULL)
	{
	  g_io_channel_close (plug_in->my_write);
	  g_io_channel_unref (plug_in->my_write);
	  plug_in->my_write = NULL;
	}
      if (plug_in->his_read != NULL)
	{
	  g_io_channel_close (plug_in->his_read);
	  g_io_channel_unref (plug_in->his_read);
	  plug_in->his_read = NULL;
	}
      if (plug_in->his_write != NULL)
	{
	  g_io_channel_close (plug_in->his_write);
	  g_io_channel_unref (plug_in->his_write);
	  plug_in->his_write = NULL;
	}
Elliot Lee's avatar
Elliot Lee committed
1099 1100 1101 1102 1103 1104

      wire_clear_error();

      /* Destroy the progress dialog if it exists
       */
      if (plug_in->progress)
1105 1106
	progress_end (plug_in->progress);
      plug_in->progress = NULL;
Elliot Lee's avatar
Elliot Lee committed
1107 1108 1109 1110 1111

      /* Set the fields to null values.
       */
      plug_in->pid = 0;
      plug_in->input_id = 0;
Tor Lillqvist's avatar
Tor Lillqvist committed
1112 1113 1114 1115
      plug_in->my_read = NULL;
      plug_in->my_write = NULL;
      plug_in->his_read = NULL;
      plug_in->his_write = NULL;
Elliot Lee's avatar
Elliot Lee committed
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141

      if (plug_in->recurse)
	gtk_main_quit ();

      plug_in->synchronous = FALSE;
      plug_in->recurse = FALSE;

      /* Unregister any temporary procedures
       */
      if (plug_in->temp_proc_defs)
	{
	  GSList *list;
	  PlugInProcDef *proc_def;

	  list = plug_in->temp_proc_defs;
	  while (list)
	    {
	      proc_def = (PlugInProcDef *) list->data;
	      plug_in_proc_def_remove (proc_def);
	      list = list->next;
	    }

	  g_slist_free (plug_in->temp_proc_defs);
	  plug_in->temp_proc_defs = NULL;
	}

1142 1143
      /* Close any dialogs that this plugin might have opened */
      brushes_check_dialogs();
1144
      patterns_check_dialogs();
1145
      gradients_check_dialogs();
1146

Elliot Lee's avatar
Elliot Lee committed
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
      open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
    }
}

static Argument *
plug_in_get_current_return_vals (ProcRecord *proc_rec)
{
  Argument *return_vals;
  int nargs;

  /* Return the status code plus the current return values. */
  nargs = proc_rec->num_values + 1;
  if (current_return_vals && current_return_nvals == nargs)
    return_vals = current_return_vals;
  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;
  current_return_vals = NULL;

  return return_vals;
}

Argument*
plug_in_run (ProcRecord *proc_rec,
	     Argument   *args,
1191
	     int         argc,
Elliot Lee's avatar
Elliot Lee committed
1192
	     int         synchronous,   
Manish Singh's avatar
Manish Singh committed
1193 1194
	     int         destroy_values,
	     int         gdisp_ID)
Elliot Lee's avatar
Elliot Lee committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
{
  GPConfig config;
  GPProcRun proc_run;
  Argument *return_vals;
  PlugIn *plug_in;

  return_vals = NULL;

  if (proc_rec->proc_type == PDB_TEMPORARY)
    {
1205
      return_vals = plug_in_temp_run (proc_rec, args, argc);
Elliot Lee's avatar
Elliot Lee committed
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
      goto done;
    }

  plug_in = plug_in_new (proc_rec->exec_method.plug_in.filename);

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

	  plug_in_push (plug_in);

	  config.version = GP_VERSION;
	  config.tile_width = TILE_WIDTH;
	  config.tile_height = TILE_HEIGHT;
	  config.shm_ID = shm_ID;
	  config.gamma = gamma_val;
	  config.install_cmap = install_cmap;
	  config.use_xshm = gdk_get_use_xshm ();
	  config.color_cube[0] = color_cube_shades[0];
	  config.color_cube[1] = color_cube_shades[1];
	  config.color_cube[2] = color_cube_shades[2];
	  config.color_cube[3] = color_cube_shades[3];
Manish Singh's avatar
Manish Singh committed
1230
	  config.gdisp_ID = gdisp_ID;
Elliot Lee's avatar
Elliot Lee committed
1231 1232

	  proc_run.name = proc_rec->name;
1233 1234
	  proc_run.nparams = argc;
	  proc_run.params = plug_in_args_to_params (args, argc, FALSE);
Elliot Lee's avatar
Elliot Lee committed
1235

Tor Lillqvist's avatar
Tor Lillqvist committed
1236 1237 1238
	  if (!gp_config_write (current_writechannel, &config) ||
	      !gp_proc_run_write (current_writechannel, &proc_run) ||
	      !wire_flush (current_writechannel))
Elliot Lee's avatar
Elliot Lee committed
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
	    {
	      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);

	  /*
	   *  If this is an automatically installed extension, wait for an
	   *   installation-confirmation message
	   */
	  if ((proc_rec->proc_type == PDB_EXTENSION) && (proc_rec->num_args == 0))
	    gtk_main ();

	  if (plug_in->recurse)
	    {
	      gtk_main ();
	      
	      return_vals = plug_in_get_current_return_vals (proc_rec);
	    }
	}
    }
  
done:
  if (return_vals && destroy_values)
    {
      procedural_db_destroy_args (return_vals, proc_rec->num_values);
      return_vals = NULL;
    }
  return return_vals;
}

void
plug_in_repeat (int with_interface)
{
  GDisplay *gdisplay;
  Argument *args;
  int i;

  if (last_plug_in)
    {
      gdisplay = gdisplay_active ();
Michael Natterer's avatar
Michael Natterer committed
1283
      if (!gdisplay) return;
Elliot Lee's avatar
Elliot Lee committed
1284 1285

      /* construct the procedures arguments */
1286
      args = g_new (Argument, 3);
Elliot Lee's avatar
Elliot Lee committed
1287

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

1292
      /* initialize the first three plug-in arguments  */
Elliot Lee's avatar
Elliot Lee committed
1293
      args[0].value.pdb_int = (with_interface ? RUN_INTERACTIVE : RUN_WITH_LAST_VALS);
1294
      args[1].value.pdb_int = pdb_image_to_id(gdisplay->gimage);
1295
      args[2].value.pdb_int = drawable_ID (gimage_active_drawable (gdisplay->gimage));
Elliot Lee's avatar
Elliot Lee committed
1296 1297

      /* run the plug-in procedure */
1298
      plug_in_run (last_plug_in, args, 3, FALSE, TRUE, gdisplay->ID);
Elliot Lee's avatar
Elliot Lee committed
1299 1300 1301 1302 1303 1304

      g_free (args);
    }
}

void
1305
plug_in_set_menu_sensitivity (GimpImageType type)
Elliot Lee's avatar
Elliot Lee committed
1306 1307 1308
{
  PlugInProcDef *proc_def;
  GSList *tmp;
1309
  gboolean sensitive = FALSE;
Elliot Lee's avatar
Elliot Lee committed
1310

1311
  for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
1312 1313 1314 1315
    {
      proc_def = tmp->data;

      if (proc_def->image_types_val && proc_def->menu_path)
1316
	{
1317
	  switch (type)
1318 1319
	    {
	    case RGB_GIMAGE:
1320
	      sensitive = proc_def->image_types_val & PLUG_IN_RGB_IMAGE;
1321 1322
	      break;
	    case RGBA_GIMAGE:
1323
	      sensitive = proc_def->image_types_val & PLUG_IN_RGBA_IMAGE;
1324 1325
	      break;
	    case GRAY_GIMAGE:
1326
	      sensitive = proc_def->image_types_val & PLUG_IN_GRAY_IMAGE;
1327 1328
	      break;
	    case GRAYA_GIMAGE:
1329
	      sensitive = proc_def->image_types_val & PLUG_IN_GRAYA_IMAGE;
1330 1331
	      break;
	    case INDEXED_GIMAGE:
1332
	      sensitive = proc_def->image_types_val & PLUG_IN_INDEXED_IMAGE;
1333 1334
	      break;
	    case INDEXEDA_GIMAGE:
1335
	      sensitive = proc_def->image_types_val & PLUG_IN_INDEXEDA_IMAGE;
1336
	      break;
1337 1338 1339
	    default:
	      sensitive = FALSE;
	      break;
1340 1341
	    }

1342
	  menus_set_sensitive (proc_def->menu_path, sensitive);
1343

1344 1345
          if (last_plug_in && (last_plug_in == &(proc_def->db_info)))
	    {
Sven Neumann's avatar
Sven Neumann committed
1346 1347
	      menus_set_sensitive ("<Image>/Filters/Repeat Last", sensitive);
	      menus_set_sensitive ("<Image>/Filters/Re-Show Last", sensitive);
1348 1349
	    }
	}
Elliot Lee's avatar
Elliot Lee committed
1350 1351 1352
    }
}

Tor Lillqvist's avatar
Tor Lillqvist committed
1353 1354 1355 1356
static gboolean
plug_in_recv_message (GIOChannel  *channel,
		      GIOCondition cond,
		      gpointer	   data)
Elliot Lee's avatar
Elliot Lee committed
1357 1358 1359 1360
{
  WireMessage msg;

  plug_in_push ((PlugIn*) data);
Tor Lillqvist's avatar
Tor Lillqvist committed
1361 1362
  if (current_readchannel == NULL)
    return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1363 1364

  memset (&msg, 0, sizeof (WireMessage));
Tor Lillqvist's avatar
Tor Lillqvist committed
1365
  if (!wire_read_msg (current_readchannel, &msg))
Elliot Lee's avatar
Elliot Lee committed
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376
    plug_in_close (current_plug_in, TRUE);
  else 
    {
      plug_in_handle_message (&msg);
      wire_destroy (&msg);
    }

  if (!current_plug_in->open)
    plug_in_destroy (current_plug_in);
  else
    plug_in_pop ();
Tor Lillqvist's avatar
Tor Lillqvist committed
1377
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
}

static void
plug_in_handle_message (WireMessage *msg)
{
  switch (msg->type)
    {
    case GP_QUIT:
      plug_in_handle_quit ();
      break;
    case GP_CONFIG:
1389