/* 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 2 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifndef WAIT_ANY #define WAIT_ANY -1 #endif #include #ifndef G_OS_WIN32 #include "libgimpbase/gimpsignal.h" #else #include #endif #ifdef HAVE_IPC_H #include #endif #ifdef HAVE_SHM_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) # define STRICT # include # undef RGB #endif #ifdef __EMX__ # include #endif #include #include #ifndef LIBGIMP_COMPILATION #define LIBGIMP_COMPILATION #endif #include "libgimpbase/gimpbasetypes.h" #include "libgimpbase/gimpenv.h" #include "libgimpbase/gimpprotocol.h" #include "libgimpbase/gimpwire.h" #include "gimp.h" /* 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_DEFAULT = (GIMP_DEBUG_RUN | GIMP_DEBUG_FATAL_WARNINGS) } GimpDebugFlag; #define WRITE_BUFFER_SIZE 1024 void gimp_extension_process (guint timeout); void gimp_extension_ack (void); void gimp_read_expect_msg (WireMessage *msg, gint type); static void gimp_debug_stop (void); #ifndef G_OS_WIN32 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, 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_message_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer data); static void gimp_process_message (WireMessage *msg); static void gimp_close (void); GIOChannel *_readchannel = NULL; GIOChannel *_writechannel = NULL; gint _shm_ID = -1; guchar *_shm_addr = NULL; guint gimp_major_version = GIMP_MAJOR_VERSION; guint gimp_minor_version = GIMP_MINOR_VERSION; guint gimp_micro_version = GIMP_MICRO_VERSION; #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) static HANDLE shm_handle; #endif static gdouble _gamma_val; static gboolean _install_cmap; static gboolean _show_tool_tips; static gint _min_colors; static gint _gdisp_ID = -1; static gchar *progname = NULL; static guint8 write_buffer[WRITE_BUFFER_SIZE]; static guint 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}, {"on", GIMP_DEBUG_DEFAULT} }; static const guint gimp_ndebug_keys = sizeof (gimp_debug_keys) / sizeof (GDebugKey); #ifdef G_OS_WIN32 static GimpPlugInInfo *PLUG_IN_INFO_PTR; #define PLUG_IN_INFO (*PLUG_IN_INFO_PTR) void set_gimp_PLUG_IN_INFO_PTR (GimpPlugInInfo *p) { PLUG_IN_INFO_PTR = p; } #else #ifndef __EMX__ extern GimpPlugInInfo PLUG_IN_INFO; #else static GimpPlugInInfo PLUG_IN_INFO; void set_gimp_PLUG_IN_INFO (const GimpPlugInInfo *p) { PLUG_IN_INFO = *p; } #endif #endif int gimp_main (int argc, char *argv[]) { gchar *basename; const gchar *env_string; gchar *debug_string; #ifdef G_OS_WIN32 gint i, j, k; g_assert (PLUG_IN_INFO_PTR != NULL); /* 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[0]); for (j = 1; j <= i; j++) { s = g_string_append_c (s, ' '); s = g_string_append (s, argv[j]); } argv[0] = 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 if ((argc != 6) || (strcmp (argv[1], "-gimp") != 0)) { g_printerr ("%s is a gimp plug-in and must be run by the gimp to be used\n", argv[0]); return 1; } progname = argv[0]; basename = g_path_get_basename (progname); g_set_prgname (basename); env_string = g_getenv ("GIMP_PLUGIN_DEBUG"); if (env_string) { 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, gimp_ndebug_keys); } } else if (strcmp (env_string, basename) == 0) { gimp_debug_flags = GIMP_DEBUG_DEFAULT; } } g_free (basename); stack_trace_mode = (GimpStackTraceMode) CLAMP (atoi (argv[5]), 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 (SIGBUS, gimp_plugin_sigfatal_handler, 0); gimp_signal_private (SIGSEGV, gimp_plugin_sigfatal_handler, 0); gimp_signal_private (SIGTERM, 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 _readchannel = g_io_channel_unix_new (atoi (argv[2])); _writechannel = g_io_channel_unix_new (atoi (argv[3])); #ifdef __EMX__ setmode (g_io_channel_unix_get_fd (_readchannel), O_BINARY); setmode (g_io_channel_unix_get_fd (_writechannel), O_BINARY); #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 (); wire_set_writer (gimp_write); wire_set_flusher (gimp_flush); /* 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 */ g_log_set_handler (G_LOG_DOMAIN, 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); } if (strcmp (argv[4], "-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 0; } if (strcmp (argv[4], "-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 0; } 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!\n"); 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 0; } static void gimp_close (void) { if (PLUG_IN_INFO.quit_proc) (* PLUG_IN_INFO.quit_proc) (); #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) CloseHandle (shm_handle); #else #ifdef HAVE_SHM_H if ((_shm_ID != -1) && _shm_addr) shmdt ((char*) _shm_addr); #endif #endif gp_quit_write (_writechannel, NULL); } void gimp_quit (void) { gimp_close (); exit (0); } static void gimp_debug_stop (void) { #ifndef G_OS_WIN32 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Waiting for debugger...\n"); kill (getpid (), SIGSTOP); #else g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Debugging not implemented on Win32\n"); #endif } gint32 gimp_default_display (void) { return _gdisp_ID; } static void gimp_message_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer data) { gimp_message ((gchar *) message); } void gimp_install_procedure (gchar *name, gchar *blurb, gchar *help, gchar *author, gchar *copyright, gchar *date, gchar *menu_path, gchar *image_types, gint type, gint nparams, gint nreturn_vals, GimpParamDef *params, GimpParamDef *return_vals) { GPProcInstall proc_install; proc_install.name = name; proc_install.blurb = blurb; proc_install.help = help; proc_install.author = author; proc_install.copyright = copyright; proc_install.date = date; proc_install.menu_path = menu_path; proc_install.image_types = image_types; proc_install.type = type; proc_install.nparams = nparams; proc_install.nreturn_vals = nreturn_vals; proc_install.params = (GPParamDef *) params; proc_install.return_vals = (GPParamDef *) return_vals; if (! gp_proc_install_write (_writechannel, &proc_install, NULL)) gimp_quit (); } void gimp_install_temp_proc (gchar *name, gchar *blurb, gchar *help, gchar *author, gchar *copyright, gchar *date, gchar *menu_path, gchar *image_types, gint type, gint nparams, gint nreturn_vals, GimpParamDef *params, GimpParamDef *return_vals, GimpRunProc run_proc) { gimp_install_procedure (name, blurb, help, author, copyright, date, menu_path, image_types, type, nparams, nreturn_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); } void gimp_uninstall_temp_proc (gchar *name) { GPProcUninstall proc_uninstall; gpointer hash_name; gboolean found; proc_uninstall.name = 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); } } GimpParam * gimp_run_procedure (gchar *name, gint *nreturn_vals, ...) { GPProcRun proc_run; GPProcReturn *proc_return; WireMessage msg; GimpPDBArgType param_type; GimpParam *return_vals; va_list args; gint i; proc_run.name = name; proc_run.nparams = 0; proc_run.params = NULL; va_start (args, nreturn_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_LAYER: case GIMP_PDB_CHANNEL: case GIMP_PDB_DRAWABLE: case GIMP_PDB_SELECTION: case GIMP_PDB_BOUNDARY: case GIMP_PDB_PATH: 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: (void) va_arg (args, GimpRGB *); break; case GIMP_PDB_PARASITE: (void) va_arg (args, GimpParasite *); break; case GIMP_PDB_REGION: break; case GIMP_PDB_END: break; } proc_run.nparams += 1; param_type = va_arg (args, GimpPDBArgType); } va_end (args); proc_run.params = g_new (GPParam, proc_run.nparams); va_start (args, nreturn_vals); for (i = 0; i < proc_run.nparams; i++) { proc_run.params[i].type = va_arg (args, GimpPDBArgType); switch (proc_run.params[i].type) { case GIMP_PDB_INT32: proc_run.params[i].data.d_int32 = (gint32) va_arg (args, gint); break; case GIMP_PDB_INT16: proc_run.params[i].data.d_int16 = (gint16) va_arg (args, gint); break; case GIMP_PDB_INT8: proc_run.params[i].data.d_int8 = (gint8) va_arg (args, gint); break; case GIMP_PDB_FLOAT: proc_run.params[i].data.d_float = (gdouble) va_arg (args, gdouble); break; case GIMP_PDB_STRING: proc_run.params[i].data.d_string = va_arg (args, gchar *); break; case GIMP_PDB_INT32ARRAY: proc_run.params[i].data.d_int32array = va_arg (args, gint32 *); break; case GIMP_PDB_INT16ARRAY: proc_run.params[i].data.d_int16array = va_arg (args, gint16 *); break; case GIMP_PDB_INT8ARRAY: proc_run.params[i].data.d_int8array = va_arg (args, gint8 *); break; case GIMP_PDB_FLOATARRAY: proc_run.params[i].data.d_floatarray = va_arg (args, gdouble *); break; case GIMP_PDB_STRINGARRAY: proc_run.params[i].data.d_stringarray = va_arg (args, gchar **); break; case GIMP_PDB_COLOR: proc_run.params[i].data.d_color = *va_arg (args, GimpRGB *); break; case GIMP_PDB_REGION: break; case GIMP_PDB_DISPLAY: proc_run.params[i].data.d_display = va_arg (args, gint32); break; case GIMP_PDB_IMAGE: proc_run.params[i].data.d_image = va_arg (args, gint32); break; case GIMP_PDB_LAYER: proc_run.params[i].data.d_layer = va_arg (args, gint32); break; case GIMP_PDB_CHANNEL: proc_run.params[i].data.d_channel = va_arg (args, gint32); break; case GIMP_PDB_DRAWABLE: proc_run.params[i].data.d_drawable = va_arg (args, gint32); break; case GIMP_PDB_SELECTION: proc_run.params[i].data.d_selection = va_arg (args, gint32); break; case GIMP_PDB_BOUNDARY: proc_run.params[i].data.d_boundary = va_arg (args, gint32); break; case GIMP_PDB_PATH: proc_run.params[i].data.d_path = va_arg (args, gint32); break; case GIMP_PDB_PARASITE: { GimpParasite *parasite = va_arg (args, GimpParasite *); if (parasite == NULL) { proc_run.params[i].data.d_parasite.name = NULL; proc_run.params[i].data.d_parasite.data = NULL; } else { proc_run.params[i].data.d_parasite.name = parasite->name; proc_run.params[i].data.d_parasite.flags = parasite->flags; proc_run.params[i].data.d_parasite.size = parasite->size; proc_run.params[i].data.d_parasite.data = parasite->data; } } break; case GIMP_PDB_STATUS: proc_run.params[i].data.d_status = va_arg (args, gint32); break; case GIMP_PDB_END: break; } } va_end (args); if (! gp_proc_run_write (_writechannel, &proc_run, NULL)) gimp_quit (); gimp_read_expect_msg (&msg, GP_PROC_RETURN); proc_return = msg.data; *nreturn_vals = proc_return->nparams; return_vals = (GimpParam*) proc_return->params; switch (return_vals[0].data.d_status) { case GIMP_PDB_EXECUTION_ERROR: /*g_warning ("an execution error occured while trying to run: \"%s\"", name);*/ break; case GIMP_PDB_CALLING_ERROR: g_warning ("a calling error occured while trying to run: \"%s\"", name); break; default: break; } g_free (proc_run.params); g_free (proc_return->name); g_free (proc_return); return return_vals; } void gimp_read_expect_msg (WireMessage *msg, gint type) { while (TRUE) { if (! wire_read_msg (_readchannel, msg, NULL)) gimp_quit (); if (msg->type != type) { if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT) { gimp_process_message (msg); continue; } else g_error ("unexpected message: %d\n", msg->type); } else break; } } GimpParam * gimp_run_procedure2 (gchar *name, gint *nreturn_vals, gint nparams, GimpParam *params) { GPProcRun proc_run; GPProcReturn *proc_return; WireMessage msg; GimpParam *return_vals; proc_run.name = name; proc_run.nparams = nparams; 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; *nreturn_vals = proc_return->nparams; return_vals = (GimpParam *) proc_return->params; switch (return_vals[0].data.d_status) { case GIMP_PDB_EXECUTION_ERROR: /*g_warning ("an execution error occured while trying to run: \"%s\"", name);*/ break; case GIMP_PDB_CALLING_ERROR: g_warning ("a calling error occured while trying to run: \"%s\"", name); break; default: break; } g_free (proc_return->name); g_free (proc_return); return return_vals; } void gimp_destroy_params (GimpParam *params, gint nparams) { extern void _gp_params_destroy (GPParam *params, gint nparams); _gp_params_destroy ((GPParam*) params, nparams); } void gimp_destroy_paramdefs (GimpParamDef *paramdefs, gint nparams) { while (nparams--) { g_free (paramdefs[nparams].name); g_free (paramdefs[nparams].description); } g_free (paramdefs); } gdouble gimp_gamma (void) { return _gamma_val; } gboolean gimp_install_cmap (void) { return _install_cmap; } gint gimp_min_colors (void) { return _min_colors; } gboolean gimp_show_tool_tips (void) { return _show_tool_tips; } static void gimp_process_message (WireMessage *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)\n"); break; case GP_PROC_RUN: g_warning ("unexpected proc run message received (should not happen)\n"); break; case GP_PROC_RETURN: g_warning ("unexpected proc return message received (should not happen)\n"); 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)\n"); break; case GP_PROC_INSTALL: g_warning ("unexpected proc install message received (should not happen)\n"); break; case GP_HAS_INIT: g_warning ("unexpected has init message received (should not happen)\n"); break; } } static void gimp_single_message (void) { WireMessage msg; /* Run a temp function */ if (! wire_read_msg (_readchannel, &msg, NULL)) gimp_quit (); gimp_process_message (&msg); wire_destroy (&msg); } void gimp_extension_process (guint timeout) { #ifndef G_OS_WIN32 fd_set readfds; gint select_val; 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) { perror ("gimp_process"); gimp_quit (); } #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 } void gimp_extension_ack (void) { /* Send an extension initialization acknowledgement */ if (! gp_extension_ack_write (_writechannel, NULL)) gimp_quit (); } void gimp_run_temp (void) { gimp_single_message (); } gchar * gimp_get_progname (void) { return progname; } /** * 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 the GIMP. * * See Also: gimp_parasite_attach() */ void gimp_attach_new_parasite (const gchar *name, gint flags, gint size, const gpointer data) { GimpParasite *parasite = gimp_parasite_new (name, flags, size, data); gimp_parasite_attach (parasite); gimp_parasite_free (parasite); } #ifndef G_OS_WIN32 static void gimp_plugin_sigfatal_handler (gint sig_num) { switch (sig_num) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGABRT: case SIGTERM: g_printerr ("%s terminated: %s\n", progname, g_strsignal (sig_num)); break; 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); g_on_error_query (progname); } break; case GIMP_STACK_TRACE_ALWAYS: { sigset_t sigset; sigemptyset (&sigset); sigprocmask (SIG_SETMASK, &sigset, NULL); g_on_error_stack_trace (progname); } break; } break; } gimp_quit (); } #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, 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 (! 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) { WireMessage msg; while (TRUE) { if (! wire_read_msg (_readchannel, &msg, NULL)) { gimp_close (); return; } switch (msg.type) { case GP_QUIT: 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)\n"); break; case GP_PROC_RUN: gimp_proc_run (msg.data); gimp_close (); return; case GP_PROC_RETURN: g_warning ("unexpected proc return message received (should not happen)\n"); break; case GP_TEMP_PROC_RUN: g_warning ("unexpected temp proc run message received (should not happen\n"); break; case GP_TEMP_PROC_RETURN: g_warning ("unexpected temp proc return message received (should not happen\n"); break; case GP_PROC_INSTALL: g_warning ("unexpected proc install message received (should not happen)\n"); break; case GP_HAS_INIT: g_warning ("unexpected has init message received (should not happen)\n"); break; } wire_destroy (&msg); } } static void gimp_config (GPConfig *config) { extern gint _gimp_tile_width; extern gint _gimp_tile_height; if (config->version < GP_VERSION) { g_message ("Could not execute plug-in \"%s\"\n(%s)" "because the GIMP is using an older version of the " "plug-in protocol.", g_get_prgname (), progname); gimp_quit (); } else if (config->version > GP_VERSION) { g_message ("Could not execute plug-in \"%s\"\n(%s)" "because it uses an obsolete version of the " "plug-in protocol.", g_get_prgname (), progname); gimp_quit (); } _gimp_tile_width = config->tile_width; _gimp_tile_height = config->tile_height; _shm_ID = config->shm_ID; _gamma_val = config->gamma; _install_cmap = config->install_cmap; _show_tool_tips = config->show_tool_tips; _min_colors = config->min_colors; _gdisp_ID = config->gdisp_ID; if (_shm_ID != -1) { #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) /* * Use Win32 shared memory mechanisms for * transfering tile data */ gchar fileMapName[128]; gint tileByteSize = _gimp_tile_width * _gimp_tile_height * 4; /* 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, tileByteSize); /* Verify that we mapped our view */ if (!_shm_addr) { g_warning ("MapViewOfFile error: %d... disabling shared memory transport", GetLastError()); } } else { g_warning ("OpenFileMapping error: %d... disabling shared memory transport", GetLastError()); } #else #ifdef HAVE_SHM_H _shm_addr = (guchar*) shmat (_shm_ID, 0, 0); if (_shm_addr == (guchar*) -1) g_error ("could not attach to gimp shared memory segment\n"); #endif #endif } } static void gimp_proc_run (GPProcRun *proc_run) { GPProcReturn proc_return; GimpParam *return_vals; gint nreturn_vals; if (PLUG_IN_INFO.run_proc) { (* PLUG_IN_INFO.run_proc) (proc_run->name, proc_run->nparams, (GimpParam*) proc_run->params, &nreturn_vals, &return_vals); proc_return.name = proc_run->name; proc_return.nparams = nreturn_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) { GimpParam *return_vals; gint nreturn_vals; GimpRunProc run_proc; run_proc = (GimpRunProc) g_hash_table_lookup (temp_proc_ht, (gpointer) proc_run->name); if (run_proc) { (* run_proc) (proc_run->name, proc_run->nparams, (GimpParam*) proc_run->params, &nreturn_vals, &return_vals); /* No longer a return message */ /* proc_return.name = proc_run->name; */ /* proc_return.nparams = nreturn_vals; */ /* proc_return.params = (GPParam*) return_vals; */ /* if (! gp_temp_proc_return_write (_writechannel, &proc_return, NULL)) */ /* gimp_quit (); */ } }