buffer-source.c 5.99 KB
Newer Older
1 2 3 4 5
/* This file is an image processing operation for GEGL
 *
 * GEGL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
6
 * version 3 of the License, or (at your option) any later version.
7 8 9 10 11 12 13
 *
 * GEGL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
14
 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15 16 17
 *
 * Copyright 2006 Øyvind Kolås <pippin@gimp.org>
 */
18 19 20 21 22

#include "config.h"
#include <glib/gi18n-lib.h>


23
#ifdef GEGL_PROPERTIES
24

25 26
property_object (buffer, _("Input buffer"), GEGL_TYPE_BUFFER)
    description (_("The GeglBuffer to load into the pipeline"))
27

28 29
#else

30
#define GEGL_OP_SOURCE
31
#define GEGL_OP_NAME     buffer_source
32
#define GEGL_OP_C_SOURCE buffer-source.c
33

34
#include "gegl-op.h"
35

36 37 38 39 40 41
typedef struct
{
  gulong buffer_changed_handler;
} Priv;

static Priv *
42
get_priv (GeglProperties *o)
43
{
44 45 46 47 48 49 50
  Priv *priv = o->user_data;

  if (! priv)
    {
      priv = g_new0 (Priv, 1);
      o->user_data = priv;
    }
51 52 53 54

  return priv;
}

55 56 57 58
static void
buffer_changed (GeglBuffer          *buffer,
                const GeglRectangle *rect,
                gpointer             data)
59
{
60
  gegl_operation_invalidate (data, rect, FALSE);
61 62
}

63 64 65
static void
gegl_buffer_source_prepare (GeglOperation *operation)
{
66 67
  GeglProperties *o      = GEGL_PROPERTIES (operation);
  const Babl     *format = NULL;
68 69 70 71 72 73 74

  if (o->buffer)
    format = gegl_buffer_get_format (GEGL_BUFFER (o->buffer));

  gegl_operation_set_format (operation, "output", format);
}

75 76
static GeglRectangle
get_bounding_box (GeglOperation *operation)
77
{
78 79 80 81 82
  GeglProperties *o      = GEGL_PROPERTIES (operation);
  GeglRectangle   result = { 0, 0, 0, 0 };

  if (o->buffer)
    result = *gegl_buffer_get_extent (GEGL_BUFFER (o->buffer));
83

84
  return result;
85 86
}

87
static void
88 89 90 91
my_set_property (GObject      *object,
                 guint         property_id,
                 const GValue *value,
                 GParamSpec   *pspec)
92
{
93 94 95 96
  GeglOperation  *operation = GEGL_OPERATION (object);
  GeglProperties *o         = GEGL_PROPERTIES (operation);
  Priv           *p         = get_priv (o);
  GeglBuffer     *buffer    = NULL;
97

98 99 100 101 102
  /* we split buffer replacement into two parts -- before and after calling
   * set_property() to update o->buffer -- so that code executed as a result
   * of the invalidation performed by buffer_changed() sees the op with the
   * right buffer.
   */
103
  switch (property_id)
104
    {
105
    case PROP_buffer:
106 107 108 109 110 111
      if (o->buffer)
        {
          /* Invariant: valid buffer should always have valid signal handler */
          g_assert (p->buffer_changed_handler > 0);
          g_signal_handler_disconnect (o->buffer, p->buffer_changed_handler);
          /* XXX: should decrement signal connected count */
112 113 114 115

          buffer_changed (GEGL_BUFFER (o->buffer),
                          gegl_buffer_get_extent (GEGL_BUFFER (o->buffer)),
                          operation);
116
        }
117 118 119 120 121
      break;

    default:
      break;
  }
122

123 124 125 126 127 128 129 130
  /* The set_property provided by the chant system does the storing
   * and reffing/unreffing of the input properties
   */
  set_property (object, property_id, value, pspec);

  switch (property_id)
    {
    case PROP_buffer:
131 132 133 134 135 136 137 138
      buffer = g_value_get_object (value);

      if (buffer)
        {
          p->buffer_changed_handler =
            gegl_buffer_signal_connect (buffer, "changed",
                                        G_CALLBACK (buffer_changed),
                                        operation);
139 140 141

          buffer_changed (buffer, gegl_buffer_get_extent (buffer),
                          operation);
142
        }
143
      break;
144

145 146 147 148 149
    default:
      break;
  }
}

150
static gboolean
151 152 153 154 155
process (GeglOperation        *operation,
         GeglOperationContext *context,
         const gchar          *output_pad,
         const GeglRectangle  *result,
         gint                  level)
156
{
157
  GeglProperties *o = GEGL_PROPERTIES (operation);
158

159
  if (o->buffer)
160
    {
161 162 163 164 165 166
      /* Override core behaviour, by resetting the buffer in the
       * operation_context.
       *
       * Also add an extra reference, since take_object() is consuming
       * one.
       */
167
      gegl_operation_context_take_object (context, "output",
168 169 170 171
                                          g_object_ref (o->buffer));

      /* Mark that this buffer should not be used for in-place
       * processing
172
       */
173
      gegl_object_set_has_forked (G_OBJECT (o->buffer));
174
    }
175

176 177 178
  return TRUE;
}

179 180
static void
dispose (GObject *object)
181
{
182
  GeglProperties *o = GEGL_PROPERTIES (object);
183
  Priv           *p = get_priv (o);
184

185
  if (o->buffer)
186
    {
187 188
      /* Invariant: valid buffer should always have valid signal handler */
      g_assert (p->buffer_changed_handler > 0);
189
      g_signal_handler_disconnect (o->buffer, p->buffer_changed_handler);
190 191
      /* XXX: should decrement signal connected count */

Debarshi Ray's avatar
Debarshi Ray committed
192
      g_clear_object (&o->buffer);
193
    }
194

195 196 197 198 199
  if (p)
    {
      g_free (p);
      o->user_data = NULL;
    }
200

201
  G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object);
202 203
}

204
static void
205
gegl_op_class_init (GeglOpClass *klass)
206
{
207 208
  GObjectClass       *object_class    = G_OBJECT_CLASS (klass);
  GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
209

210 211
  object_class->set_property = my_set_property;
  object_class->dispose      = dispose;
212

213 214
  operation_class->prepare          = gegl_buffer_source_prepare;
  operation_class->process          = process;
215 216
  operation_class->get_bounding_box = get_bounding_box;

217
  gegl_operation_class_set_keys (operation_class,
218 219 220
      "name",        "gegl:buffer-source",
      "title",       _("Buffer Source"),
      "categories",  "programming:input",
221
      "description", _("Use an existing in-memory GeglBuffer as image source."),
222
      NULL);
223

224
  operation_class->cache_policy = GEGL_CACHE_POLICY_NEVER;
225 226
}

227
#endif