Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scrolling #1935

Merged
merged 1 commit into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const char* s
auto_gchar gchar* end_date_fmt = end_time ? end_time : g_date_time_format_iso8601(now);
auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM ("
"SELECT COALESCE(B.`message`, A.`message`) AS message, "
"A.`timestamp`, A.`from_jid`, A.`to_jid`, A.`type`, A.`encryption` FROM `ChatLogs` AS A "
"A.`timestamp`, A.`from_jid`, A.`to_jid`, A.`type`, A.`encryption`, A.`stanza_id` FROM `ChatLogs` AS A "
"LEFT JOIN `ChatLogs` AS B ON (A.`replaced_by_db_id` = B.`id` AND A.`from_jid` = B.`from_jid`) "
"WHERE (A.`replaces_db_id` IS NULL) "
"AND ((A.`from_jid` = %Q AND A.`to_jid` = %Q) OR (A.`from_jid` = %Q AND A.`to_jid` = %Q)) "
Expand Down Expand Up @@ -365,8 +365,10 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const char* s
char* to_jid = (char*)sqlite3_column_text(stmt, 3);
char* type = (char*)sqlite3_column_text(stmt, 4);
char* encryption = (char*)sqlite3_column_text(stmt, 5);
char* id = (char*)sqlite3_column_text(stmt, 6);

ProfMessage* msg = message_init();
msg->id = id ? strdup(id) : NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you introduced STRDUP_OR_NULL in buffer.c. I wonder if it would be worth it to have this in common.h and use it here (and in other places) as well? @sjaeckel ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sjaeckel ping

msg->from_jid = jid_create(from);
msg->to_jid = jid_create(to_jid);
msg->plain = strdup(message ?: "");
Expand Down
97 changes: 53 additions & 44 deletions src/ui/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,29 @@
#include <curses.h>
#endif

#include "log.h"
#include "ui/window.h"
#include "ui/buffer.h"

#define BUFF_SIZE 200
#define MAX_BUFFER_SIZE 200
#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);

ProfBuff
buffer_create(void)
{
ProfBuff new_buff = malloc(sizeof(struct prof_buff_t));
new_buff->entries = NULL;
new_buff->lines = 0;
return new_buff;
}

Expand All @@ -84,58 +90,37 @@ buffer_free(ProfBuff buffer)
}

void
buffer_append(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)
buffer_append(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)
{
ProfBuffEntry* e = malloc(sizeof(struct prof_buff_entry_t));
e->show_char = strdup(show_char);
e->pad_indent = pad_indent;
e->flags = flags;
e->theme_item = theme_item;
e->time = g_date_time_ref(time);
e->display_from = display_from ? strdup(display_from) : NULL;
e->from_jid = from_jid ? strdup(from_jid) : NULL;
e->message = strdup(message);
e->receipt = receipt;
if (id) {
e->id = strdup(id);
} else {
e->id = NULL;
}

if (g_slist_length(buffer->entries) == BUFF_SIZE) {
_free_entry(buffer->entries->data);
buffer->entries = g_slist_delete_link(buffer->entries, buffer->entries);
}

buffer->entries = g_slist_append(buffer->entries, e);
_buffer_add(buffer, show_char, pad_indent, time, flags, theme_item, display_from, from_jid, message, receipt, id, y_start_pos, y_end_pos, TRUE);
}

void
buffer_prepend(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)
buffer_prepend(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)
{
ProfBuffEntry* e = malloc(sizeof(struct prof_buff_entry_t));
e->show_char = strdup(show_char);
e->pad_indent = pad_indent;
e->flags = flags;
e->theme_item = theme_item;
e->time = g_date_time_ref(time);
e->display_from = display_from ? strdup(display_from) : NULL;
e->from_jid = from_jid ? strdup(from_jid) : NULL;
e->message = strdup(message);
e->receipt = receipt;
if (id) {
e->id = strdup(id);
} else {
e->id = NULL;
_buffer_add(buffer, show_char, pad_indent, time, flags, theme_item, display_from, from_jid, message, receipt, id, y_start_pos, y_end_pos, FALSE);
}

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)
{
ProfBuffEntry* e = _create_entry(show_char, pad_indent, time, flags, theme_item, display_from, from_jid, message, receipt, id, y_start_pos, y_end_pos);

buffer->lines += e->_lines;

while (g_slist_length(buffer->entries) >= MAX_BUFFER_SIZE) {
GSList* buffer_entry_to_delete = append ? buffer->entries : g_slist_last(buffer->entries);
ProfBuffEntry* entry_to_delete = (ProfBuffEntry*)buffer_entry_to_delete->data;
buffer->lines -= entry_to_delete->_lines;
_free_entry(entry_to_delete);
buffer->entries = g_slist_delete_link(buffer->entries, buffer_entry_to_delete);
}

if (g_slist_length(buffer->entries) == BUFF_SIZE) {
GSList* last = g_slist_last(buffer->entries);
_free_entry(last->data);
buffer->entries = g_slist_delete_link(buffer->entries, last);
if (from_jid && y_end_pos == y_start_pos) {
log_warning("Ncurses Overflow! From: %s, pos: %d, ID: %s, message: %s", from_jid, y_end_pos, id, message);
}

buffer->entries = g_slist_prepend(buffer->entries, e);
buffer->entries = append ? g_slist_append(buffer->entries, e) : g_slist_prepend(buffer->entries, e);
}

void
Expand All @@ -145,6 +130,7 @@ buffer_remove_entry_by_id(ProfBuff buffer, const char* const id)
while (entries) {
ProfBuffEntry* entry = entries->data;
if (entry->id && (g_strcmp0(entry->id, id) == 0)) {
buffer->lines -= entry->_lines;
_free_entry(entry);
buffer->entries = g_slist_delete_link(buffer->entries, entries);
break;
Expand All @@ -157,6 +143,8 @@ void
buffer_remove_entry(ProfBuff buffer, int entry)
{
GSList* node = g_slist_nth(buffer->entries, entry);
ProfBuffEntry* e = node->data;
buffer->lines -= e->_lines;
_free_entry(node->data);
buffer->entries = g_slist_delete_link(buffer->entries, node);
}
Expand Down Expand Up @@ -201,6 +189,27 @@ buffer_get_entry_by_id(ProfBuff buffer, const char* const id)
return NULL;
}

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)
{
ProfBuffEntry* e = malloc(sizeof(struct prof_buff_entry_t));
e->show_char = STRDUP_OR_NULL(show_char);
e->pad_indent = pad_indent;
e->flags = flags;
e->theme_item = theme_item;
e->time = g_date_time_ref(time);
e->display_from = STRDUP_OR_NULL(display_from);
e->from_jid = STRDUP_OR_NULL(from_jid);
e->message = STRDUP_OR_NULL(message);
e->receipt = receipt;
e->id = STRDUP_OR_NULL(id);
e->y_start_pos = y_start_pos;
e->y_end_pos = y_end_pos;
e->_lines = e->y_end_pos - e->y_start_pos;

return e;
}

static void
_free_entry(ProfBuffEntry* entry)
{
Expand Down
7 changes: 5 additions & 2 deletions src/ui/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ typedef struct prof_buff_entry_t
// pointer because it could be a unicode symbol as well
gchar* show_char;
int pad_indent;
int y_start_pos;
int y_end_pos;
int _lines;
GDateTime* time;
int flags;
theme_item_t theme_item;
Expand All @@ -69,8 +72,8 @@ typedef struct prof_buff_t* ProfBuff;

ProfBuff buffer_create();
void buffer_free(ProfBuff buffer);
void buffer_append(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 barejid, const char* const message, DeliveryReceipt* receipt, const char* const id);
void buffer_prepend(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 barejid, const char* const message, DeliveryReceipt* receipt, const char* const id);
void buffer_append(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 barejid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos);
void buffer_prepend(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 barejid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos);
void buffer_remove_entry_by_id(ProfBuff buffer, const char* const id);
void buffer_remove_entry(ProfBuff buffer, int entry);
int buffer_size(ProfBuff buffer);
Expand Down
60 changes: 39 additions & 21 deletions src/ui/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,16 +629,14 @@ win_free(ProfWin* window)
void
win_page_up(ProfWin* window, int scroll_size)
{
int rows = getmaxy(stdscr);
int total_rows = getcury(window->layout->win);
int page_space = rows - 4;
int* page_start = &(window->layout->y_pos);
int page_start_initial = *page_start;
int total_rows = getcury(window->layout->win);
int page_space = getmaxy(stdscr) - 4;
if (scroll_size == 0)
scroll_size = page_space;
win_scroll_state_t* scroll_state = &window->scroll_state;
*scroll_state = (*scroll_state == WIN_SCROLL_REACHED_BOTTOM) ? WIN_SCROLL_INNER : *scroll_state;

*page_start -= scroll_size;

if (*page_start == -scroll_size && window->type == WIN_CHAT) {
Expand All @@ -655,14 +653,21 @@ win_page_up(ProfWin* window, int scroll_size)
win_print_loading_history(window);
iq_mam_request_older(chatwin);
}

int buff_size = buffer_size(window->layout->buffer);
int offset_entry_id = buff_size > 10 ? 10 : buff_size - 1;
int offset = buffer_get_entry(window->layout->buffer, offset_entry_id)->y_end_pos;
*page_start = offset - page_space;
}
}

// went past beginning, show first page
jubalh marked this conversation as resolved.
Show resolved Hide resolved
if (*page_start < 0)
if (*page_start < 0) {
*page_start = 0;
}

window->layout->paged = 1;

// update only if position has changed
jubalh marked this conversation as resolved.
Show resolved Hide resolved
if (page_start_initial != *page_start) {
win_update_virtual(window);
Expand All @@ -677,10 +682,9 @@ win_page_up(ProfWin* window, int scroll_size)
void
win_page_down(ProfWin* window, int scroll_size)
{
int rows = getmaxy(stdscr);
int* page_start = &(window->layout->y_pos);
int total_rows = getcury(window->layout->win);
int page_space = rows - 4;
int* page_start = &(window->layout->y_pos);
int page_space = getmaxy(stdscr) - 4;
int page_start_initial = *page_start;
if (scroll_size == 0)
scroll_size = page_space;
Expand All @@ -693,18 +697,23 @@ win_page_down(ProfWin* window, int scroll_size)
if ((*page_start == total_rows || (*page_start == page_space && *page_start >= total_rows)) && window->type == WIN_CHAT) {
int bf_size = buffer_size(window->layout->buffer);
if (bf_size > 0) {
auto_gchar gchar* start = g_date_time_format_iso8601(buffer_get_entry(window->layout->buffer, bf_size - 1)->time);
ProfBuffEntry* last_entry = buffer_get_entry(window->layout->buffer, bf_size - 1);
auto_gchar gchar* start = g_date_time_format_iso8601(last_entry->time);
GDateTime* now = g_date_time_new_now_local();
gchar* end = g_date_time_format_iso8601(now);
// end is free'd inside
if (*scroll_state != WIN_SCROLL_REACHED_BOTTOM && !chatwin_db_history((ProfChatWin*)window, start, end, FALSE)) {
gchar* end_date = g_date_time_format_iso8601(now);
if (*scroll_state != WIN_SCROLL_REACHED_BOTTOM && !chatwin_db_history((ProfChatWin*)window, start, end_date, FALSE)) {
*scroll_state = WIN_SCROLL_REACHED_BOTTOM;
}

g_date_time_unref(now);

int offset = last_entry->y_end_pos - 1;
*page_start = offset;
}
}

total_rows = getcury(window->layout->win);

// only got half a screen, show full screen
if ((total_rows - (*page_start)) < page_space)
*page_start = total_rows - page_space;
Expand All @@ -714,6 +723,7 @@ win_page_down(ProfWin* window, int scroll_size)
*page_start = total_rows - page_space - 1;

window->layout->paged = 1;

// update only if position has changed
jubalh marked this conversation as resolved.
Show resolved Hide resolved
if (page_start_initial != *page_start) {
win_update_virtual(window);
Expand Down Expand Up @@ -1486,10 +1496,11 @@ win_print_history(ProfWin* window, const ProfMessage* const message)
auto_gchar gchar* display_name = get_display_name(message, &flags);
auto_char char* ch = get_show_char(message->enc);

buffer_append(window->layout->buffer, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, NULL, message->plain, NULL, NULL);
wins_add_urls_ac(window, message, FALSE);
wins_add_quotes_ac(window, message->plain, FALSE);
int y_start_pos = getcury(window->layout->win);
_win_print_internal(window, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->plain, NULL);
buffer_append(window->layout->buffer, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->from_jid->barejid, message->plain, NULL, message->id, y_start_pos, getcury(window->layout->win));

inp_nonblocking(TRUE);
g_date_time_unref(message->timestamp);
Expand All @@ -1505,10 +1516,11 @@ win_print_old_history(ProfWin* window, const ProfMessage* const message)

auto_char char* ch = get_show_char(message->enc);

buffer_prepend(window->layout->buffer, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, NULL, message->plain, NULL, NULL);
int y_start_pos = getcury(window->layout->win);
wins_add_urls_ac(window, message, TRUE);
wins_add_quotes_ac(window, message->plain, TRUE);
_win_print_internal(window, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->plain, NULL);
buffer_prepend(window->layout->buffer, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->from_jid->barejid, message->plain, NULL, message->id, y_start_pos, getcury(window->layout->win));

inp_nonblocking(TRUE);
g_date_time_unref(message->timestamp);
Expand All @@ -1521,8 +1533,9 @@ win_println_va_internal(ProfWin* window, theme_item_t theme_item, int pad, int f

auto_gchar gchar* msg = g_strdup_vprintf(message, arg);

buffer_append(window->layout->buffer, show_char, pad, timestamp, flags, theme_item, "", NULL, msg, NULL, NULL);
int y_start_pos = getcury(window->layout->win);
_win_print_internal(window, show_char, pad, timestamp, flags, theme_item, "", msg, NULL);
buffer_append(window->layout->buffer, show_char, pad, timestamp, flags, theme_item, "", NULL, msg, NULL, NULL, y_start_pos, getcury(window->layout->win));

inp_nonblocking(TRUE);
g_date_time_unref(timestamp);
Expand Down Expand Up @@ -1615,8 +1628,9 @@ win_print_outgoing_with_receipt(ProfWin* window, const char* show_char, const ch
if (_win_correct(window, message, id, replace_id, myjid)) {
free(receipt); // TODO: probably we should use this in _win_correct()
} else {
buffer_append(window->layout->buffer, show_char, 0, time, 0, THEME_TEXT_ME, from, myjid, message, receipt, id);
int y_start_pos = getcury(window->layout->win);
_win_print_internal(window, show_char, 0, time, 0, THEME_TEXT_ME, from, message, receipt);
buffer_append(window->layout->buffer, show_char, 0, time, 0, THEME_TEXT_ME, from, myjid, message, receipt, id, y_start_pos, getcury(window->layout->win));
}

// TODO: cross-reference.. this should be replaced by a real event-based system
Expand Down Expand Up @@ -1675,8 +1689,9 @@ _win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* t

auto_gchar gchar* msg = g_strdup_vprintf(message, arg);

buffer_append(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, display_from, from_jid, msg, NULL, message_id);
int y_start_pos = getcury(window->layout->win);
_win_print_internal(window, show_char, pad_indent, timestamp, flags, theme_item, display_from, msg, NULL);
buffer_append(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, display_from, from_jid, msg, NULL, message_id, y_start_pos, getcury(window->layout->win));

inp_nonblocking(TRUE);
g_date_time_unref(timestamp);
Expand Down Expand Up @@ -1955,20 +1970,21 @@ win_print_trackbar(ProfWin* window)
void
win_redraw(ProfWin* window)
{
int size;
int size = buffer_size(window->layout->buffer);
werase(window->layout->win);
size = buffer_size(window->layout->buffer);

for (int i = 0; i < size; i++) {
ProfBuffEntry* e = buffer_get_entry(window->layout->buffer, i);

e->y_start_pos = getcury(window->layout->win);
if (e->display_from == NULL && e->message && e->message[0] == '-') {
// just an indicator to print the trackbar/separator not the actual message
win_print_trackbar(window);
} else {
// regular thing to print
_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);
}
}

Expand All @@ -1984,7 +2000,8 @@ win_print_loading_history(ProfWin* window)
timestamp = g_date_time_new_now_local();
}

buffer_prepend(window->layout->buffer, "-", 0, timestamp, NO_DATE, THEME_ROOMINFO, NULL, NULL, LOADING_MESSAGE, NULL, NULL);
int cur_y = getcury(window->layout->win);
buffer_prepend(window->layout->buffer, "-", 0, timestamp, NO_DATE, THEME_ROOMINFO, NULL, NULL, LOADING_MESSAGE, NULL, NULL, cur_y, cur_y + 1);

if (is_buffer_empty)
g_date_time_unref(timestamp);
Expand Down Expand Up @@ -2202,7 +2219,8 @@ win_insert_last_read_position_marker(ProfWin* window, char* id)
// the trackbar/separator will actually be print in win_redraw().
// this only puts it in the buffer and win_redraw() will interpret it.
// so that we have the correct length even when resizing.
buffer_append(window->layout->buffer, " ", 0, time, 0, THEME_TEXT, NULL, NULL, "-", NULL, id);
int y_start_pos = getcury(window->layout->win);
buffer_append(window->layout->buffer, " ", 0, time, 0, THEME_TEXT, NULL, NULL, "-", NULL, id, y_start_pos, getcury(window->layout->win));
win_redraw(window);

g_date_time_unref(time);
Expand Down
Loading