From 01207c3c8ed00e6de1d66901b257bf3ffee7d350 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 12 Apr 2013 13:05:32 -0400 Subject: ECalModel: Give ClientData a reference count. Adds some private ECalModel functions: client_data_new() client_data_ref() client_data_unref() --- calendar/gui/e-cal-model.c | 246 ++++++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 103 deletions(-) (limited to 'calendar/gui') diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c index 73b569a776..db641278d6 100644 --- a/calendar/gui/e-cal-model.c +++ b/calendar/gui/e-cal-model.c @@ -54,11 +54,15 @@ struct _ECalModelComponentPrivate { ((obj), E_TYPE_CAL_MODEL_COMPONENT, ECalModelComponentPrivate)) struct _ClientData { + volatile gint ref_count; + GWeakRef model; ECalClient *client; - ECalClientView *view; gboolean do_query; + ECalClientView *view; GCancellable *cancellable; + + gulong backend_died_handler_id; }; struct _ECalModelPrivate { @@ -148,8 +152,7 @@ static gchar *ecm_value_to_string (ETableModel *etm, gint col, gconstpointer val static const gchar *ecm_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data); -static ClientData *add_new_client (ECalModel *model, ECalClient *client, gboolean do_query); -static ClientData *find_client_data (ECalModel *model, ECalClient *client); +static void add_new_client (ECalModel *model, ECalClient *client, gboolean do_query); static void remove_client_objects (ECalModel *model, ClientData *client_data); static void remove_client (ECalModel *model, ClientData *client_data); static void redo_queries (ECalModel *model); @@ -201,6 +204,105 @@ G_DEFINE_TYPE ( e_cal_model_component, G_TYPE_OBJECT) +static void +client_data_backend_died_cb (ECalClient *client, + ClientData *client_data) +{ + ECalModel *model; + + model = g_weak_ref_get (&client_data->model); + if (model != NULL) { + e_cal_model_remove_client (model, client); + g_object_unref (model); + } +} + +static ClientData * +client_data_new (ECalModel *model, + ECalClient *client, + gboolean do_query) +{ + ClientData *client_data; + gulong handler_id; + + client_data = g_slice_new0 (ClientData); + client_data->ref_count = 1; + g_weak_ref_set (&client_data->model, model); + client_data->client = g_object_ref (client); + client_data->do_query = do_query; + + handler_id = g_signal_connect ( + client_data->client, "backend-died", + G_CALLBACK (client_data_backend_died_cb), client_data); + client_data->backend_died_handler_id = handler_id; + + return client_data; +} + +static ClientData * +client_data_ref (ClientData *client_data) +{ + g_return_val_if_fail (client_data != NULL, NULL); + g_return_val_if_fail (client_data->ref_count > 0, NULL); + + g_atomic_int_inc (&client_data->ref_count); + + return client_data; +} + +static void +client_data_unref (ClientData *client_data) +{ + g_return_if_fail (client_data != NULL); + g_return_if_fail (client_data->ref_count > 0); + + if (g_atomic_int_dec_and_test (&client_data->ref_count)) { + ECalModel *model; + + g_signal_handler_disconnect ( + client_data->client, + client_data->backend_died_handler_id); + + model = g_weak_ref_get (&client_data->model); + if (model != NULL) { + if (client_data->view != NULL) + g_signal_handlers_disconnect_matched ( + client_data->view, + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, model); + g_object_unref (model); + } + + g_weak_ref_set (&client_data->model, NULL); + g_clear_object (&client_data->client); + g_clear_object (&client_data->view); + g_clear_object (&client_data->cancellable); + + g_slice_free (ClientData, client_data); + } +} + +static ClientData * +cal_model_ref_client_data (ECalModel *model, + ECalClient *client) +{ + GList *head, *link; + + head = g_queue_peek_head_link (&model->priv->clients); + + for (link = head; link != NULL; link = g_list_next (link)) { + ClientData *client_data; + + client_data = (ClientData *) link->data; + g_return_val_if_fail (client_data != NULL, NULL); + + if (client_data->client == client) + return client_data_ref (client_data); + } + + return NULL; +} + static void cal_model_set_registry (ECalModel *model, ESourceRegistry *registry) @@ -540,28 +642,8 @@ cal_model_dispose (GObject *object) priv->loading_clients = NULL; } - while (!g_queue_is_empty (&priv->clients)) { - ClientData *client_data; - - client_data = g_queue_pop_head (&priv->clients); - - g_signal_handlers_disconnect_matched ( - client_data->client, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - if (client_data->view) - g_signal_handlers_disconnect_matched ( - client_data->view, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - - g_object_unref (client_data->client); - if (client_data->cancellable) { - g_cancellable_cancel (client_data->cancellable); - g_object_unref (client_data->cancellable); - } - if (client_data->view) - g_object_unref (client_data->view); - g_free (client_data); - } + while (!g_queue_is_empty (&priv->clients)) + client_data_unref (g_queue_pop_head (&priv->clients)); priv->default_client = NULL; @@ -2433,7 +2515,6 @@ e_cal_model_set_default_client (ECalModel *model, ECalClient *client) { ECalModelPrivate *priv; - ClientData *client_data; g_return_if_fail (E_IS_CAL_MODEL (model)); @@ -2445,24 +2526,27 @@ e_cal_model_set_default_client (ECalModel *model, if (priv->default_client == client) return; - if (priv->default_client) { - client_data = find_client_data (model, priv->default_client); - if (!client_data) { - g_warning ("client_data is NULL\n"); - } else { + if (priv->default_client == NULL) { + ClientData *client_data; + + client_data = cal_model_ref_client_data ( + model, priv->default_client); + if (client_data != NULL) { if (!client_data->do_query) remove_client (model, client_data); + client_data_unref (client_data); } } if (client != NULL) { /* Make sure its in the model */ - client_data = add_new_client (model, client, FALSE); + add_new_client (model, client, FALSE); /* Store the default client */ - priv->default_client = client_data->client; - } else + priv->default_client = client; + } else { priv->default_client = NULL; + } g_object_notify (G_OBJECT (model), "default-client"); } @@ -2532,27 +2616,6 @@ e_cal_model_get_client_for_source (ECalModel *model, return NULL; } -static ClientData * -find_client_data (ECalModel *model, - ECalClient *client) -{ - GList *head, *link; - - head = g_queue_peek_head_link (&model->priv->clients); - - for (link = head; link != NULL; link = g_list_next (link)) { - ClientData *client_data; - - client_data = (ClientData *) link->data; - g_return_val_if_fail (client_data != NULL, NULL); - - if (client_data->client == client) - return client_data; - } - - return NULL; -} - static ECalModelComponent * search_by_id_and_client (ECalModelPrivate *priv, ECalClient *client, @@ -2797,9 +2860,11 @@ process_added (ECalClientView *view, ensure_dates_are_in_default_zone (model, l->data); if (e_cal_util_component_has_recurrences (l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) { - ClientData *client_data = find_client_data (model, client); + ClientData *client_data; - if (client_data) { + client_data = cal_model_ref_client_data (model, client); + + if (client_data != NULL) { RecurrenceExpansionData *rdata = g_new0 (RecurrenceExpansionData, 1); rdata->client = g_object_ref (client); rdata->view = g_object_ref (view); @@ -2807,6 +2872,8 @@ process_added (ECalClientView *view, e_cal_client_generate_instances_for_object (rdata->client, l->data, priv->start, priv->end, client_data->cancellable, (ECalRecurInstanceFn) add_instance_cb, rdata, free_rdata); + + client_data_unref (client_data); } } else { e_table_model_pre_change (E_TABLE_MODEL (model)); @@ -3277,57 +3344,33 @@ e_cal_model_update_status_message (ECalModel *model, } static void -backend_died_cb (ECalClient *client, - gpointer user_data) -{ - ECalModel *model; - - model = E_CAL_MODEL (user_data); - - e_cal_model_remove_client (model, client); -} - -static ClientData * add_new_client (ECalModel *model, ECalClient *client, gboolean do_query) { - ECalModelPrivate *priv; ClientData *client_data; - - priv = model->priv; - - /* DEBUG the load state should always be loaded here - if (e_cal_get_load_state (client) != E_CAL_LOAD_LOADED) { - g_assert_not_reached (); - } */ + gboolean update_view = TRUE; /* Look to see if we already have this client */ - client_data = find_client_data (model, client); - if (client_data) { + client_data = cal_model_ref_client_data (model, client); + if (client_data != NULL) { if (client_data->do_query) - return client_data; + update_view = FALSE; else client_data->do_query = do_query; - goto load; - } - - client_data = g_new0 (ClientData, 1); - client_data->client = g_object_ref (client); - client_data->view = NULL; - client_data->do_query = do_query; - - g_queue_push_tail (&priv->clients, client_data); + } else { + client_data = client_data_new (model, client, do_query); - g_signal_connect ( - client_data->client, "backend-died", - G_CALLBACK (backend_died_cb), model); + g_queue_push_tail ( + &model->priv->clients, + client_data_ref (client_data)); + } - load: - update_e_cal_view_for_client (model, client_data); + if (update_view) + update_e_cal_view_for_client (model, client_data); - return client_data; + client_data_unref (client_data); } /** @@ -3398,13 +3441,8 @@ remove_client (ECalModel *model, model->priv->default_client = NULL; /* Remove the client from the queue. */ - g_queue_remove (&model->priv->clients, client_data); - - /* free all remaining memory */ - g_object_unref (client_data->client); - if (client_data->view) - g_object_unref (client_data->view); - g_free (client_data); + if (g_queue_remove (&model->priv->clients, client_data)) + client_data_unref (client_data); } /** @@ -3419,9 +3457,11 @@ e_cal_model_remove_client (ECalModel *model, g_return_if_fail (E_IS_CAL_MODEL (model)); g_return_if_fail (E_IS_CAL_CLIENT (client)); - client_data = find_client_data (model, client); - if (client_data) + client_data = cal_model_ref_client_data (model, client); + if (client_data != NULL) { remove_client (model, client_data); + client_data_unref (client_data); + } } /** -- cgit v1.2.3