1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3 *
4 * gimpcontainer.c
5 * Copyright (C) 2001 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gio/gio.h>
24 #include <gegl.h>
25
26 #include "libgimpconfig/gimpconfig.h"
27
28 #include "core-types.h"
29
30 #include "gimp.h"
31 #include "gimp-memsize.h"
32 #include "gimpcontainer.h"
33 #include "gimpmarshal.h"
34
35
36 /* #define DEBUG_CONTAINER */
37
38 #ifdef DEBUG_CONTAINER
39 #define D(stmnt) stmnt
40 #else
41 #define D(stmnt)
42 #endif
43
44
45 enum
46 {
47 ADD,
48 REMOVE,
49 REORDER,
50 FREEZE,
51 THAW,
52 LAST_SIGNAL
53 };
54
55 enum
56 {
57 PROP_0,
58 PROP_CHILDREN_TYPE,
59 PROP_POLICY
60 };
61
62
63 typedef struct
64 {
65 gchar *signame;
66 GCallback callback;
67 gpointer callback_data;
68
69 GQuark quark; /* used to attach the signal id's of child signals */
70 } GimpContainerHandler;
71
72 struct _GimpContainerPrivate
73 {
74 GType children_type;
75 GimpContainerPolicy policy;
76 gint n_children;
77
78 GList *handlers;
79 gint freeze_count;
80 };
81
82
83 /* local function prototypes */
84
85 static void gimp_container_config_iface_init (GimpConfigInterface *iface);
86
87 static void gimp_container_dispose (GObject *object);
88
89 static void gimp_container_set_property (GObject *object,
90 guint property_id,
91 const GValue *value,
92 GParamSpec *pspec);
93 static void gimp_container_get_property (GObject *object,
94 guint property_id,
95 GValue *value,
96 GParamSpec *pspec);
97
98 static gint64 gimp_container_get_memsize (GimpObject *object,
99 gint64 *gui_size);
100
101 static void gimp_container_real_add (GimpContainer *container,
102 GimpObject *object);
103 static void gimp_container_real_remove (GimpContainer *container,
104 GimpObject *object);
105
106 static gboolean gimp_container_serialize (GimpConfig *config,
107 GimpConfigWriter *writer,
108 gpointer data);
109 static gboolean gimp_container_deserialize (GimpConfig *config,
110 GScanner *scanner,
111 gint nest_level,
112 gpointer data);
113
114 static void gimp_container_disconnect_callback (GimpObject *object,
115 gpointer data);
116
117 static void gimp_container_free_handler (GimpContainer *container,
118 GimpContainerHandler *handler);
119
120
121 G_DEFINE_TYPE_WITH_CODE (GimpContainer, gimp_container, GIMP_TYPE_OBJECT,
122 G_ADD_PRIVATE (GimpContainer)
123 G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
124 gimp_container_config_iface_init))
125
126 #define parent_class gimp_container_parent_class
127
128 static guint container_signals[LAST_SIGNAL] = { 0, };
129
130
131 static void
gimp_container_class_init(GimpContainerClass * klass)132 gimp_container_class_init (GimpContainerClass *klass)
133 {
134 GObjectClass *object_class = G_OBJECT_CLASS (klass);
135 GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
136
137 container_signals[ADD] =
138 g_signal_new ("add",
139 G_TYPE_FROM_CLASS (klass),
140 G_SIGNAL_RUN_FIRST,
141 G_STRUCT_OFFSET (GimpContainerClass, add),
142 NULL, NULL,
143 gimp_marshal_VOID__OBJECT,
144 G_TYPE_NONE, 1,
145 GIMP_TYPE_OBJECT);
146
147 container_signals[REMOVE] =
148 g_signal_new ("remove",
149 G_TYPE_FROM_CLASS (klass),
150 G_SIGNAL_RUN_FIRST,
151 G_STRUCT_OFFSET (GimpContainerClass, remove),
152 NULL, NULL,
153 gimp_marshal_VOID__OBJECT,
154 G_TYPE_NONE, 1,
155 GIMP_TYPE_OBJECT);
156
157 container_signals[REORDER] =
158 g_signal_new ("reorder",
159 G_TYPE_FROM_CLASS (klass),
160 G_SIGNAL_RUN_FIRST,
161 G_STRUCT_OFFSET (GimpContainerClass, reorder),
162 NULL, NULL,
163 gimp_marshal_VOID__OBJECT_INT,
164 G_TYPE_NONE, 2,
165 GIMP_TYPE_OBJECT,
166 G_TYPE_INT);
167
168 container_signals[FREEZE] =
169 g_signal_new ("freeze",
170 G_TYPE_FROM_CLASS (klass),
171 G_SIGNAL_RUN_LAST,
172 G_STRUCT_OFFSET (GimpContainerClass, freeze),
173 NULL, NULL,
174 gimp_marshal_VOID__VOID,
175 G_TYPE_NONE, 0);
176
177 container_signals[THAW] =
178 g_signal_new ("thaw",
179 G_TYPE_FROM_CLASS (klass),
180 G_SIGNAL_RUN_LAST,
181 G_STRUCT_OFFSET (GimpContainerClass, thaw),
182 NULL, NULL,
183 gimp_marshal_VOID__VOID,
184 G_TYPE_NONE, 0);
185
186 object_class->dispose = gimp_container_dispose;
187 object_class->set_property = gimp_container_set_property;
188 object_class->get_property = gimp_container_get_property;
189
190 gimp_object_class->get_memsize = gimp_container_get_memsize;
191
192 klass->add = gimp_container_real_add;
193 klass->remove = gimp_container_real_remove;
194 klass->reorder = NULL;
195 klass->freeze = NULL;
196 klass->thaw = NULL;
197
198 klass->clear = NULL;
199 klass->have = NULL;
200 klass->foreach = NULL;
201 klass->search = NULL;
202 klass->get_unique_names = NULL;
203 klass->get_child_by_name = NULL;
204 klass->get_child_by_index = NULL;
205 klass->get_child_index = NULL;
206
207 g_object_class_install_property (object_class, PROP_CHILDREN_TYPE,
208 g_param_spec_gtype ("children-type",
209 NULL, NULL,
210 GIMP_TYPE_OBJECT,
211 GIMP_PARAM_READWRITE |
212 G_PARAM_CONSTRUCT_ONLY));
213
214 g_object_class_install_property (object_class, PROP_POLICY,
215 g_param_spec_enum ("policy",
216 NULL, NULL,
217 GIMP_TYPE_CONTAINER_POLICY,
218 GIMP_CONTAINER_POLICY_STRONG,
219 GIMP_PARAM_READWRITE |
220 G_PARAM_CONSTRUCT_ONLY));
221 }
222
223 static void
gimp_container_config_iface_init(GimpConfigInterface * iface)224 gimp_container_config_iface_init (GimpConfigInterface *iface)
225 {
226 iface->serialize = gimp_container_serialize;
227 iface->deserialize = gimp_container_deserialize;
228 }
229
230 static void
gimp_container_init(GimpContainer * container)231 gimp_container_init (GimpContainer *container)
232 {
233 container->priv = gimp_container_get_instance_private (container);
234 container->priv->handlers = NULL;
235 container->priv->freeze_count = 0;
236
237 container->priv->children_type = G_TYPE_NONE;
238 container->priv->policy = GIMP_CONTAINER_POLICY_STRONG;
239 container->priv->n_children = 0;
240 }
241
242 static void
gimp_container_dispose(GObject * object)243 gimp_container_dispose (GObject *object)
244 {
245 GimpContainer *container = GIMP_CONTAINER (object);
246
247 gimp_container_clear (container);
248
249 while (container->priv->handlers)
250 gimp_container_remove_handler (container,
251 ((GimpContainerHandler *)
252 container->priv->handlers->data)->quark);
253
254 if (container->priv->children_type != G_TYPE_NONE)
255 {
256 g_type_class_unref (g_type_class_peek (container->priv->children_type));
257 container->priv->children_type = G_TYPE_NONE;
258 }
259
260 G_OBJECT_CLASS (parent_class)->dispose (object);
261 }
262
263 static void
gimp_container_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)264 gimp_container_set_property (GObject *object,
265 guint property_id,
266 const GValue *value,
267 GParamSpec *pspec)
268 {
269 GimpContainer *container = GIMP_CONTAINER (object);
270
271 switch (property_id)
272 {
273 case PROP_CHILDREN_TYPE:
274 container->priv->children_type = g_value_get_gtype (value);
275 g_type_class_ref (container->priv->children_type);
276 break;
277 case PROP_POLICY:
278 container->priv->policy = g_value_get_enum (value);
279 break;
280 default:
281 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
282 break;
283 }
284 }
285
286 static void
gimp_container_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)287 gimp_container_get_property (GObject *object,
288 guint property_id,
289 GValue *value,
290 GParamSpec *pspec)
291 {
292 GimpContainer *container = GIMP_CONTAINER (object);
293
294 switch (property_id)
295 {
296 case PROP_CHILDREN_TYPE:
297 g_value_set_gtype (value, container->priv->children_type);
298 break;
299 case PROP_POLICY:
300 g_value_set_enum (value, container->priv->policy);
301 break;
302 default:
303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
304 break;
305 }
306 }
307
308 static gint64
gimp_container_get_memsize(GimpObject * object,gint64 * gui_size)309 gimp_container_get_memsize (GimpObject *object,
310 gint64 *gui_size)
311 {
312 GimpContainer *container = GIMP_CONTAINER (object);
313 gint64 memsize = 0;
314 GList *list;
315
316 for (list = container->priv->handlers; list; list = g_list_next (list))
317 {
318 GimpContainerHandler *handler = list->data;
319
320 memsize += (sizeof (GList) +
321 sizeof (GimpContainerHandler) +
322 gimp_string_get_memsize (handler->signame));
323 }
324
325 return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
326 gui_size);
327 }
328
329 static void
gimp_container_real_add(GimpContainer * container,GimpObject * object)330 gimp_container_real_add (GimpContainer *container,
331 GimpObject *object)
332 {
333 container->priv->n_children++;
334 }
335
336 static void
gimp_container_real_remove(GimpContainer * container,GimpObject * object)337 gimp_container_real_remove (GimpContainer *container,
338 GimpObject *object)
339 {
340 container->priv->n_children--;
341 }
342
343
344 typedef struct
345 {
346 GimpConfigWriter *writer;
347 gpointer data;
348 gboolean success;
349 } SerializeData;
350
351 static void
gimp_container_serialize_foreach(GObject * object,SerializeData * serialize_data)352 gimp_container_serialize_foreach (GObject *object,
353 SerializeData *serialize_data)
354 {
355 GimpConfigInterface *config_iface;
356 const gchar *name;
357
358 config_iface = GIMP_CONFIG_GET_INTERFACE (object);
359
360 if (! config_iface)
361 serialize_data->success = FALSE;
362
363 if (! serialize_data->success)
364 return;
365
366 gimp_config_writer_open (serialize_data->writer,
367 g_type_name (G_TYPE_FROM_INSTANCE (object)));
368
369 name = gimp_object_get_name (object);
370
371 if (name)
372 gimp_config_writer_string (serialize_data->writer, name);
373 else
374 gimp_config_writer_print (serialize_data->writer, "NULL", 4);
375
376 serialize_data->success = config_iface->serialize (GIMP_CONFIG (object),
377 serialize_data->writer,
378 serialize_data->data);
379 gimp_config_writer_close (serialize_data->writer);
380 }
381
382 static gboolean
gimp_container_serialize(GimpConfig * config,GimpConfigWriter * writer,gpointer data)383 gimp_container_serialize (GimpConfig *config,
384 GimpConfigWriter *writer,
385 gpointer data)
386 {
387 GimpContainer *container = GIMP_CONTAINER (config);
388 SerializeData serialize_data;
389
390 serialize_data.writer = writer;
391 serialize_data.data = data;
392 serialize_data.success = TRUE;
393
394 gimp_container_foreach (container,
395 (GFunc) gimp_container_serialize_foreach,
396 &serialize_data);
397
398 return serialize_data.success;
399 }
400
401 static gboolean
gimp_container_deserialize(GimpConfig * config,GScanner * scanner,gint nest_level,gpointer data)402 gimp_container_deserialize (GimpConfig *config,
403 GScanner *scanner,
404 gint nest_level,
405 gpointer data)
406 {
407 GimpContainer *container = GIMP_CONTAINER (config);
408 GTokenType token;
409
410 token = G_TOKEN_LEFT_PAREN;
411
412 while (g_scanner_peek_next_token (scanner) == token)
413 {
414 token = g_scanner_get_next_token (scanner);
415
416 switch (token)
417 {
418 case G_TOKEN_LEFT_PAREN:
419 token = G_TOKEN_IDENTIFIER;
420 break;
421
422 case G_TOKEN_IDENTIFIER:
423 {
424 GimpObject *child = NULL;
425 GType type;
426 gchar *name = NULL;
427 gboolean add_child = FALSE;
428
429 type = g_type_from_name (scanner->value.v_identifier);
430
431 if (! type)
432 {
433 g_scanner_error (scanner,
434 "unable to determine type of '%s'",
435 scanner->value.v_identifier);
436 return FALSE;
437 }
438
439 if (! g_type_is_a (type, container->priv->children_type))
440 {
441 g_scanner_error (scanner,
442 "'%s' is not a subclass of '%s'",
443 scanner->value.v_identifier,
444 g_type_name (container->priv->children_type));
445 return FALSE;
446 }
447
448 if (! g_type_is_a (type, GIMP_TYPE_CONFIG))
449 {
450 g_scanner_error (scanner,
451 "'%s' does not implement GimpConfigInterface",
452 scanner->value.v_identifier);
453 return FALSE;
454 }
455
456 if (! gimp_scanner_parse_string (scanner, &name))
457 {
458 token = G_TOKEN_STRING;
459 break;
460 }
461
462 if (! name)
463 name = g_strdup ("");
464
465 if (gimp_container_get_unique_names (container))
466 child = gimp_container_get_child_by_name (container, name);
467
468 if (! child)
469 {
470 if (GIMP_IS_GIMP (data))
471 child = g_object_new (type, "gimp", data, NULL);
472 else
473 child = g_object_new (type, NULL);
474
475 add_child = TRUE;
476 }
477
478 /* always use the deserialized name. while it normally
479 * doesn't make a difference there are obscure case like
480 * template migration.
481 */
482 gimp_object_take_name (child, name);
483
484 if (! GIMP_CONFIG_GET_INTERFACE (child)->deserialize (GIMP_CONFIG (child),
485 scanner,
486 nest_level + 1,
487 NULL))
488 {
489 if (add_child)
490 g_object_unref (child);
491
492 /* warning should be already set by child */
493 return FALSE;
494 }
495
496 if (add_child)
497 {
498 gimp_container_add (container, child);
499
500 if (container->priv->policy == GIMP_CONTAINER_POLICY_STRONG)
501 g_object_unref (child);
502 }
503 }
504 token = G_TOKEN_RIGHT_PAREN;
505 break;
506
507 case G_TOKEN_RIGHT_PAREN:
508 token = G_TOKEN_LEFT_PAREN;
509 break;
510
511 default: /* do nothing */
512 break;
513 }
514 }
515
516 return gimp_config_deserialize_return (scanner, token, nest_level);
517 }
518
519 static void
gimp_container_disconnect_callback(GimpObject * object,gpointer data)520 gimp_container_disconnect_callback (GimpObject *object,
521 gpointer data)
522 {
523 GimpContainer *container = GIMP_CONTAINER (data);
524
525 gimp_container_remove (container, object);
526 }
527
528 static void
gimp_container_free_handler_foreach_func(GimpObject * object,GimpContainerHandler * handler)529 gimp_container_free_handler_foreach_func (GimpObject *object,
530 GimpContainerHandler *handler)
531 {
532 gulong handler_id;
533
534 handler_id = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (object),
535 handler->quark));
536
537 if (handler_id)
538 {
539 g_signal_handler_disconnect (object, handler_id);
540
541 g_object_set_qdata (G_OBJECT (object), handler->quark, NULL);
542 }
543 }
544
545 static void
gimp_container_free_handler(GimpContainer * container,GimpContainerHandler * handler)546 gimp_container_free_handler (GimpContainer *container,
547 GimpContainerHandler *handler)
548 {
549 D (g_print ("%s: id = %d\n", G_STRFUNC, handler->quark));
550
551 gimp_container_foreach (container,
552 (GFunc) gimp_container_free_handler_foreach_func,
553 handler);
554
555 g_free (handler->signame);
556 g_slice_free (GimpContainerHandler, handler);
557 }
558
559 GType
gimp_container_get_children_type(GimpContainer * container)560 gimp_container_get_children_type (GimpContainer *container)
561 {
562 g_return_val_if_fail (GIMP_IS_CONTAINER (container), G_TYPE_NONE);
563
564 return container->priv->children_type;
565 }
566
567 GimpContainerPolicy
gimp_container_get_policy(GimpContainer * container)568 gimp_container_get_policy (GimpContainer *container)
569 {
570 g_return_val_if_fail (GIMP_IS_CONTAINER (container), 0);
571
572 return container->priv->policy;
573 }
574
575 gint
gimp_container_get_n_children(GimpContainer * container)576 gimp_container_get_n_children (GimpContainer *container)
577 {
578 g_return_val_if_fail (GIMP_IS_CONTAINER (container), 0);
579
580 return container->priv->n_children;
581 }
582
583 gboolean
gimp_container_add(GimpContainer * container,GimpObject * object)584 gimp_container_add (GimpContainer *container,
585 GimpObject *object)
586 {
587 GList *list;
588 gint n_children;
589
590 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
591 g_return_val_if_fail (object != NULL, FALSE);
592 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object,
593 container->priv->children_type),
594 FALSE);
595
596 if (gimp_container_have (container, object))
597 {
598 g_warning ("%s: container %p already contains object %p",
599 G_STRFUNC, container, object);
600 return FALSE;
601 }
602
603 for (list = container->priv->handlers; list; list = g_list_next (list))
604 {
605 GimpContainerHandler *handler = list->data;
606 gulong handler_id;
607
608 handler_id = g_signal_connect (object,
609 handler->signame,
610 handler->callback,
611 handler->callback_data);
612
613 g_object_set_qdata (G_OBJECT (object), handler->quark,
614 GUINT_TO_POINTER (handler_id));
615 }
616
617 switch (container->priv->policy)
618 {
619 case GIMP_CONTAINER_POLICY_STRONG:
620 g_object_ref (object);
621 break;
622
623 case GIMP_CONTAINER_POLICY_WEAK:
624 g_signal_connect (object, "disconnect",
625 G_CALLBACK (gimp_container_disconnect_callback),
626 container);
627 break;
628 }
629
630 n_children = container->priv->n_children;
631
632 g_signal_emit (container, container_signals[ADD], 0, object);
633
634 if (n_children == container->priv->n_children)
635 {
636 g_warning ("%s: GimpContainer::add() implementation did not "
637 "chain up. Please report this at https://www.gimp.org/bugs/",
638 G_STRFUNC);
639
640 container->priv->n_children++;
641 }
642
643 return TRUE;
644 }
645
646 gboolean
gimp_container_remove(GimpContainer * container,GimpObject * object)647 gimp_container_remove (GimpContainer *container,
648 GimpObject *object)
649 {
650 GList *list;
651 gint n_children;
652
653 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
654 g_return_val_if_fail (object != NULL, FALSE);
655 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object,
656 container->priv->children_type),
657 FALSE);
658
659 if (! gimp_container_have (container, object))
660 {
661 g_warning ("%s: container %p does not contain object %p",
662 G_STRFUNC, container, object);
663 return FALSE;
664 }
665
666 for (list = container->priv->handlers; list; list = g_list_next (list))
667 {
668 GimpContainerHandler *handler = list->data;
669 gulong handler_id;
670
671 handler_id = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (object),
672 handler->quark));
673
674 if (handler_id)
675 {
676 g_signal_handler_disconnect (object, handler_id);
677
678 g_object_set_qdata (G_OBJECT (object), handler->quark, NULL);
679 }
680 }
681
682 n_children = container->priv->n_children;
683
684 g_signal_emit (container, container_signals[REMOVE], 0, object);
685
686 if (n_children == container->priv->n_children)
687 {
688 g_warning ("%s: GimpContainer::remove() implementation did not "
689 "chain up. Please report this at https://www.gimp.org/bugs/",
690 G_STRFUNC);
691
692 container->priv->n_children--;
693 }
694
695 switch (container->priv->policy)
696 {
697 case GIMP_CONTAINER_POLICY_STRONG:
698 g_object_unref (object);
699 break;
700
701 case GIMP_CONTAINER_POLICY_WEAK:
702 g_signal_handlers_disconnect_by_func (object,
703 gimp_container_disconnect_callback,
704 container);
705 break;
706 }
707
708 return TRUE;
709 }
710
711 gboolean
gimp_container_insert(GimpContainer * container,GimpObject * object,gint index)712 gimp_container_insert (GimpContainer *container,
713 GimpObject *object,
714 gint index)
715 {
716 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
717 g_return_val_if_fail (object != NULL, FALSE);
718 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object,
719 container->priv->children_type),
720 FALSE);
721
722 g_return_val_if_fail (index >= -1 &&
723 index <= container->priv->n_children, FALSE);
724
725 if (gimp_container_have (container, object))
726 {
727 g_warning ("%s: container %p already contains object %p",
728 G_STRFUNC, container, object);
729 return FALSE;
730 }
731
732 if (gimp_container_add (container, object))
733 {
734 return gimp_container_reorder (container, object, index);
735 }
736
737 return FALSE;
738 }
739
740 gboolean
gimp_container_reorder(GimpContainer * container,GimpObject * object,gint new_index)741 gimp_container_reorder (GimpContainer *container,
742 GimpObject *object,
743 gint new_index)
744 {
745 gint index;
746
747 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
748 g_return_val_if_fail (object != NULL, FALSE);
749 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object,
750 container->priv->children_type),
751 FALSE);
752
753 g_return_val_if_fail (new_index >= -1 &&
754 new_index < container->priv->n_children, FALSE);
755
756 if (new_index == -1)
757 new_index = container->priv->n_children - 1;
758
759 index = gimp_container_get_child_index (container, object);
760
761 if (index == -1)
762 {
763 g_warning ("%s: container %p does not contain object %p",
764 G_STRFUNC, container, object);
765 return FALSE;
766 }
767
768 if (index != new_index)
769 g_signal_emit (container, container_signals[REORDER], 0,
770 object, new_index);
771
772 return TRUE;
773 }
774
775 void
gimp_container_freeze(GimpContainer * container)776 gimp_container_freeze (GimpContainer *container)
777 {
778 g_return_if_fail (GIMP_IS_CONTAINER (container));
779
780 container->priv->freeze_count++;
781
782 if (container->priv->freeze_count == 1)
783 g_signal_emit (container, container_signals[FREEZE], 0);
784 }
785
786 void
gimp_container_thaw(GimpContainer * container)787 gimp_container_thaw (GimpContainer *container)
788 {
789 g_return_if_fail (GIMP_IS_CONTAINER (container));
790
791 if (container->priv->freeze_count > 0)
792 container->priv->freeze_count--;
793
794 if (container->priv->freeze_count == 0)
795 g_signal_emit (container, container_signals[THAW], 0);
796 }
797
798 gboolean
gimp_container_frozen(GimpContainer * container)799 gimp_container_frozen (GimpContainer *container)
800 {
801 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
802
803 return (container->priv->freeze_count > 0) ? TRUE : FALSE;
804 }
805
806 gint
gimp_container_freeze_count(GimpContainer * container)807 gimp_container_freeze_count (GimpContainer *container)
808 {
809 g_return_val_if_fail (GIMP_IS_CONTAINER (container), 0);
810
811 return container->priv->freeze_count;
812 }
813
814 void
gimp_container_clear(GimpContainer * container)815 gimp_container_clear (GimpContainer *container)
816 {
817 g_return_if_fail (GIMP_IS_CONTAINER (container));
818
819 if (container->priv->n_children > 0)
820 {
821 gimp_container_freeze (container);
822 GIMP_CONTAINER_GET_CLASS (container)->clear (container);
823 gimp_container_thaw (container);
824 }
825 }
826
827 gboolean
gimp_container_is_empty(GimpContainer * container)828 gimp_container_is_empty (GimpContainer *container)
829 {
830 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
831
832 return (container->priv->n_children == 0);
833 }
834
835 gboolean
gimp_container_have(GimpContainer * container,GimpObject * object)836 gimp_container_have (GimpContainer *container,
837 GimpObject *object)
838 {
839 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
840
841 if (container->priv->n_children < 1)
842 return FALSE;
843
844 return GIMP_CONTAINER_GET_CLASS (container)->have (container, object);
845 }
846
847 void
gimp_container_foreach(GimpContainer * container,GFunc func,gpointer user_data)848 gimp_container_foreach (GimpContainer *container,
849 GFunc func,
850 gpointer user_data)
851 {
852 g_return_if_fail (GIMP_IS_CONTAINER (container));
853 g_return_if_fail (func != NULL);
854
855 if (container->priv->n_children > 0)
856 GIMP_CONTAINER_GET_CLASS (container)->foreach (container, func, user_data);
857 }
858
859 GimpObject *
gimp_container_search(GimpContainer * container,GimpContainerSearchFunc func,gpointer user_data)860 gimp_container_search (GimpContainer *container,
861 GimpContainerSearchFunc func,
862 gpointer user_data)
863 {
864 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
865 g_return_val_if_fail (func != NULL, NULL);
866
867 if (container->priv->n_children > 0)
868 {
869 return GIMP_CONTAINER_GET_CLASS (container)->search (container,
870 func, user_data);
871 }
872
873 return NULL;
874 }
875
876 gboolean
gimp_container_get_unique_names(GimpContainer * container)877 gimp_container_get_unique_names (GimpContainer *container)
878 {
879 g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE);
880
881 if (GIMP_CONTAINER_GET_CLASS (container)->get_unique_names)
882 return GIMP_CONTAINER_GET_CLASS (container)->get_unique_names (container);
883
884 return FALSE;
885 }
886
887 GimpObject *
gimp_container_get_child_by_name(GimpContainer * container,const gchar * name)888 gimp_container_get_child_by_name (GimpContainer *container,
889 const gchar *name)
890 {
891 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
892
893 if (!name)
894 return NULL;
895
896 return GIMP_CONTAINER_GET_CLASS (container)->get_child_by_name (container,
897 name);
898 }
899
900 GimpObject *
gimp_container_get_child_by_index(GimpContainer * container,gint index)901 gimp_container_get_child_by_index (GimpContainer *container,
902 gint index)
903 {
904 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
905
906 if (index < 0 || index >= container->priv->n_children)
907 return NULL;
908
909 return GIMP_CONTAINER_GET_CLASS (container)->get_child_by_index (container,
910 index);
911 }
912
913 /**
914 * gimp_container_get_first_child:
915 * @container: a #GimpContainer
916 *
917 * Return value: the first child object stored in @container or %NULL if the
918 * container is empty
919 */
920 GimpObject *
gimp_container_get_first_child(GimpContainer * container)921 gimp_container_get_first_child (GimpContainer *container)
922 {
923 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
924
925 if (container->priv->n_children > 0)
926 return GIMP_CONTAINER_GET_CLASS (container)->get_child_by_index (container,
927 0);
928
929 return NULL;
930 }
931
932 /**
933 * gimp_container_get_last_child:
934 * @container: a #GimpContainer
935 *
936 * Return value: the last child object stored in @container or %NULL if the
937 * container is empty
938 */
939 GimpObject *
gimp_container_get_last_child(GimpContainer * container)940 gimp_container_get_last_child (GimpContainer *container)
941 {
942 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
943
944 if (container->priv->n_children > 0)
945 return GIMP_CONTAINER_GET_CLASS (container)->get_child_by_index (container,
946 container->priv->n_children - 1);
947
948 return NULL;
949 }
950
951 gint
gimp_container_get_child_index(GimpContainer * container,GimpObject * object)952 gimp_container_get_child_index (GimpContainer *container,
953 GimpObject *object)
954 {
955 g_return_val_if_fail (GIMP_IS_CONTAINER (container), -1);
956 g_return_val_if_fail (object != NULL, -1);
957 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object,
958 container->priv->children_type),
959 -1);
960
961 return GIMP_CONTAINER_GET_CLASS (container)->get_child_index (container,
962 object);
963 }
964
965 GimpObject *
gimp_container_get_neighbor_of(GimpContainer * container,GimpObject * object)966 gimp_container_get_neighbor_of (GimpContainer *container,
967 GimpObject *object)
968 {
969 gint index;
970
971 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
972 g_return_val_if_fail (GIMP_IS_OBJECT (object), NULL);
973
974 index = gimp_container_get_child_index (container, object);
975
976 if (index != -1)
977 {
978 GimpObject *new;
979
980 new = gimp_container_get_child_by_index (container, index + 1);
981
982 if (! new && index > 0)
983 new = gimp_container_get_child_by_index (container, index - 1);
984
985 return new;
986 }
987
988 return NULL;
989 }
990
991 static void
gimp_container_get_name_array_foreach_func(GimpObject * object,gchar *** iter)992 gimp_container_get_name_array_foreach_func (GimpObject *object,
993 gchar ***iter)
994 {
995 gchar **array = *iter;
996
997 *array = g_strdup (gimp_object_get_name (object));
998 (*iter)++;
999 }
1000
1001 gchar **
gimp_container_get_name_array(GimpContainer * container,gint * length)1002 gimp_container_get_name_array (GimpContainer *container,
1003 gint *length)
1004 {
1005 gchar **names;
1006 gchar **iter;
1007
1008 g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
1009 g_return_val_if_fail (length != NULL, NULL);
1010
1011 *length = gimp_container_get_n_children (container);
1012 if (*length == 0)
1013 return NULL;
1014
1015 names = iter = g_new (gchar *, *length);
1016
1017 gimp_container_foreach (container,
1018 (GFunc) gimp_container_get_name_array_foreach_func,
1019 &iter);
1020
1021 return names;
1022 }
1023
1024 static void
gimp_container_add_handler_foreach_func(GimpObject * object,GimpContainerHandler * handler)1025 gimp_container_add_handler_foreach_func (GimpObject *object,
1026 GimpContainerHandler *handler)
1027 {
1028 gulong handler_id;
1029
1030 handler_id = g_signal_connect (object,
1031 handler->signame,
1032 handler->callback,
1033 handler->callback_data);
1034
1035 g_object_set_qdata (G_OBJECT (object), handler->quark,
1036 GUINT_TO_POINTER (handler_id));
1037 }
1038
1039 GQuark
gimp_container_add_handler(GimpContainer * container,const gchar * signame,GCallback callback,gpointer callback_data)1040 gimp_container_add_handler (GimpContainer *container,
1041 const gchar *signame,
1042 GCallback callback,
1043 gpointer callback_data)
1044 {
1045 GimpContainerHandler *handler;
1046 gchar *key;
1047
1048 static gint handler_id = 0;
1049
1050 g_return_val_if_fail (GIMP_IS_CONTAINER (container), 0);
1051 g_return_val_if_fail (signame != NULL, 0);
1052 g_return_val_if_fail (callback != NULL, 0);
1053
1054 if (! g_str_has_prefix (signame, "notify::"))
1055 g_return_val_if_fail (g_signal_lookup (signame,
1056 container->priv->children_type), 0);
1057
1058 handler = g_slice_new0 (GimpContainerHandler);
1059
1060 /* create a unique key for this handler */
1061 key = g_strdup_printf ("%s-%d", signame, handler_id++);
1062
1063 handler->signame = g_strdup (signame);
1064 handler->callback = callback;
1065 handler->callback_data = callback_data;
1066 handler->quark = g_quark_from_string (key);
1067
1068 D (g_print ("%s: key = %s, id = %d\n", G_STRFUNC, key, handler->quark));
1069
1070 g_free (key);
1071
1072 container->priv->handlers = g_list_prepend (container->priv->handlers, handler);
1073
1074 gimp_container_foreach (container,
1075 (GFunc) gimp_container_add_handler_foreach_func,
1076 handler);
1077
1078 return handler->quark;
1079 }
1080
1081 void
gimp_container_remove_handler(GimpContainer * container,GQuark id)1082 gimp_container_remove_handler (GimpContainer *container,
1083 GQuark id)
1084 {
1085 GimpContainerHandler *handler;
1086 GList *list;
1087
1088 g_return_if_fail (GIMP_IS_CONTAINER (container));
1089 g_return_if_fail (id != 0);
1090
1091 for (list = container->priv->handlers; list; list = g_list_next (list))
1092 {
1093 handler = (GimpContainerHandler *) list->data;
1094
1095 if (handler->quark == id)
1096 break;
1097 }
1098
1099 if (! list)
1100 {
1101 g_warning ("%s: tried to remove handler which unknown id %d",
1102 G_STRFUNC, id);
1103 return;
1104 }
1105
1106 gimp_container_free_handler (container, handler);
1107
1108 container->priv->handlers = g_list_delete_link (container->priv->handlers,
1109 list);
1110 }
1111
1112 void
gimp_container_remove_handlers_by_func(GimpContainer * container,GCallback callback,gpointer callback_data)1113 gimp_container_remove_handlers_by_func (GimpContainer *container,
1114 GCallback callback,
1115 gpointer callback_data)
1116 {
1117 GList *list;
1118
1119 g_return_if_fail (GIMP_IS_CONTAINER (container));
1120 g_return_if_fail (callback != NULL);
1121
1122 list = container->priv->handlers;
1123
1124 while (list)
1125 {
1126 GimpContainerHandler *handler = list->data;
1127 GList *next = g_list_next (list);
1128
1129 if (handler->callback == callback &&
1130 handler->callback_data == callback_data)
1131 {
1132 gimp_container_free_handler (container, handler);
1133
1134 container->priv->handlers = g_list_delete_link (
1135 container->priv->handlers, list);
1136 }
1137
1138 list = next;
1139 }
1140 }
1141
1142 void
gimp_container_remove_handlers_by_data(GimpContainer * container,gpointer callback_data)1143 gimp_container_remove_handlers_by_data (GimpContainer *container,
1144 gpointer callback_data)
1145 {
1146 GList *list;
1147
1148 g_return_if_fail (GIMP_IS_CONTAINER (container));
1149
1150 list = container->priv->handlers;
1151
1152 while (list)
1153 {
1154 GimpContainerHandler *handler = list->data;
1155 GList *next = g_list_next (list);
1156
1157 if (handler->callback_data == callback_data)
1158 {
1159 gimp_container_free_handler (container, handler);
1160
1161 container->priv->handlers = g_list_delete_link (
1162 container->priv->handlers, list);
1163 }
1164
1165 list = next;
1166 }
1167 }
1168