下面相关代码主要功能是:
在网络连接时,evolution发出准备联接信号,前端通知后端evolution-data-server进行长时逻辑,待后端逻辑处理完成后,前端收尾函数被自动调用。
这段代码主要几个知识点:
1.使用GSimpleAsyncResult进行异步操作。
2.使用g_object_add_toggle_ref进行引用趋势判断。由于前端无法知道evolution-data-server何时处理完成,并且不知道对应object会被多少后端逻辑进行引用。所以需要使用g_object_add_toggle_ref函数,当最后一个引用使用完成后,自动触发相关的收尾操作。
前端:
shell/e-shell.c:
static void
shell_prepare_for_online (EShell *shell)
{
/* Are preparations already in progress? */
if (shell->priv->preparing_for_line_change != NULL)
return;
shell->priv->preparing_for_line_change = e_activity_new ();
e_activity_set_text (
shell->priv->preparing_for_line_change,
_("Preparing to go online..."));
// 对preparing_for_line_change引用加一
// 并且在对象最后一次被引用(引用计数从n到1)或者最后一次引用后被其他函数引用(引用计数从1到n)时
// 调用回调 shell_ready_for_online
g_object_add_toggle_ref (
G_OBJECT (shell->priv->preparing_for_line_change),
(GToggleNotify) shell_ready_for_online, shell);
g_object_add_weak_pointer (
G_OBJECT (shell->priv->preparing_for_line_change),
&shell->priv->preparing_for_line_change);
// 通知后端进行长时逻辑操作
g_signal_emit (
shell, signals[PREPARE_FOR_ONLINE], 0,
shell->priv->preparing_for_line_change);
g_object_unref (shell->priv->preparing_for_line_change);
}
static void
shell_ready_for_online (EShell *shell,
EActivity *activity,
gboolean is_last_ref)
{
// 引用从n到1 is_last_ref = true
// 引用从1到n is_last_ref = false
if (!is_last_ref)
return;
// 引用为1,说明后端操作结束,前端准备发出信号并进行收尾
/* Increment the reference count so we can safely emit
* a signal without triggering the toggle reference. */
g_object_ref (activity);
e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
g_object_remove_toggle_ref (
G_OBJECT (activity), (GToggleNotify)
shell_ready_for_online, shell);
/* Finalize the activity. */
g_object_unref (activity);
shell->priv->online = TRUE;
g_object_notify (G_OBJECT (shell), "online");
}
后端:
mail/e-mail-backend.c:
// 后端关联信号进行长时操作
g_signal_connect (
shell, "prepare-for-online",
G_CALLBACK (mail_backend_prepare_for_online_cb),
shell_backend);
static void
mail_backend_prepare_for_online_cb (EShell *shell,
EActivity *activity,
EMailBackend *backend)
{
...
// 对于标志activity引用+1
// 当 e_mail_store_go_online长时操作结束后,自动调用mail_backend_store_operation_done_cb进行引用-1
/* FIXME Not passing a GCancellable. */
e_mail_store_go_online (
CAMEL_STORE (service), G_PRIORITY_DEFAULT,
NULL, (GAsyncReadyCallback)
mail_backend_store_operation_done_cb,
g_object_ref (activity));
...
}
/* Callback for various asynchronous CamelStore operations where
* the EActivity's reference count is used as a counting semaphore. */
static void
mail_backend_store_operation_done_cb (CamelStore *store,
GAsyncResult *result,
EActivity *activity)
{
/* FIXME Not checking result for error. To fix this, we need
* separate callbacks to call different finish functions
* and then submit an EAlert on error. */
g_object_unref (activity);
}
libemail-engine/e-mail-store-utils.c:
void
e_mail_store_go_online (CamelStore *store,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
g_return_if_fail (CAMEL_IS_STORE (store));
// 新建异步操作对象,设定操作结束后自动调用callback函数
simple = g_simple_async_result_new (
G_OBJECT (store), callback,
user_data, e_mail_store_go_online);
// 使用新线程进行长时操作mail_store_go_online_thread
// 当mail_store_go_online_thread结束后自动调用 GAsyncReadyCallback callback
g_simple_async_result_run_in_thread (
simple, (GSimpleAsyncThreadFunc)
mail_store_go_online_thread,
io_priority, cancellable);
g_object_unref (simple);
}
static void
mail_store_go_online_thread (GSimpleAsyncResult *simple,
CamelStore *store,
GCancellable *cancellable)
{
// 下面是长时操作
CamelService *service;
const gchar *display_name;
GError *error = NULL;
service = CAMEL_SERVICE (store);
display_name = camel_service_get_display_name (service);
if (display_name == NULL || *display_name == '\0')
display_name = G_OBJECT_TYPE_NAME (service);
camel_operation_push_message (
cancellable, _("Reconnecting to '%s'"), display_name);
if (CAMEL_IS_DISCO_STORE (store))
camel_disco_store_set_status (
CAMEL_DISCO_STORE (store),
CAMEL_DISCO_STORE_ONLINE,
cancellable, &error);
else if (CAMEL_IS_OFFLINE_STORE (store))
camel_offline_store_set_online_sync (
CAMEL_OFFLINE_STORE (store),
TRUE, cancellable, &error);
if (error != NULL)
g_simple_async_result_take_error (simple, error);
camel_operation_pop_message (cancellable);
}