Choose OpenGL / Raster surface at runtime.

This commit is contained in:
John Preston 2021-05-19 16:59:31 +04:00
parent 9510ba07f7
commit a45064257a
10 changed files with 343 additions and 236 deletions

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/gl/gl_surface.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/empty_userpic.h" #include "ui/empty_userpic.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
@ -50,35 +51,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow> #include <QtGui/QWindow>
namespace Calls { namespace Calls {
namespace {
#if 1 class Panel::Incoming final {
#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<QOpenGLWidget>;
#else // USE_OPENGL_OVERLAY_WIDGET
using IncomingParent = Ui::RpWidget;
#endif // USE_OPENGL_OVERLAY_WIDGET
} // namespace
class Panel::Incoming final : public IncomingParent {
public: public:
Incoming( Incoming(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track); not_null<Webrtc::VideoTrack*> track);
[[nodiscard]] not_null<QWidget*> widget() const;
[[nodiscard]] not_null<Ui::RpWidgetWrap* > rp() const;
private: private:
void paintEvent(QPaintEvent *e) override; void paint(QPainter &p, const QRegion &clip, bool opengl);
void initBottomShadow(); void initBottomShadow();
void fillTopShadow(QPainter &p); void fillTopShadow(QPainter &p);
void fillBottomShadow(QPainter &p); void fillBottomShadow(QPainter &p);
[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Capabilities capabilities);
const std::unique_ptr<Ui::RpWidgetWrap> _surface;
const not_null<Webrtc::VideoTrack*> _track; const not_null<Webrtc::VideoTrack*> _track;
QPixmap _bottomShadow; QPixmap _bottomShadow;
@ -87,35 +80,76 @@ private:
Panel::Incoming::Incoming( Panel::Incoming::Incoming(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track) not_null<Webrtc::VideoTrack*> track)
: IncomingParent(parent) : _surface(Ui::GL::CreateSurface(
parent,
[=](Ui::GL::Capabilities capabilities) {
return chooseRenderer(capabilities);
}))
, _track(track) { , _track(track) {
initBottomShadow(); initBottomShadow();
setAttribute(Qt::WA_OpaquePaintEvent); widget()->setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_TransparentForMouseEvents); widget()->setAttribute(Qt::WA_TransparentForMouseEvents);
} }
void Panel::Incoming::paintEvent(QPaintEvent *e) { not_null<QWidget*> Panel::Incoming::widget() const {
QPainter p(this); return _surface->rpWidget();
}
not_null<Ui::RpWidgetWrap*> 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<Panel::Incoming*> 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<Panel::Incoming*> _owner;
};
return {
.renderer = std::make_unique<Renderer>(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(); const auto [image, rotation] = _track->frameOriginalWithRotation();
if (image.isNull()) { if (image.isNull()) {
p.fillRect(e->rect(), Qt::black); p.fillRect(clip.boundingRect(), Qt::black);
} else { } else {
const auto rect = widget()->rect();
using namespace Media::View; using namespace Media::View;
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
if (UsePainterRotation(rotation, USE_OPENGL_OVERLAY_WIDGET)) { if (UsePainterRotation(rotation, opengl)) {
if (rotation) { if (rotation) {
p.save(); p.save();
p.rotate(rotation); p.rotate(rotation);
} }
p.drawImage(RotatedRect(rect(), rotation), image); p.drawImage(RotatedRect(rect, rotation), image);
if (rotation) { if (rotation) {
p.restore(); p.restore();
} }
} else if (rotation) { } else if (rotation) {
p.drawImage(rect(), RotateFrameImage(image, rotation)); p.drawImage(rect, RotateFrameImage(image, rotation));
} else { } else {
p.drawImage(rect(), image); p.drawImage(rect, image);
} }
fillBottomShadow(p); fillBottomShadow(p);
fillTopShadow(p); fillTopShadow(p);
@ -146,18 +180,19 @@ void Panel::Incoming::initBottomShadow() {
void Panel::Incoming::fillTopShadow(QPainter &p) { void Panel::Incoming::fillTopShadow(QPainter &p) {
#ifdef Q_OS_WIN #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 position = QPoint(width - st::callTitleShadow.width(), 0);
const auto shadowArea = QRect( const auto shadowArea = QRect(
position, position,
st::callTitleShadow.size()); st::callTitleShadow.size());
const auto fill = shadowArea.intersected(geometry()).translated(-pos()); const auto fill = shadowArea.intersected(
widget()->geometry()).translated(-widget()->pos());
if (fill.isEmpty()) { if (fill.isEmpty()) {
return; return;
} }
p.save(); p.save();
p.setClipRect(fill); p.setClipRect(fill);
st::callTitleShadow.paint(p, position - pos(), width); st::callTitleShadow.paint(p, position - widget()->pos(), width);
p.restore(); p.restore();
#endif // Q_OS_WIN #endif // Q_OS_WIN
} }
@ -165,10 +200,11 @@ void Panel::Incoming::fillTopShadow(QPainter &p) {
void Panel::Incoming::fillBottomShadow(QPainter &p) { void Panel::Incoming::fillBottomShadow(QPainter &p) {
const auto shadowArea = QRect( const auto shadowArea = QRect(
0, 0,
parentWidget()->height() - st::callBottomShadowSize, widget()->parentWidget()->height() - st::callBottomShadowSize,
parentWidget()->width(), widget()->parentWidget()->width(),
st::callBottomShadowSize); st::callBottomShadowSize);
const auto fill = shadowArea.intersected(geometry()).translated(-pos()); const auto fill = shadowArea.intersected(
widget()->geometry()).translated(-widget()->pos());
if (fill.isEmpty()) { if (fill.isEmpty()) {
return; return;
} }
@ -178,7 +214,8 @@ void Panel::Incoming::fillBottomShadow(QPainter &p) {
_bottomShadow, _bottomShadow,
QRect( QRect(
0, 0,
factor * (fill.y() - shadowArea.translated(-pos()).y()), (factor
* (fill.y() - shadowArea.translated(-widget()->pos()).y())),
factor, factor,
factor * fill.height())); factor * fill.height()));
} }
@ -394,7 +431,7 @@ void Panel::refreshIncomingGeometry() {
Expects(_incoming != nullptr); Expects(_incoming != nullptr);
if (_incomingFrameSize.isEmpty()) { if (_incomingFrameSize.isEmpty()) {
_incoming->hide(); _incoming->widget()->hide();
return; return;
} }
const auto to = widget()->size(); const auto to = widget()->size();
@ -411,8 +448,8 @@ void Panel::refreshIncomingGeometry() {
const auto pos = QPoint( const auto pos = QPoint(
(to.width() - use.width()) / 2, (to.width() - use.width()) / 2,
(to.height() - use.height()) / 2); (to.height() - use.height()) / 2);
_incoming->setGeometry(QRect(pos, use)); _incoming->widget()->setGeometry(QRect(pos, use));
_incoming->show(); _incoming->widget()->show();
} }
void Panel::reinitWithCall(Call *call) { void Panel::reinitWithCall(Call *call) {
@ -449,7 +486,7 @@ void Panel::reinitWithCall(Call *call) {
_incoming = std::make_unique<Incoming>( _incoming = std::make_unique<Incoming>(
widget(), widget(),
_call->videoIncoming()); _call->videoIncoming());
_incoming->hide(); _incoming->widget()->hide();
_call->mutedValue( _call->mutedValue(
) | rpl::start_with_next([=](bool mute) { ) | rpl::start_with_next([=](bool mute) {
@ -480,12 +517,12 @@ void Panel::reinitWithCall(Call *call) {
setIncomingSize((rotation == 90 || rotation == 270) setIncomingSize((rotation == 90 || rotation == 270)
? QSize(frame.height(), frame.width()) ? QSize(frame.height(), frame.width())
: frame.size()); : frame.size());
if (_incoming->isHidden()) { if (_incoming->widget()->isHidden()) {
return; return;
} }
const auto incoming = incomingFrameGeometry(); const auto incoming = incomingFrameGeometry();
const auto outgoing = outgoingFrameGeometry(); const auto outgoing = outgoingFrameGeometry();
_incoming->update(); _incoming->widget()->update();
if (incoming.intersects(outgoing)) { if (incoming.intersects(outgoing)) {
widget()->update(outgoing); widget()->update(outgoing);
} }
@ -497,7 +534,7 @@ void Panel::reinitWithCall(Call *call) {
const auto outgoing = outgoingFrameGeometry(); const auto outgoing = outgoingFrameGeometry();
widget()->update(outgoing); widget()->update(outgoing);
if (incoming.intersects(outgoing)) { if (incoming.intersects(outgoing)) {
_incoming->update(); _incoming->widget()->update();
} }
}, _callLifetime); }, _callLifetime);
@ -541,7 +578,7 @@ void Panel::reinitWithCall(Call *call) {
_name->setText(_user->name); _name->setText(_user->name);
updateStatusText(_call->state()); updateStatusText(_call->state());
_incoming->lower(); _incoming->widget()->lower();
} }
void Panel::createRemoteAudioMute() { void Panel::createRemoteAudioMute() {
@ -606,7 +643,7 @@ void Panel::showControls() {
_cancel->setVisible(_cancel->toggled()); _cancel->setVisible(_cancel->toggled());
const auto shown = !_incomingFrameSize.isEmpty(); const auto shown = !_incomingFrameSize.isEmpty();
_incoming->setVisible(shown); _incoming->widget()->setVisible(shown);
_name->setVisible(!shown); _name->setVisible(!shown);
_status->setVisible(!shown); _status->setVisible(!shown);
_userpic->setVisible(!shown); _userpic->setVisible(!shown);
@ -650,9 +687,9 @@ void Panel::toggleFullScreen(bool fullscreen) {
} }
QRect Panel::incomingFrameGeometry() const { QRect Panel::incomingFrameGeometry() const {
return (!_incoming || _incoming->isHidden()) return (!_incoming || _incoming->widget()->isHidden())
? QRect() ? QRect()
: _incoming->geometry(); : _incoming->widget()->geometry();
} }
QRect Panel::outgoingFrameGeometry() const { QRect Panel::outgoingFrameGeometry() const {
@ -788,13 +825,13 @@ void Panel::paint(QRect clip) {
Painter p(widget()); Painter p(widget());
auto region = QRegion(clip); auto region = QRegion(clip);
if (!_incoming->isHidden()) { if (!_incoming->widget()->isHidden()) {
region = region.subtracted(QRegion(_incoming->geometry())); region = region.subtracted(QRegion(_incoming->widget()->geometry()));
} }
for (const auto rect : region) { for (const auto rect : region) {
p.fillRect(rect, st::callBgOpaque); p.fillRect(rect, st::callBgOpaque);
} }
if (_incoming && _incoming->isHidden()) { if (_incoming && _incoming->widget()->isHidden()) {
_call->videoIncoming()->markFrameShown(); _call->videoIncoming()->markFrameShown();
} }
} }

View file

@ -13,11 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_video_track.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/abstract_button.h" #include "ui/abstract_button.h"
#include "ui/gl/gl_surface.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/effects/cross_line.h" #include "ui/effects/cross_line.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include <QtGui/QWindow>
namespace Calls::Group { namespace Calls::Group {
namespace { namespace {
@ -57,31 +60,64 @@ LargeVideo::LargeVideo(
bool visible, bool visible,
rpl::producer<LargeVideoTrack> track, rpl::producer<LargeVideoTrack> track,
rpl::producer<bool> pinned) rpl::producer<bool> pinned)
: _content(parent, [=](QRect clip) { paint(clip); }) : _content(Ui::GL::CreateSurface(
parent,
[=](Ui::GL::Capabilities capabilities) {
return chooseRenderer(capabilities);
}))
, _st(st) , _st(st)
, _pinButton((_st.pinPosition.x() >= 0) , _pinButton((_st.pinPosition.x() >= 0)
? std::make_unique<PinButton>(&_content, st) ? std::make_unique<PinButton>(widget(), st)
: nullptr) : nullptr)
, _smallLayout(!_pinButton) { , _smallLayout(!_pinButton) {
_content.setVisible(visible); widget()->setVisible(visible);
if (_smallLayout) { if (_smallLayout) {
_content.setCursor(style::cur_pointer); widget()->setCursor(style::cur_pointer);
} }
setup(std::move(track), std::move(pinned)); setup(std::move(track), std::move(pinned));
} }
LargeVideo::~LargeVideo() = default; LargeVideo::~LargeVideo() = default;
Ui::GL::ChosenRenderer LargeVideo::chooseRenderer(
Ui::GL::Capabilities capabilities) {
class Renderer : public Ui::GL::Renderer {
public:
Renderer(not_null<LargeVideo*> 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<LargeVideo*> _owner;
};
return {
.renderer = std::make_unique<Renderer>(this),
.backend = (capabilities.supported
? Ui::GL::Backend::OpenGL
: Ui::GL::Backend::Raster),
};
}
void LargeVideo::raise() { void LargeVideo::raise() {
_content.raise(); widget()->raise();
} }
void LargeVideo::setVisible(bool visible) { void LargeVideo::setVisible(bool visible) {
_content.setVisible(visible); widget()->setVisible(visible);
} }
void LargeVideo::setGeometry(int x, int y, int width, int height) { 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) { if (width > 0 && height > 0) {
const auto kMedium = style::ConvertScale(380); const auto kMedium = style::ConvertScale(380);
const auto kSmall = style::ConvertScale(200); const auto kSmall = style::ConvertScale(200);
@ -98,7 +134,7 @@ void LargeVideo::setControlsShown(float64 shown) {
return; return;
} }
_controlsShownRatio = shown; _controlsShownRatio = shown;
_content.update(); widget()->update();
updateControlsGeometry(); updateControlsGeometry();
} }
@ -119,19 +155,27 @@ rpl::producer<QSize> LargeVideo::trackSizeValue() const {
rpl::producer<VideoQuality> LargeVideo::requestedQuality() const { rpl::producer<VideoQuality> LargeVideo::requestedQuality() const {
using namespace rpl::mappers; using namespace rpl::mappers;
return rpl::combine( return rpl::combine(
_content.shownValue(), _content->shownValue(),
_requestedQuality.value() _requestedQuality.value()
) | rpl::filter([=](bool shown, auto) { ) | rpl::filter([=](bool shown, auto) {
return shown; return shown;
}) | rpl::map(_2); }) | rpl::map(_2);
} }
rpl::lifetime &LargeVideo::lifetime() {
return _content->lifetime();
}
not_null<QWidget*> LargeVideo::widget() const {
return _content->rpWidget();
}
void LargeVideo::setup( void LargeVideo::setup(
rpl::producer<LargeVideoTrack> track, rpl::producer<LargeVideoTrack> track,
rpl::producer<bool> pinned) { rpl::producer<bool> pinned) {
_content.setAttribute(Qt::WA_OpaquePaintEvent); widget()->setAttribute(Qt::WA_OpaquePaintEvent);
_content.events( _content->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
const auto type = e->type(); const auto type = e->type();
if (type == QEvent::Enter && _pinButton) { if (type == QEvent::Enter && _pinButton) {
@ -147,21 +191,21 @@ void LargeVideo::setup(
e.get())->button() == Qt::LeftButton e.get())->button() == Qt::LeftButton
&& _mouseDown) { && _mouseDown) {
_mouseDown = false; _mouseDown = false;
if (!_content.isHidden()) { if (!widget()->isHidden()) {
_clicks.fire({}); _clicks.fire({});
} }
} }
}, _content.lifetime()); }, _content->lifetime());
rpl::combine( rpl::combine(
_content.shownValue(), _content->shownValue(),
std::move(track) std::move(track)
) | rpl::map([=](bool shown, LargeVideoTrack track) { ) | rpl::map([=](bool shown, LargeVideoTrack track) {
return shown ? track : LargeVideoTrack(); return shown ? track : LargeVideoTrack();
}) | rpl::distinct_until_changed( }) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](LargeVideoTrack track) { ) | rpl::start_with_next([=](LargeVideoTrack track) {
_track = track; _track = track;
_content.update(); widget()->update();
_trackLifetime.destroy(); _trackLifetime.destroy();
if (!track.track) { if (!track.track) {
@ -176,12 +220,12 @@ void LargeVideo::setup(
} else { } else {
_trackSize = size; _trackSize = size;
} }
_content.update(); widget()->update();
}, _trackLifetime); }, _trackLifetime);
if (const auto size = track.track->frameSize(); !size.isEmpty()) { if (const auto size = track.track->frameSize(); !size.isEmpty()) {
_trackSize = size; _trackSize = size;
} }
}, _content.lifetime()); }, _content->lifetime());
setupControls(std::move(pinned)); setupControls(std::move(pinned));
} }
@ -194,7 +238,7 @@ void LargeVideo::togglePinShown(bool shown) {
} }
_pinButton->shown = shown; _pinButton->shown = shown;
_pinButton->shownAnimation.start( _pinButton->shownAnimation.start(
[=] { updateControlsGeometry(); _content.update(); }, [=] { updateControlsGeometry(); widget()->update(); },
shown ? 0. : 1., shown ? 0. : 1.,
shown ? 1. : 0., shown ? 1. : 0.,
st::slideWrapDuration); st::slideWrapDuration);
@ -211,13 +255,13 @@ void LargeVideo::setupControls(rpl::producer<bool> pinned) {
: tr::lng_pinned_pin)(tr::now)); : tr::lng_pinned_pin)(tr::now));
updateControlsGeometry(); updateControlsGeometry();
} }
_content.update(); widget()->update();
}, _content.lifetime()); }, _content->lifetime());
_content.sizeValue( _content->sizeValue(
) | rpl::start_with_next([=](QSize size) { ) | rpl::start_with_next([=](QSize size) {
updateControlsGeometry(); updateControlsGeometry();
}, _content.lifetime()); }, _content->lifetime());
} }
void LargeVideo::updateControlsGeometry() { void LargeVideo::updateControlsGeometry() {
@ -236,20 +280,20 @@ void LargeVideo::updateControlsGeometry() {
0, 0,
_pinButton->shownAnimation.value(_pinButton->shown ? 1. : 0.)); _pinButton->shownAnimation.value(_pinButton->shown ? 1. : 0.));
_pinButton->rect = QRect( _pinButton->rect = QRect(
_content.width() - _st.pinPosition.x() - buttonWidth, widget()->width() - _st.pinPosition.x() - buttonWidth,
_st.pinPosition.y() - slide, _st.pinPosition.y() - slide,
buttonWidth, buttonWidth,
buttonHeight); buttonHeight);
_pinButton->area.setGeometry( _pinButton->area.setGeometry(
_content.width() - fullWidth, widget()->width() - fullWidth,
-slide, -slide,
fullWidth, fullWidth,
fullHeight); fullHeight);
} }
} }
void LargeVideo::paint(QRect clip) { void LargeVideo::paint(QRect clip, bool opengl) {
auto p = Painter(&_content); auto p = Painter(widget());
const auto fill = [&](QRect rect) { const auto fill = [&](QRect rect) {
if (rect.intersects(clip)) { if (rect.intersects(clip)) {
p.fillRect(rect.intersected(clip), st::groupCallMembersBg); p.fillRect(rect.intersected(clip), st::groupCallMembersBg);
@ -264,7 +308,7 @@ void LargeVideo::paint(QRect clip) {
} }
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
using namespace Media::View; using namespace Media::View;
const auto size = _content.size(); const auto size = widget()->size();
const auto scaled = FlipSizeByRotation( const auto scaled = FlipSizeByRotation(
image.size(), image.size(),
rotation rotation
@ -272,7 +316,7 @@ void LargeVideo::paint(QRect clip) {
const auto left = (size.width() - scaled.width()) / 2; const auto left = (size.width() - scaled.width()) / 2;
const auto top = (size.height() - scaled.height()) / 2; const auto top = (size.height() - scaled.height()) / 2;
const auto target = QRect(QPoint(left, top), scaled); const auto target = QRect(QPoint(left, top), scaled);
if (UsePainterRotation(rotation, USE_OPENGL_LARGE_VIDEO)) { if (UsePainterRotation(rotation, opengl)) {
if (rotation) { if (rotation) {
p.save(); p.save();
p.rotate(rotation); p.rotate(rotation);
@ -307,8 +351,8 @@ void LargeVideo::paint(QRect clip) {
} }
void LargeVideo::paintControls(Painter &p, QRect clip) { void LargeVideo::paintControls(Painter &p, QRect clip) {
const auto width = _content.width(); const auto width = widget()->width();
const auto height = _content.height(); const auto height = widget()->height();
// Pin. // Pin.
if (_pinButton && _pinButton->rect.intersects(clip)) { if (_pinButton && _pinButton->rect.intersects(clip)) {

View file

@ -9,12 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h" #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 { namespace style {
struct GroupCallLargeVideo; struct GroupCallLargeVideo;
} // namespace style } // namespace style
@ -25,6 +19,11 @@ class VideoTrack;
namespace Ui { namespace Ui {
class AbstractButton; class AbstractButton;
class RpWidgetWrap;
namespace GL {
struct Capabilities;
struct ChosenRenderer;
} // namespace GL
} // namespace Ui } // namespace Ui
namespace Calls::Group { namespace Calls::Group {
@ -77,45 +76,26 @@ public:
[[nodiscard]] rpl::producer<QSize> trackSizeValue() const; [[nodiscard]] rpl::producer<QSize> trackSizeValue() const;
[[nodiscard]] rpl::producer<VideoQuality> requestedQuality() const; [[nodiscard]] rpl::producer<VideoQuality> requestedQuality() const;
[[nodiscard]] rpl::lifetime &lifetime() { [[nodiscard]] rpl::lifetime &lifetime();
return _content.lifetime();
}
private: private:
#if USE_OPENGL_LARGE_VIDEO
using ContentParent = Ui::RpWidgetWrap<QOpenGLWidget>;
#else // USE_OPENGL_OVERLAY_WIDGET
using ContentParent = Ui::RpWidget;
#endif // USE_OPENGL_OVERLAY_WIDGET
class Content final : public ContentParent {
public:
Content(QWidget *parent, Fn<void(QRect)> paint)
: ContentParent(parent), _paint(std::move(paint)) {
Expects(_paint != nullptr);
}
private:
void paintEvent(QPaintEvent *e) override {
_paint(e->rect());
}
Fn<void(QRect)> _paint;
};
struct PinButton; struct PinButton;
[[nodiscard]] not_null<QWidget*> widget() const;
void setup( void setup(
rpl::producer<LargeVideoTrack> track, rpl::producer<LargeVideoTrack> track,
rpl::producer<bool> pinned); rpl::producer<bool> pinned);
void setupControls(rpl::producer<bool> pinned); void setupControls(rpl::producer<bool> pinned);
void paint(QRect clip); void paint(QRect clip, bool opengl);
void paintControls(Painter &p, QRect clip); void paintControls(Painter &p, QRect clip);
void updateControlsGeometry(); void updateControlsGeometry();
void togglePinShown(bool shown); void togglePinShown(bool shown);
Content _content; [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Capabilities capabilities);
const std::unique_ptr<Ui::RpWidgetWrap> _content;
const style::GroupCallLargeVideo &_st; const style::GroupCallLargeVideo &_st;
LargeVideoTrack _track; LargeVideoTrack _track;
QImage _shadow; QImage _shadow;

View file

@ -1263,11 +1263,9 @@ void Panel::setupPinnedVideo() {
raw->events( raw->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Enter) { if (e->type() == QEvent::Enter) {
LOG(("Track Enter"));
Ui::Integration::Instance().registerLeaveSubscription(raw); Ui::Integration::Instance().registerLeaveSubscription(raw);
toggleWideControls(true); toggleWideControls(true);
} else if (e->type() == QEvent::Leave) { } else if (e->type() == QEvent::Leave) {
LOG(("Track Leave"));
Ui::Integration::Instance().unregisterLeaveSubscription(raw); Ui::Integration::Instance().unregisterLeaveSubscription(raw);
toggleWideControls(false); toggleWideControls(false);
} }
@ -1281,12 +1279,10 @@ void Panel::toggleWideControls(bool shown) {
return; return;
} }
_showWideControls = shown; _showWideControls = shown;
LOG(("On Main Scheduled"));
crl::on_main(widget(), [=] { crl::on_main(widget(), [=] {
if (_wideControlsShown == _showWideControls) { if (_wideControlsShown == _showWideControls) {
return; return;
} }
LOG(("On Main Fired: %1").arg(Logs::b(_showWideControls)));
_wideControlsShown = _showWideControls; _wideControlsShown = _showWideControls;
_wideControlsAnimation.start( _wideControlsAnimation.start(
[=] { updateButtonsGeometry(); }, [=] { updateButtonsGeometry(); },
@ -1343,7 +1339,7 @@ void Panel::setupAllowedToSpeakToasts() {
Ui::ShowMultilineToast({ Ui::ShowMultilineToast({
.parentOverride = widget(), .parentOverride = widget(),
.text = { tr::lng_group_call_can_speak_here(tr::now) }, .text = { tr::lng_group_call_can_speak_here(tr::now) },
}); });
} else { } else {
const auto real = _call->lookupReal(); const auto real = _call->lookupReal();
const auto name = (real && !real->title().isEmpty()) const auto name = (real && !real->title().isEmpty())
@ -1355,7 +1351,7 @@ void Panel::setupAllowedToSpeakToasts() {
lt_chat, lt_chat,
Ui::Text::Bold(name), Ui::Text::Bold(name),
Ui::Text::WithEntities), Ui::Text::WithEntities),
}); });
} }
}, widget()->lifetime()); }, widget()->lifetime());
} }
@ -1866,10 +1862,8 @@ void Panel::trackControls(bool track) {
raw->events( raw->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Enter) { if (e->type() == QEvent::Enter) {
LOG(("Track Enter"));
toggleWideControls(true); toggleWideControls(true);
} else if (e->type() == QEvent::Leave) { } else if (e->type() == QEvent::Leave) {
LOG(("Track Leave"));
toggleWideControls(false); toggleWideControls(false);
} }
}, _trackControlsOverStateLifetime); }, _trackControlsOverStateLifetime);

View file

@ -300,6 +300,8 @@ public:
[[nodiscard]] ImageLocation userpicLocation() const { [[nodiscard]] ImageLocation userpicLocation() const {
return _userpic.location(); return _userpic.location();
} }
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
[[nodiscard]] bool userpicPhotoUnknown() const { [[nodiscard]] bool userpicPhotoUnknown() const {
return (_userpicPhotoId == kUnknownPhotoId); return (_userpicPhotoId == kUnknownPhotoId);
} }
@ -411,8 +413,6 @@ private:
void setUserpicChecked(PhotoId photoId, const ImageLocation &location); void setUserpicChecked(PhotoId photoId, const ImageLocation &location);
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
const not_null<Data::Session*> _owner; const not_null<Data::Session*> _owner;
mutable Data::CloudImage _userpic; mutable Data::CloudImage _userpic;

View file

@ -474,7 +474,9 @@ void OverlayWidget::updateGeometry() {
const auto useSizeHack = (USE_OPENGL_OVERLAY_WIDGET const auto useSizeHack = (USE_OPENGL_OVERLAY_WIDGET
&& Platform::IsWindows()); && Platform::IsWindows());
const auto use = available.marginsAdded({ 0, 0, 0, 1 }); 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) if ((geometry() == use)
&& (!useSizeHack || (window && window->mask() == mask))) { && (!useSizeHack || (window && window->mask() == mask))) {
return; return;

View file

@ -63,9 +63,9 @@ struct OverlayParentTraits : Ui::RpWidgetDefaultTraits {
}; };
#if USE_OPENGL_OVERLAY_WIDGET #if USE_OPENGL_OVERLAY_WIDGET
using OverlayParent = Ui::RpWidgetWrap<QOpenGLWidget, OverlayParentTraits>; using OverlayParent = Ui::RpWidgetBase<QOpenGLWidget, OverlayParentTraits>;
#else // USE_OPENGL_OVERLAY_WIDGET #else // USE_OPENGL_OVERLAY_WIDGET
using OverlayParent = Ui::RpWidgetWrap<QWidget, OverlayParentTraits>; using OverlayParent = Ui::RpWidgetBase<QWidget, OverlayParentTraits>;
#endif // USE_OPENGL_OVERLAY_WIDGET #endif // USE_OPENGL_OVERLAY_WIDGET
class OverlayWidget final class OverlayWidget final

View file

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/text/format_values.h" #include "ui/text/format_values.h"
#include "ui/gl/gl_surface.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_window.h" #include "styles/style_window.h"
@ -372,35 +373,77 @@ QImage RotateFrameImage(QImage image, int rotation) {
PipPanel::PipPanel( PipPanel::PipPanel(
QWidget *parent, QWidget *parent,
Fn<void(QPainter&, FrameRequest)> paint) Fn<void(QPainter&, FrameRequest, bool)> paint)
: _parent(parent) : _content(Ui::GL::CreateSurface(
parent,
[=](Ui::GL::Capabilities capabilities) {
return chooseRenderer(capabilities);
}))
, _parent(parent)
, _paint(std::move(paint)) { , _paint(std::move(paint)) {
} }
Ui::GL::ChosenRenderer PipPanel::chooseRenderer(
Ui::GL::Capabilities capabilities) {
class Renderer : public Ui::GL::Renderer {
public:
Renderer(not_null<PipPanel*> 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<PipPanel*> _owner;
};
return {
.renderer = std::make_unique<Renderer>(this),
.backend = (capabilities.supported
? Ui::GL::Backend::OpenGL
: Ui::GL::Backend::Raster),
};
}
void PipPanel::init() { void PipPanel::init() {
setWindowFlags(Qt::Tool widget()->setWindowFlags(Qt::Tool
| Qt::WindowStaysOnTopHint | Qt::WindowStaysOnTopHint
| Qt::FramelessWindowHint | Qt::FramelessWindowHint
| Qt::WindowDoesNotAcceptFocus); | Qt::WindowDoesNotAcceptFocus);
setAttribute(Qt::WA_ShowWithoutActivating); widget()->setAttribute(Qt::WA_ShowWithoutActivating);
setAttribute(Qt::WA_MacAlwaysShowToolWindow); widget()->setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_NoSystemBackground); widget()->setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground); widget()->setAttribute(Qt::WA_TranslucentBackground);
Ui::Platform::IgnoreAllActivation(this); Ui::Platform::IgnoreAllActivation(widget());
Ui::Platform::InitOnTopPanel(this); Ui::Platform::InitOnTopPanel(widget());
setMouseTracking(true); widget()->setMouseTracking(true);
resize(0, 0); widget()->resize(0, 0);
hide(); widget()->hide();
createWinId(); 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) { not_null<QWidget*> PipPanel::widget() const {
PipParent::setVisibleHook(visible); return _content->rpWidget();
}
// workaround Qt's forced transient parent not_null<Ui::RpWidgetWrap*> PipPanel::rp() const {
if (visible) { return _content.get();
Ui::Platform::ClearTransientParent(this);
}
} }
void PipPanel::setAspectRatio(QSize ratio) { void PipPanel::setAspectRatio(QSize ratio) {
@ -411,7 +454,7 @@ void PipPanel::setAspectRatio(QSize ratio) {
if (_ratio.isEmpty()) { if (_ratio.isEmpty()) {
_ratio = QSize(1, 1); _ratio = QSize(1, 1);
} }
if (!size().isEmpty()) { if (!widget()->size().isEmpty()) {
setPosition(countPosition()); setPosition(countPosition());
} }
} }
@ -429,7 +472,7 @@ void PipPanel::setPosition(Position position) {
} }
QRect PipPanel::inner() const { QRect PipPanel::inner() const {
return rect().marginsRemoved(_padding); return widget()->rect().marginsRemoved(_padding);
} }
RectParts PipPanel::attached() const { RectParts PipPanel::attached() const {
@ -452,7 +495,10 @@ rpl::producer<> PipPanel::saveGeometryRequests() const {
} }
QScreen *PipPanel::myScreen() 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 { PipPanel::Position PipPanel::countPosition() const {
@ -462,7 +508,7 @@ PipPanel::Position PipPanel::countPosition() const {
} }
auto result = Position(); auto result = Position();
result.screen = screen->geometry(); result.screen = screen->geometry();
result.geometry = geometry().marginsRemoved(_padding); result.geometry = widget()->geometry().marginsRemoved(_padding);
const auto available = screen->availableGeometry(); const auto available = screen->availableGeometry();
const auto skip = st::pipBorderSkip; const auto skip = st::pipBorderSkip;
const auto left = result.geometry.x(); const auto left = result.geometry.x();
@ -501,9 +547,9 @@ void PipPanel::setPositionDefault() {
return nullptr; return nullptr;
}; };
const auto parentScreen = widgetScreen(_parent); const auto parentScreen = widgetScreen(_parent);
const auto myScreen = widgetScreen(this); const auto myScreen = widgetScreen(widget());
if (parentScreen && myScreen && myScreen != parentScreen) { if (parentScreen && myScreen && myScreen != parentScreen) {
windowHandle()->setScreen(parentScreen); widget()->windowHandle()->setScreen(parentScreen);
} }
const auto screen = parentScreen const auto screen = parentScreen
? parentScreen ? parentScreen
@ -583,21 +629,19 @@ void PipPanel::setPositionOnScreen(Position position, QRect available) {
geometry += _padding; geometry += _padding;
setGeometry(geometry); widget()->setGeometry(geometry);
setMinimumSize(minimalSize); widget()->setMinimumSize(minimalSize);
setMaximumSize( widget()->setMaximumSize(
std::max(minimalSize.width(), maximalSize.width()), std::max(minimalSize.width(), maximalSize.width()),
std::max(minimalSize.height(), maximalSize.height())); std::max(minimalSize.height(), maximalSize.height()));
updateDecorations(); updateDecorations();
update(); widget()->update();
} }
void PipPanel::paintEvent(QPaintEvent *e) { void PipPanel::paint(QPainter &p, const QRegion &clip, bool opengl) {
QPainter p(this); if (_useTransparency && opengl) {
if (_useTransparency && USE_OPENGL_PIP_WIDGET) {
p.setCompositionMode(QPainter::CompositionMode_Source); p.setCompositionMode(QPainter::CompositionMode_Source);
for (const auto rect : e->region()) { for (const auto rect : clip) {
p.fillRect(rect, Qt::transparent); p.fillRect(rect, Qt::transparent);
} }
p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setCompositionMode(QPainter::CompositionMode_SourceOver);
@ -622,27 +666,27 @@ void PipPanel::paintEvent(QPaintEvent *e) {
request.radius = ImageRoundRadius::Large; request.radius = ImageRoundRadius::Large;
if (_useTransparency) { if (_useTransparency) {
const auto sides = RectPart::AllSides & ~_attached; 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) { void PipPanel::handleMousePress(QPoint position, Qt::MouseButton button) {
if (e->button() != Qt::LeftButton) { if (button != Qt::LeftButton) {
return; return;
} }
updateOverState(e->pos()); updateOverState(position);
_pressState = _overState; _pressState = _overState;
_pressPoint = e->globalPos(); _pressPoint = QCursor::pos();
} }
void PipPanel::mouseReleaseEvent(QMouseEvent *e) { void PipPanel::handleMouseRelease(QPoint position, Qt::MouseButton button) {
if (e->button() != Qt::LeftButton || !base::take(_pressState)) { if (button != Qt::LeftButton || !base::take(_pressState)) {
return; return;
} else if (!base::take(_dragState)) { } else if (!base::take(_dragState)) {
//playbackPauseResume(); //playbackPauseResume();
} else { } 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 top = count(RectPart::Top, _padding.top());
const auto right = count(RectPart::Right, _padding.right()); const auto right = count(RectPart::Right, _padding.right());
const auto bottom = count(RectPart::Bottom, _padding.bottom()); const auto bottom = count(RectPart::Bottom, _padding.bottom());
const auto width = widget()->width();
const auto height = widget()->height();
const auto overState = [&] { const auto overState = [&] {
if (point.x() < left) { if (point.x() < left) {
if (point.y() < top) { if (point.y() < top) {
return RectPart::TopLeft; return RectPart::TopLeft;
} else if (point.y() >= height() - bottom) { } else if (point.y() >= height - bottom) {
return RectPart::BottomLeft; return RectPart::BottomLeft;
} else { } else {
return RectPart::Left; return RectPart::Left;
} }
} else if (point.x() >= width() - right) { } else if (point.x() >= width - right) {
if (point.y() < top) { if (point.y() < top) {
return RectPart::TopRight; return RectPart::TopRight;
} else if (point.y() >= height() - bottom) { } else if (point.y() >= height - bottom) {
return RectPart::BottomRight; return RectPart::BottomRight;
} else { } else {
return RectPart::Right; return RectPart::Right;
} }
} else if (point.y() < top) { } else if (point.y() < top) {
return RectPart::Top; return RectPart::Top;
} else if (point.y() >= height() - bottom) { } else if (point.y() >= height - bottom) {
return RectPart::Bottom; return RectPart::Bottom;
} else { } else {
return RectPart::Center; return RectPart::Center;
@ -683,7 +729,7 @@ void PipPanel::updateOverState(QPoint point) {
}(); }();
if (_overState != overState) { if (_overState != overState) {
_overState = overState; _overState = overState;
setCursor([&] { widget()->setCursor([&] {
switch (_overState) { switch (_overState) {
case RectPart::Center: case RectPart::Center:
return style::cur_pointer; 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) { if (!_pressState) {
updateOverState(e->pos()); updateOverState(position);
return; return;
} }
const auto point = e->globalPos(); const auto point = QCursor::pos();
const auto distance = QApplication::startDragDistance(); const auto distance = QApplication::startDragDistance();
if (!_dragState if (!_dragState
&& (point - _pressPoint).manhattanLength() > distance && (point - _pressPoint).manhattanLength() > distance
&& !_dragDisabled) { && !_dragDisabled) {
_dragState = _pressState; _dragState = _pressState;
updateDecorations(); updateDecorations();
_dragStartGeometry = geometry().marginsRemoved(_padding); _dragStartGeometry = widget()->geometry().marginsRemoved(_padding);
} }
if (_dragState) { if (_dragState) {
if (Platform::IsWayland()) { if (Platform::IsWayland()) {
@ -733,9 +779,9 @@ void PipPanel::startSystemDrag() {
const auto stateEdges = RectPartToQtEdges(*_dragState); const auto stateEdges = RectPartToQtEdges(*_dragState);
if (stateEdges) { if (stateEdges) {
windowHandle()->startSystemResize(stateEdges); widget()->windowHandle()->startSystemResize(stateEdges);
} else { } else {
windowHandle()->startSystemMove(); widget()->windowHandle()->startSystemMove();
} }
} }
@ -780,14 +826,14 @@ void PipPanel::processDrag(QPoint point) {
} else { } else {
const auto newGeometry = valid.marginsAdded(_padding); const auto newGeometry = valid.marginsAdded(_padding);
_positionAnimation.stop(); _positionAnimation.stop();
setGeometry(newGeometry); widget()->setGeometry(newGeometry);
} }
} }
void PipPanel::finishDrag(QPoint point) { void PipPanel::finishDrag(QPoint point) {
const auto screen = ScreenFromPosition(point); const auto screen = ScreenFromPosition(point);
const auto inner = geometry().marginsRemoved(_padding); const auto inner = widget()->geometry().marginsRemoved(_padding);
const auto position = pos(); const auto position = widget()->pos();
const auto clamped = [&] { const auto clamped = [&] {
auto result = position; auto result = position;
if (Platform::IsWayland()) { if (Platform::IsWayland()) {
@ -818,7 +864,8 @@ void PipPanel::finishDrag(QPoint point) {
void PipPanel::updatePositionAnimated() { void PipPanel::updatePositionAnimated() {
const auto progress = _positionAnimation.value(1.); const auto progress = _positionAnimation.value(1.);
if (!_positionAnimation.animating()) { if (!_positionAnimation.animating()) {
move(_positionAnimationTo - QPoint(_padding.left(), _padding.top())); widget()->move(_positionAnimationTo
- QPoint(_padding.left(), _padding.top()));
if (!_dragState) { if (!_dragState) {
updateDecorations(); updateDecorations();
} }
@ -826,7 +873,7 @@ void PipPanel::updatePositionAnimated() {
} }
const auto from = QPointF(_positionAnimationFrom); const auto from = QPointF(_positionAnimationFrom);
const auto to = QPointF(_positionAnimationTo); const auto to = QPointF(_positionAnimationTo);
move((from + (to - from) * progress).toPoint() widget()->move((from + (to - from) * progress).toPoint()
- QPoint(_padding.left(), _padding.top())); - QPoint(_padding.left(), _padding.top()));
} }
@ -835,7 +882,8 @@ void PipPanel::moveAnimated(QPoint to) {
return; return;
} }
_positionAnimationTo = to; _positionAnimationTo = to;
_positionAnimationFrom = pos() + QPoint(_padding.left(), _padding.top()); _positionAnimationFrom = widget()->pos()
+ QPoint(_padding.left(), _padding.top());
_positionAnimation.stop(); _positionAnimation.stop();
_positionAnimation.start( _positionAnimation.start(
[=] { updatePositionAnimated(); }, [=] { updatePositionAnimated(); },
@ -868,9 +916,9 @@ void PipPanel::updateDecorations() {
_attached = position.attached; _attached = position.attached;
_padding = padding; _padding = padding;
_useTransparency = use; _useTransparency = use;
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); widget()->setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
setGeometry(newGeometry); widget()->setGeometry(newGeometry);
update(); widget()->update();
} }
Pip::Pip( Pip::Pip(
@ -886,7 +934,9 @@ Pip::Pip(
, _instance(std::move(shared), [=] { waitingAnimationCallback(); }) , _instance(std::move(shared), [=] { waitingAnimationCallback(); })
, _panel( , _panel(
_delegate->pipParentWidget(), _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<PlaybackProgress>()) , _playbackProgress(std::make_unique<PlaybackProgress>())
, _rotation(data->owner().mediaRotation().get(data)) , _rotation(data->owner().mediaRotation().get(data))
, _roundRect(ImageRoundRadius::Large, st::radialBg) , _roundRect(ImageRoundRadius::Large, st::radialBg)
@ -899,7 +949,7 @@ Pip::Pip(
_data->session().account().sessionChanges( _data->session().account().sessionChanges(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_destroy(); _destroy();
}, _panel.lifetime()); }, _panel.rp()->lifetime());
} }
Pip::~Pip() = default; Pip::~Pip() = default;
@ -920,14 +970,14 @@ void Pip::setupPanel() {
}(); }();
_panel.setAspectRatio(FlipSizeByRotation(size, _rotation)); _panel.setAspectRatio(FlipSizeByRotation(size, _rotation));
_panel.setPosition(Deserialize(_delegate->pipLoadGeometry())); _panel.setPosition(Deserialize(_delegate->pipLoadGeometry()));
_panel.show(); _panel.widget()->show();
_panel.saveGeometryRequests( _panel.saveGeometryRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
saveGeometry(); saveGeometry();
}, _panel.lifetime()); }, _panel.rp()->lifetime());
_panel.events( _panel.rp()->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
const auto mousePosition = [&] { const auto mousePosition = [&] {
return static_cast<QMouseEvent*>(e.get())->pos(); return static_cast<QMouseEvent*>(e.get())->pos();
@ -951,11 +1001,11 @@ void Pip::setupPanel() {
handleDoubleClick(mouseButton()); handleDoubleClick(mouseButton());
break; break;
} }
}, _panel.lifetime()); }, _panel.rp()->lifetime());
} }
void Pip::handleClose() { void Pip::handleClose() {
crl::on_main(&_panel, [=] { crl::on_main(_panel.widget(), [=] {
_destroy(); _destroy();
}); });
} }
@ -965,6 +1015,7 @@ void Pip::handleLeave() {
} }
void Pip::handleMouseMove(QPoint position) { void Pip::handleMouseMove(QPoint position) {
_panel.handleMouseMove(position);
setOverState(computeState(position)); setOverState(computeState(position));
seekUpdate(position); seekUpdate(position);
} }
@ -978,7 +1029,7 @@ void Pip::setOverState(OverState state) {
const auto nowShown = (_over != OverState::None); const auto nowShown = (_over != OverState::None);
if ((was != OverState::None) != nowShown) { if ((was != OverState::None) != nowShown) {
_controlsShown.start( _controlsShown.start(
[=] { _panel.update(); }, [=] { _panel.widget()->update(); },
nowShown ? 0. : 1., nowShown ? 0. : 1.,
nowShown ? 1. : 0., nowShown ? 1. : 0.,
st::fadeWrapDuration, st::fadeWrapDuration,
@ -987,7 +1038,7 @@ void Pip::setOverState(OverState state) {
if (!_pressed) { if (!_pressed) {
updateActiveState(was); updateActiveState(was);
} }
_panel.update(); _panel.widget()->update();
} }
void Pip::setPressedState(std::optional<OverState> state) { void Pip::setPressedState(std::optional<OverState> state) {
@ -1012,7 +1063,7 @@ void Pip::updateActiveState(OverState was) {
const auto now = (activeState() == button.state); const auto now = (activeState() == button.state);
if ((was == button.state) != now) { if ((was == button.state) != now) {
button.active.start( button.active.start(
[=, &button] { _panel.update(button.icon); }, [=, &button] { _panel.widget()->update(button.icon); },
now ? 0. : 1., now ? 0. : 1.,
now ? 1. : 0., now ? 1. : 0.,
st::fadeWrapDuration, st::fadeWrapDuration,
@ -1026,6 +1077,7 @@ void Pip::updateActiveState(OverState was) {
} }
void Pip::handleMousePress(QPoint position, Qt::MouseButton button) { void Pip::handleMousePress(QPoint position, Qt::MouseButton button) {
_panel.handleMousePress(position, button);
if (button != Qt::LeftButton) { if (button != Qt::LeftButton) {
return; return;
} }
@ -1037,6 +1089,7 @@ void Pip::handleMousePress(QPoint position, Qt::MouseButton button) {
} }
void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) { void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
_panel.handleMouseRelease(position, button);
if (button != Qt::LeftButton) { if (button != Qt::LeftButton) {
return; return;
} }
@ -1053,7 +1106,7 @@ void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
_lastHandledPress = _over; _lastHandledPress = _over;
switch (_over) { switch (_over) {
case OverState::Close: _panel.close(); break; case OverState::Close: _panel.widget()->close(); break;
case OverState::Enlarge: _closeAndContinue(); break; case OverState::Enlarge: _closeAndContinue(); break;
case OverState::Other: playbackPauseResume(); break; case OverState::Other: playbackPauseResume(); break;
} }
@ -1120,7 +1173,7 @@ void Pip::setupButtons() {
_enlarge.state = OverState::Enlarge; _enlarge.state = OverState::Enlarge;
_playback.state = OverState::Playback; _playback.state = OverState::Playback;
_play.state = OverState::Other; _play.state = OverState::Other;
_panel.sizeValue( _panel.rp()->sizeValue(
) | rpl::map([=] { ) | rpl::map([=] {
return _panel.inner(); return _panel.inner();
}) | rpl::start_with_next([=](QRect rect) { }) | rpl::start_with_next([=](QRect rect) {
@ -1162,12 +1215,12 @@ void Pip::setupButtons() {
playbackHeight); playbackHeight);
_playback.icon = _playback.area.marginsRemoved( _playback.icon = _playback.area.marginsRemoved(
{ playbackSkip, playbackSkip, playbackSkip, playbackSkip }); { playbackSkip, playbackSkip, playbackSkip, playbackSkip });
}, _panel.lifetime()); }, _panel.rp()->lifetime());
_playbackProgress->setValueChangedCallback([=]( _playbackProgress->setValueChangedCallback([=](
float64 value, float64 value,
float64 receivedTill) { 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); auto showPause = Player::ShowPauseIcon(state.state);
if (showPause != _showPause) { if (showPause != _showPause) {
_showPause = showPause; _showPause = showPause;
_panel.update(); _panel.widget()->update();
} }
} }
@ -1196,7 +1249,7 @@ void Pip::setupStreaming() {
updatePlaybackState(); updatePlaybackState();
} }
void Pip::paint(QPainter &p, FrameRequest request) { void Pip::paint(QPainter &p, FrameRequest request, bool opengl) {
const auto image = videoFrameForDirectPaint( const auto image = videoFrameForDirectPaint(
UnrotateRequest(request, _rotation)); UnrotateRequest(request, _rotation));
const auto inner = _panel.inner(); const auto inner = _panel.inner();
@ -1204,7 +1257,7 @@ void Pip::paint(QPainter &p, FrameRequest request) {
inner.topLeft(), inner.topLeft(),
request.outer / style::DevicePixelRatio() request.outer / style::DevicePixelRatio()
}; };
if (UsePainterRotation(_rotation, USE_OPENGL_PIP_WIDGET)) { if (UsePainterRotation(_rotation, opengl)) {
if (_rotation) { if (_rotation) {
p.save(); p.save();
p.rotate(_rotation); p.rotate(_rotation);
@ -1257,7 +1310,7 @@ void Pip::paintFade(QPainter &p) const {
void Pip::paintButtons(QPainter &p) const { void Pip::paintButtons(QPainter &p) const {
const auto opacity = p.opacity(); const auto opacity = p.opacity();
const auto outer = _panel.width(); const auto outer = _panel.widget()->width();
const auto drawOne = [&]( const auto drawOne = [&](
const Button &button, const Button &button,
const style::icon &icon, const style::icon &icon,
@ -1344,7 +1397,7 @@ void Pip::handleStreamingUpdate(Streaming::Update &&update) {
}, [&](const PreloadedVideo &update) { }, [&](const PreloadedVideo &update) {
updatePlaybackState(); updatePlaybackState();
}, [&](const UpdateVideo &update) { }, [&](const UpdateVideo &update) {
_panel.update(); _panel.widget()->update();
Core::App().updateNonIdle(); Core::App().updateNonIdle();
updatePlaybackState(); updatePlaybackState();
}, [&](const PreloadedAudio &update) { }, [&](const PreloadedAudio &update) {
@ -1399,7 +1452,7 @@ void Pip::updatePlaybackTexts(
_timeAlready = already; _timeAlready = already;
_timeLeft = left; _timeLeft = left;
_timeLeftWidth = st::pipPlaybackFont->width(_timeLeft); _timeLeftWidth = st::pipPlaybackFont->width(_timeLeft);
_panel.update(QRect( _panel.widget()->update(QRect(
_playback.area.x(), _playback.area.x(),
_playback.icon.y() - st::pipPlaybackFont->height, _playback.icon.y() - st::pipPlaybackFont->height,
_playback.area.width(), _playback.area.width(),
@ -1407,12 +1460,12 @@ void Pip::updatePlaybackTexts(
} }
void Pip::handleStreamingError(Streaming::Error &&error) { void Pip::handleStreamingError(Streaming::Error &&error) {
_panel.close(); _panel.widget()->close();
} }
void Pip::playbackPauseResume() { void Pip::playbackPauseResume() {
if (_instance.player().failed()) { if (_instance.player().failed()) {
_panel.close(); _panel.widget()->close();
} else if (_instance.player().finished() } else if (_instance.player().finished()
|| !_instance.player().active()) { || !_instance.player().active()) {
_startPaused = false; _startPaused = false;
@ -1602,7 +1655,7 @@ void Pip::paintRadialLoadingContent(QPainter &p, const QRect &inner) const {
_instance.waitingState(), _instance.waitingState(),
arc.topLeft(), arc.topLeft(),
arc.size(), arc.size(),
_panel.width(), _panel.widget()->width(),
st::radialFg, st::radialFg,
st::radialLine); st::radialLine);
} }
@ -1632,7 +1685,7 @@ Pip::OverState Pip::computeState(QPoint position) const {
} }
void Pip::waitingAnimationCallback() { void Pip::waitingAnimationCallback() {
_panel.update(countRadialRect()); _panel.widget()->update(countRadialRect());
} }
} // namespace View } // namespace View

View file

@ -22,6 +22,10 @@ namespace Ui {
class IconButton; class IconButton;
template <typename Widget> template <typename Widget>
class FadeWrap; class FadeWrap;
namespace GL {
struct ChosenRenderer;
struct Capabilities;
} // namespace GL
} // namespace Ui } // namespace Ui
namespace Media { namespace Media {
@ -38,19 +42,7 @@ class PlaybackProgress;
[[nodiscard]] QSize FlipSizeByRotation(QSize size, int rotation); [[nodiscard]] QSize FlipSizeByRotation(QSize size, int rotation);
[[nodiscard]] QImage RotateFrameImage(QImage image, int rotation); [[nodiscard]] QImage RotateFrameImage(QImage image, int rotation);
#if 1 class PipPanel final {
#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<QOpenGLWidget>;
#else // USE_OPENGL_PIP_WIDGET
using PipParent = Ui::RpWidget;
#endif // USE_OPENGL_PIP_WIDGET
class PipPanel final : public PipParent {
public: public:
struct Position { struct Position {
RectParts attached = RectPart(0); RectParts attached = RectPart(0);
@ -62,9 +54,12 @@ public:
PipPanel( PipPanel(
QWidget *parent, QWidget *parent,
Fn<void(QPainter&, FrameRequest)> paint); Fn<void(QPainter&, FrameRequest, bool)> paint);
void init(); void init();
[[nodiscard]] not_null<QWidget*> widget() const;
[[nodiscard]] not_null<Ui::RpWidgetWrap*> rp() const;
void setAspectRatio(QSize ratio); void setAspectRatio(QSize ratio);
[[nodiscard]] Position countPosition() const; [[nodiscard]] Position countPosition() const;
void setPosition(Position position); void setPosition(Position position);
@ -73,17 +68,15 @@ public:
void setDragDisabled(bool disabled); void setDragDisabled(bool disabled);
[[nodiscard]] bool dragging() const; [[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; [[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: private:
void paint(QPainter &p, const QRegion &clip, bool opengl);
void setPositionDefault(); void setPositionDefault();
void setPositionOnScreen(Position position, QRect available); void setPositionOnScreen(Position position, QRect available);
@ -96,8 +89,12 @@ private:
void moveAnimated(QPoint to); void moveAnimated(QPoint to);
void updateDecorations(); void updateDecorations();
[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Capabilities capabilities);
std::unique_ptr<Ui::RpWidgetWrap> _content;
QPointer<QWidget> _parent; QPointer<QWidget> _parent;
Fn<void(QPainter&, FrameRequest)> _paint; Fn<void(QPainter&, FrameRequest, bool)> _paint;
RectParts _attached = RectParts(); RectParts _attached = RectParts();
RectParts _snapped = RectParts(); RectParts _snapped = RectParts();
QSize _ratio; QSize _ratio;
@ -164,7 +161,7 @@ private:
void setupPanel(); void setupPanel();
void setupButtons(); void setupButtons();
void setupStreaming(); void setupStreaming();
void paint(QPainter &p, FrameRequest request); void paint(QPainter &p, FrameRequest request, bool opengl);
void playbackPauseResume(); void playbackPauseResume();
void waitingAnimationCallback(); void waitingAnimationCallback();
void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingUpdate(Streaming::Update &&update);

@ -1 +1 @@
Subproject commit e9fcbfcbacfe9f2f454a7bd34f1a3c5403245523 Subproject commit 95ee92088e62dfa20eb11d6fe59b0fb1834a1207