[gegl/wip/Jehan/gegl_node_process_success] gegl: new gegl_node_process_success() function.



commit 447c4d6a998e18d3731f4dc146bb13f0765bdbe0
Author: Jehan <jehan girinstud io>
Date:   Fri Mar 22 19:08:49 2019 +0100

    gegl: new gegl_node_process_success() function.
    
    gegl_node_process_success() returns TRUE if the last call of
    gegl_node_process(), gegl_node_blit() or gegl_node_blit_buffer() was a
    success.
    This will also return the success from a call to gegl_processor_work() if
    you use the node given to gegl_node_new_processor() as argument.
    
    Additionally in case of process failure, a GError is returned, allowing
    calling applications to process failure appropriately.
    To make usage of this new possibility, GeglOperation subclass should
    implement the new virtual method process2() (same as process() with the
    added GError parameter).
    
    A similar virtual method process2() was added to various GeglOperation
    families (GeglOperationSink, GeglOperationSource, GeglOperationTemporal,
    GeglOperation*Composer(3), GeglOperation*Filter and
    GelOperationPointRender).

 gegl/graph/gegl-node-private.h                 |  3 +
 gegl/graph/gegl-node.c                         | 21 ++++++
 gegl/graph/gegl-node.h                         | 16 +++++
 gegl/operation/gegl-operation-composer.c       | 40 +++++++----
 gegl/operation/gegl-operation-composer.h       | 21 ++++--
 gegl/operation/gegl-operation-composer3.c      | 43 ++++++++----
 gegl/operation/gegl-operation-composer3.h      | 24 ++++---
 gegl/operation/gegl-operation-filter.c         | 37 ++++++----
 gegl/operation/gegl-operation-filter.h         |  6 ++
 gegl/operation/gegl-operation-point-composer.c | 94 ++++++++++++++++++-------
 gegl/operation/gegl-operation-point-composer.h | 22 ++++--
 gegl/operation/gegl-operation-point-filter.c   | 96 ++++++++++++++++++--------
 gegl/operation/gegl-operation-point-filter.h   | 25 ++++---
 gegl/operation/gegl-operation-point-render.c   | 26 ++++---
 gegl/operation/gegl-operation-point-render.h   | 18 +++--
 gegl/operation/gegl-operation-sink.c           | 33 ++++++---
 gegl/operation/gegl-operation-sink.h           | 17 +++--
 gegl/operation/gegl-operation-source.c         | 40 +++++++----
 gegl/operation/gegl-operation-source.h         | 17 +++--
 gegl/operation/gegl-operation-temporal.c       | 17 +++--
 gegl/operation/gegl-operation-temporal.h       | 18 +++--
 gegl/operation/gegl-operation.c                | 35 ++++++++--
 gegl/operation/gegl-operation.h                | 13 ++++
 gegl/process/gegl-eval-manager.c               |  4 +-
 gegl/process/gegl-graph-traversal.c            | 35 +++++++---
 gegl/process/gegl-graph-traversal.h            |  3 +-
 gegl/process/gegl-processor.c                  | 14 ++--
 27 files changed, 529 insertions(+), 209 deletions(-)
---
diff --git a/gegl/graph/gegl-node-private.h b/gegl/graph/gegl-node-private.h
index 21d127dd7..2ea3b0c0e 100644
--- a/gegl/graph/gegl-node-private.h
+++ b/gegl/graph/gegl-node-private.h
@@ -91,6 +91,9 @@ struct _GeglNode
 
   gint            passthrough;
 
+  gboolean        success;
+  GError         *error;
+
   /*< private >*/
   GeglNodePrivate *priv;
 };
diff --git a/gegl/graph/gegl-node.c b/gegl/graph/gegl-node.c
index 80152605f..9a962fab3 100644
--- a/gegl/graph/gegl-node.c
+++ b/gegl/graph/gegl-node.c
@@ -239,6 +239,8 @@ gegl_node_init (GeglNode *self)
   self->is_graph         = FALSE;
   self->cache            = NULL;
   self->output_visitable = gegl_node_output_visitable_new (self);
+  self->success          = FALSE;
+  self->error            = NULL;
   g_mutex_init (&self->mutex);
 
 }
@@ -288,6 +290,7 @@ gegl_node_finalize (GObject *gobject)
   g_clear_object (&self->output_visitable);
   g_free (self->priv->name);
   g_free (self->priv->debug_name);
+  g_clear_error (&self->error);
 
   g_mutex_clear (&self->mutex);
 
@@ -1850,6 +1853,24 @@ gegl_node_process (GeglNode *self) /* XXX: add level argument?  */
   g_object_unref (processor);
 }
 
+gboolean
+gegl_node_process_success (GeglNode  *self,
+                           GError   **error)
+{
+  GeglNode *real_node;
+
+  /* If @self is a graph, the error will be set on its output proxy. */
+  if (GEGL_IS_OPERATION (self->operation))
+    real_node = self;
+  else
+    real_node = gegl_node_get_output_proxy (self, "output");
+
+  if (error && ! real_node->success && real_node->error)
+    *error = g_error_copy (real_node->error);
+
+  return real_node->success;
+}
+
 GeglNode *
 gegl_node_detect (GeglNode *root,
                   gint      x,
diff --git a/gegl/graph/gegl-node.h b/gegl/graph/gegl-node.h
index 6eca2cfb9..8d63df977 100644
--- a/gegl/graph/gegl-node.h
+++ b/gegl/graph/gegl-node.h
@@ -342,6 +342,22 @@ void          gegl_node_blit_buffer      (GeglNode            *node,
  */
 void          gegl_node_process          (GeglNode      *sink_node);
 
+/**
+ * gegl_node_process_success:
+ * @node: a #GeglNode.
+ * @error: (out): an optional error string.
+ *
+ * Returns: TRUE is the last call to gegl_node_process(), gegl_node_blit() or
+ * gegl_node_blit_buffer() on @node was a success, FALSE otherwise.
+ *
+ * This will also return the success from a call to gegl_processor_work() if
+ * you use the node given to gegl_node_new_processor().
+ *
+ * In case of failure and if @error was not NULL, a copy of the error string
+ * will be allocated.
+ */
+gboolean      gegl_node_process_success  (GeglNode      *node,
+                                          GError       **error);
 
 /***
  * Reparenting:
diff --git a/gegl/operation/gegl-operation-composer.c b/gegl/operation/gegl-operation-composer.c
index 526d40b23..91073ae68 100644
--- a/gegl/operation/gegl-operation-composer.c
+++ b/gegl/operation/gegl-operation-composer.c
@@ -26,11 +26,12 @@
 #include "gegl-operation-context.h"
 #include "gegl-config.h"
 
-static gboolean gegl_operation_composer_process (GeglOperation       *operation,
+static gboolean gegl_operation_composer_process2 (GeglOperation       *operation,
                               GeglOperationContext     *context,
                               const gchar         *output_prop,
                               const GeglRectangle *result,
-                              gint                 level);
+                              gint                 level,
+                              GError             **error);
 static void     attach       (GeglOperation       *operation);
 static GeglNode*detect       (GeglOperation       *operation,
                               gint                 x,
@@ -50,7 +51,7 @@ gegl_operation_composer_class_init (GeglOperationComposerClass * klass)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
 
-  operation_class->process = gegl_operation_composer_process;
+  operation_class->process2 = gegl_operation_composer_process2;
   operation_class->threaded = TRUE;
   operation_class->attach = attach;
   operation_class->detect = detect;
@@ -108,6 +109,7 @@ typedef struct ThreadData
   const GeglRectangle        *roi;
   gint                        level;
   gboolean                    success;
+  GError                    **error;
 } ThreadData;
 
 static void
@@ -115,6 +117,7 @@ thread_process (const GeglRectangle *area,
                 ThreadData          *data)
 {
   GeglBuffer *input;
+  gboolean    success = TRUE;
 
   if (area->x == data->roi->x && area->y == data->roi->y)
     {
@@ -126,20 +129,27 @@ thread_process (const GeglRectangle *area,
                                                            "input", area);
     }
 
-  if (!data->klass->process (data->operation,
-                             input, data->aux, data->output,
-                             area, data->level))
+  if (data->klass->process2)
+    success = data->klass->process2 (data->operation,
+                                     input, data->aux, data->output,
+                                     area, data->level, data->error);
+  else
+    success = data->klass->process (data->operation,
+                                    input, data->aux, data->output,
+                                    area, data->level);
+  if (! success)
     data->success = FALSE;
 
   g_object_unref (input);
 }
 
 static gboolean
-gegl_operation_composer_process (GeglOperation        *operation,
-                                 GeglOperationContext *context,
-                                 const gchar          *output_prop,
-                                 const GeglRectangle  *result,
-                                 gint                  level)
+gegl_operation_composer_process2 (GeglOperation        *operation,
+                                  GeglOperationContext *context,
+                                  const gchar          *output_prop,
+                                  const GeglRectangle  *result,
+                                  gint                  level,
+                                  GError              **error)
 {
   GeglOperationComposerClass *klass   = GEGL_OPERATION_COMPOSER_GET_CLASS (operation);
   GeglBuffer                 *input;
@@ -179,6 +189,7 @@ gegl_operation_composer_process (GeglOperation        *operation,
         data.roi = result;
         data.level = level;
         data.success = TRUE;
+        data.error = error;
 
         gegl_parallel_distribute_area (
           result,
@@ -191,7 +202,12 @@ gegl_operation_composer_process (GeglOperation        *operation,
       }
       else
       {
-        success = klass->process (operation, input, aux, output, result, level);
+        if (klass->process2)
+          success = klass->process2 (operation, input, aux, output,
+                                     result, level, error);
+        else
+          success = klass->process (operation, input, aux, output,
+                                    result, level);
       }
 
       g_clear_object (&input);
diff --git a/gegl/operation/gegl-operation-composer.h b/gegl/operation/gegl-operation-composer.h
index 783498610..cb0fac606 100644
--- a/gegl/operation/gegl-operation-composer.h
+++ b/gegl/operation/gegl-operation-composer.h
@@ -46,13 +46,20 @@ struct _GeglOperationComposerClass
 {
   GeglOperationClass parent_class;
 
-  gboolean (* process) (GeglOperation       *self,
-                        GeglBuffer          *input,
-                        GeglBuffer          *aux,
-                        GeglBuffer          *output,
-                        const GeglRectangle *result,
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *aux,
+                         GeglBuffer          *output,
+                         const GeglRectangle *result,
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *aux,
+                         GeglBuffer          *output,
+                         const GeglRectangle *result,
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType gegl_operation_composer_get_type (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation-composer3.c b/gegl/operation/gegl-operation-composer3.c
index 91691ee47..0fe09a1b4 100644
--- a/gegl/operation/gegl-operation-composer3.c
+++ b/gegl/operation/gegl-operation-composer3.c
@@ -26,12 +26,13 @@
 #include "gegl-operation-context.h"
 #include "gegl-config.h"
 
-static gboolean gegl_operation_composer3_process
+static gboolean gegl_operation_composer3_process2
 (GeglOperation        *operation,
  GeglOperationContext *context,
  const gchar          *output_prop,
  const GeglRectangle  *result,
- gint                  level);
+ gint                  level,
+ GError             **error);
 static void     attach       (GeglOperation        *operation);
 static GeglNode*detect       (GeglOperation        *operation,
     gint                  x,
@@ -51,7 +52,7 @@ gegl_operation_composer3_class_init (GeglOperationComposer3Class * klass)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
 
-  operation_class->process = gegl_operation_composer3_process;
+  operation_class->process2 = gegl_operation_composer3_process2;
   operation_class->attach = attach;
   operation_class->detect = detect;
   operation_class->get_bounding_box = get_bounding_box;
@@ -118,6 +119,7 @@ typedef struct ThreadData
   const GeglRectangle         *roi;
   gint                         level;
   gboolean                     success;
+  GError                     **error;
 } ThreadData;
 
 static void
@@ -125,6 +127,7 @@ thread_process (const GeglRectangle *area,
                 ThreadData          *data)
 {
   GeglBuffer *input;
+  gboolean    success = TRUE;
 
   if (area->x == data->roi->x && area->y == data->roi->y)
     {
@@ -136,21 +139,29 @@ thread_process (const GeglRectangle *area,
                                                            "input", area);
     }
 
-  if (!data->klass->process (data->operation,
-                             input, data->aux, data->aux2, 
-                             data->output, area, data->level))
+  if (data->klass->process2)
+    success = data->klass->process2 (data->operation,
+                                     input, data->aux, data->aux2,
+                                     data->output, area, data->level,
+                                     data->error);
+  else
+    success = data->klass->process (data->operation,
+                                    input, data->aux, data->aux2,
+                                    data->output, area, data->level);
+  if (! success)
     data->success = FALSE;
 
   g_object_unref (input);
 }
 
 
-  static gboolean
-gegl_operation_composer3_process (GeglOperation        *operation,
-    GeglOperationContext *context,
-    const gchar          *output_prop,
-    const GeglRectangle  *result,
-    gint                  level)
+static gboolean
+gegl_operation_composer3_process2 (GeglOperation        *operation,
+                                   GeglOperationContext *context,
+                                   const gchar          *output_prop,
+                                   const GeglRectangle  *result,
+                                   gint                  level,
+                                   GError              **error)
 {
   GeglOperationComposer3Class *klass   = GEGL_OPERATION_COMPOSER3_GET_CLASS (operation);
   GeglBuffer                  *input;
@@ -201,6 +212,7 @@ gegl_operation_composer3_process (GeglOperation        *operation,
         data.roi = result;
         data.level = level;
         data.success = TRUE;
+        data.error = error;
 
         gegl_parallel_distribute_area (
           result,
@@ -208,12 +220,15 @@ gegl_operation_composer3_process (GeglOperation        *operation,
           GEGL_SPLIT_STRATEGY_AUTO,
           (GeglParallelDistributeAreaFunc) thread_process,
           &data);
-        
+
         success = data.success;
       }
       else
       {
-        success = klass->process (operation, input, aux, aux2, output, result, level);
+        if (klass->process2)
+          success = klass->process2 (operation, input, aux, aux2, output, result, level, error);
+        else
+          success = klass->process (operation, input, aux, aux2, output, result, level);
       }
 
       g_clear_object (&input);
diff --git a/gegl/operation/gegl-operation-composer3.h b/gegl/operation/gegl-operation-composer3.h
index c8b6c7bf3..0db2e3d5c 100644
--- a/gegl/operation/gegl-operation-composer3.h
+++ b/gegl/operation/gegl-operation-composer3.h
@@ -41,14 +41,22 @@ struct _GeglOperationComposer3Class
 {
   GeglOperationClass parent_class;
 
-  gboolean (* process) (GeglOperation       *self,
-                        GeglBuffer          *input,
-                        GeglBuffer          *aux,
-                        GeglBuffer          *aux2,
-                        GeglBuffer          *output,
-                        const GeglRectangle *result,
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *aux,
+                         GeglBuffer          *aux2,
+                         GeglBuffer          *output,
+                         const GeglRectangle *result,
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *aux,
+                         GeglBuffer          *aux2,
+                         GeglBuffer          *output,
+                         const GeglRectangle *result,
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType gegl_operation_composer3_get_type (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation-filter.c b/gegl/operation/gegl-operation-filter.c
index 5a43f9e1b..a69aace9e 100644
--- a/gegl/operation/gegl-operation-filter.c
+++ b/gegl/operation/gegl-operation-filter.c
@@ -26,12 +26,13 @@
 #include "gegl-operation-context.h"
 #include "gegl-config.h"
 
-static gboolean gegl_operation_filter_process
+static gboolean gegl_operation_filter_process2
                                       (GeglOperation        *operation,
                                        GeglOperationContext *context,
                                        const gchar          *output_prop,
                                        const GeglRectangle  *result,
-                                       gint                  level);
+                                       gint                  level,
+                                       GError              **error);
 
 static void     attach                 (GeglOperation *operation);
 static GeglNode *detect                (GeglOperation *operation,
@@ -61,7 +62,7 @@ gegl_operation_filter_class_init (GeglOperationFilterClass * klass)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
 
-  operation_class->process                 = gegl_operation_filter_process;
+  operation_class->process2                = gegl_operation_filter_process2;
   operation_class->threaded                = TRUE;
   operation_class->attach                  = attach;
   operation_class->detect                  = detect;
@@ -125,6 +126,7 @@ typedef struct ThreadData
   const GeglRectangle      *roi;
   gint                      level;
   gboolean                  success;
+  GError                  **error;
 } ThreadData;
 
 static void
@@ -132,6 +134,7 @@ thread_process (const GeglRectangle *area,
                 ThreadData          *data)
 {
   GeglBuffer *input;
+  gboolean    success = TRUE;
 
   if (area->x == data->roi->x && area->y == data->roi->y)
     {
@@ -143,19 +146,25 @@ thread_process (const GeglRectangle *area,
                                                            "input", area);
     }
 
-  if (!data->klass->process (data->operation,
-                             input, data->output, area, data->level))
+  if (data->klass->process2)
+    success = data->klass->process2 (data->operation,
+                                     input, data->output, area, data->level, data->error);
+  else
+    success = data->klass->process (data->operation,
+                                    input, data->output, area, data->level);
+  if (! success)
     data->success = FALSE;
 
   g_object_unref (input);
 }
 
 static gboolean
-gegl_operation_filter_process (GeglOperation        *operation,
-                               GeglOperationContext *context,
-                               const gchar          *output_prop,
-                               const GeglRectangle  *result,
-                               gint                  level)
+gegl_operation_filter_process2 (GeglOperation        *operation,
+                                GeglOperationContext *context,
+                                const gchar          *output_prop,
+                                const GeglRectangle  *result,
+                                gint                  level,
+                                GError              **error)
 {
   GeglOperationFilterClass *klass;
   GeglBuffer               *input;
@@ -164,7 +173,7 @@ gegl_operation_filter_process (GeglOperation        *operation,
 
   klass = GEGL_OPERATION_FILTER_GET_CLASS (operation);
 
-  g_assert (klass->process);
+  g_assert (klass->process || klass->process2);
 
   if (strcmp (output_prop, "output"))
     {
@@ -197,6 +206,7 @@ gegl_operation_filter_process (GeglOperation        *operation,
     data.roi = result;
     data.level = level;
     data.success = TRUE;
+    data.error = error;
 
     gegl_parallel_distribute_area (
       result,
@@ -209,7 +219,10 @@ gegl_operation_filter_process (GeglOperation        *operation,
   }
   else
   {
-    success = klass->process (operation, input, output, result, level);
+    if (klass->process2)
+      success = klass->process2 (operation, input, output, result, level, error);
+    else
+      success = klass->process (operation, input, output, result, level);
   }
 
   g_clear_object (&input);
diff --git a/gegl/operation/gegl-operation-filter.h b/gegl/operation/gegl-operation-filter.h
index 20ce3e293..3ac19e5c7 100644
--- a/gegl/operation/gegl-operation-filter.h
+++ b/gegl/operation/gegl-operation-filter.h
@@ -50,6 +50,12 @@ struct _GeglOperationFilterClass
                                             GeglBuffer           *output,
                                             const GeglRectangle  *roi,
                                             gint                  level);
+  gboolean          (* process2)           (GeglOperation        *self,
+                                            GeglBuffer           *input,
+                                            GeglBuffer           *output,
+                                            const GeglRectangle  *roi,
+                                            gint                  level,
+                                            GError              **error);
 
   /* How to split the area for multithreaded processing.  Should be irrelevant
    * for most ops.
diff --git a/gegl/operation/gegl-operation-point-composer.c b/gegl/operation/gegl-operation-point-composer.c
index e13f8b8ed..5b469ed6f 100644
--- a/gegl/operation/gegl-operation-point-composer.c
+++ b/gegl/operation/gegl-operation-point-composer.c
@@ -47,6 +47,7 @@ typedef struct ThreadData
   GeglBuffer                      *output;
   gint                             level;
   gboolean                         success;
+  GError                         **error;
 
   const Babl *input_format;
   const Babl *aux_format;
@@ -78,19 +79,27 @@ thread_process (const GeglRectangle *area,
 
   while (gegl_buffer_iterator_next (i))
   {
-     data->success =
-     data->klass->process (data->operation, data->input?i->items[read].data:NULL,
-                           data->aux?i->items[aux].data:NULL,
-                           i->items[0].data, i->length, &(i->items[0].roi), data->level);
+    if (data->klass->process2)
+      data->success =
+        data->klass->process2 (data->operation, data->input?i->items[read].data:NULL,
+                               data->aux?i->items[aux].data:NULL,
+                               i->items[0].data, i->length, &(i->items[0].roi),
+                               data->level, data->error);
+    else
+      data->success =
+        data->klass->process (data->operation, data->input?i->items[read].data:NULL,
+                              data->aux?i->items[aux].data:NULL,
+                              i->items[0].data, i->length, &(i->items[0].roi), data->level);
   }
 }
 
 static gboolean
-gegl_operation_composer_process (GeglOperation        *operation,
-                                 GeglOperationContext *context,
-                                 const gchar          *output_prop,
-                                 const GeglRectangle  *result,
-                                 gint                  level)
+gegl_operation_composer_process2 (GeglOperation        *operation,
+                                  GeglOperationContext *context,
+                                  const gchar          *output_prop,
+                                  const GeglRectangle  *result,
+                                  gint                  level,
+                                  GError              **error)
 {
   GeglOperationComposerClass *klass   = GEGL_OPERATION_COMPOSER_GET_CLASS (operation);
   GeglBuffer                 *input;
@@ -110,7 +119,18 @@ gegl_operation_composer_process (GeglOperation        *operation,
 
   if (strcmp (output_prop, "output"))
     {
-      g_warning ("requested processing of %s pad on a composer", output_prop);
+      if (error)
+        {
+          gchar *msg;
+
+          msg = g_strdup_printf ("requested processing of %s pad on a composer",
+                                 output_prop);
+          *error = g_error_new (g_quark_from_static_string ("gegl"),
+                                0, "Operation %s failed: %s",
+                                gegl_operation_get_name (operation),
+                                msg);
+          g_free (msg);
+        }
       return FALSE;
     }
 
@@ -134,27 +154,41 @@ gegl_operation_composer_process (GeglOperation        *operation,
   if (input != NULL ||
       aux != NULL)
     {
-      success = klass->process (operation, input, aux, output, result, level);
+      if (klass->process2)
+        success = klass->process2 (operation, input, aux, output, result, level, error);
+      else
+        success = klass->process (operation, input, aux, output, result, level);
 
       g_clear_object (&input);
       g_clear_object (&aux);
     }
   else
     {
-      g_warning ("%s received NULL input, aux, and aux2",
-                 gegl_node_get_operation (operation->node));
+      if (error)
+        {
+          gchar *msg;
+
+          msg = g_strdup_printf ("%s received NULL input, aux, and aux2",
+                                 gegl_node_get_operation (operation->node));
+          *error = g_error_new (g_quark_from_static_string ("gegl"),
+                                0, "Operation %s failed: %s",
+                                gegl_operation_get_name (operation),
+                                msg);
+          g_free (msg);
+        }
     }
 
   return success;
 }
 
-static gboolean gegl_operation_point_composer_process
+static gboolean gegl_operation_point_composer_process2
                               (GeglOperation       *operation,
                                GeglBuffer          *input,
                                GeglBuffer          *aux,
                                GeglBuffer          *output,
                                const GeglRectangle *result,
-                               gint                 level);
+                               gint                 level,
+                               GError             **error);
 
 G_DEFINE_TYPE (GeglOperationPointComposer, gegl_operation_point_composer, GEGL_TYPE_OPERATION_COMPOSER)
 
@@ -269,8 +303,8 @@ gegl_operation_point_composer_class_init (GeglOperationPointComposerClass *klass
   GeglOperationClass          *operation_class = GEGL_OPERATION_CLASS (klass);
   GeglOperationComposerClass *composer_class  = GEGL_OPERATION_COMPOSER_CLASS (klass);
 
-  composer_class->process = gegl_operation_point_composer_process;
-  operation_class->process = gegl_operation_composer_process;
+  composer_class->process2 = gegl_operation_point_composer_process2;
+  operation_class->process2 = gegl_operation_composer_process2;
   operation_class->prepare = prepare;
   operation_class->want_in_place = TRUE;
   operation_class->threaded = TRUE;
@@ -283,12 +317,13 @@ gegl_operation_point_composer_init (GeglOperationPointComposer *self)
 }
 
 static gboolean
-gegl_operation_point_composer_process (GeglOperation       *operation,
-                                       GeglBuffer          *input,
-                                       GeglBuffer          *aux,
-                                       GeglBuffer          *output,
-                                       const GeglRectangle *result,
-                                       gint                 level)
+gegl_operation_point_composer_process2 (GeglOperation       *operation,
+                                        GeglBuffer          *input,
+                                        GeglBuffer          *aux,
+                                        GeglBuffer          *output,
+                                        const GeglRectangle *result,
+                                        gint                 level,
+                                        GError             **error)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
   GeglOperationPointComposerClass *point_composer_class = GEGL_OPERATION_POINT_COMPOSER_GET_CLASS 
(operation);
@@ -318,6 +353,7 @@ gegl_operation_point_composer_process (GeglOperation       *operation,
         data.input_format = in_format;
         data.aux_format = aux_format;
         data.output_format = out_format;
+        data.error = error;
 
         if (gegl_cl_is_accelerated ())
         {
@@ -348,9 +384,15 @@ gegl_operation_point_composer_process (GeglOperation       *operation,
 
         while (gegl_buffer_iterator_next (i))
           {
-            point_composer_class->process (operation, input?i->items[read].data:NULL,
-                                                      aux?i->items[foo].data:NULL,
-                                                      i->items[0].data, i->length, &(i->items[0].roi), 
level);
+            if (point_composer_class->process2)
+              point_composer_class->process2 (operation, input?i->items[read].data:NULL,
+                                              aux?i->items[foo].data:NULL,
+                                              i->items[0].data, i->length, &(i->items[0].roi),
+                                              level, error);
+            else
+              point_composer_class->process (operation, input?i->items[read].data:NULL,
+                                             aux?i->items[foo].data:NULL,
+                                             i->items[0].data, i->length, &(i->items[0].roi), level);
           }
         return TRUE;
       }
diff --git a/gegl/operation/gegl-operation-point-composer.h b/gegl/operation/gegl-operation-point-composer.h
index 1305ec36e..f40cb0ef9 100644
--- a/gegl/operation/gegl-operation-point-composer.h
+++ b/gegl/operation/gegl-operation-point-composer.h
@@ -50,13 +50,21 @@ struct _GeglOperationPointComposerClass
 {
   GeglOperationComposerClass parent_class;
 
-  gboolean (* process) (GeglOperation       *self,      /* for parameters      */
-                        void                *in,
-                        void                *aux,
-                        void                *out,
-                        glong                samples, /* number of samples   */
-                        const GeglRectangle *roi,     /* rectangular region in output buffer */
-                        gint                 level);
+  gboolean (* process)    (GeglOperation       *self,      /* for parameters      */
+                           void                *in,
+                           void                *aux,
+                           void                *out,
+                           glong                samples, /* number of samples   */
+                           const GeglRectangle *roi,     /* rectangular region in output buffer */
+                           gint                 level);
+  gboolean (* process2)   (GeglOperation       *self,
+                           void                *in,
+                           void                *aux,
+                           void                *out,
+                           glong                samples,
+                           const GeglRectangle *roi,
+                           gint                 level,
+                           GError             **error);
 
   gboolean (* cl_process) (GeglOperation       *self,
                            cl_mem               in_tex,
diff --git a/gegl/operation/gegl-operation-point-filter.c b/gegl/operation/gegl-operation-point-filter.c
index 3197e5c83..7f0e792ea 100644
--- a/gegl/operation/gegl-operation-point-filter.c
+++ b/gegl/operation/gegl-operation-point-filter.c
@@ -45,6 +45,7 @@ typedef struct ThreadData
   GeglBuffer                    *output;
   gint                           level;
   gboolean                       success;
+  GError                       **error;
   const Babl                    *input_format;
   const Babl                    *output_format;
 } ThreadData;
@@ -67,23 +68,30 @@ thread_process (const GeglRectangle *area,
 
   while (gegl_buffer_iterator_next (i))
   {
-     data->success =
-     data->klass->process (data->operation, data->input?i->items[read].data:NULL,
-                           i->items[0].data, i->length, &(i->items[0].roi), data->level);
+    if (data->klass->process2)
+      data->success =
+        data->klass->process2 (data->operation, data->input?i->items[read].data:NULL,
+                               i->items[0].data, i->length, &(i->items[0].roi),
+                               data->level, data->error);
+    else
+      data->success =
+        data->klass->process (data->operation, data->input?i->items[read].data:NULL,
+                              i->items[0].data, i->length, &(i->items[0].roi), data->level);
   }
 }
 
 static gboolean
-gegl_operation_filter_process (GeglOperation        *operation,
-                                 GeglOperationContext *context,
-                                 const gchar          *output_prop,
-                                 const GeglRectangle  *result,
-                                 gint                  level)
+gegl_operation_filter_process2 (GeglOperation        *operation,
+                                GeglOperationContext *context,
+                                const gchar          *output_prop,
+                                const GeglRectangle  *result,
+                                gint                  level,
+                                GError              **error)
 {
-  GeglOperationFilterClass *klass    = GEGL_OPERATION_FILTER_GET_CLASS (operation);
-  GeglBuffer                 *input;
-  GeglBuffer                 *output;
-  gboolean                    success = FALSE;
+  GeglOperationFilterClass *klass   = GEGL_OPERATION_FILTER_GET_CLASS (operation);
+  GeglBuffer               *input;
+  GeglBuffer               *output;
+  gboolean                  success = FALSE;
 
   GeglRectangle scaled_result = *result;
   if (level)
@@ -97,7 +105,18 @@ gegl_operation_filter_process (GeglOperation        *operation,
 
   if (strcmp (output_prop, "output"))
     {
-      g_warning ("requested processing of %s pad on a filter", output_prop);
+      if (error)
+        {
+          gchar *msg;
+
+          msg = g_strdup_printf ("requested processing of %s pad on a filter",
+                                 output_prop);
+          *error = g_error_new (g_quark_from_static_string ("gegl"),
+                                0, "Operation %s failed: %s",
+                                gegl_operation_get_name (operation),
+                                msg);
+          g_free (msg);
+        }
       return FALSE;
     }
 
@@ -115,24 +134,38 @@ gegl_operation_filter_process (GeglOperation        *operation,
 
   if (input != NULL)
     {
-      success = klass->process (operation, input, output, result, level);
+      if (klass->process2)
+        success = klass->process2 (operation, input, output, result, level, error);
+      else
+        success = klass->process (operation, input, output, result, level);
       g_clear_object (&input);
     }
   else
     {
-      g_warning ("%s received NULL input",
-                 gegl_node_get_operation (operation->node));
+      if (error)
+        {
+          gchar *msg;
+
+          msg = g_strdup_printf ("%s received NULL input",
+                                 gegl_node_get_operation (operation->node));
+          *error = g_error_new (g_quark_from_static_string ("gegl"),
+                                0, "Operation %s failed: %s",
+                                gegl_operation_get_name (operation),
+                                msg);
+          g_free (msg);
+        }
     }
 
   return success;
 }
 
-static gboolean gegl_operation_point_filter_process
+static gboolean gegl_operation_point_filter_process2
                               (GeglOperation       *operation,
                                GeglBuffer          *input,
                                GeglBuffer          *output,
                                const GeglRectangle *result,
-                               gint                 level);
+                               gint                 level,
+                               GError             **error);
 
 G_DEFINE_TYPE (GeglOperationPointFilter, gegl_operation_point_filter, GEGL_TYPE_OPERATION_FILTER)
 
@@ -233,11 +266,11 @@ error:
 static void
 gegl_operation_point_filter_class_init (GeglOperationPointFilterClass *klass)
 {
-  GeglOperationClass          *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationClass       *operation_class = GEGL_OPERATION_CLASS (klass);
   GeglOperationFilterClass *filter_class  = GEGL_OPERATION_FILTER_CLASS (klass);
 
-  filter_class->process = gegl_operation_point_filter_process;
-  operation_class->process = gegl_operation_filter_process;
+  filter_class->process2 = gegl_operation_point_filter_process2;
+  operation_class->process2 = gegl_operation_filter_process2;
   operation_class->prepare = prepare;
   operation_class->want_in_place = TRUE;
   operation_class->threaded = TRUE;
@@ -250,11 +283,12 @@ gegl_operation_point_filter_init (GeglOperationPointFilter *self)
 }
 
 static gboolean
-gegl_operation_point_filter_process (GeglOperation       *operation,
-                                       GeglBuffer          *input,
-                                       GeglBuffer          *output,
-                                       const GeglRectangle *result,
-                                       gint                 level)
+gegl_operation_point_filter_process2 (GeglOperation       *operation,
+                                      GeglBuffer          *input,
+                                      GeglBuffer          *output,
+                                      const GeglRectangle *result,
+                                      gint                 level,
+                                      GError             **error)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
   GeglOperationPointFilterClass *point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);
@@ -281,6 +315,7 @@ gegl_operation_point_filter_process (GeglOperation       *operation,
         data.level = level;
         data.input_format = in_format;
         data.output_format = out_format;
+        data.error = error;
 
         if (gegl_cl_is_accelerated () && input)
           gegl_buffer_flush_ext (input, result);
@@ -306,8 +341,13 @@ gegl_operation_point_filter_process (GeglOperation       *operation,
 
         while (gegl_buffer_iterator_next (i))
           {
-            point_filter_class->process (operation, input?i->items[read].data:NULL,
-                                                    i->items[0].data, i->length, &(i->items[0].roi), level);
+            if (point_filter_class->process2)
+              point_filter_class->process2 (operation, input?i->items[read].data:NULL,
+                                            i->items[0].data, i->length, &(i->items[0].roi),
+                                            level, error);
+            else
+              point_filter_class->process (operation, input?i->items[read].data:NULL,
+                                           i->items[0].data, i->length, &(i->items[0].roi), level);
           }
         return TRUE;
       }
diff --git a/gegl/operation/gegl-operation-point-filter.h b/gegl/operation/gegl-operation-point-filter.h
index 64fe4d852..2437b2f97 100644
--- a/gegl/operation/gegl-operation-point-filter.h
+++ b/gegl/operation/gegl-operation-point-filter.h
@@ -50,15 +50,22 @@ struct _GeglOperationPointFilterClass
 {
   GeglOperationFilterClass parent_class;
 
-  gboolean (* process) (GeglOperation      *self,    /* for parameters    */
-                        void               *in_buf,  /* input buffer      */
-                        void               *out_buf, /* output buffer     */
-                        glong               samples, /* number of samples */
-                        const GeglRectangle *roi,    /* rectangle out_buf spans
-                                                        in in buffer, see the
-                                                        checkerboard op for
-                                                        semantics */
-                        gint                 level);
+  gboolean (* process)    (GeglOperation       *self,    /* for parameters    */
+                           void                *in_buf,  /* input buffer      */
+                           void                *out_buf, /* output buffer     */
+                           glong                samples, /* number of samples */
+                           const GeglRectangle *roi,    /* rectangle out_buf spans
+                                                           in in buffer, see the
+                                                           checkerboard op for
+                                                           semantics */
+                           gint                 level);
+  gboolean (* process2)   (GeglOperation       *self,
+                           void                *in_buf,
+                           void                *out_buf,
+                           glong                samples,
+                           const GeglRectangle *roi,
+                           gint                 level,
+                           GError             **error);
   gboolean (* cl_process) (GeglOperation       *self,
                            cl_mem               in_tex,
                            cl_mem               out_tex,
diff --git a/gegl/operation/gegl-operation-point-render.c b/gegl/operation/gegl-operation-point-render.c
index 5060d022f..cc63827f5 100644
--- a/gegl/operation/gegl-operation-point-render.c
+++ b/gegl/operation/gegl-operation-point-render.c
@@ -26,11 +26,12 @@
 #include "gegl-operation-context.h"
 #include "gegl-types-internal.h"
 
-static gboolean gegl_operation_point_render_process
+static gboolean gegl_operation_point_render_process2
                               (GeglOperation       *operation,
                                GeglBuffer          *output,
                                const GeglRectangle *result,
-                               gint                 level);
+                               gint                 level,
+                               GError             **error);
 
 G_DEFINE_TYPE (GeglOperationPointRender, gegl_operation_point_render, GEGL_TYPE_OPERATION_SOURCE)
 
@@ -54,7 +55,7 @@ gegl_operation_point_render_class_init (GeglOperationPointRenderClass *klass)
   GeglOperationSourceClass *source_class    = GEGL_OPERATION_SOURCE_CLASS (klass);
   GeglOperationClass       *operation_class = GEGL_OPERATION_CLASS (klass);
 
-  source_class->process    = gegl_operation_point_render_process;
+  source_class->process2    = gegl_operation_point_render_process2;
   operation_class->prepare = prepare;
 
   operation_class->detect = detect;
@@ -68,10 +69,11 @@ gegl_operation_point_render_init (GeglOperationPointRender *self)
 
 
 static gboolean
-gegl_operation_point_render_process (GeglOperation       *operation,
-                                     GeglBuffer          *output,
-                                     const GeglRectangle *result,
-                                     gint                 level)
+gegl_operation_point_render_process2 (GeglOperation       *operation,
+                                      GeglBuffer          *output,
+                                      const GeglRectangle *result,
+                                      gint                 level,
+                                      GError             **error)
 {
   const Babl *out_format;
   GeglOperationPointRenderClass *point_render_class;
@@ -102,7 +104,15 @@ gegl_operation_point_render_process (GeglOperation       *operation,
                                                         GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 2);
 
       while (gegl_buffer_iterator_next (i))
-          point_render_class->process (operation, i->items[0].data, i->length, &i->items[0].roi, level);
+        {
+          if (point_render_class->process2)
+            point_render_class->process2 (operation, i->items[0].data,
+                                          i->length, &i->items[0].roi,
+                                          level, error);
+          else
+            point_render_class->process (operation, i->items[0].data,
+                                         i->length, &i->items[0].roi, level);
+        }
     }
 
   return TRUE;
diff --git a/gegl/operation/gegl-operation-point-render.h b/gegl/operation/gegl-operation-point-render.h
index 26f68d5cc..199ca3ebb 100644
--- a/gegl/operation/gegl-operation-point-render.h
+++ b/gegl/operation/gegl-operation-point-render.h
@@ -47,12 +47,18 @@ struct _GeglOperationPointRenderClass
 {
   GeglOperationSourceClass parent_class;
 
-  gboolean (* process) (GeglOperation       *self,      /* for parameters    */
-                        void                *out_buf,   /* output buffer     */
-                        glong                samples,   /* number of samples */
-                        const GeglRectangle *roi,       /* can be used if position is of importance*/
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,      /* for parameters    */
+                         void                *out_buf,   /* output buffer     */
+                         glong                samples,   /* number of samples */
+                         const GeglRectangle *roi,       /* can be used if position is of importance*/
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,      /* for parameters    */
+                         void                *out_buf,   /* output buffer     */
+                         glong                samples,   /* number of samples */
+                         const GeglRectangle *roi,       /* can be used if position is of importance*/
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType gegl_operation_point_render_get_type (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation-sink.c b/gegl/operation/gegl-operation-sink.c
index 823551e83..d161e658c 100644
--- a/gegl/operation/gegl-operation-sink.c
+++ b/gegl/operation/gegl-operation-sink.c
@@ -26,11 +26,12 @@
 #include "gegl-operation-sink.h"
 #include "gegl-operation-context.h"
 
-static gboolean      gegl_operation_sink_process                 (GeglOperation        *operation,
+static gboolean      gegl_operation_sink_process2                (GeglOperation        *operation,
                                                                   GeglOperationContext *context,
                                                                   const gchar          *output_prop,
                                                                   const GeglRectangle  *result,
-                                                                  gint                  level);
+                                                                  gint                  level,
+                                                                  GError              **error);
 static void          gegl_operation_sink_attach                  (GeglOperation        *operation);
 static GeglRectangle gegl_operation_sink_get_bounding_box        (GeglOperation        *self);
 static GeglRectangle gegl_operation_sink_get_required_for_output (GeglOperation        *operation,
@@ -48,7 +49,7 @@ gegl_operation_sink_class_init (GeglOperationSinkClass * klass)
 
   klass->needs_full = FALSE;
 
-  operation_class->process                 = gegl_operation_sink_process;
+  operation_class->process2                = gegl_operation_sink_process2;
   operation_class->attach                  = gegl_operation_sink_attach;
   operation_class->get_bounding_box        = gegl_operation_sink_get_bounding_box;
   operation_class->get_required_for_output = gegl_operation_sink_get_required_for_output;
@@ -76,26 +77,36 @@ gegl_operation_sink_attach (GeglOperation *self)
 }
 
 static gboolean
-gegl_operation_sink_process (GeglOperation        *operation,
-                             GeglOperationContext *context,
-                             const gchar          *output_prop,
-                             const GeglRectangle  *result,
-                             gint                  level)
+gegl_operation_sink_process2 (GeglOperation         *operation,
+                              GeglOperationContext  *context,
+                              const gchar           *output_prop,
+                              const GeglRectangle   *result,
+                              gint                   level,
+                              GError               **error)
 {
   GeglOperationSinkClass *klass;
   GeglBuffer             *input;
   gboolean                success = FALSE;
 
-  klass               = GEGL_OPERATION_SINK_GET_CLASS (operation);
+  klass = GEGL_OPERATION_SINK_GET_CLASS (operation);
 
-  g_assert (klass->process);
+  g_assert (klass->process || klass->process2);
 
   input = (GeglBuffer*) gegl_operation_context_dup_object (context, "input");
   if (input)
     {
-      success = klass->process (operation, input, result, level);
+      if (klass->process2)
+        success = klass->process2 (operation, input, result, level, error);
+      else
+        success = klass->process (operation, input, result, level);
+
       g_object_unref (input);
     }
+  else if (error)
+    {
+      *error = g_error_new (g_quark_from_static_string ("gegl"),
+                            0, "Sink operation has no input");
+    }
 
   return success;
 }
diff --git a/gegl/operation/gegl-operation-sink.h b/gegl/operation/gegl-operation-sink.h
index 6859a35b6..586e87695 100644
--- a/gegl/operation/gegl-operation-sink.h
+++ b/gegl/operation/gegl-operation-sink.h
@@ -49,13 +49,18 @@ struct _GeglOperationSinkClass
   /* Whether or not the sink operation needs full input data in one go
    * in order to be able to do its processing
    */
-  gboolean              needs_full;
+  gboolean               needs_full;
 
-  gboolean (* process) (GeglOperation       *self,
-                        GeglBuffer          *input,
-                        const GeglRectangle *roi,
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         const GeglRectangle *roi,
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         const GeglRectangle *roi,
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType    gegl_operation_sink_get_type   (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation-source.c b/gegl/operation/gegl-operation-source.c
index 35fc471a9..053405969 100644
--- a/gegl/operation/gegl-operation-source.c
+++ b/gegl/operation/gegl-operation-source.c
@@ -26,12 +26,13 @@
 #include "gegl-operation-context.h"
 #include "gegl-config.h"
 
-static gboolean gegl_operation_source_process
+static gboolean gegl_operation_source_process2
                              (GeglOperation        *operation,
                               GeglOperationContext *context,
                               const gchar          *output_prop,
                               const GeglRectangle  *result,
-                              gint                  level);
+                              gint                  level,
+                              GError              **error);
 static void     attach       (GeglOperation *operation);
 
 
@@ -49,8 +50,8 @@ gegl_operation_source_class_init (GeglOperationSourceClass * klass)
 {
   GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
 
-  operation_class->process = gegl_operation_source_process;
-  operation_class->attach  = attach;
+  operation_class->process2 = gegl_operation_source_process2;
+  operation_class->attach   = attach;
 
   operation_class->get_bounding_box  = get_bounding_box;
   operation_class->get_required_for_output = get_required_for_output;
@@ -84,23 +85,32 @@ typedef struct ThreadData
   GeglBuffer               *output;
   gint                      level;
   gboolean                  success;
+  GError                  **error;
 } ThreadData;
 
 static void
 thread_process (const GeglRectangle *area,
                 ThreadData          *data)
 {
-  if (!data->klass->process (data->operation,
-                       data->output, area, data->level))
+  gboolean success = TRUE;
+
+  if (data->klass->process2)
+    success = data->klass->process2 (data->operation,
+                                     data->output, area, data->level, data->error);
+  else
+    success = data->klass->process (data->operation,
+                                    data->output, area, data->level);
+  if (! success)
     data->success = FALSE;
 }
 
 static gboolean
-gegl_operation_source_process (GeglOperation        *operation,
-                               GeglOperationContext *context,
-                               const gchar          *output_prop,
-                               const GeglRectangle  *result,
-                               gint                  level)
+gegl_operation_source_process2 (GeglOperation        *operation,
+                                GeglOperationContext *context,
+                                const gchar          *output_prop,
+                                const GeglRectangle  *result,
+                                gint                  level,
+                                GError              **error)
 {
   GeglOperationSourceClass *klass = GEGL_OPERATION_SOURCE_GET_CLASS (operation);
   GeglBuffer               *output;
@@ -112,7 +122,7 @@ gegl_operation_source_process (GeglOperation        *operation,
       return FALSE;
     }
 
-  g_assert (klass->process);
+  g_assert (klass->process || klass->process2);
   output = gegl_operation_context_get_target (context, "output");
 
   if (gegl_operation_use_threading (operation, result))
@@ -124,6 +134,7 @@ gegl_operation_source_process (GeglOperation        *operation,
     data.output = output;
     data.level = level;
     data.success = TRUE;
+    data.error = error;
 
     gegl_parallel_distribute_area (
       result,
@@ -136,7 +147,10 @@ gegl_operation_source_process (GeglOperation        *operation,
   }
   else
   {
-    success = klass->process (operation, output, result, level);
+    if (klass->process2)
+      success = klass->process2 (operation, output, result, level, error);
+    else
+      success = klass->process (operation, output, result, level);
   }
 
   return success;
diff --git a/gegl/operation/gegl-operation-source.h b/gegl/operation/gegl-operation-source.h
index fc19c8245..77cfbfb85 100644
--- a/gegl/operation/gegl-operation-source.h
+++ b/gegl/operation/gegl-operation-source.h
@@ -44,13 +44,18 @@ struct _GeglOperationSource
 typedef struct _GeglOperationSourceClass GeglOperationSourceClass;
 struct _GeglOperationSourceClass
 {
-  GeglOperationClass    parent_class;
+  GeglOperationClass     parent_class;
 
-  gboolean (* process) (GeglOperation       *self,
-                        GeglBuffer          *output,
-                        const GeglRectangle *roi,
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,
+                         GeglBuffer          *output,
+                         const GeglRectangle *roi,
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,
+                         GeglBuffer          *output,
+                         const GeglRectangle *roi,
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType gegl_operation_source_get_type (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation-temporal.c b/gegl/operation/gegl-operation-temporal.c
index 7e0a3db62..67d920a63 100644
--- a/gegl/operation/gegl-operation-temporal.c
+++ b/gegl/operation/gegl-operation-temporal.c
@@ -79,11 +79,12 @@ gegl_operation_temporal_get_frame (GeglOperation *op,
   return buffer;
 }
 
-static gboolean gegl_operation_temporal_process (GeglOperation       *self,
-                                                 GeglBuffer          *input,
-                                                 GeglBuffer          *output,
-                                                 const GeglRectangle *result,
-                                                 gint                 level)
+static gboolean gegl_operation_temporal_process2 (GeglOperation       *self,
+                                                  GeglBuffer          *input,
+                                                  GeglBuffer          *output,
+                                                  const GeglRectangle *result,
+                                                  gint                 level,
+                                                  GError             **error)
 {
   GeglOperationTemporal *temporal = GEGL_OPERATION_TEMPORAL (self);
   GeglOperationTemporalPrivate *priv = temporal->priv;
@@ -105,7 +106,9 @@ static gboolean gegl_operation_temporal_process (GeglOperation       *self,
      priv->next_to_write=0;
   }
 
- if (temporal_class->process)
+ if (temporal_class->process2)
+   return temporal_class->process2 (self, input, output, result, level, error);
+ else
    return temporal_class->process (self, input, output, result, level);
  return FALSE;
 }
@@ -125,7 +128,7 @@ gegl_operation_temporal_class_init (GeglOperationTemporalClass *klass)
   GeglOperationFilterClass *operation_filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
 
   operation_class->prepare = gegl_operation_temporal_prepare;
-  operation_filter_class->process = gegl_operation_temporal_process;
+  operation_filter_class->process2 = gegl_operation_temporal_process2;
 }
 
 static void
diff --git a/gegl/operation/gegl-operation-temporal.h b/gegl/operation/gegl-operation-temporal.h
index 0a369fc4c..4e8863ae6 100644
--- a/gegl/operation/gegl-operation-temporal.h
+++ b/gegl/operation/gegl-operation-temporal.h
@@ -48,12 +48,18 @@ typedef struct _GeglOperationTemporalClass GeglOperationTemporalClass;
 struct _GeglOperationTemporalClass
 {
   GeglOperationFilterClass parent_class;
-  gboolean (* process) (GeglOperation       *self,
-                        GeglBuffer          *input,
-                        GeglBuffer          *output,
-                        const GeglRectangle *roi,
-                        gint                 level);
-  gpointer              pad[4];
+  gboolean (* process)  (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *output,
+                         const GeglRectangle *roi,
+                         gint                 level);
+  gboolean (* process2) (GeglOperation       *self,
+                         GeglBuffer          *input,
+                         GeglBuffer          *output,
+                         const GeglRectangle *roi,
+                         gint                 level,
+                         GError             **error);
+  gpointer               pad[4];
 };
 
 GType gegl_operation_temporal_get_type (void) G_GNUC_CONST;
diff --git a/gegl/operation/gegl-operation.c b/gegl/operation/gegl-operation.c
index 0b31c146f..08356c979 100644
--- a/gegl/operation/gegl-operation.c
+++ b/gegl/operation/gegl-operation.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include <glib-object.h>
+#include <glib/gi18n-lib.h>
 #include <string.h>
 
 #include "gegl.h"
@@ -146,20 +147,31 @@ gegl_operation_process (GeglOperation        *operation,
                         const GeglRectangle  *result,
                         gint                  level)
 {
-  GeglOperationClass  *klass;
+  GeglOperationClass *klass;
+  gboolean            success = TRUE;
 
   g_return_val_if_fail (GEGL_IS_OPERATION (operation), FALSE);
 
   klass = GEGL_OPERATION_GET_CLASS (operation);
 
+  operation->node->success = TRUE;
+  g_clear_error (&operation->node->error);
+
   if (!strcmp (output_pad, "output") &&
       (result->width == 0 || result->height == 0))
     {
       GeglBuffer *output = gegl_buffer_new (NULL, NULL);
-      g_warning ("%s Eeek: processing 0px rectangle", G_STRLOC);
+
+      operation->node->error = g_error_new (g_quark_from_static_string ("gegl"),
+                                            0, _("Operation %s failed: %s"),
+                                            gegl_operation_get_name (operation),
+                                            _("processing 0px rectangle."));
+      operation->node->success = FALSE;
+
       /* when this case is hit.. we've done something bad.. */
       gegl_operation_context_take_object (context, "output", G_OBJECT (output));
-      return TRUE;
+
+      return FALSE;
     }
 
   if (operation->node->passthrough)
@@ -169,9 +181,22 @@ gegl_operation_process (GeglOperation        *operation,
     return TRUE;
   }
 
-  g_return_val_if_fail (klass->process, FALSE);
+  g_return_val_if_fail (klass->process || klass->process2, FALSE);
+
+  if (klass->process2)
+    success = klass->process2 (operation, context, output_pad, result, level,
+                               &operation->node->error);
+  else
+    success = klass->process (operation, context, output_pad, result, level);
+
+  operation->node->success = success;
+  if (! success && operation->node->error == NULL)
+    operation->node->error = g_error_new (g_quark_from_static_string ("gegl"),
+                                          0, _("Operation %s failed: %s"),
+                                          gegl_operation_get_name (operation),
+                                          _("unknown error."));
 
-  return klass->process (operation, context, output_pad, result, level);
+  return success;
 }
 
 /* Calls an extending class' get_bound_box method if defined otherwise
diff --git a/gegl/operation/gegl-operation.h b/gegl/operation/gegl-operation.h
index fa100034c..11c031240 100644
--- a/gegl/operation/gegl-operation.h
+++ b/gegl/operation/gegl-operation.h
@@ -133,6 +133,8 @@ struct _GeglOperationClass
   /* Compute the rectangular region output roi for the specified output_pad.
    * For operations that are sinks (have no output pads), roi is the rectangle
    * to consume and the output_pad argument is to be ignored.
+   * If the processing may fail and return FALSE, you should implement
+   * process2() instead.
    */
   gboolean      (*process)                   (GeglOperation        *operation,
                                               GeglOperationContext *context,
@@ -140,6 +142,17 @@ struct _GeglOperationClass
                                               const GeglRectangle  *roi,
                                               gint                  level);
 
+  /* Same as process() but allows to report an error. Operations should
+   * implement process2() rather than process() unless the operation always
+   * succeed. If both virtual methods are implemented, process() is ignored.
+   */
+  gboolean      (*process2)                  (GeglOperation        *operation,
+                                              GeglOperationContext *context,
+                                              const gchar          *output_pad,
+                                              const GeglRectangle  *roi,
+                                              gint                  level,
+                                              GError              **error);
+
   /* The node providing data for a specific location within the operations
    * output. The node is responsible for delegating blame to one of it's
    * inputs taking into account opacity and similar issues.
diff --git a/gegl/process/gegl-eval-manager.c b/gegl/process/gegl-eval-manager.c
index 6934ced4e..351b9b26e 100644
--- a/gegl/process/gegl-eval-manager.c
+++ b/gegl/process/gegl-eval-manager.c
@@ -113,6 +113,8 @@ gegl_eval_manager_apply (GeglEvalManager     *self,
   g_return_val_if_fail (GEGL_IS_EVAL_MANAGER (self), NULL);
   g_return_val_if_fail (GEGL_IS_NODE (self->node), NULL);
 
+  g_clear_error (&self->node->error);
+
   if (level >= GEGL_CACHE_VALID_MIPMAPS)
     level = GEGL_CACHE_VALID_MIPMAPS-1;
 
@@ -125,7 +127,7 @@ gegl_eval_manager_apply (GeglEvalManager     *self,
   GEGL_INSTRUMENT_END ("gegl", "prepare-request");
 
   GEGL_INSTRUMENT_START();
-  object = gegl_graph_process (self->traversal, level);
+  object = gegl_graph_process (self->traversal, level, &self->node->error);
   GEGL_INSTRUMENT_END ("gegl", "process");
 
   return object;
diff --git a/gegl/process/gegl-graph-traversal.c b/gegl/process/gegl-graph-traversal.c
index e095c9c66..b4d964029 100644
--- a/gegl/process/gegl-graph-traversal.c
+++ b/gegl/process/gegl-graph-traversal.c
@@ -396,6 +396,7 @@ gegl_graph_get_shared_empty (GeglGraphTraversal *path)
 /**
  * gegl_graph_process:
  * @path: The traversal path
+ * @error: an optional #GError.
  *
  * Process the prepared request. This will return the
  * resulting buffer from the final node, or NULL if
@@ -404,18 +405,22 @@ gegl_graph_get_shared_empty (GeglGraphTraversal *path)
  * If gegl_graph_prepare_request has not been called
  * the behavior of this function is undefined.
  *
- * Return value: (transfer full): The result of the graph, or NULL if
- * there is no output pad.
+ * Return value: (transfer full): The result of the graph, or #NULL either if
+ * there is no output pad or if an error was encountered. If @error is not
+ * #NULL, it will be set in case of error.
+
  */
 GeglBuffer *
-gegl_graph_process (GeglGraphTraversal *path,
-                    gint                level)
+gegl_graph_process (GeglGraphTraversal  *path,
+                    gint                 level,
+                    GError             **error)
 {
   GList *list_iter = NULL;
   GeglBuffer *result = NULL;
   GeglOperationContext *context = NULL;
   GeglOperationContext *last_context = NULL;
   GeglBuffer *operation_result = NULL;
+  gboolean    success = TRUE;
 
   for (list_iter = g_queue_peek_head_link (&path->path);
        list_iter;
@@ -467,7 +472,16 @@ gegl_graph_process (GeglGraphTraversal *path,
               /* note: this hard-coding of "output" makes some more custom
                * graph topologies harder than necessary.
                */
-              gegl_operation_process (operation, context, "output", &context->need_rect, context->level);
+              if (! gegl_operation_process (operation, context, "output", &context->need_rect, 
context->level))
+                {
+                  /* Propagate the error to the calling node, because this is
+                   * where we will look when checking for errors.
+                   */
+                  g_propagate_error (error, operation->node->error);
+                  operation->node->error = NULL;
+                  success = FALSE;
+                  break;
+                }
               operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));
 
               if (operation_result && operation_result == (GeglBuffer *)operation->node->cache)
@@ -507,10 +521,13 @@ gegl_graph_process (GeglGraphTraversal *path,
     }
   if (last_context)
     {
-      if (operation_result)
-        result = g_object_ref (operation_result);
-      else if (gegl_node_has_pad (last_context->operation->node, "output"))
-        result = g_object_ref (gegl_graph_get_shared_empty (path));
+      if (success)
+        {
+          if (operation_result)
+            result = g_object_ref (operation_result);
+          else if (gegl_node_has_pad (last_context->operation->node, "output"))
+            result = g_object_ref (gegl_graph_get_shared_empty (path));
+        }
       gegl_operation_context_purge (last_context);
     }
 
diff --git a/gegl/process/gegl-graph-traversal.h b/gegl/process/gegl-graph-traversal.h
index 38f3774a0..c7eb658cd 100644
--- a/gegl/process/gegl-graph-traversal.h
+++ b/gegl/process/gegl-graph-traversal.h
@@ -30,7 +30,8 @@ void                gegl_graph_prepare_request  (GeglGraphTraversal  *path,
                                                  const GeglRectangle *roi,
                                                  gint                 level);
 GeglBuffer         *gegl_graph_process          (GeglGraphTraversal  *path,
-                                                 gint                 level);
+                                                 gint                 level,
+                                                 GError             **error);
 
 GeglRectangle       gegl_graph_get_bounding_box (GeglGraphTraversal  *path);
 
diff --git a/gegl/process/gegl-processor.c b/gegl/process/gegl-processor.c
index 15668d758..dcdbe936a 100644
--- a/gegl/process/gegl-processor.c
+++ b/gegl/process/gegl-processor.c
@@ -785,20 +785,20 @@ gegl_processor_work (GeglProcessor *processor,
       *progress = 1.0;
     }
 
+  more_work = FALSE;
   if (processor->context)
     {
       /* the actual writing to the destination */
-      gegl_operation_process (processor->real_node->operation,
-                              processor->context,
-                              "output"  /* ignored output_pad */,
-                              &processor->context->result_rect, processor->context->level);
+      more_work = gegl_operation_process (processor->real_node->operation,
+                                          processor->context,
+                                          "output"  /* ignored output_pad */,
+                                          &processor->context->result_rect, processor->context->level);
+      processor->real_node->success = more_work;
       gegl_operation_context_destroy (processor->context);
       processor->context = NULL;
-
-      return TRUE;
     }
 
-  return FALSE;
+  return more_work;
 }
 
 GeglProcessor *


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