libanjuta: bgo #696984 - Fix function argument name typos in documentation comments
[anjuta.git] / libanjuta / anjuta-profile-manager.c
blobb87f6b979760cf2e8fbf945a4ac734ee389dc88c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-profile-manager.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
5 *
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
21 /**
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.
37 #include <string.h>
39 #include <libanjuta/anjuta-debug.h>
40 #include <libanjuta/anjuta-marshal.h>
41 #include "anjuta-profile-manager.h"
43 enum
45 PROP_0,
46 PROP_PLUGIN_MANAGER,
47 PROP_PROFILES
50 enum
52 PROFILE_PUSHED,
53 PROFILE_POPPED,
54 PROFILE_DESCOPED,
55 PROFILE_SCOPED,
56 LAST_SIGNAL
59 struct _AnjutaProfileManagerPriv
61 AnjutaPluginManager *plugin_manager;
62 GList *profiles;
64 /* Pending queue. Profiles are queued until freeze count becomes 0 */
65 GList *profiles_queue;
67 /* Freeze count. Pending profiles are loaded when it reaches 0 */
68 gint freeze_count;
71 static GObjectClass* parent_class = NULL;
72 static guint profile_manager_signals[LAST_SIGNAL] = { 0 };
74 static void
75 on_plugin_activated (AnjutaPluginManager *plugin_manager,
76 AnjutaPluginDescription *plugin_desc,
77 GObject *plugin_object,
78 AnjutaProfileManager *profile_manager)
80 AnjutaProfileManagerPriv *priv;
81 priv = profile_manager->priv;
83 if (priv->profiles)
85 /* Add it current profile */
86 gboolean exclude;
88 if (!anjuta_plugin_description_get_boolean (plugin_desc, "Anjuta Plugin", "ExcludeFromSession", &exclude) || !exclude)
90 anjuta_profile_add_plugin (ANJUTA_PROFILE (priv->profiles->data),
91 plugin_desc);
96 static void
97 on_plugin_deactivated (AnjutaPluginManager *plugin_manager,
98 AnjutaPluginDescription *plugin_desc,
99 GObject *plugin_object,
100 AnjutaProfileManager *profile_manager)
102 AnjutaProfileManagerPriv *priv;
103 priv = profile_manager->priv;
105 if (priv->profiles)
107 /* Remove from current profile */
108 anjuta_profile_remove_plugin (ANJUTA_PROFILE (priv->profiles->data),
109 plugin_desc);
113 static void
114 anjuta_profile_manager_init (AnjutaProfileManager *object)
116 object->priv = g_new0 (AnjutaProfileManagerPriv, 1);
119 static void
120 anjuta_profile_manager_finalize (GObject *object)
122 AnjutaProfileManagerPriv *priv = ANJUTA_PROFILE_MANAGER (object)->priv;
124 if (priv->profiles)
125 g_list_free_full (priv->profiles, g_object_unref);
127 if (priv->profiles_queue)
128 g_list_free_full (priv->profiles_queue, g_object_unref);
131 G_OBJECT_CLASS (parent_class)->finalize (object);
134 static void
135 anjuta_profile_manager_set_property (GObject *object, guint prop_id,
136 const GValue *value, GParamSpec *pspec)
138 AnjutaProfileManagerPriv *priv;
139 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
140 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
142 switch (prop_id)
144 case PROP_PLUGIN_MANAGER:
145 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (g_value_get_object (value)));
146 priv->plugin_manager = g_value_get_object (value);
147 g_signal_connect (priv->plugin_manager, "plugin-activated",
148 G_CALLBACK (on_plugin_activated), object);
149 g_signal_connect (priv->plugin_manager, "plugin-deactivated",
150 G_CALLBACK (on_plugin_deactivated), object);
151 break;
152 default:
153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
154 break;
158 static void
159 anjuta_profile_manager_get_property (GObject *object, guint prop_id,
160 GValue *value, GParamSpec *pspec)
162 AnjutaProfileManagerPriv *priv;
163 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
164 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
166 switch (prop_id)
168 case PROP_PLUGIN_MANAGER:
169 g_value_set_object (value, priv->plugin_manager);
170 break;
171 case PROP_PROFILES:
172 g_value_set_pointer (value, priv->profiles);
173 break;
174 default:
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176 break;
180 static void
181 anjuta_profile_manager_class_init (AnjutaProfileManagerClass *klass)
183 GObjectClass* object_class = G_OBJECT_CLASS (klass);
184 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
186 object_class->finalize = anjuta_profile_manager_finalize;
187 object_class->set_property = anjuta_profile_manager_set_property;
188 object_class->get_property = anjuta_profile_manager_get_property;
190 g_object_class_install_property (object_class,
191 PROP_PLUGIN_MANAGER,
192 g_param_spec_object ("plugin-manager",
193 "Plugin Manager",
194 "The plugin manager to use for profile plugins",
195 ANJUTA_TYPE_PLUGIN_MANAGER,
196 G_PARAM_READABLE |
197 G_PARAM_WRITABLE |
198 G_PARAM_CONSTRUCT));
200 * AnjutaProfileManager::profile-pushed:
201 * @profile_manager: a #AnjutaProfileManager object.
202 * @profile: the new #AnjutaProfile added.
204 * Emitted when a profile is added in the stack. If the profile manager is
205 * not frozen, the current profile will be unloaded and the new one
206 * will be loaded.
208 profile_manager_signals[PROFILE_PUSHED] =
209 g_signal_new ("profile-pushed",
210 G_OBJECT_CLASS_TYPE (klass),
211 G_SIGNAL_RUN_FIRST,
212 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
213 profile_pushed),
214 NULL, NULL,
215 anjuta_cclosure_marshal_VOID__OBJECT,
216 G_TYPE_NONE, 1,
217 ANJUTA_TYPE_PROFILE);
220 * AnjutaProfileManager::profile-popped:
221 * @profile_manager: a #AnjutaProfileManager object.
222 * @profile: the current removed #AnjutaProfile.
224 * Emitted when a profile is removed from the stack. If the profile manager
225 * is not frozen, the current profile will be unloaded and the previous one
226 * will be loaded.
228 profile_manager_signals[PROFILE_POPPED] =
229 g_signal_new ("profile-popped",
230 G_OBJECT_CLASS_TYPE (klass),
231 G_SIGNAL_RUN_FIRST,
232 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
233 profile_popped),
234 NULL, NULL,
235 anjuta_cclosure_marshal_VOID__OBJECT,
236 G_TYPE_NONE, 1,
237 ANJUTA_TYPE_PROFILE);
240 * AnjutaProfileManager::profile-descoped:
241 * @profile_manager: a #AnjutaProfileManager object.
242 * @profile: the old unloaded #AnjutaProfile.
244 * Emitted when a profile will be unloaded.
246 profile_manager_signals[PROFILE_DESCOPED] =
247 g_signal_new ("profile-descoped",
248 G_OBJECT_CLASS_TYPE (klass),
249 G_SIGNAL_RUN_FIRST,
250 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
251 profile_descoped),
252 NULL, NULL,
253 anjuta_cclosure_marshal_VOID__OBJECT,
254 G_TYPE_NONE, 1,
255 ANJUTA_TYPE_PROFILE);
258 * AnjutaProfileManager::profile-scoped:
259 * @profile_manager: a #AnjutaProfileManager object.
260 * @profile: the current loaded #AnjutaProfile.
262 * Emitted when a new profile is loaded.
264 profile_manager_signals[PROFILE_SCOPED] =
265 g_signal_new ("profile-scoped",
266 G_OBJECT_CLASS_TYPE (klass),
267 G_SIGNAL_RUN_FIRST,
268 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
269 profile_scoped),
270 NULL, NULL,
271 anjuta_cclosure_marshal_VOID__OBJECT,
272 G_TYPE_NONE, 1,
273 ANJUTA_TYPE_PROFILE);
276 GType
277 anjuta_profile_manager_get_type (void)
279 static GType our_type = 0;
281 if(our_type == 0)
283 static const GTypeInfo our_info =
285 sizeof (AnjutaProfileManagerClass), /* class_size */
286 (GBaseInitFunc) NULL, /* base_init */
287 (GBaseFinalizeFunc) NULL, /* base_finalize */
288 (GClassInitFunc) anjuta_profile_manager_class_init, /* class_init */
289 (GClassFinalizeFunc) NULL, /* class_finalize */
290 NULL /* class_data */,
291 sizeof (AnjutaProfileManager), /* instance_size */
292 0, /* n_preallocs */
293 (GInstanceInitFunc) anjuta_profile_manager_init, /* instance_init */
294 NULL /* value_table */
297 our_type = g_type_register_static (G_TYPE_OBJECT, "AnjutaProfileManager",
298 &our_info, 0);
301 return our_type;
305 * anjuta_profile_manager_new:
306 * @plugin_manager: the #AnjutaPluginManager used by all profiles.
308 * Create a new profile manager.
310 * Return value: the new #AnjutaProfileManager object.
312 AnjutaProfileManager*
313 anjuta_profile_manager_new (AnjutaPluginManager *plugin_manager)
315 GObject *obj;
317 obj = g_object_new (ANJUTA_TYPE_PROFILE_MANAGER, "plugin-manager",
318 plugin_manager, NULL);
319 return ANJUTA_PROFILE_MANAGER (obj);
322 static gboolean
323 anjuta_profile_manager_load_profile (AnjutaProfileManager *profile_manager,
324 AnjutaProfile *profile,
325 AnjutaProfile *previous_profile,
326 GError **error)
328 AnjutaProfileManagerPriv *priv;
329 GList *active_plugins, *node;
330 GList *plugins_to_activate, *plugins_to_deactivate;
331 GList *selected_plugins;
333 GHashTable *active_plugins_hash, *plugins_to_activate_hash;
335 priv = profile_manager->priv;
337 /* Disable profile synchronization while the profile is being activated */
338 g_signal_handlers_block_by_func (priv->plugin_manager,
339 G_CALLBACK (on_plugin_activated),
340 profile_manager);
341 g_signal_handlers_block_by_func (priv->plugin_manager,
342 G_CALLBACK (on_plugin_deactivated),
343 profile_manager);
345 /* Emit pre-change for the last profile */
346 if (previous_profile)
348 g_signal_emit_by_name (profile_manager, "profile-descoped",
349 previous_profile);
352 /* Prepare plugins to activate */
353 plugins_to_activate_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
355 /* Select plugins in the profile */
356 if (profile)
357 selected_plugins = anjuta_profile_get_plugins (profile);
358 else
359 selected_plugins = NULL;
361 node = selected_plugins;
362 while (node)
364 g_hash_table_insert (plugins_to_activate_hash, node->data, node->data);
365 node = g_list_next (node);
368 /* Prepare active plugins hash */
369 active_plugins =
370 anjuta_plugin_manager_get_active_plugins (priv->plugin_manager);
371 active_plugins_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
372 node = active_plugins;
373 while (node)
375 g_hash_table_insert (active_plugins_hash, node->data, node->data);
376 node = g_list_next (node);
379 plugins_to_deactivate = NULL;
381 /* Prepare plugins to deactiveate that are already active, but are
382 * not requested to be active
384 node = active_plugins;
385 while (node)
387 if (!g_hash_table_lookup (plugins_to_activate_hash, node->data))
389 plugins_to_deactivate = g_list_prepend (plugins_to_deactivate,
390 node->data);
392 node = g_list_next (node);
394 plugins_to_deactivate = g_list_reverse (plugins_to_deactivate);
396 /* Deactivate plugins */
397 node = plugins_to_deactivate;
398 while (node)
400 AnjutaPluginDescription *desc;
401 gchar *plugin_id = NULL;
403 desc = (AnjutaPluginDescription *)node->data;
404 anjuta_plugin_description_get_string (desc, "Anjuta Plugin",
405 "Location", &plugin_id);
406 g_assert (plugin_id != NULL);
408 /* DEBUG_PRINT ("Profile: deactivating %s", plugin_id); */
410 anjuta_plugin_manager_unload_plugin_by_id (priv->plugin_manager,
411 plugin_id);
412 node = g_list_next (node);
415 /* Prepare the plugins to activate */
416 plugins_to_activate = NULL;
417 node = selected_plugins;
418 while (node)
420 if (!g_hash_table_lookup (active_plugins_hash, node->data))
421 plugins_to_activate = g_list_prepend (plugins_to_activate,
422 node->data);
423 node = g_list_next (node);
426 /* Now activate the plugins */
427 if (plugins_to_activate)
429 /* Activate them */
430 plugins_to_activate = g_list_reverse (plugins_to_activate);
431 anjuta_plugin_manager_activate_plugins (priv->plugin_manager,
432 plugins_to_activate);
435 g_list_free (plugins_to_activate);
436 g_list_free (active_plugins);
438 g_hash_table_destroy (plugins_to_activate_hash);
439 g_hash_table_destroy (active_plugins_hash);
441 /* Enable profile synchronization */
442 g_signal_handlers_unblock_by_func (priv->plugin_manager,
443 G_CALLBACK (on_plugin_activated),
444 profile_manager);
445 g_signal_handlers_unblock_by_func (priv->plugin_manager,
446 G_CALLBACK (on_plugin_deactivated),
447 profile_manager);
448 g_signal_emit_by_name (profile_manager, "profile-scoped", profile);
449 return TRUE;
452 static gboolean
453 anjuta_profile_manager_queue_profile (AnjutaProfileManager *profile_manager,
454 AnjutaProfile *profile,
455 GError **error)
457 AnjutaProfileManagerPriv *priv;
459 priv = profile_manager->priv;
460 priv->profiles_queue = g_list_prepend (priv->profiles_queue,
461 profile);
462 /* If there is no freeze load profile now */
463 if (priv->freeze_count <= 0)
465 AnjutaProfile *previous_profile = NULL;
467 if (priv->profiles)
468 previous_profile = priv->profiles->data;
470 /* Push queued profiles in stack */
471 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
472 priv->profiles_queue = NULL;
474 return anjuta_profile_manager_load_profile (profile_manager,
475 ANJUTA_PROFILE (priv->profiles->data),
476 previous_profile,
477 error);
479 else
481 return FALSE;
486 * anjuta_profile_manager_push:
487 * @profile_manager: the #AnjutaProfileManager object.
488 * @profile: the new #AnjutaProfile.
489 * @error: error propagation and reporting.
491 * Add a new profile at the top of the profile manager stack. If the profile
492 * manager is not frozen, this new profile will be loaded immediatly and
493 * become the current profile.
495 * Return value: TRUE on success, FALSE otherwise.
497 gboolean
498 anjuta_profile_manager_push (AnjutaProfileManager *profile_manager,
499 AnjutaProfile *profile, GError **error)
501 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
503 /* Emit profile push signal */
504 g_signal_emit_by_name (profile_manager, "profile-pushed",
505 profile);
507 return anjuta_profile_manager_queue_profile (profile_manager, profile,
508 error);
512 * anjuta_profile_manager_pop:
513 * @profile_manager: the #AnjutaProfileManager object.
514 * @profile_name: the name of the profile to remove.
515 * @error: error propagation and reporting.
517 * Remove a profile from the profile manager stack. If the manager is not
518 * frozen, only the current profile can be removed. It will be unloaded and
519 * the previous profile will be loaded.
520 * If the manager is frozen, the current profile or the last pushed profile
521 * can be removed.
523 * Return value: TRUE on success, FALSE otherwise.
525 gboolean
526 anjuta_profile_manager_pop (AnjutaProfileManager *profile_manager,
527 const gchar *profile_name, GError **error)
529 AnjutaProfileManagerPriv *priv;
530 AnjutaProfile *profile;
532 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
533 priv = profile_manager->priv;
535 /* First check in the queue */
536 if (priv->profiles_queue)
538 profile = priv->profiles_queue->data;
539 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
540 profile_name) == 0, FALSE);
541 priv->profiles_queue = g_list_remove (priv->profiles_queue, profile);
543 g_signal_emit_by_name (profile_manager, "profile-popped",
544 profile);
546 g_object_unref (profile);
547 return TRUE;
550 /* Then check in the current stack */
551 if (priv->profiles)
553 profile = priv->profiles->data;
554 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
555 profile_name) == 0, FALSE);
556 priv->profiles = g_list_remove (priv->profiles, profile);
558 g_signal_emit_by_name (profile_manager, "profile-popped",
559 profile);
561 /* Restore the next profile in the stack */
562 if (priv->profiles)
564 return anjuta_profile_manager_load_profile (profile_manager,
565 ANJUTA_PROFILE (priv->profiles->data),
566 profile,
567 error);
569 else
571 return anjuta_profile_manager_load_profile (profile_manager,
572 NULL, profile,
573 error);
575 g_object_unref (profile);
578 return FALSE;
582 * anjuta_profile_manager_freeze:
583 * @profile_manager: the #AnjutaProfileManager object.
585 * Freeze the plugin manager. In this state, plugins can be added and removed
586 * from the stack without triggering any change in the current profile. It is
587 * possible to freeze the manager several times but it will be back in its normal
588 * state only after as much call of anjuta_profile_manager_thaw().
590 void
591 anjuta_profile_manager_freeze (AnjutaProfileManager *profile_manager)
593 AnjutaProfileManagerPriv *priv;
594 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
596 priv = profile_manager->priv;
597 priv->freeze_count++;
601 * anjuta_profile_manager_thaw:
602 * @profile_manager: the #AnjutaProfileManager object.
603 * @error: error propagation and reporting.
605 * Put back the plugin manager in its normal mode after calling
606 * anjuta_profile_manager_freeze(). It will load a new profile if one has been
607 * added while the manager was frozen.
609 * Return value: TRUE on success, FALSE otherwise.
611 gboolean
612 anjuta_profile_manager_thaw (AnjutaProfileManager *profile_manager,
613 GError **error)
615 AnjutaProfileManagerPriv *priv;
616 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
618 priv = profile_manager->priv;
620 if (priv->freeze_count > 0)
621 priv->freeze_count--;
623 if (priv->freeze_count <= 0 && priv->profiles_queue)
625 AnjutaProfile *previous_profile = NULL;
627 if (priv->profiles)
628 previous_profile = priv->profiles->data;
630 /* Push queued profiles in stack */
631 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
632 priv->profiles_queue = NULL;
634 /* Load the profile */
635 return anjuta_profile_manager_load_profile (profile_manager,
636 ANJUTA_PROFILE (priv->profiles->data),
637 previous_profile,
638 error);
640 else
642 return FALSE;
647 * anjuta_profile_manager_get_current :
648 * @profile_manager: A #AnjutaProfileManager object.
650 * Return the current profile.
652 * Return value: a #AnjutaProfile object or NULL if the profile stack is empty.
654 AnjutaProfile*
655 anjuta_profile_manager_get_current (AnjutaProfileManager *profile_manager)
657 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), NULL);
659 if (profile_manager->priv->profiles_queue)
660 return ANJUTA_PROFILE (profile_manager->priv->profiles_queue->data);
661 else if (profile_manager->priv->profiles)
662 return ANJUTA_PROFILE (profile_manager->priv->profiles->data);
663 else
664 return NULL;
668 * anjuta_profile_manager_close:
669 * @profile_manager: A #AnjutaProfileManager object.
671 * Close the #AnjutaProfileManager causing "profile-descoped" to be emitted and
672 * all queued and previous profiles to be released. This function is to be used
673 * when destroying an Anjuta instance.
675 void
676 anjuta_profile_manager_close (AnjutaProfileManager *profile_manager)
678 AnjutaProfileManagerPriv *priv;
680 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
682 priv = profile_manager->priv;
684 g_signal_handlers_disconnect_by_func (priv->plugin_manager,
685 on_plugin_activated, profile_manager);
686 g_signal_handlers_disconnect_by_func (priv->plugin_manager,
687 on_plugin_deactivated, profile_manager);
689 if (priv->profiles)
691 AnjutaProfile *profile = ANJUTA_PROFILE (priv->profiles->data);
693 /* Emit "profile-descoped" so that other parts of anjuta can store
694 * information about the currently loaded profile. */
695 g_signal_emit_by_name (profile_manager, "profile-descoped",
696 profile);
698 g_list_free_full (priv->profiles, g_object_unref);
699 priv->profiles = NULL;
702 if (priv->profiles_queue)
704 g_list_free_full (priv->profiles, g_object_unref);
705 priv->profiles_queue = NULL;