diff --git a/src/qEmbyApp/components/nativedanmakuoverlay.cpp b/src/qEmbyApp/components/nativedanmakuoverlay.cpp index 808814e..3640b27 100644 --- a/src/qEmbyApp/components/nativedanmakuoverlay.cpp +++ b/src/qEmbyApp/components/nativedanmakuoverlay.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -26,7 +28,9 @@ constexpr qreal kReferenceHeight = 1080.0; constexpr qreal kTopMargin = 24.0; constexpr qreal kBottomMargin = 48.0; constexpr int kResizeRebuildDebounceMs = 48; -constexpr int kDefaultFrameIntervalMs = 8; +constexpr int kFallbackFrameIntervalMs = 16; +constexpr int kMinFrameIntervalMs = 4; +constexpr int kMaxFrameIntervalMs = 33; constexpr qreal kScrollStartPadding = 32.0; constexpr qreal kScrollEndPadding = 48.0; constexpr qreal kScrollLaneGapPadding = 96.0; @@ -150,7 +154,7 @@ NativeDanmakuOverlay::NativeDanmakuOverlay(MpvController *controller, m_frameTimer = new QTimer(this); m_frameTimer->setTimerType(Qt::PreciseTimer); - m_frameTimer->setInterval(kDefaultFrameIntervalMs); + m_frameTimer->setInterval(kFallbackFrameIntervalMs); connect(m_frameTimer, &QTimer::timeout, this, [this]() { const qint64 positionMs = currentPositionMs(); if (m_lastResolvedPositionMs < 0 || positionMs < m_lastResolvedPositionMs || @@ -168,6 +172,8 @@ NativeDanmakuOverlay::NativeDanmakuOverlay(MpvController *controller, connect(m_scheduleRebuildTimer, &QTimer::timeout, this, &NativeDanmakuOverlay::rebuildScheduleNow); + updateScreenRefreshBinding(); + if (!m_controller) { return; } @@ -331,6 +337,13 @@ void NativeDanmakuOverlay::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); requestScheduleRebuild(false, false); + updateScreenRefreshBinding(); +} + +void NativeDanmakuOverlay::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + updateScreenRefreshBinding(); } void NativeDanmakuOverlay::rebuildSchedule() @@ -653,20 +666,76 @@ void NativeDanmakuOverlay::syncFrameTimer() int NativeDanmakuOverlay::targetFrameIntervalMs() const { - const QScreen *targetScreen = screen(); - if (!targetScreen && window()) { - targetScreen = window()->screen(); - } - - const qreal refreshRate = targetScreen ? targetScreen->refreshRate() : 0.0; + const QScreen *screen = targetScreen(); + const qreal refreshRate = screen ? screen->refreshRate() : 0.0; if (refreshRate <= 0.0) { - return kDefaultFrameIntervalMs; + return kFallbackFrameIntervalMs; } - const qreal desiredRefreshRate = std::max(120.0, refreshRate); - return qBound(4, - static_cast(std::lround(1000.0 / desiredRefreshRate)), - kDefaultFrameIntervalMs); + return qBound(kMinFrameIntervalMs, + static_cast(std::lround(1000.0 / refreshRate)), + kMaxFrameIntervalMs); +} + +QScreen *NativeDanmakuOverlay::targetScreen() const +{ + if (QScreen *widgetScreen = screen()) { + return widgetScreen; + } + if (const QWidget *topLevel = window()) { + if (QWindow *handle = topLevel->windowHandle()) { + if (QScreen *windowScreen = handle->screen()) { + return windowScreen; + } + } + if (QScreen *windowScreen = topLevel->screen()) { + return windowScreen; + } + } + return nullptr; +} + +void NativeDanmakuOverlay::updateScreenRefreshBinding() +{ + QWindow *currentWindow = nullptr; + if (QWidget *topLevel = window()) { + currentWindow = topLevel->windowHandle(); + } + + if (m_observedWindow != currentWindow) { + if (m_windowScreenConnection) { + QObject::disconnect(m_windowScreenConnection); + m_windowScreenConnection = {}; + } + m_observedWindow = currentWindow; + if (m_observedWindow) { + m_windowScreenConnection = + connect(m_observedWindow, &QWindow::screenChanged, this, + [this](QScreen *) { + updateScreenRefreshBinding(); + syncFrameTimer(); + }); + } + } + + QScreen *currentScreen = targetScreen(); + if (m_observedScreen == currentScreen) { + syncFrameTimer(); + return; + } + + if (m_screenRefreshConnection) { + QObject::disconnect(m_screenRefreshConnection); + m_screenRefreshConnection = {}; + } + m_observedScreen = currentScreen; + if (m_observedScreen) { + m_screenRefreshConnection = + connect(m_observedScreen, &QScreen::refreshRateChanged, this, + [this](qreal) { syncFrameTimer(); }); + } + + syncFrameTimer(); } void NativeDanmakuOverlay::refreshBasePosition(qint64 positionMs) diff --git a/src/qEmbyApp/components/nativedanmakuoverlay.h b/src/qEmbyApp/components/nativedanmakuoverlay.h index 705acf7..fbc6403 100644 --- a/src/qEmbyApp/components/nativedanmakuoverlay.h +++ b/src/qEmbyApp/components/nativedanmakuoverlay.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -14,9 +15,12 @@ class MpvController; class QPaintEvent; class QResizeEvent; +class QScreen; +class QShowEvent; class QTimer; class QVariant; class QRectF; +class QWindow; class NativeDanmakuOverlay : public QWidget { @@ -35,6 +39,7 @@ public: protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; + void showEvent(QShowEvent *event) override; private: enum class ItemType { @@ -66,6 +71,8 @@ private: void clearScheduledState(bool clearSpriteCache = false); void syncFrameTimer(); int targetFrameIntervalMs() const; + QScreen *targetScreen() const; + void updateScreenRefreshBinding(); void refreshBasePosition(qint64 positionMs); qreal currentPositionMsPrecise() const; qint64 currentPositionMs() const; @@ -80,6 +87,10 @@ private: QPointer m_controller; QTimer *m_frameTimer = nullptr; QTimer *m_scheduleRebuildTimer = nullptr; + QPointer m_observedWindow; + QPointer m_observedScreen; + QMetaObject::Connection m_windowScreenConnection; + QMetaObject::Connection m_screenRefreshConnection; QElapsedTimer m_positionClock; QList m_comments; QList m_sortedComments;