From a3a45ad47766c5e59178291d69e5aef6ff07698a Mon Sep 17 00:00:00 2001 From: Jabber Developer Date: Sat, 16 May 2026 15:47:49 +0000 Subject: [PATCH] fix(ui): preserve messages in non-chat windows while scrolled _win_printf dropped buffer append and render for any window in paged state, but only WIN_CHAT can recover lost messages via chatwin_db_history() on scroll-down. WIN_MUC, WIN_PRIVATE and WIN_AI have no such fallback, so incoming and outgoing messages were silently lost when the user was viewing history. Introduce log_database_can_recover_messages() to check whether the DB backend can replay messages (returns FALSE when PREF_DBLOG is "off", "redact", or no backend is active). Gate the WIN_CHAT early return in _win_printf() on this check: when recovery is impossible, fall through and append to the buffer so messages remain visible on scroll-down. Add a buffer-bottom reset in win_page_down() for non-chat windows. WIN_SCROLL_REACHED_BOTTOM is only set on the is_chat DB branch, so non-chat windows never clear paged on their own; reset paged and unread_msg when the last line of the buffer reaches the screen. Add missing scroll rendering for AI windows in the title bar draw function, ensuring AI windows display their scrolled state consistently with other window types. Remove the manual paged/unread_msg reset before printing the user message in cl_ev_send_ai_msg() -- it was a local workaround for the same drop and is no longer needed. --- src/database.c | 16 ++++++++++++++++ src/database.h | 3 +++ src/event/client_events.c | 6 ------ src/ui/titlebar.c | 5 +++++ src/ui/window.c | 14 ++++++++++++-- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/database.c b/src/database.c index b97e8539..0f3c8dc7 100644 --- a/src/database.c +++ b/src/database.c @@ -61,6 +61,22 @@ integrity_issue_free(integrity_issue_t* issue) } } +gboolean +log_database_can_recover_messages(void) +{ + if (!active_db_backend) { + return FALSE; + } + auto_gchar gchar* pref_dblog = prefs_get_string(PREF_DBLOG); + if (g_strcmp0(pref_dblog, "off") == 0) { + return FALSE; + } + if (g_strcmp0(pref_dblog, "redact") == 0) { + return FALSE; + } + return TRUE; +} + gboolean log_database_init(ProfAccount* account) { diff --git a/src/database.h b/src/database.h index c897230f..2204c0b0 100644 --- a/src/database.h +++ b/src/database.h @@ -109,6 +109,9 @@ ProfMessage* log_database_get_limits_info(const gchar* const contact_barejid, gb void log_database_close(void); GSList* log_database_verify_integrity(const gchar* const contact_barejid); +// FALSE if no backend, or PREF_DBLOG is "off" / "redact". +gboolean log_database_can_recover_messages(void); + // Cross-backend export/import (requires HAVE_SQLITE) #ifdef HAVE_SQLITE int log_database_export_to_flatfile(const gchar* const contact_jid); diff --git a/src/event/client_events.c b/src/event/client_events.c index 6adfc612..b90218db 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -301,12 +301,6 @@ cl_ev_send_ai_msg(ProfAiWin* aiwin, const char* const message, const char* const return; } - /* Reset paged flag before printing user message. - * If the user scrolled up to view history, paged=1 would suppress - * the message in _win_printf(). Reset it here so the message displays. */ - aiwin->window.layout->paged = 0; - aiwin->window.layout->unread_msg = 0; - // Display user message in AI window. win_print_outgoing(&aiwin->window, ">>", id, NULL, message); diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index bed87b4a..f5fddbee 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -46,6 +46,7 @@ #include "ui/ui.h" #include "ui/titlebar.h" #include "ui/inputwin.h" +#include "ui/win_types.h" #include "ui/window_list.h" #include "ui/window.h" #include "ui/screen.h" @@ -252,6 +253,10 @@ _title_bar_draw(void) _show_muc_privacy(mucwin); _show_attention(current, mucwin->has_attention); _show_scrolled(current); + } else if (current && current->type == WIN_AI) { + ProfAiWin* aiwin = (ProfAiWin*)current; + assert(aiwin->memcheck == PROFAIWIN_MEMCHECK); + _show_scrolled(current); } _show_self_presence(); diff --git a/src/ui/window.c b/src/ui/window.c index a41a73fe..63be8fc6 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -848,6 +848,14 @@ win_page_down(ProfWin* window, int scroll_size) window->layout->paged = 0; window->layout->unread_msg = 0; } + + // Non-chat windows have no DB to fetch from, so WIN_SCROLL_REACHED_BOTTOM + // never fires; reset paged once the buffer's last line is on screen. + if (window->type != WIN_CHAT + && (total_rows - *page_start) <= page_space + 1) { + window->layout->paged = 0; + window->layout->unread_msg = 0; + } } void @@ -1801,10 +1809,12 @@ static void _win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...) { - /* Prevent printing and buffer update when user is viewing message history [SCROLLING]*/ if (window->layout->paged && wins_is_current(window)) { window->layout->unread_msg++; - return; + // Skip buffer only when DB can replay the message on scroll-down. + if (window->type == WIN_CHAT && log_database_can_recover_messages()) { + return; + } } if (timestamp == NULL) {