Code

r15555@tres: ted | 2007-06-08 08:57:04 -0700
[inkscape.git] / src / extension / implementation / script.cpp
index 11544463dd11021e10ad0b3921d1df5c6f8f045a..f8cdfd9f2c17e063774a10300a931b0f4ed8f031 100644 (file)
@@ -6,11 +6,28 @@
  *   Bryce Harrington <bryce@osdl.org>
  *   Ted Gould <ted@gould.cx>
  *
- * Copyright (C) 2002-2005 Authors
+ * Copyright (C) 2002-2005,2007 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 
+/*
+TODO:
+FIXME:
+  After Inkscape makes a formal requirement for a GTK version above 2.11.4, please
+  replace all the instances of ink_ext_XXXXXX in this file that represent
+  svg files with ink_ext_XXXXXX.svg . Doing so will prevent errors in extensions
+  that call inkscape to manipulate the file.
+  
+  "** (inkscape:5848): WARNING **: Format autodetect failed. The file is being opened as SVG."
+  
+  references:
+  http://www.gtk.org/api/2.6/glib/glib-File-Utilities.html#g-mkstemp
+  http://ftp.gnome.org/pub/gnome/sources/glib/2.11/glib-2.11.4.changes
+  http://developer.gnome.org/doc/API/2.0/glib/glib-File-Utilities.html#g-mkstemp
+  
+  --Aaron Spike
+*/
 #define __INKSCAPE_EXTENSION_IMPLEMENTATION_SCRIPT_C__
 
 #ifdef HAVE_CONFIG_H
 #include "selection.h"
 #include "sp-namedview.h"
 #include "io/sys.h"
-#include "registrytool.h"
 #include "prefs-utils.h"
 #include "../system.h"
 #include "extension/effect.h"
 #include "extension/output.h"
 #include "extension/db.h"
 #include "script.h"
+#include "dialogs/dialog-events.h"
 
 #include "util/glib-list-iterators.h"
 
@@ -42,6 +59,7 @@
 #ifdef WIN32
 #include <windows.h>
 #include <sys/stat.h>
+#include "registrytool.h"
 #endif
 
 
@@ -66,6 +84,12 @@ struct interpreter_t {
 };
 
 
+/** \brief  A table of what interpreters to call for a given language
+
+    This table is used to keep track of all the programs to execute a
+    given script.  It also tracks the preference to use to overwrite
+    the given interpreter to a custom one per user.
+*/
 static interpreter_t interpreterTab[] = {
         {"perl",   "perl-interpreter",   "perl"   },
         {"python", "python-interpreter", "python" },
@@ -127,7 +151,7 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg)
         if (stat(interpPath .c_str(), &finfo) ==0) {
             g_message("Found local interpreter, '%s',  Size: %d",
                       interpPath .c_str(),
-                      finfo.st_size);
+                      (int)finfo.st_size);
             return interpPath;
         }                       
     }
@@ -150,14 +174,68 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg)
 }
 
 
+class file_listener {
+    Glib::ustring _string;
+    sigc::connection _conn;
+    Glib::RefPtr<Glib::IOChannel> _channel;
+    Glib::RefPtr<Glib::MainLoop> _main_loop;
+    
+public:
+    file_listener () { };
+    ~file_listener () {
+        _conn.disconnect();
+    };
 
+    void init (int fd, Glib::RefPtr<Glib::MainLoop> main) {
+        _channel = Glib::IOChannel::create_from_fd(fd);
+        _channel->set_encoding();
+        _conn = Glib::signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR);
+        _main_loop = main;
 
+        return;
+    };
 
+    bool read (Glib::IOCondition condition) {
+        if (condition != Glib::IO_IN) {
+            _main_loop->quit();
+            return false;
+        }
 
-/**
-    \return    A script object
-    \brief     This function creates a script object and sets up the
+        Glib::IOStatus status;
+        Glib::ustring out;
+        status = _channel->read_to_end(out);
+
+        if (status != Glib::IO_STATUS_NORMAL) {
+            _main_loop->quit();
+            return false;
+        }
+
+        _string += out;
+        return true;
+    };
+
+    // Note, doing a copy here, on purpose
+    Glib::ustring string (void) { return _string; };
+
+    void toFile (const Glib::ustring &name) {
+        Glib::RefPtr<Glib::IOChannel> stdout_file = Glib::IOChannel::create_from_file(name, "w");
+        stdout_file->write(_string);
+        return;
+    };
+};
+
+int execute (const std::list<std::string> &in_command,
+             const std::list<std::string> &in_params,
+             const Glib::ustring &filein,
+             file_listener &fileout);
+void checkStderr (const Glib::ustring &data,
+                        Gtk::MessageType type,
+                  const Glib::ustring &message);
+
+
+/** \brief     This function creates a script object and sets up the
                variables.
+    \return    A script object
 
    This function just sets the command to NULL.  It should get built
    officially in the load function.  This allows for less allocation
@@ -275,8 +353,8 @@ Script::check_existance(const Glib::ustring &command)
            The default search path is the current directory */
         path = G_SEARCHPATH_SEPARATOR_S;
 
-    unsigned int pos  = 0;
-    unsigned int pos2 = 0;
+    std::string::size_type pos  = 0;
+    std::string::size_type pos2 = 0;
     while ( pos < path.size() ) {
 
         Glib::ustring localPath;
@@ -295,8 +373,9 @@ Script::check_existance(const Glib::ustring &command)
                       Glib::build_filename(localPath, command);
 
         if (Inkscape::IO::file_test(candidatePath .c_str(),
-                      G_FILE_TEST_EXISTS))
+                      G_FILE_TEST_EXISTS)) {
             return true;
+        }
 
     }
 
@@ -335,25 +414,23 @@ Script::load(Inkscape::Extension::Extension *module)
 
     /* This should probably check to find the executable... */
     Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
-    Glib::ustring command_text;
     while (child_repr != NULL) {
         if (!strcmp(child_repr->name(), "script")) {
             child_repr = sp_repr_children(child_repr);
             while (child_repr != NULL) {
                 if (!strcmp(child_repr->name(), "command")) {
-                    command_text = solve_reldir(child_repr);
-
                     const gchar *interpretstr = child_repr->attribute("interpreter");
                     if (interpretstr != NULL) {
                         Glib::ustring interpString =
                             resolveInterpreterExecutable(interpretstr);
-                        interpString .append(" ");
-                        interpString .append(command_text);
-                        command_text = interpString;
+                        command.insert(command.end(), interpretstr);
                     }
+
+                    command.insert(command.end(), solve_reldir(child_repr));
                 }
-                if (!strcmp(child_repr->name(), "helper_extension"))
+                if (!strcmp(child_repr->name(), "helper_extension")) {
                     helper_extension = sp_repr_children(child_repr)->content();
+                }
                 child_repr = sp_repr_next(child_repr);
             }
 
@@ -362,9 +439,8 @@ Script::load(Inkscape::Extension::Extension *module)
         child_repr = sp_repr_next(child_repr);
     }
 
-    g_return_val_if_fail(command_text.size() > 0, FALSE);
+    //g_return_val_if_fail(command.length() > 0, FALSE);
 
-    command = command_text;
     return true;
 }
 
@@ -380,7 +456,7 @@ Script::load(Inkscape::Extension::Extension *module)
 void
 Script::unload(Inkscape::Extension::Extension *module)
 {
-    command          = "";
+    command.clear();
     helper_extension = "";
 }
 
@@ -441,7 +517,7 @@ Script::check(Inkscape::Extension::Extension *module)
 */
 Gtk::Widget *
 Script::prefs_input(Inkscape::Extension::Input *module,
-                    const Glib::ustring &filename)
+                    const gchar *filename)
 {
     /*return module->autogui(); */
     return NULL;
@@ -473,19 +549,21 @@ Script::prefs_output(Inkscape::Extension::Output *module)
 */
 Gtk::Widget *
 Script::prefs_effect(Inkscape::Extension::Effect *module,
-                     Inkscape::UI::View::View *view)
+                     Inkscape::UI::View::View *view,
+                     sigc::signal<void> * changeSignal)
 {
-
     SPDocument * current_document = view->doc();
 
     using Inkscape::Util::GSListConstIterator;
     GSListConstIterator<SPItem *> selected =
            sp_desktop_selection((SPDesktop *)view)->itemList();
     Inkscape::XML::Node * first_select = NULL;
-    if (selected != NULL) 
-           first_select = SP_OBJECT_REPR(*selected);
+    if (selected != NULL) {
+        const SPItem * item = *selected;
+        first_select = SP_OBJECT_REPR(item);
+    }
 
-    return module->autogui(current_document, first_select);
+    return module->autogui(current_document, first_select, changeSignal);
 }
 
 
@@ -514,8 +592,10 @@ Script::prefs_effect(Inkscape::Extension::Effect *module,
 */
 SPDocument *
 Script::open(Inkscape::Extension::Input *module,
-             const Glib::ustring &filename)
+             const gchar *filenameArg)
 {
+#if 0
+    Glib::ustring filename = filenameArg;
 
     gchar *tmpname;
 
@@ -549,7 +629,6 @@ Script::open(Inkscape::Extension::Input *module,
 
     int data_read = execute(command, local_filename, tempfilename_out);
 
-
     SPDocument *mydoc = NULL;
     if (data_read > 10) {
         if (helper_extension.size()==0) {
@@ -573,6 +652,7 @@ Script::open(Inkscape::Extension::Input *module,
 
 
     return mydoc;
+#endif
 }
 
 
@@ -604,8 +684,10 @@ Script::open(Inkscape::Extension::Input *module,
 void
 Script::save(Inkscape::Extension::Output *module,
              SPDocument *doc,
-             const Glib::ustring &filename)
+             const gchar *filenameArg)
 {
+#if 0
+    Glib::ustring filename = filenameArg;
 
     gchar *tmpname;
     // FIXME: process the GError instead of passing NULL
@@ -657,6 +739,7 @@ Script::save(Inkscape::Extension::Output *module,
     close(tempfd);
     // FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
     unlink(tempfilename_in.c_str());
+#endif
 }
 
 
@@ -670,7 +753,7 @@ Script::save(Inkscape::Extension::Output *module,
     This function is a little bit trickier than the previous two.  It
     needs two temporary files to get it's work done.  Both of these
     files have random names created for them using the g_file_open_temp function
-    with the sp_ext_ prefix in the temporary directory.  Like the other
+    with the ink_ext_ prefix in the temporary directory.  Like the other
     functions, the temporary files are deleted at the end.
 
     To save/load the two temporary documents (both are SVG) the internal
@@ -692,7 +775,19 @@ Script::save(Inkscape::Extension::Output *module,
 void
 Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc)
 {
-    SPDocument * mydoc = NULL;
+    std::list<std::string> params;
+
+    if (module->no_doc) { 
+        // this is a no-doc extension, e.g. a Help menu command; 
+        // just run the command without any files, ignoring errors
+        module->paramListString(params);
+
+        Glib::ustring empty;
+        file_listener outfile;
+        execute(command, params, empty, outfile);
+
+        return;
+    }
 
     gchar *tmpname;
     // FIXME: process the GError instead of passing NULL
@@ -738,33 +833,30 @@ Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *do
     Glib::ustring tempfilename_out= tmpname;
     g_free(tmpname);
 
+    SPDesktop *desktop = (SPDesktop *) doc;
+    sp_namedview_document_from_window(desktop);
+
     Inkscape::Extension::save(
               Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
               doc->doc(), tempfilename_in.c_str(), FALSE, FALSE, FALSE);
 
-    Glib::ustring local_command(command);
-
-    /* fixme: Should be some sort of checking here.  Don't know how to do this with structs instead
-     * of classes. */
-    SPDesktop *desktop = (SPDesktop *) doc;
     if (desktop != NULL) {
         Inkscape::Util::GSListConstIterator<SPItem *> selected =
              sp_desktop_selection(desktop)->itemList();
         while ( selected != NULL ) {
-            local_command += " --id=";
-            local_command += SP_OBJECT_ID(*selected);
+            Glib::ustring selected_id;
+            selected_id += "--id=";
+            selected_id += SP_OBJECT_ID(*selected);
+            params.insert(params.begin(), selected_id);
             ++selected;
         }
     }
 
-    Glib::ustring paramString = *module->paramString();
-    local_command.append(paramString);
-
-
-    // std::cout << local_command << std::endl;
-
-    int data_read = execute(local_command, tempfilename_in, tempfilename_out);
+    file_listener fileout;
+    int data_read = execute(command, params, tempfilename_in, fileout);
+    fileout.toFile(tempfilename_out);
 
+    SPDocument * mydoc = NULL;
     if (data_read > 10)
         mydoc = Inkscape::Extension::open(
               Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG),
@@ -778,14 +870,16 @@ Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *do
     unlink(tempfilename_in.c_str());
     unlink(tempfilename_out.c_str());
 
-
     /* Do something with mydoc.... */
     if (mydoc) {
         doc->doc()->emitReconstructionStart();
         copy_doc(doc->doc()->rroot, mydoc->rroot);
         doc->doc()->emitReconstructionFinish();
         mydoc->release();
+        sp_namedview_update_layers_from_document(desktop);
     }
+
+    return;
 }
 
 
@@ -814,8 +908,6 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
             child = child->next()) {
         if (!strcmp("sodipodi:namedview", child->name()))
             continue;
-        if (!strcmp("svg:defs", child->name()))
-            continue;
         delete_list.push_back(child);
     }
     for (unsigned int i = 0; i < delete_list.size(); i++)
@@ -826,55 +918,51 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
             child = child->next()) {
         if (!strcmp("sodipodi:namedview", child->name()))
             continue;
-        if (!strcmp("svg:defs", child->name()))
-            continue;
-        oldroot->appendChild(child->duplicate());
+        oldroot->appendChild(child->duplicate(newroot->document()));
     }
 
     /** \todo  Restore correct layer */
     /** \todo  Restore correct selection */
 }
 
+/**  \brief  This function checks the stderr file, and if it has data,
+             shows it in a warning dialog to the user
+     \param  filename  Filename of the stderr file
+*/
+void
+checkStderr (const Glib::ustring &data,
+                   Gtk::MessageType type,
+             const Glib::ustring &message)
+{
+    Gtk::MessageDialog warning(message, false, type, Gtk::BUTTONS_OK, true);
+    warning.set_resizable(true);
+    GtkWidget *dlg = GTK_WIDGET(warning.gobj());
+    sp_transientize(dlg);
 
+    Gtk::VBox * vbox = warning.get_vbox();
 
-/* Helper class used by Script::execute */
-class pipe_t {
-public:
-    /* These functions set errno if they return false.
-       I'm not sure whether that's a good idea or not, but it should be reasonably
-       straightforward to change it if needed. */
-    bool open(const Glib::ustring &command,
-              const Glib::ustring &errorFile,
-              int mode);
-    bool close();
-
-    /* These return the number of bytes read/written. */
-    size_t read(void *buffer, size_t size);
-    size_t write(void const *buffer, size_t size);
-
-    enum {
-        mode_read  = 1 << 0,
-        mode_write = 1 << 1,
-    };
+    /* Gtk::TextView * textview = new Gtk::TextView(Gtk::TextBuffer::create()); */
+    Gtk::TextView * textview = new Gtk::TextView();
+    textview->set_editable(false);
+    textview->set_wrap_mode(Gtk::WRAP_WORD);
+    textview->show();
 
-private:
-#ifdef WIN32
-    /* This is used to translate win32 errors into errno errors.
-       It only recognizes a few win32 errors for the moment though. */
-    static int translate_error(DWORD err);
+    textview->get_buffer()->set_text(data.c_str());
 
-    HANDLE hpipe;
-#else
-    FILE *ppipe;
-#endif
-};
+    Gtk::ScrolledWindow * scrollwindow = new Gtk::ScrolledWindow();
+    scrollwindow->add(*textview);
+    scrollwindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+    scrollwindow->set_shadow_type(Gtk::SHADOW_IN);
+    scrollwindow->show();
 
+    vbox->pack_start(*scrollwindow, true, true, 5 /* fix these */);
 
+    warning.run();
 
+    return;
+}
 
-/**
-    \return   none
-    \brief    This is the core of the extension file as it actually does
+/** \brief    This is the core of the extension file as it actually does
               the execution of the extension.
     \param    in_command  The command to be executed
     \param    filein      Filename coming in
@@ -902,341 +990,85 @@ private:
     are closed, and we return to what we were doing.
 */
 int
-Script::execute (const Glib::ustring &in_command,
-                 const Glib::ustring &filein,
-                 const Glib::ustring &fileout)
+execute (const std::list<std::string> &in_command,
+         const std::list<std::string> &in_params,
+         const Glib::ustring &filein,
+         file_listener &fileout)
 {
     g_return_val_if_fail(in_command.size() > 0, 0);
-    // printf("Executing: %s\n", in_command);
+    // printf("Executing\n");
 
-    gchar *tmpname;
-    gint errorFileNum;
-    errorFileNum = g_file_open_tmp("ink_ext_stderr_XXXXXX", &tmpname, NULL);
-    if (errorFileNum != 0) {
-        close(errorFileNum);
-    } else {
-        g_free(tmpname);
-    }
+    std::vector <std::string> argv;
 
-    Glib::ustring errorFile = tmpname;
-    g_free(tmpname);
-
-    Glib::ustring localCommand = in_command;
-    localCommand .append(" \"");
-    localCommand .append(filein);
-    localCommand .append("\"");
-
-    // std::cout << "Command to run: " << command << std::endl;
-
-    pipe_t pipe;
-    bool open_success = pipe.open((char *)localCommand.c_str(),
-                                  errorFile.c_str(),
-                                  pipe_t::mode_read);
-
-    /* Run script */
-    if (!open_success) {
-        /* Error - could not open pipe - check errno */
-        if (errno == EINVAL) {
-            perror("Extension::Script:  Invalid mode argument in popen\n");
-        } else if (errno == ECHILD) {
-            perror("Extension::Script:  Cannot obtain child extension status in popen\n");
-        } else {
-            perror("Extension::Script:  Unknown error for popen\n");
-        }
-        return 0;
+    for (std::list<std::string>::const_iterator i = in_command.begin();
+            i != in_command.end(); i++) {
+        argv.push_back(*i);
     }
 
-    Inkscape::IO::dump_fopen_call(fileout.c_str(), "J");
-    FILE *pfile = Inkscape::IO::fopen_utf8name(fileout.c_str(), "w");
-
-    if (pfile == NULL) {
-        /* Error - could not open file */
-        if (errno == EINVAL) {
-            perror("Extension::Script:  The mode provided to fopen was invalid\n");
-        } else {
-            perror("Extension::Script:  Unknown error attempting to open temporary file\n");
-        }
-        return 0;
-    }
-
-    /* Copy pipe output to a temporary file */
-    int amount_read = 0;
-    char buf[BUFSIZE];
-    int num_read;
-    while ((num_read = pipe.read(buf, BUFSIZE)) != 0) {
-        amount_read += num_read;
-        fwrite(buf, 1, num_read, pfile);
-    }
-
-    /* Close file */
-    if (fclose(pfile) == EOF) {
-        if (errno == EBADF) {
-            perror("Extension::Script:  The filedescriptor for the temporary file is invalid\n");
-            return 0;
-        } else {
-            perror("Extension::Script:  Unknown error closing temporary file\n");
-        }
+    if (!(filein.empty())) {
+        argv.push_back(filein);
     }
 
-    /* Close pipe */
-    if (!pipe.close()) {
-        if (errno == EINVAL) {
-            perror("Extension::Script:  Invalid mode set for pclose\n");
-        } else if (errno == ECHILD) {
-            perror("Extension::Script:  Could not obtain child status for pclose\n");
-        } else {
-            if (errorFile != NULL) {
-                checkStderr(errorFile, Gtk::MESSAGE_ERROR,
-                    _("Inkscape has received an error from the script that it called.  "
-                      "The text returned with the error is included below.  "
-                      "Inkscape will continue working, but the action you requested has been cancelled."));
-            } else {
-                perror("Extension::Script:  Unknown error for pclose\n");
-            }
-        }
-        /* Could be a lie, but if there is an error, we don't want
-         * to count on what was read being good */
-        amount_read = 0;
-    } else {
-        if (errorFile.size()>0) {
-            checkStderr(errorFile, Gtk::MESSAGE_INFO,
-                _("Inkscape has received additional data from the script executed.  "
-                  "The script did not return an error, but this may indicate the results will not be as expected."));
-        }
+    for (std::list<std::string>::const_iterator i = in_params.begin();
+            i != in_params.end(); i++) {
+        argv.push_back(*i);
     }
 
-    if (errorFile.size()>0) {
-        unlink(errorFile.c_str());
+/*
+    for (std::vector<std::string>::const_iterator i = argv.begin();
+            i != argv.end(); i++) {
+        std::cout << *i << std::endl;
     }
-
-    return amount_read;
-}
-
-
-
-
-/**  \brief  This function checks the stderr file, and if it has data,
-             shows it in a warning dialog to the user
-     \param  filename  Filename of the stderr file
 */
-void
-Script::checkStderr (const Glib::ustring &filename,
-                     Gtk::MessageType type,
-                     const Glib::ustring &message)
-{
-
-    // magic win32 crlf->lf conversion means the file length is not the same as
-    // the text length, but luckily gtk will accept crlf in textviews so we can
-    // just use binary mode
-    std::ifstream stderrf (filename.c_str(), std::ios_base::in | std::ios_base::binary);
-    if (!stderrf.is_open()) return;
-
-    stderrf.seekg(0, std::ios::end);
-    int length = stderrf.tellg();
-    if (0 == length) return;
-    stderrf.seekg(0, std::ios::beg);
-
-    Gtk::MessageDialog warning(message, false, type, Gtk::BUTTONS_OK, true);
-    warning.set_resizable(true);
-
-    Gtk::VBox * vbox = warning.get_vbox();
-
-    /* Gtk::TextView * textview = new Gtk::TextView(Gtk::TextBuffer::create()); */
-    Gtk::TextView * textview = new Gtk::TextView();
-    textview->set_editable(false);
-    textview->set_wrap_mode(Gtk::WRAP_WORD);
-    textview->show();
-
-    char * buffer = new char [length];
-    stderrf.read(buffer, length);
-    textview->get_buffer()->set_text(buffer, buffer + length);
-    delete buffer;
-    stderrf.close();
-
-    Gtk::ScrolledWindow * scrollwindow = new Gtk::ScrolledWindow();
-    scrollwindow->add(*textview);
-    scrollwindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
-    scrollwindow->set_shadow_type(Gtk::SHADOW_IN);
-    scrollwindow->show();
-
-    vbox->pack_start(*scrollwindow, true, true, 5 /* fix these */);
-
-    warning.run();
-
-    return;
-}
-
-
-
-
-#ifdef WIN32
-
-
-bool pipe_t::open(const Glib::ustring &command,
-                  const Glib::ustring &errorFile,
-                  int mode_p) {
-    HANDLE pipe_write;
-
-    //###############  Create pipe
-    SECURITY_ATTRIBUTES secattrs;
-    ZeroMemory(&secattrs, sizeof(secattrs));
-    secattrs.nLength = sizeof(secattrs);
-    secattrs.lpSecurityDescriptor = 0;
-    secattrs.bInheritHandle = TRUE;
-    HANDLE t_pipe_read = 0;
-    if ( !CreatePipe(&t_pipe_read, &pipe_write, &secattrs, 0) ) {
-        errno = translate_error(GetLastError());
-        return false;
-    }
-    // This duplicate handle makes the read pipe uninheritable
-    BOOL ret = DuplicateHandle(GetCurrentProcess(),
-                               t_pipe_read,
-                               GetCurrentProcess(),
-                               &hpipe, 0, FALSE,
-                               DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
-    if (!ret) {
-        int en = translate_error(GetLastError());
-        CloseHandle(t_pipe_read);
-        CloseHandle(pipe_write);
-        errno = en;
-        return false;
-    }
 
-    //############### Open stderr file
-    HANDLE hStdErrFile = CreateFile(errorFile.c_str(),
-                      GENERIC_WRITE,
-                      FILE_SHARE_READ | FILE_SHARE_WRITE,
-                      NULL, CREATE_ALWAYS, 0, NULL);
-    HANDLE hInheritableStdErr;
-    DuplicateHandle(GetCurrentProcess(),
-                    hStdErrFile,
-                    GetCurrentProcess(),
-                    &hInheritableStdErr,
-                    0, 
-                    TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
-
-    //############### Create process
-    PROCESS_INFORMATION procinfo;
-    STARTUPINFO startupinfo;
-    ZeroMemory(&procinfo, sizeof(procinfo));
-    ZeroMemory(&startupinfo, sizeof(startupinfo));
-    startupinfo.cb = sizeof(startupinfo);
-    //startupinfo.lpReserved = 0;
-    //startupinfo.lpDesktop = 0;
-    //startupinfo.lpTitle = 0;
-    startupinfo.dwFlags = STARTF_USESTDHANDLES;
-    startupinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-    startupinfo.hStdOutput = pipe_write;
-    startupinfo.hStdError = hInheritableStdErr;
-
-    if ( !CreateProcess(NULL, (CHAR *)command.c_str(),
-                        NULL, NULL, TRUE,
-                        0, NULL, NULL,
-                        &startupinfo, &procinfo) ) {
-        errno = translate_error(GetLastError());
-        return false;
+    Glib::Pid pid;
+    int stdout_pipe, stderr_pipe;
+
+    try {
+        Glib::spawn_async_with_pipes(Glib::get_tmp_dir(), // working directory
+                                     argv,  // arg v
+                                     Glib::SPAWN_SEARCH_PATH /*| Glib::SPAWN_DO_NOT_REAP_CHILD*/,
+                                     sigc::slot<void>(),
+                                     &pid,           // Pid
+                                     NULL,           // STDIN
+                                     &stdout_pipe,   // STDOUT
+                                     &stderr_pipe);  // STDERR
+    } catch (Glib::SpawnError e) {
+        printf("Can't Spawn!!! %d\n", e.code());
+        return 0;
     }
-    CloseHandle(procinfo.hThread);
-    CloseHandle(procinfo.hProcess);
-
-    // Close our copy of the write handle
-    CloseHandle(hInheritableStdErr);
-    CloseHandle(pipe_write);
-
-    return true;
-}
 
+    Glib::RefPtr<Glib::MainLoop> main_loop = Glib::MainLoop::create(false);
 
+    file_listener fileerr;
+    fileout.init(stdout_pipe, main_loop);
+    fileerr.init(stderr_pipe, main_loop);
 
-bool pipe_t::close() {
-    BOOL retval = CloseHandle(hpipe);
-    if ( !retval )
-        errno = translate_error(GetLastError());
-    return retval != FALSE;
-}
-
-size_t pipe_t::read(void *buffer, size_t size) {
-    DWORD bytes_read = 0;
-    ReadFile(hpipe, buffer, size, &bytes_read, 0);
-    return bytes_read;
-}
+    main_loop->run();
 
-size_t pipe_t::write(void const *buffer, size_t size) {
-    DWORD bytes_written = 0;
-    WriteFile(hpipe, buffer, size, &bytes_written, 0);
-    return bytes_written;
-}
-
-int pipe_t::translate_error(DWORD err) {
-    switch (err) {
-        case ERROR_FILE_NOT_FOUND:
-            return ENOENT;
-        case ERROR_INVALID_HANDLE:
-        case ERROR_INVALID_PARAMETER:
-            return EINVAL;
-        default:
-            return 0;
+    Glib::ustring stderr_data = fileerr.string();
+    if (stderr_data.length() != 0) {
+        checkStderr(stderr_data, Gtk::MESSAGE_INFO,
+                                 _("Inkscape has received additional data from the script executed.  "
+                                   "The script did not return an error, but this may indicate the results will not be as expected."));
     }
-}
 
-
-#else // not Win32
-
-
-bool pipe_t::open(const Glib::ustring &command,
-                  const Glib::ustring &errorFile,
-                  int mode_p) {
-
-    Glib::ustring popen_mode;
-
-    if ( (mode_p & mode_read) != 0 )
-        popen_mode.append("r");
-
-    if ( (mode_p & mode_write) != 0 )
-        popen_mode.append("w");
-
-    // Get the commandline to be run
-    Glib::ustring pipeStr = command;
-    if (errorFile.size()>0) {
-        pipeStr .append(" 2> ");
-        pipeStr .append(errorFile);
+    Glib::ustring stdout_data = fileout.string();
+    if (stdout_data.length() == 0) {
+        return 0;
     }
 
-    ppipe = popen(pipeStr.c_str(), popen_mode.c_str());
-
-    return ppipe != NULL;
-}
-
-
-bool pipe_t::close() {
-    return fclose(ppipe) == 0;
+    // std::cout << "Finishing Execution." << std::endl;
+    return stdout_data.length();
 }
 
 
-size_t pipe_t::read(void *buffer, size_t size) {
-    return fread(buffer, 1, size, ppipe);
-}
-
-
-size_t pipe_t::write(void const *buffer, size_t size) {
-    return fwrite(buffer, 1, size, ppipe);
-}
-
-
-
-
-#endif // (Non-)Win32
-
-
 
 
 }  // namespace Implementation
 }  // namespace Extension
 }  // namespace Inkscape
 
-
-
-
 /*
   Local Variables:
   mode:c++