Scroll is getting stuck #36

Closed
opened 2025-10-06 14:49:04 +00:00 by jabber.developer · 1 comment

Current Behavior

When the window is scrolled up ([SCROLLED] state) and new message appears from either side, scrolling down might cause getting stuck in the middle of the conversation. The state will switch from [SCROLLED], yet only new message and middle (arbitrary stuck point) of the conversation is show.

Deep Dive

The actual issue is that CProof tries to fetch the history from the wrong range of time.

Data Storage

Long-term storage of the messages, including full conversational history, is stored in the SQLite database.

CProof keeps currently displayed messages in an internal buffer. The messages in the buffer are the ones that are supposed to be displayed. Buffer also contains some display meta-data details, such as message visual location (line numbers) size in lines. Actual location of each character, scrolling and other UI details are stored in and handled by the NCurses.

NCurses' window size (PAD_SIZE) is 10.000 lines. Once exceeded, any text that was written there would disappear (causing window to be stuck). To avoid this issue, we track line sizes in the NCurses' window buffer and delete messages from the other side of the buffer.

Events

Once a new message appears (sent or received), it is immediately appended to the internal buffer.

Once user presses page_down, to determine which messages are needed to be fetched, CProof utilizes the latest message's timestamp as a starting point in the DB request. Since new message's timestamp is nearly current date, no other messages are found from the DB to fetch. It causes CProof to assume that the end of DB is reached.

src/ui/window.c Lines 718 to 721 in 40dd773c6a
ProfBuffEntry* last_entry = buffer_get_entry(window->layout->buffer, bf_size - 1);
auto_gchar gchar* start = g_date_time_format_iso8601(last_entry->time);
auto_gchar gchar* end_date = g_date_time_format_iso8601(now);
db_history_result_t db_response = chatwin_db_history((ProfChatWin*)window, start, end_date, FALSE);

Potential solutions

1

Avoid displaying new messages if scrolled past the buffer size. Just add them to the DB to be scrolled into eventually. It would preserve message ordering.

Questions: how to determine if scrolled past buffer size?
Downsides: slight complexity and chances of bugs causing messages to not appear.

2

Get rid of a buffer cleanups: add metadata to avoid displaying messages if past the NCurses' size.

Downsides:

  • Potentially, keeping too much data in the buffer; suboptimal for memory management
  • New mechanism requirement: sliding through the buffer prior to fetching from DB.

Solution Log

Currently, buffer cleanup was improved, masking the issue by PR #37.

while (g_slist_length(buffer->entries) >= MAX_BUFFER_SIZE) {

Prior to the change, the buffer kept up to MAX_BUFFER_SIZE=200 messages, even though they might take much less than 10k lines. Since line tracking was introducing earlier, it allowed to remove buffer size limitation and scale it based on the amount of lines.

However, it does not fix the underlying issue with the message cleanup causing getting stuck, but 10k lines of actual buffer will significantly increase responsiveness of the application and reduce occurrences of message deletion, therefore masking the issue.

Steps to Reproduce

  1. Scroll upwards around 200+ messages
  2. Send/receive a message
  3. Scroll downwards until the bottom of the conversation:
  4. Observe that conversation is abruptly jumps from the middle to the latest messages
## Current Behavior When the window is scrolled up (`[SCROLLED]` state) and new message appears from either side, scrolling down might cause getting stuck in the middle of the conversation. The state will switch from `[SCROLLED]`, yet only new message and middle (arbitrary stuck point) of the conversation is show. ## Deep Dive The actual issue is that CProof tries to fetch the history from the wrong range of time. ### Data Storage Long-term storage of the messages, including full conversational history, is stored in the SQLite database. CProof keeps currently displayed messages in an internal [buffer](https://git.jabber.space/devs/cproof/src/commit/40dd773c6a41028c9cc6d1d3e3ea1127fc2f697f/src/ui/buffer.c). The messages in the buffer are the ones that are supposed to be displayed. Buffer also contains some display meta-data details, such as message visual location (line numbers) size in lines. Actual location of each character, scrolling and other UI details are stored in and handled by the NCurses. NCurses' window size (`PAD_SIZE`) is 10.000 lines. Once exceeded, any text that was written there would disappear (causing window to be stuck). To avoid this issue, we track line sizes in the NCurses' window buffer and delete messages from the other side of the buffer. ### Events Once a new message appears (sent or received), it is immediately appended to the internal buffer. Once user presses `page_down`, to determine which messages are needed to be fetched, CProof utilizes the latest message's timestamp as a starting point in the DB request. Since new message's timestamp is nearly current date, no other messages are found from the DB to fetch. It causes CProof to assume that the end of DB is reached. https://git.jabber.space/devs/cproof/src/commit/40dd773c6a41028c9cc6d1d3e3ea1127fc2f697f/src/ui/window.c#L718-L721 ## Potential solutions ### 1 Avoid displaying new messages if scrolled past the buffer size. Just add them to the DB to be scrolled into eventually. It would preserve message ordering. Questions: how to determine if scrolled past buffer size? Downsides: slight complexity and chances of bugs causing messages to not appear. ### 2 Get rid of a buffer cleanups: add metadata to avoid displaying messages if past the NCurses' size. Downsides: - Potentially, keeping too much data in the buffer; suboptimal for memory management - New mechanism requirement: sliding through the buffer prior to fetching from DB. ## Solution Log Currently, buffer cleanup was improved, masking the issue by PR #37. https://git.jabber.space/devs/cproof/src/commit/40dd773c6a41028c9cc6d1d3e3ea1127fc2f697f/src/ui/buffer.c#L111 Prior to the change, the buffer kept up to `MAX_BUFFER_SIZE=200` messages, even though they might take much less than 10k lines. Since line tracking was introducing earlier, it allowed to remove buffer size limitation and scale it based on the amount of lines. However, it does not fix the underlying issue with the message cleanup causing getting stuck, but 10k lines of actual buffer will significantly increase responsiveness of the application and reduce occurrences of message deletion, therefore masking the issue. ## Steps to Reproduce 1. Scroll upwards around 200+ messages 2. Send/receive a message 3. Scroll downwards until the bottom of the conversation: 4. Observe that conversation is abruptly jumps from the middle to the latest messages
jabber.developer added the
Kind/Bug
Priority
High
2
labels 2025-10-06 14:49:04 +00:00
jabber.developer self-assigned this 2025-10-06 14:49:04 +00:00
jabber.developer removed their assignment 2025-10-11 10:51:32 +00:00
jabber.developer2 was assigned by jabber.developer 2025-10-11 10:52:08 +00:00
jabber.developer added this to the Plans (2025-2026) project 2025-10-11 10:52:11 +00:00
jabber.developer moved this to To Do in Plans (2025-2026) on 2025-10-11 10:52:18 +00:00
jabber.developer moved this to In Progress in Plans (2025-2026) on 2025-10-11 10:52:19 +00:00
jabber.developer moved this to Backlog in Plans (2025-2026) on 2025-11-10 12:27:48 +00:00
jabber.developer moved this to In Progress in Plans (2025-2026) on 2025-11-10 12:37:08 +00:00
jabber.developer2 moved this to Verification in Plans (2025-2026) on 2025-11-10 13:00:57 +00:00
jabber.developer added the due date 2025-11-16 2025-11-10 13:10:44 +00:00
Author
Owner

Resolved by #45 and #37

Resolved by #45 and #37
jabber.developer moved this to Done in Plans (2025-2026) on 2026-01-14 08:55:48 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2025-11-16
Dependencies

No dependencies set.

Reference: devs/cproof#36
No description provided.