[gtksourceview/wip/various-stuff: 3/7] Completion: weak reference to the view



commit 6877b934fa58a4098b30374f0ee5263331dab24f
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sun Jan 26 20:30:26 2014 +0100

    Completion: weak reference to the view
    
    There was a reference cycle between the view and completion. Now only
    the view has a strong reference to the completion. It is more logical
    that the view owns the completion, not vice-versa.
    
    This wasn't really a problem as far as the view was added to a
    container. Because when the container is destroyed, it calls
    gtk_widget_destroy() on its children, which calls g_object_run_dispose()
    which breaks the reference cycle.
    
    Anyway, it's better to not rely on gtk_widget_destroy(), and thus avoid
    reference cycles in C code.
    
    The drawback is that there are now checks to see if view == NULL, before
    using view.

 gtksourceview/gtksourcecompletion.c |   76 +++++++++++++++++++++++++++++++---
 1 files changed, 69 insertions(+), 7 deletions(-)
---
diff --git a/gtksourceview/gtksourcecompletion.c b/gtksourceview/gtksourcecompletion.c
index 4acdf5b..a151209 100644
--- a/gtksourceview/gtksourcecompletion.c
+++ b/gtksourceview/gtksourcecompletion.c
@@ -172,6 +172,9 @@ struct _GtkSourceCompletionPrivate
 
        /* Properties */
 
+       /* Weak reference to the view. You must check if view != NULL before
+        * using it.
+        */
        GtkSourceView *view;
        guint num_accelerators;
        guint auto_complete_delay;
@@ -293,6 +296,8 @@ get_iter_at_insert (GtkSourceCompletion *completion,
 {
        GtkTextBuffer *buffer;
 
+       g_return_if_fail (GTK_IS_TEXT_VIEW (completion->priv->view));
+
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (completion->priv->view));
        gtk_text_buffer_get_iter_at_mark (buffer,
                                          iter,
@@ -436,6 +441,11 @@ update_window_position (GtkSourceCompletion *completion)
        GtkTextIter iter;
        gboolean iter_set = FALSE;
 
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        /* The model can be modified while there is no completion context, for
         * example when the headers are shown or hidden. This triggers a signal
         * to update the window position, but if there is no completion context,
@@ -564,6 +574,11 @@ update_proposal_info (GtkSourceCompletion *completion)
 static void
 gtk_source_completion_show_default (GtkSourceCompletion *completion)
 {
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        gtk_widget_show (GTK_WIDGET (completion->priv->main_window));
 
        if (!completion->priv->remember_info_visibility)
@@ -637,6 +652,11 @@ gtk_source_completion_activate_proposal (GtkSourceCompletion *completion)
        GtkTextIter insert_iter;
        gboolean activated;
 
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        if (!get_selected_proposal (completion, &provider, &proposal))
        {
                return;
@@ -1560,7 +1580,14 @@ gtk_source_completion_dispose (GObject *object)
 
        reset_completion (completion);
 
-       g_clear_object (&completion->priv->view);
+       if (completion->priv->view != NULL)
+       {
+               g_object_remove_weak_pointer (G_OBJECT (completion->priv->view),
+                                             (gpointer *)&completion->priv->view);
+
+               completion->priv->view = NULL;
+       }
+
        g_clear_object (&completion->priv->default_info);
        g_clear_object (&completion->priv->model_proposals);
 
@@ -1583,10 +1610,17 @@ gtk_source_completion_dispose (GObject *object)
 }
 
 static void
-connect_view (GtkSourceCompletion *completion)
+connect_view (GtkSourceCompletion *completion,
+             GtkSourceView       *view)
 {
-       GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (completion->priv->view));
-       GtkStyleContext *style_context = gtk_widget_get_style_context (GTK_WIDGET (completion->priv->view));
+       GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+       GtkStyleContext *style_context = gtk_widget_get_style_context (GTK_WIDGET (view));
+
+       g_assert (completion->priv->view == NULL);
+       completion->priv->view = view;
+
+       g_object_add_weak_pointer (G_OBJECT (view),
+                                  (gpointer *)&completion->priv->view);
 
        g_signal_connect_object (completion->priv->view,
                                 "focus-out-event",
@@ -1733,9 +1767,7 @@ gtk_source_completion_set_property (GObject      *object,
        switch (prop_id)
        {
                case PROP_VIEW:
-                       /* On construction only */
-                       completion->priv->view = g_value_dup_object (value);
-                       connect_view (completion);
+                       connect_view (completion, g_value_get_object (value));
                        break;
                case PROP_REMEMBER_INFO_VISIBILITY:
                        completion->priv->remember_info_visibility = g_value_get_boolean (value);
@@ -2337,6 +2369,11 @@ static void
 init_main_window (GtkSourceCompletion *completion,
                  GtkBuilder          *builder)
 {
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        completion->priv->main_window = GTK_SOURCE_COMPLETION_INFO (gtk_builder_get_object (builder, 
"main_window"));
        completion->priv->info_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "info_button"));
        completion->priv->selection_image = GTK_IMAGE (gtk_builder_get_object (builder, "selection_image"));
@@ -2491,6 +2528,11 @@ gtk_source_completion_show (GtkSourceCompletion        *completion,
        g_return_val_if_fail (GTK_SOURCE_IS_COMPLETION (completion), FALSE);
        g_return_val_if_fail (GTK_SOURCE_IS_COMPLETION_CONTEXT (context), FALSE);
 
+       if (completion->priv->view == NULL)
+       {
+               return FALSE;
+       }
+
        /* Make sure to clear any active completion */
        reset_completion (completion);
 
@@ -2742,6 +2784,11 @@ gtk_source_completion_create_context (GtkSourceCompletion *completion,
 
        g_return_val_if_fail (GTK_SOURCE_IS_COMPLETION (completion), NULL);
 
+       if (completion->priv->view == NULL)
+       {
+               return NULL;
+       }
+
        if (position == NULL)
        {
                get_iter_at_insert (completion, &iter);
@@ -2770,6 +2817,11 @@ gtk_source_completion_move_window (GtkSourceCompletion *completion,
        g_return_if_fail (GTK_SOURCE_IS_COMPLETION (completion));
        g_return_if_fail (iter != NULL);
 
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        if (!gtk_widget_get_visible (GTK_WIDGET (completion->priv->main_window)))
        {
                return;
@@ -2800,6 +2852,11 @@ gtk_source_completion_block_interactive (GtkSourceCompletion *completion)
 
        g_return_if_fail (GTK_SOURCE_IS_COMPLETION (completion));
 
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (completion->priv->view));
 
        g_signal_handler_block (buffer, completion->priv->signals_ids[TEXT_BUFFER_INSERT_TEXT]);
@@ -2821,6 +2878,11 @@ gtk_source_completion_unblock_interactive (GtkSourceCompletion *completion)
 
        g_return_if_fail (GTK_SOURCE_IS_COMPLETION (completion));
 
+       if (completion->priv->view == NULL)
+       {
+               return;
+       }
+
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (completion->priv->view));
 
        g_signal_handler_unblock (buffer, completion->priv->signals_ids[TEXT_BUFFER_INSERT_TEXT]);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]