fix(scroll): handle edge case of extremely long messages #38

Manually merged
jabber.developer merged 1 commits from fix/buffer-cleanup into master 2025-10-08 11:21:47 +00:00
3 changed files with 20 additions and 14 deletions

View File

@@ -30,6 +30,7 @@
*/
#include "config.h"
#include "ui/window_list.h"
#include <stdlib.h>
#include <string.h>
@@ -51,12 +52,6 @@
#define STRDUP_OR_NULL(str) ((str) ? strdup(str) : NULL)
struct prof_buff_t
{
GSList* entries;
int lines;
};
static void _free_entry(ProfBuffEntry* entry);
static ProfBuffEntry* _create_entry(const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos);
static void _buffer_add(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos, gboolean append);
@@ -102,23 +97,24 @@ _buffer_add(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* t
buffer->lines += e->_lines;
while (buffer->lines >= PAD_SIZE) {
// With 10% margin to ensure overflow prevention
while (buffer->lines >= PAD_SIZE - (PAD_SIZE / 10) && g_slist_length(buffer->entries) > 1) {
// Delete message from the opposite size to free buffer
GSList* buffer_entry_to_delete = append ? buffer->entries : g_slist_last(buffer->entries);
ProfBuffEntry* entry_to_delete = (ProfBuffEntry*)buffer_entry_to_delete->data;
// log_debug("(Messages left in buffer: %d) DELETING: %s", g_slist_length(buffer->entries), entry_to_delete->id);
buffer->lines -= entry_to_delete->_lines;
_free_entry(entry_to_delete);
buffer->entries = g_slist_delete_link(buffer->entries, buffer_entry_to_delete);
}
if (from_jid && y_end_pos == y_start_pos) {
log_warning("Ncurses Overflow! From: %s, position: %d, ID: %s, append: %s, used message buffer size: %d, rendered lines buffer size: %d",
from_jid, y_start_pos, id, append ? "TRUE" : "FALSE", g_slist_length(buffer->entries), PAD_SIZE);
// At this point we have a message that caused overflow of the render buffer.
// Ideally, we want to clean other messages to rerender everything properly. To do so,
// first we need to determine the size of the message that we are trying to display,
// then we need to print the message.
// However, _buffer_add is too late in the code to do this, therefore it has to be done in the win_print_old_history.
// win_redraw will redraw with entries above removed,
// it will also recalculate actual size of the message that caused overflow
int old_lines = buffer->lines;
win_redraw(wins_get_current());
log_debug("Ncurses Overflow! From: %s, position: %d, ID: %s, append: %s, used message buffer size: %d, rendered lines: (old: %d/ actual: %d/ max: %d)",
from_jid, y_start_pos, id, append ? "TRUE" : "FALSE", g_slist_length(buffer->entries), old_lines, buffer->lines, PAD_SIZE);
}
buffer->entries = append ? g_slist_append(buffer->entries, e) : g_slist_prepend(buffer->entries, e);

View File

@@ -68,6 +68,12 @@ typedef struct prof_buff_entry_t
char* id;
} ProfBuffEntry;
struct prof_buff_t
{
GSList* entries;
int lines;
};
typedef struct prof_buff_t* ProfBuff;
ProfBuff buffer_create();

View File

@@ -2003,6 +2003,10 @@ win_redraw(ProfWin* window)
_win_print_internal(window, e->show_char, e->pad_indent, e->time, e->flags, e->theme_item, e->display_from, e->message, e->receipt);
}
e->y_end_pos = getcury(window->layout->win);
// Recalculate lines (might be incorrect in case of NCurses overflow)
window->layout->buffer->lines -= e->_lines;
e->_lines = e->y_end_pos - e->y_start_pos;
window->layout->buffer->lines += e->_lines;
}
}