diff --git a/CHANGELOG.md b/CHANGELOG.md index b8a047e7c7d..18753a26f7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ - Dev: BREAKING: Replace custom `import()` with normal Lua `require()`. (#5014) - Dev: Fixed most compiler warnings. (#5028) - Dev: Added the ability to show `ChannelView`s without a `Split`. (#4747) +- Dev: Channels without any animated elements on screen will skip updates from the GIF timer. (#5042) ## 2.4.6 diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index d80eba7d535..160ea51ca5b 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -196,8 +196,10 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags) } // Painting -void MessageLayout::paint(const MessagePaintContext &ctx) +MessagePaintResult MessageLayout::paint(const MessagePaintContext &ctx) { + MessagePaintResult result; + QPixmap *pixmap = this->ensureBuffer(ctx.painter, ctx.canvasWidth); if (!this->bufferValid_) @@ -209,7 +211,8 @@ void MessageLayout::paint(const MessagePaintContext &ctx) ctx.painter.drawPixmap(0, ctx.y, *pixmap); // draw gif emotes - this->container_.paintAnimatedElements(ctx.painter, ctx.y); + result.hasAnimatedElements = + this->container_.paintAnimatedElements(ctx.painter, ctx.y); // draw disabled if (this->message_->flags.has(MessageFlag::Disabled)) @@ -270,6 +273,8 @@ void MessageLayout::paint(const MessagePaintContext &ctx) } this->bufferValid_ = true; + + return result; } QPixmap *MessageLayout::ensureBuffer(QPainter &painter, int width) diff --git a/src/messages/layouts/MessageLayout.hpp b/src/messages/layouts/MessageLayout.hpp index d87a526b293..40275ff22da 100644 --- a/src/messages/layouts/MessageLayout.hpp +++ b/src/messages/layouts/MessageLayout.hpp @@ -32,6 +32,10 @@ enum class MessageLayoutFlag : uint8_t { }; using MessageLayoutFlags = FlagsEnum; +struct MessagePaintResult { + bool hasAnimatedElements = false; +}; + class MessageLayout { public: @@ -55,7 +59,7 @@ class MessageLayout bool layout(int width, float scale_, MessageElementFlags flags); // Painting - void paint(const MessagePaintContext &ctx); + MessagePaintResult paint(const MessagePaintContext &ctx); void invalidateBuffer(); void deleteBuffer(); void deleteCache(); diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index 0b2b729b8b3..aa3135a00be 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -235,13 +235,15 @@ void MessageLayoutContainer::paintElements(QPainter &painter, } } -void MessageLayoutContainer::paintAnimatedElements(QPainter &painter, +bool MessageLayoutContainer::paintAnimatedElements(QPainter &painter, int yOffset) const { + bool anyAnimatedElement = false; for (const auto &element : this->elements_) { - element->paintAnimated(painter, yOffset); + anyAnimatedElement |= element->paintAnimated(painter, yOffset); } + return anyAnimatedElement; } void MessageLayoutContainer::paintSelection(QPainter &painter, diff --git a/src/messages/layouts/MessageLayoutContainer.hpp b/src/messages/layouts/MessageLayoutContainer.hpp index 5887295fbdd..be765da85d4 100644 --- a/src/messages/layouts/MessageLayoutContainer.hpp +++ b/src/messages/layouts/MessageLayoutContainer.hpp @@ -64,8 +64,9 @@ struct MessageLayoutContainer { /** * Paint the animated elements in this message + * @returns true if this container contains at least one animated element */ - void paintAnimatedElements(QPainter &painter, int yOffset) const; + bool paintAnimatedElements(QPainter &painter, int yOffset) const; /** * Paint the selection for this container diff --git a/src/messages/layouts/MessageLayoutElement.cpp b/src/messages/layouts/MessageLayoutElement.cpp index 523a6b14570..11139ea39ff 100644 --- a/src/messages/layouts/MessageLayoutElement.cpp +++ b/src/messages/layouts/MessageLayoutElement.cpp @@ -153,11 +153,11 @@ void ImageLayoutElement::paint(QPainter &painter, } } -void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) +bool ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) { if (this->image_ == nullptr) { - return; + return false; } if (this->image_->animated()) @@ -167,8 +167,10 @@ void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) auto rect = this->getRect(); rect.moveTop(rect.y() + yOffset); painter.drawPixmap(QRectF(rect), *pixmap, QRectF()); + return true; } } + return false; } int ImageLayoutElement::getMouseOverIndex(const QPoint &abs) const @@ -265,7 +267,7 @@ void LayeredImageLayoutElement::paint(QPainter &painter, } } -void LayeredImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) +bool LayeredImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) { auto fullRect = QRectF(this->getRect()); fullRect.moveTop(fullRect.y() + yOffset); @@ -297,6 +299,7 @@ void LayeredImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) } } } + return animatedFlag; } int LayeredImageLayoutElement::getMouseOverIndex(const QPoint &abs) const @@ -446,8 +449,9 @@ void TextLayoutElement::paint(QPainter &painter, QTextOption(Qt::AlignLeft | Qt::AlignTop)); } -void TextLayoutElement::paintAnimated(QPainter &, int) +bool TextLayoutElement::paintAnimated(QPainter & /*painter*/, int /*yOffset*/) { + return false; } int TextLayoutElement::getMouseOverIndex(const QPoint &abs) const @@ -567,8 +571,10 @@ void TextIconLayoutElement::paint(QPainter &painter, } } -void TextIconLayoutElement::paintAnimated(QPainter &painter, int yOffset) +bool TextIconLayoutElement::paintAnimated(QPainter & /*painter*/, + int /*yOffset*/) { + return false; } int TextIconLayoutElement::getMouseOverIndex(const QPoint &abs) const @@ -640,8 +646,10 @@ void ReplyCurveLayoutElement::paint(QPainter &painter, painter.drawPath(path); } -void ReplyCurveLayoutElement::paintAnimated(QPainter &painter, int yOffset) +bool ReplyCurveLayoutElement::paintAnimated(QPainter & /*painter*/, + int /*yOffset*/) { + return false; } int ReplyCurveLayoutElement::getMouseOverIndex(const QPoint &abs) const diff --git a/src/messages/layouts/MessageLayoutElement.hpp b/src/messages/layouts/MessageLayoutElement.hpp index df42d1c9cde..894a5829d94 100644 --- a/src/messages/layouts/MessageLayoutElement.hpp +++ b/src/messages/layouts/MessageLayoutElement.hpp @@ -52,7 +52,8 @@ class MessageLayoutElement virtual size_t getSelectionIndexCount() const = 0; virtual void paint(QPainter &painter, const MessageColors &messageColors) = 0; - virtual void paintAnimated(QPainter &painter, int yOffset) = 0; + /// @returns true if anything was painted + virtual bool paintAnimated(QPainter &painter, int yOffset) = 0; virtual int getMouseOverIndex(const QPoint &abs) const = 0; virtual int getXFromIndex(size_t index) = 0; @@ -86,7 +87,7 @@ class ImageLayoutElement : public MessageLayoutElement uint32_t to = UINT32_MAX) const override; size_t getSelectionIndexCount() const override; void paint(QPainter &painter, const MessageColors &messageColors) override; - void paintAnimated(QPainter &painter, int yOffset) override; + bool paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(size_t index) override; @@ -105,7 +106,7 @@ class LayeredImageLayoutElement : public MessageLayoutElement uint32_t to = UINT32_MAX) const override; size_t getSelectionIndexCount() const override; void paint(QPainter &painter, const MessageColors &messageColors) override; - void paintAnimated(QPainter &painter, int yOffset) override; + bool paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(size_t index) override; @@ -158,7 +159,7 @@ class TextLayoutElement : public MessageLayoutElement uint32_t to = UINT32_MAX) const override; size_t getSelectionIndexCount() const override; void paint(QPainter &painter, const MessageColors &messageColors) override; - void paintAnimated(QPainter &painter, int yOffset) override; + bool paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(size_t index) override; @@ -182,7 +183,7 @@ class TextIconLayoutElement : public MessageLayoutElement uint32_t to = UINT32_MAX) const override; size_t getSelectionIndexCount() const override; void paint(QPainter &painter, const MessageColors &messageColors) override; - void paintAnimated(QPainter &painter, int yOffset) override; + bool paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(size_t index) override; @@ -200,7 +201,7 @@ class ReplyCurveLayoutElement : public MessageLayoutElement protected: void paint(QPainter &painter, const MessageColors &messageColors) override; - void paintAnimated(QPainter &painter, int yOffset) override; + bool paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(size_t index) override; void addCopyTextToString(QString &str, uint32_t from = 0, diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 474ff55c364..748220b7d46 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -406,7 +406,10 @@ void ChannelView::initializeSignals() this->signalHolder_.managedConnect(getApp()->windows->gifRepaintRequested, [&] { - this->queueUpdate(); + if (this->anyAnimationShown_) + { + this->queueUpdate(); + } }); this->signalHolder_.managedConnect( @@ -1470,6 +1473,8 @@ void ChannelView::drawMessages(QPainter &painter) }; bool showLastMessageIndicator = getSettings()->showLastMessageIndicator; + bool anyAnimation = false; + for (; ctx.messageIndex < messagesSnapshot.size(); ++ctx.messageIndex) { MessageLayout *layout = messagesSnapshot[ctx.messageIndex].get(); @@ -1483,7 +1488,7 @@ void ChannelView::drawMessages(QPainter &painter) ctx.isLastReadMessage = false; } - layout->paint(ctx); + anyAnimation |= layout->paint(ctx).hasAnimatedElements; if (this->highlightedMessage_ == layout) { @@ -1504,6 +1509,7 @@ void ChannelView::drawMessages(QPainter &painter) break; } } + this->anyAnimationShown_ = anyAnimation; if (end == nullptr) { diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index 71b43954088..522f335325b 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -273,6 +273,9 @@ class ChannelView final : public BaseWidget bool lastMessageHasAlternateBackground_ = false; bool lastMessageHasAlternateBackgroundReverse_ = true; + /// Tracks if this view has painted any animated element in the last #paintEvent(). + bool anyAnimationShown_ = false; + bool pausable_ = false; QTimer pauseTimer_; std::unordered_map>