From 9b6d77821ab26ad3b69ec0953aabacedc41a3169 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Tue, 19 May 2026 21:28:43 +0200 Subject: [PATCH] Suppress status-bar updates if nothing had changed --- src/SettingsList.h | 6 +++-- src/activities/Activity.h | 5 ++++ src/activities/ActivityManager.cpp | 4 ++- src/activities/reader/EpubReaderActivity.cpp | 26 ++++++++++++++++++++ src/activities/reader/EpubReaderActivity.h | 7 ++++++ src/activities/reader/MdReaderActivity.cpp | 25 +++++++++++++++++++ src/activities/reader/MdReaderActivity.h | 5 ++++ src/activities/reader/TxtReaderActivity.cpp | 25 +++++++++++++++++++ src/activities/reader/TxtReaderActivity.h | 5 ++++ 9 files changed, 105 insertions(+), 3 deletions(-) diff --git a/src/SettingsList.h b/src/SettingsList.h index 5cd1dc10..7dc1f9a2 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -138,9 +138,11 @@ inline const std::vector list = { StrId::STR_CAT_READER), SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering, {StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS}, - "imageRendering", StrId::STR_CAT_READER), + "imageRendering", StrId::STR_CAT_READER) + .withSubmenu(StrId::STR_IMAGES), SettingInfo::Toggle(StrId::STR_LARGE_IMAGE_PLACEHOLDER, &CrossPointSettings::largeImagePlaceholder, - "largeImagePlaceholder", StrId::STR_CAT_READER), + "largeImagePlaceholder", StrId::STR_CAT_READER) + .withSubmenu(StrId::STR_IMAGES), SettingInfo::Value(StrId::STR_SCREEN_MARGIN, &CrossPointSettings::screenMargin, {5, 40, 5}, "screenMargin", StrId::STR_CAT_READER) .withSubmenu(StrId::STR_MENU_READER_SPACING), diff --git a/src/activities/Activity.h b/src/activities/Activity.h index 2eebecea..2583e1c6 100644 --- a/src/activities/Activity.h +++ b/src/activities/Activity.h @@ -47,6 +47,11 @@ class Activity { virtual bool preventAutoSleep() { return false; } virtual bool isReaderActivity() const { return false; } + // Return true to suppress the minute-tick requestUpdate() from ActivityManager when nothing + // status-bar-relevant has changed since the last render. Skipping avoids a no-op page render + // followed by a no-diff e-ink refresh, which on X3 panels accumulates visible speckle. + virtual bool shouldSkipPeriodicUpdate() const { return false; } + // Called by ActivityManager when a globally-configured button action targets the // current activity. Override in reader activities to handle reader-specific actions. // Non-reader activities can ignore this (default is no-op). diff --git a/src/activities/ActivityManager.cpp b/src/activities/ActivityManager.cpp index a40826f8..4b69e459 100644 --- a/src/activities/ActivityManager.cpp +++ b/src/activities/ActivityManager.cpp @@ -111,7 +111,9 @@ void ActivityManager::loop() { time_t minute = now / 60; if (minute != lastMinute) { lastMinute = minute; - requestUpdate(); + if (!currentActivity || !currentActivity->shouldSkipPeriodicUpdate()) { + requestUpdate(); + } } } } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index f01e1d1f..aac4dbc8 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -2256,6 +2258,30 @@ void EpubReaderActivity::renderStatusBar() const { const bool isStarred = section && bookmarkStore.has(static_cast(currentSpineIndex), static_cast(section->currentPage)); GUI.drawStatusBar(renderer, bookProgress, currentPage, pageCount, title, 0, isStarred); + + lastStatusBarPage = currentPage; + lastStatusBarBattery = SETTINGS.statusBarBattery ? static_cast(powerManager.getBatteryPercentage()) : -1; + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + lastStatusBarClockMinute = now > 0 ? static_cast(now / 60) : -1; + } else { + lastStatusBarClockMinute = -1; + } +} + +bool EpubReaderActivity::shouldSkipPeriodicUpdate() const { + if (lastStatusBarPage < 0) return false; // no baseline yet — let the first render happen + const int currentPage = section ? section->currentPage + 1 : -1; + if (currentPage != lastStatusBarPage) return false; + if (SETTINGS.statusBarBattery) { + if (static_cast(powerManager.getBatteryPercentage()) != lastStatusBarBattery) return false; + } + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + const int minute = now > 0 ? static_cast(now / 60) : -1; + if (minute != lastStatusBarClockMinute) return false; + } + return true; } void EpubReaderActivity::navigateToHref(const std::string& hrefStr, const bool savePosition) { diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index ddbdf5ce..519f2de3 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -262,6 +262,12 @@ class EpubReaderActivity final : public Activity { void displayPreRenderedPage(const Page& page, int orientedMarginTop, int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft); void renderStatusBar() const; + // Snapshot of the three status-bar signals that can change while a page is otherwise idle. + // Compared in shouldSkipPeriodicUpdate() to suppress no-op minute-tick re-renders that on + // X3 panels accumulate visible speckle via repeated no-diff FAST refreshes. + mutable int lastStatusBarPage = -1; + mutable int lastStatusBarBattery = -1; + mutable int lastStatusBarClockMinute = -1; void silentIndexNextChapterIfNeeded(uint16_t viewportWidth, uint16_t viewportHeight); void saveProgress(int spineIndex, int currentPage, int pageCount); // Jump to a percentage of the book (0-100), mapping it to spine and page. @@ -314,6 +320,7 @@ class EpubReaderActivity final : public Activity { void loop() override; void render(RenderLock&& lock) override; bool isReaderActivity() const override { return true; } + bool shouldSkipPeriodicUpdate() const override; void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override; // Renders the last saved page to the frame buffer without flushing to display. diff --git a/src/activities/reader/MdReaderActivity.cpp b/src/activities/reader/MdReaderActivity.cpp index e0cd6c04..4cf07319 100644 --- a/src/activities/reader/MdReaderActivity.cpp +++ b/src/activities/reader/MdReaderActivity.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include @@ -881,6 +883,29 @@ void MdReaderActivity::renderStatusBar() const { title = txt->getTitle(); } GUI.drawStatusBar(renderer, progress, currentPage + 1, totalPages, title); + + lastStatusBarPage = currentPage + 1; + lastStatusBarBattery = SETTINGS.statusBarBattery ? static_cast(powerManager.getBatteryPercentage()) : -1; + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + lastStatusBarClockMinute = now > 0 ? static_cast(now / 60) : -1; + } else { + lastStatusBarClockMinute = -1; + } +} + +bool MdReaderActivity::shouldSkipPeriodicUpdate() const { + if (lastStatusBarPage < 0) return false; + if (currentPage + 1 != lastStatusBarPage) return false; + if (SETTINGS.statusBarBattery) { + if (static_cast(powerManager.getBatteryPercentage()) != lastStatusBarBattery) return false; + } + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + const int minute = now > 0 ? static_cast(now / 60) : -1; + if (minute != lastStatusBarClockMinute) return false; + } + return true; } void MdReaderActivity::saveProgress() const { diff --git a/src/activities/reader/MdReaderActivity.h b/src/activities/reader/MdReaderActivity.h index 614364bc..78fdce84 100644 --- a/src/activities/reader/MdReaderActivity.h +++ b/src/activities/reader/MdReaderActivity.h @@ -60,6 +60,10 @@ class MdReaderActivity final : public Activity { void renderPage(); void renderStatusBar() const; + // See EpubReaderActivity for rationale — suppresses no-op minute-tick re-renders. + mutable int lastStatusBarPage = -1; + mutable int lastStatusBarBattery = -1; + mutable int lastStatusBarClockMinute = -1; void initializeReader(); bool loadPageAtOffset(size_t offset, bool startInCodeBlock, std::vector& outLines, size_t& nextOffset, @@ -91,5 +95,6 @@ class MdReaderActivity final : public Activity { void loop() override; void render(RenderLock&&) override; bool isReaderActivity() const override { return true; } + bool shouldSkipPeriodicUpdate() const override; void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override; }; \ No newline at end of file diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index fe2a1bb4..30c038fc 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include @@ -482,6 +484,29 @@ void TxtReaderActivity::renderStatusBar() const { } const bool isStarred = bookmarkStore.has(0, static_cast(currentPage)); GUI.drawStatusBar(renderer, progress, currentPage + 1, totalPages, title, 0, isStarred); + + lastStatusBarPage = currentPage + 1; + lastStatusBarBattery = SETTINGS.statusBarBattery ? static_cast(powerManager.getBatteryPercentage()) : -1; + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + lastStatusBarClockMinute = now > 0 ? static_cast(now / 60) : -1; + } else { + lastStatusBarClockMinute = -1; + } +} + +bool TxtReaderActivity::shouldSkipPeriodicUpdate() const { + if (lastStatusBarPage < 0) return false; + if (currentPage + 1 != lastStatusBarPage) return false; + if (SETTINGS.statusBarBattery) { + if (static_cast(powerManager.getBatteryPercentage()) != lastStatusBarBattery) return false; + } + if (SETTINGS.useClock && SETTINGS.statusBarClock && HalClock::isSynced()) { + const time_t now = HalClock::now(); + const int minute = now > 0 ? static_cast(now / 60) : -1; + if (minute != lastStatusBarClockMinute) return false; + } + return true; } void TxtReaderActivity::saveProgress() const { diff --git a/src/activities/reader/TxtReaderActivity.h b/src/activities/reader/TxtReaderActivity.h index 6d54c09a..58b06d69 100644 --- a/src/activities/reader/TxtReaderActivity.h +++ b/src/activities/reader/TxtReaderActivity.h @@ -39,6 +39,10 @@ class TxtReaderActivity final : public Activity { void renderPage(); void renderStatusBar() const; + // See EpubReaderActivity for rationale — suppresses no-op minute-tick re-renders. + mutable int lastStatusBarPage = -1; + mutable int lastStatusBarBattery = -1; + mutable int lastStatusBarClockMinute = -1; void initializeReader(); bool loadPageAtOffset(size_t offset, std::vector& outLines, size_t& nextOffset); @@ -60,6 +64,7 @@ class TxtReaderActivity final : public Activity { void loop() override; void render(RenderLock&&) override; bool isReaderActivity() const override { return true; } + bool shouldSkipPeriodicUpdate() const override; void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override; // Renders the last saved page to the frame buffer without flushing to display.