1 /*
2  * Nautilus-Actions
3  * A Nautilus extension which offers configurable context menu actions.
4  *
5  * Copyright (C) 2005 The GNOME Foundation
6  * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7  * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8  *
9  * Nautilus-Actions is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * Nautilus-Actions is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Nautilus-Actions; see the file COPYING. If not, see
21  * <http://www.gnu.org/licenses/>.
22  *
23  * Authors:
24  *   Frederic Ruaudel <grumz@grumz.net>
25  *   Rodrigo Moya <rodrigo@gnome-db.org>
26  *   Pierre Wieser <pwieser@trychlos.org>
27  *   ... and many others (see AUTHORS)
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <api/na-object-api.h>
35 
36 #include "na-factory-object.h"
37 
38 /* private class data
39  */
40 struct _NAObjectClassPrivate {
41 	void *empty;						/* so that gcc -pedantic is happy */
42 };
43 
44 /* private instance data
45  */
46 struct _NAObjectPrivate {
47 	gboolean   dispose_has_run;
48 };
49 
50 static GObjectClass *st_parent_class   = NULL;
51 
52 static GType    register_type( void );
53 static void     class_init( NAObjectClass *klass );
54 static void     instance_init( GTypeInstance *instance, gpointer klass );
55 static void     instance_dispose( GObject *object );
56 static void     instance_finalize( GObject *object );
57 
58 static void     object_dump( const NAObject *object );
59 
60 static void     iduplicable_iface_init( NAIDuplicableInterface *iface, void *user_data );
61 static void     iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source, guint mode );
62 static gboolean iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
63 static gboolean iduplicable_is_valid( const NAIDuplicable *object );
64 
65 static void     check_status_down_rec( const NAObject *object );
66 static void     check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was_valid );
67 static void     v_copy( NAObject *target, const NAObject *source, guint mode );
68 static gboolean v_are_equal( const NAObject *a, const NAObject *b );
69 static gboolean v_is_valid( const NAObject *a );
70 static void     dump_tree( GList *tree, gint level );
71 
72 GType
na_object_object_get_type(void)73 na_object_object_get_type( void )
74 {
75 	static GType item_type = 0;
76 
77 	if( item_type == 0 ){
78 		item_type = register_type();
79 	}
80 
81 	return( item_type );
82 }
83 
84 static GType
register_type(void)85 register_type( void )
86 {
87 	static const gchar *thisfn = "na_object_register_type";
88 	GType type;
89 
90 	static GTypeInfo info = {
91 		sizeof( NAObjectClass ),
92 		NULL,
93 		NULL,
94 		( GClassInitFunc ) class_init,
95 		NULL,
96 		NULL,
97 		sizeof( NAObject ),
98 		0,
99 		( GInstanceInitFunc ) instance_init
100 	};
101 
102 	static const GInterfaceInfo iduplicable_iface_info = {
103 		( GInterfaceInitFunc ) iduplicable_iface_init,
104 		NULL,
105 		NULL
106 	};
107 
108 	g_debug( "%s", thisfn );
109 
110 	type = g_type_register_static( G_TYPE_OBJECT, "NAObject", &info, 0 );
111 
112 	g_type_add_interface_static( type, NA_TYPE_IDUPLICABLE, &iduplicable_iface_info );
113 
114 	return( type );
115 }
116 
117 static void
class_init(NAObjectClass * klass)118 class_init( NAObjectClass *klass )
119 {
120 	static const gchar *thisfn = "na_object_class_init";
121 	GObjectClass *object_class;
122 	NAObjectClass *naobject_class;
123 
124 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
125 
126 	st_parent_class = g_type_class_peek_parent( klass );
127 
128 	object_class = G_OBJECT_CLASS( klass );
129 	object_class->dispose = instance_dispose;
130 	object_class->finalize = instance_finalize;
131 
132 	naobject_class = NA_OBJECT_CLASS( klass );
133 	naobject_class->dump = object_dump;
134 	naobject_class->copy = NULL;
135 	naobject_class->are_equal = NULL;
136 	naobject_class->is_valid = NULL;
137 
138 	klass->private = g_new0( NAObjectClassPrivate, 1 );
139 }
140 
141 static void
instance_init(GTypeInstance * instance,gpointer klass)142 instance_init( GTypeInstance *instance, gpointer klass )
143 {
144 	NAObject *self;
145 
146 	g_return_if_fail( NA_IS_OBJECT( instance ));
147 
148 	self = NA_OBJECT( instance );
149 
150 	self->private = g_new0( NAObjectPrivate, 1 );
151 }
152 
153 static void
instance_dispose(GObject * object)154 instance_dispose( GObject *object )
155 {
156 	NAObject *self;
157 
158 	g_return_if_fail( NA_IS_OBJECT( object ));
159 
160 	self = NA_OBJECT( object );
161 
162 	if( !self->private->dispose_has_run ){
163 
164 		self->private->dispose_has_run = TRUE;
165 
166 		na_iduplicable_dispose( NA_IDUPLICABLE( object ));
167 
168 		/* chain up to the parent class */
169 		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
170 			G_OBJECT_CLASS( st_parent_class )->dispose( object );
171 		}
172 	}
173 }
174 
175 static void
instance_finalize(GObject * object)176 instance_finalize( GObject *object )
177 {
178 	NAObject *self;
179 
180 	g_return_if_fail( NA_IS_OBJECT( object ));
181 
182 	self = NA_OBJECT( object );
183 
184 	g_free( self->private );
185 
186 	if( NA_IS_IFACTORY_OBJECT( object )){
187 		na_factory_object_finalize( NA_IFACTORY_OBJECT( object ));
188 	}
189 
190 	/* chain call to parent class */
191 	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
192 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
193 	}
194 }
195 
196 static void
object_dump(const NAObject * object)197 object_dump( const NAObject *object )
198 {
199 	if( !object->private->dispose_has_run ){
200 
201 		na_iduplicable_dump( NA_IDUPLICABLE( object ));
202 
203 		if( NA_IS_IFACTORY_OBJECT( object )){
204 			na_factory_object_dump( NA_IFACTORY_OBJECT( object ));
205 		}
206 	}
207 }
208 
209 static void
iduplicable_iface_init(NAIDuplicableInterface * iface,void * user_data)210 iduplicable_iface_init( NAIDuplicableInterface *iface, void *user_data )
211 {
212 	static const gchar *thisfn = "na_object_iduplicable_iface_init";
213 
214 	g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
215 
216 	iface->copy = iduplicable_copy;
217 	iface->are_equal = iduplicable_are_equal;
218 	iface->is_valid = iduplicable_is_valid;
219 }
220 
221 /*
222  * implementation of na_iduplicable::copy interface virtual function
223  * it recursively copies @source to @target
224  */
225 static void
iduplicable_copy(NAIDuplicable * target,const NAIDuplicable * source,guint mode)226 iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source, guint mode )
227 {
228 	static const gchar *thisfn = "na_object_iduplicable_copy";
229 	NAObject *dest, *src;
230 
231 	g_return_if_fail( NA_IS_OBJECT( target ));
232 	g_return_if_fail( NA_IS_OBJECT( source ));
233 
234 	dest = NA_OBJECT( target );
235 	src = NA_OBJECT( source );
236 
237 	if( !dest->private->dispose_has_run &&
238 		!src->private->dispose_has_run ){
239 
240 		g_debug( "%s: target=%p (%s), source=%p (%s), mode=%d",
241 				thisfn,
242 				( void * ) dest, G_OBJECT_TYPE_NAME( dest ),
243 				( void * ) src, G_OBJECT_TYPE_NAME( src ),
244 				mode );
245 
246 		if( NA_IS_IFACTORY_OBJECT( target )){
247 			na_factory_object_copy( NA_IFACTORY_OBJECT( target ), NA_IFACTORY_OBJECT( source ));
248 		}
249 
250 		if( NA_IS_ICONTEXT( target )){
251 			na_icontext_copy( NA_ICONTEXT( target ), NA_ICONTEXT( source ));
252 		}
253 
254 		v_copy( dest, src, mode );
255 	}
256 }
257 
258 static gboolean
iduplicable_are_equal(const NAIDuplicable * a,const NAIDuplicable * b)259 iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
260 {
261 	static const gchar *thisfn = "na_object_iduplicable_are_equal";
262 	gboolean are_equal;
263 
264 	g_return_val_if_fail( NA_IS_OBJECT( a ), FALSE );
265 	g_return_val_if_fail( NA_IS_OBJECT( b ), FALSE );
266 
267 	are_equal = FALSE;
268 
269 	if( !NA_OBJECT( a )->private->dispose_has_run &&
270 		!NA_OBJECT( b )->private->dispose_has_run ){
271 
272 		g_debug( "%s: a=%p (%s), b=%p", thisfn, ( void * ) a, G_OBJECT_TYPE_NAME( a ), ( void * ) b );
273 
274 		are_equal = TRUE;
275 
276 		if( NA_IS_IFACTORY_OBJECT( a )){
277 			are_equal &= na_factory_object_are_equal( NA_IFACTORY_OBJECT( a ), NA_IFACTORY_OBJECT( b ));
278 		}
279 
280 		if( NA_IS_ICONTEXT( a )){
281 			are_equal &= na_icontext_are_equal( NA_ICONTEXT( a ), NA_ICONTEXT( b ));
282 		}
283 
284 		are_equal &= v_are_equal( NA_OBJECT( a ), NA_OBJECT( b ));
285 	}
286 
287 	return( are_equal );
288 }
289 
290 static gboolean
iduplicable_is_valid(const NAIDuplicable * object)291 iduplicable_is_valid( const NAIDuplicable *object )
292 {
293 	static const gchar *thisfn = "na_object_iduplicable_is_valid";
294 	gboolean is_valid;
295 
296 	g_return_val_if_fail( NA_IS_OBJECT( object ), FALSE );
297 
298 	is_valid = FALSE;
299 
300 	if( !NA_OBJECT( object )->private->dispose_has_run ){
301 		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
302 
303 		is_valid = TRUE;
304 
305 		if( NA_IS_IFACTORY_OBJECT( object )){
306 			is_valid &= na_factory_object_is_valid( NA_IFACTORY_OBJECT( object ));
307 		}
308 
309 		if( NA_IS_ICONTEXT( object )){
310 			is_valid &= na_icontext_is_valid( NA_ICONTEXT( object ));
311 		}
312 
313 		is_valid &= v_is_valid( NA_OBJECT( object ));
314 	}
315 
316 	return( is_valid );
317 }
318 
319 /**
320  * na_object_object_check_status_rec:
321  * @object: the #NAObject -derived object to be checked.
322  *
323  * Recursively checks for the edition status of @object and its children
324  * (if any).
325  *
326  * Internally set some properties which may be requested later. This
327  * two-steps check-request let us optimize some work in the UI.
328  *
329  * <literallayout>
330  * na_object_object_check_status_rec( object )
331  *  +- na_iduplicable_check_status( object )
332  *      +- get_origin( object )
333  *      +- modified_status = v_are_equal( origin, object )
334  *      |  +-> interface <structfield>NAObjectClass::are_equal</structfield>
335  *      |      which happens to be iduplicable_are_equal( a, b )
336  *      |       +- v_are_equal( a, b )
337  *      |           +- NAObjectAction::are_equal()
338  *      |               +- na_factory_object_are_equal()
339  *      |               +- check NAObjectActionPrivate data
340  *      |               +- call parent class
341  *      |                  +- NAObjectItem::are_equal()
342  *      |                      +- check NAObjectItemPrivate data
343  *      |                      +- call parent class
344  *      |                          +- NAObjectId::are_equal()
345  *      |
346  *      +- valid_status = v_is_valid( object )             -> interface <structfield>NAObjectClass::is_valid</structfield>
347  * </literallayout>
348  *
349  *   Note that the recursivity is managed here, so that we can be sure
350  *   that edition status of children is actually checked before those of
351  *   the parent.
352  *
353  * <formalpara>
354  *  <title>
355  *   As of 3.1.0:
356  *  </title>
357  *  <para>
358  *   <itemizedlist>
359  *    <listitem>
360  *     <para>
361  *      when the modification status of a NAObjectProfile changes, then its
362  *      NAObjectAction parent is rechecked;
363  *     </para>
364  *    </listitem>
365  *    <listitem>
366  *     <para>
367  *      when the validity status of an object is changed, then its parent is
368  *      also rechecked.
369  *     </para>
370  *    </listitem>
371  *   </itemizedlist>
372  *  </para>
373  * </formalpara>
374  *
375  * Since: 2.30
376  */
377 void
na_object_object_check_status_rec(const NAObject * object)378 na_object_object_check_status_rec( const NAObject *object )
379 {
380 	static const gchar *thisfn = "na_object_object_check_status_rec";
381 	gboolean was_modified, was_valid;
382 
383 	g_return_if_fail( NA_IS_OBJECT( object ));
384 
385 	if( !object->private->dispose_has_run ){
386 		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
387 
388 		was_modified = na_object_is_modified( object );
389 		was_valid = na_object_is_valid( object );
390 		check_status_down_rec( object );
391 		check_status_up_rec( object, was_modified, was_valid );
392 	}
393 }
394 
395 /*
396  * recursively checks the status downstream
397  */
398 static void
check_status_down_rec(const NAObject * object)399 check_status_down_rec( const NAObject *object )
400 {
401 	if( NA_IS_OBJECT_ITEM( object )){
402 		g_list_foreach( na_object_get_items( object ), ( GFunc ) check_status_down_rec, NULL );
403 	}
404 
405 	na_iduplicable_check_status( NA_IDUPLICABLE( object ));
406 }
407 
408 /*
409  * if the status appears changed, then rechecks the parent
410  * recurse upstream while there is a parent, and its status changes
411  */
412 static void
check_status_up_rec(const NAObject * object,gboolean was_modified,gboolean was_valid)413 check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was_valid )
414 {
415 	gboolean is_modified, is_valid;
416 	NAObjectItem *parent;
417 
418 	is_modified = na_object_is_modified( object );
419 	is_valid = na_object_is_valid( object );
420 
421 	if(( NA_IS_OBJECT_PROFILE( object ) && was_modified != is_modified ) ||
422 			was_valid != is_valid ){
423 
424 			parent = na_object_get_parent( object );
425 
426 			if( parent ){
427 				was_modified = na_object_is_modified( parent );
428 				was_valid = na_object_is_valid( parent );
429 				na_iduplicable_check_status( NA_IDUPLICABLE( parent ));
430 				check_status_up_rec( NA_OBJECT( parent ), was_modified, was_valid );
431 			}
432 	}
433 }
434 
435 static void
v_copy(NAObject * target,const NAObject * source,guint mode)436 v_copy( NAObject *target, const NAObject *source, guint mode )
437 {
438 	if( NA_OBJECT_GET_CLASS( target )->copy ){
439 		NA_OBJECT_GET_CLASS( target )->copy( target, source, mode );
440 	}
441 }
442 
443 static gboolean
v_are_equal(const NAObject * a,const NAObject * b)444 v_are_equal( const NAObject *a, const NAObject *b )
445 {
446 	if( NA_OBJECT_GET_CLASS( a )->are_equal ){
447 		return( NA_OBJECT_GET_CLASS( a )->are_equal( a, b ));
448 	}
449 
450 	return( TRUE );
451 }
452 
453 static gboolean
v_is_valid(const NAObject * a)454 v_is_valid( const NAObject *a )
455 {
456 	if( NA_OBJECT_GET_CLASS( a )->is_valid ){
457 		return( NA_OBJECT_GET_CLASS( a )->is_valid( a ));
458 	}
459 
460 	return( TRUE );
461 }
462 
463 /**
464  * na_object_object_dump:
465  * @object: the #NAObject -derived object to be dumped.
466  *
467  * Dumps via g_debug() the actual content of the object.
468  *
469  * The recursivity is dealt with here because, if we would let
470  * #NAObjectItem do this, the dump of #NAObjectItem -derived object
471  * would be splitted, children being inserted inside.
472  *
473  * na_object_dump() doesn't modify the reference count of the dumped
474  * object.
475  *
476  * Since: 2.30
477  */
478 void
na_object_object_dump(const NAObject * object)479 na_object_object_dump( const NAObject *object )
480 {
481 	GList *children, *ic;
482 
483 	g_return_if_fail( NA_IS_OBJECT( object ));
484 
485 	if( !object->private->dispose_has_run ){
486 
487 		na_object_dump_norec( object );
488 
489 		if( NA_IS_OBJECT_ITEM( object )){
490 			children = na_object_get_items( object );
491 
492 			for( ic = children ; ic ; ic = ic->next ){
493 				na_object_dump( ic->data );
494 			}
495 		}
496 	}
497 }
498 
499 /**
500  * na_object_object_dump_norec:
501  * @object: the #NAObject -derived object to be dumped.
502  *
503  * Dumps via g_debug the actual content of the object.
504  *
505  * This function is not recursive.
506  *
507  * Since: 2.30
508  */
509 void
na_object_object_dump_norec(const NAObject * object)510 na_object_object_dump_norec( const NAObject *object )
511 {
512 	g_return_if_fail( NA_IS_OBJECT( object ));
513 
514 	if( !object->private->dispose_has_run ){
515 		if( NA_OBJECT_GET_CLASS( object )->dump ){
516 			NA_OBJECT_GET_CLASS( object )->dump( object );
517 		}
518 	}
519 }
520 
521 /**
522  * na_object_object_dump_tree:
523  * @tree: a hierarchical list of #NAObject -derived objects.
524  *
525  * Outputs a brief, hierarchical dump of the provided list.
526  *
527  * Since: 2.30
528  */
529 void
na_object_object_dump_tree(GList * tree)530 na_object_object_dump_tree( GList *tree )
531 {
532 	dump_tree( tree, 0 );
533 }
534 
535 static void
dump_tree(GList * tree,gint level)536 dump_tree( GList *tree, gint level )
537 {
538 	GString *prefix;
539 	gint i;
540 	GList *it;
541 	const NAObject *object;
542 	gchar *label;
543 
544 	prefix = g_string_new( "" );
545 	for( i = 0 ; i < level ; ++i ){
546 		g_string_append_printf( prefix, "  " );
547 	}
548 
549 	for( it = tree ; it ; it = it->next ){
550 		object = ( const NAObject * ) it->data;
551 		label = na_object_get_label( object );
552 		g_debug( "na_object_dump_tree: %s%p (%s, ref_count=%u) '%s'", prefix->str,
553 				( void * ) object, G_OBJECT_TYPE_NAME( object ), G_OBJECT( object )->ref_count, label );
554 		g_free( label );
555 
556 		if( NA_IS_OBJECT_ITEM( object )){
557 			dump_tree( na_object_get_items( object ), level+1 );
558 		}
559 	}
560 
561 	g_string_free( prefix, TRUE );
562 }
563 
564 /**
565  * na_object_object_reset_origin:
566  * @object: a #NAObject -derived object.
567  * @origin: must be a duplication of @object.
568  *
569  * Recursively reset origin of @object and its children to @origin (and
570  * its children), so that @origin appears as the actual origin of @object.
571  *
572  * The origin of @origin itself is set to NULL.
573  *
574  * This only works if @origin has just been duplicated from @object,
575  * and thus we do not have to check if children lists are equal.
576  *
577  * Since: 2.30
578  */
579 void
na_object_object_reset_origin(NAObject * object,const NAObject * origin)580 na_object_object_reset_origin( NAObject *object, const NAObject *origin )
581 {
582 	GList *origin_children, *iorig;
583 	GList *object_children, *iobj;
584 
585 	g_return_if_fail( NA_IS_OBJECT( origin ));
586 	g_return_if_fail( NA_IS_OBJECT( object ));
587 
588 	if( !object->private->dispose_has_run && !origin->private->dispose_has_run ){
589 
590 		origin_children = na_object_get_items( origin );
591 		object_children = na_object_get_items( object );
592 
593 		for( iorig = origin_children, iobj = object_children ; iorig && iobj ; iorig = iorig->next, iobj = iobj->next ){
594 			na_object_reset_origin( iobj->data, iorig->data );
595 		}
596 
597 		na_iduplicable_set_origin( NA_IDUPLICABLE( object ), NA_IDUPLICABLE( origin ));
598 		na_iduplicable_set_origin( NA_IDUPLICABLE( origin ), NULL );
599 	}
600 }
601 
602 /**
603  * na_object_object_ref:
604  * @object: a #NAObject -derived object.
605  *
606  * Recursively ref the @object and all its children, incrementing their
607  * reference_count by 1.
608  *
609  * Returns: a reference on the @object.
610  *
611  * Since: 2.30
612  */
613 NAObject *
na_object_object_ref(NAObject * object)614 na_object_object_ref( NAObject *object )
615 {
616 	NAObject *ref;
617 
618 	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
619 
620 	ref = NULL;
621 
622 	if( !object->private->dispose_has_run ){
623 
624 		if( NA_IS_OBJECT_ITEM( object )){
625 			g_list_foreach( na_object_get_items( object ), ( GFunc ) na_object_object_ref, NULL );
626 		}
627 
628 		ref = g_object_ref( object );
629 	}
630 
631 	return( ref );
632 }
633 
634 /**
635  * na_object_object_unref:
636  * @object: a #NAObject -derived object.
637  *
638  * Recursively unref the @object and all its children, decrementing their
639  * reference_count by 1.
640  *
641  * Note that we may want to free a copy+ref of a list of items whichy have
642  * had already disposed (which is probably a bug somewhere). So first test
643  * is the object is still alive.
644  *
645  * Since: 2.30
646  */
647 void
na_object_object_unref(NAObject * object)648 na_object_object_unref( NAObject *object )
649 {
650 	g_return_if_fail( NA_IS_OBJECT( object ));
651 
652 	if( !object->private->dispose_has_run ){
653 		if( NA_IS_OBJECT_ITEM( object )){
654 			g_list_foreach( na_object_get_items( object ), ( GFunc ) na_object_object_unref, NULL );
655 		}
656 		g_object_unref( object );
657 	}
658 }
659 
660 #ifdef NA_ENABLE_DEPRECATED
661 /*
662  * build the class hierarchy
663  * returns a list of GObjectClass, which starts with NAObject,
664  * and to with the most derived class (e.g. NAObjectAction or so)
665  */
666 static GList *
build_class_hierarchy(const NAObject * object)667 build_class_hierarchy( const NAObject *object )
668 {
669 	GObjectClass *class;
670 	GList *hierarchy;
671 
672 	hierarchy = NULL;
673 	class = G_OBJECT_GET_CLASS( object );
674 
675 	while( G_OBJECT_CLASS_TYPE( class ) != NA_TYPE_OBJECT ){
676 
677 		hierarchy = g_list_prepend( hierarchy, class );
678 		class = g_type_class_peek_parent( class );
679 	}
680 
681 	hierarchy = g_list_prepend( hierarchy, class );
682 
683 	return( hierarchy );
684 }
685 
686 /**
687  * na_object_get_hierarchy:
688  * @object: the #NAObject -derived object.
689  *
690  * Returns: the class hierarchy,
691  * from the topmost base class, to the most-derived one.
692  *
693  * Since: 2.30
694  * Deprecated: 3.1
695  */
696 GList *
na_object_get_hierarchy(const NAObject * object)697 na_object_get_hierarchy( const NAObject *object )
698 {
699 	GList *hierarchy;
700 
701 	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
702 
703 	hierarchy = NULL;
704 
705 	if( !object->private->dispose_has_run ){
706 
707 		hierarchy = build_class_hierarchy( object );
708 	}
709 
710 	return( hierarchy );
711 }
712 
713 /**
714  * na_object_free_hierarchy:
715  * @hierarchy: the #GList of hierarchy, as returned from
716  *  na_object_get_hierarchy().
717  *
718  * Releases the #NAObject hierarchy.
719  *
720  * Since: 2.30
721  * Deprecated: 3.1
722  */
723 void
na_object_free_hierarchy(GList * hierarchy)724 na_object_free_hierarchy( GList *hierarchy )
725 {
726 	g_list_free( hierarchy );
727 }
728 #endif /* NA_ENABLE_DEPRECATED */
729 
730 /**
731  * na_object_object_debug_invalid:
732  * @object: the #NAObject -derived object which is invalid.
733  * @reason: the reason.
734  *
735  * Dump the object with the invalidity reason.
736  *
737  * Since: 2.30
738  */
739 void
na_object_object_debug_invalid(const NAObject * object,const gchar * reason)740 na_object_object_debug_invalid( const NAObject *object, const gchar *reason )
741 {
742 	g_debug( "na_object_object_debug_invalid: object %p (%s) is marked invalid for reason \"%s\"",
743 			( void * ) object, G_OBJECT_TYPE_NAME( object ), reason );
744 }
745