Fixes NB#106361, stack overflow caused by recursive calls to a signal handler
[modest] / src / widgets / modest-recpt-editor.c
index ea78c4f..f20c763 100644 (file)
@@ -71,7 +71,7 @@ struct _ModestRecptEditorPrivate
        GtkWidget *abook_button;
        GtkWidget *scrolled_window;
        gchar *recipients;
-
+       gulong on_mark_set_handler;
 };
 
 #define MODEST_RECPT_EDITOR_GET_PRIVATE(o)     \
@@ -87,13 +87,14 @@ static void modest_recpt_editor_class_init (ModestRecptEditorClass *klass);
 /* widget events */
 static void modest_recpt_editor_on_abook_clicked (GtkButton *button,
                                                  ModestRecptEditor *editor);
-static gboolean modest_recpt_editor_on_button_release_event (GtkWidget *widget,
-                                                            GdkEventButton *event,
-                                                            ModestRecptEditor *editor);
 static void modest_recpt_editor_move_cursor_to_end (ModestRecptEditor *editor);
 static gboolean modest_recpt_editor_on_focus_in (GtkTextView *text_view,
                                             GdkEventFocus *event,
                                             ModestRecptEditor *editor);
+static void modest_recpt_editor_on_mark_set (GtkTextBuffer *buffer,
+                                            GtkTextIter *iter,
+                                            GtkTextMark *mark,
+                                            ModestRecptEditor *editor);
 static void modest_recpt_editor_on_insert_text (GtkTextBuffer *buffer,
                                                GtkTextIter *location,
                                                gchar *text,
@@ -263,6 +264,25 @@ modest_recpt_editor_replace_with_resolved_recipient (ModestRecptEditor *recpt_ed
                                                     GtkTextIter *start, GtkTextIter *end,
                                                     GSList *email_list, const gchar * recipient_id)
 {
+       GSList *email_lists_list;
+       GSList *recipient_ids_list;
+
+       email_lists_list = g_slist_append (NULL, email_list);
+       recipient_ids_list = g_slist_append (NULL, (gpointer) recipient_id);
+
+       modest_recpt_editor_replace_with_resolved_recipients (recpt_editor, start, end,
+                                                             email_lists_list, recipient_ids_list);
+
+       g_slist_free (email_lists_list);
+       g_slist_free (recipient_ids_list);
+
+}
+
+void 
+modest_recpt_editor_replace_with_resolved_recipients (ModestRecptEditor *recpt_editor, 
+                                                    GtkTextIter *start, GtkTextIter *end,
+                                                    GSList *email_lists_list, GSList * recipient_ids_list)
+{
        ModestRecptEditorPrivate *priv;
        GtkTextBuffer *buffer;
        GtkTextTag *tag;
@@ -281,7 +301,10 @@ modest_recpt_editor_replace_with_resolved_recipient (ModestRecptEditor *recpt_ed
 
        gtk_text_buffer_delete (buffer, start, end);
 
-       if (email_list) {
+       while (email_lists_list) {
+               gchar *recipient_id = (gchar *) recipient_ids_list->data;
+               GSList *email_list = (GSList *) email_lists_list->data;
+               
          
                tag = gtk_text_buffer_create_tag (buffer, NULL, 
                                                  "underline", PANGO_UNDERLINE_SINGLE,
@@ -306,6 +329,9 @@ modest_recpt_editor_replace_with_resolved_recipient (ModestRecptEditor *recpt_ed
                                is_first_recipient = FALSE;
                        }
                }
+
+               email_lists_list = g_slist_next (email_lists_list);
+               recipient_ids_list = g_slist_next (recipient_ids_list);
        }
        g_signal_handlers_unblock_by_func (buffer, modest_recpt_editor_on_insert_text, recpt_editor);
 
@@ -420,12 +446,13 @@ modest_recpt_editor_instance_init (GTypeInstance *instance, gpointer g_class)
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
 #endif
        g_signal_connect (G_OBJECT (priv->abook_button), "clicked", G_CALLBACK (modest_recpt_editor_on_abook_clicked), instance);
-       g_signal_connect (G_OBJECT (priv->text_view), "button-release-event", G_CALLBACK (modest_recpt_editor_on_button_release_event), instance);
        g_signal_connect (G_OBJECT (priv->text_view), "key-press-event", G_CALLBACK (modest_recpt_editor_on_key_press_event), instance);
        g_signal_connect (G_OBJECT (priv->text_view), "focus-in-event", G_CALLBACK (modest_recpt_editor_on_focus_in), instance);
        g_signal_connect (G_OBJECT (buffer), "insert-text", G_CALLBACK (modest_recpt_editor_on_insert_text), instance);
 
-/*     gtk_container_set_focus_child (GTK_CONTAINER (instance), priv->text_view); */
+       priv->on_mark_set_handler = g_signal_connect (G_OBJECT (buffer), "mark-set", 
+                                                     G_CALLBACK (modest_recpt_editor_on_mark_set), 
+                                                     instance);
 
        return;
 }
@@ -469,23 +496,25 @@ modest_recpt_editor_on_abook_clicked (GtkButton *button, ModestRecptEditor *edit
        g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
 }
 
-static gboolean
-modest_recpt_editor_on_button_release_event (GtkWidget *widget,
-                                            GdkEventButton *event,
-                                            ModestRecptEditor *recpt_editor)
+static void
+modest_recpt_editor_on_mark_set (GtkTextBuffer *buffer,
+                                GtkTextIter *iter,
+                                GtkTextMark *mark,
+                                ModestRecptEditor *recpt_editor)
 {
        ModestRecptEditorPrivate *priv;
-       GtkTextIter location, start, end;
-       GtkTextMark *mark;
-       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       GtkTextMark *selection_bound;
        GtkTextTag *tag;
        gboolean selection_changed = FALSE;
        
        priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
 
        buffer = modest_recpt_editor_get_buffer (recpt_editor);
-       mark = gtk_text_buffer_get_insert (buffer);
-       gtk_text_buffer_get_iter_at_mark (buffer, &location, mark);
+       selection_bound = gtk_text_buffer_get_selection_bound (buffer);
+
+       if (mark != selection_bound)
+               return;
 
        gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
 
@@ -504,12 +533,14 @@ modest_recpt_editor_on_button_release_event (GtkWidget *widget,
                }
 
        if (selection_changed) {
+               /* We block this signal handler in order to prevent a
+                  stack overflow caused by recursive calls to this
+                  handler as the select_range call could issue a
+                  "mark-set" signal */
+               g_signal_handler_block (recpt_editor, priv->on_mark_set_handler);
                gtk_text_buffer_select_range (buffer, &start, &end);
-       } else {
-               GTK_TEXT_VIEW (priv->text_view)->pending_place_cursor_button = 0;
+               g_signal_handler_unblock (recpt_editor, priv->on_mark_set_handler);
        }
-
-       return FALSE;
 }
 
 static gboolean 
@@ -969,6 +1000,10 @@ modest_recpt_editor_finalize (GObject *object)
        ModestRecptEditorPrivate *priv;
        priv = MODEST_RECPT_EDITOR_GET_PRIVATE (object);
 
+       if (g_signal_handler_is_connected (object, priv->on_mark_set_handler))
+               g_signal_handler_disconnect (object, priv->on_mark_set_handler);
+       priv->on_mark_set_handler = 0;
+
        if (priv->recipients) {
                g_free (priv->recipients);
                priv->recipients = NULL;