diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 1d476a789..ecd0852da 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/fade_wrap.h" #include "ui/wrap/padding_wrap.h" #include "ui/platform/ui_platform_utility.h" +#include "ui/gl/gl_surface.h" #include "ui/toast/toast.h" #include "ui/empty_userpic.h" #include "ui/emoji_config.h" @@ -50,35 +51,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include namespace Calls { -namespace { -#if 1 -#define USE_OPENGL_OVERLAY_WIDGET 1 -#else // Q_OS_MAC && !OS_MAC_OLD -#define USE_OPENGL_OVERLAY_WIDGET 0 -#endif // Q_OS_MAC && !OS_MAC_OLD - -#if USE_OPENGL_OVERLAY_WIDGET -using IncomingParent = Ui::RpWidgetWrap; -#else // USE_OPENGL_OVERLAY_WIDGET -using IncomingParent = Ui::RpWidget; -#endif // USE_OPENGL_OVERLAY_WIDGET - -} // namespace - -class Panel::Incoming final : public IncomingParent { +class Panel::Incoming final { public: Incoming( not_null parent, not_null track); + [[nodiscard]] not_null widget() const; + [[nodiscard]] not_null rp() const; + private: - void paintEvent(QPaintEvent *e) override; + void paint(QPainter &p, const QRegion &clip, bool opengl); void initBottomShadow(); void fillTopShadow(QPainter &p); void fillBottomShadow(QPainter &p); + [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( + Ui::GL::Capabilities capabilities); + + const std::unique_ptr _surface; const not_null _track; QPixmap _bottomShadow; @@ -87,35 +80,76 @@ private: Panel::Incoming::Incoming( not_null parent, not_null track) -: IncomingParent(parent) +: _surface(Ui::GL::CreateSurface( + parent, + [=](Ui::GL::Capabilities capabilities) { + return chooseRenderer(capabilities); + })) , _track(track) { initBottomShadow(); - setAttribute(Qt::WA_OpaquePaintEvent); - setAttribute(Qt::WA_TransparentForMouseEvents); + widget()->setAttribute(Qt::WA_OpaquePaintEvent); + widget()->setAttribute(Qt::WA_TransparentForMouseEvents); } -void Panel::Incoming::paintEvent(QPaintEvent *e) { - QPainter p(this); +not_null Panel::Incoming::widget() const { + return _surface->rpWidget(); +} +not_null Panel::Incoming::rp() const { + return _surface.get(); +} + +Ui::GL::ChosenRenderer Panel::Incoming::chooseRenderer( + Ui::GL::Capabilities capabilities) { + class Renderer : public Ui::GL::Renderer { + public: + Renderer(not_null owner) : _owner(owner) { + } + + void paintFallback( + QPainter &&p, + const QRegion &clip, + Ui::GL::Backend backend) override { + _owner->paint( + p, + clip.boundingRect(), + backend == Ui::GL::Backend::OpenGL); + } + + private: + const not_null _owner; + + }; + + return { + .renderer = std::make_unique(this), + .backend = (capabilities.supported + ? Ui::GL::Backend::OpenGL + : Ui::GL::Backend::Raster), + }; +} + +void Panel::Incoming::paint(QPainter &p, const QRegion &clip, bool opengl) { const auto [image, rotation] = _track->frameOriginalWithRotation(); if (image.isNull()) { - p.fillRect(e->rect(), Qt::black); + p.fillRect(clip.boundingRect(), Qt::black); } else { + const auto rect = widget()->rect(); using namespace Media::View; auto hq = PainterHighQualityEnabler(p); - if (UsePainterRotation(rotation, USE_OPENGL_OVERLAY_WIDGET)) { + if (UsePainterRotation(rotation, opengl)) { if (rotation) { p.save(); p.rotate(rotation); } - p.drawImage(RotatedRect(rect(), rotation), image); + p.drawImage(RotatedRect(rect, rotation), image); if (rotation) { p.restore(); } } else if (rotation) { - p.drawImage(rect(), RotateFrameImage(image, rotation)); + p.drawImage(rect, RotateFrameImage(image, rotation)); } else { - p.drawImage(rect(), image); + p.drawImage(rect, image); } fillBottomShadow(p); fillTopShadow(p); @@ -146,18 +180,19 @@ void Panel::Incoming::initBottomShadow() { void Panel::Incoming::fillTopShadow(QPainter &p) { #ifdef Q_OS_WIN - const auto width = parentWidget()->width(); + const auto width = widget()->parentWidget()->width(); const auto position = QPoint(width - st::callTitleShadow.width(), 0); const auto shadowArea = QRect( position, st::callTitleShadow.size()); - const auto fill = shadowArea.intersected(geometry()).translated(-pos()); + const auto fill = shadowArea.intersected( + widget()->geometry()).translated(-widget()->pos()); if (fill.isEmpty()) { return; } p.save(); p.setClipRect(fill); - st::callTitleShadow.paint(p, position - pos(), width); + st::callTitleShadow.paint(p, position - widget()->pos(), width); p.restore(); #endif // Q_OS_WIN } @@ -165,10 +200,11 @@ void Panel::Incoming::fillTopShadow(QPainter &p) { void Panel::Incoming::fillBottomShadow(QPainter &p) { const auto shadowArea = QRect( 0, - parentWidget()->height() - st::callBottomShadowSize, - parentWidget()->width(), + widget()->parentWidget()->height() - st::callBottomShadowSize, + widget()->parentWidget()->width(), st::callBottomShadowSize); - const auto fill = shadowArea.intersected(geometry()).translated(-pos()); + const auto fill = shadowArea.intersected( + widget()->geometry()).translated(-widget()->pos()); if (fill.isEmpty()) { return; } @@ -178,7 +214,8 @@ void Panel::Incoming::fillBottomShadow(QPainter &p) { _bottomShadow, QRect( 0, - factor * (fill.y() - shadowArea.translated(-pos()).y()), + (factor + * (fill.y() - shadowArea.translated(-widget()->pos()).y())), factor, factor * fill.height())); } @@ -394,7 +431,7 @@ void Panel::refreshIncomingGeometry() { Expects(_incoming != nullptr); if (_incomingFrameSize.isEmpty()) { - _incoming->hide(); + _incoming->widget()->hide(); return; } const auto to = widget()->size(); @@ -411,8 +448,8 @@ void Panel::refreshIncomingGeometry() { const auto pos = QPoint( (to.width() - use.width()) / 2, (to.height() - use.height()) / 2); - _incoming->setGeometry(QRect(pos, use)); - _incoming->show(); + _incoming->widget()->setGeometry(QRect(pos, use)); + _incoming->widget()->show(); } void Panel::reinitWithCall(Call *call) { @@ -449,7 +486,7 @@ void Panel::reinitWithCall(Call *call) { _incoming = std::make_unique( widget(), _call->videoIncoming()); - _incoming->hide(); + _incoming->widget()->hide(); _call->mutedValue( ) | rpl::start_with_next([=](bool mute) { @@ -480,12 +517,12 @@ void Panel::reinitWithCall(Call *call) { setIncomingSize((rotation == 90 || rotation == 270) ? QSize(frame.height(), frame.width()) : frame.size()); - if (_incoming->isHidden()) { + if (_incoming->widget()->isHidden()) { return; } const auto incoming = incomingFrameGeometry(); const auto outgoing = outgoingFrameGeometry(); - _incoming->update(); + _incoming->widget()->update(); if (incoming.intersects(outgoing)) { widget()->update(outgoing); } @@ -497,7 +534,7 @@ void Panel::reinitWithCall(Call *call) { const auto outgoing = outgoingFrameGeometry(); widget()->update(outgoing); if (incoming.intersects(outgoing)) { - _incoming->update(); + _incoming->widget()->update(); } }, _callLifetime); @@ -541,7 +578,7 @@ void Panel::reinitWithCall(Call *call) { _name->setText(_user->name); updateStatusText(_call->state()); - _incoming->lower(); + _incoming->widget()->lower(); } void Panel::createRemoteAudioMute() { @@ -606,7 +643,7 @@ void Panel::showControls() { _cancel->setVisible(_cancel->toggled()); const auto shown = !_incomingFrameSize.isEmpty(); - _incoming->setVisible(shown); + _incoming->widget()->setVisible(shown); _name->setVisible(!shown); _status->setVisible(!shown); _userpic->setVisible(!shown); @@ -650,9 +687,9 @@ void Panel::toggleFullScreen(bool fullscreen) { } QRect Panel::incomingFrameGeometry() const { - return (!_incoming || _incoming->isHidden()) + return (!_incoming || _incoming->widget()->isHidden()) ? QRect() - : _incoming->geometry(); + : _incoming->widget()->geometry(); } QRect Panel::outgoingFrameGeometry() const { @@ -788,13 +825,13 @@ void Panel::paint(QRect clip) { Painter p(widget()); auto region = QRegion(clip); - if (!_incoming->isHidden()) { - region = region.subtracted(QRegion(_incoming->geometry())); + if (!_incoming->widget()->isHidden()) { + region = region.subtracted(QRegion(_incoming->widget()->geometry())); } for (const auto rect : region) { p.fillRect(rect, st::callBgOpaque); } - if (_incoming && _incoming->isHidden()) { + if (_incoming && _incoming->widget()->isHidden()) { _call->videoIncoming()->markFrameShown(); } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp b/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp index 0b5a7736b..72cec93de 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp @@ -13,11 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "webrtc/webrtc_video_track.h" #include "ui/painter.h" #include "ui/abstract_button.h" +#include "ui/gl/gl_surface.h" #include "ui/effects/animations.h" #include "ui/effects/cross_line.h" #include "lang/lang_keys.h" #include "styles/style_calls.h" +#include + namespace Calls::Group { namespace { @@ -57,31 +60,64 @@ LargeVideo::LargeVideo( bool visible, rpl::producer track, rpl::producer pinned) -: _content(parent, [=](QRect clip) { paint(clip); }) +: _content(Ui::GL::CreateSurface( + parent, + [=](Ui::GL::Capabilities capabilities) { + return chooseRenderer(capabilities); + })) , _st(st) , _pinButton((_st.pinPosition.x() >= 0) - ? std::make_unique(&_content, st) + ? std::make_unique(widget(), st) : nullptr) , _smallLayout(!_pinButton) { - _content.setVisible(visible); + widget()->setVisible(visible); if (_smallLayout) { - _content.setCursor(style::cur_pointer); + widget()->setCursor(style::cur_pointer); } setup(std::move(track), std::move(pinned)); } LargeVideo::~LargeVideo() = default; +Ui::GL::ChosenRenderer LargeVideo::chooseRenderer( + Ui::GL::Capabilities capabilities) { + class Renderer : public Ui::GL::Renderer { + public: + Renderer(not_null owner) : _owner(owner) { + } + + void paintFallback( + QPainter &&p, + const QRegion &clip, + Ui::GL::Backend backend) override { + _owner->paint( + clip.boundingRect(), + backend == Ui::GL::Backend::OpenGL); + } + + private: + const not_null _owner; + + }; + + return { + .renderer = std::make_unique(this), + .backend = (capabilities.supported + ? Ui::GL::Backend::OpenGL + : Ui::GL::Backend::Raster), + }; +} + void LargeVideo::raise() { - _content.raise(); + widget()->raise(); } void LargeVideo::setVisible(bool visible) { - _content.setVisible(visible); + widget()->setVisible(visible); } void LargeVideo::setGeometry(int x, int y, int width, int height) { - _content.setGeometry(x, y, width, height); + widget()->setGeometry(x, y, width, height); if (width > 0 && height > 0) { const auto kMedium = style::ConvertScale(380); const auto kSmall = style::ConvertScale(200); @@ -98,7 +134,7 @@ void LargeVideo::setControlsShown(float64 shown) { return; } _controlsShownRatio = shown; - _content.update(); + widget()->update(); updateControlsGeometry(); } @@ -119,19 +155,27 @@ rpl::producer LargeVideo::trackSizeValue() const { rpl::producer LargeVideo::requestedQuality() const { using namespace rpl::mappers; return rpl::combine( - _content.shownValue(), + _content->shownValue(), _requestedQuality.value() ) | rpl::filter([=](bool shown, auto) { return shown; }) | rpl::map(_2); } +rpl::lifetime &LargeVideo::lifetime() { + return _content->lifetime(); +} + +not_null LargeVideo::widget() const { + return _content->rpWidget(); +} + void LargeVideo::setup( rpl::producer track, rpl::producer pinned) { - _content.setAttribute(Qt::WA_OpaquePaintEvent); + widget()->setAttribute(Qt::WA_OpaquePaintEvent); - _content.events( + _content->events( ) | rpl::start_with_next([=](not_null e) { const auto type = e->type(); if (type == QEvent::Enter && _pinButton) { @@ -147,21 +191,21 @@ void LargeVideo::setup( e.get())->button() == Qt::LeftButton && _mouseDown) { _mouseDown = false; - if (!_content.isHidden()) { + if (!widget()->isHidden()) { _clicks.fire({}); } } - }, _content.lifetime()); + }, _content->lifetime()); rpl::combine( - _content.shownValue(), + _content->shownValue(), std::move(track) ) | rpl::map([=](bool shown, LargeVideoTrack track) { return shown ? track : LargeVideoTrack(); }) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](LargeVideoTrack track) { _track = track; - _content.update(); + widget()->update(); _trackLifetime.destroy(); if (!track.track) { @@ -176,12 +220,12 @@ void LargeVideo::setup( } else { _trackSize = size; } - _content.update(); + widget()->update(); }, _trackLifetime); if (const auto size = track.track->frameSize(); !size.isEmpty()) { _trackSize = size; } - }, _content.lifetime()); + }, _content->lifetime()); setupControls(std::move(pinned)); } @@ -194,7 +238,7 @@ void LargeVideo::togglePinShown(bool shown) { } _pinButton->shown = shown; _pinButton->shownAnimation.start( - [=] { updateControlsGeometry(); _content.update(); }, + [=] { updateControlsGeometry(); widget()->update(); }, shown ? 0. : 1., shown ? 1. : 0., st::slideWrapDuration); @@ -211,13 +255,13 @@ void LargeVideo::setupControls(rpl::producer pinned) { : tr::lng_pinned_pin)(tr::now)); updateControlsGeometry(); } - _content.update(); - }, _content.lifetime()); + widget()->update(); + }, _content->lifetime()); - _content.sizeValue( + _content->sizeValue( ) | rpl::start_with_next([=](QSize size) { updateControlsGeometry(); - }, _content.lifetime()); + }, _content->lifetime()); } void LargeVideo::updateControlsGeometry() { @@ -236,20 +280,20 @@ void LargeVideo::updateControlsGeometry() { 0, _pinButton->shownAnimation.value(_pinButton->shown ? 1. : 0.)); _pinButton->rect = QRect( - _content.width() - _st.pinPosition.x() - buttonWidth, + widget()->width() - _st.pinPosition.x() - buttonWidth, _st.pinPosition.y() - slide, buttonWidth, buttonHeight); _pinButton->area.setGeometry( - _content.width() - fullWidth, + widget()->width() - fullWidth, -slide, fullWidth, fullHeight); } } -void LargeVideo::paint(QRect clip) { - auto p = Painter(&_content); +void LargeVideo::paint(QRect clip, bool opengl) { + auto p = Painter(widget()); const auto fill = [&](QRect rect) { if (rect.intersects(clip)) { p.fillRect(rect.intersected(clip), st::groupCallMembersBg); @@ -264,7 +308,7 @@ void LargeVideo::paint(QRect clip) { } auto hq = PainterHighQualityEnabler(p); using namespace Media::View; - const auto size = _content.size(); + const auto size = widget()->size(); const auto scaled = FlipSizeByRotation( image.size(), rotation @@ -272,7 +316,7 @@ void LargeVideo::paint(QRect clip) { const auto left = (size.width() - scaled.width()) / 2; const auto top = (size.height() - scaled.height()) / 2; const auto target = QRect(QPoint(left, top), scaled); - if (UsePainterRotation(rotation, USE_OPENGL_LARGE_VIDEO)) { + if (UsePainterRotation(rotation, opengl)) { if (rotation) { p.save(); p.rotate(rotation); @@ -307,8 +351,8 @@ void LargeVideo::paint(QRect clip) { } void LargeVideo::paintControls(Painter &p, QRect clip) { - const auto width = _content.width(); - const auto height = _content.height(); + const auto width = widget()->width(); + const auto height = widget()->height(); // Pin. if (_pinButton && _pinButton->rect.intersects(clip)) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_large_video.h b/Telegram/SourceFiles/calls/group/calls_group_large_video.h index c9805d948..997719582 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_large_video.h +++ b/Telegram/SourceFiles/calls/group/calls_group_large_video.h @@ -9,12 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" -#if 1 -#define USE_OPENGL_LARGE_VIDEO 1 -#else -#define USE_OPENGL_LARGE_VIDEO 0 -#endif // Q_OS_MAC - namespace style { struct GroupCallLargeVideo; } // namespace style @@ -25,6 +19,11 @@ class VideoTrack; namespace Ui { class AbstractButton; +class RpWidgetWrap; +namespace GL { +struct Capabilities; +struct ChosenRenderer; +} // namespace GL } // namespace Ui namespace Calls::Group { @@ -77,45 +76,26 @@ public: [[nodiscard]] rpl::producer trackSizeValue() const; [[nodiscard]] rpl::producer requestedQuality() const; - [[nodiscard]] rpl::lifetime &lifetime() { - return _content.lifetime(); - } + [[nodiscard]] rpl::lifetime &lifetime(); private: -#if USE_OPENGL_LARGE_VIDEO - using ContentParent = Ui::RpWidgetWrap; -#else // USE_OPENGL_OVERLAY_WIDGET - using ContentParent = Ui::RpWidget; -#endif // USE_OPENGL_OVERLAY_WIDGET - - class Content final : public ContentParent { - public: - Content(QWidget *parent, Fn paint) - : ContentParent(parent), _paint(std::move(paint)) { - Expects(_paint != nullptr); - } - - private: - void paintEvent(QPaintEvent *e) override { - _paint(e->rect()); - } - - Fn _paint; - - }; - struct PinButton; + [[nodiscard]] not_null widget() const; + void setup( rpl::producer track, rpl::producer pinned); void setupControls(rpl::producer pinned); - void paint(QRect clip); + void paint(QRect clip, bool opengl); void paintControls(Painter &p, QRect clip); void updateControlsGeometry(); void togglePinShown(bool shown); - Content _content; + [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( + Ui::GL::Capabilities capabilities); + + const std::unique_ptr _content; const style::GroupCallLargeVideo &_st; LargeVideoTrack _track; QImage _shadow; diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index e06e5a40e..ce995e385 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -1263,11 +1263,9 @@ void Panel::setupPinnedVideo() { raw->events( ) | rpl::start_with_next([=](not_null e) { if (e->type() == QEvent::Enter) { - LOG(("Track Enter")); Ui::Integration::Instance().registerLeaveSubscription(raw); toggleWideControls(true); } else if (e->type() == QEvent::Leave) { - LOG(("Track Leave")); Ui::Integration::Instance().unregisterLeaveSubscription(raw); toggleWideControls(false); } @@ -1281,12 +1279,10 @@ void Panel::toggleWideControls(bool shown) { return; } _showWideControls = shown; - LOG(("On Main Scheduled")); crl::on_main(widget(), [=] { if (_wideControlsShown == _showWideControls) { return; } - LOG(("On Main Fired: %1").arg(Logs::b(_showWideControls))); _wideControlsShown = _showWideControls; _wideControlsAnimation.start( [=] { updateButtonsGeometry(); }, @@ -1343,7 +1339,7 @@ void Panel::setupAllowedToSpeakToasts() { Ui::ShowMultilineToast({ .parentOverride = widget(), .text = { tr::lng_group_call_can_speak_here(tr::now) }, - }); + }); } else { const auto real = _call->lookupReal(); const auto name = (real && !real->title().isEmpty()) @@ -1355,7 +1351,7 @@ void Panel::setupAllowedToSpeakToasts() { lt_chat, Ui::Text::Bold(name), Ui::Text::WithEntities), - }); + }); } }, widget()->lifetime()); } @@ -1866,10 +1862,8 @@ void Panel::trackControls(bool track) { raw->events( ) | rpl::start_with_next([=](not_null e) { if (e->type() == QEvent::Enter) { - LOG(("Track Enter")); toggleWideControls(true); } else if (e->type() == QEvent::Leave) { - LOG(("Track Leave")); toggleWideControls(false); } }, _trackControlsOverStateLifetime); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index d7c3f96c5..6605440c7 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -300,6 +300,8 @@ public: [[nodiscard]] ImageLocation userpicLocation() const { return _userpic.location(); } + + static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL); [[nodiscard]] bool userpicPhotoUnknown() const { return (_userpicPhotoId == kUnknownPhotoId); } @@ -411,8 +413,6 @@ private: void setUserpicChecked(PhotoId photoId, const ImageLocation &location); - static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL); - const not_null _owner; mutable Data::CloudImage _userpic; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index ec783ec5c..e1adf9abe 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -474,7 +474,9 @@ void OverlayWidget::updateGeometry() { const auto useSizeHack = (USE_OPENGL_OVERLAY_WIDGET && Platform::IsWindows()); const auto use = available.marginsAdded({ 0, 0, 0, 1 }); - const auto mask = useSizeHack ? QRegion(available) : QRegion(); + const auto mask = useSizeHack + ? QRegion(QRect(QPoint(), available.size())) + : QRegion(); if ((geometry() == use) && (!useSizeHack || (window && window->mask() == mask))) { return; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 7483549a0..317324984 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -63,9 +63,9 @@ struct OverlayParentTraits : Ui::RpWidgetDefaultTraits { }; #if USE_OPENGL_OVERLAY_WIDGET -using OverlayParent = Ui::RpWidgetWrap; +using OverlayParent = Ui::RpWidgetBase; #else // USE_OPENGL_OVERLAY_WIDGET -using OverlayParent = Ui::RpWidgetWrap; +using OverlayParent = Ui::RpWidgetBase; #endif // USE_OPENGL_OVERLAY_WIDGET class OverlayWidget final diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index 0628c19c0..6f7c7777a 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/fade_wrap.h" #include "ui/widgets/shadow.h" #include "ui/text/format_values.h" +#include "ui/gl/gl_surface.h" #include "window/window_controller.h" #include "styles/style_widgets.h" #include "styles/style_window.h" @@ -372,35 +373,77 @@ QImage RotateFrameImage(QImage image, int rotation) { PipPanel::PipPanel( QWidget *parent, - Fn paint) -: _parent(parent) + Fn paint) +: _content(Ui::GL::CreateSurface( + parent, + [=](Ui::GL::Capabilities capabilities) { + return chooseRenderer(capabilities); + })) +, _parent(parent) , _paint(std::move(paint)) { } +Ui::GL::ChosenRenderer PipPanel::chooseRenderer( + Ui::GL::Capabilities capabilities) { + class Renderer : public Ui::GL::Renderer { + public: + Renderer(not_null owner) : _owner(owner) { + } + + void paintFallback( + QPainter &&p, + const QRegion &clip, + Ui::GL::Backend backend) override { + _owner->paint( + p, + clip, + backend == Ui::GL::Backend::OpenGL); + } + + private: + const not_null _owner; + + }; + + return { + .renderer = std::make_unique(this), + .backend = (capabilities.supported + ? Ui::GL::Backend::OpenGL + : Ui::GL::Backend::Raster), + }; +} + void PipPanel::init() { - setWindowFlags(Qt::Tool + widget()->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); - setAttribute(Qt::WA_ShowWithoutActivating); - setAttribute(Qt::WA_MacAlwaysShowToolWindow); - setAttribute(Qt::WA_NoSystemBackground); - setAttribute(Qt::WA_TranslucentBackground); - Ui::Platform::IgnoreAllActivation(this); - Ui::Platform::InitOnTopPanel(this); - setMouseTracking(true); - resize(0, 0); - hide(); - createWinId(); + widget()->setAttribute(Qt::WA_ShowWithoutActivating); + widget()->setAttribute(Qt::WA_MacAlwaysShowToolWindow); + widget()->setAttribute(Qt::WA_NoSystemBackground); + widget()->setAttribute(Qt::WA_TranslucentBackground); + Ui::Platform::IgnoreAllActivation(widget()); + Ui::Platform::InitOnTopPanel(widget()); + widget()->setMouseTracking(true); + widget()->resize(0, 0); + widget()->hide(); + widget()->createWinId(); + + rp()->shownValue( + ) | rpl::filter([=](bool shown) { + return shown; + }) | rpl::start_with_next([=] { + // Workaround Qt's forced transient parent. + Ui::Platform::ClearTransientParent(widget()); + }, rp()->lifetime()); } -void PipPanel::setVisibleHook(bool visible) { - PipParent::setVisibleHook(visible); +not_null PipPanel::widget() const { + return _content->rpWidget(); +} - // workaround Qt's forced transient parent - if (visible) { - Ui::Platform::ClearTransientParent(this); - } +not_null PipPanel::rp() const { + return _content.get(); } void PipPanel::setAspectRatio(QSize ratio) { @@ -411,7 +454,7 @@ void PipPanel::setAspectRatio(QSize ratio) { if (_ratio.isEmpty()) { _ratio = QSize(1, 1); } - if (!size().isEmpty()) { + if (!widget()->size().isEmpty()) { setPosition(countPosition()); } } @@ -429,7 +472,7 @@ void PipPanel::setPosition(Position position) { } QRect PipPanel::inner() const { - return rect().marginsRemoved(_padding); + return widget()->rect().marginsRemoved(_padding); } RectParts PipPanel::attached() const { @@ -452,7 +495,10 @@ rpl::producer<> PipPanel::saveGeometryRequests() const { } QScreen *PipPanel::myScreen() const { - return windowHandle() ? windowHandle()->screen() : nullptr; + if (const auto window = widget()->windowHandle()) { + return window->screen(); + } + return nullptr; } PipPanel::Position PipPanel::countPosition() const { @@ -462,7 +508,7 @@ PipPanel::Position PipPanel::countPosition() const { } auto result = Position(); result.screen = screen->geometry(); - result.geometry = geometry().marginsRemoved(_padding); + result.geometry = widget()->geometry().marginsRemoved(_padding); const auto available = screen->availableGeometry(); const auto skip = st::pipBorderSkip; const auto left = result.geometry.x(); @@ -501,9 +547,9 @@ void PipPanel::setPositionDefault() { return nullptr; }; const auto parentScreen = widgetScreen(_parent); - const auto myScreen = widgetScreen(this); + const auto myScreen = widgetScreen(widget()); if (parentScreen && myScreen && myScreen != parentScreen) { - windowHandle()->setScreen(parentScreen); + widget()->windowHandle()->setScreen(parentScreen); } const auto screen = parentScreen ? parentScreen @@ -583,21 +629,19 @@ void PipPanel::setPositionOnScreen(Position position, QRect available) { geometry += _padding; - setGeometry(geometry); - setMinimumSize(minimalSize); - setMaximumSize( + widget()->setGeometry(geometry); + widget()->setMinimumSize(minimalSize); + widget()->setMaximumSize( std::max(minimalSize.width(), maximalSize.width()), std::max(minimalSize.height(), maximalSize.height())); updateDecorations(); - update(); + widget()->update(); } -void PipPanel::paintEvent(QPaintEvent *e) { - QPainter p(this); - - if (_useTransparency && USE_OPENGL_PIP_WIDGET) { +void PipPanel::paint(QPainter &p, const QRegion &clip, bool opengl) { + if (_useTransparency && opengl) { p.setCompositionMode(QPainter::CompositionMode_Source); - for (const auto rect : e->region()) { + for (const auto rect : clip) { p.fillRect(rect, Qt::transparent); } p.setCompositionMode(QPainter::CompositionMode_SourceOver); @@ -622,27 +666,27 @@ void PipPanel::paintEvent(QPaintEvent *e) { request.radius = ImageRoundRadius::Large; if (_useTransparency) { const auto sides = RectPart::AllSides & ~_attached; - Ui::Shadow::paint(p, inner, width(), st::callShadow); + Ui::Shadow::paint(p, inner, widget()->width(), st::callShadow); } - _paint(p, request); + _paint(p, request, opengl); } -void PipPanel::mousePressEvent(QMouseEvent *e) { - if (e->button() != Qt::LeftButton) { +void PipPanel::handleMousePress(QPoint position, Qt::MouseButton button) { + if (button != Qt::LeftButton) { return; } - updateOverState(e->pos()); + updateOverState(position); _pressState = _overState; - _pressPoint = e->globalPos(); + _pressPoint = QCursor::pos(); } -void PipPanel::mouseReleaseEvent(QMouseEvent *e) { - if (e->button() != Qt::LeftButton || !base::take(_pressState)) { +void PipPanel::handleMouseRelease(QPoint position, Qt::MouseButton button) { + if (button != Qt::LeftButton || !base::take(_pressState)) { return; } else if (!base::take(_dragState)) { //playbackPauseResume(); } else { - finishDrag(e->globalPos()); + finishDrag(QCursor::pos()); } } @@ -656,26 +700,28 @@ void PipPanel::updateOverState(QPoint point) { const auto top = count(RectPart::Top, _padding.top()); const auto right = count(RectPart::Right, _padding.right()); const auto bottom = count(RectPart::Bottom, _padding.bottom()); + const auto width = widget()->width(); + const auto height = widget()->height(); const auto overState = [&] { if (point.x() < left) { if (point.y() < top) { return RectPart::TopLeft; - } else if (point.y() >= height() - bottom) { + } else if (point.y() >= height - bottom) { return RectPart::BottomLeft; } else { return RectPart::Left; } - } else if (point.x() >= width() - right) { + } else if (point.x() >= width - right) { if (point.y() < top) { return RectPart::TopRight; - } else if (point.y() >= height() - bottom) { + } else if (point.y() >= height - bottom) { return RectPart::BottomRight; } else { return RectPart::Right; } } else if (point.y() < top) { return RectPart::Top; - } else if (point.y() >= height() - bottom) { + } else if (point.y() >= height - bottom) { return RectPart::Bottom; } else { return RectPart::Center; @@ -683,7 +729,7 @@ void PipPanel::updateOverState(QPoint point) { }(); if (_overState != overState) { _overState = overState; - setCursor([&] { + widget()->setCursor([&] { switch (_overState) { case RectPart::Center: return style::cur_pointer; @@ -705,19 +751,19 @@ void PipPanel::updateOverState(QPoint point) { } } -void PipPanel::mouseMoveEvent(QMouseEvent *e) { +void PipPanel::handleMouseMove(QPoint position) { if (!_pressState) { - updateOverState(e->pos()); + updateOverState(position); return; } - const auto point = e->globalPos(); + const auto point = QCursor::pos(); const auto distance = QApplication::startDragDistance(); if (!_dragState && (point - _pressPoint).manhattanLength() > distance && !_dragDisabled) { _dragState = _pressState; updateDecorations(); - _dragStartGeometry = geometry().marginsRemoved(_padding); + _dragStartGeometry = widget()->geometry().marginsRemoved(_padding); } if (_dragState) { if (Platform::IsWayland()) { @@ -733,9 +779,9 @@ void PipPanel::startSystemDrag() { const auto stateEdges = RectPartToQtEdges(*_dragState); if (stateEdges) { - windowHandle()->startSystemResize(stateEdges); + widget()->windowHandle()->startSystemResize(stateEdges); } else { - windowHandle()->startSystemMove(); + widget()->windowHandle()->startSystemMove(); } } @@ -780,14 +826,14 @@ void PipPanel::processDrag(QPoint point) { } else { const auto newGeometry = valid.marginsAdded(_padding); _positionAnimation.stop(); - setGeometry(newGeometry); + widget()->setGeometry(newGeometry); } } void PipPanel::finishDrag(QPoint point) { const auto screen = ScreenFromPosition(point); - const auto inner = geometry().marginsRemoved(_padding); - const auto position = pos(); + const auto inner = widget()->geometry().marginsRemoved(_padding); + const auto position = widget()->pos(); const auto clamped = [&] { auto result = position; if (Platform::IsWayland()) { @@ -818,7 +864,8 @@ void PipPanel::finishDrag(QPoint point) { void PipPanel::updatePositionAnimated() { const auto progress = _positionAnimation.value(1.); if (!_positionAnimation.animating()) { - move(_positionAnimationTo - QPoint(_padding.left(), _padding.top())); + widget()->move(_positionAnimationTo + - QPoint(_padding.left(), _padding.top())); if (!_dragState) { updateDecorations(); } @@ -826,7 +873,7 @@ void PipPanel::updatePositionAnimated() { } const auto from = QPointF(_positionAnimationFrom); const auto to = QPointF(_positionAnimationTo); - move((from + (to - from) * progress).toPoint() + widget()->move((from + (to - from) * progress).toPoint() - QPoint(_padding.left(), _padding.top())); } @@ -835,7 +882,8 @@ void PipPanel::moveAnimated(QPoint to) { return; } _positionAnimationTo = to; - _positionAnimationFrom = pos() + QPoint(_padding.left(), _padding.top()); + _positionAnimationFrom = widget()->pos() + + QPoint(_padding.left(), _padding.top()); _positionAnimation.stop(); _positionAnimation.start( [=] { updatePositionAnimated(); }, @@ -868,9 +916,9 @@ void PipPanel::updateDecorations() { _attached = position.attached; _padding = padding; _useTransparency = use; - setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); - setGeometry(newGeometry); - update(); + widget()->setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); + widget()->setGeometry(newGeometry); + widget()->update(); } Pip::Pip( @@ -886,7 +934,9 @@ Pip::Pip( , _instance(std::move(shared), [=] { waitingAnimationCallback(); }) , _panel( _delegate->pipParentWidget(), - [=](QPainter &p, const FrameRequest &request) { paint(p, request); }) + [=](QPainter &p, const FrameRequest &request, bool opengl) { + paint(p, request, opengl); + }) , _playbackProgress(std::make_unique()) , _rotation(data->owner().mediaRotation().get(data)) , _roundRect(ImageRoundRadius::Large, st::radialBg) @@ -899,7 +949,7 @@ Pip::Pip( _data->session().account().sessionChanges( ) | rpl::start_with_next([=] { _destroy(); - }, _panel.lifetime()); + }, _panel.rp()->lifetime()); } Pip::~Pip() = default; @@ -920,14 +970,14 @@ void Pip::setupPanel() { }(); _panel.setAspectRatio(FlipSizeByRotation(size, _rotation)); _panel.setPosition(Deserialize(_delegate->pipLoadGeometry())); - _panel.show(); + _panel.widget()->show(); _panel.saveGeometryRequests( ) | rpl::start_with_next([=] { saveGeometry(); - }, _panel.lifetime()); + }, _panel.rp()->lifetime()); - _panel.events( + _panel.rp()->events( ) | rpl::start_with_next([=](not_null e) { const auto mousePosition = [&] { return static_cast(e.get())->pos(); @@ -951,11 +1001,11 @@ void Pip::setupPanel() { handleDoubleClick(mouseButton()); break; } - }, _panel.lifetime()); + }, _panel.rp()->lifetime()); } void Pip::handleClose() { - crl::on_main(&_panel, [=] { + crl::on_main(_panel.widget(), [=] { _destroy(); }); } @@ -965,6 +1015,7 @@ void Pip::handleLeave() { } void Pip::handleMouseMove(QPoint position) { + _panel.handleMouseMove(position); setOverState(computeState(position)); seekUpdate(position); } @@ -978,7 +1029,7 @@ void Pip::setOverState(OverState state) { const auto nowShown = (_over != OverState::None); if ((was != OverState::None) != nowShown) { _controlsShown.start( - [=] { _panel.update(); }, + [=] { _panel.widget()->update(); }, nowShown ? 0. : 1., nowShown ? 1. : 0., st::fadeWrapDuration, @@ -987,7 +1038,7 @@ void Pip::setOverState(OverState state) { if (!_pressed) { updateActiveState(was); } - _panel.update(); + _panel.widget()->update(); } void Pip::setPressedState(std::optional state) { @@ -1012,7 +1063,7 @@ void Pip::updateActiveState(OverState was) { const auto now = (activeState() == button.state); if ((was == button.state) != now) { button.active.start( - [=, &button] { _panel.update(button.icon); }, + [=, &button] { _panel.widget()->update(button.icon); }, now ? 0. : 1., now ? 1. : 0., st::fadeWrapDuration, @@ -1026,6 +1077,7 @@ void Pip::updateActiveState(OverState was) { } void Pip::handleMousePress(QPoint position, Qt::MouseButton button) { + _panel.handleMousePress(position, button); if (button != Qt::LeftButton) { return; } @@ -1037,6 +1089,7 @@ void Pip::handleMousePress(QPoint position, Qt::MouseButton button) { } void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) { + _panel.handleMouseRelease(position, button); if (button != Qt::LeftButton) { return; } @@ -1053,7 +1106,7 @@ void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) { _lastHandledPress = _over; switch (_over) { - case OverState::Close: _panel.close(); break; + case OverState::Close: _panel.widget()->close(); break; case OverState::Enlarge: _closeAndContinue(); break; case OverState::Other: playbackPauseResume(); break; } @@ -1120,7 +1173,7 @@ void Pip::setupButtons() { _enlarge.state = OverState::Enlarge; _playback.state = OverState::Playback; _play.state = OverState::Other; - _panel.sizeValue( + _panel.rp()->sizeValue( ) | rpl::map([=] { return _panel.inner(); }) | rpl::start_with_next([=](QRect rect) { @@ -1162,12 +1215,12 @@ void Pip::setupButtons() { playbackHeight); _playback.icon = _playback.area.marginsRemoved( { playbackSkip, playbackSkip, playbackSkip, playbackSkip }); - }, _panel.lifetime()); + }, _panel.rp()->lifetime()); _playbackProgress->setValueChangedCallback([=]( float64 value, float64 receivedTill) { - _panel.update(_playback.area); + _panel.widget()->update(_playback.area); }); } @@ -1179,7 +1232,7 @@ void Pip::updatePlayPauseResumeState(const Player::TrackState &state) { auto showPause = Player::ShowPauseIcon(state.state); if (showPause != _showPause) { _showPause = showPause; - _panel.update(); + _panel.widget()->update(); } } @@ -1196,7 +1249,7 @@ void Pip::setupStreaming() { updatePlaybackState(); } -void Pip::paint(QPainter &p, FrameRequest request) { +void Pip::paint(QPainter &p, FrameRequest request, bool opengl) { const auto image = videoFrameForDirectPaint( UnrotateRequest(request, _rotation)); const auto inner = _panel.inner(); @@ -1204,7 +1257,7 @@ void Pip::paint(QPainter &p, FrameRequest request) { inner.topLeft(), request.outer / style::DevicePixelRatio() }; - if (UsePainterRotation(_rotation, USE_OPENGL_PIP_WIDGET)) { + if (UsePainterRotation(_rotation, opengl)) { if (_rotation) { p.save(); p.rotate(_rotation); @@ -1257,7 +1310,7 @@ void Pip::paintFade(QPainter &p) const { void Pip::paintButtons(QPainter &p) const { const auto opacity = p.opacity(); - const auto outer = _panel.width(); + const auto outer = _panel.widget()->width(); const auto drawOne = [&]( const Button &button, const style::icon &icon, @@ -1344,7 +1397,7 @@ void Pip::handleStreamingUpdate(Streaming::Update &&update) { }, [&](const PreloadedVideo &update) { updatePlaybackState(); }, [&](const UpdateVideo &update) { - _panel.update(); + _panel.widget()->update(); Core::App().updateNonIdle(); updatePlaybackState(); }, [&](const PreloadedAudio &update) { @@ -1399,7 +1452,7 @@ void Pip::updatePlaybackTexts( _timeAlready = already; _timeLeft = left; _timeLeftWidth = st::pipPlaybackFont->width(_timeLeft); - _panel.update(QRect( + _panel.widget()->update(QRect( _playback.area.x(), _playback.icon.y() - st::pipPlaybackFont->height, _playback.area.width(), @@ -1407,12 +1460,12 @@ void Pip::updatePlaybackTexts( } void Pip::handleStreamingError(Streaming::Error &&error) { - _panel.close(); + _panel.widget()->close(); } void Pip::playbackPauseResume() { if (_instance.player().failed()) { - _panel.close(); + _panel.widget()->close(); } else if (_instance.player().finished() || !_instance.player().active()) { _startPaused = false; @@ -1602,7 +1655,7 @@ void Pip::paintRadialLoadingContent(QPainter &p, const QRect &inner) const { _instance.waitingState(), arc.topLeft(), arc.size(), - _panel.width(), + _panel.widget()->width(), st::radialFg, st::radialLine); } @@ -1632,7 +1685,7 @@ Pip::OverState Pip::computeState(QPoint position) const { } void Pip::waitingAnimationCallback() { - _panel.update(countRadialRect()); + _panel.widget()->update(countRadialRect()); } } // namespace View diff --git a/Telegram/SourceFiles/media/view/media_view_pip.h b/Telegram/SourceFiles/media/view/media_view_pip.h index f421ad583..1dba310bc 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.h +++ b/Telegram/SourceFiles/media/view/media_view_pip.h @@ -22,6 +22,10 @@ namespace Ui { class IconButton; template class FadeWrap; +namespace GL { +struct ChosenRenderer; +struct Capabilities; +} // namespace GL } // namespace Ui namespace Media { @@ -38,19 +42,7 @@ class PlaybackProgress; [[nodiscard]] QSize FlipSizeByRotation(QSize size, int rotation); [[nodiscard]] QImage RotateFrameImage(QImage image, int rotation); -#if 1 -#define USE_OPENGL_PIP_WIDGET 1 -#else -#define USE_OPENGL_PIP_WIDGET 0 -#endif // Q_OS_MAC && !OS_MAC_OLD - -#if USE_OPENGL_PIP_WIDGET -using PipParent = Ui::RpWidgetWrap; -#else // USE_OPENGL_PIP_WIDGET -using PipParent = Ui::RpWidget; -#endif // USE_OPENGL_PIP_WIDGET - -class PipPanel final : public PipParent { +class PipPanel final { public: struct Position { RectParts attached = RectPart(0); @@ -62,9 +54,12 @@ public: PipPanel( QWidget *parent, - Fn paint); + Fn paint); void init(); + [[nodiscard]] not_null widget() const; + [[nodiscard]] not_null rp() const; + void setAspectRatio(QSize ratio); [[nodiscard]] Position countPosition() const; void setPosition(Position position); @@ -73,17 +68,15 @@ public: void setDragDisabled(bool disabled); [[nodiscard]] bool dragging() const; + void handleMousePress(QPoint position, Qt::MouseButton button); + void handleMouseRelease(QPoint position, Qt::MouseButton button); + void handleMouseMove(QPoint position); + [[nodiscard]] rpl::producer<> saveGeometryRequests() const; -protected: - void paintEvent(QPaintEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - - void setVisibleHook(bool visible) override; - private: + void paint(QPainter &p, const QRegion &clip, bool opengl); + void setPositionDefault(); void setPositionOnScreen(Position position, QRect available); @@ -96,8 +89,12 @@ private: void moveAnimated(QPoint to); void updateDecorations(); + [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( + Ui::GL::Capabilities capabilities); + + std::unique_ptr _content; QPointer _parent; - Fn _paint; + Fn _paint; RectParts _attached = RectParts(); RectParts _snapped = RectParts(); QSize _ratio; @@ -164,7 +161,7 @@ private: void setupPanel(); void setupButtons(); void setupStreaming(); - void paint(QPainter &p, FrameRequest request); + void paint(QPainter &p, FrameRequest request, bool opengl); void playbackPauseResume(); void waitingAnimationCallback(); void handleStreamingUpdate(Streaming::Update &&update); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index e9fcbfcba..95ee92088 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit e9fcbfcbacfe9f2f454a7bd34f1a3c5403245523 +Subproject commit 95ee92088e62dfa20eb11d6fe59b0fb1834a1207