1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /* This file contains the code necessary for generating on canvas
19 * previews, by connecting a specified GEGL operation to do the
20 * processing. It uses drawable filters that allow for non-destructive
21 * manipulation of drawable data, with live preview on screen.
22 *
23 * To create a tool that uses this, see app/tools/gimpfiltertool.c for
24 * the interface and e.g. app/tools/gimpcolorbalancetool.c for an
25 * example of using that interface.
26 */
27
28 #include "config.h"
29
30 #include <cairo.h>
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <gegl.h>
33
34 #include "libgimpbase/gimpbase.h"
35 #include "libgimpcolor/gimpcolor.h"
36
37 #include "core-types.h"
38
39 #include "gegl/gimp-babl.h"
40 #include "gegl/gimpapplicator.h"
41 #include "gegl/gimp-gegl-utils.h"
42
43 #include "gimpchannel.h"
44 #include "gimpdrawable-filters.h"
45 #include "gimpdrawablefilter.h"
46 #include "gimpimage.h"
47 #include "gimplayer.h"
48 #include "gimpmarshal.h"
49 #include "gimpprogress.h"
50
51
52 enum
53 {
54 FLUSH,
55 LAST_SIGNAL
56 };
57
58
59 struct _GimpDrawableFilter
60 {
61 GimpFilter parent_instance;
62
63 GimpDrawable *drawable;
64 GeglNode *operation;
65
66 gboolean has_input;
67
68 gboolean clip;
69 GimpFilterRegion region;
70 gboolean crop_enabled;
71 GeglRectangle crop_rect;
72 gboolean preview_enabled;
73 gboolean preview_split_enabled;
74 GimpAlignmentType preview_split_alignment;
75 gint preview_split_position;
76 gdouble opacity;
77 GimpLayerMode paint_mode;
78 GimpLayerColorSpace blend_space;
79 GimpLayerColorSpace composite_space;
80 GimpLayerCompositeMode composite_mode;
81 gboolean add_alpha;
82 gboolean color_managed;
83 gboolean gamma_hack;
84
85 gboolean override_constraints;
86
87 GeglRectangle filter_area;
88 gboolean filter_clip;
89
90 GeglNode *translate;
91 GeglNode *crop_before;
92 GeglNode *cast_before;
93 GeglNode *transform_before;
94 GeglNode *transform_after;
95 GeglNode *cast_after;
96 GeglNode *crop_after;
97 GimpApplicator *applicator;
98 };
99
100
101 static void gimp_drawable_filter_dispose (GObject *object);
102 static void gimp_drawable_filter_finalize (GObject *object);
103
104 static void gimp_drawable_filter_sync_active (GimpDrawableFilter *filter);
105 static void gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
106 gboolean sync_region);
107 static void gimp_drawable_filter_sync_region (GimpDrawableFilter *filter);
108 static void gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
109 gboolean old_crop_enabled,
110 const GeglRectangle *old_crop_rect,
111 gboolean old_preview_split_enabled,
112 GimpAlignmentType old_preview_split_alignment,
113 gint old_preview_split_position,
114 gboolean update);
115 static void gimp_drawable_filter_sync_opacity (GimpDrawableFilter *filter);
116 static void gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter);
117 static void gimp_drawable_filter_sync_affect (GimpDrawableFilter *filter);
118 static void gimp_drawable_filter_sync_format (GimpDrawableFilter *filter);
119 static void gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter);
120 static void gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter);
121 static void gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter);
122
123 static gboolean gimp_drawable_filter_is_added (GimpDrawableFilter *filter);
124 static gboolean gimp_drawable_filter_is_active (GimpDrawableFilter *filter);
125 static gboolean gimp_drawable_filter_add_filter (GimpDrawableFilter *filter);
126 static gboolean gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter);
127
128 static void gimp_drawable_filter_update_drawable (GimpDrawableFilter *filter,
129 const GeglRectangle *area);
130
131 static void gimp_drawable_filter_affect_changed (GimpImage *image,
132 GimpChannelType channel,
133 GimpDrawableFilter *filter);
134 static void gimp_drawable_filter_mask_changed (GimpImage *image,
135 GimpDrawableFilter *filter);
136 static void gimp_drawable_filter_profile_changed (GimpColorManaged *managed,
137 GimpDrawableFilter *filter);
138 static void gimp_drawable_filter_lock_position_changed (GimpDrawable *drawable,
139 GimpDrawableFilter *filter);
140 static void gimp_drawable_filter_format_changed (GimpDrawable *drawable,
141 GimpDrawableFilter *filter);
142 static void gimp_drawable_filter_drawable_removed (GimpDrawable *drawable,
143 GimpDrawableFilter *filter);
144 static void gimp_drawable_filter_lock_alpha_changed (GimpLayer *layer,
145 GimpDrawableFilter *filter);
146
147
148 G_DEFINE_TYPE (GimpDrawableFilter, gimp_drawable_filter, GIMP_TYPE_FILTER)
149
150 #define parent_class gimp_drawable_filter_parent_class
151
152 static guint drawable_filter_signals[LAST_SIGNAL] = { 0, };
153
154
155 static void
gimp_drawable_filter_class_init(GimpDrawableFilterClass * klass)156 gimp_drawable_filter_class_init (GimpDrawableFilterClass *klass)
157 {
158 GObjectClass *object_class = G_OBJECT_CLASS (klass);
159
160 drawable_filter_signals[FLUSH] =
161 g_signal_new ("flush",
162 G_TYPE_FROM_CLASS (klass),
163 G_SIGNAL_RUN_FIRST,
164 G_STRUCT_OFFSET (GimpDrawableFilterClass, flush),
165 NULL, NULL,
166 gimp_marshal_VOID__VOID,
167 G_TYPE_NONE, 0);
168
169 object_class->dispose = gimp_drawable_filter_dispose;
170 object_class->finalize = gimp_drawable_filter_finalize;
171 }
172
173 static void
gimp_drawable_filter_init(GimpDrawableFilter * drawable_filter)174 gimp_drawable_filter_init (GimpDrawableFilter *drawable_filter)
175 {
176 drawable_filter->clip = TRUE;
177 drawable_filter->region = GIMP_FILTER_REGION_SELECTION;
178 drawable_filter->preview_enabled = TRUE;
179 drawable_filter->preview_split_enabled = FALSE;
180 drawable_filter->preview_split_alignment = GIMP_ALIGN_LEFT;
181 drawable_filter->preview_split_position = 0;
182 drawable_filter->opacity = GIMP_OPACITY_OPAQUE;
183 drawable_filter->paint_mode = GIMP_LAYER_MODE_REPLACE;
184 drawable_filter->blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
185 drawable_filter->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
186 drawable_filter->composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
187 }
188
189 static void
gimp_drawable_filter_dispose(GObject * object)190 gimp_drawable_filter_dispose (GObject *object)
191 {
192 GimpDrawableFilter *drawable_filter = GIMP_DRAWABLE_FILTER (object);
193
194 if (drawable_filter->drawable)
195 gimp_drawable_filter_remove_filter (drawable_filter);
196
197 G_OBJECT_CLASS (parent_class)->dispose (object);
198 }
199
200 static void
gimp_drawable_filter_finalize(GObject * object)201 gimp_drawable_filter_finalize (GObject *object)
202 {
203 GimpDrawableFilter *drawable_filter = GIMP_DRAWABLE_FILTER (object);
204
205 g_clear_object (&drawable_filter->operation);
206 g_clear_object (&drawable_filter->applicator);
207 g_clear_object (&drawable_filter->drawable);
208
209 G_OBJECT_CLASS (parent_class)->finalize (object);
210 }
211
212 GimpDrawableFilter *
gimp_drawable_filter_new(GimpDrawable * drawable,const gchar * undo_desc,GeglNode * operation,const gchar * icon_name)213 gimp_drawable_filter_new (GimpDrawable *drawable,
214 const gchar *undo_desc,
215 GeglNode *operation,
216 const gchar *icon_name)
217 {
218 GimpDrawableFilter *filter;
219 GeglNode *node;
220
221 g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
222 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
223 g_return_val_if_fail (GEGL_IS_NODE (operation), NULL);
224 g_return_val_if_fail (gegl_node_has_pad (operation, "output"), NULL);
225
226 filter = g_object_new (GIMP_TYPE_DRAWABLE_FILTER,
227 "name", undo_desc,
228 "icon-name", icon_name,
229 NULL);
230
231 filter->drawable = g_object_ref (drawable);
232 filter->operation = g_object_ref (operation);
233
234 node = gimp_filter_get_node (GIMP_FILTER (filter));
235
236 gegl_node_add_child (node, operation);
237 gimp_gegl_node_set_underlying_operation (node, operation);
238
239 filter->applicator = gimp_applicator_new (node);
240
241 gimp_filter_set_applicator (GIMP_FILTER (filter), filter->applicator);
242
243 gimp_applicator_set_cache (filter->applicator, TRUE);
244
245 filter->has_input = gegl_node_has_pad (filter->operation, "input");
246
247 if (filter->has_input)
248 {
249 GeglNode *input;
250
251 input = gegl_node_get_input_proxy (node, "input");
252
253 filter->translate = gegl_node_new_child (node,
254 "operation", "gegl:translate",
255 NULL);
256
257 filter->crop_before = gegl_node_new_child (node,
258 "operation", "gegl:crop",
259 NULL);
260
261 filter->cast_before = gegl_node_new_child (node,
262 "operation", "gegl:nop",
263 NULL);
264
265 filter->transform_before = gegl_node_new_child (node,
266 "operation", "gegl:nop",
267 NULL);
268
269 gegl_node_link_many (input,
270 filter->translate,
271 filter->crop_before,
272 filter->cast_before,
273 filter->transform_before,
274 filter->operation,
275 NULL);
276 }
277
278 filter->transform_after = gegl_node_new_child (node,
279 "operation", "gegl:nop",
280 NULL);
281
282 filter->cast_after = gegl_node_new_child (node,
283 "operation", "gegl:nop",
284 NULL);
285
286 filter->crop_after = gegl_node_new_child (node,
287 "operation", "gegl:crop",
288 NULL);
289
290 gegl_node_link_many (filter->operation,
291 filter->transform_after,
292 filter->cast_after,
293 filter->crop_after,
294 NULL);
295
296 gegl_node_connect_to (filter->crop_after, "output",
297 node, "aux");
298
299 return filter;
300 }
301
302 GimpDrawable *
gimp_drawable_filter_get_drawable(GimpDrawableFilter * filter)303 gimp_drawable_filter_get_drawable (GimpDrawableFilter *filter)
304 {
305 g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
306
307 return filter->drawable;
308 }
309
310 GeglNode *
gimp_drawable_filter_get_operation(GimpDrawableFilter * filter)311 gimp_drawable_filter_get_operation (GimpDrawableFilter *filter)
312 {
313 g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
314
315 return filter->operation;
316 }
317
318 void
gimp_drawable_filter_set_clip(GimpDrawableFilter * filter,gboolean clip)319 gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
320 gboolean clip)
321 {
322 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
323
324 if (clip != filter->clip)
325 {
326 filter->clip = clip;
327
328 gimp_drawable_filter_sync_clip (filter, TRUE);
329 }
330 }
331
332 void
gimp_drawable_filter_set_region(GimpDrawableFilter * filter,GimpFilterRegion region)333 gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
334 GimpFilterRegion region)
335 {
336 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
337
338 if (region != filter->region)
339 {
340 filter->region = region;
341
342 gimp_drawable_filter_sync_region (filter);
343
344 if (gimp_drawable_filter_is_active (filter))
345 gimp_drawable_filter_update_drawable (filter, NULL);
346 }
347 }
348
349 void
gimp_drawable_filter_set_crop(GimpDrawableFilter * filter,const GeglRectangle * rect,gboolean update)350 gimp_drawable_filter_set_crop (GimpDrawableFilter *filter,
351 const GeglRectangle *rect,
352 gboolean update)
353 {
354 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
355
356 if ((rect != NULL) != filter->crop_enabled ||
357 (rect && ! gegl_rectangle_equal (rect, &filter->crop_rect)))
358 {
359 gboolean old_enabled = filter->crop_enabled;
360 GeglRectangle old_rect = filter->crop_rect;
361
362 if (rect)
363 {
364 filter->crop_enabled = TRUE;
365 filter->crop_rect = *rect;
366 }
367 else
368 {
369 filter->crop_enabled = FALSE;
370 }
371
372 gimp_drawable_filter_sync_crop (filter,
373 old_enabled,
374 &old_rect,
375 filter->preview_split_enabled,
376 filter->preview_split_alignment,
377 filter->preview_split_position,
378 update);
379 }
380 }
381
382 void
gimp_drawable_filter_set_preview(GimpDrawableFilter * filter,gboolean enabled)383 gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
384 gboolean enabled)
385 {
386 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
387
388 if (enabled != filter->preview_enabled)
389 {
390 filter->preview_enabled = enabled;
391
392 gimp_drawable_filter_sync_active (filter);
393
394 if (gimp_drawable_filter_is_added (filter))
395 {
396 gimp_drawable_update_bounding_box (filter->drawable);
397
398 gimp_drawable_filter_update_drawable (filter, NULL);
399 }
400 }
401 }
402
403 void
gimp_drawable_filter_set_preview_split(GimpDrawableFilter * filter,gboolean enabled,GimpAlignmentType alignment,gint position)404 gimp_drawable_filter_set_preview_split (GimpDrawableFilter *filter,
405 gboolean enabled,
406 GimpAlignmentType alignment,
407 gint position)
408 {
409 GimpItem *item;
410
411 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
412 g_return_if_fail (alignment == GIMP_ALIGN_LEFT ||
413 alignment == GIMP_ALIGN_RIGHT ||
414 alignment == GIMP_ALIGN_TOP ||
415 alignment == GIMP_ALIGN_BOTTOM);
416
417 item = GIMP_ITEM (filter->drawable);
418
419 switch (alignment)
420 {
421 case GIMP_ALIGN_LEFT:
422 case GIMP_ALIGN_RIGHT:
423 position = CLAMP (position, 0, gimp_item_get_width (item));
424 break;
425
426 case GIMP_ALIGN_TOP:
427 case GIMP_ALIGN_BOTTOM:
428 position = CLAMP (position, 0, gimp_item_get_height (item));
429 break;
430
431 default:
432 g_return_if_reached ();
433 }
434
435 if (enabled != filter->preview_split_enabled ||
436 alignment != filter->preview_split_alignment ||
437 position != filter->preview_split_position)
438 {
439 gboolean old_enabled = filter->preview_split_enabled;
440 GimpAlignmentType old_alignment = filter->preview_split_alignment;
441 gint old_position = filter->preview_split_position;
442
443 filter->preview_split_enabled = enabled;
444 filter->preview_split_alignment = alignment;
445 filter->preview_split_position = position;
446
447 gimp_drawable_filter_sync_crop (filter,
448 filter->crop_enabled,
449 &filter->crop_rect,
450 old_enabled,
451 old_alignment,
452 old_position,
453 TRUE);
454 }
455 }
456
457 void
gimp_drawable_filter_set_opacity(GimpDrawableFilter * filter,gdouble opacity)458 gimp_drawable_filter_set_opacity (GimpDrawableFilter *filter,
459 gdouble opacity)
460 {
461 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
462
463 if (opacity != filter->opacity)
464 {
465 filter->opacity = opacity;
466
467 gimp_drawable_filter_sync_opacity (filter);
468
469 if (gimp_drawable_filter_is_active (filter))
470 gimp_drawable_filter_update_drawable (filter, NULL);
471 }
472 }
473
474 void
gimp_drawable_filter_set_mode(GimpDrawableFilter * filter,GimpLayerMode paint_mode,GimpLayerColorSpace blend_space,GimpLayerColorSpace composite_space,GimpLayerCompositeMode composite_mode)475 gimp_drawable_filter_set_mode (GimpDrawableFilter *filter,
476 GimpLayerMode paint_mode,
477 GimpLayerColorSpace blend_space,
478 GimpLayerColorSpace composite_space,
479 GimpLayerCompositeMode composite_mode)
480 {
481 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
482
483 if (paint_mode != filter->paint_mode ||
484 blend_space != filter->blend_space ||
485 composite_space != filter->composite_space ||
486 composite_mode != filter->composite_mode)
487 {
488 filter->paint_mode = paint_mode;
489 filter->blend_space = blend_space;
490 filter->composite_space = composite_space;
491 filter->composite_mode = composite_mode;
492
493 gimp_drawable_filter_sync_mode (filter);
494
495 if (gimp_drawable_filter_is_active (filter))
496 gimp_drawable_filter_update_drawable (filter, NULL);
497 }
498 }
499
500 void
gimp_drawable_filter_set_add_alpha(GimpDrawableFilter * filter,gboolean add_alpha)501 gimp_drawable_filter_set_add_alpha (GimpDrawableFilter *filter,
502 gboolean add_alpha)
503 {
504 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
505
506 if (add_alpha != filter->add_alpha)
507 {
508 filter->add_alpha = add_alpha;
509
510 gimp_drawable_filter_sync_format (filter);
511
512 if (gimp_drawable_filter_is_active (filter))
513 gimp_drawable_filter_update_drawable (filter, NULL);
514 }
515 }
516
517 void
gimp_drawable_filter_set_color_managed(GimpDrawableFilter * filter,gboolean color_managed)518 gimp_drawable_filter_set_color_managed (GimpDrawableFilter *filter,
519 gboolean color_managed)
520 {
521 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
522
523 if (color_managed != filter->color_managed)
524 {
525 filter->color_managed = color_managed;
526
527 gimp_drawable_filter_sync_transform (filter);
528
529 if (gimp_drawable_filter_is_active (filter))
530 gimp_drawable_filter_update_drawable (filter, NULL);
531 }
532 }
533
534 void
gimp_drawable_filter_set_gamma_hack(GimpDrawableFilter * filter,gboolean gamma_hack)535 gimp_drawable_filter_set_gamma_hack (GimpDrawableFilter *filter,
536 gboolean gamma_hack)
537 {
538 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
539
540 if (gamma_hack != filter->gamma_hack)
541 {
542 filter->gamma_hack = gamma_hack;
543
544 gimp_drawable_filter_sync_gamma_hack (filter);
545 gimp_drawable_filter_sync_transform (filter);
546
547 if (gimp_drawable_filter_is_active (filter))
548 gimp_drawable_filter_update_drawable (filter, NULL);
549 }
550 }
551
552 void
gimp_drawable_filter_set_override_constraints(GimpDrawableFilter * filter,gboolean override_constraints)553 gimp_drawable_filter_set_override_constraints (GimpDrawableFilter *filter,
554 gboolean override_constraints)
555 {
556 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
557
558 if (override_constraints != filter->override_constraints)
559 {
560 filter->override_constraints = override_constraints;
561
562 gimp_drawable_filter_sync_affect (filter);
563 gimp_drawable_filter_sync_format (filter);
564 gimp_drawable_filter_sync_clip (filter, TRUE);
565
566 if (gimp_drawable_filter_is_active (filter))
567 gimp_drawable_filter_update_drawable (filter, NULL);
568 }
569 }
570
571 const Babl *
gimp_drawable_filter_get_format(GimpDrawableFilter * filter)572 gimp_drawable_filter_get_format (GimpDrawableFilter *filter)
573 {
574 const Babl *format;
575
576 g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
577
578 format = gimp_applicator_get_output_format (filter->applicator);
579
580 if (! format)
581 format = gimp_drawable_get_format (filter->drawable);
582
583 return format;
584 }
585
586 void
gimp_drawable_filter_apply(GimpDrawableFilter * filter,const GeglRectangle * area)587 gimp_drawable_filter_apply (GimpDrawableFilter *filter,
588 const GeglRectangle *area)
589 {
590 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
591 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)));
592
593 gimp_drawable_filter_add_filter (filter);
594
595 gimp_drawable_filter_sync_clip (filter, TRUE);
596
597 if (gimp_drawable_filter_is_active (filter))
598 {
599 gimp_drawable_update_bounding_box (filter->drawable);
600
601 gimp_drawable_filter_update_drawable (filter, area);
602 }
603 }
604
605 gboolean
gimp_drawable_filter_commit(GimpDrawableFilter * filter,GimpProgress * progress,gboolean cancellable)606 gimp_drawable_filter_commit (GimpDrawableFilter *filter,
607 GimpProgress *progress,
608 gboolean cancellable)
609 {
610 gboolean success = TRUE;
611
612 g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), FALSE);
613 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)),
614 FALSE);
615 g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
616
617 if (gimp_drawable_filter_is_added (filter))
618 {
619 const Babl *format;
620
621 format = gimp_drawable_filter_get_format (filter);
622
623 gimp_drawable_filter_set_preview_split (filter, FALSE,
624 filter->preview_split_alignment,
625 filter->preview_split_position);
626 gimp_drawable_filter_set_preview (filter, TRUE);
627
628 success = gimp_drawable_merge_filter (filter->drawable,
629 GIMP_FILTER (filter),
630 progress,
631 gimp_object_get_name (filter),
632 format,
633 filter->filter_clip,
634 cancellable,
635 FALSE);
636
637 gimp_drawable_filter_remove_filter (filter);
638
639 if (! success)
640 gimp_drawable_filter_update_drawable (filter, NULL);
641
642 g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
643 }
644
645 return success;
646 }
647
648 void
gimp_drawable_filter_abort(GimpDrawableFilter * filter)649 gimp_drawable_filter_abort (GimpDrawableFilter *filter)
650 {
651 g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
652
653 if (gimp_drawable_filter_remove_filter (filter))
654 {
655 gimp_drawable_filter_update_drawable (filter, NULL);
656 }
657 }
658
659
660 /* private functions */
661
662 static void
gimp_drawable_filter_sync_active(GimpDrawableFilter * filter)663 gimp_drawable_filter_sync_active (GimpDrawableFilter *filter)
664 {
665 gimp_applicator_set_active (filter->applicator, filter->preview_enabled);
666 }
667
668 static void
gimp_drawable_filter_sync_clip(GimpDrawableFilter * filter,gboolean sync_region)669 gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
670 gboolean sync_region)
671 {
672 gboolean clip;
673
674 if (filter->override_constraints)
675 clip = filter->clip;
676 else
677 clip = gimp_item_get_clip (GIMP_ITEM (filter->drawable), filter->clip);
678
679 if (! clip)
680 {
681 GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
682 GimpChannel *mask = gimp_image_get_mask (image);
683
684 if (! gimp_channel_is_empty (mask))
685 clip = TRUE;
686 }
687
688 if (! clip)
689 {
690 GeglRectangle bounding_box;
691
692 bounding_box = gegl_node_get_bounding_box (filter->operation);
693
694 if (gegl_rectangle_is_infinite_plane (&bounding_box))
695 clip = TRUE;
696 }
697
698 if (clip != filter->filter_clip)
699 {
700 filter->filter_clip = clip;
701
702 if (sync_region)
703 gimp_drawable_filter_sync_region (filter);
704 }
705 }
706
707 static void
gimp_drawable_filter_sync_region(GimpDrawableFilter * filter)708 gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
709 {
710 if (filter->region == GIMP_FILTER_REGION_SELECTION)
711 {
712 if (filter->has_input)
713 {
714 gegl_node_set (filter->translate,
715 "x", (gdouble) -filter->filter_area.x,
716 "y", (gdouble) -filter->filter_area.y,
717 NULL);
718
719 gegl_node_set (filter->crop_before,
720 "width", (gdouble) filter->filter_area.width,
721 "height", (gdouble) filter->filter_area.height,
722 NULL);
723 }
724
725 if (filter->filter_clip)
726 {
727 gegl_node_set (filter->crop_after,
728 "operation", "gegl:crop",
729 "x", 0.0,
730 "y", 0.0,
731 "width", (gdouble) filter->filter_area.width,
732 "height", (gdouble) filter->filter_area.height,
733 NULL);
734 }
735 else
736 {
737 gegl_node_set (filter->crop_after,
738 "operation", "gegl:nop",
739 NULL);
740 }
741
742 gimp_applicator_set_apply_offset (filter->applicator,
743 filter->filter_area.x,
744 filter->filter_area.y);
745 }
746 else
747 {
748 GimpItem *item = GIMP_ITEM (filter->drawable);
749 gdouble width = gimp_item_get_width (item);
750 gdouble height = gimp_item_get_height (item);
751
752 if (filter->has_input)
753 {
754 gegl_node_set (filter->translate,
755 "x", (gdouble) 0.0,
756 "y", (gdouble) 0.0,
757 NULL);
758
759 gegl_node_set (filter->crop_before,
760 "width", width,
761 "height", height,
762 NULL);
763 }
764
765 if (filter->filter_clip)
766 {
767 gegl_node_set (filter->crop_after,
768 "operation", "gegl:crop",
769 "x", (gdouble) filter->filter_area.x,
770 "y", (gdouble) filter->filter_area.y,
771 "width", (gdouble) filter->filter_area.width,
772 "height", (gdouble) filter->filter_area.height,
773 NULL);
774 }
775 else
776 {
777 gegl_node_set (filter->crop_after,
778 "operation", "gegl:nop",
779 NULL);
780 }
781
782 gimp_applicator_set_apply_offset (filter->applicator, 0, 0);
783 }
784
785 if (gimp_drawable_filter_is_active (filter))
786 {
787 if (gimp_drawable_update_bounding_box (filter->drawable))
788 g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
789 }
790 }
791
792 static gboolean
gimp_drawable_filter_get_crop_rect(GimpDrawableFilter * filter,gboolean crop_enabled,const GeglRectangle * crop_rect,gboolean preview_split_enabled,GimpAlignmentType preview_split_alignment,gint preview_split_position,GeglRectangle * rect)793 gimp_drawable_filter_get_crop_rect (GimpDrawableFilter *filter,
794 gboolean crop_enabled,
795 const GeglRectangle *crop_rect,
796 gboolean preview_split_enabled,
797 GimpAlignmentType preview_split_alignment,
798 gint preview_split_position,
799 GeglRectangle *rect)
800 {
801 GeglRectangle bounds;
802 gint x1, x2;
803 gint y1, y2;
804
805 bounds = gegl_rectangle_infinite_plane ();
806
807 x1 = bounds.x;
808 x2 = bounds.x + bounds.width;
809
810 y1 = bounds.y;
811 y2 = bounds.y + bounds.height;
812
813 if (preview_split_enabled)
814 {
815 switch (preview_split_alignment)
816 {
817 case GIMP_ALIGN_LEFT:
818 x2 = preview_split_position;
819 break;
820
821 case GIMP_ALIGN_RIGHT:
822 x1 = preview_split_position;
823 break;
824
825 case GIMP_ALIGN_TOP:
826 y2 = preview_split_position;
827 break;
828
829 case GIMP_ALIGN_BOTTOM:
830 y1 = preview_split_position;
831 break;
832
833 default:
834 g_return_val_if_reached (FALSE);
835 }
836 }
837
838 gegl_rectangle_set (rect, x1, y1, x2 - x1, y2 - y1);
839
840 if (crop_enabled)
841 gegl_rectangle_intersect (rect, rect, crop_rect);
842
843 return ! gegl_rectangle_equal (rect, &bounds);
844 }
845
846 static void
gimp_drawable_filter_sync_crop(GimpDrawableFilter * filter,gboolean old_crop_enabled,const GeglRectangle * old_crop_rect,gboolean old_preview_split_enabled,GimpAlignmentType old_preview_split_alignment,gint old_preview_split_position,gboolean update)847 gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
848 gboolean old_crop_enabled,
849 const GeglRectangle *old_crop_rect,
850 gboolean old_preview_split_enabled,
851 GimpAlignmentType old_preview_split_alignment,
852 gint old_preview_split_position,
853 gboolean update)
854 {
855 GeglRectangle old_rect;
856 GeglRectangle new_rect;
857 gboolean enabled;
858
859 gimp_drawable_filter_get_crop_rect (filter,
860 old_crop_enabled,
861 old_crop_rect,
862 old_preview_split_enabled,
863 old_preview_split_alignment,
864 old_preview_split_position,
865 &old_rect);
866
867 enabled = gimp_drawable_filter_get_crop_rect (filter,
868 filter->crop_enabled,
869 &filter->crop_rect,
870 filter->preview_split_enabled,
871 filter->preview_split_alignment,
872 filter->preview_split_position,
873 &new_rect);
874
875 gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
876
877 if (update &&
878 gimp_drawable_filter_is_active (filter) &&
879 ! gegl_rectangle_equal (&old_rect, &new_rect))
880 {
881 GeglRectangle diff_rects[4];
882 gint n_diff_rects;
883 gint i;
884
885 gimp_drawable_update_bounding_box (filter->drawable);
886
887 n_diff_rects = gegl_rectangle_xor (diff_rects, &old_rect, &new_rect);
888
889 for (i = 0; i < n_diff_rects; i++)
890 gimp_drawable_filter_update_drawable (filter, &diff_rects[i]);
891 }
892 }
893
894 static void
gimp_drawable_filter_sync_opacity(GimpDrawableFilter * filter)895 gimp_drawable_filter_sync_opacity (GimpDrawableFilter *filter)
896 {
897 gimp_applicator_set_opacity (filter->applicator,
898 filter->opacity);
899 }
900
901 static void
gimp_drawable_filter_sync_mode(GimpDrawableFilter * filter)902 gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter)
903 {
904 GimpLayerMode paint_mode = filter->paint_mode;
905
906 if (! filter->has_input && paint_mode == GIMP_LAYER_MODE_REPLACE)
907 {
908 /* if the filter's op has no input, use NORMAL instead of REPLACE, so
909 * that we composite the op's output on top of the input, instead of
910 * completely replacing it.
911 */
912 paint_mode = GIMP_LAYER_MODE_NORMAL;
913 }
914
915 gimp_applicator_set_mode (filter->applicator,
916 paint_mode,
917 filter->blend_space,
918 filter->composite_space,
919 filter->composite_mode);
920 }
921
922 static void
gimp_drawable_filter_sync_affect(GimpDrawableFilter * filter)923 gimp_drawable_filter_sync_affect (GimpDrawableFilter *filter)
924 {
925 gimp_applicator_set_affect (
926 filter->applicator,
927 filter->override_constraints ?
928
929 GIMP_COMPONENT_MASK_RED |
930 GIMP_COMPONENT_MASK_GREEN |
931 GIMP_COMPONENT_MASK_BLUE |
932 GIMP_COMPONENT_MASK_ALPHA :
933
934 gimp_drawable_get_active_mask (filter->drawable));
935 }
936
937 static void
gimp_drawable_filter_sync_format(GimpDrawableFilter * filter)938 gimp_drawable_filter_sync_format (GimpDrawableFilter *filter)
939 {
940 const Babl *format;
941
942 if (filter->add_alpha &&
943 (gimp_drawable_supports_alpha (filter->drawable) ||
944 filter->override_constraints))
945 {
946 format = gimp_drawable_get_format_with_alpha (filter->drawable);
947 }
948 else
949 {
950 format = gimp_drawable_get_format (filter->drawable);
951 }
952
953 gimp_applicator_set_output_format (filter->applicator, format);
954 }
955
956 static void
gimp_drawable_filter_sync_mask(GimpDrawableFilter * filter)957 gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter)
958 {
959 GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
960 GimpChannel *mask = gimp_image_get_mask (image);
961
962 if (gimp_channel_is_empty (mask))
963 {
964 gimp_applicator_set_mask_buffer (filter->applicator, NULL);
965 }
966 else
967 {
968 GeglBuffer *mask_buffer;
969 gint offset_x, offset_y;
970
971 mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
972 gimp_item_get_offset (GIMP_ITEM (filter->drawable),
973 &offset_x, &offset_y);
974
975 gimp_applicator_set_mask_buffer (filter->applicator, mask_buffer);
976 gimp_applicator_set_mask_offset (filter->applicator,
977 -offset_x, -offset_y);
978 }
979
980 gimp_item_mask_intersect (GIMP_ITEM (filter->drawable),
981 &filter->filter_area.x,
982 &filter->filter_area.y,
983 &filter->filter_area.width,
984 &filter->filter_area.height);
985 }
986
987 static void
gimp_drawable_filter_sync_transform(GimpDrawableFilter * filter)988 gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter)
989 {
990 GimpColorManaged *managed = GIMP_COLOR_MANAGED (filter->drawable);
991
992 if (filter->color_managed)
993 {
994 const Babl *drawable_format = NULL;
995 const Babl *input_format = NULL;
996 const Babl *output_format = NULL;
997 GimpColorProfile *drawable_profile = NULL;
998 GimpColorProfile *input_profile = NULL;
999 GimpColorProfile *output_profile = NULL;
1000 guint32 dummy;
1001
1002 drawable_format = gimp_drawable_get_format (filter->drawable);
1003 if (filter->has_input)
1004 input_format = gimp_gegl_node_get_format (filter->operation, "input");
1005 output_format = gimp_gegl_node_get_format (filter->operation, "output");
1006
1007 g_printerr ("drawable format: %s\n", babl_get_name (drawable_format));
1008 if (filter->has_input)
1009 g_printerr ("filter input format: %s\n", babl_get_name (input_format));
1010 g_printerr ("filter output format: %s\n", babl_get_name (output_format));
1011
1012 /* convert the drawable format to float, so we get a precise
1013 * color transform
1014 */
1015 drawable_format =
1016 gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
1017 gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
1018 gimp_babl_format_get_linear (drawable_format)),
1019 babl_format_has_alpha (drawable_format));
1020
1021 /* convert the filter input/output formats to something we have
1022 * built-in color profiles for (see the get_color_profile()
1023 * calls below)
1024 */
1025 if (filter->has_input)
1026 input_format = gimp_color_profile_get_lcms_format (input_format, &dummy);
1027 output_format = gimp_color_profile_get_lcms_format (output_format, &dummy);
1028
1029 g_printerr ("profile transform drawable format: %s\n",
1030 babl_get_name (drawable_format));
1031 if (filter->has_input)
1032 g_printerr ("profile transform input format: %s\n",
1033 babl_get_name (input_format));
1034 g_printerr ("profile transform output format: %s\n",
1035 babl_get_name (output_format));
1036
1037 drawable_profile = gimp_color_managed_get_color_profile (managed);
1038 if (filter->has_input)
1039 input_profile = gimp_babl_format_get_color_profile (input_format);
1040 output_profile = gimp_babl_format_get_color_profile (output_format);
1041
1042 if ((filter->has_input &&
1043 ! gimp_color_transform_can_gegl_copy (drawable_profile,
1044 input_profile)) ||
1045 ! gimp_color_transform_can_gegl_copy (output_profile,
1046 drawable_profile))
1047 {
1048 g_printerr ("using gimp:profile-transform\n");
1049
1050 if (filter->has_input)
1051 {
1052 gegl_node_set (filter->transform_before,
1053 "operation", "gimp:profile-transform",
1054 "src-profile", drawable_profile,
1055 "src-format", drawable_format,
1056 "dest-profile", input_profile,
1057 "dest-format", input_format,
1058 NULL);
1059 }
1060
1061 gegl_node_set (filter->transform_after,
1062 "operation", "gimp:profile-transform",
1063 "src-profile", output_profile,
1064 "src-format", output_format,
1065 "dest-profile", drawable_profile,
1066 "dest-format", drawable_format,
1067 NULL);
1068
1069 return;
1070 }
1071 }
1072
1073 g_printerr ("using gegl copy\n");
1074
1075 if (filter->has_input)
1076 {
1077 gegl_node_set (filter->transform_before,
1078 "operation", "gegl:nop",
1079 NULL);
1080 }
1081
1082 gegl_node_set (filter->transform_after,
1083 "operation", "gegl:nop",
1084 NULL);
1085 }
1086
1087 static void
gimp_drawable_filter_sync_gamma_hack(GimpDrawableFilter * filter)1088 gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter)
1089 {
1090 if (filter->gamma_hack)
1091 {
1092 const Babl *drawable_format;
1093 const Babl *cast_format;
1094
1095 drawable_format =
1096 gimp_drawable_get_format_with_alpha (filter->drawable);
1097
1098 cast_format =
1099 gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
1100 gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
1101 ! gimp_babl_format_get_linear (drawable_format)),
1102 TRUE);
1103
1104 if (filter->has_input)
1105 {
1106 gegl_node_set (filter->cast_before,
1107 "operation", "gegl:cast-format",
1108 "input-format", drawable_format,
1109 "output-format", cast_format,
1110 NULL);
1111 }
1112
1113 gegl_node_set (filter->cast_after,
1114 "operation", "gegl:cast-format",
1115 "input-format", cast_format,
1116 "output-format", drawable_format,
1117 NULL);
1118 }
1119 else
1120 {
1121 if (filter->has_input)
1122 {
1123 gegl_node_set (filter->cast_before,
1124 "operation", "gegl:nop",
1125 NULL);
1126 }
1127
1128 gegl_node_set (filter->cast_after,
1129 "operation", "gegl:nop",
1130 NULL);
1131 }
1132 }
1133
1134 static gboolean
gimp_drawable_filter_is_added(GimpDrawableFilter * filter)1135 gimp_drawable_filter_is_added (GimpDrawableFilter *filter)
1136 {
1137 return gimp_drawable_has_filter (filter->drawable,
1138 GIMP_FILTER (filter));
1139 }
1140
1141 static gboolean
gimp_drawable_filter_is_active(GimpDrawableFilter * filter)1142 gimp_drawable_filter_is_active (GimpDrawableFilter *filter)
1143 {
1144 return gimp_drawable_filter_is_added (filter) &&
1145 filter->preview_enabled;
1146 }
1147
1148 static gboolean
gimp_drawable_filter_add_filter(GimpDrawableFilter * filter)1149 gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
1150 {
1151 if (! gimp_drawable_filter_is_added (filter))
1152 {
1153 GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
1154
1155 gimp_viewable_preview_freeze (GIMP_VIEWABLE (filter->drawable));
1156
1157 gimp_drawable_filter_sync_active (filter);
1158 gimp_drawable_filter_sync_mask (filter);
1159 gimp_drawable_filter_sync_clip (filter, FALSE);
1160 gimp_drawable_filter_sync_region (filter);
1161 gimp_drawable_filter_sync_crop (filter,
1162 filter->crop_enabled,
1163 &filter->crop_rect,
1164 filter->preview_split_enabled,
1165 filter->preview_split_alignment,
1166 filter->preview_split_position,
1167 TRUE);
1168 gimp_drawable_filter_sync_opacity (filter);
1169 gimp_drawable_filter_sync_mode (filter);
1170 gimp_drawable_filter_sync_affect (filter);
1171 gimp_drawable_filter_sync_format (filter);
1172 gimp_drawable_filter_sync_transform (filter);
1173 gimp_drawable_filter_sync_gamma_hack (filter);
1174
1175 gimp_drawable_add_filter (filter->drawable,
1176 GIMP_FILTER (filter));
1177
1178 gimp_drawable_update_bounding_box (filter->drawable);
1179
1180 g_signal_connect (image, "component-active-changed",
1181 G_CALLBACK (gimp_drawable_filter_affect_changed),
1182 filter);
1183 g_signal_connect (image, "mask-changed",
1184 G_CALLBACK (gimp_drawable_filter_mask_changed),
1185 filter);
1186 g_signal_connect (image, "profile-changed",
1187 G_CALLBACK (gimp_drawable_filter_profile_changed),
1188 filter);
1189 g_signal_connect (filter->drawable, "lock-position-changed",
1190 G_CALLBACK (gimp_drawable_filter_lock_position_changed),
1191 filter);
1192 g_signal_connect (filter->drawable, "format-changed",
1193 G_CALLBACK (gimp_drawable_filter_format_changed),
1194 filter);
1195 g_signal_connect (filter->drawable, "removed",
1196 G_CALLBACK (gimp_drawable_filter_drawable_removed),
1197 filter);
1198
1199 if (GIMP_IS_LAYER (filter->drawable))
1200 {
1201 g_signal_connect (filter->drawable, "lock-alpha-changed",
1202 G_CALLBACK (gimp_drawable_filter_lock_alpha_changed),
1203 filter);
1204 }
1205
1206 return TRUE;
1207 }
1208
1209 return FALSE;
1210 }
1211
1212 static gboolean
gimp_drawable_filter_remove_filter(GimpDrawableFilter * filter)1213 gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
1214 {
1215 if (gimp_drawable_filter_is_added (filter))
1216 {
1217 GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
1218
1219 if (GIMP_IS_LAYER (filter->drawable))
1220 {
1221 g_signal_handlers_disconnect_by_func (filter->drawable,
1222 gimp_drawable_filter_lock_alpha_changed,
1223 filter);
1224 }
1225
1226 g_signal_handlers_disconnect_by_func (filter->drawable,
1227 gimp_drawable_filter_drawable_removed,
1228 filter);
1229 g_signal_handlers_disconnect_by_func (filter->drawable,
1230 gimp_drawable_filter_format_changed,
1231 filter);
1232 g_signal_handlers_disconnect_by_func (filter->drawable,
1233 gimp_drawable_filter_lock_position_changed,
1234 filter);
1235 g_signal_handlers_disconnect_by_func (image,
1236 gimp_drawable_filter_profile_changed,
1237 filter);
1238 g_signal_handlers_disconnect_by_func (image,
1239 gimp_drawable_filter_mask_changed,
1240 filter);
1241 g_signal_handlers_disconnect_by_func (image,
1242 gimp_drawable_filter_affect_changed,
1243 filter);
1244
1245 gimp_drawable_remove_filter (filter->drawable,
1246 GIMP_FILTER (filter));
1247
1248 gimp_drawable_update_bounding_box (filter->drawable);
1249
1250 gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
1251
1252 return TRUE;
1253 }
1254
1255 return FALSE;
1256 }
1257
1258 static void
gimp_drawable_filter_update_drawable(GimpDrawableFilter * filter,const GeglRectangle * area)1259 gimp_drawable_filter_update_drawable (GimpDrawableFilter *filter,
1260 const GeglRectangle *area)
1261 {
1262 GeglRectangle bounding_box;
1263 GeglRectangle update_area;
1264
1265 bounding_box = gimp_drawable_get_bounding_box (filter->drawable);
1266
1267 if (area)
1268 {
1269 if (! gegl_rectangle_intersect (&update_area,
1270 area, &bounding_box))
1271 {
1272 return;
1273 }
1274 }
1275 else
1276 {
1277 gimp_drawable_filter_get_crop_rect (filter,
1278 filter->crop_enabled,
1279 &filter->crop_rect,
1280 filter->preview_split_enabled,
1281 filter->preview_split_alignment,
1282 filter->preview_split_position,
1283 &update_area);
1284
1285 if (! gegl_rectangle_intersect (&update_area,
1286 &update_area, &bounding_box))
1287 {
1288 return;
1289 }
1290 }
1291
1292 if (update_area.width > 0 &&
1293 update_area.height > 0)
1294 {
1295 gimp_drawable_update (filter->drawable,
1296 update_area.x,
1297 update_area.y,
1298 update_area.width,
1299 update_area.height);
1300
1301 g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
1302 }
1303 }
1304
1305 static void
gimp_drawable_filter_affect_changed(GimpImage * image,GimpChannelType channel,GimpDrawableFilter * filter)1306 gimp_drawable_filter_affect_changed (GimpImage *image,
1307 GimpChannelType channel,
1308 GimpDrawableFilter *filter)
1309 {
1310 gimp_drawable_filter_sync_affect (filter);
1311 gimp_drawable_filter_update_drawable (filter, NULL);
1312 }
1313
1314 static void
gimp_drawable_filter_mask_changed(GimpImage * image,GimpDrawableFilter * filter)1315 gimp_drawable_filter_mask_changed (GimpImage *image,
1316 GimpDrawableFilter *filter)
1317 {
1318 gimp_drawable_filter_update_drawable (filter, NULL);
1319
1320 gimp_drawable_filter_sync_mask (filter);
1321 gimp_drawable_filter_sync_clip (filter, FALSE);
1322 gimp_drawable_filter_sync_region (filter);
1323
1324 gimp_drawable_filter_update_drawable (filter, NULL);
1325 }
1326
1327 static void
gimp_drawable_filter_profile_changed(GimpColorManaged * managed,GimpDrawableFilter * filter)1328 gimp_drawable_filter_profile_changed (GimpColorManaged *managed,
1329 GimpDrawableFilter *filter)
1330 {
1331 gimp_drawable_filter_sync_transform (filter);
1332 gimp_drawable_filter_update_drawable (filter, NULL);
1333 }
1334
1335 static void
gimp_drawable_filter_lock_position_changed(GimpDrawable * drawable,GimpDrawableFilter * filter)1336 gimp_drawable_filter_lock_position_changed (GimpDrawable *drawable,
1337 GimpDrawableFilter *filter)
1338 {
1339 gimp_drawable_filter_sync_clip (filter, TRUE);
1340 gimp_drawable_filter_update_drawable (filter, NULL);
1341 }
1342
1343 static void
gimp_drawable_filter_format_changed(GimpDrawable * drawable,GimpDrawableFilter * filter)1344 gimp_drawable_filter_format_changed (GimpDrawable *drawable,
1345 GimpDrawableFilter *filter)
1346 {
1347 gimp_drawable_filter_sync_format (filter);
1348 gimp_drawable_filter_update_drawable (filter, NULL);
1349 }
1350
1351 static void
gimp_drawable_filter_drawable_removed(GimpDrawable * drawable,GimpDrawableFilter * filter)1352 gimp_drawable_filter_drawable_removed (GimpDrawable *drawable,
1353 GimpDrawableFilter *filter)
1354 {
1355 gimp_drawable_filter_remove_filter (filter);
1356 }
1357
1358 static void
gimp_drawable_filter_lock_alpha_changed(GimpLayer * layer,GimpDrawableFilter * filter)1359 gimp_drawable_filter_lock_alpha_changed (GimpLayer *layer,
1360 GimpDrawableFilter *filter)
1361 {
1362 gimp_drawable_filter_sync_affect (filter);
1363 gimp_drawable_filter_update_drawable (filter, NULL);
1364 }
1365