/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #ifdef HAVE_SYS_PARAM_H #include #endif #include #include #include #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) #define STRICT #include #include #ifdef G_OS_WIN32 #include #include #ifndef S_ISREG #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #endif #endif #ifdef G_WITH_CYGWIN #define O_TEXT 0x0100 /* text file */ #define _O_TEXT 0x0100 /* text file */ #define O_BINARY 0x0200 /* binary file */ #define _O_BINARY 0x0200 /* binary file */ #endif #endif #ifdef __EMX__ #include #include #define _O_BINARY O_BINARY #define _P_NOWAIT P_NOWAIT #define xspawnv spawnv #endif #ifdef HAVE_IPC_H #include #endif #ifdef HAVE_SHM_H #include #endif #include "libgimpbase/gimpbase.h" #include "libgimpbase/gimpprotocol.h" #include "libgimpbase/gimpwire.h" #include "display/display-types.h" #include "base/tile.h" #include "base/tile-manager.h" #include "core/gimp.h" #include "core/gimpcontext.h" #include "core/gimpcoreconfig.h" #include "core/gimpdatafiles.h" #include "core/gimpdrawable.h" #include "core/gimpimage.h" #include "display/gimpdisplay.h" #include "gui/brush-select.h" #include "gui/gradient-select.h" #include "gui/menus.h" #include "gui/pattern-select.h" #include "app_procs.h" #include "appenv.h" #include "errors.h" #include "gimpprogress.h" #include "gimprc.h" #include "plug_in.h" #include "libgimp/gimpintl.h" typedef struct _PlugInBlocked PlugInBlocked; struct _PlugInBlocked { PlugIn *plug_in; gchar *proc_name; }; typedef struct _PlugInMenuEntry PlugInMenuEntry; struct _PlugInMenuEntry { PlugInProcDef *proc_def; gchar *domain; gchar *help_path; }; typedef struct _PlugInHelpPathDef PlugInHelpPathDef; struct _PlugInHelpPathDef { gchar *prog_name; gchar *help_path; }; static gboolean plug_in_write (GIOChannel *channel, guint8 *buf, gulong count); static gboolean plug_in_flush (GIOChannel *channel); static void plug_in_push (PlugIn *plug_in); static void plug_in_pop (void); static gboolean plug_in_recv_message (GIOChannel *channel, GIOCondition cond, gpointer data); static void plug_in_handle_message (WireMessage *msg); static void plug_in_handle_quit (void); static void plug_in_handle_tile_req (GPTileReq *tile_req); static void plug_in_handle_proc_run (GPProcRun *proc_run); static void plug_in_handle_proc_return (GPProcReturn *proc_return); static void plug_in_handle_proc_install (GPProcInstall *proc_install); static void plug_in_handle_proc_uninstall (GPProcUninstall *proc_uninstall); static void plug_in_write_rc (const gchar *filename); static void plug_in_init_file (const gchar *filename, gpointer loader_data); static void plug_in_query (PlugInDef *plug_in_def); static void plug_in_add_to_db (void); static void plug_in_make_menu (void); static gint plug_in_make_menu_entry (gpointer foo, PlugInMenuEntry *menu_entry, gpointer bar); static void plug_in_callback (GtkWidget *widget, gpointer client_data); static void plug_in_proc_def_insert (PlugInProcDef *proc_def, void (* superceed_fn) (void *)); static void plug_in_proc_def_dead (void *freed_proc_def); static void plug_in_proc_def_remove (PlugInProcDef *proc_def); static void plug_in_proc_def_destroy (PlugInProcDef *proc_def, gboolean data_only); static Argument * plug_in_temp_run (ProcRecord *proc_rec, Argument *args, gint argc); static Argument * plug_in_params_to_args (GPParam *params, gint nparams, gboolean full_copy); static GPParam * plug_in_args_to_params (Argument *args, gint nargs, gboolean full_copy); static void plug_in_params_destroy (GPParam *params, gint nparams, gboolean full_destroy); static void plug_in_args_destroy (Argument *args, gint nargs, gboolean full_destroy); static void plug_in_init_shm (void); static gchar * plug_in_search_in_path (gchar *search_path, gchar *filename); PlugIn *current_plug_in = NULL; GSList *proc_defs = NULL; static GSList *plug_in_defs = NULL; static GSList *gimprc_proc_defs = NULL; static GSList *open_plug_ins = NULL; static GSList *blocked_plug_ins = NULL; static GSList *help_path_defs = NULL; static GSList *plug_in_stack = NULL; static GIOChannel *current_readchannel = NULL; static GIOChannel *current_writechannel = NULL; static gint current_write_buffer_index = 0; static gchar *current_write_buffer = NULL; static Argument *current_return_vals = NULL; static gint current_return_nvals = 0; static ProcRecord *last_plug_in = NULL; static gint shm_ID = -1; static guchar *shm_addr = NULL; #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) static HANDLE shm_handle; #endif static gboolean write_pluginrc = FALSE; static gchar *std_plugins_domain = "gimp-std-plugins"; static void plug_in_init_shm (void) { /* allocate a piece of shared memory for use in transporting tiles * to plug-ins. if we can't allocate a piece of shared memory then * we'll fall back on sending the data over the pipe. */ #ifdef HAVE_SHM_H shm_ID = shmget (IPC_PRIVATE, TILE_WIDTH * TILE_HEIGHT * 4, IPC_CREAT | 0777); if (shm_ID == -1) g_message ("shmget() failed: Disabling shared memory tile transport."); else { shm_addr = (guchar *) shmat (shm_ID, NULL, 0); if (shm_addr == (guchar *) -1) { g_message ("shmat() failed: Disabling shared memory tile transport."); shmctl (shm_ID, IPC_RMID, NULL); shm_ID = -1; } #ifdef IPC_RMID_DEFERRED_RELEASE if (shm_addr != (guchar *) -1) shmctl (shm_ID, IPC_RMID, NULL); #endif } #else #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) /* Use Win32 shared memory mechanisms for * transfering tile data. */ gint pid; gchar fileMapName[MAX_PATH]; gint tileByteSize = TILE_WIDTH * TILE_HEIGHT * 4; /* Our shared memory id will be our process ID */ pid = GetCurrentProcessId (); /* From the id, derive the file map name */ g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", pid); /* Create the file mapping into paging space */ shm_handle = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0, tileByteSize, fileMapName); if (shm_handle) { /* Map the shared memory into our address space for use */ shm_addr = (guchar *) MapViewOfFile(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, tileByteSize); /* Verify that we mapped our view */ if (shm_addr) shm_ID = pid; else { g_warning ("MapViewOfFile error: %d... disabling shared memory transport\n", GetLastError()); } } else { g_warning ("CreateFileMapping error: %d... disabling shared memory transport\n", GetLastError()); } #endif #endif } void plug_in_init (Gimp *gimp, GimpInitStatusFunc status_callback) { extern gboolean use_shm; gchar *filename; GSList *tmp; GSList *tmp2; PlugInDef *plug_in_def; PlugInProcDef *proc_def; gfloat nplugins; gfloat nth; g_return_if_fail (GIMP_IS_GIMP (gimp)); g_return_if_fail (status_callback != NULL); /* initialize the gimp protocol library and set the read and * write handlers. */ gp_init (); wire_set_writer (plug_in_write); wire_set_flusher (plug_in_flush); /* allocate a piece of shared memory for use in transporting tiles * to plug-ins. if we can't allocate a piece of shared memory then * we'll fall back on sending the data over the pipe. */ if (use_shm) plug_in_init_shm (); /* search for binaries in the plug-in directory path */ gimp_datafiles_read_directories (the_gimp->config->plug_in_path, MODE_EXECUTABLE, plug_in_init_file, NULL); /* read the pluginrc file for cached data */ filename = NULL; if (the_gimp->config->pluginrc_path) { if (g_path_is_absolute (the_gimp->config->pluginrc_path)) filename = g_strdup (the_gimp->config->pluginrc_path); else filename = g_build_filename (gimp_directory (), the_gimp->config->pluginrc_path, NULL); } else filename = gimp_personal_rc_file ("pluginrc"); (* status_callback) (_("Resource configuration"), filename, -1); gimprc_parse_file (filename); /* query any plug-ins that have changed since we last wrote out * the pluginrc file. */ tmp = plug_in_defs; (* status_callback) (_("Plug-ins"), "", 0); nplugins = g_slist_length (tmp); nth = 0; while (tmp) { plug_in_def = tmp->data; tmp = tmp->next; if (plug_in_def->query) { write_pluginrc = TRUE; if (be_verbose) g_print (_("query plug-in: \"%s\"\n"), plug_in_def->prog); plug_in_query (plug_in_def); } (* status_callback) (NULL, plug_in_def->prog, nth / nplugins); nth++; } /* insert the proc defs */ for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp)) { proc_def = g_new (PlugInProcDef, 1); *proc_def = *((PlugInProcDef*) tmp->data); plug_in_proc_def_insert (proc_def, NULL); } tmp = plug_in_defs; while (tmp) { plug_in_def = tmp->data; tmp = tmp->next; tmp2 = plug_in_def->proc_defs; while (tmp2) { proc_def = tmp2->data; tmp2 = tmp2->next; proc_def->mtime = plug_in_def->mtime; plug_in_proc_def_insert (proc_def, plug_in_proc_def_dead); } } /* write the pluginrc file if necessary */ if (write_pluginrc) { if (be_verbose) g_print (_("writing \"%s\"\n"), filename); plug_in_write_rc (filename); } g_free (filename); /* add the plug-in procs to the procedure database */ plug_in_add_to_db (); /* make the menu */ plug_in_make_menu (); /* run the available extensions */ if (be_verbose) g_print (_("Starting extensions: ")); (* status_callback) (_("Extensions"), "", 0); tmp = proc_defs; nplugins = g_slist_length (tmp); nth = 0; while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (proc_def->prog && (proc_def->db_info.num_args == 0) && (proc_def->db_info.proc_type == GIMP_EXTENSION)) { if (be_verbose) g_print ("%s ", proc_def->db_info.name); (* status_callback) (NULL, proc_def->db_info.name, nth / nplugins); plug_in_run (&proc_def->db_info, NULL, 0, FALSE, TRUE, -1); } } if (be_verbose) g_print ("\n"); /* create help path list and free up stuff */ for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp)) { plug_in_def = tmp->data; if (plug_in_def->help_path) { PlugInHelpPathDef *help_path_def; help_path_def = g_new (PlugInHelpPathDef, 1); help_path_def->prog_name = g_strdup (plug_in_def->prog); help_path_def->help_path = g_strdup (plug_in_def->help_path); help_path_defs = g_slist_prepend (help_path_defs, help_path_def); } plug_in_def_free (plug_in_def, FALSE); } g_slist_free (plug_in_defs); plug_in_defs = NULL; } void plug_in_kill (void) { GSList *tmp; PlugIn *plug_in; #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) CloseHandle (shm_handle); #else #ifdef HAVE_SHM_H #ifndef IPC_RMID_DEFERRED_RELEASE if (shm_ID != -1) { shmdt ((gchar *) shm_addr); shmctl (shm_ID, IPC_RMID, NULL); } #else /* IPC_RMID_DEFERRED_RELEASE */ if (shm_ID != -1) shmdt ((gchar *) shm_addr); #endif #endif #endif tmp = open_plug_ins; while (tmp) { plug_in = tmp->data; tmp = tmp->next; plug_in_destroy (plug_in); } } void plug_in_add (gchar *prog, gchar *menu_path, gchar *accelerator) { PlugInProcDef *proc_def; GSList *tmp; g_return_if_fail (prog != NULL); if (strncmp ("plug_in_", prog, 8) != 0) { gchar *t = g_strdup_printf ("plug_in_%s", prog); g_free (prog); prog = t; } tmp = gimprc_proc_defs; while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (strcmp (proc_def->db_info.name, prog) == 0) { if (proc_def->db_info.name) g_free (proc_def->db_info.name); if (proc_def->menu_path) g_free (proc_def->menu_path); if (proc_def->accelerator) g_free (proc_def->accelerator); if (proc_def->extensions) g_free (proc_def->extensions); if (proc_def->prefixes) g_free (proc_def->prefixes); if (proc_def->magics) g_free (proc_def->magics); if (proc_def->image_types) g_free (proc_def->image_types); proc_def->db_info.name = prog; proc_def->menu_path = menu_path; proc_def->accelerator = accelerator; proc_def->prefixes = NULL; proc_def->extensions = NULL; proc_def->magics = NULL; proc_def->image_types = NULL; return; } } proc_def = g_new0 (PlugInProcDef, 1); proc_def->db_info.name = prog; proc_def->menu_path = menu_path; proc_def->accelerator = accelerator; gimprc_proc_defs = g_slist_prepend (gimprc_proc_defs, proc_def); } gchar * plug_in_image_types (gchar *name) { PlugInDef *plug_in_def; PlugInProcDef *proc_def; GSList *tmp; g_return_val_if_fail (name != NULL, NULL); if (current_plug_in) { plug_in_def = current_plug_in->user_data; tmp = plug_in_def->proc_defs; } else { tmp = proc_defs; } while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (strcmp (proc_def->db_info.name, name) == 0) return proc_def->image_types; } return NULL; } GSList * plug_in_extensions_parse (gchar *extensions) { GSList *list; gchar *extension; gchar *next_token; list = NULL; /* EXTENSIONS can be NULL. Avoid calling strtok if it is. */ if (extensions) { extensions = g_strdup (extensions); next_token = extensions; extension = strtok (next_token, " \t,"); while (extension) { list = g_slist_prepend (list, g_strdup (extension)); extension = strtok (NULL, " \t,"); } g_free (extensions); } return g_slist_reverse (list); } void plug_in_add_internal (PlugInProcDef *proc_def) { proc_defs = g_slist_prepend (proc_defs, proc_def); } PlugInProcDef * plug_in_file_handler (gchar *name, gchar *extensions, gchar *prefixes, gchar *magics) { PlugInDef *plug_in_def; PlugInProcDef *proc_def; GSList *tmp; g_return_val_if_fail (name != NULL, NULL); if (current_plug_in) { plug_in_def = current_plug_in->user_data; tmp = plug_in_def->proc_defs; } else { tmp = proc_defs; } while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (strcmp (proc_def->db_info.name, name) == 0) { /* EXTENSIONS can be proc_def->extensions */ if (proc_def->extensions != extensions) { if (proc_def->extensions) g_free (proc_def->extensions); proc_def->extensions = g_strdup (extensions); } proc_def->extensions_list = plug_in_extensions_parse (proc_def->extensions); /* PREFIXES can be proc_def->prefixes */ if (proc_def->prefixes != prefixes) { if (proc_def->prefixes) g_free (proc_def->prefixes); proc_def->prefixes = g_strdup (prefixes); } proc_def->prefixes_list = plug_in_extensions_parse (proc_def->prefixes); /* MAGICS can be proc_def->magics */ if (proc_def->magics != magics) { if (proc_def->magics) g_free (proc_def->magics); proc_def->magics = g_strdup (magics); } proc_def->magics_list = plug_in_extensions_parse (proc_def->magics); return proc_def; } } return NULL; } PlugInDef * plug_in_def_new (const gchar *prog) { PlugInDef *plug_in_def; g_return_val_if_fail (prog != NULL, NULL); plug_in_def = g_new (PlugInDef, 1); plug_in_def->prog = g_strdup (prog); plug_in_def->proc_defs = NULL; plug_in_def->locale_domain = NULL; plug_in_def->locale_path = NULL; plug_in_def->help_path = NULL; plug_in_def->mtime = 0; plug_in_def->query = FALSE; return plug_in_def; } void plug_in_def_free (PlugInDef *plug_in_def, gboolean free_proc_defs) { GSList *list; g_free (plug_in_def->prog); if (plug_in_def->locale_domain) g_free (plug_in_def->locale_domain); if (plug_in_def->locale_path) g_free (plug_in_def->locale_path); if (plug_in_def->help_path) g_free (plug_in_def->help_path); if (free_proc_defs) { for (list = plug_in_def->proc_defs; list; list = list->next) plug_in_proc_def_destroy ((PlugInProcDef *)(list->data), FALSE); } if (plug_in_def->proc_defs) g_slist_free (plug_in_def->proc_defs); g_free (plug_in_def); } void plug_in_def_add (PlugInDef *plug_in_def) { PlugInDef *tplug_in_def; PlugInProcDef *proc_def; GSList *tmp; gchar *basename1; gchar *basename2; basename1 = g_path_get_basename (plug_in_def->prog); /* If this is a file load or save plugin, make sure we have * something for one of the extensions, prefixes, or magic number. * Other bits of code rely on detecting file plugins by the presence * of one of these things, but Nick Lamb's alien/unknown format * loader needs to be able to register no extensions, prefixes or * magics. -- austin 13/Feb/99 */ for (tmp = plug_in_def->proc_defs; tmp; tmp = g_slist_next (tmp)) { proc_def = tmp->data; if (!proc_def->extensions && !proc_def->prefixes && !proc_def->magics && proc_def->menu_path && (!strncmp (proc_def->menu_path, "", 6) || !strncmp (proc_def->menu_path, "", 6))) { proc_def->extensions = g_strdup (""); } } for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp)) { tplug_in_def = tmp->data; basename2 = g_path_get_basename (tplug_in_def->prog); if (strcmp (basename1, basename2) == 0) { if ((g_ascii_strcasecmp (plug_in_def->prog, tplug_in_def->prog) == 0) && (plug_in_def->mtime == tplug_in_def->mtime)) { /* Use cached plug-in entry */ tmp->data = plug_in_def; plug_in_def_free (tplug_in_def, TRUE); } else { plug_in_def_free (plug_in_def, TRUE); } g_free (basename2); return; } g_free (basename2); } g_free (basename1); write_pluginrc = TRUE; g_print ("\"%s\" executable not found\n", plug_in_def->prog); plug_in_def_free (plug_in_def, FALSE); } gchar * plug_in_menu_path (gchar *name) { PlugInDef *plug_in_def; PlugInProcDef *proc_def; GSList *tmp, *tmp2; g_return_val_if_fail (name != NULL, NULL); for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp)) { plug_in_def = tmp->data; for (tmp2 = plug_in_def->proc_defs; tmp2; tmp2 = g_slist_next (tmp2)) { proc_def = tmp2->data; if (strcmp (proc_def->db_info.name, name) == 0) return proc_def->menu_path; } } for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp)) { proc_def = tmp->data; if (strcmp (proc_def->db_info.name, name) == 0) return proc_def->menu_path; } return NULL; } gchar * plug_in_help_path (gchar *prog_name) { PlugInHelpPathDef *help_path_def; GSList *list; if (!prog_name || !strlen (prog_name)) return NULL; for (list = help_path_defs; list; list = g_slist_next (list)) { help_path_def = (PlugInHelpPathDef *) list->data; if (help_path_def && help_path_def->prog_name && strcmp (help_path_def->prog_name, prog_name) == 0) return help_path_def->help_path; } return NULL; } PlugIn * plug_in_new (gchar *name) { PlugIn *plug_in; gchar *path; if (! g_path_is_absolute (name)) { path = plug_in_search_in_path (the_gimp->config->plug_in_path, name); if (! path) { g_message (_("Unable to locate Plug-In: \"%s\""), name); return NULL; } } else { path = name; } plug_in = g_new (PlugIn, 1); plug_in->open = FALSE; plug_in->query = FALSE; plug_in->synchronous = FALSE; plug_in->recurse = FALSE; plug_in->busy = FALSE; plug_in->pid = 0; plug_in->args[0] = g_strdup (path); plug_in->args[1] = g_strdup ("-gimp"); plug_in->args[2] = NULL; plug_in->args[3] = NULL; plug_in->args[4] = NULL; plug_in->args[5] = NULL; plug_in->args[6] = NULL; plug_in->my_read = NULL; plug_in->my_write = NULL; plug_in->his_read = NULL; plug_in->his_write = NULL; plug_in->input_id = 0; plug_in->write_buffer_index = 0; plug_in->temp_proc_defs = NULL; plug_in->progress = NULL; plug_in->user_data = NULL; return plug_in; } void plug_in_destroy (PlugIn *plug_in) { if (plug_in) { if (plug_in->open) plug_in_close (plug_in, TRUE); if (plug_in->args[0]) g_free (plug_in->args[0]); if (plug_in->args[1]) g_free (plug_in->args[1]); if (plug_in->args[2]) g_free (plug_in->args[2]); if (plug_in->args[3]) g_free (plug_in->args[3]); if (plug_in->args[4]) g_free (plug_in->args[4]); if (plug_in->args[5]) g_free (plug_in->args[5]); if (plug_in->progress) progress_end (plug_in->progress); plug_in->progress = NULL; if (plug_in == current_plug_in) plug_in_pop (); g_free (plug_in); } } #ifdef G_OS_WIN32 /* The Microsoft _spawnv() does not allow to run scripts. But * this is essential to get scripting extension up and running. * Following the replacement function xspawnv(). */ gint xspawnv (gint mode, const gchar *cmdname, const gchar *const *argv) { gchar sExecutable[_MAX_PATH*2]; gchar** sArgsList; gchar sCmndLine[1024]; gchar* sPath; HINSTANCE hInst; gint i; gint pid; /* only use it if _spawnv fails */ pid = _spawnv (mode, cmdname, argv); if (pid != -1) return pid; /* stuff parameters into one cmndline */ sCmndLine[0] = 0; for (i = 1; argv[i] != NULL; i++) { strcat (sCmndLine, argv[i]); strcat (sCmndLine, " "); } /* remove last blank */ sCmndLine[strlen (sCmndLine)-1] = 0; /* do we really need _spawnv (ShelExecute seems not to do it)*/ if (32 <= (int) FindExecutable (cmdname, gimp_directory (), sExecutable)) { /* g_print("_spawnlp %s %s %s", sExecutable, cmdname, sCmndLine); */ pid = _spawnlp (mode, sExecutable, "-c", cmdname, sCmndLine, NULL); } else { g_warning ("Execution error for: %s", cmdname); return -1; } return pid; } #endif /* G_OS_WIN32 */ gboolean plug_in_open (PlugIn *plug_in) { gint my_read[2]; gint my_write[2]; if (plug_in) { /* Open two pipes. (Bidirectional communication). */ if ((pipe (my_read) == -1) || (pipe (my_write) == -1)) { g_message ("pipe() failed: Unable to start Plug-In \"%s\"\n(%s)", g_path_get_basename (plug_in->args[0]), plug_in->args[0]); return FALSE; } #if defined(G_WITH_CYGWIN) || defined(__EMX__) /* Set to binary mode */ setmode (my_read[0], _O_BINARY); setmode (my_write[0], _O_BINARY); setmode (my_read[1], _O_BINARY); setmode (my_write[1], _O_BINARY); #endif plug_in->my_read = g_io_channel_unix_new (my_read[0]); plug_in->my_write = g_io_channel_unix_new (my_write[1]); plug_in->his_read = g_io_channel_unix_new (my_write[0]); plug_in->his_write = g_io_channel_unix_new (my_read[1]); g_io_channel_set_encoding (plug_in->my_read, NULL, NULL); g_io_channel_set_encoding (plug_in->my_write, NULL, NULL); g_io_channel_set_encoding (plug_in->his_read, NULL, NULL); g_io_channel_set_encoding (plug_in->his_write, NULL, NULL); g_io_channel_set_buffered (plug_in->my_read, FALSE); g_io_channel_set_buffered (plug_in->my_write, FALSE); g_io_channel_set_buffered (plug_in->his_read, FALSE); g_io_channel_set_buffered (plug_in->his_write, FALSE); g_io_channel_set_close_on_unref (plug_in->my_read, TRUE); g_io_channel_set_close_on_unref (plug_in->my_write, TRUE); g_io_channel_set_close_on_unref (plug_in->his_read, TRUE); g_io_channel_set_close_on_unref (plug_in->his_write, TRUE); /* Remember the file descriptors for the pipes. */ plug_in->args[2] = g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_read)); plug_in->args[3] = g_strdup_printf ("%d", g_io_channel_unix_get_fd (plug_in->his_write)); /* Set the rest of the command line arguments. */ if (plug_in->query) { plug_in->args[4] = g_strdup ("-query"); } else { plug_in->args[4] = g_strdup ("-run"); } plug_in->args[5] = g_strdup_printf ("%d", (gint) stack_trace_mode); /* Fork another process. We'll remember the process id * so that we can later use it to kill the filter if * necessary. */ #ifdef __EMX__ fcntl (my_read[0], F_SETFD, 1); fcntl (my_write[1], F_SETFD, 1); #endif #if defined(G_OS_WIN32) || defined (G_WITH_CYGWIN) || defined(__EMX__) plug_in->pid = xspawnv (_P_NOWAIT, plug_in->args[0], plug_in->args); if (plug_in->pid == -1) #else plug_in->pid = fork (); if (plug_in->pid == 0) { g_io_channel_unref (plug_in->my_read); plug_in->my_read = NULL; g_io_channel_unref (plug_in->my_write); plug_in->my_write = NULL; /* Execute the filter. The "_exit" call should never * be reached, unless some strange error condition * exists. */ execvp (plug_in->args[0], plug_in->args); _exit (1); } else if (plug_in->pid == -1) #endif { g_message ("fork() failed: Unable to run Plug-In: \"%s\"\n(%s)", g_path_get_basename (plug_in->args[0]), plug_in->args[0]); plug_in_destroy (plug_in); return FALSE; } g_io_channel_unref (plug_in->his_read); plug_in->his_read = NULL; g_io_channel_unref (plug_in->his_write); plug_in->his_write = NULL; if (!plug_in->synchronous) { plug_in->input_id = g_io_add_watch (plug_in->my_read, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, plug_in_recv_message, plug_in); open_plug_ins = g_slist_prepend (open_plug_ins, plug_in); } plug_in->open = TRUE; return TRUE; } return FALSE; } void plug_in_close (PlugIn *plug_in, gboolean kill_it) { gint status; #ifndef G_OS_WIN32 struct timeval tv; #endif g_return_if_fail (plug_in != NULL); g_return_if_fail (plug_in->open == TRUE); if (! plug_in->open) return; plug_in->open = FALSE; /* Ask the filter to exit gracefully */ if (kill_it && plug_in->pid) { plug_in_push (plug_in); gp_quit_write (current_writechannel); plug_in_pop (); /* give the plug-in some time (10 ms) */ #ifndef G_OS_WIN32 tv.tv_sec = 0; tv.tv_usec = 100; /* But this is 0.1 ms? */ select (0, NULL, NULL, NULL, &tv); #else Sleep (10); #endif } /* If necessary, kill the filter. */ #ifndef G_OS_WIN32 if (kill_it && plug_in->pid) status = kill (plug_in->pid, SIGKILL); /* Wait for the process to exit. This will happen * immediately if it was just killed. */ if (plug_in->pid) waitpid (plug_in->pid, &status, 0); #else if (kill_it && plug_in->pid) { /* Trying to avoid TerminateProcess (does mostly work). * Otherwise some of our needed DLLs may get into an unstable state * (see Win32 API docs). */ DWORD dwExitCode = STILL_ACTIVE; DWORD dwTries = 10; while ((STILL_ACTIVE == dwExitCode) && GetExitCodeProcess((HANDLE) plug_in->pid, &dwExitCode) && (dwTries > 0)) { Sleep(10); dwTries--; } if (STILL_ACTIVE == dwExitCode) { g_warning("Terminating %s ...", plug_in->args[0]); TerminateProcess ((HANDLE) plug_in->pid, 0); } } #endif plug_in->pid = 0; /* Remove the input handler. */ if (plug_in->input_id) { g_source_remove (plug_in->input_id); plug_in->input_id = 0; } /* Close the pipes. */ if (plug_in->my_read != NULL) { g_io_channel_unref (plug_in->my_read); plug_in->my_read = NULL; } if (plug_in->my_write != NULL) { g_io_channel_unref (plug_in->my_write); plug_in->my_write = NULL; } if (plug_in->his_read != NULL) { g_io_channel_unref (plug_in->his_read); plug_in->his_read = NULL; } if (plug_in->his_write != NULL) { g_io_channel_unref (plug_in->his_write); plug_in->his_write = NULL; } wire_clear_error (); /* Destroy the progress dialog if it exists. */ if (plug_in->progress) { progress_end (plug_in->progress); plug_in->progress = NULL; } if (plug_in->recurse) { gtk_main_quit (); plug_in->recurse = FALSE; } plug_in->synchronous = FALSE; /* Unregister any temporary procedures. */ if (plug_in->temp_proc_defs) { g_slist_foreach (plug_in->temp_proc_defs, (GFunc) plug_in_proc_def_remove, NULL); g_slist_free (plug_in->temp_proc_defs); plug_in->temp_proc_defs = NULL; } /* Close any dialogs that this plugin might have opened */ brush_select_dialogs_check (); pattern_select_dialogs_check (); gradient_select_dialogs_check (); open_plug_ins = g_slist_remove (open_plug_ins, plug_in); } static Argument * plug_in_get_current_return_vals (ProcRecord *proc_rec) { Argument *return_vals; gint nargs; /* Return the status code plus the current return values. */ nargs = proc_rec->num_values + 1; if (current_return_vals && current_return_nvals == nargs) { return_vals = current_return_vals; } else if (current_return_vals) { /* Allocate new return values of the correct size. */ return_vals = procedural_db_return_args (proc_rec, FALSE); /* Copy all of the arguments we can. */ memcpy (return_vals, current_return_vals, sizeof (Argument) * MIN (current_return_nvals, nargs)); /* Free the old argument pointer. This will cause a memory leak only if there were more values returned than we need (which shouldn't ever happen). */ g_free (current_return_vals); } else { /* Just return a dummy set of values. */ return_vals = procedural_db_return_args (proc_rec, FALSE); } /* We have consumed any saved values, so clear them. */ current_return_nvals = 0; current_return_vals = NULL; return return_vals; } Argument * plug_in_run (ProcRecord *proc_rec, Argument *args, gint argc, gboolean synchronous, gboolean destroy_values, gint gdisp_ID) { GPConfig config; GPProcRun proc_run; Argument *return_vals; PlugIn *plug_in; return_vals = NULL; if (proc_rec->proc_type == GIMP_TEMPORARY) { return_vals = plug_in_temp_run (proc_rec, args, argc); goto done; } plug_in = plug_in_new (proc_rec->exec_method.plug_in.filename); if (plug_in) { if (plug_in_open (plug_in)) { plug_in->recurse = synchronous; plug_in_push (plug_in); config.version = GP_VERSION; config.tile_width = TILE_WIDTH; config.tile_height = TILE_HEIGHT; config.shm_ID = shm_ID; config.gamma = gimprc.gamma_val; config.install_cmap = gimprc.install_cmap; config.unused = 0; config.min_colors = CLAMP (gimprc.min_colors, 27, 256); config.gdisp_ID = gdisp_ID; proc_run.name = proc_rec->name; proc_run.nparams = argc; proc_run.params = plug_in_args_to_params (args, argc, FALSE); if (!gp_config_write (current_writechannel, &config) || !gp_proc_run_write (current_writechannel, &proc_run) || !wire_flush (current_writechannel)) { return_vals = procedural_db_return_args (proc_rec, FALSE); goto done; } plug_in_pop (); plug_in_params_destroy (proc_run.params, proc_run.nparams, FALSE); /* If this is an automatically installed extension, wait for an * installation-confirmation message */ if ((proc_rec->proc_type == GIMP_EXTENSION) && (proc_rec->num_args == 0)) gtk_main (); if (plug_in->recurse) { gtk_main (); return_vals = plug_in_get_current_return_vals (proc_rec); } } } done: if (return_vals && destroy_values) { procedural_db_destroy_args (return_vals, proc_rec->num_values); return_vals = NULL; } return return_vals; } void plug_in_repeat (gboolean with_interface) { GimpDisplay *gdisplay; Argument *args; gint i; if (last_plug_in) { gdisplay = gimp_context_get_display (gimp_get_user_context (the_gimp)); if (!gdisplay) return; /* construct the procedures arguments */ args = g_new (Argument, 3); /* initialize the first three argument types */ for (i = 0; i < 3; i++) args[i].arg_type = last_plug_in->args[i].arg_type; /* initialize the first three plug-in arguments */ args[0].value.pdb_int = (with_interface ? RUN_INTERACTIVE : RUN_WITH_LAST_VALS); args[1].value.pdb_int = gimp_image_get_ID (gdisplay->gimage); args[2].value.pdb_int = gimp_drawable_get_ID (gimp_image_active_drawable (gdisplay->gimage)); /* run the plug-in procedure */ plug_in_run (last_plug_in, args, 3, FALSE, TRUE, gdisplay->ID); g_free (args); } } void plug_in_set_menu_sensitivity (GimpImageType type) { PlugInProcDef *proc_def; GSList *tmp; gboolean sensitive = FALSE; for (tmp = proc_defs; tmp; tmp = g_slist_next (tmp)) { proc_def = tmp->data; if (proc_def->image_types_val && proc_def->menu_path) { switch (type) { case RGB_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_RGB_IMAGE; break; case RGBA_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_RGBA_IMAGE; break; case GRAY_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_GRAY_IMAGE; break; case GRAYA_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_GRAYA_IMAGE; break; case INDEXED_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_INDEXED_IMAGE; break; case INDEXEDA_GIMAGE: sensitive = proc_def->image_types_val & PLUG_IN_INDEXEDA_IMAGE; break; default: sensitive = FALSE; break; } menus_set_sensitive (proc_def->menu_path, sensitive); if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { menus_set_sensitive ("/Filters/Repeat Last", sensitive); menus_set_sensitive ("/Filters/Re-Show Last", sensitive); } } } if (!last_plug_in) { menus_set_sensitive ("/Filters/Repeat Last", FALSE); menus_set_sensitive ("/Filters/Re-Show Last", FALSE); } } static gboolean plug_in_recv_message (GIOChannel *channel, GIOCondition cond, gpointer data) { gboolean got_message = FALSE; if ((PlugIn *) data != current_plug_in) plug_in_push ((PlugIn *) data); if (current_readchannel == NULL) return TRUE; if (cond & (G_IO_IN | G_IO_PRI)) { WireMessage msg; memset (&msg, 0, sizeof (WireMessage)); if (!wire_read_msg (current_readchannel, &msg)) { plug_in_close (current_plug_in, TRUE); } else { plug_in_handle_message (&msg); wire_destroy (&msg); got_message = TRUE; } } if (cond & (G_IO_ERR | G_IO_HUP)) { if (current_plug_in->open) { plug_in_close (current_plug_in, TRUE); } } if (!got_message) g_message (_("Plug-In crashed: \"%s\"\n(%s)\n\n" "The dying Plug-In may have messed up GIMP's internal state.\n" "You may want to save your images and restart GIMP\n" "to be on the safe side."), g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0]); if (!current_plug_in->open) plug_in_destroy (current_plug_in); else plug_in_pop (); return TRUE; } static void plug_in_handle_message (WireMessage *msg) { switch (msg->type) { case GP_QUIT: plug_in_handle_quit (); break; case GP_CONFIG: g_warning ("plug_in_handle_message(): " "received a config message (should not happen)"); plug_in_close (current_plug_in, TRUE); break; case GP_TILE_REQ: plug_in_handle_tile_req (msg->data); break; case GP_TILE_ACK: g_warning ("plug_in_handle_message(): " "received a tile ack message (should not happen)"); plug_in_close (current_plug_in, TRUE); break; case GP_TILE_DATA: g_warning ("plug_in_handle_message(): " "received a tile data message (should not happen)"); plug_in_close (current_plug_in, TRUE); break; case GP_PROC_RUN: plug_in_handle_proc_run (msg->data); break; case GP_PROC_RETURN: plug_in_handle_proc_return (msg->data); plug_in_close (current_plug_in, FALSE); break; case GP_TEMP_PROC_RUN: g_warning ("plug_in_handle_message(): " "received a temp proc run message (should not happen)"); plug_in_close (current_plug_in, TRUE); break; case GP_TEMP_PROC_RETURN: plug_in_handle_proc_return (msg->data); gtk_main_quit (); break; case GP_PROC_INSTALL: plug_in_handle_proc_install (msg->data); break; case GP_PROC_UNINSTALL: plug_in_handle_proc_uninstall (msg->data); break; case GP_EXTENSION_ACK: gtk_main_quit (); break; } } static void plug_in_handle_quit (void) { plug_in_close (current_plug_in, FALSE); } static void plug_in_handle_tile_req (GPTileReq *tile_req) { GPTileData tile_data; GPTileData *tile_info; WireMessage msg; TileManager *tm; Tile *tile; if (tile_req->drawable_ID == -1) { tile_data.drawable_ID = -1; tile_data.tile_num = 0; tile_data.shadow = 0; tile_data.bpp = 0; tile_data.width = 0; tile_data.height = 0; tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE; tile_data.data = NULL; if (!gp_tile_data_write (current_writechannel, &tile_data)) { g_warning ("plug_in_handle_tile_req: ERROR"); plug_in_close (current_plug_in, TRUE); return; } if (!wire_read_msg (current_readchannel, &msg)) { g_warning ("plug_in_handle_tile_req: ERROR"); plug_in_close (current_plug_in, TRUE); return; } if (msg.type != GP_TILE_DATA) { g_warning ("expected tile data and received: %d", msg.type); plug_in_close (current_plug_in, TRUE); return; } tile_info = msg.data; if (tile_info->shadow) tm = gimp_drawable_shadow (gimp_drawable_get_by_ID (the_gimp, tile_info->drawable_ID)); else tm = gimp_drawable_data (gimp_drawable_get_by_ID (the_gimp, tile_info->drawable_ID)); if (!tm) { g_warning ("plug-in requested invalid drawable (killing)"); plug_in_close (current_plug_in, TRUE); return; } tile = tile_manager_get (tm, tile_info->tile_num, TRUE, TRUE); if (!tile) { g_warning ("plug-in requested invalid tile (killing)"); plug_in_close (current_plug_in, TRUE); return; } if (tile_data.use_shm) memcpy (tile_data_pointer (tile, 0, 0), shm_addr, tile_size (tile)); else memcpy (tile_data_pointer (tile, 0, 0), tile_info->data, tile_size (tile)); tile_release (tile, TRUE); wire_destroy (&msg); if (!gp_tile_ack_write (current_writechannel)) { g_warning ("plug_in_handle_tile_req: ERROR"); plug_in_close (current_plug_in, TRUE); return; } } else { if (tile_req->shadow) tm = gimp_drawable_shadow (gimp_drawable_get_by_ID (the_gimp, tile_req->drawable_ID)); else tm = gimp_drawable_data (gimp_drawable_get_by_ID (the_gimp, tile_req->drawable_ID)); if (!tm) { g_warning ("plug-in requested invalid drawable (killing)"); plug_in_close (current_plug_in, TRUE); return; } tile = tile_manager_get (tm, tile_req->tile_num, TRUE, FALSE); if (!tile) { g_warning ("plug-in requested invalid tile (killing)"); plug_in_close (current_plug_in, TRUE); return; } tile_data.drawable_ID = tile_req->drawable_ID; tile_data.tile_num = tile_req->tile_num; tile_data.shadow = tile_req->shadow; tile_data.bpp = tile_bpp (tile); tile_data.width = tile_ewidth (tile); tile_data.height = tile_eheight (tile); tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE; if (tile_data.use_shm) memcpy (shm_addr, tile_data_pointer (tile, 0, 0), tile_size (tile)); else tile_data.data = tile_data_pointer (tile, 0, 0); if (!gp_tile_data_write (current_writechannel, &tile_data)) { g_message ("plug_in_handle_tile_req: ERROR"); plug_in_close (current_plug_in, TRUE); return; } tile_release (tile, FALSE); if (!wire_read_msg (current_readchannel, &msg)) { g_message ("plug_in_handle_tile_req: ERROR"); plug_in_close (current_plug_in, TRUE); return; } if (msg.type != GP_TILE_ACK) { g_warning ("expected tile ack and received: %d", msg.type); plug_in_close (current_plug_in, TRUE); return; } wire_destroy (&msg); } } static void plug_in_handle_proc_run (GPProcRun *proc_run) { GPProcReturn proc_return; ProcRecord *proc_rec; Argument *args; Argument *return_vals; PlugInBlocked *blocked; args = plug_in_params_to_args (proc_run->params, proc_run->nparams, FALSE); proc_rec = procedural_db_lookup (the_gimp, proc_run->name); if (proc_rec) { return_vals = procedural_db_execute (the_gimp, proc_run->name, args); } else { /* if the name lookup failed, construct a * dummy "executiuon error" return value --Michael */ return_vals = g_new (Argument, 1); return_vals[0].arg_type = GIMP_PDB_STATUS; return_vals[0].value.pdb_int = GIMP_PDB_EXECUTION_ERROR; } if (return_vals) { proc_return.name = proc_run->name; if (proc_rec) { proc_return.nparams = proc_rec->num_values + 1; proc_return.params = plug_in_args_to_params (return_vals, proc_rec->num_values + 1, FALSE); } else { proc_return.nparams = 1; proc_return.params = plug_in_args_to_params (return_vals, 1, FALSE); } if (!gp_proc_return_write (current_writechannel, &proc_return)) { g_warning ("plug_in_handle_proc_run: ERROR"); plug_in_close (current_plug_in, TRUE); return; } plug_in_args_destroy (args, proc_run->nparams, FALSE); plug_in_args_destroy (return_vals, (proc_rec ? (proc_rec->num_values + 1) : 1), TRUE); plug_in_params_destroy (proc_return.params, proc_return.nparams, FALSE); } else { blocked = g_new (PlugInBlocked, 1); blocked->plug_in = current_plug_in; blocked->proc_name = g_strdup (proc_run->name); blocked_plug_ins = g_slist_prepend (blocked_plug_ins, blocked); } } static void plug_in_handle_proc_return (GPProcReturn *proc_return) { PlugInBlocked *blocked; GSList *tmp; if (current_plug_in->recurse) { current_return_vals = plug_in_params_to_args (proc_return->params, proc_return->nparams, TRUE); current_return_nvals = proc_return->nparams; } else { tmp = blocked_plug_ins; while (tmp) { blocked = tmp->data; tmp = tmp->next; if (blocked->proc_name && proc_return->name && strcmp (blocked->proc_name, proc_return->name) == 0) { plug_in_push (blocked->plug_in); if (!gp_proc_return_write (current_writechannel, proc_return)) { g_message ("plug_in_handle_proc_run: ERROR"); plug_in_close (current_plug_in, TRUE); return; } plug_in_pop (); blocked_plug_ins = g_slist_remove (blocked_plug_ins, blocked); g_free (blocked->proc_name); g_free (blocked); break; } } } } static void plug_in_handle_proc_install (GPProcInstall *proc_install) { PlugInDef *plug_in_def = NULL; PlugInProcDef *proc_def; ProcRecord *proc = NULL; PlugInMenuEntry *menu_entry; GSList *tmp = NULL; gchar *prog = NULL; gboolean add_proc_def; gboolean valid; gint i; /* Argument checking * --only sanity check arguments when the procedure requests a menu path */ if (proc_install->menu_path) { if (strncmp (proc_install->menu_path, "", 9) == 0) { if ((proc_install->nparams < 1) || (proc_install->params[0].type != GIMP_PDB_INT32)) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "which does not take the standard Plug-In args.", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name); return; } } else if (strncmp (proc_install->menu_path, "", 7) == 0) { if ((proc_install->nparams < 3) || (proc_install->params[0].type != GIMP_PDB_INT32) || (proc_install->params[1].type != GIMP_PDB_IMAGE) || (proc_install->params[2].type != GIMP_PDB_DRAWABLE)) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "which does not take the standard Plug-In args.", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name); return; } } else if (strncmp (proc_install->menu_path, "", 6) == 0) { if ((proc_install->nparams < 3) || (proc_install->params[0].type != GIMP_PDB_INT32) || (proc_install->params[1].type != GIMP_PDB_STRING) || (proc_install->params[2].type != GIMP_PDB_STRING)) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "which does not take the standard Plug-In args.", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name); return; } } else if (strncmp (proc_install->menu_path, "", 6) == 0) { if ((proc_install->nparams < 5) || (proc_install->params[0].type != GIMP_PDB_INT32) || (proc_install->params[1].type != GIMP_PDB_IMAGE) || (proc_install->params[2].type != GIMP_PDB_DRAWABLE) || (proc_install->params[3].type != GIMP_PDB_STRING) || (proc_install->params[4].type != GIMP_PDB_STRING)) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "which does not take the standard Plug-In args.", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name); return; } } else { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "in an invalid menu location.\n" "Use either \"\", \"\", " "\"\", or \"\".", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name); return; } } /* Sanity check for array arguments */ for (i = 1; i < proc_install->nparams; i++) { if ((proc_install->params[i].type == GIMP_PDB_INT32ARRAY || proc_install->params[i].type == GIMP_PDB_INT8ARRAY || proc_install->params[i].type == GIMP_PDB_FLOATARRAY || proc_install->params[i].type == GIMP_PDB_STRINGARRAY) && proc_install->params[i-1].type != GIMP_PDB_INT32) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "which fails to comply with the array parameter\n" "passing standard. Argument %d is noncompliant.", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0], proc_install->name, i); return; } } /* Sanity check strings for UTF-8 validity */ valid = FALSE; if ((proc_install->menu_path == NULL || g_utf8_validate (proc_install->menu_path, -1, NULL)) && (g_utf8_validate (proc_install->name, -1, NULL)) && (proc_install->blurb == NULL || g_utf8_validate (proc_install->blurb, -1, NULL)) && (proc_install->help == NULL || g_utf8_validate (proc_install->help, -1, NULL)) && (proc_install->author == NULL || g_utf8_validate (proc_install->author, -1, NULL)) && (proc_install->copyright == NULL || g_utf8_validate (proc_install->copyright, -1, NULL)) && (proc_install->date == NULL || g_utf8_validate (proc_install->date, -1, NULL))) { valid = TRUE; for (i = 0; i < proc_install->nparams && valid; i++) { if (! (g_utf8_validate (proc_install->params[i].name, -1, NULL) && (proc_install->params[i].description == NULL || g_utf8_validate (proc_install->params[i].description, -1, NULL)))) valid = FALSE; } for (i = 0; i < proc_install->nreturn_vals && valid; i++) { if (! (g_utf8_validate (proc_install->return_vals[i].name, -1, NULL) && (proc_install->return_vals[i].description == NULL || g_utf8_validate (proc_install->return_vals[i].description, -1, NULL)))) valid = FALSE; } } if (!valid) { g_message ("Plug-In \"%s\"\n(%s)\n" "attempted to install a procedure with invalid UTF-8 strings.\n", g_path_get_basename (current_plug_in->args[0]), current_plug_in->args[0]); return; } /* Initialization */ proc_def = NULL; switch (proc_install->type) { case GIMP_PLUGIN: case GIMP_EXTENSION: plug_in_def = current_plug_in->user_data; prog = plug_in_def->prog; tmp = plug_in_def->proc_defs; break; case GIMP_TEMPORARY: prog = "none"; tmp = current_plug_in->temp_proc_defs; break; } while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (strcmp (proc_def->db_info.name, proc_install->name) == 0) { if (proc_install->type == GIMP_TEMPORARY) plug_in_proc_def_remove (proc_def); else plug_in_proc_def_destroy (proc_def, TRUE); /* destroys data_only */ break; } proc_def = NULL; } add_proc_def = FALSE; if (!proc_def) { add_proc_def = TRUE; proc_def = g_new (PlugInProcDef, 1); } proc_def->prog = g_strdup (prog); proc_def->menu_path = g_strdup (proc_install->menu_path); proc_def->accelerator = NULL; proc_def->extensions = NULL; proc_def->prefixes = NULL; proc_def->magics = NULL; proc_def->image_types = g_strdup (proc_install->image_types); proc_def->image_types_val = plug_in_image_types_parse (proc_def->image_types); /* Install temp one use todays time */ proc_def->mtime = time (NULL); proc = &proc_def->db_info; /* The procedural database procedure */ proc->name = g_strdup (proc_install->name); proc->blurb = g_strdup (proc_install->blurb); proc->help = g_strdup (proc_install->help); proc->author = g_strdup (proc_install->author); proc->copyright = g_strdup (proc_install->copyright); proc->date = g_strdup (proc_install->date); proc->proc_type = proc_install->type; proc->num_args = proc_install->nparams; proc->num_values = proc_install->nreturn_vals; proc->args = g_new (ProcArg, proc->num_args); proc->values = g_new (ProcArg, proc->num_values); for (i = 0; i < proc->num_args; i++) { proc->args[i].arg_type = proc_install->params[i].type; proc->args[i].name = g_strdup (proc_install->params[i].name); proc->args[i].description = g_strdup (proc_install->params[i].description); } for (i = 0; i < proc->num_values; i++) { proc->values[i].arg_type = proc_install->return_vals[i].type; proc->values[i].name = g_strdup (proc_install->return_vals[i].name); proc->values[i].description = g_strdup (proc_install->return_vals[i].description); } switch (proc_install->type) { case GIMP_PLUGIN: case GIMP_EXTENSION: if (add_proc_def) plug_in_def->proc_defs = g_slist_prepend (plug_in_def->proc_defs, proc_def); break; case GIMP_TEMPORARY: if (add_proc_def) current_plug_in->temp_proc_defs = g_slist_prepend (current_plug_in->temp_proc_defs, proc_def); proc_defs = g_slist_append (proc_defs, proc_def); proc->exec_method.temporary.plug_in = (void *) current_plug_in; procedural_db_register (the_gimp, proc); /* If there is a menu path specified, create a menu entry */ if (proc_install->menu_path) { menu_entry = g_new (PlugInMenuEntry, 1); menu_entry->proc_def = proc_def; /* Below we use a hack to allow translations of Script-Fu paths. * Would be nice if we could solve this properly, but I haven't * found a way yet ... (Sven) */ if (plug_in_def && plug_in_def->locale_domain) menu_entry->domain = plug_in_def->locale_domain; else if (strncmp (proc_def->db_info.name, "script_fu", 9) == 0) menu_entry->domain = "gimp-script-fu"; else menu_entry->domain = std_plugins_domain; if (plug_in_def) menu_entry->help_path = plug_in_def->help_path; else menu_entry->help_path = NULL; /* plug_in_make_menu_entry frees the menu_entry for us */ plug_in_make_menu_entry (NULL, menu_entry, NULL); } break; } } static void plug_in_handle_proc_uninstall (GPProcUninstall *proc_uninstall) { PlugInProcDef *proc_def; GSList *tmp; tmp = current_plug_in->temp_proc_defs; while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (strcmp (proc_def->db_info.name, proc_uninstall->name) == 0) { current_plug_in->temp_proc_defs = g_slist_remove (current_plug_in->temp_proc_defs, proc_def); plug_in_proc_def_remove (proc_def); break; } } } static gboolean plug_in_write (GIOChannel *channel, guint8 *buf, gulong count) { gulong bytes; while (count > 0) { if ((current_write_buffer_index + count) >= WRITE_BUFFER_SIZE) { bytes = WRITE_BUFFER_SIZE - current_write_buffer_index; memcpy (¤t_write_buffer[current_write_buffer_index], buf, bytes); current_write_buffer_index += bytes; if (!wire_flush (channel)) return FALSE; } else { bytes = count; memcpy (¤t_write_buffer[current_write_buffer_index], buf, bytes); current_write_buffer_index += bytes; } buf += bytes; count -= bytes; } return TRUE; } static gboolean plug_in_flush (GIOChannel *channel) { GIOStatus status; GError *error = NULL; gint count; guint bytes; if (current_write_buffer_index > 0) { count = 0; while (count != current_write_buffer_index) { do { bytes = 0; status = g_io_channel_write_chars (channel, ¤t_write_buffer[count], (current_write_buffer_index - count), &bytes, &error); } while (status == G_IO_STATUS_AGAIN); if (status != G_IO_STATUS_NORMAL) { if (error) { g_warning ("%s: plug_in_flush(): error: %s", g_get_prgname (), error->message); g_error_free (error); } else { g_warning ("%s: plug_in_flush(): error", g_get_prgname ()); } return FALSE; } count += bytes; } current_write_buffer_index = 0; } return TRUE; } static void plug_in_push (PlugIn *plug_in) { if (plug_in) { current_plug_in = plug_in; plug_in_stack = g_slist_prepend (plug_in_stack, current_plug_in); current_readchannel = current_plug_in->my_read; current_writechannel = current_plug_in->my_write; current_write_buffer_index = current_plug_in->write_buffer_index; current_write_buffer = current_plug_in->write_buffer; } else { current_readchannel = NULL; current_writechannel = NULL; current_write_buffer_index = 0; current_write_buffer = NULL; } } static void plug_in_pop (void) { GSList *tmp; if (current_plug_in) { current_plug_in->write_buffer_index = current_write_buffer_index; tmp = plug_in_stack; plug_in_stack = plug_in_stack->next; tmp->next = NULL; g_slist_free (tmp); } if (plug_in_stack) { current_plug_in = plug_in_stack->data; current_readchannel = current_plug_in->my_read; current_writechannel = current_plug_in->my_write; current_write_buffer_index = current_plug_in->write_buffer_index; current_write_buffer = current_plug_in->write_buffer; } else { current_plug_in = NULL; current_readchannel = NULL; current_writechannel = NULL; current_write_buffer_index = 0; current_write_buffer = NULL; } } static void plug_in_write_rc_string (FILE *fp, gchar *str) { fputc ('"', fp); if (str) while (*str) { if (*str == '\n') { fputc ('\\', fp); fputc ('n', fp); } else if (*str == '\r') { fputc ('\\', fp); fputc ('r', fp); } else if (*str == '\032') /* ^Z is problematic on Windows */ { fputc ('\\', fp); fputc ('z', fp); } else { if ((*str == '"') || (*str == '\\')) fputc ('\\', fp); fputc (*str, fp); } str += 1; } fputc ('"', fp); } static void plug_in_write_rc (const gchar *filename) { FILE *fp; PlugInDef *plug_in_def; PlugInProcDef *proc_def; GSList *tmp; GSList *tmp2; gint i; fp = fopen (filename, "w"); if (!fp) return; tmp = plug_in_defs; while (tmp) { plug_in_def = tmp->data; tmp = tmp->next; if (plug_in_def->proc_defs) { fprintf (fp, "(plug-in-def "); plug_in_write_rc_string (fp, plug_in_def->prog); fprintf (fp, " %ld", (long) plug_in_def->mtime); tmp2 = plug_in_def->proc_defs; if (tmp2) fprintf (fp, "\n"); while (tmp2) { proc_def = tmp2->data; tmp2 = tmp2->next; fprintf (fp, "\t(proc-def \"%s\" %d\n", proc_def->db_info.name, proc_def->db_info.proc_type); fprintf (fp, "\t\t"); plug_in_write_rc_string (fp, proc_def->db_info.blurb); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->db_info.help); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->db_info.author); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->db_info.copyright); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->db_info.date); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->menu_path); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->extensions); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->prefixes); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->magics); fprintf (fp, "\n\t\t"); plug_in_write_rc_string (fp, proc_def->image_types); fprintf (fp, "\n\t\t%d %d\n", proc_def->db_info.num_args, proc_def->db_info.num_values); for (i = 0; i < proc_def->db_info.num_args; i++) { fprintf (fp, "\t\t(proc-arg %d ", proc_def->db_info.args[i].arg_type); plug_in_write_rc_string (fp, proc_def->db_info.args[i].name); plug_in_write_rc_string (fp, proc_def->db_info.args[i].description); fprintf (fp, ")%s", (proc_def->db_info.num_values || (i < (proc_def->db_info.num_args - 1))) ? "\n" : ""); } for (i = 0; i < proc_def->db_info.num_values; i++) { fprintf (fp, "\t\t(proc-arg %d ", proc_def->db_info.values[i].arg_type); plug_in_write_rc_string (fp, proc_def->db_info.values[i].name); plug_in_write_rc_string (fp, proc_def->db_info.values[i].description); fprintf (fp, ")%s", (i < (proc_def->db_info.num_values - 1)) ? "\n" : ""); } fprintf (fp, ")"); if (tmp2) fprintf (fp, "\n"); } if (plug_in_def->locale_domain) { fprintf (fp, "\n\t(locale-def \"%s\"", plug_in_def->locale_domain); if (plug_in_def->locale_path) fprintf (fp, " \"%s\")", plug_in_def->locale_path); else fprintf (fp, ")"); } if (plug_in_def->help_path) { fprintf (fp, "\n\t(help-def \"%s\")", plug_in_def->help_path); } fprintf (fp, ")\n"); if (tmp) fprintf (fp, "\n"); } } fclose (fp); } static void plug_in_init_file (const gchar *filename, gpointer loader_data) { GSList *tmp; PlugInDef *plug_in_def; gchar *plug_in_name; gchar *basename; basename = g_path_get_basename (filename); plug_in_def = NULL; tmp = plug_in_defs; while (tmp) { plug_in_def = tmp->data; tmp = tmp->next; plug_in_name = g_path_get_basename (plug_in_def->prog); if (g_ascii_strcasecmp (basename, plug_in_name) == 0) { g_print ("duplicate plug-in: \"%s\" (skipping)\n", filename); return; } g_free (plug_in_name); plug_in_def = NULL; } g_free (basename); plug_in_def = plug_in_def_new (filename); plug_in_def->mtime = gimp_datafile_mtime (); plug_in_def->query = TRUE; plug_in_defs = g_slist_append (plug_in_defs, plug_in_def); } static void plug_in_query (PlugInDef *plug_in_def) { PlugIn *plug_in; WireMessage msg; plug_in = plug_in_new (plug_in_def->prog); if (plug_in) { plug_in->query = TRUE; plug_in->synchronous = TRUE; plug_in->user_data = plug_in_def; if (plug_in_open (plug_in)) { plug_in_push (plug_in); while (plug_in->open) { if (!wire_read_msg (current_readchannel, &msg)) plug_in_close (current_plug_in, TRUE); else { plug_in_handle_message (&msg); wire_destroy (&msg); } } plug_in_pop (); plug_in_destroy (plug_in); } } } static void plug_in_add_to_db (void) { PlugInProcDef *proc_def; Argument args[4]; Argument *return_vals; GSList *tmp; tmp = proc_defs; while (tmp) { proc_def = tmp->data; tmp = tmp->next; if (proc_def->prog && (proc_def->db_info.proc_type != GIMP_INTERNAL)) { proc_def->db_info.exec_method.plug_in.filename = proc_def->prog; procedural_db_register (the_gimp, &proc_def->db_info); } } for (tmp = proc_defs; tmp; tmp = tmp->next) { proc_def = tmp->data; if (proc_def->extensions || proc_def->prefixes || proc_def->magics) { args[0].arg_type = GIMP_PDB_STRING; args[0].value.pdb_pointer = proc_def->db_info.name; args[1].arg_type = GIMP_PDB_STRING; args[1].value.pdb_pointer = proc_def->extensions; args[2].arg_type = GIMP_PDB_STRING; args[2].value.pdb_pointer = proc_def->prefixes; args[3].arg_type = GIMP_PDB_STRING; args[3].value.pdb_pointer = proc_def->magics; if (proc_def->image_types) { return_vals = procedural_db_execute (the_gimp, "gimp_register_save_handler", args); g_free (return_vals); } else { return_vals = procedural_db_execute (the_gimp, "gimp_register_magic_load_handler", args); g_free (return_vals); } } } } /* The following function has to be a GTraverseFunction, * but is also called directly. Please note that it frees the * menu_entry strcuture. --Sven */ static gint plug_in_make_menu_entry (gpointer foo, PlugInMenuEntry *menu_entry, gpointer bar) { GimpItemFactoryEntry entry; gchar *help_page; gchar *basename; gchar *lowercase_page; basename = g_path_get_basename (menu_entry->proc_def->prog); if (menu_entry->help_path) { help_page = g_strconcat (menu_entry->help_path, "@", /* HACK: locale subdir */ basename, ".html", NULL); } else { help_page = g_strconcat ("filters/", /* _not_ G_DIR_SEPARATOR_S */ basename, ".html", NULL); } g_free (basename); lowercase_page = g_ascii_strdown (help_page, -1); g_free (help_page); entry.entry.path = menu_entry->proc_def->menu_path; entry.entry.accelerator = menu_entry->proc_def->accelerator; entry.entry.callback = plug_in_callback; entry.entry.callback_action = 0; entry.entry.item_type = NULL; entry.quark_string = NULL; entry.help_page = lowercase_page; entry.description = NULL; menus_create_item_from_full_path (&entry, menu_entry->domain, &menu_entry->proc_def->db_info); g_free (menu_entry); return FALSE; } static void plug_in_make_menu (void) { PlugInDef *plug_in_def; PlugInProcDef *proc_def; PlugInMenuEntry *menu_entry; GSList *domains = NULL; GSList *procs; GSList *tmp; GTree *menu_entries; #ifdef ENABLE_NLS bindtextdomain (std_plugins_domain, LOCALEDIR); bind_textdomain_codeset (std_plugins_domain, "UTF-8"); domains = g_slist_append (domains, std_plugins_domain); #endif #ifdef ENABLE_NLS menu_entries = g_tree_new ((GCompareFunc)strcoll); #else menu_entries = g_tree_new ((GCompareFunc)strcmp); #endif tmp = plug_in_defs; while (tmp) { plug_in_def = tmp->data; tmp = tmp->next; procs = plug_in_def->proc_defs; if (!procs) continue; #ifdef ENABLE_NLS { gchar *domain; GSList *list; gboolean found = FALSE; if (plug_in_def->locale_domain) { domain = plug_in_def->locale_domain; for (list = domains; list && !found; list = list->next) { if (strcmp (domain, (gchar*)(list->data)) == 0) found = TRUE; } if (!found) { domains = g_slist_append (domains, domain); if (plug_in_def->locale_path) bindtextdomain (domain, plug_in_def->locale_path); else bindtextdomain (domain, LOCALEDIR); bind_textdomain_codeset (domain, "UTF-8"); } } } #endif /* ENABLE_NLS */ while (procs) { proc_def = procs->data; procs = procs->next; if (proc_def->prog && proc_def->menu_path && (!proc_def->extensions && !proc_def->prefixes && !proc_def->magics)) { menu_entry = g_new (PlugInMenuEntry, 1); menu_entry->proc_def = proc_def; menu_entry->domain = plug_in_def->locale_domain ? plug_in_def->locale_domain : std_plugins_domain; menu_entry->help_path = plug_in_def->help_path; g_tree_insert (menu_entries, dgettext (menu_entry->domain, proc_def->menu_path), menu_entry); } } } g_tree_traverse (menu_entries, (GTraverseFunc)plug_in_make_menu_entry, G_IN_ORDER, NULL); g_tree_destroy (menu_entries); g_slist_free (domains); } static void plug_in_callback (GtkWidget *widget, gpointer client_data) { GimpDisplay *gdisplay; ProcRecord *proc_rec; Argument *args; gint i; gint gdisp_ID = -1; gint argc = 0; /* calm down a gcc warning. */ /* get the active gdisplay */ gdisplay = gimp_context_get_display (gimp_get_user_context (the_gimp)); proc_rec = (ProcRecord *) client_data; /* construct the procedures arguments */ args = g_new0 (Argument, proc_rec->num_args); /* initialize the argument types */ for (i = 0; i < proc_rec->num_args; i++) args[i].arg_type = proc_rec->args[i].arg_type; switch (proc_rec->proc_type) { case GIMP_EXTENSION: /* initialize the first argument */ args[0].value.pdb_int = RUN_INTERACTIVE; argc = 1; break; case GIMP_PLUGIN: if (gdisplay) { gdisp_ID = gdisplay->ID; /* initialize the first 3 plug-in arguments */ args[0].value.pdb_int = RUN_INTERACTIVE; args[1].value.pdb_int = gimp_image_get_ID (gdisplay->gimage); args[2].value.pdb_int = gimp_drawable_get_ID (gimp_image_active_drawable (gdisplay->gimage)); argc = 3; } else { g_warning ("Uh-oh, no active gdisplay for the plug-in!"); g_free (args); return; } break; case GIMP_TEMPORARY: args[0].value.pdb_int = RUN_INTERACTIVE; argc = 1; if (proc_rec->num_args >= 3 && proc_rec->args[1].arg_type == GIMP_PDB_IMAGE && proc_rec->args[2].arg_type == GIMP_PDB_DRAWABLE) { if (gdisplay) { gdisp_ID = gdisplay->ID; args[1].value.pdb_int = gimp_image_get_ID (gdisplay->gimage); args[2].value.pdb_int = gimp_drawable_get_ID (gimp_image_active_drawable (gdisplay->gimage)); argc = 3; } else { g_warning ("Uh-oh, no active gdisplay for the temporary procedure!"); g_free (args); return; } } break; default: g_error ("Unknown procedure type."); g_free (args); return; } /* run the plug-in procedure */ plug_in_run (proc_rec, args, argc, FALSE, TRUE, gdisp_ID); if (proc_rec->proc_type == GIMP_PLUGIN) last_plug_in = proc_rec; g_free (args); } static void plug_in_proc_def_insert (PlugInProcDef *proc_def, void (*superceed_fn)(void*)) { PlugInProcDef *tmp_proc_def; GSList *tmp; GSList *prev; GSList *list; prev = NULL; tmp = proc_defs; while (tmp) { tmp_proc_def = tmp->data; if (strcmp (proc_def->db_info.name, tmp_proc_def->db_info.name) == 0) { tmp->data = proc_def; if (proc_def->menu_path) g_free (proc_def->menu_path); if (proc_def->accelerator) g_free (proc_def->accelerator); proc_def->menu_path = tmp_proc_def->menu_path; proc_def->accelerator = tmp_proc_def->accelerator; tmp_proc_def->menu_path = NULL; tmp_proc_def->accelerator = NULL; if (superceed_fn) (* superceed_fn) (tmp_proc_def); plug_in_proc_def_destroy (tmp_proc_def, FALSE); return; } else if (!proc_def->menu_path || (tmp_proc_def->menu_path && (strcmp (proc_def->menu_path, tmp_proc_def->menu_path) < 0))) { list = g_slist_alloc (); list->data = proc_def; list->next = tmp; if (prev) prev->next = list; else proc_defs = list; return; } prev = tmp; tmp = tmp->next; } proc_defs = g_slist_append (proc_defs, proc_def); } /* called when plug_in_proc_def_insert causes a proc_def to be * overridden and thus g_free()d. */ static void plug_in_proc_def_dead (void *freed_proc_def) { GSList *tmp; PlugInDef *plug_in_def; PlugInProcDef *proc_def = freed_proc_def; g_warning ("removing duplicate PDB procedure \"%s\"", proc_def->db_info.name); /* search the plugin list to see if any plugins had references to * the recently freed proc_def. */ for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp)) { plug_in_def = tmp->data; plug_in_def->proc_defs = g_slist_remove (plug_in_def->proc_defs, freed_proc_def); } } static void plug_in_proc_def_remove (PlugInProcDef *proc_def) { /* Destroy the menu item */ if (proc_def->menu_path) menus_destroy (proc_def->menu_path); /* Unregister the procedural database entry */ procedural_db_unregister (the_gimp, proc_def->db_info.name); /* Remove the defintion from the global list */ proc_defs = g_slist_remove (proc_defs, proc_def); /* Destroy the definition */ plug_in_proc_def_destroy (proc_def, TRUE); } static void plug_in_proc_def_destroy (PlugInProcDef *proc_def, gboolean data_only) { gint i; if (proc_def->prog) g_free (proc_def->prog); if (proc_def->menu_path) g_free (proc_def->menu_path); if (proc_def->accelerator) g_free (proc_def->accelerator); if (proc_def->extensions) g_free (proc_def->extensions); if (proc_def->prefixes) g_free (proc_def->prefixes); if (proc_def->magics) g_free (proc_def->magics); if (proc_def->image_types) g_free (proc_def->image_types); if (proc_def->db_info.name) g_free (proc_def->db_info.name); if (proc_def->db_info.blurb) g_free (proc_def->db_info.blurb); if (proc_def->db_info.help) g_free (proc_def->db_info.help); if (proc_def->db_info.author) g_free (proc_def->db_info.author); if (proc_def->db_info.copyright) g_free (proc_def->db_info.copyright); if (proc_def->db_info.date) g_free (proc_def->db_info.date); for (i = 0; i < proc_def->db_info.num_args; i++) { if (proc_def->db_info.args[i].name) g_free (proc_def->db_info.args[i].name); if (proc_def->db_info.args[i].description) g_free (proc_def->db_info.args[i].description); } for (i = 0; i < proc_def->db_info.num_values; i++) { if (proc_def->db_info.values[i].name) g_free (proc_def->db_info.values[i].name); if (proc_def->db_info.values[i].description) g_free (proc_def->db_info.values[i].description); } if (proc_def->db_info.args) g_free (proc_def->db_info.args); if (proc_def->db_info.values) g_free (proc_def->db_info.values); if (!data_only) g_free (proc_def); } static Argument * plug_in_temp_run (ProcRecord *proc_rec, Argument *args, gint argc) { Argument *return_vals; PlugIn *plug_in; GPProcRun proc_run; gint old_recurse; return_vals = NULL; plug_in = (PlugIn *) proc_rec->exec_method.temporary.plug_in; if (plug_in) { if (plug_in->busy) { return_vals = procedural_db_return_args (proc_rec, FALSE); goto done; } plug_in->busy = TRUE; plug_in_push (plug_in); proc_run.name = proc_rec->name; proc_run.nparams = argc; proc_run.params = plug_in_args_to_params (args, argc, FALSE); if (!gp_temp_proc_run_write (current_writechannel, &proc_run) || !wire_flush (current_writechannel)) { return_vals = procedural_db_return_args (proc_rec, FALSE); goto done; } plug_in_pop (); plug_in_params_destroy (proc_run.params, proc_run.nparams, FALSE); old_recurse = plug_in->recurse; plug_in->recurse = TRUE; /* gtk_main (); */ /* return_vals = plug_in_get_current_return_vals (proc_rec); */ return_vals = procedural_db_return_args (proc_rec, TRUE); plug_in->recurse = old_recurse; plug_in->busy = FALSE; } done: return return_vals; } static Argument* plug_in_params_to_args (GPParam *params, gint nparams, gboolean full_copy) { Argument *args; gchar **stringarray; gint count; gint i, j; if (nparams == 0) return NULL; args = g_new (Argument, nparams); for (i = 0; i < nparams; i++) { args[i].arg_type = params[i].type; switch (args[i].arg_type) { case GIMP_PDB_INT32: args[i].value.pdb_int = params[i].data.d_int32; break; case GIMP_PDB_INT16: args[i].value.pdb_int = params[i].data.d_int16; break; case GIMP_PDB_INT8: args[i].value.pdb_int = params[i].data.d_int8; break; case GIMP_PDB_FLOAT: args[i].value.pdb_float = params[i].data.d_float; break; case GIMP_PDB_STRING: if (full_copy) args[i].value.pdb_pointer = g_strdup (params[i].data.d_string); else args[i].value.pdb_pointer = params[i].data.d_string; break; case GIMP_PDB_INT32ARRAY: if (full_copy) { count = args[i-1].value.pdb_int; args[i].value.pdb_pointer = g_new (gint32, count); memcpy (args[i].value.pdb_pointer, params[i].data.d_int32array, count * 4); } else { args[i].value.pdb_pointer = params[i].data.d_int32array; } break; case GIMP_PDB_INT16ARRAY: if (full_copy) { count = args[i-1].value.pdb_int; args[i].value.pdb_pointer = g_new (gint16, count); memcpy (args[i].value.pdb_pointer, params[i].data.d_int16array, count * 2); } else { args[i].value.pdb_pointer = params[i].data.d_int16array; } break; case GIMP_PDB_INT8ARRAY: if (full_copy) { count = args[i-1].value.pdb_int; args[i].value.pdb_pointer = g_new (gint8, count); memcpy (args[i].value.pdb_pointer, params[i].data.d_int8array, count); } else { args[i].value.pdb_pointer = params[i].data.d_int8array; } break; case GIMP_PDB_FLOATARRAY: if (full_copy) { count = args[i-1].value.pdb_int; args[i].value.pdb_pointer = g_new (gdouble, count); memcpy (args[i].value.pdb_pointer, params[i].data.d_floatarray, count * 8); } else { args[i].value.pdb_pointer = params[i].data.d_floatarray; } break; case GIMP_PDB_STRINGARRAY: if (full_copy) { args[i].value.pdb_pointer = g_new (gchar *, args[i-1].value.pdb_int); stringarray = args[i].value.pdb_pointer; for (j = 0; j < args[i-1].value.pdb_int; j++) stringarray[j] = g_strdup (params[i].data.d_stringarray[j]); } else { args[i].value.pdb_pointer = params[i].data.d_stringarray; } break; case GIMP_PDB_COLOR: args[i].value.pdb_color = params[i].data.d_color; break; case GIMP_PDB_REGION: g_message ("the \"region\" arg type is not currently supported"); break; case GIMP_PDB_DISPLAY: args[i].value.pdb_int = params[i].data.d_display; break; case GIMP_PDB_IMAGE: args[i].value.pdb_int = params[i].data.d_image; break; case GIMP_PDB_LAYER: args[i].value.pdb_int = params[i].data.d_layer; break; case GIMP_PDB_CHANNEL: args[i].value.pdb_int = params[i].data.d_channel; break; case GIMP_PDB_DRAWABLE: args[i].value.pdb_int = params[i].data.d_drawable; break; case GIMP_PDB_SELECTION: args[i].value.pdb_int = params[i].data.d_selection; break; case GIMP_PDB_BOUNDARY: args[i].value.pdb_int = params[i].data.d_boundary; break; case GIMP_PDB_PATH: args[i].value.pdb_int = params[i].data.d_path; break; case GIMP_PDB_PARASITE: if (full_copy) args[i].value.pdb_pointer = gimp_parasite_copy ((GimpParasite *) &(params[i].data.d_parasite)); else args[i].value.pdb_pointer = (gpointer) &(params[i].data.d_parasite); break; case GIMP_PDB_STATUS: args[i].value.pdb_int = params[i].data.d_status; break; case GIMP_PDB_END: break; } } return args; } static GPParam* plug_in_args_to_params (Argument *args, gint nargs, gboolean full_copy) { GPParam *params; gchar **stringarray; gint i, j; if (nargs == 0) return NULL; params = g_new (GPParam, nargs); for (i = 0; i < nargs; i++) { params[i].type = args[i].arg_type; switch (args[i].arg_type) { case GIMP_PDB_INT32: params[i].data.d_int32 = args[i].value.pdb_int; break; case GIMP_PDB_INT16: params[i].data.d_int16 = args[i].value.pdb_int; break; case GIMP_PDB_INT8: params[i].data.d_int8 = args[i].value.pdb_int; break; case GIMP_PDB_FLOAT: params[i].data.d_float = args[i].value.pdb_float; break; case GIMP_PDB_STRING: if (full_copy) params[i].data.d_string = g_strdup (args[i].value.pdb_pointer); else params[i].data.d_string = args[i].value.pdb_pointer; break; case GIMP_PDB_INT32ARRAY: if (full_copy) { params[i].data.d_int32array = g_new (gint32, params[i-1].data.d_int32); memcpy (params[i].data.d_int32array, args[i].value.pdb_pointer, params[i-1].data.d_int32 * 4); } else { params[i].data.d_int32array = args[i].value.pdb_pointer; } break; case GIMP_PDB_INT16ARRAY: if (full_copy) { params[i].data.d_int16array = g_new (gint16, params[i-1].data.d_int32); memcpy (params[i].data.d_int16array, args[i].value.pdb_pointer, params[i-1].data.d_int32 * 2); } else { params[i].data.d_int16array = args[i].value.pdb_pointer; } break; case GIMP_PDB_INT8ARRAY: if (full_copy) { params[i].data.d_int8array = g_new (gint8, params[i-1].data.d_int32); memcpy (params[i].data.d_int8array, args[i].value.pdb_pointer, params[i-1].data.d_int32); } else { params[i].data.d_int8array = args[i].value.pdb_pointer; } break; case GIMP_PDB_FLOATARRAY: if (full_copy) { params[i].data.d_floatarray = g_new (gdouble, params[i-1].data.d_int32); memcpy (params[i].data.d_floatarray, args[i].value.pdb_pointer, params[i-1].data.d_int32 * 8); } else { params[i].data.d_floatarray = args[i].value.pdb_pointer; } break; case GIMP_PDB_STRINGARRAY: if (full_copy) { params[i].data.d_stringarray = g_new (gchar*, params[i-1].data.d_int32); stringarray = args[i].value.pdb_pointer; for (j = 0; j < params[i-1].data.d_int32; j++) params[i].data.d_stringarray[j] = g_strdup (stringarray[j]); } else { params[i].data.d_stringarray = args[i].value.pdb_pointer; } break; case GIMP_PDB_COLOR: params[i].data.d_color = args[i].value.pdb_color; break; case GIMP_PDB_REGION: g_message ("the \"region\" arg type is not currently supported"); break; case GIMP_PDB_DISPLAY: params[i].data.d_display = args[i].value.pdb_int; break; case GIMP_PDB_IMAGE: params[i].data.d_image = args[i].value.pdb_int; break; case GIMP_PDB_LAYER: params[i].data.d_layer = args[i].value.pdb_int; break; case GIMP_PDB_CHANNEL: params[i].data.d_channel = args[i].value.pdb_int; break; case GIMP_PDB_DRAWABLE: params[i].data.d_drawable = args[i].value.pdb_int; break; case GIMP_PDB_SELECTION: params[i].data.d_selection = args[i].value.pdb_int; break; case GIMP_PDB_BOUNDARY: params[i].data.d_boundary = args[i].value.pdb_int; break; case GIMP_PDB_PATH: params[i].data.d_path = args[i].value.pdb_int; break; case GIMP_PDB_PARASITE: if (full_copy) { GimpParasite *tmp; tmp = gimp_parasite_copy (args[i].value.pdb_pointer); if (tmp == NULL) { params[i].data.d_parasite.name = 0; params[i].data.d_parasite.flags = 0; params[i].data.d_parasite.size = 0; params[i].data.d_parasite.data = 0; } else { memcpy (¶ms[i].data.d_parasite, tmp, sizeof (GimpParasite)); g_free (tmp); } } else { if (args[i].value.pdb_pointer == NULL) { params[i].data.d_parasite.name = 0; params[i].data.d_parasite.flags = 0; params[i].data.d_parasite.size = 0; params[i].data.d_parasite.data = 0; } else memcpy (¶ms[i].data.d_parasite, (GimpParasite *) (args[i].value.pdb_pointer), sizeof (GimpParasite)); } break; case GIMP_PDB_STATUS: params[i].data.d_status = args[i].value.pdb_int; break; case GIMP_PDB_END: break; } } return params; } static void plug_in_params_destroy (GPParam *params, gint nparams, gboolean full_destroy) { gint i, j; for (i = 0; i < nparams; i++) { switch (params[i].type) { case GIMP_PDB_INT32: case GIMP_PDB_INT16: case GIMP_PDB_INT8: case GIMP_PDB_FLOAT: break; case GIMP_PDB_STRING: if (full_destroy) g_free (params[i].data.d_string); break; case GIMP_PDB_INT32ARRAY: if (full_destroy) g_free (params[i].data.d_int32array); break; case GIMP_PDB_INT16ARRAY: if (full_destroy) g_free (params[i].data.d_int16array); break; case GIMP_PDB_INT8ARRAY: if (full_destroy) g_free (params[i].data.d_int8array); break; case GIMP_PDB_FLOATARRAY: if (full_destroy) g_free (params[i].data.d_floatarray); break; case GIMP_PDB_STRINGARRAY: if (full_destroy) { for (j = 0; j < params[i-1].data.d_int32; j++) g_free (params[i].data.d_stringarray[j]); g_free (params[i].data.d_stringarray); } break; case GIMP_PDB_COLOR: break; case GIMP_PDB_REGION: g_message ("the \"region\" arg type is not currently supported"); break; 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: break; case GIMP_PDB_PARASITE: if (full_destroy) if (params[i].data.d_parasite.data) { g_free (params[i].data.d_parasite.name); g_free (params[i].data.d_parasite.data); params[i].data.d_parasite.name = 0; params[i].data.d_parasite.data = 0; } break; case GIMP_PDB_STATUS: break; case GIMP_PDB_END: break; } } g_free (params); } static void plug_in_args_destroy (Argument *args, gint nargs, gboolean full_destroy) { gchar **stringarray; gint count; gint i, j; for (i = 0; i < nargs; i++) { switch (args[i].arg_type) { case GIMP_PDB_INT32: case GIMP_PDB_INT16: case GIMP_PDB_INT8: case GIMP_PDB_FLOAT: break; case GIMP_PDB_STRING: if (full_destroy) g_free (args[i].value.pdb_pointer); break; case GIMP_PDB_INT32ARRAY: if (full_destroy) g_free (args[i].value.pdb_pointer); break; case GIMP_PDB_INT16ARRAY: if (full_destroy) g_free (args[i].value.pdb_pointer); break; case GIMP_PDB_INT8ARRAY: if (full_destroy) g_free (args[i].value.pdb_pointer); break; case GIMP_PDB_FLOATARRAY: if (full_destroy) g_free (args[i].value.pdb_pointer); break; case GIMP_PDB_STRINGARRAY: if (full_destroy) { count = args[i-1].value.pdb_int; stringarray = args[i].value.pdb_pointer; for (j = 0; j < count; j++) g_free (stringarray[j]); g_free (args[i].value.pdb_pointer); } break; case GIMP_PDB_COLOR: break; case GIMP_PDB_REGION: g_message ("the \"region\" arg type is not currently supported"); break; 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: break; case GIMP_PDB_PARASITE: if (full_destroy) { gimp_parasite_free ((GimpParasite *) (args[i].value.pdb_pointer)); args[i].value.pdb_pointer = NULL; } break; case GIMP_PDB_STATUS: break; case GIMP_PDB_END: break; } } g_free (args); } gint plug_in_image_types_parse (gchar *image_types) { gchar *type_spec = image_types; gint types = 0; /* * If the plug_in registers with image_type == NULL or "", return 0 * By doing so it won't be touched by plug_in_set_menu_sensitivity() */ if (!image_types) return types; while (*image_types) { while (*image_types && ((*image_types == ' ') || (*image_types == '\t') || (*image_types == ','))) image_types++; if (*image_types) { if (strncmp (image_types, "RGBA", 4) == 0) { types |= PLUG_IN_RGBA_IMAGE; image_types += 4; } else if (strncmp (image_types, "RGB*", 4) == 0) { types |= PLUG_IN_RGB_IMAGE | PLUG_IN_RGBA_IMAGE; image_types += 4; } else if (strncmp (image_types, "RGB", 3) == 0) { types |= PLUG_IN_RGB_IMAGE; image_types += 3; } else if (strncmp (image_types, "GRAYA", 5) == 0) { types |= PLUG_IN_GRAYA_IMAGE; image_types += 5; } else if (strncmp (image_types, "GRAY*", 5) == 0) { types |= PLUG_IN_GRAY_IMAGE | PLUG_IN_GRAYA_IMAGE; image_types += 5; } else if (strncmp (image_types, "GRAY", 4) == 0) { types |= PLUG_IN_GRAY_IMAGE; image_types += 4; } else if (strncmp (image_types, "INDEXEDA", 8) == 0) { types |= PLUG_IN_INDEXEDA_IMAGE; image_types += 8; } else if (strncmp (image_types, "INDEXED*", 8) == 0) { types |= PLUG_IN_INDEXED_IMAGE | PLUG_IN_INDEXEDA_IMAGE; image_types += 8; } else if (strncmp (image_types, "INDEXED", 7) == 0) { types |= PLUG_IN_INDEXED_IMAGE; image_types += 7; } else if (strncmp (image_types, "*", 1) == 0) { types |= PLUG_IN_RGB_IMAGE | PLUG_IN_RGBA_IMAGE | PLUG_IN_GRAY_IMAGE | PLUG_IN_GRAYA_IMAGE | PLUG_IN_INDEXED_IMAGE | PLUG_IN_INDEXEDA_IMAGE; image_types += 1; } else { g_warning ("image_type contains unrecognizable parts: '%s'", type_spec); while (*image_types && ((*image_types != ' ') || (*image_types != '\t') || (*image_types != ','))) image_types++; } } } return types; } static void plug_in_progress_cancel (GtkWidget *widget, PlugIn *plug_in) { plug_in_destroy (plug_in); } void plug_in_progress_init (PlugIn *plug_in, gchar *message, gint gdisp_ID) { GimpDisplay *gdisp = NULL; if (!message) message = plug_in->args[0]; if (gdisp_ID > 0) gdisp = gdisplay_get_by_ID (the_gimp, gdisp_ID); if (plug_in->progress) plug_in->progress = progress_restart (plug_in->progress, message, G_CALLBACK (plug_in_progress_cancel), plug_in); else plug_in->progress = progress_start (gdisp, message, TRUE, G_CALLBACK (plug_in_progress_cancel), plug_in); } void plug_in_progress_update (PlugIn *plug_in, gdouble percentage) { if (!plug_in->progress) plug_in_progress_init (plug_in, NULL, -1); progress_update (plug_in->progress, percentage); } static gchar * plug_in_search_in_path (gchar *search_path, gchar *filename) { gchar *local_path; gchar *token; gchar *next_token; gchar *path; struct stat buf; gint err; local_path = g_strdup (search_path); next_token = local_path; token = strtok (next_token, G_SEARCHPATH_SEPARATOR_S); while (token) { path = g_build_filename (token, filename, NULL); err = stat (path, &buf); if (!err && S_ISREG (buf.st_mode)) { token = path; break; } g_free (path); token = strtok (NULL, G_SEARCHPATH_SEPARATOR_S); } g_free (local_path); return token; }