plug-in-commands.c 86.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 18
 */
#include "config.h"
19

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

24 25
#include <glib.h>

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

44
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
45 46 47 48
#define STRICT
#include <windows.h>
#include <process.h>

49
#ifdef G_OS_WIN32
50 51 52 53
#include <fcntl.h>
#include <io.h>
#endif

54
#ifdef G_WITH_CYGWIN
55 56 57 58 59 60 61 62
#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

63 64 65 66 67 68 69
#ifdef __EMX__
#include <fcntl.h>
#include <process.h>
#define _O_BINARY O_BINARY
#define _P_NOWAIT P_NOWAIT
#endif

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

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

78
#include "app_procs.h"
Elliot Lee's avatar
Elliot Lee committed
79
#include "appenv.h"
80
#include "brush_select.h"  /* Need for closing dialogs */
Elliot Lee's avatar
Elliot Lee committed
81 82 83 84 85 86
#include "drawable.h"
#include "datafiles.h"
#include "gdisplay.h"
#include "general.h"
#include "gimage.h"
#include "gimprc.h"
87
#include "gradient_select.h"
Elliot Lee's avatar
Elliot Lee committed
88
#include "menus.h"
89
#include "pattern_select.h"   /* Needed for closing pattern dialogs */
Elliot Lee's avatar
Elliot Lee committed
90 91
#include "plug_in.h"

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

94 95 96 97 98 99
#include "libgimp/gimpenv.h"
#include "libgimp/gimpprotocol.h"
#include "libgimp/gimpwire.h"
#include "libgimp/parasite.h"
#include "libgimp/parasiteP.h" /* ick */

100 101
#include "libgimp/gimpintl.h"

102

Elliot Lee's avatar
Elliot Lee committed
103 104 105 106 107
typedef struct _PlugInBlocked  PlugInBlocked;

struct _PlugInBlocked
{
  PlugIn *plug_in;
108
  gchar  *proc_name;
Elliot Lee's avatar
Elliot Lee committed
109 110 111
};


112 113 114 115 116 117
typedef struct _PlugInMenuEntry PlugInMenuEntry;

struct _PlugInMenuEntry
{
  PlugInProcDef *proc_def;
  gchar         *domain;
118 119 120 121 122 123 124 125 126 127
  gchar         *help_path;
};


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 133
					   guint8            *buf,
				           gulong             count);
134 135 136
static gboolean plug_in_flush             (GIOChannel        *channel);
static void     plug_in_push              (PlugIn            *plug_in);
static void     plug_in_pop               (void);
137 138 139
static gboolean plug_in_recv_message	  (GIOChannel	     *channel,
					   GIOCondition	      cond,
					   gpointer	      data);
Elliot Lee's avatar
Elliot Lee committed
140 141 142 143 144 145 146
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);
147 148
static void plug_in_write_rc              (gchar             *filename);
static void plug_in_init_file             (gchar             *filename);
149
static void plug_in_query                 (PlugInDef         *plug_in_def);
Elliot Lee's avatar
Elliot Lee committed
150 151
static void plug_in_add_to_db             (void);
static void plug_in_make_menu             (void);
152 153 154
static gint plug_in_make_menu_entry       (gpointer           foo,
					   PlugInMenuEntry   *menu_entry,
					   gpointer           bar);
Elliot Lee's avatar
Elliot Lee committed
155 156
static void plug_in_callback              (GtkWidget         *widget,
					   gpointer           client_data);
157 158 159
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
160 161
static void plug_in_proc_def_remove       (PlugInProcDef     *proc_def);
static void plug_in_proc_def_destroy      (PlugInProcDef     *proc_def,
162
					   gboolean           data_only);
Elliot Lee's avatar
Elliot Lee committed
163 164

static Argument* plug_in_temp_run       (ProcRecord *proc_rec,
165
  					 Argument   *args,
166 167 168 169 170 171 172 173 174 175 176 177 178 179
  					 gint        argc);
static Argument* plug_in_params_to_args (GPParam    *params,
  					 gint        nparams,
					 gboolean    full_copy);
static GPParam*  plug_in_args_to_params (Argument   *args,
  					 gint        nargs,
  					 gboolean    full_copy);
static void      plug_in_params_destroy (GPParam    *params,
  					 gint        nparams,
  					 gboolean    full_destroy);
static void      plug_in_args_destroy   (Argument   *args,
  					 gint        nargs,
  					 gboolean    full_destroy);
static void      plug_in_init_shm       (void);
180

181
PlugIn *current_plug_in = NULL;
182
GSList *proc_defs       = NULL;
Elliot Lee's avatar
Elliot Lee committed
183

184
static GSList *plug_in_defs     = NULL;
Elliot Lee's avatar
Elliot Lee committed
185
static GSList *gimprc_proc_defs = NULL;
186
static GSList *open_plug_ins    = NULL;
Elliot Lee's avatar
Elliot Lee committed
187 188
static GSList *blocked_plug_ins = NULL;

189 190 191 192 193
static GSList *help_path_defs = NULL;

static GSList     *plug_in_stack              = NULL;
static GIOChannel *current_readchannel        = NULL;
static GIOChannel *current_writechannel       = NULL;
194
static gint        current_write_buffer_index = 0;
195 196 197
static gchar      *current_write_buffer       = NULL;
static Argument   *current_return_vals        = NULL;
static gint        current_return_nvals       = 0;
Elliot Lee's avatar
Elliot Lee committed
198 199 200

static ProcRecord *last_plug_in = NULL;

201
static gint    shm_ID = -1;
Elliot Lee's avatar
Elliot Lee committed
202 203
static guchar *shm_addr = NULL;

204
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
205 206 207
static HANDLE shm_handle;
#endif

208
static gboolean write_pluginrc = FALSE;
Elliot Lee's avatar
Elliot Lee committed
209

210
static gchar *std_plugins_domain = "gimp-std-plugins";
211 212 213 214 215 216 217 218 219 220 221 222 223 224


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)
225
    g_message ("shmget() failed: Disabling shared memory tile transport.");
226 227
  else
    {
228 229
      shm_addr = (guchar *) shmat (shm_ID, NULL, 0);
      if (shm_addr == (guchar *) -1)
230
	{
231
	  g_message ("shmat() failed: Disabling shared memory tile transport.");
232
	  shmctl (shm_ID, IPC_RMID, NULL);
233 234 235 236
	  shm_ID = -1;
	}
      
#ifdef	IPC_RMID_DEFERRED_RELEASE
237 238
      if (shm_addr != (guchar *) -1)
	shmctl (shm_ID, IPC_RMID, NULL);
239 240 241
#endif
    }
#else
242
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
243 244 245
  /* Use Win32 shared memory mechanisms for
   * transfering tile data.
   */
246 247 248
  gint  pid;
  gchar fileMapName[MAX_PATH];
  gint  tileByteSize = TILE_WIDTH * TILE_HEIGHT * 4;
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
  
  /* 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,
265
					  FILE_MAP_ALL_ACCESS,
266 267 268 269 270
					  0, 0, tileByteSize);
      
      /* Verify that we mapped our view */
      if (shm_addr)
	shm_ID = pid;
271 272 273 274
      else
	{
	  g_warning ("MapViewOfFile error: %d... disabling shared memory transport\n", GetLastError());
	}
275 276 277 278 279 280 281 282 283
    }
  else
    {
      g_warning ("CreateFileMapping error: %d... disabling shared memory transport\n", GetLastError());
    }
#endif
#endif
}

Elliot Lee's avatar
Elliot Lee committed
284
void
285
plug_in_init (void)
Elliot Lee's avatar
Elliot Lee committed
286
{
287 288
  extern gboolean use_shm;
  gchar  *filename;
Elliot Lee's avatar
Elliot Lee committed
289
  GSList *tmp, *tmp2;
290
  PlugInDef     *plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
291
  PlugInProcDef *proc_def;
292
  gfloat nplugins, nth;
Elliot Lee's avatar
Elliot Lee committed
293 294 295 296 297 298 299 300 301 302 303 304 305

  /* 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)
306 307 308
    {
      plug_in_init_shm ();
    }
Elliot Lee's avatar
Elliot Lee committed
309 310 311 312
  /* 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 */
313
  filename = NULL;
314 315
  if (pluginrc_path)
    {
316 317
      if (g_path_is_absolute (pluginrc_path))
        filename = g_strdup (pluginrc_path);
318
      else
319 320
        filename = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
				    gimp_directory (), pluginrc_path);
321 322
    }
  else
323
    filename = gimp_personal_rc_file ("pluginrc");
324

325
  app_init_update_status (_("Resource configuration"), filename, -1);
Elliot Lee's avatar
Elliot Lee committed
326 327 328 329 330 331
  parse_gimprc_file (filename);

  /* query any plug-ins that have changed since we last wrote out
   *  the pluginrc file.
   */
  tmp = plug_in_defs;
332 333
  app_init_update_status (_("Plug-ins"), "", 0);
  nplugins = g_slist_length (tmp);
334
  nth = 0;
Elliot Lee's avatar
Elliot Lee committed
335 336 337 338 339 340 341 342
  while (tmp)
    {
      plug_in_def = tmp->data;
      tmp = tmp->next;

      if (plug_in_def->query)
	{
	  write_pluginrc = TRUE;
343
	  if ((be_verbose == TRUE) || (no_splash == TRUE))
344
	    g_print (_("query plug-in: \"%s\"\n"), plug_in_def->prog);
345
	  plug_in_query (plug_in_def);
Elliot Lee's avatar
Elliot Lee committed
346
	}
347
      app_init_update_status (NULL, plug_in_def->prog, nth / nplugins);
348
      nth++;
Elliot Lee's avatar
Elliot Lee committed
349 350 351
    }

  /* insert the proc defs */
352
  for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
353 354 355
    {
      proc_def = g_new (PlugInProcDef, 1);
      *proc_def = *((PlugInProcDef*) tmp->data);
356
      plug_in_proc_def_insert (proc_def, NULL);
Elliot Lee's avatar
Elliot Lee committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370
    }

  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
371
 	  proc_def->mtime = plug_in_def->mtime; 
372
	  plug_in_proc_def_insert (proc_def, plug_in_proc_def_dead);
Elliot Lee's avatar
Elliot Lee committed
373 374 375 376 377 378
	}
    }

  /* write the pluginrc file if necessary */
  if (write_pluginrc)
    {
379
      if ((be_verbose == TRUE) || (no_splash == TRUE))
380
	g_print (_("writing \"%s\"\n"), filename);
Elliot Lee's avatar
Elliot Lee committed
381 382 383
      plug_in_write_rc (filename);
    }

384 385
  g_free (filename);

Elliot Lee's avatar
Elliot Lee committed
386 387 388 389 390 391 392 393
  /* 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;
394
  if ((be_verbose == TRUE) || (no_splash == TRUE))
395
    g_print (_("Starting extensions: "));
396 397
  app_init_update_status (_("Extensions"), "", 0);
  nplugins = g_slist_length (tmp); nth = 0;
398

Elliot Lee's avatar
Elliot Lee committed
399 400 401 402 403 404 405 406 407
  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))
	{
408 409
	  if ((be_verbose == TRUE) || (no_splash == TRUE))
	    g_print ("%s ", proc_def->db_info.name);
410 411
	  app_init_update_status (NULL, proc_def->db_info.name,
				  nth / nplugins);
412

413
	  plug_in_run (&proc_def->db_info, NULL, 0, FALSE, TRUE, -1);
Elliot Lee's avatar
Elliot Lee committed
414 415
	}
    }
416 417
  if ((be_verbose == TRUE) || (no_splash == TRUE))
    g_print ("\n");
Elliot Lee's avatar
Elliot Lee committed
418

419
  /* create help path list and free up stuff */
420
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
421 422 423
    {
      plug_in_def = tmp->data;

424 425 426 427 428 429 430 431 432 433 434 435
      if (plug_in_def->help_path)
	{
	  PlugInHelpPathDef *help_path_def;

	  help_path_def = g_new (PlugInHelpPathDef, 1);

	  help_path_def->prog_name = g_strdup (plug_in_def->prog);
	  help_path_def->help_path = g_strdup (plug_in_def->help_path);

	  help_path_defs = g_slist_prepend (help_path_defs, help_path_def);
	}

Sven Neumann's avatar
Sven Neumann committed
436
      plug_in_def_free (plug_in_def, FALSE);
Elliot Lee's avatar
Elliot Lee committed
437
    }
438

Elliot Lee's avatar
Elliot Lee committed
439
  g_slist_free (plug_in_defs);
440
  plug_in_defs = NULL;
Elliot Lee's avatar
Elliot Lee committed
441 442
}

443

Elliot Lee's avatar
Elliot Lee committed
444
void
445
plug_in_kill (void)
Elliot Lee's avatar
Elliot Lee committed
446 447 448 449
{
  GSList *tmp;
  PlugIn *plug_in;
  
450
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
451 452
  CloseHandle (shm_handle);
#else
453
#ifdef HAVE_SHM_H
Elliot Lee's avatar
Elliot Lee committed
454 455 456
#ifndef	IPC_RMID_DEFERRED_RELEASE
  if (shm_ID != -1)
    {
457 458
      shmdt ((gchar *) shm_addr);
      shmctl (shm_ID, IPC_RMID, NULL);
Elliot Lee's avatar
Elliot Lee committed
459 460 461
    }
#else	/* IPC_RMID_DEFERRED_RELEASE */
  if (shm_ID != -1)
462
    shmdt ((gchar *) shm_addr);
Elliot Lee's avatar
Elliot Lee committed
463
#endif
464
#endif
465 466
#endif
 
Elliot Lee's avatar
Elliot Lee committed
467 468 469 470 471 472 473 474 475 476 477
  tmp = open_plug_ins;
  while (tmp)
    {
      plug_in = tmp->data;
      tmp = tmp->next;

      plug_in_destroy (plug_in);
    }
}

void
478 479 480
plug_in_add (gchar *prog,
	     gchar *menu_path,
	     gchar *accelerator)
Elliot Lee's avatar
Elliot Lee committed
481 482 483 484 485 486
{
  PlugInProcDef *proc_def;
  GSList *tmp;

  if (strncmp ("plug_in_", prog, 8) != 0)
    {
487
      gchar *t = g_strdup_printf ("plug_in_%s", prog);
Elliot Lee's avatar
Elliot Lee committed
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
      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);
}

534 535
gchar*
plug_in_image_types (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
{
  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;
}

563
GSList *
564
plug_in_extensions_parse (gchar *extensions)
Elliot Lee's avatar
Elliot Lee committed
565 566
{
  GSList *list;
567 568 569
  gchar  *extension;
  gchar  *next_token;

Elliot Lee's avatar
Elliot Lee committed
570
  list = NULL;
571

Elliot Lee's avatar
Elliot Lee committed
572 573 574 575
  /* EXTENSIONS can be NULL.  Avoid calling strtok if it is.  */
  if (extensions)
    {
      extensions = g_strdup (extensions);
576 577
      next_token = extensions;
      extension = strtok (next_token, " \t,");
Elliot Lee's avatar
Elliot Lee committed
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
      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);
}

595
PlugInProcDef *
596 597 598 599
plug_in_file_handler (gchar *name,
		      gchar *extensions,
		      gchar *prefixes,
		      gchar *magics)
Elliot Lee's avatar
Elliot Lee committed
600
{
601
  PlugInDef     *plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
  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);

640
	  /* MAGICS can be proc_def->magics  */
Elliot Lee's avatar
Elliot Lee committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654
	  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;
}

655 656 657 658 659 660 661 662 663 664

PlugInDef *
plug_in_def_new (gchar *prog)
{
  PlugInDef *plug_in_def;

  g_return_val_if_fail (prog != NULL, NULL);

  plug_in_def = g_new (PlugInDef, 1);

665 666
  plug_in_def->prog          = g_strdup (prog);
  plug_in_def->proc_defs     = NULL;
667
  plug_in_def->locale_domain = NULL;
668 669 670 671
  plug_in_def->locale_path   = NULL;
  plug_in_def->help_path     = NULL;
  plug_in_def->mtime         = 0;
  plug_in_def->query         = FALSE;
672 673 674 675 676 677 678 679 680 681 682 683
  
  return plug_in_def;
}


void
plug_in_def_free (PlugInDef *plug_in_def,
		  gboolean   free_proc_defs)
{
  GSList *list;

  g_free (plug_in_def->prog);
684 685 686
  if (plug_in_def->locale_domain) g_free (plug_in_def->locale_domain);
  if (plug_in_def->locale_path)   g_free (plug_in_def->locale_path);
  if (plug_in_def->help_path)     g_free (plug_in_def->help_path);
687

Sven Neumann's avatar
Sven Neumann committed
688
  if (free_proc_defs)
689 690
    {
      for (list = plug_in_def->proc_defs; list; list = list->next)
Sven Neumann's avatar
Sven Neumann committed
691
	plug_in_proc_def_destroy ((PlugInProcDef *)(list->data), FALSE);
692 693
    }

Sven Neumann's avatar
Sven Neumann committed
694 695 696
  if (plug_in_def->proc_defs)
    g_slist_free (plug_in_def->proc_defs);

697 698 699 700
  g_free (plug_in_def);
}


Elliot Lee's avatar
Elliot Lee committed
701 702 703
void
plug_in_def_add (PlugInDef *plug_in_def)
{
704
  PlugInDef     *tplug_in_def;
705
  PlugInProcDef *proc_def;
706 707
  GSList *tmp;
  gchar  *t1, *t2;
Elliot Lee's avatar
Elliot Lee committed
708

709
  t1 = g_basename (plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
710

711 712 713 714 715 716
  /* 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 */
717
  for (tmp = plug_in_def->proc_defs; tmp; tmp = g_slist_next (tmp))
718
    {
719
      proc_def = tmp->data;
720

721 722 723 724 725
      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)))
	{
726
	  proc_def->extensions = g_strdup ("");
727 728
	}
    }
729

730
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
731 732 733
    {
      tplug_in_def = tmp->data;

734
      t2 = g_basename (tplug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
735 736 737

      if (strcmp (t1, t2) == 0)
	{
738
	  if ((g_strcasecmp (plug_in_def->prog, tplug_in_def->prog) == 0) &&
Elliot Lee's avatar
Elliot Lee committed
739 740 741 742
	      (plug_in_def->mtime == tplug_in_def->mtime))
	    {
	      /* Use cached plug-in entry */
	      tmp->data = plug_in_def;
Sven Neumann's avatar
Sven Neumann committed
743
	      plug_in_def_free (tplug_in_def, TRUE);
Elliot Lee's avatar
Elliot Lee committed
744 745 746
	    }
	  else
	    {
Sven Neumann's avatar
Sven Neumann committed
747
	      plug_in_def_free (plug_in_def, TRUE);    
Elliot Lee's avatar
Elliot Lee committed
748
	    }
749
	  
Elliot Lee's avatar
Elliot Lee committed
750 751 752 753 754
	  return;
	}
    }

  write_pluginrc = TRUE;
755
  g_print ("\"%s\" executable not found\n", plug_in_def->prog);
756
  plug_in_def_free (plug_in_def, FALSE);
Elliot Lee's avatar
Elliot Lee committed
757 758
}

759 760
gchar *
plug_in_menu_path (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
761 762 763 764 765
{
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
  GSList *tmp, *tmp2;

766
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
767 768 769
    {
      plug_in_def = tmp->data;

770
      for (tmp2 = plug_in_def->proc_defs; tmp2; tmp2 = g_slist_next (tmp2))
Elliot Lee's avatar
Elliot Lee committed
771 772 773 774 775 776 777 778
	{
	  proc_def = tmp2->data;

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

779
  for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
780 781 782 783 784 785 786 787 788 789
    {
      proc_def = tmp->data;

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

  return NULL;
}

790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
gchar *
plug_in_help_path (gchar *prog_name)
{
  PlugInHelpPathDef *help_path_def;
  GSList *list;

  if (!prog_name || !strlen (prog_name))
    return NULL;

  for (list = help_path_defs; list; list = g_slist_next (list))
    {
      help_path_def = (PlugInHelpPathDef *) list->data;

      if (help_path_def &&
	  help_path_def->prog_name &&
	  strcmp (help_path_def->prog_name, prog_name) == 0)
	return help_path_def->help_path;
    }

  return NULL;
}

812
PlugIn *
813
plug_in_new (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
814 815
{
  PlugIn *plug_in;
816
  gchar  *path;
Elliot Lee's avatar
Elliot Lee committed
817

818
  if (!g_path_is_absolute (name))
Elliot Lee's avatar
Elliot Lee committed
819 820 821 822
    {
      path = search_in_path (plug_in_path, name);
      if (!path)
	{
823
	  g_message (_("Unable to locate Plug-In: \"%s\""), name);
Elliot Lee's avatar
Elliot Lee committed
824 825 826 827 828 829 830 831 832 833
	  return NULL;
	}
    }
  else
    {
      path = name;
    }

  plug_in = g_new (PlugIn, 1);

834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
  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");
  plug_in->args[2]            = g_new (gchar, 32);
  plug_in->args[3]            = g_new (gchar, 32);
  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
853
  plug_in->write_buffer_index = 0;
854 855 856
  plug_in->temp_proc_defs     = NULL;
  plug_in->progress           = NULL;
  plug_in->user_data          = NULL;
Elliot Lee's avatar
Elliot Lee committed
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

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

881 882 883
      if (plug_in->progress)
	progress_end (plug_in->progress);
      plug_in->progress = NULL;
884

Elliot Lee's avatar
Elliot Lee committed
885 886 887 888 889 890 891 892
      if (plug_in == current_plug_in)
	plug_in_pop ();

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

893 894 895 896 897
#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().
 */
898 899 900 901
gint
xspawnv (gint                mode,
	 const gchar        *cmdname,
	 const gchar *const *argv )
902
{
903 904 905 906
  gchar sExecutable[_MAX_PATH*2];
  gchar** sArgsList;
  gchar sCmndLine[1024];
  gchar* sPath;
907
  HINSTANCE hInst;
908 909
  gint i;
  gint pid;
910 911

  /* only use it if _spawnv fails */
912
  pid = _spawnv (mode, cmdname, argv);
913 914 915 916 917 918
  if (pid != -1) return pid;

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

  /* do we really need _spawnv (ShelExecute seems not to do it)*/
926 927 928
  if (32 <= (int) FindExecutable (cmdname, 
				  gimp_directory (),
				  sExecutable))
929
    {
930
      /* g_print("_spawnlp %s %s %s", sExecutable, cmdname, sCmndLine); */
931
      
932
      pid = _spawnlp (mode, sExecutable, "-c", cmdname, sCmndLine, NULL);
933 934 935
    }
  else
    {
936
      g_warning ("Execution error for: %s", cmdname);
937 938 939 940 941 942 943 944 945
      return -1;
    }
  return pid;
}
#undef _spawnv
#define _spawnv xspawnv

#endif /* G_OS_WIN32 */

946
gboolean
Elliot Lee's avatar
Elliot Lee committed
947 948
plug_in_open (PlugIn *plug_in)
{
949 950
  gint my_read[2];
  gint my_write[2];
Elliot Lee's avatar
Elliot Lee committed
951 952 953 954 955 956 957

  if (plug_in)
    {
      /* Open two pipes. (Bidirectional communication).
       */
      if ((pipe (my_read) == -1) || (pipe (my_write) == -1))
	{
958 959
	  g_message ("pipe() failed: Unable to start Plug-In \"%s\"\n(%s)",
		     g_basename (plug_in->args[0]), plug_in->args[0]);
960
	  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
961 962
	}

963
#if defined(G_WITH_CYGWIN) || defined(__EMX__)
964
      /* Set to binary mode */
965 966 967 968
      setmode (my_read[0], _O_BINARY);
      setmode (my_write[0], _O_BINARY);
      setmode (my_read[1], _O_BINARY);
      setmode (my_write[1], _O_BINARY);
969 970
#endif

971
#ifndef G_OS_WIN32
972 973 974
      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]);
975 976
      plug_in->his_write = g_io_channel_unix_new (my_read[1]);
#else
977 978
      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]);
979
      plug_in->his_read_fd = my_write[0];
980 981
      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]);
982
#endif
Elliot Lee's avatar
Elliot Lee committed
983 984 985

      /* Remember the file descriptors for the pipes.
       */
986
#ifndef G_OS_WIN32
987 988 989 990 991 992 993
      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));
994
      sprintf (plug_in->args[3], "%d:%u:%d",
995 996 997 998
	       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
999 1000 1001 1002 1003 1004 1005 1006 1007

      /* Set the rest of the command line arguments.
       */
      if (plug_in->query)
	{
	  plug_in->args[4] = g_strdup ("-query");
	}
      else
	{
1008 1009
	  plug_in->args[4] = g_new (gchar, 16);
	  plug_in->args[5] = g_new (gchar, 16);
Elliot Lee's avatar
Elliot Lee committed
1010 1011 1012 1013 1014 1015 1016 1017 1018

	  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.
       */
1019 1020 1021 1022
#ifdef __EMX__
      fcntl(my_read[0], F_SETFD, 1);
      fcntl(my_write[1], F_SETFD, 1);
#endif
1023
#if defined(G_OS_WIN32) || defined (G_WITH_CYGWIN) || defined(__EMX__)
Tor Lillqvist's avatar
Tor Lillqvist committed
1024
      plug_in->pid = _spawnv (_P_NOWAIT, plug_in->args[0], plug_in->args);
1025 1026
      if (plug_in->pid == -1)
#else
Elliot Lee's avatar
Elliot Lee committed
1027 1028 1029 1030
      plug_in->pid = fork ();

      if (plug_in->pid == 0)
	{
1031 1032 1033 1034 1035 1036 1037
	  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
1038 1039 1040 1041 1042 1043 1044 1045
          /* 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)
1046
#endif
Elliot Lee's avatar
Elliot Lee committed
1047
	{
1048 1049
          g_message ("fork() failed: Unable to run Plug-In: \"%s\"\n(%s)",
		     g_basename (plug_in->args[0]), plug_in->args[0]);
Elliot Lee's avatar
Elliot Lee committed
1050
          plug_in_destroy (plug_in);
1051
          return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1052 1053
	}

1054 1055 1056 1057 1058 1059 1060
      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;

1061
#ifdef G_OS_WIN32
1062 1063 1064 1065 1066
      /* 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))
	    {
1067
	      g_message ("Unable to read Plug-In's thread id");
1068
	      plug_in_destroy (plug_in);
1069
	      return FALSE;
1070 1071 1072
	    }
	}
#endif
Elliot Lee's avatar
Elliot Lee committed
1073 1074 1075

      if (!plug_in->synchronous)
	{
1076 1077 1078 1079 1080
	  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
1081 1082 1083 1084 1085

	  open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
	}

      plug_in->open = TRUE;
1086
      return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1087 1088
    }

1089
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1090 1091 1092
}

void
1093 1094
plug_in_close (PlugIn   *plug_in,
	       gboolean  kill_it)
Elliot Lee's avatar
Elliot Lee committed
1095
{
1096
  gint status;
1097
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1098
  struct timeval tv;
1099
#endif
Elliot Lee's avatar
Elliot Lee committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109

  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);
1110
	  gp_quit_write (current_writechannel);
Elliot Lee's avatar
Elliot Lee committed
1111 1112 1113
	  plug_in_pop ();

	  /*  give the plug-in some time (10 ms)  */
1114
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1115
	  tv.tv_sec = 0;
1116
	  tv.tv_usec = 100;	/* But this is 0.1 ms? */
Elliot Lee's avatar
Elliot Lee committed
1117
	  select (0, NULL, NULL, NULL, &tv);
1118 1119 1120
#else
	  Sleep (10);
#endif
Elliot Lee's avatar
Elliot Lee committed
1121 1122 1123 1124
	}

      /* If necessary, kill the filter.
       */
1125
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1126 1127 1128 1129 1130 1131 1132 1133
      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);
1134 1135
#else
      if (kill_it && plug_in->pid)
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	{
	  /* 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);
	    }
	}
1156
#endif
Elliot Lee's avatar
Elliot Lee committed
1157 1158 1159 1160 1161 1162 1163 1164

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

      /* Close the pipes.
       */
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
      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
1189

1190
      wire_clear_error ();
Elliot Lee's avatar
Elliot Lee committed
1191 1192 1193 1194

      /* Destroy the progress dialog if it exists
       */
      if (plug_in->progress)
1195 1196
	progress_end (plug_in->progress);
      plug_in->progress = NULL;
Elliot Lee's avatar
Elliot Lee committed
1197 1198 1199 1200 1201

      /* Set the fields to null values.
       */
      plug_in->pid = 0;
      plug_in->input_id = 0;
1202 1203 1204 1205
      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
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219

      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;

1220
	  for (list = plug_in->temp_proc_defs; list; list = g_slist_next (list))
Elliot Lee's avatar
Elliot Lee committed
1221 1222 1223 1224 1225 1226 1227 1228 1229
	    {
	      proc_def = (PlugInProcDef *) list->data;
	      plug_in_proc_def_remove (proc_def);
	    }

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

1230
      /* Close any dialogs that this plugin might have opened */
1231 1232 1233
      brushes_check_dialogs ();
      patterns_check_dialogs ();
      gradients_check_dialogs ();
1234

Elliot Lee's avatar
Elliot Lee committed
1235 1236 1237 1238 1239 1240 1241 1242
      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;
1243
  gint nargs;
Elliot Lee's avatar
Elliot Lee committed
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

  /* 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,
1279 1280 1281 1282
	     gint        argc,
	     gboolean    synchronous,   
	     gboolean    destroy_values,
	     gint        gdisp_ID)
Elliot Lee's avatar
Elliot Lee committed
1283
{
1284 1285 1286 1287
  GPConfig   config;
  GPProcRun  proc_run;
  Argument  *return_vals;
  PlugIn    *plug_in;
Elliot Lee's avatar
Elliot Lee committed
1288 1289 1290 1291 1292

  return_vals = NULL;

  if (proc_rec->proc_type == PDB_TEMPORARY)
    {
1293
      return_vals = plug_in_temp_run (proc_rec, args, argc);
Elliot Lee's avatar
Elliot Lee committed
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
      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);

1307 1308 1309 1310 1311
	  config.version      = GP_VERSION;
	  config.tile_width   = TILE_WIDTH;
	  config.tile_height  = TILE_HEIGHT;
	  config.shm_ID       = shm_ID;
	  config.gamma        = gamma_val;
Elliot Lee's avatar
Elliot Lee committed
1312
	  config.install_cmap = install_cmap;
1313 1314 1315 1316 1317 1318 1319 1320 1321
	  config.use_xshm     = gdk_get_use_xshm ();
	  config.gdisp_ID     = gdisp_ID;

	  if (gtk_check_version (1, 2, 8))
	    config.min_colors = CLAMP (min_colors, 27, 216);
	  else
	    config.min_colors = CLAMP (min_colors, 27, 256);

	  proc_run.name    = proc_rec->name;
1322
	  proc_run.nparams = argc;
1323
	  proc_run.params  = plug_in_args_to_params (args, argc, FALSE);
Elliot Lee's avatar
Elliot Lee committed
1324

1325 1326 1327
	  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
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
	    {
	      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
	   */
1341 1342
	  if ((proc_rec->proc_type == PDB_EXTENSION) &&
	      (proc_rec->num_args == 0))
Elliot Lee's avatar
Elliot Lee committed
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
	    gtk_main ();

	  if (plug_in->recurse)
	    {
	      gtk_main ();
	      
	      return_vals = plug_in_get_current_return_vals (proc_rec);
	    }
	}
    }
1353

1354
 done:
Elliot Lee's avatar
Elliot Lee committed
1355 1356 1357 1358 1359 1360 1361 1362 1363
  if (return_vals && destroy_values)
    {
      procedural_db_destroy_args (return_vals, proc_rec->num_values);
      return_vals = NULL;
    }
  return return_vals;
}

void
1364
plug_in_repeat (gboolean with_interface)
Elliot Lee's avatar
Elliot Lee committed
1365 1366 1367
{
  GDisplay *gdisplay;
  Argument *args;
1368
  gint i;
Elliot Lee's avatar
Elliot Lee committed
1369 1370 1371 1372

  if (last_plug_in)
    {
      gdisplay = gdisplay_active ();
Michael Natterer's avatar
Michael Natterer committed
1373
      if (!gdisplay) return;
Elliot Lee's avatar
Elliot Lee committed
1374 1375

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

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

1382
      /* initialize the first three plug-in arguments  */
Elliot Lee's avatar
Elliot Lee committed
1383
      args[0].value.pdb_int = (with_interface ? RUN_INTERACTIVE : RUN_WITH_LAST_VALS);
1384
      args[1].value.pdb_int = pdb_image_to_id(gdisplay->gimage);
1385
      args[2].value.pdb_int = drawable_ID (gimage_active_drawable (gdisplay->gimage));
Elliot Lee's avatar
Elliot Lee committed
1386 1387

      /* run the plug-in procedure */
1388
      plug_in_run (last_plug_in, args, 3, FALSE, TRUE, gdisplay->ID);
Elliot Lee's avatar
Elliot Lee committed
1389 1390 1391 1392 1393 1394

      g_free (args);
    }
}

void
1395
plug_in_set_menu_sensitivity (GimpImageType type)
Elliot Lee's avatar
Elliot Lee committed
1396 1397 1398
{
  PlugInProcDef *proc_def;
  GSList *tmp;
1399
  gboolean sensitive = FALSE;
Elliot Lee's avatar
Elliot Lee committed
1400

1401
  for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
1402 1403 1404 1405
    {
      proc_def = tmp->data;

      if (proc_def->image_types_val && proc_def->menu_path)
1406
	{
1407
	  switch (type)
1408 1409
	    {
	    case RGB_GIMAGE:
1410
	      sensitive = proc_def->image_types_val & PLUG_IN_RGB_IMAGE;
1411 1412
	      break;
	    case RGBA_GIMAGE:
1413
	      sensitive = proc_def->image_types_val & PLUG_IN_RGBA_IMAGE;
1414 1415
	      break;
	    case GRAY_GIMAGE:
1416
	      sensitive = proc_def->image_types_val & PLUG_IN_GRAY_IMAGE;
1417 1418
	      break;
	    case GRAYA_GIMAGE:
1419
	      sensitive = proc_def->image_types_val & PLUG_IN_GRAYA_IMAGE;
1420 1421
	      break;
	    case INDEXED_GIMAGE:
1422
	      sensitive = proc_def->image_types_val & PLUG_IN_INDEXED_IMAGE;
1423 1424
	      break;
	    case INDEXEDA_GIMAGE:
1425
	      sensitive = proc_def->image_types_val & PLUG_IN_INDEXEDA_IMAGE;
1426
	      break;
1427 1428 1429
	    default:
	      sensitive = FALSE;
	      break;
1430 1431
	    }

1432
	  menus_set_sensitive (proc_def->menu_path, sensitive);
1433

1434 1435
          if (last_plug_in && (last_plug_in == &(proc_def->db_info)))
	    {
Sven Neumann's avatar
Sven Neumann committed
1436 1437
	      menus_set_sensitive ("<Image>/Filters/Repeat Last", sensitive);
	      menus_set_sensitive ("<Image>/Filters/Re-Show Last", sensitive);
1438 1439
	    }
	}
Elliot Lee's avatar
Elliot Lee committed
1440
    }
1441 1442 1443 1444 1445 1446

  if (!last_plug_in)
    {
      menus_set_sensitive ("<Image>/Filters/Repeat Last", FALSE);
      menus_set_sensitive ("<Image>/Filters/Re-Show Last", FALSE);
    }
Elliot Lee's avatar
Elliot Lee committed
1447 1448
}

1449 1450 1451 1452
static gboolean
plug_in_recv_message (GIOChannel  *channel,
		      GIOCondition cond,
		      gpointer	   data)
Elliot Lee's avatar
Elliot Lee committed
1453
{
1454 1455 1456 1457
  gboolean got_message = FALSE;

  if ((PlugIn *) data != current_plug_in)
    plug_in_push ((PlugIn *) data);
Elliot Lee's avatar
Elliot Lee committed
1458

1459 1460
  if (current_readchannel == NULL)
    return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1461

1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
  if (cond & (G_IO_IN | G_IO_PRI))
    {
      WireMessage msg;

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

      if (!wire_read_msg (current_readchannel, &msg))
	{
	  plug_in_close (current_plug_in, TRUE);
	}
      else 
	{
	  plug_in_handle_message (&msg);
	  wire_destroy (&msg);
	  got_message = TRUE;
	}

    }

  if (cond & (G_IO_ERR | G_IO_HUP))
Elliot Lee's avatar
Elliot Lee committed
1482
    {
1483 1484 1485 1486
      if (current_plug_in->open)
	{
	  plug_in_close (current_plug_in, TRUE);
	}
Elliot Lee's avatar
Elliot Lee committed
1487 1488
    }

1489
  if (!got_message)
1490 1491 1492 1493
    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."),
1494 1495 1496
	       g_basename (current_plug_in->args[0]),
	       current_plug_in->args[0]);

Elliot Lee's avatar
Elliot Lee committed
1497 1498 1499 1500
  if (!current_plug_in->open)
    plug_in_destroy (current_plug_in);
  else
    plug_in_pop ();
1501

1502
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
}

static void
plug_in_handle_message (WireMessage *msg)
{
  switch (msg->type)
    {
    case GP_QUIT:
      plug_in_handle_quit ();
      break;
    case GP_CONFIG:
1514
      g_warning ("plug_in_handle_message(): received a config message (should not happen)");
Elliot Lee's avatar
Elliot Lee committed
1515 1516 1517 1518 1519 1520
      plug_in_close (current_plug_in, TRUE);
      break;
    case GP_TILE_REQ:
      plug_in_handle_tile_req (msg->data);
      break;
    case GP_TILE_ACK:
1521
      g_warning ("plug_in_handle_message(): received a tile ack message (should not happen)");
Elliot Lee's avatar
Elliot Lee committed
1522 1523 1524
      plug_in_close (current_plug_in, TRUE);
      break;
    case GP_TILE_DATA:
1525
      g_warning ("plug_in_handle_message(): received a tile data message (should not happen)");
Elliot Lee's avatar
Elliot Lee committed
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
      plug_in_close (current_plug_in, TRUE);
      break;
    case GP_PROC_RUN:
      plug_in_handle_proc_run (msg->data);
      break;
    case GP_PROC_RETURN:
      plug_in_handle_proc_return (msg->data);
      plug_in_close (current_plug_in, FALSE);
      break;
    case GP_TEMP_PROC_RUN:
1536
      g_warning ("plug_in_handle_message(): received a temp proc run message (should not happen)");
Elliot Lee's avatar
Elliot Lee committed
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
      plug_in_close (current_plug_in, TRUE);
      break;
    case GP_TEMP_PROC_RETURN:
      plug_in_handle_proc_return (msg->data);
      gtk_main_quit ();
      break;
    case GP_PROC_INSTALL:
      plug_in_handle_proc_install (msg->data);
      break;
    case GP_PROC_UNINSTALL:
      plug_in_handle_proc_uninstall (msg->data);
      break;
    case GP_EXTENSION_ACK:
      gtk_main_quit ();
      break;
1552
    case GP_REQUEST_WAKEUPS:
1553
#ifdef G_OS_WIN32
1554 1555 1556 1557 1558
      g_io_channel_win32_pipe_request_wakeups (current_plug_in->my_write,
					       current_plug_in->his_thread_id,
					       current_plug_in->his_read_fd);
#endif
      break;