typedef struct _AsyncContext AsyncContext;
typedef struct _AuthContext AuthContext;
+typedef struct _CreateContext CreateContext;
typedef struct _SourceClosure SourceClosure;
typedef struct _ThreadClosure ThreadClosure;
EDBusSourceManager *dbus_source_manager;
GHashTable *object_path_table;
- GMutex *object_path_table_lock;
+ GMutex object_path_table_lock;
GHashTable *sources;
- GMutex *sources_lock;
+ GMutex sources_lock;
GSettings *settings;
};
GError **error;
};
+/* Used in e_source_registry_create_sources_sync() */
+struct _CreateContext {
+ GHashTable *pending_uids;
+ GMainContext *main_context;
+ GMainLoop *main_loop;
+};
+
struct _SourceClosure {
ESourceRegistry *registry;
ESource *source;
ESourceRegistry *registry;
GMainContext *main_context;
GMainLoop *main_loop;
- GCond *main_loop_cond;
- GMutex *main_loop_mutex;
+ GCond main_loop_cond;
+ GMutex main_loop_mutex;
+ GError *error;
};
enum {
g_slice_free (AuthContext, auth_context);
}
+static CreateContext *
+create_context_new (void)
+{
+ CreateContext *create_context;
+
+ create_context = g_slice_new0 (CreateContext);
+
+ create_context->pending_uids = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ create_context->main_context = g_main_context_new ();
+
+ create_context->main_loop = g_main_loop_new (
+ create_context->main_context, FALSE);
+
+ return create_context;
+}
+
+static void
+create_context_free (CreateContext *create_context)
+{
+ g_main_loop_unref (create_context->main_loop);
+ g_main_context_unref (create_context->main_context);
+ g_hash_table_unref (create_context->pending_uids);
+
+ g_slice_free (CreateContext, create_context);
+}
+
static void
source_closure_free (SourceClosure *closure)
{
g_main_context_unref (closure->main_context);
g_main_loop_unref (closure->main_loop);
- g_cond_free (closure->main_loop_cond);
- g_mutex_free (closure->main_loop_mutex);
+ g_cond_clear (&closure->main_loop_cond);
+ g_mutex_clear (&closure->main_loop_mutex);
+
+ /* The GError should be NULL at this point,
+ * regardless of whether an error occurred. */
+ g_warn_if_fail (closure->error == NULL);
g_slice_free (ThreadClosure, closure);
}
g_return_if_fail (object_path != NULL);
g_return_if_fail (E_IS_SOURCE (source));
- g_mutex_lock (registry->priv->object_path_table_lock);
+ g_mutex_lock (®istry->priv->object_path_table_lock);
g_hash_table_insert (
registry->priv->object_path_table,
g_strdup (object_path),
g_object_ref (source));
- g_mutex_unlock (registry->priv->object_path_table_lock);
+ g_mutex_unlock (®istry->priv->object_path_table_lock);
}
static ESource *
g_return_val_if_fail (object_path != NULL, NULL);
- g_mutex_lock (registry->priv->object_path_table_lock);
+ g_mutex_lock (®istry->priv->object_path_table_lock);
source = g_hash_table_lookup (
registry->priv->object_path_table, object_path);
if (source != NULL)
g_object_ref (source);
- g_mutex_unlock (registry->priv->object_path_table_lock);
+ g_mutex_unlock (®istry->priv->object_path_table_lock);
return source;
}
g_return_val_if_fail (object_path != NULL, FALSE);
- g_mutex_lock (registry->priv->object_path_table_lock);
+ g_mutex_lock (®istry->priv->object_path_table_lock);
removed = g_hash_table_remove (
registry->priv->object_path_table, object_path);
- g_mutex_unlock (registry->priv->object_path_table_lock);
+ g_mutex_unlock (®istry->priv->object_path_table_lock);
return removed;
}
uid = e_source_get_uid (source);
g_return_if_fail (uid != NULL);
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
g_hash_table_insert (
registry->priv->sources,
g_strdup (uid), g_object_ref (source));
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
}
static gboolean
uid = e_source_get_uid (source);
g_return_val_if_fail (uid != NULL, FALSE);
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
removed = g_hash_table_remove (registry->priv->sources, uid);
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
return removed;
}
g_return_val_if_fail (uid != NULL, NULL);
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
source = g_hash_table_lookup (registry->priv->sources, uid);
if (source != NULL)
g_object_ref (source);
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
return source;
}
{
GList *values;
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
values = g_hash_table_get_values (registry->priv->sources);
g_list_foreach (values, (GFunc) g_object_ref, NULL);
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
return values;
}
GHashTableIter iter;
gpointer key, value;
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
root = g_node_new (NULL);
index = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_destroy (index);
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
return root;
}
{
const gchar *uid;
+ /* This is called in the manager thread during initialization
+ * and in response to "object-added" signals from the manager. */
+
uid = e_source_get_uid (source);
g_return_if_fail (uid != NULL);
- g_mutex_lock (registry->priv->sources_lock);
+ g_mutex_lock (®istry->priv->sources_lock);
/* Check if we already have this source in the registry. */
if (g_hash_table_lookup (registry->priv->sources, uid) != NULL) {
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
return;
}
G_CALLBACK (source_registry_source_notify_enabled_cb),
registry);
- g_mutex_unlock (registry->priv->sources_lock);
+ g_mutex_unlock (®istry->priv->sources_lock);
source_registry_sources_insert (registry, source);
-
- g_signal_emit (registry, signals[SOURCE_ADDED], 0, source);
-}
-
-static void
-source_registry_remove_source (ESourceRegistry *registry,
- ESource *source)
-{
- g_object_ref (source);
-
- if (source_registry_sources_remove (registry, source))
- g_signal_emit (registry, signals[SOURCE_REMOVED], 0, source);
-
- g_object_unref (source);
}
static gboolean
source_registry_object_added_idle_cb (gpointer user_data)
{
SourceClosure *closure = user_data;
+ ESourceRegistry *registry = closure->registry;
+ ESource *source = closure->source;
- source_registry_add_source (closure->registry, closure->source);
+ g_signal_emit (registry, signals[SOURCE_ADDED], 0, source);
return FALSE;
}
source = source_registry_new_source (registry, dbus_object);
g_return_if_fail (source != NULL);
+ /* Add the new ESource to our internal hash table so it can be
+ * obtained through e_source_registry_ref_source() immediately. */
+ source_registry_add_source (registry, source);
+
/* Schedule a callback on the ESourceRegistry's GMainContext. */
closure = g_slice_new0 (SourceClosure);
source_registry_object_removed_idle_cb (gpointer user_data)
{
SourceClosure *closure = user_data;
+ ESourceRegistry *registry = closure->registry;
+ ESource *source = closure->source;
- source_registry_remove_source (closure->registry, closure->source);
+ /* Removing the ESource won't finalize it because the
+ * SourceClosure itself still holds a reference on it. */
+ if (source_registry_sources_remove (registry, source))
+ g_signal_emit (registry, signals[SOURCE_REMOVED], 0, source);
return FALSE;
}
{
ThreadClosure *closure = data;
- g_mutex_lock (closure->main_loop_mutex);
- g_cond_broadcast (closure->main_loop_cond);
- g_mutex_unlock (closure->main_loop_mutex);
+ g_mutex_lock (&closure->main_loop_mutex);
+ g_cond_broadcast (&closure->main_loop_cond);
+ g_mutex_unlock (&closure->main_loop_mutex);
return FALSE;
}
ThreadClosure *closure = data;
GSource *idle_source;
GList *list, *link;
- gulong object_added_id;
- gulong object_removed_id;
- GError *error = NULL;
+ gulong object_added_id = 0;
+ gulong object_removed_id = 0;
/* GDBusObjectManagerClient grabs the thread-default GMainContext
* at creation time and only emits signals from that GMainContext.
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
SOURCES_DBUS_SERVICE_NAME,
DBUS_OBJECT_PATH,
- NULL, &error);
+ NULL, &closure->error);
- /* If this fails there's really no point in continuing
- * since we rely on the object manager to populate the
- * registry. Abort the process with a fatal error. */
- if (error != NULL) {
- g_error ("%s", error->message);
- g_assert_not_reached ();
- }
+ /* Sanity check. */
+ g_warn_if_fail (
+ ((object_manager != NULL) && (closure->error == NULL)) ||
+ ((object_manager == NULL) && (closure->error != NULL)));
+
+ /* If we failed to create the GDBusObjectManagerClient, skip
+ * straight to the main loop. The GError will be propagated
+ * back to the caller, the main loop will terminate, and the
+ * partially-initialized ESourceRegistry will be destroyed. */
+ if (object_manager == NULL)
+ goto notify;
/* Give the registry a handle to the object manager. */
closure->registry->priv->dbus_object_manager =
g_list_free_full (list, (GDestroyNotify) g_object_unref);
- /* Schedule a one-time idle callback to broadcast through a
- * condition variable that our main loop is up and running. */
-
- idle_source = g_idle_source_new ();
- g_source_set_callback (
- idle_source,
- source_registry_object_manager_running,
- closure, (GDestroyNotify) NULL);
- g_source_attach (idle_source, closure->main_context);
- g_source_unref (idle_source);
-
/* Listen for D-Bus object additions and removals. */
object_added_id = g_signal_connect (
G_CALLBACK (source_registry_object_removed_cb),
closure->registry);
+notify:
+ /* Schedule a one-time idle callback to broadcast through a
+ * condition variable that our main loop is up and running. */
+
+ idle_source = g_idle_source_new ();
+ g_source_set_callback (
+ idle_source,
+ source_registry_object_manager_running,
+ closure, (GDestroyNotify) NULL);
+ g_source_attach (idle_source, closure->main_context);
+ g_source_unref (idle_source);
+
/* Now we mostly idle here for the rest of the session. */
g_main_loop_run (closure->main_loop);
/* Clean up and exit. */
- g_signal_handler_disconnect (object_manager, object_added_id);
- g_signal_handler_disconnect (object_manager, object_removed_id);
-
- g_object_unref (object_manager);
+ if (object_manager != NULL) {
+ g_signal_handler_disconnect (object_manager, object_added_id);
+ g_signal_handler_disconnect (object_manager, object_removed_id);
+ g_object_unref (object_manager);
+ }
g_main_context_pop_thread_default (closure->main_context);
g_hash_table_remove_all (priv->sources);
if (priv->settings != NULL) {
+ g_signal_handlers_disconnect_by_data (priv->settings, object);
g_object_unref (priv->settings);
priv->settings = NULL;
}
priv = E_SOURCE_REGISTRY_GET_PRIVATE (object);
g_hash_table_destroy (priv->object_path_table);
- g_mutex_free (priv->object_path_table_lock);
+ g_mutex_clear (&priv->object_path_table_lock);
g_hash_table_destroy (priv->sources);
- g_mutex_free (priv->sources_lock);
+ g_mutex_clear (&priv->sources_lock);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_source_registry_parent_class)->finalize (object);
* we wait for the main loop to start running as a way of
* synchronizing with the manager thread. */
closure->main_loop = g_main_loop_new (closure->main_context, FALSE);
- closure->main_loop_cond = g_cond_new ();
- closure->main_loop_mutex = g_mutex_new ();
+ g_cond_init (&closure->main_loop_cond);
+ g_mutex_init (&closure->main_loop_mutex);
registry->priv->thread_closure = closure;
- registry->priv->manager_thread = g_thread_create (
+ registry->priv->manager_thread = g_thread_new (
+ NULL,
source_registry_object_manager_thread,
- closure, TRUE /* joinable */, error);
+ closure);
if (registry->priv->manager_thread == NULL)
return FALSE;
/* Wait for notification that the manager
* thread's main loop has been started. */
- g_mutex_lock (closure->main_loop_mutex);
+ g_mutex_lock (&closure->main_loop_mutex);
while (!g_main_loop_is_running (closure->main_loop))
g_cond_wait (
- closure->main_loop_cond,
- closure->main_loop_mutex);
- g_mutex_unlock (closure->main_loop_mutex);
-
- /* We should now have a GDBusObjectManagerClient available. */
- g_return_val_if_fail (
- G_IS_DBUS_OBJECT_MANAGER_CLIENT (
- registry->priv->dbus_object_manager), FALSE);
+ &closure->main_loop_cond,
+ &closure->main_loop_mutex);
+ g_mutex_unlock (&closure->main_loop_mutex);
+
+ /* Check for error in the manager thread. */
+ if (closure->error != NULL) {
+ g_propagate_error (error, closure->error);
+ closure->error = NULL;
+ return FALSE;
+ }
- /* The registry should now be populated with sources. */
- g_warn_if_fail (g_hash_table_size (registry->priv->sources) > 0);
+ /* The registry should now be populated with sources.
+ *
+ * XXX Actually, not necessarily if the registry service was
+ * just now activated. There may yet be a small window
+ * while the registry service starts up before it exports
+ * any sources, even built-in sources. This COULD create
+ * problems if any logic that depends on those built-in
+ * sources executes during this time window, but so far
+ * we haven't seen any cases of that.
+ *
+ * Attempts in the past to stop and wait for sources to
+ * show up have proven problematic. See for example:
+ * https://bugzilla.gnome.org/678378
+ *
+ * Leave the runtime check disabled for the moment.
+ * I have a feeling I'll be revisiting this again.
+ */
+ /*g_warn_if_fail (g_hash_table_size (registry->priv->sources) > 0);*/
/* The EDBusSourceManagerProxy is just another D-Bus interface
* that resides at the same object path. It's unrelated to the
if (registry->priv->dbus_source_manager == NULL)
return FALSE;
+ /* Allow authentication prompts for all exported data sources
+ * when a new EDBusSourceManagerProxy is created. The thought
+ * being, if you cancel an authentication prompt you will not
+ * be bothered again until you start (or restart) a new E-D-S
+ * client app. Failure here is non-fatal, ignore errors. */
+ e_dbus_source_manager_call_allow_auth_prompt_all_sync (
+ registry->priv->dbus_source_manager, cancellable, NULL);
+
return TRUE;
}
(GDestroyNotify) g_free,
(GDestroyNotify) g_object_unref);
- registry->priv->object_path_table_lock = g_mutex_new ();
+ g_mutex_init (®istry->priv->object_path_table_lock);
/* UID string -> ESource */
registry->priv->sources = g_hash_table_new_full (
(GDestroyNotify) g_free,
(GDestroyNotify) source_registry_unref_source);
- registry->priv->sources_lock = g_mutex_new ();
+ g_mutex_init (®istry->priv->sources_lock);
registry->priv->settings = g_settings_new (GSETTINGS_SCHEMA);
e_source_registry_new_sync (GCancellable *cancellable,
GError **error)
{
+ /* XXX Work around http://bugzilla.gnome.org/show_bug.cgi?id=683519
+ * until GObject's type initialization deadlock issue is fixed.
+ * Apparently only the synchronous instantiation is affected. */
+ g_type_ensure (G_TYPE_DBUS_CONNECTION);
+
return g_initable_new (
E_TYPE_SOURCE_REGISTRY,
cancellable, error, NULL);
* session will either time out on its own or the authentication
* dialog will eventually be dismissed by the user. */
+ /* If we were cancelled from our side, we have a bit of a dilemma.
+ * We need to tell the server to cancel the authentication session,
+ * but that involves making a synchronous D-Bus call, which we are
+ * not supposed to do if we know we've been cancelled. But if we
+ * don't tell the server, the authentication session will be left
+ * to timeout on its own (which may take minutes), and meanwhile
+ * all other authentication requests are blocked. So choose the
+ * lesser evil and make the synchronous call but without passing
+ * the already-cancelled GCancellable. */
+ if (g_cancellable_is_cancelled (auth_context->cancellable)) {
+ e_dbus_authenticator_call_cancel_sync (
+ auth_context->dbus_auth,
+ NULL, &non_fatal_error);
+ g_main_loop_quit (auth_context->main_loop);
+ auth_context->success = FALSE;
+
/* If an error occurred while attempting to authenticate,
* tell the server to cancel the authentication session. */
- if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
+ } else if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
e_dbus_authenticator_call_cancel_sync (
auth_context->dbus_auth,
auth_context->cancellable,
exit:
g_main_context_pop_thread_default (main_context);
+
+ /* Make sure the main_context doesn't have pending operations;
+ workarounds https://bugzilla.gnome.org/show_bug.cgi?id=690126 */
+ while (g_main_context_pending (main_context))
+ g_main_context_iteration (main_context, FALSE);
+
g_main_context_unref (main_context);
return success;
*
* If @source does NOT have a #GDBusObject (implying it's a scratch
* #ESource), its contents are submitted to the D-Bus service through
- * e_source_registry_create_sources_sync().
+ * either e_source_remote_create_sync() if @source is to be a collection
+ * member, or e_source_registry_create_sources_sync() if @source to be an
+ * independent data source.
*
* If an error occurs, the function will set @error and return %FALSE.
*
GError **error)
{
GDBusObject *dbus_object;
+ ESource *collection_source;
+ gboolean collection_member;
gboolean success;
g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
dbus_object = e_source_ref_dbus_object (source);
+ collection_source = e_source_registry_find_extension (
+ registry, source, E_SOURCE_EXTENSION_COLLECTION);
+
+ collection_member =
+ (collection_source != NULL) &&
+ (collection_source != source);
+
if (dbus_object != NULL) {
success = e_source_write_sync (source, cancellable, error);
g_object_unref (dbus_object);
+
+ } else if (collection_member) {
+ success = e_source_remote_create_sync (
+ collection_source, source, cancellable, error);
+
} else {
GList *list = g_list_prepend (NULL, source);
success = e_source_registry_create_sources_sync (
g_list_free (list);
}
+ if (collection_source != NULL)
+ g_object_unref (collection_source);
+
return success;
}
g_simple_async_result_take_error (simple, error);
}
+/* Helper for e_source_registry_create_sources_sync() */
+static gboolean
+source_registry_create_sources_main_loop_quit_cb (gpointer user_data)
+{
+ GMainLoop *main_loop = user_data;
+
+ g_main_loop_quit (main_loop);
+
+ return FALSE;
+}
+
+/* Helper for e_source_registry_create_sources_sync() */
+static void
+source_registry_create_sources_object_added_cb (GDBusObjectManager *object_manager,
+ GDBusObject *dbus_object,
+ CreateContext *create_context)
+{
+ EDBusObject *e_dbus_object;
+ EDBusSource *e_dbus_source;
+ const gchar *uid;
+
+ e_dbus_object = E_DBUS_OBJECT (dbus_object);
+ e_dbus_source = e_dbus_object_get_source (e_dbus_object);
+ uid = e_dbus_source_get_uid (e_dbus_source);
+
+ g_hash_table_remove (create_context->pending_uids, uid);
+
+ /* The hash table will be empty when all of the expected
+ * GDBusObjects have been added to the GDBusObjectManager. */
+ if (g_hash_table_size (create_context->pending_uids) == 0) {
+ GSource *idle_source;
+
+ idle_source = g_idle_source_new ();
+ g_source_set_callback (
+ idle_source,
+ source_registry_create_sources_main_loop_quit_cb,
+ g_main_loop_ref (create_context->main_loop),
+ (GDestroyNotify) g_main_loop_unref);
+ g_source_attach (idle_source, create_context->main_context);
+ g_source_unref (idle_source);
+ }
+}
+
/**
* e_source_registry_create_sources_sync:
* @registry: an #ESourceRegistry
GCancellable *cancellable,
GError **error)
{
+ CreateContext *create_context;
GVariantBuilder builder;
GVariant *variant;
GList *link;
+ gulong object_added_id;
gboolean success;
g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
for (link = list_of_sources; link != NULL; link = g_list_next (link))
g_return_val_if_fail (E_IS_SOURCE (link->data), FALSE);
+ create_context = create_context_new ();
+ g_main_context_push_thread_default (create_context->main_context);
+
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
for (link = list_of_sources; link != NULL; link = g_list_next (link)) {
ESource *source;
- const gchar *uid;
gchar *source_data;
+ gchar *uid;
source = E_SOURCE (link->data);
- uid = e_source_get_uid (source);
+ uid = e_source_dup_uid (source);
+
+ /* Takes ownership of the UID string. */
+ g_hash_table_add (create_context->pending_uids, uid);
source_data = e_source_to_string (source, NULL);
g_variant_builder_add (&builder, "{ss}", uid, source_data);
variant = g_variant_builder_end (&builder);
+ /* Use G_CONNECT_AFTER so source_registry_object_added_cb()
+ * runs first and actually adds the ESource to the internal
+ * hash table before we go quitting our main loop. */
+ object_added_id = g_signal_connect_after (
+ registry->priv->dbus_object_manager, "object-added",
+ G_CALLBACK (source_registry_create_sources_object_added_cb),
+ create_context);
+
/* This function sinks the floating GVariant reference. */
success = e_dbus_source_manager_call_create_sources_sync (
registry->priv->dbus_source_manager,
g_variant_builder_clear (&builder);
+ /* Wait for an "object-added" signal for each created ESource.
+ * But also set a short timeout to avoid getting stuck here in
+ * case the registry service adds sources to its orphan table,
+ * which prevents them from being exported over D-Bus. */
+ if (success) {
+ GSource *timeout_source;
+
+ timeout_source = g_timeout_source_new_seconds (2);
+ g_source_set_callback (
+ timeout_source,
+ source_registry_create_sources_main_loop_quit_cb,
+ g_main_loop_ref (create_context->main_loop),
+ (GDestroyNotify) g_main_loop_unref);
+ g_source_attach (timeout_source, create_context->main_context);
+ g_source_unref (timeout_source);
+
+ g_main_loop_run (create_context->main_loop);
+ }
+
+ g_signal_handler_disconnect (
+ registry->priv->dbus_object_manager, object_added_id);
+
+ g_main_context_pop_thread_default (create_context->main_context);
+ create_context_free (create_context);
+
return success;
}
}
/**
+ * e_source_registry_check_enabled:
+ * @registry: an #ESourceRegistry
+ * @source: an #ESource
+ *
+ * Determines whether @source is "effectively" enabled by examining its
+ * own #ESource:enabled property as well as those of its ancestors in the
+ * #ESource hierarchy. If all examined #ESource:enabled properties are
+ * %TRUE, then the function returns %TRUE. If any are %FALSE, then the
+ * function returns %FALSE.
+ *
+ * Use this function instead of e_source_get_enabled() to determine
+ * things like whether to display an #ESource in a user interface or
+ * whether to act on the data set described by the #ESource.
+ *
+ * Returns: whether @source is "effectively" enabled
+ *
+ * Since: 3.8
+ **/
+gboolean
+e_source_registry_check_enabled (ESourceRegistry *registry,
+ ESource *source)
+{
+ gboolean enabled;
+ gchar *parent_uid;
+
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+ g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+ enabled = e_source_get_enabled (source);
+ parent_uid = e_source_dup_parent (source);
+
+ while (enabled && parent_uid != NULL) {
+ ESource *parent;
+
+ parent = e_source_registry_ref_source (registry, parent_uid);
+
+ g_free (parent_uid);
+ parent_uid = NULL;
+
+ if (parent != NULL) {
+ enabled = e_source_get_enabled (parent);
+ parent_uid = e_source_dup_parent (parent);
+ g_object_unref (parent);
+ }
+ }
+
+ g_free (parent_uid);
+
+ return enabled;
+}
+
+/**
* e_source_registry_find_extension:
* @registry: an #ESourceRegistry
* @source: an #ESource
uid = E_SOURCE_BUILTIN_ADDRESS_BOOK_UID;
source = e_source_registry_ref_source (registry, uid);
- g_return_val_if_fail (source != NULL, NULL);
return source;
}
source = e_source_registry_ref_source (registry, uid);
g_free (uid);
- /* The built-in source is always present. */
+ /* The built-in source is present in normal EDS installations. */
if (source == NULL)
source = e_source_registry_ref_builtin_address_book (registry);
- g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
return source;
}
uid = E_SOURCE_BUILTIN_CALENDAR_UID;
source = e_source_registry_ref_source (registry, uid);
- g_return_val_if_fail (source != NULL, NULL);
return source;
}
source = e_source_registry_ref_source (registry, uid);
g_free (uid);
- /* The built-in source is always present. */
+ /* The built-in source is present in normal EDS installations. */
if (source == NULL)
source = e_source_registry_ref_builtin_calendar (registry);
- g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
return source;
}
for (link = list; link != NULL; link = g_list_next (link)) {
ESource *candidate = E_SOURCE (link->data);
- if (e_source_get_enabled (candidate)) {
+ if (e_source_registry_check_enabled (registry, candidate)) {
source = g_object_ref (candidate);
break;
}
}
if (source == NULL && list != NULL)
- source = g_object_ref (link->data);
+ source = g_object_ref (list->data);
g_list_free_full (list, (GDestroyNotify) g_object_unref);