Fix a random crash when vim modelines are used
[anjuta.git] / libanjuta / anjuta-profile-manager.c
blobb7fb7087bfcd1fc706a3353736ecbed0289098b3
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 three profiles. A system profile which contains mandatory
29 * plugins which are never unloaded. A user profile is used when no project is
30 * loaded and a project profile when one is loaded.
31 * If a second project is loaded, it is loaded in another instance of Anjuta.
32 * When a project is closed, Anjuta goes back to the user profile.
34 * The profile manager can be in a frozen state where you can push or
35 * pop a profile from the stack without triggering a change of the profile.
38 #include <string.h>
40 #include <libanjuta/anjuta-debug.h>
41 #include <libanjuta/anjuta-marshal.h>
42 #include "anjuta-profile-manager.h"
44 enum
46 PROP_0,
47 PROP_PLUGIN_MANAGER,
48 PROP_PROFILES
51 enum
53 PROFILE_PUSHED,
54 PROFILE_POPPED,
55 LAST_SIGNAL
58 struct _AnjutaProfileManagerPriv
60 AnjutaPluginManager *plugin_manager;
61 GList *profiles;
63 /* Pending queue. Profiles are queued until freeze count becomes 0 */
64 GList *profiles_queue;
66 /* Freeze count. Pending profiles are loaded when it reaches 0 */
67 gint freeze_count;
70 static GObjectClass* parent_class = NULL;
71 static guint profile_manager_signals[LAST_SIGNAL] = { 0 };
73 static void
74 anjuta_profile_manager_init (AnjutaProfileManager *object)
76 object->priv = g_new0 (AnjutaProfileManagerPriv, 1);
79 static void
80 anjuta_profile_manager_finalize (GObject *object)
82 AnjutaProfileManagerPriv *priv = ANJUTA_PROFILE_MANAGER (object)->priv;
84 if (priv->profiles)
85 g_list_free_full (priv->profiles, g_object_unref);
87 if (priv->profiles_queue)
88 g_list_free_full (priv->profiles_queue, g_object_unref);
91 G_OBJECT_CLASS (parent_class)->finalize (object);
94 static void
95 anjuta_profile_manager_set_property (GObject *object, guint prop_id,
96 const GValue *value, GParamSpec *pspec)
98 AnjutaProfileManagerPriv *priv;
99 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
100 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
102 switch (prop_id)
104 case PROP_PLUGIN_MANAGER:
105 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (g_value_get_object (value)));
106 priv->plugin_manager = g_value_get_object (value);
107 break;
108 default:
109 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
110 break;
114 static void
115 anjuta_profile_manager_get_property (GObject *object, guint prop_id,
116 GValue *value, GParamSpec *pspec)
118 AnjutaProfileManagerPriv *priv;
119 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
120 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
122 switch (prop_id)
124 case PROP_PLUGIN_MANAGER:
125 g_value_set_object (value, priv->plugin_manager);
126 break;
127 case PROP_PROFILES:
128 g_value_set_pointer (value, priv->profiles);
129 break;
130 default:
131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
132 break;
136 static void
137 anjuta_profile_manager_class_init (AnjutaProfileManagerClass *klass)
139 GObjectClass* object_class = G_OBJECT_CLASS (klass);
140 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
142 object_class->finalize = anjuta_profile_manager_finalize;
143 object_class->set_property = anjuta_profile_manager_set_property;
144 object_class->get_property = anjuta_profile_manager_get_property;
146 g_object_class_install_property (object_class,
147 PROP_PLUGIN_MANAGER,
148 g_param_spec_object ("plugin-manager",
149 "Plugin Manager",
150 "The plugin manager to use for profile plugins",
151 ANJUTA_TYPE_PLUGIN_MANAGER,
152 G_PARAM_READABLE |
153 G_PARAM_WRITABLE |
154 G_PARAM_CONSTRUCT));
156 * AnjutaProfileManager::profile-pushed:
157 * @profile_manager: a #AnjutaProfileManager object.
158 * @profile: the new #AnjutaProfile added.
160 * Emitted when a profile is added in the stack. If the profile manager is
161 * not frozen, the current profile will be unloaded and the new one
162 * will be loaded.
164 profile_manager_signals[PROFILE_PUSHED] =
165 g_signal_new ("profile-pushed",
166 G_OBJECT_CLASS_TYPE (klass),
167 G_SIGNAL_RUN_FIRST,
168 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
169 profile_pushed),
170 NULL, NULL,
171 anjuta_cclosure_marshal_VOID__OBJECT,
172 G_TYPE_NONE, 1,
173 ANJUTA_TYPE_PROFILE);
176 * AnjutaProfileManager::profile-popped:
177 * @profile_manager: a #AnjutaProfileManager object.
178 * @profile: the current removed #AnjutaProfile.
180 * Emitted when a profile is removed from the stack. If the profile manager
181 * is not frozen, the current profile will be unloaded and the previous one
182 * will be loaded.
184 profile_manager_signals[PROFILE_POPPED] =
185 g_signal_new ("profile-popped",
186 G_OBJECT_CLASS_TYPE (klass),
187 G_SIGNAL_RUN_FIRST,
188 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
189 profile_popped),
190 NULL, NULL,
191 anjuta_cclosure_marshal_VOID__OBJECT,
192 G_TYPE_NONE, 1,
193 ANJUTA_TYPE_PROFILE);
197 GType
198 anjuta_profile_manager_get_type (void)
200 static GType our_type = 0;
202 if(our_type == 0)
204 static const GTypeInfo our_info =
206 sizeof (AnjutaProfileManagerClass), /* class_size */
207 (GBaseInitFunc) NULL, /* base_init */
208 (GBaseFinalizeFunc) NULL, /* base_finalize */
209 (GClassInitFunc) anjuta_profile_manager_class_init, /* class_init */
210 (GClassFinalizeFunc) NULL, /* class_finalize */
211 NULL /* class_data */,
212 sizeof (AnjutaProfileManager), /* instance_size */
213 0, /* n_preallocs */
214 (GInstanceInitFunc) anjuta_profile_manager_init, /* instance_init */
215 NULL /* value_table */
218 our_type = g_type_register_static (G_TYPE_OBJECT, "AnjutaProfileManager",
219 &our_info, 0);
222 return our_type;
226 * anjuta_profile_manager_new:
227 * @plugin_manager: the #AnjutaPluginManager used by all profiles.
229 * Create a new profile manager.
231 * Return value: the new #AnjutaProfileManager object.
233 AnjutaProfileManager*
234 anjuta_profile_manager_new (AnjutaPluginManager *plugin_manager)
236 GObject *obj;
238 obj = g_object_new (ANJUTA_TYPE_PROFILE_MANAGER, "plugin-manager",
239 plugin_manager, NULL);
240 return ANJUTA_PROFILE_MANAGER (obj);
243 static gboolean
244 anjuta_profile_manager_load_profiles (AnjutaProfileManager *profile_manager, GError **error)
246 AnjutaProfileManagerPriv *priv;
247 gboolean loaded = FALSE;
249 priv = profile_manager->priv;
251 /* If there is no freeze load profile now */
252 while ((priv->freeze_count <= 0) && (priv->profiles_queue != NULL))
254 AnjutaProfile *previous_profile = NULL;
255 GList *node;
257 /* We need to load each profile one by one because a "system" profile
258 * contains plugins which are never unloaded. */
259 if (priv->profiles)
260 previous_profile = priv->profiles->data;
261 node = g_list_last (priv->profiles_queue);
262 priv->profiles_queue = g_list_remove_link (priv->profiles_queue, node);
263 priv->profiles = g_list_concat (node, priv->profiles);
265 /* Load profile. Note that loading a profile can trigger the load of
266 * additional profile. Typically loading the default profile will
267 * trigger the load of the last project profile. */
268 if (previous_profile != NULL) anjuta_profile_unload (previous_profile, NULL);
269 loaded = anjuta_profile_load (ANJUTA_PROFILE (node->data), error);
272 return loaded;
275 static gboolean
276 anjuta_profile_manager_queue_profile (AnjutaProfileManager *profile_manager,
277 AnjutaProfile *profile,
278 GError **error)
280 AnjutaProfileManagerPriv *priv;
282 priv = profile_manager->priv;
284 priv->profiles_queue = g_list_prepend (priv->profiles_queue, profile);
286 /* If there is no freeze load profile now */
287 return anjuta_profile_manager_load_profiles (profile_manager, error);
291 * anjuta_profile_manager_push:
292 * @profile_manager: the #AnjutaProfileManager object.
293 * @profile: the new #AnjutaProfile.
294 * @error: error propagation and reporting.
296 * Add a new profile at the top of the profile manager stack. If the profile
297 * manager is not frozen, this new profile will be loaded immediatly and
298 * become the current profile.
300 * Return value: %TRUE on success, %FALSE otherwise.
302 gboolean
303 anjuta_profile_manager_push (AnjutaProfileManager *profile_manager,
304 AnjutaProfile *profile, GError **error)
306 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
308 /* Emit profile push signal */
309 g_signal_emit_by_name (profile_manager, "profile-pushed",
310 profile);
312 return anjuta_profile_manager_queue_profile (profile_manager, profile,
313 error);
317 * anjuta_profile_manager_pop:
318 * @profile_manager: the #AnjutaProfileManager object.
319 * @profile: the #AnjutaProfile to remove.
320 * @error: error propagation and reporting.
322 * Remove a profile from the profile manager stack. If the manager is not
323 * frozen, only the current profile can be removed. It will be unloaded and
324 * the previous profile will be loaded.
325 * If the manager is frozen, the current profile or the last pushed profile
326 * can be removed.
328 * Return value: %TRUE on success, %FALSE otherwise.
330 gboolean
331 anjuta_profile_manager_pop (AnjutaProfileManager *profile_manager,
332 AnjutaProfile *profile, GError **error)
334 AnjutaProfileManagerPriv *priv;
336 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
337 priv = profile_manager->priv;
339 /* First check in the queue */
340 if (priv->profiles_queue)
342 g_return_val_if_fail (priv->profiles_queue->data == profile, FALSE);
343 priv->profiles_queue = g_list_remove (priv->profiles_queue, profile);
345 g_signal_emit_by_name (profile_manager, "profile-popped",
346 profile);
348 g_object_unref (profile);
349 return TRUE;
352 /* Then check in the current stack */
353 if (priv->profiles)
355 g_return_val_if_fail (priv->profiles->data == profile, FALSE);
356 priv->profiles = g_list_remove (priv->profiles, profile);
358 g_signal_emit_by_name (profile_manager, "profile-popped",
359 profile);
361 /* Restore the next profile in the stack */
362 anjuta_profile_unload (profile, NULL);
363 g_object_unref (profile);
364 if (priv->profiles)
366 return anjuta_profile_load (ANJUTA_PROFILE (priv->profiles->data), error);
368 return TRUE;
371 return FALSE;
375 * anjuta_profile_manager_freeze:
376 * @profile_manager: the #AnjutaProfileManager object.
378 * Freeze the plugin manager. In this state, plugins can be added and removed
379 * from the stack without triggering any change in the current profile. It is
380 * possible to freeze the manager several times but it will be back in its normal
381 * state only after as much call of anjuta_profile_manager_thaw().
383 void
384 anjuta_profile_manager_freeze (AnjutaProfileManager *profile_manager)
386 AnjutaProfileManagerPriv *priv;
387 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
389 priv = profile_manager->priv;
390 priv->freeze_count++;
394 * anjuta_profile_manager_thaw:
395 * @profile_manager: the #AnjutaProfileManager object.
396 * @error: error propagation and reporting.
398 * Put back the plugin manager in its normal mode after calling
399 * anjuta_profile_manager_freeze(). It will load a new profile if one has been
400 * added while the manager was frozen.
402 * Return value: %TRUE on success, %FALSE otherwise.
404 gboolean
405 anjuta_profile_manager_thaw (AnjutaProfileManager *profile_manager,
406 GError **error)
408 AnjutaProfileManagerPriv *priv;
409 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
411 priv = profile_manager->priv;
413 if (priv->freeze_count > 0)
414 priv->freeze_count--;
416 return anjuta_profile_manager_load_profiles (profile_manager, error);
420 * anjuta_profile_manager_get_current :
421 * @profile_manager: A #AnjutaProfileManager object.
423 * Return the current profile.
425 * Return value: (transfer none) (allow-none): a #AnjutaProfile object or %NULL
426 * if the profile stack is empty.
428 AnjutaProfile*
429 anjuta_profile_manager_get_current (AnjutaProfileManager *profile_manager)
431 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), NULL);
433 if (profile_manager->priv->profiles_queue)
434 return ANJUTA_PROFILE (profile_manager->priv->profiles_queue->data);
435 else if (profile_manager->priv->profiles)
436 return ANJUTA_PROFILE (profile_manager->priv->profiles->data);
437 else
438 return NULL;
442 * anjuta_profile_manager_close:
443 * @profile_manager: A #AnjutaProfileManager object.
445 * Close the #AnjutaProfileManager causing "descoped" to be emitted and
446 * all queued and previous profiles to be released. This function is to be used
447 * when destroying an Anjuta instance.
449 void
450 anjuta_profile_manager_close (AnjutaProfileManager *profile_manager)
452 AnjutaProfileManagerPriv *priv;
454 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
456 priv = profile_manager->priv;
458 if (priv->profiles)
460 AnjutaProfile *profile = ANJUTA_PROFILE (priv->profiles->data);
462 /* Emit "descoped" so that other parts of anjuta can store
463 * information about the currently loaded profile. */
464 anjuta_profile_unload (profile, NULL);
466 g_list_free_full (priv->profiles, g_object_unref);
467 priv->profiles = NULL;
470 if (priv->profiles_queue)
472 g_list_free_full (priv->profiles, g_object_unref);
473 priv->profiles_queue = NULL;