diff options
-rw-r--r-- | calendar/ChangeLog | 30 | ||||
-rw-r--r-- | calendar/pcs/query.c | 67 |
2 files changed, 72 insertions, 25 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 067afc7e8a..ac5fdd96fa 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,33 @@ +2001-11-09 Federico Mena Quintero <federico@ximian.com> + + (committed by Damon) + + Fix bug #14699. + + * pcs/query.c (QueryState): Added a state QUERY_WAIT_FOR_BACKEND + to indicate that the query is not populated as we are waiting for + the backend to be opened. + (query_init): Start in the QUERY_WAIT_FOR_BACKEND state. + (query_destroy): Only disconnect from the backend if we are in a + state that implies that we are connected to its signals. + (query_construct): If the backend is already loaded, immediately + set the state to QUERY_START_PENDING. + (backend_opened_cb): Disconnect from the backend's "opened" + signal. Set the state to QUERY_START_PENDING. + (match_component): We can now only match components if the query + is in progress or if it is done. Assert to that effect, and do + not ensure_sexp(). + (match_component): Do not check for a nonexistent component using + g_return_if_fail(). Also, there is no need to ref/unref the + component. + (backend_obj_updated_cb): Assert to the effect of our state. + (backend_obj_removed_cb): Likewise. + (parse_sexp): Renamed from ensure_sexp(). Assert that the query + has not started. Do not disconnect from the backend's signals + here, since we have no connections. + (start_query_cb): Set the state to QUERY_IN_PROGRESS here instead + of in populate_query(). + 2001-12-07 Rodrigo Moya <rodrigo@ximian.com> * gui/calendar-config.c (calendar_config_get_default_uri): diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index 33289ed107..bf008ab655 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -38,7 +38,8 @@ /* States of a query */ typedef enum { - QUERY_START_PENDING, /* the query is not populated yet */ + QUERY_WAIT_FOR_BACKEND, /* the query is not populated and the backend is not loaded */ + QUERY_START_PENDING, /* the query is not populated yet, but the backend is loaded */ QUERY_IN_PROGRESS, /* the query is populated; components are still being processed */ QUERY_DONE, /* the query is done, but still accepts object changes */ QUERY_PARSE_ERROR /* a parse error occurred when initially creating the ESexp */ @@ -124,7 +125,7 @@ query_init (Query *query) priv->sexp = NULL; priv->idle_id = 0; - priv->state = QUERY_START_PENDING; + priv->state = QUERY_WAIT_FOR_BACKEND; priv->pending_uids = NULL; priv->uids = g_hash_table_new (g_str_hash, g_str_equal); @@ -156,7 +157,18 @@ query_destroy (GtkObject *object) priv = query->priv; if (priv->backend) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query); + /* If we are waiting for the backend to be opened, we'll be + * connected to its "opened" signal. If we are in the middle of + * a query or if we are just waiting for object update + * notifications, we'll have the "obj_removed" and "obj_updated" + * connections. Otherwise, we are either in a parse error state + * or waiting for the query to be populated, and in both cases + * we have no signal connections. + */ + if (priv->state == QUERY_WAIT_FOR_BACKEND + || priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE) + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query); + gtk_object_unref (GTK_OBJECT (priv->backend)); priv->backend = NULL; } @@ -1040,22 +1052,17 @@ create_sexp (Query *query) return esexp; } -/* Ensures that the sexp has been parsed and the ESexp has been created. If a - * parse error occurs, it sets the query state to QUERY_PARSE_ERROR and returns - * FALSE. +/* Creates the ESexp and parses the esexp. If a parse error occurs, it sets the + * query state to QUERY_PARSE_ERROR and returns FALSE. */ static gboolean -ensure_sexp (Query *query) +parse_sexp (Query *query) { QueryPrivate *priv; priv = query->priv; - if (priv->state == QUERY_PARSE_ERROR) - g_assert_not_reached (); /* we should already have terminated everything */ - - if (priv->esexp) - return TRUE; + g_assert (priv->state == QUERY_START_PENDING); /* Compile the query string */ @@ -1068,10 +1075,7 @@ ensure_sexp (Query *query) const char *error_str; CORBA_Environment ev; - /* Change the state and disconnect from any notifications */ - priv->state = QUERY_PARSE_ERROR; - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query); /* Report the error to the listener */ @@ -1086,7 +1090,7 @@ ensure_sexp (Query *query) &ev); if (BONOBO_EX (&ev)) - g_message ("ensure_sexp(): Could not notify the listener of " + g_message ("parse_sexp(): Could not notify the listener of " "a parse error"); CORBA_exception_free (&ev); @@ -1113,14 +1117,12 @@ match_component (Query *query, const char *uid, priv = query->priv; - g_assert (priv->state != QUERY_PARSE_ERROR); - - if (!ensure_sexp (query)) - return; + g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); + g_assert (priv->esexp != NULL); comp = cal_backend_get_object_component (priv->backend, uid); - g_return_if_fail (comp != NULL); - gtk_object_ref (GTK_OBJECT (comp)); + if (!comp) + return; /* Eval the sexp */ @@ -1128,7 +1130,6 @@ match_component (Query *query, const char *uid, priv->next_comp = comp; result = e_sexp_eval (priv->esexp); - gtk_object_unref (GTK_OBJECT (comp)); priv->next_comp = NULL; if (!result) { @@ -1262,7 +1263,6 @@ populate_query (Query *query) priv->n_pending = priv->pending_total; priv->idle_id = g_idle_add (process_component_cb, query); - priv->state = QUERY_IN_PROGRESS; } /* Callback used when a component changes in the backend */ @@ -1270,8 +1270,12 @@ static void backend_obj_updated_cb (CalBackend *backend, const char *uid, gpointer data) { Query *query; + QueryPrivate *priv; query = QUERY (data); + priv = query->priv; + + g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); bonobo_object_ref (BONOBO_OBJECT (query)); @@ -1291,6 +1295,8 @@ backend_obj_removed_cb (CalBackend *backend, const char *uid, gpointer data) query = QUERY (data); priv = query->priv; + g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); + bonobo_object_ref (BONOBO_OBJECT (query)); remove_component (query, uid); @@ -1309,9 +1315,11 @@ start_query_cb (gpointer data) query = QUERY (data); priv = query->priv; + g_assert (priv->state == QUERY_START_PENDING); + priv->idle_id = 0; - if (!ensure_sexp (query)) + if (!parse_sexp (query)) return FALSE; /* Populate the query with UIDs so that we can process them asynchronously */ @@ -1325,6 +1333,8 @@ start_query_cb (gpointer data) GTK_SIGNAL_FUNC (backend_obj_removed_cb), query); + priv->state = QUERY_IN_PROGRESS; + return FALSE; } @@ -1340,6 +1350,11 @@ backend_opened_cb (CalBackend *backend, CalBackendOpenStatus status, gpointer da query = QUERY (data); priv = query->priv; + g_assert (priv->state == QUERY_WAIT_FOR_BACKEND); + + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query); + priv->state = QUERY_START_PENDING; + if (status == CAL_BACKEND_OPEN_SUCCESS) { g_assert (cal_backend_is_loaded (backend)); g_assert (priv->idle_id == 0); @@ -1400,6 +1415,8 @@ query_construct (Query *query, /* Queue the query to be started asynchronously */ if (cal_backend_is_loaded (priv->backend)) { + priv->state = QUERY_START_PENDING; + g_assert (priv->idle_id == 0); priv->idle_id = g_idle_add (start_query_cb, query); } else |