1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * anjuta-profile-manager.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * SECTION:anjuta-profile-manager
23 * @short_description: Managers a stack of plugins profiles
24 * @see_also: #AnjutaPluginManager, #AnjutaProfile
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-profile-manager.h
28 * Anjuta uses up to two profiles. A "no project" profile is used when no
29 * project is loaded a project profile when one is loaded.
30 * If a second project is loaded, it is loaded in another instance of Anjuta.
31 * When a project is closed, Anjuta goes back to the "no project" profile.
33 * The profile manager can be in a frozen state where you can push or
34 * pop a profile from the stack without triggering a change of the profile.
38 #include <libxml/parser.h>
39 #include <libxml/tree.h>
41 #include <libanjuta/anjuta-debug.h>
42 #include <libanjuta/anjuta-marshal.h>
43 #include "anjuta-profile-manager.h"
61 struct _AnjutaProfileManagerPriv
63 AnjutaPluginManager
*plugin_manager
;
66 /* Pending queue. Profiles are queued until freeze count becomes 0 */
67 GList
*profiles_queue
;
69 /* Freeze count. Pending profiles are loaded when it reaches 0 */
73 static GObjectClass
* parent_class
= NULL
;
74 static guint profile_manager_signals
[LAST_SIGNAL
] = { 0 };
77 on_plugin_activated (AnjutaPluginManager
*plugin_manager
,
78 AnjutaPluginDescription
*plugin_desc
,
79 GObject
*plugin_object
,
80 AnjutaProfileManager
*profile_manager
)
82 AnjutaProfileManagerPriv
*priv
;
83 priv
= profile_manager
->priv
;
87 /* Add it current profile */
90 if (!anjuta_plugin_description_get_boolean (plugin_desc
, "Anjuta Plugin", "ExcludeFromSession", &exclude
) || !exclude
)
92 anjuta_profile_add_plugin (ANJUTA_PROFILE (priv
->profiles
->data
),
99 on_plugin_deactivated (AnjutaPluginManager
*plugin_manager
,
100 AnjutaPluginDescription
*plugin_desc
,
101 GObject
*plugin_object
,
102 AnjutaProfileManager
*profile_manager
)
104 AnjutaProfileManagerPriv
*priv
;
105 priv
= profile_manager
->priv
;
109 /* Remove from current profile */
110 anjuta_profile_remove_plugin (ANJUTA_PROFILE (priv
->profiles
->data
),
116 anjuta_profile_manager_init (AnjutaProfileManager
*object
)
118 object
->priv
= g_new0 (AnjutaProfileManagerPriv
, 1);
122 anjuta_profile_manager_finalize (GObject
*object
)
124 AnjutaProfileManagerPriv
*priv
;
125 priv
= ANJUTA_PROFILE_MANAGER (object
)->priv
;
128 g_list_foreach (priv
->profiles
, (GFunc
)g_object_unref
, NULL
);
129 g_list_free (priv
->profiles
);
130 priv
->profiles
= NULL
;
132 if (priv
->profiles_queue
)
134 g_list_foreach (priv
->profiles_queue
, (GFunc
)g_object_unref
, NULL
);
135 g_list_free (priv
->profiles_queue
);
136 priv
->profiles_queue
= NULL
;
139 G_OBJECT_CLASS (parent_class
)->finalize (object
);
143 anjuta_profile_manager_set_property (GObject
*object
, guint prop_id
,
144 const GValue
*value
, GParamSpec
*pspec
)
146 AnjutaProfileManagerPriv
*priv
;
147 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object
));
148 priv
= ANJUTA_PROFILE_MANAGER (object
)->priv
;
152 case PROP_PLUGIN_MANAGER
:
153 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (g_value_get_object (value
)));
154 priv
->plugin_manager
= g_value_get_object (value
);
155 g_signal_connect (priv
->plugin_manager
, "plugin-activated",
156 G_CALLBACK (on_plugin_activated
), object
);
157 g_signal_connect (priv
->plugin_manager
, "plugin-deactivated",
158 G_CALLBACK (on_plugin_deactivated
), object
);
161 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
167 anjuta_profile_manager_get_property (GObject
*object
, guint prop_id
,
168 GValue
*value
, GParamSpec
*pspec
)
170 AnjutaProfileManagerPriv
*priv
;
171 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object
));
172 priv
= ANJUTA_PROFILE_MANAGER (object
)->priv
;
176 case PROP_PLUGIN_MANAGER
:
177 g_value_set_object (value
, priv
->plugin_manager
);
180 g_value_set_pointer (value
, priv
->profiles
);
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
189 anjuta_profile_manager_class_init (AnjutaProfileManagerClass
*klass
)
191 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
192 parent_class
= G_OBJECT_CLASS (g_type_class_peek_parent (klass
));
194 object_class
->finalize
= anjuta_profile_manager_finalize
;
195 object_class
->set_property
= anjuta_profile_manager_set_property
;
196 object_class
->get_property
= anjuta_profile_manager_get_property
;
198 g_object_class_install_property (object_class
,
200 g_param_spec_object ("plugin-manager",
202 "The plugin manager to use for profile plugins",
203 ANJUTA_TYPE_PLUGIN_MANAGER
,
208 * AnjutaProfileManager::profile-pushed:
209 * @profile_manager: a #AnjutaProfileManager object.
210 * @profile: the new #AnjutaProfile added.
212 * Emitted when a profile is added in the stack. If the profile manager is
213 * not frozen, the current profile will be unloaded and the new one
216 profile_manager_signals
[PROFILE_PUSHED
] =
217 g_signal_new ("profile-pushed",
218 G_OBJECT_CLASS_TYPE (klass
),
220 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
223 anjuta_cclosure_marshal_VOID__OBJECT
,
225 ANJUTA_TYPE_PROFILE
);
228 * AnjutaProfileManager::profile-popped:
229 * @profile_manager: a #AnjutaProfileManager object.
230 * @profile: the current removed #AnjutaProfile.
232 * Emitted when a profile is removed from the stack. If the profile manager
233 * is not frozen, the current profile will be unloaded and the previous one
236 profile_manager_signals
[PROFILE_POPPED
] =
237 g_signal_new ("profile-popped",
238 G_OBJECT_CLASS_TYPE (klass
),
240 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
243 anjuta_cclosure_marshal_VOID__OBJECT
,
245 ANJUTA_TYPE_PROFILE
);
248 * AnjutaProfileManager::profile-descoped:
249 * @profile_manager: a #AnjutaProfileManager object.
250 * @profile: the old unloaded #AnjutaProfile.
252 * Emitted when a profile will be unloaded.
254 profile_manager_signals
[PROFILE_DESCOPED
] =
255 g_signal_new ("profile-descoped",
256 G_OBJECT_CLASS_TYPE (klass
),
258 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
261 anjuta_cclosure_marshal_VOID__OBJECT
,
263 ANJUTA_TYPE_PROFILE
);
266 * AnjutaProfileManager::profile-scoped:
267 * @profile_manager: a #AnjutaProfileManager object.
268 * @profile: the current loaded #AnjutaProfile.
270 * Emitted when a new profile is loaded.
272 profile_manager_signals
[PROFILE_SCOPED
] =
273 g_signal_new ("profile-scoped",
274 G_OBJECT_CLASS_TYPE (klass
),
276 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
279 anjuta_cclosure_marshal_VOID__OBJECT
,
281 ANJUTA_TYPE_PROFILE
);
285 anjuta_profile_manager_get_type (void)
287 static GType our_type
= 0;
291 static const GTypeInfo our_info
=
293 sizeof (AnjutaProfileManagerClass
), /* class_size */
294 (GBaseInitFunc
) NULL
, /* base_init */
295 (GBaseFinalizeFunc
) NULL
, /* base_finalize */
296 (GClassInitFunc
) anjuta_profile_manager_class_init
, /* class_init */
297 (GClassFinalizeFunc
) NULL
, /* class_finalize */
298 NULL
/* class_data */,
299 sizeof (AnjutaProfileManager
), /* instance_size */
301 (GInstanceInitFunc
) anjuta_profile_manager_init
, /* instance_init */
302 NULL
/* value_table */
305 our_type
= g_type_register_static (G_TYPE_OBJECT
, "AnjutaProfileManager",
313 * anjuta_profile_manager_new:
314 * @plugin_manager: the #AnjutaPluginManager used by all profiles.
316 * Create a new profile manager.
318 * Return value: the new #AnjutaProfileManager object.
320 AnjutaProfileManager
*
321 anjuta_profile_manager_new (AnjutaPluginManager
*plugin_manager
)
325 obj
= g_object_new (ANJUTA_TYPE_PROFILE_MANAGER
, "plugin-manager",
326 plugin_manager
, NULL
);
327 return ANJUTA_PROFILE_MANAGER (obj
);
331 anjuta_profile_manager_load_profile (AnjutaProfileManager
*profile_manager
,
332 AnjutaProfile
*profile
,
333 AnjutaProfile
*previous_profile
,
336 AnjutaProfileManagerPriv
*priv
;
337 GList
*active_plugins
, *node
;
338 GList
*plugins_to_activate
, *plugins_to_deactivate
;
339 GList
*selected_plugins
;
341 GHashTable
*active_plugins_hash
, *plugins_to_activate_hash
;
343 priv
= profile_manager
->priv
;
345 /* Disable profile synchronization while the profile is being activated */
346 g_signal_handlers_block_by_func (priv
->plugin_manager
,
347 G_CALLBACK (on_plugin_activated
),
349 g_signal_handlers_block_by_func (priv
->plugin_manager
,
350 G_CALLBACK (on_plugin_deactivated
),
353 /* Emit pre-change for the last profile */
354 if (previous_profile
)
356 g_signal_emit_by_name (profile_manager
, "profile-descoped",
360 /* Prepare plugins to activate */
361 plugins_to_activate_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
363 /* Select plugins in the profile */
365 selected_plugins
= anjuta_profile_get_plugins (profile
);
367 selected_plugins
= NULL
;
369 node
= selected_plugins
;
372 g_hash_table_insert (plugins_to_activate_hash
, node
->data
, node
->data
);
373 node
= g_list_next (node
);
376 /* Prepare active plugins hash */
378 anjuta_plugin_manager_get_active_plugins (priv
->plugin_manager
);
379 active_plugins_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
380 node
= active_plugins
;
383 g_hash_table_insert (active_plugins_hash
, node
->data
, node
->data
);
384 node
= g_list_next (node
);
387 plugins_to_deactivate
= NULL
;
389 /* Prepare plugins to deactiveate that are already active, but are
390 * not requested to be active
392 node
= active_plugins
;
395 if (!g_hash_table_lookup (plugins_to_activate_hash
, node
->data
))
397 plugins_to_deactivate
= g_list_prepend (plugins_to_deactivate
,
400 node
= g_list_next (node
);
402 plugins_to_deactivate
= g_list_reverse (plugins_to_deactivate
);
404 /* Deactivate plugins */
405 node
= plugins_to_deactivate
;
408 AnjutaPluginDescription
*desc
;
409 GObject
*plugin_object
;
410 gchar
*plugin_id
= NULL
;
412 desc
= (AnjutaPluginDescription
*)node
->data
;
413 anjuta_plugin_description_get_string (desc
, "Anjuta Plugin",
414 "Location", &plugin_id
);
415 g_assert (plugin_id
!= NULL
);
417 /* DEBUG_PRINT ("Profile: deactivating %s", plugin_id); */
420 anjuta_plugin_manager_get_plugin_by_id (priv
->plugin_manager
,
422 g_assert (plugin_object
!= NULL
);
424 anjuta_plugin_manager_unload_plugin (priv
->plugin_manager
,
427 node
= g_list_next (node
);
430 /* Prepare the plugins to activate */
431 plugins_to_activate
= NULL
;
432 node
= selected_plugins
;
435 if (!g_hash_table_lookup (active_plugins_hash
, node
->data
))
436 plugins_to_activate
= g_list_prepend (plugins_to_activate
,
438 node
= g_list_next (node
);
441 /* Now activate the plugins */
442 if (plugins_to_activate
)
445 plugins_to_activate
= g_list_reverse (plugins_to_activate
);
446 anjuta_plugin_manager_activate_plugins (priv
->plugin_manager
,
447 plugins_to_activate
);
450 g_list_free (plugins_to_activate
);
451 g_list_free (active_plugins
);
453 g_hash_table_destroy (plugins_to_activate_hash
);
454 g_hash_table_destroy (active_plugins_hash
);
456 /* Enable profile synchronization */
457 g_signal_handlers_unblock_by_func (priv
->plugin_manager
,
458 G_CALLBACK (on_plugin_activated
),
460 g_signal_handlers_unblock_by_func (priv
->plugin_manager
,
461 G_CALLBACK (on_plugin_deactivated
),
463 g_signal_emit_by_name (profile_manager
, "profile-scoped", profile
);
468 anjuta_profile_manager_queue_profile (AnjutaProfileManager
*profile_manager
,
469 AnjutaProfile
*profile
,
472 AnjutaProfileManagerPriv
*priv
;
474 priv
= profile_manager
->priv
;
475 priv
->profiles_queue
= g_list_prepend (priv
->profiles_queue
,
477 /* If there is no freeze load profile now */
478 if (priv
->freeze_count
<= 0)
480 AnjutaProfile
*previous_profile
= NULL
;
483 previous_profile
= priv
->profiles
->data
;
485 /* Push queued profiles in stack */
486 priv
->profiles
= g_list_concat (priv
->profiles_queue
, priv
->profiles
);
487 priv
->profiles_queue
= NULL
;
489 return anjuta_profile_manager_load_profile (profile_manager
,
490 ANJUTA_PROFILE (priv
->profiles
->data
),
501 * anjuta_profile_manager_push:
502 * @profile_manager: the #AnjutaProfileManager object.
503 * @profile: the new #AnjutaProfile.
504 * @error: error propagation and reporting.
506 * Add a new profile at the top of the profile manager stack. If the profile
507 * manager is not frozen, this new profile will be loaded immediatly and
508 * become the current profile.
510 * Return value: TRUE on success, FALSE otherwise.
513 anjuta_profile_manager_push (AnjutaProfileManager
*profile_manager
,
514 AnjutaProfile
*profile
, GError
**error
)
516 AnjutaProfileManagerPriv
*priv
;
518 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager
), FALSE
);
519 priv
= profile_manager
->priv
;
521 /* Emit profile push signal */
522 g_signal_emit_by_name (profile_manager
, "profile-pushed",
525 return anjuta_profile_manager_queue_profile (profile_manager
, profile
,
530 * anjuta_profile_manager_pop:
531 * @profile_manager: the #AnjutaProfileManager object.
532 * @profile_name: the name of the profile to remove.
533 * @error: error propagation and reporting.
535 * Remove a profile from the profile manager stack. If the manager is not
536 * frozen, only the current profile can be removed. It will be unloaded and
537 * the previous profile will be loaded.
538 * If the manager is frozen, the current profile or the last pushed profile
541 * Return value: TRUE on success, FALSE otherwise.
544 anjuta_profile_manager_pop (AnjutaProfileManager
*profile_manager
,
545 const gchar
*profile_name
, GError
**error
)
547 AnjutaProfileManagerPriv
*priv
;
548 AnjutaProfile
*profile
;
549 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager
), FALSE
);
551 priv
= profile_manager
->priv
;
553 /* First check in the queue */
554 if (priv
->profiles_queue
)
556 profile
= priv
->profiles_queue
->data
;
557 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile
),
558 profile_name
) == 0, FALSE
);
559 priv
->profiles_queue
= g_list_remove (priv
->profiles_queue
, profile
);
561 g_signal_emit_by_name (profile_manager
, "profile-popped",
564 g_object_unref (profile
);
568 /* Then check in the current stack */
571 profile
= priv
->profiles
->data
;
572 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile
),
573 profile_name
) == 0, FALSE
);
574 priv
->profiles
= g_list_remove (priv
->profiles
, profile
);
576 g_signal_emit_by_name (profile_manager
, "profile-popped",
579 /* Restore the next profile in the stack */
582 return anjuta_profile_manager_load_profile (profile_manager
,
583 ANJUTA_PROFILE (priv
->profiles
->data
),
589 return anjuta_profile_manager_load_profile (profile_manager
,
593 g_object_unref (profile
);
596 g_warning ("No profiles in the stack. Can not pop out any profile: %s",
602 * anjuta_profile_manager_freeze:
603 * @profile_manager: the #AnjutaProfileManager object.
605 * Freeze the plugin manager. In this state, plugins can be added and removed
606 * from the stack without triggering any change in the current profile. It is
607 * possible to freeze the manager several times but it will be back in its normal
608 * state only after as much call of anjuta_profile_manager_thaw().
611 anjuta_profile_manager_freeze (AnjutaProfileManager
*profile_manager
)
613 AnjutaProfileManagerPriv
*priv
;
614 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager
));
615 priv
= profile_manager
->priv
;
616 priv
->freeze_count
++;
620 * anjuta_profile_manager_thaw:
621 * @profile_manager: the #AnjutaProfileManager object.
622 * @error: error propagation and reporting.
624 * Put back the plugin manager in its normal mode after calling
625 * anjuta_profile_manager_freeze(). It will load a new profile if one has been
626 * added while the manager was frozen.
628 * Return value: TRUE on success, FALSE otherwise.
631 anjuta_profile_manager_thaw (AnjutaProfileManager
*profile_manager
,
634 AnjutaProfileManagerPriv
*priv
;
635 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager
), FALSE
);
636 priv
= profile_manager
->priv
;
638 if (priv
->freeze_count
> 0)
639 priv
->freeze_count
--;
641 if (priv
->freeze_count
<= 0 && priv
->profiles_queue
)
643 AnjutaProfile
*previous_profile
= NULL
;
646 previous_profile
= priv
->profiles
->data
;
648 /* Push queued profiles in stack */
649 priv
->profiles
= g_list_concat (priv
->profiles_queue
, priv
->profiles
);
650 priv
->profiles_queue
= NULL
;
652 /* Load the profile */
653 return anjuta_profile_manager_load_profile (profile_manager
,
654 ANJUTA_PROFILE (priv
->profiles
->data
),
665 * anjuta_profile_manager_get_current :
666 * @profile_manager: A #AnjutaProfileManager object.
668 * Return the current profile.
670 * Return value: a #AnjutaProfile object or NULL if the profile stack is empty.
673 anjuta_profile_manager_get_current (AnjutaProfileManager
*profile_manager
)
675 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager
), NULL
);
676 if (profile_manager
->priv
->profiles_queue
)
677 return ANJUTA_PROFILE (profile_manager
->priv
->profiles_queue
->data
);
678 else if (profile_manager
->priv
->profiles
)
679 return ANJUTA_PROFILE (profile_manager
->priv
->profiles
->data
);