gimp.c 68.5 KB
Newer Older
Manish Singh's avatar
Manish Singh committed
1 2 3
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
4 5
 * gimp.c
 *
6
 * This library is free software: you can redistribute it and/or
Marc Lehmann's avatar
Marc Lehmann committed
7
 * modify it under the terms of the GNU Lesser General Public
Manish Singh's avatar
Manish Singh committed
8
 * License as published by the Free Software Foundation; either
9
 * version 3 of the License, or (at your option) any later version.
Manish Singh's avatar
Manish Singh committed
10 11 12 13 14 15
 *
 * This library 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
 * Library General Public License for more details.
 *
Marc Lehmann's avatar
Marc Lehmann committed
16
 * You should have received a copy of the GNU Lesser General Public
17 18
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
Manish Singh's avatar
Manish Singh committed
19
 */
20

Elliot Lee's avatar
Elliot Lee committed
21 22
#include "config.h"

23
#define _GNU_SOURCE  /* for the sigaction stuff */
24

Elliot Lee's avatar
Elliot Lee committed
25 26 27 28 29 30
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
31

32
#ifdef HAVE_SYS_TIME_H
Elliot Lee's avatar
Elliot Lee committed
33
#include <sys/time.h>
34
#endif
35

36
#ifdef HAVE_SYS_PARAM_H
Elliot Lee's avatar
Elliot Lee committed
37
#include <sys/param.h>
38
#endif
39

40 41 42
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
43

44
#ifdef HAVE_UNISTD_H
Elliot Lee's avatar
Elliot Lee committed
45
#include <unistd.h>
46
#endif
47 48 49 50 51

#ifndef WAIT_ANY
#define WAIT_ANY -1
#endif

52
#include <gtk/gtk.h> /* need GDK_WINDOWING_FOO defines */
53

Manish Singh's avatar
Manish Singh committed
54
#ifndef G_OS_WIN32
55
#include "libgimpbase/gimpsignal.h"
56

57 58
#else

59 60 61 62 63
#ifdef HAVE_EXCHNDL
#include <time.h>
#include <exchndl.h>
#endif

Manish Singh's avatar
Manish Singh committed
64 65
#include <signal.h>
#endif
66

67 68 69 70 71 72
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#if defined(USE_SYSV_SHM)

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

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

81 82 83 84
#elif defined(USE_POSIX_SHM)

#ifdef HAVE_UNISTD_H
#include <unistd.h>
Elliot Lee's avatar
Elliot Lee committed
85 86
#endif

87 88 89 90 91
#include <fcntl.h>
#include <sys/mman.h>

#endif /* USE_POSIX_SHM */

92 93 94 95
#ifdef GDK_WINDOWING_QUARTZ
#include <Cocoa/Cocoa.h>
#endif

96
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
97 98 99
#  ifdef STRICT
#  undef STRICT
#  endif
100
#  define STRICT
101 102 103 104

#  ifdef _WIN32_WINNT
#  undef _WIN32_WINNT
#  endif
105
#  define _WIN32_WINNT 0x0601
106

107
#  include <windows.h>
108
#  include <tlhelp32.h>
109
#  undef RGB
110
#  define USE_WIN32_SHM 1
111
#endif
112

113 114
#include <locale.h>

115
#include "libgimpbase/gimpbase.h"
116
#include "libgimpbase/gimpbase-private.h"
117 118 119
#include "libgimpbase/gimpprotocol.h"
#include "libgimpbase/gimpwire.h"

Elliot Lee's avatar
Elliot Lee committed
120
#include "gimp.h"
121
#include "gimpunitcache.h"
Elliot Lee's avatar
Elliot Lee committed
122

123 124
#include "libgimp-intl.h"

125

126 127 128 129 130 131 132 133 134 135 136
/**
 * SECTION: gimp
 * @title: Gimp
 * @short_description: Main functions needed for building a GIMP plug-in.
 *                     This header includes all other GIMP Library headers.
 *
 * Main functions needed for building a GIMP plug-in. This header
 * includes all other GIMP Library headers.
 **/


137
#define TILE_MAP_SIZE (_tile_width * _tile_height * 32)
138 139 140

#define ERRMSG_SHM_FAILED "Could not attach to gimp shared memory segment"

141
/* Maybe this should go in a public header if we add other things to it */
142 143
typedef enum
{
144 145 146 147 148 149 150 151
  GIMP_DEBUG_PID            = 1 << 0,
  GIMP_DEBUG_FATAL_WARNINGS = 1 << 1,
  GIMP_DEBUG_QUERY          = 1 << 2,
  GIMP_DEBUG_INIT           = 1 << 3,
  GIMP_DEBUG_RUN            = 1 << 4,
  GIMP_DEBUG_QUIT           = 1 << 5,

  GIMP_DEBUG_DEFAULT        = (GIMP_DEBUG_RUN | GIMP_DEBUG_FATAL_WARNINGS)
152
} GimpDebugFlag;
Elliot Lee's avatar
Elliot Lee committed
153 154 155

#define WRITE_BUFFER_SIZE  1024

156
void gimp_read_expect_msg   (GimpWireMessage *msg,
157
                             gint             type);
158

Elliot Lee's avatar
Elliot Lee committed
159

160
static void       gimp_close                   (void);
161
static void       gimp_debug_stop              (void);
162
static void       gimp_message_func            (const gchar    *log_domain,
163 164 165
                                                GLogLevelFlags  log_level,
                                                const gchar    *message,
                                                gpointer        data);
166 167 168 169
static void       gimp_fatal_func              (const gchar    *log_domain,
                                                GLogLevelFlags  flags,
                                                const gchar    *message,
                                                gpointer        data);
170 171 172 173 174
#ifdef G_OS_WIN32
#ifdef HAVE_EXCHNDL
static LONG WINAPI gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo);
#endif
#else
175
static void       gimp_plugin_sigfatal_handler (gint            sig_num);
176
#endif
177
static gboolean   gimp_plugin_io_error_handler (GIOChannel      *channel,
178 179
                                                GIOCondition     cond,
                                                gpointer         data);
180
static gboolean   gimp_write                   (GIOChannel      *channel,
181
                                                const guint8    *buf,
182
                                                gulong           count,
183 184 185
                                                gpointer         user_data);
static gboolean   gimp_flush                   (GIOChannel      *channel,
                                                gpointer         user_data);
186
static void       gimp_loop                    (void);
187 188 189 190
static void       gimp_config                  (GPConfig        *config);
static void       gimp_proc_run                (GPProcRun       *proc_run);
static void       gimp_temp_proc_run           (GPProcRun       *proc_run);
static void       gimp_process_message         (GimpWireMessage *msg);
191
static void       gimp_single_message          (void);
192 193 194
static gboolean   gimp_extension_read          (GIOChannel      *channel,
                                                GIOCondition     condition,
                                                gpointer         data);
195

196 197 198
static void       gimp_set_pdb_error           (const GimpParam *return_vals,
                                                gint             n_return_vals);

199

200 201 202 203 204 205 206
#if defined G_OS_WIN32 && defined HAVE_EXCHNDL
static LPTOP_LEVEL_EXCEPTION_FILTER  _prevExceptionFilter    = NULL;
static gchar                         *plug_in_backtrace_path = NULL;
#endif

static GIOChannel                   *_readchannel            = NULL;
GIOChannel                          *_writechannel           = NULL;
207

208
#ifdef USE_WIN32_SHM
209 210
static HANDLE shm_handle;
#endif
Manish Singh's avatar
Manish Singh committed
211

212 213 214 215
static gint           _tile_width        = -1;
static gint           _tile_height       = -1;
static gint           _shm_ID            = -1;
static guchar        *_shm_addr          = NULL;
216
static const gdouble  _gamma_val         = 2.2;
217 218
static gboolean       _install_cmap      = FALSE;
static gboolean       _show_tool_tips    = TRUE;
219
static gboolean       _show_help_button  = TRUE;
220 221 222
static gboolean       _export_exif       = FALSE;
static gboolean       _export_xmp        = FALSE;
static gboolean       _export_iptc       = FALSE;
223 224 225 226 227 228 229
static GimpCheckSize  _check_size        = GIMP_CHECK_SIZE_MEDIUM_CHECKS;
static GimpCheckType  _check_type        = GIMP_CHECK_TYPE_GRAY_CHECKS;
static gint           _min_colors        = 144;
static gint           _gdisp_ID          = -1;
static gchar         *_wm_class          = NULL;
static gchar         *_display_name      = NULL;
static gint           _monitor_number    = 0;
230
static guint32        _timestamp         = 0;
231
static const gchar   *progname           = NULL;
Elliot Lee's avatar
Elliot Lee committed
232

233 234
static gchar          write_buffer[WRITE_BUFFER_SIZE];
static gulong         write_buffer_index = 0;
Elliot Lee's avatar
Elliot Lee committed
235

236 237
static GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_NEVER;

238
static GHashTable    *temp_proc_ht       = NULL;
Elliot Lee's avatar
Elliot Lee committed
239

240
static guint          gimp_debug_flags   = 0;
241

242 243 244 245 246 247 248 249 250 251
static const GDebugKey gimp_debug_keys[] =
{
  { "pid",            GIMP_DEBUG_PID            },
  { "fatal-warnings", GIMP_DEBUG_FATAL_WARNINGS },
  { "fw",             GIMP_DEBUG_FATAL_WARNINGS },
  { "query",          GIMP_DEBUG_QUERY          },
  { "init",           GIMP_DEBUG_INIT           },
  { "run",            GIMP_DEBUG_RUN            },
  { "quit",           GIMP_DEBUG_QUIT           },
  { "on",             GIMP_DEBUG_DEFAULT        }
252 253
};

254
static GimpPlugInInfo PLUG_IN_INFO;
Elliot Lee's avatar
Elliot Lee committed
255 256


257 258 259 260
static GimpPDBStatusType  pdb_error_status   = GIMP_PDB_SUCCESS;
static gchar             *pdb_error_message  = NULL;


261 262 263 264 265
/**
 * gimp_main:
 * @info: the PLUG_IN_INFO structure
 * @argc: the number of arguments
 * @argv: the arguments
266
 *
267 268
 * The main procedure that must be called with the PLUG_IN_INFO structure
 * and the 'argc' and 'argv' that are passed to "main".
269
 *
270 271
 * Returns: an exit status as defined by the C library,
 *          on success %EXIT_SUCCESS.
272 273
 **/
gint
274
gimp_main (const GimpPlugInInfo *info,
275
           gint                  argc,
276
           gchar                *argv[])
Elliot Lee's avatar
Elliot Lee committed
277
{
278 279 280 281 282 283 284 285 286 287 288 289
  enum
  {
    ARG_PROGNAME,
    ARG_GIMP,
    ARG_READ_FD,
    ARG_WRITE_FD,
    ARG_MODE,
    ARG_STACK_TRACE_MODE,

    N_ARGS
  };

290 291 292
  gchar       *basename;
  const gchar *env_string;
  gchar       *debug_string;
293

294
#ifdef G_OS_WIN32
295
  gint i, j, k;
296

297 298 299 300 301
  /* Reduce risks */
  {
    typedef BOOL (WINAPI *t_SetDllDirectoryA) (LPCSTR lpPathName);
    t_SetDllDirectoryA p_SetDllDirectoryA;

302 303
    p_SetDllDirectoryA = (t_SetDllDirectoryA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
                                                              "SetDllDirectoryA");
304 305 306
    if (p_SetDllDirectoryA)
      (*p_SetDllDirectoryA) ("");
  }
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

  /* On Windows, set DLL search path to $INSTALLDIR/bin so that GEGL
     file operations can find their respective file library DLLs (such
     as jasper, etc.) without needing to set external PATH. */
  {
    const gchar *install_dir;
    gchar       *bin_dir;
    LPWSTR       w_bin_dir;
    int          n;

    w_bin_dir = NULL;
    install_dir = gimp_installation_directory ();
    bin_dir = g_build_filename (install_dir, "bin", NULL);

    n = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
                             bin_dir, -1, NULL, 0);
    if (n == 0)
      goto out;

    w_bin_dir = g_malloc_n (n + 1, sizeof (wchar_t));
    n = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
                             bin_dir, -1,
                             w_bin_dir, (n + 1) * sizeof (wchar_t));
    if (n == 0)
      goto out;

    SetDllDirectoryW (w_bin_dir);

  out:
    if (w_bin_dir)
      g_free (w_bin_dir);
    g_free (bin_dir);
  }

341 342 343
#ifdef HAVE_EXCHNDL
  /* Use Dr. Mingw (dumps backtrace on crash) if it is available. */
  {
344 345 346
    time_t  t;
    gchar  *filename;
    gchar  *dir;
347 348 349 350 351 352 353 354 355 356 357 358 359

    /* This has to be the non-roaming directory (i.e., the local
       directory) as backtraces correspond to the binaries on this
       system. */
    dir = g_build_filename (g_get_user_data_dir (),
                            GIMPDIR, GIMP_USER_VERSION, "CrashLog",
                            NULL);
    /* Ensure the path exists. */
    g_mkdir_with_parents (dir, 0700);

    time (&t);
    filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt",
                                g_get_prgname(), t);
360
    plug_in_backtrace_path = g_build_filename (dir, filename, NULL);
361 362 363
    g_free (filename);
    g_free (dir);

364 365 366 367 368
    /* Similar to core crash handling in app/signals.c, the order here
     * is very important!
     */
    if (! _prevExceptionFilter)
      _prevExceptionFilter = SetUnhandledExceptionFilter (gimp_plugin_sigfatal_handler);
369

370 371
    ExcHndlInit ();
    ExcHndlSetLogFileNameA (plug_in_backtrace_path);
372 373 374
  }
#endif

375 376 377 378 379 380
#ifndef _WIN64
  {
    typedef BOOL (WINAPI *t_SetProcessDEPPolicy) (DWORD dwFlags);
    t_SetProcessDEPPolicy p_SetProcessDEPPolicy;

    p_SetProcessDEPPolicy = GetProcAddress (GetModuleHandle ("kernel32.dll"),
Jehan's avatar
Jehan committed
381
                                            "SetProcessDEPPolicy");
382 383 384 385 386
    if (p_SetProcessDEPPolicy)
      (*p_SetProcessDEPPolicy) (PROCESS_DEP_ENABLE|PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
  }
#endif

387 388 389 390 391
  /* Group all our windows together on the taskbar */
  {
    typedef HRESULT (WINAPI *t_SetCurrentProcessExplicitAppUserModelID) (PCWSTR lpPathName);
    t_SetCurrentProcessExplicitAppUserModelID p_SetCurrentProcessExplicitAppUserModelID;

392 393
    p_SetCurrentProcessExplicitAppUserModelID = (t_SetCurrentProcessExplicitAppUserModelID) GetProcAddress (GetModuleHandle ("shell32.dll"),
                                                                                                            "SetCurrentProcessExplicitAppUserModelID");
394 395 396 397
    if (p_SetCurrentProcessExplicitAppUserModelID)
      (*p_SetCurrentProcessExplicitAppUserModelID) (L"gimp.GimpApplication");
  }

398 399 400 401 402 403 404 405
  /* Check for exe file name with spaces in the path having been split up
   * by buggy NT C runtime, or something. I don't know why this happens
   * on NT (including w2k), but not on w95/98.
   */

  for (i = 1; i < argc; i++)
    {
      k = strlen (argv[i]);
406

407
      if (k > 10)
408 409 410 411 412 413 414
        {
          if (g_ascii_strcasecmp (argv[i] + k - 4, ".exe") == 0)
            {
              /* Found the end of the executable name, most probably.
               * Splice the parts of the name back together.
               */
              GString *s;
415

416
              s = g_string_new (argv[ARG_PROGNAME]);
417

418 419 420 421 422
              for (j = 1; j <= i; j++)
                {
                  s = g_string_append_c (s, ' ');
                  s = g_string_append (s, argv[j]);
                }
423

424
              argv[ARG_PROGNAME] = s->str;
425

426 427 428
              /* Move rest of argv down */
              for (j = 1; j < argc - i; j++)
                argv[j] = argv[j + i];
429

430 431
              argv[argc - i] = NULL;
              argc -= i;
432

433 434
              break;
          }
435
       }
436
    }
437 438
#endif

439 440 441 442
  g_assert (info != NULL);

  PLUG_IN_INFO = *info;

443
  if ((argc != N_ARGS) || (strcmp (argv[ARG_GIMP], "-gimp") != 0))
Elliot Lee's avatar
Elliot Lee committed
444
    {
445
      g_printerr ("%s is a GIMP plug-in and must be run by GIMP to be used\n",
446
                  argv[ARG_PROGNAME]);
Elliot Lee's avatar
Elliot Lee committed
447 448 449
      return 1;
    }

450 451
  gimp_env_init (TRUE);

452
  progname = argv[ARG_PROGNAME];
Elliot Lee's avatar
Elliot Lee committed
453

454 455 456 457
  basename = g_path_get_basename (progname);

  g_set_prgname (basename);

458 459 460 461
  env_string = g_getenv ("GIMP_PLUGIN_DEBUG");

  if (env_string)
    {
462 463
      const gchar *debug_messages;

464 465 466 467 468 469
      debug_string = strchr (env_string, ',');

      if (debug_string)
        {
          gint len = debug_string - env_string;

470
          if ((strlen (basename) == len) &&
471 472
              (strncmp (basename, env_string, len) == 0))
            {
473 474 475 476
              gimp_debug_flags =
                g_parse_debug_string (debug_string + 1,
                                      gimp_debug_keys,
                                      G_N_ELEMENTS (gimp_debug_keys));
477 478 479 480 481 482
            }
        }
      else if (strcmp (env_string, basename) == 0)
        {
          gimp_debug_flags = GIMP_DEBUG_DEFAULT;
        }
483 484 485 486 487 488 489 490 491 492 493 494 495 496

      /*  make debug output visible by setting G_MESSAGES_DEBUG  */
      debug_messages = g_getenv ("G_MESSAGES_DEBUG");

      if (debug_messages)
        {
          gchar *tmp = g_strconcat (debug_messages, ",LibGimp", NULL);
          g_setenv ("G_MESSAGES_DEBUG", tmp, TRUE);
          g_free (tmp);
        }
      else
        {
          g_setenv ("G_MESSAGES_DEBUG", "LibGimp", TRUE);
        }
497 498
    }

499
  g_free (basename);
500

501
  stack_trace_mode = (GimpStackTraceMode) CLAMP (atoi (argv[ARG_STACK_TRACE_MODE]),
502 503
                                                 GIMP_STACK_TRACE_NEVER,
                                                 GIMP_STACK_TRACE_ALWAYS);
504

505
#ifndef G_OS_WIN32
506 507 508 509 510
  /* No use catching these on Win32, the user won't get any meaningful
   * stack trace from glib anyhow. It's better to let Windows inform
   * about the program error, and offer debugging if the plug-in
   * has been built with MSVC, and the user has MSVC installed.
   */
511 512 513
  gimp_signal_private (SIGHUP,  gimp_plugin_sigfatal_handler, 0);
  gimp_signal_private (SIGINT,  gimp_plugin_sigfatal_handler, 0);
  gimp_signal_private (SIGQUIT, gimp_plugin_sigfatal_handler, 0);
514 515 516
  gimp_signal_private (SIGTERM, gimp_plugin_sigfatal_handler, 0);

  gimp_signal_private (SIGABRT, gimp_plugin_sigfatal_handler, 0);
517 518 519 520 521 522 523 524
  gimp_signal_private (SIGBUS,  gimp_plugin_sigfatal_handler, 0);
  gimp_signal_private (SIGSEGV, gimp_plugin_sigfatal_handler, 0);
  gimp_signal_private (SIGFPE,  gimp_plugin_sigfatal_handler, 0);

  /* Ignore SIGPIPE from crashing Gimp */
  gimp_signal_private (SIGPIPE, SIG_IGN, 0);

  /* Restart syscalls interrupted by SIGCHLD */
525
  gimp_signal_private (SIGCHLD, SIG_DFL, SA_RESTART);
526
#endif
Elliot Lee's avatar
Elliot Lee committed
527

528
#ifdef G_OS_WIN32
529 530
  _readchannel  = g_io_channel_win32_new_fd (atoi (argv[ARG_READ_FD]));
  _writechannel = g_io_channel_win32_new_fd (atoi (argv[ARG_WRITE_FD]));
531
#else
532 533
  _readchannel  = g_io_channel_unix_new (atoi (argv[ARG_READ_FD]));
  _writechannel = g_io_channel_unix_new (atoi (argv[ARG_WRITE_FD]));
534
#endif
Elliot Lee's avatar
Elliot Lee committed
535

536 537 538
  g_io_channel_set_encoding (_readchannel, NULL, NULL);
  g_io_channel_set_encoding (_writechannel, NULL, NULL);

539 540 541 542 543 544
  g_io_channel_set_buffered (_readchannel, FALSE);
  g_io_channel_set_buffered (_writechannel, FALSE);

  g_io_channel_set_close_on_unref (_readchannel, TRUE);
  g_io_channel_set_close_on_unref (_writechannel, TRUE);

Elliot Lee's avatar
Elliot Lee committed
545
  gp_init ();
546 547 548

  gimp_wire_set_writer (gimp_write);
  gimp_wire_set_flusher (gimp_flush);
Elliot Lee's avatar
Elliot Lee committed
549

550
  gimp_enums_init ();
551

552 553
  /*  initialize units  */
  {
554
    GimpUnitVtable vtable;
555 556

    vtable.unit_get_number_of_units = _gimp_unit_cache_get_number_of_units;
557 558
    vtable.unit_get_number_of_built_in_units =
      _gimp_unit_cache_get_number_of_built_in_units;
559 560 561 562 563 564 565 566 567 568 569 570 571 572
    vtable.unit_new                 = _gimp_unit_cache_new;
    vtable.unit_get_deletion_flag   = _gimp_unit_cache_get_deletion_flag;
    vtable.unit_set_deletion_flag   = _gimp_unit_cache_set_deletion_flag;
    vtable.unit_get_factor          = _gimp_unit_cache_get_factor;
    vtable.unit_get_digits          = _gimp_unit_cache_get_digits;
    vtable.unit_get_identifier      = _gimp_unit_cache_get_identifier;
    vtable.unit_get_symbol          = _gimp_unit_cache_get_symbol;
    vtable.unit_get_abbreviation    = _gimp_unit_cache_get_abbreviation;
    vtable.unit_get_singular        = _gimp_unit_cache_get_singular;
    vtable.unit_get_plural          = _gimp_unit_cache_get_plural;

    gimp_base_init (&vtable);
  }

573 574 575 576 577 578 579 580 581 582 583
  /* initialize i18n support */

  setlocale (LC_ALL, "");

  bindtextdomain (GETTEXT_PACKAGE"-libgimp", gimp_locale_directory ());
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
  bind_textdomain_codeset (GETTEXT_PACKAGE"-libgimp", "UTF-8");
#endif


  /* set handler both for the "LibGimp" and "" domains */
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
  {
    const gchar * const log_domains[] =
    {
      "LibGimp",
      "LibGimpBase",
      "LibGimpColor",
      "LibGimpConfig",
      "LibGimpMath",
      "LibGimpModule",
      "LibGimpThumb",
      "LibGimpWidgets"
    };
    gint i;

    for (i = 0; i < G_N_ELEMENTS (log_domains); i++)
      g_log_set_handler (log_domains[i],
                         G_LOG_LEVEL_MESSAGE,
                         gimp_message_func,
                         NULL);

    g_log_set_handler (NULL,
                       G_LOG_LEVEL_MESSAGE,
                       gimp_message_func,
                       NULL);
  }
609

610 611 612 613 614 615 616
  if (gimp_debug_flags & GIMP_DEBUG_FATAL_WARNINGS)
    {
      GLogLevelFlags fatal_mask;

      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
      g_log_set_always_fatal (fatal_mask);
617 618 619 620 621 622 623 624 625 626 627

      g_log_set_handler (NULL,
                         G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL |
                         G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
                         gimp_fatal_func, NULL);
    }
  else
    {
      g_log_set_handler (NULL,
                         G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
                         gimp_fatal_func, NULL);
628 629
    }

630
  if (strcmp (argv[ARG_MODE], "-query") == 0)
Elliot Lee's avatar
Elliot Lee committed
631
    {
632
      if (PLUG_IN_INFO.init_proc)
633
        gp_has_init_write (_writechannel, NULL);
634 635 636 637

      if (gimp_debug_flags & GIMP_DEBUG_QUERY)
        gimp_debug_stop ();

Elliot Lee's avatar
Elliot Lee committed
638
      if (PLUG_IN_INFO.query_proc)
639
        (* PLUG_IN_INFO.query_proc) ();
640

Marc Lehmann's avatar
Marc Lehmann committed
641
      gimp_close ();
642 643

      return EXIT_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
644 645
    }

646
  if (strcmp (argv[ARG_MODE], "-init") == 0)
647
    {
648 649 650
      if (gimp_debug_flags & GIMP_DEBUG_INIT)
        gimp_debug_stop ();

651
      if (PLUG_IN_INFO.init_proc)
652
        (* PLUG_IN_INFO.init_proc) ();
653

654
      gimp_close ();
655 656

      return EXIT_SUCCESS;
657 658
    }

659 660 661
  if (gimp_debug_flags & GIMP_DEBUG_RUN)
    gimp_debug_stop ();
  else if (gimp_debug_flags & GIMP_DEBUG_PID)
662
    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Here I am!");
663

664
  temp_proc_ht = g_hash_table_new (g_str_hash, g_str_equal);
Elliot Lee's avatar
Elliot Lee committed
665

666
  g_io_add_watch (_readchannel,
667 668 669
                  G_IO_ERR | G_IO_HUP,
                  gimp_plugin_io_error_handler,
                  NULL);
670

Elliot Lee's avatar
Elliot Lee committed
671
  gimp_loop ();
672 673

  return EXIT_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
674 675
}

676 677
/**
 * gimp_quit:
678
 *
679
 * Forcefully causes the GIMP library to exit and close down its
680 681
 * connection to main gimp application. This function never returns.
 **/
Marc Lehmann's avatar
Marc Lehmann committed
682
void
683
gimp_quit (void)
Marc Lehmann's avatar
Marc Lehmann committed
684 685
{
  gimp_close ();
686

687 688 689 690 691
#if defined G_OS_WIN32 && defined HAVE_EXCHNDL
  if (plug_in_backtrace_path)
    g_free (plug_in_backtrace_path);
#endif

692
  exit (EXIT_SUCCESS);
Elliot Lee's avatar
Elliot Lee committed
693 694
}

695 696 697 698 699 700 701 702 703
/**
 * gimp_install_procedure:
 * @name:          the procedure's name.
 * @blurb:         a short text describing what the procedure does.
 * @help:          the help text for the procedure (usually considerably
 *                 longer than @blurb).
 * @author:        the procedure's author(s).
 * @copyright:     the procedure's copyright.
 * @date:          the date the procedure was added.
704 705
 * @menu_label:    the label to use for the procedure's menu entry,
 *                 or #NULL if the procedure has no menu entry.
706 707 708 709 710 711
 * @image_types:   the drawable types the procedure can handle.
 * @type:          the type of the procedure.
 * @n_params:      the number of parameters the procedure takes.
 * @n_return_vals: the number of return values the procedure returns.
 * @params:        the procedure's parameters.
 * @return_vals:   the procedure's return values.
712
 *
713 714
 * Installs a new procedure with the PDB (procedural database).
 *
715 716
 * Call this function from within your plug-in's query() function for
 * each procedure your plug-in implements.
717 718 719 720 721 722 723 724 725
 *
 * The @name parameter is mandatory and should be unique, or it will
 * overwrite an already existing procedure (overwrite procedures only
 * if you know what you're doing).
 *
 * The @blurb, @help, @author, @copyright and @date parameters are
 * optional but then you shouldn't write procedures without proper
 * documentation, should you.
 *
726
 * @menu_label defines the label that should be used for the
727 728 729 730 731
 * procedure's menu entry. The position where to register in the menu
 * hierarchy is chosen using gimp_plugin_menu_register().  This
 * function also still accepts the old (pre-2.2) way of registering a
 * menu entry and takes a string in the form
 * "&lt;Domain&gt;/Path/To/My/Menu"
732
 * (e.g. "&lt;Image&gt;/Filters/Render/Useless").
733
 *
734
 * It is possible to register a procedure only for keyboard-shortcut
735 736 737 738
 * activation by passing a @menu_label to gimp_install_procedure() but
 * not registering any menu path with gimp_plugin_menu_register(). In
 * this case, the given @menu_label will only be used as the
 * procedure's user-visible name in the keyboard shortcut editor.
739
 *
740 741 742 743 744 745
 * @image_types is a comma separated list of image types, or actually
 * drawable types, that this procedure can deal with. Wildcards are
 * possible here, so you could say "RGB*" instead of "RGB, RGBA" or
 * "*" for all image types. If the procedure doesn't need an image to
 * run, use the empty string.
 *
746
 * @type must be one of %GIMP_PLUGIN or %GIMP_EXTENSION. Note that
747 748 749
 * temporary procedures must be installed using
 * gimp_install_temp_proc().
 *
750
 * NOTE: Unlike the GIMP 1.2 API, %GIMP_EXTENSION no longer means
751 752
 * that the procedure's menu prefix is &lt;Toolbox&gt;, but that
 * it will install temporary procedures. Therefore, the GIMP core
753
 * will wait until the %GIMP_EXTENSION procedure has called
754 755 756 757
 * gimp_extension_ack(), which means that the procedure has done
 * its initialization, installed its temporary procedures and is
 * ready to run.
 *
758
 * <emphasis>Not calling gimp_extension_ack() from a %GIMP_EXTENSION
759
 * procedure will cause the GIMP core to lock up.</emphasis>
760
 *
761
 * Additionally, a %GIMP_EXTENSION procedure with no parameters
762 763 764
 * (@n_params == 0 and @params == #NULL) is an "automatic" extension
 * that will be automatically started on each GIMP startup.
 **/
Elliot Lee's avatar
Elliot Lee committed
765
void
766
gimp_install_procedure (const gchar        *name,
767 768 769 770 771 772 773 774 775 776 777 778
                        const gchar        *blurb,
                        const gchar        *help,
                        const gchar        *author,
                        const gchar        *copyright,
                        const gchar        *date,
                        const gchar        *menu_label,
                        const gchar        *image_types,
                        GimpPDBProcType     type,
                        gint                n_params,
                        gint                n_return_vals,
                        const GimpParamDef *params,
                        const GimpParamDef *return_vals)
Elliot Lee's avatar
Elliot Lee committed
779 780 781
{
  GPProcInstall proc_install;

782 783 784 785 786 787 788 789 790 791 792 793 794
  g_return_if_fail (name != NULL);
  g_return_if_fail (type != GIMP_INTERNAL);
  g_return_if_fail ((n_params == 0 && params == NULL) ||
                    (n_params > 0  && params != NULL));
  g_return_if_fail ((n_return_vals == 0 && return_vals == NULL) ||
                    (n_return_vals > 0  && return_vals != NULL));

  proc_install.name         = (gchar *) name;
  proc_install.blurb        = (gchar *) blurb;
  proc_install.help         = (gchar *) help;
  proc_install.author       = (gchar *) author;
  proc_install.copyright    = (gchar *) copyright;
  proc_install.date         = (gchar *) date;
795
  proc_install.menu_path    = (gchar *) menu_label;
796
  proc_install.image_types  = (gchar *) image_types;
797
  proc_install.type         = type;
798 799
  proc_install.nparams      = n_params;
  proc_install.nreturn_vals = n_return_vals;
800 801
  proc_install.params       = (GPParamDef *) params;
  proc_install.return_vals  = (GPParamDef *) return_vals;
Elliot Lee's avatar
Elliot Lee committed
802

803
  if (! gp_proc_install_write (_writechannel, &proc_install, NULL))
Elliot Lee's avatar
Elliot Lee committed
804 805 806
    gimp_quit ();
}

807 808 809 810 811 812 813 814 815
/**
 * gimp_install_temp_proc:
 * @name:          the procedure's name.
 * @blurb:         a short text describing what the procedure does.
 * @help:          the help text for the procedure (usually considerably
 *                 longer than @blurb).
 * @author:        the procedure's author(s).
 * @copyright:     the procedure's copyright.
 * @date:          the date the procedure was added.
816
 * @menu_label:    the procedure's menu label, or #NULL if the procedure has
817 818 819 820 821 822 823 824
 *                 no menu entry.
 * @image_types:   the drawable types the procedure can handle.
 * @type:          the type of the procedure.
 * @n_params:      the number of parameters the procedure takes.
 * @n_return_vals: the number of return values the procedure returns.
 * @params:        the procedure's parameters.
 * @return_vals:   the procedure's return values.
 * @run_proc:      the function to call for executing the procedure.
825
 *
826 827 828
 * Installs a new temporary procedure with the PDB (procedural database).
 *
 * A temporary procedure is a procedure which is only available while
829
 * one of your plug-in's "real" procedures is running.
830 831 832
 *
 * See gimp_install_procedure() for most details.
 *
833
 * @type <emphasis>must</emphasis> be %GIMP_TEMPORARY or the function
834 835 836 837 838
 * will fail.
 *
 * @run_proc is the function which will be called to execute the
 * procedure.
 *
839 840
 * NOTE: Normally, plug-in communication is triggered by the plug-in
 * and the GIMP core only responds to the plug-in's requests. You must
841
 * explicitly enable receiving of temporary procedure run requests
842 843 844 845
 * using either gimp_extension_enable() or
 * gimp_extension_process(). See this functions' documentation for
 * details.
 **/
Elliot Lee's avatar
Elliot Lee committed
846
void
847
gimp_install_temp_proc (const gchar        *name,
848 849 850 851 852 853 854 855 856 857 858 859 860
                        const gchar        *blurb,
                        const gchar        *help,
                        const gchar        *author,
                        const gchar        *copyright,
                        const gchar        *date,
                        const gchar        *menu_label,
                        const gchar        *image_types,
                        GimpPDBProcType     type,
                        gint                n_params,
                        gint                n_return_vals,
                        const GimpParamDef *params,
                        const GimpParamDef *return_vals,
                        GimpRunProc         run_proc)
Elliot Lee's avatar
Elliot Lee committed
861
{
862 863 864 865 866 867 868 869
  g_return_if_fail (name != NULL);
  g_return_if_fail ((n_params == 0 && params == NULL) ||
                    (n_params > 0  && params != NULL));
  g_return_if_fail ((n_return_vals == 0 && return_vals == NULL) ||
                    (n_return_vals > 0  && return_vals != NULL));
  g_return_if_fail (type == GIMP_TEMPORARY);
  g_return_if_fail (run_proc != NULL);

870
  gimp_install_procedure (name,
871 872 873 874 875 876 877
                          blurb, help,
                          author, copyright, date,
                          menu_label,
                          image_types,
                          type,
                          n_params, n_return_vals,
                          params, return_vals);
Elliot Lee's avatar
Elliot Lee committed
878 879

  /*  Insert the temp proc run function into the hash table  */
880
  g_hash_table_insert (temp_proc_ht, g_strdup (name), (gpointer) run_proc);
Elliot Lee's avatar
Elliot Lee committed
881 882
}

883 884 885
/**
 * gimp_uninstall_temp_proc:
 * @name: the procedure's name
886
 *
887 888 889
 * Uninstalls a temporary procedure which has previously been
 * installed using gimp_install_temp_proc().
 **/
Elliot Lee's avatar
Elliot Lee committed
890
void
891
gimp_uninstall_temp_proc (const gchar *name)
Elliot Lee's avatar
Elliot Lee committed
892 893
{
  GPProcUninstall proc_uninstall;
894 895 896 897 898 899
  gpointer        hash_name;
  gboolean        found;

  g_return_if_fail (name != NULL);

  proc_uninstall.name = (gchar *) name;
Elliot Lee's avatar
Elliot Lee committed
900

901
  if (! gp_proc_uninstall_write (_writechannel, &proc_uninstall, NULL))
Elliot Lee's avatar
Elliot Lee committed
902
    gimp_quit ();
903

904 905
  found = g_hash_table_lookup_extended (temp_proc_ht, name, &hash_name, NULL);
  if (found)
906 907
    {
      g_hash_table_remove (temp_proc_ht, (gpointer) name);
908
      g_free (hash_name);
909
    }
Elliot Lee's avatar
Elliot Lee committed
910 911
}

912 913 914 915
/**
 * gimp_run_procedure:
 * @name:          the name of the procedure to run
 * @n_return_vals: return location for the number of return values
916
 * @...:           list of procedure parameters
917 918 919
 *
 * This function calls a GIMP procedure and returns its return values.
 *
Sven Neumann's avatar
Sven Neumann committed
920
 * The procedure's parameters are given by a va_list in the format
921
 * (type, value, type, value) and must be terminated by %GIMP_PDB_END.
922
 *
Sven Neumann's avatar
Sven Neumann committed
923 924 925
 * This function converts the va_list of parameters into an array and
 * passes them to gimp_run_procedure2(). Please look there for further
 * information.
926
 *
927 928 929
 * Return value: the procedure's return values unless there was an error,
 * in which case the zero-th return value will be the error status, and
 * the first return value will be a string detailing the error.
930
 **/
931
GimpParam *
932
gimp_run_procedure (const gchar *name,
933 934
                    gint        *n_return_vals,
                    ...)
Elliot Lee's avatar
Elliot Lee committed
935
{
936 937
  GimpPDBArgType  param_type;
  GimpParam      *return_vals;
938 939
  GimpParam      *params   = NULL;
  gint            n_params = 0;
940 941
  va_list         args;
  gint            i;
Elliot Lee's avatar
Elliot Lee committed
942

943 944
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (n_return_vals != NULL, NULL);
Elliot Lee's avatar
Elliot Lee committed
945

946
  va_start (args, n_return_vals);
947
  param_type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
948

949
  while (param_type != GIMP_PDB_END)
Elliot Lee's avatar
Elliot Lee committed
950 951
    {
      switch (param_type)
952 953
        {
        case GIMP_PDB_INT32:
954 955
        case GIMP_PDB_DISPLAY:
        case GIMP_PDB_IMAGE:
956
        case GIMP_PDB_ITEM:
957 958 959 960
        case GIMP_PDB_LAYER:
        case GIMP_PDB_CHANNEL:
        case GIMP_PDB_DRAWABLE:
        case GIMP_PDB_SELECTION:
961
        case GIMP_PDB_VECTORS:
962
        case GIMP_PDB_STATUS:
963 964 965 966 967 968 969 970
          (void) va_arg (args, gint);
          break;
        case GIMP_PDB_INT16:
          (void) va_arg (args, gint);
          break;
        case GIMP_PDB_INT8:
          (void) va_arg (args, gint);
          break;
971
        case GIMP_PDB_FLOAT:
972
          (void) va_arg (args, gdouble);
Elliot Lee's avatar
Elliot Lee committed
973
          break;
974
        case GIMP_PDB_STRING:
975
          (void) va_arg (args, gchar *);
Elliot Lee's avatar
Elliot Lee committed
976
          break;
977
        case GIMP_PDB_INT32ARRAY:
978
          (void) va_arg (args, gint32 *);
Elliot Lee's avatar
Elliot Lee committed
979
          break;
980
        case GIMP_PDB_INT16ARRAY:
981
          (void) va_arg (args, gint16 *);
Elliot Lee's avatar
Elliot Lee committed
982
          break;
983
        case GIMP_PDB_INT8ARRAY:
984
          (void) va_arg (args, gint8 *);
Elliot Lee's avatar
Elliot Lee committed
985
          break;
986
        case GIMP_PDB_FLOATARRAY:
987
          (void) va_arg (args, gdouble *);
Elliot Lee's avatar
Elliot Lee committed
988
          break;
989
        case GIMP_PDB_STRINGARRAY:
990
          (void) va_arg (args, gchar **);
Elliot Lee's avatar
Elliot Lee committed
991
          break;
992
        case GIMP_PDB_COLOR:
Jehan's avatar
Jehan committed
993
        case GIMP_PDB_COLORARRAY:
994
          (void) va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
995
          break;
996
        case GIMP_PDB_PARASITE:
997
          (void) va_arg (args, GimpParasite *);
998
          break;
999 1000 1001
        case GIMP_PDB_END:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
1002

1003 1004
      n_params++;

1005
      param_type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
1006 1007 1008 1009
    }

  va_end (args);

1010
  params = g_new0 (GimpParam, n_params);
Elliot Lee's avatar
Elliot Lee committed
1011

1012
  va_start (args, n_return_vals);
Elliot Lee's avatar
Elliot Lee committed
1013

1014
  for (i = 0; i < n_params; i++)
Elliot Lee's avatar
Elliot Lee committed
1015
    {
1016
      params[i].type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
1017

1018
      switch (params[i].type)
1019 1020 1021 1022 1023 1024 1025 1026
        {
        case GIMP_PDB_INT32:
          params[i].data.d_int32 = (gint32) va_arg (args, gint);
          break;
        case GIMP_PDB_INT16:
          params[i].data.d_int16 = (gint16) va_arg (args, gint);
          break;
        case GIMP_PDB_INT8:
1027
          params[i].data.d_int8 = (guint8) va_arg (args, gint);
1028
          break;
1029
        case GIMP_PDB_FLOAT:
1030
          params[i].data.d_float = (gdouble) va_arg (args, gdouble);
Elliot Lee's avatar
Elliot Lee committed
1031
          break;
1032
        case GIMP_PDB_STRING:
1033
          params[i].data.d_string = va_arg (args, gchar *);
Elliot Lee's avatar
Elliot Lee committed
1034
          break;
1035
        case GIMP_PDB_INT32ARRAY:
1036
          params[i].data.d_int32array = va_arg (args, gint32 *);
Elliot Lee's avatar
Elliot Lee committed
1037
          break;
1038
        case GIMP_PDB_INT16ARRAY:
1039
          params[i].data.d_int16array = va_arg (args, gint16 *);
Elliot Lee's avatar
Elliot Lee committed
1040
          break;
1041
        case GIMP_PDB_INT8ARRAY:
1042
          params[i].data.d_int8array = va_arg (args, guint8 *);
Elliot Lee's avatar
Elliot Lee committed
1043
          break;
1044
        case GIMP_PDB_FLOATARRAY:
1045
          params[i].data.d_floatarray = va_arg (args, gdouble *);
Elliot Lee's avatar
Elliot Lee committed
1046
          break;
1047
        case GIMP_PDB_STRINGARRAY:
1048
          params[i].data.d_stringarray = va_arg (args, gchar **);
Elliot Lee's avatar
Elliot Lee committed
1049
          break;
1050
        case GIMP_PDB_COLOR:
1051
          params[i].data.d_color = *va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
1052
          break;
1053 1054
        case GIMP_PDB_ITEM:
          params[i].data.d_item = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1055
          break;
1056
        case GIMP_PDB_DISPLAY:
1057
          params[i].data.d_display = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1058
          break;
1059
        case GIMP_PDB_IMAGE:
1060
          params[i].data.d_image = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1061
          break;
1062
        case GIMP_PDB_LAYER:
1063
          params[i].data.d_layer = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1064
          break;
1065
        case GIMP_PDB_CHANNEL:
1066
          params[i].data.d_channel = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1067
          break;
1068
        case GIMP_PDB_DRAWABLE:
1069
          params[i].data.d_drawable = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1070
          break;
1071
        case GIMP_PDB_SELECTION:
1072
          params[i].data.d_selection = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1073
          break;
1074 1075
        case GIMP_PDB_COLORARRAY:
          params[i].data.d_colorarray = va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
1076
          break;
1077
        case GIMP_PDB_VECTORS:
1078
          params[i].data.d_vectors = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1079
          break;
1080
        case GIMP_PDB_PARASITE:
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
          {
            GimpParasite *parasite = va_arg (args, GimpParasite *);

            if (parasite == NULL)
              {
                params[i].data.d_parasite.name = NULL;
                params[i].data.d_parasite.data = NULL;
              }
            else
              {
                params[i].data.d_parasite.name  = parasite->name;
                params[i].data.d_parasite.flags = parasite->flags;
                params[i].data.d_parasite.size  = parasite->size;
                params[i].data.d_parasite.data  = parasite->data;
              }
          }
          break;
1098
        case GIMP_PDB_STATUS:
1099
          params[i].data.d_status = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1100
          break;
1101 1102 1103
        case GIMP_PDB_END:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
1104 1105 1106 1107
    }

  va_end (args);

1108
  return_vals = gimp_run_procedure2 (name, n_return_vals, n_params, params);
Elliot Lee's avatar
Elliot Lee committed
1109

1110
  g_free (params);
Elliot Lee's avatar
Elliot Lee committed
1111 1112 1113 1114

  return return_vals;
}

1115
void
1116
gimp_read_expect_msg (GimpWireMessage *msg,
1117
                      gint             type)
1118
{
1119
  while (TRUE)
1120
    {
1121
      if (! gimp_wire_read_msg (_readchannel, msg, NULL))
1122
        gimp_quit ();
1123

1124
      if (msg->type == type)
1125
        return; /* up to the caller to call wire_destroy() */
1126 1127 1128 1129 1130

      if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT)
        {
          gimp_process_message (msg);
        }
1131
      else
1132 1133 1134 1135
        {
          g_error ("unexpected message: %d", msg->type);
        }

1136
      gimp_wire_destroy (msg);
1137 1138 1139
    }
}

1140 1141 1142 1143 1144 1145
/**
 * gimp_run_procedure2:
 * @name:          the name of the procedure to run
 * @n_return_vals: return location for the number of return values
 * @n_params:      the number of parameters the procedure takes.
 * @params:        the procedure's parameters array.
1146
 *
1147
 * This function calls a GIMP procedure and returns its return values.
Sven Neumann's avatar
Sven Neumann committed
1148 1149
 * To get more information about the available procedures and the
 * parameters they expect, please have a look at the Procedure Browser
1150
 * as found in the Xtns menu in GIMP's toolbox.
Sven Neumann's avatar
Sven Neumann committed
1151 1152 1153
 *
 * As soon as you don't need the return values any longer, you should
 * free them using gimp_destroy_params().
1154
 *
1155 1156
 * Return value: the procedure's return values unless there was an error,
 * in which case the zero-th return value will be the error status, and
1157 1158
 * if there are two values returned, the other return value will be a
 * string detailing the error.
1159
 **/
1160
GimpParam *
1161
gimp_run_procedure2 (const gchar     *name,
1162 1163 1164
                     gint            *n_return_vals,
                     gint             n_params,
                     const GimpParam *params)
Elliot Lee's avatar
Elliot Lee committed
1165
{
1166 1167 1168 1169
  GPProcRun        proc_run;
  GPProcReturn    *proc_return;
  GimpWireMessage  msg;
  GimpParam       *return_vals;
Elliot Lee's avatar
Elliot Lee committed
1170

1171 1172 1173 1174 1175
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (n_return_vals != NULL, NULL);

  proc_run.name    = (gchar *) name;
  proc_run.nparams = n_params;
1176
  proc_run.params  = (GPParam *) params;
Elliot Lee's avatar
Elliot Lee committed
1177

1178
  gp_lock ();
1179
  if (! gp_proc_run_write (_writechannel, &proc_run, NULL))
Elliot Lee's avatar
Elliot Lee committed
1180 1181
    gimp_quit ();

1182
  gimp_read_expect_msg (&msg, GP_PROC_RETURN);
1183
  gp_unlock ();
1184

Elliot Lee's avatar
Elliot Lee committed
1185
  proc_return = msg.data;
1186

1187
  *n_return_vals = proc_return->nparams;
1188 1189 1190 1191
  return_vals    = (GimpParam *) proc_return->params;

  proc_return->nparams = 0;
  proc_return->params  = NULL;
Elliot Lee's avatar
Elliot Lee committed
1192

1193
  gimp_wire_destroy (&msg);
Elliot Lee's avatar
Elliot Lee committed
1194

1195 1196
  gimp_set_pdb_error (return_vals, *n_return_vals);

Elliot Lee's avatar
Elliot Lee committed
1197 1198 1199
  return return_vals;
}

1200 1201 1202 1203
/**
 * gimp_destroy_params:
 * @params:   the #GimpParam array to destroy
 * @n_params: the number of elements in the array
1204
 *
Sven Neumann's avatar
Sven Neumann committed
1205 1206
 * Destroys a #GimpParam array as returned by gimp_run_procedure() or
 * gimp_run_procedure2().
1207
 **/
Elliot Lee's avatar
Elliot Lee committed
1208
void
1209
gimp_destroy_params (GimpParam *params,
1210
                     gint       n_params)
Elliot Lee's avatar
Elliot Lee committed
1211
{
1212
  gp_params_destroy ((GPParam *) params, n_params);
Elliot Lee's avatar
Elliot Lee committed
1213 1214
}

1215 1216 1217 1218
/**
 * gimp_destroy_paramdefs:
 * @paramdefs: the #GimpParamDef array to destroy
 * @n_params:  the number of elements in the array
1219
 *
1220 1221
 * Destroys a #GimpParamDef array as returned by
 * gimp_procedural_db_proc_info().
1222
 **/
1223
void
1224
gimp_destroy_paramdefs (GimpParamDef *paramdefs,
1225
                        gint          n_params)
1226
{
1227
  while (n_params--)
1228
    {
1229 1230
      g_free (paramdefs[n_params].name);
      g_free (paramdefs[n_params].description);
1231
    }
1232

1233 1234 1235
  g_free (paramdefs);
}

1236 1237 1238 1239 1240 1241 1242
/**
 * gimp_get_pdb_error:
 *
 * Retrieves the error message from the last procedure call.
 *
 * If a procedure call fails, then it might pass an error message with
 * the return values. Plug-ins that are using the libgimp C wrappers