* plugins/debug-manager/plugin.c:
[anjuta-git-plugin.git] / libanjuta / anjuta-profile-manager.c
blobdc9bfa62a9c9ddf59cc7404ef343b162696d5adf
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
30 #include <string.h>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libgnomevfs/gnome-vfs.h>
35 #include <libanjuta/anjuta-debug.h>
36 #include <libanjuta/anjuta-marshal.h>
37 #include "anjuta-profile-manager.h"
39 enum
41 PROP_0,
42 PROP_PLUGIN_MANAGER,
43 PROP_PROFILES
46 enum
48 PROFILE_PUSHED,
49 PROFILE_POPPED,
50 PROFILE_DESCOPED,
51 PROFILE_SCOPED,
52 LAST_SIGNAL
55 struct _AnjutaProfileManagerPriv
57 AnjutaPluginManager *plugin_manager;
58 GList *profiles;
60 /* Pending queue. Profiles are queued until freeze count becomes 0 */
61 GList *profiles_queue;
63 /* Freeze count. Pending profiles are loaded when it reaches 0 */
64 gint freeze_count;
67 static GObjectClass* parent_class = NULL;
68 static guint profile_manager_signals[LAST_SIGNAL] = { 0 };
70 static void
71 on_plugin_activated (AnjutaPluginManager *plugin_manager,
72 AnjutaPluginDescription *plugin_desc,
73 GObject *plugin_object,
74 AnjutaProfileManager *profile_manager)
76 AnjutaProfileManagerPriv *priv;
77 priv = profile_manager->priv;
79 if (priv->profiles)
81 /* Add it current profile */
82 anjuta_profile_add_plugin (ANJUTA_PROFILE (priv->profiles->data),
83 plugin_desc);
87 static void
88 on_plugin_deactivated (AnjutaPluginManager *plugin_manager,
89 AnjutaPluginDescription *plugin_desc,
90 GObject *plugin_object,
91 AnjutaProfileManager *profile_manager)
93 AnjutaProfileManagerPriv *priv;
94 priv = profile_manager->priv;
96 if (priv->profiles)
98 /* Remove from current profile */
99 anjuta_profile_remove_plugin (ANJUTA_PROFILE (priv->profiles->data),
100 plugin_desc);
104 static void
105 anjuta_profile_manager_init (AnjutaProfileManager *object)
107 object->priv = g_new0 (AnjutaProfileManagerPriv, 1);
110 static void
111 anjuta_profile_manager_finalize (GObject *object)
113 AnjutaProfileManagerPriv *priv;
114 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
115 if (priv->profiles)
117 g_list_foreach (priv->profiles, (GFunc)g_object_unref, NULL);
118 g_list_free (priv->profiles);
119 priv->profiles = NULL;
121 if (priv->profiles_queue)
123 g_list_foreach (priv->profiles_queue, (GFunc)g_object_unref, NULL);
124 g_list_free (priv->profiles_queue);
125 priv->profiles_queue = NULL;
128 G_OBJECT_CLASS (parent_class)->finalize (object);
131 static void
132 anjuta_profile_manager_set_property (GObject *object, guint prop_id,
133 const GValue *value, GParamSpec *pspec)
135 AnjutaProfileManagerPriv *priv;
136 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
137 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
139 switch (prop_id)
141 case PROP_PLUGIN_MANAGER:
142 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (g_value_get_object (value)));
143 priv->plugin_manager = g_value_get_object (value);
144 g_signal_connect (priv->plugin_manager, "plugin-activated",
145 G_CALLBACK (on_plugin_activated), object);
146 g_signal_connect (priv->plugin_manager, "plugin-deactivated",
147 G_CALLBACK (on_plugin_deactivated), object);
148 break;
149 default:
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
151 break;
155 static void
156 anjuta_profile_manager_get_property (GObject *object, guint prop_id,
157 GValue *value, GParamSpec *pspec)
159 AnjutaProfileManagerPriv *priv;
160 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
161 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
163 switch (prop_id)
165 case PROP_PLUGIN_MANAGER:
166 g_value_set_object (value, priv->plugin_manager);
167 break;
168 case PROP_PROFILES:
169 g_value_set_pointer (value, priv->profiles);
170 break;
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173 break;
177 static void
178 anjuta_profile_manager_class_init (AnjutaProfileManagerClass *klass)
180 GObjectClass* object_class = G_OBJECT_CLASS (klass);
181 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
183 object_class->finalize = anjuta_profile_manager_finalize;
184 object_class->set_property = anjuta_profile_manager_set_property;
185 object_class->get_property = anjuta_profile_manager_get_property;
187 g_object_class_install_property (object_class,
188 PROP_PLUGIN_MANAGER,
189 g_param_spec_object ("plugin-manager",
190 "Plugin Manager",
191 "The plugin manager to use for profile plugins",
192 ANJUTA_TYPE_PLUGIN_MANAGER,
193 G_PARAM_READABLE |
194 G_PARAM_WRITABLE |
195 G_PARAM_CONSTRUCT));
196 profile_manager_signals[PROFILE_PUSHED] =
197 g_signal_new ("profile-pushed",
198 G_OBJECT_CLASS_TYPE (klass),
199 G_SIGNAL_RUN_FIRST,
200 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
201 profile_pushed),
202 NULL, NULL,
203 anjuta_cclosure_marshal_VOID__OBJECT,
204 G_TYPE_NONE, 1,
205 ANJUTA_TYPE_PROFILE);
206 profile_manager_signals[PROFILE_POPPED] =
207 g_signal_new ("profile-popped",
208 G_OBJECT_CLASS_TYPE (klass),
209 G_SIGNAL_RUN_FIRST,
210 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
211 profile_popped),
212 NULL, NULL,
213 anjuta_cclosure_marshal_VOID__OBJECT,
214 G_TYPE_NONE, 1,
215 ANJUTA_TYPE_PROFILE);
216 profile_manager_signals[PROFILE_DESCOPED] =
217 g_signal_new ("profile-descoped",
218 G_OBJECT_CLASS_TYPE (klass),
219 G_SIGNAL_RUN_FIRST,
220 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
221 profile_descoped),
222 NULL, NULL,
223 anjuta_cclosure_marshal_VOID__OBJECT,
224 G_TYPE_NONE, 1,
225 ANJUTA_TYPE_PROFILE);
226 profile_manager_signals[PROFILE_SCOPED] =
227 g_signal_new ("profile-scoped",
228 G_OBJECT_CLASS_TYPE (klass),
229 G_SIGNAL_RUN_FIRST,
230 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
231 profile_scoped),
232 NULL, NULL,
233 anjuta_cclosure_marshal_VOID__OBJECT,
234 G_TYPE_NONE, 1,
235 ANJUTA_TYPE_PROFILE);
238 GType
239 anjuta_profile_manager_get_type (void)
241 static GType our_type = 0;
243 if(our_type == 0)
245 static const GTypeInfo our_info =
247 sizeof (AnjutaProfileManagerClass), /* class_size */
248 (GBaseInitFunc) NULL, /* base_init */
249 (GBaseFinalizeFunc) NULL, /* base_finalize */
250 (GClassInitFunc) anjuta_profile_manager_class_init, /* class_init */
251 (GClassFinalizeFunc) NULL, /* class_finalize */
252 NULL /* class_data */,
253 sizeof (AnjutaProfileManager), /* instance_size */
254 0, /* n_preallocs */
255 (GInstanceInitFunc) anjuta_profile_manager_init, /* instance_init */
256 NULL /* value_table */
259 our_type = g_type_register_static (G_TYPE_OBJECT, "AnjutaProfileManager",
260 &our_info, 0);
263 return our_type;
266 AnjutaProfileManager*
267 anjuta_profile_manager_new (AnjutaPluginManager *plugin_manager)
269 GObject *obj;
271 obj = g_object_new (ANJUTA_TYPE_PROFILE_MANAGER, "plugin-manager",
272 plugin_manager, NULL);
273 return ANJUTA_PROFILE_MANAGER (obj);
276 static gboolean
277 anjuta_profile_manager_load_profile (AnjutaProfileManager *profile_manager,
278 AnjutaProfile *profile,
279 AnjutaProfile *previous_profile,
280 GError **error)
282 AnjutaProfileManagerPriv *priv;
283 GList *active_plugins, *node;
284 GList *plugins_to_activate, *plugins_to_deactivate;
285 GList *selected_plugins;
287 GHashTable *active_plugins_hash, *plugins_to_activate_hash;
289 priv = profile_manager->priv;
291 /* Disable profile synchronization while the profile is being activated */
292 g_signal_handlers_block_by_func (priv->plugin_manager,
293 G_CALLBACK (on_plugin_activated),
294 profile_manager);
295 g_signal_handlers_block_by_func (priv->plugin_manager,
296 G_CALLBACK (on_plugin_deactivated),
297 profile_manager);
299 /* Emit pre-change for the last profile */
300 if (previous_profile)
302 g_signal_emit_by_name (profile_manager, "profile-descoped",
303 previous_profile);
306 /* Prepare plugins to activate */
307 plugins_to_activate_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
309 /* Select plugins in the profile */
310 if (profile)
311 selected_plugins = anjuta_profile_get_plugins (profile);
312 else
313 selected_plugins = NULL;
315 node = selected_plugins;
316 while (node)
318 g_hash_table_insert (plugins_to_activate_hash, node->data, node->data);
319 node = g_list_next (node);
322 /* Prepare active plugins hash */
323 active_plugins =
324 anjuta_plugin_manager_get_active_plugins (priv->plugin_manager);
325 active_plugins_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
326 node = active_plugins;
327 while (node)
329 g_hash_table_insert (active_plugins_hash, node->data, node->data);
330 node = g_list_next (node);
333 plugins_to_deactivate = NULL;
335 /* Prepare plugins to deactiveate that are already active, but are
336 * not requested to be active
338 node = active_plugins;
339 while (node)
341 if (!g_hash_table_lookup (plugins_to_activate_hash, node->data))
343 plugins_to_deactivate = g_list_prepend (plugins_to_deactivate,
344 node->data);
346 node = g_list_next (node);
348 plugins_to_deactivate = g_list_reverse (plugins_to_deactivate);
350 /* Deactivate plugins */
351 node = plugins_to_deactivate;
352 while (node)
354 AnjutaPluginDescription *desc;
355 GObject *plugin_object;
356 gchar *plugin_id = NULL;
358 desc = (AnjutaPluginDescription *)node->data;
359 anjuta_plugin_description_get_string (desc, "Anjuta Plugin",
360 "Location", &plugin_id);
361 g_assert (plugin_id != NULL);
363 /* DEBUG_PRINT ("Profile: deactivating %s", plugin_id); */
365 plugin_object =
366 anjuta_plugin_manager_get_plugin_by_id (priv->plugin_manager,
367 plugin_id);
368 g_assert (plugin_object != NULL);
370 anjuta_plugin_manager_unload_plugin (priv->plugin_manager,
371 plugin_object);
372 g_free (plugin_id);
373 node = g_list_next (node);
376 /* Prepare the plugins to activate */
377 plugins_to_activate = NULL;
378 node = selected_plugins;
379 while (node)
381 if (!g_hash_table_lookup (active_plugins_hash, node->data))
382 plugins_to_activate = g_list_prepend (plugins_to_activate,
383 node->data);
384 node = g_list_next (node);
387 /* Now activate the plugins */
388 if (plugins_to_activate)
390 /* Activate them */
391 plugins_to_activate = g_list_reverse (plugins_to_activate);
392 anjuta_plugin_manager_activate_plugins (priv->plugin_manager,
393 plugins_to_activate);
396 g_list_free (plugins_to_activate);
397 g_list_free (active_plugins);
399 g_hash_table_destroy (plugins_to_activate_hash);
400 g_hash_table_destroy (active_plugins_hash);
402 /* Enable profile synchronization */
403 g_signal_handlers_unblock_by_func (priv->plugin_manager,
404 G_CALLBACK (on_plugin_activated),
405 profile_manager);
406 g_signal_handlers_unblock_by_func (priv->plugin_manager,
407 G_CALLBACK (on_plugin_deactivated),
408 profile_manager);
409 g_signal_emit_by_name (profile_manager, "profile-scoped", profile);
410 return TRUE;
413 static gboolean
414 anjuta_profile_manager_queue_profile (AnjutaProfileManager *profile_manager,
415 AnjutaProfile *profile,
416 GError **error)
418 AnjutaProfileManagerPriv *priv;
420 priv = profile_manager->priv;
421 priv->profiles_queue = g_list_prepend (priv->profiles_queue,
422 profile);
423 /* If there is no freeze load profile now */
424 if (priv->freeze_count <= 0)
426 AnjutaProfile *previous_profile = NULL;
428 if (priv->profiles)
429 previous_profile = priv->profiles->data;
431 /* Push queued profiles in stack */
432 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
433 priv->profiles_queue = NULL;
435 return anjuta_profile_manager_load_profile (profile_manager,
436 ANJUTA_PROFILE (priv->profiles->data),
437 previous_profile,
438 error);
440 else
442 return FALSE;
446 gboolean
447 anjuta_profile_manager_push (AnjutaProfileManager *profile_manager,
448 AnjutaProfile *profile, GError **error)
450 AnjutaProfileManagerPriv *priv;
452 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
453 priv = profile_manager->priv;
455 /* Emit profile push signal */
456 g_signal_emit_by_name (profile_manager, "profile-pushed",
457 profile);
459 return anjuta_profile_manager_queue_profile (profile_manager, profile,
460 error);
463 /* Only the last profile can be popped */
464 gboolean
465 anjuta_profile_manager_pop (AnjutaProfileManager *profile_manager,
466 const gchar *profile_name, GError **error)
468 AnjutaProfileManagerPriv *priv;
469 AnjutaProfile *profile;
470 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
472 priv = profile_manager->priv;
474 /* First check in the queue */
475 if (priv->profiles_queue)
477 profile = priv->profiles_queue->data;
478 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
479 profile_name) == 0, FALSE);
480 priv->profiles_queue = g_list_remove (priv->profiles_queue, profile);
482 g_signal_emit_by_name (profile_manager, "profile-popped",
483 profile);
485 g_object_unref (profile);
486 return TRUE;
489 /* Then check in the current stack */
490 if (priv->profiles)
492 profile = priv->profiles->data;
493 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
494 profile_name) == 0, FALSE);
495 priv->profiles = g_list_remove (priv->profiles, profile);
497 g_signal_emit_by_name (profile_manager, "profile-popped",
498 profile);
500 /* Restore the next profile in the stack */
501 if (priv->profiles)
503 return anjuta_profile_manager_load_profile (profile_manager,
504 ANJUTA_PROFILE (priv->profiles->data),
505 profile,
506 error);
508 else
510 return anjuta_profile_manager_load_profile (profile_manager,
511 NULL, profile,
512 error);
514 g_object_unref (profile);
517 g_warning ("No profiles in the stack. Can not pop out any profile: %s",
518 profile_name);
519 return FALSE;
522 void
523 anjuta_profile_manager_freeze (AnjutaProfileManager *profile_manager)
525 AnjutaProfileManagerPriv *priv;
526 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
527 priv = profile_manager->priv;
528 priv->freeze_count++;
531 gboolean
532 anjuta_profile_manager_thaw (AnjutaProfileManager *profile_manager,
533 GError **error)
535 AnjutaProfileManagerPriv *priv;
536 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
537 priv = profile_manager->priv;
539 if (priv->freeze_count > 0)
540 priv->freeze_count--;
542 if (priv->freeze_count <= 0 && priv->profiles_queue)
544 AnjutaProfile *previous_profile = NULL;
546 if (priv->profiles)
547 previous_profile = priv->profiles->data;
549 /* Push queued profiles in stack */
550 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
551 priv->profiles_queue = NULL;
553 /* Load the profile */
554 return anjuta_profile_manager_load_profile (profile_manager,
555 ANJUTA_PROFILE (priv->profiles->data),
556 previous_profile,
557 error);
559 else
561 return FALSE;
565 AnjutaProfile*
566 anjuta_profile_manager_get_current (AnjutaProfileManager *profile_manager)
568 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), NULL);
569 if (profile_manager->priv->profiles_queue)
570 return ANJUTA_PROFILE (profile_manager->priv->profiles_queue->data);
571 else if (profile_manager->priv->profiles)
572 return ANJUTA_PROFILE (profile_manager->priv->profiles->data);
573 else
574 return NULL;