GitLab repository storage has been migrated to hashed layout. Please contact Infrastructure team if you notice any issues with repositories or hooks.

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

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

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

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

Elliot Lee's avatar
Elliot Lee committed
27 28 29 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
#include <fcntl.h>
#include <io.h>
53 54 55
#ifndef S_ISREG
#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
56 57
#endif

Manish Singh's avatar
Manish Singh committed
58
#ifdef G_WITH_CYGWIN
Tor Lillqvist's avatar
Tor Lillqvist committed
59 60 61 62 63 64 65 66
#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
67 68 69 70 71
#ifdef __EMX__
#include <fcntl.h>
#include <process.h>
#define _O_BINARY O_BINARY
#define _P_NOWAIT P_NOWAIT
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
72
#define xspawnv spawnv
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
73 74
#endif

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

83 84 85
#include "libgimpbase/gimpbase.h"
#include "libgimpbase/gimpprotocol.h"
#include "libgimpbase/gimpwire.h"
86

87
#include "display/display-types.h"
88

Michael Natterer's avatar
Michael Natterer committed
89 90 91
#include "base/tile.h"
#include "base/tile-manager.h"

92
#include "core/gimp.h"
Michael Natterer's avatar
Michael Natterer committed
93
#include "core/gimpcoreconfig.h"
94
#include "core/gimpdatafiles.h"
95 96
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
97

98 99
#include "display/gimpdisplay.h"

100 101 102 103 104
#include "gui/brush-select.h"
#include "gui/gradient-select.h"
#include "gui/menus.h"
#include "gui/pattern-select.h"

105
#include "app_procs.h"
Elliot Lee's avatar
Elliot Lee committed
106
#include "appenv.h"
107
#include "errors.h"
108
#include "gimpprogress.h"
Elliot Lee's avatar
Elliot Lee committed
109 110 111
#include "gimprc.h"
#include "plug_in.h"

112 113
#include "libgimp/gimpintl.h"

114

115
typedef struct _PlugInBlocked PlugInBlocked;
Elliot Lee's avatar
Elliot Lee committed
116 117 118 119

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


124 125 126 127 128 129
typedef struct _PlugInMenuEntry PlugInMenuEntry;

struct _PlugInMenuEntry
{
  PlugInProcDef *proc_def;
  gchar         *domain;
130 131 132 133 134 135 136 137 138 139
  gchar         *help_path;
};


typedef struct _PlugInHelpPathDef PlugInHelpPathDef;

struct _PlugInHelpPathDef
{
  gchar *prog_name;
  gchar *help_path;
140 141 142
};


143
static gboolean plug_in_write             (GIOChannel	     *channel,
Elliot Lee's avatar
Elliot Lee committed
144 145
					   guint8            *buf,
				           gulong             count);
146 147 148
static gboolean plug_in_flush             (GIOChannel        *channel);
static void     plug_in_push              (PlugIn            *plug_in);
static void     plug_in_pop               (void);
Tor Lillqvist's avatar
Tor Lillqvist committed
149 150 151
static gboolean plug_in_recv_message	  (GIOChannel	     *channel,
					   GIOCondition	      cond,
					   gpointer	      data);
Elliot Lee's avatar
Elliot Lee committed
152 153 154 155 156 157 158
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);
159
static void plug_in_write_rc              (const gchar       *filename);
160 161
static void plug_in_init_file             (const gchar       *filename,
					   gpointer           loader_data);
162
static void plug_in_query                 (PlugInDef         *plug_in_def);
Elliot Lee's avatar
Elliot Lee committed
163 164
static void plug_in_add_to_db             (void);
static void plug_in_make_menu             (void);
165 166 167
static gint plug_in_make_menu_entry       (gpointer           foo,
					   PlugInMenuEntry   *menu_entry,
					   gpointer           bar);
Elliot Lee's avatar
Elliot Lee committed
168 169
static void plug_in_callback              (GtkWidget         *widget,
					   gpointer           client_data);
170
static void plug_in_proc_def_insert       (PlugInProcDef     *proc_def,
171 172
					   void (* superceed_fn) (void *));
static void plug_in_proc_def_dead         (void              *freed_proc_def);
Elliot Lee's avatar
Elliot Lee committed
173 174
static void plug_in_proc_def_remove       (PlugInProcDef     *proc_def);
static void plug_in_proc_def_destroy      (PlugInProcDef     *proc_def,
175
					   gboolean           data_only);
Elliot Lee's avatar
Elliot Lee committed
176

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
static Argument * plug_in_temp_run       (ProcRecord *proc_rec,
					  Argument   *args,
					  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);

194 195
static gchar    * plug_in_search_in_path (gchar      *search_path,
					  gchar      *filename);
196

197
PlugIn *current_plug_in = NULL;
198
GSList *proc_defs       = NULL;
Elliot Lee's avatar
Elliot Lee committed
199

200
static GSList *plug_in_defs     = NULL;
Elliot Lee's avatar
Elliot Lee committed
201
static GSList *gimprc_proc_defs = NULL;
202
static GSList *open_plug_ins    = NULL;
Elliot Lee's avatar
Elliot Lee committed
203 204
static GSList *blocked_plug_ins = NULL;

205 206 207 208 209
static GSList *help_path_defs = NULL;

static GSList     *plug_in_stack              = NULL;
static GIOChannel *current_readchannel        = NULL;
static GIOChannel *current_writechannel       = NULL;
210
static gint        current_write_buffer_index = 0;
211 212 213
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
214 215 216

static ProcRecord *last_plug_in = NULL;

217
static gint    shm_ID = -1;
Elliot Lee's avatar
Elliot Lee committed
218 219
static guchar *shm_addr = NULL;

Manish Singh's avatar
Manish Singh committed
220
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
221 222 223
static HANDLE shm_handle;
#endif

224
static gboolean write_pluginrc = FALSE;
Elliot Lee's avatar
Elliot Lee committed
225

226
static gchar *std_plugins_domain = "gimp-std-plugins";
227 228 229 230 231 232 233 234 235 236 237 238 239 240


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)
241
    g_message ("shmget() failed: Disabling shared memory tile transport.");
242 243
  else
    {
244 245
      shm_addr = (guchar *) shmat (shm_ID, NULL, 0);
      if (shm_addr == (guchar *) -1)
246
	{
247
	  g_message ("shmat() failed: Disabling shared memory tile transport.");
248
	  shmctl (shm_ID, IPC_RMID, NULL);
249 250 251 252
	  shm_ID = -1;
	}
      
#ifdef	IPC_RMID_DEFERRED_RELEASE
253 254
      if (shm_addr != (guchar *) -1)
	shmctl (shm_ID, IPC_RMID, NULL);
255 256 257
#endif
    }
#else
Manish Singh's avatar
Manish Singh committed
258
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
259 260 261
  /* Use Win32 shared memory mechanisms for
   * transfering tile data.
   */
262 263 264
  gint  pid;
  gchar fileMapName[MAX_PATH];
  gint  tileByteSize = TILE_WIDTH * TILE_HEIGHT * 4;
265 266 267 268 269
  
  /* Our shared memory id will be our process ID */
  pid = GetCurrentProcessId ();
  
  /* From the id, derive the file map name */
270 271
  g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", pid);

272 273 274 275 276 277 278 279 280
  /* 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,
281
					  FILE_MAP_ALL_ACCESS,
282 283 284 285 286
					  0, 0, tileByteSize);
      
      /* Verify that we mapped our view */
      if (shm_addr)
	shm_ID = pid;
287 288 289 290
      else
	{
	  g_warning ("MapViewOfFile error: %d... disabling shared memory transport\n", GetLastError());
	}
291 292 293 294 295 296 297 298 299
    }
  else
    {
      g_warning ("CreateFileMapping error: %d... disabling shared memory transport\n", GetLastError());
    }
#endif
#endif
}

Elliot Lee's avatar
Elliot Lee committed
300
void
301
plug_in_init (void)
Elliot Lee's avatar
Elliot Lee committed
302
{
303
  extern gboolean use_shm;
304 305 306 307

  gchar         *filename;
  GSList        *tmp;
  GSList        *tmp2;
308
  PlugInDef     *plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
309
  PlugInProcDef *proc_def;
310 311
  gfloat         nplugins;
  gfloat         nth;
Elliot Lee's avatar
Elliot Lee committed
312 313 314 315 316 317 318 319 320 321 322 323 324

  /* 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)
325 326
    plug_in_init_shm ();

Elliot Lee's avatar
Elliot Lee committed
327
  /* search for binaries in the plug-in directory path */
328 329
  gimp_datafiles_read_directories (the_gimp->config->plug_in_path, 
                                   MODE_EXECUTABLE,
Michael Natterer's avatar
Michael Natterer committed
330
				   plug_in_init_file, NULL);
Elliot Lee's avatar
Elliot Lee committed
331 332

  /* read the pluginrc file for cached data */
Tor Lillqvist's avatar
Tor Lillqvist committed
333
  filename = NULL;
334
  if (the_gimp->config->pluginrc_path)
335
    {
336 337
      if (g_path_is_absolute (the_gimp->config->pluginrc_path))
        filename = g_strdup (the_gimp->config->pluginrc_path);
338
      else
Tor Lillqvist's avatar
Tor Lillqvist committed
339
        filename = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
Michael Natterer's avatar
Michael Natterer committed
340
				    gimp_directory (),
341
				    the_gimp->config->pluginrc_path);
342 343
    }
  else
Tor Lillqvist's avatar
Tor Lillqvist committed
344
    filename = gimp_personal_rc_file ("pluginrc");
345

346
  app_init_update_status (_("Resource configuration"), filename, -1);
347
  gimprc_parse_file (filename);
Elliot Lee's avatar
Elliot Lee committed
348 349 350 351 352

  /* query any plug-ins that have changed since we last wrote out
   *  the pluginrc file.
   */
  tmp = plug_in_defs;
353 354
  app_init_update_status (_("Plug-ins"), "", 0);
  nplugins = g_slist_length (tmp);
355
  nth = 0;
Elliot Lee's avatar
Elliot Lee committed
356 357 358 359 360 361 362 363
  while (tmp)
    {
      plug_in_def = tmp->data;
      tmp = tmp->next;

      if (plug_in_def->query)
	{
	  write_pluginrc = TRUE;
364 365

	  if (be_verbose)
366
	    g_print (_("query plug-in: \"%s\"\n"), plug_in_def->prog);
367

368
	  plug_in_query (plug_in_def);
Elliot Lee's avatar
Elliot Lee committed
369
	}
370

371
      app_init_update_status (NULL, plug_in_def->prog, nth / nplugins);
372
      nth++;
Elliot Lee's avatar
Elliot Lee committed
373 374 375
    }

  /* insert the proc defs */
376
  for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
377 378 379
    {
      proc_def = g_new (PlugInProcDef, 1);
      *proc_def = *((PlugInProcDef*) tmp->data);
380
      plug_in_proc_def_insert (proc_def, NULL);
Elliot Lee's avatar
Elliot Lee committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394
    }

  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
395
 	  proc_def->mtime = plug_in_def->mtime; 
396
	  plug_in_proc_def_insert (proc_def, plug_in_proc_def_dead);
Elliot Lee's avatar
Elliot Lee committed
397 398 399 400 401 402
	}
    }

  /* write the pluginrc file if necessary */
  if (write_pluginrc)
    {
403
      if (be_verbose)
404
	g_print (_("writing \"%s\"\n"), filename);
405

Elliot Lee's avatar
Elliot Lee committed
406 407 408
      plug_in_write_rc (filename);
    }

Tor Lillqvist's avatar
Tor Lillqvist committed
409 410
  g_free (filename);

Elliot Lee's avatar
Elliot Lee committed
411 412 413 414 415 416 417
  /* 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 */
418
  if (be_verbose)
419
    g_print (_("Starting extensions: "));
420

421
  app_init_update_status (_("Extensions"), "", 0);
422 423

  tmp = proc_defs;
424
  nplugins = g_slist_length (tmp); nth = 0;
425

Elliot Lee's avatar
Elliot Lee committed
426 427 428 429 430 431 432
  while (tmp)
    {
      proc_def = tmp->data;
      tmp = tmp->next;

      if (proc_def->prog &&
	  (proc_def->db_info.num_args == 0) &&
433
	  (proc_def->db_info.proc_type == GIMP_EXTENSION))
Elliot Lee's avatar
Elliot Lee committed
434
	{
435
	  if (be_verbose)
436
	    g_print ("%s ", proc_def->db_info.name);
437

438 439
	  app_init_update_status (NULL, proc_def->db_info.name,
				  nth / nplugins);
440

441
	  plug_in_run (&proc_def->db_info, NULL, 0, FALSE, TRUE, -1);
Elliot Lee's avatar
Elliot Lee committed
442 443
	}
    }
444 445

  if (be_verbose)
446
    g_print ("\n");
Elliot Lee's avatar
Elliot Lee committed
447

448
  /* create help path list and free up stuff */
449
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
450 451 452
    {
      plug_in_def = tmp->data;

453 454 455 456 457 458 459 460 461 462 463 464
      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
465
      plug_in_def_free (plug_in_def, FALSE);
Elliot Lee's avatar
Elliot Lee committed
466
    }
467

Elliot Lee's avatar
Elliot Lee committed
468
  g_slist_free (plug_in_defs);
469
  plug_in_defs = NULL;
Elliot Lee's avatar
Elliot Lee committed
470 471
}

472

Elliot Lee's avatar
Elliot Lee committed
473
void
474
plug_in_kill (void)
Elliot Lee's avatar
Elliot Lee committed
475 476 477 478
{
  GSList *tmp;
  PlugIn *plug_in;
  
Manish Singh's avatar
Manish Singh committed
479
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
Tor Lillqvist's avatar
Tor Lillqvist committed
480 481
  CloseHandle (shm_handle);
#else
482
#ifdef HAVE_SHM_H
Elliot Lee's avatar
Elliot Lee committed
483 484 485
#ifndef	IPC_RMID_DEFERRED_RELEASE
  if (shm_ID != -1)
    {
486 487
      shmdt ((gchar *) shm_addr);
      shmctl (shm_ID, IPC_RMID, NULL);
Elliot Lee's avatar
Elliot Lee committed
488 489 490
    }
#else	/* IPC_RMID_DEFERRED_RELEASE */
  if (shm_ID != -1)
491
    shmdt ((gchar *) shm_addr);
Elliot Lee's avatar
Elliot Lee committed
492
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
493
#endif
494 495
#endif
 
Elliot Lee's avatar
Elliot Lee committed
496 497 498 499 500 501 502 503 504 505 506
  tmp = open_plug_ins;
  while (tmp)
    {
      plug_in = tmp->data;
      tmp = tmp->next;

      plug_in_destroy (plug_in);
    }
}

void
507 508 509
plug_in_add (gchar *prog,
	     gchar *menu_path,
	     gchar *accelerator)
Elliot Lee's avatar
Elliot Lee committed
510 511
{
  PlugInProcDef *proc_def;
512
  GSList        *tmp;
Elliot Lee's avatar
Elliot Lee committed
513

Sven Neumann's avatar
Sven Neumann committed
514 515
  g_return_if_fail (prog != NULL);

Elliot Lee's avatar
Elliot Lee committed
516 517
  if (strncmp ("plug_in_", prog, 8) != 0)
    {
518
      gchar *t = g_strdup_printf ("plug_in_%s", prog);
Elliot Lee's avatar
Elliot Lee committed
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
      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;
547 548 549 550 551 552
	  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;
Elliot Lee's avatar
Elliot Lee committed
553 554 555 556 557 558
	  return;
	}
    }

  proc_def = g_new0 (PlugInProcDef, 1);
  proc_def->db_info.name = prog;
559 560
  proc_def->menu_path    = menu_path;
  proc_def->accelerator  = accelerator;
Elliot Lee's avatar
Elliot Lee committed
561 562 563 564

  gimprc_proc_defs = g_slist_prepend (gimprc_proc_defs, proc_def);
}

565
gchar *
566
plug_in_image_types (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
567
{
568
  PlugInDef     *plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
569
  PlugInProcDef *proc_def;
570
  GSList        *tmp;
Elliot Lee's avatar
Elliot Lee committed
571

Sven Neumann's avatar
Sven Neumann committed
572 573
  g_return_val_if_fail (name != NULL, NULL);

Elliot Lee's avatar
Elliot Lee committed
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
  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;
}

596
GSList *
597
plug_in_extensions_parse (gchar *extensions)
Elliot Lee's avatar
Elliot Lee committed
598 599
{
  GSList *list;
600 601 602
  gchar  *extension;
  gchar  *next_token;

Elliot Lee's avatar
Elliot Lee committed
603
  list = NULL;
604

Elliot Lee's avatar
Elliot Lee committed
605 606 607 608
  /* EXTENSIONS can be NULL.  Avoid calling strtok if it is.  */
  if (extensions)
    {
      extensions = g_strdup (extensions);
609 610
      next_token = extensions;
      extension = strtok (next_token, " \t,");
Elliot Lee's avatar
Elliot Lee committed
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
      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);
}

628
PlugInProcDef *
629 630 631 632
plug_in_file_handler (gchar *name,
		      gchar *extensions,
		      gchar *prefixes,
		      gchar *magics)
Elliot Lee's avatar
Elliot Lee committed
633
{
634
  PlugInDef     *plug_in_def;
Elliot Lee's avatar
Elliot Lee committed
635
  PlugInProcDef *proc_def;
636
  GSList        *tmp;
Elliot Lee's avatar
Elliot Lee committed
637

Sven Neumann's avatar
Sven Neumann committed
638 639
  g_return_val_if_fail (name != NULL, NULL);

Elliot Lee's avatar
Elliot Lee committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
  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);

675
	  /* MAGICS can be proc_def->magics  */
Elliot Lee's avatar
Elliot Lee committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689
	  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;
}

690 691

PlugInDef *
692
plug_in_def_new (const gchar *prog)
693 694 695 696 697 698 699
{
  PlugInDef *plug_in_def;

  g_return_val_if_fail (prog != NULL, NULL);

  plug_in_def = g_new (PlugInDef, 1);

700 701
  plug_in_def->prog          = g_strdup (prog);
  plug_in_def->proc_defs     = NULL;
702
  plug_in_def->locale_domain = NULL;
703 704 705 706
  plug_in_def->locale_path   = NULL;
  plug_in_def->help_path     = NULL;
  plug_in_def->mtime         = 0;
  plug_in_def->query         = FALSE;
707 708 709 710 711 712 713 714 715 716 717 718
  
  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);
719 720 721 722 723 724
  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);
725

Sven Neumann's avatar
Sven Neumann committed
726
  if (free_proc_defs)
727 728
    {
      for (list = plug_in_def->proc_defs; list; list = list->next)
Sven Neumann's avatar
Sven Neumann committed
729
	plug_in_proc_def_destroy ((PlugInProcDef *)(list->data), FALSE);
730 731
    }

Sven Neumann's avatar
Sven Neumann committed
732 733 734
  if (plug_in_def->proc_defs)
    g_slist_free (plug_in_def->proc_defs);

735 736 737 738
  g_free (plug_in_def);
}


Elliot Lee's avatar
Elliot Lee committed
739 740 741
void
plug_in_def_add (PlugInDef *plug_in_def)
{
742
  PlugInDef     *tplug_in_def;
743
  PlugInProcDef *proc_def;
744 745 746
  GSList        *tmp;
  gchar         *basename1;
  gchar         *basename2;
Elliot Lee's avatar
Elliot Lee committed
747

748
  basename1 = g_path_get_basename (plug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
749

750 751 752 753 754 755 756
  /*  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
   */
757
  for (tmp = plug_in_def->proc_defs; tmp; tmp = g_slist_next (tmp))
758
    {
759
      proc_def = tmp->data;
760

761 762 763 764 765
      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)))
	{
766
	  proc_def->extensions = g_strdup ("");
767 768
	}
    }
769

770
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
771 772 773
    {
      tplug_in_def = tmp->data;

774
      basename2 = g_path_get_basename (tplug_in_def->prog);
Elliot Lee's avatar
Elliot Lee committed
775

776
      if (strcmp (basename1, basename2) == 0)
Elliot Lee's avatar
Elliot Lee committed
777
	{
778
	  if ((g_ascii_strcasecmp (plug_in_def->prog, tplug_in_def->prog) == 0) &&
Elliot Lee's avatar
Elliot Lee committed
779 780 781 782
	      (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
783
	      plug_in_def_free (tplug_in_def, TRUE);
Elliot Lee's avatar
Elliot Lee committed
784 785 786
	    }
	  else
	    {
Sven Neumann's avatar
Sven Neumann committed
787
	      plug_in_def_free (plug_in_def, TRUE);    
Elliot Lee's avatar
Elliot Lee committed
788
	    }
789 790 791

	  g_free (basename2);

Elliot Lee's avatar
Elliot Lee committed
792 793
	  return;
	}
794 795

      g_free (basename2);
Elliot Lee's avatar
Elliot Lee committed
796 797
    }

798 799
  g_free (basename1);

Elliot Lee's avatar
Elliot Lee committed
800
  write_pluginrc = TRUE;
Sven Neumann's avatar
Sven Neumann committed
801
  g_print ("\"%s\" executable not found\n", plug_in_def->prog);
802
  plug_in_def_free (plug_in_def, FALSE);
Elliot Lee's avatar
Elliot Lee committed
803 804
}

805 806
gchar *
plug_in_menu_path (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
807 808 809 810 811
{
  PlugInDef *plug_in_def;
  PlugInProcDef *proc_def;
  GSList *tmp, *tmp2;

Sven Neumann's avatar
Sven Neumann committed
812 813
  g_return_val_if_fail (name != NULL, NULL);

814
  for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
815 816 817
    {
      plug_in_def = tmp->data;

818
      for (tmp2 = plug_in_def->proc_defs; tmp2; tmp2 = g_slist_next (tmp2))
Elliot Lee's avatar
Elliot Lee committed
819 820 821 822 823 824 825 826
	{
	  proc_def = tmp2->data;

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

827
  for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
828 829 830 831 832 833 834 835 836 837
    {
      proc_def = tmp->data;

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

  return NULL;
}

838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
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;
}

860
PlugIn *
861
plug_in_new (gchar *name)
Elliot Lee's avatar
Elliot Lee committed
862 863
{
  PlugIn *plug_in;
864
  gchar  *path;
Elliot Lee's avatar
Elliot Lee committed
865

866
  if (! g_path_is_absolute (name))
Elliot Lee's avatar
Elliot Lee committed
867
    {
868
      path = plug_in_search_in_path (the_gimp->config->plug_in_path, name);
869 870

      if (! path)
Elliot Lee's avatar
Elliot Lee committed
871
	{
872
	  g_message (_("Unable to locate Plug-In: \"%s\""), name);
Elliot Lee's avatar
Elliot Lee committed
873 874 875 876 877 878 879 880 881 882
	  return NULL;
	}
    }
  else
    {
      path = name;
    }

  plug_in = g_new (PlugIn, 1);

883 884 885 886 887 888 889 890 891
  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");
892 893
  plug_in->args[2]            = NULL;
  plug_in->args[3]            = NULL;
894 895 896 897 898 899 900 901
  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
902
  plug_in->write_buffer_index = 0;
903 904 905
  plug_in->temp_proc_defs     = NULL;
  plug_in->progress           = NULL;
  plug_in->user_data          = NULL;
Elliot Lee's avatar
Elliot Lee committed
906 907 908 909 910 911 912 913 914

  return plug_in;
}

void
plug_in_destroy (PlugIn *plug_in)
{
  if (plug_in)
    {
915 916
      if (plug_in->open)
	plug_in_close (plug_in, TRUE);
Elliot Lee's avatar
Elliot Lee committed
917 918 919 920 921 922 923 924 925 926 927 928 929 930

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

931 932 933
      if (plug_in->progress)
	progress_end (plug_in->progress);
      plug_in->progress = NULL;
934

Elliot Lee's avatar
Elliot Lee committed
935 936 937 938 939 940 941 942
      if (plug_in == current_plug_in)
	plug_in_pop ();

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

Tor Lillqvist's avatar
Tor Lillqvist committed
943 944 945 946 947
#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().
 */
948 949 950
gint
xspawnv (gint                mode,
	 const gchar        *cmdname,
951
	 const gchar *const *argv)
Tor Lillqvist's avatar
Tor Lillqvist committed
952
{
953 954 955 956
  gchar sExecutable[_MAX_PATH*2];
  gchar** sArgsList;
  gchar sCmndLine[1024];
  gchar* sPath;
Tor Lillqvist's avatar
Tor Lillqvist committed
957
  HINSTANCE hInst;
958 959
  gint i;
  gint pid;
Tor Lillqvist's avatar
Tor Lillqvist committed
960 961

  /* only use it if _spawnv fails */
962
  pid = _spawnv (mode, cmdname, argv);
Tor Lillqvist's avatar
Tor Lillqvist committed
963 964 965 966 967 968
  if (pid != -1) return pid;

  /* stuff parameters into one cmndline */
  sCmndLine[0] = 0;
  for (i = 1; argv[i] != NULL; i++)
    {
969 970
       strcat (sCmndLine, argv[i]);
       strcat (sCmndLine, " ");
Tor Lillqvist's avatar
Tor Lillqvist committed
971 972
    }
  /* remove last blank */
973
  sCmndLine[strlen (sCmndLine)-1] = 0;
Tor Lillqvist's avatar
Tor Lillqvist committed
974 975

  /* do we really need _spawnv (ShelExecute seems not to do it)*/
976 977 978
  if (32 <= (int) FindExecutable (cmdname, 
				  gimp_directory (),
				  sExecutable))
Tor Lillqvist's avatar
Tor Lillqvist committed
979
    {
980
      /* g_print("_spawnlp %s %s %s", sExecutable, cmdname, sCmndLine); */
Tor Lillqvist's avatar
Tor Lillqvist committed
981
      
982
      pid = _spawnlp (mode, sExecutable, "-c", cmdname, sCmndLine, NULL);
Tor Lillqvist's avatar
Tor Lillqvist committed
983 984 985
    }
  else
    {
986
      g_warning ("Execution error for: %s", cmdname);
Tor Lillqvist's avatar
Tor Lillqvist committed
987 988 989 990 991 992 993
      return -1;
    }
  return pid;
}

#endif /* G_OS_WIN32 */

994
gboolean
Elliot Lee's avatar
Elliot Lee committed
995 996
plug_in_open (PlugIn *plug_in)
{
997 998
  gint my_read[2];
  gint my_write[2];
Elliot Lee's avatar
Elliot Lee committed
999 1000 1001 1002 1003 1004 1005

  if (plug_in)
    {
      /* Open two pipes. (Bidirectional communication).
       */
      if ((pipe (my_read) == -1) || (pipe (my_write) == -1))
	{
1006
	  g_message ("pipe() failed: Unable to start Plug-In \"%s\"\n(%s)",
1007 1008
		     g_path_get_basename (plug_in->args[0]),
		     plug_in->args[0]);
1009
	  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1010 1011
	}

Manish Singh's avatar
Manish Singh committed
1012
#if defined(G_WITH_CYGWIN) || defined(__EMX__)
Tor Lillqvist's avatar
Tor Lillqvist committed
1013
      /* Set to binary mode */
1014 1015 1016 1017
      setmode (my_read[0], _O_BINARY);
      setmode (my_write[0], _O_BINARY);
      setmode (my_read[1], _O_BINARY);
      setmode (my_write[1], _O_BINARY);
Tor Lillqvist's avatar
Tor Lillqvist committed
1018 1019
#endif

1020 1021 1022
      plug_in->my_read   = g_io_channel_unix_new (my_read[0]);
      plug_in->my_write  = g_io_channel_unix_new (my_write[1]);
      plug_in->his_read  = g_io_channel_unix_new (my_write[0]);
Tor Lillqvist's avatar
Tor Lillqvist committed
1023
      plug_in->his_write = g_io_channel_unix_new (my_read[1]);
Elliot Lee's avatar
Elliot Lee committed
1024

1025 1026 1027 1028 1029
      g_io_channel_set_encoding (plug_in->my_read, NULL, NULL);
      g_io_channel_set_encoding (plug_in->my_write, NULL, NULL);
      g_io_channel_set_encoding (plug_in->his_read, NULL, NULL);
      g_io_channel_set_encoding (plug_in->his_write, NULL, NULL);

1030 1031 1032 1033 1034
      g_io_channel_set_buffered (plug_in->my_read, FALSE);
      g_io_channel_set_buffered (plug_in->my_write, FALSE);
      g_io_channel_set_buffered (plug_in->his_read, FALSE);
      g_io_channel_set_buffered (plug_in->his_write, FALSE);

1035 1036 1037 1038 1039
      g_io_channel_set_close_on_unref (plug_in->my_read, TRUE);
      g_io_channel_set_close_on_unref (plug_in->my_write, TRUE);
      g_io_channel_set_close_on_unref (plug_in->his_read, TRUE);
      g_io_channel_set_close_on_unref (plug_in->his_write, TRUE);

Elliot Lee's avatar
Elliot Lee committed
1040 1041
      /* Remember the file descriptors for the pipes.
       */
1042 1043 1044 1045
      plug_in->args[2] =
	g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_read));
      plug_in->args[3] =
	g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_write));
Elliot Lee's avatar
Elliot Lee committed
1046 1047 1048 1049 1050 1051 1052 1053 1054

      /* Set the rest of the command line arguments.
       */
      if (plug_in->query)
	{
	  plug_in->args[4] = g_strdup ("-query");
	}
      else
	{
1055
	  plug_in->args[4] = g_strdup ("-run");
Elliot Lee's avatar
Elliot Lee committed
1056 1057
	}

1058 1059
      plug_in->args[5] = g_strdup_printf ("%d", (gint) stack_trace_mode);

Elliot Lee's avatar
Elliot Lee committed
1060 1061 1062 1063
      /* 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
1064
#ifdef __EMX__
1065 1066
      fcntl (my_read[0], F_SETFD, 1);
      fcntl (my_write[1], F_SETFD, 1);
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
1067
#endif
Manish Singh's avatar
Manish Singh committed
1068
#if defined(G_OS_WIN32) || defined (G_WITH_CYGWIN) || defined(__EMX__)
1069
      plug_in->pid = xspawnv (_P_NOWAIT, plug_in->args[0], plug_in->args);
Tor Lillqvist's avatar
Tor Lillqvist committed
1070 1071
      if (plug_in->pid == -1)
#else
Elliot Lee's avatar
Elliot Lee committed
1072 1073 1074 1075
      plug_in->pid = fork ();

      if (plug_in->pid == 0)
	{
1076 1077
	  g_io_channel_unref (plug_in->my_read);
	  plug_in->my_read  = NULL;
1078

1079 1080 1081
	  g_io_channel_unref (plug_in->my_write);
	  plug_in->my_write  = NULL;

Elliot Lee's avatar
Elliot Lee committed
1082 1083 1084 1085 1086 1087 1088 1089
          /* 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
1090
#endif
Elliot Lee's avatar
Elliot Lee committed
1091
	{
1092
          g_message ("fork() failed: Unable to run Plug-In: \"%s\"\n(%s)",
1093 1094
		     g_path_get_basename (plug_in->args[0]),
		     plug_in->args[0]);
Elliot Lee's avatar
Elliot Lee committed
1095
          plug_in_destroy (plug_in);
1096
          return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1097 1098
	}

Tor Lillqvist's avatar
Tor Lillqvist committed
1099 1100
      g_io_channel_unref (plug_in->his_read);
      plug_in->his_read  = NULL;
1101

Tor Lillqvist's avatar
Tor Lillqvist committed
1102 1103 1104
      g_io_channel_unref (plug_in->his_write);
      plug_in->his_write = NULL;

Elliot Lee's avatar
Elliot Lee committed
1105 1106
      if (!plug_in->synchronous)
	{
1107 1108 1109 1110 1111
	  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
1112 1113 1114 1115 1116

	  open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
	}

      plug_in->open = TRUE;
1117
      return TRUE;
Elliot Lee's avatar
Elliot Lee committed
1118 1119
    }

1120
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1121 1122 1123
}

void
1124 1125
plug_in_close (PlugIn   *plug_in,
	       gboolean  kill_it)
Elliot Lee's avatar
Elliot Lee committed
1126
{
1127
  gint status;
1128
#ifndef G_OS_WIN32
Elliot Lee's avatar
Elliot Lee committed
1129
  struct timeval tv;
Tor Lillqvist's avatar
Tor Lillqvist committed
1130
#endif
Elliot Lee's avatar
Elliot Lee committed
1131

1132 1133
  g_return_if_fail (plug_in != NULL);
  g_return_if_fail (plug_in->open == TRUE);
Elliot Lee's avatar
Elliot Lee committed
1134

1135 1136 1137 1138
  if (! plug_in->open)
    return;

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

1140 1141 1142 1143 1144 1145 1146 1147
  /*  Ask the filter to exit gracefully  */
  if (kill_it && plug_in->pid)
    {
      plug_in_push (plug_in);
      gp_quit_write (current_writechannel);
      plug_in_pop ();

      /*  give the plug-in some time (10 ms)  */
1148
#ifndef G_OS_WIN32
1149 1150 1151
      tv.tv_sec  = 0;
      tv.tv_usec = 100;	/* But this is 0.1 ms? */
      select (0, NULL, NULL, NULL, &tv);
Tor Lillqvist's avatar
Tor Lillqvist committed
1152
#else
1153
      Sleep (10);
Tor Lillqvist's avatar
Tor Lillqvist committed
1154
#endif
1155
    }
Elliot Lee's avatar
Elliot Lee committed
1156

1157
  /* If necessary, kill the filter. */
1158
#ifndef G_OS_WIN32
1159 1160
  if (kill_it && plug_in->pid)
    status = kill (plug_in->pid, SIGKILL);
Elliot Lee's avatar
Elliot Lee committed
1161

1162 1163 1164 1165 1166
  /* 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
1167
#else
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
  if (kill_it && plug_in->pid)
    {
      /* Trying to avoid TerminateProcess (does mostly work).
       * Otherwise some of our needed DLLs may get into an unstable state
       * (see Win32 API docs).
       */
      DWORD dwExitCode = STILL_ACTIVE;
      DWORD dwTries  = 10;
      while ((STILL_ACTIVE == dwExitCode)
	     && GetExitCodeProcess((HANDLE) plug_in->pid, &dwExitCode)
	     && (dwTries > 0))
Tor Lillqvist's avatar
Tor Lillqvist committed
1179
	{
1180 1181
	  Sleep(10);
	  dwTries--;
Tor Lillqvist's avatar
Tor Lillqvist committed
1182
	}
1183
      if (STILL_ACTIVE == dwExitCode)
Tor Lillqvist's avatar
Tor Lillqvist committed
1184
	{
1185 1186
	  g_warning("Terminating %s ...", plug_in->args[0]);
	  TerminateProcess ((HANDLE) plug_in->pid, 0);
Tor Lillqvist's avatar
Tor Lillqvist committed
1187
	}
1188 1189
    }
#endif
Elliot Lee's avatar
Elliot Lee committed
1190

1191
  plug_in->pid = 0;
Elliot Lee's avatar
Elliot Lee committed
1192

1193 1194 1195 1196
  /* Remove the input handler. */