[gimp] libgimp: add gimp_plug_in_extension_enable() and _extension_process()



commit 5f8d0ef27b95ffb9b7bb41a47e7496bdcf7fa918
Author: Michael Natterer <mitch gimp org>
Date:   Fri Aug 2 11:06:48 2019 +0200

    libgimp: add gimp_plug_in_extension_enable() and _extension_process()
    
    Start copying all the actual wire communication to GimpPlugIn, and
    move the legacy versions to gimplegacy.c.
    
    This implies having the entire protocol code twice, but without any
    if(PLUG_IN) { plug_in_stuff(); } else { legacy_stuff(); }
    
    At the moment it is a wild mixture of old and new, but when finished
    the wire code in gimplegacy.c will be entirely separate from the wire
    code in GimpPlugIn, which will make it easy to g_assert() that only
    one API is used by a plug-in.

 libgimp/gimp-private.h          |   2 +
 libgimp/gimp.c                  | 249 +-------------------------------------
 libgimp/gimp.h                  |   8 --
 libgimp/gimplegacy.c            | 259 ++++++++++++++++++++++++++++++++++++++++
 libgimp/gimplegacy.h            |  12 ++
 libgimp/gimpplugin-private.c    | 110 ++++++++++++++++-
 libgimp/gimpplugin-private.h    |  13 +-
 libgimp/gimpplugin.c            | 140 +++++++++++++++++++++-
 libgimp/gimpplugin.h            |   4 +
 plug-ins/common/goat-exercise.c |   2 +
 plug-ins/help/help.c            |   4 +-
 11 files changed, 541 insertions(+), 262 deletions(-)
---
diff --git a/libgimp/gimp-private.h b/libgimp/gimp-private.h
index ba0ac8834a..89fbb88d09 100644
--- a/libgimp/gimp-private.h
+++ b/libgimp/gimp-private.h
@@ -27,10 +27,12 @@ G_BEGIN_DECLS
 #include "libgimpbase/gimpwire.h"
 
 
+extern GIOChannel *_gimp_readchannel;
 extern GIOChannel *_gimp_writechannel;
 extern GHashTable *_gimp_temp_proc_ht;
 
 
+void _gimp_config          (GPConfig        *config);
 void _gimp_read_expect_msg (GimpWireMessage *msg,
                             gint             type);
 
diff --git a/libgimp/gimp.c b/libgimp/gimp.c
index bd56c4194b..77a264e7a7 100644
--- a/libgimp/gimp.c
+++ b/libgimp/gimp.c
@@ -178,18 +178,11 @@ static gboolean   gimp_write                   (GIOChannel      *channel,
 static gboolean   gimp_flush                   (GIOChannel      *channel,
                                                 gpointer         user_data);
 static void       gimp_loop                    (void);
-static void       gimp_config                  (GPConfig        *config);
 static void       gimp_proc_run                (GPProcRun       *proc_run);
-static void       gimp_temp_proc_run           (GPProcRun       *proc_run);
 static void       gimp_proc_run_internal       (GPProcRun       *proc_run,
                                                 GimpProcedure   *procedure,
                                                 GimpRunProc      run_proc,
                                                 GPProcReturn    *proc_return);
-static void       gimp_process_message         (GimpWireMessage *msg);
-static void       gimp_single_message          (void);
-static gboolean   gimp_extension_read          (GIOChannel      *channel,
-                                                GIOCondition     condition,
-                                                gpointer         data);
 
 static void       gimp_set_pdb_error           (GimpValueArray  *return_vals);
 
@@ -198,7 +191,7 @@ static LPTOP_LEVEL_EXCEPTION_FILTER  _prevExceptionFilter    = NULL;
 static gchar                         *plug_in_backtrace_path = NULL;
 #endif
 
-static GIOChannel                   *_gimp_readchannel       = NULL;
+GIOChannel                          *_gimp_readchannel       = NULL;
 GIOChannel                          *_gimp_writechannel      = NULL;
 
 #ifdef USE_WIN32_SHM
@@ -811,31 +804,6 @@ gimp_quit (void)
   exit (EXIT_SUCCESS);
 }
 
-void
-_gimp_read_expect_msg (GimpWireMessage *msg,
-                       gint             type)
-{
-  while (TRUE)
-    {
-      if (! gimp_wire_read_msg (_gimp_readchannel, msg, NULL))
-        gimp_quit ();
-
-      if (msg->type == type)
-        return; /* up to the caller to call wire_destroy() */
-
-      if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT)
-        {
-          gimp_process_message (msg);
-        }
-      else
-        {
-          g_error ("unexpected message: %d", msg->type);
-        }
-
-      gimp_wire_destroy (msg);
-    }
-}
-
 GimpValueArray *
 gimp_run_procedure_with_array (const gchar    *name,
                                GimpValueArray *arguments)
@@ -1228,113 +1196,6 @@ gimp_get_progname (void)
   return progname;
 }
 
-/**
- * gimp_extension_enable:
- *
- * Enables asynchronous processing of messages from the main GIMP
- * application.
- *
- * Normally, a plug-in is not called by GIMP except for the call to
- * the procedure it implements. All subsequent communication is
- * triggered by the plug-in and all messages sent from GIMP to the
- * plug-in are just answers to requests the plug-in made.
- *
- * If the plug-in however registered temporary procedures using
- * gimp_install_temp_proc(), it needs to be able to receive requests
- * to execute them. Usually this will be done by running
- * gimp_extension_process() in an endless loop.
- *
- * If the plug-in cannot use gimp_extension_process(), i.e. if it has
- * a GUI and is hanging around in a #GMainLoop, it must call
- * gimp_extension_enable().
- *
- * Note that the plug-in does not need to be a #GIMP_EXTENSION to
- * register temporary procedures.
- *
- * See also: gimp_install_procedure(), gimp_install_temp_proc()
- **/
-void
-gimp_extension_enable (void)
-{
-  static gboolean callback_added = FALSE;
-
-  if (! callback_added)
-    {
-      g_io_add_watch (_gimp_readchannel, G_IO_IN | G_IO_PRI,
-                      gimp_extension_read,
-                      NULL);
-
-      callback_added = TRUE;
-    }
-}
-
-/**
- * gimp_extension_process:
- * @timeout: The timeout (in ms) to use for the select() call.
- *
- * Processes one message sent by GIMP and returns.
- *
- * Call this function in an endless loop after calling
- * gimp_extension_ack() to process requests for running temporary
- * procedures.
- *
- * See gimp_extension_enable() for an asynchronous way of doing the
- * same if running an endless loop is not an option.
- *
- * See also: gimp_install_procedure(), gimp_install_temp_proc()
- **/
-void
-gimp_extension_process (guint timeout)
-{
-#ifndef G_OS_WIN32
-  gint select_val;
-
-  do
-    {
-      fd_set readfds;
-      struct timeval  tv;
-      struct timeval *tvp;
-
-      if (timeout)
-        {
-          tv.tv_sec  = timeout / 1000;
-          tv.tv_usec = (timeout % 1000) * 1000;
-          tvp = &tv;
-        }
-      else
-        tvp = NULL;
-
-      FD_ZERO (&readfds);
-      FD_SET (g_io_channel_unix_get_fd (_gimp_readchannel), &readfds);
-
-      if ((select_val = select (FD_SETSIZE, &readfds, NULL, NULL, tvp)) > 0)
-        {
-          gimp_single_message ();
-        }
-      else if (select_val == -1 && errno != EINTR)
-        {
-          perror ("gimp_extension_process");
-          gimp_quit ();
-        }
-    }
-  while (select_val == -1 && errno == EINTR);
-#else
-  /* Zero means infinite wait for us, but g_poll and
-   * g_io_channel_win32_poll use -1 to indicate
-   * infinite wait.
-   */
-  GPollFD pollfd;
-
-  if (timeout == 0)
-    timeout = -1;
-
-  g_io_channel_win32_make_pollfd (_gimp_readchannel, G_IO_IN, &pollfd);
-
-  if (g_io_channel_win32_poll (&pollfd, 1, timeout) == 1)
-    gimp_single_message ();
-#endif
-}
-
 
 /*  private functions  */
 
@@ -1707,7 +1568,7 @@ gimp_loop (void)
           return;
 
         case GP_CONFIG:
-          gimp_config (msg.data);
+          _gimp_config (msg.data);
           break;
 
         case GP_TILE_REQ:
@@ -1747,8 +1608,8 @@ gimp_loop (void)
     }
 }
 
-static void
-gimp_config (GPConfig *config)
+void
+_gimp_config (GPConfig *config)
 {
   GFile *file;
   gchar *path;
@@ -1903,47 +1764,6 @@ gimp_proc_run (GPProcRun *proc_run)
     gimp_quit ();
 }
 
-static void
-gimp_temp_proc_run (GPProcRun *proc_run)
-{
-  GPProcReturn proc_return;
-
-  if (PLUG_IN)
-    {
-      GimpProcedure *procedure;
-
-      procedure = gimp_plug_in_get_temp_procedure (PLUG_IN, proc_run->name);
-
-      if (procedure)
-        {
-          gimp_proc_run_internal (proc_run, procedure, NULL,
-                                  &proc_return);
-        }
-    }
-  else
-    {
-      GimpRunProc run_proc = g_hash_table_lookup (_gimp_temp_proc_ht,
-                                                  proc_run->name);
-
-      if (run_proc)
-        {
-#ifdef GDK_WINDOWING_QUARTZ
-          if (proc_run->params &&
-              proc_run->params[0].data.d_int == GIMP_RUN_INTERACTIVE)
-            {
-              [NSApp activateIgnoringOtherApps: YES];
-            }
-#endif
-
-          gimp_proc_run_internal (proc_run, NULL, run_proc,
-                                  &proc_return);
-        }
-    }
-
-  if (! gp_temp_proc_return_write (_gimp_writechannel, &proc_return, NULL))
-    gimp_quit ();
-}
-
 static void
 gimp_proc_run_internal (GPProcRun     *proc_run,
                         GimpProcedure *procedure,
@@ -1992,67 +1812,6 @@ gimp_proc_run_internal (GPProcRun     *proc_run,
   gimp_value_array_unref (return_values);
 }
 
-static void
-gimp_process_message (GimpWireMessage *msg)
-{
-  switch (msg->type)
-    {
-    case GP_QUIT:
-      gimp_quit ();
-      break;
-    case GP_CONFIG:
-      gimp_config (msg->data);
-      break;
-    case GP_TILE_REQ:
-    case GP_TILE_ACK:
-    case GP_TILE_DATA:
-      g_warning ("unexpected tile message received (should not happen)");
-      break;
-    case GP_PROC_RUN:
-      g_warning ("unexpected proc run message received (should not happen)");
-      break;
-    case GP_PROC_RETURN:
-      g_warning ("unexpected proc return message received (should not happen)");
-      break;
-    case GP_TEMP_PROC_RUN:
-      gimp_temp_proc_run (msg->data);
-      break;
-    case GP_TEMP_PROC_RETURN:
-      g_warning ("unexpected temp proc return message received (should not happen)");
-      break;
-    case GP_PROC_INSTALL:
-      g_warning ("unexpected proc install message received (should not happen)");
-      break;
-    case GP_HAS_INIT:
-      g_warning ("unexpected has init message received (should not happen)");
-      break;
-    }
-}
-
-static void
-gimp_single_message (void)
-{
-  GimpWireMessage msg;
-
-  /* Run a temp function */
-  if (! gimp_wire_read_msg (_gimp_readchannel, &msg, NULL))
-    gimp_quit ();
-
-  gimp_process_message (&msg);
-
-  gimp_wire_destroy (&msg);
-}
-
-static gboolean
-gimp_extension_read (GIOChannel  *channel,
-                     GIOCondition condition,
-                     gpointer     data)
-{
-  gimp_single_message ();
-
-  return TRUE;
-}
-
 static void
 gimp_set_pdb_error (GimpValueArray *return_values)
 {
diff --git a/libgimp/gimp.h b/libgimp/gimp.h
index 5ea89b02be..f92af4db0b 100644
--- a/libgimp/gimp.h
+++ b/libgimp/gimp.h
@@ -149,14 +149,6 @@ gint                gimp_main                 (GType  plug_in_type,
  */
 void                gimp_quit                 (void) G_GNUC_NORETURN;
 
-/* Enable asynchronous processing of temp_procs
- */
-void                gimp_extension_enable     (void);
-
-/* Process one temp_proc and return
- */
-void                gimp_extension_process    (guint  timeout);
-
 /* Run a procedure in the procedure database. The parameters are
  *  specified as a GimpValueArray, so are the return values.
  *
diff --git a/libgimp/gimplegacy.c b/libgimp/gimplegacy.c
index 1b31c3cb27..68f750e0d5 100644
--- a/libgimp/gimplegacy.c
+++ b/libgimp/gimplegacy.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include "errno.h"
+
 #include <gio/gio.h>
 
 #include "libgimpbase/gimpbase.h"
@@ -46,6 +48,13 @@
 static gpointer   gimp_param_copy (gpointer boxed);
 static void       gimp_param_free (gpointer boxed);
 
+static void       gimp_process_message         (GimpWireMessage *msg);
+static void       gimp_single_message          (void);
+static gboolean   gimp_extension_read          (GIOChannel      *channel,
+                                                GIOCondition     condition,
+                                                gpointer         data);
+static void       gimp_temp_proc_run           (GPProcRun       *proc_run);
+
 
 /**
  * gimp_plug_in_info_set_callbacks:
@@ -465,6 +474,138 @@ gimp_extension_ack (void)
     gimp_quit ();
 }
 
+/**
+ * gimp_extension_enable:
+ *
+ * Enables asynchronous processing of messages from the main GIMP
+ * application.
+ *
+ * Normally, a plug-in is not called by GIMP except for the call to
+ * the procedure it implements. All subsequent communication is
+ * triggered by the plug-in and all messages sent from GIMP to the
+ * plug-in are just answers to requests the plug-in made.
+ *
+ * If the plug-in however registered temporary procedures using
+ * gimp_install_temp_proc(), it needs to be able to receive requests
+ * to execute them. Usually this will be done by running
+ * gimp_extension_process() in an endless loop.
+ *
+ * If the plug-in cannot use gimp_extension_process(), i.e. if it has
+ * a GUI and is hanging around in a #GMainLoop, it must call
+ * gimp_extension_enable().
+ *
+ * Note that the plug-in does not need to be a #GIMP_EXTENSION to
+ * register temporary procedures.
+ *
+ * See also: gimp_install_procedure(), gimp_install_temp_proc()
+ **/
+void
+gimp_extension_enable (void)
+{
+  static gboolean callback_added = FALSE;
+
+  if (! callback_added)
+    {
+      g_io_add_watch (_gimp_readchannel, G_IO_IN | G_IO_PRI,
+                      gimp_extension_read,
+                      NULL);
+
+      callback_added = TRUE;
+    }
+}
+
+/**
+ * gimp_extension_process:
+ * @timeout: The timeout (in ms) to use for the select() call.
+ *
+ * Processes one message sent by GIMP and returns.
+ *
+ * Call this function in an endless loop after calling
+ * gimp_extension_ack() to process requests for running temporary
+ * procedures.
+ *
+ * See gimp_extension_enable() for an asynchronous way of doing the
+ * same if running an endless loop is not an option.
+ *
+ * See also: gimp_install_procedure(), gimp_install_temp_proc()
+ **/
+void
+gimp_extension_process (guint timeout)
+{
+#ifndef G_OS_WIN32
+  gint select_val;
+
+  do
+    {
+      fd_set readfds;
+      struct timeval  tv;
+      struct timeval *tvp;
+
+      if (timeout)
+        {
+          tv.tv_sec  = timeout / 1000;
+          tv.tv_usec = (timeout % 1000) * 1000;
+          tvp = &tv;
+        }
+      else
+        tvp = NULL;
+
+      FD_ZERO (&readfds);
+      FD_SET (g_io_channel_unix_get_fd (_gimp_readchannel), &readfds);
+
+      if ((select_val = select (FD_SETSIZE, &readfds, NULL, NULL, tvp)) > 0)
+        {
+          gimp_single_message ();
+        }
+      else if (select_val == -1 && errno != EINTR)
+        {
+          perror ("gimp_extension_process");
+          gimp_quit ();
+        }
+    }
+  while (select_val == -1 && errno == EINTR);
+#else
+  /* Zero means infinite wait for us, but g_poll and
+   * g_io_channel_win32_poll use -1 to indicate
+   * infinite wait.
+   */
+  GPollFD pollfd;
+
+  if (timeout == 0)
+    timeout = -1;
+
+  g_io_channel_win32_make_pollfd (_gimp_readchannel, G_IO_IN, &pollfd);
+
+  if (g_io_channel_win32_poll (&pollfd, 1, timeout) == 1)
+    gimp_single_message ();
+#endif
+}
+
+void
+_gimp_read_expect_msg (GimpWireMessage *msg,
+                       gint             type)
+{
+  while (TRUE)
+    {
+      if (! gimp_wire_read_msg (_gimp_readchannel, msg, NULL))
+        gimp_quit ();
+
+      if (msg->type == type)
+        return; /* up to the caller to call wire_destroy() */
+
+      if (msg->type == GP_TEMP_PROC_RUN || msg->type == GP_QUIT)
+        {
+          gimp_process_message (msg);
+        }
+      else
+        {
+          g_error ("unexpected message: %d", msg->type);
+        }
+
+      gimp_wire_destroy (msg);
+    }
+}
+
 /**
  * gimp_run_procedure: (skip)
  * @name:          the name of the procedure to run
@@ -1045,3 +1186,121 @@ gimp_plugin_icon_register (const gchar  *procedure_name,
   return _gimp_plugin_icon_register (procedure_name,
                                      icon_type, icon_data_length, icon_data);
 }
+
+
+/*  private functions  */
+
+static void
+gimp_process_message (GimpWireMessage *msg)
+{
+  switch (msg->type)
+    {
+    case GP_QUIT:
+      gimp_quit ();
+      break;
+    case GP_CONFIG:
+      _gimp_config (msg->data);
+      break;
+    case GP_TILE_REQ:
+    case GP_TILE_ACK:
+    case GP_TILE_DATA:
+      g_warning ("unexpected tile message received (should not happen)");
+      break;
+    case GP_PROC_RUN:
+      g_warning ("unexpected proc run message received (should not happen)");
+      break;
+    case GP_PROC_RETURN:
+      g_warning ("unexpected proc return message received (should not happen)");
+      break;
+    case GP_TEMP_PROC_RUN:
+      gimp_temp_proc_run (msg->data);
+      break;
+    case GP_TEMP_PROC_RETURN:
+      g_warning ("unexpected temp proc return message received (should not happen)");
+      break;
+    case GP_PROC_INSTALL:
+      g_warning ("unexpected proc install message received (should not happen)");
+      break;
+    case GP_HAS_INIT:
+      g_warning ("unexpected has init message received (should not happen)");
+      break;
+    }
+}
+
+static void
+gimp_single_message (void)
+{
+  GimpWireMessage msg;
+
+  /* Run a temp function */
+  if (! gimp_wire_read_msg (_gimp_readchannel, &msg, NULL))
+    gimp_quit ();
+
+  gimp_process_message (&msg);
+
+  gimp_wire_destroy (&msg);
+}
+
+static gboolean
+gimp_extension_read (GIOChannel  *channel,
+                     GIOCondition condition,
+                     gpointer     data)
+{
+  gimp_single_message ();
+
+  return TRUE;
+}
+
+static void
+gimp_temp_proc_run (GPProcRun *proc_run)
+{
+  GPProcReturn proc_return;
+  GimpRunProc  run_proc = g_hash_table_lookup (_gimp_temp_proc_ht,
+                                               proc_run->name);
+
+  if (run_proc)
+    {
+      GimpValueArray *arguments;
+      GimpValueArray *return_values = NULL;
+      GimpParam      *params;
+      GimpParam      *return_vals;
+      gint            n_params;
+      gint            n_return_vals;
+
+#ifdef GDK_WINDOWING_QUARTZ
+      if (proc_run->params &&
+          proc_run->params[0].data.d_int == GIMP_RUN_INTERACTIVE)
+        {
+          [NSApp activateIgnoringOtherApps: YES];
+        }
+#endif
+
+      arguments = _gimp_gp_params_to_value_array (NULL, 0,
+                                                  proc_run->params,
+                                                  proc_run->nparams,
+                                                  FALSE, FALSE);
+
+      n_params = gimp_value_array_length (arguments);
+      params   = _gimp_value_array_to_params (arguments, FALSE);
+
+      run_proc (proc_run->name,
+                n_params,       params,
+                &n_return_vals, &return_vals);
+
+      return_values = _gimp_params_to_value_array (return_vals,
+                                                   n_return_vals,
+                                                   FALSE);
+
+      g_free (params);
+      gimp_value_array_unref (arguments);
+
+      proc_return.name    = proc_run->name;
+      proc_return.nparams = gimp_value_array_length (return_values);
+      proc_return.params  = _gimp_value_array_to_gp_params (return_values, TRUE);
+
+      gimp_value_array_unref (return_values);
+    }
+
+  if (! gp_temp_proc_return_write (_gimp_writechannel, &proc_return, NULL))
+    gimp_quit ();
+}
diff --git a/libgimp/gimplegacy.h b/libgimp/gimplegacy.h
index a714dd09c3..ad735ad4e8 100644
--- a/libgimp/gimplegacy.h
+++ b/libgimp/gimplegacy.h
@@ -27,6 +27,8 @@
 
 G_BEGIN_DECLS
 
+#ifndef GIMP_DISABLE_COMPAT_CRUFT
+
 
 /**
  * GimpInitProc:
@@ -265,6 +267,14 @@ void           gimp_uninstall_temp_proc (const gchar        *name);
  */
 void           gimp_extension_ack       (void);
 
+/* Enable asynchronous processing of temp_procs
+ */
+void           gimp_extension_enable    (void);
+
+/* Process one temp_proc and return
+ */
+void           gimp_extension_process   (guint            timeout);
+
 /* Run a procedure in the procedure database. The parameters are
  *  specified via the variable length argument list. The return
  *  values are returned in the 'GimpParam*' array.
@@ -317,6 +327,8 @@ gboolean   gimp_plugin_icon_register        (const gchar  *procedure_name,
                                              const guint8 *icon_data);
 
 
+#endif /* GIMP_DISABLE_COMPAT_CRUFT */
+
 G_END_DECLS
 
 #endif /* __GIMP_LEGACY_H__ */
diff --git a/libgimp/gimpplugin-private.c b/libgimp/gimpplugin-private.c
index 1a88a92190..0142cacf36 100644
--- a/libgimp/gimpplugin-private.c
+++ b/libgimp/gimpplugin-private.c
@@ -22,14 +22,23 @@
 #include "config.h"
 
 #include "gimp.h"
+
+#include "libgimpbase/gimpprotocol.h"
+
+#include "gimp-private.h"
+#include "gimpgpparams.h"
 #include "gimpplugin-private.h"
 #include "gimpprocedure-private.h"
 
 
 /*  local function prototpes  */
 
-static void   gimp_plug_in_register (GimpPlugIn *plug_in,
-                                     gboolean    init);
+static void   gimp_plug_in_register        (GimpPlugIn      *plug_in,
+                                            gboolean         init);
+static void   gimp_plug_in_process_message (GimpPlugIn      *plug_in,
+                                            GimpWireMessage *msg);
+static void   gimp_plug_in_temp_proc_run   (GimpPlugIn      *plug_in,
+                                            GPProcRun       *proc_run);
 
 
 /*  public functions  */
@@ -65,6 +74,18 @@ _gimp_plug_in_quit (GimpPlugIn *plug_in)
     GIMP_PLUG_IN_GET_CLASS (plug_in)->quit (plug_in);
 }
 
+gboolean
+_gimp_plug_in_extension_read (GIOChannel  *channel,
+                              GIOCondition condition,
+                              gpointer     data)
+{
+  GimpPlugIn *plug_in = data;
+
+  _gimp_plug_in_single_message (plug_in);
+
+  return G_SOURCE_CONTINUE;
+}
+
 
 /*  private functions  */
 
@@ -130,3 +151,88 @@ gimp_plug_in_register (GimpPlugIn *plug_in,
                                         branch->menu_label);
     }
 }
+
+void
+_gimp_plug_in_single_message (GimpPlugIn *plug_in)
+{
+  GimpWireMessage msg;
+
+  /* Run a temp function */
+  if (! gimp_wire_read_msg (_gimp_readchannel, &msg, NULL))
+    gimp_quit ();
+
+  gimp_plug_in_process_message (plug_in, &msg);
+
+  gimp_wire_destroy (&msg);
+}
+
+static void
+gimp_plug_in_process_message (GimpPlugIn      *plug_in,
+                              GimpWireMessage *msg)
+{
+  switch (msg->type)
+    {
+    case GP_QUIT:
+      gimp_quit ();
+      break;
+    case GP_CONFIG:
+      _gimp_config (msg->data);
+      break;
+    case GP_TILE_REQ:
+    case GP_TILE_ACK:
+    case GP_TILE_DATA:
+      g_warning ("unexpected tile message received (should not happen)");
+      break;
+    case GP_PROC_RUN:
+      g_warning ("unexpected proc run message received (should not happen)");
+      break;
+    case GP_PROC_RETURN:
+      g_warning ("unexpected proc return message received (should not happen)");
+      break;
+    case GP_TEMP_PROC_RUN:
+      gimp_plug_in_temp_proc_run (plug_in, msg->data);
+      break;
+    case GP_TEMP_PROC_RETURN:
+      g_warning ("unexpected temp proc return message received (should not happen)");
+      break;
+    case GP_PROC_INSTALL:
+      g_warning ("unexpected proc install message received (should not happen)");
+      break;
+    case GP_HAS_INIT:
+      g_warning ("unexpected has init message received (should not happen)");
+      break;
+    }
+}
+
+static void
+gimp_plug_in_temp_proc_run (GimpPlugIn *plug_in,
+                            GPProcRun  *proc_run)
+{
+  GPProcReturn   proc_return;
+  GimpProcedure *procedure;
+
+  procedure = gimp_plug_in_get_temp_procedure (plug_in, proc_run->name);
+
+  if (procedure)
+    {
+      GimpValueArray *arguments;
+      GimpValueArray *return_values = NULL;
+
+      arguments = _gimp_gp_params_to_value_array (NULL, 0,
+                                                  proc_run->params,
+                                                  proc_run->nparams,
+                                                  FALSE, FALSE);
+
+      return_values = gimp_procedure_run (procedure, arguments);
+      gimp_value_array_unref (arguments);
+
+      proc_return.name    = proc_run->name;
+      proc_return.nparams = gimp_value_array_length (return_values);
+      proc_return.params  = _gimp_value_array_to_gp_params (return_values, TRUE);
+
+      gimp_value_array_unref (return_values);
+    }
+
+  if (! gp_temp_proc_return_write (_gimp_writechannel, &proc_return, NULL))
+    gimp_quit ();
+}
diff --git a/libgimp/gimpplugin-private.h b/libgimp/gimpplugin-private.h
index af0ea851eb..910f0bc0d9 100644
--- a/libgimp/gimpplugin-private.h
+++ b/libgimp/gimpplugin-private.h
@@ -44,12 +44,19 @@ struct _GimpPlugInPrivate
   GList *menu_branches;
 
   GList *temp_procedures;
+
+  guint  extension_source_id;
 };
 
 
-void   _gimp_plug_in_init  (GimpPlugIn *plug_in);
-void   _gimp_plug_in_query (GimpPlugIn *plug_in);
-void   _gimp_plug_in_quit  (GimpPlugIn *plug_in);
+void       _gimp_plug_in_init           (GimpPlugIn  *plug_in);
+void       _gimp_plug_in_query          (GimpPlugIn  *plug_in);
+void       _gimp_plug_in_quit           (GimpPlugIn  *plug_in);
+
+gboolean   _gimp_plug_in_extension_read (GIOChannel  *channel,
+                                         GIOCondition condition,
+                                         gpointer     data);
+void       _gimp_plug_in_single_message (GimpPlugIn  *plug_in);
 
 
 G_END_DECLS
diff --git a/libgimp/gimpplugin.c b/libgimp/gimpplugin.c
index df42f9b717..445b646d91 100644
--- a/libgimp/gimpplugin.c
+++ b/libgimp/gimpplugin.c
@@ -21,9 +21,14 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <string.h>
 
 #include "gimp.h"
+
+#include "libgimpbase/gimpprotocol.h"
+
+#include "gimp-private.h"
 #include "gimpplugin-private.h"
 #include "gimpprocedure-private.h"
 
@@ -68,6 +73,12 @@ gimp_plug_in_finalize (GObject *object)
   GimpPlugIn *plug_in = GIMP_PLUG_IN (object);
   GList      *list;
 
+  if (plug_in->priv->extension_source_id)
+    {
+      g_source_remove (plug_in->priv->extension_source_id);
+      plug_in->priv->extension_source_id = 0;
+    }
+
   if (plug_in->priv->temp_procedures)
     {
       g_list_free_full (plug_in->priv->temp_procedures, g_object_unref);
@@ -250,9 +261,9 @@ gimp_plug_in_create_procedure (GimpPlugIn  *plug_in,
  * NOTE: Normally, plug-in communication is triggered by the plug-in
  * and the GIMP core only responds to the plug-in's requests. You must
  * explicitly enable receiving of temporary procedure run requests
- * using either gimp_extension_enable() or
- * gimp_extension_process(). See this functions' documentation for
- * details.
+ * using either gimp_plug_in_extension_enable() or
+ * gimp_plug_in_extension_process(). See this functions' documentation
+ * for details.
  *
  * Since: 3.0
  **/
@@ -353,3 +364,126 @@ gimp_plug_in_get_temp_procedure (GimpPlugIn  *plug_in,
 
   return NULL;
 }
+
+/**
+ * gimp_plug_in_extension_enable:
+ * @plug_in: A #GimpPlugIn
+ *
+ * Enables asynchronous processing of messages from the main GIMP
+ * application.
+ *
+ * Normally, a plug-in is not called by GIMP except for the call to
+ * the procedure it implements. All subsequent communication is
+ * triggered by the plug-in and all messages sent from GIMP to the
+ * plug-in are just answers to requests the plug-in made.
+ *
+ * If the plug-in however registered temporary procedures using
+ * gimp_plug_in_add_temp_procedure(), it needs to be able to receive
+ * requests to execute them. Usually this will be done by running
+ * gimp_plug_in_extension_process() in an endless loop.
+ *
+ * If the plug-in cannot use gimp_plug_in_extension_process(), i.e. if
+ * it has a GUI and is hanging around in a #GMainLoop, it must call
+ * gimp_plug_in_extension_enable().
+ *
+ * Note that the plug-in does not need to be a #GIMP_EXTENSION to
+ * register temporary procedures.
+ *
+ * See also: gimp_plug_in_add_temp_procedure().
+ *
+ * Since: 3.0
+ **/
+void
+gimp_plug_in_extension_enable (GimpPlugIn *plug_in)
+{
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+
+  if (! plug_in->priv->extension_source_id)
+    {
+      plug_in->priv->extension_source_id =
+        g_io_add_watch (_gimp_readchannel, G_IO_IN | G_IO_PRI,
+                        _gimp_plug_in_extension_read,
+                        plug_in);
+    }
+}
+
+/**
+ * gimp_plug_in_extension_process:
+ * @plug_in: A #GimpPlugIn.
+ * @timeout: The timeout (in ms) to use for the select() call.
+ *
+ * Processes one message sent by GIMP and returns.
+ *
+ * Call this function in an endless loop after calling
+ * gimp_plug_in_extension_ready() to process requests for running
+ * temporary procedures.
+ *
+ * See gimp_plug_in_extension_enable() for an asynchronous way of
+ * doing the same if running an endless loop is not an option.
+ *
+ * See also: gimp_plug_in_add_temp_procedure().
+ *
+ * Since: 3.0
+ **/
+void
+gimp_plug_in_extension_process (GimpPlugIn *plug_in,
+                                guint       timeout)
+{
+#ifndef G_OS_WIN32
+
+  gint select_val;
+
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+
+  do
+    {
+      fd_set readfds;
+      struct timeval  tv;
+      struct timeval *tvp;
+
+      if (timeout)
+        {
+          tv.tv_sec  = timeout / 1000;
+          tv.tv_usec = (timeout % 1000) * 1000;
+          tvp = &tv;
+        }
+      else
+        tvp = NULL;
+
+      FD_ZERO (&readfds);
+      FD_SET (g_io_channel_unix_get_fd (_gimp_readchannel), &readfds);
+
+      if ((select_val = select (FD_SETSIZE, &readfds, NULL, NULL, tvp)) > 0)
+        {
+          _gimp_plug_in_single_message (plug_in);
+        }
+      else if (select_val == -1 && errno != EINTR)
+        {
+          perror ("gimp_plug_in_extension_process");
+          gimp_quit ();
+        }
+    }
+  while (select_val == -1 && errno == EINTR);
+
+#else
+
+  /* Zero means infinite wait for us, but g_poll and
+   * g_io_channel_win32_poll use -1 to indicate
+   * infinite wait.
+   */
+  GPollFD pollfd;
+
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+
+  if (timeout == 0)
+    timeout = -1;
+
+  g_io_channel_win32_make_pollfd (_gimp_readchannel, G_IO_IN, &pollfd);
+
+  if (g_io_channel_win32_poll (&pollfd, 1, timeout) == 1)
+    {
+      _gimp_plug_in_single_message (plug_in);
+    }
+
+#endif
+}
diff --git a/libgimp/gimpplugin.h b/libgimp/gimpplugin.h
index c373770b44..3ae9fb44d9 100644
--- a/libgimp/gimpplugin.h
+++ b/libgimp/gimpplugin.h
@@ -159,6 +159,10 @@ GList         * gimp_plug_in_get_temp_procedures    (GimpPlugIn    *plug_in);
 GimpProcedure * gimp_plug_in_get_temp_procedure     (GimpPlugIn    *plug_in,
                                                      const gchar   *name);
 
+void            gimp_plug_in_extension_enable       (GimpPlugIn    *plug_in);
+void            gimp_plug_in_extension_process      (GimpPlugIn    *plug_in,
+                                                     guint          timeout);
+
 
 G_END_DECLS
 
diff --git a/plug-ins/common/goat-exercise.c b/plug-ins/common/goat-exercise.c
index 712fc55696..e78e782bde 100644
--- a/plug-ins/common/goat-exercise.c
+++ b/plug-ins/common/goat-exercise.c
@@ -19,6 +19,8 @@
 
 #include "config.h"
 
+#define GIMP_DISABLE_COMPAR_CRUFT
+
 #include <libgimp/gimp.h>
 #include <libgimp/gimpui.h>
 
diff --git a/plug-ins/help/help.c b/plug-ins/help/help.c
index 7d697d2f90..0f557669fc 100644
--- a/plug-ins/help/help.c
+++ b/plug-ins/help/help.c
@@ -26,6 +26,8 @@
 
 #include <glib.h>
 
+#define GIMP_DISABLE_COMPAT_CRUFT
+
 #include "libgimp/gimp.h"
 
 #include "gimphelp.h"
@@ -206,7 +208,7 @@ help_run (GimpProcedure        *procedure,
       help_temp_proc_install (plug_in);
 
       gimp_procedure_extension_ready (procedure);
-      gimp_extension_enable ();
+      gimp_plug_in_extension_enable (plug_in);
 
       g_main_loop_run (main_loop);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]