gegl-node.c 57.3 KB
Newer Older
1
/* This file is part of GEGL
2
 *
3 4 5
 * 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
 * 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.
12
 *
13
 * You should have received a copy of the GNU Lesser General Public
14
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
15
 *
16 17
 * Copyright 2003 Calvin Williamson
 *           2006 Øyvind Kolås
Daniel Sabo's avatar
Daniel Sabo committed
18
 *           2013 Daniel Sabo
19
 */
Michael Natterer's avatar
Michael Natterer committed
20 21 22 23 24

#include "config.h"

#include <string.h>

25
#include <glib-object.h>
26
#include <gobject/gvaluecollector.h>
27

28
#include "gegl-types-internal.h"
29

30
#include "gegl.h"
31
#include "gegl-debug.h"
32
#include "gegl-node-private.h"
33
#include "gegl-connection.h"
34 35
#include "gegl-pad.h"
#include "gegl-visitable.h"
36
#include "gegl-config.h"
37

Daniel Sabo's avatar
Daniel Sabo committed
38 39
#include "graph/gegl-visitor.h"

40
#include "operation/gegl-operation.h"
41
#include "operation/gegl-operations.h"
42
#include "operation/gegl-operation-meta.h"
43

44
#include "process/gegl-eval-manager.h"
Michael Natterer's avatar
Michael Natterer committed
45

46 47
enum
{
48
  PROP_0,
49
  PROP_OP_CLASS,
50
  PROP_OPERATION,
51
  PROP_NAME,
52 53
  PROP_DONT_CACHE,
  PROP_USE_OPENCL
54 55
};

56 57 58 59 60 61 62
enum
{
  INVALIDATED,
  COMPUTED,
  LAST_SIGNAL
};

63 64

struct _GeglNodePrivate
65
{
66 67 68 69 70
  GSList          *source_connections;
  GSList          *sink_connections;
  GSList          *children;  /*  used for children */
  GeglNode        *parent;
  gchar           *name;
71
  gchar           *debug_name;
Daniel Sabo's avatar
Daniel Sabo committed
72
  GeglEvalManager *eval_manager;
73
};
74 75


76
static guint gegl_node_signals[LAST_SIGNAL] = {0};
77

78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
static void            gegl_node_class_init               (GeglNodeClass *klass);
static void            gegl_node_init                     (GeglNode      *self);
static void            gegl_node_finalize                 (GObject       *self_object);
static void            gegl_node_dispose                  (GObject       *self_object);
static void            gegl_node_local_set_property       (GObject       *gobject,
                                                           guint          prop_id,
                                                           const GValue  *value,
                                                           GParamSpec    *pspec);
static void            gegl_node_local_get_property       (GObject       *gobject,
                                                           guint          prop_id,
                                                           GValue        *value,
                                                           GParamSpec    *pspec);
static gboolean        gegl_node_pads_exist               (GeglNode      *sink,
                                                           const gchar   *sink_pad_name,
                                                           GeglNode      *source,
                                                           const gchar   *source_pad_name);
static GeglConnection *gegl_node_find_connection          (GeglNode      *sink,
                                                           GeglPad       *sink_pad);
static void            gegl_node_visitable_iface_init     (gpointer       ginterface,
                                                           gpointer       interface_data);
static void            gegl_node_visitable_accept         (GeglVisitable *visitable,
                                                           GeglVisitor   *visitor);
static GSList*         gegl_node_visitable_depends_on     (GeglVisitable *visitable);
static void            gegl_node_set_operation_object     (GeglNode      *self,
                                                           GeglOperation *operation);
static void            gegl_node_set_op_class             (GeglNode      *self,
                                                           const gchar   *op_class,
                                                           const gchar   *first_property,
                                                           va_list        var_args);
static void            gegl_node_disconnect_sinks         (GeglNode      *self);
static void            gegl_node_disconnect_sources       (GeglNode      *self);
static void            gegl_node_property_changed         (GObject       *gobject,
                                                           GParamSpec    *arg1,
                                                           gpointer       user_data);

114 115
static void            gegl_node_update_debug_name        (GeglNode *node);

116

117
G_DEFINE_TYPE_WITH_CODE (GeglNode, gegl_node, G_TYPE_OBJECT,
118
                         G_IMPLEMENT_INTERFACE (GEGL_TYPE_VISITABLE,
119
                                                gegl_node_visitable_iface_init))
120

121

122
static void
123
gegl_node_class_init (GeglNodeClass *klass)
124 125 126
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

127
  g_type_class_add_private (klass, sizeof (GeglNodePrivate));
128

129 130 131 132
  gobject_class->finalize     = gegl_node_finalize;
  gobject_class->dispose      = gegl_node_dispose;
  gobject_class->set_property = gegl_node_local_set_property;
  gobject_class->get_property = gegl_node_local_get_property;
133

134
  g_object_class_install_property (gobject_class, PROP_OPERATION,
135
                                   g_param_spec_object ("gegl-operation",
136 137 138
                                                        "Operation Object",
                                                        "The associated GeglOperation instance",
                                                        GEGL_TYPE_OPERATION,
139
                                                        G_PARAM_READWRITE |
140
                                                        G_PARAM_CONSTRUCT));
141

142
  g_object_class_install_property (gobject_class, PROP_OP_CLASS,
143
                                   g_param_spec_string ("operation",
144 145 146 147 148
                                                        "Operation Type",
                                                        "The type of associated GeglOperation",
                                                        "",
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_READWRITE));
149

150 151 152
  g_object_class_install_property (gobject_class, PROP_DONT_CACHE,
                                   g_param_spec_boolean ("dont-cache",
                                                         "Do not cache",
153
                                                        "Do not cache the result of this operation, the property is inherited by children created from a node.",
154 155
                                                        FALSE,
                                                        G_PARAM_CONSTRUCT |
156 157
                                                        G_PARAM_READWRITE));

158 159 160 161 162 163 164 165
  g_object_class_install_property (gobject_class, PROP_USE_OPENCL,
                                   g_param_spec_boolean ("use-opencl",
                                                         "Use OpenCL",
                                                         "Use the OpenCL version of this operation if available, this property is inherited by children created from a node.",
                                                         TRUE,
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_READWRITE));

166

167 168 169 170 171 172 173 174
  g_object_class_install_property (gobject_class, PROP_NAME,
                                   g_param_spec_string ("name",
                                                        "Name",
                                                        "The name of the node",
                                                        "",
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_READWRITE));

175 176 177
  gegl_node_signals[INVALIDATED] =
    g_signal_new ("invalidated",
                  G_TYPE_FROM_CLASS (klass),
178
                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
179 180
                  0,
                  NULL, NULL,
181
                  g_cclosure_marshal_VOID__BOXED,
182 183
                  G_TYPE_NONE, 1,
                  GEGL_TYPE_RECTANGLE);
184

185 186 187
  gegl_node_signals[COMPUTED] =
    g_signal_new ("computed",
                  G_TYPE_FROM_CLASS (klass),
188
                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
189 190
                  0,
                  NULL, NULL,
191
                  g_cclosure_marshal_VOID__BOXED,
192 193
                  G_TYPE_NONE, 1,
                  GEGL_TYPE_RECTANGLE);
194 195
}

196
static void
197
gegl_node_init (GeglNode *self)
198
{
199 200
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
                                            GEGL_TYPE_NODE,
201
                                            GeglNodePrivate);
202

203 204 205 206 207 208 209
  self->pads        = NULL;
  self->input_pads  = NULL;
  self->output_pads = NULL;
  self->operation   = NULL;
  self->is_graph    = FALSE;
  self->cache       = NULL;
  g_mutex_init (&self->mutex);
210

211 212
}

213
static void
214 215
gegl_node_visitable_iface_init (gpointer ginterface,
                                gpointer interface_data)
216 217 218
{
  GeglVisitableClass *visitable_class = ginterface;

219 220
  visitable_class->accept         = gegl_node_visitable_accept;
  visitable_class->depends_on     = gegl_node_visitable_depends_on;
221 222
}

223
static void
224
gegl_node_dispose (GObject *gobject)
225
{
226
  GeglNode *self = GEGL_NODE (gobject);
227

228
  if (self->priv->parent != NULL)
229
    {
230 231
      GeglNode *parent = self->priv->parent;
      self->priv->parent = NULL;
232 233 234
      gegl_node_remove_child (parent, self);
    }

235
  gegl_node_remove_children (self);
236 237 238 239 240
  if (self->cache)
    {
      g_object_unref (self->cache);
      self->cache = NULL;
    }
241

Daniel Sabo's avatar
Daniel Sabo committed
242 243 244 245 246
  if (self->priv->eval_manager)
    {
      g_object_unref (self->priv->eval_manager);
      self->priv->eval_manager = NULL;
    }
247

248 249 250
  G_OBJECT_CLASS (gegl_node_parent_class)->dispose (gobject);
}

251
static void
252
gegl_node_finalize (GObject *gobject)
253
{
254
  GeglNode *self = GEGL_NODE (gobject);
255

256 257
  gegl_node_disconnect_sources (self);
  gegl_node_disconnect_sinks (self);
258

Øyvind Kolås's avatar
Øyvind Kolås committed
259
  if (self->pads)
260
    {
261 262
      g_slist_foreach (self->pads, (GFunc) g_object_unref, NULL);
      g_slist_free (self->pads);
Øyvind Kolås's avatar
Øyvind Kolås committed
263
      self->pads = NULL;
264
    }
265

266 267
  g_slist_free (self->input_pads);
  g_slist_free (self->output_pads);
268

269 270 271 272 273 274
  if (self->operation)
    {
      g_object_unref (self->operation);
      self->operation = NULL;
    }

275
  if (self->priv->name)
276
    {
277
      g_free (self->priv->name);
278
    }
279 280 281 282 283 284

  if (self->priv->debug_name)
    {
      g_free (self->priv->debug_name);
    }

285
  g_mutex_clear (&self->mutex);
286

287
  G_OBJECT_CLASS (gegl_node_parent_class)->finalize (gobject);
288 289
}

290
static void
291 292 293 294
gegl_node_local_set_property (GObject      *gobject,
                              guint         property_id,
                              const GValue *value,
                              GParamSpec   *pspec)
295
{
296
  GeglNode *node = GEGL_NODE (gobject);
297

298 299
  switch (property_id)
    {
300 301 302 303
      case PROP_NAME:
        gegl_node_set_name (node, g_value_get_string (value));
        break;

304 305 306 307
      case PROP_DONT_CACHE:
        node->dont_cache = g_value_get_boolean (value);
        break;

308 309 310 311
      case PROP_USE_OPENCL:
        node->use_opencl = g_value_get_boolean (value);
        break;

312
      case PROP_OP_CLASS:
313 314
        {
          va_list null; /* dummy to pass along, it's not used anyways since
315 316
                         * the preceding argument is NULL, gcc might warn about
                         * use of uninitialized variable.
317
                         */
318
#if defined(__GNUC__)
319
          memset(&null, 0, sizeof(null));
320
#endif
321 322
          gegl_node_set_op_class (node, g_value_get_string (value), NULL, null);
        }
323 324 325
        break;

      case PROP_OPERATION:
326
        gegl_node_set_operation_object (node, g_value_get_object (value));
327 328 329 330 331
        break;

      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
        break;
332
    }
333 334 335
}

static void
336 337 338 339
gegl_node_local_get_property (GObject    *gobject,
                              guint       property_id,
                              GValue     *value,
                              GParamSpec *pspec)
340
{
341
  GeglNode *node = GEGL_NODE (gobject);
342

343 344
  switch (property_id)
    {
345 346 347 348
      case PROP_OP_CLASS:
        if (node->operation)
          g_value_set_string (value, GEGL_OPERATION_GET_CLASS (node->operation)->name);
        break;
349

350 351 352
      case PROP_DONT_CACHE:
        g_value_set_boolean (value, node->dont_cache);
        break;
353 354 355 356 357

      case PROP_USE_OPENCL:
        g_value_set_boolean (value, node->use_opencl);
        break;

358 359 360 361
      case PROP_NAME:
        g_value_set_string (value, gegl_node_get_name (node));
        break;

362 363 364 365
      case PROP_OPERATION:
        g_value_set_object (value, node->operation);
        break;

366 367 368
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
        break;
369
    }
370 371
}

372
/**
Øyvind Kolås's avatar
Øyvind Kolås committed
373
 * gegl_node_get_pad:
374
 * @self: a #GeglNode.
375
 * @name: property name.
376
 *
377
 * Get a property.
378
 *
Øyvind Kolås's avatar
Øyvind Kolås committed
379
 * Returns: A #GeglPad.
380
 **/
Øyvind Kolås's avatar
Øyvind Kolås committed
381 382 383
GeglPad *
gegl_node_get_pad (GeglNode    *self,
                   const gchar *name)
384
{
385
  GSList *list;
386

387 388 389
  g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
  g_return_val_if_fail (name != NULL, NULL);

390 391 392
  if (!self->pads)
    return NULL;

393
  for (list = self->pads; list; list = g_slist_next (list))
394
    {
Øyvind Kolås's avatar
Øyvind Kolås committed
395
      GeglPad *property = list->data;
396

397
      if (!strcmp (name, gegl_pad_get_name (property)))
398 399
        return property;
    }
400

401
  return NULL;
402
}
403

404 405 406 407 408 409 410
gboolean
gegl_node_has_pad (GeglNode      *self,
                   const gchar   *name)
{
  return gegl_node_get_pad (self, name) != NULL;
}

411
/**
Øyvind Kolås's avatar
Øyvind Kolås committed
412
 * gegl_node_get_pads:
413 414
 * @self: a #GeglNode.
 *
Øyvind Kolås's avatar
Øyvind Kolås committed
415
 * Returns: A list of #GeglPad.
416
 **/
417
GSList *
Øyvind Kolås's avatar
Øyvind Kolås committed
418
gegl_node_get_pads (GeglNode *self)
419
{
420 421
  g_return_val_if_fail (GEGL_IS_NODE (self), NULL);

Øyvind Kolås's avatar
Øyvind Kolås committed
422
  return self->pads;
423 424 425
}

/**
Øyvind Kolås's avatar
Øyvind Kolås committed
426
 * gegl_node_get_input_pads:
427 428
 * @self: a #GeglNode.
 *
Øyvind Kolås's avatar
Øyvind Kolås committed
429
 * Returns: A list of #GeglPad.
430
 **/
431
GSList *
Øyvind Kolås's avatar
Øyvind Kolås committed
432
gegl_node_get_input_pads (GeglNode *self)
433
{
434 435
  g_return_val_if_fail (GEGL_IS_NODE (self), NULL);

Øyvind Kolås's avatar
Øyvind Kolås committed
436
  return self->input_pads;
437 438
}

439
void
Øyvind Kolås's avatar
Øyvind Kolås committed
440 441
gegl_node_add_pad (GeglNode *self,
                   GeglPad  *pad)
442
{
443
  g_return_if_fail (GEGL_IS_NODE (self));
Øyvind Kolås's avatar
Øyvind Kolås committed
444
  g_return_if_fail (GEGL_IS_PAD (pad));
445

446
  if (gegl_node_get_pad (self, gegl_pad_get_name (pad)))
Martin Nordholts's avatar
Martin Nordholts committed
447 448
    return;

449
  self->pads = g_slist_prepend (self->pads, pad);
450

Øyvind Kolås's avatar
Øyvind Kolås committed
451
  if (gegl_pad_is_output (pad))
452
    self->output_pads = g_slist_prepend (self->output_pads, pad);
453

Øyvind Kolås's avatar
Øyvind Kolås committed
454
  if (gegl_pad_is_input (pad))
455
    self->input_pads = g_slist_prepend (self->input_pads, pad);
456 457 458
}

void
Øyvind Kolås's avatar
Øyvind Kolås committed
459 460
gegl_node_remove_pad (GeglNode *self,
                      GeglPad  *pad)
461
{
462 463
  GeglNode *pad_node;

464
  g_return_if_fail (GEGL_IS_NODE (self));
Øyvind Kolås's avatar
Øyvind Kolås committed
465
  g_return_if_fail (GEGL_IS_PAD (pad));
466

467
  self->pads = g_slist_remove (self->pads, pad);
468

Øyvind Kolås's avatar
Øyvind Kolås committed
469
  if (gegl_pad_is_output (pad))
470
    self->output_pads = g_slist_remove (self->output_pads, pad);
471

Øyvind Kolås's avatar
Øyvind Kolås committed
472
  if (gegl_pad_is_input (pad))
473
    self->input_pads = g_slist_remove (self->input_pads, pad);
474

475 476 477 478 479 480
  pad_node = gegl_pad_get_node (pad);

  /* This was a proxy pad, also remove the nop node */
  if (self != pad_node)
    gegl_node_remove_child (self, pad_node);

481
  g_object_unref (pad);
482
}
483

484
static gboolean
485 486 487 488
gegl_node_pads_exist (GeglNode    *sink,
                      const gchar *sink_pad_name,
                      GeglNode    *source,
                      const gchar *source_pad_name)
489
{
490
  GeglPad *sink_pad;
491

492 493 494
  GeglPad *source_pad;

  if (sink)
495
    {
496
      g_assert (sink_pad_name);
497
      sink_pad = gegl_node_get_pad (sink, sink_pad_name);
498 499
      if (!sink_pad || !gegl_pad_is_input (sink_pad))
        {
500 501
          g_warning ("%s: Can't find sink property %s of %s", G_STRFUNC,
                     sink_pad_name, gegl_node_get_debug_name (sink));
502 503
          return FALSE;
        }
504
    }
505 506

  if (source)
507
    {
508 509 510 511
      g_assert (source_pad_name);
      source_pad = gegl_node_get_pad (source, source_pad_name);
      if (!source_pad || !gegl_pad_is_output (source_pad))
        {
512 513
          g_warning ("%s: Can't find source property %s of %s", G_STRFUNC,
                     source_pad_name, gegl_node_get_debug_name (source));
514 515
          return FALSE;
        }
516
    }
517

518
  return TRUE;
519 520
}

521
static GeglConnection *
522 523
gegl_node_find_connection (GeglNode *sink,
                           GeglPad  *sink_pad)
524
{
525
  GSList *list;
526

527 528
  g_return_val_if_fail (GEGL_IS_NODE (sink), NULL);

529
  for (list = sink->priv->source_connections; list; list = g_slist_next (list))
530
    {
531
      GeglConnection *connection = list->data;
532

Øyvind Kolås's avatar
Øyvind Kolås committed
533
      if (sink_pad == gegl_connection_get_sink_pad (connection))
534 535
        return connection;
    }
536

537
  return NULL;
538
}
539

540 541 542 543 544 545 546 547 548
gboolean
gegl_node_connect_to (GeglNode    *source,
                      const gchar *source_pad_name,
                      GeglNode    *sink,
                      const gchar *sink_pad_name)
{
  return gegl_node_connect_from (sink, sink_pad_name, source, source_pad_name);
}

549
void
550
gegl_node_invalidated (GeglNode            *node,
551 552
                       const GeglRectangle *rect,
                       gboolean             clear_cache)
553
{
554
  g_return_if_fail (GEGL_IS_NODE (node));
555 556 557

  if (!rect)
    rect = &node->have_rect;
558

559 560
  if (node->cache)
    {
561 562
      if (rect && clear_cache)
        gegl_buffer_clear (GEGL_BUFFER (node->cache), rect);
563

564 565
      gegl_cache_invalidate (node->cache, rect);
    }
566
  node->valid_have_rect = FALSE;
567 568 569

  g_signal_emit (node, gegl_node_signals[INVALIDATED], 0,
                 rect, NULL);
570 571
}

572
static void
573 574 575
gegl_node_source_invalidated (GeglNode            *source,
                              const GeglRectangle *rect,
                              gpointer             data)
576
{
577 578 579
  GeglPad       *destination_pad = GEGL_PAD (data);
  GeglNode      *destination     = gegl_pad_get_node (destination_pad);
  GeglRectangle  dirty_rect;
580

581 582 583 584 585
  GEGL_NOTE (GEGL_DEBUG_INVALIDATION, "%s.%s is dirtied from %s (%i,%i %i×%i)",
             gegl_node_get_debug_name (destination), gegl_pad_get_name (destination_pad),
             gegl_node_get_debug_name (source),
             rect->x, rect->y,
             rect->width, rect->height);
586 587 588

  if (destination->operation)
    {
589
      dirty_rect =
590 591 592
        gegl_operation_get_invalidated_by_change (destination->operation,
                                                  gegl_pad_get_name (destination_pad),
                                                  rect);
593 594 595 596 597 598
    }
  else
    {
      dirty_rect = *rect;
    }

599
  gegl_node_invalidated (destination, &dirty_rect, FALSE);
600 601
}

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
static GSList *
gegl_node_get_depends_on (GeglNode *self);

static gboolean
gegl_node_has_source (GeglNode *self,
                      GeglNode *potential_source)
{
  GSList *producers, *p;
  gboolean found = FALSE;

  if (self == potential_source)
    return TRUE;

  producers = gegl_node_get_depends_on (self);
  for (p = producers; p; p = p->next)
    {
      if (p->data == potential_source)
        found = TRUE;
      else
        found = gegl_node_has_source (p->data, potential_source);
      if (found)
        break;
    }
  g_slist_free (producers);

  return found;
}

630
gboolean
631
gegl_node_connect_from (GeglNode    *sink,
632 633 634
                        const gchar *sink_pad_name,
                        GeglNode    *source,
                        const gchar *source_pad_name)
635
{
636 637 638 639
  GeglNode    *real_sink            = sink;
  GeglNode    *real_source          = source;
  const gchar *real_sink_pad_name   = sink_pad_name;
  const gchar *real_source_pad_name = source_pad_name;
640

641
  g_return_val_if_fail (GEGL_IS_NODE (sink), FALSE);
642
  g_return_val_if_fail (sink_pad_name != NULL, FALSE);
643
  g_return_val_if_fail (GEGL_IS_NODE (source), FALSE);
644
  g_return_val_if_fail (source_pad_name != NULL, FALSE);
645

646 647 648 649 650 651
  if (gegl_node_has_source (source, sink))
    {
      g_warning ("Construction of loop requested, bailing\n");
      return FALSE;
    }

652 653
  /* For graph nodes we implicitly use the proxy nodes */
  if (sink->is_graph)
654 655 656 657 658 659 660 661
    {
      real_sink = gegl_node_get_input_proxy (sink, sink_pad_name);

      /* The name of the input pad of proxynop input nodes is always
       * "input"
       */
      real_sink_pad_name = "input";
    }
662
  if (source->is_graph)
663 664 665 666
    {
      real_source = gegl_node_get_output_proxy (source, source_pad_name);

      /* The name of the output pad of proxynop output nodes is always
667
       * "output"
668 669 670
       */
      real_source_pad_name = "output";
    }
671

672 673 674
  {
    GeglPad *pad;
    GeglPad *other_pad = NULL;
675

676
    pad = gegl_node_get_pad (real_sink, real_sink_pad_name);
677 678 679 680
    if (pad)
      other_pad = gegl_pad_get_connected_to (pad);
    else
      {
681
        g_warning ("%s: Didn't find pad '%s' of '%s'",
682
                   G_STRFUNC, real_sink_pad_name, gegl_node_get_debug_name (real_sink));
683
      }
684 685 686

    if (other_pad)
      {
687
        gegl_node_disconnect (real_sink, real_sink_pad_name);
688
      }
689
  }
690
  if (gegl_node_pads_exist (real_sink, real_sink_pad_name, real_source, real_source_pad_name))
691
    {
692 693
      GeglPad        *sink_pad   = gegl_node_get_pad (real_sink, real_sink_pad_name);
      GeglPad        *source_pad = gegl_node_get_pad (real_source, real_source_pad_name);
694 695
      GeglConnection *connection = gegl_pad_connect (sink_pad,
                                                     source_pad);
696

697 698
      gegl_connection_set_sink_node (connection, real_sink);
      gegl_connection_set_source_node (connection, real_source);
699

700 701
      real_sink->priv->source_connections = g_slist_prepend (real_sink->priv->source_connections, connection);
      real_source->priv->sink_connections = g_slist_prepend (real_source->priv->sink_connections, connection);
702

703
      g_signal_connect (G_OBJECT (real_source), "invalidated",
704
                        G_CALLBACK (gegl_node_source_invalidated), sink_pad);
705

706
      gegl_node_property_changed (G_OBJECT (real_source->operation), NULL, real_source);
707

708
      return TRUE;
709
    }
710 711

  return FALSE;
712 713
}

714
gboolean
715
gegl_node_disconnect (GeglNode    *sink,
716
                      const gchar *sink_pad_name)
717
{
718 719
  GeglNode    *real_sink          = sink;
  const gchar *real_sink_pad_name = sink_pad_name;
720

721
  g_return_val_if_fail (GEGL_IS_NODE (sink), FALSE);
722
  g_return_val_if_fail (sink_pad_name != NULL, FALSE);
723

724 725
  /* For graph nodes we implicitly use the proxy nodes */
  if (sink->is_graph)
726 727 728 729 730 731 732 733
    {
      real_sink = gegl_node_get_input_proxy (sink, sink_pad_name);

      /* The name of the input pad of proxynop input nodes is always
       * "input"
       */
      real_sink_pad_name = "input";
    }
734

735
  if (gegl_node_pads_exist (real_sink, real_sink_pad_name, NULL, NULL))
736
    {
737
      GeglPad        *sink_pad   = gegl_node_get_pad (real_sink, real_sink_pad_name);
738
      GeglConnection *connection = gegl_node_find_connection (real_sink, sink_pad);
739 740
      GeglNode       *source;
      GeglPad        *source_pad;
741

742
      if (!connection)
743 744
        return FALSE;

745
      source_pad = gegl_connection_get_source_pad (connection);
746
      source     = gegl_connection_get_source_node (connection);
747

748 749
      gegl_node_source_invalidated (source, &source->have_rect, sink_pad);

750 751 752 753 754
      {
        /* disconnecting dirt propagation */
        gulong handler;

        handler = g_signal_handler_find (source, G_SIGNAL_MATCH_DATA,
755
                                         gegl_node_signals[INVALIDATED],
756
                                         0, NULL, NULL, sink_pad);
757 758 759 760 761 762
        if (handler)
          {
            g_signal_handler_disconnect (source, handler);
          }
      }

Øyvind Kolås's avatar
Øyvind Kolås committed
763
      gegl_pad_disconnect (sink_pad, source_pad, connection);
764

765
      real_sink->priv->source_connections = g_slist_remove (real_sink->priv->source_connections, connection);
766
      source->priv->sink_connections = g_slist_remove (source->priv->sink_connections, connection);
767

768
      gegl_connection_destroy (connection);
769

770

771
      return TRUE;
772
    }
773 774

  return FALSE;
775 776
}

777
static void
778 779
gegl_node_disconnect_sources (GeglNode *self)
{
780 781
  while (TRUE)
    {
782
      GeglConnection *connection = g_slist_nth_data (self->priv->source_connections, 0);
783 784 785

      if (connection)
        {
786 787
          GeglNode    *sink          = gegl_connection_get_sink_node (connection);
          GeglPad     *sink_pad      = gegl_connection_get_sink_pad (connection);
Øyvind Kolås's avatar
Øyvind Kolås committed
788
          const gchar *sink_pad_name = gegl_pad_get_name (sink_pad);
789 790 791

          g_assert (self == sink);

792
          gegl_node_disconnect (sink, sink_pad_name);
793 794 795 796
        }
      else
        break;
    }
797 798
}

799
static void
800 801
gegl_node_disconnect_sinks (GeglNode *self)
{
802 803
  while (TRUE)
    {
804
      GeglConnection *connection = g_slist_nth_data (self->priv->sink_connections, 0);
805 806 807

      if (connection)
        {
808 809 810
          GeglNode    *sink          = gegl_connection_get_sink_node (connection);
          GeglNode    *source        = gegl_connection_get_source_node (connection);
          GeglPad     *sink_pad      = gegl_connection_get_sink_pad (connection);
Øyvind Kolås's avatar
Øyvind Kolås committed
811
          const gchar *sink_pad_name = gegl_pad_get_name (sink_pad);
812 813 814

          g_assert (self == source);

815
          gegl_node_disconnect (sink, sink_pad_name);
816 817 818 819
        }
      else
        break;
    }
820 821
}

822
/**
823
 * gegl_node_num_sinks:
824 825
 * @self: a #GeglNode.
 *
826
 * Gets the number of sinks
827
 *
828
 * Returns: number of sinks
829
 **/
830
gint
831
gegl_node_get_num_sinks (GeglNode *self)
832 833
{
  g_return_val_if_fail (GEGL_IS_NODE (self), -1);
834

835
  return g_slist_length (self->priv->sink_connections);
836 837 838
}

/**
839
 * gegl_node_get_sinks:
840 841
 * @self: a #GeglNode.
 *
842
 * Gets list of sink connections attached to this self.
843
 *
844
 * Returns: list of sink connections.
845
 **/
846
GSList *
847
gegl_node_get_sinks (GeglNode *self)
848
{
849 850
  g_return_val_if_fail (GEGL_IS_NODE (self), FALSE);

851
  return self->priv->sink_connections;
852 853
}

854 855 856
void
gegl_node_link (GeglNode *source,
                GeglNode *sink)
Øyvind Kolås's avatar
Øyvind Kolås committed
857
{
858 859 860
  g_return_if_fail (GEGL_IS_NODE (source));
  g_return_if_fail (GEGL_IS_NODE (sink));

861 862 863 864
  /* using connect_to is more natural here, but leads to an extra
   * function call, perhaps connect_to and connect_from should be swapped?
   */
  gegl_node_connect_to (source, "output", sink, "input");
Øyvind Kolås's avatar
Øyvind Kolås committed
865 866
}

867 868 869 870
void
gegl_node_link_many (GeglNode *source,
                     GeglNode *dest,
                     ...)
Øyvind Kolås's avatar
Øyvind Kolås committed
871
{
872 873
  va_list var_args;

874 875
  g_return_if_fail (GEGL_IS_NODE (source));
  g_return_if_fail (GEGL_IS_NODE (dest));
Øyvind Kolås's avatar
Øyvind Kolås committed
876 877 878 879 880 881

  va_start (var_args, dest);
  while (dest)
    {
      gegl_node_link (source, dest);
      source = dest;
882
      dest   = va_arg (var_args, GeglNode *);
Øyvind Kolås's avatar
Øyvind Kolås committed
883 884 885 886
    }
  va_end (var_args);
}

Daniel Sabo's avatar
Daniel Sabo committed
887 888
static GeglEvalManager *
gegl_node_get_eval_manager (GeglNode *self)
889
{
Daniel Sabo's avatar
Daniel Sabo committed
890 891 892
  if (!self->priv->eval_manager)
    self->priv->eval_manager = gegl_eval_manager_new (self, "output");
  return self->priv->eval_manager;
893 894
}

895
static GeglBuffer *
896
gegl_node_apply_roi (GeglNode            *self,
Daniel Sabo's avatar
Daniel Sabo committed
897 898 899
                     const GeglRectangle *roi)
{
  GeglEvalManager *eval_manager = gegl_node_get_eval_manager (self);
900

901 902
  if (roi)
    {
Daniel Sabo's avatar
Daniel Sabo committed
903
      return gegl_eval_manager_apply (eval_manager, roi);
904 905 906
    }
  else
    {
Daniel Sabo's avatar
Daniel Sabo committed
907 908
      GeglRectangle node_bbox = gegl_node_get_bounding_box (self);
      return gegl_eval_manager_apply (eval_manager, &node_bbox);
909
    }
910
}
Øyvind Kolås's avatar
Øyvind Kolås committed
911

Daniel Sabo's avatar
Daniel Sabo committed
912 913 914 915
void
gegl_node_blit_buffer (GeglNode            *self,
                       GeglBuffer          *buffer,
                       const GeglRectangle *roi)
916
{
Daniel Sabo's avatar
Daniel Sabo committed
917 918 919
  GeglEvalManager *eval_manager;
  GeglBuffer      *result;
  GeglRectangle    request;
920