Use native child window in video calls on Windows.

This commit is contained in:
John Preston 2021-06-21 11:29:29 +04:00
parent b70276912e
commit 659ddae9a8
6 changed files with 149 additions and 225 deletions

View file

@ -42,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "window/main_window.h" #include "window/main_window.h"
#include "media/view/media_view_pip.h" // Utilities for frame rotation.
#include "app.h" #include "app.h"
#include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
@ -51,16 +50,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QDesktopWidget> #include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtCore/QTimer>
namespace Calls { namespace Calls {
Panel::Panel(not_null<Call*> call) Panel::Panel(not_null<Call*> call)
: _call(call) : _call(call)
, _user(call->user()) , _user(call->user())
, _window(createWindow())
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
, _controls(std::make_unique<Ui::Platform::TitleControls>( , _controls(std::make_unique<Ui::Platform::TitleControls>(
_window->body(), widget(),
st::callTitle, st::callTitle,
[=](bool maximized) { toggleFullScreen(maximized); })) [=](bool maximized) { toggleFullScreen(maximized); }))
#endif // !Q_OS_MAC #endif // !Q_OS_MAC
@ -86,46 +85,27 @@ Panel::Panel(not_null<Call*> call)
Panel::~Panel() = default; Panel::~Panel() = default;
std::unique_ptr<Ui::Window> Panel::createWindow() {
auto result = std::make_unique<Ui::Window>();
const auto capabilities = Ui::GL::CheckCapabilities(result.get());
const auto use = Platform::IsMac()
? true
: Platform::IsWindows()
? capabilities.supported
: capabilities.transparency;
LOG(("OpenGL: %1 (Incoming)").arg(Logs::b(use)));
_backend = use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster;
if (use) {
return result;
}
// We have to create a new window, if OpenGL initialization failed.
return std::make_unique<Ui::Window>();
}
bool Panel::isActive() const { bool Panel::isActive() const {
return _window->isActiveWindow() return window()->isActiveWindow()
&& _window->isVisible() && window()->isVisible()
&& !(_window->windowState() & Qt::WindowMinimized); && !(window()->windowState() & Qt::WindowMinimized);
} }
void Panel::showAndActivate() { void Panel::showAndActivate() {
if (_window->isHidden()) { if (window()->isHidden()) {
_window->show(); window()->show();
} }
const auto state = _window->windowState(); const auto state = window()->windowState();
if (state & Qt::WindowMinimized) { if (state & Qt::WindowMinimized) {
_window->setWindowState(state & ~Qt::WindowMinimized); window()->setWindowState(state & ~Qt::WindowMinimized);
} }
_window->raise(); window()->raise();
_window->activateWindow(); window()->activateWindow();
_window->setFocus(); window()->setFocus();
} }
void Panel::minimize() { void Panel::minimize() {
_window->setWindowState(_window->windowState() | Qt::WindowMinimized); window()->setWindowState(window()->windowState() | Qt::WindowMinimized);
} }
void Panel::replaceCall(not_null<Call*> call) { void Panel::replaceCall(not_null<Call*> call) {
@ -134,26 +114,26 @@ void Panel::replaceCall(not_null<Call*> call) {
} }
void Panel::initWindow() { void Panel::initWindow() {
_window->setAttribute(Qt::WA_OpaquePaintEvent); window()->setAttribute(Qt::WA_OpaquePaintEvent);
_window->setAttribute(Qt::WA_NoSystemBackground); window()->setAttribute(Qt::WA_NoSystemBackground);
_window->setWindowIcon( window()->setWindowIcon(
QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly))); QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
_window->setTitle(u" "_q); window()->setTitle(u" "_q);
_window->setTitleStyle(st::callTitle); window()->setTitleStyle(st::callTitle);
_window->events( window()->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close) { if (e->type() == QEvent::Close) {
handleClose(); handleClose();
} else if (e->type() == QEvent::KeyPress) { } else if (e->type() == QEvent::KeyPress) {
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape) if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
&& _window->isFullScreen()) { && window()->isFullScreen()) {
_window->showNormal(); window()->showNormal();
} }
} }
}, _window->lifetime()); }, window()->lifetime());
_window->setBodyTitleArea([=](QPoint widgetPoint) { window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag; using Flag = Ui::WindowTitleHitTestFlag;
if (!widget()->rect().contains(widgetPoint)) { if (!widget()->rect().contains(widgetPoint)) {
return Flag::None | Flag(0); return Flag::None | Flag(0);
@ -179,28 +159,31 @@ void Panel::initWindow() {
: (Flag::Move | Flag::FullScreen); : (Flag::Move | Flag::FullScreen);
}); });
#ifdef Q_OS_WIN // Don't do that, it looks awful :(
// On Windows we replace snap-to-top maximizing with fullscreen. //#ifdef Q_OS_WIN
// // // On Windows we replace snap-to-top maximizing with fullscreen.
// We have to switch first to showNormal, so that showFullScreen // //
// will remember correct normal window geometry and next showNormal // // We have to switch first to showNormal, so that showFullScreen
// will show it instead of a moving maximized window. // // will remember correct normal window geometry and next showNormal
// // // will show it instead of a moving maximized window.
// We have to do it in InvokeQueued, otherwise it still captures // //
// the maximized window geometry and saves it. // // We have to do it in InvokeQueued, otherwise it still captures
// // // the maximized window geometry and saves it.
// I couldn't find a less glitchy way to do that *sigh*. // //
const auto object = _window->windowHandle(); // // I couldn't find a less glitchy way to do that *sigh*.
const auto signal = &QWindow::windowStateChanged; // const auto object = window()->windowHandle();
QObject::connect(object, signal, [=](Qt::WindowState state) { // const auto signal = &QWindow::windowStateChanged;
if (state == Qt::WindowMaximized) { // QObject::connect(object, signal, [=](Qt::WindowState state) {
InvokeQueued(object, [=] { // if (state == Qt::WindowMaximized) {
_window->showNormal(); // InvokeQueued(object, [=] {
_window->showFullScreen(); // window()->showNormal();
}); // InvokeQueued(object, [=] {
} // window()->showFullScreen();
}); // });
#endif // Q_OS_WIN // });
// }
// });
//#endif // Q_OS_WIN
} }
void Panel::initWidget() { void Panel::initWidget() {
@ -339,7 +322,7 @@ void Panel::reinitWithCall(Call *call) {
_incoming = std::make_unique<Incoming>( _incoming = std::make_unique<Incoming>(
widget(), widget(),
_call->videoIncoming(), _call->videoIncoming(),
_backend); _window.backend());
_incoming->widget()->hide(); _incoming->widget()->hide();
_call->mutedValue( _call->mutedValue(
@ -519,16 +502,20 @@ void Panel::showControls() {
} }
void Panel::closeBeforeDestroy() { void Panel::closeBeforeDestroy() {
_window->close(); window()->close();
reinitWithCall(nullptr); reinitWithCall(nullptr);
} }
rpl::lifetime &Panel::lifetime() {
return window()->lifetime();
}
void Panel::initGeometry() { void Panel::initGeometry() {
const auto center = Core::App().getPointForCallPanelCenter(); const auto center = Core::App().getPointForCallPanelCenter();
const auto initRect = QRect(0, 0, st::callWidth, st::callHeight); const auto initRect = QRect(0, 0, st::callWidth, st::callHeight);
_window->setGeometry(initRect.translated(center - initRect.center())); window()->setGeometry(initRect.translated(center - initRect.center()));
_window->setMinimumSize({ st::callWidthMin, st::callHeightMin }); window()->setMinimumSize({ st::callWidthMin, st::callHeightMin });
_window->show(); window()->show();
updateControlsGeometry(); updateControlsGeometry();
} }
@ -546,9 +533,9 @@ void Panel::refreshOutgoingPreviewInBody(State state) {
void Panel::toggleFullScreen(bool fullscreen) { void Panel::toggleFullScreen(bool fullscreen) {
if (fullscreen) { if (fullscreen) {
_window->showFullScreen(); window()->showFullScreen();
} else { } else {
_window->showNormal(); window()->showNormal();
} }
} }
@ -724,8 +711,12 @@ void Panel::handleClose() {
} }
} }
not_null<Ui::Window*> Panel::window() const {
return _window.window();
}
not_null<Ui::RpWidget*> Panel::widget() const { not_null<Ui::RpWidget*> Panel::widget() const {
return _window->body(); return _window.widget();
} }
void Panel::stateChanged(State state) { void Panel::stateChanged(State state) {
@ -741,7 +732,7 @@ void Panel::stateChanged(State state) {
auto toggleButton = [&](auto &&button, bool visible) { auto toggleButton = [&](auto &&button, bool visible) {
button->toggle( button->toggle(
visible, visible,
_window->isHidden() window()->isHidden()
? anim::type::instant ? anim::type::instant
: anim::type::normal); : anim::type::normal);
}; };

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/object_ptr.h" #include "base/object_ptr.h"
#include "calls/calls_call.h" #include "calls/calls_call.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
class Image; class Image;
@ -60,6 +61,8 @@ public:
void replaceCall(not_null<Call*> call); void replaceCall(not_null<Call*> call);
void closeBeforeDestroy(); void closeBeforeDestroy();
rpl::lifetime &lifetime();
private: private:
class Incoming; class Incoming;
using State = Call::State; using State = Call::State;
@ -70,7 +73,7 @@ private:
Redial, Redial,
}; };
std::unique_ptr<Ui::Window> createWindow(); [[nodiscard]] not_null<Ui::Window*> window() const;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const; [[nodiscard]] not_null<Ui::RpWidget*> widget() const;
void paint(QRect clip); void paint(QRect clip);
@ -106,8 +109,7 @@ private:
Call *_call = nullptr; Call *_call = nullptr;
not_null<UserData*> _user; not_null<UserData*> _user;
Ui::GL::Backend _backend = Ui::GL::Backend(); Ui::GL::Window _window;
const std::unique_ptr<Ui::Window> _window;
std::unique_ptr<Incoming> _incoming; std::unique_ptr<Incoming> _incoming;
#ifndef Q_OS_MAC #ifndef Q_OS_MAC

View file

@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration. #include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
#include "window/window_controller.h" // Controller::sessionController. #include "window/window_controller.h" // Controller::sessionController.
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "media/view/media_view_pip.h"
#include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"

View file

@ -20,13 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/controls/call_mute_button.h" #include "ui/controls/call_mute_button.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/window.h"
#include "ui/widgets/call_button.h" #include "ui/widgets/call_button.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "ui/gl/gl_detection.h" #include "ui/widgets/window.h"
#include "ui/chat/group_call_bar.h" #include "ui/chat/group_call_bar.h"
#include "ui/layers/layer_manager.h" #include "ui/layers/layer_manager.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
@ -47,7 +46,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h" #include "main/main_session.h"
#include "base/event_filter.h" #include "base/event_filter.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/platform/base_platform_info.h"
#include "base/qt_signal_producer.h" #include "base/qt_signal_producer.h"
#include "base/timer_rpl.h" #include "base/timer_rpl.h"
#include "app.h" #include "app.h"
@ -76,7 +74,6 @@ constexpr auto kMicrophoneTooltipAfterLoudCount = 3;
constexpr auto kDropLoudAfterQuietCount = 5; constexpr auto kDropLoudAfterQuietCount = 5;
constexpr auto kMicrophoneTooltipLevelThreshold = 0.2; constexpr auto kMicrophoneTooltipLevelThreshold = 0.2;
constexpr auto kMicrophoneTooltipCheckInterval = crl::time(500); constexpr auto kMicrophoneTooltipCheckInterval = crl::time(500);
constexpr auto kUseNativeChild = Platform::IsWindows();
} // namespace } // namespace
@ -136,16 +133,14 @@ void Panel::MicLevelTester::check() {
Panel::Panel(not_null<GroupCall*> call) Panel::Panel(not_null<GroupCall*> call)
: _call(call) : _call(call)
, _peer(call->peer()) , _peer(call->peer())
, _window(std::make_unique<Ui::Window>())
, _nativeBodyWindow(createBodyWidget())
, _body(_nativeBodyWindow ? _nativeBodyWindow.get() : _window->body().get())
, _layerBg(std::make_unique<Ui::LayerManager>(widget())) , _layerBg(std::make_unique<Ui::LayerManager>(widget()))
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
, _controls(std::make_unique<Ui::Platform::TitleControls>( , _controls(std::make_unique<Ui::Platform::TitleControls>(
widget(), widget(),
st::groupCallTitle)) st::groupCallTitle))
#endif // !Q_OS_MAC #endif // !Q_OS_MAC
, _viewport(std::make_unique<Viewport>(widget(), PanelMode::Wide, _backend)) , _viewport(
std::make_unique<Viewport>(widget(), PanelMode::Wide, _window.backend()))
, _mute(std::make_unique<Ui::CallMuteButton>( , _mute(std::make_unique<Ui::CallMuteButton>(
widget(), widget(),
st::callMuteButton, st::callMuteButton,
@ -175,7 +170,7 @@ Panel::Panel(not_null<GroupCall*> call)
SubscribeToMigration( SubscribeToMigration(
_peer, _peer,
_window->lifetime(), lifetime(),
[=](not_null<ChannelData*> channel) { migrate(channel); }); [=](not_null<ChannelData*> channel) { migrate(channel); });
setupRealCallViewers(); setupRealCallViewers();
@ -191,77 +186,11 @@ Panel::~Panel() {
_viewport = nullptr; _viewport = nullptr;
} }
std::unique_ptr<Ui::Window> Panel::createWindow() {
auto result = std::make_unique<Ui::Window>();
if constexpr (!kUseNativeChild) {
const auto capabilities = Ui::GL::CheckCapabilities(result.get());
const auto use = Platform::IsMac()
? true
: Platform::IsWindows()
? capabilities.supported
: capabilities.transparency;
LOG(("OpenGL: %1 (Calls::Group::Panel)").arg(Logs::b(use)));
_backend = use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster;
if (!use) {
// We have to create a new window, if OpenGL initialization failed.
result = std::make_unique<Ui::Window>();
}
}
return result;
}
std::unique_ptr<Ui::RpWidget> Panel::createBodyWidget() {
if constexpr (!kUseNativeChild) {
return nullptr;
}
const auto create = [] {
auto result = std::make_unique<Ui::RpWidget>();
result->setWindowFlags(Qt::FramelessWindowHint | Qt::Window);
result->setAttribute(Qt::WA_NativeWindow);
result->setAttribute(Qt::WA_DontCreateNativeAncestors);
result->setAttribute(Qt::WA_OpaquePaintEvent);
result->setAttribute(Qt::WA_NoSystemBackground);
return result;
};
auto result = create();
const auto capabilities = Ui::GL::CheckCapabilities(result.get());
const auto use = Platform::IsMac()
? true
: Platform::IsWindows()
? capabilities.supported
: capabilities.transparency;
LOG(("OpenGL: %1 (Calls::Group::Panel)").arg(Logs::b(use)));
_backend = use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster;
if (!use) {
// We have to create a new window, if OpenGL initialization failed.
result = create();
}
const auto raw = result.get();
raw->setParent(_window->body());
raw->show();
raw->update();
_window->sizeValue(
) | rpl::start_with_next([=](QSize size) {
raw->setGeometry(QRect(QPoint(), size));
}, raw->lifetime());
_window->body()->paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(_window->body()).fillRect(clip, QColor(255, 0, 0));
}, _window->body()->lifetime());
return result;
}
void Panel::setupRealCallViewers() { void Panel::setupRealCallViewers() {
_call->real( _call->real(
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) { ) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
subscribeToChanges(real); subscribeToChanges(real);
}, _window->lifetime()); }, lifetime());
} }
not_null<GroupCall*> Panel::call() const { not_null<GroupCall*> Panel::call() const {
@ -269,9 +198,9 @@ not_null<GroupCall*> Panel::call() const {
} }
bool Panel::isActive() const { bool Panel::isActive() const {
return _window->isActiveWindow() return window()->isActiveWindow()
&& _window->isVisible() && window()->isVisible()
&& !(_window->windowState() & Qt::WindowMinimized); && !(window()->windowState() & Qt::WindowMinimized);
} }
void Panel::showToast(TextWithEntities &&text, crl::time duration) { void Panel::showToast(TextWithEntities &&text, crl::time duration) {
@ -286,24 +215,24 @@ void Panel::showToast(TextWithEntities &&text, crl::time duration) {
} }
void Panel::minimize() { void Panel::minimize() {
_window->setWindowState(_window->windowState() | Qt::WindowMinimized); window()->setWindowState(window()->windowState() | Qt::WindowMinimized);
} }
void Panel::close() { void Panel::close() {
_window->close(); window()->close();
} }
void Panel::showAndActivate() { void Panel::showAndActivate() {
if (_window->isHidden()) { if (window()->isHidden()) {
_window->show(); window()->show();
} }
const auto state = _window->windowState(); const auto state = window()->windowState();
if (state & Qt::WindowMinimized) { if (state & Qt::WindowMinimized) {
_window->setWindowState(state & ~Qt::WindowMinimized); window()->setWindowState(state & ~Qt::WindowMinimized);
} }
_window->raise(); window()->raise();
_window->activateWindow(); window()->activateWindow();
_window->setFocus(); window()->setFocus();
} }
void Panel::migrate(not_null<ChannelData*> channel) { void Panel::migrate(not_null<ChannelData*> channel) {
@ -318,12 +247,12 @@ void Panel::subscribeToPeerChanges() {
Info::Profile::NameValue( Info::Profile::NameValue(
_peer _peer
) | rpl::start_with_next([=](const TextWithEntities &name) { ) | rpl::start_with_next([=](const TextWithEntities &name) {
_window->setTitle(name.text); window()->setTitle(name.text);
}, _peerLifetime); }, _peerLifetime);
} }
QWidget *Panel::chooseSourceParent() { QWidget *Panel::chooseSourceParent() {
return _window.get(); return window().get();
} }
QString Panel::chooseSourceActiveDeviceId() { QString Panel::chooseSourceActiveDeviceId() {
@ -331,7 +260,7 @@ QString Panel::chooseSourceActiveDeviceId() {
} }
rpl::lifetime &Panel::chooseSourceInstanceLifetime() { rpl::lifetime &Panel::chooseSourceInstanceLifetime() {
return _window->lifetime(); return lifetime();
} }
void Panel::chooseSourceAccepted(const QString &deviceId) { void Panel::chooseSourceAccepted(const QString &deviceId) {
@ -343,15 +272,15 @@ void Panel::chooseSourceStop() {
} }
void Panel::initWindow() { void Panel::initWindow() {
_window->setAttribute(Qt::WA_OpaquePaintEvent); window()->setAttribute(Qt::WA_OpaquePaintEvent);
_window->setAttribute(Qt::WA_NoSystemBackground); window()->setAttribute(Qt::WA_NoSystemBackground);
_window->setWindowIcon( window()->setWindowIcon(
QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly))); QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
_window->setTitleStyle(st::groupCallTitle); window()->setTitleStyle(st::groupCallTitle);
subscribeToPeerChanges(); subscribeToPeerChanges();
base::install_event_filter(_window.get(), [=](not_null<QEvent*> e) { base::install_event_filter(window().get(), [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close && handleClose()) { if (e->type() == QEvent::Close && handleClose()) {
e->ignore(); e->ignore();
return base::EventFilterResult::Cancel; return base::EventFilterResult::Cancel;
@ -366,7 +295,7 @@ void Panel::initWindow() {
return base::EventFilterResult::Continue; return base::EventFilterResult::Continue;
}); });
_window->setBodyTitleArea([=](QPoint widgetPoint) { window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag; using Flag = Ui::WindowTitleHitTestFlag;
const auto titleRect = QRect( const auto titleRect = QRect(
0, 0,
@ -385,7 +314,7 @@ void Panel::initWindow() {
_call->hasVideoWithFramesValue( _call->hasVideoWithFramesValue(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
updateMode(); updateMode();
}, _window->lifetime()); }, lifetime());
} }
void Panel::initWidget() { void Panel::initWidget() {
@ -394,7 +323,7 @@ void Panel::initWidget() {
widget()->paintRequest( widget()->paintRequest(
) | rpl::start_with_next([=](QRect clip) { ) | rpl::start_with_next([=](QRect clip) {
paint(clip); paint(clip);
}, widget()->lifetime()); }, lifetime());
widget()->sizeValue( widget()->sizeValue(
) | rpl::skip(1) | rpl::start_with_next([=](QSize size) { ) | rpl::skip(1) | rpl::start_with_next([=](QSize size) {
@ -405,7 +334,7 @@ void Panel::initWidget() {
// title geometry depends on _controls->geometry, // title geometry depends on _controls->geometry,
// which is not updated here yet. // which is not updated here yet.
crl::on_main(widget(), [=] { refreshTitle(); }); crl::on_main(widget(), [=] { refreshTitle(); });
}, widget()->lifetime()); }, lifetime());
} }
void Panel::endCall() { void Panel::endCall() {
@ -479,7 +408,7 @@ void Panel::initControls() {
_call->canManageValue() _call->canManageValue()
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
refreshTopButton(); refreshTopButton();
}, widget()->lifetime()); }, lifetime());
_hangup->setClickedCallback([=] { endCall(); }); _hangup->setClickedCallback([=] { endCall(); });
@ -697,7 +626,7 @@ void Panel::initShareAction() {
callback(); callback();
} }
}; };
widget()->lifetime().add(std::move(shareLinkLifetime)); lifetime().add(std::move(shareLinkLifetime));
} }
void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) { void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
@ -773,7 +702,7 @@ void Panel::setupScheduledLabels(rpl::producer<TimeId> date) {
) | rpl::map([=](TimeId date) { ) | rpl::map([=](TimeId date) {
_countdownData = std::make_shared<Ui::GroupCallScheduledLeft>(date); _countdownData = std::make_shared<Ui::GroupCallScheduledLeft>(date);
return rpl::empty_value(); return rpl::empty_value();
}) | rpl::start_spawning(widget()->lifetime()); }) | rpl::start_spawning(lifetime());
_countdown = Ui::CreateGradientLabel(widget(), rpl::duplicate( _countdown = Ui::CreateGradientLabel(widget(), rpl::duplicate(
countdownCreated countdownCreated
@ -841,7 +770,7 @@ void Panel::setupMembers() {
_countdown.destroy(); _countdown.destroy();
_startsWhen.destroy(); _startsWhen.destroy();
_members.create(widget(), _call, mode(), _backend); _members.create(widget(), _call, mode(), _window.backend());
setupVideo(_viewport.get()); setupVideo(_viewport.get());
setupVideo(_members->viewport()); setupVideo(_members->viewport());
@ -898,40 +827,40 @@ void Panel::setupMembers() {
} }
void Panel::enlargeVideo() { void Panel::enlargeVideo() {
_lastSmallGeometry = _window->geometry(); _lastSmallGeometry = window()->geometry();
const auto available = _window->screen()->availableGeometry(); const auto available = window()->screen()->availableGeometry();
const auto width = std::max( const auto width = std::max(
_window->width(), window()->width(),
std::max( std::max(
std::min(available.width(), st::groupCallWideModeSize.width()), std::min(available.width(), st::groupCallWideModeSize.width()),
st::groupCallWideModeWidthMin)); st::groupCallWideModeWidthMin));
const auto height = std::max( const auto height = std::max(
_window->height(), window()->height(),
std::min(available.height(), st::groupCallWideModeSize.height())); std::min(available.height(), st::groupCallWideModeSize.height()));
auto geometry = QRect(_window->pos(), QSize(width, height)); auto geometry = QRect(window()->pos(), QSize(width, height));
if (geometry.x() < available.x()) { if (geometry.x() < available.x()) {
geometry.setX(std::min(available.x(), _window->x())); geometry.setX(std::min(available.x(), window()->x()));
} }
if (geometry.x() + geometry.width() if (geometry.x() + geometry.width()
> available.x() + available.width()) { > available.x() + available.width()) {
geometry.setX(std::max( geometry.setX(std::max(
available.x() + available.width(), available.x() + available.width(),
_window->x() + _window->width()) - geometry.width()); window()->x() + window()->width()) - geometry.width());
} }
if (geometry.y() < available.y()) { if (geometry.y() < available.y()) {
geometry.setY(std::min(available.y(), _window->y())); geometry.setY(std::min(available.y(), window()->y()));
} }
if (geometry.y() + geometry.height() > available.y() + available.height()) { if (geometry.y() + geometry.height() > available.y() + available.height()) {
geometry.setY(std::max( geometry.setY(std::max(
available.y() + available.height(), available.y() + available.height(),
_window->y() + _window->height()) - geometry.height()); window()->y() + window()->height()) - geometry.height());
} }
if (_lastLargeMaximized) { if (_lastLargeMaximized) {
_window->setWindowState( window()->setWindowState(
_window->windowState() | Qt::WindowMaximized); window()->windowState() | Qt::WindowMaximized);
} else { } else {
_window->setGeometry((_lastLargeGeometry window()->setGeometry((_lastLargeGeometry
&& available.intersects(*_lastLargeGeometry)) && available.intersects(*_lastLargeGeometry))
? *_lastLargeGeometry ? *_lastLargeGeometry
: geometry); : geometry);
@ -939,23 +868,23 @@ void Panel::enlargeVideo() {
} }
void Panel::minimizeVideo() { void Panel::minimizeVideo() {
if (_window->windowState() & Qt::WindowMaximized) { if (window()->windowState() & Qt::WindowMaximized) {
_lastLargeMaximized = true; _lastLargeMaximized = true;
_window->setWindowState( window()->setWindowState(
_window->windowState() & ~Qt::WindowMaximized); window()->windowState() & ~Qt::WindowMaximized);
} else { } else {
_lastLargeMaximized = false; _lastLargeMaximized = false;
_lastLargeGeometry = _window->geometry(); _lastLargeGeometry = window()->geometry();
} }
const auto available = _window->screen()->availableGeometry(); const auto available = window()->screen()->availableGeometry();
const auto width = st::groupCallWidth; const auto width = st::groupCallWidth;
const auto height = st::groupCallHeight; const auto height = st::groupCallHeight;
auto geometry = QRect( auto geometry = QRect(
_window->x() + (_window->width() - width) / 2, window()->x() + (window()->width() - width) / 2,
_window->y() + (_window->height() - height) / 2, window()->y() + (window()->height() - height) / 2,
width, width,
height); height);
_window->setGeometry((_lastSmallGeometry window()->setGeometry((_lastSmallGeometry
&& available.intersects(*_lastSmallGeometry)) && available.intersects(*_lastSmallGeometry))
? *_lastSmallGeometry ? *_lastSmallGeometry
: geometry); : geometry);
@ -1134,7 +1063,7 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
: tr::lng_group_call_recording_stopped)( : tr::lng_group_call_recording_stopped)(
tr::now, tr::now,
Ui::Text::RichLangValue)); Ui::Text::RichLangValue));
}, widget()->lifetime()); }, lifetime());
validateRecordingMark(real->recordStartDate() != 0); validateRecordingMark(real->recordStartDate() != 0);
rpl::combine( rpl::combine(
@ -1143,14 +1072,14 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
refreshVideoButtons(); refreshVideoButtons();
showStickedTooltip(); showStickedTooltip();
}, widget()->lifetime()); }, lifetime());
rpl::combine( rpl::combine(
_call->videoIsWorkingValue(), _call->videoIsWorkingValue(),
_call->isSharingScreenValue() _call->isSharingScreenValue()
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
refreshTopButton(); refreshTopButton();
}, widget()->lifetime()); }, lifetime());
_call->mutedValue( _call->mutedValue(
) | rpl::skip(1) | rpl::start_with_next([=](MuteState state) { ) | rpl::skip(1) | rpl::start_with_next([=](MuteState state) {
@ -1162,7 +1091,7 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
StickedTooltipHide::Activated); StickedTooltipHide::Activated);
} }
showStickedTooltip(); showStickedTooltip();
}, widget()->lifetime()); }, lifetime());
updateControlsGeometry(); updateControlsGeometry();
} }
@ -1208,7 +1137,7 @@ void Panel::refreshTopButton() {
chooseJoinAs(); chooseJoinAs();
}); });
updateControlsGeometry(); updateControlsGeometry();
}, widget()->lifetime()); }, lifetime());
} else { } else {
_menuToggle.destroy(); _menuToggle.destroy();
_joinAsToggle.destroy(); _joinAsToggle.destroy();
@ -1462,7 +1391,7 @@ void Panel::initLayout() {
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
// _menuToggle geometry depends on _controls arrangement. // _menuToggle geometry depends on _controls arrangement.
crl::on_main(widget(), [=] { updateControlsGeometry(); }); crl::on_main(widget(), [=] { updateControlsGeometry(); });
}, widget()->lifetime()); }, lifetime());
#endif // !Q_OS_MAC #endif // !Q_OS_MAC
} }
@ -1474,16 +1403,20 @@ void Panel::showControls() {
} }
void Panel::closeBeforeDestroy() { void Panel::closeBeforeDestroy() {
_window->close(); window()->close();
_callLifetime.destroy(); _callLifetime.destroy();
} }
rpl::lifetime &Panel::lifetime() {
return window()->lifetime();
}
void Panel::initGeometry() { void Panel::initGeometry() {
const auto center = Core::App().getPointForCallPanelCenter(); const auto center = Core::App().getPointForCallPanelCenter();
const auto rect = QRect(0, 0, st::groupCallWidth, st::groupCallHeight); const auto rect = QRect(0, 0, st::groupCallWidth, st::groupCallHeight);
_window->setGeometry(rect.translated(center - rect.center())); window()->setGeometry(rect.translated(center - rect.center()));
_window->setMinimumSize(rect.size()); window()->setMinimumSize(rect.size());
_window->show(); window()->show();
} }
QRect Panel::computeTitleRect() const { QRect Panel::computeTitleRect() const {
@ -2277,14 +2210,18 @@ void Panel::paint(QRect clip) {
bool Panel::handleClose() { bool Panel::handleClose() {
if (_call) { if (_call) {
_window->hide(); window()->hide();
return true; return true;
} }
return false; return false;
} }
not_null<Ui::Window*> Panel::window() const {
return _window.window();
}
not_null<Ui::RpWidget*> Panel::widget() const { not_null<Ui::RpWidget*> Panel::widget() const {
return _body.get(); return _window.widget();
} }
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/group/calls_choose_join_as.h" #include "calls/group/calls_choose_join_as.h"
#include "calls/group/ui/desktop_capture_choose_source.h" #include "calls/group/ui/desktop_capture_choose_source.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
class Image; class Image;
@ -38,14 +39,10 @@ template <typename Widget>
class FadeWrap; class FadeWrap;
template <typename Widget> template <typename Widget>
class PaddingWrap; class PaddingWrap;
class Window;
class ScrollArea; class ScrollArea;
class GenericBox; class GenericBox;
class LayerManager; class LayerManager;
class GroupCallScheduledLeft; class GroupCallScheduledLeft;
namespace GL {
enum class Backend;
} // namespace GL
namespace Toast { namespace Toast {
class Instance; class Instance;
} // namespace Toast } // namespace Toast
@ -82,6 +79,8 @@ public:
void showAndActivate(); void showAndActivate();
void closeBeforeDestroy(); void closeBeforeDestroy();
rpl::lifetime &lifetime();
private: private:
using State = GroupCall::State; using State = GroupCall::State;
struct ControlsBackgroundNarrow; struct ControlsBackgroundNarrow;
@ -97,8 +96,7 @@ private:
}; };
class MicLevelTester; class MicLevelTester;
[[nodiscard]] std::unique_ptr<Ui::Window> createWindow(); [[nodiscard]] not_null<Ui::Window*> window() const;
[[nodiscard]] std::unique_ptr<Ui::RpWidget> createBodyWidget();
[[nodiscard]] not_null<Ui::RpWidget*> widget() const; [[nodiscard]] not_null<Ui::RpWidget*> widget() const;
[[nodiscard]] PanelMode mode() const; [[nodiscard]] PanelMode mode() const;
@ -178,10 +176,7 @@ private:
const not_null<GroupCall*> _call; const not_null<GroupCall*> _call;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
Ui::GL::Backend _backend = Ui::GL::Backend(); Ui::GL::Window _window;
const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<Ui::RpWidget> _nativeBodyWindow;
const not_null<Ui::RpWidget*> _body;
const std::unique_ptr<Ui::LayerManager> _layerBg; const std::unique_ptr<Ui::LayerManager> _layerBg;
rpl::variable<PanelMode> _mode; rpl::variable<PanelMode> _mode;

@ -1 +1 @@
Subproject commit bd989cb67f5076b07556e8422cf6f8be6ba8d8ae Subproject commit f646439624766ec994d341102dc73b2b16d7fca2