From 9d718fccf46f8d8c94d4fe7409c42cf082e3b4f4 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Sat, 21 Jul 2018 12:09:23 +0300 Subject: [PATCH] Clear timeline widgets when they exceed a certain limit (#158) That's a fix to deal with long running sessions which will end up taking more & more memory given enough time. --- src/timeline/TimelineView.cpp | 44 +++++++++++++++++++++++++++++++++-- src/timeline/TimelineView.h | 3 +++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/timeline/TimelineView.cpp b/src/timeline/TimelineView.cpp index 61a507b3..95cde0f4 100644 --- a/src/timeline/TimelineView.cpp +++ b/src/timeline/TimelineView.cpp @@ -38,6 +38,10 @@ using TimelineEvent = mtx::events::collections::TimelineEvents; +//! Maximum number of widgets to keep in the timeline layout. +constexpr int MAX_RETAINED_WIDGETS = 100; +constexpr int MIN_SCROLLBAR_HANDLE = 60; + //! Retrieve the timestamp of the event represented by the given widget. QDateTime getDate(QWidget *widget) @@ -481,8 +485,7 @@ TimelineView::addEvents(const mtx::responses::Timeline &timeline) void TimelineView::init() { - QSettings settings; - local_user_ = settings.value("auth/user_id").toString(); + local_user_ = utils::localUser(); QIcon icon; icon.addFile(":/icons/icons/ui/angle-arrow-down.png"); @@ -965,6 +968,19 @@ TimelineView::showEvent(QShowEvent *event) QWidget::showEvent(event); } +void +TimelineView::hideEvent(QHideEvent *event) +{ + const auto handleHeight = scroll_area_->verticalScrollBar()->sizeHint().height(); + const auto widgetsNum = scroll_layout_->count(); + + // Remove widgets from the timeline to reduce the memory footprint. + if (handleHeight < MIN_SCROLLBAR_HANDLE && widgetsNum > MAX_RETAINED_WIDGETS) + clearTimeline(); + + QWidget::hideEvent(event); +} + bool TimelineView::event(QEvent *event) { @@ -974,6 +990,30 @@ TimelineView::event(QEvent *event) return QWidget::event(event); } +void +TimelineView::clearTimeline() +{ + // Delete all widgets. + QLayoutItem *item; + while ((item = scroll_layout_->takeAt(0)) != nullptr) { + delete item->widget(); + delete item; + } + + // The next call to /messages will be without a prev token. + prev_batch_token_.clear(); + eventIds_.clear(); + + // Clear queues with pending messages to be rendered. + bottomMessages_.clear(); + topMessages_.clear(); + + firstSender_.clear(); + lastSender_.clear(); + + scroll_layout_->addStretch(1); +} + void TimelineView::toggleScrollDownButton() { diff --git a/src/timeline/TimelineView.h b/src/timeline/TimelineView.h index 5c42415a..d622b698 100644 --- a/src/timeline/TimelineView.h +++ b/src/timeline/TimelineView.h @@ -161,6 +161,7 @@ signals: protected: void paintEvent(QPaintEvent *event) override; void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; bool event(QEvent *event) override; private: @@ -271,6 +272,8 @@ private: //! Store the event id associated with the given widget. void saveEventId(QWidget *widget); + //! Remove all widgets from the timeline layout. + void clearTimeline(); QVBoxLayout *top_layout_; QVBoxLayout *scroll_layout_;