forked from openkylin/gimp
2589 lines
70 KiB
C
2589 lines
70 KiB
C
|
/* LIBGIMP - The GIMP Library
|
||
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||
|
*
|
||
|
* gimp.c
|
||
|
*
|
||
|
* This library is free software: you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 3 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library. If not, see
|
||
|
* <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#define _GNU_SOURCE /* for the sigaction stuff */
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#ifdef HAVE_SYS_TIME_H
|
||
|
#include <sys/time.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SYS_PARAM_H
|
||
|
#include <sys/param.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SYS_WAIT_H
|
||
|
#include <sys/wait.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_UNISTD_H
|
||
|
#include <unistd.h>
|
||
|
#endif
|
||
|
|
||
|
#ifndef WAIT_ANY
|
||
|
#define WAIT_ANY -1
|
||
|
#endif
|
||
|
|
||
|
#include <gtk/gtk.h> /* need GDK_WINDOWING_FOO defines */
|
||
|
|
||
|
#ifndef G_OS_WIN32
|
||
|
#include "libgimpbase/gimpsignal.h"
|
||
|
|
||
|
#else
|
||
|
|
||
|
#ifdef HAVE_EXCHNDL
|
||
|
#include <time.h>
|
||
|
#include <exchndl.h>
|
||
|
#endif
|
||
|
|
||
|
#include <signal.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SYS_SELECT_H
|
||
|
#include <sys/select.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(USE_SYSV_SHM)
|
||
|
|
||
|
#ifdef HAVE_IPC_H
|
||
|
#include <sys/ipc.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_SHM_H
|
||
|
#include <sys/shm.h>
|
||
|
#endif
|
||
|
|
||
|
#elif defined(USE_POSIX_SHM)
|
||
|
|
||
|
#ifdef HAVE_UNISTD_H
|
||
|
#include <unistd.h>
|
||
|
#endif
|
||
|
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/mman.h>
|
||
|
|
||
|
#endif /* USE_POSIX_SHM */
|
||
|
|
||
|
#ifdef GDK_WINDOWING_QUARTZ
|
||
|
#include <Cocoa/Cocoa.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
|
||
|
# ifdef STRICT
|
||
|
# undef STRICT
|
||
|
# endif
|
||
|
# define STRICT
|
||
|
|
||
|
# ifdef _WIN32_WINNT
|
||
|
# undef _WIN32_WINNT
|
||
|
# endif
|
||
|
# define _WIN32_WINNT 0x0601
|
||
|
|
||
|
# include <windows.h>
|
||
|
# include <tlhelp32.h>
|
||
|
# undef RGB
|
||
|
# define USE_WIN32_SHM 1
|
||
|
#endif
|
||
|
|
||
|
#include <locale.h>
|
||
|
|
||
|
#include "libgimpbase/gimpbase.h"
|
||
|
#include "libgimpbase/gimpbase-private.h"
|
||
|
#include "libgimpbase/gimpprotocol.h"
|
||
|
#include "libgimpbase/gimpwire.h"
|
||
|
|
||
|
#include "gimp.h"
|
||
|
#include "gimpunitcache.h"
|
||
|
|
||
|
#include "libgimp-intl.h"
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
**/
|
||
|
|
||
|
|
||
|
#define TILE_MAP_SIZE (_tile_width * _tile_height * 32)
|
||
|
|
||
|
#define ERRMSG_SHM_FAILED "Could not attach to gimp shared memory segment"
|
||
|
|
||
|
/* Maybe this should go in a public header if we add other things to it */
|
||
|
typedef enum
|
||
|
{
|
||
|
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)
|
||
|
} GimpDebugFlag;
|
||
|
|
||
|
#define WRITE_BUFFER_SIZE 1024
|
||
|
|
||
|
void gimp_read_expect_msg (GimpWireMessage *msg,
|
||
|
gint type);
|
||
|
|
||
|
|
||
|
static void gimp_close (void);
|
||
|
static void gimp_debug_stop (void);
|
||
|
static void gimp_message_func (const gchar *log_domain,
|
||
|
GLogLevelFlags log_level,
|
||
|
const gchar *message,
|
||
|
gpointer data);
|
||
|
static void gimp_fatal_func (const gchar *log_domain,
|
||
|
GLogLevelFlags flags,
|
||
|
const gchar *message,
|
||
|
gpointer data);
|
||
|
#ifdef G_OS_WIN32
|
||
|
#ifdef HAVE_EXCHNDL
|
||
|
static LONG WINAPI gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo);
|
||
|
#endif
|
||
|
#else
|
||
|
static void gimp_plugin_sigfatal_handler (gint sig_num);
|
||
|
#endif
|
||
|
static gboolean gimp_plugin_io_error_handler (GIOChannel *channel,
|
||
|
GIOCondition cond,
|
||
|
gpointer data);
|
||
|
static gboolean gimp_write (GIOChannel *channel,
|
||
|
const guint8 *buf,
|
||
|
gulong count,
|
||
|
gpointer user_data);
|
||
|
static gboolean gimp_flush (GIOChannel *channel,
|
||
|
gpointer user_data);
|
||
|
static void gimp_loop (void);
|
||
|
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);
|
||
|
static void gimp_single_message (void);
|
||
|
static gboolean gimp_extension_read (GIOChannel *channel,
|
||
|
GIOCondition condition,
|
||
|
gpointer data);
|
||
|
|
||
|
static void gimp_set_pdb_error (const GimpParam *return_vals,
|
||
|
gint n_return_vals);
|
||
|
|
||
|
|
||
|
#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;
|
||
|
|
||
|
#ifdef USE_WIN32_SHM
|
||
|
static HANDLE shm_handle;
|
||
|
#endif
|
||
|
|
||
|
static gint _tile_width = -1;
|
||
|
static gint _tile_height = -1;
|
||
|
static gint _shm_ID = -1;
|
||
|
static guchar *_shm_addr = NULL;
|
||
|
static gboolean _show_tool_tips = TRUE;
|
||
|
static gboolean _show_help_button = TRUE;
|
||
|
static gboolean _export_profile = FALSE;
|
||
|
static gboolean _export_exif = FALSE;
|
||
|
static gboolean _export_xmp = FALSE;
|
||
|
static gboolean _export_iptc = FALSE;
|
||
|
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;
|
||
|
static guint32 _timestamp = 0;
|
||
|
static gchar *_icon_theme_dir = NULL;
|
||
|
static const gchar *progname = NULL;
|
||
|
|
||
|
static gchar write_buffer[WRITE_BUFFER_SIZE];
|
||
|
static gulong write_buffer_index = 0;
|
||
|
|
||
|
static GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_NEVER;
|
||
|
|
||
|
static GHashTable *temp_proc_ht = NULL;
|
||
|
|
||
|
static guint gimp_debug_flags = 0;
|
||
|
|
||
|
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 }
|
||
|
};
|
||
|
|
||
|
static GimpPlugInInfo PLUG_IN_INFO;
|
||
|
|
||
|
|
||
|
static GimpPDBStatusType pdb_error_status = GIMP_PDB_SUCCESS;
|
||
|
static gchar *pdb_error_message = NULL;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* gimp_main:
|
||
|
* @info: the PLUG_IN_INFO structure
|
||
|
* @argc: the number of arguments
|
||
|
* @argv: the arguments
|
||
|
*
|
||
|
* The main procedure that must be called with the PLUG_IN_INFO structure
|
||
|
* and the 'argc' and 'argv' that are passed to "main".
|
||
|
*
|
||
|
* Returns: an exit status as defined by the C library,
|
||
|
* on success EXIT_SUCCESS.
|
||
|
**/
|
||
|
gint
|
||
|
gimp_main (const GimpPlugInInfo *info,
|
||
|
gint argc,
|
||
|
gchar *argv[])
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
ARG_PROGNAME,
|
||
|
ARG_GIMP,
|
||
|
ARG_READ_FD,
|
||
|
ARG_WRITE_FD,
|
||
|
ARG_MODE,
|
||
|
ARG_STACK_TRACE_MODE,
|
||
|
|
||
|
N_ARGS
|
||
|
};
|
||
|
|
||
|
gchar *basename;
|
||
|
const gchar *env_string;
|
||
|
gchar *debug_string;
|
||
|
|
||
|
#ifdef G_OS_WIN32
|
||
|
gint i, j, k;
|
||
|
|
||
|
/* Reduce risks */
|
||
|
{
|
||
|
typedef BOOL (WINAPI *t_SetDllDirectoryA) (LPCSTR lpPathName);
|
||
|
t_SetDllDirectoryA p_SetDllDirectoryA;
|
||
|
|
||
|
p_SetDllDirectoryA = (t_SetDllDirectoryA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
|
||
|
"SetDllDirectoryA");
|
||
|
if (p_SetDllDirectoryA)
|
||
|
(*p_SetDllDirectoryA) ("");
|
||
|
}
|
||
|
|
||
|
/* 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);
|
||
|
}
|
||
|
|
||
|
#ifdef HAVE_EXCHNDL
|
||
|
/* Use Dr. Mingw (dumps backtrace on crash) if it is available. */
|
||
|
{
|
||
|
time_t t;
|
||
|
gchar *filename;
|
||
|
gchar *dir;
|
||
|
|
||
|
/* 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);
|
||
|
plug_in_backtrace_path = g_build_filename (dir, filename, NULL);
|
||
|
g_free (filename);
|
||
|
g_free (dir);
|
||
|
|
||
|
/* Similar to core crash handling in app/signals.c, the order here
|
||
|
* is very important!
|
||
|
*/
|
||
|
if (! _prevExceptionFilter)
|
||
|
_prevExceptionFilter = SetUnhandledExceptionFilter (gimp_plugin_sigfatal_handler);
|
||
|
|
||
|
ExcHndlInit ();
|
||
|
ExcHndlSetLogFileNameA (plug_in_backtrace_path);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef _WIN64
|
||
|
{
|
||
|
typedef BOOL (WINAPI *t_SetProcessDEPPolicy) (DWORD dwFlags);
|
||
|
t_SetProcessDEPPolicy p_SetProcessDEPPolicy;
|
||
|
|
||
|
p_SetProcessDEPPolicy = GetProcAddress (GetModuleHandle ("kernel32.dll"),
|
||
|
"SetProcessDEPPolicy");
|
||
|
if (p_SetProcessDEPPolicy)
|
||
|
(*p_SetProcessDEPPolicy) (PROCESS_DEP_ENABLE|PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Group all our windows together on the taskbar */
|
||
|
{
|
||
|
typedef HRESULT (WINAPI *t_SetCurrentProcessExplicitAppUserModelID) (PCWSTR lpPathName);
|
||
|
t_SetCurrentProcessExplicitAppUserModelID p_SetCurrentProcessExplicitAppUserModelID;
|
||
|
|
||
|
p_SetCurrentProcessExplicitAppUserModelID = (t_SetCurrentProcessExplicitAppUserModelID) GetProcAddress (GetModuleHandle ("shell32.dll"),
|
||
|
"SetCurrentProcessExplicitAppUserModelID");
|
||
|
if (p_SetCurrentProcessExplicitAppUserModelID)
|
||
|
(*p_SetCurrentProcessExplicitAppUserModelID) (L"gimp.GimpApplication");
|
||
|
}
|
||
|
|
||
|
/* 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]);
|
||
|
|
||
|
if (k > 10)
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
s = g_string_new (argv[ARG_PROGNAME]);
|
||
|
|
||
|
for (j = 1; j <= i; j++)
|
||
|
{
|
||
|
s = g_string_append_c (s, ' ');
|
||
|
s = g_string_append (s, argv[j]);
|
||
|
}
|
||
|
|
||
|
argv[ARG_PROGNAME] = s->str;
|
||
|
|
||
|
/* Move rest of argv down */
|
||
|
for (j = 1; j < argc - i; j++)
|
||
|
argv[j] = argv[j + i];
|
||
|
|
||
|
argv[argc - i] = NULL;
|
||
|
argc -= i;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
g_assert (info != NULL);
|
||
|
|
||
|
PLUG_IN_INFO = *info;
|
||
|
|
||
|
if ((argc != N_ARGS) || (strcmp (argv[ARG_GIMP], "-gimp") != 0))
|
||
|
{
|
||
|
g_printerr ("%s is a GIMP plug-in and must be run by GIMP to be used\n",
|
||
|
argv[ARG_PROGNAME]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
gimp_env_init (TRUE);
|
||
|
|
||
|
progname = argv[ARG_PROGNAME];
|
||
|
|
||
|
basename = g_path_get_basename (progname);
|
||
|
|
||
|
g_set_prgname (basename);
|
||
|
|
||
|
env_string = g_getenv ("GIMP_PLUGIN_DEBUG");
|
||
|
|
||
|
if (env_string)
|
||
|
{
|
||
|
const gchar *debug_messages;
|
||
|
|
||
|
debug_string = strchr (env_string, ',');
|
||
|
|
||
|
if (debug_string)
|
||
|
{
|
||
|
gint len = debug_string - env_string;
|
||
|
|
||
|
if ((strlen (basename) == len) &&
|
||
|
(strncmp (basename, env_string, len) == 0))
|
||
|
{
|
||
|
gimp_debug_flags =
|
||
|
g_parse_debug_string (debug_string + 1,
|
||
|
gimp_debug_keys,
|
||
|
G_N_ELEMENTS (gimp_debug_keys));
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp (env_string, basename) == 0)
|
||
|
{
|
||
|
gimp_debug_flags = GIMP_DEBUG_DEFAULT;
|
||
|
}
|
||
|
|
||
|
/* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
g_free (basename);
|
||
|
|
||
|
stack_trace_mode = (GimpStackTraceMode) CLAMP (atoi (argv[ARG_STACK_TRACE_MODE]),
|
||
|
GIMP_STACK_TRACE_NEVER,
|
||
|
GIMP_STACK_TRACE_ALWAYS);
|
||
|
|
||
|
#ifndef G_OS_WIN32
|
||
|
/* 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.
|
||
|
*/
|
||
|
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);
|
||
|
gimp_signal_private (SIGTERM, gimp_plugin_sigfatal_handler, 0);
|
||
|
|
||
|
gimp_signal_private (SIGABRT, gimp_plugin_sigfatal_handler, 0);
|
||
|
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 */
|
||
|
gimp_signal_private (SIGCHLD, SIG_DFL, SA_RESTART);
|
||
|
#endif
|
||
|
|
||
|
#ifdef G_OS_WIN32
|
||
|
_readchannel = g_io_channel_win32_new_fd (atoi (argv[ARG_READ_FD]));
|
||
|
_writechannel = g_io_channel_win32_new_fd (atoi (argv[ARG_WRITE_FD]));
|
||
|
#else
|
||
|
_readchannel = g_io_channel_unix_new (atoi (argv[ARG_READ_FD]));
|
||
|
_writechannel = g_io_channel_unix_new (atoi (argv[ARG_WRITE_FD]));
|
||
|
#endif
|
||
|
|
||
|
g_io_channel_set_encoding (_readchannel, NULL, NULL);
|
||
|
g_io_channel_set_encoding (_writechannel, NULL, NULL);
|
||
|
|
||
|
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);
|
||
|
|
||
|
gp_init ();
|
||
|
|
||
|
gimp_wire_set_writer (gimp_write);
|
||
|
gimp_wire_set_flusher (gimp_flush);
|
||
|
|
||
|
gimp_enums_init ();
|
||
|
|
||
|
/* initialize units */
|
||
|
{
|
||
|
GimpUnitVtable vtable;
|
||
|
|
||
|
vtable.unit_get_number_of_units = _gimp_unit_cache_get_number_of_units;
|
||
|
vtable.unit_get_number_of_built_in_units =
|
||
|
_gimp_unit_cache_get_number_of_built_in_units;
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/* 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 */
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
if (strcmp (argv[ARG_MODE], "-query") == 0)
|
||
|
{
|
||
|
if (PLUG_IN_INFO.init_proc)
|
||
|
gp_has_init_write (_writechannel, NULL);
|
||
|
|
||
|
if (gimp_debug_flags & GIMP_DEBUG_QUERY)
|
||
|
gimp_debug_stop ();
|
||
|
|
||
|
if (PLUG_IN_INFO.query_proc)
|
||
|
(* PLUG_IN_INFO.query_proc) ();
|
||
|
|
||
|
gimp_close ();
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
if (strcmp (argv[ARG_MODE], "-init") == 0)
|
||
|
{
|
||
|
if (gimp_debug_flags & GIMP_DEBUG_INIT)
|
||
|
gimp_debug_stop ();
|
||
|
|
||
|
if (PLUG_IN_INFO.init_proc)
|
||
|
(* PLUG_IN_INFO.init_proc) ();
|
||
|
|
||
|
gimp_close ();
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
if (gimp_debug_flags & GIMP_DEBUG_RUN)
|
||
|
gimp_debug_stop ();
|
||
|
else if (gimp_debug_flags & GIMP_DEBUG_PID)
|
||
|
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Here I am!");
|
||
|
|
||
|
temp_proc_ht = g_hash_table_new (g_str_hash, g_str_equal);
|
||
|
|
||
|
g_io_add_watch (_readchannel,
|
||
|
G_IO_ERR | G_IO_HUP,
|
||
|
gimp_plugin_io_error_handler,
|
||
|
NULL);
|
||
|
|
||
|
gimp_loop ();
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_quit:
|
||
|
*
|
||
|
* Forcefully causes the GIMP library to exit and close down its
|
||
|
* connection to main gimp application. This function never returns.
|
||
|
**/
|
||
|
void
|
||
|
gimp_quit (void)
|
||
|
{
|
||
|
gimp_close ();
|
||
|
|
||
|
#if defined G_OS_WIN32 && defined HAVE_EXCHNDL
|
||
|
if (plug_in_backtrace_path)
|
||
|
g_free (plug_in_backtrace_path);
|
||
|
#endif
|
||
|
|
||
|
exit (EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
* @menu_label: the label to use for the procedure's menu entry,
|
||
|
* or #NULL if the procedure has 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.
|
||
|
*
|
||
|
* Installs a new procedure with the PDB (procedural database).
|
||
|
*
|
||
|
* Call this function from within your plug-in's query() function for
|
||
|
* each procedure your plug-in implements.
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
* @menu_label defines the label that should be used for the
|
||
|
* 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
|
||
|
* "<Domain>/Path/To/My/Menu"
|
||
|
* (e.g. "<Image>/Filters/Render/Useless").
|
||
|
*
|
||
|
* Note that registering a full (pre-2.2-style) menu path is
|
||
|
* deprecated and will cause a failure in GIMP 3.0 and newer.
|
||
|
*
|
||
|
* It is possible to register a procedure only for keyboard-shortcut
|
||
|
* 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.
|
||
|
*
|
||
|
* @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.
|
||
|
*
|
||
|
* @type must be one of %GIMP_PLUGIN or %GIMP_EXTENSION. Note that
|
||
|
* temporary procedures must be installed using
|
||
|
* gimp_install_temp_proc().
|
||
|
*
|
||
|
* NOTE: Unlike the GIMP 1.2 API, %GIMP_EXTENSION no longer means
|
||
|
* that the procedure's menu prefix is <Toolbox>, but that
|
||
|
* it will install temporary procedures. Therefore, the GIMP core
|
||
|
* will wait until the %GIMP_EXTENSION procedure has called
|
||
|
* gimp_extension_ack(), which means that the procedure has done
|
||
|
* its initialization, installed its temporary procedures and is
|
||
|
* ready to run.
|
||
|
*
|
||
|
* <emphasis>Not calling gimp_extension_ack() from a %GIMP_EXTENSION
|
||
|
* procedure will cause the GIMP core to lock up.</emphasis>
|
||
|
*
|
||
|
* Additionally, a %GIMP_EXTENSION procedure with no parameters
|
||
|
* (@n_params == 0 and @params == #NULL) is an "automatic" extension
|
||
|
* that will be automatically started on each GIMP startup.
|
||
|
**/
|
||
|
void
|
||
|
gimp_install_procedure (const gchar *name,
|
||
|
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)
|
||
|
{
|
||
|
GPProcInstall proc_install;
|
||
|
|
||
|
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;
|
||
|
proc_install.menu_path = (gchar *) menu_label;
|
||
|
proc_install.image_types = (gchar *) image_types;
|
||
|
proc_install.type = type;
|
||
|
proc_install.nparams = n_params;
|
||
|
proc_install.nreturn_vals = n_return_vals;
|
||
|
proc_install.params = (GPParamDef *) params;
|
||
|
proc_install.return_vals = (GPParamDef *) return_vals;
|
||
|
|
||
|
if (! gp_proc_install_write (_writechannel, &proc_install, NULL))
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
* @menu_label: the procedure's menu label, or #NULL if the procedure has
|
||
|
* 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.
|
||
|
*
|
||
|
* Installs a new temporary procedure with the PDB (procedural database).
|
||
|
*
|
||
|
* A temporary procedure is a procedure which is only available while
|
||
|
* one of your plug-in's "real" procedures is running.
|
||
|
*
|
||
|
* See gimp_install_procedure() for most details.
|
||
|
*
|
||
|
* @type <emphasis>must</emphasis> be %GIMP_TEMPORARY or the function
|
||
|
* will fail.
|
||
|
*
|
||
|
* @run_proc is the function which will be called to execute the
|
||
|
* procedure.
|
||
|
*
|
||
|
* 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
|
||
|
* explicitly enable receiving of temporary procedure run requests
|
||
|
* using either gimp_extension_enable() or
|
||
|
* gimp_extension_process(). See this functions' documentation for
|
||
|
* details.
|
||
|
**/
|
||
|
void
|
||
|
gimp_install_temp_proc (const gchar *name,
|
||
|
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)
|
||
|
{
|
||
|
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);
|
||
|
|
||
|
gimp_install_procedure (name,
|
||
|
blurb, help,
|
||
|
author, copyright, date,
|
||
|
menu_label,
|
||
|
image_types,
|
||
|
type,
|
||
|
n_params, n_return_vals,
|
||
|
params, return_vals);
|
||
|
|
||
|
/* Insert the temp proc run function into the hash table */
|
||
|
g_hash_table_insert (temp_proc_ht, g_strdup (name), (gpointer) run_proc);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_uninstall_temp_proc:
|
||
|
* @name: the procedure's name
|
||
|
*
|
||
|
* Uninstalls a temporary procedure which has previously been
|
||
|
* installed using gimp_install_temp_proc().
|
||
|
**/
|
||
|
void
|
||
|
gimp_uninstall_temp_proc (const gchar *name)
|
||
|
{
|
||
|
GPProcUninstall proc_uninstall;
|
||
|
gpointer hash_name;
|
||
|
gboolean found;
|
||
|
|
||
|
g_return_if_fail (name != NULL);
|
||
|
|
||
|
proc_uninstall.name = (gchar *) name;
|
||
|
|
||
|
if (! gp_proc_uninstall_write (_writechannel, &proc_uninstall, NULL))
|
||
|
gimp_quit ();
|
||
|
|
||
|
found = g_hash_table_lookup_extended (temp_proc_ht, name, &hash_name, NULL);
|
||
|
if (found)
|
||
|
{
|
||
|
g_hash_table_remove (temp_proc_ht, (gpointer) name);
|
||
|
g_free (hash_name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_run_procedure:
|
||
|
* @name: the name of the procedure to run
|
||
|
* @n_return_vals: return location for the number of return values
|
||
|
* @...: list of procedure parameters
|
||
|
*
|
||
|
* This function calls a GIMP procedure and returns its return values.
|
||
|
*
|
||
|
* The procedure's parameters are given by a va_list in the format
|
||
|
* (type, value, type, value) and must be terminated by %GIMP_PDB_END.
|
||
|
*
|
||
|
* This function converts the va_list of parameters into an array and
|
||
|
* passes them to gimp_run_procedure2(). Please look there for further
|
||
|
* information.
|
||
|
*
|
||
|
* 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.
|
||
|
**/
|
||
|
GimpParam *
|
||
|
gimp_run_procedure (const gchar *name,
|
||
|
gint *n_return_vals,
|
||
|
...)
|
||
|
{
|
||
|
GimpPDBArgType param_type;
|
||
|
GimpParam *return_vals;
|
||
|
GimpParam *params = NULL;
|
||
|
gint n_params = 0;
|
||
|
va_list args;
|
||
|
gint i;
|
||
|
|
||
|
g_return_val_if_fail (name != NULL, NULL);
|
||
|
g_return_val_if_fail (n_return_vals != NULL, NULL);
|
||
|
|
||
|
va_start (args, n_return_vals);
|
||
|
param_type = va_arg (args, GimpPDBArgType);
|
||
|
|
||
|
while (param_type != GIMP_PDB_END)
|
||
|
{
|
||
|
switch (param_type)
|
||
|
{
|
||
|
case GIMP_PDB_INT32:
|
||
|
case GIMP_PDB_DISPLAY:
|
||
|
case GIMP_PDB_IMAGE:
|
||
|
case GIMP_PDB_ITEM:
|
||
|
case GIMP_PDB_LAYER:
|
||
|
case GIMP_PDB_CHANNEL:
|
||
|
case GIMP_PDB_DRAWABLE:
|
||
|
case GIMP_PDB_SELECTION:
|
||
|
case GIMP_PDB_VECTORS:
|
||
|
case GIMP_PDB_STATUS:
|
||
|
(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;
|
||
|
case GIMP_PDB_FLOAT:
|
||
|
(void) va_arg (args, gdouble);
|
||
|
break;
|
||
|
case GIMP_PDB_STRING:
|
||
|
(void) va_arg (args, gchar *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT32ARRAY:
|
||
|
(void) va_arg (args, gint32 *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT16ARRAY:
|
||
|
(void) va_arg (args, gint16 *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT8ARRAY:
|
||
|
(void) va_arg (args, gint8 *);
|
||
|
break;
|
||
|
case GIMP_PDB_FLOATARRAY:
|
||
|
(void) va_arg (args, gdouble *);
|
||
|
break;
|
||
|
case GIMP_PDB_STRINGARRAY:
|
||
|
(void) va_arg (args, gchar **);
|
||
|
break;
|
||
|
case GIMP_PDB_COLOR:
|
||
|
case GIMP_PDB_COLORARRAY:
|
||
|
(void) va_arg (args, GimpRGB *);
|
||
|
break;
|
||
|
case GIMP_PDB_PARASITE:
|
||
|
(void) va_arg (args, GimpParasite *);
|
||
|
break;
|
||
|
case GIMP_PDB_END:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
n_params++;
|
||
|
|
||
|
param_type = va_arg (args, GimpPDBArgType);
|
||
|
}
|
||
|
|
||
|
va_end (args);
|
||
|
|
||
|
params = g_new0 (GimpParam, n_params);
|
||
|
|
||
|
va_start (args, n_return_vals);
|
||
|
|
||
|
for (i = 0; i < n_params; i++)
|
||
|
{
|
||
|
params[i].type = va_arg (args, GimpPDBArgType);
|
||
|
|
||
|
switch (params[i].type)
|
||
|
{
|
||
|
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:
|
||
|
params[i].data.d_int8 = (guint8) va_arg (args, gint);
|
||
|
break;
|
||
|
case GIMP_PDB_FLOAT:
|
||
|
params[i].data.d_float = (gdouble) va_arg (args, gdouble);
|
||
|
break;
|
||
|
case GIMP_PDB_STRING:
|
||
|
params[i].data.d_string = va_arg (args, gchar *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT32ARRAY:
|
||
|
params[i].data.d_int32array = va_arg (args, gint32 *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT16ARRAY:
|
||
|
params[i].data.d_int16array = va_arg (args, gint16 *);
|
||
|
break;
|
||
|
case GIMP_PDB_INT8ARRAY:
|
||
|
params[i].data.d_int8array = va_arg (args, guint8 *);
|
||
|
break;
|
||
|
case GIMP_PDB_FLOATARRAY:
|
||
|
params[i].data.d_floatarray = va_arg (args, gdouble *);
|
||
|
break;
|
||
|
case GIMP_PDB_STRINGARRAY:
|
||
|
params[i].data.d_stringarray = va_arg (args, gchar **);
|
||
|
break;
|
||
|
case GIMP_PDB_COLOR:
|
||
|
params[i].data.d_color = *va_arg (args, GimpRGB *);
|
||
|
break;
|
||
|
case GIMP_PDB_ITEM:
|
||
|
params[i].data.d_item = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_DISPLAY:
|
||
|
params[i].data.d_display = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_IMAGE:
|
||
|
params[i].data.d_image = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_LAYER:
|
||
|
params[i].data.d_layer = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_CHANNEL:
|
||
|
params[i].data.d_channel = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_DRAWABLE:
|
||
|
params[i].data.d_drawable = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_SELECTION:
|
||
|
params[i].data.d_selection = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_COLORARRAY:
|
||
|
params[i].data.d_colorarray = va_arg (args, GimpRGB *);
|
||
|
break;
|
||
|
case GIMP_PDB_VECTORS:
|
||
|
params[i].data.d_vectors = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_PARASITE:
|
||
|
{
|
||
|
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;
|
||
|
case GIMP_PDB_STATUS:
|
||
|
params[i].data.d_status = va_arg (args, gint32);
|
||
|
break;
|
||
|
case GIMP_PDB_END:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
va_end (args);
|
||
|
|
||
|
return_vals = gimp_run_procedure2 (name, n_return_vals, n_params, params);
|
||
|
|
||
|
g_free (params);
|
||
|
|
||
|
return return_vals;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gimp_read_expect_msg (GimpWireMessage *msg,
|
||
|
gint type)
|
||
|
{
|
||
|
while (TRUE)
|
||
|
{
|
||
|
if (! gimp_wire_read_msg (_readchannel, msg, NULL))
|
||
|
gimp_quit ();
|
||
|
|
||
|
if (msg->type == type)
|
||
|
return; /* up to the caller to call wire_destroy() */
|
||
|
|
||
|
if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT)
|
||
|
{
|
||
|
gimp_process_message (msg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_error ("unexpected message: %d", msg->type);
|
||
|
}
|
||
|
|
||
|
gimp_wire_destroy (msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*
|
||
|
* This function calls a GIMP procedure and returns its return values.
|
||
|
* To get more information about the available procedures and the
|
||
|
* parameters they expect, please have a look at the Procedure Browser
|
||
|
* as found in the Xtns menu in GIMP's toolbox.
|
||
|
*
|
||
|
* As soon as you don't need the return values any longer, you should
|
||
|
* free them using gimp_destroy_params().
|
||
|
*
|
||
|
* 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
|
||
|
* if there are two values returned, the other return value will be a
|
||
|
* string detailing the error.
|
||
|
**/
|
||
|
GimpParam *
|
||
|
gimp_run_procedure2 (const gchar *name,
|
||
|
gint *n_return_vals,
|
||
|
gint n_params,
|
||
|
const GimpParam *params)
|
||
|
{
|
||
|
GPProcRun proc_run;
|
||
|
GPProcReturn *proc_return;
|
||
|
GimpWireMessage msg;
|
||
|
GimpParam *return_vals;
|
||
|
|
||
|
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;
|
||
|
proc_run.params = (GPParam *) params;
|
||
|
|
||
|
if (! gp_proc_run_write (_writechannel, &proc_run, NULL))
|
||
|
gimp_quit ();
|
||
|
|
||
|
gimp_read_expect_msg (&msg, GP_PROC_RETURN);
|
||
|
|
||
|
proc_return = msg.data;
|
||
|
|
||
|
*n_return_vals = proc_return->nparams;
|
||
|
return_vals = (GimpParam *) proc_return->params;
|
||
|
|
||
|
proc_return->nparams = 0;
|
||
|
proc_return->params = NULL;
|
||
|
|
||
|
gimp_wire_destroy (&msg);
|
||
|
|
||
|
gimp_set_pdb_error (return_vals, *n_return_vals);
|
||
|
|
||
|
return return_vals;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_destroy_params:
|
||
|
* @params: the #GimpParam array to destroy
|
||
|
* @n_params: the number of elements in the array
|
||
|
*
|
||
|
* Destroys a #GimpParam array as returned by gimp_run_procedure() or
|
||
|
* gimp_run_procedure2().
|
||
|
**/
|
||
|
void
|
||
|
gimp_destroy_params (GimpParam *params,
|
||
|
gint n_params)
|
||
|
{
|
||
|
gp_params_destroy ((GPParam *) params, n_params);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_destroy_paramdefs:
|
||
|
* @paramdefs: the #GimpParamDef array to destroy
|
||
|
* @n_params: the number of elements in the array
|
||
|
*
|
||
|
* Destroys a #GimpParamDef array as returned by
|
||
|
* gimp_procedural_db_proc_info().
|
||
|
**/
|
||
|
void
|
||
|
gimp_destroy_paramdefs (GimpParamDef *paramdefs,
|
||
|
gint n_params)
|
||
|
{
|
||
|
while (n_params--)
|
||
|
{
|
||
|
g_free (paramdefs[n_params].name);
|
||
|
g_free (paramdefs[n_params].description);
|
||
|
}
|
||
|
|
||
|
g_free (paramdefs);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
* don't access the procedure return values directly. Thus libgimp
|
||
|
* stores the error message and makes it available with this
|
||
|
* function. The next procedure call unsets the error message again.
|
||
|
*
|
||
|
* The returned string is owned by libgimp and must not be freed or
|
||
|
* modified.
|
||
|
*
|
||
|
* Return value: the error message
|
||
|
*
|
||
|
* Since: 2.6
|
||
|
**/
|
||
|
const gchar *
|
||
|
gimp_get_pdb_error (void)
|
||
|
{
|
||
|
if (pdb_error_message && strlen (pdb_error_message))
|
||
|
return pdb_error_message;
|
||
|
|
||
|
switch (pdb_error_status)
|
||
|
{
|
||
|
case GIMP_PDB_SUCCESS:
|
||
|
/* procedure executed successfully */
|
||
|
return _("success");
|
||
|
|
||
|
case GIMP_PDB_EXECUTION_ERROR:
|
||
|
/* procedure execution failed */
|
||
|
return _("execution error");
|
||
|
|
||
|
case GIMP_PDB_CALLING_ERROR:
|
||
|
/* procedure called incorrectly */
|
||
|
return _("calling error");
|
||
|
|
||
|
case GIMP_PDB_CANCEL:
|
||
|
/* procedure execution cancelled */
|
||
|
return _("cancelled");
|
||
|
|
||
|
default:
|
||
|
return "invalid return status";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_get_pdb_status:
|
||
|
*
|
||
|
* Retrieves the status from the last procedure call.
|
||
|
*
|
||
|
* Return value: the #GimpPDBStatusType.
|
||
|
*
|
||
|
* Since: 2.10
|
||
|
**/
|
||
|
GimpPDBStatusType
|
||
|
gimp_get_pdb_status (void)
|
||
|
{
|
||
|
return pdb_error_status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_tile_width:
|
||
|
*
|
||
|
* Returns the tile width GIMP is using.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the tile_width
|
||
|
**/
|
||
|
guint
|
||
|
gimp_tile_width (void)
|
||
|
{
|
||
|
return _tile_width;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_tile_height:
|
||
|
*
|
||
|
* Returns the tile height GIMP is using.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the tile_height
|
||
|
**/
|
||
|
guint
|
||
|
gimp_tile_height (void)
|
||
|
{
|
||
|
return _tile_height;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_shm_ID:
|
||
|
*
|
||
|
* Returns the shared memory ID used for passing tile data between the
|
||
|
* GIMP core and the plug-in.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the shared memory ID
|
||
|
**/
|
||
|
gint
|
||
|
gimp_shm_ID (void)
|
||
|
{
|
||
|
return _shm_ID;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_shm_addr:
|
||
|
*
|
||
|
* Returns the address of the shared memory segment used for passing
|
||
|
* tile data between the GIMP core and the plug-in.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the shared memory address
|
||
|
**/
|
||
|
guchar *
|
||
|
gimp_shm_addr (void)
|
||
|
{
|
||
|
return _shm_addr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_gamma:
|
||
|
*
|
||
|
* Returns the global gamma value GIMP and all its plug-ins should
|
||
|
* use.
|
||
|
*
|
||
|
* This is a constant value.
|
||
|
*
|
||
|
* NOTE: This function will always return 2.2, the gamma value for
|
||
|
* sRGB. If you need the actual gamma value of a drawable, look at its
|
||
|
* format.
|
||
|
*
|
||
|
* See also: gimp_drawable_get_format().
|
||
|
*
|
||
|
* @Deprecated: 2.8.4
|
||
|
*
|
||
|
* Return value: the gamma value
|
||
|
**/
|
||
|
gdouble
|
||
|
gimp_gamma (void)
|
||
|
{
|
||
|
return 2.2;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_install_cmap:
|
||
|
*
|
||
|
* Returns whether or not the plug-in should allocate an own colormap
|
||
|
* when running on an 8 bit display. See also: gimp_min_colors().
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* @Deprecated: 2.8
|
||
|
*
|
||
|
* Return value: the install_cmap boolean
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_install_cmap (void)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_min_colors:
|
||
|
*
|
||
|
* Returns the minimum number of colors to use when allocating an own
|
||
|
* colormap on 8 bit displays.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* See also: gimp_install_cmap()
|
||
|
*
|
||
|
* @Deprecated: 2.8
|
||
|
*
|
||
|
* Return value: the minimum number of colors to allocate
|
||
|
**/
|
||
|
gint
|
||
|
gimp_min_colors (void)
|
||
|
{
|
||
|
return _min_colors;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_show_tool_tips:
|
||
|
*
|
||
|
* Returns whether or not the plug-in should show tool-tips.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the show_tool_tips boolean
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_show_tool_tips (void)
|
||
|
{
|
||
|
return _show_tool_tips;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_show_help_button:
|
||
|
*
|
||
|
* Returns whether or not GimpDialog should automatically add a help
|
||
|
* button if help_func and help_id are given.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the show_help_button boolean
|
||
|
*
|
||
|
* Since: 2.2
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_show_help_button (void)
|
||
|
{
|
||
|
return _show_help_button;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_export_color_profile:
|
||
|
*
|
||
|
* Returns whether file plug-ins should default to exporting the
|
||
|
* image's color profile.
|
||
|
*
|
||
|
* Return value: TRUE if preferences are set to export the color profile.
|
||
|
*
|
||
|
* Since: 2.10.4
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_export_color_profile (void)
|
||
|
{
|
||
|
return _export_profile;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_export_exif:
|
||
|
*
|
||
|
* Returns whether file plug-ins should default to exporting Exif
|
||
|
* metadata, according preferences (original settings is #FALSE since
|
||
|
* metadata can contain sensitive information).
|
||
|
*
|
||
|
* Return value: TRUE if preferences are set to export Exif.
|
||
|
*
|
||
|
* Since: 2.10
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_export_exif (void)
|
||
|
{
|
||
|
return _export_exif;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_export_xmp:
|
||
|
*
|
||
|
* Returns whether file plug-ins should default to exporting XMP
|
||
|
* metadata, according preferences (original settings is #FALSE since
|
||
|
* metadata can contain sensitive information).
|
||
|
*
|
||
|
* Return value: TRUE if preferences are set to export XMP.
|
||
|
*
|
||
|
* Since: 2.10
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_export_xmp (void)
|
||
|
{
|
||
|
return _export_xmp;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_export_iptc:
|
||
|
*
|
||
|
* Returns whether file plug-ins should default to exporting IPTC
|
||
|
* metadata, according preferences (original settings is #FALSE since
|
||
|
* metadata can contain sensitive information).
|
||
|
*
|
||
|
* Return value: TRUE if preferences are set to export IPTC.
|
||
|
*
|
||
|
* Since: 2.10
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_export_iptc (void)
|
||
|
{
|
||
|
return _export_iptc;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_check_size:
|
||
|
*
|
||
|
* Returns the size of the checkerboard to be used in previews.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the check_size value
|
||
|
*
|
||
|
* Since: 2.2
|
||
|
**/
|
||
|
GimpCheckSize
|
||
|
gimp_check_size (void)
|
||
|
{
|
||
|
return _check_size;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_check_type:
|
||
|
*
|
||
|
* Returns the type of the checkerboard to be used in previews.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the check_type value
|
||
|
*
|
||
|
* Since: 2.2
|
||
|
**/
|
||
|
GimpCheckType
|
||
|
gimp_check_type (void)
|
||
|
{
|
||
|
return _check_type;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_default_display:
|
||
|
*
|
||
|
* Returns the default display ID. This corresponds to the display the
|
||
|
* running procedure's menu entry was invoked from.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the default display ID
|
||
|
**/
|
||
|
gint32
|
||
|
gimp_default_display (void)
|
||
|
{
|
||
|
return _gdisp_ID;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_wm_class:
|
||
|
*
|
||
|
* Returns the window manager class to be used for plug-in windows.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the window manager class
|
||
|
**/
|
||
|
const gchar *
|
||
|
gimp_wm_class (void)
|
||
|
{
|
||
|
return _wm_class;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_display_name:
|
||
|
*
|
||
|
* Returns the display to be used for plug-in windows.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
* Will return #NULL if GIMP has been started with no GUI, either
|
||
|
* via "--no-interface" flag, or a console build.
|
||
|
*
|
||
|
* Return value: the display name
|
||
|
**/
|
||
|
const gchar *
|
||
|
gimp_display_name (void)
|
||
|
{
|
||
|
return _display_name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_monitor_number:
|
||
|
*
|
||
|
* Returns the monitor number to be used for plug-in windows.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the monitor number
|
||
|
**/
|
||
|
gint
|
||
|
gimp_monitor_number (void)
|
||
|
{
|
||
|
return _monitor_number;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_user_time:
|
||
|
*
|
||
|
* Returns the timestamp of the user interaction that should be set on
|
||
|
* the plug-in window. This is handled transparently, plug-in authors
|
||
|
* do not have to care about it.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: timestamp for plug-in window
|
||
|
*
|
||
|
* Since: 2.6
|
||
|
**/
|
||
|
guint32
|
||
|
gimp_user_time (void)
|
||
|
{
|
||
|
return _timestamp;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_get_icon_theme_dir:
|
||
|
*
|
||
|
* Returns the directory of the current icon theme.
|
||
|
*
|
||
|
* This is a constant value given at plug-in configuration time.
|
||
|
*
|
||
|
* Return value: the icon theme directory
|
||
|
*
|
||
|
* Since: 2.10.4
|
||
|
**/
|
||
|
const gchar *
|
||
|
gimp_icon_theme_dir (void)
|
||
|
{
|
||
|
return _icon_theme_dir;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_get_progname:
|
||
|
*
|
||
|
* Returns the plug-in's executable name.
|
||
|
*
|
||
|
* Return value: the executable name
|
||
|
**/
|
||
|
const gchar *
|
||
|
gimp_get_progname (void)
|
||
|
{
|
||
|
return progname;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_extension_ack:
|
||
|
*
|
||
|
* Notify the main GIMP application that the extension has been properly
|
||
|
* initialized and is ready to run.
|
||
|
*
|
||
|
* This function <emphasis>must</emphasis> be called from every
|
||
|
* procedure that was registered as #GIMP_EXTENSION.
|
||
|
*
|
||
|
* Subsequently, extensions can process temporary procedure run
|
||
|
* requests using either gimp_extension_enable() or
|
||
|
* gimp_extension_process().
|
||
|
*
|
||
|
* See also: gimp_install_procedure(), gimp_install_temp_proc()
|
||
|
**/
|
||
|
void
|
||
|
gimp_extension_ack (void)
|
||
|
{
|
||
|
if (! gp_extension_ack_write (_writechannel, NULL))
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_extension_enable:
|
||
|
*
|
||
|
* Enables asynchronous processing of messages from the main GIMP
|
||
|
* application.
|
||
|
*
|
||
|
* Normally, a plug-in is not called by GIMP except for the call to
|
||
|
* the procedure it implements. All subsequent communication is
|
||
|
* triggered by the plug-in and all messages sent from GIMP to the
|
||
|
* plug-in are just answers to requests the plug-in made.
|
||
|
*
|
||
|
* If the plug-in however registered temporary procedures using
|
||
|
* gimp_install_temp_proc(), it needs to be able to receive requests
|
||
|
* to execute them. Usually this will be done by running
|
||
|
* gimp_extension_process() in an endless loop.
|
||
|
*
|
||
|
* If the plug-in cannot use gimp_extension_process(), i.e. if it has
|
||
|
* a GUI and is hanging around in a #GMainLoop, it must call
|
||
|
* gimp_extension_enable().
|
||
|
*
|
||
|
* Note that the plug-in does not need to be a #GIMP_EXTENSION to
|
||
|
* register temporary procedures.
|
||
|
*
|
||
|
* See also: gimp_install_procedure(), gimp_install_temp_proc()
|
||
|
**/
|
||
|
void
|
||
|
gimp_extension_enable (void)
|
||
|
{
|
||
|
static gboolean callback_added = FALSE;
|
||
|
|
||
|
if (! callback_added)
|
||
|
{
|
||
|
g_io_add_watch (_readchannel, G_IO_IN | G_IO_PRI, gimp_extension_read,
|
||
|
NULL);
|
||
|
|
||
|
callback_added = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_extension_process:
|
||
|
* @timeout: The timeout (in ms) to use for the select() call.
|
||
|
*
|
||
|
* Processes one message sent by GIMP and returns.
|
||
|
*
|
||
|
* Call this function in an endless loop after calling
|
||
|
* gimp_extension_ack() to process requests for running temporary
|
||
|
* procedures.
|
||
|
*
|
||
|
* See gimp_extension_enable() for an asynchronous way of doing the
|
||
|
* same if running an endless loop is not an option.
|
||
|
*
|
||
|
* See also: gimp_install_procedure(), gimp_install_temp_proc()
|
||
|
**/
|
||
|
void
|
||
|
gimp_extension_process (guint timeout)
|
||
|
{
|
||
|
#ifndef G_OS_WIN32
|
||
|
gint select_val;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
fd_set readfds;
|
||
|
struct timeval tv;
|
||
|
struct timeval *tvp;
|
||
|
|
||
|
if (timeout)
|
||
|
{
|
||
|
tv.tv_sec = timeout / 1000;
|
||
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||
|
tvp = &tv;
|
||
|
}
|
||
|
else
|
||
|
tvp = NULL;
|
||
|
|
||
|
FD_ZERO (&readfds);
|
||
|
FD_SET (g_io_channel_unix_get_fd (_readchannel), &readfds);
|
||
|
|
||
|
if ((select_val = select (FD_SETSIZE, &readfds, NULL, NULL, tvp)) > 0)
|
||
|
{
|
||
|
gimp_single_message ();
|
||
|
}
|
||
|
else if (select_val == -1 && errno != EINTR)
|
||
|
{
|
||
|
perror ("gimp_extension_process");
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
}
|
||
|
while (select_val == -1 && errno == EINTR);
|
||
|
#else
|
||
|
/* Zero means infinite wait for us, but g_poll and
|
||
|
* g_io_channel_win32_poll use -1 to indicate
|
||
|
* infinite wait.
|
||
|
*/
|
||
|
GPollFD pollfd;
|
||
|
|
||
|
if (timeout == 0)
|
||
|
timeout = -1;
|
||
|
|
||
|
g_io_channel_win32_make_pollfd (_readchannel, G_IO_IN, &pollfd);
|
||
|
|
||
|
if (g_io_channel_win32_poll (&pollfd, 1, timeout) == 1)
|
||
|
gimp_single_message ();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_parasite_find:
|
||
|
* @name: The name of the parasite to find.
|
||
|
*
|
||
|
* Deprecated: Use gimp_get_parasite() instead.
|
||
|
*
|
||
|
* Returns: The found parasite.
|
||
|
**/
|
||
|
GimpParasite *
|
||
|
gimp_parasite_find (const gchar *name)
|
||
|
{
|
||
|
return gimp_get_parasite (name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_parasite_attach:
|
||
|
* @parasite: The parasite to attach.
|
||
|
*
|
||
|
* Deprecated: Use gimp_attach_parasite() instead.
|
||
|
*
|
||
|
* Returns: TRUE on success.
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_parasite_attach (const GimpParasite *parasite)
|
||
|
{
|
||
|
return gimp_attach_parasite (parasite);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_parasite_detach:
|
||
|
* @name: The name of the parasite to detach.
|
||
|
*
|
||
|
* Deprecated: Use gimp_detach_parasite() instead.
|
||
|
*
|
||
|
* Returns: TRUE on success.
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_parasite_detach (const gchar *name)
|
||
|
{
|
||
|
return gimp_detach_parasite (name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_parasite_list:
|
||
|
* @num_parasites: The number of attached parasites.
|
||
|
* @parasites: The names of currently attached parasites.
|
||
|
*
|
||
|
* Deprecated: Use gimp_get_parasite_list() instead.
|
||
|
*
|
||
|
* Returns: TRUE on success.
|
||
|
**/
|
||
|
gboolean
|
||
|
gimp_parasite_list (gint *num_parasites,
|
||
|
gchar ***parasites)
|
||
|
{
|
||
|
*parasites = gimp_get_parasite_list (num_parasites);
|
||
|
|
||
|
return *parasites != NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gimp_attach_new_parasite:
|
||
|
* @name: the name of the #GimpParasite to create and attach.
|
||
|
* @flags: the flags set on the #GimpParasite.
|
||
|
* @size: the size of the parasite data in bytes.
|
||
|
* @data: a pointer to the data attached with the #GimpParasite.
|
||
|
*
|
||
|
* Convenience function that creates a parasite and attaches it
|
||
|
* to GIMP.
|
||
|
*
|
||
|
* Deprecated: Use gimp_attach_parasite() instead.
|
||
|
*
|
||
|
* Return value: TRUE on successful creation and attachment of
|
||
|
* the new parasite.
|
||
|
*
|
||
|
* See Also: gimp_attach_parasite()
|
||
|
*/
|
||
|
gboolean
|
||
|
gimp_attach_new_parasite (const gchar *name,
|
||
|
gint flags,
|
||
|
gint size,
|
||
|
gconstpointer data)
|
||
|
{
|
||
|
GimpParasite *parasite = gimp_parasite_new (name, flags, size, data);
|
||
|
gboolean success;
|
||
|
|
||
|
success = gimp_attach_parasite (parasite);
|
||
|
|
||
|
gimp_parasite_free (parasite);
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* private functions */
|
||
|
|
||
|
static void
|
||
|
gimp_close (void)
|
||
|
{
|
||
|
if (gimp_debug_flags & GIMP_DEBUG_QUIT)
|
||
|
gimp_debug_stop ();
|
||
|
|
||
|
if (PLUG_IN_INFO.quit_proc)
|
||
|
(* PLUG_IN_INFO.quit_proc) ();
|
||
|
|
||
|
#if defined(USE_SYSV_SHM)
|
||
|
|
||
|
if ((_shm_ID != -1) && _shm_addr)
|
||
|
shmdt ((char *) _shm_addr);
|
||
|
|
||
|
#elif defined(USE_WIN32_SHM)
|
||
|
|
||
|
if (shm_handle)
|
||
|
CloseHandle (shm_handle);
|
||
|
|
||
|
#elif defined(USE_POSIX_SHM)
|
||
|
|
||
|
if ((_shm_ID != -1) && (_shm_addr != MAP_FAILED))
|
||
|
munmap (_shm_addr, TILE_MAP_SIZE);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
gp_quit_write (_writechannel, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_debug_stop (void)
|
||
|
{
|
||
|
#ifndef G_OS_WIN32
|
||
|
|
||
|
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Waiting for debugger...");
|
||
|
raise (SIGSTOP);
|
||
|
|
||
|
#else
|
||
|
|
||
|
HANDLE hThreadSnap = NULL;
|
||
|
THREADENTRY32 te32 = { 0 };
|
||
|
pid_t opid = getpid ();
|
||
|
|
||
|
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
|
||
|
"Debugging (restart externally): %ld",
|
||
|
(long int) opid);
|
||
|
|
||
|
hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
|
||
|
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
|
||
|
"error getting threadsnap - debugging impossible");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
te32.dwSize = sizeof (THREADENTRY32);
|
||
|
|
||
|
if (Thread32First (hThreadSnap, &te32))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if (te32.th32OwnerProcessID == opid)
|
||
|
{
|
||
|
HANDLE hThread = OpenThread (THREAD_SUSPEND_RESUME, FALSE,
|
||
|
te32.th32ThreadID);
|
||
|
SuspendThread (hThread);
|
||
|
CloseHandle (hThread);
|
||
|
}
|
||
|
}
|
||
|
while (Thread32Next (hThreadSnap, &te32));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "error getting threads");
|
||
|
}
|
||
|
|
||
|
CloseHandle (hThreadSnap);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_message_func (const gchar *log_domain,
|
||
|
GLogLevelFlags log_level,
|
||
|
const gchar *message,
|
||
|
gpointer data)
|
||
|
{
|
||
|
gimp_message (message);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_fatal_func (const gchar *log_domain,
|
||
|
GLogLevelFlags flags,
|
||
|
const gchar *message,
|
||
|
gpointer data)
|
||
|
{
|
||
|
const gchar *level;
|
||
|
|
||
|
switch (flags & G_LOG_LEVEL_MASK)
|
||
|
{
|
||
|
case G_LOG_LEVEL_WARNING:
|
||
|
level = "WARNING";
|
||
|
break;
|
||
|
case G_LOG_LEVEL_CRITICAL:
|
||
|
level = "CRITICAL";
|
||
|
break;
|
||
|
case G_LOG_LEVEL_ERROR:
|
||
|
level = "ERROR";
|
||
|
break;
|
||
|
default:
|
||
|
level = "FATAL";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
g_printerr ("%s: %s: %s\n",
|
||
|
progname, level, message);
|
||
|
|
||
|
#ifndef G_OS_WIN32
|
||
|
switch (stack_trace_mode)
|
||
|
{
|
||
|
case GIMP_STACK_TRACE_NEVER:
|
||
|
break;
|
||
|
|
||
|
case GIMP_STACK_TRACE_QUERY:
|
||
|
{
|
||
|
sigset_t sigset;
|
||
|
|
||
|
sigemptyset (&sigset);
|
||
|
sigprocmask (SIG_SETMASK, &sigset, NULL);
|
||
|
gimp_stack_trace_query (progname);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case GIMP_STACK_TRACE_ALWAYS:
|
||
|
{
|
||
|
sigset_t sigset;
|
||
|
|
||
|
sigemptyset (&sigset);
|
||
|
sigprocmask (SIG_SETMASK, &sigset, NULL);
|
||
|
gimp_stack_trace_print (progname, stdout, NULL);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Do not end with gimp_quit().
|
||
|
* We want the plug-in to continue its normal crash course, otherwise
|
||
|
* we won't get the "Plug-in crashed" error in GIMP.
|
||
|
*/
|
||
|
exit (EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
#ifdef G_OS_WIN32
|
||
|
|
||
|
#ifdef HAVE_EXCHNDL
|
||
|
static LONG WINAPI
|
||
|
gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo)
|
||
|
{
|
||
|
g_printerr ("%s: fatal error\n", progname);
|
||
|
|
||
|
SetUnhandledExceptionFilter (_prevExceptionFilter);
|
||
|
|
||
|
/* For simplicity, do not make a difference between QUERY and ALWAYS
|
||
|
* on Windows (at least not for now).
|
||
|
*/
|
||
|
if (stack_trace_mode != GIMP_STACK_TRACE_NEVER &&
|
||
|
g_file_test (plug_in_backtrace_path, G_FILE_TEST_IS_REGULAR))
|
||
|
{
|
||
|
FILE *stream;
|
||
|
guchar buffer[256];
|
||
|
size_t read_len;
|
||
|
|
||
|
stream = fopen (plug_in_backtrace_path, "r");
|
||
|
do
|
||
|
{
|
||
|
/* Just read and output directly the file content. */
|
||
|
read_len = fread (buffer, 1, sizeof (buffer) - 1, stream);
|
||
|
buffer[read_len] = '\0';
|
||
|
g_printerr ("%s", buffer);
|
||
|
}
|
||
|
while (read_len);
|
||
|
fclose (stream);
|
||
|
}
|
||
|
|
||
|
if (_prevExceptionFilter && _prevExceptionFilter != gimp_plugin_sigfatal_handler)
|
||
|
return _prevExceptionFilter (pExceptionInfo);
|
||
|
else
|
||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#else
|
||
|
static void
|
||
|
gimp_plugin_sigfatal_handler (gint sig_num)
|
||
|
{
|
||
|
switch (sig_num)
|
||
|
{
|
||
|
case SIGHUP:
|
||
|
case SIGINT:
|
||
|
case SIGQUIT:
|
||
|
case SIGTERM:
|
||
|
g_printerr ("%s terminated: %s\n", progname, g_strsignal (sig_num));
|
||
|
break;
|
||
|
|
||
|
case SIGABRT:
|
||
|
case SIGBUS:
|
||
|
case SIGSEGV:
|
||
|
case SIGFPE:
|
||
|
case SIGPIPE:
|
||
|
default:
|
||
|
g_printerr ("%s: fatal error: %s\n", progname, g_strsignal (sig_num));
|
||
|
switch (stack_trace_mode)
|
||
|
{
|
||
|
case GIMP_STACK_TRACE_NEVER:
|
||
|
break;
|
||
|
|
||
|
case GIMP_STACK_TRACE_QUERY:
|
||
|
{
|
||
|
sigset_t sigset;
|
||
|
|
||
|
sigemptyset (&sigset);
|
||
|
sigprocmask (SIG_SETMASK, &sigset, NULL);
|
||
|
gimp_stack_trace_query (progname);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case GIMP_STACK_TRACE_ALWAYS:
|
||
|
{
|
||
|
sigset_t sigset;
|
||
|
|
||
|
sigemptyset (&sigset);
|
||
|
sigprocmask (SIG_SETMASK, &sigset, NULL);
|
||
|
gimp_stack_trace_print (progname, stdout, NULL);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Do not end with gimp_quit().
|
||
|
* We want the plug-in to continue its normal crash course, otherwise
|
||
|
* we won't get the "Plug-in crashed" error in GIMP.
|
||
|
*/
|
||
|
exit (EXIT_FAILURE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static gboolean
|
||
|
gimp_plugin_io_error_handler (GIOChannel *channel,
|
||
|
GIOCondition cond,
|
||
|
gpointer data)
|
||
|
{
|
||
|
g_printerr ("%s: fatal error: GIMP crashed\n", progname);
|
||
|
gimp_quit ();
|
||
|
|
||
|
/* never reached */
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
gimp_write (GIOChannel *channel,
|
||
|
const guint8 *buf,
|
||
|
gulong count,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
gulong bytes;
|
||
|
|
||
|
while (count > 0)
|
||
|
{
|
||
|
if ((write_buffer_index + count) >= WRITE_BUFFER_SIZE)
|
||
|
{
|
||
|
bytes = WRITE_BUFFER_SIZE - write_buffer_index;
|
||
|
memcpy (&write_buffer[write_buffer_index], buf, bytes);
|
||
|
write_buffer_index += bytes;
|
||
|
if (! gimp_wire_flush (channel, NULL))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bytes = count;
|
||
|
memcpy (&write_buffer[write_buffer_index], buf, bytes);
|
||
|
write_buffer_index += bytes;
|
||
|
}
|
||
|
|
||
|
buf += bytes;
|
||
|
count -= bytes;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
gimp_flush (GIOChannel *channel,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
GIOStatus status;
|
||
|
GError *error = NULL;
|
||
|
gsize count;
|
||
|
gsize bytes;
|
||
|
|
||
|
if (write_buffer_index > 0)
|
||
|
{
|
||
|
count = 0;
|
||
|
while (count != write_buffer_index)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
bytes = 0;
|
||
|
status = g_io_channel_write_chars (channel,
|
||
|
&write_buffer[count],
|
||
|
(write_buffer_index - count),
|
||
|
&bytes,
|
||
|
&error);
|
||
|
}
|
||
|
while (status == G_IO_STATUS_AGAIN);
|
||
|
|
||
|
if (status != G_IO_STATUS_NORMAL)
|
||
|
{
|
||
|
if (error)
|
||
|
{
|
||
|
g_warning ("%s: gimp_flush(): error: %s",
|
||
|
g_get_prgname (), error->message);
|
||
|
g_error_free (error);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_warning ("%s: gimp_flush(): error", g_get_prgname ());
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
count += bytes;
|
||
|
}
|
||
|
|
||
|
write_buffer_index = 0;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_loop (void)
|
||
|
{
|
||
|
GimpWireMessage msg;
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
if (! gimp_wire_read_msg (_readchannel, &msg, NULL))
|
||
|
{
|
||
|
gimp_close ();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (msg.type)
|
||
|
{
|
||
|
case GP_QUIT:
|
||
|
gimp_wire_destroy (&msg);
|
||
|
gimp_close ();
|
||
|
return;
|
||
|
|
||
|
case GP_CONFIG:
|
||
|
gimp_config (msg.data);
|
||
|
break;
|
||
|
|
||
|
case GP_TILE_REQ:
|
||
|
case GP_TILE_ACK:
|
||
|
case GP_TILE_DATA:
|
||
|
g_warning ("unexpected tile message received (should not happen)");
|
||
|
break;
|
||
|
|
||
|
case GP_PROC_RUN:
|
||
|
gimp_proc_run (msg.data);
|
||
|
gimp_wire_destroy (&msg);
|
||
|
gimp_close ();
|
||
|
return;
|
||
|
|
||
|
case GP_PROC_RETURN:
|
||
|
g_warning ("unexpected proc return message received (should not happen)");
|
||
|
break;
|
||
|
|
||
|
case GP_TEMP_PROC_RUN:
|
||
|
g_warning ("unexpected temp proc run message received (should not happen");
|
||
|
break;
|
||
|
|
||
|
case GP_TEMP_PROC_RETURN:
|
||
|
g_warning ("unexpected temp proc return message received (should not happen");
|
||
|
break;
|
||
|
|
||
|
case GP_PROC_INSTALL:
|
||
|
g_warning ("unexpected proc install message received (should not happen)");
|
||
|
break;
|
||
|
|
||
|
case GP_HAS_INIT:
|
||
|
g_warning ("unexpected has init message received (should not happen)");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gimp_wire_destroy (&msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_config (GPConfig *config)
|
||
|
{
|
||
|
GFile *file;
|
||
|
gchar *path;
|
||
|
|
||
|
if (config->version < GIMP_PROTOCOL_VERSION)
|
||
|
{
|
||
|
g_message ("Could not execute plug-in \"%s\"\n(%s)\n"
|
||
|
"because GIMP is using an older version of the "
|
||
|
"plug-in protocol.",
|
||
|
gimp_filename_to_utf8 (g_get_prgname ()),
|
||
|
gimp_filename_to_utf8 (progname));
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
else if (config->version > GIMP_PROTOCOL_VERSION)
|
||
|
{
|
||
|
g_message ("Could not execute plug-in \"%s\"\n(%s)\n"
|
||
|
"because it uses an obsolete version of the "
|
||
|
"plug-in protocol.",
|
||
|
gimp_filename_to_utf8 (g_get_prgname ()),
|
||
|
gimp_filename_to_utf8 (progname));
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
|
||
|
_tile_width = config->tile_width;
|
||
|
_tile_height = config->tile_height;
|
||
|
_shm_ID = config->shm_ID;
|
||
|
_check_size = config->check_size;
|
||
|
_check_type = config->check_type;
|
||
|
_show_tool_tips = config->show_tooltips ? TRUE : FALSE;
|
||
|
_show_help_button = config->show_help_button ? TRUE : FALSE;
|
||
|
_export_profile = config->export_profile ? TRUE : FALSE;
|
||
|
_export_exif = config->export_exif ? TRUE : FALSE;
|
||
|
_export_xmp = config->export_xmp ? TRUE : FALSE;
|
||
|
_export_iptc = config->export_iptc ? TRUE : FALSE;
|
||
|
_min_colors = config->min_colors;
|
||
|
_gdisp_ID = config->gdisp_ID;
|
||
|
_wm_class = g_strdup (config->wm_class);
|
||
|
_display_name = g_strdup (config->display_name);
|
||
|
_monitor_number = config->monitor_number;
|
||
|
_timestamp = config->timestamp;
|
||
|
_icon_theme_dir = g_strdup (config->icon_theme_dir);
|
||
|
|
||
|
if (config->app_name)
|
||
|
g_set_application_name (config->app_name);
|
||
|
|
||
|
gimp_cpu_accel_set_use (config->use_cpu_accel);
|
||
|
|
||
|
file = gimp_file_new_for_config_path (config->swap_path, NULL);
|
||
|
path = g_file_get_path (file);
|
||
|
|
||
|
g_object_set (gegl_config (),
|
||
|
"tile-cache-size", config->tile_cache_size,
|
||
|
"swap", path,
|
||
|
"swap-compression", config->swap_compression,
|
||
|
"threads", (gint) config->num_processors,
|
||
|
"use-opencl", config->use_opencl,
|
||
|
"application-license", "GPL3",
|
||
|
NULL);
|
||
|
|
||
|
g_free (path);
|
||
|
g_object_unref (file);
|
||
|
|
||
|
if (_shm_ID != -1)
|
||
|
{
|
||
|
#if defined(USE_SYSV_SHM)
|
||
|
|
||
|
/* Use SysV shared memory mechanisms for transferring tile data. */
|
||
|
|
||
|
_shm_addr = (guchar *) shmat (_shm_ID, NULL, 0);
|
||
|
|
||
|
if (_shm_addr == (guchar *) -1)
|
||
|
{
|
||
|
g_error ("shmat() failed: %s\n" ERRMSG_SHM_FAILED,
|
||
|
g_strerror (errno));
|
||
|
}
|
||
|
|
||
|
#elif defined(USE_WIN32_SHM)
|
||
|
|
||
|
/* Use Win32 shared memory mechanisms for transferring tile data. */
|
||
|
|
||
|
gchar fileMapName[128];
|
||
|
|
||
|
/* From the id, derive the file map name */
|
||
|
g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", _shm_ID);
|
||
|
|
||
|
/* Open the file mapping */
|
||
|
shm_handle = OpenFileMapping (FILE_MAP_ALL_ACCESS,
|
||
|
0, fileMapName);
|
||
|
if (shm_handle)
|
||
|
{
|
||
|
/* Map the shared memory into our address space for use */
|
||
|
_shm_addr = (guchar *) MapViewOfFile (shm_handle,
|
||
|
FILE_MAP_ALL_ACCESS,
|
||
|
0, 0, TILE_MAP_SIZE);
|
||
|
|
||
|
/* Verify that we mapped our view */
|
||
|
if (!_shm_addr)
|
||
|
{
|
||
|
g_error ("MapViewOfFile error: %lu... " ERRMSG_SHM_FAILED,
|
||
|
GetLastError ());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_error ("OpenFileMapping error: %lu... " ERRMSG_SHM_FAILED,
|
||
|
GetLastError ());
|
||
|
}
|
||
|
|
||
|
#elif defined(USE_POSIX_SHM)
|
||
|
|
||
|
/* Use POSIX shared memory mechanisms for transferring tile data. */
|
||
|
|
||
|
gchar map_file[32];
|
||
|
gint shm_fd;
|
||
|
|
||
|
/* From the id, derive the file map name */
|
||
|
g_snprintf (map_file, sizeof (map_file), "/gimp-shm-%d", _shm_ID);
|
||
|
|
||
|
/* Open the file mapping */
|
||
|
shm_fd = shm_open (map_file, O_RDWR, 0600);
|
||
|
|
||
|
if (shm_fd != -1)
|
||
|
{
|
||
|
/* Map the shared memory into our address space for use */
|
||
|
_shm_addr = (guchar *) mmap (NULL, TILE_MAP_SIZE,
|
||
|
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||
|
shm_fd, 0);
|
||
|
|
||
|
/* Verify that we mapped our view */
|
||
|
if (_shm_addr == MAP_FAILED)
|
||
|
{
|
||
|
g_error ("mmap() failed: %s\n" ERRMSG_SHM_FAILED,
|
||
|
g_strerror (errno));
|
||
|
}
|
||
|
|
||
|
close (shm_fd);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_error ("shm_open() failed: %s\n" ERRMSG_SHM_FAILED,
|
||
|
g_strerror (errno));
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_proc_run (GPProcRun *proc_run)
|
||
|
{
|
||
|
if (PLUG_IN_INFO.run_proc)
|
||
|
{
|
||
|
GPProcReturn proc_return;
|
||
|
GimpParam *return_vals;
|
||
|
gint n_return_vals;
|
||
|
|
||
|
(* PLUG_IN_INFO.run_proc) (proc_run->name,
|
||
|
proc_run->nparams,
|
||
|
(GimpParam *) proc_run->params,
|
||
|
&n_return_vals, &return_vals);
|
||
|
|
||
|
proc_return.name = proc_run->name;
|
||
|
proc_return.nparams = n_return_vals;
|
||
|
proc_return.params = (GPParam *) return_vals;
|
||
|
|
||
|
if (! gp_proc_return_write (_writechannel, &proc_return, NULL))
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_temp_proc_run (GPProcRun *proc_run)
|
||
|
{
|
||
|
GimpRunProc run_proc = g_hash_table_lookup (temp_proc_ht, proc_run->name);
|
||
|
|
||
|
if (run_proc)
|
||
|
{
|
||
|
GPProcReturn proc_return;
|
||
|
GimpParam *return_vals;
|
||
|
gint n_return_vals;
|
||
|
|
||
|
#ifdef GDK_WINDOWING_QUARTZ
|
||
|
if (proc_run->params &&
|
||
|
proc_run->params[0].data.d_int32 == GIMP_RUN_INTERACTIVE)
|
||
|
{
|
||
|
[NSApp activateIgnoringOtherApps: YES];
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
(* run_proc) (proc_run->name,
|
||
|
proc_run->nparams,
|
||
|
(GimpParam *) proc_run->params,
|
||
|
&n_return_vals, &return_vals);
|
||
|
|
||
|
proc_return.name = proc_run->name;
|
||
|
proc_return.nparams = n_return_vals;
|
||
|
proc_return.params = (GPParam *) return_vals;
|
||
|
|
||
|
if (! gp_temp_proc_return_write (_writechannel, &proc_return, NULL))
|
||
|
gimp_quit ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_process_message (GimpWireMessage *msg)
|
||
|
{
|
||
|
switch (msg->type)
|
||
|
{
|
||
|
case GP_QUIT:
|
||
|
gimp_quit ();
|
||
|
break;
|
||
|
case GP_CONFIG:
|
||
|
gimp_config (msg->data);
|
||
|
break;
|
||
|
case GP_TILE_REQ:
|
||
|
case GP_TILE_ACK:
|
||
|
case GP_TILE_DATA:
|
||
|
g_warning ("unexpected tile message received (should not happen)");
|
||
|
break;
|
||
|
case GP_PROC_RUN:
|
||
|
g_warning ("unexpected proc run message received (should not happen)");
|
||
|
break;
|
||
|
case GP_PROC_RETURN:
|
||
|
g_warning ("unexpected proc return message received (should not happen)");
|
||
|
break;
|
||
|
case GP_TEMP_PROC_RUN:
|
||
|
gimp_temp_proc_run (msg->data);
|
||
|
break;
|
||
|
case GP_TEMP_PROC_RETURN:
|
||
|
g_warning ("unexpected temp proc return message received (should not happen)");
|
||
|
break;
|
||
|
case GP_PROC_INSTALL:
|
||
|
g_warning ("unexpected proc install message received (should not happen)");
|
||
|
break;
|
||
|
case GP_HAS_INIT:
|
||
|
g_warning ("unexpected has init message received (should not happen)");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_single_message (void)
|
||
|
{
|
||
|
GimpWireMessage msg;
|
||
|
|
||
|
/* Run a temp function */
|
||
|
if (! gimp_wire_read_msg (_readchannel, &msg, NULL))
|
||
|
gimp_quit ();
|
||
|
|
||
|
gimp_process_message (&msg);
|
||
|
|
||
|
gimp_wire_destroy (&msg);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
gimp_extension_read (GIOChannel *channel,
|
||
|
GIOCondition condition,
|
||
|
gpointer data)
|
||
|
{
|
||
|
gimp_single_message ();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gimp_set_pdb_error (const GimpParam *return_vals,
|
||
|
gint n_return_vals)
|
||
|
{
|
||
|
if (pdb_error_message)
|
||
|
{
|
||
|
g_free (pdb_error_message);
|
||
|
pdb_error_message = NULL;
|
||
|
}
|
||
|
|
||
|
pdb_error_status = return_vals[0].data.d_status;
|
||
|
|
||
|
switch (pdb_error_status)
|
||
|
{
|
||
|
case GIMP_PDB_SUCCESS:
|
||
|
case GIMP_PDB_PASS_THROUGH:
|
||
|
break;
|
||
|
|
||
|
case GIMP_PDB_EXECUTION_ERROR:
|
||
|
case GIMP_PDB_CALLING_ERROR:
|
||
|
case GIMP_PDB_CANCEL:
|
||
|
if (n_return_vals > 1 && return_vals[1].type == GIMP_PDB_STRING)
|
||
|
{
|
||
|
pdb_error_message = g_strdup (return_vals[1].data.d_string);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|