Update copyright message
[nautilus-actions.git] / src / core / na-pivot.c
blob94f215607088936d6997653983c24446e9308a7c
1 /*
2 * Nautilus Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program 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 * This Program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <string.h>
37 #include <api/na-core-utils.h>
38 #include <api/na-gconf-monitor.h>
39 #include <api/na-gconf-utils.h>
41 #include "na-io-provider.h"
42 #include "na-iprefs.h"
43 #include "na-module.h"
44 #include "na-pivot.h"
46 /* private class data
48 struct _NAPivotClassPrivate {
49 void *empty; /* so that gcc -pedantic is happy */
52 /* private instance data
54 struct _NAPivotPrivate {
55 gboolean dispose_has_run;
57 guint loadable_set;
59 /* dynamically loaded modules (extension plugins)
61 GList *modules;
63 /* list of instances to be notified of configuration updates
64 * these are called 'consumers' of NAPivot
66 GList *consumers;
68 /* configuration tree of actions and menus
70 GList *tree;
72 /* whether to automatically reload the whole configuration tree
73 * when a modification is detected in one of the underlying I/O
74 * storage subsystems
75 * defaults to FALSE
77 gboolean automatic_reload;
78 GTimeVal last_event;
79 guint event_source_id;
81 /* list of monitoring objects on runtime preferences
83 GList *monitors;
86 /* NAPivot properties
88 enum {
89 NAPIVOT_PROP_TREE_ID = 1,
93 static GObjectClass *st_parent_class = NULL;
94 static gint st_burst_timeout = 100; /* burst timeout in msec */
96 static GType register_type( void );
97 static void class_init( NAPivotClass *klass );
98 static void instance_init( GTypeInstance *instance, gpointer klass );
99 static void instance_constructed( GObject *object );
100 static void instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
101 static void instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
102 static void instance_dispose( GObject *object );
103 static void instance_finalize( GObject *object );
105 static void iprefs_iface_init( NAIPrefsInterface *iface );
107 static NAObjectItem *get_item_from_tree( const NAPivot *pivot, GList *tree, const gchar *id );
109 /* NAIPivotConsumer management */
110 static void free_consumers( GList *list );
112 /* NAIIOProvider management */
113 static gboolean on_item_changed_timeout( NAPivot *pivot );
114 static gulong time_val_diff( const GTimeVal *recent, const GTimeVal *old );
116 /* NAGConf runtime preferences management */
117 static void monitor_runtime_preferences( NAPivot *pivot );
118 static void on_io_provider_prefs_changed( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot );
119 static void on_mandatory_prefs_changed( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot );
120 static void on_preferences_change( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot );
121 static void display_order_changed( NAPivot *pivot );
122 static void create_root_menu_changed( NAPivot *pivot );
123 static void display_about_changed( NAPivot *pivot );
124 static void autosave_changed( NAPivot *pivot );
126 GType
127 na_pivot_get_type( void )
129 static GType object_type = 0;
131 if( !object_type ){
132 object_type = register_type();
135 return( object_type );
138 static GType
139 register_type( void )
141 static const gchar *thisfn = "na_pivot_register_type";
142 GType type;
144 static GTypeInfo info = {
145 sizeof( NAPivotClass ),
146 ( GBaseInitFunc ) NULL,
147 ( GBaseFinalizeFunc ) NULL,
148 ( GClassInitFunc ) class_init,
149 NULL,
150 NULL,
151 sizeof( NAPivot ),
153 ( GInstanceInitFunc ) instance_init
156 static const GInterfaceInfo iprefs_iface_info = {
157 ( GInterfaceInitFunc ) iprefs_iface_init,
158 NULL,
159 NULL
162 g_debug( "%s", thisfn );
164 type = g_type_register_static( G_TYPE_OBJECT, "NAPivot", &info, 0 );
166 g_type_add_interface_static( type, NA_IPREFS_TYPE, &iprefs_iface_info );
168 return( type );
171 static void
172 class_init( NAPivotClass *klass )
174 static const gchar *thisfn = "na_pivot_class_init";
175 GObjectClass *object_class;
176 GParamSpec *spec;
178 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
180 st_parent_class = g_type_class_peek_parent( klass );
182 object_class = G_OBJECT_CLASS( klass );
183 object_class->constructed = instance_constructed;
184 object_class->set_property = instance_set_property;
185 object_class->get_property = instance_get_property;
186 object_class->dispose = instance_dispose;
187 object_class->finalize = instance_finalize;
189 spec = g_param_spec_pointer(
190 NAPIVOT_PROP_TREE,
191 "Items tree",
192 "Hierarchical tree of items",
193 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
194 g_object_class_install_property( object_class, NAPIVOT_PROP_TREE_ID, spec );
196 klass->private = g_new0( NAPivotClassPrivate, 1 );
199 static void
200 instance_init( GTypeInstance *instance, gpointer klass )
202 static const gchar *thisfn = "na_pivot_instance_init";
203 NAPivot *self;
205 g_return_if_fail( NA_IS_PIVOT( instance ));
206 self = NA_PIVOT( instance );
208 g_debug( "%s: instance=%p (%s), klass=%p",
209 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
211 self->private = g_new0( NAPivotPrivate, 1 );
213 self->private->dispose_has_run = FALSE;
214 self->private->loadable_set = PIVOT_LOAD_NONE;
215 self->private->modules = NULL;
216 self->private->consumers = NULL;
217 self->private->tree = NULL;
218 self->private->automatic_reload = FALSE;
219 self->private->event_source_id = 0;
220 self->private->monitors = NULL;
223 static void
224 instance_constructed( GObject *object )
226 static const gchar *thisfn = "na_pivot_instance_constructed";
227 NAPivot *self;
229 g_return_if_fail( NA_IS_PIVOT( object ));
230 self = NA_PIVOT( object );
232 if( !self->private->dispose_has_run ){
234 g_debug( "%s: object=%p", thisfn, ( void * ) object );
236 self->private->modules = na_module_load_modules();
238 monitor_runtime_preferences( self );
240 /* force class initialization and io-factory registration
242 g_object_unref( na_object_action_new_with_profile());
243 g_object_unref( na_object_menu_new());
245 /* chain up to the parent class */
246 if( G_OBJECT_CLASS( st_parent_class )->constructed ){
247 G_OBJECT_CLASS( st_parent_class )->constructed( object );
252 static void
253 instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
255 NAPivot *self;
257 g_return_if_fail( NA_IS_PIVOT( object ));
258 self = NA_PIVOT( object );
260 if( !self->private->dispose_has_run ){
262 switch( property_id ){
263 case NAPIVOT_PROP_TREE_ID:
264 g_value_set_pointer( value, self->private->tree );
265 break;
267 default:
268 G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
269 break;
274 static void
275 instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
277 NAPivot *self;
279 g_return_if_fail( NA_IS_PIVOT( object ));
280 self = NA_PIVOT( object );
282 if( !self->private->dispose_has_run ){
284 switch( property_id ){
285 case NAPIVOT_PROP_TREE_ID:
286 self->private->tree = g_value_get_pointer( value );
287 break;
289 default:
290 G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
291 break;
296 static void
297 instance_dispose( GObject *object )
299 static const gchar *thisfn = "na_pivot_instance_dispose";
300 NAPivot *self;
302 g_return_if_fail( NA_IS_PIVOT( object ));
303 self = NA_PIVOT( object );
305 if( !self->private->dispose_has_run ){
307 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
309 self->private->dispose_has_run = TRUE;
311 /* release modules */
312 na_module_release_modules( self->private->modules );
313 self->private->modules = NULL;
315 /* release list of NAIPivotConsumers */
316 free_consumers( self->private->consumers );
317 self->private->consumers = NULL;
319 /* release item tree */
320 g_debug( "%s: tree=%p, count=%u", thisfn, ( void * ) self->private->tree, g_list_length( self->private->tree ));
321 na_object_unref_items( self->private->tree );
322 self->private->tree = NULL;
324 /* release the GConf monitoring */
325 na_gconf_monitor_release_monitors( self->private->monitors );
327 /* release the I/O Provider objects */
328 na_io_provider_terminate();
330 /* chain up to the parent class */
331 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
332 G_OBJECT_CLASS( st_parent_class )->dispose( object );
337 static void
338 instance_finalize( GObject *object )
340 static const gchar *thisfn = "na_pivot_instance_finalize";
341 NAPivot *self;
343 g_return_if_fail( NA_IS_PIVOT( object ));
344 self = NA_PIVOT( object );
346 g_debug( "%s: object=%p", thisfn, ( void * ) object );
348 g_free( self->private );
350 /* chain call to parent class */
351 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
352 G_OBJECT_CLASS( st_parent_class )->finalize( object );
356 static void
357 iprefs_iface_init( NAIPrefsInterface *iface )
359 static const gchar *thisfn = "na_pivot_iprefs_iface_init";
361 g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
365 * na_pivot_new:
367 * Returns: a newly allocated #NAPivot object.
369 NAPivot *
370 na_pivot_new( void )
372 static const gchar *thisfn = "na_pivot_new";
373 NAPivot *pivot;
375 g_debug( "%s", thisfn );
377 pivot = g_object_new( NA_PIVOT_TYPE, NULL );
379 return( pivot );
383 * na_pivot_dump:
384 * @pivot: the #NAPivot object do be dumped.
386 * Dumps the content of a #NAPivot object.
388 void
389 na_pivot_dump( const NAPivot *pivot )
391 static const gchar *thisfn = "na_pivot_dump";
392 GList *it;
393 int i;
395 if( !pivot->private->dispose_has_run ){
397 g_debug( "%s: loadable_set=%d", thisfn, pivot->private->loadable_set );
398 g_debug( "%s: modules=%p (%d elts)", thisfn, ( void * ) pivot->private->modules, g_list_length( pivot->private->modules ));
399 g_debug( "%s: consumers=%p (%d elts)", thisfn, ( void * ) pivot->private->consumers, g_list_length( pivot->private->consumers ));
400 g_debug( "%s: tree=%p (%d elts)", thisfn, ( void * ) pivot->private->tree, g_list_length( pivot->private->tree ));
401 g_debug( "%s: automatic_reload=%s", thisfn, pivot->private->automatic_reload ? "True":"False" );
402 g_debug( "%s: monitors=%p (%d elts)", thisfn, ( void * ) pivot->private->monitors, g_list_length( pivot->private->monitors ));
404 for( it = pivot->private->tree, i = 0 ; it ; it = it->next ){
405 g_debug( "%s: [%d]: %p", thisfn, i++, it->data );
411 * na_pivot_get_providers:
412 * @pivot: this #NAPivot instance.
413 * @type: the type of searched interface.
414 * For now, we only have NA_IIO_PROVIDER_TYPE interfaces.
416 * Returns: a newly allocated list of providers of the required interface.
418 * This function is called by interfaces API in order to find the
419 * list of providers registered for their own given interface.
421 * The returned list should be release by calling na_pivot_free_providers().
423 GList *
424 na_pivot_get_providers( const NAPivot *pivot, GType type )
426 static const gchar *thisfn = "na_pivot_get_providers";
427 GList *list = NULL;
429 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
431 if( !pivot->private->dispose_has_run ){
433 g_debug( "%s: pivot=%p, type=%lu (%s)", thisfn, ( void * ) pivot, ( unsigned long ) type, g_type_name( type ));
435 list = na_module_get_extensions_for_type( pivot->private->modules, type );
436 g_debug( "%s: list=%p, count=%d", thisfn, ( void * ) list, list ? g_list_length( list ) : 0 );
439 return( list );
443 * na_pivot_free_providers:
444 * @providers: a list of providers.
446 * Frees a list of providers as returned from na_pivot_get_providers().
448 void
449 na_pivot_free_providers( GList *providers )
451 static const gchar *thisfn = "na_pivot_free_providers";
453 g_debug( "%s: providers=%p", thisfn, ( void * ) providers );
455 na_module_free_extensions_list( providers );
459 * na_pivot_get_item:
460 * @pivot: this #NAPivot instance.
461 * @id: the required item identifier.
463 * Returns the specified item, action or menu.
465 * Returns: the required #NAObjectItem-derived object, or %NULL if not
466 * found.
468 * The returned pointer is owned by #NAPivot, and should not be
469 * g_free() nor g_object_unref() by the caller.
471 NAObjectItem *
472 na_pivot_get_item( const NAPivot *pivot, const gchar *id )
474 NAObjectItem *object = NULL;
476 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
478 if( !pivot->private->dispose_has_run ){
480 if( !id || !strlen( id )){
481 return( NULL );
484 object = get_item_from_tree( pivot, pivot->private->tree, id );
487 return( object );
490 static NAObjectItem *
491 get_item_from_tree( const NAPivot *pivot, GList *tree, const gchar *id )
493 GList *subitems, *ia;
494 NAObjectItem *found = NULL;
496 for( ia = tree ; ia && !found ; ia = ia->next ){
498 gchar *i_id = na_object_get_id( NA_OBJECT( ia->data ));
500 if( !g_ascii_strcasecmp( id, i_id )){
501 found = NA_OBJECT_ITEM( ia->data );
504 if( !found && NA_IS_OBJECT_ITEM( ia->data )){
505 subitems = na_object_get_items( ia->data );
506 found = get_item_from_tree( pivot, subitems, id );
510 return( found );
514 * na_pivot_get_items:
515 * @pivot: this #NAPivot instance.
517 * Returns: the current configuration tree.
519 * The returned list is owned by this #NAPivot object, and should not
520 * be g_free(), nor g_object_unref() by the caller.
522 GList *
523 na_pivot_get_items( const NAPivot *pivot )
525 GList *tree;
527 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
529 tree = NULL;
531 if( !pivot->private->dispose_has_run ){
533 tree = pivot->private->tree;
536 return( tree );
540 * na_pivot_load_items:
541 * @pivot: this #NAPivot instance.
543 * Loads the hierarchical list of items from I/O providers.
545 void
546 na_pivot_load_items( NAPivot *pivot )
548 static const gchar *thisfn = "na_pivot_load_items";
549 GSList *messages, *im;
551 g_return_if_fail( NA_IS_PIVOT( pivot ));
553 if( !pivot->private->dispose_has_run ){
555 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
557 na_object_unref_items( pivot->private->tree );
559 messages = NULL;
561 pivot->private->tree = na_io_provider_read_items( pivot, &messages );
563 for( im = messages ; im ; im = im->next ){
564 g_warning( "%s: %s", thisfn, ( const gchar * ) im->data );
567 na_core_utils_slist_free( messages );
572 * na_pivot_set_new_items:
573 * @pivot: this #NAPivot instance.
574 * @tree: the new tree of items.
576 * Replace the current list with this one.
578 void
579 na_pivot_set_new_items( NAPivot *pivot, GList *items )
581 static const gchar *thisfn = "na_pivot_set_new_items";
583 g_return_if_fail( NA_IS_PIVOT( pivot ));
585 if( !pivot->private->dispose_has_run ){
587 g_debug( "%s: pivot=%p, items=%p (count=%d)",
588 thisfn, ( void * ) pivot, ( void * ) items, items ? g_list_length( items ) : 0 );
590 na_object_unref_items( pivot->private->tree );
592 pivot->private->tree = items;
597 * na_pivot_item_changed_handler:
598 * @provider: the #NAIIOProvider which has emitted the signal.
599 * @id: the id of the changed #NAObjectItem-derived object.
600 * @pivot: this #NAPivot instance.
602 * This handler is trigerred by IIOProviders when an action is changed
603 * in their underlying storage subsystems.
604 * We don't care of updating our internal list with each and every
605 * atomic modification; instead we wait for the end of notifications
606 * serie, and then reload the whole list of actions
608 void
609 na_pivot_item_changed_handler( NAIIOProvider *provider, const gchar *id, NAPivot *pivot )
611 static const gchar *thisfn = "na_pivot_item_changed_handler";
613 g_return_if_fail( NA_IS_IIO_PROVIDER( provider ));
614 g_return_if_fail( NA_IS_PIVOT( pivot ));
616 if( !pivot->private->dispose_has_run ){
618 g_debug( "%s: provider=%p, id=%s, pivot=%p", thisfn, ( void * ) provider, id, ( void * ) pivot );
620 /* set a timeout to notify clients at the end of the serie */
621 g_get_current_time( &pivot->private->last_event );
623 if( !pivot->private->event_source_id ){
624 pivot->private->event_source_id =
625 g_timeout_add( st_burst_timeout, ( GSourceFunc ) on_item_changed_timeout, pivot );
631 * this timer is set when we receive the first event of a serie
632 * we continue to loop until last event is older that our burst timeout
634 * there is no race condition here as we are not multithreaded
635 * or .. is there ?
637 static gboolean
638 on_item_changed_timeout( NAPivot *pivot )
640 static const gchar *thisfn = "na_pivot_on_item_changed_timeout";
641 GTimeVal now;
642 gulong diff;
643 GList *ic;
644 gulong timeout_usec = 1000*st_burst_timeout;
646 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
648 g_get_current_time( &now );
649 diff = time_val_diff( &now, &pivot->private->last_event );
650 if( diff < timeout_usec ){
651 return( TRUE );
654 /* last individual notification is older that the st_burst_timeout
655 * so triggers the NAIIOProvider interface and destroys this timeout
657 g_debug( "%s: triggering NAIPivotConsumer interfaces", thisfn );
659 if( pivot->private->automatic_reload ){
660 na_pivot_load_items( pivot );
663 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
664 na_ipivot_consumer_notify_of_items_changed( NA_IPIVOT_CONSUMER( ic->data ));
667 pivot->private->event_source_id = 0;
668 return( FALSE );
672 * returns the difference in microseconds.
674 static gulong
675 time_val_diff( const GTimeVal *recent, const GTimeVal *old )
677 gulong microsec = 1000000 * ( recent->tv_sec - old->tv_sec );
678 microsec += recent->tv_usec - old->tv_usec;
679 return( microsec );
683 * na_pivot_write_level_zero:
684 * @pivot: this #NAPivot instance.
685 * @items: the #GList of items whose first level is to be written.
686 * @messages: a pointer to a #GSList in which we will add happening
687 * error messages;
688 * the pointer may be %NULL;
689 * if not %NULL, the #GSList must have been initialized by the
690 * caller.
692 * Rewrite the level-zero items in GConf preferences.
694 * Returns: %TRUE if successfully written (i.e. writable, not locked,
695 * and so on), %FALSE else.
697 * @messages #GSList is only filled up in case of an error has occured.
698 * If there is no error (na_pivot_write_level_zero() returns %TRUE), then
699 * the caller may safely assume that @messages is returned in the same
700 * state that it has been provided.
702 gboolean
703 na_pivot_write_level_zero( const NAPivot *pivot, GList *items, GSList **messages )
705 static const gchar *thisfn = "na_pivot_write_level_zero";
706 gboolean written;
707 GList *it;
708 gchar *id;
709 GSList *content;
711 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
713 written = FALSE;
715 if( !pivot->private->dispose_has_run ){
717 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot);
719 if( na_pivot_is_level_zero_writable( pivot )){
721 content = NULL;
722 for( it = items ; it ; it = it->next ){
724 id = na_object_get_id( it->data );
725 content = g_slist_prepend( content, id );
727 content = g_slist_reverse( content );
729 written = na_iprefs_write_string_list( NA_IPREFS( pivot ), IPREFS_LEVEL_ZERO_ITEMS, content );
731 na_core_utils_slist_free( content );
735 return( written );
739 * na_pivot_register_consumer:
740 * @pivot: this #NAPivot instance.
741 * @consumer: a #NAIPivotConsumer which wishes be notified of any
742 * modification of an action or a menu in any of the underlying I/O
743 * storage subsystems.
745 * Registers a new consumer to be notified of configuration modification.
747 void
748 na_pivot_register_consumer( NAPivot *pivot, const NAIPivotConsumer *consumer )
750 static const gchar *thisfn = "na_pivot_register_consumer";
752 g_return_if_fail( NA_IS_PIVOT( pivot ));
753 g_return_if_fail( NA_IS_IPIVOT_CONSUMER( consumer ));
755 if( !pivot->private->dispose_has_run ){
757 g_debug( "%s: pivot=%p, consumer=%p", thisfn, ( void * ) pivot, ( void * ) consumer );
759 pivot->private->consumers = g_list_prepend( pivot->private->consumers, ( gpointer ) consumer );
763 static void
764 free_consumers( GList *consumers )
766 /*g_list_foreach( consumers, ( GFunc ) g_object_unref, NULL );*/
767 g_list_free( consumers );
771 * na_pivot_set_automatic_reload:
772 * @pivot: this #NAPivot instance.
773 * @reload: whether this #NAPivot instance should automatically reload
774 * its list of actions when I/O providers advertize it of a
775 * modification.
777 * Sets the automatic reload flag.
779 * Note that even if the #NAPivot instance is not authorized to
780 * automatically reload its list of actions when it is advertized of
781 * a modification by one of the I/O providers, it always sends an
782 * ad-hoc notification to its consumers.
784 void
785 na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload )
787 g_return_if_fail( NA_IS_PIVOT( pivot ));
789 if( !pivot->private->dispose_has_run ){
791 pivot->private->automatic_reload = reload;
796 * na_pivot_is_disable_loadable:
797 * @pivot: this #NAPivot instance.
799 * Returns: %TRUE if disabled items should be loaded, %FALSE else.
801 gboolean
802 na_pivot_is_disable_loadable( const NAPivot *pivot )
804 gboolean is_loadable;
806 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
808 is_loadable = FALSE;
810 if( !pivot->private->dispose_has_run ){
812 is_loadable = ( pivot->private->loadable_set & PIVOT_LOAD_DISABLED );
815 return( is_loadable );
819 * na_pivot_is_invalid_loadable:
820 * @pivot: this #NAPivot instance.
822 * Returns: %TRUE if invalid items should be loaded, %FALSE else.
824 gboolean
825 na_pivot_is_invalid_loadable( const NAPivot *pivot )
827 gboolean is_loadable;
829 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
831 is_loadable = FALSE;
833 if( !pivot->private->dispose_has_run ){
835 is_loadable = ( pivot->private->loadable_set & PIVOT_LOAD_INVALID );
838 return( is_loadable );
842 * na_pivot_set_loadable:
843 * @pivot: this #NAPivot instance.
844 * @loadable: the population of items to be loaded.
846 * Sets the loadable set.
848 void
849 na_pivot_set_loadable( NAPivot *pivot, guint loadable )
851 g_return_if_fail( NA_IS_PIVOT( pivot ));
853 if( !pivot->private->dispose_has_run ){
855 pivot->private->loadable_set = loadable;
860 * na_pivot_is_level_zero_writable:
861 * @pivot: this #NAPivot instance.
863 * Returns: %TRUE if we are able to update the level-zero list of items,
864 * %FALSE else.
866 gboolean
867 na_pivot_is_level_zero_writable( const NAPivot *pivot )
869 gboolean all_locked;
870 gboolean gconf_locked;
871 GConfClient *gconf;
872 gchar *path;
874 all_locked = FALSE;
875 gconf_locked = FALSE;
877 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
879 if( !pivot->private->dispose_has_run ){
881 all_locked = na_pivot_is_configuration_locked_by_admin( pivot );
883 gconf = na_iprefs_get_gconf_client( NA_IPREFS( pivot ));
885 path = gconf_concat_dir_and_key( IPREFS_GCONF_BASEDIR, "mandatory/io-gconf/locked" );
886 gconf_locked = na_gconf_utils_read_bool( gconf, path, FALSE, FALSE );
887 g_free( path );
890 return( !all_locked && !gconf_locked );
894 * na_pivot_is_configuration_locked_by_admin:
895 * @pivot: this #NAPivot.
897 * Returns: %TRUE if the whole configuration has been locked by an
898 * administrator, %FALSE else.
900 gboolean
901 na_pivot_is_configuration_locked_by_admin( const NAPivot *pivot )
903 gboolean locked;
904 GConfClient *gconf;
905 gchar *path;
907 locked = FALSE;
908 g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
910 if( !pivot->private->dispose_has_run ){
912 gconf = na_iprefs_get_gconf_client( NA_IPREFS( pivot ));
914 path = gconf_concat_dir_and_key( IPREFS_GCONF_BASEDIR, "mandatory/all/locked" );
915 locked = na_gconf_utils_read_bool( gconf, path, FALSE, FALSE );
916 g_free( path );
919 return( locked );
922 static void
923 monitor_runtime_preferences( NAPivot *pivot )
925 static const gchar *thisfn = "na_pivot_monitor_runtime_preferences";
926 GList *list = NULL;
927 gchar *path;
929 g_return_if_fail( NA_IS_PIVOT( pivot ));
930 g_return_if_fail( !pivot->private->dispose_has_run );
932 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
934 list = g_list_prepend( list,
935 na_gconf_monitor_new(
936 IPREFS_GCONF_PREFS_PATH,
937 ( GConfClientNotifyFunc ) on_preferences_change,
938 pivot ));
940 path = gconf_concat_dir_and_key( IPREFS_GCONF_BASEDIR, "mandatory" );
941 list = g_list_prepend( list,
942 na_gconf_monitor_new(
943 path,
944 ( GConfClientNotifyFunc ) on_mandatory_prefs_changed,
945 pivot ));
946 g_free( path );
948 path = gconf_concat_dir_and_key( IPREFS_GCONF_BASEDIR, "io-providers" );
949 list = g_list_prepend( list,
950 na_gconf_monitor_new(
951 path,
952 ( GConfClientNotifyFunc ) on_io_provider_prefs_changed,
953 pivot ));
954 g_free( path );
956 pivot->private->monitors = list;
959 static void
960 on_io_provider_prefs_changed( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot )
962 GList *ic;
964 g_return_if_fail( NA_IS_PIVOT( pivot ));
966 if( !pivot->private->dispose_has_run ){
968 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
969 na_ipivot_consumer_notify_of_io_provider_prefs_changed( NA_IPIVOT_CONSUMER( ic->data ));
974 static void
975 on_mandatory_prefs_changed( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot )
977 GList *ic;
979 g_return_if_fail( NA_IS_PIVOT( pivot ));
981 if( !pivot->private->dispose_has_run ){
983 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
984 na_ipivot_consumer_notify_of_mandatory_prefs_changed( NA_IPIVOT_CONSUMER( ic->data ));
989 static void
990 on_preferences_change( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAPivot *pivot )
992 /*static const gchar *thisfn = "na_pivot_on_preferences_change";*/
993 const gchar *key;
994 gchar *key_entry;
996 g_return_if_fail( NA_IS_PIVOT( pivot ));
998 key = gconf_entry_get_key( entry );
999 key_entry = g_path_get_basename( key );
1000 /*g_debug( "%s: key=%s", thisfn, key_entry );*/
1002 if( !g_ascii_strcasecmp( key_entry, IPREFS_CREATE_ROOT_MENU )){
1003 create_root_menu_changed( pivot );
1006 if( !g_ascii_strcasecmp( key_entry, IPREFS_ADD_ABOUT_ITEM )){
1007 display_about_changed( pivot );
1010 if( !g_ascii_strcasecmp( key_entry, IPREFS_DISPLAY_ALPHABETICAL_ORDER )){
1011 display_order_changed( pivot );
1014 if( !g_ascii_strcasecmp( key_entry, IPREFS_AUTOSAVE_ON ) || !g_ascii_strcasecmp( key_entry, IPREFS_AUTOSAVE_PERIOD )){
1015 autosave_changed( pivot );
1018 g_free( key_entry );
1021 static void
1022 display_order_changed( NAPivot *pivot )
1024 static const gchar *thisfn = "na_pivot_display_order_changed";
1025 GList *ic;
1026 gint order_mode;
1028 g_return_if_fail( NA_IS_PIVOT( pivot ));
1030 if( !pivot->private->dispose_has_run ){
1032 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
1034 order_mode = na_iprefs_get_order_mode( NA_IPREFS( pivot ));
1036 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
1037 na_ipivot_consumer_notify_of_display_order_changed( NA_IPIVOT_CONSUMER( ic->data ), order_mode );
1042 static void
1043 create_root_menu_changed( NAPivot *pivot )
1045 static const gchar *thisfn = "na_pivot_create_root_menu_changed";
1046 GList *ic;
1047 gboolean should_create;
1049 g_return_if_fail( NA_IS_PIVOT( pivot ));
1051 if( !pivot->private->dispose_has_run ){
1053 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
1055 should_create = na_iprefs_read_bool( NA_IPREFS( pivot ), IPREFS_CREATE_ROOT_MENU, FALSE );
1056 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
1057 na_ipivot_consumer_notify_of_create_root_menu_changed( NA_IPIVOT_CONSUMER( ic->data ), should_create );
1062 static void
1063 display_about_changed( NAPivot *pivot )
1065 static const gchar *thisfn = "na_pivot_display_about_changed";
1066 GList *ic;
1067 gboolean display_about;
1069 g_return_if_fail( NA_IS_PIVOT( pivot ));
1071 if( !pivot->private->dispose_has_run ){
1073 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
1075 display_about = na_iprefs_read_bool( NA_IPREFS( pivot ), IPREFS_ADD_ABOUT_ITEM, TRUE );
1077 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
1078 na_ipivot_consumer_notify_of_display_about_changed( NA_IPIVOT_CONSUMER( ic->data ), display_about );
1083 static void
1084 autosave_changed( NAPivot *pivot )
1086 static const gchar *thisfn = "na_pivot_autosave_changed";
1087 GList *ic;
1088 gboolean autosave_on;
1089 guint autosave_period;
1091 g_return_if_fail( NA_IS_PIVOT( pivot ));
1093 if( !pivot->private->dispose_has_run ){
1095 g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
1097 autosave_on = na_iprefs_read_bool( NA_IPREFS( pivot ), IPREFS_AUTOSAVE_ON, FALSE );
1098 autosave_period = na_iprefs_read_uint( NA_IPREFS( pivot ), IPREFS_AUTOSAVE_PERIOD, 5 );
1100 for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
1101 na_ipivot_consumer_notify_of_autosave_changed( NA_IPIVOT_CONSUMER( ic->data ), autosave_on, autosave_period );