[gimp/wip/Jehan/classy-GIMP: 15/17] app, libgimp: add some first concept of signalling to plug-ins.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/Jehan/classy-GIMP: 15/17] app, libgimp: add some first concept of signalling to plug-ins.
- Date: Thu, 15 Aug 2019 22:33:03 +0000 (UTC)
commit 10de031f1df8fb70264821c5e900992ef1a50c11
Author: Jehan <jehan girinstud io>
Date: Thu Aug 15 21:55:36 2019 +0200
app, libgimp: add some first concept of signalling to plug-ins.
This is still an early PoC, and so far I have only implemented a
"destroyed" signal on libgimp's GimpImage. This way, plug-ins can react
on destroyed images instead of crashing.
When going further, we will want to allow more complex signals with
parameters and returned values, just like for procedure. This is similar
to have standard procedures which any plug-in can hook on through
GObject signals.
app/core/gimpimage.c | 6 +++
app/plug-in/gimpplugin-message.c | 9 +++++
app/plug-in/gimpplugin.c | 32 +++++++++++++++
app/plug-in/gimpplugin.h | 4 ++
app/plug-in/gimppluginmanager.c | 12 ++++++
app/plug-in/gimppluginmanager.h | 5 +++
libgimp/gimpdisplay.c | 23 +++++++++++
libgimp/gimpdisplay.h | 5 +++
libgimp/gimpimage.c | 61 +++++++++++++++++++++++++++-
libgimp/gimpimage.h | 9 +++++
libgimp/gimpitem.c | 26 ++++++++++++
libgimp/gimpitem.h | 6 +++
libgimp/gimplegacy.c | 7 ++++
libgimp/gimpplugin-private.c | 37 +++++++++++++++++
libgimpbase/gimpprotocol.c | 87 ++++++++++++++++++++++++++++++++++++++++
libgimpbase/gimpprotocol.h | 22 +++++++++-
16 files changed, 349 insertions(+), 2 deletions(-)
---
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 379d327ce3..e06c44dbd8 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -36,6 +36,8 @@
#include "operations/layer-modes/gimp-layer-modes.h"
+#include "plug-in/gimppluginmanager.h"
+
#include "gegl/gimp-babl.h"
#include "gimp.h"
@@ -1039,6 +1041,10 @@ gimp_image_finalize (GObject *object)
g_clear_object (&private->graph);
private->visible_mask = NULL;
+ gimp_plug_in_manager_emit_signal (image->gimp->plug_in_manager,
+ object, gimp_image_get_ID (image),
+ "destroyed");
+
if (private->colormap)
gimp_image_colormap_free (image);
diff --git a/app/plug-in/gimpplugin-message.c b/app/plug-in/gimpplugin-message.c
index 6aecb72d84..8144994003 100644
--- a/app/plug-in/gimpplugin-message.c
+++ b/app/plug-in/gimpplugin-message.c
@@ -160,6 +160,15 @@ gimp_plug_in_handle_message (GimpPlugIn *plug_in,
case GP_HAS_INIT:
gimp_plug_in_handle_has_init (plug_in);
break;
+
+ case GP_SIGNAL:
+ gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
+ "Plug-in \"%s\"\n(%s)\n\n"
+ "sent a SIGNAL message. This should not happen.",
+ gimp_object_get_name (plug_in),
+ gimp_file_get_utf8_name (plug_in->file));
+ gimp_plug_in_close (plug_in, TRUE);
+ break;
}
}
diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c
index 908e6a69d5..ee51dd3fb3 100644
--- a/app/plug-in/gimpplugin.c
+++ b/app/plug-in/gimpplugin.c
@@ -75,6 +75,8 @@
#include "plug-in-types.h"
#include "core/gimp.h"
+#include "core/gimpimage.h"
+#include "core/gimpitem.h"
#include "core/gimp-spawn.h"
#include "core/gimpprogress.h"
@@ -1044,3 +1046,33 @@ gimp_plug_in_get_error_handler (GimpPlugIn *plug_in)
return GIMP_PDB_ERROR_HANDLER_INTERNAL;
}
+
+void
+gimp_plug_in_emit_signal (GimpPlugIn *plug_in,
+ GObject *object,
+ gint32 id,
+ const gchar *name)
+{
+ if (plug_in->open)
+ {
+ GPSignalType type = GP_SIGNAL_TYPE_NONE;
+
+ if (GIMP_IS_IMAGE (object))
+ type = GP_SIGNAL_TYPE_IMAGE;
+ else if (GIMP_IS_ITEM (object))
+ type = GP_SIGNAL_TYPE_ITEM;
+ else if (g_strcmp0 (G_OBJECT_TYPE_NAME (object), "GimpDisplay") == 0)
+ type = GP_SIGNAL_TYPE_DISPLAY;
+
+ if (type != GP_SIGNAL_TYPE_NONE)
+ {
+ GPSignal signal;
+
+ signal.type = type;
+ signal.id = id;
+ signal.name = (gchar *) name;
+
+ gp_signal_write (plug_in->my_write, &signal, plug_in);
+ }
+ }
+}
diff --git a/app/plug-in/gimpplugin.h b/app/plug-in/gimpplugin.h
index 2cd3756467..82a6a51b11 100644
--- a/app/plug-in/gimpplugin.h
+++ b/app/plug-in/gimpplugin.h
@@ -119,5 +119,9 @@ void gimp_plug_in_set_error_handler (GimpPlugIn *plug_in,
GimpPDBErrorHandler
gimp_plug_in_get_error_handler (GimpPlugIn *plug_in);
+void gimp_plug_in_emit_signal (GimpPlugIn *plug_in,
+ GObject *object,
+ gint32 id,
+ const gchar *name);
#endif /* __GIMP_PLUG_IN_H__ */
diff --git a/app/plug-in/gimppluginmanager.c b/app/plug-in/gimppluginmanager.c
index d8952a289f..e9479d4ffa 100644
--- a/app/plug-in/gimppluginmanager.c
+++ b/app/plug-in/gimppluginmanager.c
@@ -424,3 +424,15 @@ gimp_plug_in_manager_plug_in_pop (GimpPlugInManager *manager)
else
manager->current_plug_in = NULL;
}
+
+void
+gimp_plug_in_manager_emit_signal (GimpPlugInManager *manager,
+ GObject *object,
+ gint32 id,
+ const gchar *name)
+{
+ GSList *iter = manager->open_plug_ins;
+
+ for (; iter; iter = iter->next)
+ gimp_plug_in_emit_signal (iter->data, object, id, name);
+}
diff --git a/app/plug-in/gimppluginmanager.h b/app/plug-in/gimppluginmanager.h
index 11f80b120f..1192083d7b 100644
--- a/app/plug-in/gimppluginmanager.h
+++ b/app/plug-in/gimppluginmanager.h
@@ -114,5 +114,10 @@ void gimp_plug_in_manager_plug_in_push (GimpPlugInManager *manager,
GimpPlugIn *plug_in);
void gimp_plug_in_manager_plug_in_pop (GimpPlugInManager *manager);
+void gimp_plug_in_manager_emit_signal (GimpPlugInManager *manager,
+ GObject *object,
+ gint32 id,
+ const gchar *name);
+
#endif /* __GIMP_PLUG_IN_MANAGER_H__ */
diff --git a/libgimp/gimpdisplay.c b/libgimp/gimpdisplay.c
index 419fd59074..7c1fbbec0a 100644
--- a/libgimp/gimpdisplay.c
+++ b/libgimp/gimpdisplay.c
@@ -183,3 +183,26 @@ gimp_display_get_by_id (gint32 display_id)
return display;
}
+
+
+/* Internal API. */
+
+
+G_GNUC_INTERNAL
+void
+_gimp_display_process_signal (gint32 display_id,
+ const gchar *name)
+{
+ GimpDisplay *display = NULL;
+
+ if (! gimp_displays)
+ return;
+
+ display = g_hash_table_lookup (gimp_displays,
+ GINT_TO_POINTER (display_id));
+
+ if (! display)
+ return;
+
+ /* Below process display signals. */
+}
diff --git a/libgimp/gimpdisplay.h b/libgimp/gimpdisplay.h
index 7abfb0b053..1709e4407c 100644
--- a/libgimp/gimpdisplay.h
+++ b/libgimp/gimpdisplay.h
@@ -70,6 +70,11 @@ gint32 gimp_display_get_id (GimpDisplay *display);
GimpDisplay * gimp_display_get_by_id (gint32 display_id);
+G_GNUC_INTERNAL
+void _gimp_display_process_signal (gint32 display_id,
+ const gchar *name);
+
+
G_END_DECLS
#endif /* __GIMP_DISPLAY_H__ */
diff --git a/libgimp/gimpimage.c b/libgimp/gimpimage.c
index b3cc11686a..7355ac7ceb 100644
--- a/libgimp/gimpimage.c
+++ b/libgimp/gimpimage.c
@@ -24,6 +24,12 @@
#include "gimppixbuf.h"
+enum
+{
+ DESTROYED,
+ LAST_SIGNAL
+};
+
enum
{
PROP_0,
@@ -52,7 +58,8 @@ G_DEFINE_TYPE_WITH_PRIVATE (GimpImage, gimp_image, G_TYPE_OBJECT)
#define parent_class gimp_image_parent_class
-static GParamSpec *props[N_PROPS] = { NULL, };
+static GParamSpec *props[N_PROPS] = { NULL, };
+static guint signals[LAST_SIGNAL] = { 0 };
static void
gimp_image_class_init (GimpImageClass *klass)
@@ -62,6 +69,26 @@ gimp_image_class_init (GimpImageClass *klass)
object_class->set_property = gimp_image_set_property;
object_class->get_property = gimp_image_get_property;
+ /**
+ * GimpImageClass::destroy:
+ * @image: a #GimpImage
+ *
+ * This signal will be emitted when an image has been destroyed, just
+ * before we g_object_unref() it. This image is now invalid, none of
+ * its data can be accessed anymore, therefore all processing has to
+ * be stopped immediately.
+ * The only thing still feasible is to compare the image if you kept a
+ * reference to identify images, or to run gimp_image_get_id().
+ */
+ signals[DESTROYED] =
+ g_signal_new ("destroyed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpImageClass, destroyed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
props[PROP_ID] =
g_param_spec_int ("id",
"The image id",
@@ -511,6 +538,38 @@ gimp_image_set_metadata (GimpImage *image,
}
+/* Internal API. */
+
+
+void
+_gimp_image_process_signal (gint32 image_id,
+ const gchar *name)
+{
+ GimpImage *image = NULL;
+
+ if (! gimp_images)
+ return;
+
+ image = g_hash_table_lookup (gimp_images,
+ GINT_TO_POINTER (image_id));
+
+ if (! image)
+ /* No need to create images not referenced by the plug-in. */
+ return;
+
+ /* Below process image signals. */
+
+ if (g_strcmp0 (name, "destroyed") == 0)
+ {
+ g_hash_table_steal (gimp_images,
+ GINT_TO_POINTER (image->priv->id));
+
+ g_signal_emit (image, signals[DESTROYED], 0);
+ g_object_unref (image);
+ }
+}
+
+
/* Deprecated API. */
diff --git a/libgimp/gimpimage.h b/libgimp/gimpimage.h
index d63c5a4f74..cdec1f5882 100644
--- a/libgimp/gimpimage.h
+++ b/libgimp/gimpimage.h
@@ -51,6 +51,9 @@ struct _GimpImageClass
{
GObjectClass parent_class;
+ /* Signals. */
+ void (* destroyed) (GimpImage *image);
+
/* Padding for future expansion */
void (*_gimp_reserved1) (void);
void (*_gimp_reserved2) (void);
@@ -70,6 +73,12 @@ GimpImage * gimp_image_get_by_id (gint32 image_id);
GList * gimp_image_list (void);
+
+G_GNUC_INTERNAL
+void _gimp_image_process_signal (gint32 image_id,
+ const gchar *name);
+
+
#ifndef GIMP_DEPRECATED_REPLACE_NEW_API
GList * gimp_image_get_layers (GimpImage *image);
diff --git a/libgimp/gimpitem.c b/libgimp/gimpitem.c
index addde8a1bc..066fb2a368 100644
--- a/libgimp/gimpitem.c
+++ b/libgimp/gimpitem.c
@@ -243,6 +243,32 @@ gimp_item_get_children (GimpItem *item)
return children;
}
+
+/* Internal API. */
+
+
+void
+_gimp_item_process_signal (gint32 item_id,
+ const gchar *name)
+{
+ GimpItem *item = NULL;
+
+ if (! gimp_items)
+ return;
+
+ item = g_hash_table_lookup (gimp_items,
+ GINT_TO_POINTER (item_id));
+
+ if (! item)
+ return;
+
+ /* Below process item signals. */
+}
+
+
+/* Deprecated API. */
+
+
/**
* gimp_item_get_children_deprecated: (skip)
* @item_id: The item.
diff --git a/libgimp/gimpitem.h b/libgimp/gimpitem.h
index 0013e3e6eb..3d948e955f 100644
--- a/libgimp/gimpitem.h
+++ b/libgimp/gimpitem.h
@@ -69,6 +69,12 @@ GType gimp_item_get_type (void) G_GNUC_CONST;
gint32 gimp_item_get_id (GimpItem *item);
GimpItem * gimp_item_get_by_id (gint32 item_id);
+
+G_GNUC_INTERNAL
+void _gimp_item_process_signal (gint32 item_id,
+ const gchar *name);
+
+
#ifndef GIMP_DEPRECATED_REPLACE_NEW_API
GList * gimp_item_get_children (GimpItem *item);
diff --git a/libgimp/gimplegacy.c b/libgimp/gimplegacy.c
index ffb48095c9..ed3ee94641 100644
--- a/libgimp/gimplegacy.c
+++ b/libgimp/gimplegacy.c
@@ -677,6 +677,10 @@ gimp_loop (GimpRunProc run_proc)
case GP_HAS_INIT:
g_warning ("unexpected has init message received (should not happen)");
break;
+
+ case GP_SIGNAL:
+ g_warning ("unexpected signal message received (should not happen)");
+ break;
}
gimp_wire_destroy (&msg);
@@ -717,6 +721,9 @@ gimp_process_message (GimpWireMessage *msg)
case GP_HAS_INIT:
g_warning ("unexpected has init message received (should not happen)");
break;
+ case GP_SIGNAL:
+ g_warning ("signal message received; not supported with legacy API");
+ break;
}
}
diff --git a/libgimp/gimpplugin-private.c b/libgimp/gimpplugin-private.c
index 3366831bf5..31c50adeec 100644
--- a/libgimp/gimpplugin-private.c
+++ b/libgimp/gimpplugin-private.c
@@ -42,6 +42,9 @@ static void gimp_plug_in_register (GimpPlugIn *plug_in,
static void gimp_plug_in_loop (GimpPlugIn *plug_in);
static void gimp_plug_in_process_message (GimpPlugIn *plug_in,
GimpWireMessage *msg);
+
+static void gimp_plug_in_signal (GimpPlugIn *plug_in,
+ GPSignal *signal);
static void gimp_plug_in_proc_run (GimpPlugIn *plug_in,
GPProcRun *proc_run);
static void gimp_plug_in_temp_proc_run (GimpPlugIn *plug_in,
@@ -148,6 +151,11 @@ _gimp_plug_in_read_expect_msg (GimpPlugIn *plug_in,
{
gimp_plug_in_process_message (plug_in, msg);
}
+ else if (msg->type == GP_SIGNAL)
+ {
+ gimp_plug_in_signal (plug_in, msg->data);
+ continue;
+ }
else
{
g_error ("unexpected message: %d", msg->type);
@@ -279,6 +287,10 @@ gimp_plug_in_loop (GimpPlugIn *plug_in)
case GP_HAS_INIT:
g_warning ("unexpected has init message received (should not happen)");
break;
+
+ case GP_SIGNAL:
+ g_warning ("unexpected signal message received (should not happen)");
+ break;
}
gimp_wire_destroy (&msg);
@@ -334,6 +346,31 @@ gimp_plug_in_process_message (GimpPlugIn *plug_in,
case GP_HAS_INIT:
g_warning ("unexpected has init message received (should not happen)");
break;
+ case GP_SIGNAL:
+ gimp_plug_in_signal (plug_in, msg->data);
+ break;
+ }
+}
+
+static void
+gimp_plug_in_signal (GimpPlugIn *plug_in,
+ GPSignal *signal)
+{
+ switch (signal->type)
+ {
+ case GP_SIGNAL_TYPE_IMAGE:
+ _gimp_image_process_signal (signal->id, signal->name);
+ break;
+ case GP_SIGNAL_TYPE_ITEM:
+ _gimp_item_process_signal (signal->id, signal->name);
+ break;
+ case GP_SIGNAL_TYPE_DISPLAY:
+ _gimp_display_process_signal (signal->id, signal->name);
+ break;
+
+ case GP_SIGNAL_TYPE_NONE:
+ g_warning ("Unexpected signal without type received (should not happen)");
+ break;
}
}
diff --git a/libgimpbase/gimpprotocol.c b/libgimpbase/gimpprotocol.c
index 3add813851..ae0affd3d5 100644
--- a/libgimpbase/gimpprotocol.c
+++ b/libgimpbase/gimpprotocol.c
@@ -144,6 +144,13 @@ static void _gp_has_init_write (GIOChannel *channel,
gpointer user_data);
static void _gp_has_init_destroy (GimpWireMessage *msg);
+static void _gp_signal_read (GIOChannel *channel,
+ GimpWireMessage *msg,
+ gpointer user_data);
+static void _gp_signal_write (GIOChannel *channel,
+ GimpWireMessage *msg,
+ gpointer user_data);
+static void _gp_signal_destroy (GimpWireMessage *msg);
void
@@ -201,6 +208,10 @@ gp_init (void)
_gp_has_init_read,
_gp_has_init_write,
_gp_has_init_destroy);
+ gimp_wire_register (GP_SIGNAL,
+ _gp_signal_read,
+ _gp_signal_write,
+ _gp_signal_destroy);
}
/* public writing API */
@@ -448,6 +459,25 @@ gp_has_init_write (GIOChannel *channel,
return TRUE;
}
+gboolean
+gp_signal_write (GIOChannel *channel,
+ GPSignal *signal,
+ gpointer user_data)
+{
+ GimpWireMessage msg;
+
+ msg.type = GP_SIGNAL;
+ msg.data = signal;
+
+ if (! gimp_wire_write_msg (channel, &msg, user_data))
+ return FALSE;
+
+ if (! gimp_wire_flush (channel, user_data))
+ return FALSE;
+
+ return TRUE;
+}
+
/* quit */
static void
@@ -1953,3 +1983,60 @@ static void
_gp_has_init_destroy (GimpWireMessage *msg)
{
}
+
+static void
+_gp_signal_read (GIOChannel *channel,
+ GimpWireMessage *msg,
+ gpointer user_data)
+{
+ GPSignal *signal = g_slice_new0 (GPSignal);
+
+ if (! _gimp_wire_read_int32 (channel,
+ &signal->type, 1, user_data))
+ goto cleanup;
+ if (! _gimp_wire_read_int32 (channel,
+ &signal->id, 1, user_data))
+ goto cleanup;
+ if (! _gimp_wire_read_string (channel,
+ &signal->name, 1, user_data))
+ goto cleanup;
+
+ msg->data = signal;
+ return;
+
+ cleanup:
+ g_clear_pointer (&signal->name, g_free);
+
+ g_slice_free (GPSignal, signal);
+ msg->data = NULL;
+}
+
+static void
+_gp_signal_write (GIOChannel *channel,
+ GimpWireMessage *msg,
+ gpointer user_data)
+{
+ GPSignal *signal = msg->data;
+
+ if (! _gimp_wire_write_int32 (channel,
+ &signal->type, 1, user_data))
+ return;
+ if (! _gimp_wire_write_int32 (channel,
+ &signal->id, 1, user_data))
+ return;
+ if (! _gimp_wire_write_string (channel,
+ &signal->name, 1, user_data))
+ return;
+}
+
+static void
+_gp_signal_destroy (GimpWireMessage *msg)
+{
+ GPSignal *signal = msg->data;
+
+ if (signal)
+ {
+ g_free (signal->name);
+ g_slice_free (GPSignal, signal);
+ }
+}
diff --git a/libgimpbase/gimpprotocol.h b/libgimpbase/gimpprotocol.h
index effb494616..13fda1ac6b 100644
--- a/libgimpbase/gimpprotocol.h
+++ b/libgimpbase/gimpprotocol.h
@@ -43,7 +43,8 @@ enum
GP_PROC_INSTALL,
GP_PROC_UNINSTALL,
GP_EXTENSION_ACK,
- GP_HAS_INIT
+ GP_HAS_INIT,
+ GP_SIGNAL
};
typedef enum
@@ -72,6 +73,14 @@ typedef enum
GP_PARAM_TYPE_PARAM_DEF
} GPParamType;
+typedef enum
+{
+ GP_SIGNAL_TYPE_NONE,
+ GP_SIGNAL_TYPE_IMAGE,
+ GP_SIGNAL_TYPE_ITEM,
+ GP_SIGNAL_TYPE_DISPLAY
+} GPSignalType;
+
typedef struct _GPConfig GPConfig;
typedef struct _GPTileReq GPTileReq;
@@ -94,6 +103,7 @@ typedef struct _GPProcRun GPProcRun;
typedef struct _GPProcReturn GPProcReturn;
typedef struct _GPProcInstall GPProcInstall;
typedef struct _GPProcUninstall GPProcUninstall;
+typedef struct _GPSignal GPSignal;
struct _GPConfig
@@ -286,6 +296,13 @@ struct _GPProcUninstall
gchar *name;
};
+struct _GPSignal
+{
+ GPSignalType type;
+ guint32 id;
+ gchar *name;
+
+};
void gp_init (void);
@@ -324,6 +341,9 @@ gboolean gp_extension_ack_write (GIOChannel *channel,
gpointer user_data);
gboolean gp_has_init_write (GIOChannel *channel,
gpointer user_data);
+gboolean gp_signal_write (GIOChannel *channel,
+ GPSignal *signal,
+ gpointer user_data);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]