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
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"
55 struct _AnjutaProfileManagerPriv
57 AnjutaPluginManager
*plugin_manager
;
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 */
67 static GObjectClass
* parent_class
= NULL
;
68 static guint profile_manager_signals
[LAST_SIGNAL
] = { 0 };
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
;
81 /* Add it current profile */
82 anjuta_profile_add_plugin (ANJUTA_PROFILE (priv
->profiles
->data
),
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
;
98 /* Remove from current profile */
99 anjuta_profile_remove_plugin (ANJUTA_PROFILE (priv
->profiles
->data
),
105 anjuta_profile_manager_init (AnjutaProfileManager
*object
)
107 object
->priv
= g_new0 (AnjutaProfileManagerPriv
, 1);
111 anjuta_profile_manager_finalize (GObject
*object
)
113 AnjutaProfileManagerPriv
*priv
;
114 priv
= ANJUTA_PROFILE_MANAGER (object
)->priv
;
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
);
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
;
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
);
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
;
165 case PROP_PLUGIN_MANAGER
:
166 g_value_set_object (value
, priv
->plugin_manager
);
169 g_value_set_pointer (value
, priv
->profiles
);
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
,
189 g_param_spec_object ("plugin-manager",
191 "The plugin manager to use for profile plugins",
192 ANJUTA_TYPE_PLUGIN_MANAGER
,
196 profile_manager_signals
[PROFILE_PUSHED
] =
197 g_signal_new ("profile-pushed",
198 G_OBJECT_CLASS_TYPE (klass
),
200 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
203 anjuta_cclosure_marshal_VOID__OBJECT
,
205 ANJUTA_TYPE_PROFILE
);
206 profile_manager_signals
[PROFILE_POPPED
] =
207 g_signal_new ("profile-popped",
208 G_OBJECT_CLASS_TYPE (klass
),
210 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
213 anjuta_cclosure_marshal_VOID__OBJECT
,
215 ANJUTA_TYPE_PROFILE
);
216 profile_manager_signals
[PROFILE_DESCOPED
] =
217 g_signal_new ("profile-descoped",
218 G_OBJECT_CLASS_TYPE (klass
),
220 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
223 anjuta_cclosure_marshal_VOID__OBJECT
,
225 ANJUTA_TYPE_PROFILE
);
226 profile_manager_signals
[PROFILE_SCOPED
] =
227 g_signal_new ("profile-scoped",
228 G_OBJECT_CLASS_TYPE (klass
),
230 G_STRUCT_OFFSET (AnjutaProfileManagerClass
,
233 anjuta_cclosure_marshal_VOID__OBJECT
,
235 ANJUTA_TYPE_PROFILE
);
239 anjuta_profile_manager_get_type (void)
241 static GType 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 */
255 (GInstanceInitFunc
) anjuta_profile_manager_init
, /* instance_init */
256 NULL
/* value_table */
259 our_type
= g_type_register_static (G_TYPE_OBJECT
, "AnjutaProfileManager",
266 AnjutaProfileManager
*
267 anjuta_profile_manager_new (AnjutaPluginManager
*plugin_manager
)
271 obj
= g_object_new (ANJUTA_TYPE_PROFILE_MANAGER
, "plugin-manager",
272 plugin_manager
, NULL
);
273 return ANJUTA_PROFILE_MANAGER (obj
);
277 anjuta_profile_manager_load_profile (AnjutaProfileManager
*profile_manager
,
278 AnjutaProfile
*profile
,
279 AnjutaProfile
*previous_profile
,
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
),
295 g_signal_handlers_block_by_func (priv
->plugin_manager
,
296 G_CALLBACK (on_plugin_deactivated
),
299 /* Emit pre-change for the last profile */
300 if (previous_profile
)
302 g_signal_emit_by_name (profile_manager
, "profile-descoped",
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 */
311 selected_plugins
= anjuta_profile_get_plugins (profile
);
313 selected_plugins
= NULL
;
315 node
= selected_plugins
;
318 g_hash_table_insert (plugins_to_activate_hash
, node
->data
, node
->data
);
319 node
= g_list_next (node
);
322 /* Prepare active plugins hash */
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
;
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
;
341 if (!g_hash_table_lookup (plugins_to_activate_hash
, node
->data
))
343 plugins_to_deactivate
= g_list_prepend (plugins_to_deactivate
,
346 node
= g_list_next (node
);
348 plugins_to_deactivate
= g_list_reverse (plugins_to_deactivate
);
350 /* Deactivate plugins */
351 node
= plugins_to_deactivate
;
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); */
366 anjuta_plugin_manager_get_plugin_by_id (priv
->plugin_manager
,
368 g_assert (plugin_object
!= NULL
);
370 anjuta_plugin_manager_unload_plugin (priv
->plugin_manager
,
373 node
= g_list_next (node
);
376 /* Prepare the plugins to activate */
377 plugins_to_activate
= NULL
;
378 node
= selected_plugins
;
381 if (!g_hash_table_lookup (active_plugins_hash
, node
->data
))
382 plugins_to_activate
= g_list_prepend (plugins_to_activate
,
384 node
= g_list_next (node
);
387 /* Now activate the plugins */
388 if (plugins_to_activate
)
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
),
406 g_signal_handlers_unblock_by_func (priv
->plugin_manager
,
407 G_CALLBACK (on_plugin_deactivated
),
409 g_signal_emit_by_name (profile_manager
, "profile-scoped", profile
);
414 anjuta_profile_manager_queue_profile (AnjutaProfileManager
*profile_manager
,
415 AnjutaProfile
*profile
,
418 AnjutaProfileManagerPriv
*priv
;
420 priv
= profile_manager
->priv
;
421 priv
->profiles_queue
= g_list_prepend (priv
->profiles_queue
,
423 /* If there is no freeze load profile now */
424 if (priv
->freeze_count
<= 0)
426 AnjutaProfile
*previous_profile
= NULL
;
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
),
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",
459 return anjuta_profile_manager_queue_profile (profile_manager
, profile
,
463 /* Only the last profile can be popped */
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",
485 g_object_unref (profile
);
489 /* Then check in the current stack */
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",
500 /* Restore the next profile in the stack */
503 return anjuta_profile_manager_load_profile (profile_manager
,
504 ANJUTA_PROFILE (priv
->profiles
->data
),
510 return anjuta_profile_manager_load_profile (profile_manager
,
514 g_object_unref (profile
);
517 g_warning ("No profiles in the stack. Can not pop out any profile: %s",
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
++;
532 anjuta_profile_manager_thaw (AnjutaProfileManager
*profile_manager
,
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
;
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
),
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
);