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.
This commit is contained in:
Michael Natterer 2019-08-02 11:06:48 +02:00
parent 19fbb1d9a8
commit 5f8d0ef27b
11 changed files with 541 additions and 262 deletions

View File

@ -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);

View File

@ -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)
{

View File

@ -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.
*

View File

@ -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 ();
}

View File

@ -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__ */

View File

@ -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 ();
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -19,6 +19,8 @@
#include "config.h"
#define GIMP_DISABLE_COMPAR_CRUFT
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

View File

@ -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);