[gtksourceview/gtksourcecompletion] Make the appending of items async.
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: svn-commits-list gnome org
- Subject: [gtksourceview/gtksourcecompletion] Make the appending of items async.
- Date: Mon, 20 Apr 2009 14:51:42 -0400 (EDT)
commit 80d85752f5dbd11ef4a5951d59687c6549e09c23
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Mon Apr 20 20:47:20 2009 +0200
Make the appending of items async.
Now items are added async so the popup will appear instantly instead of waiting to have all elements added.
---
gtksourceview/gtksourcecompletion.c | 94 +++++++-----
gtksourceview/gtksourcecompletionmodel.c | 255 ++++++++++++++++++++++--------
gtksourceview/gtksourcecompletionmodel.h | 7 +-
3 files changed, 247 insertions(+), 109 deletions(-)
diff --git a/gtksourceview/gtksourcecompletion.c b/gtksourceview/gtksourcecompletion.c
index ef569e2..e00d178 100644
--- a/gtksourceview/gtksourcecompletion.c
+++ b/gtksourceview/gtksourcecompletion.c
@@ -76,6 +76,7 @@ enum
TEXT_VIEW_BUTTON_PRESS,
TEXT_BUFFER_DELETE_RANGE,
TEXT_BUFFER_INSERT_TEXT,
+ ROW_INSERTED,
LAST_EXTERNAL_SIGNAL
};
@@ -118,6 +119,8 @@ struct _GtkSourceCompletionPrivate
GtkSourceCompletionProvider *filter_provider;
gchar *filter_criteria;
+ gboolean inserting_data;
+
gulong signals_ids[LAST_EXTERNAL_SIGNAL];
};
@@ -499,7 +502,7 @@ do_refilter (GtkSourceCompletion *completion,
gtk_source_completion_model_refilter (completion->priv->model_proposals);
/* Check if there are any proposals left */
- if (finish_if_empty &&
+ if (finish_if_empty && !completion->priv->inserting_data &&
gtk_source_completion_model_is_empty (completion->priv->model_proposals, FALSE))
{
gtk_source_completion_finish (completion);
@@ -805,19 +808,6 @@ selection_changed_cb (GtkTreeSelection *selection,
}
static void
-add_proposal (GtkSourceCompletion *completion,
- GtkSourceCompletionProvider *provider,
- GtkSourceCompletionProposal *proposal)
-{
- GtkTreeIter iter;
-
- gtk_source_completion_model_append (completion->priv->model_proposals,
- provider,
- proposal,
- &iter);
-}
-
-static void
info_toggled_cb (GtkToggleButton *widget,
GtkSourceCompletion *completion)
{
@@ -1380,6 +1370,9 @@ gtk_source_completion_finish_default (GtkSourceCompletion *completion)
static void
gtk_source_completion_popup_default (GtkSourceCompletion *completion)
{
+ gtk_source_completion_utils_move_to_cursor (GTK_WINDOW (completion->priv->window),
+ GTK_SOURCE_VIEW (completion->priv->view));
+
gtk_widget_show (GTK_WIDGET (completion->priv->window));
gtk_widget_grab_focus (GTK_WIDGET (completion->priv->view));
@@ -1691,6 +1684,41 @@ selection_func (GtkTreeSelection *selection,
}
}
+static void
+on_row_inserted_cb (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkSourceCompletion *completion)
+{
+ if (!GTK_WIDGET_VISIBLE (completion->priv->window))
+ {
+ update_selection_label (completion);
+
+ if (!completion->priv->remember_info_visibility)
+ completion->priv->info_visible = FALSE;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (completion->priv->info_button),
+ completion->priv->info_visible);
+
+ g_signal_emit (completion, signals[POPUP], 0);
+
+ g_signal_handler_disconnect (tree_model, completion->priv->signals_ids[ROW_INSERTED]);
+ }
+}
+
+static void
+on_items_added_cb (GtkSourceCompletionModel *model,
+ GtkSourceCompletion *completion)
+{
+ completion->priv->inserting_data = FALSE;
+
+ /* Check if there are any completions */
+ if (gtk_source_completion_model_is_empty (model, FALSE))
+ {
+ gtk_source_completion_finish (completion);
+ }
+}
+
static GtkWidget *
initialize_proposals_ui (GtkSourceCompletion *completion)
{
@@ -1703,6 +1731,11 @@ initialize_proposals_ui (GtkSourceCompletion *completion)
completion->priv->model_proposals =
gtk_source_completion_model_new ((GtkSourceCompletionModelVisibleFunc)proposals_filter_func,
completion);
+
+ g_signal_connect (completion->priv->model_proposals,
+ "items-added",
+ G_CALLBACK (on_items_added_cb),
+ completion);
gtk_source_completion_model_set_show_headers (completion->priv->model_proposals,
completion->priv->show_headers);
@@ -1923,12 +1956,16 @@ add_proposals (GtkSourceCompletion *completion,
proposals = gtk_source_completion_provider_get_proposals (provider);
+ completion->priv->inserting_data = TRUE;
+
for (item = proposals; item; item = g_list_next (item))
{
if (GTK_IS_SOURCE_COMPLETION_PROPOSAL (item->data))
{
proposal = GTK_SOURCE_COMPLETION_PROPOSAL (item->data);
- add_proposal (completion, provider, proposal);
+ gtk_source_completion_model_append (completion->priv->model_proposals,
+ provider,
+ proposal);
g_object_unref (proposal);
}
}
@@ -1990,28 +2027,11 @@ gtk_source_completion_popup (GtkSourceCompletion *completion,
completion->priv->active_providers =
g_list_reverse (completion->priv->active_providers);
- /* Check if there are any completions */
- if (gtk_source_completion_model_is_empty (completion->priv->model_proposals, FALSE))
- {
- gtk_source_completion_finish (completion);
- return FALSE;
- }
-
- update_selection_label (completion);
-
- gtk_source_completion_utils_move_to_cursor (GTK_WINDOW (completion->priv->window),
- GTK_SOURCE_VIEW (completion->priv->view));
-
- if (!GTK_WIDGET_VISIBLE (completion->priv->window))
- {
- if (!completion->priv->remember_info_visibility)
- completion->priv->info_visible = FALSE;
-
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (completion->priv->info_button),
- completion->priv->info_visible);
- }
-
- g_signal_emit (completion, signals[POPUP], 0);
+ completion->priv->signals_ids[ROW_INSERTED] =
+ g_signal_connect (completion->priv->model_proposals,
+ "row-inserted",
+ G_CALLBACK (on_row_inserted_cb),
+ completion);
return TRUE;
}
diff --git a/gtksourceview/gtksourcecompletionmodel.c b/gtksourceview/gtksourcecompletionmodel.c
index b5b3014..2889325 100644
--- a/gtksourceview/gtksourcecompletionmodel.c
+++ b/gtksourceview/gtksourcecompletionmodel.c
@@ -1,5 +1,29 @@
+/*
+ * gtksourcecompletionmodel.c
+ * This file is part of gtksourcecompletion
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
#include "gtksourcecompletionmodel.h"
+#define ITEMS_PER_CALLBACK 500
+
#define GTK_SOURCE_COMPLETION_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModelPrivate))
typedef struct
@@ -33,8 +57,20 @@ struct _GtkSourceCompletionModelPrivate
gpointer filter_data;
gboolean show_headers;
+
+ guint idle_id;
+ GQueue *item_queue;
};
+/* Signals */
+enum
+{
+ ITEMS_ADDED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
static void tree_model_iface_init (gpointer g_iface, gpointer iface_data);
G_DEFINE_TYPE_WITH_CODE (GtkSourceCompletionModel,
@@ -387,6 +423,47 @@ tree_model_iface_init (gpointer g_iface,
}
static void
+free_node (ProposalNode *node)
+{
+ g_object_unref (node->provider);
+
+ if (node->proposal != NULL)
+ {
+ if (node->changed_id != 0)
+ {
+ g_signal_handler_disconnect (node->proposal,
+ node->changed_id);
+ }
+ g_object_unref (node->proposal);
+ }
+
+ g_slice_free (ProposalNode, node);
+}
+
+static void
+gtk_source_completion_model_dispose (GObject *object)
+{
+ GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
+
+ if (model->priv->idle_id != 0)
+ {
+ g_source_remove (model->priv->idle_id);
+ model->priv->idle_id = 0;
+ }
+
+ if (model->priv->item_queue != NULL)
+ {
+ g_queue_foreach (model->priv->item_queue,
+ (GFunc)free_node, NULL);
+ g_queue_free (model->priv->item_queue);
+
+ model->priv->item_queue = NULL;
+ }
+
+ G_OBJECT_CLASS (gtk_source_completion_model_parent_class)->dispose (object);
+}
+
+static void
gtk_source_completion_model_finalize (GObject *object)
{
GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
@@ -402,8 +479,20 @@ gtk_source_completion_model_class_init (GtkSourceCompletionModelClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_source_completion_model_finalize;
+ object_class->dispose = gtk_source_completion_model_dispose;
g_type_class_add_private (object_class, sizeof(GtkSourceCompletionModelPrivate));
+
+ signals[ITEMS_ADDED] =
+ g_signal_new ("items-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkSourceCompletionModelClass, items_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
static void
@@ -426,6 +515,10 @@ gtk_source_completion_model_init (GtkSourceCompletionModel *self)
g_direct_equal,
NULL,
free_num);
+
+ self->priv->idle_id = 0;
+ self->priv->item_queue = g_queue_new ();
+ g_queue_init (self->priv->item_queue);
}
static void
@@ -502,20 +595,6 @@ node_update_filter_state (GtkSourceCompletionModel *model,
}
static void
-free_node (ProposalNode *node)
-{
- g_object_unref (node->provider);
-
- if (node->proposal != NULL)
- {
- g_signal_handler_disconnect (node->proposal, node->changed_id);
- g_object_unref (node->proposal);
- }
-
- g_slice_free (ProposalNode, node);
-}
-
-static void
update_show_headers (GtkSourceCompletionModel *model,
gboolean show)
{
@@ -680,77 +759,109 @@ on_proposal_changed (GtkSourceCompletionProposal *proposal,
}
}
-gboolean
-gtk_source_completion_model_append (GtkSourceCompletionModel *model,
- GtkSourceCompletionProvider *provider,
- GtkSourceCompletionProposal *proposal,
- GtkTreeIter *iter)
+static gboolean
+idle_append (gpointer data)
{
- ProposalNode *node;
- GList *item;
- GtkTreePath *path;
- ProposalNode *header = NULL;
+ GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (data);
HeaderInfo *info;
+ GtkTreePath *path;
+ GList *item;
+ gint i = 0;
- g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model), FALSE);
- g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROVIDER (provider), FALSE);
- g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal), FALSE);
- g_return_val_if_fail (iter != NULL, FALSE);
-
-
- if (g_hash_table_lookup (model->priv->num_per_provider, provider) == NULL)
+ while (i < ITEMS_PER_CALLBACK)
{
- header = g_slice_new (ProposalNode);
- header->model = model;
- header->provider = g_object_ref (provider);
- header->proposal = NULL;
- header->filtered = GTK_SOURCE_COMPLETION_MODEL_FILTERED;
+ ProposalNode *node = (ProposalNode *)g_queue_pop_head (model->priv->item_queue);
+ ProposalNode *header = NULL;
+ GtkTreeIter iter;
+
+ if (node == NULL)
+ {
+ /* If we are here we added all elements of the queue */
+ g_signal_emit (model, signals[ITEMS_ADDED], 0);
+
+ model->priv->idle_id = 0;
+
+ return FALSE;
+ }
+
+ /* Check if it is a header */
+ if (g_hash_table_lookup (model->priv->num_per_provider, node->provider) == NULL)
+ {
+ header = g_slice_new (ProposalNode);
+ header->provider = g_object_ref (node->provider);
+ header->proposal = NULL;
+ header->filtered = GTK_SOURCE_COMPLETION_MODEL_FILTERED;
+
+ append_list (model, header);
+
+ info = g_slice_new (HeaderInfo);
+ info->item = model->priv->last;
+ info->num = 0;
+ info->visible_items = 0;
+
+ g_hash_table_insert (model->priv->num_per_provider, node->provider, info);
+ }
+
+ node_update_filter_state (model, node);
- append_list (model, header);
+ append_list (model, node);
- info = g_slice_new (HeaderInfo);
- info->item = model->priv->last;
- info->num = 0;
- info->visible_items = 0;
+ item = model->priv->last;
+ iter.user_data = item;
+
+ num_inc (model,
+ node->provider,
+ !node->filtered || (node->filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT),
+ !node->filtered);
+
+ if (!node->filtered)
+ {
+ path = path_from_list (model, item);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+
+ if (header != NULL)
+ {
+ update_show_headers (model, TRUE);
+ }
+ }
- g_hash_table_insert (model->priv->num_per_provider, provider, info);
+ node->changed_id = g_signal_connect (node->proposal,
+ "changed",
+ G_CALLBACK (on_proposal_changed),
+ item);
+
+ i++;
}
+
+ return TRUE;
+}
+
+void
+gtk_source_completion_model_append (GtkSourceCompletionModel *model,
+ GtkSourceCompletionProvider *provider,
+ GtkSourceCompletionProposal *proposal)
+{
+ ProposalNode *node;
+
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_PROVIDER (provider));
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal));
+
node = g_slice_new (ProposalNode);
- node->model = model;
node->provider = g_object_ref (provider);
node->proposal = g_object_ref (proposal);
-
- node_update_filter_state (model, node);
+ node->changed_id = 0;
- append_list (model, node);
- item = model->priv->last;
-
- iter->user_data = item;
+ g_queue_push_tail (model->priv->item_queue, node);
- num_inc (model,
- node->provider,
- !node->filtered || (node->filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT),
- !node->filtered);
-
- if (!node->filtered)
+ if (model->priv->idle_id == 0)
{
- path = path_from_list (model, item);
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter);
- gtk_tree_path_free (path);
-
- if (header != NULL)
- {
- update_show_headers (model, TRUE);
- }
+ model->priv->idle_id =
+ g_idle_add ((GSourceFunc)idle_append,
+ model);
}
-
- node->changed_id = g_signal_connect (proposal,
- "changed",
- G_CALLBACK (on_proposal_changed),
- item);
-
- return TRUE;
}
void
@@ -763,6 +874,12 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
+ /* Clear the queue of missing elements to append */
+ g_queue_foreach (model->priv->item_queue,
+ (GFunc)free_node, NULL);
+ g_queue_clear (model->priv->item_queue);
+ model->priv->idle_id = 0;
+
path = gtk_tree_path_new_first ();
list = model->priv->store;
diff --git a/gtksourceview/gtksourcecompletionmodel.h b/gtksourceview/gtksourcecompletionmodel.h
index b885e02..ba65a13 100644
--- a/gtksourceview/gtksourcecompletionmodel.h
+++ b/gtksourceview/gtksourcecompletionmodel.h
@@ -49,6 +49,8 @@ struct _GtkSourceCompletionModel {
struct _GtkSourceCompletionModelClass {
GObjectClass parent_class;
+
+ void (*items_added) (GtkSourceCompletionModel *model);
};
typedef enum
@@ -78,10 +80,9 @@ GtkSourceCompletionModel *
gtk_source_completion_model_new (GtkSourceCompletionModelVisibleFunc func,
gpointer userdata);
-gboolean gtk_source_completion_model_append (GtkSourceCompletionModel *model,
+void gtk_source_completion_model_append (GtkSourceCompletionModel *model,
GtkSourceCompletionProvider *provider,
- GtkSourceCompletionProposal *proposal,
- GtkTreeIter *iter);
+ GtkSourceCompletionProposal *proposal);
gboolean gtk_source_completion_model_is_empty (GtkSourceCompletionModel *model,
gboolean invisible);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]