gimp.c 65.4 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
 * License along with this library.  If not, see
18
 * <https://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 gboolean       _show_help_button  = TRUE;
217
static gboolean       _export_profile    = FALSE;
218 219 220
static gboolean       _export_exif       = FALSE;
static gboolean       _export_xmp        = FALSE;
static gboolean       _export_iptc       = FALSE;
221 222 223 224 225 226
static GimpCheckSize  _check_size        = GIMP_CHECK_SIZE_MEDIUM_CHECKS;
static GimpCheckType  _check_type        = GIMP_CHECK_TYPE_GRAY_CHECKS;
static gint           _gdisp_ID          = -1;
static gchar         *_wm_class          = NULL;
static gchar         *_display_name      = NULL;
static gint           _monitor_number    = 0;
227
static guint32        _timestamp         = 0;
228
static gchar         *_icon_theme_dir    = NULL;
229
static const gchar   *progname           = NULL;
Elliot Lee's avatar
Elliot Lee committed
230

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

234 235
static GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_NEVER;

236
static GHashTable    *temp_proc_ht       = NULL;
Elliot Lee's avatar
Elliot Lee committed
237

238
static guint          gimp_debug_flags   = 0;
239

240 241 242 243 244 245 246 247 248 249
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        }
250 251
};

252
static GimpPlugInInfo PLUG_IN_INFO;
Elliot Lee's avatar
Elliot Lee committed
253 254


255 256 257 258
static GimpPDBStatusType  pdb_error_status   = GIMP_PDB_SUCCESS;
static gchar             *pdb_error_message  = NULL;


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

    N_ARGS
  };

289 290 291
  gchar       *basename;
  const gchar *env_string;
  gchar       *debug_string;
292
  gint         protocol_version;
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]);
447
      return EXIT_FAILURE;
Elliot Lee's avatar
Elliot Lee committed
448 449
    }

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
  protocol_version = atoi (argv[ARG_PROTOCOL_VERSION]);

  if (protocol_version < GIMP_PROTOCOL_VERSION)
    {
462 463 464 465 466 467
      g_printerr ("Could not execute plug-in \"%s\"\n(%s)\n"
                  "because GIMP is using an older version of the "
                  "plug-in protocol.\n",
                  gimp_filename_to_utf8 (g_get_prgname ()),
                  gimp_filename_to_utf8 (progname));
      return EXIT_FAILURE;
468 469 470
    }
  else if (protocol_version > GIMP_PROTOCOL_VERSION)
    {
471 472 473 474 475 476
      g_printerr ("Could not execute plug-in \"%s\"\n(%s)\n"
                  "because it uses an obsolete version of the "
                  "plug-in protocol.\n",
                  gimp_filename_to_utf8 (g_get_prgname ()),
                  gimp_filename_to_utf8 (progname));
      return EXIT_FAILURE;
477 478
    }

479 480 481 482
  env_string = g_getenv ("GIMP_PLUGIN_DEBUG");

  if (env_string)
    {
483 484
      const gchar *debug_messages;

485 486 487 488 489 490
      debug_string = strchr (env_string, ',');

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

491
          if ((strlen (basename) == len) &&
492 493
              (strncmp (basename, env_string, len) == 0))
            {
494 495 496 497
              gimp_debug_flags =
                g_parse_debug_string (debug_string + 1,
                                      gimp_debug_keys,
                                      G_N_ELEMENTS (gimp_debug_keys));
498 499 500 501 502 503
            }
        }
      else if (strcmp (env_string, basename) == 0)
        {
          gimp_debug_flags = GIMP_DEBUG_DEFAULT;
        }
504 505 506 507 508 509 510 511 512 513 514 515 516 517

      /*  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);
        }
518 519
    }

520
  g_free (basename);
521

522
  stack_trace_mode = (GimpStackTraceMode) CLAMP (atoi (argv[ARG_STACK_TRACE_MODE]),
523 524
                                                 GIMP_STACK_TRACE_NEVER,
                                                 GIMP_STACK_TRACE_ALWAYS);
525

526
#ifndef G_OS_WIN32
527 528 529 530 531
  /* 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.
   */
532 533 534
  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);
535 536 537
  gimp_signal_private (SIGTERM, gimp_plugin_sigfatal_handler, 0);

  gimp_signal_private (SIGABRT, gimp_plugin_sigfatal_handler, 0);
538 539 540 541 542 543 544 545
  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 */
546
  gimp_signal_private (SIGCHLD, SIG_DFL, SA_RESTART);
547
#endif
Elliot Lee's avatar
Elliot Lee committed
548

549
#ifdef G_OS_WIN32
550 551
  _readchannel  = g_io_channel_win32_new_fd (atoi (argv[ARG_READ_FD]));
  _writechannel = g_io_channel_win32_new_fd (atoi (argv[ARG_WRITE_FD]));
552
#else
553 554
  _readchannel  = g_io_channel_unix_new (atoi (argv[ARG_READ_FD]));
  _writechannel = g_io_channel_unix_new (atoi (argv[ARG_WRITE_FD]));
555
#endif
Elliot Lee's avatar
Elliot Lee committed
556

557 558 559
  g_io_channel_set_encoding (_readchannel, NULL, NULL);
  g_io_channel_set_encoding (_writechannel, NULL, NULL);

560 561 562 563 564 565
  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
566
  gp_init ();
567 568 569

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

571
  gimp_enums_init ();
572

573 574
  /*  initialize units  */
  {
575
    GimpUnitVtable vtable;
576 577

    vtable.unit_get_number_of_units = _gimp_unit_cache_get_number_of_units;
578 579
    vtable.unit_get_number_of_built_in_units =
      _gimp_unit_cache_get_number_of_built_in_units;
580 581 582 583 584 585 586 587 588 589 590 591 592 593
    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);
  }

594 595 596 597 598 599 600 601 602 603 604
  /* 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 */
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
  {
    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);
  }
630

631 632 633 634 635 636 637
  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);
638 639 640 641 642 643 644 645 646 647 648

      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);
649 650
    }

651
  if (strcmp (argv[ARG_MODE], "-query") == 0)
Elliot Lee's avatar
Elliot Lee committed
652
    {
653
      if (PLUG_IN_INFO.init_proc)
654
        gp_has_init_write (_writechannel, NULL);
655 656 657 658

      if (gimp_debug_flags & GIMP_DEBUG_QUERY)
        gimp_debug_stop ();

Elliot Lee's avatar
Elliot Lee committed
659
      if (PLUG_IN_INFO.query_proc)
660
        (* PLUG_IN_INFO.query_proc) ();
661

Marc Lehmann's avatar
Marc Lehmann committed
662
      gimp_close ();
663 664

      return EXIT_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
665 666
    }

667
  if (strcmp (argv[ARG_MODE], "-init") == 0)
668
    {
669 670 671
      if (gimp_debug_flags & GIMP_DEBUG_INIT)
        gimp_debug_stop ();

672
      if (PLUG_IN_INFO.init_proc)
673
        (* PLUG_IN_INFO.init_proc) ();
674

675
      gimp_close ();
676 677

      return EXIT_SUCCESS;
678 679
    }

680 681 682
  if (gimp_debug_flags & GIMP_DEBUG_RUN)
    gimp_debug_stop ();
  else if (gimp_debug_flags & GIMP_DEBUG_PID)
683
    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Here I am!");
684

685
  temp_proc_ht = g_hash_table_new (g_str_hash, g_str_equal);
Elliot Lee's avatar
Elliot Lee committed
686

687
  g_io_add_watch (_readchannel,
688 689 690
                  G_IO_ERR | G_IO_HUP,
                  gimp_plugin_io_error_handler,
                  NULL);
691

Elliot Lee's avatar
Elliot Lee committed
692
  gimp_loop ();
693 694

  return EXIT_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
695 696
}

697 698
/**
 * gimp_quit:
699
 *
700
 * Forcefully causes the GIMP library to exit and close down its
701 702
 * connection to main gimp application. This function never returns.
 **/
Marc Lehmann's avatar
Marc Lehmann committed
703
void
704
gimp_quit (void)
Marc Lehmann's avatar
Marc Lehmann committed
705 706
{
  gimp_close ();
707

708 709 710 711 712
#if defined G_OS_WIN32 && defined HAVE_EXCHNDL
  if (plug_in_backtrace_path)
    g_free (plug_in_backtrace_path);
#endif

713
  exit (EXIT_SUCCESS);
Elliot Lee's avatar
Elliot Lee committed
714 715
}

716 717 718 719 720 721 722 723 724
/**
 * 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.
725 726
 * @menu_label:    the label to use for the procedure's menu entry,
 *                 or #NULL if the procedure has no menu entry.
727 728 729 730 731 732
 * @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.
733
 *
734 735
 * Installs a new procedure with the PDB (procedural database).
 *
736 737
 * Call this function from within your plug-in's query() function for
 * each procedure your plug-in implements.
738 739 740 741 742 743 744 745 746
 *
 * 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.
 *
747
 * @menu_label defines the label that should be used for the
748
 * procedure's menu entry. The position where to register in the menu
749
 * hierarchy is chosen using gimp_plugin_menu_register().
750
 *
751
 * It is possible to register a procedure only for keyboard-shortcut
752 753 754 755
 * 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.
756
 *
757 758 759 760 761 762
 * @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.
 *
763
 * @type must be one of %GIMP_PLUGIN or %GIMP_EXTENSION. Note that
764 765 766
 * temporary procedures must be installed using
 * gimp_install_temp_proc().
 *
767
 * NOTE: Unlike the GIMP 1.2 API, %GIMP_EXTENSION no longer means
768 769
 * that the procedure's menu prefix is &lt;Toolbox&gt;, but that
 * it will install temporary procedures. Therefore, the GIMP core
770
 * will wait until the %GIMP_EXTENSION procedure has called
771 772 773 774
 * gimp_extension_ack(), which means that the procedure has done
 * its initialization, installed its temporary procedures and is
 * ready to run.
 *
775
 * <emphasis>Not calling gimp_extension_ack() from a %GIMP_EXTENSION
776
 * procedure will cause the GIMP core to lock up.</emphasis>
777
 *
778
 * Additionally, a %GIMP_EXTENSION procedure with no parameters
779 780 781
 * (@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
782
void
783
gimp_install_procedure (const gchar        *name,
784 785 786 787 788 789 790 791 792 793 794 795
                        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
796 797 798
{
  GPProcInstall proc_install;

799 800 801 802 803 804 805 806 807 808 809 810 811
  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;
812
  proc_install.menu_label   = (gchar *) menu_label;
813
  proc_install.image_types  = (gchar *) image_types;
814
  proc_install.type         = type;
815 816
  proc_install.nparams      = n_params;
  proc_install.nreturn_vals = n_return_vals;
817 818
  proc_install.params       = (GPParamDef *) params;
  proc_install.return_vals  = (GPParamDef *) return_vals;
Elliot Lee's avatar
Elliot Lee committed
819

820
  if (! gp_proc_install_write (_writechannel, &proc_install, NULL))
Elliot Lee's avatar
Elliot Lee committed
821 822 823
    gimp_quit ();
}

824 825 826 827 828 829 830 831 832
/**
 * 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.
833
 * @menu_label:    the procedure's menu label, or #NULL if the procedure has
834 835 836 837 838 839 840 841
 *                 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.
842
 *
843 844 845
 * Installs a new temporary procedure with the PDB (procedural database).
 *
 * A temporary procedure is a procedure which is only available while
846
 * one of your plug-in's "real" procedures is running.
847 848 849
 *
 * See gimp_install_procedure() for most details.
 *
850
 * @type <emphasis>must</emphasis> be %GIMP_TEMPORARY or the function
851 852 853 854 855
 * will fail.
 *
 * @run_proc is the function which will be called to execute the
 * procedure.
 *
856 857
 * 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
858
 * explicitly enable receiving of temporary procedure run requests
859 860 861 862
 * using either gimp_extension_enable() or
 * gimp_extension_process(). See this functions' documentation for
 * details.
 **/
Elliot Lee's avatar
Elliot Lee committed
863
void
864
gimp_install_temp_proc (const gchar        *name,
865 866 867 868 869 870 871 872 873 874 875 876 877
                        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
878
{
879 880 881 882 883 884 885 886
  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);

887
  gimp_install_procedure (name,
888 889 890 891 892 893 894
                          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
895 896

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

900 901 902
/**
 * gimp_uninstall_temp_proc:
 * @name: the procedure's name
903
 *
904 905 906
 * Uninstalls a temporary procedure which has previously been
 * installed using gimp_install_temp_proc().
 **/
Elliot Lee's avatar
Elliot Lee committed
907
void
908
gimp_uninstall_temp_proc (const gchar *name)
Elliot Lee's avatar
Elliot Lee committed
909 910
{
  GPProcUninstall proc_uninstall;
911 912 913 914 915 916
  gpointer        hash_name;
  gboolean        found;

  g_return_if_fail (name != NULL);

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

918
  if (! gp_proc_uninstall_write (_writechannel, &proc_uninstall, NULL))
Elliot Lee's avatar
Elliot Lee committed
919
    gimp_quit ();
920

921 922
  found = g_hash_table_lookup_extended (temp_proc_ht, name, &hash_name, NULL);
  if (found)
923 924
    {
      g_hash_table_remove (temp_proc_ht, (gpointer) name);
925
      g_free (hash_name);
926
    }
Elliot Lee's avatar
Elliot Lee committed
927 928
}

929 930 931 932
/**
 * gimp_run_procedure:
 * @name:          the name of the procedure to run
 * @n_return_vals: return location for the number of return values
933
 * @...:           list of procedure parameters
934 935 936
 *
 * This function calls a GIMP procedure and returns its return values.
 *
Sven Neumann's avatar
Sven Neumann committed
937
 * The procedure's parameters are given by a va_list in the format
938
 * (type, value, type, value) and must be terminated by %GIMP_PDB_END.
939
 *
Sven Neumann's avatar
Sven Neumann committed
940 941 942
 * This function converts the va_list of parameters into an array and
 * passes them to gimp_run_procedure2(). Please look there for further
 * information.
943
 *
944 945 946
 * 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.
947
 **/
948
GimpParam *
949
gimp_run_procedure (const gchar *name,
950 951
                    gint        *n_return_vals,
                    ...)
Elliot Lee's avatar
Elliot Lee committed
952
{
953 954
  GimpPDBArgType  param_type;
  GimpParam      *return_vals;
955 956
  GimpParam      *params   = NULL;
  gint            n_params = 0;
957 958
  va_list         args;
  gint            i;
Elliot Lee's avatar
Elliot Lee committed
959

960 961
  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
962

963
  va_start (args, n_return_vals);
964
  param_type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
965

966
  while (param_type != GIMP_PDB_END)
Elliot Lee's avatar
Elliot Lee committed
967 968
    {
      switch (param_type)
969 970
        {
        case GIMP_PDB_INT32:
971 972
        case GIMP_PDB_DISPLAY:
        case GIMP_PDB_IMAGE:
973
        case GIMP_PDB_ITEM:
974 975 976 977
        case GIMP_PDB_LAYER:
        case GIMP_PDB_CHANNEL:
        case GIMP_PDB_DRAWABLE:
        case GIMP_PDB_SELECTION:
978
        case GIMP_PDB_VECTORS:
979
        case GIMP_PDB_STATUS:
980 981 982 983 984 985 986 987
          (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;
988
        case GIMP_PDB_FLOAT:
989
          (void) va_arg (args, gdouble);
Elliot Lee's avatar
Elliot Lee committed
990
          break;
991
        case GIMP_PDB_STRING:
992
          (void) va_arg (args, gchar *);
Elliot Lee's avatar
Elliot Lee committed
993
          break;
994
        case GIMP_PDB_INT32ARRAY:
995
          (void) va_arg (args, gint32 *);
Elliot Lee's avatar
Elliot Lee committed
996
          break;
997
        case GIMP_PDB_INT16ARRAY:
998
          (void) va_arg (args, gint16 *);
Elliot Lee's avatar
Elliot Lee committed
999
          break;
1000
        case GIMP_PDB_INT8ARRAY:
1001
          (void) va_arg (args, gint8 *);
Elliot Lee's avatar
Elliot Lee committed
1002
          break;
1003
        case GIMP_PDB_FLOATARRAY:
1004
          (void) va_arg (args, gdouble *);
Elliot Lee's avatar
Elliot Lee committed
1005
          break;
1006
        case GIMP_PDB_STRINGARRAY:
1007
          (void) va_arg (args, gchar **);
Elliot Lee's avatar
Elliot Lee committed
1008
          break;
1009
        case GIMP_PDB_COLOR:
Jehan's avatar
Jehan committed
1010
        case GIMP_PDB_COLORARRAY:
1011
          (void) va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
1012
          break;
1013
        case GIMP_PDB_PARASITE:
1014
          (void) va_arg (args, GimpParasite *);
1015
          break;
1016 1017 1018
        case GIMP_PDB_END:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
1019

1020 1021
      n_params++;

1022
      param_type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
1023 1024 1025 1026
    }

  va_end (args);

1027
  params = g_new0 (GimpParam, n_params);
Elliot Lee's avatar
Elliot Lee committed
1028

1029
  va_start (args, n_return_vals);
Elliot Lee's avatar
Elliot Lee committed
1030

1031
  for (i = 0; i < n_params; i++)
Elliot Lee's avatar
Elliot Lee committed
1032
    {
1033
      params[i].type = va_arg (args, GimpPDBArgType);
Elliot Lee's avatar
Elliot Lee committed
1034

1035
      switch (params[i].type)
1036 1037 1038 1039 1040 1041 1042 1043
        {
        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:
1044
          params[i].data.d_int8 = (guint8) va_arg (args, gint);
1045
          break;
1046
        case GIMP_PDB_FLOAT:
1047
          params[i].data.d_float = (gdouble) va_arg (args, gdouble);
Elliot Lee's avatar
Elliot Lee committed
1048
          break;
1049
        case GIMP_PDB_STRING:
1050
          params[i].data.d_string = va_arg (args, gchar *);
Elliot Lee's avatar
Elliot Lee committed
1051
          break;
1052
        case GIMP_PDB_INT32ARRAY:
1053
          params[i].data.d_int32array = va_arg (args, gint32 *);
Elliot Lee's avatar
Elliot Lee committed
1054
          break;
1055
        case GIMP_PDB_INT16ARRAY:
1056
          params[i].data.d_int16array = va_arg (args, gint16 *);
Elliot Lee's avatar
Elliot Lee committed
1057
          break;
1058
        case GIMP_PDB_INT8ARRAY:
1059
          params[i].data.d_int8array = va_arg (args, guint8 *);
Elliot Lee's avatar
Elliot Lee committed
1060
          break;
1061
        case GIMP_PDB_FLOATARRAY:
1062
          params[i].data.d_floatarray = va_arg (args, gdouble *);
Elliot Lee's avatar
Elliot Lee committed
1063
          break;
1064
        case GIMP_PDB_STRINGARRAY:
1065
          params[i].data.d_stringarray = va_arg (args, gchar **);
Elliot Lee's avatar
Elliot Lee committed
1066
          break;
1067
        case GIMP_PDB_COLOR:
1068
          params[i].data.d_color = *va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
1069
          break;
1070 1071
        case GIMP_PDB_ITEM:
          params[i].data.d_item = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1072
          break;
1073
        case GIMP_PDB_DISPLAY:
1074
          params[i].data.d_display = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1075
          break;
1076
        case GIMP_PDB_IMAGE:
1077
          params[i].data.d_image = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1078
          break;
1079
        case GIMP_PDB_LAYER:
1080
          params[i].data.d_layer = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1081
          break;
1082
        case GIMP_PDB_CHANNEL:
1083
          params[i].data.d_channel = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1084
          break;
1085
        case GIMP_PDB_DRAWABLE:
1086
          params[i].data.d_drawable = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1087
          break;
1088
        case GIMP_PDB_SELECTION:
1089
          params[i].data.d_selection = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1090
          break;
1091 1092
        case GIMP_PDB_COLORARRAY:
          params[i].data.d_colorarray = va_arg (args, GimpRGB *);
Elliot Lee's avatar
Elliot Lee committed
1093
          break;
1094
        case GIMP_PDB_VECTORS:
1095
          params[i].data.d_vectors = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1096
          break;
1097
        case GIMP_PDB_PARASITE:
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
          {
            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;
1115
        case GIMP_PDB_STATUS:
1116
          params[i].data.d_status = va_arg (args, gint32);
Elliot Lee's avatar
Elliot Lee committed
1117
          break;
1118 1119 1120
        case GIMP_PDB_END:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
1121 1122 1123 1124
    }

  va_end (args);

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

1127
  g_free (params);
Elliot Lee's avatar
Elliot Lee committed
1128 1129 1130 1131

  return return_vals;
}

1132
void
1133
gimp_read_expect_msg (GimpWireMessage *msg,
1134
                      gint             type)
1135
{
1136
  while (TRUE)
1137
    {
1138
      if (! gimp_wire_read_msg (_readchannel, msg, NULL))
1139
        gimp_quit ();
1140

1141
      if (msg->type == type)
1142
        return; /* up to the caller to call wire_destroy() */
1143 1144 1145 1146 1147

      if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT)
        {
          gimp_process_message (msg);
        }
1148
      else
1149 1150 1151 1152
        {
          g_error ("unexpected message: %d", msg->type);
        }

1153
      gimp_wire_destroy (msg);
1154 1155 1156
    }
}

1157 1158 1159 1160 1161 1162
/**
 * 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.
1163
 *
1164
 * This function calls a GIMP procedure and returns its return values.
Sven Neumann's avatar
Sven Neumann committed
1165 1166
 * To get more information about the available procedures and the
 * parameters they expect, please have a look at the Procedure Browser
1167
 * as found in the Xtns menu in GIMP's toolbox.
Sven Neumann's avatar
Sven Neumann committed
1168 1169 1170
 *
 * As soon as you don't need the return values any longer, you should
 * free them using gimp_destroy_params().
1171
 *
1172 1173
 * 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
1174 1175
 * if there are two values returned, the other return value will be a
 * string detailing the error.
1176
 **/
1177
GimpParam *
1178
gimp_run_procedure2 (const gchar     *name,
1179 1180 1181
                     gint            *n_return_vals,
                     gint             n_params,
                     const GimpParam *params)
Elliot Lee's avatar
Elliot Lee committed
1182
{
1183 1184 1185 1186
  GPProcRun        proc_run;
  GPProcReturn    *proc_return;
  GimpWireMessage  msg;
  GimpParam       *return_vals;
Elliot Lee's avatar
Elliot Lee committed
1187

1188 1189 1190 1191 1192
  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;
1193
  proc_run.params  = (GPParam *) params;
Elliot Lee's avatar
Elliot Lee committed
1194

1195
  gp_lock ();
1196
  if (! gp_proc_run_write (_writechannel, &proc_run, NULL))
Elliot Lee's avatar
Elliot Lee committed
1197 1198
    gimp_quit ();

1199
  gimp_read_expect_msg (&msg, GP_PROC_RETURN);
1200
  gp_unlock ();
1201

Elliot Lee's avatar
Elliot Lee committed
1202
  proc_return = msg.data;
1203

1204
  *n_return_vals = proc_return->nparams;
1205 1206 1207 1208
  return_vals    = (GimpParam *) proc_return->params;

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

1210
  gimp_wire_destroy (&msg);
Elliot Lee's avatar
Elliot Lee committed
1211

1212 1213
  gimp_set_pdb_error (return_vals, *n_return_vals);

Elliot Lee's avatar
Elliot Lee committed
1214 1215 1216
  return return_vals;
}

1217 1218 1219 1220
/**
 * gimp_destroy_params:
 * @params:   the #GimpParam array to destroy
 * @n_params: the number of elements in the array
1221
 *
Sven Neumann's avatar
Sven Neumann committed
1222 1223
 * Destroys a #GimpParam array as returned by gimp_run_procedure() or
 * gimp_run_procedure2().
1224
 **/
Elliot Lee's avatar
Elliot Lee committed
1225
void
1226
gimp_destroy_params (GimpParam *params,
1227
                     gint       n_params)
Elliot Lee's avatar
Elliot Lee committed
1228
{
1229
  gp_params_destroy ((GPParam *) params, n_params);
Elliot Lee's avatar
Elliot Lee committed
1230 1231
}

1232 1233 1234 1235
/**
 * gimp_destroy_paramdefs:
 * @paramdefs: the #GimpParamDef array to destroy
 * @n_params:  the number of elements in the array
1236
 *
1237 1238
 * Destroys a #GimpParamDef array as returned by
 * gimp_procedural_db_proc_info().
1239
 **/