3 * A file-manager extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2015 Pierre Wieser and others (see AUTHORS)
9 * FileManager-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.
14 * FileManager-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.
19 * You should have received a copy of the GNU General Public License
20 * along with FileManager-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
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)
34 #include "api/fma-iduplicable.h"
36 /* private interface data
38 struct _FMAIDuplicableInterfacePrivate
{
42 /* the data sructure set on each FMAIDuplicable object
45 FMAIDuplicable
*origin
;
51 #define FMA_IDUPLICABLE_DATA_DUPLICABLE "fma-iduplicable-data-duplicable"
53 /* signals emitted on FMAIDuplicable when a status changes
61 static FMAIDuplicableInterface
*st_interface
= NULL
;
62 static guint st_initializations
= 0;
63 static gint st_signals
[ LAST_SIGNAL
] = { 0 };
65 static GType
register_type( void );
66 static void interface_base_init( FMAIDuplicableInterface
*klass
);
67 static void interface_base_finalize( FMAIDuplicableInterface
*klass
);
69 static void v_copy( FMAIDuplicable
*target
, const FMAIDuplicable
*source
, guint mode
);
70 static gboolean
v_are_equal( const FMAIDuplicable
*a
, const FMAIDuplicable
*b
);
71 static gboolean
v_is_valid( const FMAIDuplicable
*object
);
73 static DuplicableStr
*get_duplicable_str( const FMAIDuplicable
*object
);
75 static void on_modified_changed_class_handler( FMAIDuplicable
*instance
, GObject
*object
, gboolean is_modified
);
76 static void on_valid_changed_class_handler( FMAIDuplicable
*instance
, GObject
*object
, gboolean is_valid
);
77 static void propagate_signal_to_consumers( FMAIDuplicable
*instance
, const gchar
*signal
, GObject
*object
, gboolean new_status
);
78 static void release_signal_consumers( GList
*consumers
);
81 fma_iduplicable_get_type( void )
83 static GType iface_type
= 0;
86 iface_type
= register_type();
95 static const gchar
*thisfn
= "fma_iduplicable_register_type";
98 static const GTypeInfo info
= {
99 sizeof( FMAIDuplicableInterface
),
100 ( GBaseInitFunc
) interface_base_init
,
101 ( GBaseFinalizeFunc
) interface_base_finalize
,
110 g_debug( "%s", thisfn
);
112 type
= g_type_register_static( G_TYPE_INTERFACE
, "FMAIDuplicable", &info
, 0 );
114 g_type_interface_add_prerequisite( type
, G_TYPE_OBJECT
);
120 interface_base_init( FMAIDuplicableInterface
*klass
)
122 static const gchar
*thisfn
= "fma_iduplicable_interface_base_init";
124 if( !st_initializations
){
126 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
128 klass
->private = g_new0( FMAIDuplicableInterfacePrivate
, 1 );
130 klass
->private->consumers
= NULL
;
133 klass
->are_equal
= NULL
;
134 klass
->is_valid
= NULL
;
137 * FMAIDuplicable::modified-changed:
139 * This signal is emitted by #FMAIDuplicable when the modification
140 * status of an object has been modified.
142 * The default class handler propagates the signal to registered
145 * Signal args: New modification status
148 * void ( *handler )( FMAIDuplicable *duplicable, FMAObject *object, gboolean is_modified, gpointer user_data );
150 * When the signal is first emitted, thus on FMAIDuplicable, @duplicable
151 * and @object are pointers to the same address. This duplication is
152 * relevant when propagating the signal to customer, as the signal is
153 * emitted on the customer itself, while we still need the @object
156 st_signals
[ MODIFIED_CHANGED
] = g_signal_new_class_handler(
157 IDUPLICABLE_SIGNAL_MODIFIED_CHANGED
,
159 G_SIGNAL_RUN_CLEANUP
,
160 G_CALLBACK( on_modified_changed_class_handler
),
166 G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
169 * FMAIDuplicable::valid-changed:
171 * This signal is emitted by #FMAIDuplicable when the validity
172 * status of an object has been modified.
174 * The default class handler propagates the signal to registered
177 * Signal args: New validity status
180 * void ( *handler )( FMAIDuplicable *duplicable, FMAObject *object, gboolean is_valid, gpointer user_data );
182 * When the signal is first emitted, thus on FMAIDuplicable, @duplicable
183 * and @object are pointers to the same address. This duplication is
184 * relevant when propagating the signal to customer, as the signal is
185 * emitted on the customer itself, while we still need the @object
188 st_signals
[ VALID_CHANGED
] = g_signal_new_class_handler(
189 IDUPLICABLE_SIGNAL_VALID_CHANGED
,
191 G_SIGNAL_RUN_CLEANUP
,
192 G_CALLBACK( on_valid_changed_class_handler
),
198 G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
200 st_interface
= klass
;
203 st_initializations
+= 1;
207 interface_base_finalize( FMAIDuplicableInterface
*klass
)
209 static const gchar
*thisfn
= "fma_iduplicable_interface_base_finalize";
211 st_initializations
-= 1;
213 if( !st_initializations
){
215 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
217 release_signal_consumers( klass
->private->consumers
);
219 g_free( klass
->private );
224 * fma_iduplicable_dispose:
225 * @object: the #FMAIDuplicable object to be initialized.
227 * Releases resources.
232 fma_iduplicable_dispose( const FMAIDuplicable
*object
)
236 g_return_if_fail( FMA_IS_IDUPLICABLE( object
));
238 str
= get_duplicable_str( object
);
240 g_object_set_data( G_OBJECT( object
), FMA_IDUPLICABLE_DATA_DUPLICABLE
, NULL
);
244 * fma_iduplicable_dump:
245 * @object: the #FMAIDuplicable object to be dumped.
247 * Dumps via g_debug the properties of the object.
249 * We ouput here only the data we set ourselves againt the
250 * #FMAIDuplicable -implemented object.
252 * This function should be called by the implementation when it dumps
253 * itself its own content.
258 fma_iduplicable_dump( const FMAIDuplicable
*object
)
260 static const gchar
*thisfn
= "fma_iduplicable_dump";
263 g_return_if_fail( FMA_IS_IDUPLICABLE( object
));
265 str
= get_duplicable_str( object
);
267 g_debug( "| %s: origin=%p", thisfn
, ( void * ) str
->origin
);
268 g_debug( "| %s: modified=%s", thisfn
, str
->modified
? "True" : "False" );
269 g_debug( "| %s: valid=%s", thisfn
, str
->valid
? "True" : "False" );
273 * fma_iduplicable_duplicate:
274 * @object: the #FMAIDuplicable object to be duplicated.
275 * @mode: the %FMADuplicableMode duplication mode.
277 * Exactly duplicates a #FMAIDuplicable -implemented object, including
278 * modification and validity status which are copied from @object to
279 * the duplicated one.
281 * Returns: a new #FMAIDuplicable.
286 fma_iduplicable_duplicate( const FMAIDuplicable
*object
, guint mode
)
288 static const gchar
*thisfn
= "fma_iduplicable_duplicate";
290 DuplicableStr
*dup_str
, *obj_str
;
292 g_return_val_if_fail( FMA_IS_IDUPLICABLE( object
), NULL
);
294 g_debug( "%s: object=%p (%s)",
296 ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
298 dup
= g_object_new( G_OBJECT_TYPE( object
), NULL
);
300 v_copy( dup
, object
, mode
);
302 dup_str
= get_duplicable_str( dup
);
303 obj_str
= get_duplicable_str( object
);
305 dup_str
->origin
= ( FMAIDuplicable
* ) object
;
306 dup_str
->modified
= obj_str
->modified
;
307 dup_str
->valid
= obj_str
->valid
;
313 * fma_iduplicable_check_status:
314 * @object: the #FMAIDuplicable object to be checked.
316 * Checks the edition status of the #FMAIDuplicable object, and set up
317 * the corresponding properties.
319 * This function is supposed to be called each time the object may have
320 * been modified in order to set the corresponding properties. Helper
321 * functions fma_iduplicable_is_modified() and fma_iduplicable_is_valid()
322 * will then only return the current value of the properties.
324 * fma_iduplicable_check_status() is not, as itself, recursive.
325 * That is, the modification and validity status are only set on the
327 * #FMAObject implementation has chosen to handle itself the recursivity:
328 * fma_object_check_status() so first check status for children, before
329 * calling this function.
334 fma_iduplicable_check_status( const FMAIDuplicable
*object
)
336 static const gchar
*thisfn
= "fma_iduplicable_check_status";
338 gboolean was_modified
, was_valid
;
340 g_return_if_fail( FMA_IS_IDUPLICABLE( object
));
342 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
344 str
= get_duplicable_str( object
);
346 was_modified
= str
->modified
;
347 was_valid
= str
->valid
;
350 g_debug( "%s: vs. origin=%p (%s)", thisfn
, ( void * ) str
->origin
, G_OBJECT_TYPE_NAME( str
->origin
));
351 g_return_if_fail( FMA_IS_IDUPLICABLE( str
->origin
));
352 str
->modified
= !v_are_equal( str
->origin
, object
);
355 str
->modified
= TRUE
;
358 if( was_modified
!= str
->modified
){
359 g_debug( "%s: %p (%s) status changed to modified=%s",
360 thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
), str
->modified
? "True":"False" );
361 g_signal_emit_by_name( G_OBJECT( object
), IDUPLICABLE_SIGNAL_MODIFIED_CHANGED
, object
, str
->modified
);
364 str
->valid
= v_is_valid( object
);
366 if( was_valid
!= str
->valid
){
367 g_debug( "%s: %p (%s) status changed to valid=%s",
368 thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
), str
->valid
? "True":"False" );
369 g_signal_emit_by_name( G_OBJECT( object
), IDUPLICABLE_SIGNAL_VALID_CHANGED
, object
, str
->valid
);
374 * fma_iduplicable_get_origin:
375 * @object: the #FMAIDuplicable object whose origin is to be returned.
377 * Returns the origin of a duplicated #FMAIDuplicable.
379 * Returns: the original #FMAIDuplicable, or NULL.
384 fma_iduplicable_get_origin( const FMAIDuplicable
*object
)
386 FMAIDuplicable
*origin
;
389 g_return_val_if_fail( FMA_IS_IDUPLICABLE( object
), NULL
);
391 str
= get_duplicable_str( object
);
392 origin
= str
->origin
;
398 * fma_iduplicable_is_valid:
399 * @object: the #FMAIDuplicable object whose status is to be returned.
401 * Returns the current value of the relevant property
402 * without rechecking the edition status itself.
404 * Returns: %TRUE is the provided object is valid.
409 fma_iduplicable_is_valid( const FMAIDuplicable
*object
)
414 g_return_val_if_fail( FMA_IS_IDUPLICABLE( object
), FALSE
);
416 str
= get_duplicable_str( object
);
417 is_valid
= str
->valid
;
423 * fma_iduplicable_is_modified:
424 * @object: the #FMAIDuplicable object whose status is to be returned.
426 * Returns the current value of the 'is_modified'
427 * property without rechecking the edition status itself.
429 * Returns: %TRUE is the provided object has been modified regarding of
435 fma_iduplicable_is_modified( const FMAIDuplicable
*object
)
437 gboolean is_modified
;
440 g_return_val_if_fail( FMA_IS_IDUPLICABLE( object
), FALSE
);
442 str
= get_duplicable_str( object
);
443 is_modified
= str
->modified
;
445 return( is_modified
);
449 * fma_iduplicable_set_origin:
450 * @object: the #FMAIDuplicable object whose origin is to be set.
451 * @origin: the new original #FMAIDuplicable.
453 * Sets the new origin of a duplicated #FMAIDuplicable.
458 fma_iduplicable_set_origin( FMAIDuplicable
*object
, const FMAIDuplicable
*origin
)
462 g_return_if_fail( FMA_IS_IDUPLICABLE( object
));
463 g_return_if_fail( FMA_IS_IDUPLICABLE( origin
) || !origin
);
465 str
= get_duplicable_str( object
);
466 str
->origin
= ( FMAIDuplicable
* ) origin
;
469 #ifdef FMA_ENABLE_DEPRECATED
471 * fma_iduplicable_set_modified:
472 * @object: the #FMAIDuplicable object whose modification status is to be set.
473 * @modified: the new modification status #FMAIDuplicable.
475 * Sets the new modification status of a duplicated #FMAIDuplicable.
481 fma_iduplicable_set_modified( FMAIDuplicable
*object
, gboolean modified
)
485 g_return_if_fail( FMA_IS_IDUPLICABLE( object
));
487 str
= get_duplicable_str( object
);
488 str
->modified
= modified
;
490 #endif /* FMA_ENABLE_DEPRECATED */
493 v_copy( FMAIDuplicable
*target
, const FMAIDuplicable
*source
, guint mode
)
495 if( FMA_IDUPLICABLE_GET_INTERFACE( target
)->copy
){
496 FMA_IDUPLICABLE_GET_INTERFACE( target
)->copy( target
, source
, mode
);
501 v_are_equal( const FMAIDuplicable
*a
, const FMAIDuplicable
*b
)
503 if( FMA_IDUPLICABLE_GET_INTERFACE( a
)->are_equal
){
504 return( FMA_IDUPLICABLE_GET_INTERFACE( a
)->are_equal( a
, b
));
511 v_is_valid( const FMAIDuplicable
*object
)
513 if( FMA_IDUPLICABLE_GET_INTERFACE( object
)->is_valid
){
514 return( FMA_IDUPLICABLE_GET_INTERFACE( object
)->is_valid( object
));
521 * fma_iduplicable_register_consumer:
522 * @consumer: the target instance.
524 * This function registers a consumer, i.e. an instance to which edition
525 * status signals will be propagated.
530 fma_iduplicable_register_consumer( GObject
*consumer
)
532 g_return_if_fail( st_interface
);
534 g_debug( "fma_iduplicable_register_consumer: consumer=%p", ( void * ) consumer
);
536 st_interface
->private->consumers
= g_list_prepend( st_interface
->private->consumers
, consumer
);
540 on_modified_changed_class_handler( FMAIDuplicable
*instance
, GObject
*object
, gboolean is_modified
)
542 if( FMA_IS_IDUPLICABLE( instance
)){
543 propagate_signal_to_consumers( instance
, IDUPLICABLE_SIGNAL_MODIFIED_CHANGED
, object
, is_modified
);
548 on_valid_changed_class_handler( FMAIDuplicable
*instance
, GObject
*object
, gboolean is_valid
)
550 if( FMA_IS_IDUPLICABLE( instance
)){
551 propagate_signal_to_consumers( instance
, IDUPLICABLE_SIGNAL_VALID_CHANGED
, object
, is_valid
);
556 propagate_signal_to_consumers( FMAIDuplicable
*instance
, const gchar
*signal
, GObject
*object
, gboolean new_status
)
558 static const gchar
*thisfn
= "fma_iduplicable_propagate_signals_to_consumers";
561 g_return_if_fail( FMA_IS_IDUPLICABLE( instance
));
563 g_debug( "%s: instance=%p, signal=%s", thisfn
, ( void * ) instance
, signal
);
565 for( ic
= st_interface
->private->consumers
; ic
; ic
= ic
->next
){
566 g_signal_emit_by_name( ic
->data
, signal
, object
, new_status
);
571 release_signal_consumers( GList
*consumers
)
573 g_list_free( consumers
);
576 static DuplicableStr
*
577 get_duplicable_str( const FMAIDuplicable
*object
)
581 str
= ( DuplicableStr
* ) g_object_get_data( G_OBJECT( object
), FMA_IDUPLICABLE_DATA_DUPLICABLE
);
584 str
= g_new0( DuplicableStr
, 1 );
587 str
->modified
= FALSE
;
590 g_object_set_data( G_OBJECT( object
), FMA_IDUPLICABLE_DATA_DUPLICABLE
, str
);