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