changeset 78:0b93dd0e0de1

fixed the data structure of marks that are positions of inserting user's icons.
author mikanbako <maoutwo@gmail.com>
date Sun, 29 Jun 2008 23:48:28 +0900
parents 846110b42009
children a4a6c7b204c9
files pidgin-twitter.c pidgin-twitter.h
diffstat 2 files changed, 89 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin-twitter.c	Sat Jun 28 13:59:02 2008 +0900
+++ b/pidgin-twitter.c	Sun Jun 29 23:48:28 2008 +0900
@@ -27,7 +27,7 @@
 static GHashTable *icon_id_by_user;
 static GList *requested_users = NULL;
 static GList *requestings = NULL;
-static GList *requested_icon_marks = NULL;
+static GHashTable *icon_mark_list_by_user;
 
 /* this function is a modified clone of purple_markup_strip_html() */
 static char *
@@ -700,25 +700,36 @@
 }
 
 static void
-delete_requested_icon_marks(PidginConversation* conv) {
+delete_requested_icon_marks(PidginConversation *conv) {
     GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(
         GTK_TEXT_VIEW(conv->imhtml));
-    GList *mark_list = g_list_first(requested_icon_marks);
+    GList *user_name_list = g_hash_table_get_keys(icon_mark_list_by_user);
+    GList *current_user;  
+
+    for(current_user = g_list_first(user_name_list); current_user;
+            current_user = g_list_next(current_user)) { 
+        gchar *user_name = current_user->data;
+        GList *mark_list = g_hash_table_lookup(icon_mark_list_by_user,
+                                               user_name);
 
-    /* delete the marks in the buffer that will be closed. */
-    while(mark_list) {
-        GtkTextMark *mark = mark_list->data;
-        GList *next = g_list_next(mark_list);
-
-        if(gtk_text_mark_get_buffer(mark) == text_buffer) {
-            /* the mark will be freed in the function */
-            gtk_text_buffer_delete_mark(text_buffer, mark);
-            requested_icon_marks = g_list_delete_link(
-                requested_icon_marks, mark_list);
+        /* delete the marks in the buffer that will be closed. */
+        GList *current = g_list_first(mark_list);
+        while(current) {
+            GtkTextMark *mark = current->data;
+            GList *next = g_list_next(current);
+    
+            if(gtk_text_mark_get_buffer(mark) == text_buffer) {
+                /* the mark will be freed in the function */
+                gtk_text_buffer_delete_mark(text_buffer, mark);
+                mark_list = g_list_delete_link(mark_list, current);
+            }
+    
+            current = next;
         }
 
-        mark_list = next;
+        g_hash_table_insert(icon_mark_list_by_user, user_name, mark_list);
     }
+    g_list_free(user_name_list);
 }
 
 static void
@@ -908,19 +919,13 @@
 }
 
 static void
-insert_requested_icon(gpointer data, gpointer user_data)
+insert_icon_at_mark(GtkTextMark *requested_mark, const gchar *user_name)
 {
-    GtkTextMark *requested_mark = (GtkTextMark *)data;
-    gchar *user_name = (gchar *)user_data;
     GList *win_list;
     GtkIMHtml *target_imhtml = NULL;
     GtkTextBuffer *target_buffer = NULL;
-    GtkTextIter inserting_point, next_line;
-    gchar *message;
-//    GMatchInfo *match_info = NULL;
-//    gchar *user_name_in_message;
+    GtkTextIter inserting_point;
     int icon_id;
-    GList *entry_of_mark;
 
     twitter_debug("called\n");
 
@@ -956,47 +961,6 @@
 
     gtk_text_buffer_get_iter_at_mark(target_buffer,
                                      &inserting_point, requested_mark);
-    next_line = inserting_point;
-    gtk_text_iter_forward_line(&next_line);
-
-    message = gtk_text_buffer_get_text(target_buffer, &inserting_point, &next_line, FALSE);
-
-#if 0
-    g_regex_match(regp[USER], message, 0, &match_info);
-    if(!g_match_info_matches(match_info)) {
-        g_match_info_free(match_info);
-        g_regex_match(regp[USER_FIRST_LINE], message, 0, &match_info);
-    }
-    if(!g_match_info_matches(match_info)) {
-        twitter_debug("user's name was not matched : %s\n", message);
-        g_match_info_free(match_info);
-        g_free(message);
-        return;
-    }
-
-    user_name_in_message = g_match_info_fetch(match_info, 1);
-    g_match_info_free(match_info);
-    g_free(message);
-
-    /* Return if the message is not from the user who has this icon. */
-    if(!g_str_equal(user_name, user_name_in_message)) {
-        g_free(user_name_in_message);
-        return;
-    }
-    g_free(user_name_in_message);
-#endif
-
-
-    /* simple search works sufficiently */
-    gchar *needle = g_strdup_printf("%s:", user_name);
-    if(!g_strstr_len(message, 256, needle)){ // xxx 256 is just a guess.
-        g_free(message); message = NULL;
-        g_free(needle); needle = NULL;
-        return;
-    }
-    twitter_debug("got needle %s\n", needle);
-    g_free(message); message = NULL;
-    g_free(needle); needle = NULL;
 
     /* insert icon */
     icon_id = GPOINTER_TO_INT(g_hash_table_lookup(icon_id_by_user, user_name));
@@ -1006,12 +970,17 @@
 
     /* insert icon actually */
     gtk_imhtml_insert_image_at_iter(target_imhtml, icon_id, &inserting_point);
+    gtk_text_buffer_delete_mark(target_buffer, requested_mark);
+}
 
-    /* mark the entry contains the deleted mark with NULL */
-    entry_of_mark = g_list_find(requested_icon_marks, requested_mark);
-    entry_of_mark->data = NULL;
+static void
+insert_requested_icon(const gchar *user_name)
+{
+    GList *mark_list = g_hash_table_lookup(icon_mark_list_by_user, user_name);
 
-    gtk_text_buffer_delete_mark(target_buffer, requested_mark);
+    g_list_foreach(mark_list, (GFunc) insert_icon_at_mark, (gchar *)user_name);
+    g_hash_table_remove(icon_mark_list_by_user, user_name);
+    g_list_free(mark_list);
 }
 
 static void
@@ -1036,14 +1005,20 @@
             twitter_debug("%s's icon has already been downloaded\n", user_name);
         }
 
-        requested_users = g_list_remove(requested_users, user_name);
+        GList *deleting = g_list_find_custom(requested_users,
+                                             user_name, (GCompareFunc) strcmp);
+        if(deleting) {
+            g_free(deleting->data);
+            requested_users = g_list_delete_link(requested_users, deleting);
+        }
         g_free(user_name);
         return;
     }
 
     icon_id = purple_imgstore_add_with_id(g_memdup(url_text, len), len,
                                           user_name);
-    g_hash_table_insert(icon_id_by_user, user_name, GINT_TO_POINTER(icon_id));
+    g_hash_table_insert(icon_id_by_user,
+                        g_strdup(user_name),GINT_TO_POINTER(icon_id));
 
     const gchar *dirname = purple_prefs_get_string(OPT_ICON_DIR);
 
@@ -1072,13 +1047,12 @@
         user_name, icon_id);
 
     /* Insert the icon to messages that had been received. */
-    g_list_foreach(requested_icon_marks, insert_requested_icon, user_name);
-    /* Remove the entries of the mark that inserted the icon. */
-    requested_icon_marks = g_list_remove_all(requested_icon_marks, NULL);
+    insert_requested_icon(user_name);
+    g_free(user_name);
 }
 
 static void
-request_icon(char *user_name)
+request_icon(const char *user_name)
 {
     gchar *url = NULL;
     PurpleUtilFetchUrlData *fetch_data = NULL;
@@ -1123,7 +1097,7 @@
         g_free(filename);
         g_free(path);
 
-        g_list_foreach(requested_icon_marks, insert_requested_icon, user_name);
+        insert_requested_icon(user_name);
         return;
     }
 
@@ -1132,8 +1106,8 @@
         return;
     }
 
-    /* The string object are owned by the list. */
     requested_users = g_list_append(requested_users, g_strdup(user_name));
+
     /* Create the URL of the user's icon.
      * See http://twitter.g.hatena.ne.jp/ikko615/20080107/1199703400
      */
@@ -1149,6 +1123,16 @@
 }
 
 static void
+mark_icon_for_user(GtkTextMark *mark, const gchar *user_name)
+{
+    GList *mark_list = g_hash_table_lookup(icon_mark_list_by_user, user_name);
+
+    mark_list = g_list_append(mark_list, mark);
+    g_hash_table_replace(icon_mark_list_by_user,
+                         g_strdup(user_name), mark_list);
+}
+
+static void
 displayed_im_cb(PurpleAccount *account, const char *who, char *message,
                 PurpleConversation *conv, PurpleMessageFlags flags)
 {
@@ -1186,16 +1170,14 @@
 
     icon_id = GPOINTER_TO_INT(g_hash_table_lookup(icon_id_by_user, user_name));
 
-    /* If the user's icon has not been downloaded, mark the message */
+    /* If the user's icon has not been downloaded,
+     * mark the message and request the icon. */
     if(!icon_id) {
-        requested_icon_marks =
-            g_list_append(requested_icon_marks,
-                          gtk_text_buffer_create_mark(
-                              text_buffer, NULL,
-                              &inserting_point, FALSE));
         twitter_debug("%s's icon has not been downloaded.\n", user_name);
-        /* request to attach icon to the buffer
-         * this function owns user_name string */
+        mark_icon_for_user(gtk_text_buffer_create_mark(
+                                text_buffer, NULL, &inserting_point, FALSE),
+                           user_name);
+        /* request to attach icon to the buffer */
         request_icon(user_name);
         g_free(user_name); user_name = NULL;
         return;
@@ -1235,9 +1217,13 @@
     regp[USER_FIRST_LINE] = g_regex_new(P_USER_FIRST_LINE, 0, 0, NULL);
     regp[USER_FORMATTED]  = g_regex_new(P_USER_FORMATTED, G_REGEX_RAW, 0, NULL);
 
-    /* hash table for user's icons
-     * the key is owned by requested_user */
-    icon_id_by_user = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+    /* hash table for user's icons */
+    icon_id_by_user = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                            g_free, NULL);
+
+    /* hash table for a list of marks that are alternative icons */
+    icon_mark_list_by_user = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                   g_free, NULL);
 
     /* attach counter to the existing twitter window */
     if(purple_prefs_get_bool(OPT_COUNTER)) {
@@ -1250,7 +1236,7 @@
 static gboolean
 unload_plugin(PurplePlugin *plugin)
 {
-    GList *list;
+    GList *list, *current;
 
     twitter_debug("called\n");
 
@@ -1283,8 +1269,18 @@
     g_regex_unref(regp[USER_FIRST_LINE]);
     g_regex_unref(regp[USER_FORMATTED]);
 
-    g_list_free(requested_icon_marks);
-    requested_icon_marks = NULL;
+    /* remove the hash table of marks that are alternative icons */
+    list = g_hash_table_get_values(icon_mark_list_by_user);
+    for(current = g_list_first(list); current;
+            current = g_list_next(current)) {
+        /* Free a list of marks.
+         * Do not free the marks here
+         * because the marks are owned by GtkTextBuffers.
+         */
+        g_list_free(current->data);
+    }
+    g_list_free(list);
+    g_hash_table_destroy(icon_mark_list_by_user);
 
     /* cancel request that has not been finished yet */
     for(list = g_list_first(requestings); list; list = g_list_next(list)) {
--- a/pidgin-twitter.h	Sat Jun 28 13:59:02 2008 +0900
+++ b/pidgin-twitter.h	Sun Jun 29 23:48:28 2008 +0900
@@ -88,9 +88,11 @@
 static void conv_created_cb(PurpleConversation *conv, gpointer null);
 static void deleting_conv_cb(PurpleConversation *conv);
 static gboolean receiving_im_cb(PurpleAccount *account, char **sender, char **buffer, PurpleConversation *conv, PurpleMessageFlags *flags, void *data);
-static void insert_requested_icon(gpointer data, gpointer user_data);
+static void insert_icon_at_mark(GtkTextMark *requested_mark, const gchar *user_name);
+static void insert_requested_icon(const gchar *user_name);
 static void got_icon_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message);
-static void request_icon(char *user_name);
+static void request_icon(const char *user_name);
+static void mark_icon_for_user(GtkTextMark *mark, const gchar *user_name);
 static void displayed_im_cb(PurpleAccount *account, const char *who, char *message, PurpleConversation *conv, PurpleMessageFlags flags);
 static gboolean load_plugin(PurplePlugin *plugin);
 static gboolean unload_plugin(PurplePlugin *plugin);