changeset 2225:dc3b3ac1ba76

Free the buffdata structures when buffers are closed Free the buffdata strcutures when buffers are closed and there are no more users (these structures can be shared if the "symlink" shared history is used).
author Mikael Berthe <mikael@lilotux.net>
date Sat, 07 Nov 2015 12:21:12 +0100
parents 736f9323d701
children c1eb68306520
files mcabber/mcabber/screen.c
diffstat 1 files changed, 42 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/mcabber/screen.c	Sat Nov 07 12:16:15 2015 +0100
+++ b/mcabber/mcabber/screen.c	Sat Nov 07 12:21:12 2015 +0100
@@ -100,10 +100,12 @@
 static GHashTable *winbufhash;
 
 typedef struct {
-  GList  *hbuf;
-  GList  *top;     // If top is NULL, we'll display the last lines
-  char    cleared; // For ex, user has issued a /clear command...
-  char    lock;
+  GList    *hbuf;
+  GList    *top;      // If top is NULL, we'll display the last lines
+  char      cleared;  // For ex, user has issued a /clear command...
+  char      lock;
+  char      refcount; // refcount > 0 if there are other users of this struct
+                      // e.g. with symlinked history
 } buffdata;
 
 typedef struct {
@@ -1038,6 +1040,7 @@
 static winbuf *scr_new_buddy(const char *title, int dont_show)
 {
   winbuf *tmp;
+  char *id;
 
   tmp = g_new0(winbuf, 1);
 
@@ -1055,30 +1058,34 @@
   update_panels();
 
   // If title is NULL, this is a special buffer
-  if (title) {
-    char *id;
-    id = hlog_get_log_jid(title);
-    if (id) {
-      winbuf *wb = scr_search_window(id, FALSE);
-      if (!wb)
-        wb = scr_new_buddy(id, TRUE);
-      tmp->bd=wb->bd;
-      g_free(id);
-    } else {  // Load buddy history from file (if enabled)
-      tmp->bd = g_new0(buffdata, 1);
-      hlog_read_history(title, &tmp->bd->hbuf,
-                        maxX - Roster_Width - scr_getprefixwidth());
-
-      // Set a readmark to separate new content
-      hbuf_set_readmark(tmp->bd->hbuf, TRUE);
-    }
-
-    id = g_strdup(title);
-    mc_strtolower(id);
-    g_hash_table_insert(winbufhash, id, tmp);
-  } else {
+  if (!title) {
     tmp->bd = g_new0(buffdata, 1);
+    return tmp;
   }
+
+  id = hlog_get_log_jid(title);
+  if (id) {
+    // This is a symlinked history log file.
+    // Let's check if the target JID buffer has already been created.
+    winbuf *wb = scr_search_window(id, FALSE);
+    if (!wb)
+      wb = scr_new_buddy(id, TRUE);
+    tmp->bd = wb->bd;
+    tmp->bd->refcount++;
+    g_free(id);
+  } else {  // Load buddy history from file (if enabled)
+    tmp->bd = g_new0(buffdata, 1);
+    hlog_read_history(title, &tmp->bd->hbuf,
+                      maxX - Roster_Width - scr_getprefixwidth());
+
+    // Set a readmark to separate new content
+    hbuf_set_readmark(tmp->bd->hbuf, TRUE);
+  }
+
+  id = g_strdup(title);
+  mc_strtolower(id);
+  g_hash_table_insert(winbufhash, id, tmp);
+
   return tmp;
 }
 
@@ -2867,7 +2874,9 @@
   gboolean retval = FALSE;
 
   // Delete the current hbuf
-  hbuf_free(&win_entry->bd->hbuf);
+  // unless we close the buffer *and* this is a shared bd structure
+  if (!(*p_closebuf && win_entry->bd->refcount))
+    hbuf_free(&win_entry->bd->hbuf);
 
   if (*p_closebuf) {
     GSList *roster_elt;
@@ -2876,6 +2885,12 @@
         ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
     if (roster_elt)
       buddy_setactiveresource(roster_elt->data, NULL);
+    if (win_entry->bd->refcount) {
+      win_entry->bd->refcount--;
+    } else {
+      g_free(win_entry->bd);
+      win_entry->bd = NULL;
+    }
   } else {
     win_entry->bd->cleared = FALSE;
     win_entry->bd->top = NULL;